From 81c757bc696284f39f07766f0c2ca67af64ce9bd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 2 Dec 2011 16:07:01 -0800 Subject: [SCSI] libsas: execute transport link resets with libata-eh via host workqueue Link resets leave ata affiliations intact, so arrange for libsas to make an effort to avoid dropping the device due to a slow-to-recover link. Towards this end carry out reset in the host workqueue so that it can check for ata devices and kick the reset request to libata. Hard resets, in contrast, bypass libata since they are meant for associating an ata device with another initiator in the domain (tears down affiliations). Need to add a new transport_sas_phy_reset() since the current sas_phy_reset() is a utility function to libsas lldds. They are not prepared for it to loop back into eh. Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/ata/libata-eh.c | 1 + drivers/ata/libata.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index a9b2820..c61316e 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -863,6 +863,7 @@ void ata_port_wait_eh(struct ata_port *ap) goto retry; } } +EXPORT_SYMBOL_GPL(ata_port_wait_eh); static int ata_eh_nr_in_flight(struct ata_port *ap) { diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 814486d..1fab235 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -151,7 +151,6 @@ extern void ata_eh_acquire(struct ata_port *ap); extern void ata_eh_release(struct ata_port *ap); extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); -extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_eh_fastdrain_timerfn(unsigned long arg); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); extern void ata_dev_disable(struct ata_device *dev); -- cgit v1.1 From 9508a66f898d46e726a318469312b45e0b1d078b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 18 Jan 2012 20:47:01 -0800 Subject: [SCSI] libsas: async ata scanning libsas ata error handling is already async but this does not help the scan case. Move initial link recovery out from under host->scan_mutex, and delay synchronization with eh until after all port probe/recovery work has been queued. Device ordering is maintained with scan order by still calling sas_rphy_add() in order of domain discovery. Since we now scan the domain list when invoking libata-eh we need to be careful to check for fully initialized ata ports. Acked-by: Jack Wang Acked-by: Jeff Garzik Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/ata/libata-core.c | 34 ++++++++++++++++++---------------- drivers/ata/libata-scsi.c | 13 +++++++++++++ drivers/ata/libata.h | 1 + 3 files changed, 32 insertions(+), 16 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c06e0ec..e0bda9f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5936,29 +5936,31 @@ void ata_host_init(struct ata_host *host, struct device *dev, host->ops = ops; } -int ata_port_probe(struct ata_port *ap) +void __ata_port_probe(struct ata_port *ap) { - int rc = 0; + struct ata_eh_info *ehi = &ap->link.eh_info; + unsigned long flags; - /* probe */ - if (ap->ops->error_handler) { - struct ata_eh_info *ehi = &ap->link.eh_info; - unsigned long flags; + /* kick EH for boot probing */ + spin_lock_irqsave(ap->lock, flags); - /* kick EH for boot probing */ - spin_lock_irqsave(ap->lock, flags); + ehi->probe_mask |= ATA_ALL_DEVICES; + ehi->action |= ATA_EH_RESET; + ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; - ehi->probe_mask |= ATA_ALL_DEVICES; - ehi->action |= ATA_EH_RESET; - ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; + ap->pflags &= ~ATA_PFLAG_INITIALIZING; + ap->pflags |= ATA_PFLAG_LOADING; + ata_port_schedule_eh(ap); - ap->pflags &= ~ATA_PFLAG_INITIALIZING; - ap->pflags |= ATA_PFLAG_LOADING; - ata_port_schedule_eh(ap); + spin_unlock_irqrestore(ap->lock, flags); +} - spin_unlock_irqrestore(ap->lock, flags); +int ata_port_probe(struct ata_port *ap) +{ + int rc = 0; - /* wait for EH to finish */ + if (ap->ops->error_handler) { + __ata_port_probe(ap); ata_port_wait_eh(ap); } else { DPRINTK("ata%u: bus probe begin\n", ap->print_id); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 508a60b..1ee00c8 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3838,6 +3838,19 @@ void ata_sas_port_stop(struct ata_port *ap) } EXPORT_SYMBOL_GPL(ata_sas_port_stop); +int ata_sas_async_port_init(struct ata_port *ap) +{ + int rc = ap->ops->port_start(ap); + + if (!rc) { + ap->print_id = ata_print_id++; + __ata_port_probe(ap); + } + + return rc; +} +EXPORT_SYMBOL_GPL(ata_sas_async_port_init); + /** * ata_sas_port_init - Initialize a SATA device * @ap: SATA port to initialize diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 1fab235..2e26fca 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -105,6 +105,7 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern struct ata_port *ata_port_alloc(struct ata_host *host); extern const char *sata_spd_string(unsigned int spd); extern int ata_port_probe(struct ata_port *ap); +extern void __ata_port_probe(struct ata_port *ap); /* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI -- cgit v1.1