Skip to content

Commit

Permalink
[SCSI] sr: support runtime pm
Browse files Browse the repository at this point in the history
This patch adds runtime pm support for sr.

It did this by increasing the runtime usage_count of the device when
its block device is accessed. And decreasing the runtime usage_count
of the device when the access is done.

If there is media inside, runtime suspend is not allowed as we don't
always know if the ODD is being used or not.

The idea is discussed here:
http://thread.gmane.org/gmane.linux.acpi.devel/55243/focus=52703
and the restriction to check media inside is discussed here:
http://thread.gmane.org/gmane.linux.ide/53665/focus=58836

Signed-off-by: Aaron Lu <aaron.lu@intel.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
  • Loading branch information
Aaron Lu authored and Jeff Garzik committed Jan 25, 2013
1 parent 29e674d commit 6c7f1e2
Showing 1 changed file with 39 additions and 3 deletions.
42 changes: 39 additions & 3 deletions drivers/scsi/sr.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <asm/uaccess.h>

#include <scsi/scsi.h>
Expand Down Expand Up @@ -79,13 +80,19 @@ static DEFINE_MUTEX(sr_mutex);
static int sr_probe(struct device *);
static int sr_remove(struct device *);
static int sr_done(struct scsi_cmnd *);
static int sr_runtime_suspend(struct device *dev);

static struct dev_pm_ops sr_pm_ops = {
.runtime_suspend = sr_runtime_suspend,
};

static struct scsi_driver sr_template = {
.owner = THIS_MODULE,
.gendrv = {
.name = "sr",
.probe = sr_probe,
.remove = sr_remove,
.pm = &sr_pm_ops,
},
.done = sr_done,
};
Expand Down Expand Up @@ -131,6 +138,16 @@ static inline struct scsi_cd *scsi_cd(struct gendisk *disk)
return container_of(disk->private_data, struct scsi_cd, driver);
}

static int sr_runtime_suspend(struct device *dev)
{
struct scsi_cd *cd = dev_get_drvdata(dev);

if (cd->media_present)
return -EBUSY;
else
return 0;
}

/*
* The get and put routines for the struct scsi_cd. Note this entity
* has a scsi_device pointer and owns a reference to this.
Expand All @@ -146,7 +163,8 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk)
kref_get(&cd->kref);
if (scsi_device_get(cd->device))
goto out_put;
goto out;
if (!scsi_autopm_get_device(cd->device))
goto out;

out_put:
kref_put(&cd->kref, sr_kref_release);
Expand All @@ -162,6 +180,7 @@ static void scsi_cd_put(struct scsi_cd *cd)

mutex_lock(&sr_ref_mutex);
kref_put(&cd->kref, sr_kref_release);
scsi_autopm_put_device(sdev);
scsi_device_put(sdev);
mutex_unlock(&sr_ref_mutex);
}
Expand Down Expand Up @@ -540,6 +559,8 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
void __user *argp = (void __user *)arg;
int ret;

scsi_autopm_get_device(cd->device);

mutex_lock(&sr_mutex);

/*
Expand Down Expand Up @@ -571,27 +592,38 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,

out:
mutex_unlock(&sr_mutex);
scsi_autopm_put_device(cd->device);
return ret;
}

static unsigned int sr_block_check_events(struct gendisk *disk,
unsigned int clearing)
{
struct scsi_cd *cd = scsi_cd(disk);
return cdrom_check_events(&cd->cdi, clearing);
unsigned int ret;

scsi_autopm_get_device(cd->device);
ret = cdrom_check_events(&cd->cdi, clearing);
scsi_autopm_put_device(cd->device);

return ret;
}

static int sr_block_revalidate_disk(struct gendisk *disk)
{
struct scsi_cd *cd = scsi_cd(disk);
struct scsi_sense_hdr sshdr;

scsi_autopm_get_device(cd->device);

/* if the unit is not ready, nothing more to do */
if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
return 0;
goto out;

sr_cd_check(&cd->cdi);
get_sectorsize(cd);
out:
scsi_autopm_put_device(cd->device);
return 0;
}

Expand Down Expand Up @@ -718,6 +750,8 @@ static int sr_probe(struct device *dev)

sdev_printk(KERN_DEBUG, sdev,
"Attached scsi CD-ROM %s\n", cd->cdi.name);
scsi_autopm_put_device(cd->device);

return 0;

fail_put:
Expand Down Expand Up @@ -965,6 +999,8 @@ static int sr_remove(struct device *dev)
{
struct scsi_cd *cd = dev_get_drvdata(dev);

scsi_autopm_get_device(cd->device);

blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn);
del_gendisk(cd->disk);

Expand Down

0 comments on commit 6c7f1e2

Please sign in to comment.