Branch data Line data Source code
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 : : 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 : : 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 : : 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 : : 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 : : 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 : : 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 : : 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 : : 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 : : bool was_runtime_suspended; 84 : : 85 : : was_runtime_suspended = pm_runtime_suspended(dev); 86 : : 87 : : pm_runtime_disable(dev); 88 : : err = pm_runtime_set_active(dev); 89 : : pm_runtime_enable(dev); 90 : : 91 : : /* 92 : : * Forcibly set runtime PM status of request queue to "active" 93 : : * to make sure we can again get requests from the queue 94 : : * (see also blk_pm_peek_request()). 95 : : * 96 : : * The resume hook will correct runtime PM status of the disk. 97 : : */ 98 : : if (!err && scsi_is_sdev_device(dev)) { 99 : : struct scsi_device *sdev = to_scsi_device(dev); 100 : : if (was_runtime_suspended) 101 : : blk_post_runtime_resume(sdev->request_queue, 0); 102 : : else 103 : : blk_set_runtime_active(sdev->request_queue); 104 : : } 105 : : } 106 : : 107 : : return err; 108 : : } 109 : : 110 : : static int 111 : : scsi_bus_suspend_common(struct device *dev, 112 : : int (*cb)(struct device *, const struct dev_pm_ops *)) 113 : : { 114 : : int err = 0; 115 : : 116 : : if (scsi_is_sdev_device(dev)) { 117 : : /* 118 : : * All the high-level SCSI drivers that implement runtime 119 : : * PM treat runtime suspend, system suspend, and system 120 : : * hibernate nearly identically. In all cases the requirements 121 : : * for runtime suspension are stricter. 122 : : */ 123 : : if (pm_runtime_suspended(dev)) 124 : : return 0; 125 : : 126 : : err = scsi_dev_type_suspend(dev, cb); 127 : : } 128 : : 129 : : return err; 130 : : } 131 : : 132 : : static void async_sdev_resume(void *dev, async_cookie_t cookie) 133 : : { 134 : : scsi_dev_type_resume(dev, do_scsi_resume); 135 : : } 136 : : 137 : : static void async_sdev_thaw(void *dev, async_cookie_t cookie) 138 : : { 139 : : scsi_dev_type_resume(dev, do_scsi_thaw); 140 : : } 141 : : 142 : : static void async_sdev_restore(void *dev, async_cookie_t cookie) 143 : : { 144 : : scsi_dev_type_resume(dev, do_scsi_restore); 145 : : } 146 : : 147 : : static int scsi_bus_resume_common(struct device *dev, 148 : : int (*cb)(struct device *, const struct dev_pm_ops *)) 149 : : { 150 : : async_func_t fn; 151 : : 152 : : if (!scsi_is_sdev_device(dev)) 153 : : fn = NULL; 154 : : else if (cb == do_scsi_resume) 155 : : fn = async_sdev_resume; 156 : : else if (cb == do_scsi_thaw) 157 : : fn = async_sdev_thaw; 158 : : else if (cb == do_scsi_restore) 159 : : fn = async_sdev_restore; 160 : : else 161 : : fn = NULL; 162 : : 163 : : if (fn) { 164 : : async_schedule_domain(fn, dev, &scsi_sd_pm_domain); 165 : : 166 : : /* 167 : : * If a user has disabled async probing a likely reason 168 : : * is due to a storage enclosure that does not inject 169 : : * staggered spin-ups. For safety, make resume 170 : : * synchronous as well in that case. 171 : : */ 172 : : if (strncmp(scsi_scan_type, "async", 5) != 0) 173 : : async_synchronize_full_domain(&scsi_sd_pm_domain); 174 : : } else { 175 : : pm_runtime_disable(dev); 176 : : pm_runtime_set_active(dev); 177 : : pm_runtime_enable(dev); 178 : : } 179 : : return 0; 180 : : } 181 : : 182 : : static int scsi_bus_prepare(struct device *dev) 183 : : { 184 : : if (scsi_is_host_device(dev)) { 185 : : /* Wait until async scanning is finished */ 186 : : scsi_complete_async_scans(); 187 : : } 188 : : return 0; 189 : : } 190 : : 191 : : static int scsi_bus_suspend(struct device *dev) 192 : : { 193 : : return scsi_bus_suspend_common(dev, do_scsi_suspend); 194 : : } 195 : : 196 : : static int scsi_bus_resume(struct device *dev) 197 : : { 198 : : return scsi_bus_resume_common(dev, do_scsi_resume); 199 : : } 200 : : 201 : : static int scsi_bus_freeze(struct device *dev) 202 : : { 203 : : return scsi_bus_suspend_common(dev, do_scsi_freeze); 204 : : } 205 : : 206 : : static int scsi_bus_thaw(struct device *dev) 207 : : { 208 : : return scsi_bus_resume_common(dev, do_scsi_thaw); 209 : : } 210 : : 211 : : static int scsi_bus_poweroff(struct device *dev) 212 : : { 213 : : return scsi_bus_suspend_common(dev, do_scsi_poweroff); 214 : : } 215 : : 216 : : static int scsi_bus_restore(struct device *dev) 217 : : { 218 : : return scsi_bus_resume_common(dev, do_scsi_restore); 219 : : } 220 : : 221 : : #else /* CONFIG_PM_SLEEP */ 222 : : 223 : : #define scsi_bus_prepare NULL 224 : : #define scsi_bus_suspend NULL 225 : : #define scsi_bus_resume NULL 226 : : #define scsi_bus_freeze NULL 227 : : #define scsi_bus_thaw NULL 228 : : #define scsi_bus_poweroff NULL 229 : : #define scsi_bus_restore NULL 230 : : 231 : : #endif /* CONFIG_PM_SLEEP */ 232 : : 233 : 0 : static int sdev_runtime_suspend(struct device *dev) 234 : : { 235 : 0 : const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 236 : : struct scsi_device *sdev = to_scsi_device(dev); 237 : : int err = 0; 238 : : 239 : 0 : err = blk_pre_runtime_suspend(sdev->request_queue); 240 : 0 : if (err) 241 : : return err; 242 : 0 : if (pm && pm->runtime_suspend) 243 : 0 : err = pm->runtime_suspend(dev); 244 : 0 : blk_post_runtime_suspend(sdev->request_queue, err); 245 : : 246 : 0 : return err; 247 : : } 248 : : 249 : 0 : static int scsi_runtime_suspend(struct device *dev) 250 : : { 251 : : int err = 0; 252 : : 253 : : dev_dbg(dev, "scsi_runtime_suspend\n"); 254 : 0 : if (scsi_is_sdev_device(dev)) 255 : 0 : err = sdev_runtime_suspend(dev); 256 : : 257 : : /* Insert hooks here for targets, hosts, and transport classes */ 258 : : 259 : 0 : return err; 260 : : } 261 : : 262 : 0 : static int sdev_runtime_resume(struct device *dev) 263 : : { 264 : : struct scsi_device *sdev = to_scsi_device(dev); 265 : 0 : const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 266 : : int err = 0; 267 : : 268 : 0 : blk_pre_runtime_resume(sdev->request_queue); 269 : 0 : if (pm && pm->runtime_resume) 270 : 0 : err = pm->runtime_resume(dev); 271 : 0 : blk_post_runtime_resume(sdev->request_queue, err); 272 : : 273 : 0 : return err; 274 : : } 275 : : 276 : 0 : static int scsi_runtime_resume(struct device *dev) 277 : : { 278 : : int err = 0; 279 : : 280 : : dev_dbg(dev, "scsi_runtime_resume\n"); 281 : 0 : if (scsi_is_sdev_device(dev)) 282 : 0 : err = sdev_runtime_resume(dev); 283 : : 284 : : /* Insert hooks here for targets, hosts, and transport classes */ 285 : : 286 : 0 : return err; 287 : : } 288 : : 289 : 0 : static int scsi_runtime_idle(struct device *dev) 290 : : { 291 : : dev_dbg(dev, "scsi_runtime_idle\n"); 292 : : 293 : : /* Insert hooks here for targets, hosts, and transport classes */ 294 : : 295 : 0 : if (scsi_is_sdev_device(dev)) { 296 : : pm_runtime_mark_last_busy(dev); 297 : : pm_runtime_autosuspend(dev); 298 : 0 : return -EBUSY; 299 : : } 300 : : 301 : : return 0; 302 : : } 303 : : 304 : 0 : int scsi_autopm_get_device(struct scsi_device *sdev) 305 : : { 306 : : int err; 307 : : 308 : 0 : err = pm_runtime_get_sync(&sdev->sdev_gendev); 309 : 0 : if (err < 0 && err !=-EACCES) 310 : : pm_runtime_put_sync(&sdev->sdev_gendev); 311 : : else 312 : : err = 0; 313 : 0 : return err; 314 : : } 315 : : EXPORT_SYMBOL_GPL(scsi_autopm_get_device); 316 : : 317 : 0 : void scsi_autopm_put_device(struct scsi_device *sdev) 318 : : { 319 : 0 : pm_runtime_put_sync(&sdev->sdev_gendev); 320 : 0 : } 321 : : EXPORT_SYMBOL_GPL(scsi_autopm_put_device); 322 : : 323 : 0 : void scsi_autopm_get_target(struct scsi_target *starget) 324 : : { 325 : 0 : pm_runtime_get_sync(&starget->dev); 326 : 0 : } 327 : : 328 : 0 : void scsi_autopm_put_target(struct scsi_target *starget) 329 : : { 330 : 0 : pm_runtime_put_sync(&starget->dev); 331 : 0 : } 332 : : 333 : 0 : int scsi_autopm_get_host(struct Scsi_Host *shost) 334 : : { 335 : : int err; 336 : : 337 : 0 : err = pm_runtime_get_sync(&shost->shost_gendev); 338 : 0 : if (err < 0 && err !=-EACCES) 339 : : pm_runtime_put_sync(&shost->shost_gendev); 340 : : else 341 : : err = 0; 342 : 0 : return err; 343 : : } 344 : : 345 : 0 : void scsi_autopm_put_host(struct Scsi_Host *shost) 346 : : { 347 : 0 : pm_runtime_put_sync(&shost->shost_gendev); 348 : 0 : } 349 : : 350 : : const struct dev_pm_ops scsi_bus_pm_ops = { 351 : : .prepare = scsi_bus_prepare, 352 : : .suspend = scsi_bus_suspend, 353 : : .resume = scsi_bus_resume, 354 : : .freeze = scsi_bus_freeze, 355 : : .thaw = scsi_bus_thaw, 356 : : .poweroff = scsi_bus_poweroff, 357 : : .restore = scsi_bus_restore, 358 : : .runtime_suspend = scsi_runtime_suspend, 359 : : .runtime_resume = scsi_runtime_resume, 360 : : .runtime_idle = scsi_runtime_idle, 361 : : };