summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1998-11-17 06:14:59 +0000
committerJason Downs <downsj@cvs.openbsd.org>1998-11-17 06:14:59 +0000
commit0abf07064b05c7d5da4ca6405654736b5d03ff97 (patch)
treec8d8119dcd07e7f060dbc3702c77affcdb91f0d6 /sys/dev
parent2bffaf53bd4f3e1ec0b0dc5684260384cd98c508 (diff)
Add adw device driver, from NetBSD.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/adw.c994
-rw-r--r--sys/dev/ic/adw.h111
-rw-r--r--sys/dev/ic/adwlib.c1332
-rw-r--r--sys/dev/ic/adwlib.h1093
-rw-r--r--sys/dev/ic/adwmcode.c361
-rw-r--r--sys/dev/ic/adwmcode.h49
6 files changed, 3940 insertions, 0 deletions
diff --git a/sys/dev/ic/adw.c b/sys/dev/ic/adw.c
new file mode 100644
index 00000000000..46fc2b6570f
--- /dev/null
+++ b/sys/dev/ic/adw.c
@@ -0,0 +1,994 @@
+/* $OpenBSD: adw.c,v 1.1 1998/11/17 06:14:58 downsj Exp $ */
+/* $NetBSD: adw.c,v 1.3 1998/10/10 00:28:33 thorpej Exp $ */
+
+/*
+ * Generic driver for the Advanced Systems Inc. SCSI controllers
+ *
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Author: Baldassare Dante Profeta <dante@mclink.it>
+ *
+ * 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/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 <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/adwlib.h>
+#include <dev/ic/adw.h>
+
+#ifndef DDB
+#define Debugger() panic("should call debugger here (adv.c)")
+#endif /* ! DDB */
+
+/******************************************************************************/
+
+
+static void adw_enqueue __P((ADW_SOFTC *, struct scsi_xfer *, int));
+static struct scsi_xfer *adw_dequeue __P((ADW_SOFTC *));
+
+static int adw_alloc_ccbs __P((ADW_SOFTC *));
+static int adw_create_ccbs __P((ADW_SOFTC *, ADW_CCB *, int));
+static void adw_free_ccb __P((ADW_SOFTC *, ADW_CCB *));
+static void adw_reset_ccb __P((ADW_CCB *));
+static int adw_init_ccb __P((ADW_SOFTC *, ADW_CCB *));
+static ADW_CCB *adw_get_ccb __P((ADW_SOFTC *, int));
+static void adw_queue_ccb __P((ADW_SOFTC *, ADW_CCB *));
+static void adw_start_ccbs __P((ADW_SOFTC *));
+
+static int adw_scsi_cmd __P((struct scsi_xfer *));
+static int adw_build_req __P((struct scsi_xfer *, ADW_CCB *));
+static void adw_build_sglist __P((ADW_CCB *, ADW_SCSI_REQ_Q *));
+static void adwminphys __P((struct buf *));
+static void adw_wide_isr_callback __P((ADW_SOFTC *, ADW_SCSI_REQ_Q *));
+
+static int adw_poll __P((ADW_SOFTC *, struct scsi_xfer *, int));
+static void adw_timeout __P((void *));
+static void adw_watchdog __P((void *));
+
+
+/******************************************************************************/
+
+
+struct cfdriver adw_cd = {
+ NULL, "adw", DV_DULL
+};
+
+
+struct scsi_adapter adw_switch =
+{
+ adw_scsi_cmd, /* called to start/enqueue a SCSI command */
+ adwminphys, /* to limit the transfer to max device can do */
+ 0,
+ 0,
+};
+
+
+/* the below structure is so we have a default dev struct for out link struct */
+struct scsi_device adw_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+
+#define ADW_ABORT_TIMEOUT 10000 /* time to wait for abort (mSec) */
+#define ADW_WATCH_TIMEOUT 10000 /* time to wait for watchdog (mSec) */
+
+
+/******************************************************************************/
+/* scsi_xfer queue routines */
+/******************************************************************************/
+
+/*
+ * Insert a scsi_xfer into the software queue. We overload xs->free_list
+ * to avoid having to allocate additional resources (since we're used
+ * only during resource shortages anyhow.
+ */
+static void
+adw_enqueue(sc, xs, infront)
+ ADW_SOFTC *sc;
+ struct scsi_xfer *xs;
+ int infront;
+{
+
+ if (infront || sc->sc_queue.lh_first == NULL) {
+ if (sc->sc_queue.lh_first == NULL)
+ sc->sc_queuelast = xs;
+ LIST_INSERT_HEAD(&sc->sc_queue, xs, free_list);
+ return;
+ }
+ LIST_INSERT_AFTER(sc->sc_queuelast, xs, free_list);
+ sc->sc_queuelast = xs;
+}
+
+
+/*
+ * Pull a scsi_xfer off the front of the software queue.
+ */
+static struct scsi_xfer *
+adw_dequeue(sc)
+ ADW_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);
+}
+
+
+/******************************************************************************/
+/* Control Blocks routines */
+/******************************************************************************/
+
+
+static int
+adw_alloc_ccbs(sc)
+ ADW_SOFTC *sc;
+{
+ bus_dma_segment_t seg;
+ int error, rseg;
+
+ /*
+ * Allocate the control blocks.
+ */
+ if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct adw_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 adw_control), (caddr_t *) & sc->sc_control,
+ BUS_DMA_NOWAIT | BUS_DMAMEM_NOSYNC)) != 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 control blocks.
+ */
+ if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct adw_control),
+ 1, sizeof(struct adw_control), 0, BUS_DMA_NOWAIT,
+ &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 adw_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);
+ }
+ return (0);
+}
+
+
+/*
+ * Create a set of ccbs and add them to the free list. Called once
+ * by adw_init(). We return the number of CCBs successfully created.
+ */
+static int
+adw_create_ccbs(sc, ccbstore, count)
+ ADW_SOFTC *sc;
+ ADW_CCB *ccbstore;
+ int count;
+{
+ ADW_CCB *ccb;
+ int i, error;
+
+ bzero(ccbstore, sizeof(ADW_CCB) * count);
+ for (i = 0; i < count; i++) {
+ ccb = &ccbstore[i];
+ if ((error = adw_init_ccb(sc, ccb)) != 0) {
+ printf("%s: unable to initialize ccb, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (i);
+ }
+ TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain);
+ }
+
+ return (i);
+}
+
+
+/*
+ * A ccb is put onto the free list.
+ */
+static void
+adw_free_ccb(sc, ccb)
+ ADW_SOFTC *sc;
+ ADW_CCB *ccb;
+{
+ int s;
+
+ s = splbio();
+
+ adw_reset_ccb(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);
+}
+
+
+static void
+adw_reset_ccb(ccb)
+ ADW_CCB *ccb;
+{
+
+ ccb->flags = 0;
+}
+
+
+static int
+adw_init_ccb(sc, ccb)
+ ADW_SOFTC *sc;
+ ADW_CCB *ccb;
+{
+ int error;
+
+ /*
+ * Create the DMA map for this CCB.
+ */
+ error = bus_dmamap_create(sc->sc_dmat,
+ (ADW_MAX_SG_LIST - 1) * PAGE_SIZE,
+ ADW_MAX_SG_LIST, (ADW_MAX_SG_LIST - 1) * PAGE_SIZE,
+ 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->dmamap_xfer);
+ if (error) {
+ printf("%s: unable to create DMA map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+ adw_reset_ccb(ccb);
+ return (0);
+}
+
+
+/*
+ * Get a free ccb
+ *
+ * If there are none, see if we can allocate a new one
+ */
+static ADW_CCB *
+adw_get_ccb(sc, flags)
+ ADW_SOFTC *sc;
+ int flags;
+{
+ ADW_CCB *ccb = 0;
+ 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, "adwccb", 0);
+ }
+
+ ccb->flags |= CCB_ALLOC;
+
+out:
+ splx(s);
+ return (ccb);
+}
+
+
+/*
+ * Queue a CCB to be sent to the controller, and send it if possible.
+ */
+static void
+adw_queue_ccb(sc, ccb)
+ ADW_SOFTC *sc;
+ ADW_CCB *ccb;
+{
+
+ TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
+
+ adw_start_ccbs(sc);
+}
+
+
+static void
+adw_start_ccbs(sc)
+ ADW_SOFTC *sc;
+{
+ ADW_CCB *ccb;
+
+ while ((ccb = sc->sc_waiting_ccb.tqh_first) != NULL) {
+ if (ccb->flags & CCB_WATCHDOG)
+ untimeout(adw_watchdog, ccb);
+
+ if (AdvExeScsiQueue(sc, &ccb->scsiq) == ADW_BUSY) {
+ ccb->flags |= CCB_WATCHDOG;
+ timeout(adw_watchdog, ccb,
+ (ADW_WATCH_TIMEOUT * hz) / 1000);
+ break;
+ }
+ TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
+
+ if ((ccb->xs->flags & SCSI_POLL) == 0)
+ timeout(adw_timeout, ccb, (ccb->timeout * hz) / 1000);
+ }
+}
+
+
+/******************************************************************************/
+/* SCSI layer interfacing routines */
+/******************************************************************************/
+
+
+int
+adw_init(sc)
+ ADW_SOFTC *sc;
+{
+ u_int16_t warn_code;
+
+
+ sc->cfg.lib_version = (ADW_LIB_VERSION_MAJOR << 8) |
+ ADW_LIB_VERSION_MINOR;
+ sc->cfg.chip_version =
+ ADW_GET_CHIP_VERSION(sc->sc_iot, sc->sc_ioh, sc->bus_type);
+
+ /*
+ * Reset the chip to start and allow register writes.
+ */
+ if (ADW_FIND_SIGNATURE(sc->sc_iot, sc->sc_ioh) == 0) {
+ panic("adw_init: adw_find_signature failed");
+ } else {
+ AdvResetChip(sc->sc_iot, sc->sc_ioh);
+
+ warn_code = AdvInitFromEEP(sc);
+ if (warn_code & ASC_WARN_EEPROM_CHKSUM)
+ printf("%s: Bad checksum found. "
+ "Setting default values\n",
+ sc->sc_dev.dv_xname);
+ if (warn_code & ASC_WARN_EEPROM_TERMINATION)
+ printf("%s: Bad bus termination setting."
+ "Using automatic termination.\n",
+ sc->sc_dev.dv_xname);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed.
+ */
+ if (sc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+ AdvResetSCSIBus(sc);
+ }
+
+ sc->isr_callback = (ulong) adw_wide_isr_callback;
+
+ return (0);
+}
+
+
+void
+adw_attach(sc)
+ ADW_SOFTC *sc;
+{
+ int i, error;
+
+
+ /*
+ * Initialize the ASC3550.
+ */
+ switch (AdvInitAsc3550Driver(sc)) {
+ case ASC_IERR_MCODE_CHKSUM:
+ panic("%s: Microcode checksum error",
+ sc->sc_dev.dv_xname);
+ break;
+
+ case ASC_IERR_ILLEGAL_CONNECTION:
+ panic("%s: All three connectors are in use",
+ sc->sc_dev.dv_xname);
+ break;
+
+ case ASC_IERR_REVERSED_CABLE:
+ panic("%s: Cable is reversed",
+ sc->sc_dev.dv_xname);
+ break;
+
+ case ASC_IERR_SINGLE_END_DEVICE:
+ panic("%s: single-ended device is attached to"
+ " one of the connectors",
+ sc->sc_dev.dv_xname);
+ break;
+ }
+
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = sc->chip_scsi_id;
+ sc->sc_link.adapter = &adw_switch;
+ sc->sc_link.device = &adw_dev;
+ sc->sc_link.openings = 4;
+ sc->sc_link.adapter_buswidth = ADW_MAX_TID;
+
+
+ TAILQ_INIT(&sc->sc_free_ccb);
+ TAILQ_INIT(&sc->sc_waiting_ccb);
+ LIST_INIT(&sc->sc_queue);
+
+
+ /*
+ * Allocate the Control Blocks.
+ */
+ error = adw_alloc_ccbs(sc);
+ if (error)
+ return; /* (error) */ ;
+
+ /*
+ * Create and initialize the Control Blocks.
+ */
+ i = adw_create_ccbs(sc, sc->sc_control->ccbs, ADW_MAX_CCB);
+ if (i == 0) {
+ printf("%s: unable to create control blocks\n",
+ sc->sc_dev.dv_xname);
+ return; /* (ENOMEM) */ ;
+ } else if (i != ADW_MAX_CCB) {
+ printf("%s: WARNING: only %d of %d control blocks"
+ " created\n",
+ sc->sc_dev.dv_xname, i, ADW_MAX_CCB);
+ }
+ config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
+}
+
+
+static void
+adwminphys(bp)
+ struct buf *bp;
+{
+
+ if (bp->b_bcount > ((ADW_MAX_SG_LIST - 1) * PAGE_SIZE))
+ bp->b_bcount = ((ADW_MAX_SG_LIST - 1) * PAGE_SIZE);
+ minphys(bp);
+}
+
+
+/*
+ * start a scsi operation given the command and the data address.
+ * Also needs the unit, target and lu.
+ */
+static int
+adw_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ ADW_SOFTC *sc = sc_link->adapter_softc;
+ ADW_CCB *ccb;
+ int s, fromqueue = 1, dontqueue = 0;
+
+ s = splbio(); /* protect the queue */
+
+ /*
+ * If we're running the queue from adw_done(), we've been
+ * called with the first queue entry as our argument.
+ */
+ if (xs == sc->sc_queue.lh_first) {
+ xs = adw_dequeue(sc);
+ fromqueue = 1;
+ } else {
+
+ /* 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.
+ */
+ adw_enqueue(sc, xs, 0);
+ xs = adw_dequeue(sc);
+ fromqueue = 1;
+ }
+ }
+
+
+ /*
+ * get a ccb to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+
+ if ((ccb = adw_get_ccb(sc, xs->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.
+ */
+ adw_enqueue(sc, xs, fromqueue);
+ splx(s);
+ return (SUCCESSFULLY_QUEUED);
+ }
+ splx(s); /* done playing with the queue */
+
+ ccb->xs = xs;
+ ccb->timeout = xs->timeout;
+
+ if (adw_build_req(xs, ccb)) {
+ s = splbio();
+ adw_queue_ccb(sc, ccb);
+ splx(s);
+
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ if ((xs->flags & SCSI_POLL) == 0)
+ return (SUCCESSFULLY_QUEUED);
+
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ if (adw_poll(sc, xs, ccb->timeout)) {
+ adw_timeout(ccb);
+ if (adw_poll(sc, xs, ccb->timeout))
+ adw_timeout(ccb);
+ }
+ }
+ return (COMPLETE);
+}
+
+
+/*
+ * Build a request structure for the Wide Boards.
+ */
+static int
+adw_build_req(xs, ccb)
+ struct scsi_xfer *xs;
+ ADW_CCB *ccb;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ ADW_SOFTC *sc = sc_link->adapter_softc;
+ bus_dma_tag_t dmat = sc->sc_dmat;
+ ADW_SCSI_REQ_Q *scsiqp;
+ int error;
+
+ scsiqp = &ccb->scsiq;
+ bzero(scsiqp, sizeof(ADW_SCSI_REQ_Q));
+
+ /*
+ * Set the ADW_SCSI_REQ_Q 'ccb_ptr' to point to the CCB structure.
+ */
+ scsiqp->ccb_ptr = (ulong) ccb;
+
+
+ /*
+ * Build the ADW_SCSI_REQ_Q request.
+ */
+
+ /*
+ * Set CDB length and copy it to the request structure.
+ */
+ bcopy(xs->cmd, &scsiqp->cdb, scsiqp->cdb_len = xs->cmdlen);
+
+ scsiqp->target_id = sc_link->target;
+ scsiqp->target_lun = sc_link->lun;
+
+ scsiqp->vsense_addr = (ulong) & ccb->scsi_sense;
+ scsiqp->sense_addr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, scsi_sense);
+ scsiqp->sense_len = sizeof(struct scsi_sense_data);
+
+ /*
+ * Build ADW_SCSI_REQ_Q for a scatter-gather buffer command.
+ */
+ if (xs->datalen) {
+ /*
+ * Map the DMA transfer.
+ */
+#ifdef TFS
+ if (xs->flags & SCSI_DATA_UIO) {
+ error = bus_dmamap_load_uio(dmat,
+ ccb->dmamap_xfer, (struct uio *) xs->data,
+ (xs->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,
+ (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
+ BUS_DMA_WAITOK);
+ }
+
+ if (error) {
+ if (error == EFBIG) {
+ printf("%s: adw_scsi_cmd, more than %d dma"
+ " segments\n",
+ sc->sc_dev.dv_xname, ADW_MAX_SG_LIST);
+ } else {
+ printf("%s: adw_scsi_cmd, error %d loading"
+ " dma map\n",
+ sc->sc_dev.dv_xname, error);
+ }
+
+ xs->error = XS_DRIVER_STUFFUP;
+ adw_free_ccb(sc, ccb);
+ return (0);
+ }
+ bus_dmamap_sync(dmat, ccb->dmamap_xfer,
+ (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
+ BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Build scatter-gather list.
+ */
+ scsiqp->data_cnt = xs->datalen;
+ scsiqp->vdata_addr = (ulong) xs->data;
+ scsiqp->data_addr = ccb->dmamap_xfer->dm_segs[0].ds_addr;
+ scsiqp->sg_list_ptr = &ccb->sg_block[0];
+ bzero(scsiqp->sg_list_ptr,
+ sizeof(ADW_SG_BLOCK) * ADW_NUM_SG_BLOCK);
+ adw_build_sglist(ccb, scsiqp);
+ } else {
+ /*
+ * No data xfer, use non S/G values.
+ */
+ scsiqp->data_cnt = 0;
+ scsiqp->vdata_addr = 0;
+ scsiqp->data_addr = 0;
+ scsiqp->sg_list_ptr = NULL;
+ }
+
+ return (1);
+}
+
+
+/*
+ * Build scatter-gather list for Wide Boards.
+ */
+static void
+adw_build_sglist(ccb, scsiqp)
+ ADW_CCB *ccb;
+ ADW_SCSI_REQ_Q *scsiqp;
+{
+ struct scsi_xfer *xs = ccb->xs;
+ ADW_SOFTC *sc = xs->sc_link->adapter_softc;
+ ADW_SG_BLOCK *sg_block = scsiqp->sg_list_ptr;
+ ulong sg_block_next_addr; /* block and its next */
+ ulong sg_block_physical_addr;
+ int sg_block_index, i; /* how many SG entries */
+ bus_dma_segment_t *sg_list = &ccb->dmamap_xfer->dm_segs[0];
+ int sg_elem_cnt = ccb->dmamap_xfer->dm_nsegs;
+
+
+ sg_block_next_addr = (ulong) sg_block; /* allow math operation */
+ sg_block_physical_addr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, sg_block[0]);
+ scsiqp->sg_real_addr = sg_block_physical_addr;
+
+ /*
+ * If there are more than NO_OF_SG_PER_BLOCK dma segments (hw sg-list)
+ * then split the request into multiple sg-list blocks.
+ */
+
+ sg_block_index = 0;
+ do {
+ sg_block->first_entry_no = sg_block_index;
+ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
+ sg_block->sg_list[i].sg_addr = sg_list->ds_addr;
+ sg_block->sg_list[i].sg_count = sg_list->ds_len;
+
+ if (--sg_elem_cnt == 0) {
+ /* last entry, get out */
+ scsiqp->sg_entry_cnt = sg_block_index + i + 1;
+ sg_block->last_entry_no = sg_block_index + i;
+ sg_block->sg_ptr = NULL; /* next link = NULL */
+ return;
+ }
+ sg_list++;
+ }
+ sg_block_next_addr += sizeof(ADW_SG_BLOCK);
+ sg_block_physical_addr += sizeof(ADW_SG_BLOCK);
+
+ sg_block_index += NO_OF_SG_PER_BLOCK;
+ sg_block->sg_ptr = (ADW_SG_BLOCK *) sg_block_physical_addr;
+ sg_block->last_entry_no = sg_block_index - 1;
+ sg_block = (ADW_SG_BLOCK *) sg_block_next_addr; /* virt. addr */
+ }
+ while (1);
+}
+
+
+int
+adw_intr(arg)
+ void *arg;
+{
+ ADW_SOFTC *sc = arg;
+ struct scsi_xfer *xs;
+
+
+ AdvISR(sc);
+
+ /*
+ * 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: adw_scsi_cmd() relies on our calling it with
+ * the first entry in the queue.
+ */
+ if ((xs = sc->sc_queue.lh_first) != NULL)
+ (void) adw_scsi_cmd(xs);
+
+ return (1);
+}
+
+
+/*
+ * Poll a particular unit, looking for a particular xs
+ */
+static int
+adw_poll(sc, xs, count)
+ ADW_SOFTC *sc;
+ struct scsi_xfer *xs;
+ int count;
+{
+
+ /* timeouts are in msec, so we loop in 1000 usec cycles */
+ while (count) {
+ adw_intr(sc);
+ if (xs->flags & ITSDONE)
+ return (0);
+ delay(1000); /* only happens in boot so ok */
+ count--;
+ }
+ return (1);
+}
+
+
+static void
+adw_timeout(arg)
+ void *arg;
+{
+ ADW_CCB *ccb = arg;
+ struct scsi_xfer *xs = ccb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ ADW_SOFTC *sc = sc_link->adapter_softc;
+ int s;
+
+ sc_print_addr(sc_link);
+ printf("timed out");
+
+ s = splbio();
+
+ /*
+ * If it has been through before, then a previous abort has failed,
+ * don't try abort again, reset the bus instead.
+ */
+ if (ccb->flags & CCB_ABORT) {
+ /* abort timed out */
+ printf(" AGAIN. Resetting Bus\n");
+ /* Lets try resetting the bus! */
+ AdvResetSCSIBus(sc);
+ ccb->timeout = ADW_ABORT_TIMEOUT;
+ adw_queue_ccb(sc, ccb);
+ } else {
+ /* abort the operation that has timed out */
+ printf("\n");
+ ADW_ABORT_CCB(sc, ccb);
+ xs->error = XS_TIMEOUT;
+ ccb->timeout = ADW_ABORT_TIMEOUT;
+ ccb->flags |= CCB_ABORT;
+ adw_queue_ccb(sc, ccb);
+ }
+
+ splx(s);
+}
+
+
+static void
+adw_watchdog(arg)
+ void *arg;
+{
+ ADW_CCB *ccb = arg;
+ struct scsi_xfer *xs = ccb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ ADW_SOFTC *sc = sc_link->adapter_softc;
+ int s;
+
+ s = splbio();
+
+ ccb->flags &= ~CCB_WATCHDOG;
+ adw_start_ccbs(sc);
+
+ splx(s);
+}
+
+
+/******************************************************************************/
+/* NARROW and WIDE boards Interrupt callbacks */
+/******************************************************************************/
+
+
+/*
+ * adw_wide_isr_callback() - Second Level Interrupt Handler called by AdvISR()
+ *
+ * Interrupt callback function for the Wide SCSI Adv Library.
+ */
+static void
+adw_wide_isr_callback(sc, scsiq)
+ ADW_SOFTC *sc;
+ ADW_SCSI_REQ_Q *scsiq;
+{
+ bus_dma_tag_t dmat = sc->sc_dmat;
+ ADW_CCB *ccb = (ADW_CCB *) scsiq->ccb_ptr;
+ struct scsi_xfer *xs = ccb->xs;
+ struct scsi_sense_data *s1, *s2;
+ //int underrun = ASC_FALSE;
+
+
+ untimeout(adw_timeout, ccb);
+
+ /*
+ * If we were a data transfer, unload the map that described
+ * the data buffer.
+ */
+ if (xs->datalen) {
+ bus_dmamap_sync(dmat, ccb->dmamap_xfer,
+ (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(dmat, ccb->dmamap_xfer);
+ }
+ if ((ccb->flags & CCB_ALLOC) == 0) {
+ printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
+ Debugger();
+ return;
+ }
+ /*
+ * Check for an underrun condition.
+ */
+ /*
+ * if (xs->request_bufflen != 0 && scsiqp->data_cnt != 0) {
+ * ASC_DBG1(1, "adw_isr_callback: underrun condition %lu bytes\n",
+ * scsiqp->data_cnt); underrun = ASC_TRUE; }
+ */
+ /*
+ * 'done_status' contains the command's ending status.
+ */
+ switch (scsiq->done_status) {
+ case QD_NO_ERROR:
+ switch (scsiq->host_status) {
+ case QHSTA_NO_ERROR:
+ xs->error = XS_NOERROR;
+ xs->resid = 0;
+ break;
+ default:
+ /* QHSTA error occurred. */
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ /*
+ * If there was an underrun without any other error,
+ * set DID_ERROR to indicate the underrun error.
+ *
+ * Note: There is no way yet to indicate the number
+ * of underrun bytes.
+ */
+ /*
+ * if (xs->error == XS_NOERROR && underrun == ASC_TRUE) {
+ * scp->result = HOST_BYTE(DID_UNDERRUN); }
+ */ break;
+
+ case QD_WITH_ERROR:
+ switch (scsiq->host_status) {
+ case QHSTA_NO_ERROR:
+ if (scsiq->scsi_status == SS_CHK_CONDITION) {
+ s1 = &ccb->scsi_sense;
+ s2 = &xs->sense;
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ } else {
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ break;
+
+ default:
+ /* Some other QHSTA error occurred. */
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ default:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+
+ adw_free_ccb(sc, ccb);
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+}
diff --git a/sys/dev/ic/adw.h b/sys/dev/ic/adw.h
new file mode 100644
index 00000000000..f70211f7d4e
--- /dev/null
+++ b/sys/dev/ic/adw.h
@@ -0,0 +1,111 @@
+/* $OpenBSD: adw.h,v 1.1 1998/11/17 06:14:58 downsj Exp $ */
+/* $NetBSD: adw.h,v 1.1 1998/09/26 16:10:41 dante Exp $ */
+
+/*
+ * Generic driver definitions and exported functions for the Advanced
+ * Systems Inc. SCSI controllers
+ *
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Author: Baldassare Dante Profeta <dante@mclink.it>
+ *
+ * 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.
+ */
+
+#ifndef _ADVANSYS_WIDE_H_
+#define _ADVANSYS_WIDE_H_
+
+/******************************************************************************/
+
+typedef int (* ADW_ISR_CALLBACK) (ADW_SOFTC *, ADW_SCSI_REQ_Q *);
+typedef int (* ADW_SBRESET_CALLBACK) (ADW_SOFTC *);
+
+/* per request scatter-gather element limit */
+#define ADW_MAX_SG_LIST 64
+
+/*
+ * Scatter-Gather Definitions per request.
+ */
+
+#define NO_OF_SG_PER_BLOCK 15
+
+/* Number of SG blocks needed. */
+#define ADW_NUM_SG_BLOCK \
+ ((ADW_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
+
+
+struct adw_ccb
+{
+ ADW_SG_BLOCK sg_block[ADW_NUM_SG_BLOCK];
+ ADW_SCSI_REQ_Q scsiq;
+
+ struct scsi_sense_data scsi_sense;
+
+ TAILQ_ENTRY(adw_ccb) chain;
+ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
+ int flags; /* see below */
+
+ int timeout;
+ /*
+ * This DMA map maps the buffer involved in the transfer.
+ */
+ bus_dmamap_t dmamap_xfer;
+};
+
+typedef struct adw_ccb ADW_CCB;
+
+/* flags for ADW_CCB */
+#define CCB_ALLOC 0x01
+#define CCB_ABORT 0x02
+#define CCB_WATCHDOG 0x10
+
+
+#define ADW_MAX_CCB 16
+
+struct adw_control
+{
+ ADW_CCB ccbs[ADW_MAX_CCB]; /* all our control blocks */
+};
+
+/*
+ * Offset of a CCB from the beginning of the control DMA mapping.
+ */
+#define ADW_CCB_OFF(c) (offsetof(struct adw_control, ccbs[0]) + \
+ (((u_long)(c)) - ((u_long)&sc->sc_control->ccbs[0])))
+
+/******************************************************************************/
+
+int adw_init __P((ADW_SOFTC *sc));
+void adw_attach __P((ADW_SOFTC *sc));
+int adw_intr __P((void *arg));
+
+/******************************************************************************/
+
+#endif /* _ADVANSYS_ADW_H_ */
diff --git a/sys/dev/ic/adwlib.c b/sys/dev/ic/adwlib.c
new file mode 100644
index 00000000000..89fffccb186
--- /dev/null
+++ b/sys/dev/ic/adwlib.c
@@ -0,0 +1,1332 @@
+/* $NetBSD: adwlib.c,v 1.2 1998/09/26 19:54:22 dante Exp $ */
+
+/*
+ * Low level routines for the Advanced Systems Inc. SCSI controllers chips
+ *
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Author: Baldassare Dante Profeta <dante@mclink.it>
+ *
+ * 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.
+ */
+/*
+ * Ported from:
+ */
+/*
+ * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
+ *
+ * Copyright (c) 1995-1998 Advanced System Products, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <dev/ic/adwlib.h>
+#include <dev/ic/adw.h>
+#include <dev/ic/adwmcode.h>
+
+
+/* Static Functions */
+
+static u_int16_t AdvGetEEPConfig __P((bus_space_tag_t, bus_space_handle_t,
+ ADWEEP_CONFIG *));
+static u_int16_t AdvReadEEPWord __P((bus_space_tag_t, bus_space_handle_t,
+ int));
+static void AdvWaitEEPCmd __P((bus_space_tag_t, bus_space_handle_t));
+static void AdvSetEEPConfig __P((bus_space_tag_t, bus_space_handle_t,
+ ADWEEP_CONFIG *));
+static int AdvSendScsiCmd __P((ADW_SOFTC *, ADW_SCSI_REQ_Q *));
+static void AdvInquiryHandling __P((ADW_SOFTC *, ADW_SCSI_REQ_Q *));
+
+static void DvcSleepMilliSecond __P((ulong));
+static void DvcDelayMicroSecond __P((ulong));
+
+
+/*
+ * EEPROM Configuration.
+ *
+ * All drivers should use this structure to set the default EEPROM
+ * configuration. The BIOS now uses this structure when it is built.
+ * Additional structure information can be found in advlib.h where
+ * the structure is defined.
+ */
+static ADWEEP_CONFIG
+Default_EEPROM_Config = {
+ ADW_EEPROM_BIOS_ENABLE, /* cfg_msw */
+ 0x0000, /* cfg_lsw */
+ 0xFFFF, /* disc_enable */
+ 0xFFFF, /* wdtr_able */
+ 0xFFFF, /* sdtr_able */
+ 0xFFFF, /* start_motor */
+ 0xFFFF, /* tagqng_able */
+ 0xFFFF, /* bios_scan */
+ 0, /* scam_tolerant */
+ 7, /* adapter_scsi_id */
+ 0, /* bios_boot_delay */
+ 3, /* scsi_reset_delay */
+ 0, /* bios_id_lun */
+ 0, /* termination */
+ 0, /* reserved1 */
+ 0xFFEF, /* bios_ctrl */
+ 0xFFFF, /* ultra_able */
+ 0, /* reserved2 */
+ ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
+ ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
+ 0, /* dvc_cntl */
+ 0, /* bug_fix */
+ 0, /* serial_number_word1 */
+ 0, /* serial_number_word2 */
+ 0, /* serial_number_word3 */
+ 0, /* check_sum */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* oem_name[16] */
+ 0, /* dvc_err_code */
+ 0, /* adv_err_code */
+ 0, /* adv_err_addr */
+ 0, /* saved_dvc_err_code */
+ 0, /* saved_adv_err_code */
+ 0, /* saved_adv_err_addr */
+ 0 /* num_of_err */
+};
+
+/*
+ * Initialize the ASC3550.
+ *
+ * On failure set the ADW_SOFTC field 'err_code' and return ADW_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+int
+AdvInitAsc3550Driver(sc)
+ADW_SOFTC *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int16_t warn_code;
+ u_int32_t sum;
+ int begin_addr;
+ int end_addr;
+ int code_sum;
+ int word;
+ int rql_addr; /* RISC Queue List address */
+ int i;
+ u_int16_t scsi_cfg1;
+ u_int8_t biosmem[ASC_MC_BIOSLEN]; /* BIOS RISC Memory
+ * 0x40-0x8F */
+
+
+ warn_code = 0;
+
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN; i++) {
+ ADW_READ_BYTE_LRAM(iot, ioh, ASC_MC_BIOSMEM + i, biosmem[i]);
+ }
+
+ /*
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ */
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RAM_ADDR, 0);
+ for (word = 0; word < adv_mcode_size; word += 2) {
+ ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh,
+ *((u_int16_t *) (&adv_mcode[word])));
+ }
+
+ /*
+ * Clear the rest of Condor's Internal RAM (8KB).
+ */
+ for (; word < ADW_CONDOR_MEMSIZE; word += 2) {
+ ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh, 0);
+ }
+
+ /*
+ * Verify the microcode checksum.
+ */
+ sum = 0;
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RAM_ADDR, 0);
+ for (word = 0; word < adv_mcode_size; word += 2) {
+ sum += ADW_READ_WORD_AUTO_INC_LRAM(iot, ioh);
+ }
+
+ if (sum != adv_mcode_chksum)
+ return ASC_IERR_MCODE_CHKSUM;
+
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN; i++) {
+ ADW_WRITE_BYTE_LRAM(iot, ioh, ASC_MC_BIOSMEM + i, biosmem[i]);
+ }
+
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += *((u_int16_t *) (&adv_mcode[word]));
+ }
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_CODE_CHK_SUM, code_sum);
+
+ /*
+ * Read microcode version and date.
+ */
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_VERSION_DATE, sc->cfg.mcode_date);
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_VERSION_NUM, sc->cfg.mcode_version);
+
+ /*
+ * Initialize microcode operating variables
+ */
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_ADAPTER_SCSI_ID,
+ sc->chip_scsi_id);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (sc->cfg.control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_CONTROL_FLAG, word);
+ }
+ /*
+ * Set default microcode operating variables for WDTR, SDTR, and
+ * command tag queuing based on the EEPROM configuration values.
+ *
+ * These ADW_DVC_VAR fields and the microcode variables will be
+ * changed in AdvInquiryHandling() if it is found a device is
+ * incapable of a particular feature.
+ */
+
+ /*
+ * Set the microcode ULTRA target mask from EEPROM value. The
+ * SDTR target mask overrides the ULTRA target mask in the
+ * microcode so it is safe to set this value without determining
+ * whether the device supports SDTR.
+ *
+ * Note: There is no way to know whether a device supports ULTRA
+ * speed without attempting a SDTR ULTRA speed negotiation with
+ * the device. The device will reject the speed if it does not
+ * support it by responding with an SDTR message containing a
+ * slower speed.
+ */
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_ULTRA_ABLE, sc->ultra_able);
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_DISC_ENABLE, sc->cfg.disc_enable);
+
+
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_DEFAULT_SCSI_CFG0,
+ ADW_PARITY_EN | ADW_SEL_TMO_LONG | ADW_OUR_ID_EN | sc->chip_scsi_id);
+
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1);
+
+ /*
+ * If all three connectors are in use, return an error.
+ */
+ if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+ (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
+ return ASC_IERR_ILLEGAL_CONNECTION;
+ }
+ /*
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
+ */
+ if ((ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CTRL) & 0x3F07) ==
+ 0x3F07) {
+
+ return ASC_IERR_REVERSED_CABLE;
+ }
+
+ /*
+ * If this is a differential board and a single-ended device
+ * is attached to one of the connectors, return an error.
+ */
+ if ((scsi_cfg1 & ADW_DIFF_MODE) && (scsi_cfg1 & ADW_DIFF_SENSE) == 0)
+ return ASC_IERR_SINGLE_END_DEVICE;
+
+ /*
+ * If automatic termination control is enabled, then set the
+ * termination value based on a table listed in advlib.h.
+ *
+ * If manual termination was specified with an EEPROM setting
+ * then 'termination' was set-up in AdvInitFromEEP() and
+ * is ready to be 'ored' into SCSI_CFG1.
+ */
+ if (sc->cfg.termination == 0) {
+ /*
+ * The software always controls termination by setting
+ * ADW_TERM_CTL_SEL.
+ * If ADW_TERM_CTL_SEL were set to 0, the hardware would
+ * set termination.
+ */
+ sc->cfg.termination |= ADW_TERM_CTL_SEL;
+
+ switch (scsi_cfg1 & ADW_CABLE_DETECT) {
+ /* ADW_TERM_CTL_H: on, ADW_TERM_CTL_L: on */
+ case 0x3:
+ case 0x7:
+ case 0xB:
+ case 0xD:
+ case 0xE:
+ case 0xF:
+ sc->cfg.termination |= (ADW_TERM_CTL_H |
+ ADW_TERM_CTL_L);
+ break;
+
+ /* ADW_TERM_CTL_H: on, ADW_TERM_CTL_L: off */
+ case 0x1:
+ case 0x5:
+ case 0x9:
+ case 0xA:
+ case 0xC:
+ sc->cfg.termination |= ADW_TERM_CTL_H;
+ break;
+
+ /* ADW_TERM_CTL_H: off, ADW_TERM_CTL_L: off */
+ case 0x2:
+ case 0x6:
+ break;
+ }
+ }
+ /*
+ * Clear any set ADW_TERM_CTL_H and ADW_TERM_CTL_L bits.
+ */
+ scsi_cfg1 &= ~ADW_TERM_CTL;
+
+ /*
+ * Invert the ADW_TERM_CTL_H and ADW_TERM_CTL_L bits and then
+ * set 'scsi_cfg1'. The ADW_TERM_POL bit does not need to be
+ * referenced, because the hardware internally inverts
+ * the Termination High and Low bits if ADW_TERM_POL is set.
+ */
+ scsi_cfg1 |= (ADW_TERM_CTL_SEL | (~sc->cfg.termination & ADW_TERM_CTL));
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set filter value and possibly modified termination control
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_DEFAULT_SCSI_CFG1,
+ ADW_FLTR_11_TO_20NS | scsi_cfg1);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_DEFAULT_SEL_MASK,
+ ADW_TID_TO_TIDMASK(sc->chip_scsi_id));
+
+ /*
+ * Link all the RISC Queue Lists together in a doubly-linked
+ * NULL terminated list.
+ *
+ * Skip the NULL (0) queue which is not used.
+ */
+ for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE+ASC_MC_RISC_Q_LIST_SIZE;
+ i < ASC_MC_RISC_Q_TOTAL_CNT;
+ i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE) {
+ /*
+ * Set the current RISC Queue List's RQL_FWD and
+ * RQL_BWD pointers in a one word write and set
+ * the state (RQL_STATE) to free.
+ */
+ ADW_WRITE_WORD_LRAM(iot, ioh, rql_addr,
+ ((i + 1) + ((i - 1) << 8)));
+ ADW_WRITE_BYTE_LRAM(iot, ioh, rql_addr + RQL_STATE,
+ ASC_MC_QS_FREE);
+ }
+
+ /*
+ * Set the Host and RISC Queue List pointers.
+ *
+ * Both sets of pointers are initialized with the same values:
+ * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF).
+ */
+ ADW_WRITE_BYTE_LRAM(iot, ioh, ASC_MC_HOST_NEXT_READY,
+ ASC_MC_RISC_Q_FIRST);
+ ADW_WRITE_BYTE_LRAM(iot, ioh, ASC_MC_HOST_NEXT_DONE,
+ ASC_MC_RISC_Q_LAST);
+
+ ADW_WRITE_BYTE_LRAM(iot, ioh, ASC_MC_RISC_NEXT_READY,
+ ASC_MC_RISC_Q_FIRST);
+ ADW_WRITE_BYTE_LRAM(iot, ioh, ASC_MC_RISC_NEXT_DONE,
+ ASC_MC_RISC_Q_LAST);
+
+ /*
+ * Finally, set up the last RISC Queue List (255) with
+ * a NULL forward pointer.
+ */
+ ADW_WRITE_WORD_LRAM(iot, ioh, rql_addr,
+ (ASC_MC_NULL_Q + ((i - 1) << 8)));
+ ADW_WRITE_BYTE_LRAM(iot, ioh, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+
+ ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_INTR_ENABLES,
+ (ADW_INTR_ENABLE_HOST_INTR | ADW_INTR_ENABLE_GLOBAL_INTR));
+
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_CODE_BEGIN_ADDR, word);
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RISC_CSR, ADW_RISC_CSR_RUN);
+
+ return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADW_SOFTC and
+ * ADW_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADW_DVC_VAR field 'err_code' and return ADW_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+int
+AdvInitFromEEP(sc)
+ ADW_SOFTC *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int16_t warn_code;
+ ADWEEP_CONFIG eep_config;
+ int eep_chksum, i;
+
+
+ warn_code = 0;
+
+ /*
+ * Read the board's EEPROM configuration.
+ *
+ * Set default values if a bad checksum is found.
+ */
+ eep_chksum = AdvGetEEPConfig(iot, ioh, &eep_config);
+
+ if (eep_chksum != eep_config.check_sum) {
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+ /*
+ * Set EEPROM default values.
+ */
+ for (i = 0; i < sizeof(ADWEEP_CONFIG); i++) {
+ *((u_int8_t *) & eep_config + i) =
+ *((u_int8_t *) & Default_EEPROM_Config + i);
+ }
+
+ /*
+ * Assume the 6 byte board serial number that was read
+ * from EEPROM is correct even if the EEPROM checksum
+ * failed.
+ */
+ eep_config.serial_number_word3 =
+ AdvReadEEPWord(iot, ioh, ASC_EEP_DVC_CFG_END - 1);
+ eep_config.serial_number_word2 =
+ AdvReadEEPWord(iot, ioh, ASC_EEP_DVC_CFG_END - 2);
+ eep_config.serial_number_word1 =
+ AdvReadEEPWord(iot, ioh, ASC_EEP_DVC_CFG_END - 3);
+ AdvSetEEPConfig(iot, ioh, &eep_config);
+ }
+ /*
+ * Set ADW_DVC_VAR and ADW_DVC_CFG variables from the
+ * EEPROM configuration that was read.
+ *
+ * This is the mapping of EEPROM fields to Adv Library fields.
+ */
+ sc->wdtr_able = eep_config.wdtr_able;
+ sc->sdtr_able = eep_config.sdtr_able;
+ sc->ultra_able = eep_config.ultra_able;
+ sc->tagqng_able = eep_config.tagqng_able;
+ sc->cfg.disc_enable = eep_config.disc_enable;
+ sc->max_host_qng = eep_config.max_host_qng;
+ sc->max_dvc_qng = eep_config.max_dvc_qng;
+ sc->chip_scsi_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
+ sc->start_motor = eep_config.start_motor;
+ sc->scsi_reset_wait = eep_config.scsi_reset_delay;
+ sc->cfg.bios_boot_wait = eep_config.bios_boot_delay;
+ sc->bios_ctrl = eep_config.bios_ctrl;
+ sc->no_scam = eep_config.scam_tolerant;
+ sc->cfg.serial1 = eep_config.serial_number_word1;
+ sc->cfg.serial2 = eep_config.serial_number_word2;
+ sc->cfg.serial3 = eep_config.serial_number_word3;
+
+ /*
+ * Set the host maximum queuing (max. 253, min. 16) and the per device
+ * maximum queuing (max. 63, min. 4).
+ */
+ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_host_qng == 0) {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else {
+ eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+ }
+ }
+ if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_dvc_qng == 0) {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else {
+ eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+ }
+ }
+ /*
+ * If 'max_dvc_qng' is greater than 'max_host_qng', then
+ * set 'max_dvc_qng' to 'max_host_qng'.
+ */
+ if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+ eep_config.max_dvc_qng = eep_config.max_host_qng;
+ }
+ /*
+ * Set ADW_DVC_VAR 'max_host_qng' and ADW_DVC_CFG 'max_dvc_qng'
+ * values based on possibly adjusted EEPROM values.
+ */
+ sc->max_host_qng = eep_config.max_host_qng;
+ sc->max_dvc_qng = eep_config.max_dvc_qng;
+
+
+ /*
+ * If the EEPROM 'termination' field is set to automatic (0), then set
+ * the ADW_DVC_CFG 'termination' field to automatic also.
+ *
+ * If the termination is specified with a non-zero 'termination'
+ * value check that a legal value is set and set the ADW_DVC_CFG
+ * 'termination' field appropriately.
+ */
+ if (eep_config.termination == 0) {
+ sc->cfg.termination = 0; /* auto termination */
+ } else {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination == 1) {
+ sc->cfg.termination = ADW_TERM_CTL_SEL;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination == 2) {
+ sc->cfg.termination = ADW_TERM_CTL_SEL | ADW_TERM_CTL_H;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination == 3) {
+ sc->cfg.termination = ADW_TERM_CTL_SEL |
+ ADW_TERM_CTL_H | ADW_TERM_CTL_L;
+ } else {
+ /*
+ * The EEPROM 'termination' field contains a bad value.
+ * Use automatic termination instead.
+ */
+ sc->cfg.termination = 0;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
+
+ return warn_code;
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+static u_int16_t
+AdvGetEEPConfig(iot, ioh, cfg_buf)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ ADWEEP_CONFIG *cfg_buf;
+{
+ u_int16_t wval, chksum;
+ u_int16_t *wbuf;
+ int eep_addr;
+
+ wbuf = (u_int16_t *) cfg_buf;
+ chksum = 0;
+
+ for (eep_addr = ASC_EEP_DVC_CFG_BEGIN;
+ eep_addr < ASC_EEP_DVC_CFG_END;
+ eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iot, ioh, eep_addr);
+ chksum += wval;
+ *wbuf = wval;
+ }
+ *wbuf = AdvReadEEPWord(iot, ioh, eep_addr);
+ wbuf++;
+ for (eep_addr = ASC_EEP_DVC_CTL_BEGIN;
+ eep_addr < ASC_EEP_MAX_WORD_ADDR;
+ eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iot, ioh, eep_addr);
+ }
+ return chksum;
+}
+
+/*
+ * Read the EEPROM from specified location
+ */
+static u_int16_t
+AdvReadEEPWord(iot, ioh, eep_word_addr)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int eep_word_addr;
+{
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
+ ASC_EEP_CMD_READ | eep_word_addr);
+ AdvWaitEEPCmd(iot, iot);
+ return ADW_READ_WORD_REGISTER(iot, ioh, IOPW_EE_DATA);
+}
+
+/*
+ * Wait for EEPROM command to complete
+ */
+static void
+AdvWaitEEPCmd(iot, ioh)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+{
+ DvcSleepMilliSecond(1);
+
+ for (;;) {
+ if (ADW_READ_WORD_REGISTER(iot, ioh, IOPW_EE_CMD) &
+ ASC_EEP_CMD_DONE) {
+ break;
+ }
+ DvcSleepMilliSecond(1);
+ }
+
+ return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+static void
+AdvSetEEPConfig(iot, ioh, cfg_buf)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ ADWEEP_CONFIG *cfg_buf;
+{
+ u_int16_t *wbuf;
+ u_int16_t addr, chksum;
+
+ wbuf = (u_int16_t *) cfg_buf;
+ chksum = 0;
+
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iot, ioh);
+
+ /*
+ * Write EEPROM from word 0 to word 15
+ */
+ for (addr = ASC_EEP_DVC_CFG_BEGIN;
+ addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) {
+ chksum += *wbuf;
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, *wbuf);
+ ADW_WRITE_WORD_REGISTER(iot, ioh,
+ IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iot, ioh);
+ DvcSleepMilliSecond(ASC_EEP_DELAY_MS);
+ }
+
+ /*
+ * Write EEPROM checksum at word 18
+ */
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, chksum);
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iot, ioh);
+ wbuf++; /* skip over check_sum */
+
+ /*
+ * Write EEPROM OEM name at words 19 to 26
+ */
+ for (addr = ASC_EEP_DVC_CTL_BEGIN;
+ addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, *wbuf);
+ ADW_WRITE_WORD_REGISTER(iot, ioh,
+ IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iot, ioh);
+ }
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iot, ioh);
+ return;
+}
+
+/*
+ * This function resets the chip and SCSI bus
+ *
+ * It is up to the caller to add a delay to let the bus settle after
+ * calling this function.
+ *
+ * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in
+ * AdvInitAsc3550Driver(). Here when doing a write to one of these
+ * registers read first and then write.
+ *
+ * Note: A SCSI Bus Reset can not be done until after the EEPROM
+ * configuration is read to determine whether SCSI Bus Resets
+ * should be performed.
+ */
+void
+AdvResetChip(iot, ioh)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+{
+ u_int16_t word;
+ u_int8_t byte;
+
+
+ /*
+ * Reset Chip.
+ */
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
+ ADW_CTRL_REG_CMD_RESET);
+ DvcSleepMilliSecond(100);
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
+ ADW_CTRL_REG_CMD_WR_IO_REG);
+
+ /*
+ * Initialize Chip registers.
+ *
+ * Note: Don't remove the use of a temporary variable in the following
+ * code, otherwise the Microsoft C compiler will turn the following
+ * lines into a no-op.
+ */
+ byte = ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_MEM_CFG);
+ byte |= RAM_SZ_8KB;
+ ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_MEM_CFG, byte);
+
+ word = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1);
+ word &= ~BIG_ENDIAN;
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1, word);
+
+ /*
+ * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold
+ * of 128 bytes. This register is only accessible to the host.
+ */
+ ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_DMA_CFG0,
+ START_CTL_EMFU | READ_CMD_MRM);
+}
+
+/*
+ * Description:
+ * Send a SCSI request to the ASC3550 chip
+ *
+ * If there is no SG list for the request, set 'sg_entry_cnt' to 0.
+ *
+ * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be
+ * called. It is assumed the caller has already initialized 'sg_real_addr'.
+ *
+ * Return:
+ * ADW_SUCCESS(1) - the request is in the mailbox
+ * ADW_BUSY(0) - total request count > 253, try later
+ * ADW_ERROR(-1) - invalid scsi request Q
+ */
+int
+AdvExeScsiQueue(sc, scsiq)
+ ADW_SOFTC *sc;
+ ADW_SCSI_REQ_Q *scsiq;
+{
+ return AdvSendScsiCmd(sc, scsiq);
+}
+
+/*
+ * Reset SCSI Bus and purge all outstanding requests.
+ *
+ * Return Value:
+ * ADW_TRUE(1) - All requests are purged and SCSI Bus is reset.
+ *
+ * Note: Should always return ADW_TRUE.
+ */
+int
+AdvResetCCB(sc)
+ ADW_SOFTC *sc;
+{
+ int status;
+
+ status = AdvSendIdleCmd(sc, (u_int16_t) IDLE_CMD_SCSI_RESET, 0L, 0);
+
+ AdvResetSCSIBus(sc);
+
+ return status;
+}
+
+/*
+ * Reset SCSI Bus and delay.
+ */
+void
+AdvResetSCSIBus(sc)
+ ADW_SOFTC *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int16_t scsi_ctrl;
+
+
+
+ /*
+ * The microcode currently sets the SCSI Bus Reset signal while
+ * handling the AdvSendIdleCmd() IDLE_CMD_SCSI_RESET command above.
+ * But the SCSI Bus Reset Hold Time in the uCode is not deterministic
+ * (it may in fact be for less than the SCSI Spec. minimum of 25 us).
+ * Therefore on return the Adv Library sets the SCSI Bus Reset signal
+ * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
+ * than 25 us.
+ */
+ scsi_ctrl = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CTRL);
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_SCSI_CTRL,
+ scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);
+ DvcDelayMicroSecond((u_int16_t) ASC_SCSI_RESET_HOLD_TIME_US);
+ ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_SCSI_CTRL,
+ scsi_ctrl & ~ADW_SCSI_CTRL_RSTOUT);
+
+ DvcSleepMilliSecond((ulong) sc->scsi_reset_wait * 1000);
+}
+
+
+/*
+ * Adv Library Interrupt Service Routine
+ *
+ * This function is called by a driver's interrupt service routine.
+ * The function disables and re-enables interrupts.
+ *
+ * When a microcode idle command is completed, the ADW_DVC_VAR
+ * 'idle_cmd_done' field is set to ADW_TRUE.
+ *
+ * Note: AdvISR() can be called when interrupts are disabled or even
+ * when there is no hardware interrupt condition present. It will
+ * always check for completed idle commands and microcode requests.
+ * This is an important feature that shouldn't be changed because it
+ * allows commands to be completed from polling mode loops.
+ *
+ * Return:
+ * ADW_TRUE(1) - interrupt was pending
+ * ADW_FALSE(0) - no interrupt was pending
+ */
+int
+AdvISR(sc)
+ ADW_SOFTC *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t int_stat;
+ u_int16_t next_done_loc, target_bit;
+ int completed_q;
+ ADW_SCSI_REQ_Q *scsiq;
+ ASC_REQ_SENSE *sense_data;
+ int ret;
+
+
+ ret = (ADW_IS_INT_PENDING(iot, ioh)) ? ADW_TRUE : ADW_FALSE;
+
+ /* Reading the register clears the interrupt. */
+ int_stat = ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_INTR_STATUS_REG);
+
+ if (int_stat & ADW_INTR_STATUS_INTRB) {
+ sc->idle_cmd_done = ADW_TRUE;
+ }
+ /*
+ * Notify the driver of a hardware detected SCSI Bus Reset.
+ */
+ if (int_stat & ADW_INTR_STATUS_INTRC) {
+ if (sc->sbreset_callback) {
+ (*(ADW_SBRESET_CALLBACK) sc->sbreset_callback) (sc);
+ }
+ }
+ /*
+ * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC
+ * Queue List request. Its forward pointer (RQL_FWD) points to the
+ * current completed RISC Queue List request.
+ */
+ ADW_READ_BYTE_LRAM(iot, ioh, ASC_MC_HOST_NEXT_DONE, next_done_loc);
+ next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
+ (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD;
+
+ ADW_READ_BYTE_LRAM(iot, ioh, next_done_loc, completed_q);
+
+ /* Loop until all completed Q's are processed. */
+ while (completed_q != ASC_MC_NULL_Q) {
+ ADW_WRITE_BYTE_LRAM(iot, ioh, ASC_MC_HOST_NEXT_DONE,
+ completed_q);
+
+ next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
+ (completed_q * ASC_MC_RISC_Q_LIST_SIZE);
+
+ /*
+ * Read the ADW_SCSI_REQ_Q virtual address pointer from
+ * the RISC list entry. The microcode has changed the
+ * ADW_SCSI_REQ_Q physical address to its virtual address.
+ *
+ * Refer to comments at the end of AdvSendScsiCmd() for
+ * more information on the RISC list structure.
+ */
+ {
+ ushort lsw, msw;
+ ADW_READ_WORD_LRAM(iot, ioh,
+ next_done_loc + RQL_PHYADDR, lsw);
+ ADW_READ_WORD_LRAM(iot, ioh,
+ next_done_loc + RQL_PHYADDR + 2, msw);
+
+ scsiq = (ADW_SCSI_REQ_Q *)
+ (((u_int32_t) msw << 16) | lsw);
+ }
+
+ target_bit = ADW_TID_TO_TIDMASK(scsiq->target_id);
+
+ /*
+ * Clear request microcode control flag.
+ */
+ scsiq->cntl = 0;
+
+ /*
+ * Check Condition handling
+ */
+ if ((scsiq->done_status == QD_WITH_ERROR) &&
+ (scsiq->scsi_status == SS_CHK_CONDITION) &&
+ (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 &&
+ (scsiq->orig_sense_len - scsiq->sense_len) >=
+ ASC_MIN_SENSE_LEN) {
+ /*
+ * Command returned with a check condition and valid
+ * sense data.
+ */
+ }
+ /*
+ * If the command that completed was a SCSI INQUIRY and
+ * LUN 0 was sent the command, then process the INQUIRY
+ * command information for the device.
+ */
+ else if (scsiq->done_status == QD_NO_ERROR &&
+ scsiq->cdb[0] == INQUIRY &&
+ scsiq->target_lun == 0) {
+ AdvInquiryHandling(sc, scsiq);
+ }
+ /* Change the RISC Queue List state to free. */
+ ADW_WRITE_BYTE_LRAM(iot, ioh,
+ next_done_loc + RQL_STATE, ASC_MC_QS_FREE);
+
+ /* Get the RISC Queue List forward pointer. */
+ ADW_READ_BYTE_LRAM(iot, ioh,
+ next_done_loc + RQL_FWD, completed_q);
+
+ /*
+ * Notify the driver of the completed request by passing
+ * the ADW_SCSI_REQ_Q pointer to its callback function.
+ */
+ sc->cur_host_qng--;
+ scsiq->a_flag |= ADW_SCSIQ_DONE;
+ (*(ADW_ISR_CALLBACK) sc->isr_callback) (sc, scsiq);
+ /*
+ * Note: After the driver callback function is called, 'scsiq'
+ * can no longer be referenced.
+ *
+ * Fall through and continue processing other completed
+ * requests...
+ */
+ }
+ return ret;
+}
+
+/*
+ * Send an idle command to the chip and wait for completion.
+ *
+ * Interrupts do not have to be enabled on entry.
+ *
+ * Return Values:
+ * ADW_TRUE - command completed successfully
+ * ADW_FALSE - command failed
+ */
+int
+AdvSendIdleCmd(sc, idle_cmd, idle_cmd_parameter, flags)
+ ADW_SOFTC *sc;
+ u_int16_t idle_cmd;
+ u_int32_t idle_cmd_parameter;
+ int flags;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int32_t i;
+ int ret;
+
+ sc->idle_cmd_done = 0;
+
+ /*
+ * Write the idle command value after the idle command parameter
+ * has been written to avoid a race condition. If the order is not
+ * followed, the microcode may process the idle command before the
+ * parameters have been written to LRAM.
+ */
+ ADW_WRITE_DWORD_LRAM(iot, ioh, ASC_MC_IDLE_PARA_STAT,
+ idle_cmd_parameter);
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_IDLE_CMD, idle_cmd);
+
+ /*
+ * If the 'flags' argument contains the ADW_NOWAIT flag, then
+ * return with success.
+ */
+ if (flags & ADW_NOWAIT)
+ return ADW_TRUE;
+
+ for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++) {
+ /*
+ * 'idle_cmd_done' is set by AdvISR().
+ */
+ if (sc->idle_cmd_done)
+ break;
+
+ DvcSleepMilliSecond(1);
+
+ /*
+ * If interrupts were disabled on entry to AdvSendIdleCmd(),
+ * then they will still be disabled here. Call AdvISR() to
+ * check for the idle command completion.
+ */
+ (void) AdvISR(sc);
+ }
+
+ if (sc->idle_cmd_done == ADW_FALSE) {
+ return ADW_FALSE;
+ } else {
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_IDLE_PARA_STAT, ret);
+ return ret;
+ }
+}
+
+/*
+ * Send the SCSI request block to the adapter
+ *
+ * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the
+ * following structure:
+ *
+ * 0: RQL_FWD - RISC list forward pointer (1 byte)
+ * 1: RQL_BWD - RISC list backward pointer (1 byte)
+ * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte)
+ * 3: RQL_TID - request target id (1 byte)
+ * 4: RQL_PHYADDR - ADW_SCSI_REQ_Q physical pointer (4 bytes)
+ *
+ * Return:
+ * ADW_SUCCESS(1) - the request is in the mailbox
+ * ADW_BUSY(0) - total request count > 253, try later
+ */
+static int
+AdvSendScsiCmd(sc, scsiq)
+ ADW_SOFTC *sc;
+ ADW_SCSI_REQ_Q *scsiq;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ ADW_CCB *ccb = (ADW_CCB *) scsiq->ccb_ptr;
+ u_int16_t next_ready_loc;
+ u_int8_t next_ready_loc_fwd;
+ long req_size;
+ u_int32_t q_phy_addr;
+
+
+ if (sc->cur_host_qng >= sc->max_host_qng) {
+ return ADW_BUSY;
+ } else {
+ sc->cur_host_qng++;
+ }
+
+ /*
+ * Clear the ADW_SCSI_REQ_Q done flag.
+ */
+ scsiq->a_flag &= ~ADW_SCSIQ_DONE;
+
+ /*
+ * Save the original sense buffer length.
+ *
+ * After the request completes 'sense_len' will be set to the residual
+ * byte count of the Auto-Request Sense if a command returns CHECK
+ * CONDITION and the Sense Data is valid indicated by 'host_status' not
+ * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid
+ * Sense Data Length subtract 'sense_len' from 'orig_sense_len'.
+ */
+ scsiq->orig_sense_len = scsiq->sense_len;
+
+ ADW_READ_BYTE_LRAM(iot, ioh, ASC_MC_HOST_NEXT_READY, next_ready_loc);
+ next_ready_loc = ASC_MC_RISC_Q_LIST_BASE +
+ (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE);
+
+ /*
+ * Write the physical address of the Q to the mailbox.
+ * We need to skip the first four bytes, because the microcode
+ * uses them internally for linking Q's together.
+ */
+ req_size = sizeof(ADW_SCSI_REQ_Q);
+ q_phy_addr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, scsiq);
+
+ scsiq->scsiq_ptr = scsiq;
+
+ /*
+ * The RISC list structure, which 'next_ready_loc' is a pointer
+ * to in microcode LRAM, has the format detailed in the comment
+ * header for this function.
+ *
+ * Write the ADW_SCSI_REQ_Q physical pointer to
+ * 'next_ready_loc' request.
+ */
+ ADW_WRITE_DWORD_LRAM(iot, ioh, next_ready_loc + RQL_PHYADDR,
+ q_phy_addr);
+
+ /* Write target_id to 'next_ready_loc' request. */
+ ADW_WRITE_BYTE_LRAM(iot, ioh, next_ready_loc + RQL_TID,
+ scsiq->target_id);
+
+ /*
+ * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to
+ * the 'next_ready_loc' request forward pointer.
+ *
+ * Do this *before* changing the 'next_ready_loc' queue to QS_READY.
+ * After the state is changed to QS_READY 'RQL_FWD' will be changed
+ * by the microcode.
+ *
+ * NOTE: The temporary variable 'next_ready_loc_fwd' is required to
+ * prevent some compilers from optimizing out 'AdvReadByteLram()' if
+ * it were used as the 3rd argument to 'AdvWriteByteLram()'.
+ */
+ ADW_READ_BYTE_LRAM(iot, ioh, next_ready_loc + RQL_FWD,
+ next_ready_loc_fwd);
+ ADW_WRITE_BYTE_LRAM(iot, ioh, ASC_MC_HOST_NEXT_READY,
+ next_ready_loc_fwd);
+
+ /*
+ * Change the state of 'next_ready_loc' request from QS_FREE to
+ * QS_READY which will cause the microcode to pick it up and
+ * execute it.
+ *
+ * Can't reference 'next_ready_loc' after changing the request
+ * state to QS_READY. The microcode now owns the request.
+ */
+ ADW_WRITE_BYTE_LRAM(iot, ioh, next_ready_loc + RQL_STATE,
+ ASC_MC_QS_READY);
+
+ return ADW_SUCCESS;
+}
+
+/*
+ * Inquiry Information Byte 7 Handling
+ *
+ * Handle SCSI Inquiry Command information for a device by setting
+ * microcode operating variables that affect WDTR, SDTR, and Tag
+ * Queuing.
+ */
+static void
+AdvInquiryHandling(sc, scsiq)
+ ADW_SOFTC *sc;
+ ADW_SCSI_REQ_Q *scsiq;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ ASC_SCSI_INQUIRY *inq;
+ u_int16_t cfg_word;
+ u_int16_t tidmask;
+ u_int8_t tid;
+
+ /*
+ * AdvInquiryHandling() requires up to INQUIRY information Byte 7
+ * to be available.
+ *
+ * If less than 8 bytes of INQUIRY information were requested or less
+ * than 8 bytes were transferred, then return. cdb[4] is the request
+ * length and the ADW_SCSI_REQ_Q 'data_cnt' field is set by the
+ * microcode to the transfer residual count.
+ */
+ if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8) {
+ return;
+ }
+ tid = scsiq->target_id;
+ inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr;
+
+ /*
+ * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
+ */
+ if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2) {
+ return;
+ } else {
+ /*
+ * INQUIRY Byte 7 Handling
+ *
+ * Use a device's INQUIRY byte 7 to determine whether it
+ * supports WDTR, SDTR, and Tag Queuing. If the feature
+ * is enabled in the EEPROM and the device supports the
+ * feature, then enable it in the microcode.
+ */
+
+ tidmask = ADW_TID_TO_TIDMASK(tid);
+ /*
+ * Wide Transfers
+ *
+ * If the EEPROM enabled WDTR for the device and the device
+ * supports wide bus (16 bit) transfers, then turn on the
+ * device's 'wdtr_able' bit and write the new value to the
+ * microcode.
+ */
+ if ((sc->wdtr_able & tidmask) && inq->byte7.WBus16) {
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_WDTR_ABLE,
+ cfg_word);
+ if ((cfg_word & tidmask) == 0) {
+ cfg_word |= tidmask;
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_WDTR_ABLE,
+ cfg_word);
+
+ /*
+ * Clear the microcode "WDTR negotiation" done
+ * indicator for the target to cause it
+ * to negotiate with the new setting set above.
+ */
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_WDTR_DONE,
+ cfg_word);
+ cfg_word &= ~tidmask;
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_WDTR_DONE,
+ cfg_word);
+ }
+ }
+ /*
+ * Synchronous Transfers
+ *
+ * If the EEPROM enabled SDTR for the device and the device
+ * supports synchronous transfers, then turn on the device's
+ * 'sdtr_able' bit. Write the new value to the microcode.
+ */
+ if ((sc->sdtr_able & tidmask) && inq->byte7.Sync) {
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_SDTR_ABLE,
+ cfg_word);
+ if ((cfg_word & tidmask) == 0) {
+ cfg_word |= tidmask;
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_SDTR_ABLE,
+ cfg_word);
+
+ /*
+ * Clear the microcode "SDTR negotiation" done
+ * indicator for the target to cause it
+ * to negotiate with the new setting set above.
+ */
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_SDTR_DONE,
+ cfg_word);
+ cfg_word &= ~tidmask;
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_SDTR_DONE,
+ cfg_word);
+ }
+ }
+ /*
+ * If the EEPROM enabled Tag Queuing for device and the
+ * device supports Tag Queuing, then turn on the device's
+ * 'tagqng_enable' bit in the microcode and set the microcode
+ * maximum command count to the ADW_DVC_VAR 'max_dvc_qng'
+ * value.
+ *
+ * Tag Queuing is disabled for the BIOS which runs in polled
+ * mode and would see no benefit from Tag Queuing. Also by
+ * disabling Tag Queuing in the BIOS devices with Tag Queuing
+ * bugs will at least work with the BIOS.
+ */
+ if ((sc->tagqng_able & tidmask) && inq->byte7.CmdQue) {
+ ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_TAGQNG_ABLE,
+ cfg_word);
+ cfg_word |= tidmask;
+ ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_TAGQNG_ABLE,
+ cfg_word);
+ ADW_WRITE_BYTE_LRAM(iot, ioh,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ sc->max_dvc_qng);
+ }
+ }
+}
+
+static void
+DvcSleepMilliSecond(n)
+ ulong n;
+{
+
+ DELAY(n * 1000);
+}
+
+static void
+DvcDelayMicroSecond(n)
+ ulong n;
+{
+
+ DELAY(n);
+}
diff --git a/sys/dev/ic/adwlib.h b/sys/dev/ic/adwlib.h
new file mode 100644
index 00000000000..8b6bacb918c
--- /dev/null
+++ b/sys/dev/ic/adwlib.h
@@ -0,0 +1,1093 @@
+/* $OpenBSD: adwlib.h,v 1.1 1998/11/17 06:14:58 downsj Exp $ */
+/* $NetBSD: adwlib.h,v 1.1 1998/09/26 16:10:42 dante Exp $ */
+
+/*
+ * Definitions for low level routines and data structures
+ * for the Advanced Systems Inc. SCSI controllers chips.
+ *
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Author: Baldassare Dante Profeta <dante@mclink.it>
+ *
+ * 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.
+ */
+/*
+ * Ported from:
+ */
+/*
+ * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
+ *
+ * Copyright (c) 1995-1996 Advanced System Products, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ */
+
+#ifndef _ADVANSYS_WIDE_LIBRARY_H_
+#define _ADVANSYS_WIDE_LIBRARY_H_
+
+
+/*
+ * --- Adv Library Constants and Macros
+ */
+
+#define ADW_LIB_VERSION_MAJOR 3
+#define ADW_LIB_VERSION_MINOR 45
+
+/*
+ * Define Adv Reset Hold Time grater than 25 uSec.
+ * See AdvResetSCSIBus() for more info.
+ */
+#define ASC_SCSI_RESET_HOLD_TIME_US 60
+
+/*
+ * Define Adv EEPROM constants.
+ */
+
+#define ASC_EEP_DVC_CFG_BEGIN (0x00)
+#define ASC_EEP_DVC_CFG_END (0x15)
+#define ASC_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
+#define ASC_EEP_MAX_WORD_ADDR (0x1E)
+
+#define ASC_EEP_DELAY_MS 100
+
+/*
+ * EEPROM bits reference by the RISC after initialization.
+ */
+#define ADW_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
+#define ADW_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
+#define ADW_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
+
+/*
+ * EEPROM configuration format
+ *
+ * Field naming convention:
+ *
+ * *_enable indicates the field enables or disables the feature. The
+ * value is never reset.
+ *
+ * *_able indicates both whether a feature should be enabled or disabled
+ * and whether a device isi capable of the feature. At initialization
+ * this field may be set, but later if a device is found to be incapable
+ * of the feature, the field is cleared.
+ *
+ * Default values are maintained in a_init.c in the structure
+ * Default_EEPROM_Config.
+ */
+typedef struct adweep_config
+{
+ /* Word Offset, Description */
+
+ u_int16_t cfg_lsw; /* 00 power up initialization */
+ /* bit 13 set - Term Polarity Control */
+ /* bit 14 set - BIOS Enable */
+ /* bit 15 set - Big Endian Mode */
+ u_int16_t cfg_msw; /* 01 unused */
+ u_int16_t disc_enable; /* 02 disconnect enable */
+ u_int16_t wdtr_able; /* 03 Wide DTR able */
+ u_int16_t sdtr_able; /* 04 Synchronous DTR able */
+ u_int16_t start_motor; /* 05 send start up motor */
+ u_int16_t tagqng_able; /* 06 tag queuing able */
+ u_int16_t bios_scan; /* 07 BIOS device control */
+ u_int16_t scam_tolerant; /* 08 no scam */
+
+ u_int8_t adapter_scsi_id; /* 09 Host Adapter ID */
+ u_int8_t bios_boot_delay; /* power up wait */
+
+ u_int8_t scsi_reset_delay; /* 10 reset delay */
+ u_int8_t bios_id_lun; /* first boot device scsi id & lun */
+ /* high nibble is lun */
+ /* low nibble is scsi id */
+
+ u_int8_t termination; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ u_int8_t reserved1; /* reserved byte (not used) */
+
+ u_int16_t bios_ctrl; /* 12 BIOS control bits */
+ /* bit 0 set: BIOS don't act as initiator. */
+ /* bit 1 set: BIOS > 1 GB support */
+ /* bit 2 set: BIOS > 2 Disk Support */
+ /* bit 3 set: BIOS don't support removables */
+ /* bit 4 set: BIOS support bootable CD */
+ /* bit 5 set: */
+ /* bit 6 set: BIOS support multiple LUNs */
+ /* bit 7 set: BIOS display of message */
+ /* bit 8 set: */
+ /* bit 9 set: Reset SCSI bus during init. */
+ /* bit 10 set: */
+ /* bit 11 set: No verbose initialization. */
+ /* bit 12 set: SCSI parity enabled */
+ /* bit 13 set: */
+ /* bit 14 set: */
+ /* bit 15 set: */
+ u_int16_t ultra_able; /* 13 ULTRA speed able */
+ u_int16_t reserved2; /* 14 reserved */
+ u_int8_t max_host_qng; /* 15 maximum host queuing */
+ u_int8_t max_dvc_qng; /* maximum per device queuing */
+ u_int16_t dvc_cntl; /* 16 control bit for driver */
+ u_int16_t bug_fix; /* 17 control bit for bug fix */
+ u_int16_t serial_number_word1; /* 18 Board serial number word 1 */
+ u_int16_t serial_number_word2; /* 19 Board serial number word 2 */
+ u_int16_t serial_number_word3; /* 20 Board serial number word 3 */
+ u_int16_t check_sum; /* 21 EEP check sum */
+ u_int8_t oem_name[16]; /* 22 OEM name */
+ u_int16_t dvc_err_code; /* 30 last device driver error code */
+ u_int16_t adv_err_code; /* 31 last uc and Adv Lib error code */
+ u_int16_t adv_err_addr; /* 32 last uc error address */
+ u_int16_t saved_dvc_err_code; /* 33 saved last dev. driver error code */
+ u_int16_t saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
+ u_int16_t saved_adv_err_addr; /* 35 saved last uc error address */
+ u_int16_t num_of_err; /* 36 number of error */
+} ADWEEP_CONFIG;
+
+/*
+ * EEPROM Commands
+ */
+#define ASC_EEP_CMD_READ 0x80
+#define ASC_EEP_CMD_WRITE 0x40
+#define ASC_EEP_CMD_WRITE_ABLE 0x30
+#define ASC_EEP_CMD_WRITE_DISABLE 0x00
+
+#define ASC_EEP_CMD_DONE 0x0200
+#define ASC_EEP_CMD_DONE_ERR 0x0001
+
+/* cfg_word */
+#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
+
+/* bios_ctrl */
+#define BIOS_CTRL_BIOS 0x0001
+#define BIOS_CTRL_EXTENDED_XLAT 0x0002
+#define BIOS_CTRL_GT_2_DISK 0x0004
+#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
+#define BIOS_CTRL_BOOTABLE_CD 0x0010
+#define BIOS_CTRL_MULTIPLE_LUN 0x0040
+#define BIOS_CTRL_DISPLAY_MSG 0x0080
+#define BIOS_CTRL_NO_SCAM 0x0100
+#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
+#define BIOS_CTRL_INIT_VERBOSE 0x0800
+#define BIOS_CTRL_SCSI_PARITY 0x1000
+
+/*
+ * ASC 3550 Internal Memory Size - 8KB
+ */
+#define ADW_CONDOR_MEMSIZE 0x2000 /* 8 KB Internal Memory */
+
+/*
+ * ASC 3550 I/O Length - 64 bytes
+ */
+#define ADW_CONDOR_IOLEN 0x40 /* I/O Port Range in bytes */
+
+/*
+ * Byte I/O register address from base of 'iop_base'.
+ */
+#define IOPB_INTR_STATUS_REG 0x00
+#define IOPB_CHIP_ID_1 0x01
+#define IOPB_INTR_ENABLES 0x02
+#define IOPB_CHIP_TYPE_REV 0x03
+#define IOPB_RES_ADDR_4 0x04
+#define IOPB_RES_ADDR_5 0x05
+#define IOPB_RAM_DATA 0x06
+#define IOPB_RES_ADDR_7 0x07
+#define IOPB_FLAG_REG 0x08
+#define IOPB_RES_ADDR_9 0x09
+#define IOPB_RISC_CSR 0x0A
+#define IOPB_RES_ADDR_B 0x0B
+#define IOPB_RES_ADDR_C 0x0C
+#define IOPB_RES_ADDR_D 0x0D
+#define IOPB_RES_ADDR_E 0x0E
+#define IOPB_RES_ADDR_F 0x0F
+#define IOPB_MEM_CFG 0x10
+#define IOPB_RES_ADDR_11 0x11
+#define IOPB_RES_ADDR_12 0x12
+#define IOPB_RES_ADDR_13 0x13
+#define IOPB_FLASH_PAGE 0x14
+#define IOPB_RES_ADDR_15 0x15
+#define IOPB_RES_ADDR_16 0x16
+#define IOPB_RES_ADDR_17 0x17
+#define IOPB_FLASH_DATA 0x18
+#define IOPB_RES_ADDR_19 0x19
+#define IOPB_RES_ADDR_1A 0x1A
+#define IOPB_RES_ADDR_1B 0x1B
+#define IOPB_RES_ADDR_1C 0x1C
+#define IOPB_RES_ADDR_1D 0x1D
+#define IOPB_RES_ADDR_1E 0x1E
+#define IOPB_RES_ADDR_1F 0x1F
+#define IOPB_DMA_CFG0 0x20
+#define IOPB_DMA_CFG1 0x21
+#define IOPB_TICKLE 0x22
+#define IOPB_DMA_REG_WR 0x23
+#define IOPB_SDMA_STATUS 0x24
+#define IOPB_SCSI_BYTE_CNT 0x25
+#define IOPB_HOST_BYTE_CNT 0x26
+#define IOPB_BYTE_LEFT_TO_XFER 0x27
+#define IOPB_BYTE_TO_XFER_0 0x28
+#define IOPB_BYTE_TO_XFER_1 0x29
+#define IOPB_BYTE_TO_XFER_2 0x2A
+#define IOPB_BYTE_TO_XFER_3 0x2B
+#define IOPB_ACC_GRP 0x2C
+#define IOPB_RES_ADDR_2D 0x2D
+#define IOPB_DEV_ID 0x2E
+#define IOPB_RES_ADDR_2F 0x2F
+#define IOPB_SCSI_DATA 0x30
+#define IOPB_RES_ADDR_31 0x31
+#define IOPB_RES_ADDR_32 0x32
+#define IOPB_SCSI_DATA_HSHK 0x33
+#define IOPB_SCSI_CTRL 0x34
+#define IOPB_RES_ADDR_35 0x35
+#define IOPB_RES_ADDR_36 0x36
+#define IOPB_RES_ADDR_37 0x37
+#define IOPB_RES_ADDR_38 0x38
+#define IOPB_RES_ADDR_39 0x39
+#define IOPB_RES_ADDR_3A 0x3A
+#define IOPB_RES_ADDR_3B 0x3B
+#define IOPB_RFIFO_CNT 0x3C
+#define IOPB_RES_ADDR_3D 0x3D
+#define IOPB_RES_ADDR_3E 0x3E
+#define IOPB_RES_ADDR_3F 0x3F
+
+/*
+ * Word I/O register address from base of 'iop_base'.
+ */
+#define IOPW_CHIP_ID_0 0x00 /* CID0 */
+#define IOPW_CTRL_REG 0x02 /* CC */
+#define IOPW_RAM_ADDR 0x04 /* LA */
+#define IOPW_RAM_DATA 0x06 /* LD */
+#define IOPW_RES_ADDR_08 0x08
+#define IOPW_RISC_CSR 0x0A /* CSR */
+#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
+#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
+#define IOPW_RES_ADDR_10 0x10
+#define IOPW_SEL_MASK 0x12 /* SM */
+#define IOPW_RES_ADDR_14 0x14
+#define IOPW_FLASH_ADDR 0x16 /* FA */
+#define IOPW_RES_ADDR_18 0x18
+#define IOPW_EE_CMD 0x1A /* EC */
+#define IOPW_EE_DATA 0x1C /* ED */
+#define IOPW_SFIFO_CNT 0x1E /* SFC */
+#define IOPW_RES_ADDR_20 0x20
+#define IOPW_Q_BASE 0x22 /* QB */
+#define IOPW_QP 0x24 /* QP */
+#define IOPW_IX 0x26 /* IX */
+#define IOPW_SP 0x28 /* SP */
+#define IOPW_PC 0x2A /* PC */
+#define IOPW_RES_ADDR_2C 0x2C
+#define IOPW_RES_ADDR_2E 0x2E
+#define IOPW_SCSI_DATA 0x30 /* SD */
+#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
+#define IOPW_SCSI_CTRL 0x34 /* SC */
+#define IOPW_HSHK_CFG 0x36 /* HCFG */
+#define IOPW_SXFR_STATUS 0x36 /* SXS */
+#define IOPW_SXFR_CNTL 0x38 /* SXL */
+#define IOPW_SXFR_CNTH 0x3A /* SXH */
+#define IOPW_RES_ADDR_3C 0x3C
+#define IOPW_RFIFO_DATA 0x3E /* RFD */
+
+/*
+ * Doubleword I/O register address from base of 'iop_base'.
+ */
+#define IOPDW_RES_ADDR_0 0x00
+#define IOPDW_RAM_DATA 0x04
+#define IOPDW_RES_ADDR_8 0x08
+#define IOPDW_RES_ADDR_C 0x0C
+#define IOPDW_RES_ADDR_10 0x10
+#define IOPDW_RES_ADDR_14 0x14
+#define IOPDW_RES_ADDR_18 0x18
+#define IOPDW_RES_ADDR_1C 0x1C
+#define IOPDW_SDMA_ADDR0 0x20
+#define IOPDW_SDMA_ADDR1 0x24
+#define IOPDW_SDMA_COUNT 0x28
+#define IOPDW_SDMA_ERROR 0x2C
+#define IOPDW_RDMA_ADDR0 0x30
+#define IOPDW_RDMA_ADDR1 0x34
+#define IOPDW_RDMA_COUNT 0x38
+#define IOPDW_RDMA_ERROR 0x3C
+
+#define ADW_CHIP_ID_BYTE 0x25
+#define ADW_CHIP_ID_WORD 0x04C1
+
+#define ADW_SC_SCSI_BUS_RESET 0x2000
+
+#define ADW_INTR_ENABLE_HOST_INTR 0x01
+#define ADW_INTR_ENABLE_SEL_INTR 0x02
+#define ADW_INTR_ENABLE_DPR_INTR 0x04
+#define ADW_INTR_ENABLE_RTA_INTR 0x08
+#define ADW_INTR_ENABLE_RMA_INTR 0x10
+#define ADW_INTR_ENABLE_RST_INTR 0x20
+#define ADW_INTR_ENABLE_DPE_INTR 0x40
+#define ADW_INTR_ENABLE_GLOBAL_INTR 0x80
+
+#define ADW_INTR_STATUS_INTRA 0x01
+#define ADW_INTR_STATUS_INTRB 0x02
+#define ADW_INTR_STATUS_INTRC 0x04
+
+#define ADW_RISC_CSR_STOP (0x0000)
+#define ADW_RISC_TEST_COND (0x2000)
+#define ADW_RISC_CSR_RUN (0x4000)
+#define ADW_RISC_CSR_SINGLE_STEP (0x8000)
+
+#define ADW_CTRL_REG_HOST_INTR 0x0100
+#define ADW_CTRL_REG_SEL_INTR 0x0200
+#define ADW_CTRL_REG_DPR_INTR 0x0400
+#define ADW_CTRL_REG_RTA_INTR 0x0800
+#define ADW_CTRL_REG_RMA_INTR 0x1000
+#define ADW_CTRL_REG_RES_BIT14 0x2000
+#define ADW_CTRL_REG_DPE_INTR 0x4000
+#define ADW_CTRL_REG_POWER_DONE 0x8000
+#define ADW_CTRL_REG_ANY_INTR 0xFF00
+
+#define ADW_CTRL_REG_CMD_RESET 0x00C6
+#define ADW_CTRL_REG_CMD_WR_IO_REG 0x00C5
+#define ADW_CTRL_REG_CMD_RD_IO_REG 0x00C4
+#define ADW_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
+#define ADW_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
+
+#define ADW_SCSI_CTRL_RSTOUT 0x2000
+
+#define ADW_IS_INT_PENDING(iot, ioh) \
+ (ADW_READ_WORD_REGISTER((iot), (ioh), IOPW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR)
+
+/*
+ * SCSI_CFG0 Register bit definitions
+ */
+#define ADW_TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
+#define ADW_PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
+#define ADW_EVEN_PARITY 0x1000 /* Select Even Parity */
+#define ADW_WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
+#define ADW_QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
+#define ADW_PRIM_MODE 0x0100 /* Primitive SCSI mode */
+#define ADW_SCAM_EN 0x0080 /* Enable SCAM selection */
+#define ADW_SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
+#define ADW_CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
+#define ADW_OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
+#define ADW_OUR_ID 0x000F /* SCSI ID */
+
+/*
+ * SCSI_CFG1 Register bit definitions
+ */
+#define ADW_BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
+#define ADW_TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
+#define ADW_SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
+#define ADW_FILTER_SEL 0x0C00 /* Filter Period Selection */
+#define ADW_FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
+#define ADW_FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
+#define ADW_FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
+#define ADW_ACTIVE_DBL 0x0200 /* Disable Active Negation */
+#define ADW_DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
+#define ADW_DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
+#define ADW_TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
+#define ADW_TERM_CTL 0x0030 /* External SCSI Termination Bits */
+#define ADW_TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
+#define ADW_TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
+#define ADW_CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
+
+#define CABLE_ILLEGAL_A 0x7
+ /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
+
+#define CABLE_ILLEGAL_B 0xB
+ /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
+
+/*
+ The following table details the SCSI_CFG1 Termination Polarity,
+ Termination Control and Cable Detect bits.
+
+ Cable Detect | Termination
+ Bit 3 2 1 0 | 5 4 | Notes
+ _____________|________|____________________
+ 1 1 1 0 | on on | Internal wide only
+ 1 1 0 1 | on on | Internal narrow only
+ 1 0 1 1 | on on | External narrow only
+ 0 x 1 1 | on on | External wide only
+ 1 1 0 0 | on off| Internal wide and internal narrow
+ 1 0 1 0 | on off| Internal wide and external narrow
+ 0 x 1 0 | off off| Internal wide and external wide
+ 1 0 0 1 | on off| Internal narrow and external narrow
+ 0 x 0 1 | on off| Internal narrow and external wide
+ 1 1 1 1 | on on | No devices are attached
+ x 0 0 0 | on on | Illegal (all 3 connectors are used)
+ 0 x 0 0 | on on | Illegal (all 3 connectors are used)
+
+ x means don't-care (either '0' or '1')
+
+ If term_pol (bit 13) is '0' (active-low terminator enable), then:
+ 'on' is '0' and 'off' is '1'.
+
+ If term_pol bit is '1' (meaning active-hi terminator enable), then:
+ 'on' is '1' and 'off' is '0'.
+ */
+
+/*
+ * MEM_CFG Register bit definitions
+ */
+#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
+#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
+#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
+#define RAM_SZ_2KB 0x00 /* 2 KB */
+#define RAM_SZ_4KB 0x04 /* 4 KB */
+#define RAM_SZ_8KB 0x08 /* 8 KB */
+#define RAM_SZ_16KB 0x0C /* 16 KB */
+#define RAM_SZ_32KB 0x10 /* 32 KB */
+#define RAM_SZ_64KB 0x14 /* 64 KB */
+
+/*
+ * DMA_CFG0 Register bit definitions
+ *
+ * This register is only accessible to the host.
+ */
+#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
+#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
+#define FIFO_THRESH_16B 0x00 /* 16 bytes */
+#define FIFO_THRESH_32B 0x20 /* 32 bytes */
+#define FIFO_THRESH_48B 0x30 /* 48 bytes */
+#define FIFO_THRESH_64B 0x40 /* 64 bytes */
+#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
+#define FIFO_THRESH_96B 0x60 /* 96 bytes */
+#define FIFO_THRESH_112B 0x70 /* 112 bytes */
+#define START_CTL 0x0C /* DMA start conditions */
+#define START_CTL_TH 0x00 /* Wait threshold level (default) */
+#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
+#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
+#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
+#define READ_CMD 0x03 /* Memory Read Method */
+#define READ_CMD_MR 0x00 /* Memory Read */
+#define READ_CMD_MRL 0x02 /* Memory Read Long */
+#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
+
+
+/*
+ * Adv Library Status Definitions
+ */
+#define ADW_TRUE 1
+#define ADW_FALSE 0
+#define ADW_NOERROR 1
+#define ADW_SUCCESS 1
+#define ADW_BUSY 0
+#define ADW_ERROR (-1)
+
+
+/*
+ * ASC_DVC_VAR 'warn_code' values
+ */
+#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
+#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
+#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
+#define ASC_WARN_ERROR 0xFFFF /* ADW_ERROR return */
+
+#define ADW_MAX_TID 15 /* max. target identifier */
+#define ADW_MAX_LUN 7 /* max. logical unit number */
+
+
+/*
+ * AscInitGetConfig() and AscInitAsc1000Driver() Definitions
+ *
+ * Error code values are set in ASC_DVC_VAR 'err_code'.
+ */
+#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
+#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
+#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
+#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
+#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
+#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
+#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
+#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
+#define ASC_IERR_RW_LRAM 0x8000 /* read/write local RAM error */
+
+/*
+ * Fixed locations of microcode operating variables.
+ */
+#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
+#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
+#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
+#define ASC_MC_STACK_BEGIN 0x002E /* microcode stack begin */
+#define ASC_MC_STACK_END 0x0030 /* microcode stack end */
+#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
+#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
+#define ASCV_VER_SERIAL_W 0x003C /* used in dos_init */
+#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
+#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
+#define ASC_MC_HALTCODE 0x0094 /* microcode halt code */
+#define ASC_MC_CALLERPC 0x0096 /* microcode halt caller PC */
+#define ASC_MC_ADAPTER_SCSI_ID 0x0098 /* one ID byte + reserved */
+#define ASC_MC_ULTRA_ABLE 0x009C
+#define ASC_MC_SDTR_ABLE 0x009E /* Sync. Transfer TID bitmask. */
+#define ASC_MC_TAGQNG_ABLE 0x00A0
+#define ASC_MC_DISC_ENABLE 0x00A2
+#define ASC_MC_IDLE_CMD 0x00A6
+#define ASC_MC_IDLE_PARA_STAT 0x00A8
+#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
+#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
+#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
+#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
+#define ASC_MC_RISC_NEXT_READY 0x00B4
+#define ASC_MC_RISC_NEXT_DONE 0x00B5
+#define ASC_MC_SDTR_DONE 0x00B6
+#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
+#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
+#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
+#define ASC_MC_WDTR_ABLE 0x0120 /* Wide Transfer TID bitmask. */
+#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
+#define ASC_MC_WDTR_DONE 0x0124
+#define ASC_MC_HOST_NEXT_READY 0x0128 /* Host Next Ready RQL Entry. */
+#define ASC_MC_HOST_NEXT_DONE 0x0129 /* Host Next Done RQL Entry. */
+
+/*
+ * BIOS LRAM variable absolute offsets.
+ */
+#define BIOS_CODESEG 0x54
+#define BIOS_CODELEN 0x56
+#define BIOS_SIGNATURE 0x58
+#define BIOS_VERSION 0x5A
+#define BIOS_SIGNATURE 0x58
+
+/*
+ * Microcode Control Flags
+ *
+ * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
+ * and handled by the microcode.
+ */
+#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
+
+/*
+ * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
+ */
+#define HSHK_CFG_WIDE_XFR 0x8000
+#define HSHK_CFG_RATE 0x0F00
+#define HSHK_CFG_OFFSET 0x001F
+
+/*
+ * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF)
+ *
+ * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes
+ * starting at LRAM address 0x1200 is 8 bytes and has the following
+ * structure. Only 253 of these are actually used for command queues.
+ */
+
+#define ASC_MC_RISC_Q_LIST_BASE 0x1200
+#define ASC_MC_RISC_Q_LIST_SIZE 0x0008
+#define ASC_MC_RISC_Q_TOTAL_CNT 0x00FF /* Num. queue slots in LRAM. */
+#define ASC_MC_RISC_Q_FIRST 0x0001
+#define ASC_MC_RISC_Q_LAST 0x00FF
+
+#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
+#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
+#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
+#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
+
+/* RISC Queue List structure - 8 bytes */
+#define RQL_FWD 0 /* forward pointer (1 byte) */
+#define RQL_BWD 1 /* backward pointer (1 byte) */
+#define RQL_STATE 2 /* state byte - free, ready, done, aborted (1 byte) */
+#define RQL_TID 3 /* request target id (1 byte) */
+#define RQL_PHYADDR 4 /* request physical pointer (4 bytes) */
+
+/* RISC Queue List state values */
+#define ASC_MC_QS_FREE 0x00
+#define ASC_MC_QS_READY 0x01
+#define ASC_MC_QS_DONE 0x40
+#define ASC_MC_QS_ABORTED 0x80
+
+/* RISC Queue List pointer values */
+#define ASC_MC_NULL_Q 0x00 /* NULL_Q == 0 */
+#define ASC_MC_BIOS_Q 0xFF /* BIOS_Q = 255 */
+
+/* ASC_SCSI_REQ_Q 'cntl' field values */
+#define ASC_MC_QC_START_MOTOR 0x02 /* Issue start motor. */
+#define ASC_MC_QC_NO_OVERRUN 0x04 /* Don't report overrun. */
+#define ASC_MC_QC_FIRST_DMA 0x08 /* Internal microcode flag. */
+#define ASC_MC_QC_ABORTED 0x10 /* Request aborted by host. */
+#define ASC_MC_QC_REQ_SENSE 0x20 /* Auto-Request Sense. */
+#define ASC_MC_QC_DOS_REQ 0x80 /* Request issued by DOS. */
+
+
+/*
+ * ASC_SCSI_REQ_Q 'a_flag' definitions
+ *
+ * The Adv Library should limit use to the lower nibble (4 bits) of
+ * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
+ */
+#define ADW_POLL_REQUEST 0x01 /* poll for request completion */
+#define ADW_SCSIQ_DONE 0x02 /* request done */
+
+/*
+ * Adapter temporary configuration structure
+ *
+ * This structure can be discarded after initialization. Don't add
+ * fields here needed after initialization.
+ *
+ * Field naming convention:
+ *
+ * *_enable indicates the field enables or disables a feature. The
+ * value of the field is never reset.
+ */
+typedef struct adw_dvc_cfg {
+ u_int16_t disc_enable; /* enable disconnection */
+ u_int8_t chip_version; /* chip version */
+ u_int8_t termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
+ u_int16_t pci_device_id; /* PCI device code number */
+ u_int16_t lib_version; /* Adv Library version number */
+ u_int16_t control_flag; /* Microcode Control Flag */
+ u_int16_t mcode_date; /* Microcode date */
+ u_int16_t mcode_version; /* Microcode version */
+ u_int16_t pci_slot_info; /* high byte device/function number */
+ /* bits 7-3 device num., bits 2-0 function num. */
+ /* low byte bus num. */
+ u_int16_t bios_boot_wait; /* BIOS boot time delay */
+ u_int16_t serial1; /* EEPROM serial number word 1 */
+ u_int16_t serial2; /* EEPROM serial number word 2 */
+ u_int16_t serial3; /* EEPROM serial number word 3 */
+} ADW_DVC_CFG;
+
+/*
+ * Adapter operation variable structure.
+ *
+ * One structure is required per host adapter.
+ *
+ * Field naming convention:
+ *
+ * *_able indicates both whether a feature should be enabled or disabled
+ * and whether a device is capable of the feature. At initialization
+ * this field may be set, but later if a device is found to be incapable
+ * of the feature, the field is cleared.
+ */
+typedef struct adw_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 */
+ void *sc_ih;
+
+ struct adw_control *sc_control; /* control structures */
+ TAILQ_HEAD(, adw_ccb) sc_free_ccb, sc_waiting_ccb;
+ struct scsi_link sc_link; /* prototype for devs */
+
+ LIST_HEAD(, scsi_xfer) sc_queue;
+ struct scsi_xfer *sc_queuelast;
+
+ u_int32_t sc_flags; /* see below sc_flags values */
+
+ u_int16_t bios_ctrl; /* BIOS control word, EEPROM word 12 */
+ ulong isr_callback; /* pointer to function, called in AdvISR() */
+ ulong sbreset_callback; /* pointer to function, called in AdvISR() */
+ u_int16_t wdtr_able; /* try WDTR for a device */
+ u_int16_t sdtr_able; /* try SDTR for a device */
+ u_int16_t ultra_able; /* try SDTR Ultra speed for a device */
+ u_int16_t tagqng_able; /* try tagged queuing with a device */
+ u_int8_t max_dvc_qng; /* maximum number of tagged commands per device */
+ u_int16_t start_motor; /* start motor command allowed */
+ u_int8_t scsi_reset_wait; /* delay in seconds after scsi bus reset */
+ u_int8_t chip_no; /* should be assigned by caller */
+ u_int8_t max_host_qng; /* maximum number of Q'ed command allowed */
+ u_int8_t cur_host_qng; /* total number of queue command */
+ u_int8_t irq_no; /* IRQ number */
+ u_int16_t no_scam; /* scam_tolerant of EEPROM */
+ u_int16_t idle_cmd_done; /* microcode idle command done set by AdvISR() */
+ ulong drv_ptr; /* driver pointer to private structure */
+ u_int8_t chip_scsi_id; /* chip SCSI target ID */
+ /*
+ * Note: The following fields will not be used after initialization. The
+ * driver may discard the buffer after initialization is done.
+ */
+ ADW_DVC_CFG cfg; /* temporary configuration structure */
+} ADW_SOFTC;
+
+/* sc_flags values */
+#define ADW_WIDE_BOARD 0x04
+
+
+#define ADW_IS_NARROW_BOARD(sc) (((sc)->sc_flags & ADW_WIDE_BOARD) == 0)
+#define ADW_IS_WIDE_BOARD(sc) ((sc)->sc_flags & ADW_WIDE_BOARD)
+
+
+#define NO_OF_SG_PER_BLOCK 15
+
+typedef struct adw_sg_block {
+ u_int8_t reserved1;
+ u_int8_t reserved2;
+ u_int8_t first_entry_no; /* starting entry number */
+ u_int8_t last_entry_no; /* last entry number */
+ struct adw_sg_block *sg_ptr; /* links to the next sg block */
+ struct {
+ u_int32_t sg_addr; /* SG element address */
+ u_int32_t sg_count; /* SG element count */
+ } sg_list[NO_OF_SG_PER_BLOCK];
+} ADW_SG_BLOCK;
+
+/*
+ * ADW_SCSI_REQ_Q - microcode request structure
+ *
+ * All fields in this structure up to byte 60 are used by the microcode.
+ * The microcode makes assumptions about the size and ordering of fields
+ * in this structure. Do not change the structure definition here without
+ * coordinating the change with the microcode.
+ */
+typedef struct adw_scsi_req_q {
+ u_int8_t cntl; /* Ucode flags and state (ASC_MC_QC_*). */
+ u_int8_t sg_entry_cnt; /* SG element count. Zero for no SG. */
+ u_int8_t target_id; /* Device target identifier. */
+ u_int8_t target_lun; /* Device target logical unit number. */
+ ulong data_addr; /* Data buffer physical address. */
+ u_int32_t data_cnt; /* Data count. Ucode sets to residual. */
+ ulong sense_addr; /* Sense buffer physical address. */
+ ulong ccb_ptr; /* Driver request pointer. */
+ u_int8_t a_flag; /* Adv Library flag field. */
+ u_int8_t sense_len; /* Auto-sense length. Ucode sets to residual. */
+ u_int8_t cdb_len; /* SCSI CDB length. */
+ u_int8_t tag_code; /* SCSI-2 Tag Queue Code: 00, 20-22. */
+ u_int8_t done_status; /* Completion status. */
+ u_int8_t scsi_status; /* SCSI status byte. (see below) */
+ u_int8_t host_status; /* Ucode host status. */
+ u_int8_t ux_sg_ix; /* Ucode working SG variable. */
+ u_int8_t cdb[12]; /* SCSI command block. */
+ ulong sg_real_addr; /* SG list physical address. */
+ struct adw_scsi_req_q *free_scsiq_link;
+ ulong ux_wk_data_cnt; /* Saved data count at disconnection. */
+ struct adw_scsi_req_q *scsiq_ptr;
+ ADW_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
+ /*
+ * End of microcode structure - 60 bytes. The rest of the structure
+ * is used by the Adv Library and ignored by the microcode.
+ */
+ ulong vsense_addr; /* Sense buffer virtual address. */
+ ulong vdata_addr; /* Data buffer virtual address. */
+ u_int8_t orig_sense_len; /* Original length of sense buffer. */
+ u_int8_t pads[3]; /* padding bytes (align to long) */
+} ADW_SCSI_REQ_Q;
+
+/*
+ * scsi_status conditions
+ */
+#define SS_GOOD 0x00
+#define SS_CHK_CONDITION 0x02
+#define SS_CONDITION_MET 0x04
+#define SS_TARGET_BUSY 0x08
+#define SS_INTERMID 0x10
+#define SS_INTERMID_COND_MET 0x14
+#define SS_RSERV_CONFLICT 0x18
+#define SS_CMD_TERMINATED 0x22
+#define SS_QUEUE_FULL 0x28
+
+/*
+ * Microcode idle loop commands
+ */
+#define IDLE_CMD_COMPLETED 0
+#define IDLE_CMD_STOP_CHIP 0x0001
+#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
+#define IDLE_CMD_SEND_INT 0x0004
+#define IDLE_CMD_ABORT 0x0008
+#define IDLE_CMD_DEVICE_RESET 0x0010
+#define IDLE_CMD_SCSI_RESET 0x0020
+
+/*
+ * AdvSendIdleCmd() flag definitions.
+ */
+#define ADW_NOWAIT 0x01
+
+/*
+ * Wait loop time out values.
+ */
+#define SCSI_WAIT_10_SEC 10 /* 10 seconds */
+#define SCSI_MS_PER_SEC 1000 /* milliseconds per second */
+
+
+/* Read byte from a register. */
+#define ADW_READ_BYTE_REGISTER(iot, ioh, reg_off) \
+ bus_space_read_1((iot), (ioh), (reg_off))
+
+/* Write byte to a register. */
+#define ADW_WRITE_BYTE_REGISTER(iot, ioh, reg_off, byte) \
+ bus_space_write_1((iot), (ioh), (reg_off), (byte))
+
+/* Read word (2 bytes) from a register. */
+#define ADW_READ_WORD_REGISTER(iot, ioh, reg_off) \
+ bus_space_read_2((iot), (ioh), (reg_off))
+
+/* Write word (2 bytes) to a register. */
+#define ADW_WRITE_WORD_REGISTER(iot, ioh, reg_off, word) \
+ bus_space_write_2((iot), (ioh), (reg_off), (word))
+
+/* Read byte from LRAM. */
+#define ADW_READ_BYTE_LRAM(iot, ioh, addr, byte) \
+do { \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_ADDR, (addr)); \
+ (byte) = bus_space_read_1((iot), (ioh), IOPB_RAM_DATA); \
+} while (0)
+
+/* Write byte to LRAM. */
+#define ADW_WRITE_BYTE_LRAM(iot, ioh, addr, byte) \
+do { \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_ADDR, (addr)); \
+ bus_space_write_1((iot), (ioh), IOPB_RAM_DATA, (byte)); \
+} while (0)
+
+/* Read word (2 bytes) from LRAM. */
+#define ADW_READ_WORD_LRAM(iot, ioh, addr, word) \
+do { \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_ADDR, (addr)); \
+ (word) = bus_space_read_2((iot), (ioh), IOPW_RAM_DATA); \
+} while (0)
+
+/* Write word (2 bytes) to LRAM. */
+#define ADW_WRITE_WORD_LRAM(iot, ioh, addr, word) \
+do { \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_ADDR, (addr)); \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_DATA, (word)); \
+} while (0)
+
+/* Write double word (4 bytes) to LRAM */
+/* Because of unspecified C language ordering don't use auto-increment. */
+#define ADW_WRITE_DWORD_LRAM(iot, ioh, addr, dword) \
+do { \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_ADDR, (addr)); \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_DATA, \
+ (ushort) ((dword) & 0xFFFF)); \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_ADDR, (addr) + 2); \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_DATA, \
+ (ushort) ((dword >> 16) & 0xFFFF)); \
+} while (0)
+
+/* Read word (2 bytes) from LRAM assuming that the address is already set. */
+#define ADW_READ_WORD_AUTO_INC_LRAM(iot, ioh) \
+ bus_space_read_2((iot), (ioh), IOPW_RAM_DATA) \
+
+/* Write word (2 bytes) to LRAM assuming that the address is already set. */
+#define ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh, word) \
+ bus_space_write_2((iot), (ioh), IOPW_RAM_DATA, (word))
+
+/*
+ * Define macro to check for Condor signature.
+ *
+ * Evaluate to ADW_TRUE if a Condor chip is found the specified port
+ * address 'iop_base'. Otherwise evalue to ADW_FALSE.
+ */
+#define ADW_FIND_SIGNATURE(iot, ioh) \
+ (((ADW_READ_BYTE_REGISTER((iot), (ioh), IOPB_CHIP_ID_1) == \
+ ADW_CHIP_ID_BYTE) && \
+ (ADW_READ_WORD_REGISTER((iot), (ioh), IOPW_CHIP_ID_0) == \
+ ADW_CHIP_ID_WORD)) ? ADW_TRUE : ADW_FALSE)
+
+/*
+ * Define macro to Return the version number of the chip at 'iop_base'.
+ *
+ * The second parameter 'bus_type' is currently unused.
+ */
+#define ADW_GET_CHIP_VERSION(iot, ioh, bus_type) \
+ ADW_READ_BYTE_REGISTER((iot), (ioh), IOPB_CHIP_TYPE_REV)
+
+/*
+ * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
+ * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
+ *
+ * If the request has not yet been sent to the device it will simply be
+ * aborted from RISC memory. If the request is disconnected it will be
+ * aborted on reselection by sending an Abort Message to the target ID.
+ *
+ * Return value:
+ * ADW_TRUE(1) - Queue was successfully aborted.
+ * ADW_FALSE(0) - Queue was not found on the active queue list.
+ */
+#define ADW_ABORT_CCB(sc, ccb_ptr) \
+ AdvSendIdleCmd((sc), (u_int16_t) IDLE_CMD_ABORT, \
+ (ulong) (ccb_ptr), 0)
+
+/*
+ * Send a Bus Device Reset Message to the specified target ID.
+ *
+ * All outstanding commands will be purged if sending the
+ * Bus Device Reset Message is successful.
+ *
+ * Return Value:
+ * ADW_TRUE(1) - All requests on the target are purged.
+ * ADW_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
+ * are not purged.
+ */
+#define ADW_RESET_DEVICE(sc, target_id) \
+ AdvSendIdleCmd((sc), (u_int16_t) IDLE_CMD_DEVICE_RESET, \
+ (ulong) (target_id), 0)
+
+/*
+ * SCSI Wide Type definition.
+ */
+#define ADW_SCSI_BIT_ID_TYPE ushort
+
+/*
+ * AdvInitScsiTarget() 'cntl_flag' options.
+ */
+#define ADW_SCAN_LUN 0x01
+#define ADW_CAPINFO_NOLUN 0x02
+
+/*
+ * Convert target id to target id bit mask.
+ */
+#define ADW_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADW_MAX_TID))
+
+/*
+ * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
+ */
+
+#define QD_NO_STATUS 0x00 /* Request not completed yet. */
+#define QD_NO_ERROR 0x01
+#define QD_ABORTED_BY_HOST 0x02
+#define QD_WITH_ERROR 0x04
+
+#define QHSTA_NO_ERROR 0x00
+#define QHSTA_M_SEL_TIMEOUT 0x11
+#define QHSTA_M_DATA_OVER_RUN 0x12
+#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
+#define QHSTA_M_QUEUE_ABORTED 0x15
+#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
+#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
+#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
+#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
+#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
+#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
+#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
+/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
+#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
+#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
+#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
+#define QHSTA_M_WTM_TIMEOUT 0x41
+#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
+#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
+#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
+#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
+
+/*
+ * SCSI Iquiry structure
+ */
+
+typedef struct
+{
+ u_int8_t peri_dvc_type:5;
+ u_int8_t peri_qualifier:3;
+} ASC_SCSI_INQ0;
+
+typedef struct
+{
+ u_int8_t dvc_type_modifier:7;
+ u_int8_t rmb:1;
+} ASC_SCSI_INQ1;
+
+typedef struct
+{
+ u_int8_t ansi_apr_ver:3;
+ u_int8_t ecma_ver:3;
+ u_int8_t iso_ver:2;
+} ASC_SCSI_INQ2;
+
+typedef struct
+{
+ u_int8_t rsp_data_fmt:4;
+ u_int8_t res:2;
+ u_int8_t TemIOP:1;
+ u_int8_t aenc:1;
+} ASC_SCSI_INQ3;
+
+typedef struct
+{
+ u_int8_t StfRe:1;
+ u_int8_t CmdQue:1;
+ u_int8_t Reserved:1;
+ u_int8_t Linked:1;
+ u_int8_t Sync:1;
+ u_int8_t WBus16:1;
+ u_int8_t WBus32:1;
+ u_int8_t RelAdr:1;
+} ASC_SCSI_INQ7;
+
+typedef struct
+{
+ ASC_SCSI_INQ0 byte0;
+ ASC_SCSI_INQ1 byte1;
+ ASC_SCSI_INQ2 byte2;
+ ASC_SCSI_INQ3 byte3;
+ u_int8_t add_len;
+ u_int8_t res1;
+ u_int8_t res2;
+ ASC_SCSI_INQ7 byte7;
+ u_int8_t vendor_id[8];
+ u_int8_t product_id[16];
+ u_int8_t product_rev_level[4];
+} ASC_SCSI_INQUIRY;
+
+
+#define ASC_MAX_SENSE_LEN 32
+#define ASC_MIN_SENSE_LEN 14
+
+typedef struct asc_req_sense {
+ u_int8_t err_code:7;
+ u_int8_t info_valid:1;
+ u_int8_t segment_no;
+ u_int8_t sense_key:4;
+ u_int8_t reserved_bit:1;
+ u_int8_t sense_ILI:1;
+ u_int8_t sense_EOM:1;
+ u_int8_t file_mark:1;
+ u_int8_t info1[4];
+ u_int8_t add_sense_len;
+ u_int8_t cmd_sp_info[4];
+ u_int8_t asc;
+ u_int8_t ascq;
+ u_int8_t fruc;
+ u_int8_t sks_byte0:7;
+ u_int8_t sks_valid:1;
+ u_int8_t sks_bytes[2];
+ u_int8_t notused[2];
+ u_int8_t ex_sense_code;
+ u_int8_t info2[4];
+} ASC_REQ_SENSE;
+
+
+/*
+ * Adv Library functions available to drivers.
+ */
+
+int AdvInitFromEEP __P((ADW_SOFTC *));
+int AdvExeScsiQueue __P((ADW_SOFTC *, ADW_SCSI_REQ_Q *));
+int AdvISR __P((ADW_SOFTC *));
+int AdvSendIdleCmd __P((ADW_SOFTC *, u_int16_t, u_int32_t, int));
+int AdvInitGetConfig __P((ADW_SOFTC *));
+int AdvInitAsc3550Driver __P((ADW_SOFTC *));
+void AdvResetChip __P((bus_space_tag_t, bus_space_handle_t));
+void AdvResetSCSIBus __P((ADW_SOFTC *));
+int AdvResetCCB __P((ADW_SOFTC *));
+
+#define offsetof(type, member) ((size_t)(&((type *)0)->member))
+
+#endif /* _ADVANSYS_WIDE_LIBRARY_H_ */
diff --git a/sys/dev/ic/adwmcode.c b/sys/dev/ic/adwmcode.c
new file mode 100644
index 00000000000..30315e73417
--- /dev/null
+++ b/sys/dev/ic/adwmcode.c
@@ -0,0 +1,361 @@
+/* $OpenBSD: adwmcode.c,v 1.1 1998/11/17 06:14:58 downsj Exp $ */
+/* $NetBSD: adwmcode.c,v 1.1 1998/09/26 16:10:42 dante Exp $ */
+
+/*
+ * Generic driver definitions and exported functions for the Advanced
+ * Systems Inc. SCSI controllers
+ *
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Author: Baldassare Dante Profeta <dante@mclink.it>
+ *
+ * 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.
+ */
+/*
+ * Ported from:
+ */
+/*
+ * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
+ *
+ * Copyright (c) 1995-1998 Advanced System Products, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ */
+
+
+#include <sys/param.h>
+
+
+/*
+ * This is the uCode for the Wide board RISC cpu.
+ * This code is loaded into Lram during initializzation procedure.
+ */
+u_int8_t adv_mcode[] = {
+ 0x9C, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x44, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x01, 0xD6, 0x11, 0x00, 0x00, 0x70, 0x01,
+ 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x10, 0x2D, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x0C, 0x1C, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF2, 0xD6, 0x0A,
+ 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x3E, 0x57, 0x3C, 0x56, 0x0C, 0x1C, 0x00, 0xFC,
+ 0xA6, 0x00, 0x01, 0x58, 0xAA, 0x13, 0x20, 0xF0, 0xA6, 0x03, 0x06, 0xEC, 0xB9, 0x00, 0x0E, 0x47,
+ 0x03, 0xE6, 0x10, 0x00, 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0x06, 0xEA, 0xB9, 0x00, 0x47, 0x4B,
+ 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x4E, 0x12, 0x03, 0xF6, 0xC0, 0x00,
+ 0x00, 0xF2, 0x68, 0x0A, 0x41, 0x58, 0x03, 0xF6, 0xD0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x49, 0x44,
+ 0x59, 0xF0, 0x0A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x44, 0x58, 0x00, 0xF2,
+ 0xE2, 0x0D, 0x02, 0xCC, 0x4A, 0xE4, 0x01, 0x00, 0x55, 0xF0, 0x08, 0x03, 0x45, 0xF4, 0x02, 0x00,
+ 0x83, 0x5A, 0x04, 0xCC, 0x01, 0x4A, 0x12, 0x12, 0x00, 0xF2, 0xE2, 0x0D, 0x00, 0xCD, 0x48, 0xE4,
+ 0x01, 0x00, 0xE9, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0xFA, 0x10, 0x0E, 0x47, 0x03, 0xE6, 0x10, 0x00,
+ 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0xCE, 0x47, 0x97, 0x13, 0x04, 0xEC, 0xB4, 0x00, 0x00, 0xF2,
+ 0xE2, 0x0D, 0x00, 0xCD, 0x48, 0xE4, 0x00, 0x00, 0x12, 0x12, 0x3E, 0x57, 0x06, 0xCC, 0x45, 0xF4,
+ 0x02, 0x00, 0x83, 0x5A, 0x00, 0xCC, 0x00, 0xEA, 0xB4, 0x00, 0x92, 0x10, 0x00, 0xF0, 0x8C, 0x01,
+ 0x43, 0xF0, 0x5C, 0x02, 0x44, 0xF0, 0x60, 0x02, 0x45, 0xF0, 0x64, 0x02, 0x46, 0xF0, 0x68, 0x02,
+ 0x47, 0xF0, 0x6E, 0x02, 0x48, 0xF0, 0x9E, 0x02, 0xB9, 0x54, 0x62, 0x10, 0x00, 0x1C, 0x5A, 0x10,
+ 0x02, 0x1C, 0x56, 0x10, 0x1E, 0x1C, 0x52, 0x10, 0x00, 0xF2, 0x1E, 0x11, 0x50, 0x10, 0x06, 0xFC,
+ 0xA8, 0x00, 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x4E, 0x0A, 0x8C, 0x10, 0x01, 0xF6, 0x01, 0x00,
+ 0x01, 0xFA, 0xA8, 0x00, 0x00, 0xF2, 0x2C, 0x0B, 0x06, 0x10, 0xB9, 0x54, 0x01, 0xFA, 0xA8, 0x00,
+ 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x58, 0x0A, 0x01, 0xFC, 0xA8, 0x00, 0x20, 0x10, 0x58, 0x1C,
+ 0x00, 0xF2, 0x1C, 0x0B, 0x5A, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, 0x00, 0xFA, 0xA6, 0x00,
+ 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x72, 0x01, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54,
+ 0x00, 0xFA, 0xA6, 0x00, 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x80, 0x01, 0x03, 0xF6,
+ 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x0A, 0x13, 0x00, 0xF2, 0x38, 0x10, 0x00, 0xF2,
+ 0x54, 0x0F, 0x24, 0x10, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x02, 0xF6, 0xD0, 0x00,
+ 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x49, 0x44, 0x5B, 0xF0, 0x04, 0x03, 0x00, 0xF2, 0x9C, 0x0F,
+ 0x00, 0xF0, 0x80, 0x01, 0x00, 0xF2, 0x14, 0x10, 0x0C, 0x1C, 0x02, 0x4B, 0xBF, 0x57, 0x9E, 0x43,
+ 0x77, 0x57, 0x07, 0x4B, 0x20, 0xF0, 0xA6, 0x03, 0x40, 0x1C, 0x1E, 0xF0, 0x30, 0x03, 0x26, 0xF0,
+ 0x2C, 0x03, 0xA0, 0xF0, 0x1A, 0x03, 0x11, 0xF0, 0xA6, 0x03, 0x12, 0x10, 0x9F, 0xF0, 0x3E, 0x03,
+ 0x46, 0x1C, 0x82, 0xE7, 0x05, 0x00, 0x9E, 0xE7, 0x11, 0x00, 0x00, 0xF0, 0x06, 0x0A, 0x0C, 0x1C,
+ 0x48, 0x1C, 0x46, 0x1C, 0x38, 0x54, 0x00, 0xEC, 0xBA, 0x00, 0x08, 0x44, 0x00, 0xEA, 0xBA, 0x00,
+ 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x08, 0x44, 0x00, 0x4C, 0x82, 0xE7, 0x02, 0x00,
+ 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x70, 0x03, 0x00, 0xF2, 0x60, 0x0B,
+ 0x06, 0xF0, 0x80, 0x03, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A,
+ 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x55, 0xF0, 0xAC, 0x04, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2,
+ 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x01, 0xF0,
+ 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x46, 0x1C, 0x0C, 0x1C, 0x67, 0x1B, 0xBF, 0x57, 0x77, 0x57,
+ 0x02, 0x4B, 0x48, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x92, 0x0D, 0x30, 0x1C, 0x96, 0xF0, 0xBC, 0x03,
+ 0xB1, 0xF0, 0xC0, 0x03, 0x1E, 0xF0, 0xFC, 0x09, 0x85, 0xF0, 0x02, 0x0A, 0x00, 0xFC, 0xBE, 0x00,
+ 0x98, 0x57, 0x14, 0x12, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11,
+ 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A,
+ 0x01, 0x48, 0x55, 0xF0, 0x98, 0x04, 0x03, 0x82, 0x03, 0xFC, 0xA0, 0x00, 0x9B, 0x57, 0x40, 0x12,
+ 0x69, 0x18, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x42, 0x04, 0x69, 0x08, 0x00, 0xF2, 0x12, 0x11,
+ 0x85, 0xF0, 0x02, 0x0A, 0x68, 0x08, 0x4C, 0x44, 0x28, 0x12, 0x44, 0x48, 0x03, 0xF6, 0xE0, 0x00,
+ 0x00, 0xF2, 0x68, 0x0A, 0x45, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xCC, 0x01, 0x48, 0x55, 0xF0,
+ 0x98, 0x04, 0x4C, 0x44, 0xEF, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2, 0x14, 0x10, 0x08, 0x10,
+ 0x68, 0x18, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0x04, 0x80, 0x18, 0xE4, 0x10, 0x00, 0x28, 0x12,
+ 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00,
+ 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00,
+ 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x69, 0x08, 0x05, 0x80, 0x48, 0xE4, 0x00, 0x00,
+ 0x0C, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2, 0xB6, 0x10, 0x82, 0xE7,
+ 0x02, 0x00, 0x1C, 0x90, 0x40, 0x5C, 0x00, 0x16, 0x01, 0xE6, 0x06, 0x00, 0x00, 0xF2, 0x4E, 0x0D,
+ 0x01, 0xF0, 0x80, 0x01, 0x1E, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0xA0, 0x04, 0x42, 0x5B, 0x06, 0xF7,
+ 0x03, 0x00, 0x46, 0x59, 0xBF, 0x57, 0x77, 0x57, 0x01, 0xE6, 0x80, 0x00, 0x07, 0x80, 0x31, 0x44,
+ 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x56, 0x13, 0x20, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x4E, 0x12,
+ 0x00, 0xFC, 0xA2, 0x00, 0x98, 0x57, 0x55, 0xF0, 0x1C, 0x05, 0x31, 0xE4, 0x40, 0x00, 0x00, 0xFC,
+ 0xA0, 0x00, 0x98, 0x57, 0x36, 0x12, 0x4C, 0x1C, 0x00, 0xF2, 0x12, 0x11, 0x89, 0x48, 0x00, 0xF2,
+ 0x12, 0x11, 0x86, 0xF0, 0x2E, 0x05, 0x82, 0xE7, 0x06, 0x00, 0x1B, 0x80, 0x48, 0xE4, 0x22, 0x00,
+ 0x5B, 0xF0, 0x0C, 0x05, 0x48, 0xE4, 0x20, 0x00, 0x59, 0xF0, 0x10, 0x05, 0x00, 0xE6, 0x20, 0x00,
+ 0x09, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0x2E, 0x05, 0x83, 0x80, 0x04, 0x10, 0x00, 0xF2,
+ 0xA2, 0x0D, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x26, 0x01, 0x01, 0xEA, 0x27, 0x01, 0x04, 0x80,
+ 0x18, 0xE4, 0x10, 0x00, 0x36, 0x12, 0xB9, 0x54, 0x00, 0xF2, 0xF6, 0x0E, 0x01, 0xE6, 0x06, 0x00,
+ 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4E, 0x0D,
+ 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x04, 0xE6, 0x02, 0x00,
+ 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0xFC, 0x20, 0x01,
+ 0x98, 0x57, 0x34, 0x12, 0x00, 0xFC, 0x24, 0x01, 0x98, 0x57, 0x2C, 0x13, 0xB9, 0x54, 0x00, 0xF2,
+ 0xF6, 0x0E, 0x86, 0xF0, 0xA8, 0x05, 0x03, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0x8C, 0x0E, 0x85, 0xF0,
+ 0x9E, 0x05, 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC,
+ 0x24, 0x01, 0xB0, 0x57, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFC, 0x9E, 0x00, 0x98, 0x57, 0x5A, 0x12,
+ 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57, 0x52, 0x13, 0x03, 0xE6, 0x0C, 0x00, 0x00, 0xFC, 0x9C, 0x00,
+ 0x98, 0x57, 0x04, 0x13, 0x03, 0xE6, 0x19, 0x00, 0x05, 0xE6, 0x08, 0x00, 0x00, 0xF6, 0x00, 0x01,
+ 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x04, 0x13, 0x05, 0xE6,
+ 0x0F, 0x00, 0xB9, 0x54, 0x00, 0xF2, 0xF6, 0x0E, 0x86, 0xF0, 0x0A, 0x06, 0x00, 0xF2, 0xBA, 0x0E,
+ 0x85, 0xF0, 0x00, 0x06, 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x82, 0xE7, 0x02, 0x00,
+ 0x00, 0xFC, 0xB6, 0x00, 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0xF2,
+ 0xF6, 0x0E, 0x9C, 0x32, 0x4E, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x92, 0x0D, 0x30, 0x1C, 0x82, 0xE7,
+ 0x04, 0x00, 0xB1, 0xF0, 0x22, 0x06, 0x0A, 0xF0, 0x3E, 0x06, 0x05, 0xF0, 0xD6, 0x06, 0x06, 0xF0,
+ 0xDC, 0x06, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A, 0x04, 0x80,
+ 0x18, 0xE4, 0x20, 0x00, 0x30, 0x12, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x21, 0x80,
+ 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2,
+ 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x99, 0xA4, 0x00, 0xF2, 0x12, 0x11,
+ 0x09, 0xE7, 0x00, 0x00, 0x9A, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x34, 0x12, 0x09, 0xE7,
+ 0x1B, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2,
+ 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2,
+ 0x12, 0x11, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF0,
+ 0x0C, 0x09, 0xBB, 0x55, 0x9A, 0x81, 0x03, 0xF7, 0x20, 0x00, 0x09, 0x6F, 0x93, 0x45, 0x55, 0xF0,
+ 0xE2, 0x06, 0xB1, 0xF0, 0xC2, 0x06, 0x0A, 0xF0, 0xBA, 0x06, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0,
+ 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0xF2, 0x60, 0x0B, 0x47, 0x10, 0x09, 0xE7, 0x08, 0x00,
+ 0x41, 0x10, 0x05, 0x80, 0x48, 0xE4, 0x00, 0x00, 0x1E, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA,
+ 0xB8, 0x00, 0x00, 0xF2, 0xB6, 0x10, 0x2C, 0x90, 0xAE, 0x90, 0x08, 0x50, 0x8A, 0x50, 0x38, 0x54,
+ 0x1F, 0x40, 0x00, 0xF2, 0xB4, 0x0D, 0x08, 0x10, 0x08, 0x90, 0x8A, 0x90, 0x30, 0x50, 0xB2, 0x50,
+ 0x9C, 0x32, 0x0C, 0x92, 0x8E, 0x92, 0x38, 0x54, 0x04, 0x80, 0x30, 0xE4, 0x08, 0x00, 0x04, 0x40,
+ 0x0C, 0x1C, 0x00, 0xF6, 0x03, 0x00, 0xB1, 0xF0, 0x26, 0x07, 0x9E, 0xF0, 0x3A, 0x07, 0x01, 0x48,
+ 0x55, 0xF0, 0xFC, 0x09, 0x0C, 0x1C, 0x10, 0x44, 0xED, 0x10, 0x0B, 0xF0, 0x5E, 0x07, 0x0C, 0xF0,
+ 0x62, 0x07, 0x05, 0xF0, 0x52, 0x07, 0x06, 0xF0, 0x58, 0x07, 0x09, 0xF0, 0x24, 0x09, 0x00, 0xF0,
+ 0x02, 0x0A, 0x00, 0xF2, 0x60, 0x0B, 0xCF, 0x10, 0x09, 0xE7, 0x08, 0x00, 0xC9, 0x10, 0x2E, 0x1C,
+ 0x02, 0x10, 0x2C, 0x1C, 0xAA, 0xF0, 0x64, 0x07, 0xAC, 0xF0, 0x72, 0x07, 0x40, 0x10, 0x34, 0x1C,
+ 0xF3, 0x10, 0xAD, 0xF0, 0x7C, 0x07, 0xC8, 0x10, 0x36, 0x1C, 0xE9, 0x10, 0x2B, 0xF0, 0x82, 0x08,
+ 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFE, 0x20, 0x12, 0x01, 0x58, 0xD2, 0xF0, 0x82, 0x08, 0x76, 0x18,
+ 0x18, 0xF4, 0x03, 0x00, 0xEC, 0x12, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xE2, 0x12,
+ 0x0B, 0xF0, 0x64, 0x07, 0x0C, 0xF0, 0x64, 0x07, 0x36, 0x1C, 0x34, 0x1C, 0xB7, 0x10, 0x38, 0x54,
+ 0xB9, 0x54, 0x84, 0x80, 0x19, 0xE4, 0x20, 0x00, 0xB2, 0x13, 0x85, 0x80, 0x81, 0x48, 0x66, 0x12,
+ 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x58, 0x13, 0x1F, 0x80, 0x08, 0x44, 0xC8, 0x44, 0x9F, 0x12,
+ 0x1F, 0x40, 0x34, 0x91, 0xB6, 0x91, 0x44, 0x55, 0xE5, 0x55, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49,
+ 0xBB, 0x55, 0x82, 0x81, 0xC0, 0x55, 0x48, 0xF4, 0x0F, 0x00, 0x5A, 0xF0, 0x1A, 0x08, 0x4A, 0xE4,
+ 0x17, 0x00, 0xD5, 0xF0, 0xFA, 0x07, 0x02, 0xF6, 0x0F, 0x00, 0x02, 0xF4, 0x02, 0x00, 0x02, 0xEA,
+ 0xB8, 0x00, 0x04, 0x91, 0x86, 0x91, 0x02, 0x4B, 0x2C, 0x90, 0x08, 0x50, 0x2E, 0x90, 0x0A, 0x50,
+ 0x2C, 0x51, 0xAE, 0x51, 0x00, 0xF2, 0xB6, 0x10, 0x38, 0x54, 0x00, 0xF2, 0xB4, 0x0D, 0x56, 0x10,
+ 0x34, 0x91, 0xB6, 0x91, 0x0C, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x41, 0x12, 0x0C, 0x91,
+ 0x8E, 0x91, 0x04, 0x80, 0x18, 0xE4, 0xF7, 0x00, 0x04, 0x40, 0x30, 0x90, 0xB2, 0x90, 0x36, 0x10,
+ 0x02, 0x80, 0x48, 0xE4, 0x10, 0x00, 0x31, 0x12, 0x82, 0xE7, 0x10, 0x00, 0x84, 0x80, 0x19, 0xE4,
+ 0x20, 0x00, 0x10, 0x13, 0x0C, 0x90, 0x8E, 0x90, 0x5D, 0xF0, 0x78, 0x07, 0x0C, 0x58, 0x8D, 0x58,
+ 0x00, 0xF0, 0x64, 0x07, 0x38, 0x54, 0xB9, 0x54, 0x19, 0x80, 0xF1, 0x10, 0x3A, 0x55, 0x19, 0x81,
+ 0xBB, 0x55, 0x10, 0x90, 0x92, 0x90, 0x10, 0x58, 0x91, 0x58, 0x14, 0x59, 0x95, 0x59, 0x00, 0xF0,
+ 0x64, 0x07, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x6C, 0x19, 0x19, 0x41, 0x7C, 0x10,
+ 0x6C, 0x19, 0x0C, 0x51, 0xED, 0x19, 0x8E, 0x51, 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFF, 0x02, 0x13,
+ 0x6A, 0x10, 0x01, 0x58, 0xD2, 0xF0, 0xC0, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x0A, 0x12,
+ 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0x06, 0x13, 0x9E, 0xE7, 0x16, 0x00, 0x4C, 0x10,
+ 0xD1, 0xF0, 0xCA, 0x08, 0x9E, 0xE7, 0x17, 0x00, 0x42, 0x10, 0xD0, 0xF0, 0xD4, 0x08, 0x9E, 0xE7,
+ 0x19, 0x00, 0x38, 0x10, 0xCF, 0xF0, 0xDE, 0x08, 0x9E, 0xE7, 0x20, 0x00, 0x2E, 0x10, 0xCE, 0xF0,
+ 0xE8, 0x08, 0x9E, 0xE7, 0x21, 0x00, 0x24, 0x10, 0xCD, 0xF0, 0xF2, 0x08, 0x9E, 0xE7, 0x22, 0x00,
+ 0x1A, 0x10, 0xCC, 0xF0, 0x04, 0x09, 0x84, 0x80, 0x19, 0xE4, 0x04, 0x00, 0x06, 0x12, 0x9E, 0xE7,
+ 0x12, 0x00, 0x08, 0x10, 0xCB, 0xF0, 0x0C, 0x09, 0x9E, 0xE7, 0x24, 0x00, 0xB1, 0xF0, 0x0C, 0x09,
+ 0x05, 0xF0, 0x1E, 0x09, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0xE4, 0x10, 0x00, 0xF2,
+ 0x60, 0x0B, 0xE9, 0x10, 0x9C, 0x32, 0x82, 0xE7, 0x20, 0x00, 0x32, 0x1C, 0xE9, 0x09, 0x00, 0xF2,
+ 0x12, 0x11, 0x85, 0xF0, 0x02, 0x0A, 0x69, 0x08, 0x01, 0xF0, 0x44, 0x09, 0x1E, 0xF0, 0xFC, 0x09,
+ 0x00, 0xF0, 0x38, 0x09, 0x30, 0x44, 0x06, 0x12, 0x9E, 0xE7, 0x42, 0x00, 0xB8, 0x10, 0x04, 0xF6,
+ 0x01, 0x00, 0xB3, 0x45, 0x74, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x22, 0x13, 0x4B, 0xE4,
+ 0x02, 0x00, 0x36, 0x12, 0x4B, 0xE4, 0x28, 0x00, 0xAC, 0x13, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2,
+ 0xC8, 0x11, 0x03, 0xF6, 0xD0, 0x00, 0xFA, 0x14, 0x82, 0xE7, 0x01, 0x00, 0x00, 0xF0, 0x80, 0x01,
+ 0x9E, 0xE7, 0x44, 0x00, 0x4B, 0xE4, 0x02, 0x00, 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x76, 0x10,
+ 0x00, 0xF2, 0xA2, 0x0D, 0x03, 0xE6, 0x02, 0x00, 0x6C, 0x10, 0x00, 0xF2, 0xA2, 0x0D, 0x19, 0x82,
+ 0x34, 0x46, 0x0A, 0x13, 0x03, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x43, 0x00, 0x68, 0x10, 0x04, 0x80,
+ 0x30, 0xE4, 0x20, 0x00, 0x04, 0x40, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x82, 0xE7,
+ 0x01, 0x00, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x08, 0x03, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00,
+ 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x3E, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x3A, 0x12,
+ 0x04, 0x80, 0x18, 0xE4, 0xFD, 0x00, 0x04, 0x40, 0x1C, 0x1C, 0x9D, 0xF0, 0xEA, 0x09, 0x1C, 0x1C,
+ 0x9D, 0xF0, 0xF0, 0x09, 0xC1, 0x10, 0x9E, 0xE7, 0x13, 0x00, 0x0A, 0x10, 0x9E, 0xE7, 0x41, 0x00,
+ 0x04, 0x10, 0x9E, 0xE7, 0x24, 0x00, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0xD5, 0xF0, 0x8A, 0x02,
+ 0x04, 0xE6, 0x04, 0x00, 0x06, 0x10, 0x04, 0xE6, 0x04, 0x00, 0x9D, 0x41, 0x1C, 0x42, 0x9F, 0xE7,
+ 0x00, 0x00, 0x06, 0xF7, 0x02, 0x00, 0x03, 0xF6, 0xE0, 0x00, 0x3C, 0x14, 0x44, 0x58, 0x45, 0x58,
+ 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xF2, 0x7E, 0x10, 0x00, 0xF2, 0xC6, 0x0F, 0x3C, 0x14, 0x1E, 0x1C,
+ 0x00, 0xF0, 0x80, 0x01, 0x12, 0x1C, 0x22, 0x1C, 0xD2, 0x14, 0x00, 0xF0, 0x72, 0x01, 0x83, 0x59,
+ 0x03, 0xDC, 0x73, 0x57, 0x80, 0x5D, 0x00, 0x16, 0x83, 0x59, 0x03, 0xDC, 0x38, 0x54, 0x70, 0x57,
+ 0x33, 0x54, 0x3B, 0x54, 0x80, 0x5D, 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x38, 0x54, 0x00, 0xCC,
+ 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x00, 0x4C, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x01, 0x00,
+ 0x0E, 0x12, 0x48, 0xE4, 0x05, 0x00, 0x08, 0x12, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11,
+ 0xC1, 0x5A, 0x3A, 0x55, 0x02, 0xEC, 0xB5, 0x00, 0x45, 0x59, 0x00, 0xF2, 0xF6, 0x0D, 0x83, 0x58,
+ 0x30, 0xE7, 0x00, 0x00, 0x10, 0x4D, 0x30, 0xE7, 0x40, 0x00, 0x10, 0x4F, 0x38, 0x90, 0xBA, 0x90,
+ 0x10, 0x5C, 0x80, 0x5C, 0x83, 0x5A, 0x10, 0x4E, 0x04, 0xEA, 0xB5, 0x00, 0x43, 0x5B, 0x03, 0xF4,
+ 0xE0, 0x00, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x0A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D,
+ 0x00, 0xF2, 0x38, 0x10, 0x00, 0x16, 0x08, 0x1C, 0x00, 0xFC, 0xAC, 0x00, 0x06, 0x58, 0x67, 0x18,
+ 0x18, 0xF4, 0x8F, 0xE1, 0x01, 0xFC, 0xAE, 0x00, 0x19, 0xF4, 0x70, 0x1E, 0xB0, 0x54, 0x07, 0x58,
+ 0x00, 0xFC, 0xB0, 0x00, 0x08, 0x58, 0x00, 0xFC, 0xB2, 0x00, 0x09, 0x58, 0x0A, 0x1C, 0x00, 0xE6,
+ 0x0F, 0x00, 0x00, 0xEA, 0xB9, 0x00, 0x38, 0x54, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFA, 0xB6, 0x00,
+ 0x18, 0x1C, 0x14, 0x1C, 0x10, 0x1C, 0x32, 0x1C, 0x12, 0x1C, 0x00, 0x16, 0x3E, 0x57, 0x0C, 0x14,
+ 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47, 0xF5, 0x13, 0x00, 0x16, 0x00, 0xF2, 0xA2, 0x0D,
+ 0x02, 0x4B, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x20, 0x12, 0x44, 0x58,
+ 0x45, 0x58, 0x9E, 0xE7, 0x15, 0x00, 0x9C, 0xE7, 0x04, 0x00, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xF2,
+ 0x7E, 0x10, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2, 0x7A, 0x0A, 0x1E, 0x1C, 0xD5, 0x10, 0x00, 0x16,
+ 0x69, 0x08, 0x48, 0xE4, 0x04, 0x00, 0x64, 0x12, 0x48, 0xE4, 0x02, 0x00, 0x20, 0x12, 0x48, 0xE4,
+ 0x03, 0x00, 0x1A, 0x12, 0x48, 0xE4, 0x08, 0x00, 0x14, 0x12, 0x48, 0xE4, 0x01, 0x00, 0xF0, 0x12,
+ 0x48, 0xE4, 0x07, 0x00, 0x12, 0x12, 0x01, 0xE6, 0x07, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2,
+ 0x12, 0x11, 0x05, 0xF0, 0x60, 0x0B, 0x00, 0x16, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x99, 0x00,
+ 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0xE7, 0x12, 0x48, 0xE4, 0x06, 0x00, 0xE1, 0x12, 0x01, 0xE6,
+ 0x06, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7,
+ 0x15, 0x00, 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4,
+ 0x10, 0x00, 0x1C, 0x12, 0x82, 0xE7, 0x08, 0x00, 0x3C, 0x56, 0x03, 0x82, 0x00, 0xF2, 0xE2, 0x0D,
+ 0x30, 0xE7, 0x08, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x80, 0x01,
+ 0x6C, 0x19, 0xED, 0x19, 0x5D, 0xF0, 0xD4, 0x0B, 0x44, 0x55, 0xE5, 0x55, 0x59, 0xF0, 0x52, 0x0C,
+ 0x04, 0x55, 0xA5, 0x55, 0x1F, 0x80, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x49, 0x44,
+ 0x2E, 0x13, 0x01, 0xEC, 0xB8, 0x00, 0x41, 0xE4, 0x02, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x49, 0xE4,
+ 0x11, 0x00, 0x59, 0xF0, 0x2E, 0x0C, 0x01, 0xE6, 0x17, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x02, 0x4B,
+ 0x88, 0x90, 0xAC, 0x50, 0x8A, 0x90, 0xAE, 0x50, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80,
+ 0x10, 0x44, 0x02, 0x4B, 0x1F, 0x40, 0xC0, 0x44, 0x00, 0xF2, 0xB4, 0x0D, 0x04, 0x55, 0xA5, 0x55,
+ 0x9F, 0x10, 0x0C, 0x51, 0x8E, 0x51, 0x30, 0x90, 0xB2, 0x90, 0x00, 0x56, 0xA1, 0x56, 0x30, 0x50,
+ 0xB2, 0x50, 0x34, 0x90, 0xB6, 0x90, 0x40, 0x56, 0xE1, 0x56, 0x34, 0x50, 0xB6, 0x50, 0x65, 0x10,
+ 0xB1, 0xF0, 0x70, 0x0C, 0x85, 0xF0, 0xCA, 0x0B, 0xE9, 0x09, 0x4B, 0xE4, 0x03, 0x00, 0x78, 0x12,
+ 0x4B, 0xE4, 0x02, 0x00, 0x01, 0x13, 0xB1, 0xF0, 0x86, 0x0C, 0x85, 0xF0, 0xCA, 0x0B, 0x69, 0x08,
+ 0x48, 0xE4, 0x03, 0x00, 0xD5, 0xF0, 0x86, 0x0B, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0xCA, 0x0B,
+ 0xE8, 0x09, 0x3C, 0x56, 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x02, 0x13, 0xBB, 0x45, 0x4B, 0xE4,
+ 0x00, 0x00, 0x08, 0x12, 0x03, 0xE6, 0x01, 0x00, 0x04, 0xF6, 0x00, 0x80, 0xA8, 0x14, 0xD2, 0x14,
+ 0x30, 0x1C, 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x10, 0x13, 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57,
+ 0x02, 0x13, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF0, 0x8E, 0x0B, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57,
+ 0x00, 0xFA, 0x24, 0x01, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0x8E, 0x0B,
+ 0x00, 0xF2, 0x8C, 0x0E, 0x00, 0xF0, 0x8E, 0x0B, 0xB1, 0xF0, 0xF8, 0x0C, 0x85, 0xF0, 0x86, 0x0B,
+ 0x69, 0x08, 0x48, 0xE4, 0x01, 0x00, 0xD5, 0xF0, 0x86, 0x0B, 0xFC, 0x14, 0x42, 0x58, 0x6C, 0x14,
+ 0x80, 0x14, 0x30, 0x1C, 0x4A, 0xF4, 0x02, 0x00, 0x55, 0xF0, 0x86, 0x0B, 0x4A, 0xF4, 0x01, 0x00,
+ 0x0E, 0x12, 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x06, 0x13, 0x3E, 0x1C, 0x00, 0xF0, 0x8E, 0x0B,
+ 0x00, 0xFC, 0xB6, 0x00, 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2,
+ 0x12, 0x11, 0x86, 0xF0, 0x8E, 0x0B, 0x00, 0xF2, 0xBA, 0x0E, 0x00, 0xF0, 0x8E, 0x0B, 0x4C, 0x1C,
+ 0xB1, 0xF0, 0x50, 0x0D, 0x85, 0xF0, 0x5C, 0x0D, 0x69, 0x08, 0xF3, 0x10, 0x86, 0xF0, 0x64, 0x0D,
+ 0x4E, 0x1C, 0x89, 0x48, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58,
+ 0x00, 0xDC, 0x18, 0xF4, 0xFF, 0x7F, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01,
+ 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x30, 0x56, 0x00, 0x5C,
+ 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x0B, 0x58,
+ 0x00, 0x16, 0x03, 0xF6, 0x24, 0x01, 0x00, 0xF2, 0x58, 0x0A, 0x03, 0xF6, 0xB6, 0x00, 0x00, 0xF2,
+ 0x58, 0x0A, 0x00, 0x16, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0x18, 0xF4, 0xFF, 0x00, 0x00, 0x54,
+ 0x00, 0x54, 0x00, 0x54, 0x00, 0xF4, 0x08, 0x00, 0xE1, 0x18, 0x80, 0x54, 0x03, 0x58, 0x00, 0xDD,
+ 0x01, 0xDD, 0x02, 0xDD, 0x03, 0xDC, 0x02, 0x4B, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x51, 0xB6, 0x51,
+ 0x00, 0x16, 0x45, 0x5A, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4,
+ 0x02, 0x12, 0x83, 0x5A, 0x00, 0x16, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56,
+ 0x05, 0xF4, 0x00, 0x12, 0x83, 0x5A, 0x00, 0x16, 0x38, 0x54, 0xBB, 0x55, 0x3C, 0x56, 0xBD, 0x56,
+ 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x82, 0x0E, 0xE9, 0x09, 0xC1, 0x59, 0x00, 0xF2, 0x12, 0x11,
+ 0x85, 0xF0, 0x82, 0x0E, 0xE8, 0x0A, 0x83, 0x55, 0x83, 0x55, 0x4B, 0xF4, 0x90, 0x01, 0x5C, 0xF0,
+ 0x36, 0x0E, 0xBD, 0x56, 0x40, 0x10, 0x4B, 0xF4, 0x30, 0x00, 0x59, 0xF0, 0x48, 0x0E, 0x01, 0xF6,
+ 0x0C, 0x00, 0x00, 0xF6, 0x01, 0x00, 0x2E, 0x10, 0x02, 0xFC, 0x9C, 0x00, 0x9A, 0x57, 0x14, 0x13,
+ 0x4B, 0xF4, 0x64, 0x00, 0x59, 0xF0, 0x64, 0x0E, 0x03, 0xF6, 0x64, 0x00, 0x01, 0xF6, 0x19, 0x00,
+ 0x00, 0xF6, 0x01, 0x00, 0x43, 0xF4, 0x33, 0x00, 0x56, 0xF0, 0x76, 0x0E, 0x04, 0xF4, 0x00, 0x01,
+ 0x43, 0xF4, 0x19, 0x00, 0xF3, 0x10, 0xB4, 0x56, 0xC3, 0x58, 0x02, 0xFC, 0x9E, 0x00, 0x9A, 0x57,
+ 0x08, 0x13, 0x3C, 0x56, 0x00, 0xF6, 0x02, 0x00, 0x00, 0x16, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00,
+ 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xB8, 0x0E, 0x09, 0xE7, 0x02, 0x00, 0x00, 0xF2, 0x12, 0x11,
+ 0x86, 0xF0, 0xB8, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xB8, 0x0E,
+ 0x4E, 0x1C, 0x89, 0x49, 0x00, 0xF2, 0x12, 0x11, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2,
+ 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0,
+ 0xF2, 0x0E, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x89, 0x49,
+ 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x4E, 0x1C, 0x89, 0x4A, 0x00, 0xF2, 0x12, 0x11,
+ 0x00, 0x16, 0x3C, 0x56, 0x00, 0x16, 0x00, 0xEC, 0x26, 0x01, 0x48, 0xE4, 0x01, 0x00, 0x1E, 0x13,
+ 0x38, 0x44, 0x00, 0xEA, 0x26, 0x01, 0x49, 0xF4, 0x00, 0x00, 0x04, 0x12, 0x4E, 0x1C, 0x02, 0x10,
+ 0x4C, 0x1C, 0x01, 0xEC, 0x27, 0x01, 0x89, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x02, 0x14, 0x00, 0x16,
+ 0x85, 0xF0, 0x52, 0x0F, 0x38, 0x54, 0x00, 0xEA, 0x99, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x02, 0x80,
+ 0x48, 0xE4, 0x06, 0x00, 0x1C, 0x13, 0x00, 0xEC, 0x99, 0x00, 0x48, 0xE4, 0x01, 0x00, 0x0A, 0x12,
+ 0x04, 0x80, 0x30, 0xE4, 0x01, 0x00, 0x04, 0x40, 0x08, 0x10, 0x04, 0x80, 0x18, 0xE4, 0xFE, 0x00,
+ 0x04, 0x40, 0x00, 0x16, 0x02, 0xF6, 0xE0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x81, 0x48,
+ 0x22, 0x12, 0x00, 0x4E, 0x83, 0x5A, 0x90, 0x4C, 0x20, 0xE7, 0x00, 0x00, 0xC3, 0x58, 0x1B, 0xF4,
+ 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x8B, 0x55, 0x83, 0x59,
+ 0x00, 0x4E, 0x00, 0x16, 0x00, 0x4E, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x00, 0x4E,
+ 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, 0x16, 0x02, 0xF6, 0xF0, 0x00,
+ 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x80, 0x4C,
+ 0xC3, 0x58, 0x1B, 0xF4, 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12,
+ 0x83, 0x59, 0x00, 0x4E, 0x00, 0x16, 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x3A, 0x55,
+ 0x02, 0xCC, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0xC0, 0x5A, 0x40, 0x5C, 0x38, 0x54, 0x00, 0xCD,
+ 0x01, 0xCC, 0x4A, 0x46, 0x0A, 0x13, 0x83, 0x59, 0x00, 0x4C, 0x01, 0x48, 0x16, 0x13, 0x0C, 0x10,
+ 0xC5, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0x4C, 0x01, 0x48, 0x08, 0x13, 0x05, 0xF6, 0xF0, 0x00,
+ 0x05, 0x57, 0x08, 0x10, 0x45, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x8D, 0x56, 0x83, 0x5A, 0x80, 0x4C,
+ 0x05, 0x17, 0x00, 0x16, 0x02, 0x4B, 0x06, 0xF7, 0x04, 0x00, 0x62, 0x0B, 0x03, 0x82, 0x00, 0xF2,
+ 0xE2, 0x0D, 0x02, 0x80, 0x00, 0x4C, 0x45, 0xF4, 0x02, 0x00, 0x52, 0x14, 0x06, 0xF7, 0x02, 0x00,
+ 0x06, 0x14, 0x00, 0xF2, 0x54, 0x0F, 0x00, 0x16, 0x02, 0x4B, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C,
+ 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x1D, 0xF7, 0x3C, 0x00, 0xB8, 0xF0,
+ 0x4E, 0x10, 0x9C, 0x14, 0x01, 0x48, 0x1C, 0x13, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00,
+ 0xAF, 0x19, 0x03, 0x42, 0x45, 0xF4, 0x02, 0x00, 0x83, 0x5A, 0x02, 0xCC, 0x02, 0x41, 0x45, 0xF4,
+ 0x02, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0, 0x3E, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x01, 0xF6,
+ 0xFF, 0x00, 0x38, 0x1C, 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x0E, 0xF7,
+ 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00, 0x0F, 0x79, 0x1C, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x9C, 0x10,
+ 0x4E, 0x14, 0x01, 0x48, 0x06, 0x13, 0x45, 0xF4, 0x04, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0,
+ 0x82, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x02, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x2C, 0xBC, 0xAE, 0xBC,
+ 0xE2, 0x08, 0x00, 0xEC, 0xB8, 0x00, 0x02, 0x48, 0x1D, 0xF7, 0x80, 0x00, 0xB8, 0xF0, 0xCC, 0x10,
+ 0x1E, 0x14, 0x01, 0x48, 0x0E, 0x13, 0x0E, 0xF7, 0x80, 0x00, 0x38, 0x54, 0x03, 0x58, 0xAF, 0x19,
+ 0x82, 0x48, 0x00, 0x16, 0x82, 0x48, 0x12, 0x45, 0xD5, 0xF0, 0xBA, 0x10, 0x00, 0xF0, 0x9E, 0x02,
+ 0x39, 0xF0, 0xF8, 0x10, 0x38, 0x44, 0x00, 0x16, 0x7E, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x04, 0x13,
+ 0x61, 0x18, 0x00, 0x16, 0x38, 0x1C, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xF1, 0x12,
+ 0xE3, 0x10, 0x30, 0x44, 0x30, 0x44, 0x30, 0x44, 0xB1, 0xF0, 0x18, 0x11, 0x00, 0x16, 0x3E, 0x57,
+ 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x6A, 0x12, 0x45, 0x5A,
+ 0x00, 0xF2, 0xF6, 0x0D, 0x02, 0x4B, 0x70, 0x14, 0x34, 0x13, 0x02, 0x80, 0x48, 0xE4, 0x08, 0x00,
+ 0x18, 0x12, 0x9C, 0xE7, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2,
+ 0x7A, 0x0A, 0x1E, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x30, 0xE4, 0x10, 0x00, 0x04, 0x40,
+ 0x00, 0xF2, 0xE2, 0x0D, 0x20, 0xE7, 0x01, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x04, 0xDC,
+ 0x01, 0x4A, 0x24, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0x43, 0x5B, 0x06, 0xEC, 0x98, 0x00,
+ 0x00, 0xF2, 0x38, 0x10, 0xC6, 0x59, 0x20, 0x14, 0x0A, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2,
+ 0x14, 0x10, 0xA7, 0x10, 0x83, 0x5A, 0xD7, 0x10, 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47,
+ 0x5A, 0xF0, 0x20, 0x11, 0xB9, 0x54, 0x00, 0x16, 0x14, 0x90, 0x96, 0x90, 0x02, 0xFC, 0xA8, 0x00,
+ 0x03, 0xFC, 0xAA, 0x00, 0x48, 0x55, 0x02, 0x13, 0xC9, 0x55, 0x00, 0x16, 0x00, 0xEC, 0xBA, 0x00,
+ 0x10, 0x44, 0x00, 0xEA, 0xBA, 0x00, 0x00, 0x16, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A,
+ 0x10, 0x44, 0x00, 0x4C, 0x00, 0x16
+};
+
+u_int16_t adv_mcode_size = sizeof(adv_mcode); /* 0x11D6 */
+
+/*
+ * This checksum is used to compare with that one that will be calculated
+ * at run time.
+ * This is performed to ensure the uCode is correctly loaded into the Lram.
+ */
+u_int32_t adv_mcode_chksum = 0x03494981UL;
diff --git a/sys/dev/ic/adwmcode.h b/sys/dev/ic/adwmcode.h
new file mode 100644
index 00000000000..0f9e2c2e15f
--- /dev/null
+++ b/sys/dev/ic/adwmcode.h
@@ -0,0 +1,49 @@
+/* $OpenBSD: adwmcode.h,v 1.1 1998/11/17 06:14:58 downsj Exp $ */
+/* $NetBSD: adwmcode.h,v 1.1 1998/09/26 16:10:42 dante Exp $ */
+
+/*
+ * Generic driver definitions and exported functions for the Advanced
+ * Systems Inc. SCSI controllers
+ *
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Author: Baldassare Dante Profeta <dante@mclink.it>
+ *
+ * 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.
+ */
+
+#ifndef ADV_MCODE_H
+#define ADV_MCODE_H
+
+extern u_int8_t adv_mcode[];
+extern u_int16_t adv_mcode_size;
+extern u_int32_t adv_mcode_chksum;
+
+#endif /* ADV_MCODE_H */