Commit 478a8a05 authored by Alan Stern's avatar Alan Stern Committed by James Bottomley

[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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent bc4f2401
...@@ -759,6 +759,10 @@ static int sd_open(struct block_device *bdev, fmode_t mode) ...@@ -759,6 +759,10 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
sdev = sdkp->device; sdev = sdkp->device;
retval = scsi_autopm_get_device(sdev);
if (retval)
goto error_autopm;
/* /*
* If the device is in error recovery, wait until it is done. * If the device is in error recovery, wait until it is done.
* If the device is offline, then disallow any access to it. * 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,6 +807,8 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
return 0; return 0;
error_out: error_out:
scsi_autopm_put_device(sdev);
error_autopm:
scsi_disk_put(sdkp); scsi_disk_put(sdkp);
return retval; return retval;
} }
...@@ -834,6 +840,8 @@ static int sd_release(struct gendisk *disk, fmode_t mode) ...@@ -834,6 +840,8 @@ static int sd_release(struct gendisk *disk, fmode_t mode)
* XXX and what if there are packets in flight and this close() * XXX and what if there are packets in flight and this close()
* XXX is followed by a "rmmod sd_mod"? * XXX is followed by a "rmmod sd_mod"?
*/ */
scsi_autopm_put_device(sdev);
scsi_disk_put(sdkp); scsi_disk_put(sdkp);
return 0; return 0;
} }
...@@ -2232,7 +2240,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie) ...@@ -2232,7 +2240,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
if (sdp->removable) if (sdp->removable)
gd->flags |= GENHD_FL_REMOVABLE; gd->flags |= GENHD_FL_REMOVABLE;
dev_set_drvdata(dev, sdkp);
add_disk(gd); add_disk(gd);
sd_dif_config_host(sdkp); sd_dif_config_host(sdkp);
...@@ -2240,6 +2247,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) ...@@ -2240,6 +2247,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
sdp->removable ? "removable " : ""); sdp->removable ? "removable " : "");
scsi_autopm_put_device(sdp);
put_device(&sdkp->dev); put_device(&sdkp->dev);
} }
...@@ -2317,14 +2325,15 @@ static int sd_probe(struct device *dev) ...@@ -2317,14 +2325,15 @@ static int sd_probe(struct device *dev)
} }
device_initialize(&sdkp->dev); device_initialize(&sdkp->dev);
sdkp->dev.parent = &sdp->sdev_gendev; sdkp->dev.parent = dev;
sdkp->dev.class = &sd_disk_class; sdkp->dev.class = &sd_disk_class;
dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev)); dev_set_name(&sdkp->dev, dev_name(dev));
if (device_add(&sdkp->dev)) if (device_add(&sdkp->dev))
goto out_free_index; goto out_free_index;
get_device(&sdp->sdev_gendev); get_device(dev);
dev_set_drvdata(dev, sdkp);
get_device(&sdkp->dev); /* prevent release before async_schedule */ get_device(&sdkp->dev); /* prevent release before async_schedule */
async_schedule(sd_probe_async, sdkp); async_schedule(sd_probe_async, sdkp);
...@@ -2358,8 +2367,10 @@ static int sd_remove(struct device *dev) ...@@ -2358,8 +2367,10 @@ static int sd_remove(struct device *dev)
{ {
struct scsi_disk *sdkp; struct scsi_disk *sdkp;
async_synchronize_full();
sdkp = dev_get_drvdata(dev); sdkp = dev_get_drvdata(dev);
scsi_autopm_get_device(sdkp->device);
async_synchronize_full();
blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn);
device_del(&sdkp->dev); device_del(&sdkp->dev);
del_gendisk(sdkp->disk); del_gendisk(sdkp->disk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment