diff options
author | Gilad Broner <gbroner@codeaurora.org> | 2014-12-30 13:15:34 +0200 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 10:59:01 -0700 |
commit | 1478bf7fa32edf87b142046937d0aba5071f3ff4 (patch) | |
tree | ca878541ec572a19061cfaa48f05f0d3c761bb11 | |
parent | 2d109dcf970558b4397eddac1ed1773a3c8f9a29 (diff) |
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>
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 4ec60c19f42d..d177131d3f2f 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -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_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) { int ret = 0; @@ -2532,6 +2537,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) hba = shost_priv(host); 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); switch (hba->ufshcd_state) { @@ -5885,6 +5896,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) host = cmd->device->host; hba = shost_priv(host); 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]; 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 (!(test_bit(tag, &hba->outstanding_reqs))) { dev_err(hba->dev, - "%s: cmd already completed, outstanding=0x%lx, doorbell=0x%x\n", - __func__, hba->outstanding_reqs, reg); + "%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n", + __func__, tag, hba->outstanding_reqs, reg); goto out; } |