summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcmetz <cmetz@openbsd.org>1999-11-30 07:55:55 +0000
committercmetz <cmetz@openbsd.org>1999-11-30 07:55:55 +0000
commit30a6e20a9d805b4bc711933dcacbed1b095d9526 (patch)
tree8c5fa9131c1a58b83b6ae49e04b798e17099bebc
parentUVM support (how could I miss this?). From jason@ (diff)
downloadwireguard-openbsd-30a6e20a9d805b4bc711933dcacbed1b095d9526.tar.xz
wireguard-openbsd-30a6e20a9d805b4bc711933dcacbed1b095d9526.zip
Added port of the NetBSD (-current) DPT SmartCache III/IV PCI/EISA host adapter
driver to OpenBSD.
-rw-r--r--sys/arch/i386/conf/GENERIC5
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/eisa/dpt_eisa.c214
-rw-r--r--sys/dev/eisa/files.eisa7
-rw-r--r--sys/dev/ic/dpt.c1441
-rw-r--r--sys/dev/ic/dptreg.h300
-rw-r--r--sys/dev/ic/dptvar.h128
-rw-r--r--sys/dev/pci/dpt_pci.c163
-rw-r--r--sys/dev/pci/files.pci6
9 files changed, 2266 insertions, 4 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index a5162bed1c9..8f073217c72 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.142 1999/11/28 12:17:04 downsj Exp $
+# $OpenBSD: GENERIC,v 1.143 1999/11/30 07:55:55 cmetz Exp $
# $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $
#
# GENERIC -- everything that's currently supported
@@ -144,6 +144,9 @@ ahc0 at isa? port ? irq ? # Adaptec 284x SCSI controllers
ahc* at eisa? slot ? # Adaptec 274x, aic7770 SCSI controllers
ahc* at pci? dev ? function ? # Adaptec 2940 SCSI controllers
scsibus* at ahc?
+dpt* at pci? dev ? function ? # DPT SmartCache/SmartRAID PCI
+dpt* at eisa? slot ? # DPT SmartCache/SmartRAID EISA
+scsibus* at dpt?
isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel
scsibus* at isp?
aic0 at isa? port 0x340 irq 11 # Adaptec 152[02] SCSI controllers
diff --git a/sys/conf/files b/sys/conf/files
index 46ffaad50ca..cb167e90925 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.136 1999/11/28 11:50:36 downsj Exp $
+# $OpenBSD: files,v 1.137 1999/11/30 07:55:55 cmetz Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -66,6 +66,10 @@ file dev/ic/aic7xxx.c ahc
device aic: scsi
file dev/ic/aic6360.c aic
+# DPT EATA SCSI controllers
+device dpt: scsi
+file dev/ic/dpt.c dpt
+
# AdvanSys 1200A, 1200B and ULTRA SCSI controllers
device adv: scsi
file dev/ic/adv.c adv
diff --git a/sys/dev/eisa/dpt_eisa.c b/sys/dev/eisa/dpt_eisa.c
new file mode 100644
index 00000000000..fca43e730f9
--- /dev/null
+++ b/sys/dev/eisa/dpt_eisa.c
@@ -0,0 +1,214 @@
+/* $OpenBSD: dpt_eisa.c,v 1.1 1999/11/30 07:55:56 cmetz Exp $ */
+/* $NetBSD: dpt_eisa.c,v 1.2 1999/10/18 21:59:19 ad Exp $ */
+
+/*
+ * Copyright (c) 1999 Andy Doran <ad@NetBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * EISA front-end for DPT EATA SCSI driver.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __NetBSD__
+__KERNEL_RCSID(0, "$NetBSD: dpt_eisa.c,v 1.2 1999/10/18 21:59:19 ad Exp $");
+#endif /* __NetBSD__ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#ifdef __NetBSD__
+#include <dev/scsipi/scsi_all.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsiconf.h>
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#endif /* __OpenBSD__ */
+
+#include <dev/eisa/eisavar.h>
+#include <dev/eisa/eisadevs.h>
+
+#include <dev/ic/dptreg.h>
+#include <dev/ic/dptvar.h>
+
+#define DPT_EISA_SLOT_OFFSET 0x0c00
+#define DPT_EISA_IOSIZE 0x0100
+#define DPT_EISA_IOCONF 0x90
+#define DPT_EISA_EATA_REG_OFFSET 0x88
+
+int dpt_eisa_irq __P((bus_space_tag_t, bus_space_handle_t, int *));
+#ifdef __NetBSD__
+int dpt_eisa_match __P((struct device *, struct cfdata *, void *));
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+int dpt_eisa_match __P((struct device *, void *, void *));
+#endif /* __OpenBSD__ */
+void dpt_eisa_attach __P((struct device *, struct device *, void *));
+
+struct cfattach dpt_eisa_ca = {
+ sizeof(struct dpt_softc), dpt_eisa_match, dpt_eisa_attach
+};
+
+const char *dpt_eisa_boards[] = {
+ "DPT2402",
+ "DPTA401",
+ "DPTA402",
+ "DPTA410",
+ "DPTA411",
+ "DPTA412",
+ "DPTA420",
+ "DPTA501",
+ "DPTA502",
+ "DPTA701",
+ "DPTBC01",
+ "NEC8200", /* OEM */
+ "ATT2408", /* OEM */
+ NULL
+};
+
+int
+dpt_eisa_irq(iot, ioh, irq)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int *irq;
+{
+
+ switch (bus_space_read_1(iot, ioh, DPT_EISA_IOCONF) & 0x38) {
+ case 0x08:
+ *irq = 11;
+ break;
+ case 0x10:
+ *irq = 15;
+ break;
+ case 0x20:
+ *irq = 14;
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+dpt_eisa_match(parent, match, aux)
+ struct device *parent;
+#ifdef __NetBSD__
+ struct cfdata *match;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ void *match;
+#endif /* __OpenBSD__ */
+ void *aux;
+{
+ struct eisa_attach_args *ea;
+ int i;
+
+ ea = aux;
+
+ for (i = 0; dpt_eisa_boards[i] != NULL; i++)
+ if (strcmp(ea->ea_idstring, dpt_eisa_boards[i]) == 0)
+ break;
+
+ return (dpt_eisa_boards[i] != NULL);
+}
+
+void
+dpt_eisa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct eisa_attach_args *ea;
+ bus_space_handle_t ioh;
+ eisa_chipset_tag_t ec;
+ eisa_intr_handle_t ih;
+ struct dpt_softc *sc;
+ bus_space_tag_t iot;
+ const char *intrstr;
+ int irq;
+
+ ea = aux;
+ sc = (struct dpt_softc *)self;
+ iot = ea->ea_iot;
+ ec = ea->ea_ec;
+
+ printf(": ");
+
+ if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
+ DPT_EISA_SLOT_OFFSET, DPT_EISA_IOSIZE, 0, &ioh)) {
+ printf("can't map i/o space\n");
+ return;
+ }
+
+ sc->sc_iot = iot;
+ sc->sc_ioh = ioh;
+ sc->sc_dmat = ea->ea_dmat;
+
+ /* Map and establish the interrupt. */
+ if (dpt_eisa_irq(iot, ioh, &irq)) {
+ printf("HBA on invalid IRQ (%d)\n", irq);
+ return;
+ }
+
+ if (eisa_intr_map(ec, irq, &ih)) {
+ printf("can't map interrupt (%d)\n", irq);
+ return;
+ }
+
+ intrstr = eisa_intr_string(ec, ih);
+#ifdef __NetBSD__
+ sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO,
+ dpt_intr, sc);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO,
+ dpt_intr, sc, sc->sc_dv.dv_xname);
+#endif /* __OpenBSD__ */
+ if (sc->sc_ih == NULL) {
+ printf("can't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+
+ /* Read the EATA configuration */
+ if (dpt_readcfg(sc)) {
+ printf("%s: readcfg failed - see dpt(4)\n",
+ sc->sc_dv.dv_xname);
+ return;
+ }
+
+ /* Now attach to the bus-independant code */
+ dpt_init(sc, intrstr);
+}
diff --git a/sys/dev/eisa/files.eisa b/sys/dev/eisa/files.eisa
index 8e26747fb2c..22ff6417699 100644
--- a/sys/dev/eisa/files.eisa
+++ b/sys/dev/eisa/files.eisa
@@ -1,4 +1,4 @@
-# $OpenBSD: files.eisa,v 1.8 1996/11/28 23:27:40 niklas Exp $
+# $OpenBSD: files.eisa,v 1.9 1999/11/30 07:55:55 cmetz Exp $
# $NetBSD: files.eisa,v 1.12 1996/09/01 00:10:55 mycroft Exp $
#
# Config.new file and device description for machine-independent EISA code.
@@ -24,6 +24,11 @@ file dev/eisa/ahc_eisa.c ahc_eisa
attach bha at eisa with bha_eisa
file dev/eisa/bha_eisa.c bha_eisa
+# DPT EATA SCSI controllers
+# device declaration in sys/conf/files
+attach dpt at eisa with dpt_eisa
+file dev/eisa/dpt_eisa.c dpt_eisa
+
# UltraStor UHA-24f boards
# device declaration in sys/conf/files
attach uha at eisa with uha_eisa
diff --git a/sys/dev/ic/dpt.c b/sys/dev/ic/dpt.c
new file mode 100644
index 00000000000..6b11da58777
--- /dev/null
+++ b/sys/dev/ic/dpt.c
@@ -0,0 +1,1441 @@
+/* $OpenBSD: dpt.c,v 1.1 1999/11/30 07:55:56 cmetz Exp $ */
+/* $NetBSD: dpt.c,v 1.12 1999/10/23 16:26:33 ad Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andy Doran, Charles M. Hannum and by Jason R. Thorpe of the Numerical
+ * Aerospace Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Portions of this code fall under the following copyright:
+ *
+ * Originally written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ */
+
+/*
+ * Driver for DPT EATA SCSI adapters.
+ *
+ * TODO:
+ *
+ * o Need a front-end for (newer) ISA boards.
+ * o Handle older firmware better.
+ * o Find a bunch of different firmware EEPROMs and try them out.
+ * o Test with a bunch of different boards.
+ * o dpt_readcfg() should not be using CP_PIO_GETCFG.
+ * o An interface to userland applications.
+ * o Some sysctls or a utility (eg dptctl(8)) to control parameters.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __NetBSD__
+__KERNEL_RCSID(0, "$NetBSD: dpt.c,v 1.12 1999/10/23 16:26:33 ad Exp $");
+#endif /* __NetBSD__ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+
+#include <machine/endian.h>
+#ifdef __NetBSD__
+#include <machine/bswap.h>
+#endif /* __NetBSD__ */
+#include <machine/bus.h>
+
+#ifdef __NetBSD__
+#include <dev/scsipi/scsi_all.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsiconf.h>
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#endif /* __OpenBSD__ */
+
+#include <dev/ic/dptreg.h>
+#include <dev/ic/dptvar.h>
+
+#ifdef __OpenBSD__
+static void dpt_enqueue __P((struct dpt_softc *, struct scsi_xfer *, int));
+static struct scsi_xfer *dpt_dequeue __P((struct dpt_softc *));
+
+struct cfdriver dpt_cd = {
+ NULL, "dpt", DV_DULL
+};
+#endif /* __OpenBSD__ */
+
+/* A default for our link struct */
+#ifdef __NetBSD__
+static struct scsipi_device dpt_dev = {
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+static struct scsi_device dpt_dev = {
+#endif /* __OpenBSD__ */
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+#ifndef offsetof
+#define offsetof(type, member) (int)((&((type *)0)->member))
+#endif /* offsetof */
+
+static char *dpt_cname[] = {
+ "PM3334", "SmartRAID IV",
+ "PM3332", "SmartRAID IV",
+ "PM2144", "SmartCache IV",
+ "PM2044", "SmartCache IV",
+ "PM2142", "SmartCache IV",
+ "PM2042", "SmartCache IV",
+ "PM2041", "SmartCache IV",
+ "PM3224", "SmartRAID III",
+ "PM3222", "SmartRAID III",
+ "PM3021", "SmartRAID III",
+ "PM2124", "SmartCache III",
+ "PM2024", "SmartCache III",
+ "PM2122", "SmartCache III",
+ "PM2022", "SmartCache III",
+ "PM2021", "SmartCache III",
+ "SK2012", "SmartCache Plus",
+ "SK2011", "SmartCache Plus",
+ NULL, "unknown adapter, please report using send-pr(1)",
+};
+
+/*
+ * Handle an interrupt from the HBA.
+ */
+int
+dpt_intr(xxx_sc)
+ void *xxx_sc;
+{
+ struct dpt_softc *sc;
+ struct dpt_ccb *ccb;
+ struct eata_sp *sp;
+ static int moretimo;
+ int more;
+
+ sc = xxx_sc;
+ sp = sc->sc_statpack;
+
+ if (!sp) {
+#ifdef DEBUG
+ printf("%s: premature intr (st:%02x aux:%02x)\n",
+ sc->sc_dv.dv_xname, dpt_inb(sc, HA_STATUS),
+ dpt_inb(sc, HA_AUX_STATUS));
+#else /* DEBUG */
+ (void) dpt_inb(sc, HA_STATUS);
+#endif /* DEBUG */
+ return (0);
+ }
+
+ more = 0;
+
+#ifdef DEBUG
+ if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) == 0)
+ printf("%s: spurious intr\n", sc->sc_dv.dv_xname);
+#endif
+
+ /* Don't get stalled by HA_ST_MORE */
+ if (moretimo < DPT_MORE_TIMEOUT / 100)
+ moretimo = 0;
+
+ for (;;) {
+ /*
+ * HBA might have interrupted while we were dealing with the
+ * last completed command, since we ACK before we deal; keep
+ * polling. If no interrupt is signalled, but the HBA has
+ * indicated that more data will be available soon, hang
+ * around.
+ */
+ if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) == 0) {
+ if (more != 0 && moretimo++ < DPT_MORE_TIMEOUT / 100) {
+ DELAY(10);
+ continue;
+ }
+ break;
+ }
+
+#ifdef __NetBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_spoff,
+ sizeof(struct eata_sp), BUS_DMASYNC_POSTREAD);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb,
+ BUS_DMASYNC_POSTREAD);
+#endif /* __OpenBSD__ */
+
+ if (!sp) {
+ more = dpt_inb(sc, HA_STATUS) & HA_ST_MORE;
+
+ /* Don't get stalled by HA_ST_MORE */
+ if (moretimo < DPT_MORE_TIMEOUT / 100)
+ moretimo = 0;
+ continue;
+ }
+
+ /* Might have looped before HBA can reset HBA_AUX_INTR */
+ if (sp->sp_ccbid == -1) {
+ DELAY(50);
+#ifdef DIAGNOSTIC
+ printf("%s: slow reset of HA_AUX_STATUS?",
+ sc->sc_dv.dv_xname);
+#endif
+ if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) == 0)
+ return (0);
+#ifdef DIAGNOSTIC
+ printf("%s: was a slow reset of HA_AUX_STATUS",
+ sc->sc_dv.dv_xname);
+#endif
+ /* Re-sync DMA map */
+#ifdef __NetBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb,
+ sc->sc_spoff, sizeof(struct eata_sp),
+ BUS_DMASYNC_POSTREAD);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb,
+ BUS_DMASYNC_POSTREAD);
+#endif /* __OpenBSD__ */
+ }
+
+ /* Make sure CCB ID from status packet is realistic */
+ if (sp->sp_ccbid >= 0 && sp->sp_ccbid < sc->sc_nccbs) {
+ /* Sync up DMA map and cache cmd status */
+ ccb = sc->sc_ccbs + sp->sp_ccbid;
+
+#ifdef __NetBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb,
+ CCB_OFF(sc, ccb), sizeof(struct dpt_ccb),
+ BUS_DMASYNC_POSTWRITE);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb,
+ BUS_DMASYNC_POSTWRITE);
+#endif /* __OpenBSD__ */
+
+ ccb->ccb_hba_status = sp->sp_hba_status & 0x7F;
+ ccb->ccb_scsi_status = sp->sp_scsi_status;
+
+ /*
+ * Ack the interrupt and process the CCB. If this
+ * is a private CCB it's up to dpt_poll() to notice.
+ */
+ sp->sp_ccbid = -1;
+ ccb->ccb_flg |= CCB_INTR;
+ more = dpt_inb(sc, HA_STATUS) & HA_ST_MORE;
+ if ((ccb->ccb_flg & CCB_PRIVATE) == 0)
+ dpt_done_ccb(sc, ccb);
+ } else {
+ printf("%s: bogus status (returned CCB id %d)\n",
+ sc->sc_dv.dv_xname, sp->sp_ccbid);
+
+ /* Ack the interrupt */
+ sp->sp_ccbid = -1;
+ more = dpt_inb(sc, HA_STATUS) & HA_ST_MORE;
+ }
+
+ /* Don't get stalled by HA_ST_MORE */
+ if (moretimo < DPT_MORE_TIMEOUT / 100)
+ moretimo = 0;
+ }
+
+ return (0);
+}
+
+/*
+ * Initialize and attach the HBA. This is the entry point from bus
+ * specific probe-and-attach code.
+ */
+void
+dpt_init(sc, intrstr)
+ struct dpt_softc *sc;
+ const char *intrstr;
+{
+ struct eata_inquiry_data *ei;
+ int i, j, error, rseg, mapsize;
+ bus_dma_segment_t seg;
+ struct eata_cfg *ec;
+ char model[16];
+
+ ec = &sc->sc_ec;
+
+ /* Allocate the CCB/status packet/scratch DMA map and load */
+ sc->sc_nccbs = min(betoh16(*(int16_t *)ec->ec_queuedepth),
+ DPT_MAX_CCBS);
+ sc->sc_spoff = sc->sc_nccbs * sizeof(struct dpt_ccb);
+ sc->sc_scroff = sc->sc_spoff + sizeof(struct eata_sp);
+ sc->sc_scrlen = 256; /* XXX */
+ mapsize = sc->sc_nccbs * sizeof(struct dpt_ccb) + sc->sc_scrlen +
+ sizeof(struct eata_sp);
+
+ if ((error = bus_dmamem_alloc(sc->sc_dmat, mapsize, NBPG, 0,
+ &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to allocate CCBs, error = %d\n",
+ sc->sc_dv.dv_xname, error);
+ return;
+ }
+
+ if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, mapsize,
+ (caddr_t *)&sc->sc_ccbs, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
+ printf("%s: unable to map CCBs, error = %d\n",
+ sc->sc_dv.dv_xname, error);
+ return;
+ }
+
+ if ((error = bus_dmamap_create(sc->sc_dmat, mapsize, mapsize, 1, 0,
+ BUS_DMA_NOWAIT, &sc->sc_dmamap_ccb)) != 0) {
+ printf("%s: unable to create CCB DMA map, error = %d\n",
+ sc->sc_dv.dv_xname, error);
+ return;
+ }
+
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_ccb,
+ sc->sc_ccbs, mapsize, NULL, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to load CCB DMA map, error = %d\n",
+ sc->sc_dv.dv_xname, error);
+ return;
+ }
+
+ sc->sc_statpack = (struct eata_sp *)((caddr_t)sc->sc_ccbs +
+ sc->sc_spoff);
+ sc->sc_sppa = sc->sc_dmamap_ccb->dm_segs[0].ds_addr + sc->sc_spoff;
+ sc->sc_scr = (caddr_t)sc->sc_ccbs + sc->sc_scroff;
+ sc->sc_scrpa = sc->sc_dmamap_ccb->dm_segs[0].ds_addr + sc->sc_scroff;
+ sc->sc_statpack->sp_ccbid = -1;
+
+ /* Initialize the CCBs */
+ TAILQ_INIT(&sc->sc_free_ccb);
+ i = dpt_create_ccbs(sc, sc->sc_ccbs, sc->sc_nccbs);
+
+ if (i == 0) {
+ printf("%s: unable to create CCBs\n", sc->sc_dv.dv_xname);
+ return;
+ } else if (i != sc->sc_nccbs) {
+ printf("%s: %d/%d CCBs created!\n", sc->sc_dv.dv_xname, i,
+ sc->sc_nccbs);
+ sc->sc_nccbs = i;
+ }
+
+ /* Set shutdownhook before we start any device activity */
+ sc->sc_sdh = shutdownhook_establish(dpt_shutdown, sc);
+
+ /* Get the page 0 inquiry data from the HBA */
+ dpt_hba_inquire(sc, &ei);
+
+ /*
+ * dpt0 at pci0 dev 12 function 0: DPT SmartRAID III (PM3224A/9X-R)
+ * dpt0: interrupting at irq 10
+ * dpt0: 64 queued commands, 1 channel(s), adapter on ID(s) 7
+ */
+ for (i = 0; ei->ei_vendor[i] != ' ' && i < 8; i++)
+ ;
+ ei->ei_vendor[i] = '\0';
+
+ for (i = 0; ei->ei_model[i] != ' ' && i < 7; i++)
+ model[i] = ei->ei_model[i];
+ for (j = 0; ei->ei_suffix[j] != ' ' && j < 7; j++)
+ model[i++] = ei->ei_model[i];
+ model[i] = '\0';
+
+ /* Find the cannonical name for the board */
+ for (i = 0; dpt_cname[i] != NULL; i += 2)
+ if (memcmp(ei->ei_model, dpt_cname[i], 6) == 0)
+ break;
+
+ printf("%s %s (%s)\n", ei->ei_vendor, dpt_cname[i + 1], model);
+
+ if (intrstr != NULL)
+ printf("%s: interrupting at %s\n", sc->sc_dv.dv_xname, intrstr);
+
+ printf("%s: %d queued commands, %d channel(s), adapter on ID(s)",
+ sc->sc_dv.dv_xname, sc->sc_nccbs, ec->ec_maxchannel + 1);
+
+ for (i = 0; i <= ec->ec_maxchannel; i++)
+ printf(" %d", ec->ec_hba[3 - i]);
+ printf("\n");
+
+ /* Reset the SCSI bus */
+ if (dpt_cmd(sc, NULL, 0, CP_IMMEDIATE, CPI_BUS_RESET))
+ panic("%s: dpt_cmd failed", sc->sc_dv.dv_xname);
+ DELAY(20000);
+
+ /* Fill in the adapter, each link and attach in turn */
+#ifdef __NetBSD__
+ sc->sc_adapter.scsipi_cmd = dpt_scsi_cmd;
+ sc->sc_adapter.scsipi_minphys = dpt_minphys;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ sc->sc_adapter.scsi_cmd = dpt_scsi_cmd;
+ sc->sc_adapter.scsi_minphys = dpt_minphys;
+#endif /* __OpenBSD__ */
+
+ for (i = 0; i <= ec->ec_maxchannel; i++) {
+#ifdef __NetBSD__
+ struct scsipi_link *link;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ struct scsi_link *link;
+#endif /* __OpenBSD__ */
+ sc->sc_hbaid[i] = ec->ec_hba[3 - i];
+ link = &sc->sc_link[i];
+#ifdef __NetBSD__
+ link->scsipi_scsi.scsibus = i;
+ link->scsipi_scsi.adapter_target = sc->sc_hbaid[i];
+ link->scsipi_scsi.max_lun = ec->ec_maxlun;
+ link->scsipi_scsi.max_target = ec->ec_maxtarget;
+ link->type = BUS_SCSI;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ link->scsibus = i;
+ link->adapter_target = sc->sc_hbaid[i];
+#endif /* __OpenBSD__ */
+ link->device = &dpt_dev;
+ link->adapter = &sc->sc_adapter;
+ link->adapter_softc = sc;
+ link->openings = sc->sc_nccbs;
+ config_found(&sc->sc_dv, link, scsiprint);
+ }
+}
+
+/*
+ * Our 'shutdownhook' to cleanly shut down the HBA. The HBA must flush
+ * all data from it's cache and mark array groups as clean.
+ */
+void
+dpt_shutdown(xxx_sc)
+ void *xxx_sc;
+{
+ struct dpt_softc *sc;
+
+ sc = xxx_sc;
+ printf("shutting down %s...", sc->sc_dv.dv_xname);
+ dpt_cmd(sc, NULL, 0, CP_IMMEDIATE, CPI_POWEROFF_WARN);
+ DELAY(5000*1000);
+ printf(" done\n");
+}
+
+/*
+ * Send an EATA command to the HBA.
+ */
+int
+dpt_cmd(sc, cp, addr, eatacmd, icmd)
+ struct dpt_softc *sc;
+ struct eata_cp *cp;
+ u_int32_t addr;
+ int eatacmd, icmd;
+{
+ int i;
+
+ for (i = 20000; i; i--) {
+ if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_BUSY) == 0)
+ break;
+ DELAY(50);
+ }
+
+ /* Not the most graceful way to handle this */
+ if (i == 0) {
+ printf("%s: HBA timeout on EATA command issue; aborting\n",
+ sc->sc_dv.dv_xname);
+ return (-1);
+ }
+
+ if (cp == NULL)
+ addr = 0;
+
+ dpt_outb(sc, HA_DMA_BASE + 0, (u_int32_t)addr);
+ dpt_outb(sc, HA_DMA_BASE + 1, (u_int32_t)addr >> 8);
+ dpt_outb(sc, HA_DMA_BASE + 2, (u_int32_t)addr >> 16);
+ dpt_outb(sc, HA_DMA_BASE + 3, (u_int32_t)addr >> 24);
+
+ if (eatacmd == CP_IMMEDIATE) {
+ if (cp == NULL) {
+ /* XXX should really pass meaningful values */
+ dpt_outb(sc, HA_ICMD_CODE2, 0);
+ dpt_outb(sc, HA_ICMD_CODE1, 0);
+ }
+ dpt_outb(sc, HA_ICMD, icmd);
+ }
+
+ dpt_outb(sc, HA_COMMAND, eatacmd);
+ return (0);
+}
+
+/*
+ * Wait for the HBA to reach an arbitrary state.
+ */
+int
+dpt_wait(sc, mask, state, ms)
+ struct dpt_softc *sc;
+ u_int8_t mask, state;
+ int ms;
+{
+
+ for (ms *= 10; ms; ms--) {
+ if ((dpt_inb(sc, HA_STATUS) & mask) == state)
+ return (0);
+ DELAY(100);
+ }
+ return (-1);
+}
+
+/*
+ * Wait for the specified CCB to finish. This is used when we may not be
+ * able to sleep and/or interrupts are disabled (eg autoconfiguration).
+ * The timeout value from the CCB is used. This should only be used for
+ * CCB_PRIVATE requests; otherwise the CCB will get recycled before we get
+ * a look at it.
+ */
+int
+dpt_poll(sc, ccb)
+ struct dpt_softc *sc;
+ struct dpt_ccb *ccb;
+{
+ int i;
+
+#ifdef DEBUG
+ if ((ccb->ccb_flg & CCB_PRIVATE) == 0)
+ panic("dpt_poll: called for non-CCB_PRIVATE request\n");
+#endif
+
+ if ((ccb->ccb_flg & CCB_INTR) != 0)
+ return (0);
+
+ for (i = ccb->ccb_timeout * 20; i; i--) {
+ if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) != 0)
+ dpt_intr(sc);
+ if ((ccb->ccb_flg & CCB_INTR) != 0)
+ return (0);
+ DELAY(50);
+ }
+ return (-1);
+}
+
+/*
+ * Read the EATA configuration from the HBA and perform some sanity checks.
+ */
+int
+dpt_readcfg(sc)
+ struct dpt_softc *sc;
+{
+ struct eata_cfg *ec;
+ int i, j, stat;
+ u_int16_t *p;
+
+ ec = &sc->sc_ec;
+
+ /* Older firmware may puke if we talk to it too soon after reset */
+ dpt_outb(sc, HA_COMMAND, CP_RESET);
+ DELAY(750000);
+
+ for (i = 1000; i; i--) {
+ if ((dpt_inb(sc, HA_STATUS) & HA_ST_READY) != 0)
+ break;
+ DELAY(2000);
+ }
+
+ if (i == 0) {
+ printf("%s: HBA not ready after reset: %02x\n",
+ sc->sc_dv.dv_xname, dpt_inb(sc, HA_STATUS));
+ return (-1);
+ }
+
+ while((((stat = dpt_inb(sc, HA_STATUS))
+ != (HA_ST_READY|HA_ST_SEEK_COMPLETE))
+ && (stat != (HA_ST_READY|HA_ST_SEEK_COMPLETE|HA_ST_ERROR))
+ && (stat != (HA_ST_READY|HA_ST_SEEK_COMPLETE|HA_ST_ERROR|HA_ST_DRQ)))
+ || (dpt_wait(sc, HA_ST_BUSY, 0, 2000))) {
+ /* RAID drives still spinning up? */
+ if((dpt_inb(sc, HA_ERROR) != 'D')
+ || (dpt_inb(sc, HA_ERROR + 1) != 'P')
+ || (dpt_inb(sc, HA_ERROR + 2) != 'T')) {
+ printf("%s: HBA not ready\n", sc->sc_dv.dv_xname);
+ return (-1);
+ }
+ }
+
+ /*
+ * Issue the read-config command and wait for the data to appear.
+ * XXX we shouldn't be doing this with PIO, but it makes it a lot
+ * easier as no DMA setup is required.
+ */
+ dpt_outb(sc, HA_COMMAND, CP_PIO_GETCFG);
+ memset(ec, 0, sizeof(*ec));
+ i = ((int)&((struct eata_cfg *)0)->ec_cfglen +
+ sizeof(ec->ec_cfglen)) >> 1;
+ p = (u_int16_t *)ec;
+
+ if (dpt_wait(sc, 0xFF, HA_ST_DATA_RDY, 2000)) {
+ printf("%s: cfg data didn't appear (status:%02x)\n",
+ sc->sc_dv.dv_xname, dpt_inb(sc, HA_STATUS));
+ return (-1);
+ }
+
+ /* Begin reading */
+ while (i--)
+ *p++ = dpt_inw(sc, HA_DATA);
+
+ if ((i = ec->ec_cfglen) > (sizeof(struct eata_cfg)
+ - (int)(&(((struct eata_cfg *)0L)->ec_cfglen))
+ - sizeof(ec->ec_cfglen)))
+ i = sizeof(struct eata_cfg)
+ - (int)(&(((struct eata_cfg *)0L)->ec_cfglen))
+ - sizeof(ec->ec_cfglen);
+
+ j = i + (int)(&(((struct eata_cfg *)0L)->ec_cfglen)) +
+ sizeof(ec->ec_cfglen);
+ i >>= 1;
+
+ while (i--)
+ *p++ = dpt_inw(sc, HA_DATA);
+
+ /* Flush until we have read 512 bytes. */
+ i = (512 - j + 1) >> 1;
+ while (i--)
+ dpt_inw(sc, HA_DATA);
+
+ /* Defaults for older Firmware */
+ if (p <= (u_short *)&ec->ec_hba[DPT_MAX_CHANNELS - 1])
+ ec->ec_hba[DPT_MAX_CHANNELS - 1] = 7;
+
+ if ((dpt_inb(sc, HA_STATUS) & HA_ST_ERROR) != 0) {
+ printf("%s: HBA error\n", sc->sc_dv.dv_xname);
+ return (-1);
+ }
+
+ if (!ec->ec_hbavalid) {
+ printf("%s: ec_hba field invalid\n", sc->sc_dv.dv_xname);
+ return (-1);
+ }
+
+ if (memcmp(ec->ec_eatasig, "EATA", 4) != 0) {
+ printf("%s: EATA signature mismatch\n", sc->sc_dv.dv_xname);
+ return (-1);
+ }
+
+ if (!ec->ec_dmasupported) {
+ printf("%s: DMA not supported\n", sc->sc_dv.dv_xname);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Adjust the size of each I/O before it passes to the SCSI layer.
+ */
+void
+dpt_minphys(bp)
+ struct buf *bp;
+{
+
+ if (bp->b_bcount > DPT_MAX_XFER)
+ bp->b_bcount = DPT_MAX_XFER;
+ minphys(bp);
+}
+
+/*
+ * Put a CCB onto the freelist.
+ */
+void
+dpt_free_ccb(sc, ccb)
+ struct dpt_softc *sc;
+ struct dpt_ccb *ccb;
+{
+ int s;
+
+ s = splbio();
+ ccb->ccb_flg = 0;
+ TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, ccb_chain);
+
+ /* Wake anybody waiting for a free ccb */
+ if (ccb->ccb_chain.tqe_next == 0)
+ wakeup(&sc->sc_free_ccb);
+ splx(s);
+}
+
+/*
+ * Initialize the specified CCB.
+ */
+int
+dpt_init_ccb(sc, ccb)
+ struct dpt_softc *sc;
+ struct dpt_ccb *ccb;
+{
+ int error;
+
+ /* Create the DMA map for this CCB's data */
+ error = bus_dmamap_create(sc->sc_dmat, DPT_MAX_XFER, DPT_SG_SIZE,
+ DPT_MAX_XFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &ccb->ccb_dmamap_xfer);
+
+ if (error) {
+ printf("%s: can't create ccb dmamap (%d)\n",
+ sc->sc_dv.dv_xname, error);
+ return (error);
+ }
+
+ ccb->ccb_flg = 0;
+ ccb->ccb_ccbpa = sc->sc_dmamap_ccb->dm_segs[0].ds_addr +
+ CCB_OFF(sc, ccb);
+ return (0);
+}
+
+/*
+ * Create a set of CCBs and add them to the free list.
+ */
+int
+dpt_create_ccbs(sc, ccbstore, count)
+ struct dpt_softc *sc;
+ struct dpt_ccb *ccbstore;
+ int count;
+{
+ struct dpt_ccb *ccb;
+ int i, error;
+
+ memset(ccbstore, 0, sizeof(struct dpt_ccb) * count);
+
+ for (i = 0, ccb = ccbstore; i < count; i++, ccb++) {
+ if ((error = dpt_init_ccb(sc, ccb)) != 0) {
+ printf("%s: unable to init ccb, error = %d\n",
+ sc->sc_dv.dv_xname, error);
+ break;
+ }
+ ccb->ccb_id = i;
+ TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_chain);
+ }
+
+ return (i);
+}
+
+/*
+ * Get a free ccb. If there are none, see if we can allocate a new one. If
+ * none are available right now and we are permitted to sleep, then wait
+ * until one becomes free, otherwise return an error.
+ */
+struct dpt_ccb *
+dpt_alloc_ccb(sc, flg)
+ struct dpt_softc *sc;
+ int flg;
+{
+ struct dpt_ccb *ccb;
+ int s;
+
+ s = splbio();
+
+ for (;;) {
+ ccb = TAILQ_FIRST(&sc->sc_free_ccb);
+ if (ccb) {
+ TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_chain);
+ break;
+ }
+#ifdef __NetBSD__
+ if ((flg & XS_CTL_NOSLEEP) != 0) {
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ if ((flg & SCSI_NOSLEEP) != 0) {
+#endif /* __OpenBSD__ */
+ splx(s);
+ return (NULL);
+ }
+ tsleep(&sc->sc_free_ccb, PRIBIO, "dptccb", 0);
+ }
+
+ ccb->ccb_flg |= CCB_ALLOC;
+ splx(s);
+ return (ccb);
+}
+
+/*
+ * We have a CCB which has been processed by the HBA, now we look to see how
+ * the operation went. CCBs marked with CCB_PRIVATE are not automatically
+ * passed here by dpt_intr().
+ */
+void
+dpt_done_ccb(sc, ccb)
+ struct dpt_softc *sc;
+ struct dpt_ccb *ccb;
+{
+#ifdef __NetBSD__
+ struct scsipi_sense_data *s1, *s2;
+ struct scsipi_xfer *xs;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs;
+#endif /* __OpenBSD__ */
+ bus_dma_tag_t dmat;
+
+ dmat = sc->sc_dmat;
+ xs = ccb->ccb_xs;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("dpt_done_ccb\n"));
+
+ /*
+ * If we were a data transfer, unload the map that described the
+ * data buffer.
+ */
+ if (xs->datalen) {
+#ifdef __NetBSD__
+ bus_dmamap_sync(dmat, ccb->ccb_dmamap_xfer, 0,
+ ccb->ccb_dmamap_xfer->dm_mapsize,
+ (xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMASYNC_POSTREAD :
+ BUS_DMASYNC_POSTWRITE);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bus_dmamap_sync(dmat, ccb->ccb_dmamap_xfer,
+ (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
+ BUS_DMASYNC_POSTWRITE);
+#endif /* __OpenBSD__ */
+ bus_dmamap_unload(dmat, ccb->ccb_dmamap_xfer);
+ }
+
+ /*
+ * Otherwise, put the results of the operation into the xfer and
+ * call whoever started it.
+ */
+#ifdef DIAGNOSTIC
+ if ((ccb->ccb_flg & CCB_ALLOC) == 0) {
+ panic("%s: done ccb not allocated!\n", sc->sc_dv.dv_xname);
+ return;
+ }
+#endif
+
+ if (xs->error == XS_NOERROR) {
+ if (ccb->ccb_hba_status != HA_NO_ERROR) {
+ switch (ccb->ccb_hba_status) {
+ case HA_ERROR_SEL_TO:
+ xs->error = XS_SELTIMEOUT;
+ break;
+ case HA_ERROR_RESET:
+ xs->error = XS_RESET;
+ break;
+ default: /* Other scsi protocol messes */
+ printf("%s: HBA status %x\n",
+ sc->sc_dv.dv_xname, ccb->ccb_hba_status);
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ } else if (ccb->ccb_scsi_status != SCSI_OK) {
+ switch (ccb->ccb_scsi_status) {
+ case SCSI_CHECK:
+ s1 = &ccb->ccb_sense;
+#ifdef __NetBSD__
+ s2 = &xs->sense.scsi_sense;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ s2 = &xs->sense;
+#endif /* __OpenBSD__ */
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ break;
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+ default:
+ printf("%s: SCSI status %x\n",
+ sc->sc_dv.dv_xname, ccb->ccb_scsi_status);
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ } else
+ xs->resid = 0;
+
+ xs->status = ccb->ccb_scsi_status;
+ }
+
+ /* Free up the CCB and mark the command as done */
+ dpt_free_ccb(sc, ccb);
+#ifdef __NetBSD__
+ xs->xs_status |= XS_STS_DONE;
+ scsipi_done(xs);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+#endif /* __OpenBSD__ */
+
+ /*
+ * If there are entries in the software queue, try to run the first
+ * one. We should be more or less guaranteed to succeed, since we
+ * just freed an CCB. NOTE: dpt_scsi_cmd() relies on our calling it
+ * with the first entry in the queue.
+ */
+#ifdef __NetBSD__
+ if ((xs = TAILQ_FIRST(&sc->sc_queue)) != NULL)
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ if ((xs = sc->sc_queue.lh_first) != NULL)
+#endif /* __OpenBSD__ */
+ dpt_scsi_cmd(xs);
+}
+
+#ifdef __OpenBSD__
+/*
+ * Insert a scsi_xfer into the software queue. We overload xs->free_list
+ * to avoid having to allocate additional resources (since we're used
+ * only during resource shortages anyhow.
+ */
+static void
+dpt_enqueue(sc, xs, infront)
+ struct dpt_softc *sc;
+ struct scsi_xfer *xs;
+ int infront;
+{
+
+ if (infront || sc->sc_queue.lh_first == NULL) {
+ if (sc->sc_queue.lh_first == NULL)
+ sc->sc_queuelast = xs;
+ LIST_INSERT_HEAD(&sc->sc_queue, xs, free_list);
+ return;
+ }
+ LIST_INSERT_AFTER(sc->sc_queuelast, xs, free_list);
+ sc->sc_queuelast = xs;
+}
+
+/*
+ * Pull a scsi_xfer off the front of the software queue.
+ */
+static struct scsi_xfer *
+dpt_dequeue(sc)
+ struct dpt_softc *sc;
+{
+ struct scsi_xfer *xs;
+
+ xs = sc->sc_queue.lh_first;
+ LIST_REMOVE(xs, free_list);
+
+ if (sc->sc_queue.lh_first == NULL)
+ sc->sc_queuelast = NULL;
+
+ return (xs);
+}
+#endif /* __OpenBSD__ */
+
+/*
+ * Start a SCSI command.
+ */
+int
+dpt_scsi_cmd(xs)
+#ifdef __NetBSD__
+ struct scsipi_xfer *xs;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ struct scsi_xfer *xs;
+#endif /* __OpenBSD__ */
+{
+ int error, i, flags, s, fromqueue, dontqueue;
+#ifdef __NetBSD__
+ struct scsipi_link *sc_link;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ struct scsi_link *sc_link;
+#endif /* __OpenBSD__ */
+ struct dpt_softc *sc;
+ struct dpt_ccb *ccb;
+ struct eata_sg *sg;
+ struct eata_cp *cp;
+ bus_dma_tag_t dmat;
+ bus_dmamap_t xfer;
+
+ sc_link = xs->sc_link;
+#ifdef __NetBSD__
+ flags = xs->xs_control;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ flags = xs->flags;
+#endif /* __OpenBSD__ */
+ sc = sc_link->adapter_softc;
+ dmat = sc->sc_dmat;
+ fromqueue = 0;
+ dontqueue = 0;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("dpt_scsi_cmd\n"));
+
+ /* Protect the queue */
+ s = splbio();
+
+ /*
+ * If we're running the queue from dpt_done_ccb(), we've been called
+ * with the first queue entry as our argument.
+ */
+#ifdef __NetBSD__
+ if (xs == TAILQ_FIRST(&sc->sc_queue)) {
+ TAILQ_REMOVE(&sc->sc_queue, xs, adapter_q);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ if (xs == sc->sc_queue.lh_first) {
+ xs = dpt_dequeue(sc);
+#endif /* __OpenBSD__ */
+ fromqueue = 1;
+ } else {
+ /* Cmds must be no more than 12 bytes for us */
+ if (xs->cmdlen > 12) {
+ splx(s);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+ }
+
+ /* XXX we can't reset devices just yet */
+#ifdef __NetBSD__
+ if ((flags & XS_CTL_RESET) != 0) {
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ if ((xs->flags & SCSI_RESET) != 0) {
+#endif /* __OpenBSD__ */
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+ }
+
+ /* Polled requests can't be queued for later */
+#ifdef __NetBSD__
+ dontqueue = flags & XS_CTL_POLL;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ dontqueue = xs->flags & SCSI_POLL;
+#endif /* __OpenBSD__ */
+
+ /* If there are jobs in the queue, run them first */
+#ifdef __NetBSD__
+ if (TAILQ_FIRST(&sc->sc_queue) != NULL) {
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ if (sc->sc_queue.lh_first != NULL) {
+#endif /* __OpenBSD__ */
+ /*
+ * If we can't queue we abort, since we must
+ * preserve the queue order.
+ */
+ if (dontqueue) {
+ splx(s);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+
+ /* Swap with the first queue entry. */
+#ifdef __NetBSD__
+ TAILQ_INSERT_TAIL(&sc->sc_queue, xs, adapter_q);
+ xs = TAILQ_FIRST(&sc->sc_queue);
+ TAILQ_REMOVE(&sc->sc_queue, xs, adapter_q);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ dpt_enqueue(sc, xs, 0);
+ xs = dpt_dequeue(sc);
+#endif /* __OpenBSD__ */
+ fromqueue = 1;
+ }
+ }
+
+ /* Get a CCB */
+#ifdef __NetBSD__
+ if ((ccb = dpt_alloc_ccb(sc, flags)) == NULL) {
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ if ((ccb = dpt_alloc_ccb(sc, xs->flags)) == NULL) {
+#endif /* __OpenBSD__ */
+ /* If we can't queue, we lose */
+ if (dontqueue) {
+ splx(s);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+
+ /*
+ * Stuff request into the queue, in front if we came off
+ * it in the first place.
+ */
+#ifdef __NetBSD__
+ if (fromqueue)
+ TAILQ_INSERT_HEAD(&sc->sc_queue, xs, adapter_q);
+ else
+ TAILQ_INSERT_TAIL(&sc->sc_queue, xs, adapter_q);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ dpt_enqueue(sc, xs, fromqueue);
+#endif /* __OpenBSD__ */
+ splx(s);
+ return (SUCCESSFULLY_QUEUED);
+ }
+
+ splx(s);
+
+ ccb->ccb_xs = xs;
+ ccb->ccb_timeout = xs->timeout;
+
+ cp = &ccb->ccb_eata_cp;
+#ifdef __NetBSD__
+ memcpy(&cp->cp_scsi_cmd, xs->cmd, xs->cmdlen);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bcopy(xs->cmd, &cp->cp_scsi_cmd, xs->cmdlen);
+#endif /* __OpenBSD__ */
+ cp->cp_ccbid = ccb->ccb_id;
+#ifdef __NetBSD__
+ cp->cp_id = sc_link->scsipi_scsi.target;
+ cp->cp_lun = sc_link->scsipi_scsi.lun;
+ cp->cp_channel = sc_link->scsipi_scsi.channel;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ cp->cp_id = sc_link->target;
+ cp->cp_lun = sc_link->lun;
+ cp->cp_channel = sc_link->scsibus;
+#endif /* __OpenBSD__ */
+ cp->cp_senselen = sizeof(ccb->ccb_sense);
+ cp->cp_stataddr = htobe32(sc->sc_sppa);
+ cp->cp_dispri = 1;
+ cp->cp_identify = 1;
+ cp->cp_autosense = 1;
+#ifdef __NetBSD__
+ cp->cp_datain = ((flags & XS_CTL_DATA_IN) != 0);
+ cp->cp_dataout = ((flags & XS_CTL_DATA_OUT) != 0);
+ cp->cp_interpret = (sc->sc_hbaid[sc_link->scsipi_scsi.channel] ==
+ sc_link->scsipi_scsi.target);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ cp->cp_datain = ((xs->flags & SCSI_DATA_IN) != 0);
+ cp->cp_dataout = ((xs->flags & SCSI_DATA_OUT) != 0);
+ cp->cp_interpret = (sc->sc_hbaid[sc_link->scsibus] == sc_link->target);
+#endif /* __OpenBSD__ */
+
+ /* Synchronous xfers musn't write-back through the cache */
+ if (xs->bp != NULL && (xs->bp->b_flags & (B_ASYNC | B_READ)) == 0)
+ cp->cp_nocache = 1;
+ else
+ cp->cp_nocache = 0;
+
+ cp->cp_senseaddr = htobe32(sc->sc_dmamap_ccb->dm_segs[0].ds_addr +
+ CCB_OFF(sc, ccb) + offsetof(struct dpt_ccb, ccb_sense));
+
+ if (xs->datalen) {
+ xfer = ccb->ccb_dmamap_xfer;
+#ifdef TFS
+#ifdef __NetBSD__
+ if ((flags & XS_CTL_DATA_UIO) != 0) {
+ error = bus_dmamap_load_uio(dmat, xfer,
+ (struct uio *)xs->data, (flags & XS_CTL_NOSLEEP) ?
+ BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ if ((xs->flags & SCSI_DATA_UIO) != 0) {
+ error = bus_dmamap_load_uio(dmat, xfer,
+ (xs->flags & SCSI_NOSLEEP) ?
+ BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
+#endif /* __OpenBSD__ */
+ } else
+#endif /*TFS */
+ {
+#ifdef __NetBSD__
+ error = bus_dmamap_load(dmat, xfer, xs->data,
+ xs->datalen, NULL, (flags & XS_CTL_NOSLEEP) ?
+ BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ error = bus_dmamap_load(dmat, xfer, xs->data,
+ xs->datalen, NULL, (xs->flags & SCSI_NOSLEEP) ?
+ BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
+#endif /* __OpenBSD__ */
+ }
+
+ if (error) {
+ printf("%s: dpt_scsi_cmd: ", sc->sc_dv.dv_xname);
+ if (error == EFBIG)
+ printf("more than %d dma segs\n", DPT_SG_SIZE);
+ else
+ printf("error %d loading dma map\n", error);
+
+ xs->error = XS_DRIVER_STUFFUP;
+ dpt_free_ccb(sc, ccb);
+ return (COMPLETE);
+ }
+
+#ifdef __NetBSD__
+ bus_dmamap_sync(dmat, xfer, 0, xfer->dm_mapsize,
+ (flags & XS_CTL_DATA_IN) ? BUS_DMASYNC_PREREAD :
+ BUS_DMASYNC_PREWRITE);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bus_dmamap_sync(dmat, xfer, (xs->flags & SCSI_DATA_IN) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+#endif /* __OpenBSD__ */
+
+ /* Don't bother using scatter/gather for just 1 segment */
+ if (xfer->dm_nsegs == 1) {
+ cp->cp_dataaddr = htobe32(xfer->dm_segs[0].ds_addr);
+ cp->cp_datalen = htobe32(xfer->dm_segs[0].ds_len);
+ cp->cp_scatter = 0;
+ } else {
+ /*
+ * Load the hardware scatter/gather map with the
+ * contents of the DMA map.
+ */
+ sg = ccb->ccb_sg;
+ for (i = 0; i < xfer->dm_nsegs; i++, sg++) {
+ sg->sg_addr =
+ htobe32(xfer->dm_segs[i].ds_addr);
+ sg->sg_len =
+ htobe32(xfer->dm_segs[i].ds_len);
+ }
+ cp->cp_dataaddr = htobe32(CCB_OFF(sc, ccb) +
+ sc->sc_dmamap_ccb->dm_segs[0].ds_addr +
+ offsetof(struct dpt_ccb, ccb_sg));
+ cp->cp_datalen = htobe32(i * sizeof(struct eata_sg));
+ cp->cp_scatter = 1;
+ }
+ } else {
+ cp->cp_dataaddr = 0;
+ cp->cp_datalen = 0;
+ cp->cp_scatter = 0;
+ }
+
+ /* Sync up CCB and status packet */
+#ifdef __NetBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, CCB_OFF(sc, ccb),
+ sizeof(struct dpt_ccb), BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_spoff,
+ sizeof(struct eata_sp), BUS_DMASYNC_PREREAD);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, BUS_DMASYNC_PREREAD);
+#endif /* __OpenBSD__ */
+
+ /*
+ * Start the command. If we are polling on completion, mark it
+ * private so that dpt_intr/dpt_done_ccb don't recycle the CCB
+ * without us noticing.
+ */
+ if (dontqueue != 0)
+ ccb->ccb_flg |= CCB_PRIVATE;
+
+ if (dpt_cmd(sc, &ccb->ccb_eata_cp, ccb->ccb_ccbpa, CP_DMA_CMD, 0)) {
+ printf("%s: dpt_cmd failed\n", sc->sc_dv.dv_xname);
+ xs->error = XS_DRIVER_STUFFUP;
+ dpt_free_ccb(sc, ccb);
+ return (TRY_AGAIN_LATER);
+ }
+
+ if (dontqueue == 0)
+ return (SUCCESSFULLY_QUEUED);
+
+ /* Don't wait longer than this single command wants to wait */
+ if (dpt_poll(sc, ccb)) {
+ dpt_timeout(ccb);
+ /* Wait for abort to complete */
+ if (dpt_poll(sc, ccb))
+ dpt_timeout(ccb);
+ }
+
+ dpt_done_ccb(sc, ccb);
+ return (COMPLETE);
+}
+
+/*
+ * Specified CCB has timed out, abort it.
+ */
+void
+dpt_timeout(arg)
+ void *arg;
+{
+#ifdef __NetBSD__
+ struct scsipi_link *sc_link;
+ struct scsipi_xfer *xs;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ struct scsi_link *sc_link;
+ struct scsi_xfer *xs;
+#endif /* __OpenBSD__ */
+ struct dpt_softc *sc;
+ struct dpt_ccb *ccb;
+ int s;
+
+ ccb = arg;
+ xs = ccb->ccb_xs;
+ sc_link = xs->sc_link;
+ sc = sc_link->adapter_softc;
+
+#ifdef __NetBSD__
+ scsi_print_addr(sc_link);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ sc_print_addr(sc_link);
+#endif /* __OpenBSD__ */
+ printf("timed out (status:%02x aux status:%02x)",
+ dpt_inb(sc, HA_STATUS), dpt_inb(sc, HA_AUX_STATUS));
+
+ s = splbio();
+
+ if ((ccb->ccb_flg & CCB_ABORT) != 0) {
+ /* Abort timed out, reset the HBA */
+ printf(" AGAIN, resetting HBA\n");
+ dpt_outb(sc, HA_COMMAND, CP_RESET);
+ DELAY(750000);
+ } else {
+ /* Abort the operation that has timed out */
+ printf("\n");
+ ccb->ccb_xs->error = XS_TIMEOUT;
+ ccb->ccb_timeout = DPT_ABORT_TIMEOUT;
+ ccb->ccb_flg |= CCB_ABORT;
+ /* Start the abort */
+ if (dpt_cmd(sc, &ccb->ccb_eata_cp, ccb->ccb_ccbpa,
+ CP_IMMEDIATE, CPI_SPEC_ABORT))
+ printf("%s: dpt_cmd failed\n", sc->sc_dv.dv_xname);
+ }
+
+ splx(s);
+}
+
+#ifdef DEBUG
+/*
+ * Dump the contents of an EATA status packet.
+ */
+void
+dpt_dump_sp(sp)
+ struct eata_sp *sp;
+{
+ int i;
+
+ printf("\thba_status\t%02x\n", sp->sp_hba_status);
+ printf("\tscsi_status\t%02x\n", sp->sp_scsi_status);
+ printf("\tinv_residue\t%d\n", sp->sp_inv_residue);
+ printf("\tccbid\t\t%d\n", sp->sp_ccbid);
+ printf("\tid_message\t%d\n", sp->sp_id_message);
+ printf("\tque_message\t%d\n", sp->sp_que_message);
+ printf("\ttag_message\t%d\n", sp->sp_tag_message);
+ printf("\tmessages\t");
+
+ for (i = 0; i < 9; i++)
+ printf("%d ", sp->sp_messages[i]);
+
+ printf("\n");
+}
+#endif /* DEBUG */
+
+/*
+ * Get inquiry data from the adapter.
+ */
+void
+dpt_hba_inquire(sc, ei)
+ struct dpt_softc *sc;
+ struct eata_inquiry_data **ei;
+{
+ struct dpt_ccb *ccb;
+ struct eata_cp *cp;
+ bus_dma_tag_t dmat;
+
+ *ei = (struct eata_inquiry_data *)sc->sc_scr;
+ dmat = sc->sc_dmat;
+
+ /* Get a CCB and mark as private */
+ if ((ccb = dpt_alloc_ccb(sc, 0)) == NULL)
+ panic("%s: no CCB for inquiry", sc->sc_dv.dv_xname);
+
+ ccb->ccb_flg |= CCB_PRIVATE;
+ ccb->ccb_timeout = 200;
+
+ /* Put all the arguments into the CCB */
+ cp = &ccb->ccb_eata_cp;
+ cp->cp_ccbid = ccb->ccb_id;
+ cp->cp_id = sc->sc_hbaid[0];
+ cp->cp_lun = 0;
+ cp->cp_channel = 0;
+ cp->cp_senselen = sizeof(ccb->ccb_sense);
+ cp->cp_stataddr = htobe32(sc->sc_sppa);
+ cp->cp_dispri = 1;
+ cp->cp_identify = 1;
+ cp->cp_autosense = 0;
+ cp->cp_interpret = 1;
+ cp->cp_nocache = 0;
+ cp->cp_datain = 1;
+ cp->cp_dataout = 0;
+ cp->cp_senseaddr = 0;
+ cp->cp_dataaddr = htobe32(sc->sc_scrpa);
+ cp->cp_datalen = htobe32(sizeof(struct eata_inquiry_data));
+ cp->cp_scatter = 0;
+
+ /* Put together the SCSI inquiry command */
+ memset(&cp->cp_scsi_cmd, 0, 12); /* XXX */
+ cp->cp_scsi_cmd = INQUIRY;
+ cp->cp_len = sizeof(struct eata_inquiry_data);
+
+ /* Sync up CCB, status packet and scratch area */
+#ifdef __NetBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, CCB_OFF(sc, ccb),
+ sizeof(struct dpt_ccb), BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_spoff,
+ sizeof(struct eata_sp), BUS_DMASYNC_PREREAD);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_scroff,
+ sizeof(struct eata_inquiry_data), BUS_DMASYNC_PREREAD);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, BUS_DMASYNC_PREREAD);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, BUS_DMASYNC_PREREAD);
+#endif /* __OpenBSD__ */
+
+ /* Start the command and poll on completion */
+ if (dpt_cmd(sc, &ccb->ccb_eata_cp, ccb->ccb_ccbpa, CP_DMA_CMD, 0))
+ panic("%s: dpt_cmd failed", sc->sc_dv.dv_xname);
+
+ if (dpt_poll(sc, ccb))
+ panic("%s: inquiry timed out", sc->sc_dv.dv_xname);
+
+ if (ccb->ccb_hba_status != HA_NO_ERROR ||
+ ccb->ccb_scsi_status != SCSI_OK)
+ panic("%s: inquiry failed (hba:%02x scsi:%02x",
+ sc->sc_dv.dv_xname, ccb->ccb_hba_status,
+ ccb->ccb_scsi_status);
+
+ /* Sync up the DMA map and free CCB, returning */
+#ifdef __NetBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_scroff,
+ sizeof(struct eata_inquiry_data), BUS_DMASYNC_POSTREAD);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, BUS_DMASYNC_POSTREAD);
+#endif /* __OpenBSD__ */
+ dpt_free_ccb(sc, ccb);
+}
diff --git a/sys/dev/ic/dptreg.h b/sys/dev/ic/dptreg.h
new file mode 100644
index 00000000000..080f5b25f5b
--- /dev/null
+++ b/sys/dev/ic/dptreg.h
@@ -0,0 +1,300 @@
+/* $OpenBSD: dptreg.h,v 1.1 1999/11/30 07:55:56 cmetz Exp $ */
+/* $NetBSD: dptreg.h,v 1.4 1999/10/19 20:16:48 ad Exp $ */
+
+/*
+ * Copyright (c) 1999 Andy Doran <ad@NetBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _IC_DPTREG_H_
+#define _IC_DPTREG_H_ 1
+
+/* Hardware limits */
+#define DPT_MAX_TARGETS 16
+#define DPT_MAX_LUNS 8
+#define DPT_MAX_CHANNELS 3
+
+/* Software parameters */
+#define DPT_MAX_XFER ((DPT_SG_SIZE - 1) << PGSHIFT)
+#define DPT_MAX_CCBS 256
+#define DPT_SG_SIZE 64
+#define DPT_ABORT_TIMEOUT 2000 /* milliseconds */
+#define DPT_MORE_TIMEOUT 1000 /* microseconds */
+
+#ifdef _KERNEL
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define SWAP32(x) bswap32((x))
+#define SWAP16(x) bswap16((x))
+#define RSWAP32(x) (x)
+#define RSWAP16(x) (x)
+#else
+#define SWAP32(x) (x)
+#define SWAP16(x) (x)
+#define RSWAP32(x) bswap32((x))
+#define RSWAP16(x) bswap16((x))
+#endif
+
+#define dpt_inb(x, o) \
+ bus_space_read_1((x)->sc_iot, (x)->sc_ioh, (o))
+
+#define dpt_inw(x, o) \
+ RSWAP16(bus_space_read_2((x)->sc_iot, (x)->sc_ioh, (o)))
+
+#define dpt_inl(x, o) \
+ RSWAP32(bus_space_read_4((x)->sc_iot, (x)->sc_ioh, (o)))
+
+#define dpt_outb(x, o, d) \
+ bus_space_write_1((x)->sc_iot, (x)->sc_ioh, (o), (d))
+
+#define dpt_outw(x, o, d) \
+ bus_space_write_2((x)->sc_iot, (x)->sc_ioh, (o), RSWAP16(d))
+
+#define dpt_outl(x, o, d) \
+ bus_space_write_4((x)->sc_iot, (x)->sc_ioh, (o), RSWAP32(d))
+
+#endif /* _KERNEL */
+
+/*
+ * HBA registers
+ */
+#define HA_BASE 0x10
+#define HA_DATA (HA_BASE + 0)
+#define HA_ERROR (HA_BASE + 1)
+#define HA_DMA_BASE (HA_BASE + 2)
+#define HA_ICMD_CODE2 (HA_BASE + 4)
+#define HA_ICMD_CODE1 (HA_BASE + 5)
+#define HA_ICMD (HA_BASE + 6)
+
+/* EATA commands. There are many more the we don't define or use. */
+#define HA_COMMAND (HA_BASE + 7)
+#define CP_PIO_GETCFG 0xf0 /* Read configuration data, PIO */
+#define CP_PIO_CMD 0xf2 /* Execute command, PIO */
+#define CP_DMA_GETCFG 0xfd /* Read configuration data, DMA */
+#define CP_DMA_CMD 0xff /* Execute command, DMA */
+#define CP_PIO_TRUNCATE 0xf4 /* Truncate transfer command, PIO */
+#define CP_RESET 0xf9 /* Reset controller and SCSI bus */
+#define CP_REBOOT 0x06 /* Reboot controller (last resort) */
+#define CP_IMMEDIATE 0xfa /* EATA immediate command */
+#define CPI_GEN_ABORT 0x00 /* Generic abort */
+#define CPI_SPEC_RESET 0x01 /* Specific reset */
+#define CPI_BUS_RESET 0x02 /* Bus reset */
+#define CPI_SPEC_ABORT 0x03 /* Specific abort */
+#define CPI_QUIET_INTR 0x04 /* ?? */
+#define CPI_ROM_DL_EN 0x05 /* ?? */
+#define CPI_COLD_BOOT 0x06 /* Cold boot HBA */
+#define CPI_FORCE_IO 0x07 /* ?? */
+#define CPI_BUS_OFFLINE 0x08 /* Set SCSI bus offline */
+#define CPI_RESET_MSKD_BUS 0x09 /* Reset masked bus */
+#define CPI_POWEROFF_WARN 0x0a /* Power about to fail */
+
+#define HA_STATUS (HA_BASE + 7)
+#define HA_ST_ERROR 0x01
+#define HA_ST_MORE 0x02
+#define HA_ST_CORRECTD 0x04
+#define HA_ST_DRQ 0x08
+#define HA_ST_SEEK_COMPLETE 0x10
+#define HA_ST_WRT_FLT 0x20
+#define HA_ST_READY 0x40
+#define HA_ST_BUSY 0x80
+#define HA_ST_DATA_RDY (HA_ST_SEEK_COMPLETE|HA_ST_READY|HA_ST_DRQ)
+
+#define HA_AUX_STATUS (HA_BASE + 8)
+#define HA_AUX_BUSY 0x01
+#define HA_AUX_INTR 0x02
+
+/*
+ * Structure of an EATA command packet.
+ */
+struct eata_cp {
+ u_int8_t cp_scsireset :1; /* cause a bus reset */
+ u_int8_t cp_hbainit :1; /* cause HBA to reinitialize */
+ u_int8_t cp_autosense :1; /* auto request sense on err */
+ u_int8_t cp_scatter :1; /* doing SG I/O */
+ u_int8_t cp_quick :1; /* return no status packet */
+ u_int8_t cp_interpret :1; /* HBA interprets SCSI CDB */
+ u_int8_t cp_dataout :1; /* data out phase */
+ u_int8_t cp_datain :1; /* data in phase */
+ u_int8_t cp_senselen; /* request sense length */
+ u_int8_t cp_unused0[3]; /* unused */
+ u_int8_t cp_tophys :1; /* send to RAID component */
+ u_int8_t cp_unused1 :7; /* unused */
+ u_int8_t cp_physunit :1; /* phys unit on mirrored pair */
+ u_int8_t cp_noat :1; /* no address translation */
+ u_int8_t cp_nocache :1; /* no HBA caching */
+ u_int8_t cp_unused2 :5; /* unused */
+ u_int8_t cp_id :5; /* SCSI device id of target */
+ u_int8_t cp_channel :3; /* SCSI channel id */
+ u_int8_t cp_lun :3; /* SCSI LUN id */
+ u_int8_t cp_unused3 :2; /* unused */
+ u_int8_t cp_luntar :1; /* CP is for target ROUTINE */
+ u_int8_t cp_dispri :1; /* give disconnect privilege */
+ u_int8_t cp_identify :1; /* always true */
+ u_int8_t cp_msg[3]; /* message bytes 0-3 */
+
+ /* Partial SCSI CDB ref */
+ u_int8_t cp_scsi_cmd;
+ u_int8_t cp_extent :1;
+ u_int8_t cp_bytchk :1;
+ u_int8_t cp_reladr :1;
+ u_int8_t cp_cmplst :1;
+ u_int8_t cp_fmtdata :1;
+ u_int8_t cp_cdblun :3;
+ u_int8_t cp_page;
+ u_int8_t cp_unused4;
+ u_int8_t cp_len;
+ u_int8_t cp_link :1;
+ u_int8_t cp_flag :1;
+ u_int8_t cp_unused5 :4;
+ u_int8_t cp_vendor :2;
+ u_int8_t cp_cdbmore[6];
+
+ u_int32_t cp_datalen; /* length in bytes of data/SG list */
+ u_int32_t cp_ccbid; /* ID of software CCB */
+ u_int32_t cp_dataaddr; /* address of data/SG list */
+ u_int32_t cp_stataddr; /* addr for status packet */
+ u_int32_t cp_senseaddr; /* addr of req. sense (err only) */
+};
+
+/*
+ * EATA status packet as returned by controller upon command completion. It
+ * contains status, message info and a handle on the initiating CCB.
+ */
+struct eata_sp {
+ u_int8_t sp_hba_status; /* host adapter status */
+ u_int8_t sp_scsi_status; /* SCSI bus status */
+ u_int8_t sp_reserved[2]; /* reserved */
+ u_int32_t sp_inv_residue; /* bytes not transfered */
+ u_int32_t sp_ccbid; /* ID of software CCB */
+ u_int8_t sp_id_message;
+ u_int8_t sp_que_message;
+ u_int8_t sp_tag_message;
+ u_int8_t sp_messages[9];
+};
+
+/*
+ * HBA status as returned by status packet. Bit 7 signals end of command.
+ */
+#define HA_NO_ERROR 0x00 /* No error on command */
+#define HA_ERROR_SEL_TO 0x01 /* Device selection timeout */
+#define HA_ERROR_CMD_TO 0x02 /* Device command timeout */
+#define HA_ERROR_RESET 0x03 /* SCSI bus was reset */
+#define HA_INIT_POWERUP 0x04 /* Initial controller power up */
+#define HA_UNX_BUSPHASE 0x05 /* Unexpected bus phase */
+#define HA_UNX_BUS_FREE 0x06 /* Unexpected bus free */
+#define HA_BUS_PARITY 0x07 /* SCSI bus parity error */
+#define HA_SCSI_HUNG 0x08 /* SCSI bus hung */
+#define HA_UNX_MSGRJCT 0x09 /* Unexpected message reject */
+#define HA_RESET_STUCK 0x0A /* SCSI bus reset stuck */
+#define HA_RSENSE_FAIL 0x0B /* Auto-request sense failed */
+#define HA_PARITY 0x0C /* HBA memory parity error */
+#define HA_ABORT_NA 0x0D /* CP aborted - not on bus */
+#define HA_ABORTED 0x0E /* CP aborted - was on bus */
+#define HA_RESET_NA 0x0F /* CP reset - not on bus */
+#define HA_RESET 0x10 /* CP reset - was on bus */
+#define HA_ECC 0x11 /* HBA memory ECC error */
+#define HA_PCI_PARITY 0x12 /* PCI parity error */
+#define HA_PCI_MASTER 0x13 /* PCI master abort */
+#define HA_PCI_TARGET 0x14 /* PCI target abort */
+#define HA_PCI_SIGNAL_TARGET 0x15 /* PCI signalled target abort */
+#define HA_ABORT 0x20 /* Software abort (too many retries) */
+
+/*
+ * Scatter-gather list element.
+ */
+struct eata_sg {
+ u_int32_t sg_addr;
+ u_int32_t sg_len;
+};
+
+/*
+ * EATA configuration data as returned by HBA. XXX this is bogus, some fields
+ * don't *seem* to be filled on my SmartCache III. Also, it doesn't sync up
+ * with the structure FreeBSD uses. [ad]
+ */
+struct eata_cfg {
+ u_int8_t ec_devtype;
+ u_int8_t ec_pagecode;
+ u_int8_t ec_reserved0;
+ u_int8_t ec_cfglen; /* Length in bytes after this field */
+ u_int8_t ec_eatasig[4]; /* EATA signature */
+ u_int8_t ec_eataversion; /* EATA version number */
+ u_int8_t ec_overlapcmds : 1; /* Overlapped cmds supported */
+ u_int8_t ec_targetmode : 1; /* Target mode supported */
+ u_int8_t ec_trunnotrec : 1; /* Truncate cmd not supported */
+ u_int8_t ec_moresupported:1; /* More cmd supported */
+ u_int8_t ec_dmasupported : 1; /* DMA mode supported */
+ u_int8_t ec_dmanumvalid : 1; /* DMA channel field is valid */
+ u_int8_t ec_atadev : 1; /* This is an ATA device */
+ u_int8_t ec_hbavalid : 1; /* HBA field is valid */
+ u_int8_t ec_padlength[2]; /* Pad bytes for PIO cmds */
+ u_int8_t ec_hba[4]; /* Host adapter SCSI IDs */
+ u_int8_t ec_cplen[4]; /* Command packet length */
+ u_int8_t ec_splen[4]; /* Status packet length */
+ u_int8_t ec_queuedepth[2]; /* Controller queue depth */
+ u_int8_t ec_reserved1[2];
+ u_int8_t ec_sglen[2]; /* Maximum scatter gather list size */
+ u_int8_t ec_irqnum : 4; /* IRQ number */
+ u_int8_t ec_irqtrigger : 1; /* IRQ trigger: 0 = edge, 1 = level */
+ u_int8_t ec_secondary : 1; /* Controller not at address 0x170 */
+ u_int8_t ec_dmanum : 2; /* DMA channel index for ISA */
+ u_int8_t ec_irq; /* IRQ address */
+ u_int8_t ec_iodisable : 1; /* ISA I/O address disabled */
+ u_int8_t ec_forceaddr : 1; /* PCI forced to an EISA/ISA addr */
+ u_int8_t ec_sg64k : 1; /* 64K of SG space */
+ u_int8_t ec_sgunaligned : 1; /* Can do unaligned SG, otherwise 4 */
+ u_int8_t ec_reserved2 : 4; /* Reserved */
+ u_int8_t ec_maxtarget : 5; /* Maximun SCSI target ID supported */
+ u_int8_t ec_maxchannel : 3; /* Maximun channel number supported */
+ u_int8_t ec_maxlun; /* Maximum LUN supported */
+ u_int8_t ec_reserved3 : 3; /* Reserved field */
+ u_int8_t ec_autoterm : 1; /* Support auto term (low byte) */
+ u_int8_t ec_pcim1 : 1; /* PCI M1 chipset */
+ u_int8_t ec_bogusraidid : 1; /* Raid ID may be questionable */
+ u_int8_t ec_pci : 1; /* PCI adapter */
+ u_int8_t ec_eisa : 1; /* EISA adapter */
+ u_int8_t ec_raidnum; /* RAID host adapter humber */
+};
+
+/*
+ * How SCSI inquiry data breaks down for EATA boards.
+ */
+struct eata_inquiry_data {
+ u_int8_t ei_device;
+ u_int8_t ei_dev_qual2;
+ u_int8_t ei_version;
+ u_int8_t ei_response_format;
+ u_int8_t ei_additional_length;
+ u_int8_t ei_unused[2];
+ u_int8_t ei_flags;
+ char ei_vendor[8]; /* Vendor, e.g: DPT, NEC */
+ char ei_model[7]; /* Model number */
+ char ei_suffix[9]; /* Model number suffix */
+ char ei_fw[3]; /* Firmware */
+ char ei_fwrev[1]; /* Firmware revision */
+ u_int8_t ei_extra[8];
+};
+
+#endif /* !defined _IC_DPTREG_H_ */
diff --git a/sys/dev/ic/dptvar.h b/sys/dev/ic/dptvar.h
new file mode 100644
index 00000000000..bb2e9c122a1
--- /dev/null
+++ b/sys/dev/ic/dptvar.h
@@ -0,0 +1,128 @@
+/* $OpenBSD: dptvar.h,v 1.1 1999/11/30 07:55:56 cmetz Exp $ */
+/* $NetBSD: dptvar.h,v 1.5 1999/10/23 16:26:32 ad Exp $ */
+
+/*
+ * Copyright (c) 1999 Andy Doran <ad@NetBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _IC_DPTVAR_H_
+#define _IC_DPTVAR_H_ 1
+#ifdef _KERNEL
+
+#define CCB_OFF(sc,m) ((u_long)(m) - (u_long)((sc)->sc_ccbs))
+
+#define CCB_ALLOC 0x01 /* CCB allocated */
+#define CCB_ABORT 0x02 /* abort has been issued on this CCB */
+#define CCB_INTR 0x04 /* HBA interrupted for this CCB */
+#define CCB_PRIVATE 0x08 /* ours; don't talk to scsipi when done */
+
+struct dpt_ccb {
+ struct eata_cp ccb_eata_cp; /* EATA command packet */
+ struct eata_sg ccb_sg[DPT_SG_SIZE]; /* SG element list */
+ volatile int ccb_flg; /* CCB flags */
+ int ccb_timeout; /* timeout in ms */
+ u_int32_t ccb_ccbpa; /* physical addr of this CCB */
+ bus_dmamap_t ccb_dmamap_xfer; /* dmamap for data xfers */
+ int ccb_hba_status; /* from status packet */
+ int ccb_scsi_status; /* from status packet */
+ int ccb_id; /* unique ID of this CCB */
+ TAILQ_ENTRY(dpt_ccb) ccb_chain; /* link to next CCB */
+#ifdef __NetBSD__
+ struct scsipi_sense_data ccb_sense; /* SCSI sense data on error */
+ struct scsipi_xfer *ccb_xs; /* initiating SCSI command */
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ struct scsi_sense_data ccb_sense;
+ struct scsi_xfer *ccb_xs;
+#endif /* __OpenBSD__ */
+};
+
+struct dpt_softc {
+ struct device sc_dv; /* generic device data */
+ bus_space_handle_t sc_ioh; /* bus space handle */
+#ifdef __NetBSD__
+ struct scsipi_adapter sc_adapter;/* scsipi adapter */
+ struct scsipi_link sc_link[3]; /* prototype link for each channel */
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ struct scsi_adapter sc_adapter;/* scsipi adapter */
+ struct scsi_link sc_link[3]; /* prototype link for each channel */
+#endif /* __OpenBSD__ */
+ struct eata_cfg sc_ec; /* EATA configuration data */
+ bus_space_tag_t sc_iot; /* bus space tag */
+ bus_dma_tag_t sc_dmat; /* bus DMA tag */
+ bus_dmamap_t sc_dmamap_ccb; /* maps the CCBs */
+ void *sc_ih; /* interrupt handler cookie */
+ void *sc_sdh; /* shutdown hook */
+ struct dpt_ccb *sc_ccbs; /* all our CCBs */
+ struct eata_sp *sc_statpack; /* EATA status packet */
+ int sc_spoff; /* status packet offset in dmamap */
+ u_int32_t sc_sppa; /* status packet physical address */
+ caddr_t sc_scr; /* scratch area */
+ int sc_scrlen; /* scratch area length */
+ int sc_scroff; /* scratch area offset in dmamap */
+ u_int32_t sc_scrpa; /* scratch area physical address */
+ int sc_hbaid[3]; /* ID of HBA on each channel */
+ int sc_nccbs; /* number of CCBs available */
+ int sc_open; /* device is open */
+ TAILQ_HEAD(, dpt_ccb) sc_free_ccb;/* free ccb list */
+#ifdef __NetBSD__
+ TAILQ_HEAD(, scsipi_xfer) sc_queue;/* pending commands */
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ LIST_HEAD(, scsi_xfer) sc_queue;/* pending commands */
+ struct scsi_xfer *sc_queuelast;
+#endif /* __NetBSD__ */
+};
+
+int dpt_intr __P((void *));
+int dpt_readcfg __P((struct dpt_softc *));
+void dpt_init __P((struct dpt_softc *, const char *));
+void dpt_shutdown __P((void *));
+void dpt_timeout __P((void *));
+void dpt_minphys __P((struct buf *));
+#ifdef __NetBSD__
+int dpt_scsi_cmd __P((struct scsipi_xfer *));
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+int dpt_scsi_cmd __P((struct scsi_xfer *));
+#endif /* __OpenBSD__ */
+int dpt_wait __P((struct dpt_softc *, u_int8_t, u_int8_t, int));
+int dpt_poll __P((struct dpt_softc *, struct dpt_ccb *));
+int dpt_cmd __P((struct dpt_softc *, struct eata_cp *, u_int32_t, int, int));
+void dpt_hba_inquire __P((struct dpt_softc *, struct eata_inquiry_data **));
+void dpt_reset_ccb __P((struct dpt_softc *, struct dpt_ccb *));
+void dpt_free_ccb __P((struct dpt_softc *, struct dpt_ccb *));
+void dpt_done_ccb __P((struct dpt_softc *, struct dpt_ccb *));
+int dpt_init_ccb __P((struct dpt_softc *, struct dpt_ccb *));
+int dpt_create_ccbs __P((struct dpt_softc *, struct dpt_ccb *, int));
+struct dpt_ccb *dpt_alloc_ccb __P((struct dpt_softc *, int));
+#ifdef DEBUG
+void dpt_dump_sp __P((struct eata_sp *));
+#endif
+
+#endif /* _KERNEL */
+#endif /* !defined _IC_DPTVAR_H_ */
diff --git a/sys/dev/pci/dpt_pci.c b/sys/dev/pci/dpt_pci.c
new file mode 100644
index 00000000000..82182436a9d
--- /dev/null
+++ b/sys/dev/pci/dpt_pci.c
@@ -0,0 +1,163 @@
+/* $OpenBSD: dpt_pci.c,v 1.1 1999/11/30 07:55:56 cmetz Exp $ */
+/* $NetBSD: dpt_pci.c,v 1.2 1999/09/29 17:33:02 ad Exp $ */
+
+/*
+ * Copyright (c) 1999 Andy Doran <ad@NetBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * PCI front-end for DPT EATA SCSI driver.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __NetBSD__
+__KERNEL_RCSID(0, "$NetBSD: dpt_pci.c,v 1.2 1999/09/29 17:33:02 ad Exp $");
+#endif /* __NetBSD__ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+
+#include <machine/endian.h>
+#include <machine/bus.h>
+
+#ifdef __NetBSD__
+#include <dev/scsipi/scsi_all.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsiconf.h>
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#endif /* __OpenBSD__ */
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/ic/dptreg.h>
+#include <dev/ic/dptvar.h>
+
+#define PCI_CBMA 0x14 /* Configuration base memory address */
+#define PCI_CBIO 0x10 /* Configuration base I/O address */
+
+#ifdef __NetBSD__
+int dpt_pci_match __P((struct device *, struct cfdata *, void *));
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+int dpt_pci_match __P((struct device *, void *, void *));
+#endif /* __OpenBSD__ */
+void dpt_pci_attach __P((struct device *, struct device *, void *));
+
+struct cfattach dpt_pci_ca = {
+ sizeof(struct dpt_softc), dpt_pci_match, dpt_pci_attach
+};
+
+int
+dpt_pci_match(parent, match, aux)
+ struct device *parent;
+#ifdef __NetBSD__
+ struct cfdata *match;
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ void *match;
+#endif /* __OpenBSD__ */
+ void *aux;
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *) aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_DPT &&
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_DPT_SC_RAID)
+ return (1);
+
+ return (0);
+}
+
+void
+dpt_pci_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct pci_attach_args *pa;
+ struct dpt_softc *sc;
+ pci_chipset_tag_t pc;
+ pci_intr_handle_t ih;
+ const char *intrstr;
+ pcireg_t csr;
+
+ sc = (struct dpt_softc *)self;
+ pa = (struct pci_attach_args *)aux;
+ pc = pa->pa_pc;
+ printf(": ");
+
+ if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
+ &sc->sc_ioh, NULL, NULL)) {
+ printf("can't map i/o space\n");
+ return;
+ }
+
+ sc->sc_dmat = pa->pa_dmat;
+
+ /* Enable the device. */
+ csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+ csr | PCI_COMMAND_MASTER_ENABLE);
+
+ /* Map and establish the interrupt. */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("can't map interrupt\n");
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+#ifdef __NetBSD__
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, dpt_intr, sc);
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, dpt_intr, sc,
+ sc->sc_dv.dv_xname);
+#endif /* __OpenBSD__ */
+ if (sc->sc_ih == NULL) {
+ printf("can't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+
+ /* Read the EATA configuration */
+ if (dpt_readcfg(sc)) {
+ printf("%s: readcfg failed - see dpt(4)\n",
+ sc->sc_dv.dv_xname);
+ return;
+ }
+
+ /* Now attach to the bus-independant code */
+ dpt_init(sc, intrstr);
+}
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 685b98cf632..db0807dcf9e 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.55 1999/11/28 16:43:47 aaron Exp $
+# $OpenBSD: files.pci,v 1.56 1999/11/30 07:55:56 cmetz Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -25,6 +25,10 @@ attach ahc at pci with ahc_pci
file dev/pci/ahc_pci.c ahc_pci
file dev/ic/smc93cx6.c ahc_pci
+# DPT EATA SCSI controllers
+attach dpt at pci with dpt_pci
+file dev/pci/dpt_pci.c dpt_pci
+
# AdvanSys 1200A, 1200B, and ULTRA SCSI controllers
# device declaration in sys/conf/files
attach adv at pci with adv_pci