]> Zhao Yanbai Git Server - minix.git/commitdiff
ahci: device detection rewrite
authorDavid van Moolenbroek <david@minix3.org>
Wed, 13 Feb 2013 14:22:45 +0000 (14:22 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 13 Feb 2013 14:26:48 +0000 (14:26 +0000)
- do not start a port before the BSY and DRQ flags have been cleared;
  as such, poll on device status rather than signature availability.
- change "ahci_sig_timeout" to "ahci_device_timeout" variable setting
  accordingly; this variable determines the polling duration before a
  newly attached device is given up on, and uses 30 seconds as default;
- use port connect changes (PCS/X/DET->1h) to kick off polling for an
  attached device; detachment is still detected by means of PhyRdy
  status changes (PRCS/N/DET<->3h).

drivers/ahci/ahci.c
drivers/ahci/ahci.h

index 4af5b1210e53f7d1e345674cca99e48f222ae78a..cf2b628e14006bc58c832b26bee5e973e60d8657 100644 (file)
@@ -31,7 +31,7 @@
  *        |             |      |            ^                         |
  *        v             v      |            |                         |
  *   +----------+     +----------+     +----------+     +----------+  |
- *   |  NO_DEV  | --> | WAIT_SIG | --> | WAIT_ID  | --> | GOOD_DEV |  |
+ *   |  NO_DEV  | --> | WAIT_DEV | --> | WAIT_ID  | --> | GOOD_DEV |  |
  *   +----------+     +----------+     +----------+     +----------+  |
  *        ^                |                |                |        |
  *        +----------------+----------------+----------------+--------+
  * closed and reopened. Removable media are not locked in the drive while
  * opened, because the driver author is uncomfortable with that concept.
  *
+ * Ports may leave the group of states where a device is connected (that is,
+ * WAIT_ID, GOOD_DEV, and BAD_DEV) in two ways: either due to a hot-unplug
+ * event, or due to a hard reset after a serious failure. For simplicity, we
+ * we perform a hard reset after a hot-unplug event as well, so that the link
+ * to the device is broken. Thus, in both cases, a transition to NO_DEV is
+ * made, after which the link to the device may or may not be reestablished.
+ * In both cases, ongoing requests are cancelled and the BARRIER flag is set.
+ *
  * The following table lists for each state, whether the port is started
  * (PxCMD.ST is set), whether a timer is running, what the PxIE mask is to be
  * set to, and what BDEV_OPEN calls on this port should return.
  *   State       Started     Timer       PxIE        BDEV_OPEN
  *   ---------   ---------   ---------   ---------   ---------
  *   NO_PORT     no          no          (none)      ENXIO
- *   SPIN_UP     no          yes         PRCE        (wait)
- *   NO_DEV      no          no          PRCE        ENXIO
- *   WAIT_SIG    yes         yes         PRCE        (wait)
- *   WAIT_ID     yes         yes         (all)       (wait)
+ *   SPIN_UP     no          yes         PCE         (wait)
+ *   NO_DEV      no          no          PCE         ENXIO
+ *   WAIT_DEV    no          yes         PCE         (wait)
  *   BAD_DEV     no          no          PRCE        ENXIO
- *   GOOD_DEV    yes         per-command (all)       OK
+ *   WAIT_ID     yes         yes         PRCE+       (wait)
+ *   GOOD_DEV    yes         per-command PRCE+       OK
  *
  * In order to continue deferred BDEV_OPEN calls, the BUSY flag must be unset
- * when changing from SPIN_UP to any state but WAIT_SIG, and when changing from
- * WAIT_SIG to any state but WAIT_ID, and when changing from WAIT_ID to any
+ * when changing from SPIN_UP to any state but WAIT_DEV, and when changing from
+ * WAIT_DEV to any state but WAIT_ID, and when changing from WAIT_ID to any
  * other state.
  */
 /*
@@ -183,9 +191,9 @@ static int ahci_verbose;                    /* verbosity level (0..4) */
 
 /* Timeout-related values. */
 static clock_t ahci_spinup_timeout;
-static clock_t ahci_sig_timeout;
-static clock_t ahci_sig_delay;
-static unsigned int ahci_sig_checks;
+static clock_t ahci_device_timeout;
+static clock_t ahci_device_delay;
+static unsigned int ahci_device_checks;
 static clock_t ahci_command_timeout;
 static clock_t ahci_transfer_timeout;
 static clock_t ahci_flush_timeout;
@@ -196,11 +204,11 @@ static struct {
        u32_t default_ms;                       /* default in milliseconds */
        clock_t *ptr;                           /* clock ticks value pointer */
 } ahci_timevar[] = {
-       { "ahci_init_timeout",  SPINUP_TIMEOUT,    &ahci_spinup_timeout   },
-       { "ahci_sig_timeout",   SIG_TIMEOUT,       &ahci_sig_timeout      },
-       { "ahci_cmd_timeout",   COMMAND_TIMEOUT,   &ahci_command_timeout  },
-       { "ahci_io_timeout",    TRANSFER_TIMEOUT,  &ahci_transfer_timeout },
-       { "ahci_flush_timeout", FLUSH_TIMEOUT,     &ahci_flush_timeout    }
+       { "ahci_init_timeout",   SPINUP_TIMEOUT,    &ahci_spinup_timeout   },
+       { "ahci_device_timeout", DEVICE_TIMEOUT,    &ahci_device_timeout   },
+       { "ahci_cmd_timeout",    COMMAND_TIMEOUT,   &ahci_command_timeout  },
+       { "ahci_io_timeout",     TRANSFER_TIMEOUT,  &ahci_transfer_timeout },
+       { "ahci_flush_timeout",  FLUSH_TIMEOUT,     &ahci_flush_timeout    }
 };
 
 static int ahci_map[MAX_DRIVES];               /* device-to-port mapping */
@@ -1245,6 +1253,27 @@ static void port_start(struct port_state *ps)
        dprintf(V_INFO, ("%s: started\n", ahci_portname(ps)));
 }
 
