diff options
author | Tejun Heo <htejun@gmail.com> | 2007-10-16 14:21:24 -0700 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-29 06:15:27 -0400 |
commit | 88ff6eafbb2a1c55f0f0e2e16d72e7b10d8ae8a5 (patch) | |
tree | ad6ab294a4f725540bfa24b7a451273b99fa71c1 | |
parent | 054a5fbaceb2eb3a31ea843c1cf0b8e10b91478c (diff) |
libata: implement ata_wait_after_reset()
On certain device/controller combination, 0xff status is asserted
after reset and doesn't get cleared during 150ms post-reset wait. As
0xff status is interpreted as no device (for good reasons), this can
lead to misdetection on such cases.
This patch implements ata_wait_after_reset() which replaces the 150ms
sleep and waits upto ATA_TMOUT_FF_WAIT if status is 0xff.
ATA_TMOUT_FF_WAIT is currently 800ms which is enough for
HHD424020F7SV00 to get detected but not enough for Quantum GoVault
drive which is known to take upto 2s.
Without parallel probing, spending 2s on 0xff port would incur too
much delay on ata_piix's which use 0xff to indicate empty port and
doesn't have SCR register, so GoVault needs to wait till parallel
probing.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/ahci.c | 11 | ||||
-rw-r--r-- | drivers/ata/libata-core.c | 67 | ||||
-rw-r--r-- | drivers/ata/pata_scc.c | 13 | ||||
-rw-r--r-- | drivers/ata/sata_inic162x.c | 2 | ||||
-rw-r--r-- | include/linux/libata.h | 8 |
5 files changed, 67 insertions, 34 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 49cf4cf1a5a..93bcb2cb3d3 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1153,15 +1153,8 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, tf.ctl &= ~ATA_SRST; ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); - /* spec mandates ">= 2ms" before checking status. - * We wait 150ms, because that was the magic delay used for - * ATAPI devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - */ - msleep(150); + /* wait a while before checking status */ + ata_wait_after_reset(ap, deadline); rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 50ae20101d1..8ee56e5cfb0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3118,6 +3118,55 @@ int ata_busy_sleep(struct ata_port *ap, } /** + * ata_wait_after_reset - wait before checking status after reset + * @ap: port containing status register to be polled + * @deadline: deadline jiffies for the operation + * + * After reset, we need to pause a while before reading status. + * Also, certain combination of controller and device report 0xff + * for some duration (e.g. until SATA PHY is up and running) + * which is interpreted as empty port in ATA world. This + * function also waits for such devices to get out of 0xff + * status. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline) +{ + unsigned long until = jiffies + ATA_TMOUT_FF_WAIT; + + if (time_before(until, deadline)) + deadline = until; + + /* Spec mandates ">= 2ms" before checking status. We wait + * 150ms, because that was the magic delay used for ATAPI + * devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + * + * Old drivers/ide uses the 2mS rule and then waits for ready. + */ + msleep(150); + + /* Wait for 0xff to clear. Some SATA devices take a long time + * to clear 0xff after reset. For example, HHD424020F7SV00 + * iVDR needs >= 800ms while. Quantum GoVault needs even more + * than that. + */ + while (1) { + u8 status = ata_chk_status(ap); + + if (status != 0xff || time_after(jiffies, deadline)) + return; + + msleep(50); + } +} + +/** * ata_wait_ready - sleep until BSY clears, or timeout * @ap: port containing status register to be polled * @deadline: deadline jiffies for the operation @@ -3254,17 +3303,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, ap->ops->set_piomode(ap, dev); } - /* spec mandates ">= 2ms" before checking status. - * We wait 150ms, because that was the magic delay used for - * ATAPI devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - * - * Old drivers/ide uses the 2mS rule and then waits for ready - */ - msleep(150); + /* wait a while before checking status */ + ata_wait_after_reset(ap, deadline); /* Before we perform post reset processing we want to see if * the bus shows 0xFF because the odd clown forgets the D7 @@ -3691,8 +3731,8 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, return 0; } - /* wait a while before checking status, see SRST for more info */ - msleep(150); + /* wait a while before checking status */ + ata_wait_after_reset(ap, deadline); /* If PMP is supported, we have to do follow-up SRST. Note * that some PMPs don't send D2H Reg FIS after hardreset at @@ -7358,6 +7398,7 @@ EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_ratelimit); EXPORT_SYMBOL_GPL(ata_wait_register); EXPORT_SYMBOL_GPL(ata_busy_sleep); +EXPORT_SYMBOL_GPL(ata_wait_after_reset); EXPORT_SYMBOL_GPL(ata_wait_ready); EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 55576138fae..ea2ef9fc15b 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -570,17 +570,8 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, udelay(20); out_be32(ioaddr->ctl_addr, ap->ctl); - /* spec mandates ">= 2ms" before checking status. - * We wait 150ms, because that was the magic delay used for - * ATAPI devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - * - * Old drivers/ide uses the 2mS rule and then waits for ready - */ - msleep(150); + /* wait a while before checking status */ + ata_wait_after_reset(ap, deadline); /* Before we perform post reset processing we want to see if * the bus shows 0xFF because the odd clown forgets the D7 diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 08595f34b3e..b97d077e61b 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -448,7 +448,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, struct ata_taskfile tf; /* wait a while before checking status */ - msleep(150); + ata_wait_after_reset(ap, deadline); rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 2f0fc636b4b..439d40f86c5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -235,6 +235,13 @@ enum { ATA_TMOUT_INTERNAL = 30 * HZ, ATA_TMOUT_INTERNAL_QUICK = 5 * HZ, + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * HZ / 5, + /* ATA bus states */ BUS_UNKNOWN = 0, BUS_DMA = 1, @@ -800,6 +807,7 @@ extern void ata_host_resume(struct ata_host *host); extern int ata_ratelimit(void); extern int ata_busy_sleep(struct ata_port *ap, unsigned long timeout_pat, unsigned long timeout); +extern void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline); extern int ata_wait_ready(struct ata_port *ap, unsigned long deadline); extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, unsigned long delay); |