aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@suse.de>2011-01-23 10:44:12 -0500
committerJeff Garzik <jgarzik@redhat.com>2011-03-02 02:36:45 -0500
commit00dd4998a60599d98b4d6635820a1fbeafa5b021 (patch)
tree6a7ecd27007856691964399eec8882b8d8ca8560
parent0e0b494ca8c54a7297d0cc549405091019b3b77e (diff)
libsas: convert to libata new error handler
The conversion is quite complex given that the libata new error handler has to be hooked into the current libsas timeout and error handling. The way this is done is to process all the failed commands via libsas first, but if they have no underlying sas task (and they're on a sata device) assume they are destined for the libata error handler and send them accordingly. Finally, activate the port recovery of the libata error handler for each port known to the host. This is somewhat suboptimal, since that port may not need recovering, but given the current architecture of the libata error handler, it's the only way; and the spurious activation is harmless. Signed-off-by: James Bottomley <James.Bottomley@suse.de> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/scsi/libsas/sas_ata.c87
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c14
-rw-r--r--include/scsi/sas_ata.h22
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
241static void sas_ata_phy_reset(struct ata_port *ap) 241static 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
274static void sas_ata_post_internal(struct ata_queued_cmd *qc) 280static 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
351static struct ata_port_operations sas_sata_ops = { 357static 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
795void 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
811int 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
827int 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
669out: 670out:
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
41void sas_ata_task_abort(struct sas_task *task); 41void sas_ata_task_abort(struct sas_task *task);
42void sas_ata_strategy_handler(struct Scsi_Host *shost);
43int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task,
44 enum blk_eh_timer_return *rtn);
45int 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,
55static inline void sas_ata_task_abort(struct sas_task *task) 60static inline void sas_ata_task_abort(struct sas_task *task)
56{ 61{
57} 62}
63
64static inline void sas_ata_strategy_handler(struct Scsi_Host *shost)
65{
66}
67
68static 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}
74static 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_ */