summaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci.c11
-rw-r--r--drivers/ata/libata-sff.c161
-rw-r--r--drivers/ata/pata_scc.c91
-rw-r--r--drivers/ata/sata_inic162x.c6
-rw-r--r--drivers/ata/sata_via.c2
5 files changed, 124 insertions, 147 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 939dc1d4e50..45a67a9ad8a 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1302,10 +1302,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);
- /* wait a while before checking status */
- ata_sff_wait_after_reset(ap, deadline);
-
- rc = ata_sff_wait_ready(ap, deadline);
+ /* wait for link to become ready */
+ rc = ata_sff_wait_after_reset(link, 1, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
reason = "device not ready";
@@ -1415,9 +1413,6 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
if (rc || ata_link_offline(link))
return rc;
- /* spec mandates ">= 2ms" before checking status */
- msleep(150);
-
/* The pseudo configuration device on SIMG4726 attached to
* ASUS P5W-DH Deluxe doesn't send signature FIS after
* hardreset if no device is attached to the first downstream
@@ -1431,7 +1426,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
* have to be reset again. For most cases, this should
* suffice while making probing snappish enough.
*/
- rc = ata_sff_wait_ready(ap, jiffies + 2 * HZ);
+ rc = ata_sff_wait_after_reset(link, 1, jiffies + 2 * HZ);
if (rc)
ahci_kick_engine(ap, 0);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index e530baccc9c..6e8de3c1595 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -310,7 +310,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
/**
* ata_sff_wait_ready - sleep until BSY clears, or timeout
- * @ap: port containing status register to be polled
+ * @link: SFF link to wait ready status for
* @deadline: deadline jiffies for the operation
*
* Sleep until ATA Status register bit BSY clears, or timeout
@@ -322,26 +322,52 @@ int ata_sff_busy_sleep(struct ata_port *ap,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_sff_wait_ready(struct ata_port *ap, unsigned long deadline)
+int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned long start = jiffies;
+ unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT;
int warned = 0;
+ if (time_after(nodev_deadline, deadline))
+ nodev_deadline = deadline;
+
while (1) {
u8 status = ap->ops->sff_check_status(ap);
unsigned long now = jiffies;
if (!(status & ATA_BUSY))
return 0;
- if (!ata_link_online(&ap->link) && status == 0xff)
- return -ENODEV;
+
+ /* No device status could be transient. Ignore it if
+ * link is online. Also, 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. Wait for
+ * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline.
+ *
+ * Note that some PATA controllers (pata_ali) explode
+ * if status register is read more than once when
+ * there's no device attached.
+ */
+ if (status == 0xff) {
+ if (ata_link_online(link))
+ status = ATA_BUSY;
+ else if ((link->ap->flags & ATA_FLAG_SATA) &&
+ !ata_link_offline(link) &&
+ time_before(now, nodev_deadline))
+ status = ATA_BUSY;
+ if (status == 0xff)
+ return -ENODEV;
+ }
+
if (time_after(now, deadline))
return -EBUSY;
if (!warned && time_after(now, start + 5 * HZ) &&
(deadline - now > 3 * HZ)) {
- ata_port_printk(ap, KERN_WARNING,
- "port is slow to respond, please be patient "
+ ata_link_printk(link, KERN_WARNING,
+ "link is slow to respond, please be patient "
"(Status 0x%x)\n", status);
warned = 1;
}
@@ -1625,7 +1651,6 @@ void ata_sff_thaw(struct ata_port *ap)
*/
int ata_sff_prereset(struct ata_link *link, unsigned long deadline)
{
- struct ata_port *ap = link->ap;
struct ata_eh_context *ehc = &link->eh_context;
int rc;
@@ -1639,7 +1664,7 @@ int ata_sff_prereset(struct ata_link *link, unsigned long deadline)
/* wait for !BSY if we don't know that no device is attached */
if (!ata_link_offline(link)) {
- rc = ata_sff_wait_ready(ap, deadline);
+ rc = ata_sff_wait_ready(link, deadline);
if (rc && rc != -ENODEV) {
ata_link_printk(link, KERN_WARNING, "device not ready "
"(errno=%d), forcing hardreset\n", rc);
@@ -1762,25 +1787,41 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present,
return class;
}
-static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
- unsigned long deadline)
+/**
+ * ata_sff_wait_after_reset - wait for devices to become ready after reset
+ * @link: SFF link which is just reset
+ * @devmask: mask of present devices
+ * @deadline: deadline jiffies for the operation
+ *
+ * Wait devices attached to SFF @link to become ready after
+ * reset. It contains preceding 150ms wait to avoid accessing TF
+ * status register too early.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -ENODEV if some or all of devices in @devmask
+ * don't seem to exist. -errno on other errors.
+ */
+int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
+ unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int dev0 = devmask & (1 << 0);
unsigned int dev1 = devmask & (1 << 1);
int rc, ret = 0;
- /* if device 0 was found in ata_devchk, wait for its
- * BSY bit to clear
+ msleep(ATA_WAIT_AFTER_RESET_MSECS);
+
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /* -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
*/
- if (dev0) {
- rc = ata_sff_wait_ready(ap, deadline);
- if (rc) {
- if (rc != -ENODEV)
- return rc;
- ret = rc;
- }
- }
+ if (rc)
+ return rc;
/* if device 1 was found in ata_devchk, wait for register
* access briefly, then wait for BSY to clear.
@@ -1804,7 +1845,7 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
msleep(50); /* give drive a breather */
}
- rc = ata_sff_wait_ready(ap, deadline);
+ rc = ata_sff_wait_ready(link, deadline);
if (rc) {
if (rc != -ENODEV)
return rc;
@@ -1822,61 +1863,6 @@ static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
return ret;
}
-/**
- * ata_sff_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_sff_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.
- *
- * Note that some PATA controllers (pata_ali) explode if
- * status register is read more than once when there's no
- * device attached.
- */
- if (ap->flags & ATA_FLAG_SATA) {
- while (1) {
- u8 status = ap->ops->sff_check_status(ap);
-
- if (status != 0xff || time_after(jiffies, deadline))
- return;
-
- msleep(50);
- }
- }
-}
-
static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
unsigned long deadline)
{
@@ -1891,17 +1877,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
udelay(20); /* FIXME: flush */
iowrite8(ap->ctl, ioaddr->ctl_addr);
- /* wait a while before checking status */
- ata_sff_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
- * pulldown resistor.
- */
- if (ap->ops->sff_check_status(ap) == 0xFF)
- return -ENODEV;
-
- return ata_bus_post_reset(ap, devmask, deadline);
+ /* wait the port to become ready */
+ return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
}
/**
@@ -2003,20 +1980,18 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class,
return 0;
}
- /* wait a while before checking status */
- ata_sff_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
* all if the first port is empty. Wait for it just for a
* second and request follow-up SRST.
*/
if (ap->flags & ATA_FLAG_PMP) {
- ata_sff_wait_ready(ap, jiffies + HZ);
+ ata_sff_wait_after_reset(link, 1, jiffies + HZ);
return -EAGAIN;
}
- rc = ata_sff_wait_ready(ap, deadline);
+ /* wait for the link to become online */
+ rc = ata_sff_wait_after_reset(link, 1, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
ata_link_printk(link, KERN_ERR,
@@ -2024,8 +1999,6 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class,
return rc;
}
- ap->ops->sff_dev_select(ap, 0); /* probably unnecessary */
-
*class = ata_sff_dev_classify(link->device, 1, NULL);
DPRINTK("EXIT, class=%u\n", *class);
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index 2b9da715c70..accc275e74c 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -497,47 +497,68 @@ static unsigned int scc_devchk (struct ata_port *ap,
}
/**
- * scc_bus_post_reset - PATA device post reset
+ * scc_wait_after_reset - wait for devices to become ready after reset
*
- * Note: Original code is ata_bus_post_reset().
+ * Note: Original code is ata_sff_wait_after_reset
*/
-static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask,
- unsigned long deadline)
+int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
+ unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int dev0 = devmask & (1 << 0);
unsigned int dev1 = devmask & (1 << 1);
- int rc;
+ int rc, ret = 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.
+ *
+ * Old drivers/ide uses the 2mS rule and then waits for ready.
+ */
+ msleep(150);
- /* if device 0 was found in ata_devchk, wait for its
- * BSY bit to clear
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /* -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
*/
- if (dev0) {
- rc = ata_sff_wait_ready(ap, deadline);
- if (rc && rc != -ENODEV)
- return rc;
- }
+ if (rc)
+ return rc;
- /* if device 1 was found in ata_devchk, wait for
- * register access, then wait for BSY to clear
+ /* if device 1 was found in ata_devchk, wait for register
+ * access briefly, then wait for BSY to clear.
*/
- while (dev1) {
- u8 nsect, lbal;
+ if (dev1) {
+ int i;
ap->ops->sff_dev_select(ap, 1);
- nsect = in_be32(ioaddr->nsect_addr);
- lbal = in_be32(ioaddr->lbal_addr);
- if ((nsect == 1) && (lbal == 1))
- break;
- if (time_after(jiffies, deadline))
- return -EBUSY;
- msleep(50); /* give drive a breather */
- }
- if (dev1) {
- rc = ata_sff_wait_ready(ap, deadline);
- if (rc && rc != -ENODEV)
- return rc;
+
+ /* Wait for register access. Some ATAPI devices fail
+ * to set nsect/lbal after reset, so don't waste too
+ * much time on it. We're gonna wait for !BSY anyway.
+ */
+ for (i = 0; i < 2; i++) {
+ u8 nsect, lbal;
+
+ nsect = in_be32(ioaddr->nsect_addr);
+ lbal = in_be32(ioaddr->lbal_addr);
+ if ((nsect == 1) && (lbal == 1))
+ break;
+ msleep(50); /* give drive a breather */
+ }
+
+ rc = ata_sff_wait_ready(link, deadline);
+ if (rc) {
+ if (rc != -ENODEV)
+ return rc;
+ ret = rc;
+ }
}
/* is all this really necessary? */
@@ -547,7 +568,7 @@ static int scc_bus_post_reset(struct ata_port *ap, unsigned int devmask,
if (dev0)
ap->ops->sff_dev_select(ap, 0);
- return 0;
+ return ret;
}
/**
@@ -570,17 +591,7 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
udelay(20);
out_be32(ioaddr->ctl_addr, ap->ctl);
- /* wait a while before checking status */
- ata_sff_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
- * pulldown resistor.
- */
- if (scc_check_status(ap) == 0xFF)
- return 0;
-
- scc_bus_post_reset(ap, devmask, deadline);
+ scc_wait_after_reset(&ap->link, devmask, deadlien);
return 0;
}
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 0b5a736a45e..9f47d002245 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -417,10 +417,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
if (ata_link_online(link)) {
struct ata_taskfile tf;
- /* wait a while before checking status */
- ata_sff_wait_after_reset(ap, deadline);
-
- rc = ata_sff_wait_ready(ap, deadline);
+ /* wait for link to become ready */
+ rc = ata_sff_wait_after_reset(link, 1, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
ata_link_printk(link, KERN_WARNING, "device not ready "
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index e5df3768974..96deeb354e1 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -242,7 +242,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
skip_scr:
/* wait for !BSY */
- ata_sff_wait_ready(ap, deadline);
+ ata_sff_wait_ready(link, deadline);
return 0;
}