Merge patch series "UFS Advanced RPMB"
authorMartin K. Petersen <martin.petersen@oracle.com>
Fri, 30 Dec 2022 21:01:16 +0000 (21:01 +0000)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 30 Dec 2022 21:01:16 +0000 (21:01 +0000)
Bean Huo <beanhuo@iokpp.de> says:

This series of changes is to add support for UFS advanced RPMB in
ufs_bsg. The advanced RPMB application of user space is ufs_utils, the
reference code is at:

  https://github.com/beanhuo/ufs-utils-Micron/blob/ufs_arpmb/ufs_arpmb.c.

Changes to ufs_utils will be pushed to:

  https://github.com/westerndigitalcorporation/ufs-utils

Link: https://lore.kernel.org/r/20221201140437.549272-1-beanhuo@iokpp.de
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/core/ufs_bsg.c
drivers/ufs/core/ufshcd.c
include/uapi/scsi/scsi_bsg_ufs.h
include/ufs/ufs.h
include/ufs/ufshcd.h
include/ufs/ufshci.h

index b99e3f3..a8e58fa 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <linux/bsg-lib.h>
+#include <linux/dma-mapping.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include "ufs_bsg.h"
@@ -30,21 +31,6 @@ static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len,
        return 0;
 }
 
-static int ufs_bsg_verify_query_size(struct ufs_hba *hba,
-                                    unsigned int request_len,
-                                    unsigned int reply_len)
-{
-       int min_req_len = sizeof(struct ufs_bsg_request);
-       int min_rsp_len = sizeof(struct ufs_bsg_reply);
-
-       if (min_req_len > request_len || min_rsp_len > reply_len) {
-               dev_err(hba->dev, "not enough space assigned\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int ufs_bsg_alloc_desc_buffer(struct ufs_hba *hba, struct bsg_job *job,
                                     uint8_t **desc_buff, int *desc_len,
                                     enum query_opcode desc_op)
@@ -83,23 +69,84 @@ out:
        return 0;
 }
 
+static int ufs_bsg_exec_advanced_rpmb_req(struct ufs_hba *hba, struct bsg_job *job)
+{
+       struct ufs_rpmb_request *rpmb_request = job->request;
+       struct ufs_rpmb_reply *rpmb_reply = job->reply;
+       struct bsg_buffer *payload = NULL;
+       enum dma_data_direction dir;
+       struct scatterlist *sg_list;
+       int rpmb_req_type;
+       int sg_cnt;
+       int ret;
+       int data_len;
+
+       if (hba->ufs_version < ufshci_version(4, 0) || !hba->dev_info.b_advanced_rpmb_en ||
+           !(hba->capabilities & MASK_EHSLUTRD_SUPPORTED))
+               return -EINVAL;
+
+       if (rpmb_request->ehs_req.length != 2 || rpmb_request->ehs_req.ehs_type != 1)
+               return -EINVAL;
+
+       rpmb_req_type = be16_to_cpu(rpmb_request->ehs_req.meta.req_resp_type);
+
+       switch (rpmb_req_type) {
+       case UFS_RPMB_WRITE_KEY:
+       case UFS_RPMB_READ_CNT:
+       case UFS_RPMB_PURGE_ENABLE:
+               dir = DMA_NONE;
+               break;
+       case UFS_RPMB_WRITE:
+       case UFS_RPMB_SEC_CONF_WRITE:
+               dir = DMA_TO_DEVICE;
+               break;
+       case UFS_RPMB_READ:
+       case UFS_RPMB_SEC_CONF_READ:
+       case UFS_RPMB_PURGE_STATUS_READ:
+               dir = DMA_FROM_DEVICE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (dir != DMA_NONE) {
+               payload = &job->request_payload;
+               if (!payload || !payload->payload_len || !payload->sg_cnt)
+                       return -EINVAL;
+
+               sg_cnt = dma_map_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir);
+               if (unlikely(!sg_cnt))
+                       return -ENOMEM;
+               sg_list = payload->sg_list;
+               data_len = payload->payload_len;
+       }
+
+       ret = ufshcd_advanced_rpmb_req_handler(hba, &rpmb_request->bsg_request.upiu_req,
+                                  &rpmb_reply->bsg_reply.upiu_rsp, &rpmb_request->ehs_req,
+                                  &rpmb_reply->ehs_rsp, sg_cnt, sg_list, dir);
+
+       if (dir != DMA_NONE) {
+               dma_unmap_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir);
+
+               if (!ret)
+                       rpmb_reply->bsg_reply.reply_payload_rcv_len = data_len;
+       }
+
+       return ret;
+}
+
 static int ufs_bsg_request(struct bsg_job *job)
 {
        struct ufs_bsg_request *bsg_request = job->request;
        struct ufs_bsg_reply *bsg_reply = job->reply;
        struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent));
