Module Name:    src
Committed By:   jakllsch
Date:           Tue Jul 27 22:07:51 UTC 2010

Modified Files:
        src/sys/dev/ic: ahcisata_core.c ahcisatavar.h
        src/sys/dev/pci: ahcisata_pci.c jmide.c

Log Message:
Support detachment of ahcisata(4).
Use use 64-bit DMA tag (where available) for ahcisata(4) at jmide(4).
Beginnings of detach/resume support for jmide(4).
Sprinkle static.  Misc. little changes.


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/ic/ahcisatavar.h
cvs rdiff -u -r1.19 -r1.20 src/sys/dev/pci/ahcisata_pci.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/pci/jmide.c

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.28 src/sys/dev/ic/ahcisata_core.c:1.29
--- src/sys/dev/ic/ahcisata_core.c:1.28	Tue Jul 20 19:24:11 2010
+++ src/sys/dev/ic/ahcisata_core.c	Tue Jul 27 22:07:50 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.28 2010/07/20 19:24:11 jakllsch Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.29 2010/07/27 22:07:50 jakllsch Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.28 2010/07/20 19:24:11 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.29 2010/07/27 22:07:50 jakllsch Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -54,39 +54,39 @@
 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,
@@ -113,11 +113,10 @@
 	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 int
 ahci_reset(struct ahci_softc *sc)
 {
 	int i;
@@ -139,7 +138,7 @@
 	return 0;
 }
 
-void
+static void
 ahci_setup_ports(struct ahci_softc *sc)
 {
 	uint32_t ahci_ports;
@@ -158,7 +157,7 @@
 	}
 }
 
-void
+static void
 ahci_reprobe_drives(struct ahci_softc *sc)
 {
 	uint32_t ahci_ports;
@@ -195,7 +194,7 @@
 	AHCI_WRITE(sc, AHCI_P_FBU(i), (uint64_t)achp->ahcic_bus_rfis>>32);
 }
 
-void
+static void
 ahci_enable_intrs(struct ahci_softc *sc)
 {
 
@@ -213,8 +212,6 @@
 	struct ahci_channel *achp;
 	struct ata_channel *chp;
 	int error;
-	bus_dma_segment_t seg;
-	int rseg;
 	int dmasize;
 	void *cmdhp;
 	void *cmdtblp;
@@ -261,13 +258,14 @@
 	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"
@@ -302,7 +300,7 @@
 			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;
@@ -315,13 +313,15 @@
 		}
 		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"
@@ -409,6 +409,73 @@
 }
 
 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;
+	uint32_t ahci_ports;
+	int i, j;
+	int error;
+
+	atac = &sc->sc_atac;
+	adapt = &atac->atac_atapi_adapter._generic;
+
+	ahci_ports = AHCI_READ(sc, AHCI_PI);
+	for (i = 0; i < AHCI_MAX_PORTS; i++) {
+		achp = &sc->sc_channels[i];
+		chp = &achp->ata_channel;
+
+		if ((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;
@@ -427,7 +494,7 @@
 	return r;
 }
 
-void
+static void
 ahci_intr_port(struct ahci_softc *sc, struct ahci_channel *achp)
 {
 	uint32_t is, tfd;
@@ -483,7 +550,7 @@
 	}
 }
 
-void
+static void
 ahci_reset_drive(struct ata_drive_datas *drvp, int flags)
 {
 	struct ata_channel *chp = drvp->chnl_softc;
@@ -491,7 +558,7 @@
 	return;
 }
 
-void
+static void
 ahci_reset_channel(struct ata_channel *chp, int flags)
 {
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -532,25 +599,25 @@
 	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;
@@ -622,13 +689,13 @@
 	}
 }
 
-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;
@@ -679,7 +746,7 @@
 	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;
@@ -762,7 +829,7 @@
 	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;
@@ -783,7 +850,7 @@
 	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 */
@@ -824,7 +891,7 @@
 	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;
@@ -872,7 +939,7 @@
 	return;
 }
 
-int
+static int
 ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
 {
 	struct ata_channel *chp = drvp->chnl_softc;
@@ -899,7 +966,7 @@
 	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;
@@ -981,7 +1048,7 @@
 	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 */
@@ -1009,7 +1076,7 @@
 	(*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 */
@@ -1071,7 +1138,7 @@
 	return 0;
 }
 
-void
+static void
 ahci_channel_stop(struct ahci_softc *sc, struct ata_channel *chp, int flags)
 {
 	int i;
@@ -1095,7 +1162,7 @@
 	}
 }
 
