1 /* 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 19 #ifdef CONFIG_PM_SLEEP 20 21 static int scsi_dev_type_suspend(struct device *dev, int (*cb)(struct device *)) 22 { 23 int err; 24 25 err = scsi_device_quiesce(to_scsi_device(dev)); 26 if (err == 0) { 27 if (cb) { 28 err = cb(dev); 29 if (err) 30 scsi_device_resume(to_scsi_device(dev)); 31 } 32 } 33 dev_dbg(dev, "scsi suspend: %d\n", err); 34 return err; 35 } 36 37 static int scsi_dev_type_resume(struct device *dev, int (*cb)(struct device *)) 38 { 39 int err = 0; 40 41 if (cb) 42 err = cb(dev); 43 scsi_device_resume(to_scsi_device(dev)); 44 dev_dbg(dev, "scsi resume: %d\n", err); 45 return err; 46 } 47 48 static int 49 scsi_bus_suspend_common(struct device *dev, int (*cb)(struct device *)) 50 { 51 int err = 0; 52 53 if (scsi_is_sdev_device(dev)) { 54 /* 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. 59 */ 60 if (pm_runtime_suspended(dev)) 61 return 0; 62 63 err = scsi_dev_type_suspend(dev, cb); 64 } 65 66 return err; 67 } 68 69 static int 70 scsi_bus_resume_common(struct device *dev, int (*cb)(struct device *)) 71 { 72 int err = 0; 73 74 if (scsi_is_sdev_device(dev)) 75 err = scsi_dev_type_resume(dev, cb); 76 77 if (err == 0) { 78 pm_runtime_disable(dev); 79 pm_runtime_set_active(dev); 80 pm_runtime_enable(dev); 81 } 82 return err; 83 } 84 85 static int scsi_bus_prepare(struct device *dev) 86 { 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); 90 91 } else if (scsi_is_host_device(dev)) { 92 /* Wait until async scanning is finished */ 93 scsi_complete_async_scans(); 94 } 95 return 0; 96 } 97 98 static int scsi_bus_suspend(struct device *dev) 99 { 100 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 101 return scsi_bus_suspend_common(dev, pm ? pm->suspend : NULL); 102 } 103 104 static int scsi_bus_resume(struct device *dev) 105 { 106 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 107 return scsi_bus_resume_common(dev, pm ? pm->resume : NULL); 108 } 109 110 static int scsi_bus_freeze(struct device *dev) 111 { 112 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 113 return scsi_bus_suspend_common(dev, pm ? pm->freeze : NULL); 114 } 115 116 static int scsi_bus_thaw(struct device *dev) 117 { 118 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 119 return scsi_bus_resume_common(dev, pm ? pm->thaw : NULL); 120 } 121 122 static int scsi_bus_poweroff(struct device *dev) 123 { 124 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 125 return scsi_bus_suspend_common(dev, pm ? pm->poweroff : NULL); 126 } 127 128 static int scsi_bus_restore(struct device *dev) 129 { 130 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 131 return scsi_bus_resume_common(dev, pm ? pm->restore : NULL); 132 } 133 134 #else /* CONFIG_PM_SLEEP */ 135 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 143 144 #endif /* CONFIG_PM_SLEEP */ 145 146 #ifdef CONFIG_PM_RUNTIME 147 148 static int sdev_runtime_suspend(struct device *dev) 149 { 150 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 151 struct scsi_device *sdev = to_scsi_device(dev); 152 int err; 153 154 err = blk_pre_runtime_suspend(sdev->request_queue); 155 if (err) 156 return err; 157 if (pm && pm->runtime_suspend) 158 err = pm->runtime_suspend(dev); 159 blk_post_runtime_suspend(sdev->request_queue, err); 160 161 return err; 162 } 163 164 static int scsi_runtime_suspend(struct device *dev) 165 { 166 int err = 0; 167 168 dev_dbg(dev, "scsi_runtime_suspend\n"); 169 if (scsi_is_sdev_device(dev)) 170 err = sdev_runtime_suspend(dev); 171 172 /* Insert hooks here for targets, hosts, and transport classes */ 173 174 return err; 175 } 176 177 static int sdev_runtime_resume(struct device *dev) 178 { 179 struct scsi_device *sdev = to_scsi_device(dev); 180 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 181 int err = 0; 182 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); 187 188 return err; 189 } 190 191 static int scsi_runtime_resume(struct device *dev) 192 { 193 int err = 0; 194 195 dev_dbg(dev, "scsi_runtime_resume\n"); 196 if (scsi_is_sdev_device(dev)) 197 err = sdev_runtime_resume(dev); 198 199 /* Insert hooks here for targets, hosts, and transport classes */ 200 201 return err; 202 } 203 204 static int scsi_runtime_idle(struct device *dev) 205 { 206 dev_dbg(dev, "scsi_runtime_idle\n"); 207 208 /* Insert hooks here for targets, hosts, and transport classes */ 209 210 if (scsi_is_sdev_device(dev)) { 211 pm_runtime_mark_last_busy(dev); 212 pm_runtime_autosuspend(dev); 213 return -EBUSY; 214 } 215 216 return 0; 217 } 218 219 int scsi_autopm_get_device(struct scsi_device *sdev) 220 { 221 int err; 222 223 err = pm_runtime_get_sync(&sdev->sdev_gendev); 224 if (err < 0 && err !=-EACCES) 225 pm_runtime_put_sync(&sdev->sdev_gendev); 226 else 227 err = 0; 228 return err; 229 } 230 EXPORT_SYMBOL_GPL(scsi_autopm_get_device); 231 232 void scsi_autopm_put_device(struct scsi_device *sdev) 233 { 234 pm_runtime_put_sync(&sdev->sdev_gendev); 235 } 236 EXPORT_SYMBOL_GPL(scsi_autopm_put_device); 237 238 void scsi_autopm_get_target(struct scsi_target *starget) 239 { 240 pm_runtime_get_sync(&starget->dev); 241 } 242 243 void scsi_autopm_put_target(struct scsi_target *starget) 244 { 245 pm_runtime_put_sync(&starget->dev); 246 } 247 248 int scsi_autopm_get_host(struct Scsi_Host *shost) 249 { 250 int err; 251 252 err = pm_runtime_get_sync(&shost->shost_gendev); 253 if (err < 0 && err !=-EACCES) 254 pm_runtime_put_sync(&shost->shost_gendev); 255 else 256 err = 0; 257 return err; 258 } 259 260 void scsi_autopm_put_host(struct Scsi_Host *shost) 261 { 262 pm_runtime_put_sync(&shost->shost_gendev); 263 } 264 265 #else 266 267 #define scsi_runtime_suspend NULL 268 #define scsi_runtime_resume NULL 269 #define scsi_runtime_idle NULL 270 271 #endif /* CONFIG_PM_RUNTIME */ 272 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, 284 }; 285