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