diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index ffa5b49aaf08..b48dcc281042 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -500,6 +500,30 @@ int sas_eh_target_reset_handler(struct scsi_cmnd *cmd) } EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler); +enum scsi_timeout_action sas_eh_timed_out(struct scsi_cmnd *cmd) +{ + struct domain_device *dev; + struct ata_port *ap; + unsigned long flags; + + if (!cmd) + return SCSI_EH_NOT_HANDLED; + + dev = cmd_to_domain_dev(cmd); + if (!dev || !dev_is_sata(dev)) + return SCSI_EH_NOT_HANDLED; + + ap = dev->sata_dev.ap; + if (ap) { + spin_lock_irqsave(ap->lock, flags); + ata_scsi_do_requeue_deferred_qc(ap, cmd); + spin_unlock_irqrestore(ap->lock, flags); + } + + return SCSI_EH_NOT_HANDLED; +} +EXPORT_SYMBOL_GPL(sas_eh_timed_out); + /* Try to reset a device */ static int try_to_reset_cmd_device(struct scsi_cmnd *cmd) { diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index c4f6a6a7f6bd..852de6a55448 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -712,6 +712,7 @@ void sas_task_abort(struct sas_task *); int sas_eh_abort_handler(struct scsi_cmnd *cmd); int sas_eh_device_reset_handler(struct scsi_cmnd *cmd); int sas_eh_target_reset_handler(struct scsi_cmnd *cmd); +enum scsi_timeout_action sas_eh_timed_out(struct scsi_cmnd *cmd); extern void sas_target_destroy(struct scsi_target *); extern int sas_sdev_init(struct scsi_device *); @@ -743,6 +744,7 @@ void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event, .name = DRV_NAME, \ .proc_name = DRV_NAME, \ .queuecommand = sas_queuecommand, \ + .eh_timed_out = sas_eh_timed_out, \ .dma_need_drain = ata_scsi_dma_need_drain, \ .target_alloc = sas_target_alloc, \ .change_queue_depth = sas_change_queue_depth, \