scsi: ufs: verify command tag validity
A race condition appear to exist between request completion when scsi_done() is called to end the request and set the tag back to -1 (at blk_queue_end_tag() scsi_end_request), and scsi layer error handling which aborts the command and reuses it to request sense data. Sending the request sense is done with tag which was set to -1 and so it is invalid. Assert command tag passed from scsi layer is valid. Change-Id: I71b82e1e6aca4bbf316a2a732a42c564ab0d2248 Signed-off-by: Gilad Broner <gbroner@codeaurora.org> [subhashj@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
2d109dcf97
commit
1478bf7fa3
1 changed files with 20 additions and 2 deletions
|
@ -350,6 +350,11 @@ static void ufshcd_resume_clkscaling(struct ufs_hba *hba);
|
||||||
static void ufshcd_suspend_clkscaling(struct ufs_hba *hba);
|
static void ufshcd_suspend_clkscaling(struct ufs_hba *hba);
|
||||||
static void ufshcd_release_all(struct ufs_hba *hba);
|
static void ufshcd_release_all(struct ufs_hba *hba);
|
||||||
|
|
||||||
|
static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
|
||||||
|
{
|
||||||
|
return tag >= 0 && tag < hba->nutrs;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int ufshcd_enable_irq(struct ufs_hba *hba)
|
static inline int ufshcd_enable_irq(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -2532,6 +2537,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
|
||||||
hba = shost_priv(host);
|
hba = shost_priv(host);
|
||||||
|
|
||||||
tag = cmd->request->tag;
|
tag = cmd->request->tag;
|
||||||
|
if (!ufshcd_valid_tag(hba, tag)) {
|
||||||
|
dev_err(hba->dev,
|
||||||
|
"%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
|
||||||
|
__func__, tag, cmd, cmd->request);
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||||
switch (hba->ufshcd_state) {
|
switch (hba->ufshcd_state) {
|
||||||
|
@ -5885,6 +5896,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
|
||||||
host = cmd->device->host;
|
host = cmd->device->host;
|
||||||
hba = shost_priv(host);
|
hba = shost_priv(host);
|
||||||
tag = cmd->request->tag;
|
tag = cmd->request->tag;
|
||||||
|
if (!ufshcd_valid_tag(hba, tag)) {
|
||||||
|
dev_err(hba->dev,
|
||||||
|
"%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
|
||||||
|
__func__, tag, cmd, cmd->request);
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
lrbp = &hba->lrb[tag];
|
lrbp = &hba->lrb[tag];
|
||||||
|
|
||||||
UFSHCD_UPDATE_ERROR_STATS(hba, UFS_ERR_TASK_ABORT);
|
UFSHCD_UPDATE_ERROR_STATS(hba, UFS_ERR_TASK_ABORT);
|
||||||
|
@ -5904,8 +5922,8 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
|
||||||
/* If command is already aborted/completed, return SUCCESS */
|
/* If command is already aborted/completed, return SUCCESS */
|
||||||
if (!(test_bit(tag, &hba->outstanding_reqs))) {
|
if (!(test_bit(tag, &hba->outstanding_reqs))) {
|
||||||
dev_err(hba->dev,
|
dev_err(hba->dev,
|
||||||
"%s: cmd already completed, outstanding=0x%lx, doorbell=0x%x\n",
|
"%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n",
|
||||||
__func__, hba->outstanding_reqs, reg);
|
__func__, tag, hba->outstanding_reqs, reg);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue