diff options
author | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-05 19:09:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-05 19:09:46 -0500 |
commit | ec0bf39a471bf6fcd01def2bd677128cea940b73 (patch) | |
tree | 0d98b304d97605613a14329b40ed8cbb88296528 /drivers/scsi/scsi_scan.c | |
parent | bf83c2a315637dee8a8b5c2221ce5030cc38c6db (diff) | |
parent | d32adcb85c74fd81963714689842993e7014515f (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (73 commits)
[SCSI] aic79xx: Add ASC-29320LPE ids to driver
[SCSI] stex: version update
[SCSI] stex: change wait loop code
[SCSI] stex: add new device type support
[SCSI] stex: update device id info
[SCSI] stex: adjust default queue length
[SCSI] stex: add value check in hard reset routine
[SCSI] stex: fix controller_info command handling
[SCSI] stex: fix biosparam calculation
[SCSI] megaraid: fix MMIO casts
[SCSI] tgt: fix undefined flush_dcache_page() problem
[SCSI] libsas: better error handling in sas_expander.c
[SCSI] lpfc 8.1.11 : Change version number to 8.1.11
[SCSI] lpfc 8.1.11 : Misc Fixes
[SCSI] lpfc 8.1.11 : Add soft_wwnn sysfs attribute, rename soft_wwn_enable
[SCSI] lpfc 8.1.11 : Removed decoding of PCI Subsystem Id
[SCSI] lpfc 8.1.11 : Add MSI (Message Signalled Interrupts) support
[SCSI] lpfc 8.1.11 : Adjust LOG_FCP logging
[SCSI] lpfc 8.1.11 : Fix Memory leaks
[SCSI] lpfc 8.1.11 : Fix lpfc_multi_ring_support
...
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 225 |
1 files changed, 219 insertions, 6 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 94a274645f6f..4d656148bd67 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,17 @@ 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 | #ifdef CONFIG_SCSI_SCAN_ASYNC | ||
93 | #define SCSI_SCAN_TYPE_DEFAULT "async" | ||
94 | #else | ||
95 | #define SCSI_SCAN_TYPE_DEFAULT "sync" | ||
96 | #endif | ||
97 | |||
98 | static char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT; | ||
99 | |||
100 | module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO); | ||
101 | MODULE_PARM_DESC(scan, "sync, async or none"); | ||
102 | |||
90 | /* | 103 | /* |
91 | * max_scsi_report_luns: the maximum number of LUNS that will be | 104 | * max_scsi_report_luns: the maximum number of LUNS that will be |
92 | * returned from the REPORT LUNS command. 8 times this value must | 105 | * returned from the REPORT LUNS command. 8 times this value must |
@@ -108,6 +121,68 @@ MODULE_PARM_DESC(inq_timeout, | |||
108 | "Timeout (in seconds) waiting for devices to answer INQUIRY." | 121 | "Timeout (in seconds) waiting for devices to answer INQUIRY." |
109 | " Default is 5. Some non-compliant devices need more."); | 122 | " Default is 5. Some non-compliant devices need more."); |
110 | 123 | ||
124 | static DEFINE_SPINLOCK(async_scan_lock); | ||
125 | static LIST_HEAD(scanning_hosts); | ||
126 | |||
127 | struct async_scan_data { | ||
128 | struct list_head list; | ||
129 | struct Scsi_Host *shost; | ||
130 | struct completion prev_finished; | ||
131 | }; | ||
132 | |||
133 | /** | ||
134 | * scsi_complete_async_scans - Wait for asynchronous scans to complete | ||
135 | * | ||
136 | * Asynchronous scans add themselves to the scanning_hosts list. Once | ||
137 | * that list is empty, we know that the scans are complete. Rather than | ||
138 | * waking up periodically to check the state of the list, we pretend to be | ||
139 | * a scanning task by adding ourselves at the end of the list and going to | ||
140 | * sleep. When the task before us wakes us up, we take ourselves off the | ||
141 | * list and return. | ||
142 | */ | ||
143 | int scsi_complete_async_scans(void) | ||
144 | { | ||
145 | struct async_scan_data *data; | ||
146 | |||
147 | do { | ||
148 | if (list_empty(&scanning_hosts)) | ||
149 | return 0; | ||
150 | /* If we can't get memory immediately, that's OK. Just | ||
151 | * sleep a little. Even if we never get memory, the async | ||
152 | * scans will finish eventually. | ||
153 | */ | ||
154 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
155 | if (!data) | ||
156 | msleep(1); | ||
157 | } while (!data); | ||
158 | |||
159 | data->shost = NULL; | ||
160 | init_completion(&data->prev_finished); | ||
161 | |||
162 | spin_lock(&async_scan_lock); | ||
163 | /* Check that there's still somebody else on the list */ | ||
164 | if (list_empty(&scanning_hosts)) | ||
165 | goto done; | ||
166 | list_add_tail(&data->list, &scanning_hosts); | ||
167 | spin_unlock(&async_scan_lock); | ||
168 | |||
169 | printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n"); | ||
170 | wait_for_completion(&data->prev_finished); | ||
171 | |||
172 | spin_lock(&async_scan_lock); | ||
173 | list_del(&data->list); | ||
174 | done: | ||
175 | spin_unlock(&async_scan_lock); | ||
176 | |||
177 | kfree(data); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | #ifdef MODULE | ||
182 | /* Only exported for the benefit of scsi_wait_scan */ | ||
183 | EXPORT_SYMBOL_GPL(scsi_complete_async_scans); | ||
184 | #endif | ||
185 | |||
111 | /** | 186 | /** |
112 | * scsi_unlock_floptical - unlock device via a special MODE SENSE command | 187 | * scsi_unlock_floptical - unlock device via a special MODE SENSE command |
113 | * @sdev: scsi device to send command to | 188 | * @sdev: scsi device to send command to |
@@ -619,7 +694,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 | 694 | * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized |
620 | **/ | 695 | **/ |
621 | static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | 696 | static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, |
622 | int *bflags) | 697 | int *bflags, int async) |
623 | { | 698 | { |
624 | /* | 699 | /* |
625 | * XXX do not save the inquiry, since it can change underneath us, | 700 | * XXX do not save the inquiry, since it can change underneath us, |
@@ -805,7 +880,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | |||
805 | * register it and tell the rest of the kernel | 880 | * register it and tell the rest of the kernel |
806 | * about it. | 881 | * about it. |
807 | */ | 882 | */ |
808 | if (scsi_sysfs_add_sdev(sdev) != 0) | 883 | if (!async && scsi_sysfs_add_sdev(sdev) != 0) |
809 | return SCSI_SCAN_NO_RESPONSE; | 884 | return SCSI_SCAN_NO_RESPONSE; |
810 | 885 | ||
811 | return SCSI_SCAN_LUN_PRESENT; | 886 | return SCSI_SCAN_LUN_PRESENT; |
@@ -974,7 +1049,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
974 | goto out_free_result; | 1049 | goto out_free_result; |
975 | } | 1050 | } |
976 | 1051 | ||
977 | res = scsi_add_lun(sdev, result, &bflags); | 1052 | res = scsi_add_lun(sdev, result, &bflags, shost->async_scan); |
978 | if (res == SCSI_SCAN_LUN_PRESENT) { | 1053 | if (res == SCSI_SCAN_LUN_PRESENT) { |
979 | if (bflags & BLIST_KEY) { | 1054 | if (bflags & BLIST_KEY) { |
980 | sdev->lockable = 0; | 1055 | sdev->lockable = 0; |
@@ -1474,6 +1549,12 @@ void scsi_scan_target(struct device *parent, unsigned int channel, | |||
1474 | { | 1549 | { |
1475 | struct Scsi_Host *shost = dev_to_shost(parent); | 1550 | struct Scsi_Host *shost = dev_to_shost(parent); |
1476 | 1551 | ||
1552 | if (strncmp(scsi_scan_type, "none", 4) == 0) | ||
1553 | return; | ||
1554 | |||
1555 | if (!shost->async_scan) | ||
1556 | scsi_complete_async_scans(); | ||
1557 | |||
1477 | mutex_lock(&shost->scan_mutex); | 1558 | mutex_lock(&shost->scan_mutex); |
1478 | if (scsi_host_scan_allowed(shost)) | 1559 | if (scsi_host_scan_allowed(shost)) |
1479 | __scsi_scan_target(parent, channel, id, lun, rescan); | 1560 | __scsi_scan_target(parent, channel, id, lun, rescan); |
@@ -1519,6 +1600,9 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
1519 | "%s: <%u:%u:%u>\n", | 1600 | "%s: <%u:%u:%u>\n", |
1520 | __FUNCTION__, channel, id, lun)); | 1601 | __FUNCTION__, channel, id, lun)); |
1521 | 1602 | ||
1603 | if (!shost->async_scan) | ||
1604 | scsi_complete_async_scans(); | ||
1605 | |||
1522 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || | 1606 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || |
1523 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || | 1607 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || |
1524 | ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) | 1608 | ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) |
@@ -1539,14 +1623,143 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
1539 | return 0; | 1623 | return 0; |
1540 | } | 1624 | } |
1541 | 1625 | ||
1626 | static void scsi_sysfs_add_devices(struct Scsi_Host *shost) | ||
1627 | { | ||
1628 | struct scsi_device *sdev; | ||
1629 | shost_for_each_device(sdev, shost) { | ||
1630 | if (scsi_sysfs_add_sdev(sdev) != 0) | ||
1631 | scsi_destroy_sdev(sdev); | ||
1632 | } | ||
1633 | } | ||
1634 | |||
1635 | /** | ||
1636 | * scsi_prep_async_scan - prepare for an async scan | ||
1637 | * @shost: the host which will be scanned | ||
1638 | * Returns: a cookie to be passed to scsi_finish_async_scan() | ||
1639 | * | ||
1640 | * Tells the midlayer this host is going to do an asynchronous scan. | ||
1641 | * It reserves the host's position in the scanning list and ensures | ||
1642 | * that other asynchronous scans started after this one won't affect the | ||
1643 | * ordering of the discovered devices. | ||
1644 | */ | ||
1645 | static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) | ||
1646 | { | ||
1647 | struct async_scan_data *data; | ||
1648 | |||
1649 | if (strncmp(scsi_scan_type, "sync", 4) == 0) | ||
1650 | return NULL; | ||
1651 | |||
1652 | if (shost->async_scan) { | ||
1653 | printk("%s called twice for host %d", __FUNCTION__, | ||
1654 | shost->host_no); | ||
1655 | dump_stack(); | ||
1656 | return NULL; | ||
1657 | } | ||
1658 | |||
1659 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
1660 | if (!data) | ||
1661 | goto err; | ||
1662 | data->shost = scsi_host_get(shost); | ||
1663 | if (!data->shost) | ||
1664 | goto err; | ||
1665 | init_completion(&data->prev_finished); | ||
1666 | |||
1667 | spin_lock(&async_scan_lock); | ||
1668 | shost->async_scan = 1; | ||
1669 | if (list_empty(&scanning_hosts)) | ||
1670 | complete(&data->prev_finished); | ||
1671 | list_add_tail(&data->list, &scanning_hosts); | ||
1672 | spin_unlock(&async_scan_lock); | ||
1673 | |||
1674 | return data; | ||
1675 | |||
1676 | err: | ||
1677 | kfree(data); | ||
1678 | return NULL; | ||
1679 | } | ||
1680 | |||
1681 | /** | ||
1682 | * scsi_finish_async_scan - asynchronous scan has finished | ||
1683 | * @data: cookie returned from earlier call to scsi_prep_async_scan() | ||
1684 | * | ||
1685 | * All the devices currently attached to this host have been found. | ||
1686 | * This function announces all the devices it has found to the rest | ||
1687 | * of the system. | ||
1688 | */ | ||
1689 | static void scsi_finish_async_scan(struct async_scan_data *data) | ||
1690 | { | ||
1691 | struct Scsi_Host *shost; | ||
1692 | |||
1693 | if (!data) | ||
1694 | return; | ||
1695 | |||
1696 | shost = data->shost; | ||
1697 | if (!shost->async_scan) { | ||
1698 | printk("%s called twice for host %d", __FUNCTION__, | ||
1699 | shost->host_no); | ||
1700 | dump_stack(); | ||
1701 | return; | ||
1702 | } | ||
1703 | |||
1704 | wait_for_completion(&data->prev_finished); | ||
1705 | |||
1706 | scsi_sysfs_add_devices(shost); | ||
1707 | |||
1708 | spin_lock(&async_scan_lock); | ||
1709 | shost->async_scan = 0; | ||
1710 | list_del(&data->list); | ||
1711 | if (!list_empty(&scanning_hosts)) { | ||
1712 | struct async_scan_data *next = list_entry(scanning_hosts.next, | ||
1713 | struct async_scan_data, list); | ||
1714 | complete(&next->prev_finished); | ||
1715 | } | ||
1716 | spin_unlock(&async_scan_lock); | ||
1717 | |||
1718 | scsi_host_put(shost); | ||
1719 | kfree(data); | ||
1720 | } | ||
1721 | |||
1722 | static void do_scsi_scan_host(struct Scsi_Host *shost) | ||
1723 | { | ||
1724 | if (shost->hostt->scan_finished) { | ||
1725 | unsigned long start = jiffies; | ||
1726 | if (shost->hostt->scan_start) | ||
1727 | shost->hostt->scan_start(shost); | ||
1728 | |||
1729 | while (!shost->hostt->scan_finished(shost, jiffies - start)) | ||
1730 | msleep(10); | ||
1731 | } else { | ||
1732 | scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, | ||
1733 | SCAN_WILD_CARD, 0); | ||
1734 | } | ||
1735 | } | ||
1736 | |||
1737 | static int do_scan_async(void *_data) | ||
1738 | { | ||
1739 | struct async_scan_data *data = _data; | ||
1740 | do_scsi_scan_host(data->shost); | ||
1741 | scsi_finish_async_scan(data); | ||
1742 | return 0; | ||
1743 | } | ||
1744 | |||
1542 | /** | 1745 | /** |
1543 | * scsi_scan_host - scan the given adapter | 1746 | * scsi_scan_host - scan the given adapter |
1544 | * @shost: adapter to scan | 1747 | * @shost: adapter to scan |
1545 | **/ | 1748 | **/ |
1546 | void scsi_scan_host(struct Scsi_Host *shost) | 1749 | void scsi_scan_host(struct Scsi_Host *shost) |
1547 | { | 1750 | { |
1548 | scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, | 1751 | struct async_scan_data *data; |
1549 | SCAN_WILD_CARD, 0); | 1752 | |
1753 | if (strncmp(scsi_scan_type, "none", 4) == 0) | ||
1754 | return; | ||
1755 | |||
1756 | data = scsi_prep_async_scan(shost); | ||
1757 | if (!data) { | ||
1758 | do_scsi_scan_host(shost); | ||
1759 | return; | ||
1760 | } | ||
1761 | |||
1762 | kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); | ||
1550 | } | 1763 | } |
1551 | EXPORT_SYMBOL(scsi_scan_host); | 1764 | EXPORT_SYMBOL(scsi_scan_host); |
1552 | 1765 | ||