aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_pm.c')
-rw-r--r--drivers/scsi/scsi_pm.c128
1 files changed, 99 insertions, 29 deletions
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index 001e9ceda4c3..7454498c4091 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -18,35 +18,77 @@
18 18
19#ifdef CONFIG_PM_SLEEP 19#ifdef CONFIG_PM_SLEEP
20 20
21static int scsi_dev_type_suspend(struct device *dev, int (*cb)(struct device *)) 21static int do_scsi_suspend(struct device *dev, const struct dev_pm_ops *pm)
22{ 22{
23 return pm && pm->suspend ? pm->suspend(dev) : 0;
24}
25
26static int do_scsi_freeze(struct device *dev, const struct dev_pm_ops *pm)
27{
28 return pm && pm->freeze ? pm->freeze(dev) : 0;
29}
30
31static int do_scsi_poweroff(struct device *dev, const struct dev_pm_ops *pm)
32{
33 return pm && pm->poweroff ? pm->poweroff(dev) : 0;
34}
35
36static int do_scsi_resume(struct device *dev, const struct dev_pm_ops *pm)
37{
38 return pm && pm->resume ? pm->resume(dev) : 0;
39}
40
41static int do_scsi_thaw(struct device *dev, const struct dev_pm_ops *pm)
42{
43 return pm && pm->thaw ? pm->thaw(dev) : 0;
44}
45
46static int do_scsi_restore(struct device *dev, const struct dev_pm_ops *pm)
47{
48 return pm && pm->restore ? pm->restore(dev) : 0;
49}
50
51static int scsi_dev_type_suspend(struct device *dev,
52 int (*cb)(struct device *, const struct dev_pm_ops *))
53{
54 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
23 int err; 55 int err;
24 56
57 /* flush pending in-flight resume operations, suspend is synchronous */
58 async_synchronize_full_domain(&scsi_sd_pm_domain);
59
25 err = scsi_device_quiesce(to_scsi_device(dev)); 60 err = scsi_device_quiesce(to_scsi_device(dev));
26 if (err == 0) { 61 if (err == 0) {
27 if (cb) { 62 err = cb(dev, pm);
28 err = cb(dev); 63 if (err)
29 if (err) 64 scsi_device_resume(to_scsi_device(dev));
30 scsi_device_resume(to_scsi_device(dev));
31 }
32 } 65 }
33 dev_dbg(dev, "scsi suspend: %d\n", err); 66 dev_dbg(dev, "scsi suspend: %d\n", err);
34 return err; 67 return err;
35} 68}
36 69
37static int scsi_dev_type_resume(struct device *dev, int (*cb)(struct device *)) 70static int scsi_dev_type_resume(struct device *dev,
71 int (*cb)(struct device *, const struct dev_pm_ops *))
38{ 72{
73 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
39 int err = 0; 74 int err = 0;
40 75
41 if (cb) 76 err = cb(dev, pm);
42 err = cb(dev);
43 scsi_device_resume(to_scsi_device(dev)); 77 scsi_device_resume(to_scsi_device(dev));
44 dev_dbg(dev, "scsi resume: %d\n", err); 78 dev_dbg(dev, "scsi resume: %d\n", err);
79
80 if (err == 0) {
81 pm_runtime_disable(dev);
82 pm_runtime_set_active(dev);
83 pm_runtime_enable(dev);
84 }
85
45 return err; 86 return err;
46} 87}
47 88
48static int 89static int
49scsi_bus_suspend_common(struct device *dev, int (*cb)(struct device *)) 90scsi_bus_suspend_common(struct device *dev,
91 int (*cb)(struct device *, const struct dev_pm_ops *))
50{ 92{
51 int err = 0; 93 int err = 0;
52 94
@@ -66,20 +108,54 @@ scsi_bus_suspend_common(struct device *dev, int (*cb)(struct device *))
66 return err; 108 return err;
67} 109}
68 110
69static int 111static void async_sdev_resume(void *dev, async_cookie_t cookie)
70scsi_bus_resume_common(struct device *dev, int (*cb)(struct device *))
71{ 112{
72 int err = 0; 113 scsi_dev_type_resume(dev, do_scsi_resume);
114}
73 115
74 if (scsi_is_sdev_device(dev)) 116static void async_sdev_thaw(void *dev, async_cookie_t cookie)
75 err = scsi_dev_type_resume(dev, cb); 117{
118 scsi_dev_type_resume(dev, do_scsi_thaw);
119}
76 120
77 if (err == 0) { 121static void async_sdev_restore(void *dev, async_cookie_t cookie)
122{
123 scsi_dev_type_resume(dev, do_scsi_restore);
124}
125
126static int scsi_bus_resume_common(struct device *dev,
127 int (*cb)(struct device *, const struct dev_pm_ops *))
128{
129 async_func_t fn;
130
131 if (!scsi_is_sdev_device(dev))
132 fn = NULL;
133 else if (cb == do_scsi_resume)
134 fn = async_sdev_resume;
135 else if (cb == do_scsi_thaw)
136 fn = async_sdev_thaw;
137 else if (cb == do_scsi_restore)
138 fn = async_sdev_restore;
139 else
140 fn = NULL;
141
142 if (fn) {
143 async_schedule_domain(fn, dev, &scsi_sd_pm_domain);
144
145 /*
146 * If a user has disabled async probing a likely reason
147 * is due to a storage enclosure that does not inject
148 * staggered spin-ups. For safety, make resume
149 * synchronous as well in that case.
150 */
151 if (strncmp(scsi_scan_type, "async", 5) != 0)
152 async_synchronize_full_domain(&scsi_sd_pm_domain);
153 } else {
78 pm_runtime_disable(dev); 154 pm_runtime_disable(dev);
79 pm_runtime_set_active(dev); 155 pm_runtime_set_active(dev);
80 pm_runtime_enable(dev); 156 pm_runtime_enable(dev);
81 } 157 }
82 return err; 158 return 0;
83} 159}
84 160
85static int scsi_bus_prepare(struct device *dev) 161static int scsi_bus_prepare(struct device *dev)
@@ -97,38 +173,32 @@ static int scsi_bus_prepare(struct device *dev)
97 173
98static int scsi_bus_suspend(struct device *dev) 174static int scsi_bus_suspend(struct device *dev)
99{ 175{
100 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 176 return scsi_bus_suspend_common(dev, do_scsi_suspend);
101 return scsi_bus_suspend_common(dev, pm ? pm->suspend : NULL);
102} 177}
103 178
104static int scsi_bus_resume(struct device *dev) 179static int scsi_bus_resume(struct device *dev)
105{ 180{
106 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 181 return scsi_bus_resume_common(dev, do_scsi_resume);
107 return scsi_bus_resume_common(dev, pm ? pm->resume : NULL);
108} 182}
109 183
110static int scsi_bus_freeze(struct device *dev) 184static int scsi_bus_freeze(struct device *dev)
111{ 185{
112 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 186 return scsi_bus_suspend_common(dev, do_scsi_freeze);
113 return scsi_bus_suspend_common(dev, pm ? pm->freeze : NULL);
114} 187}
115 188
116static int scsi_bus_thaw(struct device *dev) 189static int scsi_bus_thaw(struct device *dev)
117{ 190{
118 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 191 return scsi_bus_resume_common(dev, do_scsi_thaw);
119 return scsi_bus_resume_common(dev, pm ? pm->thaw : NULL);
120} 192}
121 193
122static int scsi_bus_poweroff(struct device *dev) 194static int scsi_bus_poweroff(struct device *dev)
123{ 195{
124 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 196 return scsi_bus_suspend_common(dev, do_scsi_poweroff);
125 return scsi_bus_suspend_common(dev, pm ? pm->poweroff : NULL);
126} 197}
127 198
128static int scsi_bus_restore(struct device *dev) 199static int scsi_bus_restore(struct device *dev)
129{ 200{
130 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 201 return scsi_bus_resume_common(dev, do_scsi_restore);
131 return scsi_bus_resume_common(dev, pm ? pm->restore : NULL);
132} 202}
133 203
134#else /* CONFIG_PM_SLEEP */ 204#else /* CONFIG_PM_SLEEP */