diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-12-07 04:57:19 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-07 04:57:19 -0500 |
commit | 8d1413b28033c49c7f1a4d320e815d7a5531acee (patch) | |
tree | b37281abef014cd60803b81c100388d7a475d49e /drivers/scsi/scsi_scan.c | |
parent | ed25ffa16434724f5ed825aa48734c7f3aefa203 (diff) | |
parent | 620034c84d1d939717bdfbe02c51a3fee43541c3 (diff) |
Merge branch 'master' into upstream
Conflicts:
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_main.c
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 232 |
1 files changed, 223 insertions, 9 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 94a274645f6f..14e635aa44ce 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 |
@@ -362,9 +437,10 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
362 | goto retry; | 437 | goto retry; |
363 | } | 438 | } |
364 | 439 | ||
365 | static void scsi_target_reap_usercontext(void *data) | 440 | static void scsi_target_reap_usercontext(struct work_struct *work) |
366 | { | 441 | { |
367 | struct scsi_target *starget = data; | 442 | struct scsi_target *starget = |
443 | container_of(work, struct scsi_target, ew.work); | ||
368 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 444 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
369 | unsigned long flags; | 445 | unsigned long flags; |
370 | 446 | ||
@@ -400,7 +476,7 @@ void scsi_target_reap(struct scsi_target *starget) | |||
400 | starget->state = STARGET_DEL; | 476 | starget->state = STARGET_DEL; |
401 | spin_unlock_irqrestore(shost->host_lock, flags); | 477 | spin_unlock_irqrestore(shost->host_lock, flags); |
402 | execute_in_process_context(scsi_target_reap_usercontext, | 478 | execute_in_process_context(scsi_target_reap_usercontext, |
403 | starget, &starget->ew); | 479 | &starget->ew); |
404 | return; | 480 | return; |
405 | 481 | ||
406 | } | 482 | } |
@@ -619,7 +695,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 | 695 | * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized |
620 | **/ | 696 | **/ |
621 | static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | 697 | static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, |
622 | int *bflags) | 698 | int *bflags, int async) |
623 | { | 699 | { |
624 | /* | 700 | /* |
625 | * XXX do not save the inquiry, since it can change underneath us, | 701 | * XXX do not save the inquiry, since it can change underneath us, |
@@ -805,7 +881,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | |||
805 | * register it and tell the rest of the kernel | 881 | * register it and tell the rest of the kernel |
806 | * about it. | 882 | * about it. |
807 | */ | 883 | */ |
808 | if (scsi_sysfs_add_sdev(sdev) != 0) | 884 | if (!async && scsi_sysfs_add_sdev(sdev) != 0) |
809 | return SCSI_SCAN_NO_RESPONSE; | 885 | return SCSI_SCAN_NO_RESPONSE; |
810 | 886 | ||
811 | return SCSI_SCAN_LUN_PRESENT; | 887 | return SCSI_SCAN_LUN_PRESENT; |
@@ -974,7 +1050,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
974 | goto out_free_result; | 1050 | goto out_free_result; |
975 | } | 1051 | } |
976 | 1052 | ||
977 | res = scsi_add_lun(sdev, result, &bflags); | 1053 | res = scsi_add_lun(sdev, result, &bflags, shost->async_scan); |
978 | if (res == SCSI_SCAN_LUN_PRESENT) { | 1054 | if (res == SCSI_SCAN_LUN_PRESENT) { |
979 | if (bflags & BLIST_KEY) { | 1055 | if (bflags & BLIST_KEY) { |
980 | sdev->lockable = 0; | 1056 | sdev->lockable = 0; |
@@ -1474,6 +1550,12 @@ void scsi_scan_target(struct device *parent, unsigned int channel, | |||
1474 | { | 1550 | { |
1475 | struct Scsi_Host *shost = dev_to_shost(parent); | 1551 | struct Scsi_Host *shost = dev_to_shost(parent); |
1476 | 1552 | ||
1553 | if (strncmp(scsi_scan_type, "none", 4) == 0) | ||
1554 | return; | ||
1555 | |||
1556 | if (!shost->async_scan) | ||
1557 | scsi_complete_async_scans(); | ||
1558 | |||
1477 | mutex_lock(&shost->scan_mutex); | 1559 | mutex_lock(&shost->scan_mutex); |
1478 | if (scsi_host_scan_allowed(shost)) | 1560 | if (scsi_host_scan_allowed(shost)) |
1479 | __scsi_scan_target(parent, channel, id, lun, rescan); | 1561 | __scsi_scan_target(parent, channel, id, lun, rescan); |
@@ -1519,6 +1601,9 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
1519 | "%s: <%u:%u:%u>\n", | 1601 | "%s: <%u:%u:%u>\n", |
1520 | __FUNCTION__, channel, id, lun)); | 1602 | __FUNCTION__, channel, id, lun)); |
1521 | 1603 | ||
1604 | if (!shost->async_scan) | ||
1605 | scsi_complete_async_scans(); | ||
1606 | |||
1522 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || | 1607 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || |
1523 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || | 1608 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || |
1524 | ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) | 1609 | ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) |
@@ -1539,14 +1624,143 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
1539 | return 0; | 1624 | return 0; |
1540 | } | 1625 | } |
1541 | 1626 | ||
1627 | static void scsi_sysfs_add_devices(struct Scsi_Host *shost) | ||
1628 | { | ||
1629 | struct scsi_device *sdev; | ||
1630 | shost_for_each_device(sdev, shost) { | ||
1631 | if (scsi_sysfs_add_sdev(sdev) != 0) | ||
1632 | scsi_destroy_sdev(sdev); | ||
1633 | } | ||
1634 | } | ||
1635 | |||
1636 | /** | ||
1637 | * scsi_prep_async_scan - prepare for an async scan | ||
1638 | * @shost: the host which will be scanned | ||
1639 | * Returns: a cookie to be passed to scsi_finish_async_scan() | ||
1640 | * | ||
1641 | * Tells the midlayer this host is going to do an asynchronous scan. | ||
1642 | * It reserves the host's position in the scanning list and ensures | ||
1643 | * that other asynchronous scans started after this one won't affect the | ||
1644 | * ordering of the discovered devices. | ||
1645 | */ | ||
1646 | static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) | ||
1647 | { | ||
1648 | struct async_scan_data *data; | ||
1649 | |||
1650 | if (strncmp(scsi_scan_type, "sync", 4) == 0) | ||
1651 | return NULL; | ||
1652 | |||
1653 | if (shost->async_scan) { | ||
1654 | printk("%s called twice for host %d", __FUNCTION__, | ||
1655 | shost->host_no); | ||
1656 | dump_stack(); | ||
1657 | return NULL; | ||
1658 | } | ||
1659 | |||
1660 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
1661 | if (!data) | ||
1662 | goto err; | ||
1663 | data->shost = scsi_host_get(shost); | ||
1664 | if (!data->shost) | ||
1665 | goto err; | ||
1666 | init_completion(&data->prev_finished); | ||
1667 | |||
1668 | spin_lock(&async_scan_lock); | ||
1669 | shost->async_scan = 1; | ||
1670 | if (list_empty(&scanning_hosts)) | ||
1671 | complete(&data->prev_finished); | ||
1672 | list_add_tail(&data->list, &scanning_hosts); | ||
1673 | spin_unlock(&async_scan_lock); | ||
1674 | |||
1675 | return data; | ||
1676 | |||
1677 | err: | ||
1678 | kfree(data); | ||
1679 | return NULL; | ||
1680 | } | ||
1681 | |||
1682 | /** | ||
1683 | * scsi_finish_async_scan - asynchronous scan has finished | ||
1684 | * @data: cookie returned from earlier call to scsi_prep_async_scan() | ||
1685 | * | ||
1686 | * All the devices currently attached to this host have been found. | ||
1687 | * This function announces all the devices it has found to the rest | ||
1688 | * of the system. | ||
1689 | */ | ||
1690 | static void scsi_finish_async_scan(struct async_scan_data *data) | ||
1691 | { | ||
1692 | struct Scsi_Host *shost; | ||
1693 | |||
1694 | if (!data) | ||
1695 | return; | ||
1696 | |||
1697 | shost = data->shost; | ||
1698 | if (!shost->async_scan) { | ||
1699 | printk("%s called twice for host %d", __FUNCTION__, | ||
1700 | shost->host_no); | ||
1701 | dump_stack(); | ||
1702 | return; | ||
1703 | } | ||
1704 | |||
1705 | wait_for_completion(&data->prev_finished); | ||
1706 | |||
1707 | scsi_sysfs_add_devices(shost); | ||
1708 | |||
1709 | spin_lock(&async_scan_lock); | ||
1710 | shost->async_scan = 0; | ||
1711 | list_del(&data->list); | ||
1712 | if (!list_empty(&scanning_hosts)) { | ||
1713 | struct async_scan_data *next = list_entry(scanning_hosts.next, | ||
1714 | struct async_scan_data, list); | ||
1715 | complete(&next->prev_finished); | ||
1716 | } | ||
1717 | spin_unlock(&async_scan_lock); | ||
1718 | |||
1719 | scsi_host_put(shost); | ||
1720 | kfree(data); | ||
1721 | } | ||
1722 | |||
1723 | static void do_scsi_scan_host(struct Scsi_Host *shost) | ||
1724 | { | ||
1725 | if (shost->hostt->scan_finished) { | ||
1726 | unsigned long start = jiffies; | ||
1727 | if (shost->hostt->scan_start) | ||
1728 | shost->hostt->scan_start(shost); | ||
1729 | |||
1730 | while (!shost->hostt->scan_finished(shost, jiffies - start)) | ||
1731 | msleep(10); | ||
1732 | } else { | ||
1733 | scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, | ||
1734 | SCAN_WILD_CARD, 0); | ||
1735 | } | ||
1736 | } | ||
1737 | |||
1738 | static int do_scan_async(void *_data) | ||
1739 | { | ||
1740 | struct async_scan_data *data = _data; | ||
1741 | do_scsi_scan_host(data->shost); | ||
1742 | scsi_finish_async_scan(data); | ||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1542 | /** | 1746 | /** |
1543 | * scsi_scan_host - scan the given adapter | 1747 | * scsi_scan_host - scan the given adapter |
1544 | * @shost: adapter to scan | 1748 | * @shost: adapter to scan |
1545 | **/ | 1749 | **/ |
1546 | void scsi_scan_host(struct Scsi_Host *shost) | 1750 | void scsi_scan_host(struct Scsi_Host *shost) |
1547 | { | 1751 | { |
1548 | scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, | 1752 | struct async_scan_data *data; |
1549 | SCAN_WILD_CARD, 0); | 1753 | |
1754 | if (strncmp(scsi_scan_type, "none", 4) == 0) | ||
1755 | return; | ||
1756 | |||
1757 | data = scsi_prep_async_scan(shost); | ||
1758 | if (!data) { | ||
1759 | do_scsi_scan_host(shost); | ||
1760 | return; | ||
1761 | } | ||
1762 | |||
1763 | kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); | ||
1550 | } | 1764 | } |
1551 | EXPORT_SYMBOL(scsi_scan_host); | 1765 | EXPORT_SYMBOL(scsi_scan_host); |
1552 | 1766 | ||