aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_sysfs.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-06-17 10:41:42 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-28 10:07:50 -0400
commitbc4f24014de58f045f169742701a6598884d93db (patch)
tree4e68ae6fa5fff179ce69b2d890b01a5fcc9c55d5 /drivers/scsi/scsi_sysfs.c
parentdb5bd1e0b505c54ff492172ce4abc245cf6cd639 (diff)
[SCSI] implement runtime Power Management
This patch (as1398b) adds runtime PM support to the SCSI layer. Only the machanism is provided; use of it is up to the various high-level drivers, and the patch doesn't change any of them. Except for sg -- the patch expicitly prevents a device from being runtime-suspended while its sg device file is open. The implementation is simplistic. In general, hosts and targets are automatically suspended when all their children are asleep, but for them the runtime-suspend code doesn't actually do anything. (A host's runtime PM status is propagated up the device tree, though, so a runtime-PM-aware lower-level driver could power down the host adapter hardware at the appropriate times.) There are comments indicating where a transport class might be notified or some other hooks added. LUNs are runtime-suspended by calling the drivers' existing suspend handlers (and likewise for runtime-resume). Somewhat arbitrarily, the implementation delays for 100 ms before suspending an eligible LUN. This is because there typically are occasions during bootup when the same device file is opened and closed several times in quick succession. The way this all works is that the SCSI core increments a device's PM-usage count when it is registered. If a high-level driver does nothing then the device will not be eligible for runtime-suspend because of the elevated usage count. If a high-level driver wants to use runtime PM then it can call scsi_autopm_put_device() in its probe routine to decrement the usage count and scsi_autopm_get_device() in its remove routine to restore the original count. Hosts, targets, and LUNs are not suspended while they are being probed or removed, or while the error handler is running. In fact, a fairly large part of the patch consists of code to make sure that things aren't suspended at such times. [jejb: fix up compile issues in PM config variations] Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/scsi_sysfs.c')
-rw-r--r--drivers/scsi/scsi_sysfs.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5f85f8e831f3..562fb3bce261 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -11,6 +11,7 @@
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/blkdev.h> 12#include <linux/blkdev.h>
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/pm_runtime.h>
14 15
15#include <scsi/scsi.h> 16#include <scsi/scsi.h>
16#include <scsi/scsi_device.h> 17#include <scsi/scsi_device.h>
@@ -802,8 +803,6 @@ static int scsi_target_add(struct scsi_target *starget)
802 if (starget->state != STARGET_CREATED) 803 if (starget->state != STARGET_CREATED)
803 return 0; 804 return 0;
804 805
805 device_enable_async_suspend(&starget->dev);
806
807 error = device_add(&starget->dev); 806 error = device_add(&starget->dev);
808 if (error) { 807 if (error) {
809 dev_err(&starget->dev, "target device_add failed, error %d\n", error); 808 dev_err(&starget->dev, "target device_add failed, error %d\n", error);
@@ -812,6 +811,10 @@ static int scsi_target_add(struct scsi_target *starget)
812 transport_add_device(&starget->dev); 811 transport_add_device(&starget->dev);
813 starget->state = STARGET_RUNNING; 812 starget->state = STARGET_RUNNING;
814 813
814 pm_runtime_set_active(&starget->dev);
815 pm_runtime_enable(&starget->dev);
816 device_enable_async_suspend(&starget->dev);
817
815 return 0; 818 return 0;
816} 819}
817 820
@@ -841,7 +844,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
841 return error; 844 return error;
842 845
843 transport_configure_device(&starget->dev); 846 transport_configure_device(&starget->dev);
847
844 device_enable_async_suspend(&sdev->sdev_gendev); 848 device_enable_async_suspend(&sdev->sdev_gendev);
849 scsi_autopm_get_target(starget);
850 pm_runtime_set_active(&sdev->sdev_gendev);
851 pm_runtime_forbid(&sdev->sdev_gendev);
852 pm_runtime_enable(&sdev->sdev_gendev);
853 scsi_autopm_put_target(starget);
854
855 /* The following call will keep sdev active indefinitely, until
856 * its driver does a corresponding scsi_autopm_pm_device(). Only
857 * drivers supporting autosuspend will do this.
858 */
859 scsi_autopm_get_device(sdev);
860
845 error = device_add(&sdev->sdev_gendev); 861 error = device_add(&sdev->sdev_gendev);
846 if (error) { 862 if (error) {
847 printk(KERN_INFO "error 1\n"); 863 printk(KERN_INFO "error 1\n");