aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaniv Gardi <ygardi@codeaurora.org>2016-03-10 10:37:07 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2016-03-14 21:04:45 -0400
commitf550c65b543b4d3fa55201084b1a16432b748365 (patch)
tree4a9112349e92131e90b97809c6be7635defcea7f
parent199ef13cac7d43f20d92ca077a25c3cbf91427ca (diff)
scsi: ufs: implement scsi host timeout handler
A race condition exists between request requeueing and scsi layer error handling: When UFS driver queuecommand returns a busy status for a request, it will be requeued and its tag will be freed and set to -1. At the same time it is possible that the request will timeout and scsi layer will start error handling for it. The scsi layer reuses the request and its tag to send error related commands to the device, however its tag is no longer valid. As this request was never really sent to the device, there is no point to start error handling with the device. Implement the scsi error handling timeout callback and bypass SCSI error handling for request that were not actually sent to the device. For such requests simply reset the block layer timer. Otherwise, let SCSI layer perform the usual error handling. Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Gilad Broner <gbroner@codeaurora.org> Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/ufs/ufshcd.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index de7280c4c47d..3400cebc5649 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4568,6 +4568,41 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
4568 ufshcd_probe_hba(hba); 4568 ufshcd_probe_hba(hba);
4569} 4569}
4570 4570
4571static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd)
4572{
4573 unsigned long flags;
4574 struct Scsi_Host *host;
4575 struct ufs_hba *hba;
4576 int index;
4577 bool found = false;
4578
4579 if (!scmd || !scmd->device || !scmd->device->host)
4580 return BLK_EH_NOT_HANDLED;
4581
4582 host = scmd->device->host;
4583 hba = shost_priv(host);
4584 if (!hba)
4585 return BLK_EH_NOT_HANDLED;
4586
4587 spin_lock_irqsave(host->host_lock, flags);
4588
4589 for_each_set_bit(index, &hba->outstanding_reqs, hba->nutrs) {
4590 if (hba->lrb[index].cmd == scmd) {
4591 found = true;
4592 break;
4593 }
4594 }
4595
4596 spin_unlock_irqrestore(host->host_lock, flags);
4597
4598 /*
4599 * Bypass SCSI error handling and reset the block layer timer if this
4600 * SCSI command was not actually dispatched to UFS driver, otherwise
4601 * let SCSI layer handle the error as usual.
4602 */
4603 return found ? BLK_EH_NOT_HANDLED : BLK_EH_RESET_TIMER;
4604}
4605
4571static struct scsi_host_template ufshcd_driver_template = { 4606static struct scsi_host_template ufshcd_driver_template = {
4572 .module = THIS_MODULE, 4607 .module = THIS_MODULE,
4573 .name = UFSHCD, 4608 .name = UFSHCD,
@@ -4580,6 +4615,7 @@ static struct scsi_host_template ufshcd_driver_template = {
4580 .eh_abort_handler = ufshcd_abort, 4615 .eh_abort_handler = ufshcd_abort,
4581 .eh_device_reset_handler = ufshcd_eh_device_reset_handler, 4616 .eh_device_reset_handler = ufshcd_eh_device_reset_handler,
4582 .eh_host_reset_handler = ufshcd_eh_host_reset_handler, 4617 .eh_host_reset_handler = ufshcd_eh_host_reset_handler,
4618 .eh_timed_out = ufshcd_eh_timed_out,
4583 .this_id = -1, 4619 .this_id = -1,
4584 .sg_tablesize = SG_ALL, 4620 .sg_tablesize = SG_ALL,
4585 .cmd_per_lun = UFSHCD_CMD_PER_LUN, 4621 .cmd_per_lun = UFSHCD_CMD_PER_LUN,