From 3944f50995f947558c35fb16ae0288354756762c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 29 Nov 2011 12:08:50 -0800 Subject: [SCSI] libsas: let libata handle command timeouts libsas-eh if it successfully aborts an ata command will hide the timeout condition (AC_ERR_TIMEOUT) from libata. The command likely completes with the all-zero task->task_status it started with. Instead, interpret a TMF_RESP_FUNC_COMPLETE as the end of the sas_task but keep the scmd around for libata-eh to handle. Tested-by: Andrzej Jakowski Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/libsas/sas_scsi_host.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/libsas/sas_scsi_host.c') diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 0e3fdba7b510..e02ca3d570f5 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -265,6 +265,22 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); } +static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) +{ + struct sas_task *task = TO_SAS_TASK(cmd); + struct domain_device *dev = task->dev; + struct sas_ha_struct *ha = dev->port->ha; + + if (!dev_is_sata(dev)) { + sas_eh_finish_cmd(cmd); + return; + } + + /* report the timeout to libata */ + sas_end_task(cmd, task); + list_move_tail(&cmd->eh_entry, &ha->eh_ata_q); +} + static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) { struct scsi_cmnd *cmd, *n; @@ -562,12 +578,12 @@ Again: case TASK_IS_DONE: SAS_DPRINTK("%s: task 0x%p is done\n", __func__, task); - sas_eh_finish_cmd(cmd); + sas_eh_defer_cmd(cmd); continue; case TASK_IS_ABORTED: SAS_DPRINTK("%s: task 0x%p is aborted\n", __func__, task); - sas_eh_finish_cmd(cmd); + sas_eh_defer_cmd(cmd); continue; case TASK_IS_AT_LU: SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); @@ -635,12 +651,14 @@ Again: goto clear_q; } } + list_splice_tail_init(&ha->eh_ata_q, work_q); return list_empty(work_q); clear_q: SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); list_for_each_entry_safe(cmd, n, work_q, eh_entry) sas_eh_finish_cmd(cmd); + list_splice_tail_init(&ha->eh_ata_q, work_q); return list_empty(work_q); } -- cgit v1.2.3