+/*===========================================================================*
+ *                             port_stop                                    *
+ *===========================================================================*/
+static void port_stop(struct port_state *ps)
+{
+       /* Stop the given port, if not already stopped.
+        */
+       u32_t cmd;
+
+       cmd = port_read(ps, AHCI_PORT_CMD);
+
+       if (cmd & (AHCI_PORT_CMD_CR | AHCI_PORT_CMD_ST)) {
+               port_write(ps, AHCI_PORT_CMD, cmd & ~AHCI_PORT_CMD_ST);
+
+               SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_CR),
+                       PORTREG_DELAY);
+
+               dprintf(V_INFO, ("%s: stopped\n", ahci_portname(ps)));
+       }
+}
+
 /*===========================================================================*
  *                             port_restart                                 *
  *===========================================================================*/
@@ -1252,21 +1281,12 @@ static void port_restart(struct port_state *ps)
 {
        /* Restart a port after a fatal error has occurred.
         */
-       u32_t cmd;
 
        /* Fail all outstanding commands. */
        port_fail_cmds(ps);
 
        /* Stop the port. */
-       cmd = port_read(ps, AHCI_PORT_CMD);
-       port_write(ps, AHCI_PORT_CMD, cmd & ~AHCI_PORT_CMD_ST);
-
-       SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_CR),
-               PORTREG_DELAY);
-
-       /* Reset status registers. */
-       port_write(ps, AHCI_PORT_SERR, ~0);
-       port_write(ps, AHCI_PORT_IS, ~0);
+       port_stop(ps);
 
        /* If the BSY and/or DRQ flags are set, reset the port. */
        if (port_read(ps, AHCI_PORT_TFD) &
@@ -1290,125 +1310,7 @@ static void port_restart(struct port_state *ps)
        }
 
        /* Start the port. */