-       unsigned int req_len = job->request_len;
-       unsigned int reply_len = job->reply_len;
        struct uic_command uc = {};
        int msgcode;
-       uint8_t *desc_buff = NULL;
+       uint8_t *buff = NULL;
        int desc_len = 0;
        enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP;
        int ret;
-
-       ret = ufs_bsg_verify_query_size(hba, req_len, reply_len);
-       if (ret)
-               goto out;
+       bool rpmb = false;
 
        bsg_reply->reply_payload_rcv_len = 0;
 
@@ -109,34 +156,39 @@ static int ufs_bsg_request(struct bsg_job *job)
        switch (msgcode) {
        case UPIU_TRANSACTION_QUERY_REQ:
                desc_op = bsg_request->upiu_req.qr.opcode;
-               ret = ufs_bsg_alloc_desc_buffer(hba, job, &desc_buff,
-                                               &desc_len, desc_op);
-               if (ret) {
-                       ufshcd_rpm_put_sync(hba);
+               ret = ufs_bsg_alloc_desc_buffer(hba, job, &buff, &desc_len, desc_op);
+               if (ret)
                        goto out;
-               }
-
                fallthrough;
        case UPIU_TRANSACTION_NOP_OUT:
        case UPIU_TRANSACTION_TASK_REQ:
                ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req,
                                               &bsg_reply->upiu_rsp, msgcode,
-                                              desc_buff, &desc_len, desc_op);
+                                              buff, &desc_len, desc_op);
                if (ret)
-                       dev_err(hba->dev,
-                               "exe raw upiu: error code %d\n", ret);
-
+                       dev_err(hba->dev, "exe raw upiu: error code %d\n", ret);
+               else if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len) {
+                       bsg_reply->reply_payload_rcv_len =
+                               sg_copy_from_buffer(job->request_payload.sg_list,
+                                                   job->request_payload.sg_cnt,
+                                                   buff, desc_len);
+               }
                break;
        case UPIU_TRANSACTION_UIC_CMD:
                memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
                ret = ufshcd_send_uic_cmd(hba, &uc);
                if (ret)
-                       dev_err(hba->dev,
-                               "send uic cmd: error code %d\n", ret);
+                       dev_err(hba->dev, "send uic cmd: error code %d\n", ret);
 
                memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE);
 
                break;
+       case UPIU_TRANSACTION_ARPMB_CMD:
+               rpmb = true;
+               ret = ufs_bsg_exec_advanced_rpmb_req(hba, job);
+               if (ret)
+                       dev_err(hba->dev, "ARPMB OP failed: error code  %d\n", ret);
+               break;
        default:
                ret = -ENOTSUPP;
                dev_err(hba->dev, "unsupported msgcode 0x%x\n", msgcode);
@@ -144,22 +196,11 @@ static int ufs_bsg_request(struct bsg_job *job)
                break;
        }
 
-       ufshcd_rpm_put_sync(hba);
-
-       if (!desc_buff)
-               goto out;
-
-       if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len)
-               bsg_reply->reply_payload_rcv_len =
-                       sg_copy_from_buffer(job->request_payload.sg_list,
-                                           job->request_payload.sg_cnt,
-                                           desc_buff, desc_len);
-
-       kfree(desc_buff);
-
 out:
+       ufshcd_rpm_put_sync(hba);
+       kfree(buff);
        bsg_reply->result = ret;
-       job->reply_len = sizeof(struct ufs_bsg_reply);
+       job->reply_len = !rpmb ? sizeof(struct ufs_bsg_reply) : sizeof(struct ufs_rpmb_reply);
        /* complete the job here only if no error */
        if (ret == 0)
                bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
index e18c9f4..5387603 100644 (file)
@@ -56,6 +56,9 @@
 /* Query request timeout */
 #define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
 
+/* Advanced RPMB request timeout */
+#define ADVANCED_RPMB_REQ_TIMEOUT  3000 /* 3 seconds */
+
 /* Task management command timeout */
 #define TM_CMD_TIMEOUT 100 /* msecs */
 