-void
+static void
 ahci_channel_start(struct ahci_softc *sc, struct ata_channel *chp)
 {
 	/* clear error */
@@ -1108,7 +1175,7 @@
 	    AHCI_P_CMD_FRE | AHCI_P_CMD_ST);
 }
 
-void
+static void
 ahci_timeout(void *v)
 {
 	struct ata_channel *chp = (struct ata_channel *)v;
@@ -1122,7 +1189,7 @@
 	splx(s);
 }
 
-int
+static int
 ahci_dma_setup(struct ata_channel *chp, int slot, void *data,
     size_t count, int op)
 {
@@ -1165,7 +1232,7 @@
 }
 
 #if NATAPIBUS > 0
-void
+static void
 ahci_atapibus_attach(struct atabus_softc * ata_sc)
 {
 	struct ata_channel *chp = ata_sc->sc_chan;
@@ -1197,7 +1264,7 @@
 		atapiprint);
 }
 
-void
+static void
 ahci_atapi_minphys(struct buf *bp)
 {
 	if (bp->b_bcount > MAXPHYS)
@@ -1210,7 +1277,7 @@
  *
  * Must be called at splbio().
  */
-void
+static void
 ahci_atapi_kill_pending(struct scsipi_periph *periph)
 {
 	struct atac_softc *atac =
@@ -1221,7 +1288,7 @@
 	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)
 {
@@ -1278,7 +1345,7 @@
 	}
 }
 
-void
+static void
 ahci_atapi_start(struct ata_channel *chp, struct ata_xfer *xfer)
 {
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -1360,7 +1427,7 @@
 	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 */
@@ -1419,7 +1486,7 @@
 	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;
@@ -1444,7 +1511,7 @@
 	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/ahcisatavar.h
diff -u src/sys/dev/ic/ahcisatavar.h:1.6 src/sys/dev/ic/ahcisatavar.h:1.7
--- src/sys/dev/ic/ahcisatavar.h:1.6	Tue Jul 20 18:50:48 2010
+++ src/sys/dev/ic/ahcisatavar.h	Tue Jul 27 22:07:50 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisatavar.h,v 1.6 2010/07/20 18:50:48 jakllsch Exp $	*/
+/*	$NetBSD: ahcisatavar.h,v 1.7 2010/07/27 22:07:50 jakllsch Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -47,9 +47,12 @@
 	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;
 
 	int sc_ncmds; /* number of command slots */
@@ -66,6 +69,8 @@
 		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];
@@ -93,10 +98,8 @@
     
 
 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 *);
 

Index: src/sys/dev/pci/ahcisata_pci.c
diff -u src/sys/dev/pci/ahcisata_pci.c:1.19 src/sys/dev/pci/ahcisata_pci.c:1.20
--- src/sys/dev/pci/ahcisata_pci.c:1.19	Wed Feb 24 22:37:59 2010
+++ src/sys/dev/pci/ahcisata_pci.c	Tue Jul 27 22:07:51 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_pci.c,v 1.19 2010/02/24 22:37:59 dyoung Exp $	*/
+/*	$NetBSD: ahcisata_pci.c,v 1.20 2010/07/27 22:07:51 jakllsch Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_pci.c,v 1.19 2010/02/24 22:37:59 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_pci.c,v 1.20 2010/07/27 22:07:51 jakllsch Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -44,9 +44,15 @@
 #include <dev/pci/pciidevar.h>
 #include <dev/ic/ahcisatavar.h>
 
-#define AHCI_PCI_QUIRK_FORCE	1	/* force attach */
+struct ahci_pci_quirk { 
+	pci_vendor_id_t  vendor;	/* Vendor ID */
+	pci_product_id_t product;	/* Product ID */
+	int              quirks;	/* quirks; see below */
+};
+
+#define AHCI_PCI_QUIRK_FORCE	__BIT(0)	/* force attach */
 
-static const struct pci_quirkdata ahci_pci_quirks[] = {
+static const struct ahci_pci_quirk ahci_pci_quirks[] = {
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA,
 	    AHCI_PCI_QUIRK_FORCE },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA2,
@@ -67,18 +73,30 @@
 	struct ahci_softc ah_sc;
 	pci_chipset_tag_t sc_pc;
 	pcitag_t sc_pcitag;
+	void * sc_ih;
 };
 
-
+static bool ahci_pci_has_quirk(pci_vendor_id_t, pci_product_id_t, int);
 static int  ahci_pci_match(device_t, cfdata_t, void *);
 static void ahci_pci_attach(device_t, device_t, void *);
