From 356fd2663cff131fb9db573a3e45830778cfdbdd Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 18 Feb 2016 10:54:12 +0200 Subject: scsi: Set request queue runtime PM status back to active on resume We treat system suspend of SCSI devices pretty much the same as runtime suspend. If the device is already runtime suspended we leave it to that state during system suspend. On resume from system sleep we then resume the device and correct the runtime PM status back to "active". There is a problem with this because runtime PM status of the request queue in question is not changed (it will be in "suspended" state). When SCSI disk driver (sd.c) resumes the disk it sends START message to the device and because the request queue is still in "suspended" state blk_pm_peek_request() returns NULL preventing resume of the disk. The issue can be reproduced with following commands: # echo auto > /sys/block/sda/device/power/control # echo 15000 > /sys/block/sda/device/power/autosuspend_delay_ms [ 57.191706] sd 0:0:0:0: [sda] Synchronizing SCSI cache [ 57.380015] sd 0:0:0:0: [sda] Stopping disk Now suspend the machine: # rtcwake -s10 -mmem This ends up in soft lockup because resume is not proceeding accordingly and userspace is never restarted. Also there is nothing printed to the console. Fix this by forcing request queue status to "active" before the disk is resumed. Signed-off-by: Mika Westerberg Signed-off-by: Tejun Heo --- drivers/scsi/scsi_pm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 459abe1dcc87..b44c1bb687a2 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -139,6 +139,16 @@ static int scsi_bus_resume_common(struct device *dev, else fn = NULL; + /* + * Forcibly set runtime PM status of request queue to "active" to + * make sure we can again get requests from the queue (see also + * blk_pm_peek_request()). + * + * The resume hook will correct runtime PM status of the disk. + */ + if (scsi_is_sdev_device(dev) && pm_runtime_suspended(dev)) + blk_set_runtime_active(to_scsi_device(dev)->request_queue); + if (fn) { async_schedule_domain(fn, dev, &scsi_sd_pm_domain); -- cgit v1.2.3 From 5c6fab9d558470b4e53c6d113f7dbcb31049ffc5 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 18 Feb 2016 10:54:13 +0200 Subject: scsi: Drop runtime PM usage count after host is added Runtime PM of the SCSI host is already handled by calls to scsi_autopm_get_host() and scsi_autopm_put_host() from appropriate places whenever the host needs to be powered on. This works fine when there is device connected to the host as once it runtime suspends the host will too. However, if there is no device connected the host is never runtime suspended (the usage counter is always 0). Allow runtime suspend of host even if it has no devices connected by calling scsi_autopm_put_host() at the end of scsi_add_host_with_dma(). We temporarily increase runtime PM usage counter first so call to scsi_autopm_put_host() will result idle request to be scheduled for the device. Signed-off-by: Mika Westerberg Signed-off-by: Tejun Heo --- drivers/scsi/hosts.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 82ac1cd818ac..e46bf4d152a0 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -250,6 +250,12 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, if (error) goto out_destroy_freelist; + /* + * Increase usage count temporarily here so that calling + * scsi_autopm_put_host() will trigger runtime idle if there is + * nothing else preventing suspending the device. + */ + pm_runtime_get_noresume(&shost->shost_gendev); pm_runtime_set_active(&shost->shost_gendev); pm_runtime_enable(&shost->shost_gendev); device_enable_async_suspend(&shost->shost_gendev); @@ -290,6 +296,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, goto out_destroy_host; scsi_proc_host_add(shost); + scsi_autopm_put_host(shost); return error; out_destroy_host: -- cgit v1.2.3