summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/eisa/bha_eisa.c146
-rw-r--r--sys/dev/ic/bha.c1613
-rw-r--r--sys/dev/ic/bhareg.h503
-rw-r--r--sys/dev/ic/bhavar.h135
-rw-r--r--sys/dev/isa/aha.c6
-rw-r--r--sys/dev/isa/bha_isa.c200
-rw-r--r--sys/dev/isa/bt.c1347
-rw-r--r--sys/dev/isa/btreg.h310
-rw-r--r--sys/dev/isa/files.isa6
-rw-r--r--sys/dev/pci/bha_pci.c167
-rw-r--r--sys/dev/pci/files.pci3
11 files changed, 2734 insertions, 1702 deletions
diff --git a/sys/dev/eisa/bha_eisa.c b/sys/dev/eisa/bha_eisa.c
index 78794a80f0e..397081d77c8 100644
--- a/sys/dev/eisa/bha_eisa.c
+++ b/sys/dev/eisa/bha_eisa.c
@@ -1,8 +1,12 @@
-/* $OpenBSD: bha_eisa.c,v 1.1 1996/11/28 23:27:37 niklas Exp $ */
-/* $NetBSD: bha_eisa.c,v 1.5 1996/10/21 22:31:00 thorpej Exp $ */
+/* $OpenBSD: bha_eisa.c,v 1.2 2002/01/24 22:38:03 mickey Exp $ */
+/* $NetBSD: bha_eisa.c,v 1.16 1998/08/15 10:10:49 mycroft Exp $ */
-/*
- * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved.
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -14,20 +18,23 @@
* 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 Charles M. Hannum.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * This 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 AUTHOR ``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 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.
+ * 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.
*/
#include <sys/types.h>
@@ -47,9 +54,13 @@
#include <dev/ic/bhareg.h>
#include <dev/ic/bhavar.h>
-#define BHA_EISA_SLOT_OFFSET 0xc00
-#define BHA_EISA_IOSIZE 0x100
+#define BHA_EISA_SLOT_OFFSET 0x0c80
+#define BHA_EISA_IOSIZE 0x0010
+#define BHA_ISA_IOSIZE 0x0004
+
+#define BHA_EISA_IOCONF 0x0c
+int bha_eisa_address __P((bus_space_tag_t, bus_space_handle_t, int *));
int bha_eisa_match __P((struct device *, void *, void *));
void bha_eisa_attach __P((struct device *, struct device *, void *));
@@ -57,6 +68,41 @@ struct cfattach bha_eisa_ca = {
sizeof(struct bha_softc), bha_eisa_match, bha_eisa_attach
};
+int
+bha_eisa_address(iot, ioh, portp)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int *portp;
+{
+ int port;
+
+ switch (bus_space_read_1(iot, ioh, BHA_EISA_IOCONF) & 0x07) {
+ case 0x00:
+ port = 0x330;
+ break;
+ case 0x01:
+ port = 0x334;
+ break;
+ case 0x02:
+ port = 0x230;
+ break;
+ case 0x03:
+ port = 0x234;
+ break;
+ case 0x04:
+ port = 0x130;
+ break;
+ case 0x05:
+ port = 0x134;
+ break;
+ default:
+ return (1);
+ }
+
+ *portp = port;
+ return (0);
+}
+
/*
* Check the slots looking for a board we recognise
* If we find one, note it's address (slot) and call
@@ -65,11 +111,12 @@ struct cfattach bha_eisa_ca = {
int
bha_eisa_match(parent, match, aux)
struct device *parent;
- void *match, *aux;
+ void *aux, *match;
{
struct eisa_attach_args *ea = aux;
bus_space_tag_t iot = ea->ea_iot;
- bus_space_handle_t ioh;
+ bus_space_handle_t ioh, ioh2;
+ int port;
int rv;
/* must match one of our known ID strings */
@@ -77,12 +124,20 @@ bha_eisa_match(parent, match, aux)
strcmp(ea->ea_idstring, "BUS4202"))
return (0);
- if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
- BHA_EISA_SLOT_OFFSET, BHA_EISA_IOSIZE, 0, &ioh))
+ if (bus_space_map(iot,
+ EISA_SLOT_ADDR(ea->ea_slot) + BHA_EISA_SLOT_OFFSET, BHA_EISA_IOSIZE,
+ 0, &ioh))
return (0);
- rv = bha_find(iot, ioh, NULL);
+ if (bha_eisa_address(iot, ioh, &port) ||
+ bus_space_map(iot, port, BHA_ISA_IOSIZE, 0, &ioh2)) {
+ bus_space_unmap(iot, ioh, BHA_EISA_IOSIZE);
+ return (0);
+ }
+
+ rv = bha_find(iot, ioh2, NULL);
+ bus_space_unmap(iot, ioh2, BHA_ISA_IOSIZE);
bus_space_unmap(iot, ioh, BHA_EISA_IOSIZE);
return (rv);
@@ -99,7 +154,9 @@ bha_eisa_attach(parent, self, aux)
struct eisa_attach_args *ea = aux;
struct bha_softc *sc = (void *)self;
bus_space_tag_t iot = ea->ea_iot;
- bus_space_handle_t ioh;
+ bus_space_handle_t ioh, ioh2;
+ int port;
+ struct bha_probe_data bpd;
eisa_chipset_tag_t ec = ea->ea_ec;
eisa_intr_handle_t ih;
const char *model, *intrstr;
@@ -110,34 +167,45 @@ bha_eisa_attach(parent, self, aux)
model = EISA_PRODUCT_BUS4202;
else
model = "unknown model!";
- printf(": %s\n", model);
- if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
- BHA_EISA_SLOT_OFFSET, BHA_EISA_IOSIZE, 0, &ioh))
- panic("bha_attach: could not map I/O addresses");
+ if (bus_space_map(iot,
+ EISA_SLOT_ADDR(ea->ea_slot) + BHA_EISA_SLOT_OFFSET, BHA_EISA_IOSIZE,
+ 0, &ioh)) {
+ printf(": could not map EISA slot\n");
+ return;
+ }
+
+ if (bha_eisa_address(iot, ioh, &port) ||
+ bus_space_map(iot, port, BHA_ISA_IOSIZE, 0, &ioh2)) {
+ printf(": could not map ISA address\n");
+ return;
+ }
sc->sc_iot = iot;
- sc->sc_ioh = ioh;
- if (!bha_find(iot, ioh, sc))
- panic("bha_attach: bha_find failed!");
+ sc->sc_ioh = ioh2;
+ sc->sc_dmat = ea->ea_dmat;
+ if (!bha_find(iot, ioh2, &bpd)) {
+ printf(": bha_find failed\n");
+ return;
+ }
+
+ sc->sc_dmaflags = 0;
- if (eisa_intr_map(ec, sc->sc_irq, &ih)) {
- printf("%s: couldn't map interrupt (%d)\n",
- sc->sc_dev.dv_xname, sc->sc_irq);
+ if (eisa_intr_map(ec, bpd.sc_irq, &ih)) {
+ printf(": couldn't map interrupt (%d)\n", bpd.sc_irq);
return;
}
intrstr = eisa_intr_string(ec, ih);
sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO,
bha_intr, sc, sc->sc_dev.dv_xname);
if (sc->sc_ih == NULL) {
- printf("%s: couldn't establish interrupt",
- sc->sc_dev.dv_xname);
+ printf(": couldn't establish interrupt");
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
return;
}
- printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+ printf(": %s, %s\n", intrstr, model);
- bha_attach(sc);
+ bha_attach(sc, &bpd);
}
diff --git a/sys/dev/ic/bha.c b/sys/dev/ic/bha.c
new file mode 100644
index 00000000000..cf1ba450d47
--- /dev/null
+++ b/sys/dev/ic/bha.c
@@ -0,0 +1,1613 @@
+/* $OpenBSD: bha.c,v 1.1 2002/01/24 22:38:03 mickey Exp $ */
+/* $NetBSD: bha.c,v 1.27 1998/11/19 21:53:00 thorpej Exp $ */
+
+#undef BHADEBUG
+#ifdef DDB
+#define integrate
+#else
+#define integrate static inline
+#endif
+
+/*-
+ * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by 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.
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/bhareg.h>
+#include <dev/ic/bhavar.h>
+
+#ifndef DDB
+#define Debugger() panic("should call debugger here (bha.c)")
+#endif /* ! DDB */
+
+#define BHA_MAXXFER ((BHA_NSEG - 1) << PGSHIFT)
+#define ISWIDE(sc) ((sc)->sc_iswide)
+
+#ifdef BHADEBUG
+int bha_debug = 1;
+#endif /* BHADEBUG */
+
+integrate void bha_finish_ccbs __P((struct bha_softc *));
+integrate void bha_reset_ccb __P((struct bha_softc *, struct bha_ccb *));
+void bha_free_ccb __P((struct bha_softc *, struct bha_ccb *));
+integrate int bha_init_ccb __P((struct bha_softc *, struct bha_ccb *));
+struct bha_ccb *bha_get_ccb __P((struct bha_softc *, int));
+struct bha_ccb *bha_ccb_phys_kv __P((struct bha_softc *, u_long));
+void bha_queue_ccb __P((struct bha_softc *, struct bha_ccb *));
+void bha_collect_mbo __P((struct bha_softc *));
+void bha_start_ccbs __P((struct bha_softc *));
+void bha_done __P((struct bha_softc *, struct bha_ccb *));
+int bha_init __P((struct bha_softc *));
+void bhaminphys __P((struct buf *));
+int bha_scsi_cmd __P((struct scsi_xfer *));
+int bha_poll __P((struct bha_softc *, struct scsi_xfer *, int));
+void bha_timeout __P((void *arg));
+int bha_create_ccbs __P((struct bha_softc *, struct bha_ccb *, int));
+void bha_enqueue __P((struct bha_softc *, struct scsi_xfer *, int));
+struct scsi_xfer *bha_dequeue __P((struct bha_softc *));
+
+struct cfdriver bha_cd = {
+ NULL, "bha", DV_DULL
+};
+
+/* the below structure is so we have a default dev struct for out link struct */
+struct scsi_device bha_dev = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+#define BHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
+#define BHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
+
+/*
+ * 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.
+ */
+void
+bha_enqueue(sc, xs, infront)
+ struct bha_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.
+ */
+struct scsi_xfer *
+bha_dequeue(sc)
+ struct bha_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);
+}
+
+/*
+ * bha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf)
+ *
+ * Activate Adapter command
+ * icnt: number of args (outbound bytes including opcode)
+ * ibuf: argument buffer
+ * ocnt: number of expected returned bytes
+ * obuf: result buffer
+ * wait: number of seconds to wait for response
+ *
+ * Performs an adapter command through the ports. Not to be confused with a
+ * scsi command, which is read in via the dma; one of the adapter commands
+ * tells it to read in a scsi command.
+ */
+int
+bha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ struct bha_softc *sc;
+ int icnt, ocnt;
+ u_char *ibuf, *obuf;
+{
+ const char *name;
+ register int i;
+ int wait;
+ u_char sts;
+ u_char opcode = ibuf[0];
+
+ if (sc != NULL)
+ name = sc->sc_dev.dv_xname;
+ else
+ name = "(bha probe)";
+
+ /*
+ * Calculate a reasonable timeout for the command.
+ */
+ switch (opcode) {
+ case BHA_INQUIRE_DEVICES:
+ case BHA_INQUIRE_DEVICES_2:
+ wait = 90 * 20000;
+ break;
+ default:
+ wait = 1 * 20000;
+ break;
+ }
+
+ /*
+ * Wait for the adapter to go idle, unless it's one of
+ * the commands which don't need this
+ */
+ if (opcode != BHA_MBO_INTR_EN) {
+ for (i = 20000; i; i--) { /* 1 sec? */
+ sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
+ if (sts & BHA_STAT_IDLE)
+ break;
+ delay(50);
+ }
+ if (!i) {
+ printf("%s: bha_cmd, host not idle(0x%x)\n",
+ name, sts);
+ return (1);
+ }
+ }
+ /*
+ * Now that it is idle, if we expect output, preflush the
+ * queue feeding to us.
+ */
+ if (ocnt) {
+ while ((bus_space_read_1(iot, ioh, BHA_STAT_PORT)) &
+ BHA_STAT_DF)
+ bus_space_read_1(iot, ioh, BHA_DATA_PORT);
+ }
+ /*
+ * Output the command and the number of arguments given
+ * for each byte, first check the port is empty.
+ */
+ while (icnt--) {
+ for (i = wait; i; i--) {
+ sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
+ if (!(sts & BHA_STAT_CDF))
+ break;
+ delay(50);
+ }
+ if (!i) {
+ if (opcode != BHA_INQUIRE_REVISION)
+ printf("%s: bha_cmd, cmd/data port full\n",
+ name);
+ goto bad;
+ }
+ bus_space_write_1(iot, ioh, BHA_CMD_PORT, *ibuf++);
+ }
+ /*
+ * If we expect input, loop that many times, each time,
+ * looking for the data register to have valid data
+ */
+ while (ocnt--) {
+ for (i = wait; i; i--) {
+ sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
+ if (sts & BHA_STAT_DF)
+ break;
+ delay(50);
+ }
+ if (!i) {
+ if (opcode != BHA_INQUIRE_REVISION)
+ printf("%s: bha_cmd, cmd/data port empty %d\n",
+ name, ocnt);
+ goto bad;
+ }
+ *obuf++ = bus_space_read_1(iot, ioh, BHA_DATA_PORT);
+ }
+ /*
+ * Wait for the board to report a finished instruction.
+ * We may get an extra interrupt for the HACC signal, but this is
+ * unimportant.
+ */
+ if (opcode != BHA_MBO_INTR_EN && opcode != BHA_MODIFY_IOPORT) {
+ for (i = 20000; i; i--) { /* 1 sec? */
+ sts = bus_space_read_1(iot, ioh, BHA_INTR_PORT);
+ /* XXX Need to save this in the interrupt handler? */
+ if (sts & BHA_INTR_HACC)
+ break;
+ delay(50);
+ }
+ if (!i) {
+ printf("%s: bha_cmd, host not finished(0x%x)\n",
+ name, sts);
+ return (1);
+ }
+ }
+ bus_space_write_1(iot, ioh, BHA_CTRL_PORT, BHA_CTRL_IRST);
+ return (0);
+
+bad:
+ bus_space_write_1(iot, ioh, BHA_CTRL_PORT, BHA_CTRL_SRST);
+ return (1);
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+void
+bha_attach(sc, bpd)
+ struct bha_softc *sc;
+ struct bha_probe_data *bpd;
+{
+ int s;
+
+ /*
+ * Fill in the adapter.
+ */
+ sc->sc_adapter.scsi_cmd = bha_scsi_cmd;
+ sc->sc_adapter.scsi_minphys = bhaminphys;
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = bpd->sc_scsi_dev;
+ sc->sc_link.adapter = &sc->sc_adapter;
+ sc->sc_link.device = &bha_dev;
+ sc->sc_link.openings = 4;
+
+ TAILQ_INIT(&sc->sc_free_ccb);
+ TAILQ_INIT(&sc->sc_waiting_ccb);
+ LIST_INIT(&sc->sc_queue);
+
+ s = splbio();
+ bha_inquire_setup_information(sc);
+
+ printf("%s: model BT-%s, firmware %s\n", sc->sc_dev.dv_xname,
+ sc->sc_model, sc->sc_firmware);
+
+ if (bha_init(sc) != 0) {
+ /* Error during initialization! */
+ splx(s);
+ return;
+ }
+
+ splx(s);
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
+}
+
+integrate void
+bha_finish_ccbs(sc)
+ struct bha_softc *sc;
+{
+ struct bha_mbx_in *wmbi;
+ struct bha_ccb *ccb;
+ int i;
+
+ wmbi = wmbx->tmbi;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+ if (wmbi->comp_stat == BHA_MBI_FREE) {
+ for (i = 0; i < BHA_MBX_SIZE; i++) {
+ if (wmbi->comp_stat != BHA_MBI_FREE) {
+ printf("%s: mbi not in round-robin order\n",
+ sc->sc_dev.dv_xname);
+ goto AGAIN;
+ }
+ bha_nextmbx(wmbi, wmbx, mbi);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_POSTREAD);
+ }
+#ifdef BHADIAGnot
+ printf("%s: mbi interrupt with no full mailboxes\n",
+ sc->sc_dev.dv_xname);
+#endif
+ return;
+ }
+
+AGAIN:
+ do {
+ ccb = bha_ccb_phys_kv(sc, phystol(wmbi->ccb_addr));
+ if (!ccb) {
+ printf("%s: bad mbi ccb pointer; skipping\n",
+ sc->sc_dev.dv_xname);
+ goto next;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+#ifdef BHADEBUG
+ if (bha_debug) {
+ u_int8_t *cp = ccb->scsi_cmd.bytes;
+ printf("op=%x %x %x %x %x %x\n",
+ ccb->scsi_cmd.opcode,
+ cp[0], cp[1], cp[2], cp[3], cp[4]);
+ printf("stat %x for mbi addr = 0x%08x, ",
+ wmbi->comp_stat, wmbi);
+ printf("ccb addr = 0x%x\n", ccb);
+ }
+#endif /* BHADEBUG */
+
+ switch (wmbi->comp_stat) {
+ case BHA_MBI_OK:
+ case BHA_MBI_ERROR:
+ if ((ccb->flags & CCB_ABORT) != 0) {
+ /*
+ * If we already started an abort, wait for it
+ * to complete before clearing the CCB. We
+ * could instead just clear CCB_SENDING, but
+ * what if the mailbox was already received?
+ * The worst that happens here is that we clear
+ * the CCB a bit later than we need to. BFD.
+ */
+ goto next;
+ }
+ break;
+
+ case BHA_MBI_ABORT:
+ case BHA_MBI_UNKNOWN:
+ /*
+ * Even if the CCB wasn't found, we clear it anyway.
+ * See preceeding comment.
+ */
+ break;
+
+ default:
+ printf("%s: bad mbi status %02x; skipping\n",
+ sc->sc_dev.dv_xname, wmbi->comp_stat);
+ goto next;
+ }
+
+ timeout_del(&ccb->xs->stimeout);
+ bha_done(sc, ccb);
+
+ next:
+ wmbi->comp_stat = BHA_MBI_FREE;
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ bha_nextmbx(wmbi, wmbx, mbi);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ } while (wmbi->comp_stat != BHA_MBI_FREE);
+
+ wmbx->tmbi = wmbi;
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+bha_intr(arg)
+ void *arg;
+{
+ struct bha_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_char sts;
+
+#ifdef BHADEBUG
+ printf("%s: bha_intr ", sc->sc_dev.dv_xname);
+#endif /* BHADEBUG */
+
+ /*
+ * First acknowlege the interrupt, Then if it's not telling about
+ * a completed operation just return.
+ */
+ sts = bus_space_read_1(iot, ioh, BHA_INTR_PORT);
+ if ((sts & BHA_INTR_ANYINTR) == 0)
+ return (0);
+ bus_space_write_1(iot, ioh, BHA_CTRL_PORT, BHA_CTRL_IRST);
+
+#ifdef BHADIAG
+ /* Make sure we clear CCB_SENDING before finishing a CCB. */
+ bha_collect_mbo(sc);
+#endif
+
+ /* Mail box out empty? */
+ if (sts & BHA_INTR_MBOA) {
+ struct bha_toggle toggle;
+
+ toggle.cmd.opcode = BHA_MBO_INTR_EN;
+ toggle.cmd.enable = 0;
+ bha_cmd(iot, ioh, sc,
+ sizeof(toggle.cmd), (u_char *)&toggle.cmd,
+ 0, (u_char *)0);
+ bha_start_ccbs(sc);
+ }
+
+ /* Mail box in full? */
+ if (sts & BHA_INTR_MBIF)
+ bha_finish_ccbs(sc);
+
+ return (1);
+}
+
+integrate void
+bha_reset_ccb(sc, ccb)
+ struct bha_softc *sc;
+ struct bha_ccb *ccb;
+{
+
+ ccb->flags = 0;
+}
+
+/*
+ * A ccb is put onto the free list.
+ */
+void
+bha_free_ccb(sc, ccb)
+ struct bha_softc *sc;
+ struct bha_ccb *ccb;
+{
+ int s;
+
+ s = splbio();
+
+ bha_reset_ccb(sc, ccb);
+ TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
+
+ /*
+ * If there were none, wake anybody waiting for one to come free,
+ * starting with queued entries.
+ */
+ if (ccb->chain.tqe_next == 0)
+ wakeup(&sc->sc_free_ccb);
+
+ splx(s);
+}
+
+integrate int
+bha_init_ccb(sc, ccb)
+ struct bha_softc *sc;
+ struct bha_ccb *ccb;
+{
+ bus_dma_tag_t dmat = sc->sc_dmat;
+ int hashnum, error;
+
+ /*
+ * Create the DMA map for this CCB.
+ */
+ error = bus_dmamap_create(dmat, BHA_MAXXFER, BHA_NSEG, BHA_MAXXFER,
+ 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags,
+ &ccb->dmamap_xfer);
+ if (error) {
+ printf("%s: unable to create ccb DMA map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ ccb->hashkey = sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ BHA_CCB_OFF(ccb);
+ hashnum = CCB_HASH(ccb->hashkey);
+ ccb->nexthash = sc->sc_ccbhash[hashnum];
+ sc->sc_ccbhash[hashnum] = ccb;
+ bha_reset_ccb(sc, ccb);
+ return (0);
+}
+
+/*
+ * Create a set of ccbs and add them to the free list. Called once
+ * by bha_init(). We return the number of CCBs successfully created.
+ */
+int
+bha_create_ccbs(sc, ccbstore, count)
+ struct bha_softc *sc;
+ struct bha_ccb *ccbstore;
+ int count;
+{
+ struct bha_ccb *ccb;
+ int i, error;
+
+ bzero(ccbstore, sizeof(struct bha_ccb) * count);
+ for (i = 0; i < count; i++) {
+ ccb = &ccbstore[i];
+ if ((error = bha_init_ccb(sc, ccb)) != 0) {
+ printf("%s: unable to initialize ccb, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto out;
+ }
+ TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain);
+ }
+ out:
+ return (i);
+}
+
+/*
+ * Get a free ccb
+ *
+ * If there are none, see if we can allocate a new one. If so, put it in
+ * the hash table too otherwise either return an error or sleep.
+ */
+struct bha_ccb *
+bha_get_ccb(sc, flags)
+ struct bha_softc *sc;
+ int flags;
+{
+ struct bha_ccb *ccb;
+ int s;
+
+ s = splbio();
+
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one.
+ */
+ for (;;) {
+ ccb = sc->sc_free_ccb.tqh_first;
+ if (ccb) {
+ TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
+ break;
+ }
+ if ((flags & SCSI_NOSLEEP) != 0)
+ goto out;
+ tsleep(&sc->sc_free_ccb, PRIBIO, "bhaccb", 0);
+ }
+
+ ccb->flags |= CCB_ALLOC;
+
+out:
+ splx(s);
+ return (ccb);
+}
+
+/*
+ * Given a physical address, find the ccb that it corresponds to.
+ */
+struct bha_ccb *
+bha_ccb_phys_kv(sc, ccb_phys)
+ struct bha_softc *sc;
+ u_long ccb_phys;
+{
+ int hashnum = CCB_HASH(ccb_phys);
+ struct bha_ccb *ccb = sc->sc_ccbhash[hashnum];
+
+ while (ccb) {
+ if (ccb->hashkey == ccb_phys)
+ break;
+ ccb = ccb->nexthash;
+ }
+ return (ccb);
+}
+
+/*
+ * Queue a CCB to be sent to the controller, and send it if possible.
+ */
+void
+bha_queue_ccb(sc, ccb)
+ struct bha_softc *sc;
+ struct bha_ccb *ccb;
+{
+
+ timeout_set(&ccb->xs->stimeout, bha_timeout, ccb);
+ TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
+ bha_start_ccbs(sc);
+}
+
+/*
+ * Garbage collect mailboxes that are no longer in use.
+ */
+void
+bha_collect_mbo(sc)
+ struct bha_softc *sc;
+{
+ struct bha_mbx_out *wmbo; /* Mail Box Out pointer */
+#ifdef BHADIAG
+ struct bha_ccb *ccb;
+#endif
+
+ wmbo = wmbx->cmbo;
+
+ while (sc->sc_mbofull > 0) {
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ if (wmbo->cmd != BHA_MBO_FREE)
+ break;
+
+#ifdef BHADIAG
+ ccb = bha_ccb_phys_kv(sc, phystol(wmbo->ccb_addr));
+ ccb->flags &= ~CCB_SENDING;
+#endif
+
+ --sc->sc_mbofull;
+ bha_nextmbx(wmbo, wmbx, mbo);
+ }
+
+ wmbx->cmbo = wmbo;
+}
+
+/*
+ * Send as many CCBs as we have empty mailboxes for.
+ */
+void
+bha_start_ccbs(sc)
+ struct bha_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ struct bha_mbx_out *wmbo; /* Mail Box Out pointer */
+ struct bha_ccb *ccb;
+ struct scsi_xfer *xs;
+
+ wmbo = wmbx->tmbo;
+
+ while ((ccb = sc->sc_waiting_ccb.tqh_first) != NULL) {
+
+ xs = ccb->xs;
+ if (sc->sc_mbofull >= BHA_MBX_SIZE) {
+ bha_collect_mbo(sc);
+ if (sc->sc_mbofull >= BHA_MBX_SIZE) {
+ struct bha_toggle toggle;
+
+ toggle.cmd.opcode = BHA_MBO_INTR_EN;
+ toggle.cmd.enable = 1;
+ bha_cmd(iot, ioh, sc,
+ sizeof(toggle.cmd), (u_char *)&toggle.cmd,
+ 0, (u_char *)0);
+ break;
+ }
+ }
+
+ TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
+#ifdef BHADIAG
+ ccb->flags |= CCB_SENDING;
+#endif
+
+ /* Link ccb to mbo. */
+ ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ BHA_CCB_OFF(ccb), wmbo->ccb_addr);
+ if (ccb->flags & CCB_ABORT)
+ wmbo->cmd = BHA_MBO_ABORT;
+ else
+ wmbo->cmd = BHA_MBO_START;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /* Tell the card to poll immediately. */
+ bus_space_write_1(iot, ioh, BHA_CMD_PORT, BHA_START_SCSI);
+
+ if ((xs->flags & SCSI_POLL) == 0)
+ timeout_add(&xs->stimeout, (ccb->timeout * hz) / 1000);
+
+ ++sc->sc_mbofull;
+ bha_nextmbx(wmbo, wmbx, mbo);
+ }
+
+ wmbx->tmbo = wmbo;
+}
+
+/*
+ * We have a ccb which has been processed by the
+ * adaptor, now we look to see how the operation
+ * went. Wake up the owner if waiting
+ */
+void
+bha_done(sc, ccb)
+ struct bha_softc *sc;
+ struct bha_ccb *ccb;
+{
+ bus_dma_tag_t dmat = sc->sc_dmat;
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = ccb->xs;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("bha_done\n"));
+
+ /*
+ * If we were a data transfer, unload the map that described
+ * the data buffer.
+ */
+ if (xs->datalen) {
+ bus_dmamap_sync(dmat, ccb->dmamap_xfer,
+ 0, ccb->dmamap_xfer->dm_mapsize,
+ (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(dmat, ccb->dmamap_xfer);
+ }
+
+ /*
+ * Otherwise, put the results of the operation
+ * into the xfer and call whoever started it
+ */
+#ifdef BHADIAG
+ if (ccb->flags & CCB_SENDING) {
+ printf("%s: exiting ccb still in transit!\n",
+ sc->sc_dev.dv_xname);
+ Debugger();
+ return;
+ }
+#endif
+ if ((ccb->flags & CCB_ALLOC) == 0) {
+ printf("%s: exiting ccb not allocated!\n",
+ sc->sc_dev.dv_xname);
+ Debugger();
+ return;
+ }
+ if (xs->error == XS_NOERROR) {
+ if (ccb->host_stat != BHA_OK) {
+ switch (ccb->host_stat) {
+ case BHA_SEL_TIMEOUT: /* No response */
+ xs->error = XS_SELTIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ printf("%s: host_stat %x\n",
+ sc->sc_dev.dv_xname, ccb->host_stat);
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ } else if (ccb->target_stat != SCSI_OK) {
+ switch (ccb->target_stat) {
+ case SCSI_CHECK:
+ s1 = &ccb->scsi_sense;
+ s2 = &xs->sense;
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ break;
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+ default:
+ printf("%s: target_stat %x\n",
+ sc->sc_dev.dv_xname, ccb->target_stat);
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ } else
+ xs->resid = 0;
+ }
+ bha_free_ccb(sc, ccb);
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+
+ /*
+ * If there are queue entries in the software queue, try to
+ * run the first one. We should be more or less guaranteed
+ * to succeed, since we just freed a CCB.
+ *
+ * NOTE: bha_scsi_cmd() relies on our calling it with
+ * the first entry in the queue.
+ */
+ if ((xs = sc->sc_queue.lh_first) != NULL)
+ (void) bha_scsi_cmd(xs);
+}
+
+/*
+ * Find the board and find it's irq/drq
+ */
+int
+bha_find(iot, ioh, sc)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ struct bha_probe_data *sc;
+{
+ int i, iswide;
+ u_char sts;
+ struct bha_extended_inquire inquire;
+ struct bha_config config;
+ int irq, drq;
+
+ /* Check something is at the ports we need to access */
+ sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
+ if (sts == 0xFF) {
+#ifdef BHADEBUG
+ if (bha_debug)
+ printf("bha_find: Not present\n");
+#endif /* BHADEBUG */
+ return (0);
+ }
+
+ /*
+ * Reset board, If it doesn't respond, assume
+ * that it's not there.. good for the probe
+ */
+
+ bus_space_write_1(iot, ioh, BHA_CTRL_PORT,
+ BHA_CTRL_HRST | BHA_CTRL_SRST);
+
+ for (i = BHA_RESET_TIMEOUT; i--;) {
+ delay(100);
+ sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
+ if (sts == (BHA_STAT_IDLE | BHA_STAT_INIT))
+ break;
+ }
+ if (i < 0) {
+#ifdef BHADEBUG
+ if (bha_debug)
+ printf("bha_find: No answer from board a=%x sts=%b\n",
+ ioh, sts, BHA_STAT_BITS);
+#endif /* BHADEBUG */
+ return (0);
+ }
+
+ /*
+ * The BusLogic cards implement an Adaptec 1542 (aha)-compatible
+ * interface. The native bha interface is not compatible with
+ * an aha. 1542. We need to ensure that we never match an
+ * Adaptec 1542. We must also avoid sending Adaptec-compatible
+ * commands to a real bha, lest it go into 1542 emulation mode.
+ * (On an indirect bus like ISA, we should always probe for BusLogic
+ * interfaces before Adaptec interfaces).
+ */
+
+ /*
+ * Make sure we don't match an AHA-1542A or AHA-1542B, by checking
+ * for an extended-geometry register. The 1542[AB] don't have one.
+ */
+ sts = bus_space_read_1(iot, ioh, BHA_EXTGEOM_PORT);
+ if (sts == 0xFF)
+ return (0);
+
+ /*
+ * Check that we actually know how to use this board.
+ */
+ delay(1000);
+ inquire.cmd.opcode = BHA_INQUIRE_EXTENDED;
+ inquire.cmd.len = sizeof(inquire.reply);
+ i = bha_cmd(iot, ioh, NULL,
+ sizeof(inquire.cmd), (u_char *)&inquire.cmd,
+ sizeof(inquire.reply), (u_char *)&inquire.reply);
+
+ /*
+ * Some 1542Cs (CP, perhaps not CF, may depend on firmware rev)
+ * have the extended-geometry register and also respond to
+ * BHA_INQUIRE_EXTENDED. Make sure we never match such cards,
+ * by checking the size of the reply is what a BusLogic card returns.
+ */
+ if (i) {
+#ifdef BHADEBUG
+ printf("bha_find: board returned %d instead of %d to %s\n",
+ i, sizeof(inquire.reply), "INQUIRE_EXTENDED");
+#endif
+ return (0);
+ }
+
+ /* OK, we know we've found a buslogic adaptor. */
+
+ switch (inquire.reply.bus_type) {
+ case BHA_BUS_TYPE_24BIT:
+ case BHA_BUS_TYPE_32BIT:
+ break;
+ case BHA_BUS_TYPE_MCA:
+ /* We don't grok MicroChannel (yet). */
+ return (0);
+ default:
+ printf("bha_find: illegal bus type %c\n",
+ inquire.reply.bus_type);
+ return (0);
+ }
+
+ /* Note if we have a wide bus. */
+ iswide = inquire.reply.scsi_flags & BHA_SCSI_WIDE;
+
+ /*
+ * Assume we have a board at this stage setup dma channel from
+ * jumpers and save int level
+ */
+ delay(1000);
+ config.cmd.opcode = BHA_INQUIRE_CONFIG;
+ bha_cmd(iot, ioh, NULL,
+ sizeof(config.cmd), (u_char *)&config.cmd,
+ sizeof(config.reply), (u_char *)&config.reply);
+ switch (config.reply.chan) {
+ case EISADMA:
+ drq = -1;
+ break;
+ case CHAN0:
+ drq = 0;
+ break;
+ case CHAN5:
+ drq = 5;
+ break;
+ case CHAN6:
+ drq = 6;
+ break;
+ case CHAN7:
+ drq = 7;
+ break;
+ default:
+ printf("bha_find: illegal drq setting %x\n",
+ config.reply.chan);
+ return (0);
+ }
+
+ switch (config.reply.intr) {
+ case INT9:
+ irq = 9;
+ break;
+ case INT10:
+ irq = 10;
+ break;
+ case INT11:
+ irq = 11;
+ break;
+ case INT12:
+ irq = 12;
+ break;
+ case INT14:
+ irq = 14;
+ break;
+ case INT15:
+ irq = 15;
+ break;
+ default:
+ printf("bha_find: illegal irq setting %x\n",
+ config.reply.intr);
+ return (0);
+ }
+
+ /* if we want to fill in softc, do so now */
+ if (sc != NULL) {
+ sc->sc_irq = irq;
+ sc->sc_drq = drq;
+ sc->sc_scsi_dev = config.reply.scsi_dev;
+ sc->sc_iswide = iswide;
+ }
+
+ return (1);
+}
+
+
+/*
+ * Disable the ISA-compatiblity ioports on PCI bha devices,
+ * to ensure they're not autoconfigured a second time as an ISA bha.
+ */
+int
+bha_disable_isacompat(sc)
+ struct bha_softc *sc;
+{
+ struct bha_isadisable isa_disable;
+
+ isa_disable.cmd.opcode = BHA_MODIFY_IOPORT;
+ isa_disable.cmd.modifier = BHA_IOMODIFY_DISABLE1;
+ bha_cmd(sc->sc_iot, sc->sc_ioh, sc,
+ sizeof(isa_disable.cmd), (u_char*)&isa_disable.cmd,
+ 0, (u_char *)0);
+ return (0);
+}
+
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+bha_init(sc)
+ struct bha_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ bus_dma_segment_t seg;
+ struct bha_devices devices;
+ struct bha_setup setup;
+ struct bha_mailbox mailbox;
+ struct bha_period period;
+ int error, i, j, initial_ccbs, rlen, rseg;
+
+ /* Enable round-robin scheme - appeared at firmware rev. 3.31. */
+ if (strcmp(sc->sc_firmware, "3.31") >= 0) {
+ struct bha_toggle toggle;
+
+ toggle.cmd.opcode = BHA_ROUND_ROBIN;
+ toggle.cmd.enable = 1;
+ bha_cmd(iot, ioh, sc,
+ sizeof(toggle.cmd), (u_char *)&toggle.cmd,
+ 0, (u_char *)0);
+ }
+
+ /*
+ * Inquire installed devices (to force synchronous negotiation).
+ */
+
+ /*
+ * Poll targets 0 - 7.
+ */
+ devices.cmd.opcode = BHA_INQUIRE_DEVICES;
+ bha_cmd(iot, ioh, sc,
+ sizeof(devices.cmd), (u_char *)&devices.cmd,
+ sizeof(devices.reply), (u_char *)&devices.reply);
+
+ /* Count installed units. */
+ initial_ccbs = 0;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ if (((devices.reply.lun_map[i] >> j) & 1) == 1)
+ initial_ccbs++;
+ }
+ }
+
+ /*
+ * Poll targets 8 - 15 if we have a wide bus.
+ */
+ if (ISWIDE(sc)) {
+ devices.cmd.opcode = BHA_INQUIRE_DEVICES_2;
+ bha_cmd(iot, ioh, sc,
+ sizeof(devices.cmd), (u_char *)&devices.cmd,
+ sizeof(devices.reply), (u_char *)&devices.reply);
+
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ if (((devices.reply.lun_map[i] >> j) & 1) == 1)
+ initial_ccbs++;
+ }
+ }
+ }
+
+ initial_ccbs *= sc->sc_link.openings;
+ if (initial_ccbs > BHA_CCB_MAX)
+ initial_ccbs = BHA_CCB_MAX;
+ if (initial_ccbs == 0) /* yes, this can happen */
+ initial_ccbs = sc->sc_link.openings;
+
+ /* Obtain setup information from. */
+ rlen = sizeof(setup.reply) +
+ (ISWIDE(sc) ? sizeof(setup.reply_w) : 0);
+ setup.cmd.opcode = BHA_INQUIRE_SETUP;
+ setup.cmd.len = rlen;
+ bha_cmd(iot, ioh, sc,
+ sizeof(setup.cmd), (u_char *)&setup.cmd,
+ rlen, (u_char *)&setup.reply);
+
+ printf("%s: %s, %s\n", sc->sc_dev.dv_xname,
+ setup.reply.sync_neg ? "sync" : "async",
+ setup.reply.parity ? "parity" : "no parity");
+
+ for (i = 0; i < 8; i++)
+ period.reply.period[i] = setup.reply.sync[i].period * 5 + 20;
+ if (ISWIDE(sc)) {
+ for (i = 0; i < 8; i++)
+ period.reply_w.period[i] =
+ setup.reply_w.sync_high[i].period * 5 + 20;
+ }
+
+ if (sc->sc_firmware[0] >= '3') {
+ rlen = sizeof(period.reply) +
+ (ISWIDE(sc) ? sizeof(period.reply_w) : 0);
+ period.cmd.opcode = BHA_INQUIRE_PERIOD;
+ period.cmd.len = sizeof(period.reply);
+ bha_cmd(iot, ioh, sc,
+ sizeof(period.cmd), (u_char *)&period.cmd,
+ rlen, (u_char *)&period.reply);
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (!setup.reply.sync[i].valid ||
+ (!setup.reply.sync[i].offset &&
+ !setup.reply.sync[i].period))
+ continue;
+ printf("%s targ %d: sync, offset %d, period %dnsec\n",
+ sc->sc_dev.dv_xname, i,
+ setup.reply.sync[i].offset, period.reply.period[i] * 10);
+ }
+ if (ISWIDE(sc)) {
+ for (i = 0; i < 8; i++) {
+ if (!setup.reply_w.sync_high[i].valid ||
+ (!setup.reply_w.sync_high[i].offset &&
+ !setup.reply_w.sync_high[i].period))
+ continue;
+ printf("%s targ %d: sync, offset %d, period %dnsec\n",
+ sc->sc_dev.dv_xname, i + 8,
+ setup.reply_w.sync_high[i].offset,
+ period.reply_w.period[i] * 10);
+ }
+ }
+
+ /*
+ * Allocate the mailbox and control blocks.
+ */
+ if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct bha_control),
+ NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to allocate control structures, "
+ "error = %d\n", sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+ if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
+ sizeof(struct bha_control), (caddr_t *)&sc->sc_control,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to map control structures, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+
+ /*
+ * Create and load the DMA map used for the mailbox and
+ * control blocks.
+ */
+ if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct bha_control),
+ 1, sizeof(struct bha_control), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags,
+ &sc->sc_dmamap_control)) != 0) {
+ printf("%s: unable to create control DMA map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_control,
+ sc->sc_control, sizeof(struct bha_control), NULL,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to load control DMA map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+
+ /*
+ * Initialize the control blocks.
+ */
+ i = bha_create_ccbs(sc, sc->sc_control->bc_ccbs, initial_ccbs);
+ if (i == 0) {
+ printf("%s: unable to create control blocks\n",
+ sc->sc_dev.dv_xname);
+ return (ENOMEM);
+ } else if (i != initial_ccbs) {
+ printf("%s: WARNING: only %d of %d control blocks created\n",
+ sc->sc_dev.dv_xname, i, initial_ccbs);
+ }
+
+ /*
+ * Set up initial mail box for round-robin operation.
+ */
+ for (i = 0; i < BHA_MBX_SIZE; i++) {
+ wmbx->mbo[i].cmd = BHA_MBO_FREE;
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ wmbx->mbi[i].comp_stat = BHA_MBI_FREE;
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ }
+ wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0];
+ wmbx->tmbi = &wmbx->mbi[0];
+ sc->sc_mbofull = 0;
+
+ /* Initialize mail box. */
+ mailbox.cmd.opcode = BHA_MBX_INIT_EXTENDED;
+ mailbox.cmd.nmbx = BHA_MBX_SIZE;
+ ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ offsetof(struct bha_control, bc_mbx), mailbox.cmd.addr);
+ bha_cmd(iot, ioh, sc,
+ sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
+ 0, (u_char *)0);
+ return (0);
+}
+
+void
+bha_inquire_setup_information(sc)
+ struct bha_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ struct bha_model model;
+ struct bha_revision revision;
+ struct bha_digit digit;
+ char *p;
+
+ /*
+ * Get the firmware revision.
+ */
+ p = sc->sc_firmware;
+ revision.cmd.opcode = BHA_INQUIRE_REVISION;
+ bha_cmd(iot, ioh, sc,
+ sizeof(revision.cmd), (u_char *)&revision.cmd,
+ sizeof(revision.reply), (u_char *)&revision.reply);
+ *p++ = revision.reply.firm_revision;
+ *p++ = '.';
+ *p++ = revision.reply.firm_version;
+ digit.cmd.opcode = BHA_INQUIRE_REVISION_3;
+ bha_cmd(iot, ioh, sc,
+ sizeof(digit.cmd), (u_char *)&digit.cmd,
+ sizeof(digit.reply), (u_char *)&digit.reply);
+ *p++ = digit.reply.digit;
+ if (revision.reply.firm_revision >= '3' ||
+ (revision.reply.firm_revision == '3' &&
+ revision.reply.firm_version >= '3')) {
+ digit.cmd.opcode = BHA_INQUIRE_REVISION_4;
+ bha_cmd(iot, ioh, sc,
+ sizeof(digit.cmd), (u_char *)&digit.cmd,
+ sizeof(digit.reply), (u_char *)&digit.reply);
+ *p++ = digit.reply.digit;
+ }
+ while (p > sc->sc_firmware && (p[-1] == ' ' || p[-1] == '\0'))
+ p--;
+ *p = '\0';
+
+ /*
+ * Get the model number.
+ */
+ if (revision.reply.firm_revision >= '3') {
+ p = sc->sc_model;
+ model.cmd.opcode = BHA_INQUIRE_MODEL;
+ model.cmd.len = sizeof(model.reply);
+ bha_cmd(iot, ioh, sc,
+ sizeof(model.cmd), (u_char *)&model.cmd,
+ sizeof(model.reply), (u_char *)&model.reply);
+ *p++ = model.reply.id[0];
+ *p++ = model.reply.id[1];
+ *p++ = model.reply.id[2];
+ *p++ = model.reply.id[3];
+ while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0'))
+ p--;
+ *p++ = model.reply.version[0];
+ *p++ = model.reply.version[1];
+ while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0'))
+ p--;
+ *p = '\0';
+ } else
+ strcpy(sc->sc_model, "542B");
+}
+
+void
+bhaminphys(bp)
+ struct buf *bp;
+{
+
+ if (bp->b_bcount > BHA_MAXXFER)
+ bp->b_bcount = BHA_MAXXFER;
+ minphys(bp);
+}
+
+/*
+ * start a scsi operation given the command and the data address. Also needs
+ * the unit, target and lu.
+ */
+int
+bha_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct bha_softc *sc = sc_link->adapter_softc;
+ bus_dma_tag_t dmat = sc->sc_dmat;
+ struct bha_ccb *ccb;
+ int error, seg, flags, s;
+ int fromqueue = 0, dontqueue = 0;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("bha_scsi_cmd\n"));
+
+ s = splbio(); /* protect the queue */
+
+ /*
+ * If we're running the queue from bha_done(), we've been
+ * called with the first queue entry as our argument.
+ */
+ if (xs == sc->sc_queue.lh_first) {
+ xs = bha_dequeue(sc);
+ fromqueue = 1;
+ goto get_ccb;
+ }
+
+ /* Polled requests can't be queued for later. */
+ dontqueue = xs->flags & SCSI_POLL;
+
+ /*
+ * If there are jobs in the queue, run them first.
+ */
+ if (sc->sc_queue.lh_first != NULL) {
+ /*
+ * If we can't queue, we have to abort, since
+ * we have to preserve order.
+ */
+ if (dontqueue) {
+ splx(s);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+
+ /*
+ * Swap with the first queue entry.
+ */
+ bha_enqueue(sc, xs, 0);
+ xs = bha_dequeue(sc);
+ fromqueue = 1;
+ }
+
+ get_ccb:
+ /*
+ * get a ccb to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+ flags = xs->flags;
+ if ((ccb = bha_get_ccb(sc, flags)) == NULL) {
+ /*
+ * If we can't queue, we lose.
+ */
+ if (dontqueue) {
+ splx(s);
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+
+ /*
+ * Stuff ourselves into the queue, in front
+ * if we came off in the first place.
+ */
+ bha_enqueue(sc, xs, fromqueue);
+ splx(s);
+ return (SUCCESSFULLY_QUEUED);
+ }
+
+ splx(s); /* done playing with the queue */
+
+ ccb->xs = xs;
+ ccb->timeout = xs->timeout;
+
+ /*
+ * Put all the arguments for the xfer in the ccb
+ */
+ if (flags & SCSI_RESET) {
+ ccb->opcode = BHA_RESET_CCB;
+ ccb->scsi_cmd_length = 0;
+ } else {
+ /* can't use S/G if zero length */
+ ccb->opcode = (xs->datalen ? BHA_INIT_SCAT_GATH_CCB
+ : BHA_INITIATOR_CCB);
+ bcopy(xs->cmd, &ccb->scsi_cmd,
+ ccb->scsi_cmd_length = xs->cmdlen);
+ }
+
+ if (xs->datalen) {
+ /*
+ * Map the DMA transfer.
+ */
+#ifdef TFS
+ if (flags & SCSI_DATA_UIO) {
+ error = bus_dmamap_load_uio(dmat,
+ ccb->dmamap_xfer, (struct uio *)xs->data,
+ (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
+ BUS_DMA_WAITOK);
+ } else
+#endif /* TFS */
+ {
+ error = bus_dmamap_load(dmat,
+ ccb->dmamap_xfer, xs->data, xs->datalen, NULL,
+ (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
+ BUS_DMA_WAITOK);
+ }
+
+ if (error) {
+ if (error == EFBIG) {
+ printf("%s: bha_scsi_cmd, more than %d"
+ " dma segments\n",
+ sc->sc_dev.dv_xname, BHA_NSEG);
+ } else {
+ printf("%s: bha_scsi_cmd, error %d loading"
+ " dma map\n",
+ sc->sc_dev.dv_xname, error);
+ }
+ goto bad;
+ }
+
+ bus_dmamap_sync(dmat, ccb->dmamap_xfer,
+ 0, ccb->dmamap_xfer->dm_mapsize,
+ (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
+ BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Load the hardware scatter/gather map with the
+ * contents of the DMA map.
+ */
+ for (seg = 0; seg < ccb->dmamap_xfer->dm_nsegs; seg++) {
+ ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_addr,
+ ccb->scat_gath[seg].seg_addr);
+ ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_len,
+ ccb->scat_gath[seg].seg_len);
+ }
+
+ ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ BHA_CCB_OFF(ccb) + offsetof(struct bha_ccb, scat_gath),
+ ccb->data_addr);
+ ltophys(ccb->dmamap_xfer->dm_nsegs *
+ sizeof(struct bha_scat_gath), ccb->data_length);
+ } else {
+ /*
+ * No data xfer, use non S/G values.
+ */
+ ltophys(0, ccb->data_addr);
+ ltophys(0, ccb->data_length);
+ }
+
+ ccb->data_out = 0;
+ ccb->data_in = 0;
+ ccb->target = sc_link->target;
+ ccb->lun = sc_link->lun;
+ ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ BHA_CCB_OFF(ccb) + offsetof(struct bha_ccb, scsi_sense),
+ ccb->sense_ptr);
+ ccb->req_sense_length = sizeof(ccb->scsi_sense);
+ ccb->host_stat = 0x00;
+ ccb->target_stat = 0x00;
+ ccb->link_id = 0;
+ ltophys(0, ccb->link_addr);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
+ 0, sc->sc_dmamap_control->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ s = splbio();
+ bha_queue_ccb(sc, ccb);
+ splx(s);
+
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
+ if ((flags & SCSI_POLL) == 0)
+ return (SUCCESSFULLY_QUEUED);
+
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ if (bha_poll(sc, xs, ccb->timeout)) {
+ bha_timeout(ccb);
+ if (bha_poll(sc, xs, ccb->timeout))
+ bha_timeout(ccb);
+ }
+ return (COMPLETE);
+
+bad:
+ xs->error = XS_DRIVER_STUFFUP;
+ bha_free_ccb(sc, ccb);
+ return (COMPLETE);
+}
+
+/*
+ * Poll a particular unit, looking for a particular xs
+ */
+int
+bha_poll(sc, xs, count)
+ struct bha_softc *sc;
+ struct scsi_xfer *xs;
+ int count;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ /* timeouts are in msec, so we loop in 1000 usec cycles */
+ while (count) {
+ /*
+ * If we had interrupts enabled, would we
+ * have got an interrupt?
+ */
+ if (bus_space_read_1(iot, ioh, BHA_INTR_PORT) &
+ BHA_INTR_ANYINTR)
+ bha_intr(sc);
+ if (xs->flags & ITSDONE)
+ return (0);
+ delay(1000); /* only happens in boot so ok */
+ count--;
+ }
+ return (1);
+}
+
+void
+bha_timeout(arg)
+ void *arg;
+{
+ struct bha_ccb *ccb = arg;
+ struct scsi_xfer *xs = ccb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct bha_softc *sc = sc_link->adapter_softc;
+ int s;
+
+ sc_print_addr(sc_link);
+ printf("timed out");
+
+ s = splbio();
+
+#ifdef BHADIAG
+ /*
+ * If the ccb's mbx is not free, then the board has gone Far East?
+ */
+ bha_collect_mbo(sc);
+ if (ccb->flags & CCB_SENDING) {
+ printf("%s: not taking commands!\n", sc->sc_dev.dv_xname);
+ Debugger();
+ }
+#endif
+
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (ccb->flags & CCB_ABORT) {
+ /* abort timed out */
+ printf(" AGAIN\n");
+ /* XXX Must reset! */
+ } else {
+ /* abort the operation that has timed out */
+ printf("\n");
+ ccb->xs->error = XS_TIMEOUT;
+ ccb->timeout = BHA_ABORT_TIMEOUT;
+ ccb->flags |= CCB_ABORT;
+ bha_queue_ccb(sc, ccb);
+ }
+
+ splx(s);
+}
diff --git a/sys/dev/ic/bhareg.h b/sys/dev/ic/bhareg.h
new file mode 100644
index 00000000000..11ff58cbda9
--- /dev/null
+++ b/sys/dev/ic/bhareg.h
@@ -0,0 +1,503 @@
+/* $OpenBSD: bhareg.h,v 1.1 2002/01/24 22:38:03 mickey Exp $ */
+/* $NetBSD: bhareg.h,v 1.12 1998/08/17 00:26:33 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by 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.
+ */
+
+/*
+ * 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.
+ */
+
+typedef u_int8_t physaddr[4];
+typedef u_int8_t physlen[4];
+#define ltophys _lto4l
+#define phystol _4ltol
+
+/*
+ * I/O port offsets
+ */
+#define BHA_CTRL_PORT 0 /* control (wo) */
+#define BHA_STAT_PORT 0 /* status (ro) */
+#define BHA_CMD_PORT 1 /* command (wo) */
+#define BHA_DATA_PORT 1 /* data (ro) */
+#define BHA_INTR_PORT 2 /* interrupt status (ro) */
+#define BHA_EXTGEOM_PORT 3 /* extended geometry (ro) */
+
+/*
+ * BHA_CTRL bits
+ */
+#define BHA_CTRL_HRST 0x80 /* Hardware reset */
+#define BHA_CTRL_SRST 0x40 /* Software reset */
+#define BHA_CTRL_IRST 0x20 /* Interrupt reset */
+#define BHA_CTRL_SCRST 0x10 /* SCSI bus reset */
+
+/*
+ * BHA_STAT bits
+ */
+#define BHA_STAT_STST 0x80 /* Self test in Progress */
+#define BHA_STAT_DIAGF 0x40 /* Diagnostic Failure */
+#define BHA_STAT_INIT 0x20 /* Mbx Init required */
+#define BHA_STAT_IDLE 0x10 /* Host Adapter Idle */
+#define BHA_STAT_CDF 0x08 /* cmd/data out port full */
+#define BHA_STAT_DF 0x04 /* Data in port full */
+#define BHA_STAT_INVDCMD 0x01 /* Invalid command */
+#define BHA_STAT_BITS "\020\1invcmd\3df\4cdf\5idle\6init\7diagf\10stst"
+
+/*
+ * BHA_CMD opcodes
+ */
+#define BHA_NOP 0x00 /* No operation */
+#define BHA_MBX_INIT 0x01 /* Mbx initialization */
+#define BHA_START_SCSI 0x02 /* start scsi command */
+#define BHA_EXECUTE_BIOS_CMD 0x03 /* execute BIOS command */
+#define BHA_INQUIRE_REVISION 0x04 /* Adapter Inquiry */
+#define BHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
+#define BHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
+#define BHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */
+#define BHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
+#define BHA_BUS_SPEED_SET 0x09 /* set bus transfer speed */
+#define BHA_INQUIRE_DEVICES 0x0a /* return installed devices 0-7 */
+#define BHA_INQUIRE_CONFIG 0x0b /* return configuration data */
+#define BHA_TARGET_EN 0x0c /* enable target mode */
+#define BHA_INQUIRE_SETUP 0x0d /* return setup data */
+#define BHA_WRITE_LRAM 0x1a /* write adapter local RAM */
+#define BHA_READ_LRAM 0x1b /* read adapter local RAM */
+#define BHA_WRITE_CHIP_FIFO 0x1c /* write bus master chip FIFO */
+#define BHA_READ_CHIP_FIFO 0x1d /* read bus master chip FIFO */
+#define BHA_ECHO 0x1f /* Echo command byte */
+#define BHA_ADAPTER_DIAGNOSTICS 0x20 /* host adapter diagnostics */
+#define BHA_SET_ADAPTER_OPTIONS 0x21 /* set adapter options */
+#define BHA_INQUIRE_DEVICES_2 0x23 /* return installed devices 8-15 */
+#define BHA_INQUIRE_TARG_DEVS 0x24 /* inquire target devices */
+#define BHA_DISABLE_HAC_INTR 0x25 /* disable host adapter interrupt */
+#define BHA_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */
+#define BHA_EXECUTE_SCSI_CMD 0x83 /* execute SCSI command */
+#define BHA_INQUIRE_REVISION_3 0x84 /* Get 3rd firmware version byte */
+#define BHA_INQUIRE_REVISION_4 0x85 /* Get 4th firmware version byte */
+#define BHA_INQUIRE_PCI_INFO 0x86 /* get PCI host adapter information */
+#define BHA_INQUIRE_MODEL 0x8b /* Get hardware ID and revision */
+#define BHA_INQUIRE_PERIOD 0x8c /* Get synchronous period */
+#define BHA_INQUIRE_EXTENDED 0x8d /* Adapter Setup Inquiry */
+#define BHA_ROUND_ROBIN 0x8f /* Enable/Disable(default)
+ round robin */
+#define BHA_STORE_LRAM 0x90 /* store host adapter local RAM */
+#define BHA_FETCH_LRAM 0x91 /* fetch host adapter local RAM */
+#define BHA_SAVE_TO_EEPROM 0x92 /* store local RAM data in EEPROM */
+#define BHA_UPLOAD_AUTOSCSI 0x94 /* upload AutoSCSI code */
+#define BHA_MODIFY_IOPORT 0x95 /* change or disable I/O port */
+#define BHA_SET_CCB_FORMAT 0x96 /* set CCB format (legacy/wide lun) */
+#define BHA_WRITE_INQUIRY_BUF 0x9a /* write inquiry buffer */
+#define BHA_READ_INQUIRY_BUF 0x9b /* read inquiry buffer */
+#define BHA_FLASH_UP_DOWNLOAD 0xa7 /* flash upload/downlod */
+#define BHA_READ_SCAM_DATA 0xa8 /* read SCAM data */
+#define BHA_WRITE_SCAM_DATA 0xa9 /* write SCAM data */
+
+/*
+ * BHA_INTR bits
+ */
+#define BHA_INTR_ANYINTR 0x80 /* Any interrupt */
+#define BHA_INTR_SCRD 0x08 /* SCSI reset detected */
+#define BHA_INTR_HACC 0x04 /* Command complete */
+#define BHA_INTR_MBOA 0x02 /* MBX out empty */
+#define BHA_INTR_MBIF 0x01 /* MBX in full */
+
+#pragma pack(1)
+
+struct bha_mbx_out {
+ physaddr ccb_addr;
+ u_int8_t reserved[3];
+ u_int8_t cmd;
+};
+
+struct bha_mbx_in {
+ physaddr ccb_addr;
+ u_int8_t host_stat;
+ u_int8_t target_stat;
+ u_int8_t reserved;
+ u_int8_t comp_stat;
+};
+
+/*
+ * mbo.cmd values
+ */
+#define BHA_MBO_FREE 0x0 /* MBO entry is free */
+#define BHA_MBO_START 0x1 /* MBO activate entry */
+#define BHA_MBO_ABORT 0x2 /* MBO abort entry */
+
+/*
+ * mbi.comp_stat values
+ */
+#define BHA_MBI_FREE 0x0 /* MBI entry is free */
+#define BHA_MBI_OK 0x1 /* completed without error */
+#define BHA_MBI_ABORT 0x2 /* aborted ccb */
+#define BHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
+#define BHA_MBI_ERROR 0x4 /* Completed with error */
+
+#if defined(BIG_DMA)
+WARNING...THIS WON'T WORK(won't fit on 1 page)
+#if 0
+#define BHA_NSEG 2048 /* Number of scatter gather segments - to much vm */
+#endif
+#define BHA_NSEG 128
+#else
+#define BHA_NSEG 33
+#endif /* BIG_DMA */
+
+struct bha_scat_gath {
+ physlen seg_len;
+ physaddr seg_addr;
+};
+
+struct bha_ccb {
+ u_int8_t opcode;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int8_t :3,
+ data_in :1,
+ data_out :1,
+ wide_tag_enable :1, /* Wide Lun CCB format */
+ wide_tag_type :2; /* Wide Lun CCB format */
+#else
+ u_int8_t wide_tag_type :2, /* Wide Lun CCB format */
+ wide_tag_enable :1, /* Wide Lun CCB format */
+ data_out :1,
+ data_in :1,
+ :3;
+#endif
+ u_int8_t scsi_cmd_length;
+ u_int8_t req_sense_length;
+ /*------------------------------------longword boundary */
+ physlen data_length;
+ /*------------------------------------longword boundary */
+ physaddr data_addr;
+ /*------------------------------------longword boundary */
+ u_int8_t reserved1[2];
+ u_int8_t host_stat;
+ u_int8_t target_stat;
+ /*------------------------------------longword boundary */
+ u_int8_t target;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int8_t lun :5,
+ tag_enable :1,
+ tag_type :2;
+#else
+ u_int8_t tag_type :2,
+ tag_enable :1,
+ lun :5;
+#endif
+ struct scsi_generic scsi_cmd;
+ u_int8_t reserved2[1];
+ u_int8_t link_id;
+ /*------------------------------------longword boundary */
+ physaddr link_addr;
+ /*------------------------------------longword boundary */
+ physaddr sense_ptr;
+/*-----end of HW fields-----------------------longword boundary */
+ struct scsi_sense_data scsi_sense;
+ /*------------------------------------longword boundary */
+ struct bha_scat_gath scat_gath[BHA_NSEG];
+ /*------------------------------------longword boundary */
+ TAILQ_ENTRY(bha_ccb) chain;
+ struct bha_ccb *nexthash;
+ bus_addr_t hashkey;
+
+ struct scsi_xfer *xs; /* the scsipi_xfer for this cmd */
+
+ int flags;
+#define CCB_ALLOC 0x01
+#define CCB_ABORT 0x02
+#ifdef BHADIAG
+#define CCB_SENDING 0x04
+#endif
+ int timeout;
+
+ /*
+ * This DMA map maps the buffer involved in the transfer.
+ * Its contents are loaded into "scat_gath" above.
+ */
+ bus_dmamap_t dmamap_xfer;
+};
+
+/*
+ * opcode fields
+ */
+#define BHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
+#define BHA_TARGET_CCB 0x01 /* SCSI Target CCB */
+#define BHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with S/G */
+#define BHA_INIT_RESID_CCB 0x03 /* SCSI Initiator w/ residual */
+#define BHA_INIT_RESID_SG_CCB 0x04 /* SCSI Initiator w/ residual and S/G */
+#define BHA_RESET_CCB 0x81 /* SCSI Bus reset */
+
+/*
+ * bha_ccb.host_stat values
+ */
+#define BHA_OK 0x00 /* cmd ok */
+#define BHA_LINK_OK 0x0a /* Link cmd ok */
+#define BHA_LINK_IT 0x0b /* Link cmd ok + int */
+#define BHA_DATA_UNDRN 0x0c /* data underrun error */
+#define BHA_SEL_TIMEOUT 0x11 /* Selection time out */
+#define BHA_OVER_UNDER 0x12 /* Data over/under run */
+#define BHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */
+#define BHA_INV_BUS 0x14 /* Invalid bus phase/sequence */
+#define BHA_BAD_MBO 0x15 /* Incorrect MBO cmd */
+#define BHA_BAD_CCB 0x16 /* Incorrect ccb opcode */
+#define BHA_BAD_LINK 0x17 /* Not same values of LUN for links */
+#define BHA_INV_TARGET 0x18 /* Invalid target direction */
+#define BHA_CCB_DUP 0x19 /* Duplicate CCB received */
+#define BHA_INV_CCB 0x1a /* Invalid CCB or segment list */
+#define BHA_AUTOSENSE_FAILED 0x1b /* auto REQUEST SENSE failed */
+#define BHA_TAGGED_MSG_REJ 0x1c /* tagged queueing message rejected */
+#define BHA_UNSUP_MSG_RECVD 0x1d /* unsupported message received */
+#define BHA_HARDWARE_FAILURE 0x20 /* host adapter hardware failure */
+#define BHA_TARG_IGNORED_ATN 0x21 /* target ignored ATN signal */
+#define BHA_HA_SCSI_BUS_RESET 0x22 /* host adapter asserted RST */
+#define BHA_OTHER_SCSI_BUS_RESET 0x23 /* other device asserted RST */
+#define BHA_BAD_RECONNECT 0x24 /* target reconnected improperly */
+#define BHA_HA_BUS_DEVICE_RESET 0x25 /* host adapter performed BDR */
+#define BHA_ABORT_QUEUE 0x26 /* abort queue generated */
+#define BHA_SOFTWARE_FAILURE 0x27 /* host adapter software failure */
+#define BHA_HARDWARE_WATCHDOG 0x30 /* host adapter watchdog timer fired */
+#define BHA_SCSI_PARITY_ERROR 0x34 /* SCSI parity error detected */
+
+struct bha_extended_inquire {
+ struct {
+ u_char opcode;
+ u_char len;
+ } cmd;
+ struct {
+ u_char bus_type; /* Type of bus connected to */
+#define BHA_BUS_TYPE_24BIT 'A' /* ISA bus */
+#define BHA_BUS_TYPE_32BIT 'E' /* EISA/VLB/PCI bus */
+#define BHA_BUS_TYPE_MCA 'M' /* MicroChannel bus */
+ u_char bios_address; /* Address of adapter BIOS */
+ u_short sg_limit;
+ u_char mbox_count;
+ u_char mbox_baseaddr[4]; /* packed/unaligned u_int32_t */
+ u_char intrflags;
+#define BHA_INTR_FASTEISA 0x04
+#define BHA_INTR_LEVEL 0x40 /* bit 6: level-sensitive interrupt */
+ u_char firmware_level[3]; /* last 3 digits of firmware rev */
+ u_char scsi_flags; /* supported SCSI features */
+#define BHA_SCSI_WIDE 0x01 /* host adapter is wide */
+#define BHA_SCSI_DIFFERENTIAL 0x02 /* host adapter is differential */
+#define BHA_SCSI_SCAM 0x04 /* host adapter supports SCAM */
+#define BHA_SCSI_ULTRA 0x08 /* host adapter supports Ultra */
+#define BHA_SCSI_TERMINATION 0x10 /* host adapter supports smart
+ termination */
+ } reply;
+};
+
+struct bha_config {
+ struct {
+ u_char opcode;
+ } cmd;
+ struct {
+ u_char chan;
+ u_char intr;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_char scsi_dev :3,
+ :5;
+#else
+ u_char :5,
+ scsi_dev :3;
+#endif
+ } reply;
+};
+
+struct bha_toggle {
+ struct {
+ u_char opcode;
+ u_char enable;
+ } cmd;
+};
+
+struct bha_mailbox {
+ struct {
+ u_char opcode;
+ u_char nmbx;
+ physaddr addr;
+ } cmd;
+};
+
+struct bha_model {
+ struct {
+ u_char opcode;
+ u_char len;
+ } cmd;
+ struct {
+ u_char id[4]; /* i.e bt742a -> '7','4','2','A' */
+ u_char version[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */
+ } reply;
+};
+
+struct bha_revision {
+ struct {
+ u_char opcode;
+ } cmd;
+ struct {
+ u_char board_type;
+ u_char custom_feature;
+ char firm_revision;
+ u_char firm_version;
+ } reply;
+};
+
+struct bha_digit {
+ struct {
+ u_char opcode;
+ } cmd;
+ struct {
+ u_char digit;
+ } reply;
+};
+
+struct bha_devices {
+ struct {
+ u_char opcode;
+ } cmd;
+ struct {
+ u_char lun_map[8];
+ } reply;
+};
+
+struct bha_sync {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_char offset :4,
+ period :3,
+ valid :1;
+#else
+ u_char valid :1,
+ period :3,
+ offset :4;
+#endif
+};
+
+struct bha_setup_reply {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int8_t sync_neg :1,
+ parity :1,
+ :6;
+#else
+ u_int8_t :6,
+ parity :1,
+ sync_neg :1;
+#endif
+ u_int8_t speed;
+ u_int8_t bus_on;
+ u_int8_t bus_off;
+ u_int8_t num_mbx;
+ u_int8_t mbx[3]; /*XXX */
+ /* doesn't make sense with 32bit addresses */
+ struct bha_sync sync[8];
+ u_int8_t disc_sts;
+};
+
+/* additional reply data supplied by wide controlers */
+struct bha_setup_reply_wide {
+ u_int8_t signature;
+ u_int8_t letter_d;
+ u_int8_t ha_type;
+ u_int8_t low_wide_allowed;
+ u_int8_t low_wide_active;
+ struct bha_sync sync_high[8];
+ u_int8_t high_disc_info;
+ u_int8_t reserved;
+ u_int8_t high_wide_allowed;
+ u_int8_t high_wide_active;
+};
+
+struct bha_setup {
+ struct {
+ u_char opcode;
+ u_char len;
+ } cmd;
+ struct bha_setup_reply reply;
+ struct bha_setup_reply_wide reply_w; /* for wide controllers */
+};
+
+struct bha_period_reply {
+ u_char period[8];
+};
+
+struct bha_period {
+ struct {
+ u_char opcode;
+ u_char len;
+ } cmd;
+ struct bha_period_reply reply;
+ struct bha_period_reply reply_w; /* for wide controllers */
+};
+
+struct bha_isadisable {
+ struct {
+ u_char opcode;
+ u_char modifier;
+ } cmd;
+};
+
+#pragma pack()
+
+/*
+ * bha_isadisable.modifier parameters
+ */
+#define BHA_IOMODIFY_330 0x00
+#define BHA_IOMODIFY_334 0x01
+#define BHA_IOMODIFY_DISABLE1 0x06
+#define BHA_IOMODIFY_DISABLE2 0x07
+
+#define INT9 0x01
+#define INT10 0x02
+#define INT11 0x04
+#define INT12 0x08
+#define INT14 0x20
+#define INT15 0x40
+
+#define EISADMA 0x00
+#define CHAN0 0x01
+#define CHAN5 0x20
+#define CHAN6 0x40
+#define CHAN7 0x80
diff --git a/sys/dev/ic/bhavar.h b/sys/dev/ic/bhavar.h
new file mode 100644
index 00000000000..3d5b763de78
--- /dev/null
+++ b/sys/dev/ic/bhavar.h
@@ -0,0 +1,135 @@
+/* $OpenBSD: bhavar.h,v 1.1 2002/01/24 22:38:03 mickey Exp $ */
+/* $NetBSD: bhavar.h,v 1.12 1998/11/19 21:53:00 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by 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.
+ */
+
+#include <sys/queue.h>
+
+/*
+ * Mail box defs etc.
+ * these could be bigger but we need the bha_softc to fit on a single page..
+ */
+#define BHA_MBX_SIZE 32 /* mail box size (MAX 255 MBxs) */
+ /* don't need that many really */
+#define BHA_CCB_MAX 32 /* store up to 32 CCBs at one time */
+#define CCB_HASH_SIZE 32 /* hash table size for phystokv */
+#define CCB_HASH_SHIFT 9
+#define CCB_HASH(x) ((((long)(x))>>CCB_HASH_SHIFT) & (CCB_HASH_SIZE - 1))
+
+#define bha_nextmbx(wmb, mbx, mbio) \
+ if ((wmb) == &(mbx)->mbio[BHA_MBX_SIZE - 1]) \
+ (wmb) = &(mbx)->mbio[0]; \
+ else \
+ (wmb)++;
+
+struct bha_mbx {
+ struct bha_mbx_out mbo[BHA_MBX_SIZE];
+ struct bha_mbx_in mbi[BHA_MBX_SIZE];
+ struct bha_mbx_out *cmbo; /* Collection Mail Box out */
+ struct bha_mbx_out *tmbo; /* Target Mail Box out */
+ struct bha_mbx_in *tmbi; /* Target Mail Box in */
+};
+
+struct bha_control {
+ struct bha_mbx bc_mbx; /* all our mailboxes */
+ struct bha_ccb bc_ccbs[BHA_CCB_MAX]; /* all our control blocks */
+};
+
+struct bha_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_dma_tag_t sc_dmat;
+ bus_dmamap_t sc_dmamap_control; /* maps the control structures */
+ int sc_dmaflags; /* bus-specific dma map flags */
+ void *sc_ih;
+
+ struct bha_control *sc_control; /* control structures */
+ int sc_iswide;
+
+#define wmbx (&sc->sc_control->bc_mbx)
+
+ struct bha_ccb *sc_ccbhash[CCB_HASH_SIZE];
+ TAILQ_HEAD(, bha_ccb) sc_free_ccb, sc_waiting_ccb;
+ int sc_mbofull;
+ struct scsi_link sc_link; /* prototype for devs */
+ struct scsi_adapter sc_adapter;
+
+ LIST_HEAD(, scsi_xfer) sc_queue;
+ struct scsi_xfer *sc_queuelast;
+
+ char sc_model[7],
+ sc_firmware[6];
+};
+
+/*
+ * Offset of a Mail Box In from the beginning of the control DMA mapping.
+ */
+#define BHA_MBI_OFF(m) (offsetof(struct bha_control, bc_mbx.mbi[0]) + \
+ (((u_long)(m)) - ((u_long)&wmbx->mbi[0])))
+
+/*
+ * Offset of a Mail Box Out from the beginning of the control DMA mapping.
+ */
+#define BHA_MBO_OFF(m) (offsetof(struct bha_control, bc_mbx.mbo[0]) + \
+ (((u_long)(m)) - ((u_long)&wmbx->mbo[0])))
+
+/*
+ * Offset of a CCB from the beginning of the control DMA mapping.
+ */
+#define BHA_CCB_OFF(c) (offsetof(struct bha_control, bc_ccbs[0]) + \
+ (((u_long)(c)) - ((u_long)&sc->sc_control->bc_ccbs[0])))
+
+struct bha_probe_data {
+ int sc_irq, sc_drq;
+ int sc_scsi_dev; /* adapters scsi id */
+ int sc_iswide; /* adapter is wide */
+};
+
+/*#define ISWIDE(sc) (sc->sc_link.max_target >= 8)*/
+
+int bha_cmd __P((bus_space_tag_t, bus_space_handle_t, struct bha_softc *,
+ int, u_char *, int, u_char *));
+int bha_find __P((bus_space_tag_t, bus_space_handle_t,
+ struct bha_probe_data *));
+void bha_attach __P((struct bha_softc *, struct bha_probe_data *));
+int bha_intr __P((void *));
+
+int bha_disable_isacompat __P((struct bha_softc *));
+void bha_inquire_setup_information __P((struct bha_softc *));
diff --git a/sys/dev/isa/aha.c b/sys/dev/isa/aha.c
index d7fbda87ccb..fbc80a59965 100644
--- a/sys/dev/isa/aha.c
+++ b/sys/dev/isa/aha.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aha.c,v 1.41 2001/12/08 02:24:07 art Exp $ */
+/* $OpenBSD: aha.c,v 1.42 2002/01/24 22:38:03 mickey Exp $ */
/* $NetBSD: aha.c,v 1.11 1996/05/12 23:51:23 mycroft Exp $ */
#undef AHADIAG
@@ -193,7 +193,7 @@ struct cfdriver aha_cd = {
#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
#define AHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
-#include "bt.h"
+#include "bha.h"
/*
* aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
@@ -348,7 +348,7 @@ ahaprobe(parent, match, aux)
void *match, *aux;
{
register struct isa_attach_args *ia = aux;
-#if NBT > 0
+#if NBHA > 0
extern int btports[], nbtports;
int i;
diff --git a/sys/dev/isa/bha_isa.c b/sys/dev/isa/bha_isa.c
new file mode 100644
index 00000000000..a920acf974a
--- /dev/null
+++ b/sys/dev/isa/bha_isa.c
@@ -0,0 +1,200 @@
+/* $OpenBSD: bha_isa.c,v 1.1 2002/01/24 22:38:03 mickey Exp $ */
+/* $NetBSD: bha_isa.c,v 1.14 1998/08/15 10:10:51 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
+
+#include <dev/ic/bhareg.h>
+#include <dev/ic/bhavar.h>
+
+#include "aha.h"
+#if NAHA > 0
+int btports[8]; /* cannot be more */
+int nbtports;
+#endif
+
+#define BHA_ISA_IOSIZE 4
+
+int bha_isa_probe __P((struct device *, void *, void *));
+void bha_isa_attach __P((struct device *, struct device *, void *));
+
+struct cfattach bha_isa_ca = {
+ sizeof(struct bha_softc), bha_isa_probe, bha_isa_attach
+};
+
+/*
+ * Check the slots looking for a board we recognise
+ * If we find one, note it's address (slot) and call
+ * the actual probe routine to check it out.
+ */
+int
+bha_isa_probe(parent, match, aux)
+ struct device *parent;
+ void *aux, *match;
+{
+ struct isa_attach_args *ia = aux;
+ bus_space_tag_t iot = ia->ia_iot;
+ bus_space_handle_t ioh;
+ struct bha_probe_data bpd;
+#if NAHA > 0
+ struct bha_digit digit;
+#endif
+ int rv;
+
+ /* Disallow wildcarded i/o address. */
+ if (ia->ia_iobase == IOBASEUNK)
+ return (0);
+
+ if (bus_space_map(iot, ia->ia_iobase, BHA_ISA_IOSIZE, 0, &ioh))
+ return (0);
+
+ rv = bha_find(iot, ioh, &bpd);
+
+#if NAHA > 0
+ if (rv) {
+ /* Adaptec 1542 cards do not support this */
+ digit.reply.digit = '@';
+ digit.cmd.opcode = BHA_INQUIRE_REVISION_3;
+ bha_cmd(iot, ioh, NULL, sizeof(digit.cmd), (u_char *)&digit.cmd,
+ sizeof(digit.reply), (u_char *)&digit.reply);
+ if (digit.reply.digit == '@')
+ return 1;
+ }
+#endif
+
+ bus_space_unmap(iot, ioh, BHA_ISA_IOSIZE);
+
+ if (rv) {
+ if (ia->ia_irq != -1 && ia->ia_irq != bpd.sc_irq)
+ return (0);
+ if (ia->ia_drq != -1 && ia->ia_drq != bpd.sc_drq)
+ return (0);
+ ia->ia_irq = bpd.sc_irq;
+ ia->ia_drq = bpd.sc_drq;
+ ia->ia_msize = 0;
+ ia->ia_iosize = BHA_ISA_IOSIZE;
+ }
+ return (rv);
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+void
+bha_isa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+ struct bha_softc *sc = (void *)self;
+ bus_space_tag_t iot = ia->ia_iot;
+ bus_space_handle_t ioh;
+ struct bha_probe_data bpd;
+ isa_chipset_tag_t ic = ia->ia_ic;
+#ifndef __OpenBSD__
+ int error;
+#endif
+
+ printf("\n");
+
+ if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) {
+ printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ sc->sc_iot = iot;
+ sc->sc_ioh = ioh;
+ sc->sc_dmat = ia->ia_dmat;
+ if (!bha_find(iot, ioh, &bpd)) {
+ printf("%s: bha_find failed\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ sc->sc_dmaflags = 0;
+ if (bpd.sc_drq != DRQUNK) {
+#ifdef __OpenBSD__
+ isa_dmacascade(ic, bpd.sc_drq);
+#else
+ if ((error = isa_dmacascade(ic, bpd.sc_drq)) != 0) {
+ printf("%s: unable to cascade DRQ, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return;
+ }
+#endif
+ } else {
+ /*
+ * We have a VLB controller. If we're at least both
+ * hardware revision E and firmware revision 3.37,
+ * we can do 32-bit DMA (earlier revisions are buggy
+ * in this regard).
+ */
+ bha_inquire_setup_information(sc);
+ if (strcmp(sc->sc_firmware, "3.37") < 0)
+ printf("%s: buggy VLB controller, disabling 32-bit DMA\n",
+ sc->sc_dev.dv_xname);
+ else
+ sc->sc_dmaflags = ISABUS_DMA_32BIT;
+ }
+
+ sc->sc_ih = isa_intr_establish(ic, bpd.sc_irq, IST_EDGE, IPL_BIO,
+ bha_intr, sc, sc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+
+ bha_attach(sc, &bpd);
+
+#if NAHA > 0
+ /* XXXX To avoid conflicting with the aha1542 probe */
+ btports[nbtports++] = ia->ia_iobase;
+#endif
+}
diff --git a/sys/dev/isa/bt.c b/sys/dev/isa/bt.c
deleted file mode 100644
index fa964e8736e..00000000000
--- a/sys/dev/isa/bt.c
+++ /dev/null
@@ -1,1347 +0,0 @@
-/* $OpenBSD: bt.c,v 1.24 2001/01/29 07:17:00 mickey Exp $ */
-/* $NetBSD: bt.c,v 1.10 1996/05/12 23:51:54 mycroft Exp $ */
-
-#undef BTDIAG
-#define integrate
-
-/*
- * Copyright (c) 1994, 1996 Charles M. Hannum. 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Charles M. Hannum.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR 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.
- */
-
-/*
- * 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.
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/errno.h>
-#include <sys/ioctl.h>
-#include <sys/device.h>
-#include <sys/malloc.h>
-#include <sys/buf.h>
-#include <sys/proc.h>
-#include <sys/user.h>
-
-#include <machine/intr.h>
-#include <machine/pio.h>
-
-#include <scsi/scsi_all.h>
-#include <scsi/scsiconf.h>
-
-#include <dev/isa/isavar.h>
-#include <dev/isa/isadmavar.h>
-#include <dev/isa/btreg.h>
-
-#ifndef DDB
-#define Debugger() panic("should call debugger here (bt742a.c)")
-#endif /* ! DDB */
-
-/*
- * Mail box defs etc.
- * these could be bigger but we need the bt_softc to fit on a single page..
- */
-#define BT_MBX_SIZE 32 /* mail box size (MAX 255 MBxs) */
- /* don't need that many really */
-#define BT_CCB_MAX 32 /* store up to 32 CCBs at one time */
-#define CCB_HASH_SIZE 32 /* hash table size for phystokv */
-#define CCB_HASH_SHIFT 9
-#define CCB_HASH(x) ((((long)(x))>>CCB_HASH_SHIFT) & (CCB_HASH_SIZE - 1))
-
-#define bt_nextmbx(wmb, mbx, mbio) \
- if ((wmb) == &(mbx)->mbio[BT_MBX_SIZE - 1]) \
- (wmb) = &(mbx)->mbio[0]; \
- else \
- (wmb)++;
-
-struct bt_mbx {
- struct bt_mbx_out mbo[BT_MBX_SIZE];
- struct bt_mbx_in mbi[BT_MBX_SIZE];
- struct bt_mbx_out *cmbo; /* Collection Mail Box out */
- struct bt_mbx_out *tmbo; /* Target Mail Box out */
- struct bt_mbx_in *tmbi; /* Target Mail Box in */
-};
-
-#define KVTOPHYS(x) vtophys(x)
-
-#include "aha.h"
-#include "bt.h"
-#if NAHA > 0
-int btports[NBT];
-int nbtports;
-#endif
-
-struct bt_softc {
- struct device sc_dev;
- struct isadev sc_id;
- void *sc_ih;
-
- int sc_iobase;
- int sc_irq, sc_drq;
-
- char sc_model[7],
- sc_firmware[6];
-
- struct bt_mbx sc_mbx; /* all our mailboxes */
-#define wmbx (&sc->sc_mbx)
- struct bt_ccb *sc_ccbhash[CCB_HASH_SIZE];
- TAILQ_HEAD(, bt_ccb) sc_free_ccb, sc_waiting_ccb;
- int sc_numccbs, sc_mbofull;
- int sc_scsi_dev; /* adapters scsi id */
- struct scsi_link sc_link; /* prototype for devs */
-};
-
-#ifdef BTDEBUG
-int bt_debug = 0;
-#endif /* BTDEBUG */
-
-int bt_cmd __P((int, struct bt_softc *, int, u_char *, int, u_char *));
-integrate void bt_finish_ccbs __P((struct bt_softc *));
-int btintr __P((void *));
-integrate void bt_reset_ccb __P((struct bt_softc *, struct bt_ccb *));
-void bt_free_ccb __P((struct bt_softc *, struct bt_ccb *));
-integrate void bt_init_ccb __P((struct bt_softc *, struct bt_ccb *));
-struct bt_ccb *bt_get_ccb __P((struct bt_softc *, int));
-struct bt_ccb *bt_ccb_phys_kv __P((struct bt_softc *, u_long));
-void bt_queue_ccb __P((struct bt_softc *, struct bt_ccb *));
-void bt_collect_mbo __P((struct bt_softc *));
-void bt_start_ccbs __P((struct bt_softc *));
-void bt_done __P((struct bt_softc *, struct bt_ccb *));
-int bt_find __P((struct isa_attach_args *, struct bt_softc *));
-void bt_init __P((struct bt_softc *));
-void bt_inquire_setup_information __P((struct bt_softc *));
-void btminphys __P((struct buf *));
-int bt_scsi_cmd __P((struct scsi_xfer *));
-int bt_poll __P((struct bt_softc *, struct scsi_xfer *, int));
-void bt_timeout __P((void *arg));
-
-struct scsi_adapter bt_switch = {
- bt_scsi_cmd,
- btminphys,
- 0,
- 0,
-};
-
-/* the below structure is so we have a default dev struct for out link struct */
-struct scsi_device bt_dev = {
- NULL, /* Use default error handler */
- NULL, /* have a queue, served by this */
- NULL, /* have no async handler */
- NULL, /* Use default 'done' routine */
-};
-
-int btprobe __P((struct device *, void *, void *));
-void btattach __P((struct device *, struct device *, void *));
-
-struct cfattach bt_ca = {
- sizeof(struct bt_softc), btprobe, btattach
-};
-
-struct cfdriver bt_cd = {
- NULL, "bt", DV_DULL
-};
-
-#define BT_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
-#define BT_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
-
-/*
- * bt_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
- *
- * Activate Adapter command
- * icnt: number of args (outbound bytes including opcode)
- * ibuf: argument buffer
- * ocnt: number of expected returned bytes
- * obuf: result buffer
- * wait: number of seconds to wait for response
- *
- * Performs an adapter command through the ports. Not to be confused with a
- * scsi command, which is read in via the dma; one of the adapter commands
- * tells it to read in a scsi command.
- */
-int
-bt_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
- int iobase;
- struct bt_softc *sc;
- int icnt, ocnt;
- u_char *ibuf, *obuf;
-{
- const char *name;
- register int i;
- int wait;
- u_char sts;
- u_char opcode = ibuf[0];
-
- if (sc != NULL)
- name = sc->sc_dev.dv_xname;
- else
- name = "(bt probe)";
-
- /*
- * Calculate a reasonable timeout for the command.
- */
- switch (opcode) {
- case BT_INQUIRE_DEVICES:
- wait = 15 * 20000;
- break;
- default:
- wait = 1 * 20000;
- break;
- }
-
- /*
- * Wait for the adapter to go idle, unless it's one of
- * the commands which don't need this
- */
- if (opcode != BT_MBO_INTR_EN) {
- for (i = 20000; i; i--) { /* 1 sec? */
- sts = inb(iobase + BT_STAT_PORT);
- if (sts & BT_STAT_IDLE)
- break;
- delay(50);
- }
- if (!i) {
- printf("%s: bt_cmd, host not idle(0x%x)\n",
- name, sts);
- return ENXIO;
- }
- }
- /*
- * Now that it is idle, if we expect output, preflush the
- * queue feeding to us.
- */
- if (ocnt) {
- while ((inb(iobase + BT_STAT_PORT)) & BT_STAT_DF)
- inb(iobase + BT_DATA_PORT);
- }
- /*
- * Output the command and the number of arguments given
- * for each byte, first check the port is empty.
- */
- while (icnt--) {
- for (i = wait; i; i--) {
- sts = inb(iobase + BT_STAT_PORT);
- if (!(sts & BT_STAT_CDF))
- break;
- delay(50);
- }
- if (!i) {
- if (opcode != BT_INQUIRE_REVISION &&
- opcode != BT_INQUIRE_REVISION_3)
- printf("%s: bt_cmd, cmd/data port full\n", name);
- outb(iobase + BT_CTRL_PORT, BT_CTRL_SRST);
- return ENXIO;
- }
- outb(iobase + BT_CMD_PORT, *ibuf++);
- }
- /*
- * If we expect input, loop that many times, each time,
- * looking for the data register to have valid data
- */
- while (ocnt--) {
- for (i = wait; i; i--) {
- sts = inb(iobase + BT_STAT_PORT);
- if (sts & BT_STAT_DF)
- break;
- delay(50);
- }
- if (!i) {
- if (opcode != BT_INQUIRE_REVISION &&
- opcode != BT_INQUIRE_REVISION_3)
- printf("%s: bt_cmd, cmd/data port empty %d\n",
- name, ocnt);
- outb(iobase + BT_CTRL_PORT, BT_CTRL_SRST);
- return ENXIO;
- }
- *obuf++ = inb(iobase + BT_DATA_PORT);
- }
- /*
- * Wait for the board to report a finished instruction.
- * We may get an extra interrupt for the HACC signal, but this is
- * unimportant.
- */
- if (opcode != BT_MBO_INTR_EN) {
- for (i = 20000; i; i--) { /* 1 sec? */
- sts = inb(iobase + BT_INTR_PORT);
- /* XXX Need to save this in the interrupt handler? */
- if (sts & BT_INTR_HACC)
- break;
- delay(50);
- }
- if (!i) {
- printf("%s: bt_cmd, host not finished(0x%x)\n",
- name, sts);
- return ENXIO;
- }
- }
- outb(iobase + BT_CTRL_PORT, BT_CTRL_IRST);
- return 0;
-}
-
-/*
- * Check if the device can be found at the port given
- * and if so, set it up ready for further work
- * as an argument, takes the isa_device structure from
- * autoconf.c
- */
-int
-btprobe(parent, match, aux)
- struct device *parent;
- void *match, *aux;
-{
- register struct isa_attach_args *ia = aux;
-
- /* See if there is a unit at this location. */
- if (bt_find(ia, NULL) != 0)
- return 0;
-
- ia->ia_msize = 0;
- ia->ia_iosize = 4;
- /* IRQ and DRQ set by bt_find(). */
- return 1;
-}
-
-/*
- * Attach all the sub-devices we can find
- */
-void
-btattach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
-{
- struct isa_attach_args *ia = aux;
- struct bt_softc *sc = (void *)self;
-
- if (bt_find(ia, sc) != 0)
- panic("btattach: bt_find of %s failed", self->dv_xname);
- sc->sc_iobase = ia->ia_iobase;
-
- if (sc->sc_drq != DRQUNK)
- isadma_cascade(sc->sc_drq);
-
- bt_inquire_setup_information(sc);
- bt_init(sc);
- TAILQ_INIT(&sc->sc_free_ccb);
- TAILQ_INIT(&sc->sc_waiting_ccb);
-
- /*
- * fill in the prototype scsi_link.
- */
- sc->sc_link.adapter_softc = sc;
- sc->sc_link.adapter_target = sc->sc_scsi_dev;
- sc->sc_link.adapter = &bt_switch;
- sc->sc_link.device = &bt_dev;
- sc->sc_link.openings = 4;
-
- sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE,
- IPL_BIO, btintr, sc, sc->sc_dev.dv_xname);
-
- /*
- * ask the adapter what subunits are present
- */
- config_found(self, &sc->sc_link, scsiprint);
-}
-
-integrate void
-bt_finish_ccbs(sc)
- struct bt_softc *sc;
-{
- struct bt_mbx_in *wmbi;
- struct bt_ccb *ccb;
- int i;
-
- wmbi = wmbx->tmbi;
-
- if (wmbi->stat == BT_MBI_FREE) {
- for (i = 0; i < BT_MBX_SIZE; i++) {
- if (wmbi->stat != BT_MBI_FREE) {
- printf("%s: mbi not in round-robin order\n",
- sc->sc_dev.dv_xname);
- goto AGAIN;
- }
- bt_nextmbx(wmbi, wmbx, mbi);
- }
-#ifdef BTDIAGnot
- printf("%s: mbi interrupt with no full mailboxes\n",
- sc->sc_dev.dv_xname);
-#endif
- return;
- }
-
-AGAIN:
- do {
- ccb = bt_ccb_phys_kv(sc, phystol(wmbi->ccb_addr));
- if (!ccb) {
- printf("%s: bad mbi ccb pointer; skipping\n",
- sc->sc_dev.dv_xname);
- goto next;
- }
-
-#ifdef BTDEBUG
- if (bt_debug) {
- u_char *cp = &ccb->scsi_cmd;
- printf("op=%x %x %x %x %x %x\n",
- cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
- printf("stat %x for mbi addr = 0x%08x, ",
- wmbi->stat, wmbi);
- printf("ccb addr = 0x%x\n", ccb);
- }
-#endif /* BTDEBUG */
-
- switch (wmbi->stat) {
- case BT_MBI_OK:
- case BT_MBI_ERROR:
- if ((ccb->flags & CCB_ABORT) != 0) {
- /*
- * If we already started an abort, wait for it
- * to complete before clearing the CCB. We
- * could instead just clear CCB_SENDING, but
- * what if the mailbox was already received?
- * The worst that happens here is that we clear
- * the CCB a bit later than we need to. BFD.
- */
- goto next;
- }
- break;
-
- case BT_MBI_ABORT:
- case BT_MBI_UNKNOWN:
- /*
- * Even if the CCB wasn't found, we clear it anyway.
- * See preceeding comment.
- */
- break;
-
- default:
- printf("%s: bad mbi status %02x; skipping\n",
- sc->sc_dev.dv_xname, wmbi->stat);
- goto next;
- }
-
- timeout_del(&ccb->xs->stimeout);
- bt_done(sc, ccb);
-
- next:
- wmbi->stat = BT_MBI_FREE;
- bt_nextmbx(wmbi, wmbx, mbi);
- } while (wmbi->stat != BT_MBI_FREE);
-
- wmbx->tmbi = wmbi;
-}
-
-/*
- * Catch an interrupt from the adaptor
- */
-int
-btintr(arg)
- void *arg;
-{
- struct bt_softc *sc = arg;
- int iobase = sc->sc_iobase;
- u_char sts;
-
-#ifdef BTDEBUG
- printf("%s: btintr ", sc->sc_dev.dv_xname);
-#endif /* BTDEBUG */
-
- /*
- * First acknowlege the interrupt, Then if it's not telling about
- * a completed operation just return.
- */
- sts = inb(iobase + BT_INTR_PORT);
- if ((sts & BT_INTR_ANYINTR) == 0)
- return 0;
- outb(iobase + BT_CTRL_PORT, BT_CTRL_IRST);
-
-#ifdef BTDIAG
- /* Make sure we clear CCB_SENDING before finishing a CCB. */
- bt_collect_mbo(sc);
-#endif
-
- /* Mail box out empty? */
- if (sts & BT_INTR_MBOA) {
- struct bt_toggle toggle;
-
- toggle.cmd.opcode = BT_MBO_INTR_EN;
- toggle.cmd.enable = 0;
- bt_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd, 0,
- (u_char *)0);
- bt_start_ccbs(sc);
- }
-
- /* Mail box in full? */
- if (sts & BT_INTR_MBIF)
- bt_finish_ccbs(sc);
-
- return 1;
-}
-
-integrate void
-bt_reset_ccb(sc, ccb)
- struct bt_softc *sc;
- struct bt_ccb *ccb;
-{
-
- ccb->flags = 0;
-}
-
-/*
- * A ccb is put onto the free list.
- */
-void
-bt_free_ccb(sc, ccb)
- struct bt_softc *sc;
- struct bt_ccb *ccb;
-{
- int s;
-
- s = splbio();
-
- bt_reset_ccb(sc, ccb);
- TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
-
- /*
- * If there were none, wake anybody waiting for one to come free,
- * starting with queued entries.
- */
- if (ccb->chain.tqe_next == 0)
- wakeup(&sc->sc_free_ccb);
-
- splx(s);
-}
-
-integrate void
-bt_init_ccb(sc, ccb)
- struct bt_softc *sc;
- struct bt_ccb *ccb;
-{
- int hashnum;
-
- bzero(ccb, sizeof(struct bt_ccb));
- /*
- * put in the phystokv hash table
- * Never gets taken out.
- */
- ccb->hashkey = KVTOPHYS(ccb);
- hashnum = CCB_HASH(ccb->hashkey);
- ccb->nexthash = sc->sc_ccbhash[hashnum];
- sc->sc_ccbhash[hashnum] = ccb;
- bt_reset_ccb(sc, ccb);
-}
-
-/*
- * Get a free ccb
- *
- * If there are none, see if we can allocate a new one. If so, put it in
- * the hash table too otherwise either return an error or sleep.
- */
-struct bt_ccb *
-bt_get_ccb(sc, flags)
- struct bt_softc *sc;
- int flags;
-{
- struct bt_ccb *ccb;
- int s;
-
- s = splbio();
-
- /*
- * If we can and have to, sleep waiting for one to come free
- * but only if we can't allocate a new one.
- */
- for (;;) {
- ccb = sc->sc_free_ccb.tqh_first;
- if (ccb) {
- TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
- break;
- }
- if (sc->sc_numccbs < BT_CCB_MAX) {
- ccb = (struct bt_ccb *) malloc(sizeof(struct bt_ccb),
- M_TEMP, M_NOWAIT);
- if (!ccb) {
- printf("%s: can't malloc ccb\n",
- sc->sc_dev.dv_xname);
- goto out;
- }
- bt_init_ccb(sc, ccb);
- sc->sc_numccbs++;
- break;
- }
- if ((flags & SCSI_NOSLEEP) != 0)
- goto out;
- tsleep(&sc->sc_free_ccb, PRIBIO, "btccb", 0);
- }
-
- ccb->flags |= CCB_ALLOC;
-
-out:
- splx(s);
- return ccb;
-}
-
-/*
- * Given a physical address, find the ccb that it corresponds to.
- */
-struct bt_ccb *
-bt_ccb_phys_kv(sc, ccb_phys)
- struct bt_softc *sc;
- u_long ccb_phys;
-{
- int hashnum = CCB_HASH(ccb_phys);
- struct bt_ccb *ccb = sc->sc_ccbhash[hashnum];
-
- while (ccb) {
- if (ccb->hashkey == ccb_phys)
- break;
- ccb = ccb->nexthash;
- }
- return ccb;
-}
-
-/*
- * Queue a CCB to be sent to the controller, and send it if possible.
- */
-void
-bt_queue_ccb(sc, ccb)
- struct bt_softc *sc;
- struct bt_ccb *ccb;
-{
-
- TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
- bt_start_ccbs(sc);
-}
-
-/*
- * Garbage collect mailboxes that are no longer in use.
- */
-void
-bt_collect_mbo(sc)
- struct bt_softc *sc;
-{
- struct bt_mbx_out *wmbo; /* Mail Box Out pointer */
-#ifdef BTDIAG
- struct bt_ccb *ccb;
-#endif
- wmbo = wmbx->cmbo;
-
- while (sc->sc_mbofull > 0) {
- if (wmbo->cmd != BT_MBO_FREE)
- break;
-
-#ifdef BTDIAG
- ccb = bt_ccb_phys_kv(sc, phystol(wmbo->ccb_addr));
- ccb->flags &= ~CCB_SENDING;
-#endif
-
- --sc->sc_mbofull;
- bt_nextmbx(wmbo, wmbx, mbo);
- }
-
- wmbx->cmbo = wmbo;
-}
-
-/*
- * Send as many CCBs as we have empty mailboxes for.
- */
-void
-bt_start_ccbs(sc)
- struct bt_softc *sc;
-{
- int iobase = sc->sc_iobase;
- struct bt_mbx_out *wmbo; /* Mail Box Out pointer */
- struct bt_ccb *ccb;
-
- wmbo = wmbx->tmbo;
-
- while ((ccb = sc->sc_waiting_ccb.tqh_first) != NULL) {
- if (sc->sc_mbofull >= BT_MBX_SIZE) {
- bt_collect_mbo(sc);
- if (sc->sc_mbofull >= BT_MBX_SIZE) {
- struct bt_toggle toggle;
-
- toggle.cmd.opcode = BT_MBO_INTR_EN;
- toggle.cmd.enable = 1;
- bt_cmd(iobase, sc, sizeof(toggle.cmd),
- (u_char *)&toggle.cmd, 0, (u_char *)0);
- break;
- }
- }
-
- TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
-#ifdef BTDIAG
- ccb->flags |= CCB_SENDING;
-#endif
-
- /* Link ccb to mbo. */
- ltophys(KVTOPHYS(ccb), wmbo->ccb_addr);
- if (ccb->flags & CCB_ABORT)
- wmbo->cmd = BT_MBO_ABORT;
- else
- wmbo->cmd = BT_MBO_START;
-
- /* Tell the card to poll immediately. */
- outb(iobase + BT_CMD_PORT, BT_START_SCSI);
-
- if ((ccb->xs->flags & SCSI_POLL) == 0) {
- timeout_set(&ccb->xs->stimeout, bt_timeout, ccb);
- timeout_add(&ccb->xs->stimeout, (ccb->timeout * hz) / 1000);
- }
-
- ++sc->sc_mbofull;
- bt_nextmbx(wmbo, wmbx, mbo);
- }
-
- wmbx->tmbo = wmbo;
-}
-
-/*
- * We have a ccb which has been processed by the
- * adaptor, now we look to see how the operation
- * went. Wake up the owner if waiting
- */
-void
-bt_done(sc, ccb)
- struct bt_softc *sc;
- struct bt_ccb *ccb;
-{
- struct scsi_sense_data *s1, *s2;
- struct scsi_xfer *xs = ccb->xs;
-
- SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_done\n"));
- /*
- * Otherwise, put the results of the operation
- * into the xfer and call whoever started it
- */
-#ifdef BTDIAG
- if (ccb->flags & CCB_SENDING) {
- printf("%s: exiting ccb still in transit!\n", sc->sc_dev.dv_xname);
- Debugger();
- return;
- }
-#endif
- if ((ccb->flags & CCB_ALLOC) == 0) {
- printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
- Debugger();
- return;
- }
- if (xs->error == XS_NOERROR) {
- if (ccb->host_stat != BT_OK) {
- switch (ccb->host_stat) {
- case BT_SEL_TIMEOUT: /* No response */
- xs->error = XS_SELTIMEOUT;
- break;
- default: /* Other scsi protocol messes */
- printf("%s: host_stat %x\n",
- sc->sc_dev.dv_xname, ccb->host_stat);
- xs->error = XS_DRIVER_STUFFUP;
- break;
- }
- } else if (ccb->target_stat != SCSI_OK) {
- switch (ccb->target_stat) {
- case SCSI_CHECK:
- s1 = &ccb->scsi_sense;
- s2 = &xs->sense;
- *s2 = *s1;
- xs->error = XS_SENSE;
- break;
- case SCSI_BUSY:
- xs->error = XS_BUSY;
- break;
- default:
- printf("%s: target_stat %x\n",
- sc->sc_dev.dv_xname, ccb->target_stat);
- xs->error = XS_DRIVER_STUFFUP;
- break;
- }
- } else
- xs->resid = 0;
- }
- bt_free_ccb(sc, ccb);
- xs->flags |= ITSDONE;
- scsi_done(xs);
-}
-
-/*
- * Find the board and find it's irq/drq
- */
-int
-bt_find(ia, sc)
- struct isa_attach_args *ia;
- struct bt_softc *sc;
-{
- int iobase = ia->ia_iobase;
- int i;
- u_char sts;
- struct bt_extended_inquire inquire;
- struct bt_config config;
-#if NAHA > 0
- struct bt_digit digit;
-#endif
- int irq, drq;
-
- /*
- * reset board, If it doesn't respond, assume
- * that it's not there.. good for the probe
- */
-
- outb(iobase + BT_CTRL_PORT, BT_CTRL_HRST | BT_CTRL_SRST);
-
- delay(100);
- for (i = BT_RESET_TIMEOUT; i; i--) {
- sts = inb(iobase + BT_STAT_PORT);
- if (sts == (BT_STAT_IDLE | BT_STAT_INIT))
- break;
- delay(1000);
- }
- if (!i) {
-#ifdef BTDEBUG
- if (bt_debug)
- printf("bt_find: No answer from buslogic board\n");
-#endif /* BTDEBUG */
- return 1;
- }
-
- /*
- * Check that we actually know how to use this board.
- */
- delay(1000);
- bzero(&inquire, sizeof inquire);
- inquire.cmd.opcode = BT_INQUIRE_EXTENDED;
- inquire.cmd.len = sizeof(inquire.reply);
- bt_cmd(iobase, sc, sizeof(inquire.cmd), (u_char *)&inquire.cmd,
- sizeof(inquire.reply), (u_char *)&inquire.reply);
- switch (inquire.reply.bus_type) {
- case BT_BUS_TYPE_24BIT:
- case BT_BUS_TYPE_32BIT:
- break;
- case BT_BUS_TYPE_MCA:
- /* We don't grok MicroChannel (yet). */
- return 1;
- default:
- if (inquire.reply.bus_type != 'F')
- printf("bt_find: illegal bus type %c\n",
- inquire.reply.bus_type);
- return 1;
- }
-
-#if NAHA > 0
- /* Adaptec 1542 cards do not support this */
- digit.reply.digit = '@';
- digit.cmd.opcode = BT_INQUIRE_REVISION_3;
- bt_cmd(iobase, sc, sizeof(digit.cmd), (u_char *)&digit.cmd,
- sizeof(digit.reply), (u_char *)&digit.reply);
- if (digit.reply.digit == '@')
- return 1;
-#endif
-
- /*
- * Assume we have a board at this stage setup dma channel from
- * jumpers and save int level
- */
- delay(1000);
- config.cmd.opcode = BT_INQUIRE_CONFIG;
- bt_cmd(iobase, sc, sizeof(config.cmd), (u_char *)&config.cmd,
- sizeof(config.reply), (u_char *)&config.reply);
- switch (config.reply.chan) {
- case EISADMA:
- drq = DRQUNK;
- break;
- case CHAN0:
- drq = 0;
- break;
- case CHAN5:
- drq = 5;
- break;
- case CHAN6:
- drq = 6;
- break;
- case CHAN7:
- drq = 7;
- break;
- default:
- printf("bt_find: illegal drq setting %x\n", config.reply.chan);
- return 1;
- }
-
- switch (config.reply.intr) {
- case INT9:
- irq = 9;
- break;
- case INT10:
- irq = 10;
- break;
- case INT11:
- irq = 11;
- break;
- case INT12:
- irq = 12;
- break;
- case INT14:
- irq = 14;
- break;
- case INT15:
- irq = 15;
- break;
- default:
- printf("bt_find: illegal irq setting %x\n", config.reply.intr);
- return 1;
- }
-
- if (sc != NULL) {
- /* who are we on the scsi bus? */
- sc->sc_scsi_dev = config.reply.scsi_dev;
-
- sc->sc_iobase = iobase;
- sc->sc_irq = irq;
- sc->sc_drq = drq;
- } else {
- if (ia->ia_irq == IRQUNK)
- ia->ia_irq = irq;
- else if (ia->ia_irq != irq)
- return 1;
- if (ia->ia_drq == DRQUNK)
- ia->ia_drq = drq;
- else if (ia->ia_drq != drq)
- return 1;
- }
-
-#if NAHA > 0
- /* XXXX To avoid conflicting with the aha1542 probe */
- btports[nbtports++] = iobase;
-#endif
- return 0;
-}
-
-/*
- * Start the board, ready for normal operation
- */
-void
-bt_init(sc)
- struct bt_softc *sc;
-{
- int iobase = sc->sc_iobase;
- struct bt_devices devices;
- struct bt_setup setup;
- struct bt_mailbox mailbox;
- struct bt_period period;
- int i;
-
- /* Enable round-robin scheme - appeared at firmware rev. 3.31. */
- if (strcmp(sc->sc_firmware, "3.31") >= 0) {
- struct bt_toggle toggle;
-
- toggle.cmd.opcode = BT_ROUND_ROBIN;
- toggle.cmd.enable = 1;
- bt_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd,
- 0, (u_char *)0);
- }
-
- /* Inquire Installed Devices (to force synchronous negotiation). */
- devices.cmd.opcode = BT_INQUIRE_DEVICES;
- bt_cmd(iobase, sc, sizeof(devices.cmd), (u_char *)&devices.cmd,
- sizeof(devices.reply), (u_char *)&devices.reply);
-
- /* Obtain setup information from. */
- setup.cmd.opcode = BT_INQUIRE_SETUP;
- setup.cmd.len = sizeof(setup.reply);
- bt_cmd(iobase, sc, sizeof(setup.cmd), (u_char *)&setup.cmd,
- sizeof(setup.reply), (u_char *)&setup.reply);
-
- printf("%s: %s, %s\n",
- sc->sc_dev.dv_xname,
- setup.reply.sync_neg ? "sync" : "async",
- setup.reply.parity ? "parity" : "no parity");
-
- for (i = 0; i < 8; i++)
- period.reply.period[i] = setup.reply.sync[i].period * 5 + 20;
-
- if (sc->sc_firmware[0] >= '3') {
- period.cmd.opcode = BT_INQUIRE_PERIOD;
- period.cmd.len = sizeof(period.reply);
- bt_cmd(iobase, sc, sizeof(period.cmd), (u_char *)&period.cmd,
- sizeof(period.reply), (u_char *)&period.reply);
- }
-
- for (i = 0; i < 8; i++) {
- if (!setup.reply.sync[i].valid ||
- (!setup.reply.sync[i].offset && !setup.reply.sync[i].period))
- continue;
- printf("%s targ %d: sync, offset %d, period %dnsec\n",
- sc->sc_dev.dv_xname, i,
- setup.reply.sync[i].offset, period.reply.period[i] * 10);
- }
-
- /*
- * Set up initial mail box for round-robin operation.
- */
- for (i = 0; i < BT_MBX_SIZE; i++) {
- wmbx->mbo[i].cmd = BT_MBO_FREE;
- wmbx->mbi[i].stat = BT_MBI_FREE;
- }
- wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0];
- wmbx->tmbi = &wmbx->mbi[0];
- sc->sc_mbofull = 0;
-
- /* Initialize mail box. */
- mailbox.cmd.opcode = BT_MBX_INIT_EXTENDED;
- mailbox.cmd.nmbx = BT_MBX_SIZE;
- ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr);
- bt_cmd(iobase, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
- 0, (u_char *)0);
-}
-
-void
-bt_inquire_setup_information(sc)
- struct bt_softc *sc;
-{
- int iobase = sc->sc_iobase;
- struct bt_model model;
- struct bt_revision revision;
- struct bt_digit digit;
- char *p;
-
- /*
- * Get the firmware revision.
- */
- p = sc->sc_firmware;
- revision.cmd.opcode = BT_INQUIRE_REVISION;
- bt_cmd(iobase, sc, sizeof(revision.cmd), (u_char *)&revision.cmd,
- sizeof(revision.reply), (u_char *)&revision.reply);
- *p++ = revision.reply.firm_revision;
- *p++ = '.';
- *p++ = revision.reply.firm_version;
- digit.cmd.opcode = BT_INQUIRE_REVISION_3;
- bt_cmd(iobase, sc, sizeof(digit.cmd), (u_char *)&digit.cmd,
- sizeof(digit.reply), (u_char *)&digit.reply);
- *p++ = digit.reply.digit;
- if (revision.reply.firm_revision >= '3' ||
- (revision.reply.firm_revision == '3' && revision.reply.firm_version >= '3')) {
- digit.cmd.opcode = BT_INQUIRE_REVISION_4;
- bt_cmd(iobase, sc, sizeof(digit.cmd), (u_char *)&digit.cmd,
- sizeof(digit.reply), (u_char *)&digit.reply);
- *p++ = digit.reply.digit;
- }
- while (p > sc->sc_firmware && (p[-1] == ' ' || p[-1] == '\0'))
- p--;
- *p = '\0';
-
- /*
- * Get the model number.
- */
- if (revision.reply.firm_revision >= '3') {
- p = sc->sc_model;
- model.cmd.opcode = BT_INQUIRE_MODEL;
- model.cmd.len = sizeof(model.reply);
- bt_cmd(iobase, sc, sizeof(model.cmd), (u_char *)&model.cmd,
- sizeof(model.reply), (u_char *)&model.reply);
- *p++ = model.reply.id[0];
- *p++ = model.reply.id[1];
- *p++ = model.reply.id[2];
- *p++ = model.reply.id[3];
- while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0'))
- p--;
- *p++ = model.reply.version[0];
- *p++ = model.reply.version[1];
- while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0'))
- p--;
- *p = '\0';
- } else
- strcpy(sc->sc_model, "542B");
-
- printf(": model BT-%s, firmware %s\n", sc->sc_model, sc->sc_firmware);
-}
-
-void
-btminphys(bp)
- struct buf *bp;
-{
-
- if (bp->b_bcount > ((BT_NSEG - 1) << PGSHIFT))
- bp->b_bcount = ((BT_NSEG - 1) << PGSHIFT);
- minphys(bp);
-}
-
-/*
- * start a scsi operation given the command and the data address. Also needs
- * the unit, target and lu.
- */
-int
-bt_scsi_cmd(xs)
- struct scsi_xfer *xs;
-{
- struct scsi_link *sc_link = xs->sc_link;
- struct bt_softc *sc = sc_link->adapter_softc;
- struct bt_ccb *ccb;
- struct bt_scat_gath *sg;
- int seg; /* scatter gather seg being worked on */
- u_long thiskv, thisphys, nextphys;
- int bytes_this_seg, bytes_this_page, datalen, flags;
-#ifdef TFS
- struct iovec *iovp;
-#endif
- int s;
-
- SC_DEBUG(sc_link, SDEV_DB2, ("bt_scsi_cmd\n"));
- /*
- * get a ccb to use. If the transfer
- * is from a buf (possibly from interrupt time)
- * then we can't allow it to sleep
- */
- flags = xs->flags;
- if ((ccb = bt_get_ccb(sc, flags)) == NULL) {
- xs->error = XS_DRIVER_STUFFUP;
- return TRY_AGAIN_LATER;
- }
- ccb->xs = xs;
- ccb->timeout = xs->timeout;
-
- /*
- * Put all the arguments for the xfer in the ccb
- */
- if (flags & SCSI_RESET) {
- ccb->opcode = BT_RESET_CCB;
- ccb->scsi_cmd_length = 0;
- } else {
- /* can't use S/G if zero length */
- ccb->opcode = (xs->datalen ? BT_INIT_SCAT_GATH_CCB
- : BT_INITIATOR_CCB);
- bcopy(xs->cmd, &ccb->scsi_cmd,
- ccb->scsi_cmd_length = xs->cmdlen);
- }
-
- if (xs->datalen) {
- sg = ccb->scat_gath;
- seg = 0;
-#ifdef TFS
- if (flags & SCSI_DATA_UIO) {
- iovp = ((struct uio *)xs->data)->uio_iov;
- datalen = ((struct uio *)xs->data)->uio_iovcnt;
- xs->datalen = 0;
- while (datalen && seg < BT_NSEG) {
- ltophys(iovp->iov_base, sg->seg_addr);
- ltophys(iovp->iov_len, sg->seg_len);
- xs->datalen += iovp->iov_len;
- SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
- iovp->iov_len, iovp->iov_base));
- sg++;
- iovp++;
- seg++;
- datalen--;
- }
- } else
-#endif /* TFS */
- {
- /*
- * Set up the scatter-gather block.
- */
- SC_DEBUG(sc_link, SDEV_DB4,
- ("%d @0x%x:- ", xs->datalen, xs->data));
-
- datalen = xs->datalen;
- thiskv = (int)xs->data;
- thisphys = KVTOPHYS(thiskv);
-
- while (datalen && seg < BT_NSEG) {
- bytes_this_seg = 0;
-
- /* put in the base address */
- ltophys(thisphys, sg->seg_addr);
-
- SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
-
- /* do it at least once */
- nextphys = thisphys;
- while (datalen && thisphys == nextphys) {
- /*
- * This page is contiguous (physically)
- * with the the last, just extend the
- * length
- */
- /* how far to the end of the page */
- nextphys = (thisphys & ~PGOFSET) + NBPG;
- bytes_this_page = nextphys - thisphys;
- /**** or the data ****/
- bytes_this_page = min(bytes_this_page,
- datalen);
- bytes_this_seg += bytes_this_page;
- datalen -= bytes_this_page;
-
- /* get more ready for the next page */
- thiskv = (thiskv & ~PGOFSET) + NBPG;
- if (datalen)
- thisphys = KVTOPHYS(thiskv);
- }
- /*
- * next page isn't contiguous, finish the seg
- */
- SC_DEBUGN(sc_link, SDEV_DB4,
- ("(0x%x)", bytes_this_seg));
- ltophys(bytes_this_seg, sg->seg_len);
- sg++;
- seg++;
- }
- }
- /* end of iov/kv decision */
- SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
- if (datalen) {
- /*
- * there's still data, must have run out of segs!
- */
- printf("%s: bt_scsi_cmd, more than %d dma segs\n",
- sc->sc_dev.dv_xname, BT_NSEG);
- goto bad;
- }
- ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
- ltophys(seg * sizeof(struct bt_scat_gath), ccb->data_length);
- } else { /* No data xfer, use non S/G values */
- ltophys(0, ccb->data_addr);
- ltophys(0, ccb->data_length);
- }
-
- ccb->data_out = 0;
- ccb->data_in = 0;
- ccb->target = sc_link->target;
- ccb->lun = sc_link->lun;
- ltophys(KVTOPHYS(&ccb->scsi_sense), ccb->sense_ptr);
- ccb->req_sense_length = sizeof(ccb->scsi_sense);
- ccb->host_stat = 0x00;
- ccb->target_stat = 0x00;
- ccb->link_id = 0;
- ltophys(0, ccb->link_addr);
-
- s = splbio();
- bt_queue_ccb(sc, ccb);
- splx(s);
-
- /*
- * Usually return SUCCESSFULLY QUEUED
- */
- SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
- if ((flags & SCSI_POLL) == 0)
- return SUCCESSFULLY_QUEUED;
-
- /*
- * If we can't use interrupts, poll on completion
- */
- if (bt_poll(sc, xs, ccb->timeout)) {
- bt_timeout(ccb);
- if (bt_poll(sc, xs, ccb->timeout))
- bt_timeout(ccb);
- }
- return COMPLETE;
-
-bad:
- xs->error = XS_DRIVER_STUFFUP;
- bt_free_ccb(sc, ccb);
- return COMPLETE;
-}
-
-/*
- * Poll a particular unit, looking for a particular xs
- */
-int
-bt_poll(sc, xs, count)
- struct bt_softc *sc;
- struct scsi_xfer *xs;
- int count;
-{
- int iobase = sc->sc_iobase;
-
- /* timeouts are in msec, so we loop in 1000 usec cycles */
- while (count) {
- /*
- * If we had interrupts enabled, would we
- * have got an interrupt?
- */
- if (inb(iobase + BT_INTR_PORT) & BT_INTR_ANYINTR)
- btintr(sc);
- if (xs->flags & ITSDONE)
- return 0;
- delay(1000); /* only happens in boot so ok */
- count--;
- }
- return 1;
-}
-
-void
-bt_timeout(arg)
- void *arg;
-{
- struct bt_ccb *ccb = arg;
- struct scsi_xfer *xs = ccb->xs;
- struct scsi_link *sc_link = xs->sc_link;
- struct bt_softc *sc = sc_link->adapter_softc;
- int s;
-
- sc_print_addr(sc_link);
- printf("timed out");
-
- s = splbio();
-
-#ifdef BTDIAG
- /*
- * If the ccb's mbx is not free, then the board has gone Far East?
- */
- bt_collect_mbo(sc);
- if (ccb->flags & CCB_SENDING) {
- printf("%s: not taking commands!\n", sc->sc_dev.dv_xname);
- Debugger();
- }
-#endif
-
- /*
- * If it has been through before, then
- * a previous abort has failed, don't
- * try abort again
- */
- if (ccb->flags & CCB_ABORT) {
- /* abort timed out */
- printf(" AGAIN\n");
- /* XXX Must reset! */
- } else {
- /* abort the operation that has timed out */
- printf("\n");
- ccb->xs->error = XS_TIMEOUT;
- ccb->timeout = BT_ABORT_TIMEOUT;
- ccb->flags |= CCB_ABORT;
- bt_queue_ccb(sc, ccb);
- }
-
- splx(s);
-}
diff --git a/sys/dev/isa/btreg.h b/sys/dev/isa/btreg.h
deleted file mode 100644
index 720a971d499..00000000000
--- a/sys/dev/isa/btreg.h
+++ /dev/null
@@ -1,310 +0,0 @@
-/* $OpenBSD: btreg.h,v 1.5 1997/11/07 08:06:43 niklas Exp $ */
-
-typedef u_int8_t physaddr[4];
-typedef u_int8_t physlen[4];
-#define ltophys _lto4l
-#define phystol _4ltol
-
-/*
- * I/O port offsets
- */
-#define BT_CTRL_PORT 0 /* control (wo) */
-#define BT_STAT_PORT 0 /* status (ro) */
-#define BT_CMD_PORT 1 /* command (wo) */
-#define BT_DATA_PORT 1 /* data (ro) */
-#define BT_INTR_PORT 2 /* interrupt status (ro) */
-
-/*
- * BT_CTRL bits
- */
-#define BT_CTRL_HRST 0x80 /* Hardware reset */
-#define BT_CTRL_SRST 0x40 /* Software reset */
-#define BT_CTRL_IRST 0x20 /* Interrupt reset */
-#define BT_CTRL_SCRST 0x10 /* SCSI bus reset */
-
-/*
- * BT_STAT bits
- */
-#define BT_STAT_STST 0x80 /* Self test in Progress */
-#define BT_STAT_DIAGF 0x40 /* Diagnostic Failure */
-#define BT_STAT_INIT 0x20 /* Mbx Init required */
-#define BT_STAT_IDLE 0x10 /* Host Adapter Idle */
-#define BT_STAT_CDF 0x08 /* cmd/data out port full */
-#define BT_STAT_DF 0x04 /* Data in port full */
-#define BT_STAT_INVDCMD 0x01 /* Invalid command */
-
-/*
- * BT_CMD opcodes
- */
-#define BT_NOP 0x00 /* No operation */
-#define BT_MBX_INIT 0x01 /* Mbx initialization */
-#define BT_START_SCSI 0x02 /* start scsi command */
-#define BT_INQUIRE_REVISION 0x04 /* Adapter Inquiry */
-#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
-#if 0
-#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
-#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */
-#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
-#define BT_SPEED_SET 0x09 /* set transfer speed */
-#endif
-#define BT_INQUIRE_DEVICES 0x0a /* return installed devices 0-7 */
-#define BT_INQUIRE_CONFIG 0x0b /* return configuration data */
-#define BT_TARGET_EN 0x0c /* enable target mode */
-#define BT_INQUIRE_SETUP 0x0d /* return setup data */
-#define BT_ECHO 0x1e /* Echo command data */
-#define BT_INQUIRE_DEVICES_2 0x23 /* return installed devices 8-15 */
-#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */
-#define BT_INQUIRE_REVISION_3 0x84 /* Get 3rd firmware version byte */
-#define BT_INQUIRE_REVISION_4 0x85 /* Get 4th firmware version byte */
-#define BT_INQUIRE_MODEL 0x8b /* Get hardware ID and revision */
-#define BT_INQUIRE_PERIOD 0x8c /* Get synchronous period */
-#define BT_INQUIRE_EXTENDED 0x8d /* Adapter Setup Inquiry */
-#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */
-
-/*
- * BT_INTR bits
- */
-#define BT_INTR_ANYINTR 0x80 /* Any interrupt */
-#define BT_INTR_SCRD 0x08 /* SCSI reset detected */
-#define BT_INTR_HACC 0x04 /* Command complete */
-#define BT_INTR_MBOA 0x02 /* MBX out empty */
-#define BT_INTR_MBIF 0x01 /* MBX in full */
-
-struct bt_mbx_out {
- physaddr ccb_addr;
- u_char dummy[3];
- u_char cmd;
-};
-
-struct bt_mbx_in {
- physaddr ccb_addr;
- u_char dummy[3];
- u_char stat;
-};
-
-/*
- * mbo.cmd values
- */
-#define BT_MBO_FREE 0x0 /* MBO entry is free */
-#define BT_MBO_START 0x1 /* MBO activate entry */
-#define BT_MBO_ABORT 0x2 /* MBO abort entry */
-
-/*
- * mbi.stat values
- */
-#define BT_MBI_FREE 0x0 /* MBI entry is free */
-#define BT_MBI_OK 0x1 /* completed without error */
-#define BT_MBI_ABORT 0x2 /* aborted ccb */
-#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
-#define BT_MBI_ERROR 0x4 /* Completed with error */
-
-#if defined(BIG_DMA)
-WARNING...THIS WON'T WORK(won't fit on 1 page)
-#if 0
-#define BT_NSEG 2048 /* Number of scatter gather segments - to much vm */
-#endif
-#define BT_NSEG 128
-#else
-#define BT_NSEG 33
-#endif /* BIG_DMA */
-
-struct bt_scat_gath {
- physlen seg_len;
- physaddr seg_addr;
-};
-
-struct bt_ccb {
- u_char opcode;
- u_char:3, data_in:1, data_out:1,:3;
- u_char scsi_cmd_length;
- u_char req_sense_length;
- /*------------------------------------longword boundary */
- physlen data_length;
- /*------------------------------------longword boundary */
- physaddr data_addr;
- /*------------------------------------longword boundary */
- u_char dummy1[2];
- u_char host_stat;
- u_char target_stat;
- /*------------------------------------longword boundary */
- u_char target;
- u_char lun;
- struct scsi_generic scsi_cmd;
- u_char dummy2[1];
- u_char link_id;
- /*------------------------------------longword boundary */
- physaddr link_addr;
- /*------------------------------------longword boundary */
- physaddr sense_ptr;
-/*-----end of HW fields-----------------------longword boundary */
- struct scsi_sense_data scsi_sense;
- /*------------------------------------longword boundary */
- struct bt_scat_gath scat_gath[BT_NSEG];
- /*------------------------------------longword boundary */
- TAILQ_ENTRY(bt_ccb) chain;
- struct bt_ccb *nexthash;
- long hashkey;
- struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
- int flags;
-#define CCB_ALLOC 0x01
-#define CCB_ABORT 0x02
-#ifdef BTDIAG
-#define CCB_SENDING 0x04
-#endif
- int timeout;
-};
-
-/*
- * opcode fields
- */
-#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
-#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */
-#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */
-#define BT_RESET_CCB 0x81 /* SCSI Bus reset */
-
-/*
- * bt_ccb.host_stat values
- */
-#define BT_OK 0x00 /* cmd ok */
-#define BT_LINK_OK 0x0a /* Link cmd ok */
-#define BT_LINK_IT 0x0b /* Link cmd ok + int */
-#define BT_SEL_TIMEOUT 0x11 /* Selection time out */
-#define BT_OVER_UNDER 0x12 /* Data over/under run */
-#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */
-#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */
-#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */
-#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */
-#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */
-#define BT_INV_TARGET 0x18 /* Invalid target direction */
-#define BT_CCB_DUP 0x19 /* Duplicate CCB received */
-#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */
-
-struct bt_extended_inquire {
- struct {
- u_char opcode;
- u_char len;
- } cmd;
- struct {
- u_char bus_type; /* Type of bus connected to */
-#define BT_BUS_TYPE_24BIT 'A' /* ISA bus */
-#define BT_BUS_TYPE_32BIT 'E' /* EISA/VLB/PCI bus */
-#define BT_BUS_TYPE_MCA 'M' /* MicroChannel bus */
- u_char bios_address; /* Address of adapter BIOS */
- u_short max_segment; /* ? */
- } reply;
-};
-
-struct bt_config {
- struct {
- u_char opcode;
- } cmd;
- struct {
- u_char chan;
- u_char intr;
- u_char scsi_dev:3;
- u_char :5;
- } reply;
-};
-
-struct bt_toggle {
- struct {
- u_char opcode;
- u_char enable;
- } cmd;
-};
-
-struct bt_mailbox {
- struct {
- u_char opcode;
- u_char nmbx;
- physaddr addr;
- } cmd;
-};
-
-struct bt_model {
- struct {
- u_char opcode;
- u_char len;
- } cmd;
- struct {
- u_char id[4]; /* i.e bt742a -> '7','4','2','A' */
- u_char version[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */
- } reply;
-};
-
-struct bt_revision {
- struct {
- u_char opcode;
- } cmd;
- struct {
- u_char board_type;
- u_char custom_feature;
- char firm_revision;
- u_char firm_version;
- } reply;
-};
-
-struct bt_digit {
- struct {
- u_char opcode;
- } cmd;
- struct {
- u_char digit;
- } reply;
-};
-
-struct bt_devices {
- struct {
- u_char opcode;
- } cmd;
- struct {
- u_char junk[8];
- } reply;
-};
-
-struct bt_setup {
- struct {
- u_char opcode;
- u_char len;
- } cmd;
- struct {
- u_char sync_neg:1;
- u_char parity:1;
- u_char :6;
- u_char speed;
- u_char bus_on;
- u_char bus_off;
- u_char num_mbx;
- u_char mbx[3]; /*XXX */
- /* doesn't make sense with 32bit addresses */
- struct {
- u_char offset:4;
- u_char period:3;
- u_char valid:1;
- } sync[8];
- u_char disc_sts;
- } reply;
-};
-
-struct bt_period {
- struct {
- u_char opcode;
- u_char len;
- } cmd;
- struct {
- u_char period[8];
- } reply;
-};
-
-#define INT9 0x01
-#define INT10 0x02
-#define INT11 0x04
-#define INT12 0x08
-#define INT14 0x20
-#define INT15 0x40
-
-#define EISADMA 0x00
-#define CHAN0 0x01
-#define CHAN5 0x20
-#define CHAN6 0x40
-#define CHAN7 0x80
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index b3cbb3e587d..d5df43bb828 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -1,4 +1,4 @@
-# $OpenBSD: files.isa,v 1.72 2001/12/05 10:29:45 mickey Exp $
+# $OpenBSD: files.isa,v 1.73 2002/01/24 22:38:03 mickey Exp $
# $NetBSD: files.isa,v 1.21 1996/05/16 03:45:55 mycroft Exp $
#
# Config file and device description for machine-independent ISA code.
@@ -96,6 +96,10 @@ device bt: scsi, isa_dma
attach bt at isa
file dev/isa/bt.c bt needs-count
+#
+attach bha at isa with bha_isa: isa_dma
+file dev/isa/bha_isa.c bha_isa
+
# Adaptec AIC-6[32]60 ICs
attach aic at isa with aic_isa: isa_dma
file dev/isa/aic_isa.c aic_isa
diff --git a/sys/dev/pci/bha_pci.c b/sys/dev/pci/bha_pci.c
new file mode 100644
index 00000000000..81866316401
--- /dev/null
+++ b/sys/dev/pci/bha_pci.c
@@ -0,0 +1,167 @@
+/* $OpenBSD: bha_pci.c,v 1.1 2002/01/24 22:38:03 mickey Exp $ */
+/* $NetBSD: bha_pci.c,v 1.16 1998/08/15 10:10:53 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/ic/bhareg.h>
+#include <dev/ic/bhavar.h>
+
+#define PCI_CBIO 0x10
+
+int bha_pci_match __P((struct device *, void *, void *));
+void bha_pci_attach __P((struct device *, struct device *, void *));
+
+struct cfattach bha_pci_ca = {
+ sizeof(struct bha_softc), bha_pci_match, bha_pci_attach
+};
+
+/*
+ * Check the slots looking for a board we recognise
+ * If we find one, note it's address (slot) and call
+ * the actual probe routine to check it out.
+ */
+int
+bha_pci_match(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct pci_attach_args *pa = aux;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ bus_size_t iosize;
+ int rv;
+
+ if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_BUSLOGIC)
+ return (0);
+
+ if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_BUSLOGIC_MULTIMASTER_NC &&
+ PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_BUSLOGIC_MULTIMASTER)
+ return (0);
+
+ if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, &iot, &ioh,
+ NULL, &iosize, 0))
+ return (0);
+
+ rv = bha_find(iot, ioh, NULL);
+ bus_space_unmap(iot, ioh, iosize);
+
+ return (rv);
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+void
+bha_pci_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+ struct bha_softc *sc = (void *)self;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ bus_size_t iosize;
+ struct bha_probe_data bpd;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ pcireg_t csr;
+ const char *model, *intrstr;
+
+ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BUSLOGIC_MULTIMASTER_NC)
+ model = "BusLogic 9xxC SCSI";
+ else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BUSLOGIC_MULTIMASTER)
+ model = "BusLogic 9xxC SCSI";
+ else
+ model = "unknown model!";
+
+ if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, &iot, &ioh,
+ NULL, &iosize, 0)) {
+ printf(": unable to map I/O space\n");
+ return;
+ }
+
+ sc->sc_iot = iot;
+ sc->sc_ioh = ioh;
+ sc->sc_dmat = pa->pa_dmat;
+ if (!bha_find(iot, ioh, &bpd)) {
+ printf(": bha_find failed\n");
+ bus_space_unmap(iot, ioh, iosize);
+ return;
+ }
+
+ sc->sc_dmaflags = 0;
+
+ csr = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+ csr | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE);
+
+ if (pci_intr_map(pa, &ih)) {
+ printf(": couldn't map interrupt\n");
+ bus_space_unmap(iot, ioh, iosize);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, bha_intr, sc,
+ sc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf(": couldn't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ bus_space_unmap(iot, ioh, iosize);
+ return;
+ }
+ printf(": %s, %s\n", intrstr, model);
+
+ bha_attach(sc, &bpd);
+
+ bha_disable_isacompat(sc);
+}
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 181e40ff47c..bc30676e02d 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.124 2002/01/08 23:06:01 jason Exp $
+# $OpenBSD: files.pci,v 1.125 2002/01/24 22:38:03 mickey 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.
@@ -58,7 +58,6 @@ file dev/ic/adwlib.c adw_pci
file dev/microcode/adw/adwmcode.c adw_pci
# BusLogic BT-9xx PCI family
-# device declaration in sys/dev/isa/files.isa
attach bha at pci with bha_pci
file dev/pci/bha_pci.c bha_pci