[PATCH 1/1] Revert "scsi: ufs: Let the SCSI core allocate per-command UFS data"
From: huobean
Date: Wed Mar 11 2020 - 07:29:46 EST
From: Bean Huo <beanhuo@xxxxxxxxxx>
This patch is to revert commit 2bb1156f9f1b36b1f594b89fa5412fd4178b28c6.
There are two issues in commit (scsi: ufs: Let the SCSI core
allocate per-command UFS data) with the ufshcd_init_lrb() called
in ufshcd_init_cmd_priv():
- cmd->tag is set from inside scsi_mq_prep_fn() and hence is not yet
set when ufshcd_init_cmd_priv() is set.
- Inside ufshcd_init_cmd_priv() the tag can only be derived from the SCSI
command pointer if no scheduler has been associated with the UFS block
device. If no scheduler is associated with a block device, the
relationship between hctx->tags->static_rqs[] and rq->tag is static.
If a scheduler has been configured, a single tag can be associated
with a different struct request if a request is reallocated.
So revert this commit simply.
Signed-off-by: Bean Huo <beanhuo@xxxxxxxxxx>
---
drivers/scsi/ufs/ufshcd.c | 198 ++++++++++++++------------------------
drivers/scsi/ufs/ufshcd.h | 5 +
2 files changed, 75 insertions(+), 128 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e987fa3a77c7..2a2a63b68a67 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -296,60 +296,19 @@ static void ufshcd_scsi_block_requests(struct ufs_hba *hba)
scsi_block_requests(hba->host);
}
-/*
- * Convert a SCSI or device management command tag into a request pointer. Use
- * scsi_cmd_priv() instead of this function if a SCSI command pointer is
- * available. The caller must ensure that the request state won't change as
- * long as the returned pointer is in use.
- */
-static struct request *ufshcd_tag_to_req(struct ufs_hba *hba, unsigned int tag)
-{
- return blk_mq_tag_to_rq(hba->cmd_queue->tag_set->tags[0], tag);
-}
-
-/* Convert a SCSI or device management request pointer into an LRB pointer. */
-static struct ufshcd_lrb *ufshcd_req_to_lrb(struct request *req)
-{
- struct scsi_cmnd *cmd = container_of(scsi_req(req), typeof(*cmd), req);
-
- return scsi_cmd_priv(cmd);
-}
-
-/*
- * Convert a SCSI or device management command tag into a UFS data pointer. Use
- * scsi_cmd_priv() instead of this function if a SCSI command pointer is
- * available. The caller must ensure that the SCSI command state won't change
- * as long as the returned pointer is in use.
- */
-static struct ufshcd_lrb *ufshcd_tag_to_lrb(struct ufs_hba *hba,
- unsigned int tag)
-{
- struct request *req = ufshcd_tag_to_req(hba, tag);
-
- return req ? ufshcd_req_to_lrb(req) : NULL;
-}
-
static void ufshcd_add_cmd_upiu_trace(struct ufs_hba *hba, unsigned int tag,
const char *str)
{
- struct ufshcd_lrb *lrb = ufshcd_tag_to_lrb(hba, tag);
- struct utp_upiu_req *rq;
+ struct utp_upiu_req *rq = hba->lrb[tag].ucd_req_ptr;
- if (WARN_ON_ONCE(!lrb))
- return;
- rq = lrb->ucd_req_ptr;
trace_ufshcd_upiu(dev_name(hba->dev), str, &rq->header, &rq->sc.cdb);
}
static void ufshcd_add_query_upiu_trace(struct ufs_hba *hba, unsigned int tag,
const char *str)
{
- struct ufshcd_lrb *lrb = ufshcd_tag_to_lrb(hba, tag);
- struct utp_upiu_req *rq;
+ struct utp_upiu_req *rq = hba->lrb[tag].ucd_req_ptr;
- if (WARN_ON_ONCE(!lrb))
- return;
- rq = lrb->ucd_req_ptr;
trace_ufshcd_upiu(dev_name(hba->dev), str, &rq->header, &rq->qr);
}
@@ -363,35 +322,16 @@ static void ufshcd_add_tm_upiu_trace(struct ufs_hba *hba, unsigned int tag,
&descp->input_param1);
}
-/*
- * Whether or not @req represents a SCSI command. Returns false for device
- * management commands and also for TMFs.
- */
-static bool ufshcd_is_scsi(struct request *req)
-{
- switch (req_op(req)) {
- case REQ_OP_DRV_IN:
- case REQ_OP_DRV_OUT:
- return false;
- }
- return true;
-}
-
-/* Trace a SCSI or device management command. */
-static void ufshcd_add_command_trace(struct ufs_hba *hba, struct request *req,
- const char *str)
+static void ufshcd_add_command_trace(struct ufs_hba *hba,
+ unsigned int tag, const char *str)
{
sector_t lba = -1;
u8 opcode = 0;
u32 intr, doorbell;
- struct ufshcd_lrb *lrbp = ufshcd_req_to_lrb(req);
- struct scsi_cmnd *cmd = NULL;
- unsigned int tag = req->tag;
+ struct ufshcd_lrb *lrbp = &hba->lrb[tag];
+ struct scsi_cmnd *cmd = lrbp->cmd;
int transfer_len = -1;
- if (ufshcd_is_scsi(req))
- cmd = blk_mq_rq_to_pdu(req);
-
if (!trace_ufshcd_command_enabled()) {
/* trace UPIU W/O tracing command */
if (cmd)
@@ -501,9 +441,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
int tag;
for_each_set_bit(tag, &bitmap, hba->nutrs) {
- lrbp = ufshcd_tag_to_lrb(hba, tag);
- if (!lrbp)
- continue;
+ lrbp = &hba->lrb[tag];
dev_err(hba->dev, "UPIU[%d] - issue time %lld us\n",
tag, ktime_to_us(lrbp->issue_time_stamp));
@@ -1915,17 +1853,14 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
/**
* ufshcd_send_command - Send SCSI or device management commands
* @hba: per adapter instance
- * @req: SCSI or device management command pointer
+ * @task_tag: Task tag of the command
*/
static inline
-void ufshcd_send_command(struct ufs_hba *hba, struct request *req)
+void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
{
- struct ufshcd_lrb *lrbp = ufshcd_req_to_lrb(req);
- unsigned int task_tag = req->tag;
-
- lrbp->issue_time_stamp = ktime_get();
- lrbp->compl_time_stamp = ktime_set(0, 0);
- ufshcd_add_command_trace(hba, req, "send");
+ hba->lrb[task_tag].issue_time_stamp = ktime_get();
+ hba->lrb[task_tag].compl_time_stamp = ktime_set(0, 0);
+ ufshcd_add_command_trace(hba, task_tag, "send");
ufshcd_clk_scaling_start_busy(hba);
__set_bit(task_tag, &hba->outstanding_reqs);
ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
@@ -2141,18 +2076,19 @@ 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
- * @cmd: SCSI command to map
+ * @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 scsi_cmnd *cmd)
+static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
{
- struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd);
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;
@@ -2271,13 +2207,13 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
/**
* ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
* for scsi commands
- * @cmd: SCSI command to prepare
+ * @lrbp: local reference block pointer
* @upiu_flags: flags
*/
static
-void ufshcd_prepare_utp_scsi_cmd_upiu(struct scsi_cmnd *cmd, u32 upiu_flags)
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
{
- struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd);
+ struct scsi_cmnd *cmd = lrbp->cmd;
struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
unsigned short cdb_len;
@@ -2388,12 +2324,10 @@ static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
* ufshcd_comp_scsi_upiu - UFS Protocol Information Unit(UPIU)
* for SCSI Purposes
* @hba: per adapter instance
- * @cmd: command to prepare.
+ * @lrbp: pointer to local reference block
*/
-static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct scsi_cmnd *cmd)
+static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
{
- struct request *req = cmd->request;
- struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd);
u32 upiu_flags;
int ret = 0;
@@ -2403,10 +2337,10 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct scsi_cmnd *cmd)
else
lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
- if (likely(ufshcd_is_scsi(req))) {
+ if (likely(lrbp->cmd)) {
ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags,
- cmd->sc_data_direction);
- ufshcd_prepare_utp_scsi_cmd_upiu(cmd, upiu_flags);
+ lrbp->cmd->sc_data_direction);
+ ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
} else {
ret = -EINVAL;
}
@@ -2455,7 +2389,7 @@ static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
*/
static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
- struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd);
+ struct ufshcd_lrb *lrbp;
struct ufs_hba *hba;
unsigned long flags;
int tag;
@@ -2471,8 +2405,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
BUG();
}
- WARN_ON_ONCE(!ufshcd_is_scsi(cmd->request));
-
if (!down_read_trylock(&hba->clk_scaling_lock))
return SCSI_MLQUEUE_HOST_BUSY;
@@ -2513,6 +2445,10 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
}
WARN_ON(hba->clk_gating.state != CLKS_ON);
+ lrbp = &hba->lrb[tag];
+
+ WARN_ON(lrbp->cmd);
+ lrbp->cmd = cmd;
lrbp->sense_bufflen = UFS_SENSE_SIZE;
lrbp->sense_buffer = cmd->sense_buffer;
lrbp->task_tag = tag;
@@ -2520,10 +2456,11 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
lrbp->req_abort_skip = false;
- ufshcd_comp_scsi_upiu(hba, cmd);
+ ufshcd_comp_scsi_upiu(hba, lrbp);
- err = ufshcd_map_sg(hba, cmd);
+ err = ufshcd_map_sg(hba, lrbp);
if (err) {
+ lrbp->cmd = NULL;
ufshcd_release(hba);
goto out;
}
@@ -2533,7 +2470,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
/* issue command to the controller */
spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_vops_setup_xfer_req(hba, tag, true);
- ufshcd_send_command(hba, cmd->request);
+ ufshcd_send_command(hba, tag);
out_unlock:
spin_unlock_irqrestore(hba->host->host_lock, flags);
out:
@@ -2544,6 +2481,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
struct ufshcd_lrb *lrbp, enum dev_cmd_type cmd_type, int tag)
{
+ lrbp->cmd = NULL;
lrbp->sense_bufflen = 0;
lrbp->sense_buffer = NULL;
lrbp->task_tag = tag;
@@ -2706,7 +2644,8 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
WARN_ON_ONCE(!ufshcd_valid_tag(hba, tag));
init_completion(&wait);
- lrbp = ufshcd_req_to_lrb(req);
+ lrbp = &hba->lrb[tag];
+ WARN_ON(lrbp->cmd);
err = ufshcd_compose_dev_cmd(hba, lrbp, cmd_type, tag);
if (unlikely(err))
goto out_put_tag;
@@ -2718,7 +2657,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
wmb();
spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_vops_setup_xfer_req(hba, tag, false);
- ufshcd_send_command(hba, req);
+ ufshcd_send_command(hba, tag);
spin_unlock_irqrestore(hba->host->host_lock, flags);
err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
@@ -3448,6 +3387,14 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
goto out;
}
+ /* Allocate memory for local reference block */
+ hba->lrb = devm_kcalloc(hba->dev,
+ hba->nutrs, sizeof(struct ufshcd_lrb),
+ GFP_KERNEL);
+ if (!hba->lrb) {
+ dev_err(hba->dev, "LRB Memory allocation failed\n");
+ goto out;
+ }
return 0;
out:
return -ENOMEM;
@@ -3501,15 +3448,9 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
utrdlp[i].prd_table_offset = cpu_to_le16(prdt_offset >> 2);
utrdlp[i].response_upiu_length =
cpu_to_le16(ALIGNED_UPIU_SIZE >> 2);
- }
-}
-
-static int ufshcd_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
-{
- struct ufs_hba *hba = shost_priv(shost);
- ufshcd_init_lrb(hba, scsi_cmd_priv(cmd), cmd->tag);
- return 0;
+ ufshcd_init_lrb(hba, &hba->lrb[i], i);
+ }
}
/**
@@ -4824,21 +4765,19 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
{
struct ufshcd_lrb *lrbp;
struct scsi_cmnd *cmd;
- struct request *req;
int result;
int index;
for_each_set_bit(index, &completed_reqs, hba->nutrs) {
- req = ufshcd_tag_to_req(hba, index);
- if (!req)
- continue;
- cmd = blk_mq_rq_to_pdu(req);
- lrbp = scsi_cmd_priv(cmd);
- if (ufshcd_is_scsi(req)) {
- ufshcd_add_command_trace(hba, req, "complete");
+ lrbp = &hba->lrb[index];
+ cmd = lrbp->cmd;
+ if (cmd) {
+ ufshcd_add_command_trace(hba, index, "complete");
result = ufshcd_transfer_rsp_status(hba, lrbp);
scsi_dma_unmap(cmd);
cmd->result = result;
+ /* Mark completed command as NULL in LRB */
+ lrbp->cmd = NULL;
lrbp->compl_time_stamp = ktime_get();
/* Do not touch lrbp after scsi done */
cmd->scsi_done(cmd);
@@ -4847,7 +4786,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
lrbp->compl_time_stamp = ktime_get();
if (hba->dev_cmd.complete) {
- ufshcd_add_command_trace(hba, req,
+ ufshcd_add_command_trace(hba, index,
"dev_complete");
complete(hba->dev_cmd.complete);
}
@@ -5899,7 +5838,10 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
WARN_ON_ONCE(!ufshcd_valid_tag(hba, tag));
init_completion(&wait);
- lrbp = ufshcd_req_to_lrb(req);
+ lrbp = &hba->lrb[tag];
+ WARN_ON(lrbp->cmd);
+
+ lrbp->cmd = NULL;
lrbp->sense_bufflen = 0;
lrbp->sense_buffer = NULL;
lrbp->task_tag = tag;
@@ -5940,7 +5882,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
/* Make sure descriptors are ready before ringing the doorbell */
wmb();
spin_lock_irqsave(hba->host->host_lock, flags);
- ufshcd_send_command(hba, req);
+ ufshcd_send_command(hba, tag);
spin_unlock_irqrestore(hba->host->host_lock, flags);
/*
@@ -6057,15 +5999,18 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
{
struct Scsi_Host *host;
struct ufs_hba *hba;
+ unsigned int tag;
u32 pos;
int err;
u8 resp = 0xF;
- struct ufshcd_lrb *lrbp, *lrbp2;
+ struct ufshcd_lrb *lrbp;
unsigned long flags;
host = cmd->device->host;
hba = shost_priv(host);
- lrbp = scsi_cmd_priv(cmd);
+ tag = cmd->request->tag;
+
+ lrbp = &hba->lrb[tag];
err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0, UFS_LOGICAL_RESET, &resp);
if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
if (!err)
@@ -6075,8 +6020,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
/* clear the commands that were pending for corresponding LUN */
for_each_set_bit(pos, &hba->outstanding_reqs, hba->nutrs) {
- lrbp2 = ufshcd_tag_to_lrb(hba, pos);
- if (lrbp2 && lrbp2->lun == lrbp->lun) {
+ if (hba->lrb[pos].lun == lrbp->lun) {
err = ufshcd_clear_cmd(hba, pos);
if (err)
break;
@@ -6104,9 +6048,8 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap)
int tag;
for_each_set_bit(tag, &bitmap, hba->nutrs) {
- lrbp = ufshcd_tag_to_lrb(hba, tag);
- if (lrbp)
- lrbp->req_abort_skip = true;
+ lrbp = &hba->lrb[tag];
+ lrbp->req_abort_skip = true;
}
}
@@ -6137,7 +6080,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
host = cmd->device->host;
hba = shost_priv(host);
tag = cmd->request->tag;
- lrbp = scsi_cmd_priv(cmd);
+ lrbp = &hba->lrb[tag];
if (!ufshcd_valid_tag(hba, tag)) {
dev_err(hba->dev,
"%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
@@ -6181,7 +6124,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
* to reduce repeated printouts. For other aborted requests only print
* basic details.
*/
- scsi_print_command(cmd);
+ scsi_print_command(hba->lrb[tag].cmd);
if (!hba->req_abort_count) {
ufshcd_update_reg_hist(&hba->ufs_stats.task_abort, 0);
ufshcd_print_host_regs(hba);
@@ -6261,6 +6204,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
spin_lock_irqsave(host->host_lock, flags);
ufshcd_outstanding_req_clear(hba, tag);
+ hba->lrb[tag].cmd = NULL;
spin_unlock_irqrestore(host->host_lock, flags);
out:
@@ -7180,7 +7124,6 @@ static struct scsi_host_template ufshcd_driver_template = {
.module = THIS_MODULE,
.name = UFSHCD,
.proc_name = UFSHCD,
- .init_cmd_priv = ufshcd_init_cmd_priv,
.queuecommand = ufshcd_queuecommand,
.slave_alloc = ufshcd_slave_alloc,
.slave_configure = ufshcd_slave_configure,
@@ -7192,7 +7135,6 @@ static struct scsi_host_template ufshcd_driver_template = {
.this_id = -1,
.sg_tablesize = SG_ALL,
.cmd_per_lun = UFSHCD_CMD_PER_LUN,
- .cmd_size = sizeof(struct ufshcd_lrb),
.can_queue = UFSHCD_CAN_QUEUE,
.max_segment_size = PRDT_DATA_BYTE_COUNT_MAX,
.max_host_blocked = 1,
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 5c10777154fc..d45a04444191 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -158,6 +158,7 @@ struct ufs_pm_lvl_states {
* @ucd_prdt_dma_addr: PRDT dma address for debug
* @ucd_rsp_dma_addr: UPIU response dma address for debug
* @ucd_req_dma_addr: UPIU request dma address for debug
+ * @cmd: pointer to SCSI command
* @sense_buffer: pointer to sense buffer address of the SCSI command
* @sense_bufflen: Length of the sense buffer
* @scsi_status: SCSI status of the command
@@ -180,6 +181,7 @@ struct ufshcd_lrb {
dma_addr_t ucd_rsp_dma_addr;
dma_addr_t ucd_prdt_dma_addr;
+ struct scsi_cmnd *cmd;
u8 *sense_buffer;
unsigned int sense_bufflen;
int scsi_status;
@@ -521,6 +523,7 @@ enum ufshcd_quirks {
* @utmrdl_dma_addr: UTMRDL DMA address
* @host: Scsi_Host instance of the driver
* @dev: device handle
+ * @lrb: local reference block
* @cmd_queue: Used to allocate command tags from hba->host->tag_set.
* @outstanding_tasks: Bits representing outstanding task requests
* @outstanding_reqs: Bits representing outstanding transfer requests
@@ -597,6 +600,8 @@ struct ufs_hba {
/* Auto-Hibernate Idle Timer register value */
u32 ahit;
+ struct ufshcd_lrb *lrb;
+
unsigned long outstanding_tasks;
unsigned long outstanding_reqs;
--
2.17.1