diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2010-06-16 14:52:17 -0400 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-28 10:07:50 -0400 |
| commit | 478a8a0543021172220feeb0b39bb1b3e43c988f (patch) | |
| tree | c80eb31436487294a43d23ad3869576a620fe1d3 | |
| parent | bc4f24014de58f045f169742701a6598884d93db (diff) | |
[SCSI] sd: add support for runtime PM
This patch (as1399) adds runtime-PM support to the sd driver. The
support is unsophisticated: If a SCSI disk device is mounted, or if
its device file is held open, then the device will not be
runtime-suspended; otherwise it will (provided userspace gives
permission by writing "auto" to the sysfs power/control attribute).
In order to make this work, a dev_set_drvdata() call had to be moved
from sd_probe_async() to sd_probe(). Also, a few lines of code were
changed to use a local variable instead of recalculating the address
of an embedded struct device.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
| -rw-r--r-- | drivers/scsi/sd.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8802e48bc063..cc8a1d1d915a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
| @@ -759,6 +759,10 @@ static int sd_open(struct block_device *bdev, fmode_t mode) | |||
| 759 | 759 | ||
| 760 | sdev = sdkp->device; | 760 | sdev = sdkp->device; |
| 761 | 761 | ||
| 762 | retval = scsi_autopm_get_device(sdev); | ||
| 763 | if (retval) | ||
| 764 | goto error_autopm; | ||
| 765 | |||
| 762 | /* | 766 | /* |
| 763 | * If the device is in error recovery, wait until it is done. | 767 | * If the device is in error recovery, wait until it is done. |
| 764 | * If the device is offline, then disallow any access to it. | 768 | * If the device is offline, then disallow any access to it. |
| @@ -803,6 +807,8 @@ static int sd_open(struct block_device *bdev, fmode_t mode) | |||
| 803 | return 0; | 807 | return 0; |
| 804 | 808 | ||
| 805 | error_out: | 809 | error_out: |
| 810 | scsi_autopm_put_device(sdev); | ||
| 811 | error_autopm: | ||
| 806 | scsi_disk_put(sdkp); | 812 | scsi_disk_put(sdkp); |
| 807 | return retval; | 813 | return retval; |
| 808 | } | 814 | } |
| @@ -834,6 +840,8 @@ static int sd_release(struct gendisk *disk, fmode_t mode) | |||
| 834 | * XXX and what if there are packets in flight and this close() | 840 | * XXX and what if there are packets in flight and this close() |
| 835 | * XXX is followed by a "rmmod sd_mod"? | 841 | * XXX is followed by a "rmmod sd_mod"? |
| 836 | */ | 842 | */ |
| 843 | |||
| 844 | scsi_autopm_put_device(sdev); | ||
| 837 | scsi_disk_put(sdkp); | 845 | scsi_disk_put(sdkp); |
| 838 | return 0; | 846 | return 0; |
| 839 | } | 847 | } |
| @@ -2232,7 +2240,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie) | |||
| 2232 | if (sdp->removable) | 2240 | if (sdp->removable) |
| 2233 | gd->flags |= GENHD_FL_REMOVABLE; | 2241 | gd->flags |= GENHD_FL_REMOVABLE; |
| 2234 | 2242 | ||
| 2235 | dev_set_drvdata(dev, sdkp); | ||
| 2236 | add_disk(gd); | 2243 | add_disk(gd); |
| 2237 | sd_dif_config_host(sdkp); | 2244 | sd_dif_config_host(sdkp); |
| 2238 | 2245 | ||
| @@ -2240,6 +2247,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) | |||
| 2240 | 2247 | ||
| 2241 | sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", | 2248 | sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", |
| 2242 | sdp->removable ? "removable " : ""); | 2249 | sdp->removable ? "removable " : ""); |
| 2250 | scsi_autopm_put_device(sdp); | ||
| 2243 | put_device(&sdkp->dev); | 2251 | put_device(&sdkp->dev); |
| 2244 | } | 2252 | } |
| 2245 | 2253 | ||
| @@ -2317,14 +2325,15 @@ static int sd_probe(struct device *dev) | |||
| 2317 | } | 2325 | } |
| 2318 | 2326 | ||
| 2319 | device_initialize(&sdkp->dev); | 2327 | device_initialize(&sdkp->dev); |
| 2320 | sdkp->dev.parent = &sdp->sdev_gendev; | 2328 | sdkp->dev.parent = dev; |
| 2321 | sdkp->dev.class = &sd_disk_class; | 2329 | sdkp->dev.class = &sd_disk_class; |
| 2322 | dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev)); | 2330 | dev_set_name(&sdkp->dev, dev_name(dev)); |
| 2323 | 2331 | ||
| 2324 | if (device_add(&sdkp->dev)) | 2332 | if (device_add(&sdkp->dev)) |
| 2325 | goto out_free_index; | 2333 | goto out_free_index; |
| 2326 | 2334 | ||
| 2327 | get_device(&sdp->sdev_gendev); | 2335 | get_device(dev); |
| 2336 | dev_set_drvdata(dev, sdkp); | ||
| 2328 | 2337 | ||
| 2329 | get_device(&sdkp->dev); /* prevent release before async_schedule */ | 2338 | get_device(&sdkp->dev); /* prevent release before async_schedule */ |
| 2330 | async_schedule(sd_probe_async, sdkp); | 2339 | async_schedule(sd_probe_async, sdkp); |
| @@ -2358,8 +2367,10 @@ static int sd_remove(struct device *dev) | |||
| 2358 | { | 2367 | { |
| 2359 | struct scsi_disk *sdkp; | 2368 | struct scsi_disk *sdkp; |
| 2360 | 2369 | ||
| 2361 | async_synchronize_full(); | ||
| 2362 | sdkp = dev_get_drvdata(dev); | 2370 | sdkp = dev_get_drvdata(dev); |
| 2371 | scsi_autopm_get_device(sdkp->device); | ||
| 2372 | |||
| 2373 | async_synchronize_full(); | ||
| 2363 | blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); | 2374 | blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); |
| 2364 | device_del(&sdkp->dev); | 2375 | device_del(&sdkp->dev); |
| 2365 | del_gendisk(sdkp->disk); | 2376 | del_gendisk(sdkp->disk); |
