blob: 88557e1e31619ed65d9c7ce7fabee89e779dd698 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001/*
2 * scsi_pm.c Copyright (C) 2010 Alan Stern
3 *
4 * SCSI dynamic Power Management
5 * Initial version: Alan Stern <stern@rowland.harvard.edu>
6 */
7
8#include <linux/pm_runtime.h>
9#include <linux/export.h>
10#include <linux/async.h>
11
12#include <scsi/scsi.h>
13#include <scsi/scsi_device.h>
14#include <scsi/scsi_driver.h>
15#include <scsi/scsi_host.h>
16
17#include "scsi_priv.h"
18
19static int do_scsi_runtime_resume(struct device *dev,
20 const struct dev_pm_ops *pm);
21
22#ifdef CONFIG_PM_SLEEP
23
24static int do_scsi_suspend(struct device *dev, const struct dev_pm_ops *pm)
25{
26 return pm && pm->suspend ? pm->suspend(dev) : 0;
27}
28
29static int do_scsi_freeze(struct device *dev, const struct dev_pm_ops *pm)
30{
31 return pm && pm->freeze ? pm->freeze(dev) : 0;
32}
33
34static int do_scsi_poweroff(struct device *dev, const struct dev_pm_ops *pm)
35{
36 return pm && pm->poweroff ? pm->poweroff(dev) : 0;
37}
38
39static int do_scsi_resume(struct device *dev, const struct dev_pm_ops *pm)
40{
41 return pm && pm->resume ? pm->resume(dev) : 0;
42}
43
44static int do_scsi_thaw(struct device *dev, const struct dev_pm_ops *pm)
45{
46 return pm && pm->thaw ? pm->thaw(dev) : 0;
47}
48
49static int do_scsi_restore(struct device *dev, const struct dev_pm_ops *pm)
50{
51 return pm && pm->restore ? pm->restore(dev) : 0;
52}
53
54static int scsi_dev_type_suspend(struct device *dev,
55 int (*cb)(struct device *, const struct dev_pm_ops *))
56{
57 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
58 int err;
59
60 /* flush pending in-flight resume operations, suspend is synchronous */
61 async_synchronize_full_domain(&scsi_sd_pm_domain);
62
63 err = scsi_device_quiesce(to_scsi_device(dev));
64 if (err == 0) {
65 err = cb(dev, pm);
66 if (err)
67 scsi_device_resume(to_scsi_device(dev));
68 }
69 dev_dbg(dev, "scsi suspend: %d\n", err);
70 return err;
71}
72
73static int scsi_dev_type_resume(struct device *dev,
74 int (*cb)(struct device *, const struct dev_pm_ops *))
75{
76 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
77 int err = 0;
78
79 err = cb(dev, pm);
80 scsi_device_resume(to_scsi_device(dev));
81 dev_dbg(dev, "scsi resume: %d\n", err);
82
83 if (err == 0 && (cb != do_scsi_runtime_resume)) {
84 pm_runtime_disable(dev);
85 err = pm_runtime_set_active(dev);
86 pm_runtime_enable(dev);
87
88 /*
89 * Forcibly set runtime PM status of request queue to "active"
90 * to make sure we can again get requests from the queue
91 * (see also blk_pm_peek_request()).
92 *
93 * The resume hook will correct runtime PM status of the disk.
94 */
95 if (!err && scsi_is_sdev_device(dev)) {
96 struct scsi_device *sdev = to_scsi_device(dev);
97
98 if (sdev->request_queue->dev)
99 blk_set_runtime_active(sdev->request_queue);
100 }
101 }
102
103 return err;
104}
105
106static int
107scsi_bus_suspend_common(struct device *dev,
108 int (*cb)(struct device *, const struct dev_pm_ops *))
109{
110 int err = 0;
111
112 if (scsi_is_sdev_device(dev)) {
113 /*
114 * All the high-level SCSI drivers that implement runtime
115 * PM treat runtime suspend, system suspend, and system
116 * hibernate nearly identically. In all cases the requirements
117 * for runtime suspension are stricter.
118 */
119 if (pm_runtime_suspended(dev))
120 return 0;
121
122 err = scsi_dev_type_suspend(dev, cb);
123 }
124
125 return err;
126}
127
128static void async_sdev_resume(void *dev, async_cookie_t cookie)
129{
130 scsi_dev_type_resume(dev, do_scsi_resume);
131}
132
133static void async_sdev_thaw(void *dev, async_cookie_t cookie)
134{
135 scsi_dev_type_resume(dev, do_scsi_thaw);
136}
137
138static void async_sdev_restore(void *dev, async_cookie_t cookie)
139{
140 scsi_dev_type_resume(dev, do_scsi_restore);
141}
142
143static int scsi_bus_resume_common(struct device *dev,
144 int (*cb)(struct device *, const struct dev_pm_ops *))
145{
146 async_func_t fn;
147
148 if (!scsi_is_sdev_device(dev))
149 fn = NULL;
150 else if (cb == do_scsi_resume)
151 fn = async_sdev_resume;
152 else if (cb == do_scsi_thaw)
153 fn = async_sdev_thaw;
154 else if (cb == do_scsi_restore)
155 fn = async_sdev_restore;
156 else
157 fn = NULL;
158
159 if (fn) {
160 async_schedule_domain(fn, dev, &scsi_sd_pm_domain);
161
162 /*
163 * If a user has disabled async probing a likely reason
164 * is due to a storage enclosure that does not inject
165 * staggered spin-ups. For safety, make resume
166 * synchronous as well in that case.
167 */
168 if (strncmp(scsi_scan_type, "async", 5) != 0)
169 async_synchronize_full_domain(&scsi_sd_pm_domain);
170 } else {
171 pm_runtime_disable(dev);
172 pm_runtime_set_active(dev);
173 pm_runtime_enable(dev);
174 }
175 return 0;
176}
177
178static int scsi_bus_prepare(struct device *dev)
179{
180 if (scsi_is_sdev_device(dev)) {
181 /* sd probing uses async_schedule. Wait until it finishes. */
182 async_synchronize_full_domain(&scsi_sd_probe_domain);
183
184 } else if (scsi_is_host_device(dev)) {
185 /* Wait until async scanning is finished */
186 scsi_complete_async_scans();
187 }
188 return 0;
189}
190
191static int scsi_bus_suspend(struct device *dev)
192{
193 return scsi_bus_suspend_common(dev, do_scsi_suspend);
194}
195
196static int scsi_bus_resume(struct device *dev)
197{
198 return scsi_bus_resume_common(dev, do_scsi_resume);
199}
200
201static int scsi_bus_freeze(struct device *dev)
202{
203 return scsi_bus_suspend_common(dev, do_scsi_freeze);
204}
205
206static int scsi_bus_thaw(struct device *dev)
207{
208 return scsi_bus_resume_common(dev, do_scsi_thaw);
209}
210
211static int scsi_bus_poweroff(struct device *dev)
212{
213 return scsi_bus_suspend_common(dev, do_scsi_poweroff);
214}
215
216static int scsi_bus_restore(struct device *dev)
217{
218 return scsi_bus_resume_common(dev, do_scsi_restore);
219}
220
221#else /* CONFIG_PM_SLEEP */
222
223#define scsi_bus_prepare NULL
224#define scsi_bus_suspend NULL
225#define scsi_bus_resume NULL
226#define scsi_bus_freeze NULL
227#define scsi_bus_thaw NULL
228#define scsi_bus_poweroff NULL
229#define scsi_bus_restore NULL
230
231static inline int
232scsi_dev_type_suspend(struct device *dev,
233 int (*cb)(struct device *, const struct dev_pm_ops *))
234{
235 return 0;
236}
237
238static inline int
239scsi_dev_type_resume(struct device *dev,
240 int (*cb)(struct device *, const struct dev_pm_ops *))
241{
242 return 0;
243}
244#endif /* CONFIG_PM_SLEEP */
245
246static int do_scsi_runtime_suspend(struct device *dev,
247 const struct dev_pm_ops *pm)
248{
249 return pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0;
250}
251
252static int do_scsi_runtime_resume(struct device *dev,
253 const struct dev_pm_ops *pm)
254{
255 return pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0;
256}
257
258static int sdev_runtime_suspend(struct device *dev)
259{
260 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
261 struct scsi_device *sdev = to_scsi_device(dev);
262 int err = 0;
263
264 if (!sdev->request_queue->dev) {
265 err = scsi_dev_type_suspend(dev, do_scsi_runtime_suspend);
266 if (err == -EAGAIN)
267 pm_schedule_suspend(dev, jiffies_to_msecs(
268 round_jiffies_up_relative(HZ/10)));
269 return err;
270 }
271
272 err = blk_pre_runtime_suspend(sdev->request_queue);
273 if (err)
274 return err;
275 if (pm && pm->runtime_suspend)
276 err = pm->runtime_suspend(dev);
277 blk_post_runtime_suspend(sdev->request_queue, err);
278
279 return err;
280}
281
282static int scsi_runtime_suspend(struct device *dev)
283{
284 int err = 0;
285
286 dev_dbg(dev, "scsi_runtime_suspend\n");
287 if (scsi_is_sdev_device(dev))
288 err = sdev_runtime_suspend(dev);
289
290 /* Insert hooks here for targets, hosts, and transport classes */
291
292 return err;
293}
294
295static int sdev_runtime_resume(struct device *dev)
296{
297 struct scsi_device *sdev = to_scsi_device(dev);
298 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
299 int err = 0;
300
301 if (!sdev->request_queue->dev)
302 return scsi_dev_type_resume(dev, do_scsi_runtime_resume);
303
304 blk_pre_runtime_resume(sdev->request_queue);
305 if (pm && pm->runtime_resume)
306 err = pm->runtime_resume(dev);
307 blk_post_runtime_resume(sdev->request_queue, err);
308
309 return err;
310}
311
312static int scsi_runtime_resume(struct device *dev)
313{
314 int err = 0;
315
316 dev_dbg(dev, "scsi_runtime_resume\n");
317 if (scsi_is_sdev_device(dev))
318 err = sdev_runtime_resume(dev);
319
320 /* Insert hooks here for targets, hosts, and transport classes */
321
322 return err;
323}
324
325static int scsi_runtime_idle(struct device *dev)
326{
327 dev_dbg(dev, "scsi_runtime_idle\n");
328
329 /* Insert hooks here for targets, hosts, and transport classes */
330
331 if (scsi_is_sdev_device(dev)) {
332 pm_runtime_mark_last_busy(dev);
333 pm_runtime_autosuspend(dev);
334 return -EBUSY;
335 }
336
337 return 0;
338}
339
340int scsi_autopm_get_device(struct scsi_device *sdev)
341{
342 int err;
343
344 err = pm_runtime_get_sync(&sdev->sdev_gendev);
345 if (err < 0 && err !=-EACCES)
346 pm_runtime_put_sync(&sdev->sdev_gendev);
347 else
348 err = 0;
349 return err;
350}
351EXPORT_SYMBOL_GPL(scsi_autopm_get_device);
352
353void scsi_autopm_put_device(struct scsi_device *sdev)
354{
355 pm_runtime_put_sync(&sdev->sdev_gendev);
356}
357EXPORT_SYMBOL_GPL(scsi_autopm_put_device);
358
359void scsi_autopm_get_target(struct scsi_target *starget)
360{
361 pm_runtime_get_sync(&starget->dev);
362}
363
364void scsi_autopm_put_target(struct scsi_target *starget)
365{
366 pm_runtime_put_sync(&starget->dev);
367}
368
369int scsi_autopm_get_host(struct Scsi_Host *shost)
370{
371 int err;
372
373 err = pm_runtime_get_sync(&shost->shost_gendev);
374 if (err < 0 && err !=-EACCES)
375 pm_runtime_put_sync(&shost->shost_gendev);
376 else
377 err = 0;
378 return err;
379}
380
381void scsi_autopm_put_host(struct Scsi_Host *shost)
382{
383 pm_runtime_put_sync(&shost->shost_gendev);
384}
385
386const struct dev_pm_ops scsi_bus_pm_ops = {
387 .prepare = scsi_bus_prepare,
388 .suspend = scsi_bus_suspend,
389 .resume = scsi_bus_resume,
390 .freeze = scsi_bus_freeze,
391 .thaw = scsi_bus_thaw,
392 .poweroff = scsi_bus_poweroff,
393 .restore = scsi_bus_restore,
394 .runtime_suspend = scsi_runtime_suspend,
395 .runtime_resume = scsi_runtime_resume,
396 .runtime_idle = scsi_runtime_idle,
397};