aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@suse.de>2011-01-23 10:44:12 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-02-13 14:17:46 -0500
commitc299190b9398d4edfbf80a749875d5bac199bfdc (patch)
tree30f46808bbffe80699c97a7d3b393c4109a05cb6
parent64878c0eff5737e15b3ff06d02e7227eda4aa04c (diff)
[SCSI] 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>
-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 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
243static void sas_ata_phy_reset(struct ata_port *ap) 243static 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
276static void sas_ata_post_internal(struct ata_queued_cmd *qc) 282static 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
304static struct ata_port_operations sas_sata_ops = { 310static 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
746void 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
762int 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
778int 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
668out: 669out:
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;
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_ */