-       cmd = port_read(ps, AHCI_PORT_CMD);
-       port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_ST);
-
-       dprintf(V_INFO, ("%s: restarted\n", ahci_portname(ps)));
-}
-
-/*===========================================================================*
- *                             port_stop                                    *
- *===========================================================================*/
-static void port_stop(struct port_state *ps)
-{
-       /* Stop the given port, if not already stopped.
-        */
-       u32_t cmd;
-
-       /* Disable interrupts. */
-       port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_NONE);
-
-       /* Stop the port. */
-       cmd = port_read(ps, AHCI_PORT_CMD);
-
-       if (cmd & (AHCI_PORT_CMD_CR | AHCI_PORT_CMD_ST)) {
-               cmd &= ~(AHCI_PORT_CMD_CR | AHCI_PORT_CMD_ST);
-
-               port_write(ps, AHCI_PORT_CMD, cmd);
-
-               SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_CR),
-                       PORTREG_DELAY);
-
-               dprintf(V_INFO, ("%s: stopped\n", ahci_portname(ps)));
-       }
-
-       /* Reset status registers. */
-       port_write(ps, AHCI_PORT_SERR, ~0);
-       port_write(ps, AHCI_PORT_IS, ~0);
-}
-
-/*===========================================================================*
- *                             port_sig_check                               *
- *===========================================================================*/
-static void port_sig_check(struct port_state *ps)
-{
-       /* Check whether the device's signature has become available yet, and
-        * if so, start identifying the device.
-        */
-       u32_t tfd, sig;
-
-       tfd = port_read(ps, AHCI_PORT_TFD);
-
-       /* Wait for the BSY flag to be (set and then) cleared first. Note that
-        * clearing it only happens when PxCMD.FRE is set, which is why we
-        * start the port before starting the signature wait cycle.
-        */
-       if ((tfd & AHCI_PORT_TFD_STS_BSY) || tfd == AHCI_PORT_TFD_STS_INIT) {
-               /* Try for a while before giving up. It may take seconds. */
-               if (ps->left > 0) {
-                       ps->left--;
-                       set_timer(&ps->cmd_info[0].timer, ahci_sig_delay,
-                               port_timeout, BUILD_ARG(ps - port_state, 0));
-                       return;
-               }
-
-               /* If no device is actually attached, disable the port. This
-                * value is also the initial value of the register, before the
-                * BSY flag gets set, so only check this condition on timeout.
-                */
-               if (tfd == AHCI_PORT_TFD_STS_INIT) {
-                       dprintf(V_DEV, ("%s: no device at this port\n",
-                               ahci_portname(ps)));
-
-                       port_stop(ps);
-
-                       ps->state = STATE_BAD_DEV;
-                       ps->flags &= ~FLAG_BUSY;
-
-                       return;
-               }
-
-               port_restart(ps);
-
-               dprintf(V_ERR, ("%s: timeout waiting for signature\n",
-                       ahci_portname(ps)));
-       }
-
-       /* Check the port's signature. We only support the normal ATA and ATAPI
-        * signatures. We ignore devices reporting anything else.
-        */
-       sig = port_read(ps, AHCI_PORT_SIG);
-
-       if (sig != ATA_SIG_ATA && sig != ATA_SIG_ATAPI) {
-               dprintf(V_ERR, ("%s: unsupported signature (%08x)\n",
-                       ahci_portname(ps), sig));
-
-               port_stop(ps);
-
-               ps->state = STATE_BAD_DEV;
-               ps->flags &= ~FLAG_BUSY;
-
-               return;
-       }
-
-       /* Clear all state flags except the busy flag, which may be relevant if
-        * a BDEV_OPEN call is waiting for the device to become ready; the
-        * barrier flag, which prevents access to the device until it is
-        * completely closed and (re)opened; and, the thread suspension flag.
-        */
-       ps->flags &= (FLAG_BUSY | FLAG_BARRIER | FLAG_SUSPENDED);
-
-       if (sig == ATA_SIG_ATAPI)
-               ps->flags |= FLAG_ATAPI;
-
-       /* Attempt to identify the device. Do this using continuation, because
-        * we may already be called from port_wait() here, and could end up
-        * confusing the timer expiration procedure.
-        */
-       ps->state = STATE_WAIT_ID;
-       port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_MASK);
-
-       (void) gen_identify(ps, FALSE /*blocking*/);
+       port_start(ps);
 }
 
 /*===========================================================================*
@@ -1444,8 +1346,8 @@ static void port_id_check(struct port_state *ps, int success)
        u16_t *buf;
 
        assert(ps->state == STATE_WAIT_ID);
-       assert(!(ps->flags & FLAG_BUSY));       /* unset by callers */
 
+       ps->flags &= ~FLAG_BUSY;
        cancel_timer(&ps->cmd_info[0].timer);
 
        if (!success)
@@ -1509,21 +1411,67 @@ static void port_connect(struct port_state *ps)
        /* A device has been found to be attached to this port. Start the port,
         * and do timed polling for its signature to become available.
         */
+       u32_t status, sig;
 
        dprintf(V_INFO, ("%s: device connected\n", ahci_portname(ps)));
 
