Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

James Bottomley and committed by
Jeff Garzik
00dd4998 0e0b494c

+115 -8
+81 -6
drivers/scsi/libsas/sas_ata.c
··· 238 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 245 struct domain_device *dev = ap->private_data; 244 246 struct sas_internal *i = 245 247 to_sas_internal(dev->port->ha->core.shost->transportt); 246 248 int res = TMF_RESP_FUNC_FAILED; 249 + int ret = 0; 247 250 248 251 if (i->dft->lldd_I_T_nexus_reset) 249 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 255 SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__); 256 + ret = -EAGAIN; 257 + } 253 258 254 259 switch (dev->sata_dev.command_set) { 255 260 case ATA_COMMAND_SET: 256 261 SAS_DPRINTK("%s: Found ATA device.\n", __func__); 257 - ap->link.device[0].class = ATA_DEV_ATA; 262 + *class = ATA_DEV_ATA; 258 263 break; 259 264 case ATAPI_COMMAND_SET: 260 265 SAS_DPRINTK("%s: Found ATAPI device.\n", __func__); 261 - ap->link.device[0].class = ATA_DEV_ATAPI; 266 + *class = ATA_DEV_ATAPI; 262 267 break; 263 268 default: 264 269 SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", 265 270 __func__, 266 271 dev->sata_dev.command_set); 267 - ap->link.device[0].class = ATA_DEV_UNKNOWN; 272 + *class = ATA_DEV_UNKNOWN; 268 273 break; 269 274 } 270 275 271 276 ap->cbl = ATA_CBL_SATA; 277 + return ret; 272 278 } 273 279 274 280 static void sas_ata_post_internal(struct ata_queued_cmd *qc) ··· 355 349 } 356 350 357 351 static struct ata_port_operations sas_sata_ops = { 358 - .phy_reset = sas_ata_phy_reset, 352 + .prereset = ata_std_prereset, 353 + .softreset = NULL, 354 + .hardreset = sas_ata_hard_reset, 355 + .postreset = ata_std_postreset, 356 + .error_handler = ata_std_error_handler, 359 357 .post_internal_cmd = sas_ata_post_internal, 360 358 .qc_defer = ata_std_qc_defer, 361 359 .qc_prep = ata_noop_qc_prep, ··· 790 780 } 791 781 792 782 return res; 783 + } 784 + 785 + void sas_ata_strategy_handler(struct Scsi_Host *shost) 786 + { 787 + struct scsi_device *sdev; 788 + 789 + shost_for_each_device(sdev, shost) { 790 + struct domain_device *ddev = sdev_to_domain_dev(sdev); 791 + struct ata_port *ap = ddev->sata_dev.ap; 792 + 793 + if (!dev_is_sata(ddev)) 794 + continue; 795 + 796 + ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler"); 797 + ata_scsi_port_error_handler(shost, ap); 798 + } 799 + } 800 + 801 + int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task, 802 + enum blk_eh_timer_return *rtn) 803 + { 804 + struct domain_device *ddev = cmd_to_domain_dev(cmd); 805 + 806 + if (!dev_is_sata(ddev) || task) 807 + return 0; 808 + 809 + /* we're a sata device with no task, so this must be a libata 810 + * eh timeout. Ideally should hook into libata timeout 811 + * handling, but there's no point, it just wants to activate 812 + * the eh thread */ 813 + *rtn = BLK_EH_NOT_HANDLED; 814 + return 1; 815 + } 816 + 817 + int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, 818 + struct list_head *done_q) 819 + { 820 + int rtn = 0; 821 + struct scsi_cmnd *cmd, *n; 822 + struct ata_port *ap; 823 + 824 + do { 825 + LIST_HEAD(sata_q); 826 + 827 + ap = NULL; 828 + 829 + list_for_each_entry_safe(cmd, n, work_q, eh_entry) { 830 + struct domain_device *ddev = cmd_to_domain_dev(cmd); 831 + 832 + if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd)) 833 + continue; 834 + if(ap && ap != ddev->sata_dev.ap) 835 + continue; 836 + ap = ddev->sata_dev.ap; 837 + rtn = 1; 838 + list_move(&cmd->eh_entry, &sata_q); 839 + } 840 + 841 + if (!list_empty(&sata_q)) { 842 + ata_port_printk(ap, KERN_DEBUG,"sas eh calling libata cmd error handler\n"); 843 + ata_scsi_cmd_error_handler(shost, ap, &sata_q); 844 + } 845 + } while (ap); 846 + 847 + return rtn; 793 848 }
+12 -2
drivers/scsi/libsas/sas_scsi_host.c
··· 663 663 * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any 664 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)) 667 - scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); 666 + if (!sas_ata_eh(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 670 out: 671 + /* now link into libata eh --- if we have any ata devices */ 672 + sas_ata_strategy_handler(shost); 673 + 670 674 scsi_eh_flush_done_q(&ha->eh_done_q); 675 + 671 676 SAS_DPRINTK("--- Exit %s\n", __func__); 672 677 return; 673 678 } ··· 681 676 { 682 677 struct sas_task *task = TO_SAS_TASK(cmd); 683 678 unsigned long flags; 679 + enum blk_eh_timer_return rtn; 680 + 681 + if (sas_ata_timed_out(cmd, task, &rtn)) 682 + return rtn; 683 + 684 684 685 685 if (!task) { 686 686 cmd->request->timeout /= 2;
+22
include/scsi/sas_ata.h
··· 39 39 struct scsi_target *starget); 40 40 41 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 48 #else 44 49 ··· 60 55 static inline void sas_ata_task_abort(struct sas_task *task) 61 56 { 62 57 } 58 + 59 + static inline void sas_ata_strategy_handler(struct Scsi_Host *shost) 60 + { 61 + } 62 + 63 + static inline int sas_ata_timed_out(struct scsi_cmnd *cmd, 64 + struct sas_task *task, 65 + enum blk_eh_timer_return *rtn) 66 + { 67 + return 0; 68 + } 69 + static inline int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, 70 + struct list_head *done_q) 71 + { 72 + return 0; 73 + } 74 + 63 75 #endif 64 76 65 77 #endif /* _SAS_ATA_H_ */