summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYaniv Gardi <ygardi@codeaurora.org>2014-12-31 00:09:46 +0200
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:58:27 -0700
commit5e500d99d2a5b41045e36bb2f4c7ce29f74e176f (patch)
tree40a1ead18756eaac65804a86cbac527faa62e464
parent5cdbfe11ca75af09b97123498075b56a7fa02b8d (diff)
scsi: ufs: clear outstanding_request bit in case query timeout
When sending a query to the device returns with a timeout error, we clear the corresponding bit in the DOORBELL register but we don't clear the outstanding_request field as we should. This patch fixes this bug. Change-Id: Ia7e0aa29b0d822742654ba206a5837b9091fdb4a Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
-rw-r--r--drivers/scsi/ufs/ufshcd.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 40ebaf2e25e9..7d1e575fc8d7 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -703,6 +703,16 @@ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
}
/**
+ * ufshcd_outstanding_req_clear - Clear a bit in outstanding request field
+ * @hba: per adapter instance
+ * @tag: position of the bit to be cleared
+ */
+static inline void ufshcd_outstanding_req_clear(struct ufs_hba *hba, int tag)
+{
+ __clear_bit(tag, &hba->outstanding_reqs);
+}
+
+/**
* ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
* @reg: Register value of host controller status
*
@@ -2588,8 +2598,14 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n",
__func__, lrbp->task_tag);
if (!ufshcd_clear_cmd(hba, lrbp->task_tag))
- /* sucessfully cleared the command, retry if needed */
+ /* successfully cleared the command, retry if needed */
err = -EAGAIN;
+ /*
+ * in case of an error, after clearing the doorbell,
+ * we also need to clear the outstanding_request
+ * field in hba
+ */
+ ufshcd_outstanding_req_clear(hba, lrbp->task_tag);
}
return err;
@@ -4668,7 +4684,7 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result)
lrbp->cmd = NULL;
/* Clear pending transfer requests */
ufshcd_clear_cmd(hba, index);
- __clear_bit(index, &hba->outstanding_reqs);
+ ufshcd_outstanding_req_clear(hba, index);
clear_bit_unlock(index, &hba->lrb_in_use);
/* Do not touch lrbp after scsi done */
cmd->scsi_done(cmd);
@@ -4677,7 +4693,7 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result)
if (hba->dev_cmd.complete) {
ufshcd_cond_add_cmd_trace(hba, index,
"dev_failed");
- __clear_bit(index, &hba->outstanding_reqs);
+ ufshcd_outstanding_req_clear(hba, index);
complete(hba->dev_cmd.complete);
}
}
@@ -5794,7 +5810,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
scsi_dma_unmap(cmd);
spin_lock_irqsave(host->host_lock, flags);
- __clear_bit(tag, &hba->outstanding_reqs);
+ ufshcd_outstanding_req_clear(hba, tag);
hba->lrb[tag].cmd = NULL;
spin_unlock_irqrestore(host->host_lock, flags);