-       if (ps->state == STATE_SPIN_UP)
-               cancel_timer(&ps->cmd_info[0].timer);
-
        port_start(ps);
 
-       ps->state = STATE_WAIT_SIG;
-       ps->left = ahci_sig_checks;
+       /* The next check covers a purely hypothetical race condition, where
+        * the device would disappear right before we try to start it. This is
+        * possible because we have to clear PxSERR, and with that, the DIAG.N
+        * bit. Double-check the port status, and if it is not as we expect,
+        * infer a disconnection.
+        */
+       status = port_read(ps, AHCI_PORT_SSTS) & AHCI_PORT_SSTS_DET_MASK;
+
+       if (status != AHCI_PORT_SSTS_DET_PHY) {
+               dprintf(V_ERR, ("%s: device vanished!\n", ahci_portname(ps)));
+
+               port_stop(ps);
+
+               ps->state = STATE_NO_DEV;
+               ps->flags &= ~FLAG_BUSY;
+
+               return;
+       }
+
+       /* Check the port's signature. We only support the normal ATA and ATAPI
+        * signatures. We ignore devices reporting anything else.
+        */
+       sig = port_read(ps, AHCI_PORT_SIG);
+
+       if (sig != ATA_SIG_ATA && sig != ATA_SIG_ATAPI) {
+               dprintf(V_ERR, ("%s: unsupported signature (%08x)\n",
+                       ahci_portname(ps), sig));
+
+               port_stop(ps);
+
+               ps->state = STATE_BAD_DEV;
+               port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
+               ps->flags &= ~FLAG_BUSY;
+
+               return;
+       }
+
+       /* Clear all state flags except the busy flag, which may be relevant if
+        * a BDEV_OPEN call is waiting for the device to become ready; the
+        * barrier flag, which prevents access to the device until it is
+        * completely closed and (re)opened; and, the thread suspension flag.
+        */
+       ps->flags &= (FLAG_BUSY | FLAG_BARRIER | FLAG_SUSPENDED);
+
+       if (sig == ATA_SIG_ATAPI)
+               ps->flags |= FLAG_ATAPI;
 
-       port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
+       /* Attempt to identify the device. Do this using continuation, because
+        * we may already be called from port_wait() here, and could end up
+        * confusing the timer expiration procedure.
+        */
+       ps->state = STATE_WAIT_ID;
+       port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_MASK);
 
-       /* Do the first check immediately; who knows, we may get lucky. */
-       port_sig_check(ps);
+       (void) gen_identify(ps, FALSE /*blocking*/);
 }
 
 /*===========================================================================*
@@ -1531,16 +1479,13 @@ static void port_connect(struct port_state *ps)
  *===========================================================================*/
 static void port_disconnect(struct port_state *ps)
 {
-       /* The device has detached from this port. Stop the port if necessary.
+       /* The device has detached from this port. It has already been stopped.
         */
 
        dprintf(V_INFO, ("%s: device disconnected\n", ahci_portname(ps)));
 
-       if (ps->state != STATE_BAD_DEV)
-               port_stop(ps);
-
        ps->state = STATE_NO_DEV;
-       port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
+       port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PCE);
        ps->flags &= ~FLAG_BUSY;
 
        /* Fail any ongoing request. The caller may already have done this. */
@@ -1556,6 +1501,66 @@ static void port_disconnect(struct port_state *ps)
        blockdriver_mt_set_workers(ps->device, 1);
 }
 
