scsi: ufs: core: Fix task management completion
commit f5ef336fd2e4c36dedae4e7ca66cf5349d6fda62 upstream. The UFS driver uses blk_mq_tagset_busy_iter() when identifying task management requests to complete, however blk_mq_tagset_busy_iter() doesn't work. blk_mq_tagset_busy_iter() only iterates requests dispatched by the block layer. That appears as if it might have started since commit37f4a24c24
("blk-mq: centralise related handling into blk_mq_get_driver_tag") which removed 'data->hctx->tags->rqs[rq->tag] = rq' from blk_mq_rq_ctx_init() which gets called: blk_get_request blk_mq_alloc_request __blk_mq_alloc_request blk_mq_rq_ctx_init Since UFS task management requests are not dispatched by the block layer, hctx->tags->rqs[rq->tag] remains NULL, and since blk_mq_tagset_busy_iter() relies on finding requests using hctx->tags->rqs[rq->tag], UFS task management requests are never found by blk_mq_tagset_busy_iter(). By using blk_mq_tagset_busy_iter(), the UFS driver was relying on internal details of the block layer, which was fragile and subsequently got broken. Fix by removing the use of blk_mq_tagset_busy_iter() and having the driver keep track of task management requests. Link: https://lore.kernel.org/r/20210922091059.4040-1-adrian.hunter@intel.com Fixes: 1235fc569e0b ("scsi: ufs: core: Fix task management request completion timeout") Fixes:69a6c269c0
("scsi: ufs: Use blk_{get,put}_request() to allocate and free TMFs") Cc: stable@vger.kernel.org Tested-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> [Adrian: Backport to v5.10] Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
04c586a601
commit
ddd4e46cff
|
@ -6099,27 +6099,6 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba)
|
|||
return retval;
|
||||
}
|
||||
|
||||
struct ctm_info {
|
||||
struct ufs_hba *hba;
|
||||
unsigned long pending;
|
||||
unsigned int ncpl;
|
||||
};
|
||||
|
||||
static bool ufshcd_compl_tm(struct request *req, void *priv, bool reserved)
|
||||
{
|
||||
struct ctm_info *const ci = priv;
|
||||
struct completion *c;
|
||||
|
||||
WARN_ON_ONCE(reserved);
|
||||
if (test_bit(req->tag, &ci->pending))
|
||||
return true;
|
||||
ci->ncpl++;
|
||||
c = req->end_io_data;
|
||||
if (c)
|
||||
complete(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_tmc_handler - handle task management function completion
|
||||
* @hba: per adapter instance
|
||||
|
@ -6130,14 +6109,22 @@ static bool ufshcd_compl_tm(struct request *req, void *priv, bool reserved)
|
|||
*/
|
||||
static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba)
|
||||
{
|
||||
struct request_queue *q = hba->tmf_queue;
|
||||
struct ctm_info ci = {
|
||||
.hba = hba,
|
||||
.pending = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL),
|
||||
};
|
||||
unsigned long pending, issued;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
int tag;
|
||||
|
||||
blk_mq_tagset_busy_iter(q->tag_set, ufshcd_compl_tm, &ci);
|
||||
return ci.ncpl ? IRQ_HANDLED : IRQ_NONE;
|
||||
pending = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
|
||||
|
||||
issued = hba->outstanding_tasks & ~pending;
|
||||
for_each_set_bit(tag, &issued, hba->nutmrs) {
|
||||
struct request *req = hba->tmf_rqs[tag];
|
||||
struct completion *c = req->end_io_data;
|
||||
|
||||
complete(c);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6267,9 +6254,9 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba,
|
|||
ufshcd_hold(hba, false);
|
||||
|
||||
spin_lock_irqsave(host->host_lock, flags);
|
||||
blk_mq_start_request(req);
|
||||
|
||||
task_tag = req->tag;
|
||||
hba->tmf_rqs[req->tag] = req;
|
||||
treq->req_header.dword_0 |= cpu_to_be32(task_tag);
|
||||
|
||||
memcpy(hba->utmrdl_base_addr + task_tag, treq, sizeof(*treq));
|
||||
|
@ -6313,6 +6300,7 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba,
|
|||
}
|
||||
|
||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||
hba->tmf_rqs[req->tag] = NULL;
|
||||
__clear_bit(task_tag, &hba->outstanding_tasks);
|
||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||
|
||||
|
@ -9235,6 +9223,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
|
|||
err = PTR_ERR(hba->tmf_queue);
|
||||
goto free_tmf_tag_set;
|
||||
}
|
||||
hba->tmf_rqs = devm_kcalloc(hba->dev, hba->nutmrs,
|
||||
sizeof(*hba->tmf_rqs), GFP_KERNEL);
|
||||
if (!hba->tmf_rqs) {
|
||||
err = -ENOMEM;
|
||||
goto free_tmf_queue;
|
||||
}
|
||||
|
||||
/* Reset the attached device */
|
||||
ufshcd_vops_device_reset(hba);
|
||||
|
|
|
@ -734,6 +734,7 @@ struct ufs_hba {
|
|||
|
||||
struct blk_mq_tag_set tmf_tag_set;
|
||||
struct request_queue *tmf_queue;
|
||||
struct request **tmf_rqs;
|
||||
|
||||
struct uic_command *active_uic_cmd;
|
||||
struct mutex uic_cmd_mutex;
|
||||
|
|
Loading…
Reference in New Issue
Block a user