2 * scsi_pm.c Copyright (C) 2010 Alan Stern
4 * SCSI dynamic Power Management
5 * Initial version: Alan Stern <stern@rowland.harvard.edu>
8 #include <linux/pm_runtime.h>
9 #include <linux/export.h>
10 #include <linux/async.h>
12 #include <scsi/scsi.h>
13 #include <scsi/scsi_device.h>
14 #include <scsi/scsi_driver.h>
15 #include <scsi/scsi_host.h>
17 #include "scsi_priv.h"
19 #ifdef CONFIG_PM_SLEEP
21 static int scsi_dev_type_suspend(struct device
*dev
, int (*cb
)(struct device
*))
25 err
= scsi_device_quiesce(to_scsi_device(dev
));
30 scsi_device_resume(to_scsi_device(dev
));
33 dev_dbg(dev
, "scsi suspend: %d\n", err
);
37 static int scsi_dev_type_resume(struct device
*dev
, int (*cb
)(struct device
*))
43 scsi_device_resume(to_scsi_device(dev
));
44 dev_dbg(dev
, "scsi resume: %d\n", err
);
49 scsi_bus_suspend_common(struct device
*dev
, int (*cb
)(struct device
*))
53 if (scsi_is_sdev_device(dev
)) {
55 * All the high-level SCSI drivers that implement runtime
56 * PM treat runtime suspend, system suspend, and system
57 * hibernate nearly identically. In all cases the requirements
58 * for runtime suspension are stricter.
60 if (pm_runtime_suspended(dev
))
63 err
= scsi_dev_type_suspend(dev
, cb
);
70 scsi_bus_resume_common(struct device
*dev
, int (*cb
)(struct device
*))
74 if (scsi_is_sdev_device(dev
))
75 err
= scsi_dev_type_resume(dev
, cb
);
78 pm_runtime_disable(dev
);
79 pm_runtime_set_active(dev
);
80 pm_runtime_enable(dev
);
85 static int scsi_bus_prepare(struct device
*dev
)
87 if (scsi_is_sdev_device(dev
)) {
88 /* sd probing uses async_schedule. Wait until it finishes. */
89 async_synchronize_full_domain(&scsi_sd_probe_domain
);
91 } else if (scsi_is_host_device(dev
)) {
92 /* Wait until async scanning is finished */
93 scsi_complete_async_scans();
98 static int scsi_bus_suspend(struct device
*dev
)
100 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
101 return scsi_bus_suspend_common(dev
, pm
? pm
->suspend
: NULL
);
104 static int scsi_bus_resume(struct device
*dev
)
106 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
107 return scsi_bus_resume_common(dev
, pm
? pm
->resume
: NULL
);
110 static int scsi_bus_freeze(struct device
*dev
)
112 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
113 return scsi_bus_suspend_common(dev
, pm
? pm
->freeze
: NULL
);
116 static int scsi_bus_thaw(struct device
*dev
)
118 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
119 return scsi_bus_resume_common(dev
, pm
? pm
->thaw
: NULL
);
122 static int scsi_bus_poweroff(struct device
*dev
)
124 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
125 return scsi_bus_suspend_common(dev
, pm
? pm
->poweroff
: NULL
);
128 static int scsi_bus_restore(struct device
*dev
)
130 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
131 return scsi_bus_resume_common(dev
, pm
? pm
->restore
: NULL
);
134 #else /* CONFIG_PM_SLEEP */
136 #define scsi_bus_prepare NULL
137 #define scsi_bus_suspend NULL
138 #define scsi_bus_resume NULL
139 #define scsi_bus_freeze NULL
140 #define scsi_bus_thaw NULL
141 #define scsi_bus_poweroff NULL
142 #define scsi_bus_restore NULL
144 #endif /* CONFIG_PM_SLEEP */
146 #ifdef CONFIG_PM_RUNTIME
148 static int sdev_runtime_suspend(struct device
*dev
)
150 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
151 struct scsi_device
*sdev
= to_scsi_device(dev
);
154 err
= blk_pre_runtime_suspend(sdev
->request_queue
);
157 if (pm
&& pm
->runtime_suspend
)
158 err
= pm
->runtime_suspend(dev
);
159 blk_post_runtime_suspend(sdev
->request_queue
, err
);
164 static int scsi_runtime_suspend(struct device
*dev
)
168 dev_dbg(dev
, "scsi_runtime_suspend\n");
169 if (scsi_is_sdev_device(dev
))
170 err
= sdev_runtime_suspend(dev
);
172 /* Insert hooks here for targets, hosts, and transport classes */
177 static int sdev_runtime_resume(struct device
*dev
)
179 struct scsi_device
*sdev
= to_scsi_device(dev
);
180 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
183 blk_pre_runtime_resume(sdev
->request_queue
);
184 if (pm
&& pm
->runtime_resume
)
185 err
= pm
->runtime_resume(dev
);
186 blk_post_runtime_resume(sdev
->request_queue
, err
);
191 static int scsi_runtime_resume(struct device
*dev
)
195 dev_dbg(dev
, "scsi_runtime_resume\n");
196 if (scsi_is_sdev_device(dev
))
197 err
= sdev_runtime_resume(dev
);
199 /* Insert hooks here for targets, hosts, and transport classes */
204 static int scsi_runtime_idle(struct device
*dev
)
206 dev_dbg(dev
, "scsi_runtime_idle\n");
208 /* Insert hooks here for targets, hosts, and transport classes */
210 if (scsi_is_sdev_device(dev
)) {
211 pm_runtime_mark_last_busy(dev
);
212 pm_runtime_autosuspend(dev
);
219 int scsi_autopm_get_device(struct scsi_device
*sdev
)
223 err
= pm_runtime_get_sync(&sdev
->sdev_gendev
);
224 if (err
< 0 && err
!=-EACCES
)
225 pm_runtime_put_sync(&sdev
->sdev_gendev
);
230 EXPORT_SYMBOL_GPL(scsi_autopm_get_device
);
232 void scsi_autopm_put_device(struct scsi_device
*sdev
)
234 pm_runtime_put_sync(&sdev
->sdev_gendev
);
236 EXPORT_SYMBOL_GPL(scsi_autopm_put_device
);
238 void scsi_autopm_get_target(struct scsi_target
*starget
)
240 pm_runtime_get_sync(&starget
->dev
);
243 void scsi_autopm_put_target(struct scsi_target
*starget
)
245 pm_runtime_put_sync(&starget
->dev
);
248 int scsi_autopm_get_host(struct Scsi_Host
*shost
)
252 err
= pm_runtime_get_sync(&shost
->shost_gendev
);
253 if (err
< 0 && err
!=-EACCES
)
254 pm_runtime_put_sync(&shost
->shost_gendev
);
260 void scsi_autopm_put_host(struct Scsi_Host
*shost
)
262 pm_runtime_put_sync(&shost
->shost_gendev
);
267 #define scsi_runtime_suspend NULL
268 #define scsi_runtime_resume NULL
269 #define scsi_runtime_idle NULL
271 #endif /* CONFIG_PM_RUNTIME */
273 const struct dev_pm_ops scsi_bus_pm_ops
= {
274 .prepare
= scsi_bus_prepare
,
275 .suspend
= scsi_bus_suspend
,
276 .resume
= scsi_bus_resume
,
277 .freeze
= scsi_bus_freeze
,
278 .thaw
= scsi_bus_thaw
,
279 .poweroff
= scsi_bus_poweroff
,
280 .restore
= scsi_bus_restore
,
281 .runtime_suspend
= scsi_runtime_suspend
,
282 .runtime_resume
= scsi_runtime_resume
,
283 .runtime_idle
= scsi_runtime_idle
,