|
@@ -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>
|
|
@@ -79,6 +80,11 @@ 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,
|
|
@@ -86,6 +92,7 @@ static struct scsi_driver sr_template = {
|
|
|
.name = "sr",
|
|
|
.probe = sr_probe,
|
|
|
.remove = sr_remove,
|
|
|
+ .pm = &sr_pm_ops,
|
|
|
},
|
|
|
.done = sr_done,
|
|
|
};
|
|
@@ -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.
|
|
@@ -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);
|
|
@@ -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);
|
|
|
}
|
|
@@ -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);
|
|
|
|
|
|
/*
|
|
@@ -571,6 +592,7 @@ 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;
|
|
|
}
|
|
|
|
|
@@ -578,7 +600,13 @@ 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)
|
|
@@ -586,12 +614,16 @@ 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;
|
|
|
}
|
|
|
|
|
@@ -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:
|
|
@@ -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);
|
|
|
|