Module Name: src
Committed By: matt
Date: Mon Mar 24 18:47:17 UTC 2014
Modified Files:
src/sys/dev/ic [matt-nb5-mips64]: ahcisata_core.c ahcisatareg.h
ahcisatavar.h
Log Message:
Merge needed changes from HEAD for cubie
To generate a diff of this commit:
cvs rdiff -u -r1.18.4.1.4.1 -r1.18.4.1.4.2 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.4 -r1.4.28.1 src/sys/dev/ic/ahcisatareg.h
cvs rdiff -u -r1.4 -r1.4.22.1 src/sys/dev/ic/ahcisatavar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.18.4.1.4.1 src/sys/dev/ic/ahcisata_core.c:1.18.4.1.4.2
--- src/sys/dev/ic/ahcisata_core.c:1.18.4.1.4.1 Wed Apr 21 00:27:35 2010
+++ src/sys/dev/ic/ahcisata_core.c Mon Mar 24 18:47:17 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ahcisata_core.c,v 1.18.4.1.4.1 2010/04/21 00:27:35 matt Exp $ */
+/* $NetBSD: ahcisata_core.c,v 1.18.4.1.4.2 2014/03/24 18:47:17 matt Exp $ */
/*
* Copyright (c) 2006 Manuel Bouyer.
@@ -11,11 +11,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Manuel Bouyer.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -31,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.18.4.1.4.1 2010/04/21 00:27:35 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.18.4.1.4.2 2014/03/24 18:47:17 matt Exp $");
#include <sys/types.h>
#include <sys/malloc.h>
@@ -44,10 +39,11 @@ __KERNEL_RCSID(0, "$NetBSD: ahcisata_cor
#include <uvm/uvm_extern.h>
-#include <dev/ic/wdcreg.h>
#include <dev/ata/atareg.h>
#include <dev/ata/satavar.h>
#include <dev/ata/satareg.h>
+#include <dev/ata/satafisvar.h>
+#include <dev/ata/satafisreg.h>
#include <dev/ic/ahcisatavar.h>
#include <dev/scsipi/scsi_all.h> /* for SCSI status */
@@ -58,39 +54,39 @@ __KERNEL_RCSID(0, "$NetBSD: ahcisata_cor
int ahcidebug_mask = 0x0;
#endif
-void ahci_probe_drive(struct ata_channel *);
-void ahci_setup_channel(struct ata_channel *);
+static void ahci_probe_drive(struct ata_channel *);
+static void ahci_setup_channel(struct ata_channel *);
-int ahci_ata_bio(struct ata_drive_datas *, struct ata_bio *);
-void ahci_reset_drive(struct ata_drive_datas *, int);
-void ahci_reset_channel(struct ata_channel *, int);
-int ahci_exec_command(struct ata_drive_datas *, struct ata_command *);
-int ahci_ata_addref(struct ata_drive_datas *);
-void ahci_ata_delref(struct ata_drive_datas *);
-void ahci_killpending(struct ata_drive_datas *);
-
-void ahci_cmd_start(struct ata_channel *, struct ata_xfer *);
-int ahci_cmd_complete(struct ata_channel *, struct ata_xfer *, int);
-void ahci_cmd_done(struct ata_channel *, struct ata_xfer *, int);
-void ahci_cmd_kill_xfer(struct ata_channel *, struct ata_xfer *, int) ;
-void ahci_bio_start(struct ata_channel *, struct ata_xfer *);
-int ahci_bio_complete(struct ata_channel *, struct ata_xfer *, int);
-void ahci_bio_kill_xfer(struct ata_channel *, struct ata_xfer *, int) ;
-void ahci_channel_stop(struct ahci_softc *, struct ata_channel *, int);
-void ahci_channel_start(struct ahci_softc *, struct ata_channel *);
-void ahci_timeout(void *);
-int ahci_dma_setup(struct ata_channel *, int, void *, size_t, int);
+static int ahci_ata_bio(struct ata_drive_datas *, struct ata_bio *);
+static void ahci_reset_drive(struct ata_drive_datas *, int);
+static void ahci_reset_channel(struct ata_channel *, int);
+static int ahci_exec_command(struct ata_drive_datas *, struct ata_command *);
+static int ahci_ata_addref(struct ata_drive_datas *);
+static void ahci_ata_delref(struct ata_drive_datas *);
+static void ahci_killpending(struct ata_drive_datas *);
+
+static void ahci_cmd_start(struct ata_channel *, struct ata_xfer *);
+static int ahci_cmd_complete(struct ata_channel *, struct ata_xfer *, int);
+static void ahci_cmd_done(struct ata_channel *, struct ata_xfer *, int);
+static void ahci_cmd_kill_xfer(struct ata_channel *, struct ata_xfer *, int) ;
+static void ahci_bio_start(struct ata_channel *, struct ata_xfer *);
+static int ahci_bio_complete(struct ata_channel *, struct ata_xfer *, int);
+static void ahci_bio_kill_xfer(struct ata_channel *, struct ata_xfer *, int) ;
+static void ahci_channel_stop(struct ahci_softc *, struct ata_channel *, int);
+static void ahci_channel_start(struct ahci_softc *, struct ata_channel *);
+static void ahci_timeout(void *);
+static int ahci_dma_setup(struct ata_channel *, int, void *, size_t, int);
#if NATAPIBUS > 0
-void ahci_atapibus_attach(struct atabus_softc *);
-void ahci_atapi_kill_pending(struct scsipi_periph *);
-void ahci_atapi_minphys(struct buf *);
-void ahci_atapi_scsipi_request(struct scsipi_channel *,
+static void ahci_atapibus_attach(struct atabus_softc *);
+static void ahci_atapi_kill_pending(struct scsipi_periph *);
+static void ahci_atapi_minphys(struct buf *);
+static void ahci_atapi_scsipi_request(struct scsipi_channel *,
scsipi_adapter_req_t, void *);
-void ahci_atapi_start(struct ata_channel *, struct ata_xfer *);
-int ahci_atapi_complete(struct ata_channel *, struct ata_xfer *, int);
-void ahci_atapi_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
-void ahci_atapi_probe_device(struct atapibus_softc *, int);
+static void ahci_atapi_start(struct ata_channel *, struct ata_xfer *);
+static int ahci_atapi_complete(struct ata_channel *, struct ata_xfer *, int);
+static void ahci_atapi_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
+static void ahci_atapi_probe_device(struct atapibus_softc *, int);
static const struct scsipi_bustype ahci_atapi_bustype = {
SCSIPI_BUSTYPE_ATAPI,
@@ -117,11 +113,22 @@ const struct ata_bustype ahci_ata_bustyp
ahci_killpending
};
-void ahci_intr_port(struct ahci_softc *, struct ahci_channel *);
-
+static void ahci_intr_port(struct ahci_softc *, struct ahci_channel *);
static void ahci_setup_port(struct ahci_softc *sc, int i);
-int
+static void
+ahci_enable(struct ahci_softc *sc)
+{
+ uint32_t ghc;
+
+ ghc = AHCI_READ(sc, AHCI_GHC);
+ if (!(ghc & AHCI_GHC_AE)) {
+ ghc |= AHCI_GHC_AE;
+ AHCI_WRITE(sc, AHCI_GHC, ghc);
+ }
+}
+
+static int
ahci_reset(struct ahci_softc *sc)
{
int i;
@@ -139,19 +146,25 @@ ahci_reset(struct ahci_softc *sc)
return -1;
}
/* enable ahci mode */
- AHCI_WRITE(sc, AHCI_GHC, AHCI_GHC_AE);
+ ahci_enable(sc);
+
+ if (sc->sc_save_init_data) {
+ AHCI_WRITE(sc, AHCI_CAP, sc->sc_init_data.cap);
+ if (sc->sc_init_data.cap2)
+ AHCI_WRITE(sc, AHCI_CAP2, sc->sc_init_data.cap2);
+ AHCI_WRITE(sc, AHCI_PI, sc->sc_init_data.ports);
+ }
+
return 0;
}
-void
+static void
ahci_setup_ports(struct ahci_softc *sc)
{
- u_int32_t ahci_ports;
int i, port;
- ahci_ports = AHCI_READ(sc, AHCI_PI);
for (i = 0, port = 0; i < AHCI_MAX_PORTS; i++) {
- if ((ahci_ports & (1 << i)) == 0)
+ if ((sc->sc_ahci_ports & (1 << i)) == 0)
continue;
if (port >= sc->sc_atac.atac_nchannels) {
aprint_error("%s: more ports than announced\n",
@@ -162,17 +175,15 @@ ahci_setup_ports(struct ahci_softc *sc)
}
}
-void
+static void
ahci_reprobe_drives(struct ahci_softc *sc)
{
- u_int32_t ahci_ports;
int i, port;
struct ahci_channel *achp;
struct ata_channel *chp;
- ahci_ports = AHCI_READ(sc, AHCI_PI);
for (i = 0, port = 0; i < AHCI_MAX_PORTS; i++) {
- if ((ahci_ports & (1 << i)) == 0)
+ if ((sc->sc_ahci_ports & (1 << i)) == 0)
continue;
if (port >= sc->sc_atac.atac_nchannels) {
aprint_error("%s: more ports than announced\n",
@@ -194,12 +205,12 @@ ahci_setup_port(struct ahci_softc *sc, i
achp = &sc->sc_channels[i];
AHCI_WRITE(sc, AHCI_P_CLB(i), achp->ahcic_bus_cmdh);
- AHCI_WRITE(sc, AHCI_P_CLBU(i), 0);
+ AHCI_WRITE(sc, AHCI_P_CLBU(i), (uint64_t)achp->ahcic_bus_cmdh>>32);
AHCI_WRITE(sc, AHCI_P_FB(i), achp->ahcic_bus_rfis);
- AHCI_WRITE(sc, AHCI_P_FBU(i), 0);
+ AHCI_WRITE(sc, AHCI_P_FBU(i), (uint64_t)achp->ahcic_bus_rfis>>32);
}
-void
+static void
ahci_enable_intrs(struct ahci_softc *sc)
{
@@ -212,17 +223,34 @@ ahci_enable_intrs(struct ahci_softc *sc)
void
ahci_attach(struct ahci_softc *sc)
{
- u_int32_t ahci_cap, ahci_rev, ahci_ports;
+ uint32_t ahci_rev, ahci_cap;
int i, j, port;
struct ahci_channel *achp;
struct ata_channel *chp;
int error;
- bus_dma_segment_t seg;
- int rseg;
int dmasize;
+ char buf[128];
void *cmdhp;
void *cmdtblp;
+ if (sc->sc_save_init_data) {
+ ahci_enable(sc);
+
+ sc->sc_init_data.cap = AHCI_READ(sc, AHCI_CAP);
+ sc->sc_init_data.ports = AHCI_READ(sc, AHCI_PI);
+
+ ahci_rev = AHCI_READ(sc, AHCI_VS);
+ if (AHCI_VS_MJR(ahci_rev) > 1 ||
+ (AHCI_VS_MJR(ahci_rev) == 1 && AHCI_VS_MNR(ahci_rev) >= 20)) {
+ sc->sc_init_data.cap2 = AHCI_READ(sc, AHCI_CAP2);
+ } else {
+ sc->sc_init_data.cap2 = 0;
+ }
+ if (sc->sc_init_data.ports == 0) {
+ sc->sc_init_data.ports = sc->sc_ahci_ports;
+ }
+ }
+
if (ahci_reset(sc) != 0)
return;
@@ -230,25 +258,40 @@ ahci_attach(struct ahci_softc *sc)
sc->sc_atac.atac_nchannels = (ahci_cap & AHCI_CAP_NPMASK) + 1;
sc->sc_ncmds = ((ahci_cap & AHCI_CAP_NCS) >> 8) + 1;
ahci_rev = AHCI_READ(sc, AHCI_VS);
- aprint_normal("%s: AHCI revision ", AHCINAME(sc));
- switch(ahci_rev) {
- case AHCI_VS_10:
- aprint_normal("1.0");
- break;
- case AHCI_VS_11:
- aprint_normal("1.1");
- break;
- case AHCI_VS_12:
- aprint_normal("1.2");
- break;
- default:
- aprint_normal("0x%x", ahci_rev);
- break;
- }
+#define snprintb(a,b,c,d) bitmask_snprintf((d),(c),(a),(b))
+ snprintb(buf, sizeof(buf), "\177\020"
+ /* "f\000\005NP\0" */
+ "b\005SXS\0"
+ "b\006EMS\0"
+ "b\007CCCS\0"
+ /* "f\010\005NCS\0" */
+ "b\015PSC\0"
+ "b\016SSC\0"
+ "b\017PMD\0"
+ "b\020FBSS\0"
+ "b\021SPM\0"
+ "b\022SAM\0"
+ "b\023SNZO\0"
+ "f\024\003ISS\0"
+ "=\001Gen1\0"
+ "=\002Gen2\0"
+ "=\003Gen3\0"
+ "b\030SCLO\0"
+ "b\031SAL\0"
+ "b\032SALP\0"
+ "b\033SSS\0"
+ "b\034SMPS\0"
+ "b\035SSNTF\0"
+ "b\036SNCQ\0"
+ "b\037S64A\0"
+ "\0", ahci_cap);
+ aprint_normal_dev(sc->sc_atac.atac_dev, "AHCI revision %u.%u"
+ ", %d port%s, %d slot%s, CAP %s\n",
+ AHCI_VS_MJR(ahci_rev), AHCI_VS_MNR(ahci_rev),
+ sc->sc_atac.atac_nchannels,
+ (sc->sc_atac.atac_nchannels == 1 ? "" : "s"),
+ sc->sc_ncmds, (sc->sc_ncmds == 1 ? "" : "s"), buf);
- aprint_normal(", %d ports, %d command slots, features 0x%x\n",
- sc->sc_atac.atac_nchannels, sc->sc_ncmds,
- ahci_cap & ~(AHCI_CAP_NPMASK|AHCI_CAP_NCS));
sc->sc_atac.atac_cap = ATAC_CAP_DATA16 | ATAC_CAP_DMA | ATAC_CAP_UDMA;
sc->sc_atac.atac_cap |= sc->sc_atac_capflags;
sc->sc_atac.atac_pio_cap = 4;
@@ -265,13 +308,14 @@ ahci_attach(struct ahci_softc *sc)
dmasize =
(AHCI_RFIS_SIZE + AHCI_CMDH_SIZE) * sc->sc_atac.atac_nchannels;
error = bus_dmamem_alloc(sc->sc_dmat, dmasize, PAGE_SIZE, 0,
- &seg, 1, &rseg, BUS_DMA_NOWAIT);
+ &sc->sc_cmd_hdr_seg, 1, &sc->sc_cmd_hdr_nseg, BUS_DMA_NOWAIT);
if (error) {
aprint_error("%s: unable to allocate command header memory"
", error=%d\n", AHCINAME(sc), error);
return;
}
- error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, dmasize,
+ error = bus_dmamem_map(sc->sc_dmat, &sc->sc_cmd_hdr_seg,
+ sc->sc_cmd_hdr_nseg, dmasize,
&cmdhp, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
if (error) {
aprint_error("%s: unable to map command header memory"
@@ -296,9 +340,13 @@ ahci_attach(struct ahci_softc *sc)
ahci_enable_intrs(sc);
- ahci_ports = AHCI_READ(sc, AHCI_PI);
+ if (sc->sc_ahci_ports == 0) {
+ sc->sc_ahci_ports = AHCI_READ(sc, AHCI_PI);
+ AHCIDEBUG_PRINT(("active ports %#x\n", sc->sc_ahci_ports),
+ DEBUG_PROBE);
+ }
for (i = 0, port = 0; i < AHCI_MAX_PORTS; i++) {
- if ((ahci_ports & (1 << i)) == 0)
+ if ((sc->sc_ahci_ports & (1 << i)) == 0)
continue;
if (port >= sc->sc_atac.atac_nchannels) {
aprint_error("%s: more ports than announced\n",
@@ -306,7 +354,7 @@ ahci_attach(struct ahci_softc *sc)
break;
}
achp = &sc->sc_channels[i];
- chp = (struct ata_channel *)achp;
+ chp = &achp->ata_channel;
sc->sc_chanarray[i] = chp;
chp->ch_channel = i;
chp->ch_atac = &sc->sc_atac;
@@ -319,13 +367,15 @@ ahci_attach(struct ahci_softc *sc)
}
dmasize = AHCI_CMDTBL_SIZE * sc->sc_ncmds;
error = bus_dmamem_alloc(sc->sc_dmat, dmasize, PAGE_SIZE, 0,
- &seg, 1, &rseg, BUS_DMA_NOWAIT);
+ &achp->ahcic_cmd_tbl_seg, 1, &achp->ahcic_cmd_tbl_nseg,
+ BUS_DMA_NOWAIT);
if (error) {
aprint_error("%s: unable to allocate command table "
"memory, error=%d\n", AHCINAME(sc), error);
break;
}
- error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, dmasize,
+ error = bus_dmamem_map(sc->sc_dmat, &achp->ahcic_cmd_tbl_seg,
+ achp->ahcic_cmd_tbl_nseg, dmasize,
&cmdtblp, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
if (error) {
aprint_error("%s: unable to map command table memory"
@@ -357,9 +407,10 @@ ahci_attach(struct ahci_softc *sc)
achp->ahcic_bus_rfis = sc->sc_cmd_hdrd->dm_segs[0].ds_addr +
AHCI_CMDH_SIZE * sc->sc_atac.atac_nchannels +
AHCI_RFIS_SIZE * port;
- AHCIDEBUG_PRINT(("port %d cmdh %p (0x%x) rfis %p (0x%x)\n", i,
- achp->ahcic_cmdh, (u_int)achp->ahcic_bus_cmdh,
- achp->ahcic_rfis, (u_int)achp->ahcic_bus_rfis),
+ AHCIDEBUG_PRINT(("port %d cmdh %p (0x%" PRIx64 ") "
+ "rfis %p (0x%" PRIx64 ")\n", i,
+ achp->ahcic_cmdh, (uint64_t)achp->ahcic_bus_cmdh,
+ achp->ahcic_rfis, (uint64_t)achp->ahcic_bus_rfis),
DEBUG_PROBE);
for (j = 0; j < sc->sc_ncmds; j++) {
@@ -369,11 +420,10 @@ ahci_attach(struct ahci_softc *sc)
achp->ahcic_cmd_tbld->dm_segs[0].ds_addr +
AHCI_CMDTBL_SIZE * j;
achp->ahcic_cmdh[j].cmdh_cmdtba =
- htole32(achp->ahcic_bus_cmd_tbl[j]);
- achp->ahcic_cmdh[j].cmdh_cmdtbau = htole32(0);
- AHCIDEBUG_PRINT(("port %d/%d tbl %p (0x%x)\n", i, j,
+ htole64(achp->ahcic_bus_cmd_tbl[j]);
+ AHCIDEBUG_PRINT(("port %d/%d tbl %p (0x%" PRIx64 ")\n", i, j,
achp->ahcic_cmd_tbl[j],
- (u_int)achp->ahcic_bus_cmd_tbl[j]), DEBUG_PROBE);
+ (uint64_t)achp->ahcic_bus_cmd_tbl[j]), DEBUG_PROBE);
/* The xfer DMA map */
error = bus_dmamap_create(sc->sc_dmat, MAXPHYS,
AHCI_NPRD, 0x400000 /* 4MB */, 0,
@@ -388,19 +438,19 @@ ahci_attach(struct ahci_softc *sc)
ahci_setup_port(sc, i);
chp->ch_ndrive = 1;
if (bus_space_subregion(sc->sc_ahcit, sc->sc_ahcih,
- AHCI_P_SSTS(i), 1, &achp->ahcic_sstatus) != 0) {
+ AHCI_P_SSTS(i), 4, &achp->ahcic_sstatus) != 0) {
aprint_error("%s: couldn't map channel %d "
"sata_status regs\n", AHCINAME(sc), i);
break;
}
if (bus_space_subregion(sc->sc_ahcit, sc->sc_ahcih,
- AHCI_P_SCTL(i), 1, &achp->ahcic_scontrol) != 0) {
+ AHCI_P_SCTL(i), 4, &achp->ahcic_scontrol) != 0) {
aprint_error("%s: couldn't map channel %d "
"sata_control regs\n", AHCINAME(sc), i);
break;
}
if (bus_space_subregion(sc->sc_ahcit, sc->sc_ahcih,
- AHCI_P_SERR(i), 1, &achp->ahcic_serror) != 0) {
+ AHCI_P_SERR(i), 4, &achp->ahcic_serror) != 0) {
aprint_error("%s: couldn't map channel %d "
"sata_error regs\n", AHCINAME(sc), i);
break;
@@ -413,10 +463,75 @@ end:
}
int
+ahci_detach(struct ahci_softc *sc, int flags)
+{
+ struct atac_softc *atac;
+ struct ahci_channel *achp;
+ struct ata_channel *chp;
+ struct scsipi_adapter *adapt;
+ int i, j;
+ int error;
+
+ atac = &sc->sc_atac;
+ adapt = &atac->atac_atapi_adapter._generic;
+
+ for (i = 0; i < AHCI_MAX_PORTS; i++) {
+ achp = &sc->sc_channels[i];
+ chp = &achp->ata_channel;
+
+ if ((sc->sc_ahci_ports & (1 << i)) == 0)
+ continue;
+ if (i >= sc->sc_atac.atac_nchannels) {
+ aprint_error("%s: more ports than announced\n",
+ AHCINAME(sc));
+ break;
+ }
+
+ if (chp->atabus == NULL)
+ continue;
+ if ((error = config_detach(chp->atabus, flags)) != 0)
+ return error;
+
+ for (j = 0; j < sc->sc_ncmds; j++)
+ bus_dmamap_destroy(sc->sc_dmat, achp->ahcic_datad[j]);
+
+ bus_dmamap_unload(sc->sc_dmat, achp->ahcic_cmd_tbld);
+ bus_dmamap_destroy(sc->sc_dmat, achp->ahcic_cmd_tbld);
+ bus_dmamem_unmap(sc->sc_dmat, achp->ahcic_cmd_tbl[0],
+ AHCI_CMDTBL_SIZE * sc->sc_ncmds);
+ bus_dmamem_free(sc->sc_dmat, &achp->ahcic_cmd_tbl_seg,
+ achp->ahcic_cmd_tbl_nseg);
+
+ free(chp->ch_queue, M_DEVBUF);
+ chp->atabus = NULL;
+ }
+
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_cmd_hdrd);
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmd_hdrd);
+ bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd_hdr,
+ (AHCI_RFIS_SIZE + AHCI_CMDH_SIZE) * sc->sc_atac.atac_nchannels);
+ bus_dmamem_free(sc->sc_dmat, &sc->sc_cmd_hdr_seg, sc->sc_cmd_hdr_nseg);
+
+ if (adapt->adapt_refcnt != 0)
+ return EBUSY;
+
+ return 0;
+}
+
+void
+ahci_resume(struct ahci_softc *sc)
+{
+ ahci_reset(sc);
+ ahci_setup_ports(sc);
+ ahci_reprobe_drives(sc);
+ ahci_enable_intrs(sc);
+}
+
+int
ahci_intr(void *v)
{
struct ahci_softc *sc = v;
- u_int32_t is;
+ uint32_t is;
int i, r = 0;
while ((is = AHCI_READ(sc, AHCI_IS))) {
@@ -431,10 +546,10 @@ ahci_intr(void *v)
return r;
}
-void
+static void
ahci_intr_port(struct ahci_softc *sc, struct ahci_channel *achp)
{
- u_int32_t is, tfd;
+ uint32_t is, tfd;
struct ata_channel *chp = &achp->ata_channel;
struct ata_xfer *xfer = chp->ch_queue->active_xfer;
int slot;
@@ -487,7 +602,7 @@ ahci_intr_port(struct ahci_softc *sc, st
}
}
-void
+static void
ahci_reset_drive(struct ata_drive_datas *drvp, int flags)
{
struct ata_channel *chp = drvp->chnl_softc;
@@ -495,7 +610,7 @@ ahci_reset_drive(struct ata_drive_datas
return;
}
-void
+static void
ahci_reset_channel(struct ata_channel *chp, int flags)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -536,31 +651,31 @@ ahci_reset_channel(struct ata_channel *c
return;
}
-int
+static int
ahci_ata_addref(struct ata_drive_datas *drvp)
{
return 0;
}
-void
+static void
ahci_ata_delref(struct ata_drive_datas *drvp)
{
return;
}
-void
+static void
ahci_killpending(struct ata_drive_datas *drvp)
{
return;
}
-void
+static void
ahci_probe_drive(struct ata_channel *chp)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
struct ahci_channel *achp = (struct ahci_channel *)chp;
int i, s;
- u_int32_t sig;
+ uint32_t sig;
/* XXX This should be done by other code. */
for (i = 0; i < chp->ch_ndrive; i++) {
@@ -626,13 +741,13 @@ ahci_probe_drive(struct ata_channel *chp
}
}
-void
+static void
ahci_setup_channel(struct ata_channel *chp)
{
return;
}
-int
+static int
ahci_exec_command(struct ata_drive_datas *drvp, struct ata_command *ata_c)
{
struct ata_channel *chp = drvp->chnl_softc;
@@ -683,7 +798,7 @@ ahci_exec_command(struct ata_drive_datas
return ret;
}
-void
+static void
ahci_cmd_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -692,7 +807,6 @@ ahci_cmd_start(struct ata_channel *chp,
int slot = 0 /* XXX slot */;
struct ahci_cmd_tbl *cmd_tbl;
struct ahci_cmd_header *cmd_h;
- u_int8_t *fis;
int i;
int channel = chp->ch_channel;
@@ -702,34 +816,15 @@ ahci_cmd_start(struct ata_channel *chp,
cmd_tbl = achp->ahcic_cmd_tbl[slot];
AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,
cmd_tbl), DEBUG_XFERS);
- fis = cmd_tbl->cmdt_cfis;
- fis[0] = 0x27; /* host to device */
- fis[1] = 0x80; /* command FIS */
- fis[2] = ata_c->r_command;
- fis[3] = ata_c->r_features;
- fis[4] = ata_c->r_sector;
- fis[5] = ata_c->r_cyl & 0xff;
- fis[6] = (ata_c->r_cyl >> 8) & 0xff;
- fis[7] = ata_c->r_head & 0x0f;
- fis[8] = 0;
- fis[9] = 0;
- fis[10] = 0;
- fis[11] = 0;
- fis[12] = ata_c->r_count;
- fis[13] = 0;
- fis[14] = 0;
- fis[15] = WDCTL_4BIT;
- fis[16] = 0;
- fis[17] = 0;
- fis[18] = 0;
- fis[19] = 0;
+ satafis_rhd_construct_cmd(ata_c, cmd_tbl->cmdt_cfis);
cmd_h = &achp->ahcic_cmdh[slot];
AHCIDEBUG_PRINT(("%s port %d header %p\n", AHCINAME(sc),
chp->ch_channel, cmd_h), DEBUG_XFERS);
if (ahci_dma_setup(chp, slot,
- (ata_c->flags & (AT_READ|AT_WRITE)) ? ata_c->data : NULL,
+ (ata_c->flags & (AT_READ|AT_WRITE) && ata_c->bcount > 0) ?
+ ata_c->data : NULL,
ata_c->bcount,
(ata_c->flags & AT_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)) {
ata_c->flags |= AT_DF;
@@ -738,7 +833,7 @@ ahci_cmd_start(struct ata_channel *chp,
}
cmd_h->cmdh_flags = htole16(
((ata_c->flags & AT_WRITE) ? AHCI_CMDH_F_WR : 0) |
- 20 /* fis lenght */ / 4);
+ RHD_FISLEN / 4);
cmd_h->cmdh_prdbc = 0;
AHCI_CMDH_SYNC(sc, achp, slot,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -787,7 +882,7 @@ ahci_cmd_start(struct ata_channel *chp,
AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
}
-void
+static void
ahci_cmd_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)
{
struct ata_command *ata_c = xfer->c_cmd;
@@ -808,12 +903,13 @@ ahci_cmd_kill_xfer(struct ata_channel *c
ahci_cmd_done(chp, xfer, 0 /* XXX slot */);
}
-int
+static int
ahci_cmd_complete(struct ata_channel *chp, struct ata_xfer *xfer, int is)
{
int slot = 0; /* XXX slot */
struct ata_command *ata_c = xfer->c_cmd;
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
+ struct ahci_channel *achp = (struct ahci_channel *)chp;
AHCIDEBUG_PRINT(("ahci_cmd_complete channel %d CMD 0x%x CI 0x%x\n",
chp->ch_channel, AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)),
@@ -833,28 +929,29 @@ ahci_cmd_complete(struct ata_channel *ch
wakeup(&chp->ch_queue->active_xfer);
return 0;
}
- if (is) {
- ata_c->r_head = 0;
- ata_c->r_count = 0;
- ata_c->r_sector = 0;
- ata_c->r_cyl = 0;
- if (chp->ch_status & WDCS_BSY) {
- ata_c->flags |= AT_TIMEOU;
- } else if (chp->ch_status & WDCS_ERR) {
- ata_c->r_error = chp->ch_error;
- ata_c->flags |= AT_ERROR;
- }
+
+ if (chp->ch_status & WDCS_BSY) {
+ ata_c->flags |= AT_TIMEOU;
+ } else if (chp->ch_status & WDCS_ERR) {
+ ata_c->r_error = chp->ch_error;
+ ata_c->flags |= AT_ERROR;
}
+
+ if (ata_c->flags & AT_READREG)
+ satafis_rdh_cmd_readreg(ata_c, achp->ahcic_rfis->rfis_rfis);
+
ahci_cmd_done(chp, xfer, slot);
return 0;
}
-void
+static void
ahci_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer, int slot)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
struct ahci_channel *achp = (struct ahci_channel *)chp;
struct ata_command *ata_c = xfer->c_cmd;
+ uint16_t *idwordbuf;
+ int i;
AHCIDEBUG_PRINT(("ahci_cmd_done channel %d\n", chp->ch_channel),
DEBUG_FUNCS);
@@ -862,7 +959,7 @@ ahci_cmd_done(struct ata_channel *chp, s
/* this comamnd is not active any more */
achp->ahcic_cmds_active &= ~(1 << slot);
- if (ata_c->flags & (AT_READ|AT_WRITE)) {
+ if (ata_c->flags & (AT_READ|AT_WRITE) && ata_c->bcount > 0) {
bus_dmamap_sync(sc->sc_dmat, achp->ahcic_datad[slot], 0,
achp->ahcic_datad[slot]->dm_mapsize,
(ata_c->flags & AT_READ) ? BUS_DMASYNC_POSTREAD :
@@ -873,6 +970,15 @@ ahci_cmd_done(struct ata_channel *chp, s
AHCI_CMDH_SYNC(sc, achp, slot,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ /* ata(4) expects IDENTIFY data to be in host endianess */
+ if (ata_c->r_command == WDCC_IDENTIFY ||
+ ata_c->r_command == ATAPI_IDENTIFY_DEVICE) {
+ idwordbuf = xfer->c_databuf;
+ for (i = 0; i < (xfer->c_bcount / sizeof(*idwordbuf)); i++) {
+ idwordbuf[i] = le16toh(idwordbuf[i]);
+ }
+ }
+
ata_c->flags |= AT_DONE;
if (achp->ahcic_cmdh[slot].cmdh_prdbc)
ata_c->flags |= AT_XFDONE;
@@ -886,7 +992,7 @@ ahci_cmd_done(struct ata_channel *chp, s
return;
}
-int
+static int
ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
{
struct ata_channel *chp = drvp->chnl_softc;
@@ -913,7 +1019,7 @@ ahci_ata_bio(struct ata_drive_datas *drv
return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED;
}
-void
+static void
ahci_bio_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -922,54 +1028,17 @@ ahci_bio_start(struct ata_channel *chp,
int slot = 0 /* XXX slot */;
struct ahci_cmd_tbl *cmd_tbl;
struct ahci_cmd_header *cmd_h;
- u_int8_t *fis;
- int i, nblks;
+ int i;
int channel = chp->ch_channel;
AHCIDEBUG_PRINT(("ahci_bio_start CI 0x%x\n",
AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))), DEBUG_XFERS);
- nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
-
cmd_tbl = achp->ahcic_cmd_tbl[slot];
AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,
cmd_tbl), DEBUG_XFERS);
- fis = cmd_tbl->cmdt_cfis;
- fis[0] = 0x27; /* host to device */
- fis[1] = 0x80; /* command FIS */
- if (ata_bio->flags & ATA_LBA48) {
- fis[2] = (ata_bio->flags & ATA_READ) ?
- WDCC_READDMA_EXT : WDCC_WRITEDMA_EXT;
- } else {
- fis[2] =
- (ata_bio->flags & ATA_READ) ? WDCC_READDMA : WDCC_WRITEDMA;
- }
- fis[3] = 0; /* features */
- fis[4] = ata_bio->blkno & 0xff;
- fis[5] = (ata_bio->blkno >> 8) & 0xff;
- fis[6] = (ata_bio->blkno >> 16) & 0xff;
- if (ata_bio->flags & ATA_LBA48) {
- fis[7] = WDSD_LBA;
- fis[8] = (ata_bio->blkno >> 24) & 0xff;
- fis[9] = (ata_bio->blkno >> 32) & 0xff;
- fis[10] = (ata_bio->blkno >> 40) & 0xff;
- } else {
- fis[7] = ((ata_bio->blkno >> 24) & 0x0f) | WDSD_LBA;
- fis[8] = 0;
- fis[9] = 0;
- fis[10] = 0;
- }
- fis[11] = 0; /* ext features */
- fis[12] = nblks & 0xff;
- fis[13] = (ata_bio->flags & ATA_LBA48) ?
- ((nblks >> 8) & 0xff) : 0;
- fis[14] = 0;
- fis[15] = WDCTL_4BIT;
- fis[16] = 0;
- fis[17] = 0;
- fis[18] = 0;
- fis[19] = 0;
+ satafis_rhd_construct_bio(xfer, cmd_tbl->cmdt_cfis);
cmd_h = &achp->ahcic_cmdh[slot];
AHCIDEBUG_PRINT(("%s port %d header %p\n", AHCINAME(sc),
@@ -983,7 +1052,7 @@ ahci_bio_start(struct ata_channel *chp,
}
cmd_h->cmdh_flags = htole16(
((ata_bio->flags & ATA_READ) ? 0 : AHCI_CMDH_F_WR) |
- 20 /* fis lenght */ / 4);
+ RHD_FISLEN / 4);
cmd_h->cmdh_prdbc = 0;
AHCI_CMDH_SYNC(sc, achp, slot,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -1032,7 +1101,7 @@ ahci_bio_start(struct ata_channel *chp,
AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
}
-void
+static void
ahci_bio_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)
{
int slot = 0; /* XXX slot */
@@ -1060,7 +1129,7 @@ ahci_bio_kill_xfer(struct ata_channel *c
(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
}
-int
+static int
ahci_bio_complete(struct ata_channel *chp, struct ata_xfer *xfer, int is)
{
int slot = 0; /* XXX slot */
@@ -1122,7 +1191,7 @@ ahci_bio_complete(struct ata_channel *ch
return 0;
}
-void
+static void
ahci_channel_stop(struct ahci_softc *sc, struct ata_channel *chp, int flags)
{
int i;
@@ -1144,28 +1213,38 @@ ahci_channel_stop(struct ahci_softc *sc,
/* XXX controller reset ? */
return;
}
+
+ if (sc->sc_channel_stop)
+ sc->sc_channel_stop(sc, chp);
}
-void
+static void
ahci_channel_start(struct ahci_softc *sc, struct ata_channel *chp)
{
/* clear error */
AHCI_WRITE(sc, AHCI_P_SERR(chp->ch_channel),
AHCI_READ(sc, AHCI_P_SERR(chp->ch_channel)));
+ if (sc->sc_channel_start)
+ sc->sc_channel_start(sc, chp);
+
/* and start controller */
AHCI_WRITE(sc, AHCI_P_CMD(chp->ch_channel),
AHCI_P_CMD_ICC_AC | AHCI_P_CMD_POD | AHCI_P_CMD_SUD |
AHCI_P_CMD_FRE | AHCI_P_CMD_ST);
}
-void
+static void
ahci_timeout(void *v)
{
struct ata_channel *chp = (struct ata_channel *)v;
struct ata_xfer *xfer = chp->ch_queue->active_xfer;
+#ifdef AHCI_DEBUG
+ struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
+#endif
int s = splbio();
- AHCIDEBUG_PRINT(("ahci_timeout xfer %p\n", xfer), DEBUG_INTR);
+ AHCIDEBUG_PRINT(("ahci_timeout xfer %p intr %#x ghc %08x is %08x\n", xfer, AHCI_READ(sc, AHCI_P_IS(chp->ch_channel)), AHCI_READ(sc, AHCI_GHC), AHCI_READ(sc, AHCI_IS)), DEBUG_INTR);
+
if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0) {
xfer->c_flags |= C_TIMEOU;
xfer->c_intr(chp, xfer, 0);
@@ -1173,7 +1252,7 @@ ahci_timeout(void *v)
splx(s);
}
-int
+static int
ahci_dma_setup(struct ata_channel *chp, int slot, void *data,
size_t count, int op)
{
@@ -1203,9 +1282,8 @@ ahci_dma_setup(struct ata_channel *chp,
achp->ahcic_datad[slot]->dm_mapsize,
(op == BUS_DMA_READ) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
for (seg = 0; seg < achp->ahcic_datad[slot]->dm_nsegs; seg++) {
- cmd_tbl->cmdt_prd[seg].prd_dba = htole32(
+ cmd_tbl->cmdt_prd[seg].prd_dba = htole64(
achp->ahcic_datad[slot]->dm_segs[seg].ds_addr);
- cmd_tbl->cmdt_prd[seg].prd_dbau = 0;
cmd_tbl->cmdt_prd[seg].prd_dbc = htole32(
achp->ahcic_datad[slot]->dm_segs[seg].ds_len - 1);
}
@@ -1217,7 +1295,7 @@ end:
}
#if NATAPIBUS > 0
-void
+static void
ahci_atapibus_attach(struct atabus_softc * ata_sc)
{
struct ata_channel *chp = ata_sc->sc_chan;
@@ -1249,7 +1327,7 @@ ahci_atapibus_attach(struct atabus_softc
atapiprint);
}
-void
+static void
ahci_atapi_minphys(struct buf *bp)
{
if (bp->b_bcount > MAXPHYS)
@@ -1262,7 +1340,7 @@ ahci_atapi_minphys(struct buf *bp)
*
* Must be called at splbio().
*/
-void
+static void
ahci_atapi_kill_pending(struct scsipi_periph *periph)
{
struct atac_softc *atac =
@@ -1273,7 +1351,7 @@ ahci_atapi_kill_pending(struct scsipi_pe
ata_kill_pending(&chp->ch_drive[periph->periph_target]);
}
-void
+static void
ahci_atapi_scsipi_request(struct scsipi_channel *chan,
scsipi_adapter_req_t req, void *arg)
{
@@ -1330,7 +1408,7 @@ ahci_atapi_scsipi_request(struct scsipi_
}
}
-void
+static void
ahci_atapi_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -1339,7 +1417,6 @@ ahci_atapi_start(struct ata_channel *chp
int slot = 0 /* XXX slot */;
struct ahci_cmd_tbl *cmd_tbl;
struct ahci_cmd_header *cmd_h;
- u_int8_t *fis;
int i;
int channel = chp->ch_channel;
@@ -1349,30 +1426,10 @@ ahci_atapi_start(struct ata_channel *chp
cmd_tbl = achp->ahcic_cmd_tbl[slot];
AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,
cmd_tbl), DEBUG_XFERS);
- fis = cmd_tbl->cmdt_cfis;
- fis[0] = 0x27; /* host to device */
- fis[1] = 0x80; /* command FIS */
- fis[2] = ATAPI_PKT_CMD;
+ satafis_rhd_construct_atapi(xfer, cmd_tbl->cmdt_cfis);
memset(&cmd_tbl->cmdt_acmd, 0, sizeof(cmd_tbl->cmdt_acmd));
memcpy(cmd_tbl->cmdt_acmd, sc_xfer->cmd, sc_xfer->cmdlen);
- fis[3] = (sc_xfer->datalen ? ATAPI_PKT_CMD_FTRE_DMA : 0);
- fis[4] = 0;
- fis[5] = 0;
- fis[6] = 0;
- fis[7] = WDSD_LBA;
- fis[8] = 0;
- fis[9] = 0;
- fis[10] = 0;
- fis[11] = 0; /* ext features */
- fis[12] = 0;
- fis[13] = 0;
- fis[14] = 0;
- fis[15] = WDCTL_4BIT;
- fis[16] = 0;
- fis[17] = 0;
- fis[18] = 0;
- fis[19] = 0;
cmd_h = &achp->ahcic_cmdh[slot];
AHCIDEBUG_PRINT(("%s port %d header %p\n", AHCINAME(sc),
@@ -1387,7 +1444,7 @@ ahci_atapi_start(struct ata_channel *chp
}
cmd_h->cmdh_flags = htole16(
((sc_xfer->xs_control & XS_CTL_DATA_OUT) ? AHCI_CMDH_F_WR : 0) |
- 20 /* fis lenght */ / 4 | AHCI_CMDH_F_A);
+ RHD_FISLEN / 4 | AHCI_CMDH_F_A);
cmd_h->cmdh_prdbc = 0;
AHCI_CMDH_SYNC(sc, achp, slot,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -1433,7 +1490,7 @@ ahci_atapi_start(struct ata_channel *chp
AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
}
-int
+static int
ahci_atapi_complete(struct ata_channel *chp, struct ata_xfer *xfer, int irq)
{
int slot = 0; /* XXX slot */
@@ -1492,7 +1549,7 @@ ahci_atapi_complete(struct ata_channel *
return 0;
}
-void
+static void
ahci_atapi_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)
{
struct scsipi_xfer *sc_xfer = xfer->c_cmd;
@@ -1517,7 +1574,7 @@ ahci_atapi_kill_xfer(struct ata_channel
scsipi_done(sc_xfer);
}
-void
+static void
ahci_atapi_probe_device(struct atapibus_softc *sc, int target)
{
struct scsipi_channel *chan = sc->sc_channel;
Index: src/sys/dev/ic/ahcisatareg.h
diff -u src/sys/dev/ic/ahcisatareg.h:1.4 src/sys/dev/ic/ahcisatareg.h:1.4.28.1
--- src/sys/dev/ic/ahcisatareg.h:1.4 Fri Jan 25 21:41:48 2008
+++ src/sys/dev/ic/ahcisatareg.h Mon Mar 24 18:47:17 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ahcisatareg.h,v 1.4 2008/01/25 21:41:48 xtraeme Exp $ */
+/* $NetBSD: ahcisatareg.h,v 1.4.28.1 2014/03/24 18:47:17 matt Exp $ */
/*
* Copyright (c) 2006 Manuel Bouyer.
@@ -11,11 +11,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Manuel Bouyer.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -39,23 +34,22 @@
/* in-memory structures used by the controller */
/* physical region descriptor: points to a region of data (max 4MB) */
struct ahci_dma_prd {
- u_int32_t prd_dba; /* data base address (64 bits) */
- u_int32_t prd_dbau;
- u_int32_t prd_res; /* reserved */
- u_int32_t prd_dbc; /* data byte count */
+ uint64_t prd_dba; /* data base address */
+ uint32_t prd_res; /* reserved */
+ uint32_t prd_dbc; /* data byte count */
#define AHCI_PRD_DBC_MASK 0x003fffff
#define AHCI_PRD_DBC_IPC 0x80000000 /* interrupt on completion */
-} __packed;
+} __packed __aligned(8);
#define AHCI_NPRD ((MAXPHYS/PAGE_SIZE) + 1)
/* command table: describe a command to send to drive */
struct ahci_cmd_tbl {
- u_int8_t cmdt_cfis[64]; /* command FIS */
- u_int8_t cmdt_acmd[16]; /* ATAPI command */
- u_int8_t cmdt_res[48]; /* reserved */
+ uint8_t cmdt_cfis[64]; /* command FIS */
+ uint8_t cmdt_acmd[16]; /* ATAPI command */
+ uint8_t cmdt_res[48]; /* reserved */
struct ahci_dma_prd cmdt_prd[1]; /* extended to AHCI_NPRD */
-} __packed;
+} __packed __aligned(8);
#define AHCI_CMDTBL_ALIGN 0x7f
@@ -68,7 +62,7 @@ struct ahci_cmd_tbl {
* of theses.
*/
struct ahci_cmd_header {
- u_int16_t cmdh_flags;
+ uint16_t cmdh_flags;
#define AHCI_CMDH_F_PMP_MASK 0xf000 /* port multiplier port */
#define AHCI_CMDH_F_PMP_SHIFT 12
#define AHCI_CMDH_F_CBSY 0x0400 /* clear BSY on R_OK */
@@ -79,24 +73,23 @@ struct ahci_cmd_header {
#define AHCI_CMDH_F_A 0x0020 /* ATAPI */
#define AHCI_CMDH_F_CFL_MASK 0x001f /* command FIS length (in dw) */
#define AHCI_CMDH_F_CFL_SHIFT 0
- u_int16_t cmdh_prdtl; /* number of cmdt_prd */
- u_int32_t cmdh_prdbc; /* physical region descriptor byte count */
- u_int32_t cmdh_cmdtba; /* phys. addr. of cmd_tbl */
- u_int32_t cmdh_cmdtbau; /* (64bits, 128bytes aligned) */
- u_int32_t cmdh_res[4]; /* reserved */
-} __packed;
+ uint16_t cmdh_prdtl; /* number of cmdt_prd */
+ uint32_t cmdh_prdbc; /* physical region descriptor byte count */
+ uint64_t cmdh_cmdtba; /* phys. addr. of cmd_tbl, 128bytes aligned */
+ uint32_t cmdh_res[4]; /* reserved */
+} __packed __aligned(8);
#define AHCI_CMDH_SIZE (sizeof(struct ahci_cmd_header) * AHCI_MAX_CMDS)
/* received FIS: where the HBA stores various type of FIS it receives */
struct ahci_r_fis {
- u_int8_t rfis_dsfis[32]; /* DMA setup FIS */
- u_int8_t rfis_psfis[32]; /* PIO setup FIS */
- u_int8_t rfis_rfis[24]; /* D2H register FIS */
- u_int8_t rfis_sdbfis[8]; /* set device bit FIS */
- u_int8_t rfis_ukfis[64]; /* unknown FIS */
- u_int8_t rfis_res[96];
-} __packed;
+ uint8_t rfis_dsfis[32]; /* DMA setup FIS */
+ uint8_t rfis_psfis[32]; /* PIO setup FIS */
+ uint8_t rfis_rfis[24]; /* D2H register FIS */
+ uint8_t rfis_sdbfis[8]; /* set device bit FIS */
+ uint8_t rfis_ukfis[64]; /* unknown FIS */
+ uint8_t rfis_res[96]; /* reserved */
+} __packed __aligned(8);
#define AHCI_RFIS_SIZE (sizeof(struct ahci_r_fis))
@@ -122,8 +115,9 @@ struct ahci_r_fis {
#define AHCI_CAP_SAM 0x00040000 /* AHCI-only */
#define AHCI_CAP_NZO 0x00080000 /* Non-zero DMA offset (reserved) */
#define AHCI_CAP_IS 0x00f00000 /* Interface speed */
-#define AHCI_CAP_IS_GEN1 0x00100000 /* 1.5 GB/s */
-#define AHCI_CAP_IS_GEN2 0x00200000 /* 1.5 and 3 GB/s */
+#define AHCI_CAP_IS_GEN1 0x00100000 /* 1.5 Gb/s */
+#define AHCI_CAP_IS_GEN2 0x00200000 /* 3.0 Gb/s */
+#define AHCI_CAP_IS_GEN3 0x00300000 /* 6.0 Gb/s */
#define AHCI_CAP_CLO 0x01000000 /* Command list override */
#define AHCI_CAP_AL 0x02000000 /* Single Activitly LED */
#define AHCI_CAP_ALP 0x04000000 /* Agressive link power management */
@@ -144,9 +138,13 @@ struct ahci_r_fis {
#define AHCI_PI 0x0c /* Port implemented: one bit per port */
#define AHCI_VS 0x10 /* AHCI version */
-#define AHCI_VS_10 0x00010000 /* AHCI spec 1.0 */
-#define AHCI_VS_11 0x00010100 /* AHCI spec 1.1 */
-#define AHCI_VS_12 0x00010200 /* AHCI spec 1.2 */
+#define AHCI_VS_095 0x00000905 /* AHCI spec 0.95 */
+#define AHCI_VS_100 0x00010000 /* AHCI spec 1.0 */
+#define AHCI_VS_110 0x00010100 /* AHCI spec 1.1 */
+#define AHCI_VS_120 0x00010200 /* AHCI spec 1.2 */
+#define AHCI_VS_130 0x00010300 /* AHCI spec 1.3 */
+#define AHCI_VS_MJR(v) ((unsigned int)__SHIFTOUT(v, __BITS(31, 16)))
+#define AHCI_VS_MNR(v) ((unsigned int)__SHIFTOUT(v, __BITS(15, 8)) * 10 + (unsigned int)__SHIFTOUT(v, __BITS(7, 0) * 1))
#define AHCI_CC_CTL 0x14 /* command completion coalescing control */
#define AHCI_CC_TV_MASK 0xffff0000 /* timeout value */
@@ -178,6 +176,18 @@ struct ahci_r_fis {
#define AHCI_EMC_TM 0x00000100 /* Transmit message */
#define AHCI_EMC_MR 0x00000001 /* Message received */
+#define AHCI_CAP2 0x24 /* HBA Capabilities Extended */
+#define AHCI_CAP2_APST 0x00000004
+#define AHCI_CAP2_NVMP 0x00000002
+#define AHCI_CAP2_BOH 0x00000001
+
+#define AHCI_BOHC 0x28 /* BIOS/OS Handoff Control and Status */
+#define AHCI_BOHC_BB 0x00000010
+#define AHCI_BOHC_OOC 0x00000008
+#define AHCI_BOHC_SOOE 0x00000004
+#define AHCI_BOHC_OOS 0x00000002
+#define AHCI_BOHC_BOS 0x00000001
+
/* Per-port registers */
#define AHCI_P_OFFSET(port) (0x80 * (port))
@@ -246,7 +256,7 @@ struct ahci_r_fis {
#define AHCI_P_SIG_LBAL_MASK 0x0000ff00
#define AHCI_P_SIG_LBAL_SHIFT 8
#define AHCI_P_SIG_SC_MASK 0x000000ff
-#define AHCI_P_SIG_SC_SHIFT 8
+#define AHCI_P_SIG_SC_SHIFT 0
#define AHCI_P_SSTS(p) (0x128 + AHCI_P_OFFSET(p)) /* Serial ATA status */
Index: src/sys/dev/ic/ahcisatavar.h
diff -u src/sys/dev/ic/ahcisatavar.h:1.4 src/sys/dev/ic/ahcisatavar.h:1.4.22.1
--- src/sys/dev/ic/ahcisatavar.h:1.4 Tue Mar 18 20:46:36 2008
+++ src/sys/dev/ic/ahcisatavar.h Mon Mar 24 18:47:17 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ahcisatavar.h,v 1.4 2008/03/18 20:46:36 cube Exp $ */
+/* $NetBSD: ahcisatavar.h,v 1.4.22.1 2014/03/24 18:47:17 matt Exp $ */
/*
* Copyright (c) 2006 Manuel Bouyer.
@@ -11,11 +11,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Manuel Bouyer.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -52,12 +47,17 @@ struct ahci_softc {
struct atac_softc sc_atac;
bus_space_tag_t sc_ahcit; /* ahci registers mapping */
bus_space_handle_t sc_ahcih;
+ bus_size_t sc_ahcis;
bus_dma_tag_t sc_dmat; /* DMA memory mappings: */
void *sc_cmd_hdr; /* command tables and received FIS */
bus_dmamap_t sc_cmd_hdrd;
+ bus_dma_segment_t sc_cmd_hdr_seg;
+ int sc_cmd_hdr_nseg;
int sc_atac_capflags;
+ uint32_t sc_ahci_cap; /* copy of AHCI_CAP */
int sc_ncmds; /* number of command slots */
+ uint32_t sc_ahci_ports;
struct ata_channel *sc_chanarray[AHCI_MAX_PORTS];
struct ahci_channel {
struct ata_channel ata_channel; /* generic part */
@@ -71,11 +71,23 @@ struct ahci_softc {
bus_addr_t ahcic_bus_cmdh;
/* command tables (allocated per-channel) */
bus_dmamap_t ahcic_cmd_tbld;
+ bus_dma_segment_t ahcic_cmd_tbl_seg;
+ int ahcic_cmd_tbl_nseg;
struct ahci_cmd_tbl *ahcic_cmd_tbl[AHCI_MAX_CMDS];
bus_addr_t ahcic_bus_cmd_tbl[AHCI_MAX_CMDS];
bus_dmamap_t ahcic_datad[AHCI_MAX_CMDS];
- u_int32_t ahcic_cmds_active; /* active commands */
+ uint32_t ahcic_cmds_active; /* active commands */
} sc_channels[AHCI_MAX_PORTS];
+
+ void (*sc_channel_start)(struct ahci_softc *, struct ata_channel *);
+ void (*sc_channel_stop)(struct ahci_softc *, struct ata_channel *);
+
+ bool sc_save_init_data;
+ struct {
+ uint32_t cap;
+ uint32_t cap2;
+ uint32_t ports;
+ } sc_init_data;
};
#define AHCINAME(sc) (device_xname((sc)->sc_atac.atac_dev))
@@ -98,10 +110,8 @@ struct ahci_softc {
void ahci_attach(struct ahci_softc *);
-void ahci_enable_intrs(struct ahci_softc *);
-int ahci_reset(struct ahci_softc *);
-void ahci_setup_ports(struct ahci_softc *);
-void ahci_reprobe_drives(struct ahci_softc *);
+int ahci_detach(struct ahci_softc *, int);
+void ahci_resume(struct ahci_softc *);
int ahci_intr(void *);