-const struct pci_quirkdata *ahci_pci_lookup_quirkdata(pci_vendor_id_t,
-						      pci_product_id_t);
+static int  ahci_pci_detach(device_t, int);
 static bool ahci_pci_resume(device_t, const pmf_qual_t *);
 
 
 CFATTACH_DECL_NEW(ahcisata_pci, sizeof(struct ahci_pci_softc),
-    ahci_pci_match, ahci_pci_attach, NULL, NULL);
+    ahci_pci_match, ahci_pci_attach, ahci_pci_detach, NULL);
+
+static bool
+ahci_pci_has_quirk(pci_vendor_id_t vendor, pci_product_id_t product, int quirk)
+{
+	int i;
+
+	for (i = 0; i < __arraycount(ahci_pci_quirks); i++)
+		if (vendor == ahci_pci_quirks[i].vendor &&
+		    product == ahci_pci_quirks[i].product)
+			return (ahci_pci_quirks[i].quirks & quirk) != 0;
+	return false;
+}
 
 static int
 ahci_pci_match(device_t parent, cfdata_t match, void *aux)
@@ -88,17 +106,18 @@
 	bus_space_handle_t regh;
 	bus_size_t size;
 	int ret = 0;
-	const struct pci_quirkdata *quirks;
+	bool force;
 
-	quirks = ahci_pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id),
-					   PCI_PRODUCT(pa->pa_id));
+	force = ahci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
+				   PCI_PRODUCT(pa->pa_id),
+				   AHCI_PCI_QUIRK_FORCE);
 
 	/* if wrong class and not forced by quirks, don't match */
 	if ((PCI_CLASS(pa->pa_class) != PCI_CLASS_MASS_STORAGE ||
 	    ((PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MASS_STORAGE_SATA ||
 	     PCI_INTERFACE(pa->pa_class) != PCI_INTERFACE_SATA_AHCI) &&
 	     PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MASS_STORAGE_RAID)) &&
-	    (quirks == NULL || (quirks->quirks & AHCI_PCI_QUIRK_FORCE) == 0))
+	    (force == false))
 		return 0;
 
 	if (pci_mapreg_map(pa, AHCI_PCI_ABAR,
@@ -108,8 +127,8 @@
 
 	if ((PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_SATA &&
 	     PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_SATA_AHCI) ||
-	    (quirks && quirks->quirks & AHCI_PCI_QUIRK_FORCE) ||
-	    (bus_space_read_4(regt, regh, AHCI_GHC) & AHCI_GHC_AE))
+	    (bus_space_read_4(regt, regh, AHCI_GHC) & AHCI_GHC_AE) ||
+	    (force == true))
 		ret = 3;
 
 	bus_space_unmap(regt, regh, size);
@@ -122,17 +141,15 @@
 	struct pci_attach_args *pa = aux;
 	struct ahci_pci_softc *psc = device_private(self);
 	struct ahci_softc *sc = &psc->ah_sc;
-	bus_size_t size;
 	char devinfo[256];
 	const char *intrstr;
 	pci_intr_handle_t intrhandle;
-	void *ih;
 
 	sc->sc_atac.atac_dev = self;
 
 	if (pci_mapreg_map(pa, AHCI_PCI_ABAR,
 	    PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
-	    &sc->sc_ahcit, &sc->sc_ahcih, NULL, &size) != 0) {
+	    &sc->sc_ahcit, &sc->sc_ahcih, NULL, &sc->sc_ahcis) != 0) {
 		aprint_error_dev(self, "can't map ahci registers\n");
 		return;
 	}
@@ -144,16 +161,16 @@
 	aprint_normal(": %s\n", devinfo);
 	
 	if (pci_intr_map(pa, &intrhandle) != 0) {
-		aprint_error("%s: couldn't map interrupt\n", AHCINAME(sc));
+		aprint_error_dev(self, "couldn't map interrupt\n");
 		return;
 	}
 	intrstr = pci_intr_string(pa->pa_pc, intrhandle);
-	ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO, ahci_intr, sc);
-	if (ih == NULL) {
-		aprint_error("%s: couldn't establish interrupt", AHCINAME(sc));
+	psc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO, ahci_intr, sc);
+	if (psc->sc_ih == NULL) {
+		aprint_error_dev(self, "couldn't establish interrupt\n");
 		return;
 	}
-	aprint_normal("%s: interrupting at %s\n", AHCINAME(sc),
+	aprint_normal_dev(self, "interrupting at %s\n",
 	    intrstr ? intrstr : "unknown interrupt");
 	sc->sc_dmat = pa->pa_dmat;
 
@@ -170,6 +187,27 @@
 		aprint_error_dev(self, "couldn't establish power handler\n");
 }
 
