diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_ata.c')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 94 |
1 files changed, 84 insertions, 10 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index e1a395b438ee..4d3b704ede1c 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, |
@@ -362,10 +372,9 @@ static struct ata_port_operations sas_sata_ops = { | |||
362 | }; | 372 | }; |
363 | 373 | ||
364 | static struct ata_port_info sata_port_info = { | 374 | static struct ata_port_info sata_port_info = { |
365 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | | 375 | .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ, |
366 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ, | 376 | .pio_mask = ATA_PIO4, |
367 | .pio_mask = 0x1f, /* PIO0-4 */ | 377 | .mwdma_mask = ATA_MWDMA2, |
368 | .mwdma_mask = 0x07, /* MWDMA0-2 */ | ||
369 | .udma_mask = ATA_UDMA6, | 378 | .udma_mask = ATA_UDMA6, |
370 | .port_ops = &sas_sata_ops | 379 | .port_ops = &sas_sata_ops |
371 | }; | 380 | }; |
@@ -781,3 +790,68 @@ int sas_discover_sata(struct domain_device *dev) | |||
781 | 790 | ||
782 | return res; | 791 | return res; |
783 | } | 792 | } |
793 | |||
794 | void sas_ata_strategy_handler(struct Scsi_Host *shost) | ||
795 | { | ||
796 | struct scsi_device *sdev; | ||
797 | |||
798 | shost_for_each_device(sdev, shost) { | ||
799 | struct domain_device *ddev = sdev_to_domain_dev(sdev); | ||
800 | struct ata_port *ap = ddev->sata_dev.ap; | ||
801 | |||
802 | if (!dev_is_sata(ddev)) | ||
803 | continue; | ||
804 | |||
805 | ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler"); | ||
806 | ata_scsi_port_error_handler(shost, ap); | ||
807 | } | ||
808 | } | ||
809 | |||
810 | int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task, | ||
811 | enum blk_eh_timer_return *rtn) | ||
812 | { | ||
813 | struct domain_device *ddev = cmd_to_domain_dev(cmd); | ||
814 | |||
815 | if (!dev_is_sata(ddev) || task) | ||
816 | return 0; | ||
817 | |||
818 | /* we're a sata device with no task, so this must be a libata | ||
819 | * eh timeout. Ideally should hook into libata timeout | ||
820 | * handling, but there's no point, it just wants to activate | ||
821 | * the eh thread */ | ||
822 | *rtn = BLK_EH_NOT_HANDLED; | ||
823 | return 1; | ||
824 | } | ||
825 | |||
826 | int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, | ||
827 | struct list_head *done_q) | ||
828 | { | ||
829 | int rtn = 0; | ||
830 | struct scsi_cmnd *cmd, *n; | ||
831 | struct ata_port *ap; | ||
832 | |||
833 | do { | ||
834 | LIST_HEAD(sata_q); | ||
835 | |||
836 | ap = NULL; | ||
837 | |||
838 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { | ||
839 | struct domain_device *ddev = cmd_to_domain_dev(cmd); | ||
840 | |||
841 | if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd)) | ||
842 | continue; | ||
843 | if(ap && ap != ddev->sata_dev.ap) | ||
844 | continue; | ||
845 | ap = ddev->sata_dev.ap; | ||
846 | rtn = 1; | ||
847 | list_move(&cmd->eh_entry, &sata_q); | ||
848 | } | ||
849 | |||
850 | if (!list_empty(&sata_q)) { | ||
851 | ata_port_printk(ap, KERN_DEBUG,"sas eh calling libata cmd error handler\n"); | ||
852 | ata_scsi_cmd_error_handler(shost, ap, &sata_q); | ||
853 | } | ||
854 | } while (ap); | ||
855 | |||
856 | return rtn; | ||
857 | } | ||