aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Lu <aaron.lu@intel.com>2013-01-23 02:09:32 -0500
committerJeff Garzik <jgarzik@redhat.com>2013-01-25 15:36:43 -0500
commit6f4c827e68a78731c6c75df69bf7b75b029ec70c (patch)
tree5113f12fc6fd5c7e2769aa19c2a1bb59ea647652
parent6c7f1e2f12f6f37ddda01180c9e5c407eccce616 (diff)
[libata] scsi: no poll when ODD is powered off
When the ODD is powered off, any action the user did to the ODD that would generate a media event will trigger an ACPI interrupt, so the poll for media event is no longer necessary. And the poll will also cause a runtime status change, which will stop the ODD from staying in powered off state, so the poll should better be stopped. But since we don't have access to the gendisk structure in LLDs, here comes the disk_events_disable_depth for scsi device. This field is a hint set by LLDs to convey information to upper layer drivers. A value of 0 means media poll is necessary for the device, while values above 0 means media poll is not needed and should better be skipped. So we can increase its value when we are to power off the ODD in ATA layer and decrease its value when the ODD is powered on, effectively silence the media events poll. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/ata/libata-zpodd.c7
-rw-r--r--drivers/scsi/scsi_lib.c14
-rw-r--r--drivers/scsi/sr.c10
-rw-r--r--include/scsi/scsi_device.h4
4 files changed, 32 insertions, 3 deletions
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
index 540b0b7904fb..a7df60383532 100644
--- a/drivers/ata/libata-zpodd.c
+++ b/drivers/ata/libata-zpodd.c
@@ -178,11 +178,16 @@ bool zpodd_zpready(struct ata_device *dev)
178 * Enable runtime wake capability through ACPI and set the powered_off flag, 178 * Enable runtime wake capability through ACPI and set the powered_off flag,
179 * this flag will be used during resume to decide what operations are needed 179 * this flag will be used during resume to decide what operations are needed
180 * to take. 180 * to take.
181 *
182 * Also, media poll needs to be silenced, so that it doesn't bring the ODD
183 * back to full power state every few seconds.
181 */ 184 */
182void zpodd_enable_run_wake(struct ata_device *dev) 185void zpodd_enable_run_wake(struct ata_device *dev)
183{ 186{
184 struct zpodd *zpodd = dev->zpodd; 187 struct zpodd *zpodd = dev->zpodd;
185 188
189 sdev_disable_disk_events(dev->sdev);
190
186 zpodd->powered_off = true; 191 zpodd->powered_off = true;
187 device_set_run_wake(&dev->sdev->sdev_gendev, true); 192 device_set_run_wake(&dev->sdev->sdev_gendev, true);
188 acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true); 193 acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true);
@@ -231,6 +236,8 @@ void zpodd_post_poweron(struct ata_device *dev)
231 236
232 zpodd->zp_sampled = false; 237 zpodd->zp_sampled = false;
233 zpodd->zp_ready = false; 238 zpodd->zp_ready = false;
239
240 sdev_enable_disk_events(dev->sdev);
234} 241}
235 242
236static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) 243static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index f1bf5aff68ed..765398c063c7 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2617,3 +2617,17 @@ void scsi_kunmap_atomic_sg(void *virt)
2617 kunmap_atomic(virt); 2617 kunmap_atomic(virt);
2618} 2618}
2619EXPORT_SYMBOL(scsi_kunmap_atomic_sg); 2619EXPORT_SYMBOL(scsi_kunmap_atomic_sg);
2620
2621void sdev_disable_disk_events(struct scsi_device *sdev)
2622{
2623 atomic_inc(&sdev->disk_events_disable_depth);
2624}
2625EXPORT_SYMBOL(sdev_disable_disk_events);
2626
2627void sdev_enable_disk_events(struct scsi_device *sdev)
2628{
2629 if (WARN_ON_ONCE(atomic_read(&sdev->disk_events_disable_depth) <= 0))
2630 return;
2631 atomic_dec(&sdev->disk_events_disable_depth);
2632}
2633EXPORT_SYMBOL(sdev_enable_disk_events);
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 2e8ddd77366f..f2884ee90710 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -602,9 +602,13 @@ static unsigned int sr_block_check_events(struct gendisk *disk,
602 struct scsi_cd *cd = scsi_cd(disk); 602 struct scsi_cd *cd = scsi_cd(disk);
603 unsigned int ret; 603 unsigned int ret;
604 604
605 scsi_autopm_get_device(cd->device); 605 if (atomic_read(&cd->device->disk_events_disable_depth) == 0) {
606 ret = cdrom_check_events(&cd->cdi, clearing); 606 scsi_autopm_get_device(cd->device);
607 scsi_autopm_put_device(cd->device); 607 ret = cdrom_check_events(&cd->cdi, clearing);
608 scsi_autopm_put_device(cd->device);
609 } else {
610 ret = 0;
611 }
608 612
609 return ret; 613 return ret;
610} 614}
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index e65c62e82c5a..bb1371bf171d 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -161,6 +161,8 @@ struct scsi_device {
161 unsigned wce_default_on:1; /* Cache is ON by default */ 161 unsigned wce_default_on:1; /* Cache is ON by default */
162 unsigned no_dif:1; /* T10 PI (DIF) should be disabled */ 162 unsigned no_dif:1; /* T10 PI (DIF) should be disabled */
163 163
164 atomic_t disk_events_disable_depth; /* disable depth for disk events */
165
164 DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ 166 DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
165 struct list_head event_list; /* asserted events */ 167 struct list_head event_list; /* asserted events */
166 struct work_struct event_work; 168 struct work_struct event_work;
@@ -397,6 +399,8 @@ extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
397 int data_direction, void *buffer, unsigned bufflen, 399 int data_direction, void *buffer, unsigned bufflen,
398 struct scsi_sense_hdr *, int timeout, int retries, 400 struct scsi_sense_hdr *, int timeout, int retries,
399 int *resid); 401 int *resid);
402extern void sdev_disable_disk_events(struct scsi_device *sdev);
403extern void sdev_enable_disk_events(struct scsi_device *sdev);
400 404
401#ifdef CONFIG_PM_RUNTIME 405#ifdef CONFIG_PM_RUNTIME
402extern int scsi_autopm_get_device(struct scsi_device *); 406extern int scsi_autopm_get_device(struct scsi_device *);