+/*===========================================================================*
+ *                             port_dev_check                               *
+ *===========================================================================*/
+static void port_dev_check(struct port_state *ps)
+{
+       /* Perform device detection by means of polling.
+        */
+       u32_t status, tfd;
+
+       assert(ps->state == STATE_WAIT_DEV);
+
+       status = port_read(ps, AHCI_PORT_SSTS) & AHCI_PORT_SSTS_DET_MASK;
+
+       dprintf(V_DEV, ("%s: polled status %u\n", ahci_portname(ps), status));
+
+       switch (status) {
+       case AHCI_PORT_SSTS_DET_PHY:
+               tfd = port_read(ps, AHCI_PORT_TFD);
+
+               /* If a Phy connection has been established, and the BSY and
+                * DRQ flags are cleared, the device is ready.
+                */
+               if (!(tfd & (AHCI_PORT_TFD_STS_BSY | AHCI_PORT_TFD_STS_DRQ))) {
+                       port_connect(ps);
+
+                       return;
+               }
+
+               /* fall-through */
+       case AHCI_PORT_SSTS_DET_DET:
+               /* A device has been detected, but it is not ready yet. Try for
+                * a while before giving up. This may take seconds.
+                */
+               if (ps->left > 0) {
+                       ps->left--;
+                       set_timer(&ps->cmd_info[0].timer, ahci_device_delay,
+                               port_timeout, BUILD_ARG(ps - port_state, 0));
+                       return;
+               }
+       }
+
+       dprintf(V_INFO, ("%s: device not ready\n", ahci_portname(ps)));
+
+       /* We get here on timeout, and if the HBA reports that there is no
+        * device present at all. In all cases, we change to another state.
+        */
+       if (status == AHCI_PORT_SSTS_DET_PHY) {
+               /* A device is present and initialized, but not ready. */
+               ps->state = STATE_BAD_DEV;
+               port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
+       } else {
+               /* A device may or may not be present, but it does not appear
+                * to be ready in any case. Ignore it until the next device
+                * initialization event.
+                */
+               ps->state = STATE_NO_DEV;
+               ps->flags &= ~FLAG_BUSY;
+       }
+}
+
 /*===========================================================================*
  *                             port_intr                                    *
  *===========================================================================*/
@@ -1564,7 +1569,6 @@ static void port_intr(struct port_state *ps)
        /* Process an interrupt on this port.
         */
        u32_t smask, emask;
