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 static int scsi_dev_type_suspend(struct device
*dev
, int (*cb
)(struct device
*))
23 err
= scsi_device_quiesce(to_scsi_device(dev
));
28 scsi_device_resume(to_scsi_device(dev
));
31 dev_dbg(dev
, "scsi suspend: %d\n", err
);
35 static int scsi_dev_type_resume(struct device
*dev
, int (*cb
)(struct device
*))
41 scsi_device_resume(to_scsi_device(dev
));
42 dev_dbg(dev
, "scsi resume: %d\n", err
);
46 #ifdef CONFIG_PM_SLEEP
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 identically.
59 if (pm_runtime_suspended(dev
))
62 err
= scsi_dev_type_suspend(dev
, cb
);
69 scsi_bus_resume_common(struct device
*dev
, int (*cb
)(struct device
*))
73 if (scsi_is_sdev_device(dev
))
74 err
= scsi_dev_type_resume(dev
, cb
);
77 pm_runtime_disable(dev
);
78 pm_runtime_set_active(dev
);
79 pm_runtime_enable(dev
);
84 static int scsi_bus_prepare(struct device
*dev
)
86 if (scsi_is_sdev_device(dev
)) {
87 /* sd probing uses async_schedule. Wait until it finishes. */
88 async_synchronize_full_domain(&scsi_sd_probe_domain
);
90 } else if (scsi_is_host_device(dev
)) {
91 /* Wait until async scanning is finished */
92 scsi_complete_async_scans();
97 static int scsi_bus_suspend(struct device
*dev
)
99 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
100 return scsi_bus_suspend_common(dev
, pm
? pm
->suspend
: NULL
);
103 static int scsi_bus_resume(struct device
*dev
)
105 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
106 return scsi_bus_resume_common(dev
, pm
? pm
->resume
: NULL
);
109 static int scsi_bus_freeze(struct device
*dev
)
111 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
112 return scsi_bus_suspend_common(dev
, pm
? pm
->freeze
: NULL
);
115 static int scsi_bus_thaw(struct device
*dev
)
117 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
118 return scsi_bus_resume_common(dev
, pm
? pm
->thaw
: NULL
);
121 static int scsi_bus_poweroff(struct device
*dev
)
123 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
124 return scsi_bus_suspend_common(dev
, pm
? pm
->poweroff
: NULL
);
127 static int scsi_bus_restore(struct device
*dev
)
129 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
130 return scsi_bus_resume_common(dev
, pm
? pm
->restore
: NULL
);
133 #else /* CONFIG_PM_SLEEP */
135 #define scsi_bus_prepare NULL
136 #define scsi_bus_suspend NULL
137 #define scsi_bus_resume NULL
138 #define scsi_bus_freeze NULL
139 #define scsi_bus_thaw NULL
140 #define scsi_bus_poweroff NULL
141 #define scsi_bus_restore NULL
143 #endif /* CONFIG_PM_SLEEP */
145 #ifdef CONFIG_PM_RUNTIME
147 static int scsi_runtime_suspend(struct device
*dev
)
150 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
152 dev_dbg(dev
, "scsi_runtime_suspend\n");
153 if (scsi_is_sdev_device(dev
)) {
154 err
= scsi_dev_type_suspend(dev
,
155 pm
? pm
->runtime_suspend
: NULL
);
157 pm_schedule_suspend(dev
, jiffies_to_msecs(
158 round_jiffies_up_relative(HZ
/10)));
161 /* Insert hooks here for targets, hosts, and transport classes */
166 static int scsi_runtime_resume(struct device
*dev
)
169 const struct dev_pm_ops
*pm
= dev
->driver
? dev
->driver
->pm
: NULL
;
171 dev_dbg(dev
, "scsi_runtime_resume\n");
172 if (scsi_is_sdev_device(dev
))
173 err
= scsi_dev_type_resume(dev
, pm
? pm
->runtime_resume
: NULL
);
175 /* Insert hooks here for targets, hosts, and transport classes */
180 static int scsi_runtime_idle(struct device
*dev
)
184 dev_dbg(dev
, "scsi_runtime_idle\n");
186 /* Insert hooks here for targets, hosts, and transport classes */
188 if (scsi_is_sdev_device(dev
))
189 err
= pm_schedule_suspend(dev
, 100);
191 err
= pm_runtime_suspend(dev
);
195 int scsi_autopm_get_device(struct scsi_device
*sdev
)
199 err
= pm_runtime_get_sync(&sdev
->sdev_gendev
);
200 if (err
< 0 && err
!=-EACCES
)
201 pm_runtime_put_sync(&sdev
->sdev_gendev
);
206 EXPORT_SYMBOL_GPL(scsi_autopm_get_device
);
208 void scsi_autopm_put_device(struct scsi_device
*sdev
)
210 pm_runtime_put_sync(&sdev
->sdev_gendev
);
212 EXPORT_SYMBOL_GPL(scsi_autopm_put_device
);
214 void scsi_autopm_get_target(struct scsi_target
*starget
)
216 pm_runtime_get_sync(&starget
->dev
);
219 void scsi_autopm_put_target(struct scsi_target
*starget
)
221 pm_runtime_put_sync(&starget
->dev
);
224 int scsi_autopm_get_host(struct Scsi_Host
*shost
)
228 err
= pm_runtime_get_sync(&shost
->shost_gendev
);
229 if (err
< 0 && err
!=-EACCES
)
230 pm_runtime_put_sync(&shost
->shost_gendev
);
236 void scsi_autopm_put_host(struct Scsi_Host
*shost
)
238 pm_runtime_put_sync(&shost
->shost_gendev
);
243 #define scsi_runtime_suspend NULL
244 #define scsi_runtime_resume NULL
245 #define scsi_runtime_idle NULL
247 #endif /* CONFIG_PM_RUNTIME */
249 const struct dev_pm_ops scsi_bus_pm_ops
= {
250 .prepare
= scsi_bus_prepare
,
251 .suspend
= scsi_bus_suspend
,
252 .resume
= scsi_bus_resume
,
253 .freeze
= scsi_bus_freeze
,
254 .thaw
= scsi_bus_thaw
,
255 .poweroff
= scsi_bus_poweroff
,
256 .restore
= scsi_bus_restore
,
257 .runtime_suspend
= scsi_runtime_suspend
,
258 .runtime_resume
= scsi_runtime_resume
,
259 .runtime_idle
= scsi_runtime_idle
,