aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
authorAaron Lu <aaron.lu@intel.com>2013-01-15 04:21:00 -0500
committerJeff Garzik <jgarzik@redhat.com>2013-01-21 15:41:34 -0500
commit3dc67440d99b2c718ef5f1eb1424a9066ffa3fb9 (patch)
tree4eee59932d2b99daf76f2bca624c05e719a4b004 /drivers/ata/libata-eh.c
parentf064a20dded807448669426c9bfb7d03aba5659c (diff)
libata: check zero power ready status for ZPODD
Per the Mount Fuji spec, the ODD is considered zero power ready when: - For slot type ODD, no media inside; - For tray type ODD, no media inside and tray closed. The information can be retrieved by either the returned information of command GET_EVENT_STATUS_NOTIFICATION(the command is used to poll for media event) or sense code. The information provided by the media status byte is not accurate, it is possible that after a new disc is just inserted, the status byte still returns media not present. So this information can not be used as the deciding factor, we use sense code to decide if zpready status is true. When we first sensed the ODD in the zero power ready state, the zp_sampled will be set and timestamp will be recoreded. And after ODD stayed in this state for some pre-defined period, the ODD is considered as power off ready and the zp_ready flag will be set. The zp_ready flag serves as the deciding factor other code will use to see if power off is OK for the ODD. The Mount Fuji spec suggests a delay should be used here, to avoid the case user ejects the ODD and then instantly inserts a new one again, so that we can avoid a power transition. And some ODDs may be slow to place its head to the home position after disc is ejected, so a delay here is generally a good idea. And the delay time can be changed via the module param zpodd_poweroff_delay. The zero power ready status check is performed in the ata port's runtime suspend code path, when port is not frozen yet, as we need to issue some IOs to the ODD. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index bcf4437214f5..a0dddc3b4924 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1591,7 +1591,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
1591 * RETURNS: 1591 * RETURNS:
1592 * 0 on success, AC_ERR_* mask on failure. 1592 * 0 on success, AC_ERR_* mask on failure.
1593 */ 1593 */
1594static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) 1594unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
1595{ 1595{
1596 u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 }; 1596 u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
1597 struct ata_taskfile tf; 1597 struct ata_taskfile tf;
@@ -1624,7 +1624,7 @@ static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
1624 * RETURNS: 1624 * RETURNS:
1625 * 0 on success, AC_ERR_* mask on failure 1625 * 0 on success, AC_ERR_* mask on failure
1626 */ 1626 */
1627static unsigned int atapi_eh_request_sense(struct ata_device *dev, 1627unsigned int atapi_eh_request_sense(struct ata_device *dev,
1628 u8 *sense_buf, u8 dfl_sense_key) 1628 u8 *sense_buf, u8 dfl_sense_key)
1629{ 1629{
1630 u8 cdb[ATAPI_CDB_LEN] = 1630 u8 cdb[ATAPI_CDB_LEN] =
@@ -4022,6 +4022,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
4022{ 4022{
4023 unsigned long flags; 4023 unsigned long flags;
4024 int rc = 0; 4024 int rc = 0;
4025 struct ata_device *dev;
4025 4026
4026 /* are we suspending? */ 4027 /* are we suspending? */
4027 spin_lock_irqsave(ap->lock, flags); 4028 spin_lock_irqsave(ap->lock, flags);
@@ -4034,6 +4035,15 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
4034 4035
4035 WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); 4036 WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
4036 4037
4038 /*
4039 * If we have a ZPODD attached, check its zero
4040 * power ready status before the port is frozen.
4041 */
4042 ata_for_each_dev(dev, &ap->link, ENABLED) {
4043 if (zpodd_dev_enabled(dev))
4044 zpodd_on_suspend(dev);
4045 }
4046
4037 /* tell ACPI we're suspending */ 4047 /* tell ACPI we're suspending */
4038 rc = ata_acpi_on_suspend(ap); 4048 rc = ata_acpi_on_suspend(ap);
4039 if (rc) 4049 if (rc)