diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 87 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 14 |
2 files changed, 93 insertions, 8 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index c2a5cc75b407..16c5094bc86c 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -240,37 +240,43 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) | |||
240 | return true; | 240 | return true; |
241 | } | 241 | } |
242 | 242 | ||
243 | static void sas_ata_phy_reset(struct ata_port *ap) | 243 | static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class, |
244 | unsigned long deadline) | ||
244 | { | 245 | { |
246 | struct ata_port *ap = link->ap; | ||
245 | struct domain_device *dev = ap->private_data; | 247 | struct domain_device *dev = ap->private_data; |
246 | struct sas_internal *i = | 248 | struct sas_internal *i = |
247 | to_sas_internal(dev->port->ha->core.shost->transportt); | 249 | to_sas_internal(dev->port->ha->core.shost->transportt); |
248 | int res = TMF_RESP_FUNC_FAILED; | 250 | int res = TMF_RESP_FUNC_FAILED; |
251 | int ret = 0; | ||
249 | 252 | ||
250 | if (i->dft->lldd_I_T_nexus_reset) | 253 | if (i->dft->lldd_I_T_nexus_reset) |
251 | res = i->dft->lldd_I_T_nexus_reset(dev); | 254 | res = i->dft->lldd_I_T_nexus_reset(dev); |
252 | 255 | ||
253 | if (res != TMF_RESP_FUNC_COMPLETE) | 256 | if (res != TMF_RESP_FUNC_COMPLETE) { |
254 | SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__); | 257 | SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__); |
258 | ret = -EAGAIN; | ||
259 | } | ||
255 | 260 | ||
256 | switch (dev->sata_dev.command_set) { | 261 | switch (dev->sata_dev.command_set) { |
257 | case ATA_COMMAND_SET: | 262 | case ATA_COMMAND_SET: |
258 | SAS_DPRINTK("%s: Found ATA device.\n", __func__); | 263 | SAS_DPRINTK("%s: Found ATA device.\n", __func__); |
259 | ap->link.device[0].class = ATA_DEV_ATA; | 264 | *class = ATA_DEV_ATA; |
260 | break; | 265 | break; |
261 | case ATAPI_COMMAND_SET: | 266 | case ATAPI_COMMAND_SET: |
262 | SAS_DPRINTK("%s: Found ATAPI device.\n", __func__); | 267 | SAS_DPRINTK("%s: Found ATAPI device.\n", __func__); |
263 | ap->link.device[0].class = ATA_DEV_ATAPI; | 268 | *class = ATA_DEV_ATAPI; |
264 | break; | 269 | break; |
265 | default: | 270 | default: |
266 | SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", | 271 | SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", |
267 | __func__, | 272 | __func__, |
268 | dev->sata_dev.command_set); | 273 | dev->sata_dev.command_set); |
269 | ap->link.device[0].class = ATA_DEV_UNKNOWN; | 274 | *class = ATA_DEV_UNKNOWN; |
270 | break; | 275 | break; |
271 | } | 276 | } |
272 | 277 | ||
273 | ap->cbl = ATA_CBL_SATA; | 278 | ap->cbl = ATA_CBL_SATA; |
279 | return ret; | ||
274 | } | 280 | } |
275 | 281 | ||
276 | static void sas_ata_post_internal(struct ata_queued_cmd *qc) | 282 | static void sas_ata_post_internal(struct ata_queued_cmd *qc) |
@@ -302,7 +308,11 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc) | |||
302 | } | 308 | } |
303 | 309 | ||
304 | static struct ata_port_operations sas_sata_ops = { | 310 | static struct ata_port_operations sas_sata_ops = { |
305 | .phy_reset = sas_ata_phy_reset, | 311 | .prereset = ata_std_prereset, |
312 | .softreset = NULL, | ||
313 | .hardreset = sas_ata_hard_reset, | ||
314 | .postreset = ata_std_postreset, | ||
315 | .error_handler = ata_std_error_handler, | ||
306 | .post_internal_cmd = sas_ata_post_internal, | 316 | .post_internal_cmd = sas_ata_post_internal, |
307 | .qc_defer = ata_std_qc_defer, | 317 | .qc_defer = ata_std_qc_defer, |
308 | .qc_prep = ata_noop_qc_prep, | 318 | .qc_prep = ata_noop_qc_prep, |
@@ -732,3 +742,68 @@ int sas_discover_sata(struct domain_device *dev) | |||
732 | 742 | ||
733 | return res; | 743 | return res; |
734 | } | 744 | } |
745 | |||
746 | void sas_ata_strategy_handler(struct Scsi_Host *shost) | ||
747 | { | ||
748 | struct scsi_device *sdev; | ||
749 | |||
750 | shost_for_each_device(sdev, shost) { | ||
751 | struct domain_device *ddev = sdev_to_domain_dev(sdev); | ||
752 | struct ata_port *ap = ddev->sata_dev.ap; | ||
753 | |||
754 | if (!dev_is_sata(ddev)) | ||
755 | continue; | ||
756 | |||
757 | ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler"); | ||
758 | ata_scsi_port_error_handler(shost, ap); | ||
759 | } | ||
760 | } | ||
761 | |||
762 | int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task, | ||
763 | enum blk_eh_timer_return *rtn) | ||
764 | { | ||
765 | struct domain_device *ddev = cmd_to_domain_dev(cmd); | ||
766 | |||
767 | if (!dev_is_sata(ddev) || task) | ||
768 | return 0; | ||
769 | |||
770 | /* we're a sata device with no task, so this must be a libata | ||
771 | * eh timeout. Ideally should hook into libata timeout | ||
772 | * handling, but there's no point, it just wants to activate | ||
773 | * the eh thread */ | ||
774 | *rtn = BLK_EH_NOT_HANDLED; | ||
775 | return 1; | ||
776 | } | ||
777 | |||
778 | int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, | ||
779 | struct list_head *done_q) | ||
780 | { | ||
781 | int rtn = 0; | ||
782 | struct scsi_cmnd *cmd, *n; | ||
783 | struct ata_port *ap; | ||
784 | |||
785 | do { | ||
786 | LIST_HEAD(sata_q); | ||
787 | |||
788 | ap = NULL; | ||
789 | |||
790 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { | ||
791 | struct domain_device *ddev = cmd_to_domain_dev(cmd); | ||
792 | |||
793 | if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd)) | ||
794 | continue; | ||
795 | if (ap && ap != ddev->sata_dev.ap) | ||
796 | continue; | ||
797 | ap = ddev->sata_dev.ap; | ||
798 | rtn = 1; | ||
799 | list_move(&cmd->eh_entry, &sata_q); | ||
800 | } | ||
801 | |||
802 | if (!list_empty(&sata_q)) { | ||
803 | ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata cmd error handler\n"); | ||
804 | ata_scsi_cmd_error_handler(shost, ap, &sata_q); | ||
805 | } | ||
806 | } while (ap); | ||
807 | |||
808 | return rtn; | ||
809 | } | ||
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 5815cbeb27a6..2119871aed3e 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -662,11 +662,16 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) | |||
662 | * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any | 662 | * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any |
663 | * command we see here has no sas_task and is thus unknown to the HA. | 663 | * command we see here has no sas_task and is thus unknown to the HA. |
664 | */ | 664 | */ |
665 | if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) | 665 | if (!sas_ata_eh(shost, &eh_work_q, &ha->eh_done_q)) |
666 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); | 666 | if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) |
667 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); | ||
667 | 668 | ||
668 | out: | 669 | out: |
670 | /* now link into libata eh --- if we have any ata devices */ | ||
671 | sas_ata_strategy_handler(shost); | ||
672 | |||
669 | scsi_eh_flush_done_q(&ha->eh_done_q); | 673 | scsi_eh_flush_done_q(&ha->eh_done_q); |
674 | |||
670 | SAS_DPRINTK("--- Exit %s\n", __func__); | 675 | SAS_DPRINTK("--- Exit %s\n", __func__); |
671 | return; | 676 | return; |
672 | } | 677 | } |
@@ -675,6 +680,11 @@ enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | |||
675 | { | 680 | { |
676 | struct sas_task *task = TO_SAS_TASK(cmd); | 681 | struct sas_task *task = TO_SAS_TASK(cmd); |
677 | unsigned long flags; | 682 | unsigned long flags; |
683 | enum blk_eh_timer_return rtn; | ||
684 | |||
685 | if (sas_ata_timed_out(cmd, task, &rtn)) | ||
686 | return rtn; | ||
687 | |||
678 | 688 | ||
679 | if (!task) { | 689 | if (!task) { |
680 | cmd->request->timeout /= 2; | 690 | cmd->request->timeout /= 2; |