Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=169439c2e35f01e7832a9b4fc8a7446980c3d593
Commit:     169439c2e35f01e7832a9b4fc8a7446980c3d593
Parent:     1e999736cafdffc374f22eed37b291129ef82e4e
Author:     Mark Lord <[EMAIL PROTECTED]>
AuthorDate: Tue Apr 17 18:26:07 2007 -0400
Committer:  Jeff Garzik <[EMAIL PROTECTED]>
CommitDate: Sat Apr 28 14:40:40 2007 -0400

    libata: Handle drives that require a spin-up command before first access
    
    (S)ATA drives can be configured for "power-up in standby",
    a mode whereby a specific "spin up now!" command is required
    before the first media access.
    
    Currently, a drive with this feature enabled can not be used at all
    with libata, and once in this mode, the drive becomes a doorstop.
    
    The older drivers/ide subsystem at least enumerates the drive,
    so that it can be woken up after the fact from a userspace HDIO_*
    command, but not libata.
    
    This patch adds support to libata for the "power-up in standby"
    mode where a "spin up now!" command (SET_FEATURES) is needed.
    With this, libata will recognize such drives, spin them up,
    and then re-IDENTIFY them if necessary to get a full/complete
    set of drive features data.
    
    Drives in this state are determined by looking for
    special values in id[2], as documented in the current ATA specs.
    
    Signed-off-by: Mark Lord <[EMAIL PROTECTED]>
    Signed-off-by: Jeff Garzik <[EMAIL PROTECTED]>
---
 drivers/ata/libata-core.c |   28 +++++++++++++++++++++++++++-
 include/linux/ata.h       |    2 ++
 2 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 6d0a946..227399e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1649,13 +1649,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned 
int *p_class,
        struct ata_taskfile tf;
        unsigned int err_mask = 0;
        const char *reason;
+       int tried_spinup = 0;
        int rc;
 
        if (ata_msg_ctl(ap))
                ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
 
        ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
-
  retry:
        ata_tf_init(dev, &tf);
 
@@ -1712,6 +1712,32 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int 
*p_class,
                        goto err_out;
        }
 
+       if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) {
+               tried_spinup = 1;
+               /*
+                * Drive powered-up in standby mode, and requires a specific
+                * SET_FEATURES spin-up subcommand before it will accept
+                * anything other than the original IDENTIFY command.
+                */
+               ata_tf_init(dev, &tf);
+               tf.command = ATA_CMD_SET_FEATURES;
+               tf.feature = SETFEATURES_SPINUP;
+               tf.protocol = ATA_PROT_NODATA;
+               tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+               err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+               if (err_mask) {
+                       rc = -EIO;
+                       reason = "SPINUP failed";
+                       goto err_out;
+               }
+               /*
+                * If the drive initially returned incomplete IDENTIFY info,
+                * we now must reissue the IDENTIFY command.
+                */
+               if (id[2] == 0x37c8)
+                       goto retry;
+       }
+
        if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) {
                /*
                 * The exact sequence expected by certain pre-ATA4 drives is:
diff --git a/include/linux/ata.h b/include/linux/ata.h
index f4dc8df..edb31bf 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -202,6 +202,8 @@ enum {
        SETFEATURES_WC_ON       = 0x02, /* Enable write cache */
        SETFEATURES_WC_OFF      = 0x82, /* Disable write cache */
 
+       SETFEATURES_SPINUP      = 0x07, /* Spin-up drive */
+
        /* ATAPI stuff */
        ATAPI_PKT_DMA           = (1 << 0),
        ATAPI_DMADIR            = (1 << 2),     /* ATAPI data dir:
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to