+static int
+ahci_pci_detach(device_t dv, int flags)
+{
+	struct ahci_pci_softc *psc;
+	struct ahci_softc *sc;
+	int rv;
+
+	psc = device_private(dv);
+	sc = &psc->ah_sc;
+
+	if ((rv = ahci_detach(sc, flags)))
+		return rv;
+
+	if (psc->sc_ih != NULL)
+		pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
+
+	bus_space_unmap(sc->sc_ahcit, sc->sc_ahcih, sc->sc_ahcis);
+
+	return 0;
+}
+
 static bool
 ahci_pci_resume(device_t dv, const pmf_qual_t *qual)
 {
@@ -178,23 +216,8 @@
 	int s;
 
 	s = splbio();
-	ahci_reset(sc);
-	ahci_setup_ports(sc);
-	ahci_reprobe_drives(sc);
-	ahci_enable_intrs(sc);
+	ahci_resume(sc);
 	splx(s);
 
 	return true;
 }
-
-const struct pci_quirkdata *
-ahci_pci_lookup_quirkdata(pci_vendor_id_t vendor, pci_product_id_t product)
-{
-	int i;
-
-	for (i = 0; i < __arraycount(ahci_pci_quirks); i++)
-		if (vendor == ahci_pci_quirks[i].vendor &&
-		    product == ahci_pci_quirks[i].product)
-			return (&ahci_pci_quirks[i]);
-	return (NULL);
-}

Index: src/sys/dev/pci/jmide.c
diff -u src/sys/dev/pci/jmide.c:1.7 src/sys/dev/pci/jmide.c:1.8
--- src/sys/dev/pci/jmide.c:1.7	Mon Oct 19 18:41:15 2009
+++ src/sys/dev/pci/jmide.c	Tue Jul 27 22:07:51 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: jmide.c,v 1.7 2009/10/19 18:41:15 bouyer Exp $	*/
+/*	$NetBSD: jmide.c,v 1.8 2010/07/27 22:07:51 jakllsch Exp $	*/
 
 /*
  * Copyright (c) 2007 Manuel Bouyer.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: jmide.c,v 1.7 2009/10/19 18:41:15 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: jmide.c,v 1.8 2010/07/27 22:07:51 jakllsch Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -431,9 +431,11 @@
 #ifdef NJMAHCI
 static int  jmahci_match(device_t, cfdata_t, void *);
 static void jmahci_attach(device_t, device_t, void *);
+static int  jmahci_detach(device_t, int);
+static bool jmahci_resume(device_t, const pmf_qual_t *);
 
 CFATTACH_DECL_NEW(jmahci, sizeof(struct ahci_softc),
-	jmahci_match, jmahci_attach, NULL, NULL);
+	jmahci_match, jmahci_attach, jmahci_detach, NULL);
 
 static int
 jmahci_match(device_t parent, cfdata_t match, void *aux)
@@ -447,6 +449,7 @@
 	struct jmahci_attach_args *jma = aux;
 	struct pci_attach_args *pa = jma->jma_pa;
 	struct ahci_softc *sc = device_private(self);
+	uint32_t ahci_cap;
 
 	aprint_naive(": AHCI disk controller\n");
 	aprint_normal("\n");
@@ -454,11 +457,49 @@
 	sc->sc_atac.atac_dev = self;
 	sc->sc_ahcit = jma->jma_ahcit;
 	sc->sc_ahcih = jma->jma_ahcih;
-	sc->sc_dmat = jma->jma_pa->pa_dmat;
+
+	ahci_cap = AHCI_READ(sc, AHCI_CAP);
+
+	if (pci_dma64_available(jma->jma_pa) && (ahci_cap & AHCI_CAP_64BIT))
+		sc->sc_dmat = jma->jma_pa->pa_dmat64;
+	else
+		sc->sc_dmat = jma->jma_pa->pa_dmat;
 
 	if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID)
 		sc->sc_atac_capflags = ATAC_CAP_RAID;
 
 	ahci_attach(sc);
+
+	if (!pmf_device_register(self, NULL, jmahci_resume))
+	    aprint_error_dev(self, "couldn't establish power handler\n");
+}
+
+static int
+jmahci_detach(device_t dv, int flags)
+{
+	struct ahci_softc *sc;
+	sc = device_private(dv);
+
+	int rv;
+
+	if ((rv = ahci_detach(sc, flags)))
+		return rv;
+
+	return 0;
+}
+
+static bool
+jmahci_resume(device_t dv, const pmf_qual_t *qual)
+{
+	struct ahci_softc *sc;
+	int s;
+
+	sc = device_private(dv);
+
+	s = splbio();
+	ahci_resume(sc);
+	splx(s);
+
+	return true;
 }
 #endif

Reply via email to