Index: sys/dev/ahci/ahci.c
===================================================================
--- sys/dev/ahci/ahci.c (revision 223089)
+++ sys/dev/ahci/ahci.c (working copy)
@@ -33,6 +33,7 @@
#include <sys/kernel.h>
#include <sys/ata.h>
#include <sys/bus.h>
+#include <sys/conf.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/lock.h>
@@ -44,6 +45,7 @@
#include <machine/resource.h>
#include <machine/bus.h>
#include <sys/rman.h>
+#include <dev/led/led.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include "ahci.h"
@@ -67,6 +69,7 @@
static void ahci_ch_pm(void *arg);
static void ahci_ch_intr_locked(void *data);
static void ahci_ch_intr(void *data);
+static void ahci_ch_led(void *priv, int onoff);
static int ahci_ctlr_reset(device_t dev);
static int ahci_ctlr_setup(device_t dev);
static void ahci_begin_transaction(device_t dev, union ccb *ccb);
@@ -89,10 +92,11 @@
static int ahci_sata_connect(struct ahci_channel *ch);
static int ahci_sata_phy_reset(device_t dev);
-static int ahci_wait_ready(device_t dev, int t);
+static int ahci_wait_ready(device_t dev, int t, int t0);
-static void ahci_issue_read_log(device_t dev);
+static void ahci_issue_recovery(device_t dev);
static void ahci_process_read_log(device_t dev, union ccb *ccb);
+static void ahci_process_request_sense(device_t dev, union ccb *ccb);
static void ahciaction(struct cam_sim *sim, union ccb *ccb);
static void ahcipoll(struct cam_sim *sim);
@@ -114,6 +118,8 @@
#define AHCI_Q_SATA2 128
#define AHCI_Q_NOBSYRES 256
#define AHCI_Q_NOAA 512
+#define AHCI_Q_NOCOUNT 1024
+#define AHCI_Q_ALTSIG 2048
} ahci_ids[] = {
{0x43801002, 0x00, "ATI IXP600", 0},
{0x43901002, 0x00, "ATI IXP700", 0},
@@ -161,21 +167,45 @@
{0x1c038086, 0x00, "Intel Cougar Point", 0},
{0x1c048086, 0x00, "Intel Cougar Point", 0},
{0x1c058086, 0x00, "Intel Cougar Point", 0},
+ {0x1d028086, 0x00, "Intel Patsburg", 0},
+ {0x1d048086, 0x00, "Intel Patsburg", 0},
+ {0x1d068086, 0x00, "Intel Patsburg", 0},
+ {0x1e028086, 0x00, "Intel Panther Point", 0},
+ {0x1e038086, 0x00, "Intel Panther Point", 0},
+ {0x1e048086, 0x00, "Intel Panther Point", 0},
+ {0x1e058086, 0x00, "Intel Panther Point", 0},
+ {0x1e068086, 0x00, "Intel Panther Point", 0},
+ {0x1e078086, 0x00, "Intel Panther Point", 0},
+ {0x1e0e8086, 0x00, "Intel Panther Point", 0},
+ {0x1e0f8086, 0x00, "Intel Panther Point", 0},
+ {0x23238086, 0x00, "Intel DH89xxCC", 0},
{0x2361197b, 0x00, "JMicron JMB361", AHCI_Q_NOFORCE},
{0x2363197b, 0x00, "JMicron JMB363", AHCI_Q_NOFORCE},
{0x2365197b, 0x00, "JMicron JMB365", AHCI_Q_NOFORCE},
{0x2366197b, 0x00, "JMicron JMB366", AHCI_Q_NOFORCE},
{0x2368197b, 0x00, "JMicron JMB368", AHCI_Q_NOFORCE},
- {0x611111ab, 0x00, "Marvell 88SX6111", AHCI_Q_NOFORCE|AHCI_Q_1CH|AHCI_Q_EDGEIS},
- {0x612111ab, 0x00, "Marvell 88SX6121", AHCI_Q_NOFORCE|AHCI_Q_2CH|AHCI_Q_EDGEIS},
- {0x614111ab, 0x00, "Marvell 88SX6141", AHCI_Q_NOFORCE|AHCI_Q_4CH|AHCI_Q_EDGEIS},
- {0x614511ab, 0x00, "Marvell 88SX6145", AHCI_Q_NOFORCE|AHCI_Q_4CH|AHCI_Q_EDGEIS},
- {0x91231b4b, 0x11, "Marvell 88SE912x", AHCI_Q_NOBSYRES},
+ {0x611111ab, 0x00, "Marvell 88SX6111", AHCI_Q_NOFORCE | AHCI_Q_1CH |
+ AHCI_Q_EDGEIS},
+ {0x612111ab, 0x00, "Marvell 88SX6121", AHCI_Q_NOFORCE | AHCI_Q_2CH |
+ AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT},
+ {0x614111ab, 0x00, "Marvell 88SX6141", AHCI_Q_NOFORCE | AHCI_Q_4CH |
+ AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT},
+ {0x614511ab, 0x00, "Marvell 88SX6145", AHCI_Q_NOFORCE | AHCI_Q_4CH |
+ AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT},
+ {0x91201b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_NOBSYRES},
+ {0x91231b4b, 0x11, "Marvell 88SE912x", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x91231b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_SATA2|AHCI_Q_NOBSYRES},
+ {0x91251b4b, 0x00, "Marvell 88SE9125", AHCI_Q_NOBSYRES},
+ {0x91721b4b, 0x00, "Marvell 88SE9172", AHCI_Q_NOBSYRES},
+ {0x91821b4b, 0x00, "Marvell 88SE9182", AHCI_Q_NOBSYRES},
{0x06201103, 0x00, "HighPoint RocketRAID 620", AHCI_Q_NOBSYRES},
{0x06201b4b, 0x00, "HighPoint RocketRAID 620", AHCI_Q_NOBSYRES},
{0x06221103, 0x00, "HighPoint RocketRAID 622", AHCI_Q_NOBSYRES},
{0x06221b4b, 0x00, "HighPoint RocketRAID 622", AHCI_Q_NOBSYRES},
+ {0x06401103, 0x00, "HighPoint RocketRAID 640", AHCI_Q_NOBSYRES},
+ {0x06401b4b, 0x00, "HighPoint RocketRAID 640", AHCI_Q_NOBSYRES},
+ {0x06441103, 0x00, "HighPoint RocketRAID 644", AHCI_Q_NOBSYRES},
+ {0x06441b4b, 0x00, "HighPoint RocketRAID 644", AHCI_Q_NOBSYRES},
{0x044c10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA},
{0x044d10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA},
{0x044e10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA},
@@ -253,6 +283,12 @@
{0x00000000, 0x00, NULL, 0}
};
+#define recovery_type spriv_field0
+#define RECOVERY_NONE 0
+#define RECOVERY_READ_LOG 1
+#define RECOVERY_REQUEST_SENSE 2
+#define recovery_slot spriv_field1
+
static int
ahci_probe(device_t dev)
{
@@ -365,6 +401,13 @@
if (ctlr->caps & AHCI_CAP_EMS)
ctlr->capsem = ATA_INL(ctlr->r_mem, AHCI_EM_CTL);
ctlr->ichannels = ATA_INL(ctlr->r_mem, AHCI_PI);
+
+ /* Identify and set separate quirks for HBA and RAID f/w Marvells. */
+ if ((ctlr->quirks & AHCI_Q_NOBSYRES) &&
+ (ctlr->quirks & AHCI_Q_ALTSIG) &&
+ (ctlr->caps & AHCI_CAP_SPM) == 0)
+ ctlr->quirks &= ~AHCI_Q_NOBSYRES;
+
if (ctlr->quirks & AHCI_Q_1CH) {
ctlr->caps &= ~AHCI_CAP_NPMASK;
ctlr->ichannels &= 0x01;
@@ -387,6 +430,8 @@
ctlr->caps &= ~AHCI_CAP_SNCQ;
if ((ctlr->caps & AHCI_CAP_CCCS) == 0)
ctlr->ccc = 0;
+ mtx_init(&ctlr->em_mtx, "AHCI EM lock", NULL, MTX_DEF);
+ ctlr->emloc = ATA_INL(ctlr->r_mem, AHCI_EM_LOC);
ahci_ctlr_setup(dev);
/* Setup interrupts. */
if (ahci_setup_interrupt(dev)) {
@@ -490,6 +535,7 @@
rman_fini(&ctlr->sc_iomem);
if (ctlr->r_mem)
bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
+ mtx_destroy(&ctlr->em_mtx);
return (0);
}
@@ -850,18 +896,20 @@
struct cam_devq *devq;
int rid, error, i, sata_rev = 0;
u_int32_t version;
+ char buf[32];
ch->dev = dev;
ch->unit = (intptr_t)device_get_ivars(dev);
ch->caps = ctlr->caps;
ch->caps2 = ctlr->caps2;
ch->quirks = ctlr->quirks;
- ch->numslots = ((ch->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1,
+ ch->numslots = ((ch->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1;
mtx_init(&ch->mtx, "AHCI channel lock", NULL, MTX_DEF);
resource_int_value(device_get_name(dev),
device_get_unit(dev), "pm_level", &ch->pm_level);
if (ch->pm_level > 3)
callout_init_mtx(&ch->pm_timer, &ch->mtx, 0);
+ callout_init_mtx(&ch->reset_timer, &ch->mtx, 0);
/* Limit speed for my onboard JMicron external port.
* It is not eSATA really. */
if (pci_get_devid(ctlr->dev) == 0x2363197b &&
@@ -956,6 +1004,25 @@
ahci_ch_pm, dev);
}
mtx_unlock(&ch->mtx);
+ if ((ch->caps & AHCI_CAP_EMS) &&
+ (ctlr->capsem & AHCI_EM_LED)) {
+ for (i = 0; i < AHCI_NUM_LEDS; i++) {
+ ch->leds[i].dev = dev;
+ ch->leds[i].num = i;
+ }
+ if ((ctlr->capsem & AHCI_EM_ALHD) == 0) {
+ snprintf(buf, sizeof(buf), "%s.act",
+ device_get_nameunit(dev));
+ ch->leds[0].led = led_create(ahci_ch_led,
+ &ch->leds[0], buf);
+ }
+ snprintf(buf, sizeof(buf), "%s.locate",
+ device_get_nameunit(dev));
+ ch->leds[1].led = led_create(ahci_ch_led, &ch->leds[1], buf);
+ snprintf(buf, sizeof(buf), "%s.fault",
+ device_get_nameunit(dev));
+ ch->leds[2].led = led_create(ahci_ch_led, &ch->leds[2], buf);
+ }
return (0);
err3:
@@ -975,9 +1042,19 @@
ahci_ch_detach(device_t dev)
{
struct ahci_channel *ch = device_get_softc(dev);
+ int i;
+ for (i = 0; i < AHCI_NUM_LEDS; i++) {
+ if (ch->leds[i].led)
+ led_destroy(ch->leds[i].led);
+ }
mtx_lock(&ch->mtx);
xpt_async(AC_LOST_DEVICE, ch->path, NULL);
+ /* Forget about reset. */
+ if (ch->resetting) {
+ ch->resetting = 0;
+ xpt_release_simq(ch->sim, TRUE);
+ }
xpt_free_path(ch->path);
xpt_bus_deregister(cam_sim_path(ch->sim));
cam_sim_free(ch->sim, /*free_devq*/TRUE);
@@ -985,6 +1062,7 @@
if (ch->pm_level > 3)
callout_drain(&ch->pm_timer);
+ callout_drain(&ch->reset_timer);
bus_teardown_intr(dev, ch->r_irq, ch->ih);
bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
@@ -1050,6 +1128,12 @@
mtx_lock(&ch->mtx);
xpt_freeze_simq(ch->sim, 1);
+ /* Forget about reset. */
+ if (ch->resetting) {
+ ch->resetting = 0;
+ callout_stop(&ch->reset_timer);
+ xpt_release_simq(ch->sim, TRUE);
+ }
while (ch->oslots)
msleep(ch, &ch->mtx, PRIBIO, "ahcisusp", hz/100);
ahci_ch_deinit(dev);
@@ -1086,6 +1170,47 @@
};
DRIVER_MODULE(ahcich, ahci, ahcich_driver, ahcich_devclass, 0, 0);
+static void
+ahci_ch_setleds(device_t dev)
+{
+ struct ahci_channel *ch;
+ struct ahci_controller *ctlr;
+ size_t buf;
+ int i, timeout;
+ int16_t val;
+
+ ctlr = device_get_softc(device_get_parent(dev));
+ ch = device_get_softc(dev);
+
+ val = 0;
+ for (i = 0; i < AHCI_NUM_LEDS; i++)
+ val |= ch->leds[i].state << (i * 3);
+
+ buf = (ctlr->emloc & 0xffff0000) >> 14;
+ mtx_lock(&ctlr->em_mtx);
+ timeout = 1000;
+ while (ATA_INL(ctlr->r_mem, AHCI_EM_CTL) & (AHCI_EM_TM | AHCI_EM_RST) &&
+ --timeout > 0)
+ DELAY(1000);
+ if (timeout == 0)
+ device_printf(dev, "EM timeout\n");
+ ATA_OUTL(ctlr->r_mem, buf, (1 << 8) | (0 << 16) | (0 << 24));
+ ATA_OUTL(ctlr->r_mem, buf + 4, ch->unit | (val << 16));
+ ATA_OUTL(ctlr->r_mem, AHCI_EM_CTL, AHCI_EM_TM);
+ mtx_unlock(&ctlr->em_mtx);
+}
+
+static void
+ahci_ch_led(void *priv, int onoff)
+{
+ struct ahci_led *led;
+
+ led = (struct ahci_led *)priv;
+
+ led->state = onoff;
+ ahci_ch_setleds(led->dev);
+}
+
struct ahci_dc_cb_args {
bus_addr_t maddr;
int error;
@@ -1230,37 +1355,69 @@
}
}
-static void
+static int
ahci_phy_check_events(device_t dev, u_int32_t serr)
{
struct ahci_channel *ch = device_get_softc(dev);
- if ((serr & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) {
+ if (((ch->pm_level == 0) && (serr & ATA_SE_PHY_CHANGED)) ||
+ ((ch->pm_level != 0 || ch->listening) && (serr & ATA_SE_EXCHANGED))) {
u_int32_t status = ATA_INL(ch->r_mem, AHCI_P_SSTS);
union ccb *ccb;
if (bootverbose) {
- if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) &&
- ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) &&
- ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) {
+ if ((status & ATA_SS_DET_MASK) != ATA_SS_DET_NO_DEVICE)
device_printf(dev, "CONNECT requested\n");
- } else
+ else
device_printf(dev, "DISCONNECT requested\n");
}
ahci_reset(dev);
if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
- return;
+ return (0);
if (xpt_create_path(&ccb->ccb_h.path, NULL,
cam_sim_path(ch->sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xpt_free_ccb(ccb);
- return;
+ return (0);
}
xpt_rescan(ccb);
+ return (1);
}
+ return (0);
}
static void
+ahci_cpd_check_events(device_t dev)
+{
+ struct ahci_channel *ch = device_get_softc(dev);
+ u_int32_t status;
+ union ccb *ccb;
+
+ if (ch->pm_level == 0)
+ return;
+
+ status = ATA_INL(ch->r_mem, AHCI_P_CMD);
+ if ((status & AHCI_P_CMD_CPD) == 0)
+ return;
+
+ if (bootverbose) {
+ if (status & AHCI_P_CMD_CPS) {
+ device_printf(dev, "COLD CONNECT requested\n");
+ } else
+ device_printf(dev, "COLD DISCONNECT requested\n");
+ }
+ ahci_reset(dev);
+ if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
+ return;
+ if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(ch->sim),
+ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ xpt_free_ccb(ccb);
+ return;
+ }
+ xpt_rescan(ccb);
+}
+
+static void
ahci_notify_events(device_t dev, u_int32_t status)
{
struct ahci_channel *ch = device_get_softc(dev);
@@ -1317,7 +1474,7 @@
struct ahci_channel *ch = device_get_softc(dev);
uint32_t istatus, sstatus, cstatus, serr = 0, sntf = 0, ok, err;
enum ahci_err_type et;
- int i, ccs, port;
+ int i, ccs, port, reset = 0;
/* Read and clear interrupt statuses. */
istatus = ATA_INL(ch->r_mem, AHCI_P_IS);
@@ -1353,9 +1510,12 @@
serr = ATA_INL(ch->r_mem, AHCI_P_SERR);
if (serr) {
ATA_OUTL(ch->r_mem, AHCI_P_SERR, serr);
- ahci_phy_check_events(dev, serr);
+ reset = ahci_phy_check_events(dev, serr);
}
}
+ /* Process cold presence detection events */
+ if ((istatus & AHCI_P_IX_CPD) && !reset)
+ ahci_cpd_check_events(dev);
/* Process command errors */
if (istatus & (AHCI_P_IX_OF | AHCI_P_IX_IF |
AHCI_P_IX_HBD | AHCI_P_IX_HBF | AHCI_P_IX_TFE)) {
@@ -1445,7 +1605,7 @@
* We can't reinit port if there are some other
* commands active, use resume to complete them.
*/
- if (ch->rslots != 0)
+ if (ch->rslots != 0 && !ch->recoverycmd)
ATA_OUTL(ch->r_mem, AHCI_P_FBS, AHCI_P_FBS_EN | AHCI_P_FBS_DEC);
}
/* Process NOTIFY events */
@@ -1607,7 +1767,7 @@
struct ahci_cmd_list *clp;
union ccb *ccb = slot->ccb;
int port = ccb->ccb_h.target_id & 0x0f;
- int fis_size, i;
+ int fis_size, i, softreset;
uint8_t *fis = ch->dma.rfis + 0x40;
uint8_t val;
@@ -1634,17 +1794,20 @@
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
(ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL)) {
if (ccb->ataio.cmd.control & ATA_A_RESET) {
+ softreset = 1;
/* Kick controller into sane state */
ahci_stop(dev);
ahci_clo(dev);
ahci_start(dev, 0);
clp->cmd_flags |= AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY;
} else {
+ softreset = 2;
/* Prepare FIS receive area for check. */
for (i = 0; i < 20; i++)
fis[i] = 0xff;
}
- }
+ } else
+ softreset = 0;
clp->bytecount = 0;
clp->cmd_table_phys = htole64(ch->dma.work_bus + AHCI_CT_OFFSET +
(AHCI_CT_SIZE * slot->slot));
@@ -1668,19 +1831,21 @@
ATA_OUTL(ch->r_mem, AHCI_P_CI, (1 << slot->slot));
/* Device reset commands doesn't interrupt. Poll them. */
if (ccb->ccb_h.func_code == XPT_ATA_IO &&
- (ccb->ataio.cmd.command == ATA_DEVICE_RESET ||
- (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL))) {
- int count, timeout = ccb->ccb_h.timeout;
+ (ccb->ataio.cmd.command == ATA_DEVICE_RESET || softreset)) {
+ int count, timeout = ccb->ccb_h.timeout * 100;
enum ahci_err_type et = AHCI_ERR_NONE;
for (count = 0; count < timeout; count++) {
- DELAY(1000);
+ DELAY(10);
if (!(ATA_INL(ch->r_mem, AHCI_P_CI) & (1 << slot->slot)))
break;
- if (ATA_INL(ch->r_mem, AHCI_P_TFD) & ATA_S_ERROR) {
+ if ((ATA_INL(ch->r_mem, AHCI_P_TFD) & ATA_S_ERROR) &&
+ softreset != 1) {
+#if 0
device_printf(ch->dev,
"Poll error on slot %d, TFD: %04x\n",
slot->slot, ATA_INL(ch->r_mem, AHCI_P_TFD));
+#endif
et = AHCI_ERR_TFE;
break;
}
@@ -1692,9 +1857,20 @@
break;
}
}
+
+ /* Marvell controllers do not wait for readyness. */
+ if ((ch->quirks & AHCI_Q_NOBSYRES) && softreset == 2 &&
+ et == AHCI_ERR_NONE) {
+ while ((val = fis[2]) & ATA_S_BUSY) {
+ DELAY(10);
+ if (count++ >= timeout)
+ break;
+ }
+ }
+
if (timeout && (count >= timeout)) {
- device_printf(ch->dev,
- "Poll timeout on slot %d\n", slot->slot);
+ device_printf(dev, "Poll timeout on slot %d port %d\n",
+ slot->slot, port);
device_printf(dev, "is %08x cs %08x ss %08x "
"rs %08x tfd %02x serr %08x\n",
ATA_INL(ch->r_mem, AHCI_P_IS),
@@ -1704,30 +1880,11 @@
ATA_INL(ch->r_mem, AHCI_P_SERR));
et = AHCI_ERR_TIMEOUT;
}
- /* Marvell controllers do not wait for readyness. */
- if ((ch->quirks & AHCI_Q_NOBSYRES) &&
- (ccb->ccb_h.func_code == XPT_ATA_IO) &&
- (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
- (ccb->ataio.cmd.control & ATA_A_RESET) == 0) {
- while ((val = fis[2]) & (ATA_S_BUSY | ATA_S_DRQ)) {
- DELAY(1000);
- if (count++ >= timeout) {
- device_printf(dev, "device is not "
- "ready after soft-reset: "
- "tfd = %08x\n", val);
- et = AHCI_ERR_TIMEOUT;
- break;
- }
- }
- }
+
+ /* Kick controller into sane state and enable FBS. */
+ if (softreset == 2)
+ ch->eslots |= (1 << slot->slot);
ahci_end_transaction(slot, et);
- /* Kick controller into sane state and enable FBS. */
- if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
- (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
- (ccb->ataio.cmd.control & ATA_A_RESET) == 0) {
- ahci_stop(ch->dev);
- ahci_start(ch->dev, 1);
- }
return;
}
/* Start command execution timeout */
@@ -1805,7 +1962,8 @@
return;
}
- device_printf(dev, "Timeout on slot %d\n", slot->slot);
+ device_printf(dev, "Timeout on slot %d port %d\n",
+ slot->slot, slot->ccb->ccb_h.target_id & 0x0f);
device_printf(dev, "is %08x cs %08x ss %08x rs %08x tfd %02x serr %08x\n",
ATA_INL(ch->r_mem, AHCI_P_IS), ATA_INL(ch->r_mem, AHCI_P_CI),
ATA_INL(ch->r_mem, AHCI_P_SACT), ch->rslots,
@@ -1856,6 +2014,7 @@
union ccb *ccb = slot->ccb;
struct ahci_cmd_list *clp;
int lastto;
+ uint32_t sig;
bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
@@ -1893,15 +2052,31 @@
res->lba_high_exp = fis[10];
res->sector_count = fis[12];
res->sector_count_exp = fis[13];
+
+ /*
+ * Some weird controllers do not return signature in
+ * FIS receive area. Read it from PxSIG register.
+ */
+ if ((ch->quirks & AHCI_Q_ALTSIG) &&
+ (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
+ (ccb->ataio.cmd.control & ATA_A_RESET) == 0) {
+ sig = ATA_INL(ch->r_mem, AHCI_P_SIG);
+ res->lba_high = sig >> 24;
+ res->lba_mid = sig >> 16;
+ res->lba_low = sig >> 8;
+ res->sector_count = sig;
+ }
} else
bzero(res, sizeof(*res));
if ((ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA) == 0 &&
- (ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ (ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE &&
+ (ch->quirks & AHCI_Q_NOCOUNT) == 0) {
ccb->ataio.resid =
ccb->ataio.dxfer_len - le32toh(clp->bytecount);
}
} else {
- if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE &&
+ (ch->quirks & AHCI_Q_NOCOUNT) == 0) {
ccb->csio.resid =
ccb->csio.dxfer_len - le32toh(clp->bytecount);
}
@@ -1915,7 +2090,7 @@
if (et != AHCI_ERR_NONE)
ch->eslots |= (1 << slot->slot);
/* In case of error, freeze device for proper recovery. */
- if ((et != AHCI_ERR_NONE) && (!ch->readlog) &&
+ if ((et != AHCI_ERR_NONE) && (!ch->recoverycmd) &&
!(ccb->ccb_h.status & CAM_DEV_QFRZN)) {
xpt_freeze_devq(ccb->ccb_h.path, 1);
ccb->ccb_h.status |= CAM_DEV_QFRZN;
@@ -1946,7 +2121,7 @@
break;
case AHCI_ERR_SATA:
ch->fatalerr = 1;
- if (!ch->readlog) {
+ if (!ch->recoverycmd) {
xpt_freeze_simq(ch->sim, 1);
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
@@ -1954,7 +2129,7 @@
ccb->ccb_h.status |= CAM_UNCOR_PARITY;
break;
case AHCI_ERR_TIMEOUT:
- if (!ch->readlog) {
+ if (!ch->recoverycmd) {
xpt_freeze_simq(ch->sim, 1);
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
@@ -1997,21 +2172,19 @@
return;
}
/* If it was our READ LOG command - process it. */
- if (ch->readlog) {
+ if (ccb->ccb_h.recovery_type == RECOVERY_READ_LOG) {
ahci_process_read_log(dev, ccb);
- /* If it was NCQ command error, put result on hold. */
- } else if (et == AHCI_ERR_NCQ) {
+ /* If it was our REQUEST SENSE command - process it. */
+ } else if (ccb->ccb_h.recovery_type == RECOVERY_REQUEST_SENSE) {
+ ahci_process_request_sense(dev, ccb);
+ /* If it was NCQ or ATAPI command error, put result on hold. */
+ } else if (et == AHCI_ERR_NCQ ||
+ ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR &&
+ (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)) {
ch->hold[slot->slot] = ccb;
ch->numhslots++;
} else
xpt_done(ccb);
- /* Unfreeze frozen command. */
- if (ch->frozen && !ahci_check_collision(dev, ch->frozen)) {
- union ccb *fccb = ch->frozen;
- ch->frozen = NULL;
- ahci_begin_transaction(dev, fccb);
- xpt_release_simq(ch->sim, TRUE);
- }
/* If we have no other active commands, ... */
if (ch->rslots == 0) {
/* if there was fatal error - reset port. */
@@ -2021,16 +2194,24 @@
/* if we have slots in error, we can reinit port. */
if (ch->eslots != 0) {
ahci_stop(dev);
+ ahci_clo(dev);
ahci_start(dev, 1);
}
/* if there commands on hold, we can do READ LOG. */
- if (!ch->readlog && ch->numhslots)
- ahci_issue_read_log(dev);
+ if (!ch->recoverycmd && ch->numhslots)
+ ahci_issue_recovery(dev);
}
/* If all the rest of commands are in timeout - give them chance. */
} else if ((ch->rslots & ~ch->toslots) == 0 &&
et != AHCI_ERR_TIMEOUT)
ahci_rearm_timeout(dev);
+ /* Unfreeze frozen command. */
+ if (ch->frozen && !ahci_check_collision(dev, ch->frozen)) {
+ union ccb *fccb = ch->frozen;
+ ch->frozen = NULL;
+ ahci_begin_transaction(dev, fccb);
+ xpt_release_simq(ch->sim, TRUE);
+ }
/* Start PM timer. */
if (ch->numrslots == 0 && ch->pm_level > 3 &&
(ch->curr[ch->pm_present ? 15 : 0].caps & CTS_SATA_CAPS_D_PMREQ)) {
@@ -2040,45 +2221,78 @@
}
static void
-ahci_issue_read_log(device_t dev)
+ahci_issue_recovery(device_t dev)
{
struct ahci_channel *ch = device_get_softc(dev);
union ccb *ccb;
struct ccb_ataio *ataio;
+ struct ccb_scsiio *csio;
int i;
- ch->readlog = 1;
- /* Find some holden command. */
+ /* Find some held command. */
for (i = 0; i < ch->numslots; i++) {
if (ch->hold[i])
break;
}
ccb = xpt_alloc_ccb_nowait();
if (ccb == NULL) {
- device_printf(dev, "Unable allocate READ LOG command");
- return; /* XXX */
+ device_printf(dev, "Unable to allocate recovery command\n");
+completeall:
+ /* We can't do anything -- complete held commands. */
+ for (i = 0; i < ch->numslots; i++) {
+ if (ch->hold[i] == NULL)
+ continue;
+ ch->hold[i]->ccb_h.status &= ~CAM_STATUS_MASK;
+ ch->hold[i]->ccb_h.status |= CAM_RESRC_UNAVAIL;
+ xpt_done(ch->hold[i]);
+ ch->hold[i] = NULL;
+ ch->numhslots--;
+ }
+ ahci_reset(dev);
+ return;
}
ccb->ccb_h = ch->hold[i]->ccb_h; /* Reuse old header. */
- ccb->ccb_h.func_code = XPT_ATA_IO;
- ccb->ccb_h.flags = CAM_DIR_IN;
- ccb->ccb_h.timeout = 1000; /* 1s should be enough. */
- ataio = &ccb->ataio;
- ataio->data_ptr = malloc(512, M_AHCI, M_NOWAIT);
- if (ataio->data_ptr == NULL) {
- xpt_free_ccb(ccb);
- device_printf(dev, "Unable allocate memory for READ LOG command");
- return; /* XXX */
+ if (ccb->ccb_h.func_code == XPT_ATA_IO) {
+ /* READ LOG */
+ ccb->ccb_h.recovery_type = RECOVERY_READ_LOG;
+ ccb->ccb_h.func_code = XPT_ATA_IO;
+ ccb->ccb_h.flags = CAM_DIR_IN;
+ ccb->ccb_h.timeout = 1000; /* 1s should be enough. */
+ ataio = &ccb->ataio;
+ ataio->data_ptr = malloc(512, M_AHCI, M_NOWAIT);
+ if (ataio->data_ptr == NULL) {
+ xpt_free_ccb(ccb);
+ device_printf(dev,
+ "Unable to allocate memory for READ LOG command\n");
+ goto completeall;
+ }
+ ataio->dxfer_len = 512;
+ bzero(&ataio->cmd, sizeof(ataio->cmd));
+ ataio->cmd.flags = CAM_ATAIO_48BIT;
+ ataio->cmd.command = 0x2F; /* READ LOG EXT */
+ ataio->cmd.sector_count = 1;
+ ataio->cmd.sector_count_exp = 0;
+ ataio->cmd.lba_low = 0x10;
+ ataio->cmd.lba_mid = 0;
+ ataio->cmd.lba_mid_exp = 0;
+ } else {
+ /* REQUEST SENSE */
+ ccb->ccb_h.recovery_type = RECOVERY_REQUEST_SENSE;
+ ccb->ccb_h.recovery_slot = i;
+ ccb->ccb_h.func_code = XPT_SCSI_IO;
+ ccb->ccb_h.flags = CAM_DIR_IN;
+ ccb->ccb_h.status = 0;
+ ccb->ccb_h.timeout = 1000; /* 1s should be enough. */
+ csio = &ccb->csio;
+ csio->data_ptr = (void *)&ch->hold[i]->csio.sense_data;
+ csio->dxfer_len = ch->hold[i]->csio.sense_len;
+ csio->cdb_len = 6;
+ bzero(&csio->cdb_io, sizeof(csio->cdb_io));
+ csio->cdb_io.cdb_bytes[0] = 0x03;
+ csio->cdb_io.cdb_bytes[4] = csio->dxfer_len;
}
- ataio->dxfer_len = 512;
- bzero(&ataio->cmd, sizeof(ataio->cmd));
- ataio->cmd.flags = CAM_ATAIO_48BIT;
- ataio->cmd.command = 0x2F; /* READ LOG EXT */
- ataio->cmd.sector_count = 1;
- ataio->cmd.sector_count_exp = 0;
- ataio->cmd.lba_low = 0x10;
- ataio->cmd.lba_mid = 0;
- ataio->cmd.lba_mid_exp = 0;
- /* Freeze SIM while doing READ LOG EXT. */
+ /* Freeze SIM while doing recovery. */
+ ch->recoverycmd = 1;
xpt_freeze_simq(ch->sim, 1);
ahci_begin_transaction(dev, ccb);
}
@@ -2091,7 +2305,7 @@
struct ata_res *res;
int i;
- ch->readlog = 0;
+ ch->recoverycmd = 0;
data = ccb->ataio.data_ptr;
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
@@ -2099,6 +2313,8 @@
for (i = 0; i < ch->numslots; i++) {
if (!ch->hold[i])
continue;
+ if (ch->hold[i]->ccb_h.func_code != XPT_ATA_IO)
+ continue;
if ((data[0] & 0x1F) == i) {
res = &ch->hold[i]->ataio.res;
res->status = data[2];
@@ -2129,6 +2345,8 @@
for (i = 0; i < ch->numslots; i++) {
if (!ch->hold[i])
continue;
+ if (ch->hold[i]->ccb_h.func_code != XPT_ATA_IO)
+ continue;
xpt_done(ch->hold[i]);
ch->hold[i] = NULL;
ch->numhslots--;
@@ -2140,6 +2358,28 @@
}
static void
+ahci_process_request_sense(device_t dev, union ccb *ccb)
+{
+ struct ahci_channel *ch = device_get_softc(dev);
+ int i;
+
+ ch->recoverycmd = 0;
+
+ i = ccb->ccb_h.recovery_slot;
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+ ch->hold[i]->ccb_h.status |= CAM_AUTOSNS_VALID;
+ } else {
+ ch->hold[i]->ccb_h.status &= ~CAM_STATUS_MASK;
+ ch->hold[i]->ccb_h.status |= CAM_AUTOSENSE_FAIL;
+ }
+ xpt_done(ch->hold[i]);
+ ch->hold[i] = NULL;
+ ch->numhslots--;
+ xpt_free_ccb(ccb);
+ xpt_release_simq(ch->sim, TRUE);
+}
+
+static void
ahci_start(device_t dev, int fbs)
{
struct ahci_channel *ch = device_get_softc(dev);
@@ -2175,8 +2415,8 @@
/* Wait for activity stop. */
timeout = 0;
do {
- DELAY(1000);
- if (timeout++ > 1000) {
+ DELAY(10);
+ if (timeout++ > 50000) {
device_printf(dev, "stopping AHCI engine failed\n");
break;
}
@@ -2198,8 +2438,8 @@
ATA_OUTL(ch->r_mem, AHCI_P_CMD, cmd);
timeout = 0;
do {
- DELAY(1000);
- if (timeout++ > 1000) {
+ DELAY(10);
+ if (timeout++ > 50000) {
device_printf(dev, "executing CLO failed\n");
break;
}
@@ -2220,8 +2460,8 @@
/* Wait for FIS reception stop. */
timeout = 0;
do {
- DELAY(1000);
- if (timeout++ > 1000) {
+ DELAY(10);
+ if (timeout++ > 50000) {
device_printf(dev, "stopping AHCI FR engine failed\n");
break;
}
@@ -2240,7 +2480,7 @@
}
static int
-ahci_wait_ready(device_t dev, int t)
+ahci_wait_ready(device_t dev, int t, int t0)
{
struct ahci_channel *ch = device_get_softc(dev);
int timeout = 0;
@@ -2248,19 +2488,50 @@
while ((val = ATA_INL(ch->r_mem, AHCI_P_TFD)) &
(ATA_S_BUSY | ATA_S_DRQ)) {
- DELAY(1000);
- if (timeout++ > t) {
- device_printf(dev, "device is not ready (timeout %dms) "
- "tfd = %08x\n", t, val);
+ if (timeout > t) {
+ if (t != 0) {
+ device_printf(dev,
+ "AHCI reset: device not ready after %dms "
+ "(tfd = %08x)\n",
+ MAX(t, 0) + t0, val);
+ }
return (EBUSY);
}
- }
+ DELAY(1000);
+ timeout++;
+ }
if (bootverbose)
- device_printf(dev, "ready wait time=%dms\n", timeout);
+ device_printf(dev, "AHCI reset: device ready after %dms\n",
+ timeout + t0);
return (0);
}
static void
+ahci_reset_to(void *arg)
+{
+ device_t dev = arg;
+ struct ahci_channel *ch = device_get_softc(dev);
+
+ if (ch->resetting == 0)
+ return;
+ ch->resetting--;
+ if (ahci_wait_ready(dev, ch->resetting == 0 ? -1 : 0,
+ (310 - ch->resetting) * 100) == 0) {
+ ch->resetting = 0;
+ ahci_start(dev, 1);
+ xpt_release_simq(ch->sim, TRUE);
+ return;
+ }
+ if (ch->resetting == 0) {
+ ahci_clo(dev);
+ ahci_start(dev, 1);
+ xpt_release_simq(ch->sim, TRUE);
+ return;
+ }
+ callout_schedule(&ch->reset_timer, hz / 10);
+}
+
+static void
ahci_reset(device_t dev)
{
struct ahci_channel *ch = device_get_softc(dev);
@@ -2270,6 +2541,12 @@
xpt_freeze_simq(ch->sim, 1);
if (bootverbose)
device_printf(dev, "AHCI reset...\n");
+ /* Forget about previous reset. */
+ if (ch->resetting) {
+ ch->resetting = 0;
+ callout_stop(&ch->reset_timer);
+ xpt_release_simq(ch->sim, TRUE);
+ }
/* Requeue freezed command. */
if (ch->frozen) {
union ccb *fccb = ch->frozen;
@@ -2310,29 +2587,39 @@
if (!ahci_sata_phy_reset(dev)) {
if (bootverbose)
device_printf(dev,
- "AHCI reset done: phy reset found no device\n");
+ "AHCI reset: device not found\n");
ch->devices = 0;
/* Enable wanted port interrupts */
ATA_OUTL(ch->r_mem, AHCI_P_IE,
- (AHCI_P_IX_CPD | AHCI_P_IX_PRC | AHCI_P_IX_PC));
+ (((ch->pm_level != 0) ? AHCI_P_IX_CPD | AHCI_P_IX_MP : 0) |
+ AHCI_P_IX_PRC | AHCI_P_IX_PC));
xpt_release_simq(ch->sim, TRUE);
return;
}
+ if (bootverbose)
+ device_printf(dev, "AHCI reset: device found\n");
/* Wait for clearing busy status. */
- if (ahci_wait_ready(dev, 15000))
- ahci_clo(dev);
- ahci_start(dev, 1);
+ if (ahci_wait_ready(dev, dumping ? 31000 : 0, 0)) {
+ if (dumping)
+ ahci_clo(dev);
+ else
+ ch->resetting = 310;
+ }
ch->devices = 1;
/* Enable wanted port interrupts */
ATA_OUTL(ch->r_mem, AHCI_P_IE,
- (AHCI_P_IX_CPD | AHCI_P_IX_TFE | AHCI_P_IX_HBF |
+ (((ch->pm_level != 0) ? AHCI_P_IX_CPD | AHCI_P_IX_MP : 0) |
+ AHCI_P_IX_TFE | AHCI_P_IX_HBF |
AHCI_P_IX_HBD | AHCI_P_IX_IF | AHCI_P_IX_OF |
- ((ch->pm_level == 0) ? AHCI_P_IX_PRC | AHCI_P_IX_PC : 0) |
+ ((ch->pm_level == 0) ? AHCI_P_IX_PRC : 0) | AHCI_P_IX_PC |
AHCI_P_IX_DP | AHCI_P_IX_UF | (ctlr->ccc ? 0 : AHCI_P_IX_SDB) |
AHCI_P_IX_DS | AHCI_P_IX_PS | (ctlr->ccc ? 0 : AHCI_P_IX_DHR)));
- if (bootverbose)
- device_printf(dev, "AHCI reset done: device found\n");
- xpt_release_simq(ch->sim, TRUE);
+ if (ch->resetting)
+ callout_reset(&ch->reset_timer, hz / 10, ahci_reset_to, dev);
+ else {
+ ahci_start(dev, 1);
+ xpt_release_simq(ch->sim, TRUE);
+ }
}
static int
@@ -2390,11 +2677,13 @@
ahci_sata_connect(struct ahci_channel *ch)
{
u_int32_t status;
- int timeout;
+ int timeout, found = 0;
/* Wait up to 100ms for "connect well" */
- for (timeout = 0; timeout < 100 ; timeout++) {
+ for (timeout = 0; timeout < 1000 ; timeout++) {
status = ATA_INL(ch->r_mem, AHCI_P_SSTS);
+ if ((status & ATA_SS_DET_MASK) != ATA_SS_DET_NO_DEVICE)
+ found = 1;
if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) &&
((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) &&
((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE))
@@ -2406,18 +2695,21 @@
}
return (0);
}
- DELAY(1000);
+ if (found == 0 && timeout >= 100)
+ break;
+ DELAY(100);
}
- if (timeout >= 100) {
+ if (timeout >= 1000 || !found) {
if (bootverbose) {
- device_printf(ch->dev, "SATA connect timeout status=%08x\n",
- status);
+ device_printf(ch->dev,
+ "SATA connect timeout time=%dus status=%08x\n",
+ timeout * 100, status);
}
return (0);
}
if (bootverbose) {
- device_printf(ch->dev, "SATA connect time=%dms status=%08x\n",
- timeout, status);
+ device_printf(ch->dev, "SATA connect time=%dus status=%08x\n",
+ timeout * 100, status);
}
/* Clear SATA error register */
ATA_OUTL(ch->r_mem, AHCI_P_SERR, 0xffffffff);
@@ -2431,6 +2723,12 @@
int sata_rev;
uint32_t val;
+ if (ch->listening) {
+ val = ATA_INL(ch->r_mem, AHCI_P_CMD);
+ val |= AHCI_P_CMD_SUD;
+ ATA_OUTL(ch->r_mem, AHCI_P_CMD, val);
+ ch->listening = 0;
+ }
sata_rev = ch->user[ch->pm_present ? 15 : 0].revision;
if (sata_rev == 1)
val = ATA_SC_SPD_SPEED_GEN1;
@@ -2443,13 +2741,17 @@
ATA_OUTL(ch->r_mem, AHCI_P_SCTL,
ATA_SC_DET_RESET | val |
ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER);
- DELAY(5000);
+ DELAY(1000);
ATA_OUTL(ch->r_mem, AHCI_P_SCTL,
ATA_SC_DET_IDLE | val | ((ch->pm_level > 0) ? 0 :
(ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)));
- DELAY(5000);
if (!ahci_sata_connect(ch)) {
- if (ch->pm_level > 0)
+ if (ch->caps & AHCI_CAP_SSS) {
+ val = ATA_INL(ch->r_mem, AHCI_P_CMD);
+ val &= ~AHCI_P_CMD_SUD;
+ ATA_OUTL(ch->r_mem, AHCI_P_CMD, val);
+ ch->listening = 1;
+ } else if (ch->pm_level > 0)
ATA_OUTL(ch->r_mem, AHCI_P_SCTL, ATA_SC_DET_DISABLE);
return (0);
}
@@ -2497,6 +2799,7 @@
ccb->ccb_h.status = CAM_SEL_TIMEOUT;
break;
}
+ ccb->ccb_h.recovery_type = RECOVERY_NONE;
/* Check for command collision. */
if (ahci_check_collision(dev, ccb)) {
/* Freeze command. */
@@ -2662,4 +2965,9 @@
struct ahci_channel *ch = (struct ahci_channel *)cam_sim_softc(sim);
ahci_ch_intr(ch->dev);
+ if (ch->resetting != 0 &&
+ (--ch->resetpolldiv <= 0 || !callout_pending(&ch->reset_timer))) {
+ ch->resetpolldiv = 1000;
+ ahci_reset_to(ch->dev);
+ }
}
Index: sys/dev/ahci/ahci.h
===================================================================
--- sys/dev/ahci/ahci.h (revision 223089)
+++ sys/dev/ahci/ahci.h (working copy)
@@ -118,6 +118,7 @@
#define ATA_SE_LINKSEQ_ERR 0x00800000
#define ATA_SE_TRANSPORT_ERR 0x01000000
#define ATA_SE_UNKNOWN_FIS 0x02000000
+#define ATA_SE_EXCHANGED 0x04000000
#define ATA_SCONTROL 15
#define ATA_SC_DET_MASK 0x0000000f
@@ -221,7 +222,7 @@
#define AHCI_P_IX_UF 0x00000010
#define AHCI_P_IX_DP 0x00000020
#define AHCI_P_IX_PC 0x00000040
-#define AHCI_P_IX_DI 0x00000080
+#define AHCI_P_IX_MP 0x00000080
#define AHCI_P_IX_PRC 0x00400000
#define AHCI_P_IX_IPM 0x00800000
@@ -375,6 +376,15 @@
u_int caps;
};
+struct ahci_led {
+ device_t dev; /* Device handle */
+ struct cdev *led;
+ uint8_t num; /* Number of this led */
+ uint8_t state; /* State of this led */
+};
+
+#define AHCI_NUM_LEDS 3
+
/* structure describing an ATA channel */
struct ahci_channel {
device_t dev; /* Device handle */
@@ -385,6 +395,7 @@
struct ata_dma dma; /* DMA data */
struct cam_sim *sim;
struct cam_path *path;
+ struct ahci_led leds[3];
uint32_t caps; /* Controller capabilities */
uint32_t caps2; /* Controller capabilities */
uint32_t chcaps; /* Channel capabilities */
@@ -407,13 +418,17 @@
int numrslotspd[16];/* Number of running slots per dev */
int numtslots; /* Number of tagged slots */
int numtslotspd[16];/* Number of tagged slots per dev */
- int numhslots; /* Number of holden slots */
- int readlog; /* Our READ LOG active */
+ int numhslots; /* Number of held slots */
+ int recoverycmd; /* Our READ LOG active */
int fatalerr; /* Fatal error happend */
int lastslot; /* Last used slot */
int taggedtarget; /* Last tagged target */
+ int resetting; /* Hard-reset in progress. */
+ int resetpolldiv; /* Hard-reset poll divider. */
+ int listening; /* SUD bit is cleared. */
union ccb *frozen; /* Frozen command */
struct callout pm_timer; /* Power management events */
+ struct callout reset_timer; /* Hard-reset timeout */
struct ahci_device user[16]; /* User-specified settings */
struct ahci_device curr[16]; /* Current settings */
@@ -438,6 +453,7 @@
uint32_t caps; /* Controller capabilities */
uint32_t caps2; /* Controller capabilities */
uint32_t capsem; /* Controller capabilities */
+ uint32_t emloc; /* EM buffer location */
int quirks;
int numirqs;
int channels;
@@ -448,6 +464,7 @@
void (*function)(void *);
void *argument;
} interrupt[AHCI_MAX_PORTS];
+ struct mtx em_mtx; /* EM access lock */
};
enum ahci_err_type {