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