summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilad Broner <gbroner@codeaurora.org>2014-12-30 13:15:34 +0200
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:59:01 -0700
commit1478bf7fa32edf87b142046937d0aba5071f3ff4 (patch)
treeca878541ec572a19061cfaa48f05f0d3c761bb11
parent2d109dcf970558b4397eddac1ed1773a3c8f9a29 (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.c22
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;
}