@@ -2399,38 +2402,30 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
 }
 
 /**
- * ufshcd_map_sg - Map scatter-gather list to prdt
- * @hba: per adapter instance
- * @lrbp: pointer to local reference block
- *
- * Returns 0 in case of success, non-zero value in case of failure
+ * ufshcd_sgl_to_prdt - SG list to PRTD (Physical Region Description Table, 4DW format)
+ * @hba:       per-adapter instance
+ * @lrbp:      pointer to local reference block
+ * @sg_entries:        The number of sg lists actually used
+ * @sg_list:   Pointer to SG list
  */
-static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+static void ufshcd_sgl_to_prdt(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, int sg_entries,
+                              struct scatterlist *sg_list)
 {
        struct ufshcd_sg_entry *prd_table;
        struct scatterlist *sg;
-       struct scsi_cmnd *cmd;
-       int sg_segments;
        int i;
 
-       cmd = lrbp->cmd;
-       sg_segments = scsi_dma_map(cmd);
-       if (sg_segments < 0)
-               return sg_segments;
-
-       if (sg_segments) {
+       if (sg_entries) {
 
                if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN)
                        lrbp->utr_descriptor_ptr->prd_table_length =
-                               cpu_to_le16((sg_segments *
-                                       sizeof(struct ufshcd_sg_entry)));
+                               cpu_to_le16((sg_entries * sizeof(struct ufshcd_sg_entry)));
                else
-                       lrbp->utr_descriptor_ptr->prd_table_length =
-                               cpu_to_le16(sg_segments);
+                       lrbp->utr_descriptor_ptr->prd_table_length = cpu_to_le16(sg_entries);
 
                prd_table = lrbp->ucd_prdt_ptr;
 
-               scsi_for_each_sg(cmd, sg, sg_segments, i) {
+               for_each_sg(sg_list, sg, sg_entries, i) {
                        const unsigned int len = sg_dma_len(sg);
 
                        /*
@@ -2449,6 +2444,24 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
        } else {
                lrbp->utr_descriptor_ptr->prd_table_length = 0;
        }
+}
+
+/**
+ * ufshcd_map_sg - Map scatter-gather list to prdt
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ *
+ * Returns 0 in case of success, non-zero value in case of failure
+ */
+static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+       struct scsi_cmnd *cmd = lrbp->cmd;
+       int sg_segments = scsi_dma_map(cmd);
+
+       if (sg_segments < 0)
+               return sg_segments;
+
+       ufshcd_sgl_to_prdt(hba, lrbp, sg_segments, scsi_sglist(cmd));
 
        return 0;
 }
@@ -2496,14 +2509,15 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
 }
 
 /**
- * ufshcd_prepare_req_desc_hdr() - Fills the requests header
+ * ufshcd_prepare_req_desc_hdr - Fill UTP Transfer request descriptor header according to request
  * descriptor according to request
  * @lrbp: pointer to local reference block
  * @upiu_flags: flags required in the header
  * @cmd_dir: requests data direction
+ * @ehs_length: Total EHS Length (in 32‐bytes units of all Extra Header Segments)
  */
-static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
-                       u8 *upiu_flags, enum dma_data_direction cmd_dir)
+static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, u8 *upiu_flags,
+                                       enum dma_data_direction cmd_dir, int ehs_length)
 {
        struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
        u32 data_direction;
@@ -2522,8 +2536,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
                *upiu_flags = UPIU_CMD_FLAGS_NONE;
        }
 
-       dword_0 = data_direction | (lrbp->command_type
-                               << UPIU_COMMAND_TYPE_OFFSET);
+       dword_0 = data_direction | (lrbp->command_type << UPIU_COMMAND_TYPE_OFFSET) |
+               ehs_length << 8;
        if (lrbp->intr_cmd)
                dword_0 |= UTP_REQ_DESC_INT_CMD;
 
