diff options
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 d3c5e964c964..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 |
| @@ -620,7 +695,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, | |||
| 620 | * 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 |
| 621 | **/ | 696 | **/ |
| 622 | 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, |
| 623 | int *bflags) | 698 | int *bflags, int async) |
| 624 | { | 699 | { |
| 625 | /* | 700 | /* |
| 626 | * 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, |
| @@ -806,7 +881,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | |||
| 806 | * register it and tell the rest of the kernel | 881 | * register it and tell the rest of the kernel |
| 807 | * about it. | 882 | * about it. |
| 808 | */ | 883 | */ |
| 809 | if (scsi_sysfs_add_sdev(sdev) != 0) | 884 | if (!async && scsi_sysfs_add_sdev(sdev) != 0) |
| 810 | return SCSI_SCAN_NO_RESPONSE; | 885 | return SCSI_SCAN_NO_RESPONSE; |
| 811 | 886 | ||
| 812 | return SCSI_SCAN_LUN_PRESENT; | 887 | return SCSI_SCAN_LUN_PRESENT; |
| @@ -975,7 +1050,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
| 975 | goto out_free_result; | 1050 | goto out_free_result; |
| 976 | } | 1051 | } |
| 977 | 1052 | ||
| 978 | res = scsi_add_lun(sdev, result, &bflags); | 1053 | res = scsi_add_lun(sdev, result, &bflags, shost->async_scan); |
| 979 | if (res == SCSI_SCAN_LUN_PRESENT) { | 1054 | if (res == SCSI_SCAN_LUN_PRESENT) { |
| 980 | if (bflags & BLIST_KEY) { | 1055 | if (bflags & BLIST_KEY) { |
| 981 | sdev->lockable = 0; | 1056 | sdev->lockable = 0; |
| @@ -1475,6 +1550,12 @@ void scsi_scan_target(struct device *parent, unsigned int channel, | |||
| 1475 | { | 1550 | { |
| 1476 | struct Scsi_Host *shost = dev_to_shost(parent); | 1551 | struct Scsi_Host *shost = dev_to_shost(parent); |
| 1477 | 1552 | ||
| 1553 | if (strncmp(scsi_scan_type, "none", 4) == 0) | ||
| 1554 | return; | ||
| 1555 | |||
| 1556 | if (!shost->async_scan) | ||
| 1557 | scsi_complete_async_scans(); | ||
| 1558 | |||
| 1478 | mutex_lock(&shost->scan_mutex); | 1559 | mutex_lock(&shost->scan_mutex); |
| 1479 | if (scsi_host_scan_allowed(shost)) | 1560 | if (scsi_host_scan_allowed(shost)) |
| 1480 | __scsi_scan_target(parent, channel, id, lun, rescan); | 1561 | __scsi_scan_target(parent, channel, id, lun, rescan); |
| @@ -1520,6 +1601,9 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
| 1520 | "%s: <%u:%u:%u>\n", | 1601 | "%s: <%u:%u:%u>\n", |
| 1521 | __FUNCTION__, channel, id, lun)); | 1602 | __FUNCTION__, channel, id, lun)); |
| 1522 | 1603 | ||
| 1604 | if (!shost->async_scan) | ||
| 1605 | scsi_complete_async_scans(); | ||
| 1606 | |||
| 1523 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || | 1607 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || |
| 1524 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || | 1608 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || |
| 1525 | ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) | 1609 | ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) |
| @@ -1540,14 +1624,143 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
| 1540 | return 0; | 1624 | return 0; |
| 1541 | } | 1625 | } |
| 1542 | 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 | |||
| 1543 | /** | 1746 | /** |
| 1544 | * scsi_scan_host - scan the given adapter | 1747 | * scsi_scan_host - scan the given adapter |
| 1545 | * @shost: adapter to scan | 1748 | * @shost: adapter to scan |
| 1546 | **/ | 1749 | **/ |
| 1547 | void scsi_scan_host(struct Scsi_Host *shost) | 1750 | void scsi_scan_host(struct Scsi_Host *shost) |
| 1548 | { | 1751 | { |
| 1549 | scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, | 1752 | struct async_scan_data *data; |
| 1550 | 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); | ||
| 1551 | } | 1764 | } |
| 1552 | EXPORT_SYMBOL(scsi_scan_host); | 1765 | EXPORT_SYMBOL(scsi_scan_host); |
| 1553 | 1766 | ||