-       int connected;
 
        if (ps->state == STATE_NO_PORT) {
                dprintf(V_ERR, ("%s: interrupt for invalid port!\n",
@@ -1584,26 +1588,67 @@ static void port_intr(struct port_state *ps)
        /* Check if any commands have completed. */
        port_check_cmds(ps);
 
-       if (emask & AHCI_PORT_IS_PRCS) {
+       if (emask & AHCI_PORT_IS_PCS) {
+               /* Clear the X diagnostics bit to clear this interrupt. */
+               port_write(ps, AHCI_PORT_SERR, AHCI_PORT_SERR_DIAG_X);
+
+               dprintf(V_DEV, ("%s: device attached\n", ahci_portname(ps)));
+
+               switch (ps->state) {
+               case STATE_SPIN_UP:
+               case STATE_NO_DEV:
+                       /* Reportedly, a device has shown up. Start polling its
+                        * status until it has become ready.
+                        */
+
+                       if (ps->state == STATE_SPIN_UP)
+                               cancel_timer(&ps->cmd_info[0].timer);
+
+                       ps->state = STATE_WAIT_DEV;
+                       ps->left = ahci_device_checks;
+
+                       port_dev_check(ps);
+
+                       break;
+
+               case STATE_WAIT_DEV:
+                       /* Nothing else to do. */
+                       break;
+
+               default:
+                       /* Impossible. */
+                       assert(0);
+               }
+       } else if (emask & AHCI_PORT_IS_PRCS) {
                /* Clear the N diagnostics bit to clear this interrupt. */
                port_write(ps, AHCI_PORT_SERR, AHCI_PORT_SERR_DIAG_N);
 
-               connected = (port_read(ps, AHCI_PORT_SSTS) &
-                       AHCI_PORT_SSTS_DET_MASK) == AHCI_PORT_SSTS_DET_PHY;
+               dprintf(V_DEV, ("%s: device detached\n", ahci_portname(ps)));
 
                switch (ps->state) {
-               case STATE_BAD_DEV:
-               case STATE_GOOD_DEV:
-               case STATE_WAIT_SIG:
                case STATE_WAIT_ID:
-                       port_disconnect(ps);
+               case STATE_GOOD_DEV:
+                       /* The device is no longer ready. Stop the port, cancel
+                        * ongoing requests, and disconnect the device.
+                        */
+                       port_stop(ps);
 
                        /* fall-through */
-               default:
-                       if (!connected)
-                               break;
+               case STATE_BAD_DEV:
+                       port_disconnect(ps);
 
-                       port_connect(ps);
+                       /* The device has become unusable to us at this point.
+                        * Reset the port to make sure that once the device (or
+                        * another device) becomes usable again, we will get a
+                        * PCS interrupt as well.
+                        */
+                       port_hardreset(ps);
+
+                       break;
+
+               default:
+                       /* Impossible. */
+                       assert(0);
                }
        } else if (smask & AHCI_PORT_IS_MASK) {
                /* We assume that any other interrupt indicates command
@@ -1617,7 +1662,6 @@ static void port_intr(struct port_state *ps)
 
                /* If we were waiting for ID verification, check now. */
                if (ps->state == STATE_WAIT_ID) {
-                       ps->flags &= ~FLAG_BUSY;
                        port_id_check(ps, !(port_read(ps, AHCI_PORT_TFD) &
                                (AHCI_PORT_TFD_STS_ERR |
                                AHCI_PORT_TFD_STS_DF)));
@@ -1666,19 +1710,21 @@ static void port_timeout(struct timer *tp)
         * detection and only look for hot plug events from now on.
         */
        if (ps->state == STATE_SPIN_UP) {
-               /* There is one exception: for braindead controllers that don't
-                * generate the right interrupts (cough, VirtualBox), we do an
-                * explicit check to see if a device is connected after all.
-                * Later hot-(un)plug events will not be detected in this case.
+               /* One exception: if the PCS interrupt bit is set here, then we
+                * are probably running on VirtualBox, which is currently not
+                * always raising interrupts when setting interrupt bits (!).
                 */
-               if ((port_read(ps, AHCI_PORT_SSTS) &
-                       AHCI_PORT_SSTS_DET_MASK) == AHCI_PORT_SSTS_DET_PHY) {
-                       dprintf(V_INFO, ("%s: no device connection event\n",
+               if (port_read(ps, AHCI_PORT_IS) & AHCI_PORT_IS_PCS) {
+                       dprintf(V_INFO, ("%s: bad controller, no interrupt\n",
                                ahci_portname(ps)));
 
-                       port_connect(ps);
-               }
-               else {
+                       ps->state = STATE_WAIT_DEV;
+                       ps->left = ahci_device_checks;
+
+                       port_dev_check(ps);
+
+                       return;
+               } else {
                        dprintf(V_INFO, ("%s: spin-up timeout\n",
                                ahci_portname(ps)));
 
@@ -1693,25 +1739,15 @@ static void port_timeout(struct timer *tp)
                return;
        }
 
-       /* If a device has been connected and we are waiting for its signature
-        * to become available, check now.
+       /* If we are waiting for a device to become connected and initialized,
+        * check now.
         */
-       if (ps->state == STATE_WAIT_SIG) {
-               port_sig_check(ps);
+       if (ps->state == STATE_WAIT_DEV) {
+               port_dev_check(ps);
 
                return;
        }
 
-       /* The only case where the busy flag will be set after this is for a
-        * failed identify operation. During this operation, the port will be
-        * in the WAIT_ID state. In that case, we clear the BUSY flag, fail the
-        * command by setting its state, restart port and finish identify op.
-        */
-       if (ps->flags & FLAG_BUSY) {
-               assert(ps->state == STATE_WAIT_ID);
-               ps->flags &= ~FLAG_BUSY;
-       }
-
        dprintf(V_ERR, ("%s: timeout\n", ahci_portname(ps)));
 
        /* Restart the port, failing all current commands. */
@@ -1934,8 +1970,8 @@ static void port_init(struct port_state *ps)
        /* Allocate memory for the port. */
        port_alloc(ps);
 
-       /* Just listen for device status change events for now. */
-       port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE);
+       /* Just listen for device connection events for now. */
+       port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PCE);
 
        /* Enable device spin-up for HBAs that support staggered spin-up.
         * This is a no-op for HBAs that do not support it.
@@ -2190,9 +2226,9 @@ static void ahci_get_params(void)
                *ahci_timevar[i].ptr = millis_to_hz(v);
        }
 
-       ahci_sig_delay = millis_to_hz(SIG_DELAY);
-       ahci_sig_checks =
-               (ahci_sig_timeout + ahci_sig_delay - 1) / ahci_sig_delay;
+       ahci_device_delay = millis_to_hz(DEVICE_DELAY);
+       ahci_device_checks = (ahci_device_timeout + ahci_device_delay - 1) /
+               ahci_device_delay;
 }
 
 /*===========================================================================*
index 3a58e423b22b17f25b4ef6b280731fdca20daa8c..b1ccd664dedaa5c3080df5604476766adb5ad00b 100644 (file)
@@ -8,7 +8,7 @@
 
 /* Time values that can be set with options. */
 #define SPINUP_TIMEOUT         5000    /* initial spin-up time (ms) */
-#define SIG_TIMEOUT            15000   /* time to wait for signature (ms) */
+#define DEVICE_TIMEOUT         30000   /* time to wait for device (ms) */
 #define COMMAND_TIMEOUT                10000   /* time to wait for non-I/O cmd (ms) */
 #define TRANSFER_TIMEOUT       30000   /* time to wait for I/O cmd (ms) */
 #define FLUSH_TIMEOUT          60000   /* time to wait for flush cmd (ms) */
@@ -19,7 +19,7 @@
 #define PORTREG_DELAY          500     /* maximum port register update (ms) */
 
 /* Other hardcoded time values. */
-#define SIG_DELAY              250     /* time between signature checks (ms) */
+#define DEVICE_DELAY           100     /* time between device checks (ms) */
 
 /* Generic FIS layout. */
 #define ATA_FIS_TYPE                   0       /* FIS Type */
 #define        AHCI_PORT_IS_IFS        (1L << 27)      /* Interface Fatal */
 #define        AHCI_PORT_IS_PRCS       (1L << 22)      /* PhyRdy Change */
 #define        AHCI_PORT_IS_PCS        (1L <<  6)      /* Port Conn Change */
-#define        AHCI_PORT_IS_SDBS       (1L <<  3)      /* Set Device Bits FIS */
+#define        AHCI_PORT_IS_SDBS       (1L <<  3)      /* Set Dev Bits FIS */
 #define        AHCI_PORT_IS_PSS        (1L <<  1)      /* PIO Setup FIS */
 #define        AHCI_PORT_IS_DHRS       (1L <<  0)      /* D2H Register FIS */
 #define AHCI_PORT_IS_RESTART \
        (AHCI_PORT_IS_TFES | AHCI_PORT_IS_HBFS | AHCI_PORT_IS_HBDS | \
         AHCI_PORT_IS_IFS)
 #define AHCI_PORT_IS_MASK \
-       (AHCI_PORT_IS_RESTART | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS | \
-        AHCI_PORT_IS_DHRS | AHCI_PORT_IS_PSS | AHCI_PORT_IS_SDBS)
+       (AHCI_PORT_IS_RESTART | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_DHRS | \
+        AHCI_PORT_IS_PSS | AHCI_PORT_IS_SDBS)
 #define AHCI_PORT_IE   5               /* Interrupt Enable */
 #define        AHCI_PORT_IE_MASK       AHCI_PORT_IS_MASK
 #define        AHCI_PORT_IE_PRCE       AHCI_PORT_IS_PRCS
 #define        ATA_SIG_ATAPI           0xEB140101L     /* ATAPI interface */
 #define AHCI_PORT_SSTS 10              /* Serial ATA Status */
 #define        AHCI_PORT_SSTS_DET_MASK 0x00000007L     /* Detection Mask */
+#define        AHCI_PORT_SSTS_DET_DET  0x00000001L     /* Device Detected */
 #define        AHCI_PORT_SSTS_DET_PHY  0x00000003L     /* PHY Comm Establ */
 #define AHCI_PORT_SCTL 11              /* Serial ATA Control */
 #define        AHCI_PORT_SCTL_DET_INIT 0x00000001L     /* Perform Init Seq */
 #define        AHCI_PORT_SCTL_DET_NONE 0x00000000L     /* No Action Req'd */
 #define AHCI_PORT_SERR 12              /* Serial ATA Error */
+#define        AHCI_PORT_SERR_DIAG_X   (1L << 26)      /* Exchanged */
 #define        AHCI_PORT_SERR_DIAG_N   (1L << 16)      /* PhyRdy Change */
 #define AHCI_PORT_SACT 13              /* Serial ATA Active */
 #define AHCI_PORT_CI   14              /* Command Issue */
@@ -269,7 +271,7 @@ enum {
        STATE_NO_PORT,          /* this port is not present */
        STATE_SPIN_UP,          /* waiting for device or timeout after reset */
        STATE_NO_DEV,           /* no device has been detected on this port */
-       STATE_WAIT_SIG,         /* waiting for device signature to appear */
+       STATE_WAIT_DEV,         /* waiting for functioning device to appear */
        STATE_WAIT_ID,          /* waiting for device identification */
        STATE_BAD_DEV,          /* an unusable device has been detected */
        STATE_GOOD_DEV          /* a usable device has been detected */