@@ -2578,8 +2592,7 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags)
 }
 
 /**
- * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
- * for query requsts
+ * ufshcd_prepare_utp_query_req_upiu() - fill the utp_transfer_req_desc for query request
  * @hba: UFS hba
  * @lrbp: local reference block pointer
  * @upiu_flags: flags
@@ -2650,7 +2663,7 @@ static int ufshcd_compose_devman_upiu(struct ufs_hba *hba,
        else
                lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
 
-       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE, 0);
        if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
                ufshcd_prepare_utp_query_req_upiu(hba, lrbp, upiu_flags);
        else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP)
@@ -2678,8 +2691,7 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
                lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
 
        if (likely(lrbp->cmd)) {
-               ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags,
-                                               lrbp->cmd->sc_data_direction);
+               ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, lrbp->cmd->sc_data_direction, 0);
                ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
        } else {
                ret = -EINVAL;
@@ -2945,6 +2957,12 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
                dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n",
                                __func__);
                break;
+       case UPIU_TRANSACTION_RESPONSE:
+               if (hba->dev_cmd.type != DEV_CMD_TYPE_RPMB) {
+                       err = -EINVAL;
+                       dev_err(hba->dev, "%s: unexpected response %x\n", __func__, resp);
+               }
+               break;
        default:
                err = -EINVAL;
                dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n",
@@ -4944,6 +4962,12 @@ static void ufshcd_lu_init(struct ufs_hba *hba, struct scsi_device *sdev)
            desc_buf[UNIT_DESC_PARAM_LU_WR_PROTECT] == UFS_LU_POWER_ON_WP)
                hba->dev_info.is_lu_power_on_wp = true;
 
+       /* In case of RPMB LU, check if advanced RPMB mode is enabled */
+       if (desc_buf[UNIT_DESC_PARAM_UNIT_INDEX] == UFS_UPIU_RPMB_WLUN &&
+           desc_buf[RPMB_UNIT_DESC_PARAM_REGION_EN] & BIT(4))
+               hba->dev_info.b_advanced_rpmb_en = true;
+
+
        kfree(desc_buf);
 set_qdepth:
        /*
@@ -6868,7 +6892,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
        /* update the task tag in the request upiu */
        req_upiu->header.dword_0 |= cpu_to_be32(tag);
 
-       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE, 0);
 
        /* just copy the upiu request as it is */
        memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr));
@@ -6991,6 +7015,100 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
        return err;
 }
 
+/**
+ * ufshcd_advanced_rpmb_req_handler - handle advanced RPMB request
+ * @hba:       per adapter instance
+ * @req_upiu:  upiu request
+ * @rsp_upiu:  upiu reply
+ * @req_ehs:   EHS field which contains Advanced RPMB Request Message
+ * @rsp_ehs:   EHS field which returns Advanced RPMB Response Message
+ * @sg_cnt:    The number of sg lists actually used
+ * @sg_list:   Pointer to SG list when DATA IN/OUT UPIU is required in ARPMB operation
+ * @dir:       DMA direction
+ *
+ * Returns zero on success, non-zero on failure
+ */
+int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu,
+                        struct utp_upiu_req *rsp_upiu, struct ufs_ehs *req_ehs,
+                        struct ufs_ehs *rsp_ehs, int sg_cnt, struct scatterlist *sg_list,
+                        enum dma_data_direction dir)
+{
+       DECLARE_COMPLETION_ONSTACK(wait);
+       const u32 tag = hba->reserved_slot;
+       struct ufshcd_lrb *lrbp;
+       int err = 0;
+       int result;
+       u8 upiu_flags;
+       u8 *ehs_data;
+       u16 ehs_len;
+
+       /* Protects use of hba->reserved_slot. */
+       ufshcd_hold(hba, false);
+       mutex_lock(&hba->dev_cmd.lock);
+       down_read(&hba->clk_scaling_lock);
+
+       lrbp = &hba->lrb[tag];
+       WARN_ON(lrbp->cmd);
+       lrbp->cmd = NULL;
+       lrbp->task_tag = tag;
+       lrbp->lun = UFS_UPIU_RPMB_WLUN;
+
+       lrbp->intr_cmd = true;
+       ufshcd_prepare_lrbp_crypto(NULL, lrbp);
+       hba->dev_cmd.type = DEV_CMD_TYPE_RPMB;
+
+       /* Advanced RPMB starts from UFS 4.0, so its command type is UTP_CMD_TYPE_UFS_STORAGE */
+       lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
+
+       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, dir, 2);
+
+       /* update the task tag and LUN in the request upiu */
+       req_upiu->header.dword_0 |= cpu_to_be32(upiu_flags << 16 | UFS_UPIU_RPMB_WLUN << 8 | tag);
+
+       /* copy the UPIU(contains CDB) request as it is */
+       memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr));
+       /* Copy EHS, starting with byte32, immediately after the CDB package */
+       memcpy(lrbp->ucd_req_ptr + 1, req_ehs, sizeof(*req_ehs));
+
+       if (dir != DMA_NONE && sg_list)
+               ufshcd_sgl_to_prdt(hba, lrbp, sg_cnt, sg_list);
+
+       memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+
+       hba->dev_cmd.complete = &wait;
+
+       ufshcd_send_command(hba, tag);
+
+       err = ufshcd_wait_for_dev_cmd(hba, lrbp, ADVANCED_RPMB_REQ_TIMEOUT);
+
+       if (!err) {
+               /* Just copy the upiu response as it is */
+               memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu));
+               /* Get the response UPIU result */
+               result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+               ehs_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) >> 24;
+               /*
+                * Since the bLength in EHS indicates the total size of the EHS Header and EHS Data
+                * in 32 Byte units, the value of the bLength Request/Response for Advanced RPMB
+                * Message is 02h
+                */
+               if (ehs_len == 2 && rsp_ehs) {
+                       /*
+                        * ucd_rsp_ptr points to a buffer with a length of 512 bytes
+                        * (ALIGNED_UPIU_SIZE = 512), and the EHS data just starts from byte32
+                        */
+                       ehs_data = (u8 *)lrbp->ucd_rsp_ptr + EHS_OFFSET_IN_RESPONSE;
+                       memcpy(rsp_ehs, ehs_data, ehs_len * 32);
+               }
+       }
+
+       up_read(&hba->clk_scaling_lock);
+       mutex_unlock(&hba->dev_cmd.lock);
+       ufshcd_release(hba);
+       return err ? : result;
+}
+
 /**
  * ufshcd_eh_device_reset_handler() - Reset a single logical unit.
  * @cmd: SCSI command pointer
index d55f217..276e277 100644 (file)
  */
 
 #define UFS_CDB_SIZE   16
