ahci: device detection rewrite

- 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).
This commit is contained in:
David van Moolenbroek 2013-02-13 14:22:45 +00:00
parent 23b12e29a2
commit eb89b33d39
2 changed files with 245 additions and 207 deletions

View file

@ -31,7 +31,7 @@
* | | | ^ |
* v v | | |
* +----------+ +----------+ +----------+ +----------+ |
* | NO_DEV | --> | WAIT_SIG | --> | WAIT_ID | --> | GOOD_DEV | |
* | NO_DEV | --> | WAIT_DEV | --> | WAIT_ID | --> | GOOD_DEV | |
* +----------+ +----------+ +----------+ +----------+ |
* ^ | | | |
* +----------------+----------------+----------------+--------+
@ -60,6 +60,14 @@
* 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.
@ -67,16 +75,16 @@
* 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;
@ -197,7 +205,7 @@ static struct {
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_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 }
@ -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;
/* Do the first check immediately; who knows, we may get lucky. */
port_sig_check(ps);
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*/);
}
/*===========================================================================*
@ -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)
case STATE_BAD_DEV:
port_disconnect(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;
port_connect(ps);
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;
}
/*===========================================================================*

View 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 */
@ -174,15 +174,15 @@
#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
@ -205,11 +205,13 @@
#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 */