aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_scan.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-06-17 10:41:42 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-28 10:07:50 -0400
commitbc4f24014de58f045f169742701a6598884d93db (patch)
tree4e68ae6fa5fff179ce69b2d890b01a5fcc9c55d5 /drivers/scsi/scsi_scan.c
parentdb5bd1e0b505c54ff492172ce4abc245cf6cd639 (diff)
[SCSI] implement runtime Power Management
This patch (as1398b) adds runtime PM support to the SCSI layer. Only the machanism is provided; use of it is up to the various high-level drivers, and the patch doesn't change any of them. Except for sg -- the patch expicitly prevents a device from being runtime-suspended while its sg device file is open. The implementation is simplistic. In general, hosts and targets are automatically suspended when all their children are asleep, but for them the runtime-suspend code doesn't actually do anything. (A host's runtime PM status is propagated up the device tree, though, so a runtime-PM-aware lower-level driver could power down the host adapter hardware at the appropriate times.) There are comments indicating where a transport class might be notified or some other hooks added. LUNs are runtime-suspended by calling the drivers' existing suspend handlers (and likewise for runtime-resume). Somewhat arbitrarily, the implementation delays for 100 ms before suspending an eligible LUN. This is because there typically are occasions during bootup when the same device file is opened and closed several times in quick succession. The way this all works is that the SCSI core increments a device's PM-usage count when it is registered. If a high-level driver does nothing then the device will not be eligible for runtime-suspend because of the elevated usage count. If a high-level driver wants to use runtime PM then it can call scsi_autopm_put_device() in its probe routine to decrement the usage count and scsi_autopm_get_device() in its remove routine to restore the original count. Hosts, targets, and LUNs are not suspended while they are being probed or removed, or while the error handler is running. In fact, a fairly large part of the patch consists of code to make sure that things aren't suspended at such times. [jejb: fix up compile issues in PM config variations] Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r--drivers/scsi/scsi_scan.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 1c027a97d8b9..3d0a1e6e9c48 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1513,14 +1513,18 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
1513 starget = scsi_alloc_target(parent, channel, id); 1513 starget = scsi_alloc_target(parent, channel, id);
1514 if (!starget) 1514 if (!starget)
1515 return ERR_PTR(-ENOMEM); 1515 return ERR_PTR(-ENOMEM);
1516 scsi_autopm_get_target(starget);
1516 1517
1517 mutex_lock(&shost->scan_mutex); 1518 mutex_lock(&shost->scan_mutex);
1518 if (!shost->async_scan) 1519 if (!shost->async_scan)
1519 scsi_complete_async_scans(); 1520 scsi_complete_async_scans();
1520 1521
1521 if (scsi_host_scan_allowed(shost)) 1522 if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
1522 scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); 1523 scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
1524 scsi_autopm_put_host(shost);
1525 }
1523 mutex_unlock(&shost->scan_mutex); 1526 mutex_unlock(&shost->scan_mutex);
1527 scsi_autopm_put_target(starget);
1524 scsi_target_reap(starget); 1528 scsi_target_reap(starget);
1525 put_device(&starget->dev); 1529 put_device(&starget->dev);
1526 1530
@@ -1574,6 +1578,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
1574 starget = scsi_alloc_target(parent, channel, id); 1578 starget = scsi_alloc_target(parent, channel, id);
1575 if (!starget) 1579 if (!starget)
1576 return; 1580 return;
1581 scsi_autopm_get_target(starget);
1577 1582
1578 if (lun != SCAN_WILD_CARD) { 1583 if (lun != SCAN_WILD_CARD) {
1579 /* 1584 /*
@@ -1599,6 +1604,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
1599 } 1604 }
1600 1605
1601 out_reap: 1606 out_reap:
1607 scsi_autopm_put_target(starget);
1602 /* now determine if the target has any children at all 1608 /* now determine if the target has any children at all
1603 * and if not, nuke it */ 1609 * and if not, nuke it */
1604 scsi_target_reap(starget); 1610 scsi_target_reap(starget);
@@ -1633,8 +1639,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
1633 if (!shost->async_scan) 1639 if (!shost->async_scan)
1634 scsi_complete_async_scans(); 1640 scsi_complete_async_scans();
1635 1641
1636 if (scsi_host_scan_allowed(shost)) 1642 if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
1637 __scsi_scan_target(parent, channel, id, lun, rescan); 1643 __scsi_scan_target(parent, channel, id, lun, rescan);
1644 scsi_autopm_put_host(shost);
1645 }
1638 mutex_unlock(&shost->scan_mutex); 1646 mutex_unlock(&shost->scan_mutex);
1639} 1647}
1640EXPORT_SYMBOL(scsi_scan_target); 1648EXPORT_SYMBOL(scsi_scan_target);
@@ -1686,7 +1694,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
1686 if (!shost->async_scan) 1694 if (!shost->async_scan)
1687 scsi_complete_async_scans(); 1695 scsi_complete_async_scans();
1688 1696
1689 if (scsi_host_scan_allowed(shost)) { 1697 if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
1690 if (channel == SCAN_WILD_CARD) 1698 if (channel == SCAN_WILD_CARD)
1691 for (channel = 0; channel <= shost->max_channel; 1699 for (channel = 0; channel <= shost->max_channel;
1692 channel++) 1700 channel++)
@@ -1694,6 +1702,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
1694 rescan); 1702 rescan);
1695 else 1703 else
1696 scsi_scan_channel(shost, channel, id, lun, rescan); 1704 scsi_scan_channel(shost, channel, id, lun, rescan);
1705 scsi_autopm_put_host(shost);
1697 } 1706 }
1698 mutex_unlock(&shost->scan_mutex); 1707 mutex_unlock(&shost->scan_mutex);
1699 1708
@@ -1831,8 +1840,11 @@ static void do_scsi_scan_host(struct Scsi_Host *shost)
1831static int do_scan_async(void *_data) 1840static int do_scan_async(void *_data)
1832{ 1841{
1833 struct async_scan_data *data = _data; 1842 struct async_scan_data *data = _data;
1834 do_scsi_scan_host(data->shost); 1843 struct Scsi_Host *shost = data->shost;
1844
1845 do_scsi_scan_host(shost);
1835 scsi_finish_async_scan(data); 1846 scsi_finish_async_scan(data);
1847 scsi_autopm_put_host(shost);
1836 return 0; 1848 return 0;
1837} 1849}
1838 1850
@@ -1847,16 +1859,20 @@ void scsi_scan_host(struct Scsi_Host *shost)
1847 1859
1848 if (strncmp(scsi_scan_type, "none", 4) == 0) 1860 if (strncmp(scsi_scan_type, "none", 4) == 0)
1849 return; 1861 return;
1862 if (scsi_autopm_get_host(shost) < 0)
1863 return;
1850 1864
1851 data = scsi_prep_async_scan(shost); 1865 data = scsi_prep_async_scan(shost);
1852 if (!data) { 1866 if (!data) {
1853 do_scsi_scan_host(shost); 1867 do_scsi_scan_host(shost);
1868 scsi_autopm_put_host(shost);
1854 return; 1869 return;
1855 } 1870 }
1856 1871
1857 p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); 1872 p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
1858 if (IS_ERR(p)) 1873 if (IS_ERR(p))
1859 do_scan_async(data); 1874 do_scan_async(data);
1875 /* scsi_autopm_put_host(shost) is called in do_scan_async() */
1860} 1876}
1861EXPORT_SYMBOL(scsi_scan_host); 1877EXPORT_SYMBOL(scsi_scan_host);
1862 1878