diff options
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 87 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 14 | ||||
-rw-r--r-- | include/scsi/sas_ata.h | 22 |
3 files changed, 115 insertions, 8 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index e1a395b438ee..8f56d5fbf6ec 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -238,37 +238,43 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) | |||
238 | return true; | 238 | return true; |
239 | } | 239 | } |
240 | 240 | ||
241 | static void sas_ata_phy_reset(struct ata_port *ap) | 241 | static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class, |
242 | unsigned long deadline) | ||
242 | { | 243 | { |
244 | struct ata_port *ap = link->ap; | ||
243 | struct domain_device *dev = ap->private_data; | 245 | struct domain_device *dev = ap->private_data; |
244 | struct sas_internal *i = | 246 | struct sas_internal *i = |
245 | to_sas_internal(dev->port->ha->core.shost->transportt); | 247 | to_sas_internal(dev->port->ha->core.shost->transportt); |
246 | int res = TMF_RESP_FUNC_FAILED; | 248 | int res = TMF_RESP_FUNC_FAILED; |
249 | int ret = 0; | ||
247 | 250 | ||
248 | if (i->dft->lldd_I_T_nexus_reset) | 251 | if (i->dft->lldd_I_T_nexus_reset) |
249 | res = i->dft->lldd_I_T_nexus_reset(dev); | 252 | res = i->dft->lldd_I_T_nexus_reset(dev); |
250 | 253 | ||
251 | if (res != TMF_RESP_FUNC_COMPLETE) | 254 | if (res != TMF_RESP_FUNC_COMPLETE) { |
252 | SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__); | 255 | SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__); |
256 | ret = -EAGAIN; | ||
257 | } | ||
253 | 258 | ||
254 | switch (dev->sata_dev.command_set) { | 259 | switch (dev->sata_dev.command_set) { |
255 | case ATA_COMMAND_SET: | 260 | case ATA_COMMAND_SET: |
256 | SAS_DPRINTK("%s: Found ATA device.\n", __func__); | 261 | SAS_DPRINTK("%s: Found ATA device.\n", __func__); |
257 | ap->link.device[0].class = ATA_DEV_ATA; | 262 | *class = ATA_DEV_ATA; |
258 | break; | 263 | break; |
259 | case ATAPI_COMMAND_SET: | 264 | case ATAPI_COMMAND_SET: |
260 | SAS_DPRINTK("%s: Found ATAPI device.\n", __func__); | 265 | SAS_DPRINTK("%s: Found ATAPI device.\n", __func__); |
261 | ap->link.device[0].class = ATA_DEV_ATAPI; | 266 | *class = ATA_DEV_ATAPI; |
262 | break; | 267 | break; |
263 | default: | 268 | default: |
264 | SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", | 269 | SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", |
265 | __func__, | 270 | __func__, |
266 | dev->sata_dev.command_set); | 271 | dev->sata_dev.command_set); |
267 | ap->link.device[0].class = ATA_DEV_UNKNOWN; | 272 | *class = ATA_DEV_UNKNOWN; |
268 | break; | 273 | break; |
269 | } | 274 | } |
270 | 275 | ||
271 | ap->cbl = ATA_CBL_SATA; | 276 | ap->cbl = ATA_CBL_SATA; |
277 | return ret; | ||
272 | } | 278 | } |
273 | 279 | ||
274 | static void sas_ata_post_internal(struct ata_queued_cmd *qc) | 280 | static void sas_ata_post_internal(struct ata_queued_cmd *qc) |
@@ -349,7 +355,11 @@ static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in, | |||
349 | } | 355 | } |
350 | 356 | ||
351 | static struct ata_port_operations sas_sata_ops = { | 357 | static struct ata_port_operations sas_sata_ops = { |
352 | .phy_reset = sas_ata_phy_reset, | 358 | .prereset = ata_std_prereset, |
359 | .softreset = NULL, | ||
360 | .hardreset = sas_ata_hard_reset, | ||
361 | .postreset = ata_std_postreset, | ||
362 | .error_handler = ata_std_error_handler, | ||
353 | .post_internal_cmd = sas_ata_post_internal, | 363 | .post_internal_cmd = sas_ata_post_internal, |
354 | .qc_defer = ata_std_qc_defer, | 364 | .qc_defer = ata_std_qc_defer, |
355 | .qc_prep = ata_noop_qc_prep, | 365 | .qc_prep = ata_noop_qc_prep, |
@@ -781,3 +791,68 @@ int sas_discover_sata(struct domain_device *dev) | |||
781 | 791 | ||
782 | return res; | 792 | return res; |
783 | } | 793 | } |
794 | |||
795 | void sas_ata_strategy_handler(struct Scsi_Host *shost) | ||
796 | { | ||
797 | struct scsi_device *sdev; | ||
798 | |||
799 | shost_for_each_device(sdev, shost) { | ||
800 | struct domain_device *ddev = sdev_to_domain_dev(sdev); | ||
801 | struct ata_port *ap = ddev->sata_dev.ap; | ||
802 | |||
803 | if (!dev_is_sata(ddev)) | ||
804 | continue; | ||
805 | |||
806 | ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler"); | ||
807 | ata_scsi_port_error_handler(shost, ap); | ||
808 | } | ||
809 | } | ||
810 | |||
811 | int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task, | ||
812 | enum blk_eh_timer_return *rtn) | ||
813 | { | ||
814 | struct domain_device *ddev = cmd_to_domain_dev(cmd); | ||
815 | |||
816 | if (!dev_is_sata(ddev) || task) | ||
817 | return 0; | ||
818 | |||
819 | /* we're a sata device with no task, so this must be a libata | ||
820 | * eh timeout. Ideally should hook into libata timeout | ||
821 | * handling, but there's no point, it just wants to activate | ||
822 | * the eh thread */ | ||
823 | *rtn = BLK_EH_NOT_HANDLED; | ||
824 | return 1; | ||
825 | } | ||
826 | |||
827 | int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, | ||
828 | struct list_head *done_q) | ||
829 | { | ||
830 | int rtn = 0; | ||
831 | struct scsi_cmnd *cmd, *n; | ||
832 | struct ata_port *ap; | ||
833 | |||
834 | do { | ||
835 | LIST_HEAD(sata_q); | ||
836 | |||
837 | ap = NULL; | ||
838 | |||
839 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { | ||
840 | struct domain_device *ddev = cmd_to_domain_dev(cmd); | ||
841 | |||
842 | if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd)) | ||
843 | continue; | ||
844 | if(ap && ap != ddev->sata_dev.ap) | ||
845 | continue; | ||
846 | ap = ddev->sata_dev.ap; | ||
847 | rtn = 1; | ||
848 | list_move(&cmd->eh_entry, &sata_q); | ||
849 | } | ||
850 | |||
851 | if (!list_empty(&sata_q)) { | ||
852 | ata_port_printk(ap, KERN_DEBUG,"sas eh calling libata cmd error handler\n"); | ||
853 | ata_scsi_cmd_error_handler(shost, ap, &sata_q); | ||
854 | } | ||
855 | } while (ap); | ||
856 | |||
857 | return rtn; | ||
858 | } | ||
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 9a7aaf5f1311..67758ea8eb7f 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -663,11 +663,16 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) | |||
663 | * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any | 663 | * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any |
664 | * command we see here has no sas_task and is thus unknown to the HA. | 664 | * command we see here has no sas_task and is thus unknown to the HA. |
665 | */ | 665 | */ |
666 | if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) | 666 | if (!sas_ata_eh(shost, &eh_work_q, &ha->eh_done_q)) |
667 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); | 667 | if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) |
668 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); | ||
668 | 669 | ||
669 | out: | 670 | out: |
671 | /* now link into libata eh --- if we have any ata devices */ | ||
672 | sas_ata_strategy_handler(shost); | ||
673 | |||
670 | scsi_eh_flush_done_q(&ha->eh_done_q); | 674 | scsi_eh_flush_done_q(&ha->eh_done_q); |
675 | |||
671 | SAS_DPRINTK("--- Exit %s\n", __func__); | 676 | SAS_DPRINTK("--- Exit %s\n", __func__); |
672 | return; | 677 | return; |
673 | } | 678 | } |
@@ -676,6 +681,11 @@ enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | |||
676 | { | 681 | { |
677 | struct sas_task *task = TO_SAS_TASK(cmd); | 682 | struct sas_task *task = TO_SAS_TASK(cmd); |
678 | unsigned long flags; | 683 | unsigned long flags; |
684 | enum blk_eh_timer_return rtn; | ||
685 | |||
686 | if (sas_ata_timed_out(cmd, task, &rtn)) | ||
687 | return rtn; | ||
688 | |||
679 | 689 | ||
680 | if (!task) { | 690 | if (!task) { |
681 | cmd->request->timeout /= 2; | 691 | cmd->request->timeout /= 2; |
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h index c583193ae929..9c159f74c6d0 100644 --- a/include/scsi/sas_ata.h +++ b/include/scsi/sas_ata.h | |||
@@ -39,6 +39,11 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev, | |||
39 | struct scsi_target *starget); | 39 | struct scsi_target *starget); |
40 | 40 | ||
41 | void sas_ata_task_abort(struct sas_task *task); | 41 | void sas_ata_task_abort(struct sas_task *task); |
42 | void sas_ata_strategy_handler(struct Scsi_Host *shost); | ||
43 | int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task, | ||
44 | enum blk_eh_timer_return *rtn); | ||
45 | int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, | ||
46 | struct list_head *done_q); | ||
42 | 47 | ||
43 | #else | 48 | #else |
44 | 49 | ||
@@ -55,6 +60,23 @@ static inline int sas_ata_init_host_and_port(struct domain_device *found_dev, | |||
55 | static inline void sas_ata_task_abort(struct sas_task *task) | 60 | static inline void sas_ata_task_abort(struct sas_task *task) |
56 | { | 61 | { |
57 | } | 62 | } |
63 | |||
64 | static inline void sas_ata_strategy_handler(struct Scsi_Host *shost) | ||
65 | { | ||
66 | } | ||
67 | |||
68 | static inline int sas_ata_timed_out(struct scsi_cmnd *cmd, | ||
69 | struct sas_task *task, | ||
70 | enum blk_eh_timer_return *rtn) | ||
71 | { | ||
72 | return 0; | ||
73 | } | ||
74 | static inline int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, | ||
75 | struct list_head *done_q) | ||
76 | { | ||
77 | return 0; | ||
78 | } | ||
79 | |||
58 | #endif | 80 | #endif |
59 | 81 | ||
60 | #endif /* _SAS_ATA_H_ */ | 82 | #endif /* _SAS_ATA_H_ */ |