aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
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
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')
-rw-r--r--drivers/scsi/hosts.c10
-rw-r--r--drivers/scsi/scsi_error.c16
-rw-r--r--drivers/scsi/scsi_pm.c110
-rw-r--r--drivers/scsi/scsi_priv.h14
-rw-r--r--drivers/scsi/scsi_scan.c24
-rw-r--r--drivers/scsi/scsi_sysfs.c20
-rw-r--r--drivers/scsi/sg.c10
7 files changed, 193 insertions, 11 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index a2b1414da288..8a8f803439e1 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -32,6 +32,7 @@
32#include <linux/completion.h> 32#include <linux/completion.h>
33#include <linux/transport_class.h> 33#include <linux/transport_class.h>
34#include <linux/platform_device.h> 34#include <linux/platform_device.h>
35#include <linux/pm_runtime.h>
35 36
36#include <scsi/scsi_device.h> 37#include <scsi/scsi_device.h>
37#include <scsi/scsi_host.h> 38#include <scsi/scsi_host.h>
@@ -156,6 +157,7 @@ EXPORT_SYMBOL(scsi_host_set_state);
156void scsi_remove_host(struct Scsi_Host *shost) 157void scsi_remove_host(struct Scsi_Host *shost)
157{ 158{
158 unsigned long flags; 159 unsigned long flags;
160
159 mutex_lock(&shost->scan_mutex); 161 mutex_lock(&shost->scan_mutex);
160 spin_lock_irqsave(shost->host_lock, flags); 162 spin_lock_irqsave(shost->host_lock, flags);
161 if (scsi_host_set_state(shost, SHOST_CANCEL)) 163 if (scsi_host_set_state(shost, SHOST_CANCEL))
@@ -165,6 +167,8 @@ void scsi_remove_host(struct Scsi_Host *shost)
165 return; 167 return;
166 } 168 }
167 spin_unlock_irqrestore(shost->host_lock, flags); 169 spin_unlock_irqrestore(shost->host_lock, flags);
170
171 scsi_autopm_get_host(shost);
168 scsi_forget_host(shost); 172 scsi_forget_host(shost);
169 mutex_unlock(&shost->scan_mutex); 173 mutex_unlock(&shost->scan_mutex);
170 scsi_proc_host_rm(shost); 174 scsi_proc_host_rm(shost);
@@ -216,12 +220,14 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
216 shost->shost_gendev.parent = dev ? dev : &platform_bus; 220 shost->shost_gendev.parent = dev ? dev : &platform_bus;
217 shost->dma_dev = dma_dev; 221 shost->dma_dev = dma_dev;
218 222
219 device_enable_async_suspend(&shost->shost_gendev);
220
221 error = device_add(&shost->shost_gendev); 223 error = device_add(&shost->shost_gendev);
222 if (error) 224 if (error)
223 goto out; 225 goto out;
224 226
227 pm_runtime_set_active(&shost->shost_gendev);
228 pm_runtime_enable(&shost->shost_gendev);
229 device_enable_async_suspend(&shost->shost_gendev);
230
225 scsi_host_set_state(shost, SHOST_RUNNING); 231 scsi_host_set_state(shost, SHOST_RUNNING);
226 get_device(shost->shost_gendev.parent); 232 get_device(shost->shost_gendev.parent);
227 233
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c60cffbefa3c..2bf98469dc4c 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1775,6 +1775,14 @@ int scsi_error_handler(void *data)
1775 * what we need to do to get it up and online again (if we can). 1775 * what we need to do to get it up and online again (if we can).
1776 * If we fail, we end up taking the thing offline. 1776 * If we fail, we end up taking the thing offline.
1777 */ 1777 */
1778 if (scsi_autopm_get_host(shost) != 0) {
1779 SCSI_LOG_ERROR_RECOVERY(1,
1780 printk(KERN_ERR "Error handler scsi_eh_%d "
1781 "unable to autoresume\n",
1782 shost->host_no));
1783 continue;
1784 }
1785
1778 if (shost->transportt->eh_strategy_handler) 1786 if (shost->transportt->eh_strategy_handler)
1779 shost->transportt->eh_strategy_handler(shost); 1787 shost->transportt->eh_strategy_handler(shost);
1780 else 1788 else
@@ -1788,6 +1796,7 @@ int scsi_error_handler(void *data)
1788 * which are still online. 1796 * which are still online.
1789 */ 1797 */
1790 scsi_restart_operations(shost); 1798 scsi_restart_operations(shost);
1799 scsi_autopm_put_host(shost);
1791 set_current_state(TASK_INTERRUPTIBLE); 1800 set_current_state(TASK_INTERRUPTIBLE);
1792 } 1801 }
1793 __set_current_state(TASK_RUNNING); 1802 __set_current_state(TASK_RUNNING);
@@ -1885,12 +1894,16 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
1885int 1894int
1886scsi_reset_provider(struct scsi_device *dev, int flag) 1895scsi_reset_provider(struct scsi_device *dev, int flag)
1887{ 1896{
1888 struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL); 1897 struct scsi_cmnd *scmd;
1889 struct Scsi_Host *shost = dev->host; 1898 struct Scsi_Host *shost = dev->host;
1890 struct request req; 1899 struct request req;
1891 unsigned long flags; 1900 unsigned long flags;
1892 int rtn; 1901 int rtn;
1893 1902
1903 if (scsi_autopm_get_host(shost) < 0)
1904 return FAILED;
1905
1906 scmd = scsi_get_command(dev, GFP_KERNEL);
1894 blk_rq_init(NULL, &req); 1907 blk_rq_init(NULL, &req);
1895 scmd->request = &req; 1908 scmd->request = &req;
1896 1909
@@ -1947,6 +1960,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
1947 scsi_run_host_queues(shost); 1960 scsi_run_host_queues(shost);
1948 1961
1949 scsi_next_command(scmd); 1962 scsi_next_command(scmd);
1963 scsi_autopm_put_host(shost);
1950 return rtn; 1964 return rtn;
1951} 1965}
1952EXPORT_SYMBOL(scsi_reset_provider); 1966EXPORT_SYMBOL(scsi_reset_provider);
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index cd83758ce0a2..d70e91ae60af 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -59,6 +59,12 @@ static int scsi_bus_resume_common(struct device *dev)
59 59
60 if (scsi_is_sdev_device(dev)) 60 if (scsi_is_sdev_device(dev))
61 err = scsi_dev_type_resume(dev); 61 err = scsi_dev_type_resume(dev);
62
63 if (err == 0) {
64 pm_runtime_disable(dev);
65 pm_runtime_set_active(dev);
66 pm_runtime_enable(dev);
67 }
62 return err; 68 return err;
63} 69}
64 70
@@ -86,6 +92,107 @@ static int scsi_bus_poweroff(struct device *dev)
86 92
87#endif /* CONFIG_PM_SLEEP */ 93#endif /* CONFIG_PM_SLEEP */
88 94
95#ifdef CONFIG_PM_RUNTIME
96
97static int scsi_runtime_suspend(struct device *dev)
98{
99 int err = 0;
100
101 dev_dbg(dev, "scsi_runtime_suspend\n");
102 if (scsi_is_sdev_device(dev)) {
103 err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND);
104 if (err == -EAGAIN)
105 pm_schedule_suspend(dev, jiffies_to_msecs(
106 round_jiffies_up_relative(HZ/10)));
107 }
108
109 /* Insert hooks here for targets, hosts, and transport classes */
110
111 return err;
112}
113
114static int scsi_runtime_resume(struct device *dev)
115{
116 int err = 0;
117
118 dev_dbg(dev, "scsi_runtime_resume\n");
119 if (scsi_is_sdev_device(dev))
120 err = scsi_dev_type_resume(dev);
121
122 /* Insert hooks here for targets, hosts, and transport classes */
123
124 return err;
125}
126
127static int scsi_runtime_idle(struct device *dev)
128{
129 int err;
130
131 dev_dbg(dev, "scsi_runtime_idle\n");
132
133 /* Insert hooks here for targets, hosts, and transport classes */
134
135 if (scsi_is_sdev_device(dev))
136 err = pm_schedule_suspend(dev, 100);
137 else
138 err = pm_runtime_suspend(dev);
139 return err;
140}
141
142int scsi_autopm_get_device(struct scsi_device *sdev)
143{
144 int err;
145
146 err = pm_runtime_get_sync(&sdev->sdev_gendev);
147 if (err < 0)
148 pm_runtime_put_sync(&sdev->sdev_gendev);
149 else if (err > 0)
150 err = 0;
151 return err;
152}
153EXPORT_SYMBOL_GPL(scsi_autopm_get_device);
154
155void scsi_autopm_put_device(struct scsi_device *sdev)
156{
157 pm_runtime_put_sync(&sdev->sdev_gendev);
158}
159EXPORT_SYMBOL_GPL(scsi_autopm_put_device);
160
161void scsi_autopm_get_target(struct scsi_target *starget)
162{
163 pm_runtime_get_sync(&starget->dev);
164}
165
166void scsi_autopm_put_target(struct scsi_target *starget)
167{
168 pm_runtime_put_sync(&starget->dev);
169}
170
171int scsi_autopm_get_host(struct Scsi_Host *shost)
172{
173 int err;
174
175 err = pm_runtime_get_sync(&shost->shost_gendev);
176 if (err < 0)
177 pm_runtime_put_sync(&shost->shost_gendev);
178 else if (err > 0)
179 err = 0;
180 return err;
181}
182
183void scsi_autopm_put_host(struct Scsi_Host *shost)
184{
185 pm_runtime_put_sync(&shost->shost_gendev);
186}
187
188#else
189
190#define scsi_runtime_suspend NULL
191#define scsi_runtime_resume NULL
192#define scsi_runtime_idle NULL
193
194#endif /* CONFIG_PM_RUNTIME */
195
89const struct dev_pm_ops scsi_bus_pm_ops = { 196const struct dev_pm_ops scsi_bus_pm_ops = {
90 .suspend = scsi_bus_suspend, 197 .suspend = scsi_bus_suspend,
91 .resume = scsi_bus_resume_common, 198 .resume = scsi_bus_resume_common,
@@ -93,4 +200,7 @@ const struct dev_pm_ops scsi_bus_pm_ops = {
93 .thaw = scsi_bus_resume_common, 200 .thaw = scsi_bus_resume_common,
94 .poweroff = scsi_bus_poweroff, 201 .poweroff = scsi_bus_poweroff,
95 .restore = scsi_bus_resume_common, 202 .restore = scsi_bus_resume_common,
203 .runtime_suspend = scsi_runtime_suspend,
204 .runtime_resume = scsi_runtime_resume,
205 .runtime_idle = scsi_runtime_idle,
96}; 206};
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index dddacc732550..026295e2c539 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -7,6 +7,7 @@ struct request_queue;
7struct request; 7struct request;
8struct scsi_cmnd; 8struct scsi_cmnd;
9struct scsi_device; 9struct scsi_device;
10struct scsi_target;
10struct scsi_host_template; 11struct scsi_host_template;
11struct Scsi_Host; 12struct Scsi_Host;
12struct scsi_nl_hdr; 13struct scsi_nl_hdr;
@@ -147,9 +148,20 @@ static inline void scsi_netlink_exit(void) {}
147/* scsi_pm.c */ 148/* scsi_pm.c */
148#ifdef CONFIG_PM_OPS 149#ifdef CONFIG_PM_OPS
149extern const struct dev_pm_ops scsi_bus_pm_ops; 150extern const struct dev_pm_ops scsi_bus_pm_ops;
150#else 151#else /* CONFIG_PM_OPS */
151#define scsi_bus_pm_ops (*NULL) 152#define scsi_bus_pm_ops (*NULL)
152#endif 153#endif
154#ifdef CONFIG_PM_RUNTIME
155extern void scsi_autopm_get_target(struct scsi_target *);
156extern void scsi_autopm_put_target(struct scsi_target *);
157extern int scsi_autopm_get_host(struct Scsi_Host *);
158extern void scsi_autopm_put_host(struct Scsi_Host *);
159#else
160static inline void scsi_autopm_get_target(struct scsi_target *t) {}
161static inline void scsi_autopm_put_target(struct scsi_target *t) {}
162static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
163static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
164#endif /* CONFIG_PM_RUNTIME */
153 165
154/* 166/*
155 * internal scsi timeout functions: for use by mid-layer and transport 167 * internal scsi timeout functions: for use by mid-layer and transport
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
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5f85f8e831f3..562fb3bce261 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -11,6 +11,7 @@
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/blkdev.h> 12#include <linux/blkdev.h>
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/pm_runtime.h>
14 15
15#include <scsi/scsi.h> 16#include <scsi/scsi.h>
16#include <scsi/scsi_device.h> 17#include <scsi/scsi_device.h>
@@ -802,8 +803,6 @@ static int scsi_target_add(struct scsi_target *starget)
802 if (starget->state != STARGET_CREATED) 803 if (starget->state != STARGET_CREATED)
803 return 0; 804 return 0;
804 805
805 device_enable_async_suspend(&starget->dev);
806
807 error = device_add(&starget->dev); 806 error = device_add(&starget->dev);
808 if (error) { 807 if (error) {
809 dev_err(&starget->dev, "target device_add failed, error %d\n", error); 808 dev_err(&starget->dev, "target device_add failed, error %d\n", error);
@@ -812,6 +811,10 @@ static int scsi_target_add(struct scsi_target *starget)
812 transport_add_device(&starget->dev); 811 transport_add_device(&starget->dev);
813 starget->state = STARGET_RUNNING; 812 starget->state = STARGET_RUNNING;
814 813
814 pm_runtime_set_active(&starget->dev);
815 pm_runtime_enable(&starget->dev);
816 device_enable_async_suspend(&starget->dev);
817
815 return 0; 818 return 0;
816} 819}
817 820
@@ -841,7 +844,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
841 return error; 844 return error;
842 845
843 transport_configure_device(&starget->dev); 846 transport_configure_device(&starget->dev);
847
844 device_enable_async_suspend(&sdev->sdev_gendev); 848 device_enable_async_suspend(&sdev->sdev_gendev);
849 scsi_autopm_get_target(starget);
850 pm_runtime_set_active(&sdev->sdev_gendev);
851 pm_runtime_forbid(&sdev->sdev_gendev);
852 pm_runtime_enable(&sdev->sdev_gendev);
853 scsi_autopm_put_target(starget);
854
855 /* The following call will keep sdev active indefinitely, until
856 * its driver does a corresponding scsi_autopm_pm_device(). Only
857 * drivers supporting autosuspend will do this.
858 */
859 scsi_autopm_get_device(sdev);
860
845 error = device_add(&sdev->sdev_gendev); 861 error = device_add(&sdev->sdev_gendev);
846 if (error) { 862 if (error) {
847 printk(KERN_INFO "error 1\n"); 863 printk(KERN_INFO "error 1\n");
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index d4549092400c..2968c6b83ddb 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -245,6 +245,10 @@ sg_open(struct inode *inode, struct file *filp)
245 if (retval) 245 if (retval)
246 goto sg_put; 246 goto sg_put;
247 247
248 retval = scsi_autopm_get_device(sdp->device);
249 if (retval)
250 goto sdp_put;
251
248 if (!((flags & O_NONBLOCK) || 252 if (!((flags & O_NONBLOCK) ||
249 scsi_block_when_processing_errors(sdp->device))) { 253 scsi_block_when_processing_errors(sdp->device))) {
250 retval = -ENXIO; 254 retval = -ENXIO;
@@ -302,8 +306,11 @@ sg_open(struct inode *inode, struct file *filp)
302 } 306 }
303 retval = 0; 307 retval = 0;
304error_out: 308error_out:
305 if (retval) 309 if (retval) {
310 scsi_autopm_put_device(sdp->device);
311sdp_put:
306 scsi_device_put(sdp->device); 312 scsi_device_put(sdp->device);
313 }
307sg_put: 314sg_put:
308 if (sdp) 315 if (sdp)
309 sg_put_dev(sdp); 316 sg_put_dev(sdp);
@@ -327,6 +334,7 @@ sg_release(struct inode *inode, struct file *filp)
327 sdp->exclude = 0; 334 sdp->exclude = 0;
328 wake_up_interruptible(&sdp->o_excl_wait); 335 wake_up_interruptible(&sdp->o_excl_wait);
329 336
337 scsi_autopm_put_device(sdp->device);
330 kref_put(&sfp->f_ref, sg_remove_sfp); 338 kref_put(&sfp->f_ref, sg_remove_sfp);
331 return 0; 339 return 0;
332} 340}