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 <mlord@pobox.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
1e999736ca
commit
169439c2e3
|
@ -1649,13 +1649,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
|
||||||
struct ata_taskfile tf;
|
struct ata_taskfile tf;
|
||||||
unsigned int err_mask = 0;
|
unsigned int err_mask = 0;
|
||||||
const char *reason;
|
const char *reason;
|
||||||
|
int tried_spinup = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (ata_msg_ctl(ap))
|
if (ata_msg_ctl(ap))
|
||||||
ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
|
ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
|
||||||
|
|
||||||
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
|
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
ata_tf_init(dev, &tf);
|
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;
|
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) {
|
if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) {
|
||||||
/*
|
/*
|
||||||
* The exact sequence expected by certain pre-ATA4 drives is:
|
* The exact sequence expected by certain pre-ATA4 drives is:
|
||||||
|
|
|
@ -202,6 +202,8 @@ enum {
|
||||||
SETFEATURES_WC_ON = 0x02, /* Enable write cache */
|
SETFEATURES_WC_ON = 0x02, /* Enable write cache */
|
||||||
SETFEATURES_WC_OFF = 0x82, /* Disable write cache */
|
SETFEATURES_WC_OFF = 0x82, /* Disable write cache */
|
||||||
|
|
||||||
|
SETFEATURES_SPINUP = 0x07, /* Spin-up drive */
|
||||||
|
|
||||||
/* ATAPI stuff */
|
/* ATAPI stuff */
|
||||||
ATAPI_PKT_DMA = (1 << 0),
|
ATAPI_PKT_DMA = (1 << 0),
|
||||||
ATAPI_DMADIR = (1 << 2), /* ATAPI data dir:
|
ATAPI_DMADIR = (1 << 2), /* ATAPI data dir:
|
||||||
|
|
Loading…
Reference in New Issue