diff options
Diffstat (limited to 'drivers/scsi/scsi_pm.c')
-rw-r--r-- | drivers/scsi/scsi_pm.c | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 459abe1dcc87..243b2d13fa0d 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -16,6 +16,9 @@ #include "scsi_priv.h" +static int do_scsi_runtime_resume(struct device *dev, + const struct dev_pm_ops *pm); + #ifdef CONFIG_PM_SLEEP static int do_scsi_suspend(struct device *dev, const struct dev_pm_ops *pm) @@ -77,10 +80,22 @@ static int scsi_dev_type_resume(struct device *dev, scsi_device_resume(to_scsi_device(dev)); dev_dbg(dev, "scsi resume: %d\n", err); - if (err == 0) { + if (err == 0 && (cb != do_scsi_runtime_resume)) { pm_runtime_disable(dev); - pm_runtime_set_active(dev); + err = pm_runtime_set_active(dev); pm_runtime_enable(dev); + + if (!err && scsi_is_sdev_device(dev)) { + struct scsi_device *sdev = to_scsi_device(dev); + + /* + * If scsi device runtime PM is managed by block layer + * then we should update request queue's runtime status + * as well. + */ + if (sdev->request_queue->dev) + blk_post_runtime_resume(sdev->request_queue, 0); + } } return err; @@ -213,12 +228,32 @@ static int scsi_bus_restore(struct device *dev) #endif /* CONFIG_PM_SLEEP */ +static int do_scsi_runtime_suspend(struct device *dev, + const struct dev_pm_ops *pm) +{ + return pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0; +} + +static int do_scsi_runtime_resume(struct device *dev, + const struct dev_pm_ops *pm) +{ + return pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0; +} + static int sdev_runtime_suspend(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; struct scsi_device *sdev = to_scsi_device(dev); int err = 0; + if (!sdev->request_queue->dev) { + err = scsi_dev_type_suspend(dev, do_scsi_runtime_suspend); + if (err == -EAGAIN) + pm_schedule_suspend(dev, jiffies_to_msecs( + round_jiffies_up_relative(HZ/10))); + return err; + } + err = blk_pre_runtime_suspend(sdev->request_queue); if (err) return err; @@ -248,6 +283,9 @@ static int sdev_runtime_resume(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int err = 0; + if (!sdev->request_queue->dev) + return scsi_dev_type_resume(dev, do_scsi_runtime_resume); + blk_pre_runtime_resume(sdev->request_queue); if (pm && pm->runtime_resume) err = pm->runtime_resume(dev); |