From owner-svn-src-all@FreeBSD.ORG Thu Jan 28 17:54:48 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 64BB71065670; Thu, 28 Jan 2010 17:54:48 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 128B78FC08; Thu, 28 Jan 2010 17:54:48 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o0SHsmlK010554; Thu, 28 Jan 2010 17:54:48 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o0SHsmWR010551; Thu, 28 Jan 2010 17:54:48 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201001281754.o0SHsmWR010551@svn.freebsd.org> From: Alexander Motin Date: Thu, 28 Jan 2010 17:54:48 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r203123 - head/sys/dev/ahci X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Jan 2010 17:54:48 -0000 Author: mav Date: Thu Jan 28 17:54:47 2010 New Revision: 203123 URL: http://svn.freebsd.org/changeset/base/203123 Log: Add FIS-based switching support. If controller supports FBS, it allows several devices beyond Port Multiplier to work simultaneously, substantially increasing performance. Modified: head/sys/dev/ahci/ahci.c head/sys/dev/ahci/ahci.h Modified: head/sys/dev/ahci/ahci.c ============================================================================== --- head/sys/dev/ahci/ahci.c Thu Jan 28 17:09:47 2010 (r203122) +++ head/sys/dev/ahci/ahci.c Thu Jan 28 17:54:47 2010 (r203123) @@ -78,7 +78,7 @@ static void ahci_dmafini(device_t dev); static void ahci_slotsalloc(device_t dev); static void ahci_slotsfree(device_t dev); static void ahci_reset(device_t dev); -static void ahci_start(device_t dev); +static void ahci_start(device_t dev, int fbs); static void ahci_stop(device_t dev); static void ahci_clo(device_t dev); static void ahci_start_fr(device_t dev); @@ -86,6 +86,7 @@ static void ahci_stop_fr(device_t dev); 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 void ahci_issue_read_log(device_t dev); static void ahci_process_read_log(device_t dev, union ccb *ccb); @@ -108,6 +109,7 @@ static struct { #define AHCI_Q_4CH 32 #define AHCI_Q_EDGEIS 64 #define AHCI_Q_SATA2 128 +#define AHCI_Q_NOBSYRES 256 } ahci_ids[] = { {0x43801002, 0x00, "ATI IXP600", 0}, {0x43901002, 0x00, "ATI IXP700", 0}, @@ -162,8 +164,8 @@ static struct { {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", 0}, - {0x91231b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_SATA2}, + {0x91231b4b, 0x11, "Marvell 88SE912x", AHCI_Q_NOBSYRES}, + {0x91231b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_SATA2|AHCI_Q_NOBSYRES}, {0x044c10de, 0x00, "NVIDIA MCP65", 0}, {0x044d10de, 0x00, "NVIDIA MCP65", 0}, {0x044e10de, 0x00, "NVIDIA MCP65", 0}, @@ -379,14 +381,16 @@ ahci_attach(device_t dev) /* Announce HW capabilities. */ speed = (ctlr->caps & AHCI_CAP_ISS) >> AHCI_CAP_ISS_SHIFT; device_printf(dev, - "AHCI v%x.%02x with %d %sGbps ports, Port Multiplier %s\n", + "AHCI v%x.%02x with %d %sGbps ports, Port Multiplier %s%s\n", ((version >> 20) & 0xf0) + ((version >> 16) & 0x0f), ((version >> 4) & 0xf0) + (version & 0x0f), (ctlr->caps & AHCI_CAP_NPMASK) + 1, ((speed == 1) ? "1.5":((speed == 2) ? "3": ((speed == 3) ? "6":"?"))), (ctlr->caps & AHCI_CAP_SPM) ? - "supported" : "not supported"); + "supported" : "not supported", + (ctlr->caps & AHCI_CAP_FBSS) ? + " with FBS" : ""); if (bootverbose) { device_printf(dev, "Caps:%s%s%s%s%s%s%s%s %sGbps", (ctlr->caps & AHCI_CAP_64BIT) ? " 64bit":"", @@ -419,7 +423,7 @@ ahci_attach(device_t dev) (ctlr->caps2 & AHCI_CAP2_BOH) ? " BOH":""); } if (bootverbose && (ctlr->caps & AHCI_CAP_EMS)) { - device_printf(dev, "EM Caps: %s%s%s%s%s%s%s%s\n", + device_printf(dev, "EM Caps:%s%s%s%s%s%s%s%s\n", (ctlr->capsem & AHCI_EM_PM) ? " PM":"", (ctlr->capsem & AHCI_EM_ALHD) ? " ALHD":"", (ctlr->capsem & AHCI_EM_XMT) ? " XMT":"", @@ -810,6 +814,7 @@ ahci_ch_attach(device_t dev) struct ahci_channel *ch = device_get_softc(dev); struct cam_devq *devq; int rid, error, i, sata_rev = 0; + u_int32_t version; ch->dev = dev; ch->unit = (intptr_t)device_get_ivars(dev); @@ -861,6 +866,18 @@ ahci_ch_attach(device_t dev) error = ENXIO; goto err1; } + ch->chcaps = ATA_INL(ch->r_mem, AHCI_P_CMD); + version = ATA_INL(ctlr->r_mem, AHCI_VS); + if (version < 0x00010020 && (ctlr->caps & AHCI_CAP_FBSS)) + ch->chcaps |= AHCI_P_CMD_FBSCP; + if (bootverbose) { + device_printf(dev, "Caps:%s%s%s%s%s\n", + (ch->chcaps & AHCI_P_CMD_HPCP) ? " HPCP":"", + (ch->chcaps & AHCI_P_CMD_MPSP) ? " MPSP":"", + (ch->chcaps & AHCI_P_CMD_CPD) ? " CPD":"", + (ch->chcaps & AHCI_P_CMD_ESP) ? " ESP":"", + (ch->chcaps & AHCI_P_CMD_FBSCP) ? " FBSCP":""); + } /* Create the device queue for our SIM. */ devq = cam_simq_alloc(ch->numslots); if (devq == NULL) { @@ -977,7 +994,7 @@ ahci_ch_resume(device_t dev) ((ch->pm_level == 2 || ch->pm_level == 3) ? AHCI_P_CMD_ALPE : 0) | ((ch->pm_level > 2) ? AHCI_P_CMD_ASP : 0 ))); ahci_start_fr(dev); - ahci_start(dev); + ahci_start(dev, 1); return (0); } @@ -1007,6 +1024,7 @@ ahci_dmainit(device_t dev) { struct ahci_channel *ch = device_get_softc(dev); struct ahci_dc_cb_args dcba; + size_t rfsize; if (ch->caps & AHCI_CAP_64BIT) ch->dma.max_address = BUS_SPACE_MAXADDR; @@ -1028,16 +1046,20 @@ ahci_dmainit(device_t dev) } ch->dma.work_bus = dcba.maddr; /* FIS receive area. */ - if (bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, + if (ch->chcaps & AHCI_P_CMD_FBSCP) + rfsize = 4096; + else + rfsize = 256; + if (bus_dma_tag_create(bus_get_dma_tag(dev), rfsize, 0, ch->dma.max_address, BUS_SPACE_MAXADDR, - NULL, NULL, 4096, 1, 4096, + NULL, NULL, rfsize, 1, rfsize, 0, NULL, NULL, &ch->dma.rfis_tag)) goto error; if (bus_dmamem_alloc(ch->dma.rfis_tag, (void **)&ch->dma.rfis, 0, &ch->dma.rfis_map)) goto error; if (bus_dmamap_load(ch->dma.rfis_tag, ch->dma.rfis_map, ch->dma.rfis, - 4096, ahci_dmasetupc_cb, &dcba, 0) || dcba.error) { + rfsize, ahci_dmasetupc_cb, &dcba, 0) || dcba.error) { bus_dmamem_free(ch->dma.rfis_tag, ch->dma.rfis, ch->dma.rfis_map); goto error; } @@ -1225,7 +1247,7 @@ ahci_ch_intr(void *data) 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, ncq_err = 0; + int i, ccs, port; /* Read and clear interrupt statuses. */ istatus = ATA_INL(ch->r_mem, AHCI_P_IS); @@ -1238,7 +1260,17 @@ ahci_ch_intr(void *data) if (istatus & AHCI_P_IX_SDB) { if (ch->caps & AHCI_CAP_SSNTF) sntf = ATA_INL(ch->r_mem, AHCI_P_SNTF); - else { + else if (ch->fbs_enabled) { + u_int8_t *fis = ch->dma.rfis + 0x58; + + for (i = 0; i < 16; i++) { + if (fis[1] & 0x80) { + fis[1] &= 0x7f; + sntf |= 1 << i; + } + fis += 256; + } + } else { u_int8_t *fis = ch->dma.rfis + 0x58; if (fis[1] & 0x80) @@ -1257,18 +1289,35 @@ ahci_ch_intr(void *data) /* 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)) { -//device_printf(dev, "%s ERROR is %08x cs %08x ss %08x rs %08x tfd %02x serr %08x\n", -// __func__, istatus, cstatus, sstatus, ch->rslots, ATA_INL(ch->r_mem, AHCI_P_TFD), -// serr); ccs = (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CCS_MASK) >> AHCI_P_CMD_CCS_SHIFT; +//device_printf(dev, "%s ERROR is %08x cs %08x ss %08x rs %08x tfd %02x serr %08x fbs %08x ccs %d\n", +// __func__, istatus, cstatus, sstatus, ch->rslots, ATA_INL(ch->r_mem, AHCI_P_TFD), +// serr, ATA_INL(ch->r_mem, AHCI_P_FBS), ccs); + port = -1; + if (ch->fbs_enabled) { + uint32_t fbs = ATA_INL(ch->r_mem, AHCI_P_FBS); + if (fbs & AHCI_P_FBS_SDE) { + port = (fbs & AHCI_P_FBS_DWE) + >> AHCI_P_FBS_DWE_SHIFT; + } else { + for (i = 0; i < 16; i++) { + if (ch->numrslotspd[i] == 0) + continue; + if (port == -1) + port = i; + else if (port != i) { + port = -2; + break; + } + } + } + } err = ch->rslots & (cstatus | sstatus); - /* Kick controller into sane state */ - ahci_stop(dev); - ahci_start(dev); } else { ccs = 0; err = 0; + port = -1; } /* Complete all successfull commands. */ ok = ch->rslots & ~(cstatus | sstatus); @@ -1292,9 +1341,14 @@ ahci_ch_intr(void *data) /* XXX: reqests in loading state. */ if (((err >> i) & 1) == 0) continue; + if (port >= 0 && + ch->slot[i].ccb->ccb_h.target_id != port) + continue; if (istatus & AHCI_P_IX_TFE) { + if (port != -2) { /* Task File Error */ - if (ch->numtslots == 0) { + if (ch->numtslotspd[ + ch->slot[i].ccb->ccb_h.target_id] == 0) { /* Untagged operation. */ if (i == ccs) et = AHCI_ERR_TFE; @@ -1303,10 +1357,13 @@ ahci_ch_intr(void *data) } else { /* Tagged operation. */ et = AHCI_ERR_NCQ; - ncq_err = 1; } + } else { + et = AHCI_ERR_TFE; + ch->fatalerr = 1; + } } else if (istatus & AHCI_P_IX_IF) { - if (ch->numtslots == 0 && i != ccs) + if (ch->numtslots == 0 && i != ccs && port != -2) et = AHCI_ERR_INNOCENT; else et = AHCI_ERR_SATA; @@ -1314,8 +1371,12 @@ ahci_ch_intr(void *data) et = AHCI_ERR_INVALID; ahci_end_transaction(&ch->slot[i], et); } - if (ncq_err) - ahci_issue_read_log(dev); + /* + * We can't reinit port if there are some other + * commands active, use resume to complete them. + */ + if (ch->rslots != 0) + ATA_OUTL(ch->r_mem, AHCI_P_FBS, AHCI_P_FBS_EN | AHCI_P_FBS_DEC); } /* Process NOTIFY events */ if (sntf) @@ -1327,24 +1388,39 @@ static int ahci_check_collision(device_t dev, union ccb *ccb) { struct ahci_channel *ch = device_get_softc(dev); + int t = ccb->ccb_h.target_id; if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { - /* Tagged command while untagged are active. */ - if (ch->numrslots != 0 && ch->numtslots == 0) - return (1); - /* Tagged command while tagged to other target is active. */ - if (ch->numtslots != 0 && - ch->taggedtarget != ccb->ccb_h.target_id) - return (1); /* Tagged command while we have no supported tag free. */ if (((~ch->oslots) & (0xffffffff >> (32 - - ch->curr[ccb->ccb_h.target_id].tags))) == 0) + ch->curr[t].tags))) == 0) return (1); + /* If we have FBS */ + if (ch->fbs_enabled) { + /* Tagged command while untagged are active. */ + if (ch->numrslotspd[t] != 0 && ch->numtslotspd[t] == 0) + return (1); + } else { + /* Tagged command while untagged are active. */ + if (ch->numrslots != 0 && ch->numtslots == 0) + return (1); + /* Tagged command while tagged to other target is active. */ + if (ch->numtslots != 0 && + ch->taggedtarget != ccb->ccb_h.target_id) + return (1); + } } else { - /* Untagged command while tagged are active. */ - if (ch->numrslots != 0 && ch->numtslots != 0) - return (1); + /* If we have FBS */ + if (ch->fbs_enabled) { + /* Untagged command while tagged are active. */ + if (ch->numrslotspd[t] != 0 && ch->numtslotspd[t] != 0) + return (1); + } else { + /* Untagged command while tagged are active. */ + if (ch->numrslots != 0 && ch->numtslots != 0) + return (1); + } } if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & (CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT))) { @@ -1389,9 +1465,11 @@ ahci_begin_transaction(device_t dev, uni /* Update channel stats. */ ch->oslots |= (1 << slot->slot); ch->numrslots++; + ch->numrslotspd[ccb->ccb_h.target_id]++; if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { ch->numtslots++; + ch->numtslotspd[ccb->ccb_h.target_id]++; ch->taggedtarget = ccb->ccb_h.target_id; } if ((ccb->ccb_h.func_code == XPT_ATA_IO) && @@ -1459,7 +1537,9 @@ ahci_execute_transaction(struct ahci_slo struct ahci_cmd_list *clp; union ccb *ccb = slot->ccb; int port = ccb->ccb_h.target_id & 0x0f; - int fis_size; + int fis_size, i; + uint8_t *fis = ch->dma.rfis + 0x40; + uint8_t val; /* Get a piece of the workspace for this request */ ctp = (struct ahci_cmd_tab *) @@ -1481,13 +1561,18 @@ ahci_execute_transaction(struct ahci_slo (port << 12); /* Special handling for Soft Reset command. */ if ((ccb->ccb_h.func_code == XPT_ATA_IO) && - (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) && - (ccb->ataio.cmd.control & ATA_A_RESET)) { - /* Kick controller into sane state */ - ahci_stop(dev); - ahci_clo(dev); - ahci_start(dev); - clp->cmd_flags |= AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY; + (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL)) { + if (ccb->ataio.cmd.control & ATA_A_RESET) { + /* 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 { + /* Prepare FIS receive area for check. */ + for (i = 0; i < 20; i++) + fis[i] = 0xff; + } } clp->bytecount = 0; clp->cmd_table_phys = htole64(ch->dma.work_bus + AHCI_CT_OFFSET + @@ -1501,6 +1586,11 @@ ahci_execute_transaction(struct ahci_slo (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { ATA_OUTL(ch->r_mem, AHCI_P_SACT, 1 << slot->slot); } + /* If FBS is enabled, set PMP port. */ + if (ch->fbs_enabled) { + ATA_OUTL(ch->r_mem, AHCI_P_FBS, AHCI_P_FBS_EN | + (port << AHCI_P_FBS_DEV_SHIFT)); + } /* Issue command to the controller. */ slot->state = AHCI_SLOT_RUNNING; ch->rslots |= (1 << slot->slot); @@ -1543,12 +1633,30 @@ ahci_execute_transaction(struct ahci_slo ATA_INL(ch->r_mem, AHCI_P_SERR)); et = AHCI_ERR_TIMEOUT; } - if (et != AHCI_ERR_NONE) { - /* Kick controller into sane state */ - ahci_stop(ch->dev); - ahci_start(ch->dev); + /* 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; + } + } } 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 */ @@ -1577,7 +1685,8 @@ ahci_timeout(struct ahci_slot *slot) sstatus = ATA_INL(ch->r_mem, AHCI_P_SACT); ccs = (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CCS_MASK) >> AHCI_P_CMD_CCS_SHIFT; - if ((sstatus & (1 << slot->slot)) != 0 || ccs == slot->slot) + if ((sstatus & (1 << slot->slot)) != 0 || ccs == slot->slot || + ch->fbs_enabled) slot->state = AHCI_SLOT_EXECUTING; callout_reset(&slot->timeout, @@ -1635,12 +1744,19 @@ ahci_end_transaction(struct ahci_slot *s if ((et == AHCI_ERR_TFE) || (ccb->ataio.cmd.flags & CAM_ATAIO_NEEDRESULT)) { u_int8_t *fis = ch->dma.rfis + 0x40; - uint16_t tfd = ATA_INL(ch->r_mem, AHCI_P_TFD); bus_dmamap_sync(ch->dma.rfis_tag, ch->dma.rfis_map, BUS_DMASYNC_POSTREAD); - res->status = tfd; - res->error = tfd >> 8; + if (ch->fbs_enabled) { + fis += ccb->ccb_h.target_id * 256; + res->status = fis[2]; + res->error = fis[3]; + } else { + uint16_t tfd = ATA_INL(ch->r_mem, AHCI_P_TFD); + + res->status = tfd; + res->error = tfd >> 8; + } res->lba_low = fis[4]; res->lba_mid = fis[5]; res->lba_high = fis[6]; @@ -1659,6 +1775,8 @@ ahci_end_transaction(struct ahci_slot *s BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ch->dma.data_tag, slot->dma.data_map); } + 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) && !(ccb->ccb_h.status & CAM_DEV_QFRZN)) { @@ -1722,9 +1840,11 @@ ahci_end_transaction(struct ahci_slot *s slot->ccb = NULL; /* Update channel stats. */ ch->numrslots--; + ch->numrslotspd[ccb->ccb_h.target_id]--; if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { ch->numtslots--; + ch->numtslotspd[ccb->ccb_h.target_id]--; } /* If it was first request of reset sequence and there is no error, * proceed to second request. */ @@ -1742,6 +1862,7 @@ ahci_end_transaction(struct ahci_slot *s /* If it was NCQ command error, put result on hold. */ } else if (et == AHCI_ERR_NCQ) { ch->hold[slot->slot] = ccb; + ch->numhslots++; } else xpt_done(ccb); /* Unfreeze frozen command. */ @@ -1756,6 +1877,15 @@ ahci_end_transaction(struct ahci_slot *s /* if there was fatal error - reset port. */ if (ch->fatalerr) { ahci_reset(dev); + } else { + /* if we have slots in error, we can reinit port. */ + if (ch->eslots != 0) { + ahci_stop(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); } } /* Start PM timer. */ @@ -1843,6 +1973,7 @@ ahci_process_read_log(device_t dev, unio } xpt_done(ch->hold[i]); ch->hold[i] = NULL; + ch->numhslots--; } } else { if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) @@ -1855,6 +1986,7 @@ ahci_process_read_log(device_t dev, unio continue; xpt_done(ch->hold[i]); ch->hold[i] = NULL; + ch->numhslots--; } } free(ccb->ataio.data_ptr, M_AHCI); @@ -1863,7 +1995,7 @@ ahci_process_read_log(device_t dev, unio } static void -ahci_start(device_t dev) +ahci_start(device_t dev, int fbs) { struct ahci_channel *ch = device_get_softc(dev); u_int32_t cmd; @@ -1872,6 +2004,12 @@ ahci_start(device_t dev) ATA_OUTL(ch->r_mem, AHCI_P_SERR, 0xFFFFFFFF); /* Clear any interrupts pending on this channel */ ATA_OUTL(ch->r_mem, AHCI_P_IS, 0xFFFFFFFF); + /* Configure FIS-based switching if supported. */ + if (ch->chcaps & AHCI_P_CMD_FBSCP) { + ch->fbs_enabled = (fbs && ch->pm_present) ? 1 : 0; + ATA_OUTL(ch->r_mem, AHCI_P_FBS, + ch->fbs_enabled ? AHCI_P_FBS_EN : 0); + } /* Start operations on this channel */ cmd = ATA_INL(ch->r_mem, AHCI_P_CMD); ATA_OUTL(ch->r_mem, AHCI_P_CMD, cmd | AHCI_P_CMD_ST | @@ -1897,6 +2035,7 @@ ahci_stop(device_t dev) break; } } while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CR); + ch->eslots = 0; } static void @@ -2010,7 +2149,9 @@ ahci_reset(device_t dev) continue; xpt_done(ch->hold[i]); ch->hold[i] = NULL; + ch->numhslots--; } + ch->eslots = 0; ch->fatalerr = 0; /* Tell the XPT about the event */ xpt_async(AC_BUS_RESET, ch->path, NULL); @@ -2031,7 +2172,7 @@ ahci_reset(device_t dev) /* Wait for clearing busy status. */ if (ahci_wait_ready(dev, 15000)) ahci_clo(dev); - ahci_start(dev); + ahci_start(dev, 1); ch->devices = 1; /* Enable wanted port interrupts */ ATA_OUTL(ch->r_mem, AHCI_P_IE, Modified: head/sys/dev/ahci/ahci.h ============================================================================== --- head/sys/dev/ahci/ahci.h Thu Jan 28 17:09:47 2010 (r203122) +++ head/sys/dev/ahci/ahci.h Thu Jan 28 17:54:47 2010 (r203123) @@ -247,8 +247,11 @@ #define AHCI_P_CMD_CPS 0x00010000 #define AHCI_P_CMD_PMA 0x00020000 #define AHCI_P_CMD_HPCP 0x00040000 -#define AHCI_P_CMD_ISP 0x00080000 +#define AHCI_P_CMD_MPSP 0x00080000 #define AHCI_P_CMD_CPD 0x00100000 +#define AHCI_P_CMD_ESP 0x00200000 +#define AHCI_P_CMD_FBSCP 0x00400000 +#define AHCI_P_CMD_APSTE 0x00800000 #define AHCI_P_CMD_ATAPI 0x01000000 #define AHCI_P_CMD_DLAE 0x02000000 #define AHCI_P_CMD_ALPE 0x04000000 @@ -268,6 +271,15 @@ #define AHCI_P_CI 0x38 #define AHCI_P_SNTF 0x3C #define AHCI_P_FBS 0x40 +#define AHCI_P_FBS_EN 0x00000001 +#define AHCI_P_FBS_DEC 0x00000002 +#define AHCI_P_FBS_SDE 0x00000004 +#define AHCI_P_FBS_DEV 0x00000f00 +#define AHCI_P_FBS_DEV_SHIFT 8 +#define AHCI_P_FBS_ADO 0x0000f000 +#define AHCI_P_FBS_ADO_SHIFT 12 +#define AHCI_P_FBS_DWE 0x000f0000 +#define AHCI_P_FBS_DWE_SHIFT 16 /* Just to be sure, if building as module. */ #if MAXPHYS < 512 * 1024 @@ -373,6 +385,7 @@ struct ahci_channel { struct cam_path *path; uint32_t caps; /* Controller capabilities */ uint32_t caps2; /* Controller capabilities */ + uint32_t chcaps; /* Channel capabilities */ int quirks; int numslots; /* Number of present slots */ int pm_level; /* power management level */ @@ -382,11 +395,16 @@ struct ahci_channel { struct mtx mtx; /* state lock */ int devices; /* What is present */ int pm_present; /* PM presence reported */ + int fbs_enabled; /* FIS-based switching enabled */ uint32_t oslots; /* Occupied slots */ uint32_t rslots; /* Running slots */ uint32_t aslots; /* Slots with atomic commands */ + uint32_t eslots; /* Slots in error */ int numrslots; /* Number of running slots */ + 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 fatalerr; /* Fatal error happend */ int lastslot; /* Last used slot */