mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
Merge patch series "UFS Advanced RPMB"
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>
This commit is contained in:
commit
c1635fbfef
@ -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);
|
||||
|
@ -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
|
||||
|
@ -14,10 +14,27 @@
|
||||
*/
|
||||
|
||||
#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 */
|
||||
|
@ -49,6 +49,11 @@
|
||||
*/
|
||||
#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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user