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:
Gilad Broner 2014-12-30 13:15:34 +02:00 committed by David Keitel
parent 2d109dcf97
commit 1478bf7fa3

View file

@ -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;
}