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 *);
 

Reply via email to