diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-11-29 15:08:50 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 15:07:15 -0500 |
commit | 3944f50995f947558c35fb16ae0288354756762c (patch) | |
tree | 59100b5e0a6aaef675bab78a31838356a3554a95 | |
parent | 9095a64a9aead653df320e3a6fc70835c15d46e4 (diff) |
[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 <andrzej.jakowski@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 1 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 22 | ||||
-rw-r--r-- | include/scsi/libsas.h | 3 |
3 files changed, 23 insertions, 3 deletions
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 52cd11d76664..e17fe35af30c 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c | |||
@@ -146,6 +146,7 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) | |||
146 | } | 146 | } |
147 | 147 | ||
148 | INIT_LIST_HEAD(&sas_ha->eh_done_q); | 148 | INIT_LIST_HEAD(&sas_ha->eh_done_q); |
149 | INIT_LIST_HEAD(&sas_ha->eh_ata_q); | ||
149 | 150 | ||
150 | return 0; | 151 | return 0; |
151 | 152 | ||
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) | |||
265 | scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); | 265 | scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); |
266 | } | 266 | } |
267 | 267 | ||
268 | static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) | ||
269 | { | ||
270 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
271 | struct domain_device *dev = task->dev; | ||
272 | struct sas_ha_struct *ha = dev->port->ha; | ||
273 | |||
274 | if (!dev_is_sata(dev)) { | ||
275 | sas_eh_finish_cmd(cmd); | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | /* report the timeout to libata */ | ||
280 | sas_end_task(cmd, task); | ||
281 | list_move_tail(&cmd->eh_entry, &ha->eh_ata_q); | ||
282 | } | ||
283 | |||
268 | static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) | 284 | static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) |
269 | { | 285 | { |
270 | struct scsi_cmnd *cmd, *n; | 286 | struct scsi_cmnd *cmd, *n; |
@@ -562,12 +578,12 @@ Again: | |||
562 | case TASK_IS_DONE: | 578 | case TASK_IS_DONE: |
563 | SAS_DPRINTK("%s: task 0x%p is done\n", __func__, | 579 | SAS_DPRINTK("%s: task 0x%p is done\n", __func__, |
564 | task); | 580 | task); |
565 | sas_eh_finish_cmd(cmd); | 581 | sas_eh_defer_cmd(cmd); |
566 | continue; | 582 | continue; |
567 | case TASK_IS_ABORTED: | 583 | case TASK_IS_ABORTED: |
568 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | 584 | SAS_DPRINTK("%s: task 0x%p is aborted\n", |
569 | __func__, task); | 585 | __func__, task); |
570 | sas_eh_finish_cmd(cmd); | 586 | sas_eh_defer_cmd(cmd); |
571 | continue; | 587 | continue; |
572 | case TASK_IS_AT_LU: | 588 | case TASK_IS_AT_LU: |
573 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); | 589 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); |
@@ -635,12 +651,14 @@ Again: | |||
635 | goto clear_q; | 651 | goto clear_q; |
636 | } | 652 | } |
637 | } | 653 | } |
654 | list_splice_tail_init(&ha->eh_ata_q, work_q); | ||
638 | return list_empty(work_q); | 655 | return list_empty(work_q); |
639 | clear_q: | 656 | clear_q: |
640 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); | 657 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); |
641 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) | 658 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) |
642 | sas_eh_finish_cmd(cmd); | 659 | sas_eh_finish_cmd(cmd); |
643 | 660 | ||
661 | list_splice_tail_init(&ha->eh_ata_q, work_q); | ||
644 | return list_empty(work_q); | 662 | return list_empty(work_q); |
645 | } | 663 | } |
646 | 664 | ||
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index aa7192ff4355..6b80310e08af 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h | |||
@@ -382,7 +382,8 @@ struct sas_ha_struct { | |||
382 | 382 | ||
383 | void *lldd_ha; /* not touched by sas class code */ | 383 | void *lldd_ha; /* not touched by sas class code */ |
384 | 384 | ||
385 | struct list_head eh_done_q; | 385 | struct list_head eh_done_q; /* complete via scsi_eh_flush_done_q */ |
386 | struct list_head eh_ata_q; /* scmds to promote from sas to ata eh */ | ||
386 | }; | 387 | }; |
387 | 388 | ||
388 | #define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata) | 389 | #define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata) |