aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew@wil.cx>2006-09-28 17:19:20 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-10-11 14:44:25 -0400
commit3e082a910d217b2e7b186077ebf5a1126a68c62f (patch)
treeb4ef4152b8ad0198283e36c74c990f38d90d27b7 /drivers/scsi
parent53a5fbdc2dff55161a206ed1a1385a8fa8055c34 (diff)
[SCSI] Add ability to scan scsi busses asynchronously
Since it often takes around 20-30 seconds to scan a scsi bus, it's highly advantageous to do this in parallel with other things. The bulk of this patch is ensuring that devices don't change numbering, and that all devices are discovered prior to trying to start init. For those who build SCSI as modules, there's a new scsi_wait_scan module that will ensure all bus scans are finished. This patch only handles drivers which call scsi_scan_host. Fibre Channel, SAS, SATA, USB and Firewire all need additional work. Signed-off-by: Matthew Wilcox <matthew@wil.cx> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/scsi_priv.h3
-rw-r--r--drivers/scsi/scsi_scan.c203
-rw-r--r--drivers/scsi/scsi_wait_scan.c31
4 files changed, 233 insertions, 6 deletions
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index bcca39c3bcbf..a0a77fde3708 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -141,6 +141,8 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o
141# This goes last, so that "real" scsi devices probe earlier 141# This goes last, so that "real" scsi devices probe earlier
142obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o 142obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
143 143
144obj-$(CONFIG_SCSI) += scsi_wait_scan.o
145
144scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ 146scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
145 scsicam.o scsi_error.o scsi_lib.o \ 147 scsicam.o scsi_error.o scsi_lib.o \
146 scsi_scan.o scsi_sysfs.o \ 148 scsi_scan.o scsi_sysfs.o \
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 5d023d44e5e7..f458c2f686d2 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -39,6 +39,9 @@ static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
39 { }; 39 { };
40#endif 40#endif
41 41
42/* scsi_scan.c */
43int scsi_complete_async_scans(void);
44
42/* scsi_devinfo.c */ 45/* scsi_devinfo.c */
43extern int scsi_get_device_flags(struct scsi_device *sdev, 46extern int scsi_get_device_flags(struct scsi_device *sdev,
44 const unsigned char *vendor, 47 const unsigned char *vendor,
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index fd9e281c3bfe..148e24cc3222 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -29,7 +29,9 @@
29#include <linux/moduleparam.h> 29#include <linux/moduleparam.h>
30#include <linux/init.h> 30#include <linux/init.h>
31#include <linux/blkdev.h> 31#include <linux/blkdev.h>
32#include <asm/semaphore.h> 32#include <linux/delay.h>
33#include <linux/kthread.h>
34#include <linux/spinlock.h>
33 35
34#include <scsi/scsi.h> 36#include <scsi/scsi.h>
35#include <scsi/scsi_cmnd.h> 37#include <scsi/scsi_cmnd.h>
@@ -87,6 +89,11 @@ module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR);
87MODULE_PARM_DESC(max_luns, 89MODULE_PARM_DESC(max_luns,
88 "last scsi LUN (should be between 1 and 2^32-1)"); 90 "last scsi LUN (should be between 1 and 2^32-1)");
89 91
92static char scsi_scan_type[6] = "sync";
93
94module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO);
95MODULE_PARM_DESC(scan, "sync, async or none");
96
90/* 97/*
91 * max_scsi_report_luns: the maximum number of LUNS that will be 98 * max_scsi_report_luns: the maximum number of LUNS that will be
92 * returned from the REPORT LUNS command. 8 times this value must 99 * returned from the REPORT LUNS command. 8 times this value must
@@ -108,6 +115,68 @@ MODULE_PARM_DESC(inq_timeout,
108 "Timeout (in seconds) waiting for devices to answer INQUIRY." 115 "Timeout (in seconds) waiting for devices to answer INQUIRY."
109 " Default is 5. Some non-compliant devices need more."); 116 " Default is 5. Some non-compliant devices need more.");
110 117
118static DEFINE_SPINLOCK(async_scan_lock);
119static LIST_HEAD(scanning_hosts);
120
121struct async_scan_data {
122 struct list_head list;
123 struct Scsi_Host *shost;
124 struct completion prev_finished;
125};
126
127/**
128 * scsi_complete_async_scans - Wait for asynchronous scans to complete
129 *
130 * Asynchronous scans add themselves to the scanning_hosts list. Once
131 * that list is empty, we know that the scans are complete. Rather than
132 * waking up periodically to check the state of the list, we pretend to be
133 * a scanning task by adding ourselves at the end of the list and going to
134 * sleep. When the task before us wakes us up, we take ourselves off the
135 * list and return.
136 */
137int scsi_complete_async_scans(void)
138{
139 struct async_scan_data *data;
140
141 do {
142 if (list_empty(&scanning_hosts))
143 return 0;
144 /* If we can't get memory immediately, that's OK. Just
145 * sleep a little. Even if we never get memory, the async
146 * scans will finish eventually.
147 */
148 data = kmalloc(sizeof(*data), GFP_KERNEL);
149 if (!data)
150 msleep(1);
151 } while (!data);
152
153 data->shost = NULL;
154 init_completion(&data->prev_finished);
155
156 spin_lock(&async_scan_lock);
157 /* Check that there's still somebody else on the list */
158 if (list_empty(&scanning_hosts))
159 goto done;
160 list_add_tail(&data->list, &scanning_hosts);
161 spin_unlock(&async_scan_lock);
162
163 printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n");
164 wait_for_completion(&data->prev_finished);
165
166 spin_lock(&async_scan_lock);
167 list_del(&data->list);
168 done:
169 spin_unlock(&async_scan_lock);
170
171 kfree(data);
172 return 0;
173}
174
175#ifdef MODULE
176/* Only exported for the benefit of scsi_wait_scan */
177EXPORT_SYMBOL_GPL(scsi_complete_async_scans);
178#endif
179
111/** 180/**
112 * scsi_unlock_floptical - unlock device via a special MODE SENSE command 181 * scsi_unlock_floptical - unlock device via a special MODE SENSE command
113 * @sdev: scsi device to send command to 182 * @sdev: scsi device to send command to
@@ -619,7 +688,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
619 * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized 688 * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
620 **/ 689 **/
621static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, 690static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
622 int *bflags) 691 int *bflags, int async)
623{ 692{
624 /* 693 /*
625 * XXX do not save the inquiry, since it can change underneath us, 694 * XXX do not save the inquiry, since it can change underneath us,
@@ -795,7 +864,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
795 * register it and tell the rest of the kernel 864 * register it and tell the rest of the kernel
796 * about it. 865 * about it.
797 */ 866 */
798 if (scsi_sysfs_add_sdev(sdev) != 0) 867 if (!async && scsi_sysfs_add_sdev(sdev) != 0)
799 return SCSI_SCAN_NO_RESPONSE; 868 return SCSI_SCAN_NO_RESPONSE;
800 869
801 return SCSI_SCAN_LUN_PRESENT; 870 return SCSI_SCAN_LUN_PRESENT;
@@ -964,7 +1033,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
964 goto out_free_result; 1033 goto out_free_result;
965 } 1034 }
966 1035
967 res = scsi_add_lun(sdev, result, &bflags); 1036 res = scsi_add_lun(sdev, result, &bflags, shost->async_scan);
968 if (res == SCSI_SCAN_LUN_PRESENT) { 1037 if (res == SCSI_SCAN_LUN_PRESENT) {
969 if (bflags & BLIST_KEY) { 1038 if (bflags & BLIST_KEY) {
970 sdev->lockable = 0; 1039 sdev->lockable = 0;
@@ -1464,6 +1533,9 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
1464{ 1533{
1465 struct Scsi_Host *shost = dev_to_shost(parent); 1534 struct Scsi_Host *shost = dev_to_shost(parent);
1466 1535
1536 if (!shost->async_scan)
1537 scsi_complete_async_scans();
1538
1467 mutex_lock(&shost->scan_mutex); 1539 mutex_lock(&shost->scan_mutex);
1468 if (scsi_host_scan_allowed(shost)) 1540 if (scsi_host_scan_allowed(shost))
1469 __scsi_scan_target(parent, channel, id, lun, rescan); 1541 __scsi_scan_target(parent, channel, id, lun, rescan);
@@ -1509,6 +1581,9 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
1509 "%s: <%u:%u:%u>\n", 1581 "%s: <%u:%u:%u>\n",
1510 __FUNCTION__, channel, id, lun)); 1582 __FUNCTION__, channel, id, lun));
1511 1583
1584 if (!shost->async_scan)
1585 scsi_complete_async_scans();
1586
1512 if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || 1587 if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
1513 ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || 1588 ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
1514 ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) 1589 ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
@@ -1529,14 +1604,130 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
1529 return 0; 1604 return 0;
1530} 1605}
1531 1606
1607static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
1608{
1609 struct scsi_device *sdev;
1610 shost_for_each_device(sdev, shost) {
1611 if (scsi_sysfs_add_sdev(sdev) != 0)
1612 scsi_destroy_sdev(sdev);
1613 }
1614}
1615
1616/**
1617 * scsi_prep_async_scan - prepare for an async scan
1618 * @shost: the host which will be scanned
1619 * Returns: a cookie to be passed to scsi_finish_async_scan()
1620 *
1621 * Tells the midlayer this host is going to do an asynchronous scan.
1622 * It reserves the host's position in the scanning list and ensures
1623 * that other asynchronous scans started after this one won't affect the
1624 * ordering of the discovered devices.
1625 */
1626struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
1627{
1628 struct async_scan_data *data;
1629
1630 if (strncmp(scsi_scan_type, "sync", 4) == 0)
1631 return NULL;
1632
1633 if (shost->async_scan) {
1634 printk("%s called twice for host %d", __FUNCTION__,
1635 shost->host_no);
1636 dump_stack();
1637 return NULL;
1638 }
1639
1640 data = kmalloc(sizeof(*data), GFP_KERNEL);
1641 if (!data)
1642 goto err;
1643 data->shost = scsi_host_get(shost);
1644 if (!data->shost)
1645 goto err;
1646 init_completion(&data->prev_finished);
1647
1648 spin_lock(&async_scan_lock);
1649 shost->async_scan = 1;
1650 if (list_empty(&scanning_hosts))
1651 complete(&data->prev_finished);
1652 list_add_tail(&data->list, &scanning_hosts);
1653 spin_unlock(&async_scan_lock);
1654
1655 return data;
1656
1657 err:
1658 kfree(data);
1659 return NULL;
1660}
1661
1662/**
1663 * scsi_finish_async_scan - asynchronous scan has finished
1664 * @data: cookie returned from earlier call to scsi_prep_async_scan()
1665 *
1666 * All the devices currently attached to this host have been found.
1667 * This function announces all the devices it has found to the rest
1668 * of the system.
1669 */
1670void scsi_finish_async_scan(struct async_scan_data *data)
1671{
1672 struct Scsi_Host *shost;
1673
1674 if (!data)
1675 return;
1676
1677 shost = data->shost;
1678 if (!shost->async_scan) {
1679 printk("%s called twice for host %d", __FUNCTION__,
1680 shost->host_no);
1681 dump_stack();
1682 return;
1683 }
1684
1685 wait_for_completion(&data->prev_finished);
1686
1687 scsi_sysfs_add_devices(shost);
1688
1689 spin_lock(&async_scan_lock);
1690 shost->async_scan = 0;
1691 list_del(&data->list);
1692 if (!list_empty(&scanning_hosts)) {
1693 struct async_scan_data *next = list_entry(scanning_hosts.next,
1694 struct async_scan_data, list);
1695 complete(&next->prev_finished);
1696 }
1697 spin_unlock(&async_scan_lock);
1698
1699 scsi_host_put(shost);
1700 kfree(data);
1701}
1702
1703static int do_scan_async(void *_data)
1704{
1705 struct async_scan_data *data = _data;
1706 scsi_scan_host_selected(data->shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
1707 SCAN_WILD_CARD, 0);
1708
1709 scsi_finish_async_scan(data);
1710 return 0;
1711}
1712
1532/** 1713/**
1533 * scsi_scan_host - scan the given adapter 1714 * scsi_scan_host - scan the given adapter
1534 * @shost: adapter to scan 1715 * @shost: adapter to scan
1535 **/ 1716 **/
1536void scsi_scan_host(struct Scsi_Host *shost) 1717void scsi_scan_host(struct Scsi_Host *shost)
1537{ 1718{
1538 scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, 1719 struct async_scan_data *data;
1539 SCAN_WILD_CARD, 0); 1720
1721 if (strncmp(scsi_scan_type, "none", 4) == 0)
1722 return;
1723
1724 data = scsi_prep_async_scan(shost);
1725 if (!data) {
1726 scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
1727 SCAN_WILD_CARD, 0);
1728 return;
1729 }
1730 kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
1540} 1731}
1541EXPORT_SYMBOL(scsi_scan_host); 1732EXPORT_SYMBOL(scsi_scan_host);
1542 1733
diff --git a/drivers/scsi/scsi_wait_scan.c b/drivers/scsi/scsi_wait_scan.c
new file mode 100644
index 000000000000..8a636103083d
--- /dev/null
+++ b/drivers/scsi/scsi_wait_scan.c
@@ -0,0 +1,31 @@
1/*
2 * scsi_wait_scan.c
3 *
4 * Copyright (C) 2006 James Bottomley <James.Bottomley@SteelEye.com>
5 *
6 * This is a simple module to wait until all the async scans are
7 * complete. The idea is to use it in initrd/initramfs scripts. You
8 * modprobe it after all the modprobes of the root SCSI drivers and it
9 * will wait until they have all finished scanning their busses before
10 * allowing the boot to proceed
11 */
12
13#include <linux/module.h>
14#include "scsi_priv.h"
15
16static int __init wait_scan_init(void)
17{
18 scsi_complete_async_scans();
19 return 0;
20}
21
22static void __exit wait_scan_exit(void)
23{
24}
25
26MODULE_DESCRIPTION("SCSI wait for scans");
27MODULE_AUTHOR("James Bottomley");
28MODULE_LICENSE("GPL");
29
30late_initcall(wait_scan_init);
31module_exit(wait_scan_exit);