aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_pm.c
diff options
context:
space:
mode:
authorAaron Lu <aaron.lu@intel.com>2012-11-09 02:27:54 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-11-30 04:26:48 -0500
commit80d2fd48cca2a0de806c3130551744a04ad5b80b (patch)
tree93fd73939dde64143a8f381dba5eea72b486d684 /drivers/scsi/scsi_pm.c
parent9c31d8e1319e0d3f85673c7119a10700bf03f77a (diff)
[SCSI] scsi_pm: use callbacks from dev_pm_ops for scsi devices
Use of pm_message_t is deprecated and device driver is not supposed to use that. This patch migrates the SCSI bus level pm callbacks to call device's pm callbacks defined in its driver's dev_pm_ops. This is achieved by finding out which device pm callback should be used in bus callback function, and then pass that callback function pointer as a param to the scsi_bus_{suspend,resume}_common routine, which will further pass that callback to scsi_dev_type_{suspend,resume} after proper handling. The special case for freeze in scsi_bus_suspend_common is not necessary since there is no high level SCSI driver has implemented freeze, so no need to runtime resume the device if it is in runtime suspended state for system freeze, just return like the system suspend/hibernate case. Since only sd has implemented drv->suspend/drv->resume, and I'll update sd driver to use the new callbacks in the following patch, there is no need to fallback to call drv->suspend/drv->resume if dev_pm_ops is NULL. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/scsi_pm.c')
-rw-r--r--drivers/scsi/scsi_pm.c86
1 files changed, 53 insertions, 33 deletions
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index 9923b262263d..8f6b12cbd224 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -16,16 +16,14 @@
16 16
17#include "scsi_priv.h" 17#include "scsi_priv.h"
18 18
19static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg) 19static int scsi_dev_type_suspend(struct device *dev, int (*cb)(struct device *))
20{ 20{
21 struct device_driver *drv;
22 int err; 21 int err;
23 22
24 err = scsi_device_quiesce(to_scsi_device(dev)); 23 err = scsi_device_quiesce(to_scsi_device(dev));
25 if (err == 0) { 24 if (err == 0) {
26 drv = dev->driver; 25 if (cb) {
27 if (drv && drv->suspend) { 26 err = cb(dev);
28 err = drv->suspend(dev, msg);
29 if (err) 27 if (err)
30 scsi_device_resume(to_scsi_device(dev)); 28 scsi_device_resume(to_scsi_device(dev));
31 } 29 }
@@ -34,14 +32,12 @@ static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg)
34 return err; 32 return err;
35} 33}
36 34
37static int scsi_dev_type_resume(struct device *dev) 35static int scsi_dev_type_resume(struct device *dev, int (*cb)(struct device *))
38{ 36{
39 struct device_driver *drv;
40 int err = 0; 37 int err = 0;
41 38
42 drv = dev->driver; 39 if (cb)
43 if (drv && drv->resume) 40 err = cb(dev);
44 err = drv->resume(dev);
45 scsi_device_resume(to_scsi_device(dev)); 41 scsi_device_resume(to_scsi_device(dev));
46 dev_dbg(dev, "scsi resume: %d\n", err); 42 dev_dbg(dev, "scsi resume: %d\n", err);
47 return err; 43 return err;
@@ -49,35 +45,33 @@ static int scsi_dev_type_resume(struct device *dev)
49 45
50#ifdef CONFIG_PM_SLEEP 46#ifdef CONFIG_PM_SLEEP
51 47
52static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg) 48static int
49scsi_bus_suspend_common(struct device *dev, int (*cb)(struct device *))
53{ 50{
54 int err = 0; 51 int err = 0;
55 52
56 if (scsi_is_sdev_device(dev)) { 53 if (scsi_is_sdev_device(dev)) {
57 /* 54 /*
58 * sd is the only high-level SCSI driver to implement runtime 55 * All the high-level SCSI drivers that implement runtime
59 * PM, and sd treats runtime suspend, system suspend, and 56 * PM treat runtime suspend, system suspend, and system
60 * system hibernate identically (but not system freeze). 57 * hibernate identically.
61 */ 58 */
62 if (pm_runtime_suspended(dev)) { 59 if (pm_runtime_suspended(dev))
63 if (msg.event == PM_EVENT_SUSPEND || 60 return 0;
64 msg.event == PM_EVENT_HIBERNATE)
65 return 0; /* already suspended */
66 61
67 /* wake up device so that FREEZE will succeed */ 62 err = scsi_dev_type_suspend(dev, cb);
68 pm_runtime_resume(dev);
69 }
70 err = scsi_dev_type_suspend(dev, msg);
71 } 63 }
64
72 return err; 65 return err;
73} 66}
74 67
75static int scsi_bus_resume_common(struct device *dev) 68static int
69scsi_bus_resume_common(struct device *dev, int (*cb)(struct device *))
76{ 70{
77 int err = 0; 71 int err = 0;
78 72
79 if (scsi_is_sdev_device(dev)) 73 if (scsi_is_sdev_device(dev))
80 err = scsi_dev_type_resume(dev); 74 err = scsi_dev_type_resume(dev, cb);
81 75
82 if (err == 0) { 76 if (err == 0) {
83 pm_runtime_disable(dev); 77 pm_runtime_disable(dev);
@@ -102,26 +96,49 @@ static int scsi_bus_prepare(struct device *dev)
102 96
103static int scsi_bus_suspend(struct device *dev) 97static int scsi_bus_suspend(struct device *dev)
104{ 98{
105 return scsi_bus_suspend_common(dev, PMSG_SUSPEND); 99 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
100 return scsi_bus_suspend_common(dev, pm ? pm->suspend : NULL);
101}
102
103static int scsi_bus_resume(struct device *dev)
104{
105 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
106 return scsi_bus_resume_common(dev, pm ? pm->resume : NULL);
106} 107}
107 108
108static int scsi_bus_freeze(struct device *dev) 109static int scsi_bus_freeze(struct device *dev)
109{ 110{
110 return scsi_bus_suspend_common(dev, PMSG_FREEZE); 111 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
112 return scsi_bus_suspend_common(dev, pm ? pm->freeze : NULL);
113}
114
115static int scsi_bus_thaw(struct device *dev)
116{
117 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
118 return scsi_bus_resume_common(dev, pm ? pm->thaw : NULL);
111} 119}
112 120
113static int scsi_bus_poweroff(struct device *dev) 121static int scsi_bus_poweroff(struct device *dev)
114{ 122{
115 return scsi_bus_suspend_common(dev, PMSG_HIBERNATE); 123 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
124 return scsi_bus_suspend_common(dev, pm ? pm->poweroff : NULL);
125}
126
127static int scsi_bus_restore(struct device *dev)
128{
129 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
130 return scsi_bus_resume_common(dev, pm ? pm->restore : NULL);
116} 131}
117 132
118#else /* CONFIG_PM_SLEEP */ 133#else /* CONFIG_PM_SLEEP */
119 134
120#define scsi_bus_resume_common NULL
121#define scsi_bus_prepare NULL 135#define scsi_bus_prepare NULL
122#define scsi_bus_suspend NULL 136#define scsi_bus_suspend NULL
137#define scsi_bus_resume NULL
123#define scsi_bus_freeze NULL 138#define scsi_bus_freeze NULL
139#define scsi_bus_thaw NULL
124#define scsi_bus_poweroff NULL 140#define scsi_bus_poweroff NULL
141#define scsi_bus_restore NULL
125 142
126#endif /* CONFIG_PM_SLEEP */ 143#endif /* CONFIG_PM_SLEEP */
127 144
@@ -130,10 +147,12 @@ static int scsi_bus_poweroff(struct device *dev)
130static int scsi_runtime_suspend(struct device *dev) 147static int scsi_runtime_suspend(struct device *dev)
131{ 148{
132 int err = 0; 149 int err = 0;
150 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
133 151
134 dev_dbg(dev, "scsi_runtime_suspend\n"); 152 dev_dbg(dev, "scsi_runtime_suspend\n");
135 if (scsi_is_sdev_device(dev)) { 153 if (scsi_is_sdev_device(dev)) {
136 err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND); 154 err = scsi_dev_type_suspend(dev,
155 pm ? pm->runtime_suspend : NULL);
137 if (err == -EAGAIN) 156 if (err == -EAGAIN)
138 pm_schedule_suspend(dev, jiffies_to_msecs( 157 pm_schedule_suspend(dev, jiffies_to_msecs(
139 round_jiffies_up_relative(HZ/10))); 158 round_jiffies_up_relative(HZ/10)));
@@ -147,10 +166,11 @@ static int scsi_runtime_suspend(struct device *dev)
147static int scsi_runtime_resume(struct device *dev) 166static int scsi_runtime_resume(struct device *dev)
148{ 167{
149 int err = 0; 168 int err = 0;
169 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
150 170
151 dev_dbg(dev, "scsi_runtime_resume\n"); 171 dev_dbg(dev, "scsi_runtime_resume\n");
152 if (scsi_is_sdev_device(dev)) 172 if (scsi_is_sdev_device(dev))
153 err = scsi_dev_type_resume(dev); 173 err = scsi_dev_type_resume(dev, pm ? pm->runtime_resume : NULL);
154 174
155 /* Insert hooks here for targets, hosts, and transport classes */ 175 /* Insert hooks here for targets, hosts, and transport classes */
156 176
@@ -229,11 +249,11 @@ void scsi_autopm_put_host(struct Scsi_Host *shost)
229const struct dev_pm_ops scsi_bus_pm_ops = { 249const struct dev_pm_ops scsi_bus_pm_ops = {
230 .prepare = scsi_bus_prepare, 250 .prepare = scsi_bus_prepare,
231 .suspend = scsi_bus_suspend, 251 .suspend = scsi_bus_suspend,
232 .resume = scsi_bus_resume_common, 252 .resume = scsi_bus_resume,
233 .freeze = scsi_bus_freeze, 253 .freeze = scsi_bus_freeze,
234 .thaw = scsi_bus_resume_common, 254 .thaw = scsi_bus_thaw,
235 .poweroff = scsi_bus_poweroff, 255 .poweroff = scsi_bus_poweroff,
236 .restore = scsi_bus_resume_common, 256 .restore = scsi_bus_restore,
237 .runtime_suspend = scsi_runtime_suspend, 257 .runtime_suspend = scsi_runtime_suspend,
238 .runtime_resume = scsi_runtime_resume, 258 .runtime_resume = scsi_runtime_resume,
239 .runtime_idle = scsi_runtime_idle, 259 .runtime_idle = scsi_runtime_idle,