|
@@ -2979,23 +2979,68 @@ int ata_busy_sleep(struct ata_port *ap,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
|
|
|
+/**
|
|
|
+ * ata_wait_ready - sleep until BSY clears, or timeout
|
|
|
+ * @ap: port containing status register to be polled
|
|
|
+ * @deadline: deadline jiffies for the operation
|
|
|
+ *
|
|
|
+ * Sleep until ATA Status register bit BSY clears, or timeout
|
|
|
+ * occurs.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * Kernel thread context (may sleep).
|
|
|
+ *
|
|
|
+ * RETURNS:
|
|
|
+ * 0 on success, -errno otherwise.
|
|
|
+ */
|
|
|
+int ata_wait_ready(struct ata_port *ap, unsigned long deadline)
|
|
|
+{
|
|
|
+ unsigned long start = jiffies;
|
|
|
+ int warned = 0;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ u8 status = ata_chk_status(ap);
|
|
|
+ unsigned long now = jiffies;
|
|
|
+
|
|
|
+ if (!(status & ATA_BUSY))
|
|
|
+ return 0;
|
|
|
+ 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 "
|
|
|
+ "(Status 0x%x)\n", status);
|
|
|
+ warned = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ msleep(50);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
|
|
|
+ unsigned long deadline)
|
|
|
{
|
|
|
struct ata_ioports *ioaddr = &ap->ioaddr;
|
|
|
unsigned int dev0 = devmask & (1 << 0);
|
|
|
unsigned int dev1 = devmask & (1 << 1);
|
|
|
- unsigned long timeout;
|
|
|
+ int rc;
|
|
|
|
|
|
/* if device 0 was found in ata_devchk, wait for its
|
|
|
* BSY bit to clear
|
|
|
*/
|
|
|
- if (dev0)
|
|
|
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
|
|
|
+ if (dev0) {
|
|
|
+ rc = ata_wait_ready(ap, deadline);
|
|
|
+ if (rc && rc != -ENODEV)
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
|
|
|
/* if device 1 was found in ata_devchk, wait for
|
|
|
* register access, then wait for BSY to clear
|
|
|
*/
|
|
|
- timeout = jiffies + ATA_TMOUT_BOOT;
|
|
|
while (dev1) {
|
|
|
u8 nsect, lbal;
|
|
|
|
|
@@ -3004,14 +3049,15 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
|
|
|
lbal = ioread8(ioaddr->lbal_addr);
|
|
|
if ((nsect == 1) && (lbal == 1))
|
|
|
break;
|
|
|
- if (time_after(jiffies, timeout)) {
|
|
|
- dev1 = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (time_after(jiffies, deadline))
|
|
|
+ return -EBUSY;
|
|
|
msleep(50); /* give drive a breather */
|
|
|
}
|
|
|
- if (dev1)
|
|
|
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
|
|
|
+ if (dev1) {
|
|
|
+ rc = ata_wait_ready(ap, deadline);
|
|
|
+ if (rc && rc != -ENODEV)
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
|
|
|
/* is all this really necessary? */
|
|
|
ap->ops->dev_select(ap, 0);
|
|
@@ -3019,10 +3065,12 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
|
|
|
ap->ops->dev_select(ap, 1);
|
|
|
if (dev0)
|
|
|
ap->ops->dev_select(ap, 0);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static unsigned int ata_bus_softreset(struct ata_port *ap,
|
|
|
- unsigned int devmask)
|
|
|
+static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
|
|
|
+ unsigned long deadline)
|
|
|
{
|
|
|
struct ata_ioports *ioaddr = &ap->ioaddr;
|
|
|
|
|
@@ -3054,9 +3102,7 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
|
|
|
if (ata_check_status(ap) == 0xFF)
|
|
|
return 0;
|
|
|
|
|
|
- ata_bus_post_reset(ap, devmask);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return ata_bus_post_reset(ap, devmask, deadline);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -3107,7 +3153,7 @@ void ata_bus_reset(struct ata_port *ap)
|
|
|
|
|
|
/* issue bus reset */
|
|
|
if (ap->flags & ATA_FLAG_SRST)
|
|
|
- if (ata_bus_softreset(ap, devmask))
|
|
|
+ if (ata_bus_softreset(ap, devmask, jiffies + 40 * HZ))
|
|
|
goto err_out;
|
|
|
|
|
|
/*
|
|
@@ -3150,29 +3196,37 @@ err_out:
|
|
|
* sata_phy_debounce - debounce SATA phy status
|
|
|
* @ap: ATA port to debounce SATA phy status for
|
|
|
* @params: timing parameters { interval, duratinon, timeout } in msec
|
|
|
+ * @deadline: deadline jiffies for the operation
|
|
|
*
|
|
|
* Make sure SStatus of @ap reaches stable state, determined by
|
|
|
* holding the same value where DET is not 1 for @duration polled
|
|
|
* every @interval, before @timeout. Timeout constraints the
|
|
|
- * beginning of the stable state. Because, after hot unplugging,
|
|
|
- * DET gets stuck at 1 on some controllers, this functions waits
|
|
|
+ * beginning of the stable state. Because DET gets stuck at 1 on
|
|
|
+ * some controllers after hot unplugging, this functions waits
|
|
|
* until timeout then returns 0 if DET is stable at 1.
|
|
|
*
|
|
|
+ * @timeout is further limited by @deadline. The sooner of the
|
|
|
+ * two is used.
|
|
|
+ *
|
|
|
* LOCKING:
|
|
|
* Kernel thread context (may sleep)
|
|
|
*
|
|
|
* RETURNS:
|
|
|
* 0 on success, -errno on failure.
|
|
|
*/
|
|
|
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
|
|
|
+int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
|
|
|
+ unsigned long deadline)
|
|
|
{
|
|
|
unsigned long interval_msec = params[0];
|
|
|
- unsigned long duration = params[1] * HZ / 1000;
|
|
|
- unsigned long timeout = jiffies + params[2] * HZ / 1000;
|
|
|
- unsigned long last_jiffies;
|
|
|
+ unsigned long duration = msecs_to_jiffies(params[1]);
|
|
|
+ unsigned long last_jiffies, t;
|
|
|
u32 last, cur;
|
|
|
int rc;
|
|
|
|
|
|
+ t = jiffies + msecs_to_jiffies(params[2]);
|
|
|
+ if (time_before(t, deadline))
|
|
|
+ deadline = t;
|
|
|
+
|
|
|
if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
|
|
|
return rc;
|
|
|
cur &= 0xf;
|
|
@@ -3188,7 +3242,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
|
|
|
|
|
|
/* DET stable? */
|
|
|
if (cur == last) {
|
|
|
- if (cur == 1 && time_before(jiffies, timeout))
|
|
|
+ if (cur == 1 && time_before(jiffies, deadline))
|
|
|
continue;
|
|
|
if (time_after(jiffies, last_jiffies + duration))
|
|
|
return 0;
|
|
@@ -3199,8 +3253,8 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
|
|
|
last = cur;
|
|
|
last_jiffies = jiffies;
|
|
|
|
|
|
- /* check timeout */
|
|
|
- if (time_after(jiffies, timeout))
|
|
|
+ /* check deadline */
|
|
|
+ if (time_after(jiffies, deadline))
|
|
|
return -EBUSY;
|
|
|
}
|
|
|
}
|
|
@@ -3209,6 +3263,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
|
|
|
* sata_phy_resume - resume SATA phy
|
|
|
* @ap: ATA port to resume SATA phy for
|
|
|
* @params: timing parameters { interval, duratinon, timeout } in msec
|
|
|
+ * @deadline: deadline jiffies for the operation
|
|
|
*
|
|
|
* Resume SATA phy of @ap and debounce it.
|
|
|
*
|
|
@@ -3218,7 +3273,8 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
|
|
|
* RETURNS:
|
|
|
* 0 on success, -errno on failure.
|
|
|
*/
|
|
|
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
|
|
|
+int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
|
|
|
+ unsigned long deadline)
|
|
|
{
|
|
|
u32 scontrol;
|
|
|
int rc;
|
|
@@ -3236,10 +3292,10 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
|
|
|
*/
|
|
|
msleep(200);
|
|
|
|
|
|
- return sata_phy_debounce(ap, params);
|
|
|
+ return sata_phy_debounce(ap, params, deadline);
|
|
|
}
|
|
|
|
|
|
-static void ata_wait_spinup(struct ata_port *ap)
|
|
|
+static void ata_wait_spinup(struct ata_port *ap, unsigned long deadline)
|
|
|
{
|
|
|
struct ata_eh_context *ehc = &ap->eh_context;
|
|
|
unsigned long end, secs;
|
|
@@ -3247,7 +3303,7 @@ static void ata_wait_spinup(struct ata_port *ap)
|
|
|
|
|
|
/* first, debounce phy if SATA */
|
|
|
if (ap->cbl == ATA_CBL_SATA) {
|
|
|
- rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
|
|
|
+ rc = sata_phy_debounce(ap, sata_deb_timing_hotplug, deadline);
|
|
|
|
|
|
/* if debounced successfully and offline, no need to wait */
|
|
|
if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
|
|
@@ -3271,6 +3327,7 @@ static void ata_wait_spinup(struct ata_port *ap)
|
|
|
/**
|
|
|
* ata_std_prereset - prepare for reset
|
|
|
* @ap: ATA port to be reset
|
|
|
+ * @deadline: deadline jiffies for the operation
|
|
|
*
|
|
|
* @ap is about to be reset. Initialize it.
|
|
|
*
|
|
@@ -3280,7 +3337,7 @@ static void ata_wait_spinup(struct ata_port *ap)
|
|
|
* RETURNS:
|
|
|
* 0 on success, -errno otherwise.
|
|
|
*/
|
|
|
-int ata_std_prereset(struct ata_port *ap)
|
|
|
+int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
|
|
|
{
|
|
|
struct ata_eh_context *ehc = &ap->eh_context;
|
|
|
const unsigned long *timing = sata_ehc_deb_timing(ehc);
|
|
@@ -3293,7 +3350,7 @@ int ata_std_prereset(struct ata_port *ap)
|
|
|
|
|
|
if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
|
|
|
(ap->flags & ATA_FLAG_SKIP_D2H_BSY))
|
|
|
- ata_wait_spinup(ap);
|
|
|
+ ata_wait_spinup(ap, deadline);
|
|
|
|
|
|
/* if we're about to do hardreset, nothing more to do */
|
|
|
if (ehc->i.action & ATA_EH_HARDRESET)
|
|
@@ -3301,7 +3358,7 @@ int ata_std_prereset(struct ata_port *ap)
|
|
|
|
|
|
/* if SATA, resume phy */
|
|
|
if (ap->cbl == ATA_CBL_SATA) {
|
|
|
- rc = sata_phy_resume(ap, timing);
|
|
|
+ rc = sata_phy_resume(ap, timing, deadline);
|
|
|
if (rc && rc != -EOPNOTSUPP) {
|
|
|
/* phy resume failed */
|
|
|
ata_port_printk(ap, KERN_WARNING, "failed to resume "
|
|
@@ -3314,7 +3371,7 @@ int ata_std_prereset(struct ata_port *ap)
|
|
|
* Reg FIS and we don't know that no device is attached.
|
|
|
*/
|
|
|
if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
|
|
|
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
|
|
|
+ ata_wait_ready(ap, deadline);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -3323,6 +3380,7 @@ int ata_std_prereset(struct ata_port *ap)
|
|
|
* ata_std_softreset - reset host port via ATA SRST
|
|
|
* @ap: port to reset
|
|
|
* @classes: resulting classes of attached devices
|
|
|
+ * @deadline: deadline jiffies for the operation
|
|
|
*
|
|
|
* Reset host port using ATA SRST.
|
|
|
*
|
|
@@ -3332,10 +3390,12 @@ int ata_std_prereset(struct ata_port *ap)
|
|
|
* RETURNS:
|
|
|
* 0 on success, -errno otherwise.
|
|
|
*/
|
|
|
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
|
|
|
+int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
|
|
|
+ unsigned long deadline)
|
|
|
{
|
|
|
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
|
|
|
- unsigned int devmask = 0, err_mask;
|
|
|
+ unsigned int devmask = 0;
|
|
|
+ int rc;
|
|
|
u8 err;
|
|
|
|
|
|
DPRINTK("ENTER\n");
|
|
@@ -3356,11 +3416,10 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
|
|
|
|
|
|
/* issue bus reset */
|
|
|
DPRINTK("about to softreset, devmask=%x\n", devmask);
|
|
|
- err_mask = ata_bus_softreset(ap, devmask);
|
|
|
- if (err_mask) {
|
|
|
- ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
|
|
|
- err_mask);
|
|
|
- return -EIO;
|
|
|
+ rc = ata_bus_softreset(ap, devmask, deadline);
|
|
|
+ if (rc) {
|
|
|
+ ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc);
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
/* determine by signature whether we have ATA or ATAPI devices */
|
|
@@ -3377,6 +3436,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
|
|
|
* sata_port_hardreset - reset port via SATA phy reset
|
|
|
* @ap: port to reset
|
|
|
* @timing: timing parameters { interval, duratinon, timeout } in msec
|
|
|
+ * @deadline: deadline jiffies for the operation
|
|
|
*
|
|
|
* SATA phy-reset host port using DET bits of SControl register.
|
|
|
*
|
|
@@ -3386,7 +3446,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
|
|
|
* RETURNS:
|
|
|
* 0 on success, -errno otherwise.
|
|
|
*/
|
|
|
-int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
|
|
|
+int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
|
|
|
+ unsigned long deadline)
|
|
|
{
|
|
|
u32 scontrol;
|
|
|
int rc;
|
|
@@ -3425,7 +3486,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
|
|
|
msleep(1);
|
|
|
|
|
|
/* bring phy back */
|
|
|
- rc = sata_phy_resume(ap, timing);
|
|
|
+ rc = sata_phy_resume(ap, timing, deadline);
|
|
|
out:
|
|
|
DPRINTK("EXIT, rc=%d\n", rc);
|
|
|
return rc;
|
|
@@ -3435,6 +3496,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
|
|
|
* sata_std_hardreset - reset host port via SATA phy reset
|
|
|
* @ap: port to reset
|
|
|
* @class: resulting class of attached device
|
|
|
+ * @deadline: deadline jiffies for the operation
|
|
|
*
|
|
|
* SATA phy-reset host port using DET bits of SControl register,
|
|
|
* wait for !BSY and classify the attached device.
|
|
@@ -3445,7 +3507,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
|
|
|
* RETURNS:
|
|
|
* 0 on success, -errno otherwise.
|
|
|
*/
|
|
|
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
|
|
|
+int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
|
|
|
+ unsigned long deadline)
|
|
|
{
|
|
|
const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
|
|
|
int rc;
|
|
@@ -3453,7 +3516,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
|
|
|
DPRINTK("ENTER\n");
|
|
|
|
|
|
/* do hardreset */
|
|
|
- rc = sata_port_hardreset(ap, timing);
|
|
|
+ rc = sata_port_hardreset(ap, timing, deadline);
|
|
|
if (rc) {
|
|
|
ata_port_printk(ap, KERN_ERR,
|
|
|
"COMRESET failed (errno=%d)\n", rc);
|
|
@@ -3470,10 +3533,11 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
|
|
|
/* wait a while before checking status, see SRST for more info */
|
|
|
msleep(150);
|
|
|
|
|
|
- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
|
|
|
+ rc = ata_wait_ready(ap, deadline);
|
|
|
+ if (rc && rc != -ENODEV) {
|
|
|
ata_port_printk(ap, KERN_ERR,
|
|
|
- "COMRESET failed (device not ready)\n");
|
|
|
- return -EIO;
|
|
|
+ "COMRESET failed (errno=%d)\n", rc);
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
ap->ops->dev_select(ap, 0); /* probably unnecessary */
|
|
@@ -6793,6 +6857,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_ready);
|
|
|
EXPORT_SYMBOL_GPL(ata_port_queue_task);
|
|
|
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
|
|
|
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
|