diff options
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 203 |
1 files changed, 197 insertions, 6 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 94a274645f6f..aa1b1e0e9d22 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); | |||
87 | MODULE_PARM_DESC(max_luns, | 89 | MODULE_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 | ||
92 | static char scsi_scan_type[6] = "sync"; | ||
93 | |||
94 | module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO); | ||
95 | MODULE_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 | ||
118 | static DEFINE_SPINLOCK(async_scan_lock); | ||
119 | static LIST_HEAD(scanning_hosts); | ||
120 | |||
121 | struct 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 | */ | ||
137 | int 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 */ | ||
177 | EXPORT_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 | **/ |
621 | static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | 690 | static 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, |
@@ -805,7 +874,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | |||
805 | * register it and tell the rest of the kernel | 874 | * register it and tell the rest of the kernel |
806 | * about it. | 875 | * about it. |
807 | */ | 876 | */ |
808 | if (scsi_sysfs_add_sdev(sdev) != 0) | 877 | if (!async && scsi_sysfs_add_sdev(sdev) != 0) |
809 | return SCSI_SCAN_NO_RESPONSE; | 878 | return SCSI_SCAN_NO_RESPONSE; |
810 | 879 | ||
811 | return SCSI_SCAN_LUN_PRESENT; | 880 | return SCSI_SCAN_LUN_PRESENT; |
@@ -974,7 +1043,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
974 | goto out_free_result; | 1043 | goto out_free_result; |
975 | } | 1044 | } |
976 | 1045 | ||
977 | res = scsi_add_lun(sdev, result, &bflags); | 1046 | res = scsi_add_lun(sdev, result, &bflags, shost->async_scan); |
978 | if (res == SCSI_SCAN_LUN_PRESENT) { | 1047 | if (res == SCSI_SCAN_LUN_PRESENT) { |
979 | if (bflags & BLIST_KEY) { | 1048 | if (bflags & BLIST_KEY) { |
980 | sdev->lockable = 0; | 1049 | sdev->lockable = 0; |
@@ -1474,6 +1543,9 @@ void scsi_scan_target(struct device *parent, unsigned int channel, | |||
1474 | { | 1543 | { |
1475 | struct Scsi_Host *shost = dev_to_shost(parent); | 1544 | struct Scsi_Host *shost = dev_to_shost(parent); |
1476 | 1545 | ||
1546 | if (!shost->async_scan) | ||
1547 | scsi_complete_async_scans(); | ||
1548 | |||
1477 | mutex_lock(&shost->scan_mutex); | 1549 | mutex_lock(&shost->scan_mutex); |
1478 | if (scsi_host_scan_allowed(shost)) | 1550 | if (scsi_host_scan_allowed(shost)) |
1479 | __scsi_scan_target(parent, channel, id, lun, rescan); | 1551 | __scsi_scan_target(parent, channel, id, lun, rescan); |
@@ -1519,6 +1591,9 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
1519 | "%s: <%u:%u:%u>\n", | 1591 | "%s: <%u:%u:%u>\n", |
1520 | __FUNCTION__, channel, id, lun)); | 1592 | __FUNCTION__, channel, id, lun)); |
1521 | 1593 | ||
1594 | if (!shost->async_scan) | ||
1595 | scsi_complete_async_scans(); | ||
1596 | |||
1522 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || | 1597 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || |
1523 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || | 1598 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || |
1524 | ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) | 1599 | ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) |
@@ -1539,14 +1614,130 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
1539 | return 0; | 1614 | return 0; |
1540 | } | 1615 | } |
1541 | 1616 | ||
1617 | static void scsi_sysfs_add_devices(struct Scsi_Host *shost) | ||
1618 | { | ||
1619 | struct scsi_device *sdev; | ||
1620 | shost_for_each_device(sdev, shost) { | ||
1621 | if (scsi_sysfs_add_sdev(sdev) != 0) | ||
1622 | scsi_destroy_sdev(sdev); | ||
1623 | } | ||
1624 | } | ||
1625 | |||
1626 | /** | ||
1627 | * scsi_prep_async_scan - prepare for an async scan | ||
1628 | * @shost: the host which will be scanned | ||
1629 | * Returns: a cookie to be passed to scsi_finish_async_scan() | ||
1630 | * | ||
1631 | * Tells the midlayer this host is going to do an asynchronous scan. | ||
1632 | * It reserves the host's position in the scanning list and ensures | ||
1633 | * that other asynchronous scans started after this one won't affect the | ||
1634 | * ordering of the discovered devices. | ||
1635 | */ | ||
1636 | struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) | ||
1637 | { | ||
1638 | struct async_scan_data *data; | ||
1639 | |||
1640 | if (strncmp(scsi_scan_type, "sync", 4) == 0) | ||
1641 | return NULL; | ||
1642 | |||
1643 | if (shost->async_scan) { | ||
1644 | printk("%s called twice for host %d", __FUNCTION__, | ||
1645 | shost->host_no); | ||
1646 | dump_stack(); | ||
1647 | return NULL; | ||
1648 | } | ||
1649 | |||
1650 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
1651 | if (!data) | ||
1652 | goto err; | ||
1653 | data->shost = scsi_host_get(shost); | ||
1654 | if (!data->shost) | ||
1655 | goto err; | ||
1656 | init_completion(&data->prev_finished); | ||
1657 | |||
1658 | spin_lock(&async_scan_lock); | ||
1659 | shost->async_scan = 1; | ||
1660 | if (list_empty(&scanning_hosts)) | ||
1661 | complete(&data->prev_finished); | ||
1662 | list_add_tail(&data->list, &scanning_hosts); | ||
1663 | spin_unlock(&async_scan_lock); | ||
1664 | |||
1665 | return data; | ||
1666 | |||
1667 | err: | ||
1668 | kfree(data); | ||
1669 | return NULL; | ||
1670 | } | ||
1671 | |||
1672 | /** | ||
1673 | * scsi_finish_async_scan - asynchronous scan has finished | ||
1674 | * @data: cookie returned from earlier call to scsi_prep_async_scan() | ||
1675 | * | ||
1676 | * All the devices currently attached to this host have been found. | ||
1677 | * This function announces all the devices it has found to the rest | ||
1678 | * of the system. | ||
1679 | */ | ||
1680 | void scsi_finish_async_scan(struct async_scan_data *data) | ||
1681 | { | ||
1682 | struct Scsi_Host *shost; | ||
1683 | |||
1684 | if (!data) | ||
1685 | return; | ||
1686 | |||
1687 | shost = data->shost; | ||
1688 | if (!shost->async_scan) { | ||
1689 | printk("%s called twice for host %d", __FUNCTION__, | ||
1690 | shost->host_no); | ||
1691 | dump_stack(); | ||
1692 | return; | ||
1693 | } | ||
1694 | |||
1695 | wait_for_completion(&data->prev_finished); | ||
1696 | |||
1697 | scsi_sysfs_add_devices(shost); | ||
1698 | |||
1699 | spin_lock(&async_scan_lock); | ||
1700 | shost->async_scan = 0; | ||
1701 | list_del(&data->list); | ||
1702 | if (!list_empty(&scanning_hosts)) { | ||
1703 | struct async_scan_data *next = list_entry(scanning_hosts.next, | ||
1704 | struct async_scan_data, list); | ||
1705 | complete(&next->prev_finished); | ||
1706 | } | ||
1707 | spin_unlock(&async_scan_lock); | ||
1708 | |||
1709 | scsi_host_put(shost); | ||
1710 | kfree(data); | ||
1711 | } | ||
1712 | |||
1713 | static int do_scan_async(void *_data) | ||
1714 | { | ||
1715 | struct async_scan_data *data = _data; | ||
1716 | scsi_scan_host_selected(data->shost, SCAN_WILD_CARD, SCAN_WILD_CARD, | ||
1717 | SCAN_WILD_CARD, 0); | ||
1718 | |||
1719 | scsi_finish_async_scan(data); | ||
1720 | return 0; | ||
1721 | } | ||
1722 | |||
1542 | /** | 1723 | /** |
1543 | * scsi_scan_host - scan the given adapter | 1724 | * scsi_scan_host - scan the given adapter |
1544 | * @shost: adapter to scan | 1725 | * @shost: adapter to scan |
1545 | **/ | 1726 | **/ |
1546 | void scsi_scan_host(struct Scsi_Host *shost) | 1727 | void scsi_scan_host(struct Scsi_Host *shost) |
1547 | { | 1728 | { |
1548 | scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, | 1729 | struct async_scan_data *data; |
1549 | SCAN_WILD_CARD, 0); | 1730 | |
1731 | if (strncmp(scsi_scan_type, "none", 4) == 0) | ||
1732 | return; | ||
1733 | |||
1734 | data = scsi_prep_async_scan(shost); | ||
1735 | if (!data) { | ||
1736 | scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, | ||
1737 | SCAN_WILD_CARD, 0); | ||
1738 | return; | ||
1739 | } | ||
1740 | kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); | ||
1550 | } | 1741 | } |
1551 | EXPORT_SYMBOL(scsi_scan_host); | 1742 | EXPORT_SYMBOL(scsi_scan_host); |
1552 | 1743 | ||