diff options
author | Arjan van de Ven | 2009-01-04 05:32:28 -0800 |
---|---|---|
committer | Arjan van de Ven | 2009-01-07 08:46:57 -0800 |
commit | 793180570ff2530d133343ceea85648de5f01b02 (patch) | |
tree | de75df600287442c4eb527a2e0bd607517b14a59 /drivers/ata | |
parent | 4ace92fc112c6069b4fcb95a31d3142d4a43ff2a (diff) |
fastboot: make the libata port scan asynchronous
This patch makes the libata port scanning asynchronous (per device).
There is a synchronization point before doing the actual disk scan
so that device ordering is not affected.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-core.c | 84 |
1 files changed, 46 insertions, 38 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fecca4223f8e..7d3ae6a6fce7 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -56,6 +56,7 @@ #include <linux/workqueue.h> #include <linux/scatterlist.h> #include <linux/io.h> +#include <linux/async.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_host.h> @@ -5909,6 +5910,48 @@ void ata_host_init(struct ata_host *host, struct device *dev, host->ops = ops; } + +static void async_port_probe(void *data, async_cookie_t cookie) +{ + int rc; + struct ata_port *ap = data; + /* probe */ + if (ap->ops->error_handler) { + struct ata_eh_info *ehi = &ap->link.eh_info; + unsigned long flags; + + ata_port_probe(ap); + + /* kick EH for boot probing */ + spin_lock_irqsave(ap->lock, flags); + + ehi->probe_mask |= ATA_ALL_DEVICES; + ehi->action |= ATA_EH_RESET | ATA_EH_LPM; + ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; + + ap->pflags &= ~ATA_PFLAG_INITIALIZING; + ap->pflags |= ATA_PFLAG_LOADING; + ata_port_schedule_eh(ap); + + spin_unlock_irqrestore(ap->lock, flags); + + /* wait for EH to finish */ + ata_port_wait_eh(ap); + } else { + DPRINTK("ata%u: bus probe begin\n", ap->print_id); + rc = ata_bus_probe(ap); + DPRINTK("ata%u: bus probe end\n", ap->print_id); + + if (rc) { + /* FIXME: do something useful here? + * Current libata behavior will + * tear down everything when + * the module is removed + * or the h/w is unplugged. + */ + } + } +} /** * ata_host_register - register initialized ATA host * @host: ATA host to register @@ -5988,45 +6031,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) DPRINTK("probe begin\n"); for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - - /* probe */ - if (ap->ops->error_handler) { - struct ata_eh_info *ehi = &ap->link.eh_info; - unsigned long flags; - - ata_port_probe(ap); - - /* kick EH for boot probing */ - spin_lock_irqsave(ap->lock, flags); - - ehi->probe_mask |= ATA_ALL_DEVICES; - ehi->action |= ATA_EH_RESET | ATA_EH_LPM; - ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; - - ap->pflags &= ~ATA_PFLAG_INITIALIZING; - ap->pflags |= ATA_PFLAG_LOADING; - ata_port_schedule_eh(ap); - - spin_unlock_irqrestore(ap->lock, flags); - - /* wait for EH to finish */ - ata_port_wait_eh(ap); - } else { - DPRINTK("ata%u: bus probe begin\n", ap->print_id); - rc = ata_bus_probe(ap); - DPRINTK("ata%u: bus probe end\n", ap->print_id); - - if (rc) { - /* FIXME: do something useful here? - * Current libata behavior will - * tear down everything when - * the module is removed - * or the h/w is unplugged. - */ - } - } + async_schedule(async_port_probe, ap); } - + async_synchronize_full(); /* probes are done, now scan each port's disk(s) */ DPRINTK("host probe begin\n"); for (i = 0; i < host->n_ports; i++) { @@ -6034,6 +6041,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ata_scsi_scan_host(ap, 1); } + DPRINTK("host probe end\n"); return 0; } |