-#define UPIU_TRANSACTION_UIC_CMD 0x1F
 /* uic commands are 4DW long, per UFSHCI V2.1 paragraph 5.6.1 */
 #define UIC_CMD_SIZE (sizeof(__u32) * 4)
 
+enum ufs_bsg_msg_code {
+       UPIU_TRANSACTION_UIC_CMD = 0x1F,
+       UPIU_TRANSACTION_ARPMB_CMD,
+};
+
+/* UFS RPMB Request Message Types */
+enum ufs_rpmb_op_type {
+       UFS_RPMB_WRITE_KEY              = 0x01,
+       UFS_RPMB_READ_CNT               = 0x02,
+       UFS_RPMB_WRITE                  = 0x03,
+       UFS_RPMB_READ                   = 0x04,
+       UFS_RPMB_READ_RESP              = 0x05,
+       UFS_RPMB_SEC_CONF_WRITE         = 0x06,
+       UFS_RPMB_SEC_CONF_READ          = 0x07,
+       UFS_RPMB_PURGE_ENABLE           = 0x08,
+       UFS_RPMB_PURGE_STATUS_READ      = 0x09,
+};
+
 /**
  * struct utp_upiu_header - UPIU header structure
  * @dword_0: UPIU header DW-0
@@ -79,6 +96,23 @@ struct utp_upiu_req {
        };
 };
 
+struct ufs_arpmb_meta {
+       __u16   req_resp_type;
+       __u8    nonce[16];
+       __u32   write_counter;
+       __u16   addr_lun;
+       __u16   block_count;
+       __u16   result;
+} __attribute__((__packed__));
+
+struct ufs_ehs {
+       __u8    length;
+       __u8    ehs_type;
+       __u16   ehssub_type;
+       struct ufs_arpmb_meta meta;
+       __u8    mac_key[32];
+} __attribute__((__packed__));
+
 /* request (CDB) structure of the sg_io_v4 */
 struct ufs_bsg_request {
        __u32 msgcode;
@@ -95,11 +129,21 @@ struct ufs_bsg_reply {
         * msg and status fields. The per-msgcode reply structure
         * will contain valid data.
         */
-       __u32 result;
+       int result;
 
        /* If there was reply_payload, how much was received? */
        __u32 reply_payload_rcv_len;
 
        struct utp_upiu_req upiu_rsp;
 };
+
+struct ufs_rpmb_request {
+       struct ufs_bsg_request bsg_request;
+       struct ufs_ehs ehs_req;
+};
+
+struct ufs_rpmb_reply {
+       struct ufs_bsg_reply bsg_reply;
+       struct ufs_ehs ehs_rsp;
+};
 #endif /* UFS_BSG_H */
index 1bba3fe..0c11219 100644 (file)
  */
 #define UFS_WB_EXCEED_LIFETIME         0x0B
 
+/*
+ * In UFS Spec, the Extra Header Segment (EHS) starts from byte 32 in UPIU request/response packet
+ */
+#define EHS_OFFSET_IN_RESPONSE 32
+
 /* Well known logical unit id in LUN field of UPIU */
 enum {
        UFS_UPIU_REPORT_LUNS_WLUN       = 0x81,
@@ -212,6 +217,28 @@ enum unit_desc_param {
        UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS      = 0x29,
 };
 
+/* RPMB Unit descriptor parameters offsets in bytes*/
+enum rpmb_unit_desc_param {
+       RPMB_UNIT_DESC_PARAM_LEN                = 0x0,
+       RPMB_UNIT_DESC_PARAM_TYPE               = 0x1,
+       RPMB_UNIT_DESC_PARAM_UNIT_INDEX         = 0x2,
+       RPMB_UNIT_DESC_PARAM_LU_ENABLE          = 0x3,
+       RPMB_UNIT_DESC_PARAM_BOOT_LUN_ID        = 0x4,
+       RPMB_UNIT_DESC_PARAM_LU_WR_PROTECT      = 0x5,
+       RPMB_UNIT_DESC_PARAM_LU_Q_DEPTH         = 0x6,
+       RPMB_UNIT_DESC_PARAM_PSA_SENSITIVE      = 0x7,
+       RPMB_UNIT_DESC_PARAM_MEM_TYPE           = 0x8,
+       RPMB_UNIT_DESC_PARAM_REGION_EN          = 0x9,
+       RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_SIZE   = 0xA,
+       RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_COUNT  = 0xB,
+       RPMB_UNIT_DESC_PARAM_REGION0_SIZE       = 0x13,
+       RPMB_UNIT_DESC_PARAM_REGION1_SIZE       = 0x14,
+       RPMB_UNIT_DESC_PARAM_REGION2_SIZE       = 0x15,
+       RPMB_UNIT_DESC_PARAM_REGION3_SIZE       = 0x16,
+       RPMB_UNIT_DESC_PARAM_PROVISIONING_TYPE  = 0x17,
+       RPMB_UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT   = 0x18,
+};
+
 /* Device descriptor parameters offsets in bytes*/
 enum device_desc_param {
        DEVICE_DESC_PARAM_LEN                   = 0x0,
@@ -601,6 +628,8 @@ struct ufs_dev_info {
 
        bool    b_rpm_dev_flush_capable;
        u8      b_presrv_uspc_en;
+
+       bool    b_advanced_rpmb_en;
 };
 
 /*
index 5cf81df..c3dfa80 100644 (file)
@@ -30,6 +30,7 @@ struct ufs_hba;
 enum dev_cmd_type {
        DEV_CMD_TYPE_NOP                = 0x0,
        DEV_CMD_TYPE_QUERY              = 0x1,
+       DEV_CMD_TYPE_RPMB               = 0x2,
 };
 
 enum ufs_event_type {
@@ -1201,7 +1202,10 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
                             int msgcode,
                             u8 *desc_buff, int *buff_len,
                             enum query_opcode desc_op);
-
+int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu,
+                                    struct utp_upiu_req *rsp_upiu, struct ufs_ehs *ehs_req,
+                                    struct ufs_ehs *ehs_rsp, int sg_cnt,
+                                    struct scatterlist *sg_list, enum dma_data_direction dir);
 int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable);
 int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable);
 int ufshcd_suspend_prepare(struct device *dev);
index f525566..af21629 100644 (file)
@@ -63,6 +63,7 @@ enum {
 enum {
        MASK_TRANSFER_REQUESTS_SLOTS            = 0x0000001F,
        MASK_TASK_MANAGEMENT_REQUEST_SLOTS      = 0x00070000,
+       MASK_EHSLUTRD_SUPPORTED                 = 0x00400000,
        MASK_AUTO_HIBERN8_SUPPORT               = 0x00800000,
        MASK_64_ADDRESSING_SUPPORT              = 0x01000000,
        MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000,