summaryrefslogtreecommitdiffstats
path: root/sys/dev/advansys
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/advansys')
-rw-r--r--sys/dev/advansys/adv_eisa.c346
-rw-r--r--sys/dev/advansys/adv_isa.c419
-rw-r--r--sys/dev/advansys/adv_pci.c327
-rw-r--r--sys/dev/advansys/advansys.c1424
-rw-r--r--sys/dev/advansys/advansys.h55
-rw-r--r--sys/dev/advansys/advlib.c2082
-rw-r--r--sys/dev/advansys/advlib.h876
-rw-r--r--sys/dev/advansys/advmcode.c282
-rw-r--r--sys/dev/advansys/advmcode.h19
-rw-r--r--sys/dev/advansys/adw_pci.c396
-rw-r--r--sys/dev/advansys/adwcam.c1540
-rw-r--r--sys/dev/advansys/adwlib.c893
-rw-r--r--sys/dev/advansys/adwlib.h878
-rw-r--r--sys/dev/advansys/adwmcode.c994
-rw-r--r--sys/dev/advansys/adwmcode.h135
-rw-r--r--sys/dev/advansys/adwvar.h55
16 files changed, 10721 insertions, 0 deletions
diff --git a/sys/dev/advansys/adv_eisa.c b/sys/dev/advansys/adv_eisa.c
new file mode 100644
index 0000000..4884317
--- /dev/null
+++ b/sys/dev/advansys/adv_eisa.c
@@ -0,0 +1,346 @@
+/*
+ * Device probe and attach routines for the following
+ * Advanced Systems Inc. SCSI controllers:
+ *
+ * Single Channel Products:
+ * ABP742 - Bus-Master EISA (240 CDB)
+ *
+ * Dual Channel Products:
+ * ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
+ *
+ * Copyright (c) 1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/eisa/eisaconf.h>
+
+#include <dev/advansys/advansys.h>
+
+#define EISA_DEVICE_ID_ADVANSYS_740 0x04507400
+#define EISA_DEVICE_ID_ADVANSYS_750 0x04507500
+
+#define ADV_EISA_SLOT_OFFSET 0xc00
+#define ADV_EISA_OFFSET_CHAN1 0x30
+#define ADV_EISA_OFFSET_CHAN2 0x50
+#define ADV_EISA_IOSIZE 0x100
+
+#define ADV_EISA_ROM_BIOS_ADDR_REG 0x86
+#define ADV_EISA_IRQ_BURST_LEN_REG 0x87
+#define ADV_EISA_IRQ_MASK 0x07
+#define ADV_EISA_IRQ_10 0x00
+#define ADV_EISA_IRQ_11 0x01
+#define ADV_EISA_IRQ_12 0x02
+#define ADV_EISA_IRQ_14 0x04
+#define ADV_EISA_IRQ_15 0x05
+
+#define ADV_EISA_MAX_DMA_ADDR (0x07FFFFFFL)
+#define ADV_EISA_MAX_DMA_COUNT (0x07FFFFFFL)
+
+/*
+ * The overrun buffer shared amongst all EISA adapters.
+ */
+static u_int8_t* overrun_buf;
+static bus_dma_tag_t overrun_dmat;
+static bus_dmamap_t overrun_dmamap;
+static bus_addr_t overrun_physbase;
+
+static const char*
+adv_eisa_match(eisa_id_t type)
+{
+ switch (type & ~0xF) {
+ case EISA_DEVICE_ID_ADVANSYS_740:
+ return ("AdvanSys ABP-740/742 SCSI adapter");
+ break;
+ case EISA_DEVICE_ID_ADVANSYS_750:
+ return ("AdvanSys ABP-750/752 SCSI adapter");
+ break;
+ default:
+ break;
+ }
+ return (NULL);
+}
+
+static int
+adv_eisa_probe(device_t dev)
+{
+ const char *desc;
+ u_int32_t iobase;
+ u_int8_t irq;
+
+ desc = adv_eisa_match(eisa_get_id(dev));
+ if (!desc)
+ return (ENXIO);
+ device_set_desc(dev, desc);
+
+ iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + ADV_EISA_SLOT_OFFSET;
+
+ eisa_add_iospace(dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE);
+ irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG);
+ irq &= ADV_EISA_IRQ_MASK;
+ switch (irq) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 5:
+ break;
+ default:
+ printf("adv at slot %d: illegal "
+ "irq setting %d\n", eisa_get_slot(dev),
+ irq);
+ return ENXIO;
+ }
+ eisa_add_intr(dev, irq + 10, EISA_TRIGGER_LEVEL);
+
+ return 0;
+}
+
+static int
+adv_eisa_attach(device_t dev)
+{
+ struct adv_softc *adv;
+ struct adv_softc *adv_b;
+ struct resource *io;
+ struct resource *irq;
+ int rid, error;
+ void *ih;
+
+ adv_b = NULL;
+
+ rid = 0;
+ io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!io) {
+ device_printf(dev, "No I/O space?!\n");
+ return ENOMEM;
+ }
+
+ rid = 0;
+ irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
+ if (!irq) {
+ device_printf(dev, "No irq?!\n");
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
+ return ENOMEM;
+
+ }
+
+ switch (eisa_get_id(dev) & ~0xF) {
+ case EISA_DEVICE_ID_ADVANSYS_750:
+ adv_b = adv_alloc(dev, rman_get_bustag(io),
+ rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN2);
+ if (adv_b == NULL)
+ goto bad;
+
+ /*
+ * Allocate a parent dmatag for all tags created
+ * by the MI portions of the advansys driver
+ */
+ /* XXX Should be a child of the PCI bus dma tag */
+ error = bus_dma_tag_create(
+ /* parent */ NULL,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ ADV_EISA_MAX_DMA_ADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ BUS_SPACE_MAXSIZE_32BIT,
+ /* nsegments */ ~0,
+ /* maxsegsz */ ADV_EISA_MAX_DMA_COUNT,
+ /* flags */ 0,
+ &adv_b->parent_dmat);
+
+ if (error != 0) {
+ printf("%s: Could not allocate DMA tag - error %d\n",
+ adv_name(adv_b), error);
+ adv_free(adv_b);
+ goto bad;
+ }
+
+ adv_b->init_level++;
+
+ /* FALLTHROUGH */
+ case EISA_DEVICE_ID_ADVANSYS_740:
+ adv = adv_alloc(dev, rman_get_bustag(io),
+ rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN1);
+ if (adv == NULL) {
+ if (adv_b != NULL)
+ adv_free(adv_b);
+ goto bad;
+ }
+
+ /*
+ * Allocate a parent dmatag for all tags created
+ * by the MI portions of the advansys driver
+ */
+ /* XXX Should be a child of the PCI bus dma tag */
+ error = bus_dma_tag_create(
+ /* parent */ NULL,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ ADV_EISA_MAX_DMA_ADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ BUS_SPACE_MAXSIZE_32BIT,
+ /* nsegments */ ~0,
+ /* maxsegsz */ ADV_EISA_MAX_DMA_COUNT,
+ /* flags */ 0,
+ &adv->parent_dmat);
+
+ if (error != 0) {
+ printf("%s: Could not allocate DMA tag - error %d\n",
+ adv_name(adv), error);
+ adv_free(adv);
+ goto bad;
+ }
+
+ adv->init_level++;
+ break;
+ default:
+ printf("adveisaattach: Unknown device type!\n");
+ goto bad;
+ break;
+ }
+
+ if (overrun_buf == NULL) {
+ /* Need to allocate our overrun buffer */
+ if (bus_dma_tag_create(
+ /* parent */ adv->parent_dmat,
+ /* alignment */ 8,
+ /* boundary */ 0,
+ /* lowaddr */ ADV_EISA_MAX_DMA_ADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ ADV_OVERRUN_BSIZE,
+ /* nsegments */ 1,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ 0,
+ &overrun_dmat) != 0) {
+ adv_free(adv);
+ goto bad;
+ }
+ if (bus_dmamem_alloc(overrun_dmat,
+ (void **)&overrun_buf,
+ BUS_DMA_NOWAIT,
+ &overrun_dmamap) != 0) {
+ bus_dma_tag_destroy(overrun_dmat);
+ adv_free(adv);
+ goto bad;
+ }
+ /* And permanently map it in */
+ bus_dmamap_load(overrun_dmat, overrun_dmamap,
+ overrun_buf, ADV_OVERRUN_BSIZE,
+ adv_map, &overrun_physbase,
+ /*flags*/0);
+ }
+
+ /*
+ * Now that we know we own the resources we need, do the
+ * card initialization.
+ */
+
+ /*
+ * Stop the chip.
+ */
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
+ ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
+
+ adv->chip_version = EISA_REVISION_ID(eisa_get_id(dev))
+ + ADV_CHIP_MIN_VER_EISA - 1;
+
+ if (adv_init(adv) != 0) {
+ adv_free(adv);
+ if (adv_b != NULL)
+ adv_free(adv_b);
+ return(-1);
+ }
+
+ adv->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
+ adv->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
+
+ if (adv_b != NULL) {
+ /*
+ * Stop the chip.
+ */
+ ADV_OUTB(adv_b, ADV_CHIP_CTRL, ADV_CC_HALT);
+ ADV_OUTW(adv_b, ADV_CHIP_STATUS, 0);
+
+ adv_b->chip_version = EISA_REVISION_ID(eisa_get_id(dev))
+ + ADV_CHIP_MIN_VER_EISA - 1;
+
+ if (adv_init(adv_b) != 0) {
+ adv_free(adv_b);
+ } else {
+ adv_b->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
+ adv_b->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
+ }
+ }
+
+ /*
+ * Enable our interrupt handler.
+ */
+ bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, adv_intr, adv, &ih);
+
+ /* Attach sub-devices - always succeeds */
+ adv_attach(adv);
+ if (adv_b != NULL)
+ adv_attach(adv_b);
+
+ return 0;
+
+ bad:
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
+ return -1;
+}
+
+static device_method_t adv_eisa_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, adv_eisa_probe),
+ DEVMETHOD(device_attach, adv_eisa_attach),
+ { 0, 0 }
+};
+
+static driver_t adv_eisa_driver = {
+ "adv", adv_eisa_methods, sizeof(struct adv_softc)
+};
+
+static devclass_t adv_eisa_devclass;
+DRIVER_MODULE(adv, eisa, adv_eisa_driver, adv_eisa_devclass, 0, 0);
diff --git a/sys/dev/advansys/adv_isa.c b/sys/dev/advansys/adv_isa.c
new file mode 100644
index 0000000..e8eca4e
--- /dev/null
+++ b/sys/dev/advansys/adv_isa.c
@@ -0,0 +1,419 @@
+/*
+ * Device probe and attach routines for the following
+ * Advanced Systems Inc. SCSI controllers:
+ *
+ * Connectivity Products:
+ * ABP510/5150 - Bus-Master ISA (240 CDB) *
+ * ABP5140 - Bus-Master ISA PnP (16 CDB) * **
+ * ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) ***
+ *
+ * Single Channel Products:
+ * ABP542 - Bus-Master ISA with floppy (240 CDB)
+ * ABP842 - Bus-Master VL (240 CDB)
+ *
+ * Dual Channel Products:
+ * ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
+ *
+ * * This board has been shipped by HP with the 4020i CD-R drive.
+ * The board has no BIOS so it cannot control a boot device, but
+ * it can control any secondary SCSI device.
+ * ** This board has been sold by SIIG as the i540 SpeedMaster.
+ * *** This board has been sold by SIIG as the i542 SpeedMaster.
+ *
+ * Copyright (c) 1996, 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <isa/isavar.h>
+
+#include <dev/advansys/advansys.h>
+
+#include <cam/scsi/scsi_all.h>
+
+#define ADV_ISA_MAX_DMA_ADDR (0x00FFFFFFL)
+#define ADV_ISA_MAX_DMA_COUNT (0x00FFFFFFL)
+
+#define ADV_VL_MAX_DMA_ADDR (0x07FFFFFFL)
+#define ADV_VL_MAX_DMA_COUNT (0x07FFFFFFL)
+
+/*
+ * The overrun buffer shared amongst all ISA/VL adapters.
+ */
+static u_int8_t* overrun_buf;
+static bus_dma_tag_t overrun_dmat;
+static bus_dmamap_t overrun_dmamap;
+static bus_addr_t overrun_physbase;
+
+/* Possible port addresses an ISA or VL adapter can live at */
+static u_int16_t adv_isa_ioports[] =
+{
+ 0x100,
+ 0x110, /* First selection in BIOS setup */
+ 0x120,
+ 0x130, /* Second selection in BIOS setup */
+ 0x140,
+ 0x150, /* Third selection in BIOS setup */
+ 0x190, /* Fourth selection in BIOS setup */
+ 0x210, /* Fifth selection in BIOS setup */
+ 0x230, /* Sixth selection in BIOS setup */
+ 0x250, /* Seventh selection in BIOS setup */
+ 0x330 /* Eighth and default selection in BIOS setup */
+};
+
+#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_int16_t) - 1)
+
+static int adv_isa_probe(device_t dev);
+static int adv_isa_attach(device_t dev);
+static void adv_set_isapnp_wait_for_key(void);
+static int adv_get_isa_dma_channel(struct adv_softc *adv);
+static int adv_set_isa_dma_settings(struct adv_softc *adv);
+
+static int
+adv_isa_probe(device_t dev)
+{
+ int port_index;
+ int max_port_index;
+ u_long iobase, iocount, irq;
+ int user_iobase = 0;
+ int rid = 0;
+ void *ih;
+ struct resource *iores, *irqres;
+
+ /*
+ * Default to scanning all possible device locations.
+ */
+ port_index = 0;
+ max_port_index = MAX_ISA_IOPORT_INDEX;
+
+ if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, &iocount) == 0) {
+ user_iobase = 1;
+ for (;port_index <= max_port_index; port_index++)
+ if (iobase <= adv_isa_ioports[port_index])
+ break;
+ if ((port_index > max_port_index)
+ || (iobase != adv_isa_ioports[port_index])) {
+ if (bootverbose)
+ printf("adv%d: Invalid baseport of 0x%lx specified. "
+ "Nearest valid baseport is 0x%x. Failing "
+ "probe.\n", device_get_unit(dev), iobase,
+ (port_index <= max_port_index) ?
+ adv_isa_ioports[port_index] :
+ adv_isa_ioports[max_port_index]);
+ return ENXIO;
+ }
+ max_port_index = port_index;
+ }
+
+ /* Perform the actual probing */
+ adv_set_isapnp_wait_for_key();
+ for (;port_index <= max_port_index; port_index++) {
+ u_int16_t port_addr = adv_isa_ioports[port_index];
+ bus_size_t maxsegsz;
+ bus_size_t maxsize;
+ bus_addr_t lowaddr;
+ int error;
+ struct adv_softc *adv;
+
+ if (port_addr == 0)
+ /* Already been attached */
+ continue;
+
+ if (bus_set_resource(dev, SYS_RES_IOPORT, 0, port_addr, 1))
+ continue;
+
+ /* XXX what is the real portsize? */
+ iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
+ RF_ACTIVE);
+ if (iores == NULL)
+ continue;
+
+ if (adv_find_signature(rman_get_bustag(iores),
+ rman_get_bushandle(iores)) == 0) {
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
+ continue;
+ }
+
+ /*
+ * Got one. Now allocate our softc
+ * and see if we can initialize the card.
+ */
+ adv = adv_alloc(dev, rman_get_bustag(iores),
+ rman_get_bushandle(iores));
+ if (adv == NULL) {
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
+ break;
+ }
+
+ /*
+ * Stop the chip.
+ */
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
+ ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
+ /*
+ * Determine the chip version.
+ */
+ adv->chip_version = ADV_INB(adv, ADV_NONEISA_CHIP_REVISION);
+ if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL)
+ && (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) {
+ adv->type = ADV_VL;
+ maxsegsz = ADV_VL_MAX_DMA_COUNT;
+ maxsize = BUS_SPACE_MAXSIZE_32BIT;
+ lowaddr = ADV_VL_MAX_DMA_ADDR;
+ bus_delete_resource(dev, SYS_RES_DRQ, 0);
+ } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_ISA)
+ && (adv->chip_version <= ADV_CHIP_MAX_VER_ISA)) {
+ if (adv->chip_version >= ADV_CHIP_MIN_VER_ISA_PNP) {
+ adv->type = ADV_ISAPNP;
+ ADV_OUTB(adv, ADV_REG_IFC,
+ ADV_IFC_INIT_DEFAULT);
+ } else {
+ adv->type = ADV_ISA;
+ }
+ maxsegsz = ADV_ISA_MAX_DMA_COUNT;
+ maxsize = BUS_SPACE_MAXSIZE_24BIT;
+ lowaddr = ADV_ISA_MAX_DMA_ADDR;
+ adv->isa_dma_speed = ADV_DEF_ISA_DMA_SPEED;
+ adv->isa_dma_channel = adv_get_isa_dma_channel(adv);
+ bus_set_resource(dev, SYS_RES_DRQ, 0,
+ adv->isa_dma_channel, 1);
+ } else {
+ panic("advisaprobe: Unknown card revision\n");
+ }
+
+ /*
+ * Allocate a parent dmatag for all tags created
+ * by the MI portions of the advansys driver
+ */
+ /* XXX Should be a child of the ISA bus dma tag */
+ error = bus_dma_tag_create(
+ /* parent */ NULL,
+ /* alignemnt */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ lowaddr,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ maxsize,
+ /* nsegments */ ~0,
+ /* maxsegsz */ maxsegsz,
+ /* flags */ 0,
+ &adv->parent_dmat);
+
+ if (error != 0) {
+ printf("%s: Could not allocate DMA tag - error %d\n",
+ adv_name(adv), error);
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
+ break;
+ }
+
+ adv->init_level += 2;
+
+ if (overrun_buf == NULL) {
+ /* Need to allocate our overrun buffer */
+ if (bus_dma_tag_create(
+ /* parent */ adv->parent_dmat,
+ /* alignment */ 8,
+ /* boundary */ 0,
+ /* lowaddr */ ADV_ISA_MAX_DMA_ADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ ADV_OVERRUN_BSIZE,
+ /* nsegments */ 1,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ 0,
+ &overrun_dmat) != 0) {
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, 0,
+ iores);
+ break;
+ }
+ if (bus_dmamem_alloc(overrun_dmat,
+ (void **)&overrun_buf,
+ BUS_DMA_NOWAIT,
+ &overrun_dmamap) != 0) {
+ bus_dma_tag_destroy(overrun_dmat);
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, 0,
+ iores);
+ break;
+ }
+ /* And permanently map it in */
+ bus_dmamap_load(overrun_dmat, overrun_dmamap,
+ overrun_buf, ADV_OVERRUN_BSIZE,
+ adv_map, &overrun_physbase,
+ /*flags*/0);
+ }
+
+ adv->overrun_physbase = overrun_physbase;
+
+ if (adv_init(adv) != 0) {
+ bus_dmamap_unload(overrun_dmat, overrun_dmamap);
+ bus_dmamem_free(overrun_dmat, overrun_buf,
+ overrun_dmamap);
+ bus_dma_tag_destroy(overrun_dmat);
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
+ break;
+ }
+
+ switch (adv->type) {
+ case ADV_ISAPNP:
+ if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG) {
+ adv->bug_fix_control
+ |= ADV_BUG_FIX_ASYN_USE_SYN;
+ adv->fix_asyn_xfer = ~0;
+ }
+ /* Fall Through */
+ case ADV_ISA:
+ adv->max_dma_count = ADV_ISA_MAX_DMA_COUNT;
+ adv->max_dma_addr = ADV_ISA_MAX_DMA_ADDR;
+ adv_set_isa_dma_settings(adv);
+ break;
+
+ case ADV_VL:
+ adv->max_dma_count = ADV_VL_MAX_DMA_COUNT;
+ adv->max_dma_addr = ADV_VL_MAX_DMA_ADDR;
+ break;
+ default:
+ panic("advisaprobe: Invalid card type\n");
+ }
+
+ /* Determine our IRQ */
+ if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL))
+ bus_set_resource(dev, SYS_RES_IRQ, 0,
+ adv_get_chip_irq(adv), 1);
+ else
+ adv_set_chip_irq(adv, irq);
+
+ irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_ACTIVE);
+ if (irqres == NULL ||
+ bus_setup_intr(dev, irqres, INTR_TYPE_CAM|INTR_ENTROPY,
+ adv_intr, adv, &ih)) {
+ bus_dmamap_unload(overrun_dmat, overrun_dmamap);
+ bus_dmamem_free(overrun_dmat, overrun_buf,
+ overrun_dmamap);
+ bus_dma_tag_destroy(overrun_dmat);
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
+ break;
+ }
+
+ /* Mark as probed */
+ adv_isa_ioports[port_index] = 0;
+ return 0;
+ }
+
+ if (user_iobase)
+ bus_set_resource(dev, SYS_RES_IOPORT, 0, iobase, iocount);
+ else
+ bus_delete_resource(dev, SYS_RES_IOPORT, 0);
+
+ return ENXIO;
+}
+
+static int
+adv_isa_attach(device_t dev)
+{
+ struct adv_softc *adv = device_get_softc(dev);
+
+ return (adv_attach(adv));
+}
+
+static int
+adv_get_isa_dma_channel(struct adv_softc *adv)
+{
+ int channel;
+
+ channel = ADV_INW(adv, ADV_CONFIG_LSW) & ADV_CFG_LSW_ISA_DMA_CHANNEL;
+ if (channel == 0x03)
+ return (0);
+ else if (channel == 0x00)
+ return (7);
+ return (channel + 4);
+}
+
+static int
+adv_set_isa_dma_settings(struct adv_softc *adv)
+{
+ u_int16_t cfg_lsw;
+ u_int8_t value;
+
+ if ((adv->isa_dma_channel >= 5) && (adv->isa_dma_channel <= 7)) {
+ if (adv->isa_dma_channel == 7)
+ value = 0x00;
+ else
+ value = adv->isa_dma_channel - 4;
+ cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW)
+ & ~ADV_CFG_LSW_ISA_DMA_CHANNEL;
+ cfg_lsw |= value;
+ ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
+
+ adv->isa_dma_speed &= 0x07;
+ adv_set_bank(adv, 1);
+ ADV_OUTB(adv, ADV_DMA_SPEED, adv->isa_dma_speed);
+ adv_set_bank(adv, 0);
+ isa_dmacascade(adv->isa_dma_channel);
+ }
+ return (0);
+}
+
+static void
+adv_set_isapnp_wait_for_key(void)
+{
+ static int isapnp_wait_set = 0;
+ if (isapnp_wait_set == 0) {
+ outb(ADV_ISA_PNP_PORT_ADDR, 0x02);
+ outb(ADV_ISA_PNP_PORT_WRITE, 0x02);
+ isapnp_wait_set++;
+ }
+}
+
+static device_method_t adv_isa_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, adv_isa_probe),
+ DEVMETHOD(device_attach, adv_isa_attach),
+ { 0, 0 }
+};
+
+static driver_t adv_isa_driver = {
+ "adv", adv_isa_methods, sizeof(struct adv_softc)
+};
+
+static devclass_t adv_isa_devclass;
+DRIVER_MODULE(adv, isa, adv_isa_driver, adv_isa_devclass, 0, 0);
diff --git a/sys/dev/advansys/adv_pci.c b/sys/dev/advansys/adv_pci.c
new file mode 100644
index 0000000..0891f48
--- /dev/null
+++ b/sys/dev/advansys/adv_pci.c
@@ -0,0 +1,327 @@
+/*
+ * Device probe and attach routines for the following
+ * Advanced Systems Inc. SCSI controllers:
+ *
+ * Connectivity Products:
+ * ABP902/3902 - Bus-Master PCI (16 CDB)
+ * ABP3905 - Bus-Master PCI (16 CDB)
+ * ABP915 - Bus-Master PCI (16 CDB)
+ * ABP920 - Bus-Master PCI (16 CDB)
+ * ABP3922 - Bus-Master PCI (16 CDB)
+ * ABP3925 - Bus-Master PCI (16 CDB)
+ * ABP930 - Bus-Master PCI (16 CDB) *
+ * ABP930U - Bus-Master PCI Ultra (16 CDB)
+ * ABP930UA - Bus-Master PCI Ultra (16 CDB)
+ * ABP960 - Bus-Master PCI MAC/PC (16 CDB) **
+ * ABP960U - Bus-Master PCI MAC/PC (16 CDB) **
+ *
+ * Single Channel Products:
+ * ABP940 - Bus-Master PCI (240 CDB)
+ * ABP940U - Bus-Master PCI Ultra (240 CDB)
+ * ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
+ * ABP3960UA - Bus-Master PCI MAC/PC (240 CDB)
+ * ABP970 - Bus-Master PCI MAC/PC (240 CDB)
+ * ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
+ *
+ * Dual Channel Products:
+ * ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+ * ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
+ * ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
+ * ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
+ *
+ * Footnotes:
+ * * This board has been sold by SIIG as the Fast SCSI Pro PCI.
+ * ** This board has been sold by Iomega as a Jaz Jet PCI adapter.
+ *
+ * Copyright (c) 1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#include <dev/advansys/advansys.h>
+
+#define PCI_BASEADR0 PCIR_MAPS /* I/O Address */
+#define PCI_BASEADR1 PCIR_MAPS + 4 /* Mem I/O Address */
+
+#define PCI_DEVICE_ID_ADVANSYS_1200A 0x110010CD
+#define PCI_DEVICE_ID_ADVANSYS_1200B 0x120010CD
+#define PCI_DEVICE_ID_ADVANSYS_3000 0x130010CD
+#define PCI_DEVICE_REV_ADVANSYS_3150 0x02
+#define PCI_DEVICE_REV_ADVANSYS_3050 0x03
+
+#define ADV_PCI_MAX_DMA_ADDR (0xFFFFFFFFL)
+#define ADV_PCI_MAX_DMA_COUNT (0xFFFFFFFFL)
+
+static int adv_pci_probe(device_t);
+static int adv_pci_attach(device_t);
+
+/*
+ * The overrun buffer shared amongst all PCI adapters.
+ */
+static u_int8_t* overrun_buf;
+static bus_dma_tag_t overrun_dmat;
+static bus_dmamap_t overrun_dmamap;
+static bus_addr_t overrun_physbase;
+
+static int
+adv_pci_probe(device_t dev)
+{
+ int rev = pci_get_revid(dev);
+
+ switch (pci_get_devid(dev)) {
+ case PCI_DEVICE_ID_ADVANSYS_1200A:
+ device_set_desc(dev, "AdvanSys ASC1200A SCSI controller");
+ return 0;
+ case PCI_DEVICE_ID_ADVANSYS_1200B:
+ device_set_desc(dev, "AdvanSys ASC1200B SCSI controller");
+ return 0;
+ case PCI_DEVICE_ID_ADVANSYS_3000:
+ if (rev == PCI_DEVICE_REV_ADVANSYS_3150) {
+ device_set_desc(dev,
+ "AdvanSys ASC3150 SCSI controller");
+ return 0;
+ } else if (rev == PCI_DEVICE_REV_ADVANSYS_3050) {
+ device_set_desc(dev,
+ "AdvanSys ASC3030/50 SCSI controller");
+ return 0;
+ } else if (rev >= PCI_DEVICE_REV_ADVANSYS_3150) {
+ device_set_desc(dev, "Unknown AdvanSys controller");
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return ENXIO;
+}
+
+static int
+adv_pci_attach(device_t dev)
+{
+ struct adv_softc *adv;
+ u_int32_t id;
+ u_int32_t command;
+ int error, rid, irqrid;
+ void *ih;
+ struct resource *iores, *irqres;
+
+ /*
+ * Determine the chip version.
+ */
+ id = pci_read_config(dev, PCIR_DEVVENDOR, /*bytes*/4);
+ command = pci_read_config(dev, PCIR_COMMAND, /*bytes*/1);
+
+ /*
+ * These cards do not allow memory mapped accesses, so we must
+ * ensure that I/O accesses are available or we won't be able
+ * to talk to them.
+ */
+ if ((command & (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN))
+ != (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN)) {
+ command |= PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN;
+ pci_write_config(dev, PCIR_COMMAND, command, /*bytes*/1);
+ }
+
+ /*
+ * Early chips can't handle non-zero latency timer settings.
+ */
+ if (id == PCI_DEVICE_ID_ADVANSYS_1200A
+ || id == PCI_DEVICE_ID_ADVANSYS_1200B) {
+ pci_write_config(dev, PCIR_LATTIMER, /*value*/0, /*bytes*/1);
+ }
+
+ rid = PCI_BASEADR0;
+ iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
+ RF_ACTIVE);
+ if (iores == NULL)
+ return ENXIO;
+
+ if (adv_find_signature(rman_get_bustag(iores),
+ rman_get_bushandle(iores)) == 0) {
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
+ return ENXIO;
+ }
+
+ adv = adv_alloc(dev, rman_get_bustag(iores), rman_get_bushandle(iores));
+ if (adv == NULL) {
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
+ return ENXIO;
+ }
+
+ /* Allocate a dmatag for our transfer DMA maps */
+ /* XXX Should be a child of the PCI bus dma tag */
+ error = bus_dma_tag_create(
+ /* parent */ NULL,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ ADV_PCI_MAX_DMA_ADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ BUS_SPACE_MAXSIZE_32BIT,
+ /* nsegments */ ~0,
+ /* maxsegsz */ ADV_PCI_MAX_DMA_COUNT,
+ /* flags */ 0,
+ &adv->parent_dmat);
+
+ if (error != 0) {
+ printf("%s: Could not allocate DMA tag - error %d\n",
+ adv_name(adv), error);
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
+ return ENXIO;
+ }
+
+ adv->init_level++;
+
+ if (overrun_buf == NULL) {
+ /* Need to allocate our overrun buffer */
+ if (bus_dma_tag_create(
+ /* parent */ adv->parent_dmat,
+ /* alignment */ 8,
+ /* boundary */ 0,
+ /* lowaddr */ ADV_PCI_MAX_DMA_ADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ ADV_OVERRUN_BSIZE,
+ /* nsegments */ 1,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ 0,
+ &overrun_dmat) != 0) {
+ bus_dma_tag_destroy(adv->parent_dmat);
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
+ return ENXIO;
+ }
+ if (bus_dmamem_alloc(overrun_dmat,
+ (void **)&overrun_buf,
+ BUS_DMA_NOWAIT,
+ &overrun_dmamap) != 0) {
+ bus_dma_tag_destroy(overrun_dmat);
+ bus_dma_tag_destroy(adv->parent_dmat);
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
+ return ENXIO;
+ }
+ /* And permanently map it in */
+ bus_dmamap_load(overrun_dmat, overrun_dmamap,
+ overrun_buf, ADV_OVERRUN_BSIZE,
+ adv_map, &overrun_physbase,
+ /*flags*/0);
+ }
+
+ adv->overrun_physbase = overrun_physbase;
+
+ /*
+ * Stop the chip.
+ */
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
+ ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
+
+ adv->chip_version = ADV_INB(adv, ADV_NONEISA_CHIP_REVISION);
+ adv->type = ADV_PCI;
+
+ /*
+ * Setup active negation and signal filtering.
+ */
+ {
+ u_int8_t extra_cfg;
+
+ if (adv->chip_version >= ADV_CHIP_VER_PCI_ULTRA_3150)
+ adv->type |= ADV_ULTRA;
+ if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050)
+ extra_cfg = ADV_IFC_ACT_NEG | ADV_IFC_WR_EN_FILTER;
+ else
+ extra_cfg = ADV_IFC_ACT_NEG | ADV_IFC_SLEW_RATE;
+ ADV_OUTB(adv, ADV_REG_IFC, extra_cfg);
+ }
+
+ if (adv_init(adv) != 0) {
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
+ return ENXIO;
+ }
+
+ adv->max_dma_count = ADV_PCI_MAX_DMA_COUNT;
+ adv->max_dma_addr = ADV_PCI_MAX_DMA_ADDR;
+
+#if CC_DISABLE_PCI_PARITY_INT
+ {
+ u_int16_t config_msw;
+
+ config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
+ config_msw &= 0xFFC0;
+ ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
+ }
+#endif
+
+ if (id == PCI_DEVICE_ID_ADVANSYS_1200A
+ || id == PCI_DEVICE_ID_ADVANSYS_1200B) {
+ adv->bug_fix_control |= ADV_BUG_FIX_IF_NOT_DWB;
+ adv->bug_fix_control |= ADV_BUG_FIX_ASYN_USE_SYN;
+ adv->fix_asyn_xfer = ~0;
+ }
+
+ irqrid = 0;
+ irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &irqrid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (irqres == NULL ||
+ bus_setup_intr(dev, irqres, INTR_TYPE_CAM|INTR_ENTROPY, adv_intr, adv, &ih)) {
+ adv_free(adv);
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
+ return ENXIO;
+ }
+
+ adv_attach(adv);
+ return 0;
+}
+
+static device_method_t adv_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, adv_pci_probe),
+ DEVMETHOD(device_attach, adv_pci_attach),
+ { 0, 0 }
+};
+
+static driver_t adv_pci_driver = {
+ "adv", adv_pci_methods, sizeof(struct adv_softc)
+};
+
+static devclass_t adv_pci_devclass;
+DRIVER_MODULE(adv, pci, adv_pci_driver, adv_pci_devclass, 0, 0);
diff --git a/sys/dev/advansys/advansys.c b/sys/dev/advansys/advansys.c
new file mode 100644
index 0000000..3a50c3e
--- /dev/null
+++ b/sys/dev/advansys/advansys.c
@@ -0,0 +1,1424 @@
+/*
+ * Generic driver for the Advanced Systems Inc. SCSI controllers
+ * Product specific probe and attach routines can be found in:
+ *
+ * i386/isa/adv_isa.c ABP5140, ABP542, ABP5150, ABP842, ABP852
+ * i386/eisa/adv_eisa.c ABP742, ABP752
+ * pci/adv_pci.c ABP920, ABP930, ABP930U, ABP930UA, ABP940, ABP940U,
+ * ABP940UA, ABP950, ABP960, ABP960U, ABP960UA,
+ * ABP970, ABP970U
+ *
+ * Copyright (c) 1996-2000 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Ported from:
+ * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
+ *
+ * Copyright (c) 1995-1997 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>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_debug.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <dev/advansys/advansys.h>
+
+static void adv_action(struct cam_sim *sim, union ccb *ccb);
+static void adv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
+ int nsegments, int error);
+static void adv_poll(struct cam_sim *sim);
+static void adv_run_doneq(struct adv_softc *adv);
+static struct adv_ccb_info *
+ adv_alloc_ccb_info(struct adv_softc *adv);
+static void adv_destroy_ccb_info(struct adv_softc *adv,
+ struct adv_ccb_info *cinfo);
+static __inline struct adv_ccb_info *
+ adv_get_ccb_info(struct adv_softc *adv);
+static __inline void adv_free_ccb_info(struct adv_softc *adv,
+ struct adv_ccb_info *cinfo);
+static __inline void adv_set_state(struct adv_softc *adv, adv_state state);
+static __inline void adv_clear_state(struct adv_softc *adv, union ccb* ccb);
+static void adv_clear_state_really(struct adv_softc *adv, union ccb* ccb);
+
+static __inline struct adv_ccb_info *
+adv_get_ccb_info(struct adv_softc *adv)
+{
+ struct adv_ccb_info *cinfo;
+ int opri;
+
+ opri = splcam();
+ if ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
+ SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
+ } else {
+ cinfo = adv_alloc_ccb_info(adv);
+ }
+ splx(opri);
+
+ return (cinfo);
+}
+
+static __inline void
+adv_free_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
+{
+ int opri;
+
+ opri = splcam();
+ cinfo->state = ACCB_FREE;
+ SLIST_INSERT_HEAD(&adv->free_ccb_infos, cinfo, links);
+ splx(opri);
+}
+
+static __inline void
+adv_set_state(struct adv_softc *adv, adv_state state)
+{
+ if (adv->state == 0)
+ xpt_freeze_simq(adv->sim, /*count*/1);
+ adv->state |= state;
+}
+
+static __inline void
+adv_clear_state(struct adv_softc *adv, union ccb* ccb)
+{
+ if (adv->state != 0)
+ adv_clear_state_really(adv, ccb);
+}
+
+static void
+adv_clear_state_really(struct adv_softc *adv, union ccb* ccb)
+{
+ if ((adv->state & ADV_BUSDMA_BLOCK_CLEARED) != 0)
+ adv->state &= ~(ADV_BUSDMA_BLOCK_CLEARED|ADV_BUSDMA_BLOCK);
+ if ((adv->state & ADV_RESOURCE_SHORTAGE) != 0) {
+ int openings;
+
+ openings = adv->max_openings - adv->cur_active - ADV_MIN_FREE_Q;
+ if (openings >= adv->openings_needed) {
+ adv->state &= ~ADV_RESOURCE_SHORTAGE;
+ adv->openings_needed = 0;
+ }
+ }
+
+ if ((adv->state & ADV_IN_TIMEOUT) != 0) {
+ struct adv_ccb_info *cinfo;
+
+ cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
+ if ((cinfo->state & ACCB_RECOVERY_CCB) != 0) {
+ struct ccb_hdr *ccb_h;
+
+ /*
+ * We now traverse our list of pending CCBs
+ * and reinstate their timeouts.
+ */
+ ccb_h = LIST_FIRST(&adv->pending_ccbs);
+ while (ccb_h != NULL) {
+ ccb_h->timeout_ch =
+ timeout(adv_timeout, (caddr_t)ccb_h,
+ (ccb_h->timeout * hz) / 1000);
+ ccb_h = LIST_NEXT(ccb_h, sim_links.le);
+ }
+ adv->state &= ~ADV_IN_TIMEOUT;
+ printf("%s: No longer in timeout\n", adv_name(adv));
+ }
+ }
+ if (adv->state == 0)
+ ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
+}
+
+void
+adv_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ bus_addr_t* physaddr;
+
+ physaddr = (bus_addr_t*)arg;
+ *physaddr = segs->ds_addr;
+}
+
+char *
+adv_name(struct adv_softc *adv)
+{
+ static char name[10];
+
+ snprintf(name, sizeof(name), "adv%d", adv->unit);
+ return (name);
+}
+
+static void
+adv_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct adv_softc *adv;
+
+ CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adv_action\n"));
+
+ adv = (struct adv_softc *)cam_sim_softc(sim);
+
+ switch (ccb->ccb_h.func_code) {
+ /* Common cases first */
+ case XPT_SCSI_IO: /* Execute the requested I/O operation */
+ {
+ struct ccb_hdr *ccb_h;
+ struct ccb_scsiio *csio;
+ struct adv_ccb_info *cinfo;
+
+ ccb_h = &ccb->ccb_h;
+ csio = &ccb->csio;
+ cinfo = adv_get_ccb_info(adv);
+ if (cinfo == NULL)
+ panic("XXX Handle CCB info error!!!");
+
+ ccb_h->ccb_cinfo_ptr = cinfo;
+ cinfo->ccb = ccb;
+
+ /* Only use S/G if there is a transfer */
+ if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
+ /*
+ * We've been given a pointer
+ * to a single buffer
+ */
+ if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
+ int s;
+ int error;
+
+ s = splsoftvm();
+ error =
+ bus_dmamap_load(adv->buffer_dmat,
+ cinfo->dmamap,
+ csio->data_ptr,
+ csio->dxfer_len,
+ adv_execute_ccb,
+ csio, /*flags*/0);
+ if (error == EINPROGRESS) {
+ /*
+ * So as to maintain ordering,
+ * freeze the controller queue
+ * until our mapping is
+ * returned.
+ */
+ adv_set_state(adv,
+ ADV_BUSDMA_BLOCK);
+ }
+ splx(s);
+ } else {
+ struct bus_dma_segment seg;
+
+ /* Pointer to physical buffer */
+ seg.ds_addr =
+ (bus_addr_t)csio->data_ptr;
+ seg.ds_len = csio->dxfer_len;
+ adv_execute_ccb(csio, &seg, 1, 0);
+ }
+ } else {
+ struct bus_dma_segment *segs;
+ if ((ccb_h->flags & CAM_DATA_PHYS) != 0)
+ panic("adv_setup_data - Physical "
+ "segment pointers unsupported");
+
+ if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0)
+ panic("adv_setup_data - Virtual "
+ "segment addresses unsupported");
+
+ /* Just use the segments provided */
+ segs = (struct bus_dma_segment *)csio->data_ptr;
+ adv_execute_ccb(ccb, segs, csio->sglist_cnt, 0);
+ }
+ } else {
+ adv_execute_ccb(ccb, NULL, 0, 0);
+ }
+ break;
+ }
+ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
+ case XPT_TARGET_IO: /* Execute target I/O request */
+ case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */
+ case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/
+ case XPT_EN_LUN: /* Enable LUN as a target */
+ case XPT_ABORT: /* Abort the specified CCB */
+ /* XXX Implement */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ case XPT_SET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts;
+ target_bit_vector targ_mask;
+ struct adv_transinfo *tconf;
+ u_int update_type;
+ int s;
+
+ cts = &ccb->cts;
+ targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
+ update_type = 0;
+
+ /*
+ * The user must specify which type of settings he wishes
+ * to change.
+ */
+ if (((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
+ && ((cts->flags & CCB_TRANS_USER_SETTINGS) == 0)) {
+ tconf = &adv->tinfo[cts->ccb_h.target_id].current;
+ update_type |= ADV_TRANS_GOAL;
+ } else if (((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
+ && ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0)) {
+ tconf = &adv->tinfo[cts->ccb_h.target_id].user;
+ update_type |= ADV_TRANS_USER;
+ } else {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+
+ s = splcam();
+
+ if ((update_type & ADV_TRANS_GOAL) != 0) {
+ if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
+ if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
+ adv->disc_enable |= targ_mask;
+ else
+ adv->disc_enable &= ~targ_mask;
+ adv_write_lram_8(adv, ADVV_DISC_ENABLE_B,
+ adv->disc_enable);
+ }
+
+ if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
+ if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
+ adv->cmd_qng_enabled |= targ_mask;
+ else
+ adv->cmd_qng_enabled &= ~targ_mask;
+ }
+ }
+
+ if ((update_type & ADV_TRANS_USER) != 0) {
+ if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
+ if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
+ adv->user_disc_enable |= targ_mask;
+ else
+ adv->user_disc_enable &= ~targ_mask;
+ }
+
+ if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
+ if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
+ adv->user_cmd_qng_enabled |= targ_mask;
+ else
+ adv->user_cmd_qng_enabled &= ~targ_mask;
+ }
+ }
+
+ /*
+ * If the user specifies either the sync rate, or offset,
+ * but not both, the unspecified parameter defaults to its
+ * current value in transfer negotiations.
+ */
+ if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
+ || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
+ /*
+ * If the user provided a sync rate but no offset,
+ * use the current offset.
+ */
+ if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0)
+ cts->sync_offset = tconf->offset;
+
+ /*
+ * If the user provided an offset but no sync rate,
+ * use the current sync rate.
+ */
+ if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0)
+ cts->sync_period = tconf->period;
+
+ adv_period_offset_to_sdtr(adv, &cts->sync_period,
+ &cts->sync_offset,
+ cts->ccb_h.target_id);
+
+ adv_set_syncrate(adv, /*struct cam_path */NULL,
+ cts->ccb_h.target_id, cts->sync_period,
+ cts->sync_offset, update_type);
+ }
+
+ splx(s);
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ /* Get default/user set transfer settings for the target */
+ {
+ struct ccb_trans_settings *cts;
+ struct adv_transinfo *tconf;
+ target_bit_vector target_mask;
+ int s;
+
+ cts = &ccb->cts;
+ target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
+
+ cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
+
+ s = splcam();
+ if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
+ tconf = &adv->tinfo[cts->ccb_h.target_id].current;
+ if ((adv->disc_enable & target_mask) != 0)
+ cts->flags |= CCB_TRANS_DISC_ENB;
+ if ((adv->cmd_qng_enabled & target_mask) != 0)
+ cts->flags |= CCB_TRANS_TAG_ENB;
+ } else {
+ tconf = &adv->tinfo[cts->ccb_h.target_id].user;
+ if ((adv->user_disc_enable & target_mask) != 0)
+ cts->flags |= CCB_TRANS_DISC_ENB;
+ if ((adv->user_cmd_qng_enabled & target_mask) != 0)
+ cts->flags |= CCB_TRANS_TAG_ENB;
+ }
+
+ cts->sync_period = tconf->period;
+ cts->sync_offset = tconf->offset;
+ splx(s);
+
+ cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ cts->valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID
+ | CCB_TRANS_BUS_WIDTH_VALID
+ | CCB_TRANS_DISC_VALID
+ | CCB_TRANS_TQ_VALID;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_CALC_GEOMETRY:
+ {
+ int extended;
+
+ extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0;
+ cam_calc_geometry(&ccb->ccg, extended);
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_RESET_BUS: /* Reset the specified SCSI bus */
+ {
+ int s;
+
+ s = splcam();
+ adv_stop_execution(adv);
+ adv_reset_bus(adv, /*initiate_reset*/TRUE);
+ adv_start_execution(adv);
+ splx(s);
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_TERM_IO: /* Terminate the I/O process */
+ /* XXX Implement */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ case XPT_PATH_INQ: /* Path routing inquiry */
+ {
+ struct ccb_pathinq *cpi = &ccb->cpi;
+
+ cpi->version_num = 1; /* XXX??? */
+ cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = 0;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = 7;
+ cpi->max_lun = 7;
+ cpi->initiator_id = adv->scsi_id;
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 3300;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "Advansys", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
+}
+
+/*
+ * Currently, the output of bus_dmammap_load suits our needs just
+ * fine, but should it change, we'd need to do something here.
+ */
+#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs)
+
+static void
+adv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
+ int nsegments, int error)
+{
+ struct ccb_scsiio *csio;
+ struct ccb_hdr *ccb_h;
+ struct cam_sim *sim;
+ struct adv_softc *adv;
+ struct adv_ccb_info *cinfo;
+ struct adv_scsi_q scsiq;
+ struct adv_sg_head sghead;
+ int s;
+
+ csio = (struct ccb_scsiio *)arg;
+ ccb_h = &csio->ccb_h;
+ sim = xpt_path_sim(ccb_h->path);
+ adv = (struct adv_softc *)cam_sim_softc(sim);
+ cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr;
+
+ /*
+ * Setup our done routine to release the simq on
+ * the next ccb that completes.
+ */
+ if ((adv->state & ADV_BUSDMA_BLOCK) != 0)
+ adv->state |= ADV_BUSDMA_BLOCK_CLEARED;
+
+ if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
+ if ((ccb_h->flags & CAM_CDB_PHYS) == 0) {
+ /* XXX Need phystovirt!!!! */
+ /* How about pmap_kenter??? */
+ scsiq.cdbptr = csio->cdb_io.cdb_ptr;
+ } else {
+ scsiq.cdbptr = csio->cdb_io.cdb_ptr;
+ }
+ } else {
+ scsiq.cdbptr = csio->cdb_io.cdb_bytes;
+ }
+ /*
+ * Build up the request
+ */
+ scsiq.q1.status = 0;
+ scsiq.q1.q_no = 0;
+ scsiq.q1.cntl = 0;
+ scsiq.q1.sg_queue_cnt = 0;
+ scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id);
+ scsiq.q1.target_lun = ccb_h->target_lun;
+ scsiq.q1.sense_len = csio->sense_len;
+ scsiq.q1.extra_bytes = 0;
+ scsiq.q2.ccb_index = cinfo - adv->ccb_infos;
+ scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id,
+ ccb_h->target_lun);
+ scsiq.q2.flag = 0;
+ scsiq.q2.cdb_len = csio->cdb_len;
+ if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0)
+ scsiq.q2.tag_code = csio->tag_action;
+ else
+ scsiq.q2.tag_code = 0;
+ scsiq.q2.vm_id = 0;
+
+ if (nsegments != 0) {
+ bus_dmasync_op_t op;
+
+ scsiq.q1.data_addr = dm_segs->ds_addr;
+ scsiq.q1.data_cnt = dm_segs->ds_len;
+ if (nsegments > 1) {
+ scsiq.q1.cntl |= QC_SG_HEAD;
+ sghead.entry_cnt
+ = sghead.entry_to_copy
+ = nsegments;
+ sghead.res = 0;
+ sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs);
+ scsiq.sg_head = &sghead;
+ } else {
+ scsiq.sg_head = NULL;
+ }
+ if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
+ op = BUS_DMASYNC_PREREAD;
+ else
+ op = BUS_DMASYNC_PREWRITE;
+ bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
+ } else {
+ scsiq.q1.data_addr = 0;
+ scsiq.q1.data_cnt = 0;
+ scsiq.sg_head = NULL;
+ }
+
+ s = splcam();
+
+ /*
+ * Last time we need to check if this SCB needs to
+ * be aborted.
+ */
+ if (ccb_h->status != CAM_REQ_INPROG) {
+ if (nsegments != 0)
+ bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
+ adv_clear_state(adv, (union ccb *)csio);
+ adv_free_ccb_info(adv, cinfo);
+ xpt_done((union ccb *)csio);
+ splx(s);
+ return;
+ }
+
+ if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) {
+ /* Temporary resource shortage */
+ adv_set_state(adv, ADV_RESOURCE_SHORTAGE);
+ if (nsegments != 0)
+ bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
+ csio->ccb_h.status = CAM_REQUEUE_REQ;
+ adv_clear_state(adv, (union ccb *)csio);
+ adv_free_ccb_info(adv, cinfo);
+ xpt_done((union ccb *)csio);
+ splx(s);
+ return;
+ }
+ cinfo->state |= ACCB_ACTIVE;
+ ccb_h->status |= CAM_SIM_QUEUED;
+ LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le);
+ /* Schedule our timeout */
+ ccb_h->timeout_ch =
+ timeout(adv_timeout, csio, (ccb_h->timeout * hz)/1000);
+ splx(s);
+}
+
+static struct adv_ccb_info *
+adv_alloc_ccb_info(struct adv_softc *adv)
+{
+ int error;
+ struct adv_ccb_info *cinfo;
+
+ cinfo = &adv->ccb_infos[adv->ccb_infos_allocated];
+ cinfo->state = ACCB_FREE;
+ error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0,
+ &cinfo->dmamap);
+ if (error != 0) {
+ printf("%s: Unable to allocate CCB info "
+ "dmamap - error %d\n", adv_name(adv), error);
+ return (NULL);
+ }
+ adv->ccb_infos_allocated++;
+ return (cinfo);
+}
+
+static void
+adv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
+{
+ bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap);
+}
+
+void
+adv_timeout(void *arg)
+{
+ int s;
+ union ccb *ccb;
+ struct adv_softc *adv;
+ struct adv_ccb_info *cinfo;
+
+ ccb = (union ccb *)arg;
+ adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc;
+ cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
+
+ xpt_print_path(ccb->ccb_h.path);
+ printf("Timed out\n");
+
+ s = splcam();
+ /* Have we been taken care of already?? */
+ if (cinfo == NULL || cinfo->state == ACCB_FREE) {
+ splx(s);
+ return;
+ }
+
+ adv_stop_execution(adv);
+
+ if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) {
+ struct ccb_hdr *ccb_h;
+
+ /*
+ * In order to simplify the recovery process, we ask the XPT
+ * layer to halt the queue of new transactions and we traverse
+ * the list of pending CCBs and remove their timeouts. This
+ * means that the driver attempts to clear only one error
+ * condition at a time. In general, timeouts that occur
+ * close together are related anyway, so there is no benefit
+ * in attempting to handle errors in parrallel. Timeouts will
+ * be reinstated when the recovery process ends.
+ */
+ adv_set_state(adv, ADV_IN_TIMEOUT);
+
+ /* This CCB is the CCB representing our recovery actions */
+ cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED;
+
+ ccb_h = LIST_FIRST(&adv->pending_ccbs);
+ while (ccb_h != NULL) {
+ untimeout(adv_timeout, ccb_h, ccb_h->timeout_ch);
+ ccb_h = LIST_NEXT(ccb_h, sim_links.le);
+ }
+
+ /* XXX Should send a BDR */
+ /* Attempt an abort as our first tact */
+ xpt_print_path(ccb->ccb_h.path);
+ printf("Attempting abort\n");
+ adv_abort_ccb(adv, ccb->ccb_h.target_id,
+ ccb->ccb_h.target_lun, ccb,
+ CAM_CMD_TIMEOUT, /*queued_only*/FALSE);
+ ccb->ccb_h.timeout_ch =
+ timeout(adv_timeout, ccb, 2 * hz);
+ } else {
+ /* Our attempt to perform an abort failed, go for a reset */
+ xpt_print_path(ccb->ccb_h.path);
+ printf("Resetting bus\n");
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
+ adv_reset_bus(adv, /*initiate_reset*/TRUE);
+ }
+ adv_start_execution(adv);
+ splx(s);
+}
+
+struct adv_softc *
+adv_alloc(device_t dev, bus_space_tag_t tag, bus_space_handle_t bsh)
+{
+ struct adv_softc *adv = device_get_softc(dev);
+
+ /*
+ * Allocate a storage area for us
+ */
+ LIST_INIT(&adv->pending_ccbs);
+ SLIST_INIT(&adv->free_ccb_infos);
+ adv->dev = dev;
+ adv->unit = device_get_unit(dev);
+ adv->tag = tag;
+ adv->bsh = bsh;
+
+ return(adv);
+}
+
+void
+adv_free(struct adv_softc *adv)
+{
+ switch (adv->init_level) {
+ case 6:
+ {
+ struct adv_ccb_info *cinfo;
+
+ while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
+ SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
+ adv_destroy_ccb_info(adv, cinfo);
+ }
+
+ bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap);
+ }
+ case 5:
+ bus_dmamem_free(adv->sense_dmat, adv->sense_buffers,
+ adv->sense_dmamap);
+ case 4:
+ bus_dma_tag_destroy(adv->sense_dmat);
+ case 3:
+ bus_dma_tag_destroy(adv->buffer_dmat);
+ case 2:
+ bus_dma_tag_destroy(adv->parent_dmat);
+ case 1:
+ if (adv->ccb_infos != NULL)
+ free(adv->ccb_infos, M_DEVBUF);
+ case 0:
+ break;
+ }
+}
+
+int
+adv_init(struct adv_softc *adv)
+{
+ struct adv_eeprom_config eeprom_config;
+ int checksum, i;
+ int max_sync;
+ u_int16_t config_lsw;
+ u_int16_t config_msw;
+
+ adv_lib_init(adv);
+
+ /*
+ * Stop script execution.
+ */
+ adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE);
+ adv_stop_execution(adv);
+ if (adv_stop_chip(adv) == 0 || adv_is_chip_halted(adv) == 0) {
+ printf("adv%d: Unable to halt adapter. Initialization"
+ "failed\n", adv->unit);
+ return (1);
+ }
+ ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
+ if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
+ printf("adv%d: Unable to set program counter. Initialization"
+ "failed\n", adv->unit);
+ return (1);
+ }
+
+ config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
+ config_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
+
+ if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) {
+ config_msw &= ~ADV_CFG_MSW_CLR_MASK;
+ /*
+ * XXX The Linux code flags this as an error,
+ * but what should we report to the user???
+ * It seems that clearing the config register
+ * makes this error recoverable.
+ */
+ ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
+ }
+
+ /* Suck in the configuration from the EEProm */
+ checksum = adv_get_eeprom_config(adv, &eeprom_config);
+
+ if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) {
+ /*
+ * XXX The Linux code sets a warning level for this
+ * condition, yet nothing of meaning is printed to
+ * the user. What does this mean???
+ */
+ if (adv->chip_version == 3) {
+ if (eeprom_config.cfg_lsw != config_lsw)
+ eeprom_config.cfg_lsw = config_lsw;
+ if (eeprom_config.cfg_msw != config_msw) {
+ eeprom_config.cfg_msw = config_msw;
+ }
+ }
+ }
+ if (checksum == eeprom_config.chksum) {
+
+ /* Range/Sanity checking */
+ if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) {
+ eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG;
+ }
+ if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) {
+ eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG;
+ }
+ if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) {
+ eeprom_config.max_tag_qng = eeprom_config.max_total_qng;
+ }
+ if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) {
+ eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC;
+ }
+ adv->max_openings = eeprom_config.max_total_qng;
+ adv->user_disc_enable = eeprom_config.disc_enable;
+ adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng;
+ adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config);
+ adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID;
+ EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id);
+ adv->control = eeprom_config.cntl;
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ u_int8_t sync_data;
+
+ if ((eeprom_config.init_sdtr & (0x1 << i)) == 0)
+ sync_data = 0;
+ else
+ sync_data = eeprom_config.sdtr_data[i];
+ adv_sdtr_to_period_offset(adv,
+ sync_data,
+ &adv->tinfo[i].user.period,
+ &adv->tinfo[i].user.offset,
+ i);
+ }
+ config_lsw = eeprom_config.cfg_lsw;
+ eeprom_config.cfg_msw = config_msw;
+ } else {
+ u_int8_t sync_data;
+
+ printf("adv%d: Warning EEPROM Checksum mismatch. "
+ "Using default device parameters\n", adv->unit);
+
+ /* Set reasonable defaults since we can't read the EEPROM */
+ adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1;
+ adv->max_openings = ADV_DEF_MAX_TOTAL_QNG;
+ adv->disc_enable = TARGET_BIT_VECTOR_SET;
+ adv->user_disc_enable = TARGET_BIT_VECTOR_SET;
+ adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
+ adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
+ adv->scsi_id = 7;
+ adv->control = 0xFFFF;
+
+ if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050)
+ /* Default to no Ultra to support the 3030 */
+ adv->control &= ~ADV_CNTL_SDTR_ENABLE_ULTRA;
+ sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4);
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ adv_sdtr_to_period_offset(adv, sync_data,
+ &adv->tinfo[i].user.period,
+ &adv->tinfo[i].user.offset,
+ i);
+ }
+ config_lsw |= ADV_CFG_LSW_SCSI_PARITY_ON;
+ }
+ config_msw &= ~ADV_CFG_MSW_CLR_MASK;
+ config_lsw |= ADV_CFG_LSW_HOST_INT_ON;
+ if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)
+ && (adv->control & ADV_CNTL_SDTR_ENABLE_ULTRA) == 0)
+ /* 25ns or 10MHz */
+ max_sync = 25;
+ else
+ /* Unlimited */
+ max_sync = 0;
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if (adv->tinfo[i].user.period < max_sync)
+ adv->tinfo[i].user.period = max_sync;
+ }
+
+ if (adv_test_external_lram(adv) == 0) {
+ if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) {
+ eeprom_config.max_total_qng =
+ ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
+ eeprom_config.max_tag_qng =
+ ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG;
+ } else {
+ eeprom_config.cfg_msw |= 0x0800;
+ config_msw |= 0x0800;
+ eeprom_config.max_total_qng =
+ ADV_MAX_PCI_INRAM_TOTAL_QNG;
+ eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG;
+ }
+ adv->max_openings = eeprom_config.max_total_qng;
+ }
+ ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
+ ADV_OUTW(adv, ADV_CONFIG_LSW, config_lsw);
+#if 0
+ /*
+ * Don't write the eeprom data back for now.
+ * I'd rather not mess up the user's card. We also don't
+ * fully sanitize the eeprom settings above for the write-back
+ * to be 100% correct.
+ */
+ if (adv_set_eeprom_config(adv, &eeprom_config) != 0)
+ printf("%s: WARNING! Failure writing to EEPROM.\n",
+ adv_name(adv));
+#endif
+
+ adv_set_chip_scsiid(adv, adv->scsi_id);
+ if (adv_init_lram_and_mcode(adv))
+ return (1);
+
+ adv->disc_enable = adv->user_disc_enable;
+
+ adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ /*
+ * Start off in async mode.
+ */
+ adv_set_syncrate(adv, /*struct cam_path */NULL,
+ i, /*period*/0, /*offset*/0,
+ ADV_TRANS_CUR);
+ /*
+ * Enable the use of tagged commands on all targets.
+ * This allows the kernel driver to make up it's own mind
+ * as it sees fit to tag queue instead of having the
+ * firmware try and second guess the tag_code settins.
+ */
+ adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + i,
+ adv->max_openings);
+ }
+ adv_write_lram_8(adv, ADVV_USE_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
+ adv_write_lram_8(adv, ADVV_CAN_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
+ printf("adv%d: AdvanSys %s Host Adapter, SCSI ID %d, queue depth %d\n",
+ adv->unit, (adv->type & ADV_ULTRA) && (max_sync == 0)
+ ? "Ultra SCSI" : "SCSI",
+ adv->scsi_id, adv->max_openings);
+ return (0);
+}
+
+void
+adv_intr(void *arg)
+{
+ struct adv_softc *adv;
+ u_int16_t chipstat;
+ u_int16_t saved_ram_addr;
+ u_int8_t ctrl_reg;
+ u_int8_t saved_ctrl_reg;
+ u_int8_t host_flag;
+
+ adv = (struct adv_softc *)arg;
+
+ chipstat = ADV_INW(adv, ADV_CHIP_STATUS);
+
+ /* Is it for us? */
+ if ((chipstat & (ADV_CSW_INT_PENDING|ADV_CSW_SCSI_RESET_LATCH)) == 0)
+ return;
+
+ ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL);
+ saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET |
+ ADV_CC_SINGLE_STEP | ADV_CC_DIAG |
+ ADV_CC_TEST));
+
+ if ((chipstat & (ADV_CSW_SCSI_RESET_LATCH|ADV_CSW_SCSI_RESET_ACTIVE))) {
+ printf("Detected Bus Reset\n");
+ adv_reset_bus(adv, /*initiate_reset*/FALSE);
+ return;
+ }
+
+ if ((chipstat & ADV_CSW_INT_PENDING) != 0) {
+
+ saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR);
+ host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
+ adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
+ host_flag | ADV_HOST_FLAG_IN_ISR);
+
+ adv_ack_interrupt(adv);
+
+ if ((chipstat & ADV_CSW_HALTED) != 0
+ && (ctrl_reg & ADV_CC_SINGLE_STEP) != 0) {
+ adv_isr_chip_halted(adv);
+ saved_ctrl_reg &= ~ADV_CC_HALT;
+ } else {
+ adv_run_doneq(adv);
+ }
+ ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr);
+#ifdef DIAGNOSTIC
+ if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr)
+ panic("adv_intr: Unable to set LRAM addr");
+#endif
+ adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
+ }
+
+ ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg);
+}
+
+static void
+adv_run_doneq(struct adv_softc *adv)
+{
+ struct adv_q_done_info scsiq;
+ u_int doneq_head;
+ u_int done_qno;
+
+ doneq_head = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF;
+ done_qno = adv_read_lram_8(adv, ADV_QNO_TO_QADDR(doneq_head)
+ + ADV_SCSIQ_B_FWD);
+ while (done_qno != ADV_QLINK_END) {
+ union ccb* ccb;
+ struct adv_ccb_info *cinfo;
+ u_int done_qaddr;
+ u_int sg_queue_cnt;
+ int aborted;
+
+ done_qaddr = ADV_QNO_TO_QADDR(done_qno);
+
+ /* Pull status from this request */
+ sg_queue_cnt = adv_copy_lram_doneq(adv, done_qaddr, &scsiq,
+ adv->max_dma_count);
+
+ /* Mark it as free */
+ adv_write_lram_8(adv, done_qaddr + ADV_SCSIQ_B_STATUS,
+ scsiq.q_status & ~(QS_READY|QS_ABORTED));
+
+ /* Process request based on retrieved info */
+ if ((scsiq.cntl & QC_SG_HEAD) != 0) {
+ u_int i;
+
+ /*
+ * S/G based request. Free all of the queue
+ * structures that contained S/G information.
+ */
+ for (i = 0; i < sg_queue_cnt; i++) {
+ done_qno = adv_read_lram_8(adv, done_qaddr
+ + ADV_SCSIQ_B_FWD);
+
+#ifdef DIAGNOSTIC
+ if (done_qno == ADV_QLINK_END) {
+ panic("adv_qdone: Corrupted SG "
+ "list encountered");
+ }
+#endif
+ done_qaddr = ADV_QNO_TO_QADDR(done_qno);
+
+ /* Mark SG queue as free */
+ adv_write_lram_8(adv, done_qaddr
+ + ADV_SCSIQ_B_STATUS, QS_FREE);
+ }
+ } else
+ sg_queue_cnt = 0;
+#ifdef DIAGNOSTIC
+ if (adv->cur_active < (sg_queue_cnt + 1))
+ panic("adv_qdone: Attempting to free more "
+ "queues than are active");
+#endif
+ adv->cur_active -= sg_queue_cnt + 1;
+
+ aborted = (scsiq.q_status & QS_ABORTED) != 0;
+
+ if ((scsiq.q_status != QS_DONE)
+ && (scsiq.q_status & QS_ABORTED) == 0)
+ panic("adv_qdone: completed scsiq with unknown status");
+
+ scsiq.remain_bytes += scsiq.extra_bytes;
+
+ if ((scsiq.d3.done_stat == QD_WITH_ERROR) &&
+ (scsiq.d3.host_stat == QHSTA_M_DATA_OVER_RUN)) {
+ if ((scsiq.cntl & (QC_DATA_IN|QC_DATA_OUT)) == 0) {
+ scsiq.d3.done_stat = QD_NO_ERROR;
+ scsiq.d3.host_stat = QHSTA_NO_ERROR;
+ }
+ }
+
+ cinfo = &adv->ccb_infos[scsiq.d2.ccb_index];
+ ccb = cinfo->ccb;
+ ccb->csio.resid = scsiq.remain_bytes;
+ adv_done(adv, ccb,
+ scsiq.d3.done_stat, scsiq.d3.host_stat,
+ scsiq.d3.scsi_stat, scsiq.q_no);
+
+ doneq_head = done_qno;
+ done_qno = adv_read_lram_8(adv, done_qaddr + ADV_SCSIQ_B_FWD);
+ }
+ adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, doneq_head);
+}
+
+
+void
+adv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat,
+ u_int host_stat, u_int scsi_status, u_int q_no)
+{
+ struct adv_ccb_info *cinfo;
+
+ cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
+ LIST_REMOVE(&ccb->ccb_h, sim_links.le);
+ untimeout(adv_timeout, ccb, ccb->ccb_h.timeout_ch);
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ bus_dmasync_op_t op;
+
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+ op = BUS_DMASYNC_POSTREAD;
+ else
+ op = BUS_DMASYNC_POSTWRITE;
+ bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
+ bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
+ }
+
+ switch (done_stat) {
+ case QD_NO_ERROR:
+ if (host_stat == QHSTA_NO_ERROR) {
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ xpt_print_path(ccb->ccb_h.path);
+ printf("adv_done - queue done without error, "
+ "but host status non-zero(%x)\n", host_stat);
+ /*FALLTHROUGH*/
+ case QD_WITH_ERROR:
+ switch (host_stat) {
+ case QHSTA_M_TARGET_STATUS_BUSY:
+ case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY:
+ /*
+ * Assume that if we were a tagged transaction
+ * the target reported queue full. Otherwise,
+ * report busy. The firmware really should just
+ * pass the original status back up to us even
+ * if it thinks the target was in error for
+ * returning this status as no other transactions
+ * from this initiator are in effect, but this
+ * ignores multi-initiator setups and there is
+ * evidence that the firmware gets its per-device
+ * transaction counts screwed up occassionally.
+ */
+ ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
+ if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
+ && host_stat != QHSTA_M_TARGET_STATUS_BUSY)
+ scsi_status = SCSI_STATUS_QUEUE_FULL;
+ else
+ scsi_status = SCSI_STATUS_BUSY;
+ adv_abort_ccb(adv, ccb->ccb_h.target_id,
+ ccb->ccb_h.target_lun,
+ /*ccb*/NULL, CAM_REQUEUE_REQ,
+ /*queued_only*/TRUE);
+ /*FALLTHROUGH*/
+ case QHSTA_M_NO_AUTO_REQ_SENSE:
+ case QHSTA_NO_ERROR:
+ ccb->csio.scsi_status = scsi_status;
+ switch (scsi_status) {
+ case SCSI_STATUS_CHECK_COND:
+ case SCSI_STATUS_CMD_TERMINATED:
+ ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
+ /* Structure copy */
+ ccb->csio.sense_data =
+ adv->sense_buffers[q_no - 1];
+ /* FALLTHROUGH */
+ case SCSI_STATUS_BUSY:
+ case SCSI_STATUS_RESERV_CONFLICT:
+ case SCSI_STATUS_QUEUE_FULL:
+ case SCSI_STATUS_COND_MET:
+ case SCSI_STATUS_INTERMED:
+ case SCSI_STATUS_INTERMED_COND_MET:
+ ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
+ break;
+ case SCSI_STATUS_OK:
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+ break;
+ }
+ break;
+ case QHSTA_M_SEL_TIMEOUT:
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ break;
+ case QHSTA_M_DATA_OVER_RUN:
+ ccb->ccb_h.status = CAM_DATA_RUN_ERR;
+ break;
+ case QHSTA_M_UNEXPECTED_BUS_FREE:
+ ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
+ break;
+ case QHSTA_M_BAD_BUS_PHASE_SEQ:
+ ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
+ break;
+ case QHSTA_M_BAD_CMPL_STATUS_IN:
+ /* No command complete after a status message */
+ ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
+ break;
+ case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT:
+ case QHSTA_M_WTM_TIMEOUT:
+ case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET:
+ /* The SCSI bus hung in a phase */
+ ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
+ adv_reset_bus(adv, /*initiate_reset*/TRUE);
+ break;
+ case QHSTA_M_AUTO_REQ_SENSE_FAIL:
+ ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
+ break;
+ case QHSTA_D_QDONE_SG_LIST_CORRUPTED:
+ case QHSTA_D_ASC_DVC_ERROR_CODE_SET:
+ case QHSTA_D_HOST_ABORT_FAILED:
+ case QHSTA_D_EXE_SCSI_Q_FAILED:
+ case QHSTA_D_ASPI_NO_BUF_POOL:
+ case QHSTA_M_BAD_TAG_CODE:
+ case QHSTA_D_LRAM_CMP_ERROR:
+ case QHSTA_M_MICRO_CODE_ERROR_HALT:
+ default:
+ panic("%s: Unhandled Host status error %x",
+ adv_name(adv), host_stat);
+ /* NOTREACHED */
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ /* Don't clobber any, more explicit, error codes we've set */
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
+ ccb->ccb_h.status = CAM_REQ_ABORTED;
+ break;
+
+ default:
+ xpt_print_path(ccb->ccb_h.path);
+ printf("adv_done - queue done with unknown status %x:%x\n",
+ done_stat, host_stat);
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ break;
+ }
+ adv_clear_state(adv, ccb);
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP
+ && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ }
+ adv_free_ccb_info(adv, cinfo);
+ /*
+ * Null this out so that we catch driver bugs that cause a
+ * ccb to be completed twice.
+ */
+ ccb->ccb_h.ccb_cinfo_ptr = NULL;
+ ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+ xpt_done(ccb);
+}
+
+/*
+ * Function to poll for command completion when
+ * interrupts are disabled (crash dumps)
+ */
+static void
+adv_poll(struct cam_sim *sim)
+{
+ adv_intr(cam_sim_softc(sim));
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+adv_attach(adv)
+ struct adv_softc *adv;
+{
+ struct ccb_setasync csa;
+ struct cam_devq *devq;
+ int max_sg;
+
+ /*
+ * Allocate an array of ccb mapping structures. We put the
+ * index of the ccb_info structure into the queue representing
+ * a transaction and use it for mapping the queue to the
+ * upper level SCSI transaction it represents.
+ */
+ adv->ccb_infos = malloc(sizeof(*adv->ccb_infos) * adv->max_openings,
+ M_DEVBUF, M_NOWAIT);
+
+ if (adv->ccb_infos == NULL)
+ return (ENOMEM);
+
+ adv->init_level++;
+
+ /*
+ * Create our DMA tags. These tags define the kinds of device
+ * accessible memory allocations and memory mappings we will
+ * need to perform during normal operation.
+ *
+ * Unless we need to further restrict the allocation, we rely
+ * on the restrictions of the parent dmat, hence the common
+ * use of MAXADDR and MAXSIZE.
+ *
+ * The ASC boards use chains of "queues" (the transactional
+ * resources on the board) to represent long S/G lists.
+ * The first queue represents the command and holds a
+ * single address and data pair. The queues that follow
+ * can each hold ADV_SG_LIST_PER_Q entries. Given the
+ * total number of queues, we can express the largest
+ * transaction we can map. We reserve a few queues for
+ * error recovery. Take those into account as well.
+ *
+ * There is a way to take an interrupt to download the
+ * next batch of S/G entries if there are more than 255
+ * of them (the counter in the queue structure is a u_int8_t).
+ * We don't use this feature, so limit the S/G list size
+ * accordingly.
+ */
+ max_sg = (adv->max_openings - ADV_MIN_FREE_Q - 1) * ADV_SG_LIST_PER_Q;
+ if (max_sg > 255)
+ max_sg = 255;
+
+ /* DMA tag for mapping buffers into device visible space. */
+ if (bus_dma_tag_create(
+ /* parent */ adv->parent_dmat,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ BUS_SPACE_MAXADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ MAXPHYS,
+ /* nsegments */ max_sg,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ BUS_DMA_ALLOCNOW,
+ &adv->buffer_dmat) != 0) {
+ return (ENXIO);
+ }
+ adv->init_level++;
+
+ /* DMA tag for our sense buffers */
+ if (bus_dma_tag_create(
+ /* parent */ adv->parent_dmat,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ BUS_SPACE_MAXADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ sizeof(struct scsi_sense_data) *
+ adv->max_openings,
+ /* nsegments */ 1,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ 0,
+ &adv->sense_dmat) != 0) {
+ return (ENXIO);
+ }
+
+ adv->init_level++;
+
+ /* Allocation for our sense buffers */
+ if (bus_dmamem_alloc(adv->sense_dmat, (void **)&adv->sense_buffers,
+ BUS_DMA_NOWAIT, &adv->sense_dmamap) != 0) {
+ return (ENOMEM);
+ }
+
+ adv->init_level++;
+
+ /* And permanently map them */
+ bus_dmamap_load(adv->sense_dmat, adv->sense_dmamap,
+ adv->sense_buffers,
+ sizeof(struct scsi_sense_data)*adv->max_openings,
+ adv_map, &adv->sense_physbase, /*flags*/0);
+
+ adv->init_level++;
+
+ /*
+ * Fire up the chip
+ */
+ if (adv_start_chip(adv) != 1) {
+ printf("adv%d: Unable to start on board processor. Aborting.\n",
+ adv->unit);
+ return (ENXIO);
+ }
+
+ /*
+ * Create the device queue for our SIM.
+ */
+ devq = cam_simq_alloc(adv->max_openings);
+ if (devq == NULL)
+ return (ENOMEM);
+
+ /*
+ * Construct our SIM entry.
+ */
+ adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv, adv->unit,
+ 1, adv->max_openings, devq);
+ if (adv->sim == NULL)
+ return (ENOMEM);
+
+ /*
+ * Register the bus.
+ *
+ * XXX Twin Channel EISA Cards???
+ */
+ if (xpt_bus_register(adv->sim, 0) != CAM_SUCCESS) {
+ cam_sim_free(adv->sim, /*free devq*/TRUE);
+ return (ENXIO);
+ }
+
+ if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim),
+ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
+ != CAM_REQ_CMP) {
+ xpt_bus_deregister(cam_sim_path(adv->sim));
+ cam_sim_free(adv->sim, /*free devq*/TRUE);
+ return (ENXIO);
+ }
+
+ xpt_setup_ccb(&csa.ccb_h, adv->path, /*priority*/5);
+ csa.ccb_h.func_code = XPT_SASYNC_CB;
+ csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE;
+ csa.callback = advasync;
+ csa.callback_arg = adv;
+ xpt_action((union ccb *)&csa);
+ return (0);
+}
diff --git a/sys/dev/advansys/advansys.h b/sys/dev/advansys/advansys.h
new file mode 100644
index 0000000..ab4e550
--- /dev/null
+++ b/sys/dev/advansys/advansys.h
@@ -0,0 +1,55 @@
+/*
+ * Generic driver definitions and exported functions for the Advanced
+ * Systems Inc. SCSI controllers
+ *
+ * Copyright (c) 1996-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * All rights reserved.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ADVANSYS_H_
+#define _ADVANSYS_H_
+
+#include <dev/advansys/advlib.h>
+
+struct adv_softc * adv_alloc(device_t dev, bus_space_tag_t tag,
+ bus_space_handle_t bsh);
+char * adv_name(struct adv_softc *adv);
+void adv_map(void *arg, bus_dma_segment_t *segs,
+ int nseg, int error);
+void adv_free(struct adv_softc *adv);
+int adv_init(struct adv_softc *adv);
+void adv_intr(void *arg);
+int adv_attach(struct adv_softc *adv);
+void adv_done(struct adv_softc *adv, union ccb* ccb,
+ u_int done_stat, u_int host_stat,
+ u_int scsi_stat, u_int q_no);
+timeout_t adv_timeout;
+
+#endif /* _ADVANSYS_H_ */
diff --git a/sys/dev/advansys/advlib.c b/sys/dev/advansys/advlib.c
new file mode 100644
index 0000000..06c3276
--- /dev/null
+++ b/sys/dev/advansys/advlib.c
@@ -0,0 +1,2082 @@
+/*
+ * Low level routines for the Advanced Systems Inc. SCSI controllers chips
+ *
+ * Copyright (c) 1996-1997, 1999-2000 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+#include <cam/scsi/scsi_da.h>
+#include <cam/scsi/scsi_cd.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <dev/advansys/advansys.h>
+#include <dev/advansys/advmcode.h>
+
+struct adv_quirk_entry {
+ struct scsi_inquiry_pattern inq_pat;
+ u_int8_t quirks;
+#define ADV_QUIRK_FIX_ASYN_XFER_ALWAYS 0x01
+#define ADV_QUIRK_FIX_ASYN_XFER 0x02
+};
+
+static struct adv_quirk_entry adv_quirk_table[] =
+{
+ {
+ { T_CDROM, SIP_MEDIA_REMOVABLE, "HP", "*", "*" },
+ ADV_QUIRK_FIX_ASYN_XFER_ALWAYS|ADV_QUIRK_FIX_ASYN_XFER
+ },
+ {
+ { T_CDROM, SIP_MEDIA_REMOVABLE, "NEC", "CD-ROM DRIVE", "*" },
+ 0
+ },
+ {
+ {
+ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE,
+ "TANDBERG", " TDC 36", "*"
+ },
+ 0
+ },
+ {
+ { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "*", "*" },
+ 0
+ },
+ {
+ {
+ T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
+ "*", "*", "*"
+ },
+ 0
+ },
+ {
+ {
+ T_SCANNER, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
+ "*", "*", "*"
+ },
+ 0
+ },
+ {
+ /* Default quirk entry */
+ {
+ T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
+ /*vendor*/"*", /*product*/"*", /*revision*/"*"
+ },
+ ADV_QUIRK_FIX_ASYN_XFER,
+ }
+};
+
+/*
+ * Allowable periods in ns
+ */
+static u_int8_t adv_sdtr_period_tbl[] =
+{
+ 25,
+ 30,
+ 35,
+ 40,
+ 50,
+ 60,
+ 70,
+ 85
+};
+
+static u_int8_t adv_sdtr_period_tbl_ultra[] =
+{
+ 12,
+ 19,
+ 25,
+ 32,
+ 38,
+ 44,
+ 50,
+ 57,
+ 63,
+ 69,
+ 75,
+ 82,
+ 88,
+ 94,
+ 100,
+ 107
+};
+
+struct ext_msg {
+ u_int8_t msg_type;
+ u_int8_t msg_len;
+ u_int8_t msg_req;
+ union {
+ struct {
+ u_int8_t sdtr_xfer_period;
+ u_int8_t sdtr_req_ack_offset;
+ } sdtr;
+ struct {
+ u_int8_t wdtr_width;
+ } wdtr;
+ struct {
+ u_int8_t mdp[4];
+ } mdp;
+ } u_ext_msg;
+ u_int8_t res;
+};
+
+#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
+#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
+#define wdtr_width u_ext_msg.wdtr.wdtr_width
+#define mdp_b3 u_ext_msg.mdp_b3
+#define mdp_b2 u_ext_msg.mdp_b2
+#define mdp_b1 u_ext_msg.mdp_b1
+#define mdp_b0 u_ext_msg.mdp_b0
+
+/*
+ * Some of the early PCI adapters have problems with
+ * async transfers. Instead use an offset of 1.
+ */
+#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
+
+/* LRAM routines */
+static void adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *buffer, int count);
+static void adv_write_lram_16_multi(struct adv_softc *adv,
+ u_int16_t s_addr, u_int16_t *buffer,
+ int count);
+static void adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t set_value, int count);
+static u_int32_t adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr,
+ int count);
+
+static int adv_write_and_verify_lram_16(struct adv_softc *adv,
+ u_int16_t addr, u_int16_t value);
+static u_int32_t adv_read_lram_32(struct adv_softc *adv, u_int16_t addr);
+
+
+static void adv_write_lram_32(struct adv_softc *adv, u_int16_t addr,
+ u_int32_t value);
+static void adv_write_lram_32_multi(struct adv_softc *adv,
+ u_int16_t s_addr, u_int32_t *buffer,
+ int count);
+
+/* EEPROM routines */
+static u_int16_t adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr);
+static u_int16_t adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr,
+ u_int16_t value);
+static int adv_write_eeprom_cmd_reg(struct adv_softc *adv,
+ u_int8_t cmd_reg);
+static int adv_set_eeprom_config_once(struct adv_softc *adv,
+ struct adv_eeprom_config *eeconfig);
+
+/* Initialization */
+static u_int32_t adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *mcode_buf, u_int16_t mcode_size);
+
+static void adv_reinit_lram(struct adv_softc *adv);
+static void adv_init_lram(struct adv_softc *adv);
+static int adv_init_microcode_var(struct adv_softc *adv);
+static void adv_init_qlink_var(struct adv_softc *adv);
+
+/* Interrupts */
+static void adv_disable_interrupt(struct adv_softc *adv);
+static void adv_enable_interrupt(struct adv_softc *adv);
+static void adv_toggle_irq_act(struct adv_softc *adv);
+
+/* Chip Control */
+static int adv_host_req_chip_halt(struct adv_softc *adv);
+static void adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code);
+#if UNUSED
+static u_int8_t adv_get_chip_scsi_ctrl(struct adv_softc *adv);
+#endif
+
+/* Queue handling and execution */
+static __inline int
+ adv_sgcount_to_qcount(int sgcount);
+
+static __inline int
+adv_sgcount_to_qcount(int sgcount)
+{
+ int n_sg_list_qs;
+
+ n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q);
+ if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0)
+ n_sg_list_qs++;
+ return (n_sg_list_qs + 1);
+}
+
+#if BYTE_ORDER == BIG_ENDIAN
+static void adv_adj_endian_qdone_info(struct adv_q_done_info *);
+static void adv_adj_scsiq_endian(struct adv_scsi_q *);
+#endif
+static void adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *inbuf, int words);
+static u_int adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs);
+static u_int8_t adv_alloc_free_queues(struct adv_softc *adv,
+ u_int8_t free_q_head, u_int8_t n_free_q);
+static u_int8_t adv_alloc_free_queue(struct adv_softc *adv,
+ u_int8_t free_q_head);
+static int adv_send_scsi_queue(struct adv_softc *adv,
+ struct adv_scsi_q *scsiq,
+ u_int8_t n_q_required);
+static void adv_put_ready_sg_list_queue(struct adv_softc *adv,
+ struct adv_scsi_q *scsiq,
+ u_int q_no);
+static void adv_put_ready_queue(struct adv_softc *adv,
+ struct adv_scsi_q *scsiq, u_int q_no);
+static void adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *buffer, int words);
+
+/* Messages */
+static void adv_handle_extmsg_in(struct adv_softc *adv,
+ u_int16_t halt_q_addr, u_int8_t q_cntl,
+ target_bit_vector target_id,
+ int tid);
+static void adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
+ u_int8_t sdtr_offset);
+static void adv_set_sdtr_reg_at_id(struct adv_softc *adv, int id,
+ u_int8_t sdtr_data);
+
+
+/* Exported functions first */
+
+void
+advasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
+{
+ struct adv_softc *adv;
+
+ adv = (struct adv_softc *)callback_arg;
+ switch (code) {
+ case AC_FOUND_DEVICE:
+ {
+ struct ccb_getdev *cgd;
+ target_bit_vector target_mask;
+ int num_entries;
+ caddr_t match;
+ struct adv_quirk_entry *entry;
+ struct adv_target_transinfo* tinfo;
+
+ cgd = (struct ccb_getdev *)arg;
+
+ target_mask = ADV_TID_TO_TARGET_MASK(cgd->ccb_h.target_id);
+
+ num_entries = sizeof(adv_quirk_table)/sizeof(*adv_quirk_table);
+ match = cam_quirkmatch((caddr_t)&cgd->inq_data,
+ (caddr_t)adv_quirk_table,
+ num_entries, sizeof(*adv_quirk_table),
+ scsi_inquiry_match);
+
+ if (match == NULL)
+ panic("advasync: device didn't match wildcard entry!!");
+
+ entry = (struct adv_quirk_entry *)match;
+
+ if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) {
+ if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER_ALWAYS)!=0)
+ adv->fix_asyn_xfer_always |= target_mask;
+ else
+ adv->fix_asyn_xfer_always &= ~target_mask;
+ /*
+ * We start out life with all bits set and clear them
+ * after we've determined that the fix isn't necessary.
+ * It may well be that we've already cleared a target
+ * before the full inquiry session completes, so don't
+ * gratuitously set a target bit even if it has this
+ * quirk. But, if the quirk exonerates a device, clear
+ * the bit now.
+ */
+ if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER) == 0)
+ adv->fix_asyn_xfer &= ~target_mask;
+ }
+ /*
+ * Reset our sync settings now that we've determined
+ * what quirks are in effect for the device.
+ */
+ tinfo = &adv->tinfo[cgd->ccb_h.target_id];
+ adv_set_syncrate(adv, cgd->ccb_h.path,
+ cgd->ccb_h.target_id,
+ tinfo->current.period,
+ tinfo->current.offset,
+ ADV_TRANS_CUR);
+ break;
+ }
+ case AC_LOST_DEVICE:
+ {
+ u_int target_mask;
+
+ if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) {
+ target_mask = 0x01 << xpt_path_target_id(path);
+ adv->fix_asyn_xfer |= target_mask;
+ }
+
+ /*
+ * Revert to async transfers
+ * for the next device.
+ */
+ adv_set_syncrate(adv, /*path*/NULL,
+ xpt_path_target_id(path),
+ /*period*/0,
+ /*offset*/0,
+ ADV_TRANS_GOAL|ADV_TRANS_CUR);
+ }
+ default:
+ break;
+ }
+}
+
+void
+adv_set_bank(struct adv_softc *adv, u_int8_t bank)
+{
+ u_int8_t control;
+
+ /*
+ * Start out with the bank reset to 0
+ */
+ control = ADV_INB(adv, ADV_CHIP_CTRL)
+ & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST
+ | ADV_CC_DIAG | ADV_CC_SCSI_RESET
+ | ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE));
+ if (bank == 1) {
+ control |= ADV_CC_BANK_ONE;
+ } else if (bank == 2) {
+ control |= ADV_CC_DIAG | ADV_CC_BANK_ONE;
+ }
+ ADV_OUTB(adv, ADV_CHIP_CTRL, control);
+}
+
+u_int8_t
+adv_read_lram_8(struct adv_softc *adv, u_int16_t addr)
+{
+ u_int8_t byte_data;
+ u_int16_t word_data;
+
+ /*
+ * LRAM is accessed on 16bit boundaries.
+ */
+ ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE);
+ word_data = ADV_INW(adv, ADV_LRAM_DATA);
+ if (addr & 1) {
+#if BYTE_ORDER == BIG_ENDIAN
+ byte_data = (u_int8_t)(word_data & 0xFF);
+#else
+ byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
+#endif
+ } else {
+#if BYTE_ORDER == BIG_ENDIAN
+ byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
+#else
+ byte_data = (u_int8_t)(word_data & 0xFF);
+#endif
+ }
+ return (byte_data);
+}
+
+void
+adv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value)
+{
+ u_int16_t word_data;
+
+ word_data = adv_read_lram_16(adv, addr & 0xFFFE);
+ if (addr & 1) {
+ word_data &= 0x00FF;
+ word_data |= (((u_int8_t)value << 8) & 0xFF00);
+ } else {
+ word_data &= 0xFF00;
+ word_data |= ((u_int8_t)value & 0x00FF);
+ }
+ adv_write_lram_16(adv, addr & 0xFFFE, word_data);
+}
+
+
+u_int16_t
+adv_read_lram_16(struct adv_softc *adv, u_int16_t addr)
+{
+ ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
+ return (ADV_INW(adv, ADV_LRAM_DATA));
+}
+
+void
+adv_write_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value)
+{
+ ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
+ ADV_OUTW(adv, ADV_LRAM_DATA, value);
+}
+
+/*
+ * Determine if there is a board at "iobase" by looking
+ * for the AdvanSys signatures. Return 1 if a board is
+ * found, 0 otherwise.
+ */
+int
+adv_find_signature(bus_space_tag_t tag, bus_space_handle_t bsh)
+{
+ u_int16_t signature;
+
+ if (bus_space_read_1(tag, bsh, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) {
+ signature = bus_space_read_2(tag, bsh, ADV_SIGNATURE_WORD);
+ if ((signature == ADV_1000_ID0W)
+ || (signature == ADV_1000_ID0W_FIX))
+ return (1);
+ }
+ return (0);
+}
+
+void
+adv_lib_init(struct adv_softc *adv)
+{
+ if ((adv->type & ADV_ULTRA) != 0) {
+ adv->sdtr_period_tbl = adv_sdtr_period_tbl_ultra;
+ adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl_ultra);
+ } else {
+ adv->sdtr_period_tbl = adv_sdtr_period_tbl;
+ adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl);
+ }
+}
+
+u_int16_t
+adv_get_eeprom_config(struct adv_softc *adv, struct
+ adv_eeprom_config *eeprom_config)
+{
+ u_int16_t sum;
+ u_int16_t *wbuf;
+ u_int8_t cfg_beg;
+ u_int8_t cfg_end;
+ u_int8_t s_addr;
+
+ wbuf = (u_int16_t *)eeprom_config;
+ sum = 0;
+
+ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+ *wbuf = adv_read_eeprom_16(adv, s_addr);
+ sum += *wbuf;
+ }
+
+ if (adv->type & ADV_VL) {
+ cfg_beg = ADV_EEPROM_CFG_BEG_VL;
+ cfg_end = ADV_EEPROM_MAX_ADDR_VL;
+ } else {
+ cfg_beg = ADV_EEPROM_CFG_BEG;
+ cfg_end = ADV_EEPROM_MAX_ADDR;
+ }
+
+ for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+ *wbuf = adv_read_eeprom_16(adv, s_addr);
+ sum += *wbuf;
+#if ADV_DEBUG_EEPROM
+ printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf);
+#endif
+ }
+ *wbuf = adv_read_eeprom_16(adv, s_addr);
+ return (sum);
+}
+
+int
+adv_set_eeprom_config(struct adv_softc *adv,
+ struct adv_eeprom_config *eeprom_config)
+{
+ int retry;
+
+ retry = 0;
+ while (1) {
+ if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) {
+ break;
+ }
+ if (++retry > ADV_EEPROM_MAX_RETRY) {
+ break;
+ }
+ }
+ return (retry > ADV_EEPROM_MAX_RETRY);
+}
+
+int
+adv_reset_chip(struct adv_softc *adv, int reset_bus)
+{
+ adv_stop_chip(adv);
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT
+ | (reset_bus ? ADV_CC_SCSI_RESET : 0));
+ DELAY(60);
+
+ adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
+ adv_set_chip_ih(adv, ADV_INS_HALT);
+
+ if (reset_bus)
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT);
+
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
+ if (reset_bus)
+ DELAY(200 * 1000);
+
+ ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_CLR_SCSI_RESET_INT);
+ ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
+ return (adv_is_chip_halted(adv));
+}
+
+int
+adv_test_external_lram(struct adv_softc* adv)
+{
+ u_int16_t q_addr;
+ u_int16_t saved_value;
+ int success;
+
+ success = 0;
+
+ q_addr = ADV_QNO_TO_QADDR(241);
+ saved_value = adv_read_lram_16(adv, q_addr);
+ if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) {
+ success = 1;
+ adv_write_lram_16(adv, q_addr, saved_value);
+ }
+ return (success);
+}
+
+
+int
+adv_init_lram_and_mcode(struct adv_softc *adv)
+{
+ u_int32_t retval;
+
+ adv_disable_interrupt(adv);
+
+ adv_init_lram(adv);
+
+ retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode,
+ adv_mcode_size);
+ if (retval != adv_mcode_chksum) {
+ printf("adv%d: Microcode download failed checksum!\n",
+ adv->unit);
+ return (1);
+ }
+
+ if (adv_init_microcode_var(adv) != 0)
+ return (1);
+
+ adv_enable_interrupt(adv);
+ return (0);
+}
+
+u_int8_t
+adv_get_chip_irq(struct adv_softc *adv)
+{
+ u_int16_t cfg_lsw;
+ u_int8_t chip_irq;
+
+ cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
+
+ if ((adv->type & ADV_VL) != 0) {
+ chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07));
+ if ((chip_irq == 0) ||
+ (chip_irq == 4) ||
+ (chip_irq == 7)) {
+ return (0);
+ }
+ return (chip_irq + (ADV_MIN_IRQ_NO - 1));
+ }
+ chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03));
+ if (chip_irq == 3)
+ chip_irq += 2;
+ return (chip_irq + ADV_MIN_IRQ_NO);
+}
+
+u_int8_t
+adv_set_chip_irq(struct adv_softc *adv, u_int8_t irq_no)
+{
+ u_int16_t cfg_lsw;
+
+ if ((adv->type & ADV_VL) != 0) {
+ if (irq_no != 0) {
+ if ((irq_no < ADV_MIN_IRQ_NO)
+ || (irq_no > ADV_MAX_IRQ_NO)) {
+ irq_no = 0;
+ } else {
+ irq_no -= ADV_MIN_IRQ_NO - 1;
+ }
+ }
+ cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3;
+ cfg_lsw |= 0x0010;
+ ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
+ adv_toggle_irq_act(adv);
+
+ cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0;
+ cfg_lsw |= (irq_no & 0x07) << 2;
+ ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
+ adv_toggle_irq_act(adv);
+ } else if ((adv->type & ADV_ISA) != 0) {
+ if (irq_no == 15)
+ irq_no -= 2;
+ irq_no -= ADV_MIN_IRQ_NO;
+ cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3;
+ cfg_lsw |= (irq_no & 0x03) << 2;
+ ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
+ }
+ return (adv_get_chip_irq(adv));
+}
+
+void
+adv_set_chip_scsiid(struct adv_softc *adv, int new_id)
+{
+ u_int16_t cfg_lsw;
+
+ cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
+ if (ADV_CONFIG_SCSIID(cfg_lsw) == new_id)
+ return;
+ cfg_lsw &= ~ADV_CFG_LSW_SCSIID;
+ cfg_lsw |= (new_id & ADV_MAX_TID) << ADV_CFG_LSW_SCSIID_SHIFT;
+ ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
+}
+
+int
+adv_execute_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
+ u_int32_t datalen)
+{
+ struct adv_target_transinfo* tinfo;
+ u_int32_t *p_data_addr;
+ u_int32_t *p_data_bcount;
+ int disable_syn_offset_one_fix;
+ int retval;
+ u_int n_q_required;
+ u_int32_t addr;
+ u_int8_t sg_entry_cnt;
+ u_int8_t target_ix;
+ u_int8_t sg_entry_cnt_minus_one;
+ u_int8_t tid_no;
+
+ scsiq->q1.q_no = 0;
+ retval = 1; /* Default to error case */
+ target_ix = scsiq->q2.target_ix;
+ tid_no = ADV_TIX_TO_TID(target_ix);
+ tinfo = &adv->tinfo[tid_no];
+
+ if (scsiq->cdbptr[0] == REQUEST_SENSE) {
+ /* Renegotiate if appropriate. */
+ adv_set_syncrate(adv, /*struct cam_path */NULL,
+ tid_no, /*period*/0, /*offset*/0,
+ ADV_TRANS_CUR);
+ if (tinfo->current.period != tinfo->goal.period) {
+ adv_msgout_sdtr(adv, tinfo->goal.period,
+ tinfo->goal.offset);
+ scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+ }
+ }
+
+ if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+ sg_entry_cnt = scsiq->sg_head->entry_cnt;
+ sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+
+#ifdef DIAGNOSTIC
+ if (sg_entry_cnt <= 1)
+ panic("adv_execute_scsi_queue: Queue "
+ "with QC_SG_HEAD set but %d segs.", sg_entry_cnt);
+
+ if (sg_entry_cnt > ADV_MAX_SG_LIST)
+ panic("adv_execute_scsi_queue: "
+ "Queue with too many segs.");
+
+ if ((adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) != 0) {
+ int i;
+
+ for (i = 0; i < sg_entry_cnt_minus_one; i++) {
+ addr = scsiq->sg_head->sg_list[i].addr +
+ scsiq->sg_head->sg_list[i].bytes;
+
+ if ((addr & 0x0003) != 0)
+ panic("adv_execute_scsi_queue: SG "
+ "with odd address or byte count");
+ }
+ }
+#endif
+ p_data_addr =
+ &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr;
+ p_data_bcount =
+ &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
+
+ n_q_required = adv_sgcount_to_qcount(sg_entry_cnt);
+ scsiq->sg_head->queue_cnt = n_q_required - 1;
+ } else {
+ p_data_addr = &scsiq->q1.data_addr;
+ p_data_bcount = &scsiq->q1.data_cnt;
+ n_q_required = 1;
+ }
+
+ disable_syn_offset_one_fix = FALSE;
+
+ if ((adv->fix_asyn_xfer & scsiq->q1.target_id) != 0
+ && (adv->fix_asyn_xfer_always & scsiq->q1.target_id) == 0) {
+
+ if (datalen != 0) {
+ if (datalen < 512) {
+ disable_syn_offset_one_fix = TRUE;
+ } else {
+ if (scsiq->cdbptr[0] == INQUIRY
+ || scsiq->cdbptr[0] == REQUEST_SENSE
+ || scsiq->cdbptr[0] == READ_CAPACITY
+ || scsiq->cdbptr[0] == MODE_SELECT_6
+ || scsiq->cdbptr[0] == MODE_SENSE_6
+ || scsiq->cdbptr[0] == MODE_SENSE_10
+ || scsiq->cdbptr[0] == MODE_SELECT_10
+ || scsiq->cdbptr[0] == READ_TOC) {
+ disable_syn_offset_one_fix = TRUE;
+ }
+ }
+ }
+ }
+
+ if (disable_syn_offset_one_fix) {
+ scsiq->q2.tag_code &=
+ ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
+ scsiq->q2.tag_code |= (ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX
+ | ADV_TAG_FLAG_DISABLE_DISCONNECT);
+ }
+
+ if ((adv->bug_fix_control & ADV_BUG_FIX_IF_NOT_DWB) != 0
+ && (scsiq->cdbptr[0] == READ_10 || scsiq->cdbptr[0] == READ_6)) {
+ u_int8_t extra_bytes;
+
+ addr = *p_data_addr + *p_data_bcount;
+ extra_bytes = addr & 0x0003;
+ if (extra_bytes != 0
+ && ((scsiq->q1.cntl & QC_SG_HEAD) != 0
+ || (scsiq->q1.data_cnt & 0x01FF) == 0)) {
+ scsiq->q2.tag_code |= ADV_TAG_FLAG_EXTRA_BYTES;
+ scsiq->q1.extra_bytes = extra_bytes;
+ *p_data_bcount -= extra_bytes;
+ }
+ }
+
+ if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required)
+ || ((scsiq->q1.cntl & QC_URGENT) != 0))
+ retval = adv_send_scsi_queue(adv, scsiq, n_q_required);
+
+ return (retval);
+}
+
+
+u_int8_t
+adv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr,
+ struct adv_q_done_info *scsiq, u_int32_t max_dma_count)
+{
+ u_int16_t val;
+ u_int8_t sg_queue_cnt;
+
+ adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG,
+ (u_int16_t *)scsiq,
+ (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2);
+
+#if BYTE_ORDER == BIG_ENDIAN
+ adv_adj_endian_qdone_info(scsiq);
+#endif
+
+ val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS);
+ scsiq->q_status = val & 0xFF;
+ scsiq->q_no = (val >> 8) & 0XFF;
+
+ val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL);
+ scsiq->cntl = val & 0xFF;
+ sg_queue_cnt = (val >> 8) & 0xFF;
+
+ val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN);
+ scsiq->sense_len = val & 0xFF;
+ scsiq->extra_bytes = (val >> 8) & 0xFF;
+
+ /*
+ * Due to a bug in accessing LRAM on the 940UA, the residual
+ * is split into separate high and low 16bit quantities.
+ */
+ scsiq->remain_bytes =
+ adv_read_lram_16(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT);
+ scsiq->remain_bytes |=
+ adv_read_lram_16(adv, q_addr + ADV_SCSIQ_W_ALT_DC1) << 16;
+
+ /*
+ * XXX Is this just a safeguard or will the counter really
+ * have bogus upper bits?
+ */
+ scsiq->remain_bytes &= max_dma_count;
+
+ return (sg_queue_cnt);
+}
+
+int
+adv_start_chip(struct adv_softc *adv)
+{
+ ADV_OUTB(adv, ADV_CHIP_CTRL, 0);
+ if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0)
+ return (0);
+ return (1);
+}
+
+int
+adv_stop_execution(struct adv_softc *adv)
+{
+ int count;
+
+ count = 0;
+ if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) {
+ adv_write_lram_8(adv, ADV_STOP_CODE_B,
+ ADV_STOP_REQ_RISC_STOP);
+ do {
+ if (adv_read_lram_8(adv, ADV_STOP_CODE_B) &
+ ADV_STOP_ACK_RISC_STOP) {
+ return (1);
+ }
+ DELAY(1000);
+ } while (count++ < 20);
+ }
+ return (0);
+}
+
+int
+adv_is_chip_halted(struct adv_softc *adv)
+{
+ if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) {
+ if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * XXX The numeric constants and the loops in this routine
+ * need to be documented.
+ */
+void
+adv_ack_interrupt(struct adv_softc *adv)
+{
+ u_int8_t host_flag;
+ u_int8_t risc_flag;
+ int loop;
+
+ loop = 0;
+ do {
+ risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B);
+ if (loop++ > 0x7FFF) {
+ break;
+ }
+ } while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0);
+
+ host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
+ adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
+ host_flag | ADV_HOST_FLAG_ACK_INT);
+
+ ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
+ loop = 0;
+ while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) {
+ ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
+ if (loop++ > 3) {
+ break;
+ }
+ }
+
+ adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
+}
+
+/*
+ * Handle all conditions that may halt the chip waiting
+ * for us to intervene.
+ */
+void
+adv_isr_chip_halted(struct adv_softc *adv)
+{
+ u_int16_t int_halt_code;
+ u_int16_t halt_q_addr;
+ target_bit_vector target_mask;
+ target_bit_vector scsi_busy;
+ u_int8_t halt_qp;
+ u_int8_t target_ix;
+ u_int8_t q_cntl;
+ u_int8_t tid_no;
+
+ int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W);
+ halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B);
+ halt_q_addr = ADV_QNO_TO_QADDR(halt_qp);
+ target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX);
+ q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL);
+ tid_no = ADV_TIX_TO_TID(target_ix);
+ target_mask = ADV_TID_TO_TARGET_MASK(tid_no);
+ if (int_halt_code == ADV_HALT_DISABLE_ASYN_USE_SYN_FIX) {
+ /*
+ * Temporarily disable the async fix by removing
+ * this target from the list of affected targets,
+ * setting our async rate, and then putting us
+ * back into the mask.
+ */
+ adv->fix_asyn_xfer &= ~target_mask;
+ adv_set_syncrate(adv, /*struct cam_path */NULL,
+ tid_no, /*period*/0, /*offset*/0,
+ ADV_TRANS_ACTIVE);
+ adv->fix_asyn_xfer |= target_mask;
+ } else if (int_halt_code == ADV_HALT_ENABLE_ASYN_USE_SYN_FIX) {
+ adv_set_syncrate(adv, /*struct cam_path */NULL,
+ tid_no, /*period*/0, /*offset*/0,
+ ADV_TRANS_ACTIVE);
+ } else if (int_halt_code == ADV_HALT_EXTMSG_IN) {
+ adv_handle_extmsg_in(adv, halt_q_addr, q_cntl,
+ target_mask, tid_no);
+ } else if (int_halt_code == ADV_HALT_CHK_CONDITION) {
+ struct adv_target_transinfo* tinfo;
+ union ccb *ccb;
+ u_int32_t cinfo_index;
+ u_int8_t tag_code;
+ u_int8_t q_status;
+
+ tinfo = &adv->tinfo[tid_no];
+ q_cntl |= QC_REQ_SENSE;
+
+ /* Renegotiate if appropriate. */
+ adv_set_syncrate(adv, /*struct cam_path */NULL,
+ tid_no, /*period*/0, /*offset*/0,
+ ADV_TRANS_CUR);
+ if (tinfo->current.period != tinfo->goal.period) {
+ adv_msgout_sdtr(adv, tinfo->goal.period,
+ tinfo->goal.offset);
+ q_cntl |= QC_MSG_OUT;
+ }
+ adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
+
+ /* Don't tag request sense commands */
+ tag_code = adv_read_lram_8(adv,
+ halt_q_addr + ADV_SCSIQ_B_TAG_CODE);
+ tag_code &=
+ ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
+
+ if ((adv->fix_asyn_xfer & target_mask) != 0
+ && (adv->fix_asyn_xfer_always & target_mask) == 0) {
+ tag_code |= (ADV_TAG_FLAG_DISABLE_DISCONNECT
+ | ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
+ }
+ adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE,
+ tag_code);
+ q_status = adv_read_lram_8(adv,
+ halt_q_addr + ADV_SCSIQ_B_STATUS);
+ q_status |= (QS_READY | QS_BUSY);
+ adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS,
+ q_status);
+ /*
+ * Freeze the devq until we can handle the sense condition.
+ */
+ cinfo_index =
+ adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
+ ccb = adv->ccb_infos[cinfo_index].ccb;
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
+ /*ccb*/NULL, CAM_REQUEUE_REQ,
+ /*queued_only*/TRUE);
+ scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
+ scsi_busy &= ~target_mask;
+ adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
+ /*
+ * Ensure we have enough time to actually
+ * retrieve the sense.
+ */
+ untimeout(adv_timeout, (caddr_t)ccb, ccb->ccb_h.timeout_ch);
+ ccb->ccb_h.timeout_ch =
+ timeout(adv_timeout, (caddr_t)ccb, 5 * hz);
+ } else if (int_halt_code == ADV_HALT_SDTR_REJECTED) {
+ struct ext_msg out_msg;
+
+ adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG,
+ (u_int16_t *) &out_msg,
+ sizeof(out_msg)/2);
+
+ if ((out_msg.msg_type == MSG_EXTENDED)
+ && (out_msg.msg_len == MSG_EXT_SDTR_LEN)
+ && (out_msg.msg_req == MSG_EXT_SDTR)) {
+
+ /* Revert to Async */
+ adv_set_syncrate(adv, /*struct cam_path */NULL,
+ tid_no, /*period*/0, /*offset*/0,
+ ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
+ }
+ q_cntl &= ~QC_MSG_OUT;
+ adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
+ } else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) {
+ u_int8_t scsi_status;
+ union ccb *ccb;
+ u_int32_t cinfo_index;
+
+ scsi_status = adv_read_lram_8(adv, halt_q_addr
+ + ADV_SCSIQ_SCSI_STATUS);
+ cinfo_index =
+ adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
+ ccb = adv->ccb_infos[cinfo_index].ccb;
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR;
+ ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL;
+ adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
+ /*ccb*/NULL, CAM_REQUEUE_REQ,
+ /*queued_only*/TRUE);
+ scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
+ scsi_busy &= ~target_mask;
+ adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
+ } else {
+ printf("Unhandled Halt Code %x\n", int_halt_code);
+ }
+ adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
+}
+
+void
+adv_sdtr_to_period_offset(struct adv_softc *adv,
+ u_int8_t sync_data, u_int8_t *period,
+ u_int8_t *offset, int tid)
+{
+ if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)
+ && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) {
+ *period = *offset = 0;
+ } else {
+ *period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)];
+ *offset = sync_data & 0xF;
+ }
+}
+
+void
+adv_set_syncrate(struct adv_softc *adv, struct cam_path *path,
+ u_int tid, u_int period, u_int offset, u_int type)
+{
+ struct adv_target_transinfo* tinfo;
+ u_int old_period;
+ u_int old_offset;
+ u_int8_t sdtr_data;
+
+ tinfo = &adv->tinfo[tid];
+
+ /* Filter our input */
+ sdtr_data = adv_period_offset_to_sdtr(adv, &period,
+ &offset, tid);
+
+ old_period = tinfo->current.period;
+ old_offset = tinfo->current.offset;
+
+ if ((type & ADV_TRANS_CUR) != 0
+ && ((old_period != period || old_offset != offset)
+ || period == 0 || offset == 0) /*Changes in asyn fix settings*/) {
+ int s;
+ int halted;
+
+ s = splcam();
+ halted = adv_is_chip_halted(adv);
+ if (halted == 0)
+ /* Must halt the chip first */
+ adv_host_req_chip_halt(adv);
+
+ /* Update current hardware settings */
+ adv_set_sdtr_reg_at_id(adv, tid, sdtr_data);
+
+ /*
+ * If a target can run in sync mode, we don't need
+ * to check it for sync problems.
+ */
+ if (offset != 0)
+ adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid);
+
+ if (halted == 0)
+ /* Start the chip again */
+ adv_start_chip(adv);
+
+ splx(s);
+ tinfo->current.period = period;
+ tinfo->current.offset = offset;
+
+ if (path != NULL) {
+ /*
+ * Tell the SCSI layer about the
+ * new transfer parameters.
+ */
+ struct ccb_trans_settings neg;
+
+ neg.sync_period = period;
+ neg.sync_offset = offset;
+ neg.valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID;
+ xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1);
+ xpt_async(AC_TRANSFER_NEG, path, &neg);
+ }
+ }
+
+ if ((type & ADV_TRANS_GOAL) != 0) {
+ tinfo->goal.period = period;
+ tinfo->goal.offset = offset;
+ }
+
+ if ((type & ADV_TRANS_USER) != 0) {
+ tinfo->user.period = period;
+ tinfo->user.offset = offset;
+ }
+}
+
+u_int8_t
+adv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period,
+ u_int *offset, int tid)
+{
+ u_int i;
+ u_int dummy_offset;
+ u_int dummy_period;
+
+ if (offset == NULL) {
+ dummy_offset = 0;
+ offset = &dummy_offset;
+ }
+
+ if (period == NULL) {
+ dummy_period = 0;
+ period = &dummy_period;
+ }
+
+ *offset = MIN(ADV_SYN_MAX_OFFSET, *offset);
+ if (*period != 0 && *offset != 0) {
+ for (i = 0; i < adv->sdtr_period_tbl_size; i++) {
+ if (*period <= adv->sdtr_period_tbl[i]) {
+ /*
+ * When responding to a target that requests
+ * sync, the requested rate may fall between
+ * two rates that we can output, but still be
+ * a rate that we can receive. Because of this,
+ * we want to respond to the target with
+ * the same rate that it sent to us even
+ * if the period we use to send data to it
+ * is lower. Only lower the response period
+ * if we must.
+ */
+ if (i == 0 /* Our maximum rate */)
+ *period = adv->sdtr_period_tbl[0];
+ return ((i << 4) | *offset);
+ }
+ }
+ }
+
+ /* Must go async */
+ *period = 0;
+ *offset = 0;
+ if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid))
+ return (ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+ return (0);
+}
+
+/* Internal Routines */
+
+static void
+adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *buffer, int count)
+{
+ ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
+ ADV_INSW(adv, ADV_LRAM_DATA, buffer, count);
+}
+
+static void
+adv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *buffer, int count)
+{
+ ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
+ ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count);
+}
+
+static void
+adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t set_value, int count)
+{
+ ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
+ bus_space_set_multi_2(adv->tag, adv->bsh, ADV_LRAM_DATA,
+ set_value, count);
+}
+
+static u_int32_t
+adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count)
+{
+ u_int32_t sum;
+ int i;
+
+ sum = 0;
+ ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
+ for (i = 0; i < count; i++)
+ sum += ADV_INW(adv, ADV_LRAM_DATA);
+ return (sum);
+}
+
+static int
+adv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr,
+ u_int16_t value)
+{
+ int retval;
+
+ retval = 0;
+ ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
+ ADV_OUTW(adv, ADV_LRAM_DATA, value);
+ DELAY(10000);
+ ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
+ if (value != ADV_INW(adv, ADV_LRAM_DATA))
+ retval = 1;
+ return (retval);
+}
+
+static u_int32_t
+adv_read_lram_32(struct adv_softc *adv, u_int16_t addr)
+{
+ u_int16_t val_low, val_high;
+
+ ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
+
+#if BYTE_ORDER == BIG_ENDIAN
+ val_high = ADV_INW(adv, ADV_LRAM_DATA);
+ val_low = ADV_INW(adv, ADV_LRAM_DATA);
+#else
+ val_low = ADV_INW(adv, ADV_LRAM_DATA);
+ val_high = ADV_INW(adv, ADV_LRAM_DATA);
+#endif
+
+ return (((u_int32_t)val_high << 16) | (u_int32_t)val_low);
+}
+
+static void
+adv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value)
+{
+ ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
+
+#if BYTE_ORDER == BIG_ENDIAN
+ ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
+ ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
+#else
+ ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
+ ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
+#endif
+}
+
+static void
+adv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr,
+ u_int32_t *buffer, int count)
+{
+ ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
+ ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2);
+}
+
+static u_int16_t
+adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr)
+{
+ u_int16_t read_wval;
+ u_int8_t cmd_reg;
+
+ adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
+ DELAY(1000);
+ cmd_reg = addr | ADV_EEPROM_CMD_READ;
+ adv_write_eeprom_cmd_reg(adv, cmd_reg);
+ DELAY(1000);
+ read_wval = ADV_INW(adv, ADV_EEPROM_DATA);
+ DELAY(1000);
+ return (read_wval);
+}
+
+static u_int16_t
+adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value)
+{
+ u_int16_t read_value;
+
+ read_value = adv_read_eeprom_16(adv, addr);
+ if (read_value != value) {
+ adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE);
+ DELAY(1000);
+
+ ADV_OUTW(adv, ADV_EEPROM_DATA, value);
+ DELAY(1000);
+
+ adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr);
+ DELAY(20 * 1000);
+
+ adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
+ DELAY(1000);
+ read_value = adv_read_eeprom_16(adv, addr);
+ }
+ return (read_value);
+}
+
+static int
+adv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg)
+{
+ u_int8_t read_back;
+ int retry;
+
+ retry = 0;
+ while (1) {
+ ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg);
+ DELAY(1000);
+ read_back = ADV_INB(adv, ADV_EEPROM_CMD);
+ if (read_back == cmd_reg) {
+ return (1);
+ }
+ if (retry++ > ADV_EEPROM_MAX_RETRY) {
+ return (0);
+ }
+ }
+}
+
+static int
+adv_set_eeprom_config_once(struct adv_softc *adv,
+ struct adv_eeprom_config *eeprom_config)
+{
+ int n_error;
+ u_int16_t *wbuf;
+ u_int16_t sum;
+ u_int8_t s_addr;
+ u_int8_t cfg_beg;
+ u_int8_t cfg_end;
+
+ wbuf = (u_int16_t *)eeprom_config;
+ n_error = 0;
+ sum = 0;
+ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+ sum += *wbuf;
+ if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
+ n_error++;
+ }
+ }
+ if (adv->type & ADV_VL) {
+ cfg_beg = ADV_EEPROM_CFG_BEG_VL;
+ cfg_end = ADV_EEPROM_MAX_ADDR_VL;
+ } else {
+ cfg_beg = ADV_EEPROM_CFG_BEG;
+ cfg_end = ADV_EEPROM_MAX_ADDR;
+ }
+
+ for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+ sum += *wbuf;
+ if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
+ n_error++;
+ }
+ }
+ *wbuf = sum;
+ if (sum != adv_write_eeprom_16(adv, s_addr, sum)) {
+ n_error++;
+ }
+ wbuf = (u_int16_t *)eeprom_config;
+ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+ if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
+ n_error++;
+ }
+ }
+ for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) {
+ if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
+ n_error++;
+ }
+ }
+ return (n_error);
+}
+
+static u_int32_t
+adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *mcode_buf, u_int16_t mcode_size)
+{
+ u_int32_t chksum;
+ u_int16_t mcode_lram_size;
+ u_int16_t mcode_chksum;
+
+ mcode_lram_size = mcode_size >> 1;
+ /* XXX Why zero the memory just before you write the whole thing?? */
+ adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size);
+ adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size);
+
+ chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size);
+ mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG,
+ ((mcode_size - s_addr
+ - ADV_CODE_SEC_BEG) >> 1));
+ adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum);
+ adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size);
+ return (chksum);
+}
+
+static void
+adv_reinit_lram(struct adv_softc *adv) {
+ adv_init_lram(adv);
+ adv_init_qlink_var(adv);
+}
+
+static void
+adv_init_lram(struct adv_softc *adv)
+{
+ u_int8_t i;
+ u_int16_t s_addr;
+
+ adv_mset_lram_16(adv, ADV_QADR_BEG, 0,
+ (((adv->max_openings + 2 + 1) * 64) >> 1));
+
+ i = ADV_MIN_ACTIVE_QNO;
+ s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE;
+
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1);
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings);
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
+ i++;
+ s_addr += ADV_QBLK_SIZE;
+ for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) {
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1);
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1);
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
+ }
+
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END);
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1);
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings);
+ i++;
+ s_addr += ADV_QBLK_SIZE;
+
+ for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) {
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i);
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i);
+ adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
+ }
+}
+
+static int
+adv_init_microcode_var(struct adv_softc *adv)
+{
+ int i;
+
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+
+ /* Start out async all around */
+ adv_set_syncrate(adv, /*path*/NULL,
+ i, 0, 0,
+ ADV_TRANS_GOAL|ADV_TRANS_CUR);
+ }
+
+ adv_init_qlink_var(adv);
+
+ adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
+ adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id);
+
+ adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase);
+
+ adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE);
+
+ ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
+ if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
+ printf("adv%d: Unable to set program counter. Aborting.\n",
+ adv->unit);
+ return (1);
+ }
+ return (0);
+}
+
+static void
+adv_init_qlink_var(struct adv_softc *adv)
+{
+ int i;
+ u_int16_t lram_addr;
+
+ adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1);
+ adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings);
+
+ adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1);
+ adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings);
+
+ adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B,
+ (u_int8_t)((int) adv->max_openings + 1));
+ adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B,
+ (u_int8_t)((int) adv->max_openings + 2));
+
+ adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings);
+
+ adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0);
+ adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
+ adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0);
+ adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0);
+ adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0);
+ adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0);
+
+ lram_addr = ADV_QADR_BEG;
+ for (i = 0; i < 32; i++, lram_addr += 2)
+ adv_write_lram_16(adv, lram_addr, 0);
+}
+
+static void
+adv_disable_interrupt(struct adv_softc *adv)
+{
+ u_int16_t cfg;
+
+ cfg = ADV_INW(adv, ADV_CONFIG_LSW);
+ ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON);
+}
+
+static void
+adv_enable_interrupt(struct adv_softc *adv)
+{
+ u_int16_t cfg;
+
+ cfg = ADV_INW(adv, ADV_CONFIG_LSW);
+ ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON);
+}
+
+static void
+adv_toggle_irq_act(struct adv_softc *adv)
+{
+ ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT);
+ ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
+}
+
+void
+adv_start_execution(struct adv_softc *adv)
+{
+ if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) {
+ adv_write_lram_8(adv, ADV_STOP_CODE_B, 0);
+ }
+}
+
+int
+adv_stop_chip(struct adv_softc *adv)
+{
+ u_int8_t cc_val;
+
+ cc_val = ADV_INB(adv, ADV_CHIP_CTRL)
+ & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG));
+ ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT);
+ adv_set_chip_ih(adv, ADV_INS_HALT);
+ adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
+ if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) {
+ return (0);
+ }
+ return (1);
+}
+
+static int
+adv_host_req_chip_halt(struct adv_softc *adv)
+{
+ int count;
+ u_int8_t saved_stop_code;
+
+ if (adv_is_chip_halted(adv))
+ return (1);
+
+ count = 0;
+ saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B);
+ adv_write_lram_8(adv, ADVV_STOP_CODE_B,
+ ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP);
+ while (adv_is_chip_halted(adv) == 0
+ && count++ < 2000)
+ ;
+
+ adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code);
+ return (count < 2000);
+}
+
+static void
+adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code)
+{
+ adv_set_bank(adv, 1);
+ ADV_OUTW(adv, ADV_REG_IH, ins_code);
+ adv_set_bank(adv, 0);
+}
+
+#if UNUSED
+static u_int8_t
+adv_get_chip_scsi_ctrl(struct adv_softc *adv)
+{
+ u_int8_t scsi_ctrl;
+
+ adv_set_bank(adv, 1);
+ scsi_ctrl = ADV_INB(adv, ADV_REG_SC);
+ adv_set_bank(adv, 0);
+ return (scsi_ctrl);
+}
+#endif
+
+/*
+ * XXX Looks like more padding issues in this routine as well.
+ * There has to be a way to turn this into an insw.
+ */
+static void
+adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *inbuf, int words)
+{
+ int i;
+
+ ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
+ for (i = 0; i < words; i++, inbuf++) {
+ if (i == 5) {
+ continue;
+ }
+ *inbuf = ADV_INW(adv, ADV_LRAM_DATA);
+ }
+}
+
+static u_int
+adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs)
+{
+ u_int cur_used_qs;
+ u_int cur_free_qs;
+
+ cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q;
+
+ if ((cur_used_qs + n_qs) <= adv->max_openings) {
+ cur_free_qs = adv->max_openings - cur_used_qs;
+ return (cur_free_qs);
+ }
+ adv->openings_needed = n_qs;
+ return (0);
+}
+
+static u_int8_t
+adv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head,
+ u_int8_t n_free_q)
+{
+ int i;
+
+ for (i = 0; i < n_free_q; i++) {
+ free_q_head = adv_alloc_free_queue(adv, free_q_head);
+ if (free_q_head == ADV_QLINK_END)
+ break;
+ }
+ return (free_q_head);
+}
+
+static u_int8_t
+adv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head)
+{
+ u_int16_t q_addr;
+ u_int8_t next_qp;
+ u_int8_t q_status;
+
+ next_qp = ADV_QLINK_END;
+ q_addr = ADV_QNO_TO_QADDR(free_q_head);
+ q_status = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS);
+
+ if ((q_status & QS_READY) == 0)
+ next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
+
+ return (next_qp);
+}
+
+static int
+adv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
+ u_int8_t n_q_required)
+{
+ u_int8_t free_q_head;
+ u_int8_t next_qp;
+ u_int8_t tid_no;
+ u_int8_t target_ix;
+ int retval;
+
+ retval = 1;
+ target_ix = scsiq->q2.target_ix;
+ tid_no = ADV_TIX_TO_TID(target_ix);
+ free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF;
+ if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required))
+ != ADV_QLINK_END) {
+ scsiq->q1.q_no = free_q_head;
+
+ /*
+ * Now that we know our Q number, point our sense
+ * buffer pointer to a bus dma mapped area where
+ * we can dma the data to.
+ */
+ scsiq->q1.sense_addr = adv->sense_physbase
+ + ((free_q_head - 1) * sizeof(struct scsi_sense_data));
+ adv_put_ready_sg_list_queue(adv, scsiq, free_q_head);
+ adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp);
+ adv->cur_active += n_q_required;
+ retval = 0;
+ }
+ return (retval);
+}
+
+
+static void
+adv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
+ u_int q_no)
+{
+ u_int8_t sg_list_dwords;
+ u_int8_t sg_index, i;
+ u_int8_t sg_entry_cnt;
+ u_int8_t next_qp;
+ u_int16_t q_addr;
+ struct adv_sg_head *sg_head;
+ struct adv_sg_list_q scsi_sg_q;
+
+ sg_head = scsiq->sg_head;
+
+ if (sg_head) {
+ sg_entry_cnt = sg_head->entry_cnt - 1;
+#ifdef DIAGNOSTIC
+ if (sg_entry_cnt == 0)
+ panic("adv_put_ready_sg_list_queue: ScsiQ with "
+ "a SG list but only one element");
+ if ((scsiq->q1.cntl & QC_SG_HEAD) == 0)
+ panic("adv_put_ready_sg_list_queue: ScsiQ with "
+ "a SG list but QC_SG_HEAD not set");
+#endif
+ q_addr = ADV_QNO_TO_QADDR(q_no);
+ sg_index = 1;
+ scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
+ scsi_sg_q.sg_head_qp = q_no;
+ scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+ for (i = 0; i < sg_head->queue_cnt; i++) {
+ u_int8_t segs_this_q;
+
+ if (sg_entry_cnt > ADV_SG_LIST_PER_Q)
+ segs_this_q = ADV_SG_LIST_PER_Q;
+ else {
+ /* This will be the last segment then */
+ segs_this_q = sg_entry_cnt;
+ scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+ }
+ scsi_sg_q.seq_no = i + 1;
+ sg_list_dwords = segs_this_q << 1;
+ if (i == 0) {
+ scsi_sg_q.sg_list_cnt = segs_this_q;
+ scsi_sg_q.sg_cur_list_cnt = segs_this_q;
+ } else {
+ scsi_sg_q.sg_list_cnt = segs_this_q - 1;
+ scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1;
+ }
+ next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
+ scsi_sg_q.q_no = next_qp;
+ q_addr = ADV_QNO_TO_QADDR(next_qp);
+
+ adv_write_lram_16_multi(adv,
+ q_addr + ADV_SCSIQ_SGHD_CPY_BEG,
+ (u_int16_t *)&scsi_sg_q,
+ sizeof(scsi_sg_q) >> 1);
+ adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG,
+ (u_int32_t *)&sg_head->sg_list[sg_index],
+ sg_list_dwords);
+ sg_entry_cnt -= segs_this_q;
+ sg_index += ADV_SG_LIST_PER_Q;
+ }
+ }
+ adv_put_ready_queue(adv, scsiq, q_no);
+}
+
+static void
+adv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
+ u_int q_no)
+{
+ struct adv_target_transinfo* tinfo;
+ u_int q_addr;
+ u_int tid_no;
+
+ tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix);
+ tinfo = &adv->tinfo[tid_no];
+ if ((tinfo->current.period != tinfo->goal.period)
+ || (tinfo->current.offset != tinfo->goal.offset)) {
+
+ adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset);
+ scsiq->q1.cntl |= QC_MSG_OUT;
+ }
+ q_addr = ADV_QNO_TO_QADDR(q_no);
+
+ scsiq->q1.status = QS_FREE;
+
+ adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG,
+ (u_int16_t *)scsiq->cdbptr,
+ scsiq->q2.cdb_len >> 1);
+
+#if BYTE_ORDER == BIG_ENDIAN
+ adv_adj_scsiq_endian(scsiq);
+#endif
+
+ adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG,
+ (u_int16_t *) &scsiq->q1.cntl,
+ ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1);
+
+#if CC_WRITE_IO_COUNT
+ adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT,
+ adv->req_count);
+#endif
+
+#if CC_CLEAR_DMA_REMAIN
+
+ adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0);
+ adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0);
+#endif
+
+ adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS,
+ (scsiq->q1.q_no << 8) | QS_READY);
+}
+
+static void
+adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
+ u_int16_t *buffer, int words)
+{
+ int i;
+
+ /*
+ * XXX This routine makes *gross* assumptions
+ * about padding in the data structures.
+ * Either the data structures should have explicit
+ * padding members added, or they should have padding
+ * turned off via compiler attributes depending on
+ * which yields better overall performance. My hunch
+ * would be that turning off padding would be the
+ * faster approach as an outsw is much faster than
+ * this crude loop and accessing un-aligned data
+ * members isn't *that* expensive. The other choice
+ * would be to modify the ASC script so that the
+ * the adv_scsiq_1 structure can be re-arranged so
+ * padding isn't required.
+ */
+ ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
+ for (i = 0; i < words; i++, buffer++) {
+ if (i == 2 || i == 10) {
+ continue;
+ }
+ ADV_OUTW(adv, ADV_LRAM_DATA, *buffer);
+ }
+}
+
+#if BYTE_ORDER == BIG_ENDIAN
+void
+adv_adj_endian_qdone_info(struct adv_q_done_info *scsiq)
+{
+
+ panic("adv(4) not supported on big-endian machines.\n");
+}
+
+void
+adv_adj_scsiq_endian(struct adv_scsi_q *scsiq)
+{
+
+ panic("adv(4) not supported on big-endian machines.\n");
+}
+#endif
+
+static void
+adv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr,
+ u_int8_t q_cntl, target_bit_vector target_mask,
+ int tid_no)
+{
+ struct ext_msg ext_msg;
+
+ adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg,
+ sizeof(ext_msg) >> 1);
+ if ((ext_msg.msg_type == MSG_EXTENDED)
+ && (ext_msg.msg_req == MSG_EXT_SDTR)
+ && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) {
+ union ccb *ccb;
+ struct adv_target_transinfo* tinfo;
+ u_int32_t cinfo_index;
+ u_int period;
+ u_int offset;
+ int sdtr_accept;
+ u_int8_t orig_offset;
+
+ cinfo_index =
+ adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
+ ccb = adv->ccb_infos[cinfo_index].ccb;
+ tinfo = &adv->tinfo[tid_no];
+ sdtr_accept = TRUE;
+
+ orig_offset = ext_msg.req_ack_offset;
+ if (ext_msg.xfer_period < tinfo->goal.period) {
+ sdtr_accept = FALSE;
+ ext_msg.xfer_period = tinfo->goal.period;
+ }
+
+ /* Perform range checking */
+ period = ext_msg.xfer_period;
+ offset = ext_msg.req_ack_offset;
+ adv_period_offset_to_sdtr(adv, &period, &offset, tid_no);
+ ext_msg.xfer_period = period;
+ ext_msg.req_ack_offset = offset;
+
+ /* Record our current sync settings */
+ adv_set_syncrate(adv, ccb->ccb_h.path,
+ tid_no, ext_msg.xfer_period,
+ ext_msg.req_ack_offset,
+ ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
+
+ /* Offset too high or large period forced async */
+ if (orig_offset != ext_msg.req_ack_offset)
+ sdtr_accept = FALSE;
+
+ if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
+ /* Valid response to our requested negotiation */
+ q_cntl &= ~QC_MSG_OUT;
+ } else {
+ /* Must Respond */
+ q_cntl |= QC_MSG_OUT;
+ adv_msgout_sdtr(adv, ext_msg.xfer_period,
+ ext_msg.req_ack_offset);
+ }
+
+ } else if (ext_msg.msg_type == MSG_EXTENDED
+ && ext_msg.msg_req == MSG_EXT_WDTR
+ && ext_msg.msg_len == MSG_EXT_WDTR_LEN) {
+
+ ext_msg.wdtr_width = 0;
+ adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
+ (u_int16_t *)&ext_msg,
+ sizeof(ext_msg) >> 1);
+ q_cntl |= QC_MSG_OUT;
+ } else {
+
+ ext_msg.msg_type = MSG_MESSAGE_REJECT;
+ adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
+ (u_int16_t *)&ext_msg,
+ sizeof(ext_msg) >> 1);
+ q_cntl |= QC_MSG_OUT;
+ }
+ adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
+}
+
+static void
+adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
+ u_int8_t sdtr_offset)
+{
+ struct ext_msg sdtr_buf;
+
+ sdtr_buf.msg_type = MSG_EXTENDED;
+ sdtr_buf.msg_len = MSG_EXT_SDTR_LEN;
+ sdtr_buf.msg_req = MSG_EXT_SDTR;
+ sdtr_buf.xfer_period = sdtr_period;
+ sdtr_offset &= ADV_SYN_MAX_OFFSET;
+ sdtr_buf.req_ack_offset = sdtr_offset;
+ adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
+ (u_int16_t *) &sdtr_buf,
+ sizeof(sdtr_buf) / 2);
+}
+
+int
+adv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb,
+ u_int32_t status, int queued_only)
+{
+ u_int16_t q_addr;
+ u_int8_t q_no;
+ struct adv_q_done_info scsiq_buf;
+ struct adv_q_done_info *scsiq;
+ u_int8_t target_ix;
+ int count;
+
+ scsiq = &scsiq_buf;
+ target_ix = ADV_TIDLUN_TO_IX(target, lun);
+ count = 0;
+ for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) {
+ struct adv_ccb_info *ccb_info;
+ q_addr = ADV_QNO_TO_QADDR(q_no);
+
+ adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count);
+ ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index];
+ if (((scsiq->q_status & QS_READY) != 0)
+ && ((scsiq->q_status & QS_ABORTED) == 0)
+ && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)
+ && (scsiq->d2.target_ix == target_ix)
+ && (queued_only == 0
+ || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE)))
+ && (ccb == NULL || (ccb == ccb_info->ccb))) {
+ union ccb *aborted_ccb;
+ struct adv_ccb_info *cinfo;
+
+ scsiq->q_status |= QS_ABORTED;
+ adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS,
+ scsiq->q_status);
+ aborted_ccb = ccb_info->ccb;
+ /* Don't clobber earlier error codes */
+ if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK)
+ == CAM_REQ_INPROG)
+ aborted_ccb->ccb_h.status |= status;
+ cinfo = (struct adv_ccb_info *)
+ aborted_ccb->ccb_h.ccb_cinfo_ptr;
+ cinfo->state |= ACCB_ABORT_QUEUED;
+ count++;
+ }
+ }
+ return (count);
+}
+
+int
+adv_reset_bus(struct adv_softc *adv, int initiate_bus_reset)
+{
+ int count;
+ int i;
+ union ccb *ccb;
+
+ i = 200;
+ while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0
+ && i--)
+ DELAY(1000);
+ adv_reset_chip(adv, initiate_bus_reset);
+ adv_reinit_lram(adv);
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ adv_set_syncrate(adv, NULL, i, /*period*/0,
+ /*offset*/0, ADV_TRANS_CUR);
+ ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
+
+ /* Tell the XPT layer that a bus reset occured */
+ if (adv->path != NULL)
+ xpt_async(AC_BUS_RESET, adv->path, NULL);
+
+ count = 0;
+ while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) {
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
+ ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
+ adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0);
+ count++;
+ }
+
+ adv_start_chip(adv);
+ return (count);
+}
+
+static void
+adv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data)
+{
+ int orig_id;
+
+ adv_set_bank(adv, 1);
+ orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1;
+ ADV_OUTB(adv, ADV_HOST_SCSIID, tid);
+ if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) {
+ adv_set_bank(adv, 0);
+ ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data);
+ }
+ adv_set_bank(adv, 1);
+ ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id);
+ adv_set_bank(adv, 0);
+}
diff --git a/sys/dev/advansys/advlib.h b/sys/dev/advansys/advlib.h
new file mode 100644
index 0000000..ba9703d
--- /dev/null
+++ b/sys/dev/advansys/advlib.h
@@ -0,0 +1,876 @@
+/*
+ * Definitions for low level routines and data structures
+ * for the Advanced Systems Inc. SCSI controllers chips.
+ *
+ * Copyright (c) 1996-1997, 1999-2000 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * 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 _ADVLIB_H_
+#define _ADVLIB_H_
+
+#include <sys/queue.h>
+
+struct cam_path;
+union ccb;
+
+typedef u_int8_t target_bit_vector;
+#define TARGET_BIT_VECTOR_SET -1
+#define ADV_SCSI_ID_BITS 3
+#define ADV_MAX_TID 7
+#define ADV_MAX_LUN 7
+
+/* Enumeration of board types */
+typedef enum {
+ ADV_NONE = 0x000,
+ ADV_ISA = 0x001,
+ ADV_ISAPNP = 0x003,
+ ADV_VL = 0x004,
+ ADV_EISA = 0x008,
+ ADV_PCI = 0x010,
+ ADV_MCA = 0x020,
+ ADV_PCMCIA = 0x040,
+ ADV_ULTRA = 0x100,
+ ADV_WIDE = 0x200,
+ ADV_WIDE32 = 0x400
+} adv_btype;
+
+typedef enum {
+ ADV_STATE_NONE = 0x00,
+ ADV_RESOURCE_SHORTAGE = 0x01,
+ ADV_IN_TIMEOUT = 0x02,
+ ADV_BUSDMA_BLOCK = 0x04,
+ ADV_BUSDMA_BLOCK_CLEARED = 0x08
+
+} adv_state;
+
+typedef enum {
+ ACCB_FREE = 0x00,
+ ACCB_ACTIVE = 0x01,
+ ACCB_ABORT_QUEUED = 0x02,
+ ACCB_RECOVERY_CCB = 0x04
+} adv_ccb_state;
+
+struct adv_ccb_info {
+ adv_ccb_state state;
+ bus_dmamap_t dmamap;
+ union ccb* ccb;
+ SLIST_ENTRY(adv_ccb_info) links;
+};
+
+#define ccb_cinfo_ptr spriv_ptr0
+
+#define ADV_SYN_XFER_NO 8
+#define ADV_SYN_MAX_OFFSET 0x0F
+#define ADV_DEF_SDTR_OFFSET 0x0F
+#define ADV_DEF_SDTR_INDEX 0x00
+#define ADV_OVERRUN_BSIZE 0x00000040
+#define ADV_MAX_CDB_LEN 12
+#define ADV_MAX_SENSE_LEN 32
+#define ADV_MIN_SENSE_LEN 14
+
+#define ADV_TIDLUN_TO_IX(tid, lun) ((tid) | ((lun) << ADV_SCSI_ID_BITS) )
+#define ADV_TID_TO_TARGET_MASK(tid) (0x01 << (tid))
+#define ADV_TIX_TO_TARGET_MASK(tix) (0x01 << ((tix) & ADV_MAX_TID))
+#define ADV_TIX_TO_TID(tix) ((tix) & ADV_MAX_TID)
+#define ADV_TID_TO_TIX(tid) ((tid) & ADV_MAX_TID)
+#define ADV_TIX_TO_LUN(tix) (((tix) >> ADV_SCSI_ID_BITS) & ADV_MAX_LUN )
+
+
+/*
+ * XXX
+ * PnP port addresses
+ * I believe that these are standard PnP address and should be replaced
+ * by the values in a central ISA PnP header file when we get one.
+ */
+#define ADV_ISA_PNP_PORT_ADDR (0x279)
+#define ADV_ISA_PNP_PORT_WRITE (ADV_ISA_PNP_PORT_ADDR+0x800)
+
+/*
+ * Board Signatures
+ */
+#define ADV_SIGNATURE_WORD 0x0000
+#define ADV_1000_ID0W 0x04C1
+#define ADV_1000_ID0W_FIX 0x00C1
+
+#define ADV_SIGNATURE_BYTE 0x0001
+#define ADV_1000_ID1B 0x25
+
+#define ADV_REG_IH 0x0002
+#define ADV_INS_HALTINT 0x6281
+#define ADV_INS_HALT 0x6280
+#define ADV_INS_SINT 0x6200
+#define ADV_INS_RFLAG_WTM 0x7380
+
+#define ADV_CONFIG_LSW 0x0002
+#define ADV_CFG_LSW_ISA_DMA_CHANNEL 0x0003
+#define ADV_CFG_LSW_HOST_INT_ON 0x0020
+#define ADV_CFG_LSW_BIOS_ON 0x0040
+#define ADV_CFG_LSW_VERA_BURST_ON 0x0080
+#define ADV_CFG_LSW_SCSI_PARITY_ON 0x0800
+#define ADV_CFG_LSW_SCSIID 0x0700
+#define ADV_CFG_LSW_SCSIID_SHIFT 8
+#define ADV_CONFIG_SCSIID(cfg) ((cfg >> ADV_CFG_LSW_SCSIID_SHIFT) & ADV_MAX_TID)
+
+/*
+ * Chip Revision Number
+ */
+#define ADV_NONEISA_CHIP_REVISION 0x0003
+#define ADV_CHIP_MIN_VER_VL 0x01
+#define ADV_CHIP_MAX_VER_VL 0x07
+#define ADV_CHIP_MIN_VER_PCI 0x09
+#define ADV_CHIP_MAX_VER_PCI 0x0F
+#define ADV_CHIP_VER_PCI_BIT 0x08
+#define ADV_CHIP_VER_PCI_ULTRA_3150 (ADV_CHIP_VER_PCI_BIT | 0x02)
+#define ADV_CHIP_VER_PCI_ULTRA_3050 (ADV_CHIP_VER_PCI_BIT | 0x03)
+#define ADV_CHIP_MIN_VER_ISA 0x11
+#define ADV_CHIP_MIN_VER_ISA_PNP 0x21
+#define ADV_CHIP_MAX_VER_ISA 0x27
+#define ADV_CHIP_VER_ISA_BIT 0x30
+#define ADV_CHIP_VER_ISAPNP_BIT 0x20
+#define ADV_CHIP_VER_ASYN_BUG 0x21
+#define ADV_CHIP_MIN_VER_EISA 0x41
+#define ADV_CHIP_MAX_VER_EISA 0x47
+#define ADV_CHIP_VER_EISA_BIT 0x40
+
+#define ADV_CONFIG_MSW 0x0004
+#define ADV_CFG_MSW_SCSI_TARGET_ON 0x0080
+#define ADV_CFG_MSW_LRAM_8BITS_ON 0x0800
+#define ADV_CFG_MSW_CLR_MASK 0x30C0
+
+#define ADV_EEPROM_DATA 0x0006
+
+#define ADV_EEPROM_CMD 0x0007
+#define ADV_EEPROM_CMD_READ 0x80
+#define ADV_EEPROM_CMD_WRITE 0x40
+#define ADV_EEPROM_CMD_WRITE_ENABLE 0x30
+#define ADV_EEPROM_CMD_WRITE_DISABLE 0x00
+
+#define ADV_DMA_SPEED 0x0007
+#define ADV_DEF_ISA_DMA_SPEED 4
+#define ADV_REG_FLAG 0x0007
+
+#define ADV_LRAM_DATA 0x0008
+
+#define ADV_LRAM_ADDR 0x000A
+
+#define ADV_SYN_OFFSET 0x000B
+
+#define ADV_REG_PROG_COUNTER 0x000C
+#define ADV_MCODE_START_ADDR 0x0080
+
+#define ADV_REG_IFC 0x000D
+#define ADV_IFC_REG_LOCK 0x00
+#define ADV_IFC_REG_UNLOCK 0x09
+#define ADV_IFC_WR_EN_FILTER 0x10
+#define ADV_IFC_RD_NO_EEPROM 0x10
+#define ADV_IFC_SLEW_RATE 0x20
+#define ADV_IFC_ACT_NEG 0x40
+#define ADV_IFC_INP_FILTER 0x80
+#define ADV_IFC_INIT_DEFAULT (ADV_IFC_ACT_NEG | ADV_IFC_REG_UNLOCK)
+
+#define ADV_CHIP_STATUS 0x000E
+#define ADV_CSW_TEST1 0x8000
+#define ADV_CSW_AUTO_CONFIG 0x4000
+#define ADV_CSW_RESERVED1 0x2000
+#define ADV_CSW_IRQ_WRITTEN 0x1000
+#define ADV_CSW_33MHZ_SELECTED 0x0800
+#define ADV_CSW_TEST2 0x0400
+#define ADV_CSW_TEST3 0x0200
+#define ADV_CSW_RESERVED2 0x0100
+#define ADV_CSW_DMA_DONE 0x0080
+#define ADV_CSW_FIFO_RDY 0x0040
+#define ADV_CSW_EEP_READ_DONE 0x0020
+#define ADV_CSW_HALTED 0x0010
+#define ADV_CSW_SCSI_RESET_ACTIVE 0x0008
+#define ADV_CSW_PARITY_ERR 0x0004
+#define ADV_CSW_SCSI_RESET_LATCH 0x0002
+#define ADV_CSW_INT_PENDING 0x0001
+/*
+ * XXX I don't understand the relevence of the naming
+ * convention change here. What does CIW stand for?
+ * Perhaps this is to differentiate read and write
+ * values?
+ */
+#define ADV_CIW_INT_ACK 0x0100
+#define ADV_CIW_TEST1 0x0200
+#define ADV_CIW_TEST2 0x0400
+#define ADV_CIW_SEL_33MHZ 0x0800
+#define ADV_CIW_IRQ_ACT 0x1000
+#define ADV_CIW_CLR_SCSI_RESET_INT 0x1000
+
+#define ADV_CHIP_CTRL 0x000F
+#define ADV_CC_CHIP_RESET 0x80
+#define ADV_CC_SCSI_RESET 0x40
+#define ADV_CC_HALT 0x20
+#define ADV_CC_SINGLE_STEP 0x10
+#define ADV_CC_DMA_ENABLE 0x08
+#define ADV_CC_TEST 0x04
+#define ADV_CC_BANK_ONE 0x02
+#define ADV_CC_DIAG 0x01
+
+#define ADV_HALTCODE_W 0x0040
+#define ADV_STOP_CODE_B 0x0034
+#define ADV_STOP_REQ_RISC_STOP 0x01
+#define ADV_STOP_ACK_RISC_STOP 0x03
+#define ADV_STOP_CLEAN_UP_BUSY_Q 0x10
+#define ADV_STOP_CLEAN_UP_DISC_Q 0x20
+#define ADV_STOP_HOST_REQ_RISC_HALT 0x40
+
+/*
+ * EEPROM routine constants
+ * XXX What about wide controllers?
+ * Surely they have space for 8 more targets.
+ */
+#define ADV_EEPROM_CFG_BEG_VL 2
+#define ADV_EEPROM_MAX_ADDR_VL 15
+#define ADV_EEPROM_CFG_BEG 32
+#define ADV_EEPROM_MAX_ADDR 45
+#define ADV_EEPROM_MAX_RETRY 20
+
+struct adv_eeprom_config {
+ u_int16_t cfg_lsw;
+
+ u_int16_t cfg_msw;
+
+ u_int8_t init_sdtr;
+ u_int8_t disc_enable;
+
+ u_int8_t use_cmd_qng;
+ u_int8_t start_motor;
+
+ u_int8_t max_total_qng;
+ u_int8_t max_tag_qng;
+
+ u_int8_t bios_scan;
+ u_int8_t power_up_wait;
+
+ u_int8_t no_scam;
+ u_int8_t scsi_id_dma_speed;
+#define EEPROM_SCSI_ID_MASK 0x0F
+#define EEPROM_DMA_SPEED_MASK 0xF0
+#define EEPROM_DMA_SPEED(ep) \
+ (((ep).scsi_id_dma_speed & EEPROM_DMA_SPEED_MASK) >> 4)
+#define EEPROM_SET_DMA_SPEED(ep, speed) \
+ (ep).scsi_id_dma_speed &= ~EEPROM_DMA_SPEED_MASK; \
+ (ep).scsi_id_dma_speed |= \
+ (((speed) << 4) & EEPROM_DMA_SPEED_MASK)
+#define EEPROM_SCSIID(ep) ((ep).scsi_id_dma_speed & EEPROM_SCSI_ID_MASK)
+#define EEPROM_SET_SCSIID(ep, id) \
+ (ep).scsi_id_dma_speed &= ~EEPROM_SCSI_ID_MASK; \
+ (ep).scsi_id_dma_speed |= ((id) & EEPROM_SCSI_ID_MASK)
+ u_int8_t sdtr_data[8];
+ u_int8_t adapter_info[6];
+
+ u_int16_t cntl;
+
+ u_int16_t chksum;
+};
+
+/* Bank 1 */
+#define ADV_SEQ_ACCUM 0x0000
+#define ADV_QUEUE_ELEMENT_INDEX 0x0001
+#define ADV_SEQ_INSTRUCTION_HOLD 0x0002
+#define ADV_QUEUE_ELEMENT_POINTER 0x0003
+#define ADV_HOST_DATA_FIFO_L 0x0004
+#define ADV_HOST_SCSIID 0x0005
+#define ADV_HOST_DATA_FIFO_H 0x0006
+#define ADV_SCSI_CONTROL 0x0009
+#define SC_SEL 0x80
+#define SC_BSY 0x40
+#define SC_ACK 0x20
+#define SC_REQ 0x10
+#define SC_ATN 0x08
+#define SC_IO 0x04
+#define SC_CD 0x02
+#define SC_MSG 0x01
+#define ADV_SCSIDATL 0x000B
+#define ADV_DMA_TRANSFER_CNT 0x000C
+#define ADV_DMA_TRANSFER_CNT1 0x000E
+
+/*
+ * Instruction data and code segment addresses,
+ * and transaction address translation (queues).
+ * All addresses refer to on board LRAM.
+ */
+#define ADV_DATA_SEC_BEG 0x0080
+#define ADV_DATA_SEC_END 0x0080
+#define ADV_CODE_SEC_BEG 0x0080
+#define ADV_CODE_SEC_END 0x0080
+#define ADV_QADR_BEG 0x4000
+#define ADV_QADR_END 0x7FFF
+#define ADV_QLAST_ADR 0x7FC0
+#define ADV_QBLK_SIZE 0x40
+#define ADV_BIOS_DATA_QBEG 0xF8
+#define ADV_MAX_QNO 0xF8
+#define ADV_QADR_USED (ADV_MAX_QNO * 64)
+#define ADV_QNO_TO_QADDR(q_no) ((ADV_QADR_BEG) + ((u_int16_t)(q_no) << 6))
+
+#define ADV_MIN_ACTIVE_QNO 0x01
+#define ADV_QLINK_END 0xFF
+
+#define ADV_MAX_SG_QUEUE 5
+#define ADV_SG_LIST_PER_Q 7
+#define ADV_MAX_SG_LIST (1 + ((ADV_SG_LIST_PER_Q) * (ADV_MAX_SG_QUEUE)))
+
+#define ADV_MIN_REMAIN_Q 0x02
+#define ADV_DEF_MAX_TOTAL_QNG 0xF0
+#define ADV_MIN_TAG_Q_PER_DVC 0x04
+#define ADV_DEF_TAG_Q_PER_DVC 0x04
+#define ADV_MIN_FREE_Q ADV_MIN_REMAIN_Q
+#define ADV_MIN_TOTAL_QNG ((ADV_MAX_SG_QUEUE)+(ADV_MIN_FREE_Q))
+#define ADV_MAX_TOTAL_QNG 240
+#define ADV_MAX_INRAM_TAG_QNG 16
+#define ADV_MAX_PCI_INRAM_TOTAL_QNG 20
+#define ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
+#define ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
+
+#define ADV_DEF_IRQ_NO 10
+#define ADV_MAX_IRQ_NO 15
+#define ADV_MIN_IRQ_NO 10
+
+#define ADV_SCSIQ_CPY_BEG 4
+#define ADV_SCSIQ_SGHD_CPY_BEG 2
+
+/* SCSIQ Microcode representation offsets */
+#define ADV_SCSIQ_B_FWD 0
+#define ADV_SCSIQ_B_BWD 1
+#define ADV_SCSIQ_B_STATUS 2
+#define ADV_SCSIQ_B_QNO 3
+#define ADV_SCSIQ_B_CNTL 4
+#define ADV_SCSIQ_B_SG_QUEUE_CNT 5
+#define ADV_SCSIQ_B_LIST_CNT 6
+#define ADV_SCSIQ_B_CUR_LIST_CNT 7
+#define ADV_SCSIQ_D_DATA_ADDR 8
+#define ADV_SCSIQ_D_DATA_CNT 12
+#define ADV_SCSIQ_B_SENSE_LEN 20
+#define ADV_SCSIQ_DONE_INFO_BEG 22
+#define ADV_SCSIQ_D_CINFO_IDX 22
+#define ADV_SCSIQ_B_TARGET_IX 26
+#define ADV_SCSIQ_B_CDB_LEN 28
+#define ADV_SCSIQ_B_TAG_CODE 29
+#define ADV_SCSIQ_W_VM_ID 30
+#define ADV_SCSIQ_DONE_STATUS 32
+#define ADV_SCSIQ_HOST_STATUS 33
+#define ADV_SCSIQ_SCSI_STATUS 34
+#define ADV_SCSIQ_CDB_BEG 36
+#define ADV_SCSIQ_B_FIRST_SG_QK_QP 48
+#define ADV_SCSIQ_B_SG_WK_QP 49
+#define ADV_SCSIQ_B_SG_WK_IX 50
+#define ADV_SCSIQ_W_ALT_DC1 52
+#define ADV_SCSIQ_DW_REMAIN_XFER_ADDR 56
+#define ADV_SCSIQ_DW_REMAIN_XFER_CNT 60
+
+/* LRAM Offsets */
+#define ADVV_MSGOUT_BEG 0x0000
+#define ADVV_MSGOUT_SDTR_PERIOD (ADVV_MSGOUT_BEG+3)
+#define ADVV_MSGOUT_SDTR_OFFSET (ADVV_MSGOUT_BEG+4)
+
+#define ADVV_BREAK_SAVED_CODE 0x0006
+
+#define ADVV_MSGIN_BEG (ADVV_MSGOUT_BEG+8)
+#define ADVV_MSGIN_SDTR_PERIOD (ADVV_MSGIN_BEG+3)
+#define ADVV_MSGIN_SDTR_OFFSET (ADVV_MSGIN_BEG+4)
+
+#define ADVV_SDTR_DATA_BEG (ADVV_MSGIN_BEG+8)
+#define ADVV_SDTR_DONE_BEG (ADVV_SDTR_DATA_BEG+8)
+#define ADVV_MAX_DVC_QNG_BEG 0x0020
+
+#define ADVV_BREAK_ADDR 0x0028
+#define ADVV_BREAK_NOTIFY_COUNT 0x002A
+#define ADVV_BREAK_CONTROL 0x002C
+#define ADVV_BREAK_HIT_COUNT 0x002E
+
+#define ADVV_ASCDVC_ERR_CODE_W 0x0030
+#define ADVV_MCODE_CHKSUM_W 0x0032
+#define ADVV_MCODE_SIZE_W 0x0034
+#define ADVV_STOP_CODE_B 0x0036
+#define ADVV_DVC_ERR_CODE_B 0x0037
+
+#define ADVV_OVERRUN_PADDR_D 0x0038
+#define ADVV_OVERRUN_BSIZE_D 0x003C
+
+#define ADVV_HALTCODE_W 0x0040
+#define ADV_HALT_EXTMSG_IN 0x8000
+#define ADV_HALT_CHK_CONDITION 0x8100
+#define ADV_HALT_SS_QUEUE_FULL 0x8200
+#define ADV_HALT_DISABLE_ASYN_USE_SYN_FIX 0x8300
+#define ADV_HALT_ENABLE_ASYN_USE_SYN_FIX 0x8400
+#define ADV_HALT_SDTR_REJECTED 0x4000
+#define ADV_HALT_HOST_COPY_SG_LIST_TO_RISC 0x2000
+
+#define ADVV_CHKSUM_W 0x0042
+#define ADVV_MC_DATE_W 0x0044
+#define ADVV_MC_VER_W 0x0046
+#define ADVV_NEXTRDY_B 0x0048
+#define ADVV_DONENEXT_B 0x0049
+#define ADVV_USE_TAGGED_QNG_B 0x004A
+#define ADVV_SCSIBUSY_B 0x004B
+#define ADVV_Q_DONE_IN_PROGRESS_B 0x004C
+#define ADVV_CURCDB_B 0x004D
+#define ADVV_RCLUN_B 0x004E
+#define ADVV_BUSY_QHEAD_B 0x004F
+#define ADVV_DISC1_QHEAD_B 0x0050
+
+#define ADVV_DISC_ENABLE_B 0x0052
+#define ADVV_CAN_TAGGED_QNG_B 0x0053
+#define ADVV_HOSTSCSI_ID_B 0x0055
+#define ADVV_MCODE_CNTL_B 0x0056
+#define ADVV_NULL_TARGET_B 0x0057
+
+#define ADVV_FREE_Q_HEAD_W 0x0058
+#define ADVV_DONE_Q_TAIL_W 0x005A
+#define ADVV_FREE_Q_HEAD_B (ADVV_FREE_Q_HEAD_W+1)
+#define ADVV_DONE_Q_TAIL_B (ADVV_DONE_Q_TAIL_W+1)
+
+#define ADVV_HOST_FLAG_B 0x005D
+#define ADV_HOST_FLAG_IN_ISR 0x01
+#define ADV_HOST_FLAG_ACK_INT 0x02
+
+
+#define ADVV_TOTAL_READY_Q_B 0x0064
+#define ADVV_VER_SERIAL_B 0x0065
+#define ADVV_HALTCODE_SAVED_W 0x0066
+#define ADVV_WTM_FLAG_B 0x0068
+#define ADVV_RISC_FLAG_B 0x006A
+#define ADV_RISC_FLAG_GEN_INT 0x01
+#define ADV_RISC_FLAG_REQ_SG_LIST 0x02
+
+#define ADVV_REQ_SG_LIST_QP 0x006B
+
+#define ADV_TRANS_CUR 0x01 /* Modify current neogtiation status */
+#define ADV_TRANS_ACTIVE 0x03 /* Assume this is the active target */
+#define ADV_TRANS_GOAL 0x04 /* Modify negotiation goal */
+#define ADV_TRANS_USER 0x08 /* Modify user negotiation settings */
+
+struct adv_transinfo {
+ u_int8_t period;
+ u_int8_t offset;
+};
+
+struct adv_target_transinfo {
+ struct adv_transinfo current;
+ struct adv_transinfo goal;
+ struct adv_transinfo user;
+};
+
+struct adv_softc {
+ device_t dev;
+ bus_space_tag_t tag;
+ bus_space_handle_t bsh;
+ struct cam_sim *sim;
+ LIST_HEAD(, ccb_hdr) pending_ccbs;
+ struct adv_ccb_info *ccb_infos;
+ SLIST_HEAD(, adv_ccb_info) free_ccb_infos;
+ bus_dma_tag_t parent_dmat;
+ bus_dma_tag_t buffer_dmat;
+ bus_dma_tag_t sense_dmat;
+ bus_dmamap_t sense_dmamap;
+ struct scsi_sense_data *sense_buffers;
+ bus_addr_t sense_physbase;
+ bus_addr_t overrun_physbase;
+ adv_btype type;
+ struct adv_target_transinfo tinfo[8];
+ target_bit_vector fix_asyn_xfer;
+ target_bit_vector fix_asyn_xfer_always;
+ target_bit_vector disc_enable;
+ target_bit_vector user_disc_enable;
+ target_bit_vector cmd_qng_enabled;
+ target_bit_vector user_cmd_qng_enabled;
+ u_int16_t control;
+#define ADV_CNTL_INITIATOR 0x0001
+#define ADV_CNTL_BIOS_GT_1GB 0x0002
+#define ADV_CNTL_BIOS_GT_2_DISK 0x0004
+#define ADV_CNTL_BIOS_REMOVABLE 0x0008
+#define ADV_CNTL_NO_SCAM 0x0010
+#define ADV_CNTL_INT_MULTI_Q 0x0080
+#define ADV_CNTL_NO_LUN_SUPPORT 0x0040
+#define ADV_CNTL_NO_VERIFY_COPY 0x0100
+#define ADV_CNTL_RESET_SCSI 0x0200
+#define ADV_CNTL_INIT_INQUIRY 0x0400
+#define ADV_CNTL_INIT_VERBOSE 0x0800
+#define ADV_CNTL_SCSI_PARITY 0x1000
+#define ADV_CNTL_BURST_MODE 0x2000
+#define ADV_CNTL_SDTR_ENABLE_ULTRA 0x4000
+
+ u_int16_t bug_fix_control;
+#define ADV_BUG_FIX_IF_NOT_DWB 0x0001
+#define ADV_BUG_FIX_ASYN_USE_SYN 0x0002
+
+ adv_state state;
+ struct cam_path *path;
+ int unit;
+ int init_level;
+ u_int32_t max_dma_addr;
+ u_int32_t max_dma_count;
+ u_int8_t isa_dma_speed;
+ u_int8_t isa_dma_channel;
+ u_int8_t scsi_id;
+ u_int8_t chip_version;
+ u_int8_t max_tags_per_target;
+ u_int8_t max_openings;
+ u_int8_t cur_active;
+ u_int8_t openings_needed;
+ u_int8_t ccb_infos_allocated;
+ u_int8_t *sdtr_period_tbl;
+ u_int8_t sdtr_period_tbl_size;
+};
+
+/*
+ * Structures for talking to the RISC engine.
+ */
+struct adv_scsiq_1 {
+ u_int8_t status;
+#define QS_FREE 0x00
+#define QS_READY 0x01
+#define QS_DISC1 0x02
+#define QS_DISC2 0x04
+#define QS_BUSY 0x08
+#define QS_ABORTED 0x40
+#define QS_DONE 0x80
+
+ u_int8_t q_no; /*
+ * Queue ID of the first queue
+ * used in this transaction.
+ */
+ u_int8_t cntl;
+#define QC_NO_CALLBACK 0x01
+#define QC_SG_SWAP_QUEUE 0x02
+#define QC_SG_HEAD 0x04
+#define QC_DATA_IN 0x08
+#define QC_DATA_OUT 0x10
+#define QC_URGENT 0x20
+#define QC_MSG_OUT 0x40
+#define QC_REQ_SENSE 0x80
+
+ u_int8_t sg_queue_cnt; /* Number of SG entries */
+
+ u_int8_t target_id; /* target id as a bit vector */
+ u_int8_t target_lun; /* LUN - taken from our xs */
+
+ u_int32_t data_addr; /*
+ * physical addres of first
+ * (possibly only) segment
+ * to transfer.
+ */
+ u_int32_t data_cnt; /*
+ * byte count of the first
+ * (possibly only) segment
+ * to transfer.
+ */
+ u_int32_t sense_addr; /*
+ * physical address of the sense
+ * buffer.
+ */
+ u_int8_t sense_len; /* length of sense buffer */
+ u_int8_t extra_bytes;
+};
+
+struct adv_scsiq_2 {
+ u_int32_t ccb_index; /* Index to our CCB Info */
+ u_int8_t target_ix; /* Combined TID and LUN */
+
+ u_int8_t flag;
+ u_int8_t cdb_len; /*
+ * Number of bytes in the SCSI
+ * command to execute.
+ */
+ u_int8_t tag_code; /*
+ * Tag type for this transaction
+ * (SIMPLE, ORDERED, HEAD )
+ */
+#define ADV_TAG_FLAG_EXTRA_BYTES 0x10
+#define ADV_TAG_FLAG_DISABLE_DISCONNECT 0x04
+#define ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
+#define ADV_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
+
+ u_int16_t vm_id;
+};
+
+struct adv_scsiq_3 {
+ u_int8_t done_stat;
+#define QD_IN_PROGRESS 0x00
+#define QD_NO_ERROR 0x01
+#define QD_ABORTED_BY_HOST 0x02
+#define QD_WITH_ERROR 0x04
+#define QD_INVALID_REQUEST 0x80
+#define QD_INVALID_HOST_NUM 0x81
+#define QD_INVALID_DEVICE 0x82
+#define QD_ERR_INTERNAL 0xFF
+
+ u_int8_t host_stat;
+#define QHSTA_NO_ERROR 0x00
+#define QHSTA_M_SEL_TIMEOUT 0x11
+#define QHSTA_M_DATA_OVER_RUN 0x12
+#define QHSTA_M_DATA_UNDER_RUN 0x12
+#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
+#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
+
+#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
+#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
+#define QHSTA_D_HOST_ABORT_FAILED 0x23
+#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
+#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
+#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
+
+#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_TARGET_STATUS_BUSY 0x45
+#define QHSTA_M_BAD_TAG_CODE 0x46
+
+#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
+#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
+
+#define QHSTA_D_LRAM_CMP_ERROR 0x81
+
+#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
+
+ u_int8_t scsi_stat;
+ u_int8_t scsi_msg;
+};
+
+struct adv_scsiq_4 {
+ u_int8_t cdb[ADV_MAX_CDB_LEN];
+ u_int8_t y_first_sg_list_qp;
+ u_int8_t y_working_sg_qp;
+ u_int8_t y_working_sg_ix;
+ u_int8_t y_res;
+ u_int16_t x_req_count;
+ u_int16_t x_reconnect_rtn;
+ u_int32_t x_saved_data_addr;
+ u_int32_t x_saved_data_cnt;
+};
+
+struct adv_q_done_info {
+ struct adv_scsiq_2 d2;
+ struct adv_scsiq_3 d3;
+ u_int8_t q_status;
+ u_int8_t q_no;
+ u_int8_t cntl;
+ u_int8_t sense_len;
+ u_int8_t extra_bytes;
+ u_int8_t res;
+ u_int32_t remain_bytes;
+};
+
+struct adv_sg_entry {
+ u_int32_t addr;
+ u_int32_t bytes;
+};
+
+struct adv_sg_head {
+ u_int16_t entry_cnt; /*
+ * Number of SG entries
+ * in this list
+ */
+
+ u_int16_t queue_cnt; /*
+ * Number of queues required
+ * to store entry_cnt
+ * SG entries.
+ */
+
+ u_int16_t entry_to_copy; /*
+ * Number of SG entries to
+ * copy to the board.
+ */
+ u_int16_t res;
+ struct adv_sg_entry *sg_list;
+};
+
+#define QCX_SORT (0x0001)
+#define QCX_COALEASE (0x0002)
+
+struct adv_scsi_q {
+ struct adv_scsiq_1 q1;
+ struct adv_scsiq_2 q2;
+ u_int8_t *cdbptr; /*
+ * Pointer to the SCSI command
+ * to execute.
+ */
+
+ struct adv_sg_head *sg_head; /*
+ * Pointer to possible SG list
+ */
+};
+
+struct adv_scsi_req_q {
+ struct adv_scsiq_1 r1;
+ struct adv_scsiq_2 r2;
+ u_int8_t *cdbptr;
+ struct adv_sg_head *sg_head;
+ u_int8_t *sense_ptr;
+ struct adv_scsiq_3 r3;
+ u_int8_t cdb[ADV_MAX_CDB_LEN];
+ u_int8_t sense[ADV_MIN_SENSE_LEN];
+};
+
+struct adv_risc_q {
+ u_int8_t fwd;
+ u_int8_t bwd;
+ struct adv_scsiq_1 i1;
+ struct adv_scsiq_2 i2;
+ struct adv_scsiq_3 i3;
+ struct adv_scsiq_4 i4;
+};
+
+struct adv_sg_list_q {
+ u_int8_t seq_no;
+ u_int8_t q_no;
+ u_int8_t cntl;
+#define QCSG_SG_XFER_LIST 0x02
+#define QCSG_SG_XFER_MORE 0x04
+#define QCSG_SG_XFER_END 0x08
+
+ u_int8_t sg_head_qp;
+ u_int8_t sg_list_cnt;
+ u_int8_t sg_cur_list_cnt;
+};
+#define ADV_SGQ_B_SG_CNTL 4
+#define ADV_SGQ_B_SG_HEAD_QP 5
+#define ADV_SGQ_B_SG_LIST_CNT 6
+#define ADV_SGQ_B_SG_CUR_LIST_CNT 7
+#define ADV_SGQ_LIST_BEG 8
+
+struct asc_risc_sg_list_q {
+ u_int8_t fwd;
+ u_int8_t bwd;
+ struct adv_sg_list_q sg;
+ struct adv_sg_entry sg_list[ADV_SG_LIST_PER_Q];
+};
+
+/* Chip Register functions */
+void adv_set_bank(struct adv_softc *adv, u_int8_t bank);
+
+/* LRAM routines */
+u_int8_t adv_read_lram_8(struct adv_softc *adv, u_int16_t addr);
+void adv_write_lram_8(struct adv_softc *adv, u_int16_t addr,
+ u_int8_t value);
+u_int16_t adv_read_lram_16(struct adv_softc *adv, u_int16_t addr);
+void adv_write_lram_16(struct adv_softc *adv, u_int16_t addr,
+ u_int16_t value);
+
+/* Intialization */
+int adv_find_signature(bus_space_tag_t tag, bus_space_handle_t bsh);
+void adv_lib_init(struct adv_softc *adv);
+
+u_int16_t adv_get_eeprom_config(struct adv_softc *adv,
+ struct adv_eeprom_config *eeprom_config);
+int adv_set_eeprom_config(struct adv_softc *adv,
+ struct adv_eeprom_config *eeprom_config);
+int adv_reset_chip(struct adv_softc *adv, int reset_bus);
+int adv_test_external_lram(struct adv_softc* adv);
+int adv_init_lram_and_mcode(struct adv_softc *adv);
+u_int8_t adv_get_chip_irq(struct adv_softc *adv);
+u_int8_t adv_set_chip_irq(struct adv_softc *adv, u_int8_t irq_no);
+void adv_set_chip_scsiid(struct adv_softc *adv, int new_id);
+
+/* Queue handling and execution */
+int adv_execute_scsi_queue(struct adv_softc *adv,
+ struct adv_scsi_q *scsiq,
+ u_int32_t datalen);
+u_int8_t adv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr,
+ struct adv_q_done_info *scsiq, u_int32_t max_dma_count);
+
+/* Chip Control */
+int adv_start_chip(struct adv_softc *adv);
+void adv_start_execution(struct adv_softc *adv);
+int adv_stop_execution(struct adv_softc *adv);
+int adv_stop_chip(struct adv_softc *adv);
+int adv_is_chip_halted(struct adv_softc *adv);
+
+/* Interrupt processing */
+void adv_ack_interrupt(struct adv_softc *adv);
+void adv_isr_chip_halted(struct adv_softc *adv);
+
+/* SDTR Conversion */
+void adv_set_syncrate(struct adv_softc *adv, struct cam_path *path,
+ u_int target_id, u_int period, u_int offset,
+ u_int type);
+void adv_sdtr_to_period_offset(struct adv_softc *adv,
+ u_int8_t sync_data, u_int8_t *period,
+ u_int8_t *offset, int tid);
+u_int8_t adv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period,
+ u_int *offset, int tid);
+
+/* Error recovery */
+union ccb;
+int adv_abort_ccb(struct adv_softc *adv, int target, int lun,
+ union ccb *ccb, u_int32_t status, int queued_only);
+int adv_reset_bus(struct adv_softc *adv, int initiate_reset);
+
+/* Async event callback */
+void advasync(void *callback_arg, u_int32_t code,
+ struct cam_path *path, void *arg);
+
+#define ADV_INB(adv, offset) \
+ bus_space_read_1((adv)->tag, (adv)->bsh, offset)
+#define ADV_INW(adv, offset) \
+ bus_space_read_2((adv)->tag, (adv)->bsh, offset)
+#define ADV_INSB(adv, offset, valp, count) \
+ bus_space_read_multi_1((adv)->tag, (adv)->bsh, offset, valp, count)
+
+/* These controllers seem to have problems with PIO on some fast processors */
+static __inline void ADV_INSW(struct adv_softc *, u_int, u_int16_t *, u_int);
+static __inline void
+ADV_INSW(struct adv_softc *adv, u_int offset, u_int16_t *valp, u_int count)
+{
+ while (count--)
+ *valp++ = bus_space_read_2(adv->tag, adv->bsh, offset);
+}
+
+#define ADV_OUTB(adv, offset, val) \
+ bus_space_write_1((adv)->tag, (adv)->bsh, offset, val)
+#define ADV_OUTW(adv, offset, val) \
+ bus_space_write_2((adv)->tag, (adv)->bsh, offset, val)
+
+/* These controllers seem to have problems with PIO on some fast processors */
+static __inline void ADV_OUTSW(struct adv_softc *, u_int, u_int16_t *, u_int);
+static __inline void
+ADV_OUTSW(struct adv_softc *adv, u_int offset, u_int16_t *valp, u_int count)
+{
+ while (count--)
+ bus_space_write_2(adv->tag, adv->bsh, offset, *valp++);
+}
+
+#endif /* _ADVLIB_H_ */
diff --git a/sys/dev/advansys/advmcode.c b/sys/dev/advansys/advmcode.c
new file mode 100644
index 0000000..d53a4c6
--- /dev/null
+++ b/sys/dev/advansys/advmcode.c
@@ -0,0 +1,282 @@
+/*
+ * Downloadable microcode for Advanced Systems Inc. SCSI controllers
+ *
+ * $FreeBSD$
+ *
+ * Obtained from:
+ * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
+ *
+ * Copyright (c) 1995-1999 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>
+
+u_int8_t adv_mcode[] =
+{
+ 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 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, 0xC3, 0x12, 0x0D, 0x05,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00,
+ 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
+ 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12,
+ 0xDA, 0x00, 0xA2, 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98,
+ 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36,
+ 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00,
+ 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92,
+ 0x80, 0x80, 0x62, 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE,
+ 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D,
+ 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23,
+ 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80,
+ 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01,
+ 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88, 0x80, 0x73, 0x80,
+ 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
+ 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03,
+ 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88,
+ 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A,
+ 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
+ 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2,
+ 0x00, 0x07, 0xA6, 0x34, 0x01, 0x00, 0x33, 0x04, 0x00,
+ 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D,
+ 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8,
+ 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8,
+ 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63,
+ 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01, 0x00, 0x33, 0x0A,
+ 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01,
+ 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36,
+ 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04,
+ 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01, 0x88, 0x81, 0x4E,
+ 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
+ 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02,
+ 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23,
+ 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82,
+ 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
+ 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00,
+ 0x33, 0x1B, 0x00, 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98,
+ 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4,
+ 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84,
+ 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B,
+ 0x00, 0x06, 0x61, 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01,
+ 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x84,
+ 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
+ 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0,
+ 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23,
+ 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, 0x06,
+ 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
+ 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07,
+ 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02,
+ 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03,
+ 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
+ 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02,
+ 0xA6, 0x6C, 0x02, 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6,
+ 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C,
+ 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23,
+ 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04,
+ 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00,
+ 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5,
+ 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01,
+ 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07,
+ 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6,
+ 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02, 0x00, 0xA6, 0xB4,
+ 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
+ 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D,
+ 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61,
+ 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC,
+ 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
+ 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04,
+ 0x01, 0xA2, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88,
+ 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E,
+ 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6,
+ 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10,
+ 0x03, 0x03, 0xA6, 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02,
+ 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xEE,
+ 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42,
+ 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31,
+ 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43,
+ 0x87, 0x01, 0x05, 0x05, 0x86, 0x98, 0x7E, 0x98, 0x00,
+ 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
+ 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16,
+ 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95,
+ 0x32, 0x83, 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10,
+ 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
+ 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00,
+ 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01,
+ 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15,
+ 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00,
+ 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01,
+ 0xA6, 0x96, 0x03, 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84,
+ 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6, 0xA4, 0x03, 0x00,
+ 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42,
+ 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4,
+ 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00,
+ 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42, 0x00, 0xA6, 0xBC,
+ 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+ 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38,
+ 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01,
+ 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06,
+ 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
+ 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07,
+ 0xA6, 0x06, 0x04, 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33,
+ 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60,
+ 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4,
+ 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83,
+ 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04,
+ 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6, 0x38, 0x04, 0x00,
+ 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84,
+ 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00,
+ 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00,
+ 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x5A,
+ 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
+ 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23,
+ 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04,
+ 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B,
+ 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
+ 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22,
+ 0xA3, 0xE6, 0x04, 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04,
+ 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22,
+ 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8,
+ 0x88, 0x04, 0x98, 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98,
+ 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xE8,
+ 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE,
+ 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0,
+ 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02,
+ 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44,
+ 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
+ 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04,
+ 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23,
+ 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6,
+ 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
+ 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C,
+ 0x05, 0x0A, 0x85, 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85,
+ 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80,
+ 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01,
+ 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D,
+ 0x01, 0x04, 0xD6, 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60,
+ 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81,
+ 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01,
+ 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9,
+ 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05,
+ 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, 0xFE,
+ 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
+ 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E,
+ 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88,
+ 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF,
+ 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
+ 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82,
+ 0x01, 0x50, 0x00, 0x62, 0x97, 0x04, 0x85, 0x04, 0x23,
+ 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE,
+ 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85,
+ 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC,
+ 0x86, 0x07, 0xA0, 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B,
+ 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05, 0x80, 0x67, 0x80,
+ 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23,
+ 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80,
+ 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23,
+ 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00,
+ 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
+ 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C,
+ 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01,
+ 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80,
+ 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
+ 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06,
+ 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2,
+ 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07,
+ 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33,
+ 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07,
+ 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03,
+ 0x80, 0x63, 0x00, 0x63, 0x01, 0x23, 0xDF, 0x00, 0x06,
+ 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67,
+ 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81,
+ 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03,
+ 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06, 0x07, 0xA6, 0x7C,
+ 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
+ 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA,
+ 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63,
+ 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC,
+ 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
+ 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF,
+ 0x00, 0x00, 0x63, 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33,
+ 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89,
+ 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33,
+ 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4,
+ 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E,
+ 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04,
+ 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B,
+ 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C,
+ 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95,
+ 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x2C, 0x07, 0x07,
+ 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
+ 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C,
+ 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23,
+ 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0,
+ 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
+ 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81,
+ 0x01, 0x70, 0x04, 0x80, 0x05, 0x81, 0x05, 0x00, 0x63,
+ 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1,
+ 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00,
+ 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70,
+ 0x00, 0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04,
+ 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00, 0x70,
+ 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01,
+ 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81,
+ 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01,
+ 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01, 0xA1, 0x01, 0x01,
+ 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
+ 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80,
+ 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00,
+ 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05,
+ 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
+ 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF,
+ 0x23, 0x80, 0x01, 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04,
+ 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80,
+ 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
+ 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00,
+ 0x02, 0x00, 0xA0, 0x14, 0x08, 0x16, 0x88, 0x00, 0x43,
+ 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF3,
+ 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43,
+ 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74,
+ 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01,
+ 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98, 0x26, 0x95, 0x24,
+ 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
+ 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04,
+ 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3,
+ 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00,
+ 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
+ 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83,
+ 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88,
+ 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92,
+ 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32,
+ 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80,
+ 0x32, 0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D,
+ 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40,
+ 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
+ 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00,
+ 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00,
+ 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, 0x13, 0x23, 0xF8,
+ 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
+ 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80,
+ 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00,
+ 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11,
+ 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84
+};
+
+u_int16_t adv_mcode_size = sizeof(adv_mcode);
+u_int32_t adv_mcode_chksum = 0x012C453F;
diff --git a/sys/dev/advansys/advmcode.h b/sys/dev/advansys/advmcode.h
new file mode 100644
index 0000000..b9430b7
--- /dev/null
+++ b/sys/dev/advansys/advmcode.h
@@ -0,0 +1,19 @@
+/*
+ * Exported interface to downloadable microcode for AdvanSys SCSI Adapters
+ *
+ * $FreeBSD$
+ *
+ * Obtained from:
+ *
+ * Copyright (c) 1995-1999 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.
+ */
+
+extern u_int16_t adv_mcode[];
+extern u_int16_t adv_mcode_size;
+extern u_int32_t adv_mcode_chksum;
diff --git a/sys/dev/advansys/adw_pci.c b/sys/dev/advansys/adw_pci.c
new file mode 100644
index 0000000..b843005
--- /dev/null
+++ b/sys/dev/advansys/adw_pci.c
@@ -0,0 +1,396 @@
+/*
+ * Device probe and attach routines for the following
+ * Advanced Systems Inc. SCSI controllers:
+ *
+ * ABP[3]940UW - Bus-Master PCI Ultra-Wide (253 CDB)
+ * ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB/Channel)
+ * ABP970UW - Bus-Master PCI Ultra-Wide (253 CDB)
+ * ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
+ * ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
+ *
+ * Copyright (c) 1998, 1999, 2000 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <sys/rman.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#include <cam/cam.h>
+#include <cam/scsi/scsi_all.h>
+
+#include <dev/advansys/adwvar.h>
+#include <dev/advansys/adwlib.h>
+#include <dev/advansys/adwmcode.h>
+
+#define ADW_PCI_IOBASE PCIR_MAPS /* I/O Address */
+#define ADW_PCI_MEMBASE PCIR_MAPS + 4 /* Mem I/O Address */
+
+#define PCI_ID_ADVANSYS_3550 0x230010CD00000000ull
+#define PCI_ID_ADVANSYS_38C0800_REV1 0x250010CD00000000ull
+#define PCI_ID_ADVANSYS_38C1600_REV1 0x270010CD00000000ull
+#define PCI_ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull
+#define PCI_ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull
+
+struct adw_pci_identity;
+typedef int (adw_device_setup_t)(device_t, struct adw_pci_identity *,
+ struct adw_softc *adw);
+
+struct adw_pci_identity {
+ u_int64_t full_id;
+ u_int64_t id_mask;
+ char *name;
+ adw_device_setup_t *setup;
+ const struct adw_mcode *mcode_data;
+ const struct adw_eeprom *default_eeprom;
+};
+
+static adw_device_setup_t adw_asc3550_setup;
+static adw_device_setup_t adw_asc38C0800_setup;
+#ifdef NOTYET
+static adw_device_setup_t adw_asc38C1600_setup;
+#endif
+
+struct adw_pci_identity adw_pci_ident_table[] =
+{
+ /* asc3550 based controllers */
+ {
+ PCI_ID_ADVANSYS_3550,
+ PCI_ID_DEV_VENDOR_MASK,
+ "AdvanSys 3550 Ultra SCSI Adapter",
+ adw_asc3550_setup,
+ &adw_asc3550_mcode_data,
+ &adw_asc3550_default_eeprom
+ },
+ /* asc38C0800 based controllers */
+ {
+ PCI_ID_ADVANSYS_38C0800_REV1,
+ PCI_ID_DEV_VENDOR_MASK,
+ "AdvanSys 38C0800 Ultra2 SCSI Adapter",
+ adw_asc38C0800_setup,
+ &adw_asc38C0800_mcode_data,
+ &adw_asc38C0800_default_eeprom
+ },
+#if NOTYET
+ /* XXX Disabled until I have hardware to test with */
+ /* asc38C1600 based controllers */
+ {
+ PCI_ID_ADVANSYS_38C1600_REV1,
+ PCI_ID_DEV_VENDOR_MASK,
+ "AdvanSys 38C1600 Ultra160 SCSI Adapter",
+ adw_asc38C1600_setup,
+ NULL, /* None provided by vendor thus far */
+ NULL /* None provided by vendor thus far */
+ }
+#endif
+};
+
+static const int adw_num_pci_devs =
+ sizeof(adw_pci_ident_table) / sizeof(*adw_pci_ident_table);
+
+#define ADW_PCI_MAX_DMA_ADDR (0xFFFFFFFFUL)
+#define ADW_PCI_MAX_DMA_COUNT (0xFFFFFFFFUL)
+
+static int adw_pci_probe(device_t dev);
+static int adw_pci_attach(device_t dev);
+
+static device_method_t adw_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, adw_pci_probe),
+ DEVMETHOD(device_attach, adw_pci_attach),
+ { 0, 0 }
+};
+
+static driver_t adw_pci_driver = {
+ "adw",
+ adw_pci_methods,
+ sizeof(struct adw_softc)
+};
+
+static devclass_t adw_devclass;
+
+DRIVER_MODULE(adw, pci, adw_pci_driver, adw_devclass, 0, 0);
+
+static __inline u_int64_t
+adw_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
+{
+ u_int64_t id;
+
+ id = subvendor
+ | (subdevice << 16)
+ | ((u_int64_t)vendor << 32)
+ | ((u_int64_t)device << 48);
+
+ return (id);
+}
+
+static struct adw_pci_identity *
+adw_find_pci_device(device_t dev)
+{
+ u_int64_t full_id;
+ struct adw_pci_identity *entry;
+ u_int i;
+
+ full_id = adw_compose_id(pci_get_device(dev),
+ pci_get_vendor(dev),
+ pci_get_subdevice(dev),
+ pci_get_subvendor(dev));
+
+ for (i = 0; i < adw_num_pci_devs; i++) {
+ entry = &adw_pci_ident_table[i];
+ if (entry->full_id == (full_id & entry->id_mask))
+ return (entry);
+ }
+ return (NULL);
+}
+
+static int
+adw_pci_probe(device_t dev)
+{
+ struct adw_pci_identity *entry;
+
+ entry = adw_find_pci_device(dev);
+ if (entry != NULL) {
+ device_set_desc(dev, entry->name);
+ return (0);
+ }
+ return (ENXIO);
+}
+
+static int
+adw_pci_attach(device_t dev)
+{
+ struct adw_softc *adw;
+ struct adw_pci_identity *entry;
+ u_int32_t command;
+ struct resource *regs;
+ int regs_type;
+ int regs_id;
+ int error;
+ int zero;
+
+ command = pci_read_config(dev, PCIR_COMMAND, /*bytes*/1);
+ entry = adw_find_pci_device(dev);
+ if (entry == NULL)
+ return (ENXIO);
+ regs = NULL;
+ regs_type = 0;
+ regs_id = 0;
+#ifdef ADW_ALLOW_MEMIO
+ if ((command & PCIM_CMD_MEMEN) != 0) {
+ regs_type = SYS_RES_MEMORY;
+ regs_id = ADW_PCI_MEMBASE;
+ regs = bus_alloc_resource(dev, regs_type,
+ &regs_id, 0, ~0, 1, RF_ACTIVE);
+ }
+#endif
+ if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) {
+ regs_type = SYS_RES_IOPORT;
+ regs_id = ADW_PCI_IOBASE;
+ regs = bus_alloc_resource(dev, regs_type,
+ &regs_id, 0, ~0, 1, RF_ACTIVE);
+ }
+
+ if (regs == NULL) {
+ device_printf(dev, "can't allocate register resources\n");
+ return (ENOMEM);
+ }
+
+ adw = adw_alloc(dev, regs, regs_type, regs_id);
+ if (adw == NULL)
+ return(ENOMEM);
+
+ /*
+ * Now that we have access to our registers, just verify that
+ * this really is an AdvanSys device.
+ */
+ if (adw_find_signature(adw) == 0) {
+ adw_free(adw);
+ return (ENXIO);
+ }
+
+ adw_reset_chip(adw);
+
+ error = entry->setup(dev, entry, adw);
+
+ if (error != 0)
+ return (error);
+
+ /* Ensure busmastering is enabled */
+ command |= PCIM_CMD_BUSMASTEREN;
+ pci_write_config(dev, PCIR_COMMAND, command, /*bytes*/1);
+
+ /* Allocate a dmatag for our transfer DMA maps */
+ /* XXX Should be a child of the PCI bus dma tag */
+ error = bus_dma_tag_create(
+ /* parent */ NULL,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ ADW_PCI_MAX_DMA_ADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ BUS_SPACE_MAXSIZE_32BIT,
+ /* nsegments */ ~0,
+ /* maxsegsz */ ADW_PCI_MAX_DMA_COUNT,
+ /* flags */ 0,
+ &adw->parent_dmat);
+
+ adw->init_level++;
+
+ if (error != 0) {
+ printf("%s: Could not allocate DMA tag - error %d\n",
+ adw_name(adw), error);
+ adw_free(adw);
+ return (error);
+ }
+
+ adw->init_level++;
+
+ error = adw_init(adw);
+ if (error != 0) {
+ adw_free(adw);
+ return (error);
+ }
+
+ /*
+ * 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 ((command & PCIM_CMD_PERRESPEN) == 0)
+ adw_lram_write_16(adw, ADW_MC_CONTROL_FLAG,
+ adw_lram_read_16(adw, ADW_MC_CONTROL_FLAG)
+ | ADW_MC_CONTROL_IGN_PERR);
+
+ zero = 0;
+ adw->irq_res_type = SYS_RES_IRQ;
+ adw->irq = bus_alloc_resource(dev, adw->irq_res_type, &zero,
+ 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
+ if (adw->irq == NULL) {
+ adw_free(adw);
+ return (ENOMEM);
+ }
+
+ error = adw_attach(adw);
+ if (error != 0)
+ adw_free(adw);
+ return (error);
+}
+
+static int
+adw_generic_setup(device_t dev, struct adw_pci_identity *entry,
+ struct adw_softc *adw)
+{
+ adw->channel = pci_get_function(dev) == 1 ? 'B' : 'A';
+ adw->chip = ADW_CHIP_NONE;
+ adw->features = ADW_FENONE;
+ adw->flags = ADW_FNONE;
+ adw->mcode_data = entry->mcode_data;
+ adw->default_eeprom = entry->default_eeprom;
+ return (0);
+}
+
+static int
+adw_asc3550_setup(device_t dev, struct adw_pci_identity *entry,
+ struct adw_softc *adw)
+{
+ int error;
+
+ error = adw_generic_setup(dev, entry, adw);
+ if (error != 0)
+ return (error);
+ adw->chip = ADW_CHIP_ASC3550;
+ adw->features = ADW_ASC3550_FE;
+ adw->memsize = ADW_3550_MEMSIZE;
+ /*
+ * For ASC-3550, setting the START_CTL_EMFU [3:2] bits
+ * sets a FIFO threshold of 128 bytes. This register is
+ * only accessible to the host.
+ */
+ adw_outb(adw, ADW_DMA_CFG0,
+ ADW_DMA_CFG0_START_CTL_EM_FU|ADW_DMA_CFG0_READ_CMD_MRM);
+ adw_outb(adw, ADW_MEM_CFG,
+ adw_inb(adw, ADW_MEM_CFG) | ADW_MEM_CFG_RAM_SZ_8KB);
+ return (0);
+}
+
+static int
+adw_asc38C0800_setup(device_t dev, struct adw_pci_identity *entry,
+ struct adw_softc *adw)
+{
+ int error;
+
+ error = adw_generic_setup(dev, entry, adw);
+ if (error != 0)
+ return (error);
+ /*
+ * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and
+ * START_CTL_TH [3:2] bits for the default FIFO threshold.
+ *
+ * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+ *
+ * For DMA Errata #4 set the BC_THRESH_ENB bit.
+ */
+ adw_outb(adw, ADW_DMA_CFG0,
+ ADW_DMA_CFG0_BC_THRESH_ENB|ADW_DMA_CFG0_FIFO_THRESH_80B
+ |ADW_DMA_CFG0_START_CTL_TH|ADW_DMA_CFG0_READ_CMD_MRM);
+ adw_outb(adw, ADW_MEM_CFG,
+ adw_inb(adw, ADW_MEM_CFG) | ADW_MEM_CFG_RAM_SZ_16KB);
+ adw->chip = ADW_CHIP_ASC38C0800;
+ adw->features = ADW_ASC38C0800_FE;
+ adw->memsize = ADW_38C0800_MEMSIZE;
+ return (error);
+}
+
+#ifdef NOTYET
+static int
+adw_asc38C1600_setup(device_t dev, struct adw_pci_identity *entry,
+ struct adw_softc *adw)
+{
+ int error;
+
+ error = adw_generic_setup(dev, entry, adw);
+ if (error != 0)
+ return (error);
+ adw->chip = ADW_CHIP_ASC38C1600;
+ adw->features = ADW_ASC38C1600_FE;
+ adw->memsize = ADW_38C1600_MEMSIZE;
+ return (error);
+}
+#endif
diff --git a/sys/dev/advansys/adwcam.c b/sys/dev/advansys/adwcam.c
new file mode 100644
index 0000000..74bd9ce
--- /dev/null
+++ b/sys/dev/advansys/adwcam.c
@@ -0,0 +1,1540 @@
+/*
+ * CAM SCSI interface for the the Advanced Systems Inc.
+ * Second Generation SCSI controllers.
+ *
+ * Product specific probe and attach routines can be found in:
+ *
+ * adw_pci.c ABP[3]940UW, ABP950UW, ABP3940U2W
+ *
+ * Copyright (c) 1998, 1999, 2000 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * 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>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <sys/rman.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+
+#include <cam/scsi/scsi_message.h>
+
+#include <dev/advansys/adwvar.h>
+
+/* Definitions for our use of the SIM private CCB area */
+#define ccb_acb_ptr spriv_ptr0
+#define ccb_adw_ptr spriv_ptr1
+
+u_long adw_unit;
+
+static __inline cam_status adwccbstatus(union ccb*);
+static __inline struct acb* adwgetacb(struct adw_softc *adw);
+static __inline void adwfreeacb(struct adw_softc *adw,
+ struct acb *acb);
+
+static void adwmapmem(void *arg, bus_dma_segment_t *segs,
+ int nseg, int error);
+static struct sg_map_node*
+ adwallocsgmap(struct adw_softc *adw);
+static int adwallocacbs(struct adw_softc *adw);
+
+static void adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs,
+ int nseg, int error);
+static void adw_action(struct cam_sim *sim, union ccb *ccb);
+static void adw_poll(struct cam_sim *sim);
+static void adw_async(void *callback_arg, u_int32_t code,
+ struct cam_path *path, void *arg);
+static void adwprocesserror(struct adw_softc *adw, struct acb *acb);
+static void adwtimeout(void *arg);
+static void adw_handle_device_reset(struct adw_softc *adw,
+ u_int target);
+static void adw_handle_bus_reset(struct adw_softc *adw,
+ int initiated);
+
+static __inline cam_status
+adwccbstatus(union ccb* ccb)
+{
+ return (ccb->ccb_h.status & CAM_STATUS_MASK);
+}
+
+static __inline struct acb*
+adwgetacb(struct adw_softc *adw)
+{
+ struct acb* acb;
+ int s;
+
+ s = splcam();
+ if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) {
+ SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
+ } else if (adw->num_acbs < adw->max_acbs) {
+ adwallocacbs(adw);
+ acb = SLIST_FIRST(&adw->free_acb_list);
+ if (acb == NULL)
+ printf("%s: Can't malloc ACB\n", adw_name(adw));
+ else {
+ SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
+ }
+ }
+ splx(s);
+
+ return (acb);
+}
+
+static __inline void
+adwfreeacb(struct adw_softc *adw, struct acb *acb)
+{
+ int s;
+
+ s = splcam();
+ if ((acb->state & ACB_ACTIVE) != 0)
+ LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le);
+ if ((acb->state & ACB_RELEASE_SIMQ) != 0)
+ acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
+ else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0
+ && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
+ acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
+ adw->state &= ~ADW_RESOURCE_SHORTAGE;
+ }
+ acb->state = ACB_FREE;
+ SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links);
+ splx(s);
+}
+
+static void
+adwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ bus_addr_t *busaddrp;
+
+ busaddrp = (bus_addr_t *)arg;
+ *busaddrp = segs->ds_addr;
+}
+
+static struct sg_map_node *
+adwallocsgmap(struct adw_softc *adw)
+{
+ struct sg_map_node *sg_map;
+
+ sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+
+ if (sg_map == NULL)
+ return (NULL);
+
+ /* Allocate S/G space for the next batch of ACBS */
+ if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr,
+ BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
+ free(sg_map, M_DEVBUF);
+ return (NULL);
+ }
+
+ SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links);
+
+ bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
+ PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0);
+
+ bzero(sg_map->sg_vaddr, PAGE_SIZE);
+ return (sg_map);
+}
+
+/*
+ * Allocate another chunk of CCB's. Return count of entries added.
+ * Assumed to be called at splcam().
+ */
+static int
+adwallocacbs(struct adw_softc *adw)
+{
+ struct acb *next_acb;
+ struct sg_map_node *sg_map;
+ bus_addr_t busaddr;
+ struct adw_sg_block *blocks;
+ int newcount;
+ int i;
+
+ next_acb = &adw->acbs[adw->num_acbs];
+ sg_map = adwallocsgmap(adw);
+
+ if (sg_map == NULL)
+ return (0);
+
+ blocks = sg_map->sg_vaddr;
+ busaddr = sg_map->sg_physaddr;
+
+ newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));
+ for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {
+ int error;
+
+ error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,
+ &next_acb->dmamap);
+ if (error != 0)
+ break;
+ next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb);
+ next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb);
+ next_acb->queue.sense_baddr =
+ acbvtob(adw, next_acb) + offsetof(struct acb, sense_data);
+ next_acb->sg_blocks = blocks;
+ next_acb->sg_busaddr = busaddr;
+ next_acb->state = ACB_FREE;
+ SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);
+ blocks += ADW_SG_BLOCKCNT;
+ busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks);
+ next_acb++;
+ adw->num_acbs++;
+ }
+ return (i);
+}
+
+static void
+adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
+{
+ struct acb *acb;
+ union ccb *ccb;
+ struct adw_softc *adw;
+ int s;
+
+ acb = (struct acb *)arg;
+ ccb = acb->ccb;
+ adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
+
+ if (error != 0) {
+ if (error != EFBIG)
+ printf("%s: Unexepected error 0x%x returned from "
+ "bus_dmamap_load\n", adw_name(adw), error);
+ if (ccb->ccb_h.status == CAM_REQ_INPROG) {
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
+ }
+ adwfreeacb(adw, acb);
+ xpt_done(ccb);
+ return;
+ }
+
+ if (nseg != 0) {
+ bus_dmasync_op_t op;
+
+ acb->queue.data_addr = dm_segs[0].ds_addr;
+ acb->queue.data_cnt = ccb->csio.dxfer_len;
+ if (nseg > 1) {
+ struct adw_sg_block *sg_block;
+ struct adw_sg_elm *sg;
+ bus_addr_t sg_busaddr;
+ u_int sg_index;
+ bus_dma_segment_t *end_seg;
+
+ end_seg = dm_segs + nseg;
+
+ sg_busaddr = acb->sg_busaddr;
+ sg_index = 0;
+ /* Copy the segments into our SG list */
+ for (sg_block = acb->sg_blocks;; sg_block++) {
+ u_int i;
+
+ sg = sg_block->sg_list;
+ for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) {
+ if (dm_segs >= end_seg)
+ break;
+
+ sg->sg_addr = dm_segs->ds_addr;
+ sg->sg_count = dm_segs->ds_len;
+ sg++;
+ dm_segs++;
+ }
+ sg_block->sg_cnt = i;
+ sg_index += i;
+ if (dm_segs == end_seg) {
+ sg_block->sg_busaddr_next = 0;
+ break;
+ } else {
+ sg_busaddr +=
+ sizeof(struct adw_sg_block);
+ sg_block->sg_busaddr_next = sg_busaddr;
+ }
+ }
+ acb->queue.sg_real_addr = acb->sg_busaddr;
+ } else {
+ acb->queue.sg_real_addr = 0;
+ }
+
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+ op = BUS_DMASYNC_PREREAD;
+ else
+ op = BUS_DMASYNC_PREWRITE;
+
+ bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
+
+ } else {
+ acb->queue.data_addr = 0;
+ acb->queue.data_cnt = 0;
+ acb->queue.sg_real_addr = 0;
+ }
+
+ s = splcam();
+
+ /*
+ * Last time we need to check if this CCB needs to
+ * be aborted.
+ */
+ if (ccb->ccb_h.status != CAM_REQ_INPROG) {
+ if (nseg != 0)
+ bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
+ adwfreeacb(adw, acb);
+ xpt_done(ccb);
+ splx(s);
+ return;
+ }
+
+ acb->state |= ACB_ACTIVE;
+ ccb->ccb_h.status |= CAM_SIM_QUEUED;
+ LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
+ ccb->ccb_h.timeout_ch =
+ timeout(adwtimeout, (caddr_t)acb,
+ (ccb->ccb_h.timeout * hz) / 1000);
+
+ adw_send_acb(adw, acb, acbvtob(adw, acb));
+
+ splx(s);
+}
+
+static void
+adw_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct adw_softc *adw;
+
+ CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n"));
+
+ adw = (struct adw_softc *)cam_sim_softc(sim);
+
+ switch (ccb->ccb_h.func_code) {
+ /* Common cases first */
+ case XPT_SCSI_IO: /* Execute the requested I/O operation */
+ {
+ struct ccb_scsiio *csio;
+ struct ccb_hdr *ccbh;
+ struct acb *acb;
+
+ csio = &ccb->csio;
+ ccbh = &ccb->ccb_h;
+
+ /* Max supported CDB length is 12 bytes */
+ if (csio->cdb_len > 12) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
+ if ((acb = adwgetacb(adw)) == NULL) {
+ int s;
+
+ s = splcam();
+ adw->state |= ADW_RESOURCE_SHORTAGE;
+ splx(s);
+ xpt_freeze_simq(sim, /*count*/1);
+ ccb->ccb_h.status = CAM_REQUEUE_REQ;
+ xpt_done(ccb);
+ return;
+ }
+
+ /* Link acb and ccb so we can find one from the other */
+ acb->ccb = ccb;
+ ccb->ccb_h.ccb_acb_ptr = acb;
+ ccb->ccb_h.ccb_adw_ptr = adw;
+
+ acb->queue.cntl = 0;
+ acb->queue.target_cmd = 0;
+ acb->queue.target_id = ccb->ccb_h.target_id;
+ acb->queue.target_lun = ccb->ccb_h.target_lun;
+
+ acb->queue.mflag = 0;
+ acb->queue.sense_len =
+ MIN(csio->sense_len, sizeof(acb->sense_data));
+ acb->queue.cdb_len = csio->cdb_len;
+ if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
+ switch (csio->tag_action) {
+ case MSG_SIMPLE_Q_TAG:
+ acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG;
+ break;
+ case MSG_HEAD_OF_Q_TAG:
+ acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG;
+ break;
+ case MSG_ORDERED_Q_TAG:
+ acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG;
+ break;
+ default:
+ acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
+ break;
+ }
+ } else
+ acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
+
+ if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
+ acb->queue.scsi_cntl |= ADW_QSC_NO_DISC;
+
+ acb->queue.done_status = 0;
+ acb->queue.scsi_status = 0;
+ acb->queue.host_status = 0;
+ acb->queue.sg_wk_ix = 0;
+ if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
+ if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
+ bcopy(csio->cdb_io.cdb_ptr,
+ acb->queue.cdb, csio->cdb_len);
+ } else {
+ /* I guess I could map it in... */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ adwfreeacb(adw, acb);
+ xpt_done(ccb);
+ return;
+ }
+ } else {
+ bcopy(csio->cdb_io.cdb_bytes,
+ acb->queue.cdb, csio->cdb_len);
+ }
+
+ /*
+ * If we have any data to send with this command,
+ * map it into bus space.
+ */
+ if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
+ /*
+ * We've been given a pointer
+ * to a single buffer.
+ */
+ if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
+ int s;
+ int error;
+
+ s = splsoftvm();
+ error =
+ bus_dmamap_load(adw->buffer_dmat,
+ acb->dmamap,
+ csio->data_ptr,
+ csio->dxfer_len,
+ adwexecuteacb,
+ acb, /*flags*/0);
+ if (error == EINPROGRESS) {
+ /*
+ * So as to maintain ordering,
+ * freeze the controller queue
+ * until our mapping is
+ * returned.
+ */
+ xpt_freeze_simq(sim, 1);
+ acb->state |= CAM_RELEASE_SIMQ;
+ }
+ splx(s);
+ } else {
+ struct bus_dma_segment seg;
+
+ /* Pointer to physical buffer */
+ seg.ds_addr =
+ (bus_addr_t)csio->data_ptr;
+ seg.ds_len = csio->dxfer_len;
+ adwexecuteacb(acb, &seg, 1, 0);
+ }
+ } else {
+ struct bus_dma_segment *segs;
+
+ if ((ccbh->flags & CAM_DATA_PHYS) != 0)
+ panic("adw_action - Physical "
+ "segment pointers "
+ "unsupported");
+
+ if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
+ panic("adw_action - Virtual "
+ "segment addresses "
+ "unsupported");
+
+ /* Just use the segments provided */
+ segs = (struct bus_dma_segment *)csio->data_ptr;
+ adwexecuteacb(acb, segs, csio->sglist_cnt,
+ (csio->sglist_cnt < ADW_SGSIZE)
+ ? 0 : EFBIG);
+ }
+ } else {
+ adwexecuteacb(acb, NULL, 0, 0);
+ }
+ break;
+ }
+ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
+ {
+ adw_idle_cmd_status_t status;
+
+ status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
+ ccb->ccb_h.target_id);
+ if (status == ADW_IDLE_CMD_SUCCESS) {
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ if (bootverbose) {
+ xpt_print_path(ccb->ccb_h.path);
+ printf("BDR Delivered\n");
+ }
+ } else
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_ABORT: /* Abort the specified CCB */
+ /* XXX Implement */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ case XPT_SET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts;
+ u_int target_mask;
+ int s;
+
+ cts = &ccb->cts;
+ target_mask = 0x01 << ccb->ccb_h.target_id;
+
+ s = splcam();
+ if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
+ u_int sdtrdone;
+
+ sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE);
+ if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
+ u_int discenb;
+
+ discenb =
+ adw_lram_read_16(adw, ADW_MC_DISC_ENABLE);
+
+ if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
+ discenb |= target_mask;
+ else
+ discenb &= ~target_mask;
+
+ adw_lram_write_16(adw, ADW_MC_DISC_ENABLE,
+ discenb);
+ }
+
+ if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
+
+ if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
+ adw->tagenb |= target_mask;
+ else
+ adw->tagenb &= ~target_mask;
+ }
+
+ if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
+ u_int wdtrenb_orig;
+ u_int wdtrenb;
+ u_int wdtrdone;
+
+ wdtrenb_orig =
+ adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
+ wdtrenb = wdtrenb_orig;
+ wdtrdone = adw_lram_read_16(adw,
+ ADW_MC_WDTR_DONE);
+ switch (cts->bus_width) {
+ case MSG_EXT_WDTR_BUS_32_BIT:
+ case MSG_EXT_WDTR_BUS_16_BIT:
+ wdtrenb |= target_mask;
+ break;
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ default:
+ wdtrenb &= ~target_mask;
+ break;
+ }
+ if (wdtrenb != wdtrenb_orig) {
+ adw_lram_write_16(adw,
+ ADW_MC_WDTR_ABLE,
+ wdtrenb);
+ wdtrdone &= ~target_mask;
+ adw_lram_write_16(adw,
+ ADW_MC_WDTR_DONE,
+ wdtrdone);
+ /* Wide negotiation forces async */
+ sdtrdone &= ~target_mask;
+ adw_lram_write_16(adw,
+ ADW_MC_SDTR_DONE,
+ sdtrdone);
+ }
+ }
+
+ if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
+ || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
+ u_int sdtr_orig;
+ u_int sdtr;
+ u_int sdtrable_orig;
+ u_int sdtrable;
+
+ sdtr = adw_get_chip_sdtr(adw,
+ ccb->ccb_h.target_id);
+ sdtr_orig = sdtr;
+ sdtrable = adw_lram_read_16(adw,
+ ADW_MC_SDTR_ABLE);
+ sdtrable_orig = sdtrable;
+
+ if ((cts->valid
+ & CCB_TRANS_SYNC_RATE_VALID) != 0) {
+
+ sdtr =
+ adw_find_sdtr(adw,
+ cts->sync_period);
+ }
+
+ if ((cts->valid
+ & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
+ if (cts->sync_offset == 0)
+ sdtr = ADW_MC_SDTR_ASYNC;
+ }
+
+ if (sdtr == ADW_MC_SDTR_ASYNC)
+ sdtrable &= ~target_mask;
+ else
+ sdtrable |= target_mask;
+ if (sdtr != sdtr_orig
+ || sdtrable != sdtrable_orig) {
+ adw_set_chip_sdtr(adw,
+ ccb->ccb_h.target_id,
+ sdtr);
+ sdtrdone &= ~target_mask;
+ adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
+ sdtrable);
+ adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
+ sdtrdone);
+
+ }
+ }
+ }
+ splx(s);
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ /* Get default/user set transfer settings for the target */
+ {
+ struct ccb_trans_settings *cts;
+ u_int target_mask;
+
+ cts = &ccb->cts;
+ target_mask = 0x01 << ccb->ccb_h.target_id;
+ if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
+ u_int mc_sdtr;
+
+ cts->flags = 0;
+ if ((adw->user_discenb & target_mask) != 0)
+ cts->flags |= CCB_TRANS_DISC_ENB;
+
+ if ((adw->user_tagenb & target_mask) != 0)
+ cts->flags |= CCB_TRANS_TAG_ENB;
+
+ if ((adw->user_wdtr & target_mask) != 0)
+ cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+ else
+ cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+
+ mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id);
+ cts->sync_period = adw_find_period(adw, mc_sdtr);
+ if (cts->sync_period != 0)
+ cts->sync_offset = 15; /* XXX ??? */
+ else
+ cts->sync_offset = 0;
+
+ cts->valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID
+ | CCB_TRANS_BUS_WIDTH_VALID
+ | CCB_TRANS_DISC_VALID
+ | CCB_TRANS_TQ_VALID;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ } else {
+ u_int targ_tinfo;
+
+ cts->flags = 0;
+ if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE)
+ & target_mask) != 0)
+ cts->flags |= CCB_TRANS_DISC_ENB;
+
+ if ((adw->tagenb & target_mask) != 0)
+ cts->flags |= CCB_TRANS_TAG_ENB;
+
+ targ_tinfo =
+ adw_lram_read_16(adw,
+ ADW_MC_DEVICE_HSHK_CFG_TABLE
+ + (2 * ccb->ccb_h.target_id));
+
+ if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0)
+ cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+ else
+ cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+
+ cts->sync_period =
+ adw_hshk_cfg_period_factor(targ_tinfo);
+
+ cts->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
+ if (cts->sync_period == 0)
+ cts->sync_offset = 0;
+
+ if (cts->sync_offset == 0)
+ cts->sync_period = 0;
+ }
+ cts->valid = CCB_TRANS_SYNC_RATE_VALID
+ | CCB_TRANS_SYNC_OFFSET_VALID
+ | CCB_TRANS_BUS_WIDTH_VALID
+ | CCB_TRANS_DISC_VALID
+ | CCB_TRANS_TQ_VALID;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_CALC_GEOMETRY:
+ {
+ /*
+ * XXX Use Adaptec translation until I find out how to
+ * get this information from the card.
+ */
+ cam_calc_geometry(&ccb->ccg, /*extended*/1);
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_RESET_BUS: /* Reset the specified SCSI bus */
+ {
+ int failure;
+
+ failure = adw_reset_bus(adw);
+ if (failure != 0) {
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ } else {
+ if (bootverbose) {
+ xpt_print_path(adw->path);
+ printf("Bus Reset Delivered\n");
+ }
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ }
+ xpt_done(ccb);
+ break;
+ }
+ case XPT_TERM_IO: /* Terminate the I/O process */
+ /* XXX Implement */
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ case XPT_PATH_INQ: /* Path routing inquiry */
+ {
+ struct ccb_pathinq *cpi = &ccb->cpi;
+
+ cpi->version_num = 1;
+ cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = 0;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = ADW_MAX_TID;
+ cpi->max_lun = ADW_MAX_LUN;
+ cpi->initiator_id = adw->initiator_id;
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 3300;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ break;
+ }
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
+}
+
+static void
+adw_poll(struct cam_sim *sim)
+{
+ adw_intr(cam_sim_softc(sim));
+}
+
+static void
+adw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
+{
+}
+
+struct adw_softc *
+adw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id)
+{
+ struct adw_softc *adw;
+ int i;
+
+ /*
+ * Allocate a storage area for us
+ */
+ adw = malloc(sizeof(struct adw_softc), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (adw == NULL) {
+ printf("adw%d: cannot malloc!\n", device_get_unit(dev));
+ return NULL;
+ }
+ LIST_INIT(&adw->pending_ccbs);
+ SLIST_INIT(&adw->sg_maps);
+ adw->device = dev;
+ adw->unit = device_get_unit(dev);
+ adw->regs_res_type = regs_type;
+ adw->regs_res_id = regs_id;
+ adw->regs = regs;
+ adw->tag = rman_get_bustag(regs);
+ adw->bsh = rman_get_bushandle(regs);
+ i = adw->unit / 10;
+ adw->name = malloc(sizeof("adw") + i + 1, M_DEVBUF, M_NOWAIT);
+ if (adw->name == NULL) {
+ printf("adw%d: cannot malloc name!\n", adw->unit);
+ free(adw, M_DEVBUF);
+ return NULL;
+ }
+ sprintf(adw->name, "adw%d", adw->unit);
+ return(adw);
+}
+
+void
+adw_free(struct adw_softc *adw)
+{
+ switch (adw->init_level) {
+ case 9:
+ {
+ struct sg_map_node *sg_map;
+
+ while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) {
+ SLIST_REMOVE_HEAD(&adw->sg_maps, links);
+ bus_dmamap_unload(adw->sg_dmat,
+ sg_map->sg_dmamap);
+ bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr,
+ sg_map->sg_dmamap);
+ free(sg_map, M_DEVBUF);
+ }
+ bus_dma_tag_destroy(adw->sg_dmat);
+ }
+ case 8:
+ bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
+ case 7:
+ bus_dmamem_free(adw->acb_dmat, adw->acbs,
+ adw->acb_dmamap);
+ bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
+ case 6:
+ bus_dma_tag_destroy(adw->acb_dmat);
+ case 5:
+ bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap);
+ case 4:
+ bus_dmamem_free(adw->carrier_dmat, adw->carriers,
+ adw->carrier_dmamap);
+ bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap);
+ case 3:
+ bus_dma_tag_destroy(adw->carrier_dmat);
+ case 2:
+ bus_dma_tag_destroy(adw->buffer_dmat);
+ case 1:
+ bus_dma_tag_destroy(adw->parent_dmat);
+ case 0:
+ break;
+ }
+ free(adw->name, M_DEVBUF);
+ free(adw, M_DEVBUF);
+}
+
+int
+adw_init(struct adw_softc *adw)
+{
+ struct adw_eeprom eep_config;
+ u_int tid;
+ u_int i;
+ u_int16_t checksum;
+ u_int16_t scsicfg1;
+
+ checksum = adw_eeprom_read(adw, &eep_config);
+ bcopy(eep_config.serial_number, adw->serial_number,
+ sizeof(adw->serial_number));
+ if (checksum != eep_config.checksum) {
+ u_int16_t serial_number[3];
+
+ adw->flags |= ADW_EEPROM_FAILED;
+ printf("%s: EEPROM checksum failed. Restoring Defaults\n",
+ adw_name(adw));
+
+ /*
+ * Restore the default EEPROM settings.
+ * Assume the 6 byte board serial number that was read
+ * from EEPROM is correct even if the EEPROM checksum
+ * failed.
+ */
+ bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config));
+ bcopy(adw->serial_number, eep_config.serial_number,
+ sizeof(serial_number));
+ adw_eeprom_write(adw, &eep_config);
+ }
+
+ /* Pull eeprom information into our softc. */
+ adw->bios_ctrl = eep_config.bios_ctrl;
+ adw->user_wdtr = eep_config.wdtr_able;
+ for (tid = 0; tid < ADW_MAX_TID; tid++) {
+ u_int mc_sdtr;
+ u_int16_t tid_mask;
+
+ tid_mask = 0x1 << tid;
+ if ((adw->features & ADW_ULTRA) != 0) {
+ /*
+ * Ultra chips store sdtr and ultraenb
+ * bits in their seeprom, so we must
+ * construct valid mc_sdtr entries for
+ * indirectly.
+ */
+ if (eep_config.sync1.sync_enable & tid_mask) {
+ if (eep_config.sync2.ultra_enable & tid_mask)
+ mc_sdtr = ADW_MC_SDTR_20;
+ else
+ mc_sdtr = ADW_MC_SDTR_10;
+ } else
+ mc_sdtr = ADW_MC_SDTR_ASYNC;
+ } else {
+ switch (ADW_TARGET_GROUP(tid)) {
+ case 3:
+ mc_sdtr = eep_config.sync4.sdtr4;
+ break;
+ case 2:
+ mc_sdtr = eep_config.sync3.sdtr3;
+ break;
+ case 1:
+ mc_sdtr = eep_config.sync2.sdtr2;
+ break;
+ default: /* Shut up compiler */
+ case 0:
+ mc_sdtr = eep_config.sync1.sdtr1;
+ break;
+ }
+ mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid);
+ mc_sdtr &= 0xFF;
+ }
+ adw_set_user_sdtr(adw, tid, mc_sdtr);
+ }
+ adw->user_tagenb = eep_config.tagqng_able;
+ adw->user_discenb = eep_config.disc_enable;
+ adw->max_acbs = eep_config.max_host_qng;
+ adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
+
+ /*
+ * Sanity check the number of host openings.
+ */
+ if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG)
+ adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
+ else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (adw->max_acbs == 0)
+ adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
+ else
+ adw->max_acbs = ADW_DEF_MIN_HOST_QNG;
+ }
+
+ scsicfg1 = 0;
+ if ((adw->features & ADW_ULTRA2) != 0) {
+ switch (eep_config.termination_lvd) {
+ default:
+ printf("%s: Invalid EEPROM LVD Termination Settings.\n",
+ adw_name(adw));
+ printf("%s: Reverting to Automatic LVD Termination\n",
+ adw_name(adw));
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_AUTO:
+ break;
+ case ADW_EEPROM_TERM_BOTH_ON:
+ scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO;
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_HIGH_ON:
+ scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI;
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_OFF:
+ scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV;
+ break;
+ }
+ }
+
+ switch (eep_config.termination_se) {
+ default:
+ printf("%s: Invalid SE EEPROM Termination Settings.\n",
+ adw_name(adw));
+ printf("%s: Reverting to Automatic SE Termination\n",
+ adw_name(adw));
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_AUTO:
+ break;
+ case ADW_EEPROM_TERM_BOTH_ON:
+ scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_HIGH_ON:
+ scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_OFF:
+ scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;
+ break;
+ }
+ printf("%s: SCSI ID %d, ", adw_name(adw), adw->initiator_id);
+
+ /* DMA tag for mapping buffers into device visible space. */
+ if (bus_dma_tag_create(
+ /* parent */ adw->parent_dmat,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ MAXBSIZE,
+ /* nsegments */ ADW_SGSIZE,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ BUS_DMA_ALLOCNOW,
+ &adw->buffer_dmat) != 0) {
+ return (ENOMEM);
+ }
+
+ adw->init_level++;
+
+ /* DMA tag for our ccb carrier structures */
+ if (bus_dma_tag_create(
+ /* parent */ adw->parent_dmat,
+ /* alignment */ 0x10,
+ /* boundary */ 0,
+ /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ (adw->max_acbs +
+ ADW_NUM_CARRIER_QUEUES + 1) *
+ sizeof(struct adw_carrier),
+ /* nsegments */ 1,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ 0,
+ &adw->carrier_dmat) != 0) {
+ return (ENOMEM);
+ }
+
+ adw->init_level++;
+
+ /* Allocation for our ccb carrier structures */
+ if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers,
+ BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) {
+ return (ENOMEM);
+ }
+
+ adw->init_level++;
+
+ /* And permanently map them */
+ bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap,
+ adw->carriers,
+ (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
+ * sizeof(struct adw_carrier),
+ adwmapmem, &adw->carrier_busbase, /*flags*/0);
+
+ /* Clear them out. */
+ bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
+ * sizeof(struct adw_carrier));
+
+ /* Setup our free carrier list */
+ adw->free_carriers = adw->carriers;
+ for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) {
+ adw->carriers[i].carr_offset =
+ carriervtobo(adw, &adw->carriers[i]);
+ adw->carriers[i].carr_ba =
+ carriervtob(adw, &adw->carriers[i]);
+ adw->carriers[i].areq_ba = 0;
+ adw->carriers[i].next_ba =
+ carriervtobo(adw, &adw->carriers[i+1]);
+ }
+ /* Terminal carrier. Never leaves the freelist */
+ adw->carriers[i].carr_offset =
+ carriervtobo(adw, &adw->carriers[i]);
+ adw->carriers[i].carr_ba =
+ carriervtob(adw, &adw->carriers[i]);
+ adw->carriers[i].areq_ba = 0;
+ adw->carriers[i].next_ba = ~0;
+
+ adw->init_level++;
+
+ /* DMA tag for our acb structures */
+ if (bus_dma_tag_create(
+ /* parent */ adw->parent_dmat,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ BUS_SPACE_MAXADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ adw->max_acbs * sizeof(struct acb),
+ /* nsegments */ 1,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ 0,
+ &adw->acb_dmat) != 0) {
+ return (ENOMEM);
+ }
+
+ adw->init_level++;
+
+ /* Allocation for our ccbs */
+ if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,
+ BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0)
+ return (ENOMEM);
+
+ adw->init_level++;
+
+ /* And permanently map them */
+ bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap,
+ adw->acbs,
+ adw->max_acbs * sizeof(struct acb),
+ adwmapmem, &adw->acb_busbase, /*flags*/0);
+
+ /* Clear them out. */
+ bzero(adw->acbs, adw->max_acbs * sizeof(struct acb));
+
+ /* DMA tag for our S/G structures. We allocate in page sized chunks */
+ if (bus_dma_tag_create(
+ /* parent */ adw->parent_dmat,
+ /* alignment */ 1,
+ /* boundary */ 0,
+ /* lowaddr */ BUS_SPACE_MAXADDR,
+ /* highaddr */ BUS_SPACE_MAXADDR,
+ /* filter */ NULL,
+ /* filterarg */ NULL,
+ /* maxsize */ PAGE_SIZE,
+ /* nsegments */ 1,
+ /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
+ /* flags */ 0,
+ &adw->sg_dmat) != 0) {
+ return (ENOMEM);
+ }
+
+ adw->init_level++;
+
+ /* Allocate our first batch of ccbs */
+ if (adwallocacbs(adw) == 0)
+ return (ENOMEM);
+
+ if (adw_init_chip(adw, scsicfg1) != 0)
+ return (ENXIO);
+
+ printf("Queue Depth %d\n", adw->max_acbs);
+
+ return (0);
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+adw_attach(struct adw_softc *adw)
+{
+ struct ccb_setasync csa;
+ struct cam_devq *devq;
+ int s;
+ int error;
+
+ error = 0;
+ s = splcam();
+ /* Hook up our interrupt handler */
+ if ((error = bus_setup_intr(adw->device, adw->irq,
+ INTR_TYPE_CAM | INTR_ENTROPY, adw_intr,
+ adw, &adw->ih)) != 0) {
+ device_printf(adw->device, "bus_setup_intr() failed: %d\n",
+ error);
+ goto fail;
+ }
+
+ /* Start the Risc processor now that we are fully configured. */
+ adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);
+
+ /*
+ * Create the device queue for our SIM.
+ */
+ devq = cam_simq_alloc(adw->max_acbs);
+ if (devq == NULL)
+ return (ENOMEM);
+
+ /*
+ * Construct our SIM entry.
+ */
+ adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit,
+ 1, adw->max_acbs, devq);
+ if (adw->sim == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
+
+ /*
+ * Register the bus.
+ */
+ if (xpt_bus_register(adw->sim, 0) != CAM_SUCCESS) {
+ cam_sim_free(adw->sim, /*free devq*/TRUE);
+ error = ENOMEM;
+ goto fail;
+ }
+
+ if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),
+ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
+ == CAM_REQ_CMP) {
+ xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5);
+ csa.ccb_h.func_code = XPT_SASYNC_CB;
+ csa.event_enable = AC_LOST_DEVICE;
+ csa.callback = adw_async;
+ csa.callback_arg = adw;
+ xpt_action((union ccb *)&csa);
+ }
+
+fail:
+ splx(s);
+ return (error);
+}
+
+void
+adw_intr(void *arg)
+{
+ struct adw_softc *adw;
+ u_int int_stat;
+
+ adw = (struct adw_softc *)arg;
+ if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)
+ return;
+
+ /* Reading the register clears the interrupt. */
+ int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);
+
+ if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {
+ u_int intrb_code;
+
+ /* Async Microcode Event */
+ intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE);
+ switch (intrb_code) {
+ case ADW_ASYNC_CARRIER_READY_FAILURE:
+ /*
+ * The RISC missed our update of
+ * the commandq.
+ */
+ if (LIST_FIRST(&adw->pending_ccbs) != NULL)
+ adw_tickle_risc(adw, ADW_TICKLE_A);
+ break;
+ case ADW_ASYNC_SCSI_BUS_RESET_DET:
+ /*
+ * The firmware detected a SCSI Bus reset.
+ */
+ printf("Someone Reset the Bus\n");
+ adw_handle_bus_reset(adw, /*initiated*/FALSE);
+ break;
+ case ADW_ASYNC_RDMA_FAILURE:
+ /*
+ * Handle RDMA failure by resetting the
+ * SCSI Bus and chip.
+ */
+#if XXX
+ AdvResetChipAndSB(adv_dvc_varp);
+#endif
+ break;
+
+ case ADW_ASYNC_HOST_SCSI_BUS_RESET:
+ /*
+ * Host generated SCSI bus reset occurred.
+ */
+ adw_handle_bus_reset(adw, /*initiated*/TRUE);
+ break;
+ default:
+ printf("adw_intr: unknown async code 0x%x\n",
+ intrb_code);
+ break;
+ }
+ }
+
+ /*
+ * Run down the RequestQ.
+ */
+ while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) {
+ struct adw_carrier *free_carrier;
+ struct acb *acb;
+ union ccb *ccb;
+
+#if 0
+ printf("0x%x, 0x%x, 0x%x, 0x%x\n",
+ adw->responseq->carr_offset,
+ adw->responseq->carr_ba,
+ adw->responseq->areq_ba,
+ adw->responseq->next_ba);
+#endif
+ /*
+ * The firmware copies the adw_scsi_req_q.acb_baddr
+ * field into the areq_ba field of the carrier.
+ */
+ acb = acbbotov(adw, adw->responseq->areq_ba);
+
+ /*
+ * The least significant four bits of the next_ba
+ * field are used as flags. Mask them out and then
+ * advance through the list.
+ */
+ free_carrier = adw->responseq;
+ adw->responseq =
+ carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK);
+ free_carrier->next_ba = adw->free_carriers->carr_offset;
+ adw->free_carriers = free_carrier;
+
+ /* Process CCB */
+ ccb = acb->ccb;
+ untimeout(adwtimeout, acb, ccb->ccb_h.timeout_ch);
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+ bus_dmasync_op_t op;
+
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+ op = BUS_DMASYNC_POSTREAD;
+ else
+ op = BUS_DMASYNC_POSTWRITE;
+ bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
+ bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
+ ccb->csio.resid = acb->queue.data_cnt;
+ } else
+ ccb->csio.resid = 0;
+
+ /* Common Cases inline... */
+ if (acb->queue.host_status == QHSTA_NO_ERROR
+ && (acb->queue.done_status == QD_NO_ERROR
+ || acb->queue.done_status == QD_WITH_ERROR)) {
+ ccb->csio.scsi_status = acb->queue.scsi_status;
+ ccb->ccb_h.status = 0;
+ switch (ccb->csio.scsi_status) {
+ case SCSI_STATUS_OK:
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+ break;
+ case SCSI_STATUS_CHECK_COND:
+ case SCSI_STATUS_CMD_TERMINATED:
+ bcopy(&acb->sense_data, &ccb->csio.sense_data,
+ ccb->csio.sense_len);
+ ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
+ ccb->csio.sense_resid = acb->queue.sense_len;
+ /* FALLTHROUGH */
+ default:
+ ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR
+ | CAM_DEV_QFRZN;
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ break;
+ }
+ adwfreeacb(adw, acb);
+ xpt_done(ccb);
+ } else {
+ adwprocesserror(adw, acb);
+ }
+ }
+}
+
+static void
+adwprocesserror(struct adw_softc *adw, struct acb *acb)
+{
+ union ccb *ccb;
+
+ ccb = acb->ccb;
+ if (acb->queue.done_status == QD_ABORTED_BY_HOST) {
+ ccb->ccb_h.status = CAM_REQ_ABORTED;
+ } else {
+
+ switch (acb->queue.host_status) {
+ case QHSTA_M_SEL_TIMEOUT:
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ break;
+ case QHSTA_M_SXFR_OFF_UFLW:
+ case QHSTA_M_SXFR_OFF_OFLW:
+ case QHSTA_M_DATA_OVER_RUN:
+ ccb->ccb_h.status = CAM_DATA_RUN_ERR;
+ break;
+ case QHSTA_M_SXFR_DESELECTED:
+ case QHSTA_M_UNEXPECTED_BUS_FREE:
+ ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
+ break;
+ case QHSTA_M_SCSI_BUS_RESET:
+ case QHSTA_M_SCSI_BUS_RESET_UNSOL:
+ ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
+ break;
+ case QHSTA_M_BUS_DEVICE_RESET:
+ ccb->ccb_h.status = CAM_BDR_SENT;
+ break;
+ case QHSTA_M_QUEUE_ABORTED:
+ /* BDR or Bus Reset */
+ printf("Saw Queue Aborted\n");
+ ccb->ccb_h.status = adw->last_reset;
+ break;
+ case QHSTA_M_SXFR_SDMA_ERR:
+ case QHSTA_M_SXFR_SXFR_PERR:
+ case QHSTA_M_RDMA_PERR:
+ ccb->ccb_h.status = CAM_UNCOR_PARITY;
+ break;
+ case QHSTA_M_WTM_TIMEOUT:
+ case QHSTA_M_SXFR_WD_TMO:
+ {
+ /* The SCSI bus hung in a phase */
+ xpt_print_path(adw->path);
+ printf("Watch Dog timer expired. Reseting bus\n");
+ adw_reset_bus(adw);
+ break;
+ }
+ case QHSTA_M_SXFR_XFR_PH_ERR:
+ ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
+ break;
+ case QHSTA_M_SXFR_UNKNOWN_ERROR:
+ break;
+ case QHSTA_M_BAD_CMPL_STATUS_IN:
+ /* No command complete after a status message */
+ ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
+ break;
+ case QHSTA_M_AUTO_REQ_SENSE_FAIL:
+ ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
+ break;
+ case QHSTA_M_INVALID_DEVICE:
+ ccb->ccb_h.status = CAM_PATH_INVALID;
+ break;
+ case QHSTA_M_NO_AUTO_REQ_SENSE:
+ /*
+ * User didn't request sense, but we got a
+ * check condition.
+ */
+ ccb->csio.scsi_status = acb->queue.scsi_status;
+ ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+ break;
+ default:
+ panic("%s: Unhandled Host status error %x",
+ adw_name(adw), acb->queue.host_status);
+ /* NOTREACHED */
+ }
+ }
+ if ((acb->state & ACB_RECOVERY_ACB) != 0) {
+ if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET
+ || ccb->ccb_h.status == CAM_BDR_SENT)
+ ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+ }
+ if (ccb->ccb_h.status != CAM_REQ_CMP) {
+ xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ }
+ adwfreeacb(adw, acb);
+ xpt_done(ccb);
+}
+
+static void
+adwtimeout(void *arg)
+{
+ struct acb *acb;
+ union ccb *ccb;
+ struct adw_softc *adw;
+ adw_idle_cmd_status_t status;
+ int target_id;
+ int s;
+
+ acb = (struct acb *)arg;
+ ccb = acb->ccb;
+ adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
+ xpt_print_path(ccb->ccb_h.path);
+ printf("ACB %p - timed out\n", (void *)acb);
+
+ s = splcam();
+
+ if ((acb->state & ACB_ACTIVE) == 0) {
+ xpt_print_path(ccb->ccb_h.path);
+ printf("ACB %p - timed out CCB already completed\n",
+ (void *)acb);
+ splx(s);
+ return;
+ }
+
+ acb->state |= ACB_RECOVERY_ACB;
+ target_id = ccb->ccb_h.target_id;
+
+ /* Attempt a BDR first */
+ status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
+ ccb->ccb_h.target_id);
+ splx(s);
+ if (status == ADW_IDLE_CMD_SUCCESS) {
+ printf("%s: BDR Delivered. No longer in timeout\n",
+ adw_name(adw));
+ adw_handle_device_reset(adw, target_id);
+ } else {
+ adw_reset_bus(adw);
+ xpt_print_path(adw->path);
+ printf("Bus Reset Delivered. No longer in timeout\n");
+ }
+}
+
+static void
+adw_handle_device_reset(struct adw_softc *adw, u_int target)
+{
+ struct cam_path *path;
+ cam_status error;
+
+ error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim),
+ target, CAM_LUN_WILDCARD);
+
+ if (error == CAM_REQ_CMP) {
+ xpt_async(AC_SENT_BDR, path, NULL);
+ xpt_free_path(path);
+ }
+ adw->last_reset = CAM_BDR_SENT;
+}
+
+static void
+adw_handle_bus_reset(struct adw_softc *adw, int initiated)
+{
+ if (initiated) {
+ /*
+ * The microcode currently sets the SCSI Bus Reset signal
+ * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET
+ * command above. But the SCSI Bus Reset Hold Time in the
+ * microcode 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
+ * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
+ * than 25 us.
+ */
+ u_int scsi_ctrl;
+
+ scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT;
+ adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);
+ DELAY(ADW_SCSI_RESET_HOLD_TIME_US);
+ adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl);
+
+ /*
+ * We will perform the async notification when the
+ * SCSI Reset interrupt occurs.
+ */
+ } else
+ xpt_async(AC_BUS_RESET, adw->path, NULL);
+ adw->last_reset = CAM_SCSI_BUS_RESET;
+}
diff --git a/sys/dev/advansys/adwlib.c b/sys/dev/advansys/adwlib.c
new file mode 100644
index 0000000..bbe4837
--- /dev/null
+++ b/sys/dev/advansys/adwlib.c
@@ -0,0 +1,893 @@
+/*
+ * Low level routines for Second Generation
+ * Advanced Systems Inc. SCSI controllers chips
+ *
+ * Copyright (c) 1998, 1999, 2000 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * 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>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/scsi/scsi_all.h>
+
+#include <dev/advansys/adwlib.h>
+
+const struct adw_eeprom adw_asc3550_default_eeprom =
+{
+ ADW_EEPROM_BIOS_ENABLE, /* cfg_lsw */
+ 0x0000, /* cfg_msw */
+ 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 */
+ 0xFFE7, /* bios_ctrl */
+ { 0xFFFF }, /* ultra_able */
+ { 0 }, /* reserved2 */
+ ADW_DEF_MAX_HOST_QNG, /* max_host_qng */
+ ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */
+ 0, /* dvc_cntl */
+ { 0 }, /* bug_fix */
+ { 0, 0, 0 }, /* serial_number */
+ 0, /* check_sum */
+ { /* oem_name[16] */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ 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 */
+};
+
+const struct adw_eeprom adw_asc38C0800_default_eeprom =
+{
+ ADW_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
+ 0x0000, /* 01 cfg_msw */
+ 0xFFFF, /* 02 disc_enable */
+ 0xFFFF, /* 03 wdtr_able */
+ { 0x4444 }, /* 04 sdtr_speed1 */
+ 0xFFFF, /* 05 start_motor */
+ 0xFFFF, /* 06 tagqng_able */
+ 0xFFFF, /* 07 bios_scan */
+ 0, /* 08 scam_tolerant */
+ 7, /* 09 adapter_scsi_id */
+ 0, /* bios_boot_delay */
+ 3, /* 10 scsi_reset_delay */
+ 0, /* bios_id_lun */
+ 0, /* 11 termination_se */
+ 0, /* termination_lvd */
+ 0xFFE7, /* 12 bios_ctrl */
+ { 0x4444 }, /* 13 sdtr_speed2 */
+ { 0x4444 }, /* 14 sdtr_speed3 */
+ ADW_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
+ ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */
+ 0, /* 16 dvc_cntl */
+ { 0x4444 } , /* 17 sdtr_speed4 */
+ { 0, 0, 0 }, /* 18-20 serial_number */
+ 0, /* 21 check_sum */
+ { /* 22-29 oem_name[16] */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ 0, /* 30 dvc_err_code */
+ 0, /* 31 adv_err_code */
+ 0, /* 32 adv_err_addr */
+ 0, /* 33 saved_dvc_err_code */
+ 0, /* 34 saved_adv_err_code */
+ 0, /* 35 saved_adv_err_addr */
+ { /* 36 - 55 reserved */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ 0, /* 56 cisptr_lsw */
+ 0, /* 57 cisprt_msw */
+ /* 58-59 sub-id */
+ (PCI_ID_ADVANSYS_38C0800_REV1 & PCI_ID_DEV_VENDOR_MASK) >> 32,
+};
+
+#define ADW_MC_SDTR_OFFSET_ULTRA2_DT 0
+#define ADW_MC_SDTR_OFFSET_ULTRA2 1
+#define ADW_MC_SDTR_OFFSET_ULTRA 2
+const struct adw_syncrate adw_syncrates[] =
+{
+ /* mc_sdtr period rate */
+ { ADW_MC_SDTR_80, 9, "80.0" },
+ { ADW_MC_SDTR_40, 10, "40.0" },
+ { ADW_MC_SDTR_20, 12, "20.0" },
+ { ADW_MC_SDTR_10, 25, "10.0" },
+ { ADW_MC_SDTR_5, 50, "5.0" },
+ { ADW_MC_SDTR_ASYNC, 0, "async" }
+};
+
+const int adw_num_syncrates = sizeof(adw_syncrates) / sizeof(adw_syncrates[0]);
+
+static u_int16_t adw_eeprom_read_16(struct adw_softc *adw, int addr);
+static void adw_eeprom_write_16(struct adw_softc *adw, int addr,
+ u_int data);
+static void adw_eeprom_wait(struct adw_softc *adw);
+
+int
+adw_find_signature(struct adw_softc *adw)
+{
+ if (adw_inb(adw, ADW_SIGNATURE_BYTE) == ADW_CHIP_ID_BYTE
+ && adw_inw(adw, ADW_SIGNATURE_WORD) == ADW_CHIP_ID_WORD)
+ return (1);
+ return (0);
+}
+
+/*
+ * Reset Chip.
+ */
+void
+adw_reset_chip(struct adw_softc *adw)
+{
+ adw_outw(adw, ADW_CTRL_REG, ADW_CTRL_REG_CMD_RESET);
+ DELAY(1000 * 100);
+ adw_outw(adw, ADW_CTRL_REG, ADW_CTRL_REG_CMD_WR_IO_REG);
+
+ /*
+ * Initialize Chip registers.
+ */
+ adw_outw(adw, ADW_SCSI_CFG1,
+ adw_inw(adw, ADW_SCSI_CFG1) & ~ADW_SCSI_CFG1_BIG_ENDIAN);
+}
+
+/*
+ * Reset the SCSI bus.
+ */
+int
+adw_reset_bus(struct adw_softc *adw)
+{
+ adw_idle_cmd_status_t status;
+
+ status =
+ adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START, /*param*/0);
+ if (status != ADW_IDLE_CMD_SUCCESS) {
+ xpt_print_path(adw->path);
+ printf("Bus Reset start attempt failed\n");
+ return (1);
+ }
+ DELAY(ADW_BUS_RESET_HOLD_DELAY_US);
+ status =
+ adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END, /*param*/0);
+ if (status != ADW_IDLE_CMD_SUCCESS) {
+ xpt_print_path(adw->path);
+ printf("Bus Reset end attempt failed\n");
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Read the specified EEPROM location
+ */
+static u_int16_t
+adw_eeprom_read_16(struct adw_softc *adw, int addr)
+{
+ adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_READ | addr);
+ adw_eeprom_wait(adw);
+ return (adw_inw(adw, ADW_EEP_DATA));
+}
+
+static void
+adw_eeprom_write_16(struct adw_softc *adw, int addr, u_int data)
+{
+ adw_outw(adw, ADW_EEP_DATA, data);
+ adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE | addr);
+ adw_eeprom_wait(adw);
+}
+
+/*
+ * Wait for and EEPROM command to complete
+ */
+static void
+adw_eeprom_wait(struct adw_softc *adw)
+{
+ int i;
+
+ for (i = 0; i < ADW_EEP_DELAY_MS; i++) {
+ if ((adw_inw(adw, ADW_EEP_CMD) & ADW_EEP_CMD_DONE) != 0)
+ break;
+ DELAY(1000);
+ }
+ if (i == ADW_EEP_DELAY_MS)
+ panic("%s: Timedout Reading EEPROM", adw_name(adw));
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+u_int16_t
+adw_eeprom_read(struct adw_softc *adw, struct adw_eeprom *eep_buf)
+{
+ u_int16_t *wbuf;
+ u_int16_t wval;
+ u_int16_t chksum;
+ int eep_addr;
+
+ wbuf = (u_int16_t *)eep_buf;
+ chksum = 0;
+
+ for (eep_addr = ADW_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADW_EEP_DVC_CFG_END;
+ eep_addr++, wbuf++) {
+ wval = adw_eeprom_read_16(adw, eep_addr);
+ chksum += wval;
+ *wbuf = wval;
+ }
+
+ /* checksum field is not counted in the checksum */
+ *wbuf = adw_eeprom_read_16(adw, eep_addr);
+ wbuf++;
+
+ /* Driver seeprom variables are not included in the checksum */
+ for (eep_addr = ADW_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADW_EEP_MAX_WORD_ADDR;
+ eep_addr++, wbuf++)
+ *wbuf = adw_eeprom_read_16(adw, eep_addr);
+
+ return (chksum);
+}
+
+void
+adw_eeprom_write(struct adw_softc *adw, struct adw_eeprom *eep_buf)
+{
+ u_int16_t *wbuf;
+ u_int16_t addr;
+ u_int16_t chksum;
+
+ wbuf = (u_int16_t *)eep_buf;
+ chksum = 0;
+
+ adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE_ABLE);
+ adw_eeprom_wait(adw);
+
+ /*
+ * Write EEPROM until checksum.
+ */
+ for (addr = ADW_EEP_DVC_CFG_BEGIN;
+ addr < ADW_EEP_DVC_CFG_END; addr++, wbuf++) {
+ chksum += *wbuf;
+ adw_eeprom_write_16(adw, addr, *wbuf);
+ }
+
+ /*
+ * Write calculated EEPROM checksum
+ */
+ adw_eeprom_write_16(adw, addr, chksum);
+
+ /* skip over buffer's checksum */
+ wbuf++;
+
+ /*
+ * Write the rest.
+ */
+ for (addr = ADW_EEP_DVC_CTL_BEGIN;
+ addr < ADW_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+ adw_eeprom_write_16(adw, addr, *wbuf);
+
+ adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE_DISABLE);
+ adw_eeprom_wait(adw);
+}
+
+int
+adw_init_chip(struct adw_softc *adw, u_int term_scsicfg1)
+{
+ u_int8_t biosmem[ADW_MC_BIOSLEN];
+ const u_int16_t *word_table;
+ const u_int8_t *byte_codes;
+ const u_int8_t *byte_codes_end;
+ u_int bios_sig;
+ u_int bytes_downloaded;
+ u_int addr;
+ u_int end_addr;
+ u_int checksum;
+ u_int scsicfg1;
+ u_int tid;
+
+ /*
+ * 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.
+ */
+ for (addr = 0; addr < ADW_MC_BIOSLEN; addr++)
+ biosmem[addr] = adw_lram_read_8(adw, ADW_MC_BIOSMEM + addr);
+
+ /*
+ * Save current per TID negotiated values if the BIOS has been
+ * loaded (BIOS signature is present). These will be used if
+ * we cannot get information from the EEPROM.
+ */
+ addr = ADW_MC_BIOS_SIGNATURE - ADW_MC_BIOSMEM;
+ bios_sig = biosmem[addr]
+ | (biosmem[addr + 1] << 8);
+ if (bios_sig == 0x55AA
+ && (adw->flags & ADW_EEPROM_FAILED) != 0) {
+ u_int major_ver;
+ u_int minor_ver;
+ u_int sdtr_able;
+
+ addr = ADW_MC_BIOS_VERSION - ADW_MC_BIOSMEM;
+ minor_ver = biosmem[addr + 1] & 0xF;
+ major_ver = (biosmem[addr + 1] >> 4) & 0xF;
+ if ((adw->chip == ADW_CHIP_ASC3550)
+ && (major_ver <= 3
+ || (major_ver == 3 && minor_ver == 1))) {
+ /*
+ * BIOS 3.1 and earlier location of
+ * 'wdtr_able' variable.
+ */
+ adw->user_wdtr =
+ adw_lram_read_16(adw, ADW_MC_WDTR_ABLE_BIOS_31);
+ } else {
+ adw->user_wdtr =
+ adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
+ }
+ sdtr_able = adw_lram_read_16(adw, ADW_MC_SDTR_ABLE);
+ for (tid = 0; tid < ADW_MAX_TID; tid++) {
+ u_int tid_mask;
+ u_int mc_sdtr;
+
+ tid_mask = 0x1 << tid;
+ if ((sdtr_able & tid_mask) == 0)
+ mc_sdtr = ADW_MC_SDTR_ASYNC;
+ else if ((adw->features & ADW_DT) != 0)
+ mc_sdtr = ADW_MC_SDTR_80;
+ else if ((adw->features & ADW_ULTRA2) != 0)
+ mc_sdtr = ADW_MC_SDTR_40;
+ else
+ mc_sdtr = ADW_MC_SDTR_20;
+ adw_set_user_sdtr(adw, tid, mc_sdtr);
+ }
+ adw->user_tagenb = adw_lram_read_16(adw, ADW_MC_TAGQNG_ABLE);
+ }
+
+ /*
+ * Load the Microcode.
+ *
+ * Assume the following compressed format of the microcode buffer:
+ *
+ * 253 word (506 byte) table indexed by byte code followed
+ * by the following byte codes:
+ *
+ * 1-Byte Code:
+ * 00: Emit word 0 in table.
+ * 01: Emit word 1 in table.
+ * .
+ * FD: Emit word 253 in table.
+ *
+ * Multi-Byte Code:
+ * FD RESEVED
+ *
+ * FE WW WW: (3 byte code)
+ * Word to emit is the next word WW WW.
+ * FF BB WW WW: (4 byte code)
+ * Emit BB count times next word WW WW.
+ *
+ */
+ bytes_downloaded = 0;
+ word_table = (const u_int16_t *)adw->mcode_data->mcode_buf;
+ byte_codes = (const u_int8_t *)&word_table[253];
+ byte_codes_end = adw->mcode_data->mcode_buf
+ + adw->mcode_data->mcode_size;
+ adw_outw(adw, ADW_RAM_ADDR, 0);
+ while (byte_codes < byte_codes_end) {
+ if (*byte_codes == 0xFF) {
+ u_int16_t value;
+
+ value = byte_codes[2]
+ | byte_codes[3] << 8;
+ adw_set_multi_2(adw, ADW_RAM_DATA,
+ value, byte_codes[1]);
+ bytes_downloaded += byte_codes[1];
+ byte_codes += 4;
+ } else if (*byte_codes == 0xFE) {
+ u_int16_t value;
+
+ value = byte_codes[1]
+ | byte_codes[2] << 8;
+ adw_outw(adw, ADW_RAM_DATA, value);
+ bytes_downloaded++;
+ byte_codes += 3;
+ } else {
+ adw_outw(adw, ADW_RAM_DATA, word_table[*byte_codes]);
+ bytes_downloaded++;
+ byte_codes++;
+ }
+ }
+ /* Convert from words to bytes */
+ bytes_downloaded *= 2;
+
+ /*
+ * Clear the rest of LRAM.
+ */
+ for (addr = bytes_downloaded; addr < adw->memsize; addr += 2)
+ adw_outw(adw, ADW_RAM_DATA, 0);
+
+ /*
+ * Verify the microcode checksum.
+ */
+ checksum = 0;
+ adw_outw(adw, ADW_RAM_ADDR, 0);
+ for (addr = 0; addr < bytes_downloaded; addr += 2)
+ checksum += adw_inw(adw, ADW_RAM_DATA);
+
+ if (checksum != adw->mcode_data->mcode_chksum) {
+ printf("%s: Firmware load failed!\n", adw_name(adw));
+ return (EIO);
+ }
+
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (addr = 0; addr < ADW_MC_BIOSLEN; addr++)
+ adw_lram_write_8(adw, addr + ADW_MC_BIOSLEN, biosmem[addr]);
+
+ /*
+ * Calculate and write the microcode code checksum to
+ * the microcode code checksum location.
+ */
+ addr = adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR);
+ end_addr = adw_lram_read_16(adw, ADW_MC_CODE_END_ADDR);
+ checksum = 0;
+ adw_outw(adw, ADW_RAM_ADDR, addr);
+ for (; addr < end_addr; addr += 2)
+ checksum += adw_inw(adw, ADW_RAM_DATA);
+ adw_lram_write_16(adw, ADW_MC_CODE_CHK_SUM, checksum);
+
+ /*
+ * Tell the microcode what kind of chip it's running on.
+ */
+ adw_lram_write_16(adw, ADW_MC_CHIP_TYPE, adw->chip);
+
+ /*
+ * Leave WDTR and SDTR negotiation disabled until the XPT has
+ * informed us of device capabilities, but do set the desired
+ * user rates in case we receive an SDTR request from the target
+ * before we negotiate. We turn on tagged queuing at the microcode
+ * level for all devices, and modulate this on a per command basis.
+ */
+ adw_lram_write_16(adw, ADW_MC_SDTR_SPEED1, adw->user_sdtr[0]);
+ adw_lram_write_16(adw, ADW_MC_SDTR_SPEED2, adw->user_sdtr[1]);
+ adw_lram_write_16(adw, ADW_MC_SDTR_SPEED3, adw->user_sdtr[2]);
+ adw_lram_write_16(adw, ADW_MC_SDTR_SPEED4, adw->user_sdtr[3]);
+ adw_lram_write_16(adw, ADW_MC_DISC_ENABLE, adw->user_discenb);
+ for (tid = 0; tid < ADW_MAX_TID; tid++) {
+ /* Cam limits the maximum number of commands for us */
+ adw_lram_write_8(adw, ADW_MC_NUMBER_OF_MAX_CMD + tid,
+ adw->max_acbs);
+ }
+ adw_lram_write_16(adw, ADW_MC_TAGQNG_ABLE, ~0);
+
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started.
+ */
+ adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG0,
+ ADW_SCSI_CFG0_PARITY_EN|ADW_SCSI_CFG0_SEL_TMO_LONG|
+ ADW_SCSI_CFG0_OUR_ID_EN|adw->initiator_id);
+
+ /*
+ * Tell the MC about the memory size that
+ * was setup by the probe code.
+ */
+ adw_lram_write_16(adw, ADW_MC_DEFAULT_MEM_CFG,
+ adw_inb(adw, ADW_MEM_CFG) & ADW_MEM_CFG_RAM_SZ_MASK);
+
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ scsicfg1 = adw_inw(adw, ADW_SCSI_CFG1);
+
+ /*
+ * 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_inw(adw, ADW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ printf("%s: Illegal Cable Config!\n", adw_name(adw));
+ printf("%s: Internal cable is reversed!\n", adw_name(adw));
+ return (EIO);
+ }
+
+ /*
+ * If this is a differential board and a single-ended device
+ * is attached to one of the connectors, return an error.
+ */
+ if ((adw->features & ADW_ULTRA) != 0) {
+ if ((scsicfg1 & ADW_SCSI_CFG1_DIFF_MODE) != 0
+ && (scsicfg1 & ADW_SCSI_CFG1_DIFF_SENSE) == 0) {
+ printf("%s: A Single Ended Device is attached to our "
+ "differential bus!\n", adw_name(adw));
+ return (EIO);
+ }
+ } else {
+ if ((scsicfg1 & ADW2_SCSI_CFG1_DEV_DETECT_HVD) != 0) {
+ printf("%s: A High Voltage Differential Device "
+ "is attached to this controller.\n",
+ adw_name(adw));
+ printf("%s: HVD devices are not supported.\n",
+ adw_name(adw));
+ return (EIO);
+ }
+ }
+
+ /*
+ * Perform automatic termination control if desired.
+ */
+ if ((adw->features & ADW_ULTRA2) != 0) {
+ u_int cable_det;
+
+ /*
+ * Ultra2 Chips require termination disabled to
+ * detect cable presence.
+ */
+ adw_outw(adw, ADW_SCSI_CFG1,
+ scsicfg1 | ADW2_SCSI_CFG1_DIS_TERM_DRV);
+ cable_det = adw_inw(adw, ADW_SCSI_CFG1);
+ adw_outw(adw, ADW_SCSI_CFG1, scsicfg1);
+
+ /* SE Termination first if auto-term has been specified */
+ if ((term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) == 0) {
+
+ /*
+ * For all SE cable configurations, high byte
+ * termination is enabled.
+ */
+ term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
+ if ((cable_det & ADW_SCSI_CFG1_INT8_MASK) != 0
+ || (cable_det & ADW_SCSI_CFG1_INT16_MASK) != 0) {
+ /*
+ * If either cable is not present, the
+ * low byte must be terminated as well.
+ */
+ term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;
+ }
+ }
+
+ /* LVD auto-term */
+ if ((term_scsicfg1 & ADW2_SCSI_CFG1_TERM_CTL_LVD) == 0
+ && (term_scsicfg1 & ADW2_SCSI_CFG1_DIS_TERM_DRV) == 0) {
+ /*
+ * If both cables are installed, termination
+ * is disabled. Otherwise it is enabled.
+ */
+ if ((cable_det & ADW2_SCSI_CFG1_EXTLVD_MASK) != 0
+ || (cable_det & ADW2_SCSI_CFG1_INTLVD_MASK) != 0) {
+
+ term_scsicfg1 |= ADW2_SCSI_CFG1_TERM_CTL_LVD;
+ }
+ }
+ term_scsicfg1 &= ~ADW2_SCSI_CFG1_DIS_TERM_DRV;
+ } else {
+ /* Ultra Controller Termination */
+ if ((term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) == 0) {
+ int cable_count;
+ int wide_cable_count;
+
+ cable_count = 0;
+ wide_cable_count = 0;
+ if ((scsicfg1 & ADW_SCSI_CFG1_INT16_MASK) == 0) {
+ cable_count++;
+ wide_cable_count++;
+ }
+ if ((scsicfg1 & ADW_SCSI_CFG1_INT8_MASK) == 0)
+ cable_count++;
+
+ /* There is only one external port */
+ if ((scsicfg1 & ADW_SCSI_CFG1_EXT16_MASK) == 0) {
+ cable_count++;
+ wide_cable_count++;
+ } else if ((scsicfg1 & ADW_SCSI_CFG1_EXT8_MASK) == 0)
+ cable_count++;
+
+ if (cable_count == 3) {
+ printf("%s: Illegal Cable Config!\n",
+ adw_name(adw));
+ printf("%s: Only Two Ports may be used at "
+ "a time!\n", adw_name(adw));
+ } else if (cable_count <= 1) {
+ /*
+ * At least two out of three cables missing.
+ * Terminate both bytes.
+ */
+ term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H
+ | ADW_SCSI_CFG1_TERM_CTL_L;
+ } else if (wide_cable_count <= 1) {
+ /* No two 16bit cables present. High on. */
+ term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
+ }
+ }
+ }
+
+ /* Tell the user about our decission */
+ switch (term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) {
+ case ADW_SCSI_CFG1_TERM_CTL_MASK:
+ printf("High & Low SE Term Enabled, ");
+ break;
+ case ADW_SCSI_CFG1_TERM_CTL_H:
+ printf("High SE Termination Enabled, ");
+ break;
+ case ADW_SCSI_CFG1_TERM_CTL_L:
+ printf("Low SE Term Enabled, ");
+ break;
+ default:
+ break;
+ }
+
+ if ((adw->features & ADW_ULTRA2) != 0
+ && (term_scsicfg1 & ADW2_SCSI_CFG1_TERM_CTL_LVD) != 0)
+ printf("LVD Term Enabled, ");
+
+ /*
+ * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+ * set 'scsicfg1'. The TERM_POL bit does not need to be
+ * referenced, because the hardware internally inverts
+ * the Termination High and Low bits if TERM_POL is set.
+ */
+ if ((adw->features & ADW_ULTRA2) != 0) {
+ term_scsicfg1 = ~term_scsicfg1;
+ term_scsicfg1 &= ADW_SCSI_CFG1_TERM_CTL_MASK
+ | ADW2_SCSI_CFG1_TERM_CTL_LVD;
+ scsicfg1 &= ~(ADW_SCSI_CFG1_TERM_CTL_MASK
+ |ADW2_SCSI_CFG1_TERM_CTL_LVD
+ |ADW_SCSI_CFG1_BIG_ENDIAN
+ |ADW_SCSI_CFG1_TERM_POL
+ |ADW2_SCSI_CFG1_DEV_DETECT);
+ scsicfg1 |= term_scsicfg1;
+ } else {
+ term_scsicfg1 = ~term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK;
+ scsicfg1 &= ~ADW_SCSI_CFG1_TERM_CTL_MASK;
+ scsicfg1 |= term_scsicfg1 | ADW_SCSI_CFG1_TERM_CTL_MANUAL;
+ scsicfg1 |= ADW_SCSI_CFG1_FLTR_DISABLE;
+ }
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG1, scsicfg1);
+
+ /*
+ * Only accept selections on our initiator target id.
+ * This may change in target mode scenarios...
+ */
+ adw_lram_write_16(adw, ADW_MC_DEFAULT_SEL_MASK,
+ (0x01 << adw->initiator_id));
+
+ /*
+ * Tell the microcode where it can find our
+ * Initiator Command Queue (ICQ). It is
+ * currently empty hence the "stopper" address.
+ */
+ adw->commandq = adw->free_carriers;
+ adw->free_carriers = carrierbotov(adw, adw->commandq->next_ba);
+ adw->commandq->next_ba = ADW_CQ_STOPPER;
+ adw_lram_write_32(adw, ADW_MC_ICQ, adw->commandq->carr_ba);
+
+ /*
+ * Tell the microcode where it can find our
+ * Initiator Response Queue (IRQ). It too
+ * is currently empty.
+ */
+ adw->responseq = adw->free_carriers;
+ adw->free_carriers = carrierbotov(adw, adw->responseq->next_ba);
+ adw->responseq->next_ba = ADW_CQ_STOPPER;
+ adw_lram_write_32(adw, ADW_MC_IRQ, adw->responseq->carr_ba);
+
+ adw_outb(adw, ADW_INTR_ENABLES,
+ ADW_INTR_ENABLE_HOST_INTR|ADW_INTR_ENABLE_GLOBAL_INTR);
+
+ adw_outw(adw, ADW_PC, adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR));
+
+ return (0);
+}
+
+void
+adw_set_user_sdtr(struct adw_softc *adw, u_int tid, u_int mc_sdtr)
+{
+ adw->user_sdtr[ADW_TARGET_GROUP(tid)] &= ~ADW_TARGET_GROUP_MASK(tid);
+ adw->user_sdtr[ADW_TARGET_GROUP(tid)] |=
+ mc_sdtr << ADW_TARGET_GROUP_SHIFT(tid);
+}
+
+u_int
+adw_get_user_sdtr(struct adw_softc *adw, u_int tid)
+{
+ u_int mc_sdtr;
+
+ mc_sdtr = adw->user_sdtr[ADW_TARGET_GROUP(tid)];
+ mc_sdtr &= ADW_TARGET_GROUP_MASK(tid);
+ mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid);
+ return (mc_sdtr);
+}
+
+void
+adw_set_chip_sdtr(struct adw_softc *adw, u_int tid, u_int sdtr)
+{
+ u_int mc_sdtr_offset;
+ u_int mc_sdtr;
+
+ mc_sdtr_offset = ADW_MC_SDTR_SPEED1;
+ mc_sdtr_offset += ADW_TARGET_GROUP(tid) * 2;
+ mc_sdtr = adw_lram_read_16(adw, mc_sdtr_offset);
+ mc_sdtr &= ~ADW_TARGET_GROUP_MASK(tid);
+ mc_sdtr |= sdtr << ADW_TARGET_GROUP_SHIFT(tid);
+ adw_lram_write_16(adw, mc_sdtr_offset, mc_sdtr);
+}
+
+u_int
+adw_get_chip_sdtr(struct adw_softc *adw, u_int tid)
+{
+ u_int mc_sdtr_offset;
+ u_int mc_sdtr;
+
+ mc_sdtr_offset = ADW_MC_SDTR_SPEED1;
+ mc_sdtr_offset += ADW_TARGET_GROUP(tid) * 2;
+ mc_sdtr = adw_lram_read_16(adw, mc_sdtr_offset);
+ mc_sdtr &= ADW_TARGET_GROUP_MASK(tid);
+ mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid);
+ return (mc_sdtr);
+}
+
+u_int
+adw_find_sdtr(struct adw_softc *adw, u_int period)
+{
+ int i;
+
+ i = 0;
+ if ((adw->features & ADW_DT) == 0)
+ i = ADW_MC_SDTR_OFFSET_ULTRA2;
+ if ((adw->features & ADW_ULTRA2) == 0)
+ i = ADW_MC_SDTR_OFFSET_ULTRA;
+ if (period == 0)
+ return ADW_MC_SDTR_ASYNC;
+
+ for (; i < adw_num_syncrates; i++) {
+ if (period <= adw_syncrates[i].period)
+ return (adw_syncrates[i].mc_sdtr);
+ }
+ return ADW_MC_SDTR_ASYNC;
+}
+
+u_int
+adw_find_period(struct adw_softc *adw, u_int mc_sdtr)
+{
+ int i;
+
+ for (i = 0; i < adw_num_syncrates; i++) {
+ if (mc_sdtr == adw_syncrates[i].mc_sdtr)
+ break;
+ }
+ return (adw_syncrates[i].period);
+}
+
+u_int
+adw_hshk_cfg_period_factor(u_int tinfo)
+{
+ tinfo &= ADW_HSHK_CFG_RATE_MASK;
+ tinfo >>= ADW_HSHK_CFG_RATE_SHIFT;
+ if (tinfo == 0x11)
+ /* 80MHz/DT */
+ return (9);
+ else if (tinfo == 0x10)
+ /* 40MHz */
+ return (10);
+ else
+ return (((tinfo * 25) + 50) / 4);
+}
+
+/*
+ * Send an idle command to the chip and wait for completion.
+ */
+adw_idle_cmd_status_t
+adw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter)
+{
+ u_int timeout;
+ adw_idle_cmd_status_t status;
+ int s;
+
+ s = splcam();
+
+ /*
+ * Clear the idle command status which is set by the microcode
+ * to a non-zero value to indicate when the command is completed.
+ */
+ adw_lram_write_16(adw, ADW_MC_IDLE_CMD_STATUS, 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_lram_write_32(adw, ADW_MC_IDLE_CMD_PARAMETER, parameter);
+ adw_lram_write_16(adw, ADW_MC_IDLE_CMD, cmd);
+
+ /*
+ * Tickle the RISC to tell it to process the idle command.
+ */
+ adw_tickle_risc(adw, ADW_TICKLE_B);
+
+ /* Wait for up to 10 seconds for the command to complete */
+ timeout = 5000000;
+ while (--timeout) {
+ status = adw_lram_read_16(adw, ADW_MC_IDLE_CMD_STATUS);
+ if (status != 0)
+ break;
+ DELAY(20);
+ }
+
+ if (timeout == 0)
+ panic("%s: Idle Command Timed Out!\n", adw_name(adw));
+ splx(s);
+ return (status);
+}
diff --git a/sys/dev/advansys/adwlib.h b/sys/dev/advansys/adwlib.h
new file mode 100644
index 0000000..5383447
--- /dev/null
+++ b/sys/dev/advansys/adwlib.h
@@ -0,0 +1,878 @@
+/*
+ * Definitions for low level routines and data structures
+ * for the Advanced Systems Inc. SCSI controllers chips.
+ *
+ * Copyright (c) 1998, 1999, 2000 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * 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.
+ */
+
+#ifndef _ADWLIB_H_
+#define _ADWLIB_H_
+
+#include "opt_adw.h"
+
+#include <dev/advansys/adwmcode.h>
+
+#define ADW_DEF_MAX_HOST_QNG 253
+#define ADW_DEF_MIN_HOST_QNG 16
+#define ADW_DEF_MAX_DVC_QNG 63
+#define ADW_DEF_MIN_DVC_QNG 4
+
+#define ADW_MAX_TID 15
+#define ADW_MAX_LUN 7
+
+#define ADW_ALL_TARGETS 0xFFFF
+
+#define ADW_TARGET_GROUP(tid) ((tid) & ~0x3)
+#define ADW_TARGET_GROUP_SHIFT(tid) (((tid) & 0x3) * 4)
+#define ADW_TARGET_GROUP_MASK(tid) (0xF << ADW_TARGET_GROUP_SHIFT(tid))
+
+/*
+ * Board Register offsets.
+ */
+#define ADW_INTR_STATUS_REG 0x0000
+#define ADW_INTR_STATUS_INTRA 0x01
+#define ADW_INTR_STATUS_INTRB 0x02
+#define ADW_INTR_STATUS_INTRC 0x04
+#define ADW_INTR_STATUS_INTRALL 0x07
+
+
+#define ADW_SIGNATURE_WORD 0x0000
+#define ADW_CHIP_ID_WORD 0x04C1
+
+#define ADW_SIGNATURE_BYTE 0x0001
+#define ADW_CHIP_ID_BYTE 0x25
+
+#define ADW_INTR_ENABLES 0x0002 /*8 bit */
+#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_CTRL_REG 0x0002 /*16 bit*/
+#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 0x00C3
+#define ADW_CTRL_REG_CMD_RD_PCI_CFG 0x00C2
+
+#define ADW_RAM_ADDR 0x0004
+#define ADW_RAM_DATA 0x0006
+
+#define ADW_RISC_CSR 0x000A
+#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_SCSI_CFG0 0x000C
+#define ADW_SCSI_CFG0_TIMER_MODEAB 0xC000 /*
+ * Watchdog, Second,
+ * and Selto timer CFG
+ */
+#define ADW_SCSI_CFG0_PARITY_EN 0x2000
+#define ADW_SCSI_CFG0_EVEN_PARITY 0x1000
+#define ADW_SCSI_CFG0_WD_LONG 0x0800 /*
+ * Watchdog Interval,
+ * 1: 57 min, 0: 13 sec
+ */
+#define ADW_SCSI_CFG0_QUEUE_128 0x0400 /*
+ * Queue Size,
+ * 1: 128 byte,
+ * 0: 64 byte
+ */
+#define ADW_SCSI_CFG0_PRIM_MODE 0x0100
+#define ADW_SCSI_CFG0_SCAM_EN 0x0080
+#define ADW_SCSI_CFG0_SEL_TMO_LONG 0x0040 /*
+ * Sel/Resel Timeout,
+ * 1: 400 ms,
+ * 0: 1.6 ms
+ */
+#define ADW_SCSI_CFG0_CFRM_ID 0x0020 /* SCAM id sel. */
+#define ADW_SCSI_CFG0_OUR_ID_EN 0x0010
+#define ADW_SCSI_CFG0_OUR_ID 0x000F
+
+
+#define ADW_SCSI_CFG1 0x000E
+#define ADW_SCSI_CFG1_BIG_ENDIAN 0x8000
+#define ADW_SCSI_CFG1_TERM_POL 0x2000
+#define ADW_SCSI_CFG1_SLEW_RATE 0x1000
+#define ADW_SCSI_CFG1_FILTER_MASK 0x0C00
+#define ADW_SCSI_CFG1_FLTR_DISABLE 0x0000
+#define ADW_SCSI_CFG1_FLTR_11_TO_20NS 0x0800
+#define ADW_SCSI_CFG1_FLTR_21_TO_39NS 0x0C00
+#define ADW_SCSI_CFG1_DIS_ACTIVE_NEG 0x0200
+#define ADW_SCSI_CFG1_DIFF_MODE 0x0100
+#define ADW_SCSI_CFG1_DIFF_SENSE 0x0080
+#define ADW_SCSI_CFG1_TERM_CTL_MANUAL 0x0040 /* Global Term Switch */
+#define ADW_SCSI_CFG1_TERM_CTL_MASK 0x0030
+#define ADW_SCSI_CFG1_TERM_CTL_H 0x0020 /* Enable SCSI-H */
+#define ADW_SCSI_CFG1_TERM_CTL_L 0x0010 /* Enable SCSI-L */
+#define ADW_SCSI_CFG1_CABLE_DETECT 0x000F
+#define ADW_SCSI_CFG1_EXT16_MASK 0x0008 /* Ext16 cable pres */
+#define ADW_SCSI_CFG1_EXT8_MASK 0x0004 /* Ext8 cable pres */
+#define ADW_SCSI_CFG1_INT8_MASK 0x0002 /* Int8 cable pres */
+#define ADW_SCSI_CFG1_INT16_MASK 0x0001 /* Int16 cable pres */
+#define ADW_SCSI_CFG1_ILLEGAL_CABLE_CONF_A_MASK \
+(ADW_SCSI_CFG1_EXT16_MASK|ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_INT16_MASK)
+#define ADW_SCSI_CFG1_ILLEGAL_CABLE_CONF_B_MASK \
+(ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_INT16_MASK)
+
+/*
+ * Addendum for ASC-38C0800 Chip
+ */
+#define ADW2_SCSI_CFG1_DIS_TERM_DRV 0x4000 /*
+ * The Terminators
+ * must be disabled
+ * in order to detect
+ * cable presence
+ */
+
+#define ADW2_SCSI_CFG1_DEV_DETECT 0x1C00
+#define ADW2_SCSI_CFG1_DEV_DETECT_HVD 0x1000
+#define ADW2_SCSI_CFG1_DEV_DETECT_LVD 0x0800
+#define ADW2_SCSI_CFG1_DEV_DETECT_SE 0x0400
+
+#define ADW2_SCSI_CFG1_TERM_CTL_LVD 0x00C0 /* Ultra2 Only */
+#define ADW2_SCSI_CFG1_TERM_LVD_HI 0x0080
+#define ADW2_SCSI_CFG1_TERM_LVD_LO 0x0040
+#define ADW2_SCSI_CFG1_EXTLVD_MASK 0x0008 /* ExtLVD cable pres */
+#define ADW2_SCSI_CFG1_INTLVD_MASK 0x0004 /* IntLVD cable pres */
+
+#define ADW_MEM_CFG 0x0010
+#define ADW_MEM_CFG_BIOS_EN 0x40
+#define ADW_MEM_CFG_FAST_EE_CLK 0x20 /* Diagnostic Bit */
+#define ADW_MEM_CFG_RAM_SZ_MASK 0x1C /* RISC RAM Size */
+#define ADW_MEM_CFG_RAM_SZ_2KB 0x00
+#define ADW_MEM_CFG_RAM_SZ_4KB 0x04
+#define ADW_MEM_CFG_RAM_SZ_8KB 0x08
+#define ADW_MEM_CFG_RAM_SZ_16KB 0x0C
+#define ADW_MEM_CFG_RAM_SZ_32KB 0x10
+#define ADW_MEM_CFG_RAM_SZ_64KB 0x14
+
+#define ADW_GPIO_CNTL 0x0011
+#define ADW_GPIO_DATA 0x0012
+
+#define ADW_COMMA 0x0014
+#define ADW_COMMB 0x0018
+
+#define ADW_EEP_CMD 0x001A
+#define ADW_EEP_CMD_READ 0x0080 /* or in address */
+#define ADW_EEP_CMD_WRITE 0x0040 /* or in address */
+#define ADW_EEP_CMD_WRITE_ABLE 0x0030
+#define ADW_EEP_CMD_WRITE_DISABLE 0x0000
+#define ADW_EEP_CMD_DONE 0x0200
+#define ADW_EEP_CMD_DONE_ERR 0x0001
+#define ADW_EEP_DELAY_MS 100
+
+#define ADW_EEP_DATA 0x001C
+
+#define ADW_DMA_CFG0 0x0020
+#define ADW_DMA_CFG0_BC_THRESH_ENB 0x80
+#define ADW_DMA_CFG0_FIFO_THRESH 0x70
+#define ADW_DMA_CFG0_FIFO_THRESH_16B 0x00
+#define ADW_DMA_CFG0_FIFO_THRESH_32B 0x20
+#define ADW_DMA_CFG0_FIFO_THRESH_48B 0x30
+#define ADW_DMA_CFG0_FIFO_THRESH_64B 0x40
+#define ADW_DMA_CFG0_FIFO_THRESH_80B 0x50
+#define ADW_DMA_CFG0_FIFO_THRESH_96B 0x60
+#define ADW_DMA_CFG0_FIFO_THRESH_112B 0x70
+#define ADW_DMA_CFG0_START_CTL_MASK 0x0C
+#define ADW_DMA_CFG0_START_CTL_TH 0x00 /* Start on thresh */
+#define ADW_DMA_CFG0_START_CTL_IDLE 0x04 /* Start when idle */
+#define ADW_DMA_CFG0_START_CTL_TH_IDLE 0x08 /* Either */
+#define ADW_DMA_CFG0_START_CTL_EM_FU 0x0C /* Start on full/empty */
+#define ADW_DMA_CFG0_READ_CMD_MASK 0x03
+#define ADW_DMA_CFG0_READ_CMD_MR 0x00
+#define ADW_DMA_CFG0_READ_CMD_MRL 0x02
+#define ADW_DMA_CFG0_READ_CMD_MRM 0x03
+
+#define ADW_TICKLE 0x0022
+#define ADW_TICKLE_NOP 0x00
+#define ADW_TICKLE_A 0x01
+#define ADW_TICKLE_B 0x02
+#define ADW_TICKLE_C 0x03
+
+/* Program Counter */
+#define ADW_PC 0x2A
+
+#define ADW_SCSI_CTRL 0x0034
+#define ADW_SCSI_CTRL_RSTOUT 0x2000
+
+/*
+ * ASC-38C0800 RAM BIST Register bit definitions
+ */
+#define ADW_RAM_BIST 0x0038
+#define ADW_RAM_BIST_RAM_TEST_MODE 0x80
+#define ADW_RAM_BIST_PRE_TEST_MODE 0x40
+#define ADW_RAM_BIST_NORMAL_MODE 0x00
+#define ADW_RAM_BIST_RAM_TEST_DONE 0x10
+#define ADW_RAM_BIST_RAM_TEST_STATUS 0x0F
+#define ADW_RAM_BIST_RAM_TEST_HOST_ERR 0x08
+#define ADW_RAM_BIST_RAM_TEST_RAM_ERR 0x04
+#define ADW_RAM_BIST_RAM_TEST_RISC_ERR 0x02
+#define ADW_RAM_BIST_RAM_TEST_SCSI_ERR 0x01
+#define ADW_RAM_BIST_RAM_TEST_SUCCESS 0x00
+#define ADW_RAM_BIST_PRE_TEST_VALUE 0x05
+#define ADW_RAM_BIST_NORMAL_VALUE 0x00
+#define ADW_PLL_TEST 0x0039
+
+#define ADW_SCSI_RESET_HOLD_TIME_US 60
+
+/* LRAM Constants */
+#define ADW_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
+#define ADW_3550_IOLEN 0x40 /* I/O Port Range in bytes */
+
+#define ADW_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
+#define ADW_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
+
+#define ADW_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
+#define ADW_38C1600_IOLEN 0x100 /* I/O Port Range in bytes */
+#define ADW_38C1600_MEMLEN 0x1000 /* Memory Range 4KB */
+
+#define ADW_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
+#define ADW_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
+
+#define PCI_ID_ADVANSYS_3550 0x230010CD00000000ull
+#define PCI_ID_ADVANSYS_38C0800_REV1 0x250010CD00000000ull
+#define PCI_ID_ADVANSYS_38C1600_REV1 0x270010CD00000000ull
+#define PCI_ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull
+#define PCI_ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull
+
+/* ====================== SCSI Request Structures =========================== */
+
+#define ADW_NO_OF_SG_PER_BLOCK 15
+
+/*
+ * Although the adapter can deal with S/G lists of indefinite size,
+ * we limit the list to 30 to conserve space as the kernel can only send
+ * us buffers of at most 64KB currently.
+ */
+#define ADW_SG_BLOCKCNT 2
+#define ADW_SGSIZE (ADW_NO_OF_SG_PER_BLOCK * ADW_SG_BLOCKCNT)
+
+struct adw_sg_elm {
+ u_int32_t sg_addr;
+ u_int32_t sg_count;
+};
+
+/* sg block structure used by the microcode */
+struct adw_sg_block {
+ u_int8_t reserved1;
+ u_int8_t reserved2;
+ u_int8_t reserved3;
+ u_int8_t sg_cnt; /* Valid entries in this block */
+ u_int32_t sg_busaddr_next; /* link to the next sg block */
+ struct adw_sg_elm sg_list[ADW_NO_OF_SG_PER_BLOCK];
+};
+
+/* Structure representing a single allocation block of adw sg blocks */
+struct sg_map_node {
+ bus_dmamap_t sg_dmamap;
+ bus_addr_t sg_physaddr;
+ struct adw_sg_block* sg_vaddr;
+ SLIST_ENTRY(sg_map_node) links;
+};
+
+typedef enum {
+ QHSTA_NO_ERROR = 0x00,
+ QHSTA_M_SEL_TIMEOUT = 0x11,
+ QHSTA_M_DATA_OVER_RUN = 0x12,
+ QHSTA_M_UNEXPECTED_BUS_FREE = 0x13,
+ QHSTA_M_QUEUE_ABORTED = 0x15,
+ QHSTA_M_SXFR_SDMA_ERR = 0x16, /* SCSI DMA Error */
+ QHSTA_M_SXFR_SXFR_PERR = 0x17, /* SCSI Bus Parity Error */
+ QHSTA_M_RDMA_PERR = 0x18, /* RISC PCI DMA parity error */
+ QHSTA_M_SXFR_OFF_UFLW = 0x19, /* Offset Underflow */
+ QHSTA_M_SXFR_OFF_OFLW = 0x20, /* Offset Overflow */
+ QHSTA_M_SXFR_WD_TMO = 0x21, /* Watchdog Timeout */
+ QHSTA_M_SXFR_DESELECTED = 0x22, /* Deselected */
+ QHSTA_M_SXFR_XFR_PH_ERR = 0x24, /* Transfer Phase Error */
+ QHSTA_M_SXFR_UNKNOWN_ERROR = 0x25, /* SXFR_STATUS Unknown Error */
+ QHSTA_M_SCSI_BUS_RESET = 0x30, /* Request aborted from SBR */
+ QHSTA_M_SCSI_BUS_RESET_UNSOL= 0x31, /* Request aborted from unsol. SBR*/
+ QHSTA_M_BUS_DEVICE_RESET = 0x32, /* Request aborted from BDR */
+ QHSTA_M_DIRECTION_ERR = 0x35, /* Data Phase mismatch */
+ QHSTA_M_DIRECTION_ERR_HUNG = 0x36, /* Data Phase mismatch - bus hang */
+ QHSTA_M_WTM_TIMEOUT = 0x41,
+ QHSTA_M_BAD_CMPL_STATUS_IN = 0x42,
+ QHSTA_M_NO_AUTO_REQ_SENSE = 0x43,
+ QHSTA_M_AUTO_REQ_SENSE_FAIL = 0x44,
+ QHSTA_M_INVALID_DEVICE = 0x45, /* Bad target ID */
+ QHSTA_M_FROZEN_TIDQ = 0x46, /* TID Queue frozen. */
+ QHSTA_M_SGBACKUP_ERROR = 0x47 /* Scatter-Gather backup error */
+} host_status_t;
+
+typedef enum {
+ QD_NO_STATUS = 0x00, /* Request not completed yet. */
+ QD_NO_ERROR = 0x01,
+ QD_ABORTED_BY_HOST = 0x02,
+ QD_WITH_ERROR = 0x04
+} done_status_t;
+
+/*
+ * Microcode request structure
+ *
+ * All fields in this structure are used by the microcode so their
+ * size and ordering cannot be changed.
+ */
+struct adw_scsi_req_q {
+ u_int8_t cntl; /* Ucode flags and state. */
+ u_int8_t target_cmd;
+ u_int8_t target_id; /* Device target identifier. */
+ u_int8_t target_lun; /* Device target logical unit number. */
+ u_int32_t data_addr; /* Data buffer physical address. */
+ u_int32_t data_cnt; /* Data count. Ucode sets to residual. */
+ u_int32_t sense_baddr; /* Sense buffer bus address. */
+ u_int32_t carrier_baddr; /* Carrier bus address. */
+ u_int8_t mflag; /* microcode flag field. */
+ u_int8_t sense_len; /* Auto-sense length. Residual on complete. */
+ u_int8_t cdb_len; /* SCSI CDB length. */
+ u_int8_t scsi_cntl; /* SCSI command control flags (tags, nego) */
+#define ADW_QSC_NO_DISC 0x01
+#define ADW_QSC_NO_TAGMSG 0x02
+#define ADW_QSC_NO_SYNC 0x04
+#define ADW_QSC_NO_WIDE 0x08
+#define ADW_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR */
+#define ADW_QSC_SIMPLE_Q_TAG 0x00
+#define ADW_QSC_HEAD_OF_Q_TAG 0x40
+#define ADW_QSC_ORDERED_Q_TAG 0x80
+ u_int8_t done_status; /* Completion status. */
+ u_int8_t scsi_status; /* SCSI status byte. */
+ u_int8_t host_status; /* Ucode host status. */
+ u_int8_t sg_wk_ix; /* Microcode working SG index. */
+ u_int8_t cdb[12]; /* SCSI command block. */
+ u_int32_t sg_real_addr; /* SG list physical address. */
+ u_int32_t scsi_req_baddr; /* Bus address of this structure. */
+ u_int32_t sg_wk_data_cnt; /* Saved data count at disconnection. */
+ /*
+ * The 'tokens' placed in these two fields are
+ * used to identify the scsi request and the next
+ * carrier in the response queue, *not* physical
+ * addresses. This driver uses byte offsets for
+ * portability and speed of mapping back to either
+ * a virtual or physical address.
+ */
+ u_int32_t scsi_req_bo; /* byte offset of this structure */
+ u_int32_t carrier_bo; /* byte offst of our carrier. */
+};
+
+typedef enum {
+ ACB_FREE = 0x00,
+ ACB_ACTIVE = 0x01,
+ ACB_RELEASE_SIMQ = 0x02,
+ ACB_RECOVERY_ACB = 0x04
+} acb_state;
+
+struct acb {
+ struct adw_scsi_req_q queue;
+ bus_dmamap_t dmamap;
+ acb_state state;
+ union ccb *ccb;
+ struct adw_sg_block* sg_blocks;
+ bus_addr_t sg_busaddr;
+ struct scsi_sense_data sense_data;
+ SLIST_ENTRY(acb) links;
+};
+
+/*
+ * 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 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.
+ *
+ * Default values are maintained in a_init.c in the structure
+ * Default_EEPROM_Config.
+ */
+struct adw_eeprom
+{
+ u_int16_t cfg_lsw; /* 00 power up initialization */
+#define ADW_EEPROM_BIG_ENDIAN 0x8000
+#define ADW_EEPROM_BIOS_ENABLE 0x4000
+#define ADW_EEPROM_TERM_POL 0x2000
+#define ADW_EEPROM_CIS_LD 0x1000
+
+ /* bit 13 set - Term Polarity Control */
+ /* bit 14 set - BIOS Enable */
+ /* bit 15 set - Big Endian Mode */
+ u_int16_t cfg_msw; /* unused */
+ u_int16_t disc_enable;
+ u_int16_t wdtr_able;
+ union {
+ /*
+ * sync enable bits for UW cards,
+ * actual sync rate for TID 0-3
+ * on U2W and U160 cards.
+ */
+ u_int16_t sync_enable;
+ u_int16_t sdtr1;
+ } sync1;
+ u_int16_t start_motor;
+ u_int16_t tagqng_able;
+ u_int16_t bios_scan;
+ u_int16_t scam_tolerant;
+
+ u_int8_t adapter_scsi_id;
+ u_int8_t bios_boot_delay;
+
+ u_int8_t scsi_reset_delay;
+ u_int8_t bios_id_lun; /* high nibble is lun */
+ /* low nibble is scsi id */
+
+ u_int8_t termination_se; /* 0 - automatic */
+#define ADW_EEPROM_TERM_AUTO 0
+#define ADW_EEPROM_TERM_OFF 1
+#define ADW_EEPROM_TERM_HIGH_ON 2
+#define ADW_EEPROM_TERM_BOTH_ON 3
+
+ u_int8_t termination_lvd;
+ u_int16_t bios_ctrl;
+#define ADW_BIOS_INIT_DIS 0x0001 /* Don't act as initiator */
+#define ADW_BIOS_EXT_TRANS 0x0002 /* > 1 GB support */
+#define ADW_BIOS_MORE_2DISK 0x0004 /* > 1 GB support */
+#define ADW_BIOS_NO_REMOVABLE 0x0008 /* don't support removable media */
+#define ADW_BIOS_CD_BOOT 0x0010 /* support bootable CD */
+#define ADW_BIOS_SCAN_EN 0x0020 /* BIOS SCAN enabled */
+#define ADW_BIOS_MULTI_LUN 0x0040 /* probe luns */
+#define ADW_BIOS_MESSAGE 0x0080 /* display BIOS message */
+#define ADW_BIOS_RESET_BUS 0x0200 /* reset SCSI bus durint init */
+#define ADW_BIOS_QUIET 0x0800 /* No verbose initialization */
+#define ADW_BIOS_SCSI_PAR_EN 0x1000 /* SCSI parity enabled */
+
+ union {
+ /* 13
+ * ultra enable bits for UW cards,
+ * actual sync rate for TID 4-7
+ * on U2W and U160 cards.
+ */
+ u_int16_t ultra_enable;
+ u_int16_t sdtr2;
+ } sync2;
+ union {
+ /* 14
+ * reserved for UW cards,
+ * actual sync rate for TID 8-11
+ * on U2W and U160 cards.
+ */
+ u_int16_t reserved;
+ u_int16_t sdtr3;
+ } sync3;
+ 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 */
+ union {
+ /* 17
+ * reserved for UW cards,
+ * actual sync rate for TID 12-15
+ * on U2W and U160 cards.
+ */
+ u_int16_t reserved;
+ u_int16_t sdtr4;
+ } sync4;
+ u_int16_t serial_number[3]; /* 18-20 */
+ u_int16_t checksum; /* 21 */
+ u_int8_t oem_name[16]; /* 22 - 29 */
+ u_int16_t dvc_err_code; /* 30 */
+ u_int16_t adv_err_code; /* 31 */
+ u_int16_t adv_err_addr; /* 32 */
+ u_int16_t saved_dvc_err_code; /* 33 */
+ u_int16_t saved_adv_err_code; /* 34 */
+ u_int16_t saved_adv_err_addr; /* 35 */
+ u_int16_t reserved[20]; /* 36 - 55 */
+ u_int16_t cisptr_lsw; /* 56 CIS data */
+ u_int16_t cisptr_msw; /* 57 CIS data */
+ u_int32_t subid; /* 58-59 SubSystem Vendor/Dev ID */
+ u_int16_t reserved2[4];
+};
+
+/* EEProm Addresses */
+#define ADW_EEP_DVC_CFG_BEGIN 0x00
+#define ADW_EEP_DVC_CFG_END (offsetof(struct adw_eeprom, checksum)/2)
+#define ADW_EEP_DVC_CTL_BEGIN (offsetof(struct adw_eeprom, oem_name)/2)
+#define ADW_EEP_MAX_WORD_ADDR (sizeof(struct adw_eeprom)/2)
+
+#define ADW_BUS_RESET_HOLD_DELAY_US 100
+
+typedef enum {
+ ADW_CHIP_NONE,
+ ADW_CHIP_ASC3550, /* Ultra-Wide IC */
+ ADW_CHIP_ASC38C0800, /* Ultra2-Wide/LVD IC */
+ ADW_CHIP_ASC38C1600 /* Ultra3-Wide/LVD2 IC */
+} adw_chip;
+
+typedef enum {
+ ADW_FENONE = 0x0000,
+ ADW_ULTRA = 0x0001, /* Supports 20MHz Transfers */
+ ADW_ULTRA2 = 0x0002, /* Supports 40MHz Transfers */
+ ADW_DT = 0x0004, /* Supports Double Transistion REQ/ACK*/
+ ADW_WIDE = 0x0008, /* Wide Channel */
+ ADW_ASC3550_FE = ADW_ULTRA,
+ ADW_ASC38C0800_FE = ADW_ULTRA2,
+ ADW_ASC38C1600_FE = ADW_ULTRA2|ADW_DT
+} adw_feature;
+
+typedef enum {
+ ADW_FNONE = 0x0000,
+ ADW_EEPROM_FAILED = 0x0001
+} adw_flag;
+
+typedef enum {
+ ADW_STATE_NORMAL = 0x00,
+ ADW_RESOURCE_SHORTAGE = 0x01
+} adw_state;
+
+typedef enum {
+ ADW_MC_SDTR_ASYNC,
+ ADW_MC_SDTR_5,
+ ADW_MC_SDTR_10,
+ ADW_MC_SDTR_20,
+ ADW_MC_SDTR_40,
+ ADW_MC_SDTR_80
+} adw_mc_sdtr;
+
+struct adw_syncrate
+{
+ adw_mc_sdtr mc_sdtr;
+ u_int8_t period;
+ char *rate;
+};
+
+/* We have an input and output queue for our carrier structures */
+#define ADW_OUTPUT_QUEUE 0 /* Offset into carriers member */
+#define ADW_INPUT_QUEUE 1 /* Offset into carriers member */
+#define ADW_NUM_CARRIER_QUEUES 2
+struct adw_softc
+{
+ bus_space_tag_t tag;
+ bus_space_handle_t bsh;
+ adw_state state;
+ bus_dma_tag_t buffer_dmat;
+ struct acb *acbs;
+ struct adw_carrier *carriers;
+ struct adw_carrier *free_carriers;
+ struct adw_carrier *commandq;
+ struct adw_carrier *responseq;
+ LIST_HEAD(, ccb_hdr) pending_ccbs;
+ SLIST_HEAD(, acb) free_acb_list;
+ bus_dma_tag_t parent_dmat;
+ bus_dma_tag_t carrier_dmat; /* dmat for our acb carriers*/
+ bus_dmamap_t carrier_dmamap;
+ bus_dma_tag_t acb_dmat; /* dmat for our ccb array */
+ bus_dmamap_t acb_dmamap;
+ bus_dma_tag_t sg_dmat; /* dmat for our sg maps */
+ SLIST_HEAD(, sg_map_node) sg_maps;
+ bus_addr_t acb_busbase;
+ bus_addr_t carrier_busbase;
+ adw_chip chip;
+ adw_feature features;
+ adw_flag flags;
+ u_int memsize;
+ char channel;
+ struct cam_path *path;
+ struct cam_sim *sim;
+ struct resource *regs;
+ struct resource *irq;
+ void *ih;
+ const struct adw_mcode *mcode_data;
+ const struct adw_eeprom *default_eeprom;
+ device_t device;
+ int regs_res_type;
+ int regs_res_id;
+ int irq_res_type;
+ u_int max_acbs;
+ u_int num_acbs;
+ u_int initiator_id;
+ u_int init_level;
+ u_int unit;
+ char* name;
+ cam_status last_reset; /* Last reset type */
+ u_int16_t bios_ctrl;
+ u_int16_t user_wdtr;
+ u_int16_t user_sdtr[4]; /* A nibble per-device */
+ u_int16_t user_tagenb;
+ u_int16_t tagenb;
+ u_int16_t user_discenb;
+ u_int16_t serial_number[3];
+};
+
+extern const struct adw_eeprom adw_asc3550_default_eeprom;
+extern const struct adw_eeprom adw_asc38C0800_default_eeprom;
+extern const struct adw_syncrate adw_syncrates[];
+extern const int adw_num_syncrates;
+
+#define adw_inb(adw, port) \
+ bus_space_read_1((adw)->tag, (adw)->bsh, port)
+#define adw_inw(adw, port) \
+ bus_space_read_2((adw)->tag, (adw)->bsh, port)
+#define adw_inl(adw, port) \
+ bus_space_read_4((adw)->tag, (adw)->bsh, port)
+
+#define adw_outb(adw, port, value) \
+ bus_space_write_1((adw)->tag, (adw)->bsh, port, value)
+#define adw_outw(adw, port, value) \
+ bus_space_write_2((adw)->tag, (adw)->bsh, port, value)
+#define adw_outl(adw, port, value) \
+ bus_space_write_4((adw)->tag, (adw)->bsh, port, value)
+
+#define adw_set_multi_2(adw, port, value, count) \
+ bus_space_set_multi_2((adw)->tag, (adw)->bsh, port, value, count)
+
+static __inline const char* adw_name(struct adw_softc *adw);
+static __inline u_int adw_lram_read_8(struct adw_softc *adw, u_int addr);
+static __inline u_int adw_lram_read_16(struct adw_softc *adw, u_int addr);
+static __inline u_int adw_lram_read_32(struct adw_softc *adw, u_int addr);
+static __inline void adw_lram_write_8(struct adw_softc *adw, u_int addr,
+ u_int value);
+static __inline void adw_lram_write_16(struct adw_softc *adw, u_int addr,
+ u_int value);
+static __inline void adw_lram_write_32(struct adw_softc *adw, u_int addr,
+ u_int value);
+
+static __inline u_int32_t acbvtobo(struct adw_softc *adw,
+ struct acb *acb);
+static __inline u_int32_t acbvtob(struct adw_softc *adw,
+ struct acb *acb);
+static __inline struct acb * acbbotov(struct adw_softc *adw,
+ u_int32_t busaddr);
+static __inline struct acb * acbbtov(struct adw_softc *adw,
+ u_int32_t busaddr);
+static __inline u_int32_t carriervtobo(struct adw_softc *adw,
+ struct adw_carrier *carrier);
+static __inline u_int32_t carriervtob(struct adw_softc *adw,
+ struct adw_carrier *carrier);
+static __inline struct adw_carrier *
+ carrierbotov(struct adw_softc *adw,
+ u_int32_t byte_offset);
+static __inline struct adw_carrier *
+ carrierbtov(struct adw_softc *adw,
+ u_int32_t baddr);
+
+static __inline const char*
+adw_name(struct adw_softc *adw)
+{
+ return (adw->name);
+}
+
+static __inline u_int
+adw_lram_read_8(struct adw_softc *adw, u_int addr)
+{
+ adw_outw(adw, ADW_RAM_ADDR, addr);
+ return (adw_inb(adw, ADW_RAM_DATA));
+}
+
+static __inline u_int
+adw_lram_read_16(struct adw_softc *adw, u_int addr)
+{
+ adw_outw(adw, ADW_RAM_ADDR, addr);
+ return (adw_inw(adw, ADW_RAM_DATA));
+}
+
+static __inline u_int
+adw_lram_read_32(struct adw_softc *adw, u_int addr)
+{
+ u_int retval;
+
+ adw_outw(adw, ADW_RAM_ADDR, addr);
+ retval = adw_inw(adw, ADW_RAM_DATA);
+ retval |= (adw_inw(adw, ADW_RAM_DATA) << 16);
+ return (retval);
+}
+
+static __inline void
+adw_lram_write_8(struct adw_softc *adw, u_int addr, u_int value)
+{
+ adw_outw(adw, ADW_RAM_ADDR, addr);
+ adw_outb(adw, ADW_RAM_DATA, value);
+}
+
+static __inline void
+adw_lram_write_16(struct adw_softc *adw, u_int addr, u_int value)
+{
+ adw_outw(adw, ADW_RAM_ADDR, addr);
+ adw_outw(adw, ADW_RAM_DATA, value);
+}
+
+static __inline void
+adw_lram_write_32(struct adw_softc *adw, u_int addr, u_int value)
+{
+ adw_outw(adw, ADW_RAM_ADDR, addr);
+ adw_outw(adw, ADW_RAM_DATA, value);
+ adw_outw(adw, ADW_RAM_DATA, value >> 16);
+}
+
+static __inline u_int32_t
+acbvtobo(struct adw_softc *adw, struct acb *acb)
+{
+ return ((u_int32_t)((caddr_t)acb - (caddr_t)adw->acbs));
+}
+
+static __inline u_int32_t
+acbvtob(struct adw_softc *adw, struct acb *acb)
+{
+ return (adw->acb_busbase + acbvtobo(adw, acb));
+}
+
+static __inline struct acb *
+acbbotov(struct adw_softc *adw, u_int32_t byteoffset)
+{
+ return ((struct acb *)((caddr_t)adw->acbs + byteoffset));
+}
+
+static __inline struct acb *
+acbbtov(struct adw_softc *adw, u_int32_t busaddr)
+{
+ return (acbbotov(adw, busaddr - adw->acb_busbase));
+}
+
+/*
+ * Return the byte offset for a carrier relative to our array of carriers.
+ */
+static __inline u_int32_t
+carriervtobo(struct adw_softc *adw, struct adw_carrier *carrier)
+{
+ return ((u_int32_t)((caddr_t)carrier - (caddr_t)adw->carriers));
+}
+
+static __inline u_int32_t
+carriervtob(struct adw_softc *adw, struct adw_carrier *carrier)
+{
+ return (adw->carrier_busbase + carriervtobo(adw, carrier));
+}
+
+static __inline struct adw_carrier *
+carrierbotov(struct adw_softc *adw, u_int32_t byte_offset)
+{
+ return ((struct adw_carrier *)((caddr_t)adw->carriers + byte_offset));
+}
+
+static __inline struct adw_carrier *
+carrierbtov(struct adw_softc *adw, u_int32_t baddr)
+{
+ return (carrierbotov(adw, baddr - adw->carrier_busbase));
+}
+
+/* Intialization */
+int adw_find_signature(struct adw_softc *adw);
+void adw_reset_chip(struct adw_softc *adw);
+int adw_reset_bus(struct adw_softc *adw);
+u_int16_t adw_eeprom_read(struct adw_softc *adw, struct adw_eeprom *buf);
+void adw_eeprom_write(struct adw_softc *adw, struct adw_eeprom *buf);
+int adw_init_chip(struct adw_softc *adw, u_int term_scsicfg1);
+void adw_set_user_sdtr(struct adw_softc *adw,
+ u_int tid, u_int mc_sdtr);
+u_int adw_get_user_sdtr(struct adw_softc *adw, u_int tid);
+void adw_set_chip_sdtr(struct adw_softc *adw, u_int tid, u_int sdtr);
+u_int adw_get_chip_sdtr(struct adw_softc *adw, u_int tid);
+u_int adw_find_sdtr(struct adw_softc *adw, u_int period);
+u_int adw_find_period(struct adw_softc *adw, u_int mc_sdtr);
+u_int adw_hshk_cfg_period_factor(u_int tinfo);
+
+/* Idle Commands */
+adw_idle_cmd_status_t adw_idle_cmd_send(struct adw_softc *adw, u_int cmd,
+ u_int parameter);
+
+/* SCSI Transaction Processing */
+static __inline void adw_send_acb(struct adw_softc *adw, struct acb *acb,
+ u_int32_t acb_baddr);
+
+static __inline void adw_tickle_risc(struct adw_softc *adw, u_int value)
+{
+ /*
+ * Tickle the RISC to tell it to read its Command Queue Head pointer.
+ */
+ adw_outb(adw, ADW_TICKLE, value);
+ if (adw->chip == ADW_CHIP_ASC3550) {
+ /*
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_a' does not work unless the host
+ * value is cleared.
+ */
+ adw_outb(adw, ADW_TICKLE, ADW_TICKLE_NOP);
+ }
+}
+
+static __inline void
+adw_send_acb(struct adw_softc *adw, struct acb *acb, u_int32_t acb_baddr)
+{
+ struct adw_carrier *new_cq;
+
+ new_cq = adw->free_carriers;
+ adw->free_carriers = carrierbotov(adw, new_cq->next_ba);
+ new_cq->next_ba = ADW_CQ_STOPPER;
+
+ acb->queue.carrier_baddr = adw->commandq->carr_ba;
+ acb->queue.carrier_bo = adw->commandq->carr_offset;
+ adw->commandq->areq_ba = acbvtob(adw, acb);
+ adw->commandq->next_ba = new_cq->carr_ba;
+#if 0
+ printf("EnQ 0x%x 0x%x 0x%x 0x%x\n",
+ adw->commandq->carr_offset,
+ adw->commandq->carr_ba,
+ adw->commandq->areq_ba,
+ adw->commandq->next_ba);
+#endif
+ adw->commandq = new_cq;
+
+
+ adw_tickle_risc(adw, ADW_TICKLE_A);
+}
+
+#endif /* _ADWLIB_H_ */
diff --git a/sys/dev/advansys/adwmcode.c b/sys/dev/advansys/adwmcode.c
new file mode 100644
index 0000000..c5f0504
--- /dev/null
+++ b/sys/dev/advansys/adwmcode.c
@@ -0,0 +1,994 @@
+/*
+ * Downloadable microcode for Second Generation
+ * Advanced Systems Inc. SCSI controllers
+ *
+ * $FreeBSD$
+ *
+ * Obtained from:
+ * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
+ *
+ * Copyright (c) 1995-1999 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>
+
+#include <dev/advansys/adwmcode.h>
+
+const u_int8_t adw_asc3550_mcode[] =
+{
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48,
+ 0xe4, 0x01, 0x00, 0x18, 0xe4, 0x00, 0xf6, 0x01, 0xf6, 0x18, 0x80,
+ 0x48, 0x19, 0x02, 0x00, 0xff, 0xff, 0x03, 0xf6, 0x00, 0xfa, 0xff,
+ 0x00, 0x82, 0xe7, 0x01, 0xfa, 0x9e, 0xe7, 0x09, 0xe7, 0x3a, 0x0e,
+ 0x00, 0xea, 0x01, 0xe6, 0x55, 0xf0, 0x03, 0x00, 0x08, 0x00, 0x18,
+ 0xf4, 0x3e, 0x01, 0x3e, 0x57, 0x04, 0x00, 0x85, 0xf0, 0x00, 0xe6,
+ 0x00, 0xec, 0x1e, 0xf0, 0x32, 0xf0, 0x34, 0x19, 0x86, 0xf0, 0xd0,
+ 0x01, 0xd5, 0xf0, 0xde, 0x0c, 0x98, 0x57, 0xbc, 0x00, 0x0c, 0x1c,
+ 0x0e, 0x13, 0x38, 0x54, 0xb1, 0xf0, 0xb4, 0x00, 0x01, 0xfc, 0x03,
+ 0xfc, 0xd8, 0x0c, 0x00, 0x57, 0x01, 0xf0, 0x02, 0x13, 0x03, 0xe6,
+ 0x10, 0x00, 0x18, 0x40, 0x3e, 0x1c, 0x6c, 0x01, 0x6e, 0x01, 0xbd,
+ 0x00, 0xe0, 0x00, 0x02, 0x48, 0x02, 0x80, 0x08, 0x12, 0x30, 0xe4,
+ 0x3c, 0x00, 0x4e, 0x01, 0x64, 0x12, 0x80, 0x00, 0x9c, 0x15, 0xbb,
+ 0x00, 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea, 0x04, 0x12, 0x9e, 0x0f,
+ 0xb6, 0x00, 0xb9, 0x54, 0xe2, 0x0f, 0x00, 0x80, 0x06, 0xf7, 0x10,
+ 0x44, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, 0x3c, 0x56,
+ 0x3e, 0x00, 0x4b, 0xe4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70,
+ 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0xe2, 0x0c,
+ 0x00, 0x01, 0x02, 0xee, 0x02, 0xfc, 0x03, 0x58, 0x03, 0xf7, 0x04,
+ 0x80, 0x05, 0xfc, 0x08, 0x44, 0x09, 0xf0, 0x0f, 0x00, 0x1b, 0x80,
+ 0x20, 0x01, 0x38, 0x1c, 0x40, 0x00, 0x40, 0x15, 0x4b, 0xf4, 0x4e,
+ 0x1c, 0x5b, 0xf0, 0x5d, 0xf0, 0xaa, 0x00, 0xbb, 0x55, 0xbe, 0x00,
+ 0xc0, 0x00, 0xe0, 0x08, 0xe0, 0x14, 0xec, 0x0f, 0x00, 0x4c, 0x00,
+ 0xdc, 0x02, 0x4a, 0x05, 0x00, 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13,
+ 0x08, 0x13, 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, 0x19, 0x00, 0x20,
+ 0x00, 0x2a, 0x01, 0x30, 0x0e, 0x32, 0x1c, 0x36, 0x00, 0x45, 0x5a,
+ 0x59, 0xf0, 0x62, 0x0a, 0x69, 0x08, 0x72, 0x0b, 0x83, 0x59, 0xb8,
+ 0xf0, 0xbd, 0x56, 0xcc, 0x12, 0xec, 0x17, 0xee, 0x0f, 0xf0, 0x00,
+ 0xf8, 0x17, 0x01, 0x48, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0x10, 0x04,
+ 0xea, 0x04, 0xf6, 0x04, 0xfc, 0x05, 0x80, 0x05, 0xe6, 0x06, 0x00,
+ 0x06, 0x12, 0x0a, 0x10, 0x0b, 0xf0, 0x0c, 0x10, 0x0c, 0xf0, 0x12,
+ 0x10, 0x26, 0x0e, 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x38, 0x44,
+ 0x40, 0x5c, 0x4a, 0xe4, 0x62, 0x1a, 0x68, 0x08, 0x68, 0x54, 0x83,
+ 0x55, 0x83, 0x5a, 0x8c, 0x14, 0x8e, 0x0a, 0x90, 0x14, 0x91, 0x44,
+ 0xa4, 0x00, 0xb0, 0x57, 0xb5, 0x00, 0xba, 0x00, 0xce, 0x45, 0xd0,
+ 0x00, 0xd8, 0x16, 0xe1, 0x00, 0xe7, 0x00, 0x00, 0x54, 0x01, 0x58,
+ 0x02, 0x10, 0x02, 0xe6, 0x03, 0xa1, 0x04, 0x13, 0x06, 0x83, 0x06,
+ 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0x12, 0x0a, 0xf0, 0x0c, 0x04,
+ 0x0c, 0x12, 0x0c, 0x90, 0x10, 0x10, 0x10, 0x13, 0x12, 0x1c, 0x17,
+ 0x00, 0x19, 0xe4, 0x1a, 0x10, 0x1c, 0x00, 0x1c, 0x12, 0x1d, 0xf7,
+ 0x1e, 0x13, 0x20, 0x1c, 0x20, 0xe7, 0x22, 0x01, 0x26, 0x01, 0x2a,
+ 0x12, 0x30, 0xe7, 0x34, 0x1c, 0x36, 0x1c, 0x38, 0x12, 0x41, 0x58,
+ 0x43, 0x48, 0x44, 0x55, 0x46, 0x1c, 0x4c, 0x0e, 0x4e, 0xe4, 0x52,
+ 0x14, 0x5c, 0xf0, 0x72, 0x02, 0x74, 0x03, 0x77, 0x57, 0x89, 0x48,
+ 0x8e, 0x90, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x32, 0x9e, 0x00, 0xa8,
+ 0x00, 0xb9, 0x00, 0xba, 0x06, 0xbc, 0x12, 0xbf, 0x57, 0xc0, 0x01,
+ 0xfe, 0x9c, 0xf0, 0x26, 0x02, 0xfe, 0x00, 0x0d, 0xff, 0x10, 0x00,
+ 0x00, 0xfe, 0xc2, 0x01, 0xfe, 0x56, 0x19, 0x00, 0xfc, 0xfe, 0x80,
+ 0x01, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x6a, 0x13, 0xfe, 0x05, 0x05,
+ 0xff, 0x40, 0x00, 0x00, 0x0d, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08,
+ 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff,
+ 0x10, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe,
+ 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xfc, 0x2b,
+ 0x51, 0x0c, 0x01, 0xfe, 0xea, 0x0e, 0xfe, 0x04, 0xf7, 0xfc, 0x51,
+ 0x0c, 0x1d, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x20,
+ 0xf0, 0xd0, 0x04, 0x56, 0x4b, 0x02, 0xfe, 0x1c, 0x0d, 0x01, 0xfe,
+ 0x7c, 0x0d, 0xfe, 0xe9, 0x12, 0x02, 0xfe, 0x04, 0x03, 0xfe, 0x28,
+ 0x1c, 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, 0x12, 0x4e, 0x12, 0xfe,
+ 0xa6, 0x00, 0xc5, 0xfe, 0x48, 0xf0, 0xfe, 0x7c, 0x02, 0xfe, 0x49,
+ 0xf0, 0xfe, 0x96, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xb4, 0x02, 0xfe,
+ 0x46, 0xf0, 0xfe, 0x46, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x4c, 0x02,
+ 0xfe, 0x43, 0xf0, 0xfe, 0x3a, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x3e,
+ 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x42, 0x02, 0x09, 0x0c, 0x9e, 0x09,
+ 0x06, 0x12, 0xbb, 0x02, 0x26, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10,
+ 0xfe, 0x02, 0x1c, 0xfe, 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9,
+ 0x10, 0x01, 0xfe, 0x4c, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
+ 0xf7, 0x0e, 0x78, 0x01, 0xab, 0x02, 0x26, 0x17, 0x55, 0x4a, 0xbd,
+ 0x01, 0xfe, 0x60, 0x0f, 0x0e, 0x78, 0x01, 0x8b, 0xfe, 0xbd, 0x10,
+ 0x0e, 0x78, 0x01, 0x8b, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+ 0x58, 0x1c, 0x09, 0x06, 0x12, 0xbb, 0x2b, 0x22, 0x26, 0xfe, 0x3d,
+ 0xf0, 0xfe, 0xf8, 0x01, 0x27, 0xfe, 0x8a, 0x02, 0xfe, 0x5a, 0x1c,
+ 0xd5, 0xfe, 0x14, 0x1c, 0x17, 0xfe, 0x30, 0x00, 0x4a, 0xbd, 0x01,
+ 0xfe, 0x50, 0x0f, 0x09, 0x06, 0x12, 0xbb, 0x02, 0xfe, 0xc2, 0x01,
+ 0x21, 0x2a, 0x05, 0x10, 0x35, 0xfe, 0x69, 0x10, 0x09, 0x06, 0x12,
+ 0xbb, 0xfe, 0x04, 0xec, 0x2a, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01,
+ 0x46, 0x7f, 0xfe, 0x05, 0xf6, 0xf7, 0x01, 0xfe, 0x76, 0x16, 0x0a,
+ 0x41, 0x89, 0x38, 0x11, 0x47, 0x1d, 0xca, 0x08, 0x1c, 0x09, 0x43,
+ 0x01, 0x71, 0x02, 0x26, 0x0e, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x2c,
+ 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b, 0xfe, 0x28, 0x10, 0x0e, 0xc0,
+ 0x01, 0x15, 0xe6, 0x0e, 0x79, 0x01, 0x15, 0xfe, 0x49, 0x54, 0x74,
+ 0xfe, 0x12, 0x03, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x71, 0x02, 0x26,
+ 0x2b, 0x7f, 0xfe, 0x02, 0xe8, 0x2f, 0xfb, 0xfe, 0x9e, 0x43, 0xf0,
+ 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xd0, 0xfe, 0x40, 0x1c, 0x22,
+ 0xef, 0xfe, 0x26, 0xf0, 0xfe, 0x70, 0x03, 0xfe, 0xa0, 0xf0, 0xfe,
+ 0x5e, 0x03, 0xfe, 0x11, 0xf0, 0xd0, 0xfe, 0x0e, 0x10, 0xfe, 0x9f,
+ 0xf0, 0xfe, 0x7e, 0x03, 0xe9, 0x13, 0xfe, 0x11, 0x00, 0x02, 0x62,
+ 0x2b, 0xfe, 0x48, 0x1c, 0xe9, 0x22, 0xef, 0x34, 0xef, 0xfe, 0x82,
+ 0xf0, 0xfe, 0x84, 0x03, 0x2d, 0x21, 0xbe, 0x6a, 0x16, 0xbe, 0x0e,
+ 0x79, 0x01, 0x15, 0x6a, 0x7d, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x46,
+ 0x11, 0x3d, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x71, 0xf5, 0x11, 0xfe,
+ 0xe4, 0x00, 0x2e, 0xfe, 0xca, 0x03, 0x22, 0x32, 0x1f, 0xfe, 0xda,
+ 0x03, 0x01, 0x4c, 0xcb, 0xfe, 0xea, 0x03, 0x6b, 0x92, 0xcf, 0xfe,
+ 0xaa, 0x06, 0x02, 0x28, 0x04, 0x78, 0x29, 0x18, 0xfe, 0x1c, 0x05,
+ 0x17, 0x85, 0x01, 0x44, 0x01, 0x97, 0x01, 0x9a, 0x34, 0xfe, 0x5c,
+ 0x02, 0x02, 0xee, 0xe9, 0x2b, 0x51, 0x19, 0xfe, 0x67, 0x1b, 0xfb,
+ 0xf0, 0xfe, 0x48, 0x1c, 0x8c, 0x01, 0xfa, 0xac, 0xfe, 0x96, 0xf0,
+ 0xfe, 0x24, 0x04, 0x2e, 0xfe, 0x28, 0x04, 0x34, 0x26, 0x0e, 0x3d,
+ 0x01, 0x15, 0x05, 0x10, 0x18, 0xfe, 0x08, 0x05, 0x3e, 0x90, 0x9f,
+ 0x2f, 0x82, 0x6e, 0x22, 0x32, 0x1f, 0x28, 0x04, 0x78, 0x29, 0xfe,
+ 0x10, 0x12, 0x17, 0x85, 0x01, 0x44, 0x34, 0xfe, 0x5c, 0x02, 0x02,
+ 0xee, 0x31, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e, 0x12,
+ 0x0a, 0x07, 0x06, 0xfe, 0x56, 0x12, 0x23, 0x24, 0x91, 0x01, 0x0b,
+ 0x82, 0x6e, 0x1f, 0xfe, 0xd8, 0x04, 0x23, 0x24, 0x91, 0x01, 0x0b,
+ 0x1f, 0x28, 0x23, 0x24, 0xb3, 0xfe, 0x4c, 0x44, 0xfe, 0x32, 0x12,
+ 0x57, 0xfe, 0x44, 0x48, 0x08, 0xd6, 0xfe, 0x4c, 0x54, 0x74, 0xfe,
+ 0x08, 0x05, 0x7f, 0x9f, 0x2f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47,
+ 0xfe, 0x48, 0x13, 0x3f, 0x05, 0xfe, 0xcc, 0x00, 0xfe, 0x40, 0x13,
+ 0x0a, 0x07, 0x06, 0xe5, 0xfe, 0x06, 0x10, 0x23, 0x24, 0xb3, 0x0a,
+ 0x07, 0x37, 0xda, 0x17, 0xa4, 0x0a, 0x07, 0x06, 0x4b, 0x17, 0xfe,
+ 0x0d, 0x00, 0x01, 0x44, 0x34, 0xfe, 0xc0, 0x0c, 0x02, 0x28, 0x39,
+ 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xb0, 0x03, 0x17, 0xa4,
+ 0x01, 0x44, 0x34, 0x26, 0x22, 0x26, 0x02, 0xfe, 0x10, 0x05, 0xfe,
+ 0x42, 0x5b, 0x51, 0x19, 0xfe, 0x46, 0x59, 0xfb, 0xf0, 0x17, 0x45,
+ 0xfe, 0x07, 0x80, 0xfe, 0x31, 0x44, 0x0a, 0x07, 0x0c, 0xfe, 0x78,
+ 0x13, 0xfe, 0x20, 0x80, 0x05, 0x19, 0xfe, 0x70, 0x12, 0x6d, 0x07,
+ 0x06, 0xfe, 0x60, 0x13, 0x04, 0xfe, 0xa2, 0x00, 0x29, 0x18, 0xfe,
+ 0xa8, 0x05, 0xfe, 0x31, 0xe4, 0x70, 0x6d, 0x07, 0x0c, 0xfe, 0x4a,
+ 0x13, 0x04, 0xfe, 0xa0, 0x00, 0x29, 0xfe, 0x42, 0x12, 0x5a, 0x2e,
+ 0xfe, 0x68, 0x05, 0x22, 0x32, 0xf1, 0x01, 0x0b, 0x25, 0xfe, 0xc0,
+ 0x05, 0x11, 0xfe, 0xe3, 0x00, 0x2d, 0x6d, 0xfe, 0x4a, 0xf0, 0xfe,
+ 0x92, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x8c, 0x05, 0xa8, 0x20, 0xfe,
+ 0x21, 0x00, 0xa6, 0x20, 0xfe, 0x22, 0x00, 0x9e, 0x20, 0x89, 0xfe,
+ 0x09, 0x48, 0x01, 0x0b, 0x25, 0xfe, 0xc0, 0x05, 0xfe, 0xe2, 0x08,
+ 0x6d, 0x07, 0xd9, 0x4b, 0x01, 0x96, 0x20, 0x06, 0x16, 0xe0, 0x4a,
+ 0xfe, 0x27, 0x01, 0x0a, 0x07, 0x37, 0xe1, 0x4e, 0x01, 0xb9, 0x17,
+ 0xa4, 0x0a, 0x07, 0x06, 0x4b, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x44,
+ 0x01, 0x97, 0x01, 0x9a, 0x34, 0xfe, 0xc0, 0x0c, 0x02, 0x28, 0x04,
+ 0xfe, 0x9c, 0x00, 0x29, 0xfe, 0x3e, 0x12, 0x04, 0x53, 0x29, 0xfe,
+ 0x36, 0x13, 0x4e, 0x01, 0xb9, 0x25, 0xfe, 0x38, 0x06, 0x0e, 0x06,
+ 0x6d, 0x07, 0x1a, 0xfe, 0x02, 0x12, 0x77, 0x01, 0xfe, 0x26, 0x14,
+ 0x1f, 0xfe, 0x2e, 0x06, 0x11, 0xc2, 0x01, 0x4c, 0x11, 0xfe, 0xe5,
+ 0x00, 0x04, 0x53, 0xbc, 0x0f, 0x53, 0x04, 0xf6, 0x29, 0xfe, 0x62,
+ 0x12, 0x04, 0x4d, 0x29, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x9e, 0x18,
+ 0x01, 0xfe, 0xf0, 0x18, 0xe7, 0xa3, 0x1a, 0x08, 0x63, 0xff, 0x02,
+ 0x00, 0x57, 0x66, 0x7e, 0x1b, 0x50, 0xc9, 0xa3, 0x6c, 0x4e, 0x01,
+ 0xb9, 0x25, 0xfe, 0xa2, 0x06, 0x6d, 0x07, 0x1e, 0xa5, 0x95, 0x0e,
+ 0x55, 0x01, 0xfe, 0x54, 0x14, 0x1f, 0xfe, 0x98, 0x06, 0x11, 0xc2,
+ 0x01, 0x4c, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x4d, 0xbc, 0x0f, 0x4d,
+ 0x09, 0x06, 0x01, 0xb9, 0xf5, 0x73, 0x8c, 0x01, 0xfa, 0xac, 0x11,
+ 0xfe, 0xe2, 0x00, 0x2e, 0xf9, 0x22, 0x32, 0xcf, 0xfe, 0xd6, 0x06,
+ 0x81, 0xfe, 0x74, 0x07, 0xcb, 0xfe, 0x7c, 0x07, 0x6b, 0x92, 0x02,
+ 0x28, 0x0a, 0x07, 0x0c, 0xfe, 0x2e, 0x12, 0x14, 0x19, 0x01, 0x0b,
+ 0x14, 0x00, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x00, 0x01,
+ 0x0b, 0xfe, 0x99, 0xa4, 0x01, 0x0b, 0x14, 0x00, 0x02, 0xfe, 0x4c,
+ 0x08, 0x68, 0x07, 0x1e, 0xe5, 0x0a, 0x07, 0x1e, 0xfe, 0x30, 0x13,
+ 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14,
+ 0x00, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x06, 0x01, 0x0b,
+ 0x14, 0x00, 0x02, 0xfe, 0x2a, 0x0b, 0x77, 0xfe, 0x9a, 0x81, 0x67,
+ 0x89, 0xfe, 0x09, 0x6f, 0xfe, 0x93, 0x45, 0x18, 0xfe, 0x84, 0x07,
+ 0x2e, 0xfe, 0x5c, 0x07, 0x22, 0x32, 0xcf, 0xfe, 0x54, 0x07, 0x6b,
+ 0x92, 0x81, 0xfe, 0x74, 0x07, 0x02, 0x28, 0x01, 0x4c, 0x02, 0xf9,
+ 0x14, 0x1a, 0x02, 0xf9, 0xfe, 0x9c, 0xf7, 0xfe, 0xec, 0x07, 0xfe,
+ 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x75, 0xfe, 0xd2, 0x07, 0x0f, 0x5d,
+ 0x12, 0x5e, 0x0a, 0x41, 0x70, 0x38, 0x01, 0xfe, 0x34, 0x18, 0x05,
+ 0x10, 0x83, 0xfe, 0x83, 0xe7, 0x88, 0xa6, 0xfe, 0x03, 0x40, 0x0a,
+ 0x41, 0x45, 0x38, 0x01, 0xc1, 0xaf, 0xfe, 0x1f, 0x40, 0x16, 0x61,
+ 0x01, 0xfe, 0xde, 0x12, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
+ 0x34, 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
+ 0x0f, 0x5b, 0x12, 0x5c, 0xd2, 0xf2, 0x0f, 0x3a, 0x12, 0x3b, 0xfe,
+ 0x60, 0x10, 0x0a, 0x07, 0x70, 0xe1, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+ 0x90, 0x0f, 0x5d, 0x12, 0x5e, 0x0a, 0x07, 0x45, 0xc9, 0x01, 0xc1,
+ 0xfe, 0x1f, 0x80, 0x16, 0x61, 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90,
+ 0x0f, 0x5f, 0x12, 0x60, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0f,
+ 0x5b, 0x12, 0x5c, 0xa2, 0x07, 0x45, 0x2c, 0xd2, 0xf2, 0x0f, 0x3a,
+ 0x12, 0x3b, 0xa8, 0xfe, 0x28, 0x90, 0xfe, 0xaa, 0x90, 0x0f, 0x3a,
+ 0x12, 0x3b, 0x0f, 0x42, 0x12, 0x58, 0x0a, 0x41, 0x1a, 0x38, 0x2b,
+ 0x08, 0x80, 0x2e, 0xfe, 0x62, 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x76,
+ 0x08, 0x9b, 0x18, 0x32, 0x2b, 0x52, 0xfe, 0xed, 0x10, 0xa7, 0xfe,
+ 0x9a, 0x08, 0xa9, 0xfe, 0xb6, 0x08, 0x81, 0xfe, 0x8e, 0x08, 0xcb,
+ 0xfe, 0x94, 0x08, 0x6b, 0x92, 0x02, 0x28, 0x01, 0x4c, 0xfe, 0xc9,
+ 0x10, 0x14, 0x1a, 0xfe, 0xc9, 0x10, 0x68, 0x07, 0x06, 0xfe, 0x10,
+ 0x12, 0x68, 0x07, 0x0c, 0x40, 0x0a, 0x07, 0x0c, 0xfe, 0x7e, 0x12,
+ 0xfe, 0x2e, 0x1c, 0xaa, 0x68, 0x07, 0x06, 0x40, 0x68, 0x07, 0x0c,
+ 0xfe, 0x6a, 0x12, 0xfe, 0x2c, 0x1c, 0xa2, 0x07, 0x45, 0xd4, 0xa2,
+ 0x41, 0x45, 0xfe, 0x05, 0x40, 0xd2, 0xf2, 0xfe, 0x28, 0x50, 0xfe,
+ 0xaa, 0x50, 0xfe, 0xaa, 0xf0, 0xfe, 0x4e, 0x09, 0xfe, 0xac, 0xf0,
+ 0xfe, 0xee, 0x08, 0xfe, 0x92, 0x10, 0xe3, 0xfe, 0xf3, 0x10, 0xfe,
+ 0xad, 0xf0, 0xfe, 0xfa, 0x08, 0x02, 0xfe, 0x5c, 0x0a, 0xe4, 0xfe,
+ 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xb8, 0xfe, 0x6b, 0x18, 0x1b, 0xfe,
+ 0x00, 0xfe, 0xda, 0xc5, 0xfe, 0xd2, 0xf0, 0xb8, 0xfe, 0x76, 0x18,
+ 0x1b, 0x19, 0x18, 0xb8, 0x04, 0xdf, 0x1b, 0x06, 0x18, 0xb8, 0xa7,
+ 0x7a, 0xa9, 0x7a, 0xe3, 0xe4, 0xfe, 0xb1, 0x10, 0x8c, 0x5a, 0x39,
+ 0x17, 0xa4, 0x01, 0x44, 0x13, 0xfe, 0x35, 0x00, 0x34, 0x62, 0x13,
+ 0x8d, 0x02, 0x62, 0xfe, 0x74, 0x18, 0x1b, 0xfe, 0x00, 0xf8, 0x18,
+ 0x7a, 0x51, 0x1e, 0x01, 0xfe, 0x7c, 0x0d, 0xd1, 0x08, 0x1c, 0x09,
+ 0x43, 0x01, 0x71, 0x21, 0x2f, 0x3e, 0x51, 0x19, 0x02, 0x7a, 0xfe,
+ 0x98, 0x80, 0xd7, 0x0c, 0x27, 0xfe, 0x3e, 0x0a, 0x0a, 0x07, 0x70,
+ 0xfe, 0x82, 0x12, 0x0a, 0x07, 0x1a, 0xfe, 0x66, 0x13, 0x21, 0x61,
+ 0x6a, 0xc8, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13,
+ 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x64, 0x2f, 0xfe, 0x40, 0x59,
+ 0xfe, 0xc1, 0x59, 0x75, 0xfe, 0xea, 0x08, 0x04, 0x5d, 0x30, 0x5e,
+ 0x0f, 0xae, 0x12, 0x8d, 0x9c, 0x5d, 0x9d, 0x5e, 0x01, 0xc1, 0xaf,
+ 0x64, 0x2f, 0x16, 0x61, 0xa1, 0x42, 0x69, 0x58, 0x65, 0x5f, 0x31,
+ 0x60, 0xe8, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x42, 0xfe, 0x05,
+ 0xfa, 0x58, 0x01, 0xfe, 0xde, 0x12, 0xfe, 0x36, 0x10, 0x2d, 0x0f,
+ 0xae, 0x0f, 0x8d, 0x65, 0x5f, 0x31, 0x60, 0xaa, 0x0a, 0x07, 0x1a,
+ 0x18, 0xfe, 0xea, 0x08, 0x65, 0x3a, 0x31, 0x3b, 0x0a, 0x07, 0xfe,
+ 0xf7, 0x00, 0x38, 0x04, 0x5b, 0x30, 0x5c, 0xfe, 0x10, 0x58, 0xfe,
+ 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x7a, 0x0a,
+ 0x07, 0x1a, 0x18, 0xfe, 0xea, 0x08, 0x0a, 0x07, 0xfe, 0xf7, 0x00,
+ 0x38, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x77, 0xfe, 0x10, 0x90,
+ 0xfe, 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x3f, 0x05, 0xc3, 0x18, 0xfe,
+ 0xf6, 0x08, 0x11, 0xc3, 0xfe, 0x98, 0x80, 0xd7, 0x0c, 0xfe, 0x14,
+ 0x13, 0x04, 0x3a, 0x30, 0x3b, 0x75, 0xfe, 0xf6, 0x08, 0xfe, 0x0c,
+ 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x7a, 0x2d, 0x4e, 0xfe, 0x19, 0x80,
+ 0xfe, 0xf1, 0x10, 0x0a, 0x07, 0x0c, 0xa5, 0xfe, 0x6c, 0x19, 0xfe,
+ 0x19, 0x41, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x9c, 0x3a, 0xfe,
+ 0xed, 0x19, 0x9d, 0x3b, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xfe,
+ 0x6b, 0x18, 0x1b, 0xfe, 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc5,
+ 0xfe, 0xd2, 0xf0, 0xfe, 0xd6, 0x0a, 0xfe, 0x76, 0x18, 0x1b, 0x19,
+ 0xce, 0x04, 0xdf, 0x1b, 0x06, 0x84, 0x13, 0xfe, 0x16, 0x00, 0x02,
+ 0x62, 0xfe, 0xd1, 0xf0, 0xfe, 0xe8, 0x0a, 0x17, 0x80, 0x01, 0x44,
+ 0x13, 0xd6, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xee, 0x0a,
+ 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xfa, 0x0a, 0x13, 0xfe,
+ 0x22, 0x00, 0x02, 0x62, 0xfe, 0xcb, 0xf0, 0xfe, 0x06, 0x0b, 0x13,
+ 0xfe, 0x24, 0x00, 0x02, 0x62, 0xfe, 0xd0, 0xf0, 0xfe, 0x10, 0x0b,
+ 0x13, 0x88, 0xd8, 0xfe, 0xcf, 0xf0, 0xfe, 0x1a, 0x0b, 0x13, 0x89,
+ 0xd3, 0xfe, 0xcc, 0xf0, 0xfe, 0x2a, 0x0b, 0xfe, 0x84, 0x80, 0xd7,
+ 0x1a, 0x4b, 0x13, 0xfe, 0x12, 0x00, 0x2b, 0x08, 0x80, 0x2e, 0xfe,
+ 0x30, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x44, 0x0b, 0x9b, 0x18, 0x32,
+ 0x2b, 0x52, 0xfe, 0xed, 0x10, 0xa7, 0x28, 0xa9, 0x28, 0x2b, 0xf5,
+ 0x2e, 0xfe, 0x50, 0x0b, 0x22, 0x32, 0x81, 0xfe, 0x6c, 0x0b, 0x6b,
+ 0x92, 0xa7, 0xfe, 0xec, 0x07, 0xa9, 0xfe, 0xec, 0x07, 0x02, 0x28,
+ 0x01, 0x4c, 0xfe, 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xe3, 0xe4,
+ 0x8c, 0x82, 0x6e, 0xfe, 0x89, 0xf0, 0x28, 0x23, 0x24, 0xfe, 0xe9,
+ 0x09, 0x01, 0x0b, 0x82, 0x6e, 0x1f, 0x28, 0x23, 0x24, 0x91, 0x34,
+ 0xfe, 0xa8, 0x0b, 0x22, 0x32, 0x02, 0xfe, 0x9c, 0x0b, 0x9b, 0x40,
+ 0x13, 0xfe, 0x42, 0x00, 0x02, 0x62, 0xa0, 0x06, 0xfe, 0x81, 0x49,
+ 0x96, 0x0a, 0x07, 0x0c, 0xfe, 0x5a, 0x13, 0x13, 0x00, 0x59, 0x0c,
+ 0xfe, 0x6a, 0x12, 0x59, 0xfe, 0x28, 0x00, 0x27, 0xfe, 0xee, 0x0c,
+ 0x0e, 0x79, 0x01, 0x15, 0x05, 0x00, 0x84, 0x36, 0xfe, 0x28, 0x00,
+ 0x02, 0xfe, 0xee, 0x0c, 0x01, 0x97, 0x01, 0x9a, 0x0e, 0xc0, 0x01,
+ 0xfe, 0x44, 0x0e, 0xb2, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x46, 0x11,
+ 0x47, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b, 0x02, 0x26, 0x13, 0xfe,
+ 0x44, 0x00, 0x59, 0x0c, 0xa5, 0x36, 0x0c, 0xfe, 0xc0, 0x10, 0x01,
+ 0x96, 0x36, 0x0c, 0xfe, 0xb6, 0x10, 0x01, 0x96, 0xfe, 0x19, 0x82,
+ 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x36, 0x0c, 0x13, 0xfe, 0x43,
+ 0x00, 0xfe, 0xa2, 0x10, 0x0a, 0x41, 0x0c, 0x38, 0x01, 0x97, 0x01,
+ 0x9a, 0xb2, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x46, 0x11, 0x47, 0x08,
+ 0x1c, 0x09, 0x43, 0x01, 0x7b, 0x51, 0x0c, 0xb2, 0x1d, 0xca, 0x02,
+ 0xfe, 0x48, 0x03, 0x0a, 0x07, 0x0c, 0xce, 0x36, 0x0c, 0x13, 0x00,
+ 0xfe, 0x54, 0x10, 0x68, 0x07, 0x1e, 0xfe, 0x50, 0x12, 0x0a, 0x07,
+ 0x1e, 0xfe, 0x48, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe,
+ 0xac, 0x0c, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0xb2, 0x0c,
+ 0x0a, 0x41, 0x1e, 0x38, 0xfe, 0x95, 0x10, 0x13, 0xfe, 0x15, 0x00,
+ 0xfe, 0x04, 0xe6, 0x0c, 0x77, 0xfe, 0x26, 0x10, 0x13, 0xfe, 0x13,
+ 0x00, 0xd3, 0x13, 0xfe, 0x47, 0x00, 0xa6, 0x13, 0xfe, 0x41, 0x00,
+ 0x9e, 0x13, 0xfe, 0x24, 0x00, 0x04, 0x78, 0x29, 0x27, 0xee, 0x77,
+ 0xfe, 0x04, 0xe6, 0x1e, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0xb2,
+ 0x01, 0xea, 0x02, 0x26, 0xd5, 0x17, 0x0c, 0x4a, 0xf4, 0xdd, 0x17,
+ 0xfe, 0x31, 0x00, 0x4a, 0xbd, 0x01, 0xfe, 0x50, 0x0f, 0x02, 0xfe,
+ 0xc2, 0x01, 0x1d, 0xfe, 0x06, 0xec, 0xf8, 0x86, 0x36, 0x37, 0xbf,
+ 0x35, 0x1d, 0xfe, 0x06, 0xea, 0xf8, 0xfe, 0x47, 0x4b, 0x95, 0xfe,
+ 0x75, 0x57, 0x04, 0x56, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0e,
+ 0x79, 0xfe, 0xf4, 0x14, 0x4e, 0xe6, 0x0e, 0xc0, 0xfe, 0xea, 0x14,
+ 0xfe, 0x49, 0x54, 0x8f, 0xfe, 0x62, 0x0d, 0x0e, 0x1c, 0xfe, 0xde,
+ 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x48, 0x03, 0x0e, 0x56, 0xfe,
+ 0xc8, 0x14, 0x86, 0x36, 0x37, 0xbf, 0x35, 0x1d, 0xfe, 0xce, 0x47,
+ 0xfe, 0xbd, 0x13, 0x02, 0x26, 0x21, 0x2a, 0x05, 0x10, 0xfe, 0x78,
+ 0x12, 0x2d, 0x16, 0x55, 0x16, 0xad, 0x21, 0x47, 0x4e, 0x4a, 0x47,
+ 0x9b, 0xfe, 0x0c, 0x13, 0xfe, 0xbc, 0xf0, 0xfe, 0xfe, 0x0d, 0x08,
+ 0x06, 0x16, 0x55, 0x01, 0xfe, 0x06, 0x16, 0x04, 0xfe, 0x38, 0x01,
+ 0x30, 0xfe, 0x3a, 0x01, 0x75, 0xfe, 0x02, 0x0e, 0x04, 0xfe, 0x38,
+ 0x01, 0x1b, 0xfe, 0xf0, 0xff, 0x0f, 0xfe, 0x60, 0x01, 0x04, 0xfe,
+ 0x3a, 0x01, 0x0f, 0xfe, 0x62, 0x01, 0x20, 0x06, 0x16, 0x47, 0xfe,
+ 0x04, 0xec, 0x2a, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01, 0x46, 0x7f,
+ 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x76, 0x16, 0x11,
+ 0x47, 0xca, 0x08, 0x06, 0x03, 0x2d, 0x03, 0x21, 0x55, 0xfe, 0xf7,
+ 0x12, 0x21, 0xad, 0x6a, 0x16, 0xad, 0x05, 0x80, 0xfe, 0x93, 0x13,
+ 0xfe, 0x24, 0x1c, 0x17, 0x19, 0x4a, 0xf4, 0xdd, 0xfe, 0xd9, 0x10,
+ 0x93, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03,
+ 0x93, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03,
+ 0xfe, 0x03, 0x57, 0x93, 0x2d, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03,
+ 0x57, 0x93, 0x7d, 0x03, 0x01, 0xfe, 0xae, 0x16, 0x3f, 0x05, 0x47,
+ 0xfe, 0x0a, 0x13, 0x08, 0x1c, 0x09, 0x43, 0xd3, 0x01, 0x97, 0x01,
+ 0x9a, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x46, 0x11, 0xfe, 0xe9, 0x00,
+ 0x0a, 0x07, 0x89, 0xfe, 0x52, 0x13, 0x01, 0xfe, 0x38, 0x16, 0xfe,
+ 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0x0f, 0xfe, 0x64, 0x01, 0xfe, 0x16,
+ 0x90, 0x0f, 0xfe, 0x66, 0x01, 0x0a, 0x07, 0x45, 0xe5, 0xfe, 0x03,
+ 0x80, 0x52, 0x3e, 0x11, 0x76, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x90,
+ 0x01, 0x71, 0xfe, 0x62, 0x08, 0x6a, 0x3e, 0x11, 0x76, 0x08, 0x2a,
+ 0x09, 0x3c, 0x1d, 0x90, 0x01, 0x71, 0x64, 0x2f, 0x11, 0x76, 0x08,
+ 0x2a, 0x09, 0x3c, 0x1d, 0x90, 0x01, 0x7b, 0x03, 0xfe, 0x08, 0x1c,
+ 0x04, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x04, 0xfe, 0xae, 0x00,
+ 0xfe, 0x07, 0x58, 0x04, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x04,
+ 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x20, 0x6c,
+ 0x16, 0xf8, 0x2d, 0x0f, 0x53, 0x0f, 0x4d, 0x20, 0x10, 0x16, 0x2a,
+ 0x16, 0x3c, 0x57, 0xa0, 0xd6, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01,
+ 0x7b, 0x7f, 0x11, 0x76, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe,
+ 0x2a, 0x0f, 0xd5, 0x8c, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+ 0x18, 0x1c, 0x03, 0x1d, 0xfe, 0x0c, 0x14, 0x86, 0xfe, 0x07, 0xe6,
+ 0x37, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x96, 0x0e,
+ 0x3d, 0x01, 0x15, 0x05, 0x10, 0x2c, 0x0e, 0x1c, 0x01, 0x15, 0x05,
+ 0x10, 0xda, 0xfe, 0x44, 0x58, 0x3e, 0xfe, 0x01, 0xec, 0xbd, 0xfe,
+ 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1e, 0x9f,
+ 0x2f, 0x01, 0xea, 0xfe, 0xc9, 0x10, 0x03, 0x2b, 0x82, 0x6e, 0x23,
+ 0x24, 0xb3, 0x05, 0x1e, 0xfe, 0x48, 0x12, 0x05, 0x0c, 0xfe, 0x4c,
+ 0x12, 0x05, 0x19, 0xfe, 0x30, 0x12, 0x05, 0xcc, 0x18, 0xfe, 0xf4,
+ 0x10, 0x05, 0xfe, 0x23, 0x00, 0x18, 0xfe, 0x00, 0x11, 0x05, 0x06,
+ 0x18, 0xfe, 0x5e, 0x11, 0x05, 0x1a, 0xfe, 0x12, 0x12, 0x05, 0x00,
+ 0x18, 0x28, 0x17, 0xcc, 0x01, 0x44, 0xc6, 0x39, 0x01, 0x0b, 0x81,
+ 0x4c, 0x03, 0x39, 0x11, 0xfe, 0xcc, 0x00, 0x02, 0x26, 0x39, 0x3f,
+ 0x05, 0xc3, 0xfe, 0xe3, 0x13, 0x65, 0x3a, 0x31, 0x3b, 0x75, 0xfe,
+ 0xb2, 0x10, 0x0a, 0x07, 0x70, 0xfe, 0x72, 0x12, 0xa1, 0x42, 0x69,
+ 0x58, 0xe8, 0xfe, 0xe5, 0x55, 0x8f, 0xfe, 0x7c, 0x10, 0x21, 0x61,
+ 0xfe, 0x26, 0x13, 0x04, 0xae, 0x30, 0x8d, 0x75, 0xfe, 0xd2, 0x0c,
+ 0x0f, 0x5d, 0x12, 0x5e, 0x2d, 0x0f, 0xae, 0x0f, 0x8d, 0x01, 0xc1,
+ 0x20, 0x6c, 0x52, 0x16, 0x61, 0x01, 0xfe, 0xde, 0x12, 0xa1, 0x42,
+ 0x69, 0x58, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa,
+ 0x42, 0xfe, 0x05, 0xfa, 0x58, 0xfe, 0x91, 0x10, 0x04, 0x5f, 0x30,
+ 0x60, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0f, 0x5f, 0x12, 0x60,
+ 0xa8, 0xa1, 0x42, 0x69, 0x58, 0xe8, 0xfe, 0xe5, 0x55, 0x04, 0x5b,
+ 0x30, 0x5c, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0f, 0x5b, 0x12,
+ 0x5c, 0x0a, 0x07, 0x70, 0xfe, 0x1e, 0x12, 0x21, 0x61, 0xfe, 0x1f,
+ 0x40, 0x04, 0x5d, 0x30, 0x5e, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50,
+ 0x04, 0x5f, 0x30, 0x60, 0xfe, 0x34, 0x50, 0xfe, 0xb6, 0x50, 0x04,
+ 0x5b, 0x30, 0x5c, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x04, 0x3a,
+ 0x30, 0x3b, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0x98, 0x20,
+ 0x06, 0x16, 0xf3, 0x02, 0x7c, 0x39, 0x01, 0x0b, 0x1f, 0x4f, 0x23,
+ 0x24, 0xb3, 0x05, 0x06, 0x27, 0x4f, 0x3f, 0x05, 0xc3, 0x27, 0x7c,
+ 0x01, 0xfa, 0x1b, 0x50, 0x18, 0x4f, 0x0a, 0x07, 0x0c, 0xdc, 0x65,
+ 0x3a, 0x31, 0x3b, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x9c,
+ 0x3a, 0x9d, 0x3b, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x7c,
+ 0xfe, 0x19, 0x81, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41, 0x02, 0x7c,
+ 0x39, 0x01, 0x0b, 0x1f, 0xfe, 0xf6, 0x0f, 0x23, 0x24, 0xfe, 0xe9,
+ 0x09, 0x59, 0x19, 0xfe, 0x94, 0x12, 0x59, 0x0c, 0x4b, 0x02, 0x4f,
+ 0x2e, 0xfe, 0x7e, 0x11, 0x22, 0x32, 0x1f, 0xfe, 0xf6, 0x0f, 0x23,
+ 0x24, 0x91, 0x05, 0x19, 0x27, 0x4f, 0x01, 0x0b, 0x1f, 0xfe, 0xf6,
+ 0x0f, 0x23, 0x24, 0xfe, 0xe8, 0x09, 0x57, 0x04, 0xfe, 0x9c, 0x00,
+ 0x29, 0x35, 0xfe, 0xbb, 0x45, 0x59, 0x00, 0x40, 0x36, 0x06, 0xa0,
+ 0x50, 0xfe, 0xc0, 0x14, 0xfe, 0xf8, 0x14, 0xac, 0x3f, 0x05, 0xc2,
+ 0xfe, 0x16, 0x13, 0x04, 0xf6, 0x29, 0xce, 0x04, 0x4d, 0x29, 0x35,
+ 0x5a, 0x02, 0x7c, 0xfe, 0xc0, 0x5d, 0xfe, 0xe4, 0x14, 0xfe, 0x03,
+ 0x17, 0x04, 0x53, 0xbc, 0x0f, 0x53, 0x5a, 0x39, 0x01, 0x0b, 0x25,
+ 0x98, 0x01, 0xfe, 0x26, 0x14, 0x02, 0x98, 0x2e, 0x40, 0x22, 0x32,
+ 0x1f, 0x4f, 0x23, 0x24, 0x91, 0x05, 0x06, 0x27, 0x4f, 0xfe, 0xf6,
+ 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, 0x92, 0x14, 0xac,
+ 0xfe, 0x4a, 0xf4, 0x0c, 0x18, 0x4f, 0xfe, 0x4a, 0xf4, 0x06, 0xd1,
+ 0x3f, 0x05, 0xc2, 0xc9, 0x02, 0x7c, 0x04, 0x4d, 0xbc, 0x0f, 0x4d,
+ 0x5a, 0x39, 0x01, 0x0b, 0x25, 0x98, 0x01, 0xfe, 0x54, 0x14, 0x02,
+ 0x98, 0x25, 0xfe, 0x70, 0x12, 0x73, 0xf1, 0x73, 0x03, 0x34, 0xfe,
+ 0x6c, 0x12, 0x6b, 0xfe, 0x6c, 0x12, 0x5a, 0x39, 0x01, 0x0b, 0xfe,
+ 0xe3, 0x10, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0x1b,
+ 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08,
+ 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0x1b, 0x50, 0xfe, 0x30,
+ 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57,
+ 0x66, 0x7e, 0x03, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e,
+ 0xfe, 0x0b, 0x58, 0x03, 0x0e, 0x53, 0x01, 0x8b, 0x0e, 0x4d, 0x01,
+ 0x8b, 0x03, 0xc8, 0x1b, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00,
+ 0xf4, 0x1a, 0x66, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02,
+ 0x7d, 0xfe, 0x03, 0x7c, 0x64, 0x2f, 0x0f, 0x5b, 0x12, 0x5c, 0x9c,
+ 0x5f, 0x9d, 0x60, 0x03, 0xfe, 0x62, 0x18, 0xfe, 0x82, 0x5a, 0xfe,
+ 0xe1, 0x1a, 0xb6, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x9e, 0x18,
+ 0xfe, 0x42, 0x48, 0x77, 0x57, 0x95, 0x01, 0x0b, 0x1f, 0xfe, 0x1e,
+ 0x14, 0x23, 0x24, 0xfe, 0xe9, 0x09, 0xfe, 0xc1, 0x59, 0x01, 0x0b,
+ 0x1f, 0xfe, 0x1e, 0x14, 0x23, 0x24, 0xfe, 0xe8, 0x0a, 0x04, 0xf6,
+ 0x29, 0xfe, 0xc4, 0x12, 0x2d, 0xb1, 0x1e, 0xdc, 0x59, 0xcd, 0x74,
+ 0xfe, 0x6c, 0x13, 0x4b, 0x08, 0x06, 0x09, 0xcd, 0xa0, 0xfe, 0x00,
+ 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa6, 0xff, 0x02,
+ 0x83, 0x55, 0xb1, 0x19, 0xfe, 0x12, 0x13, 0x72, 0xfe, 0x30, 0x00,
+ 0x8f, 0xfe, 0xc6, 0x13, 0x09, 0x85, 0x08, 0x06, 0xfe, 0x56, 0x10,
+ 0xb1, 0x0c, 0xfe, 0x16, 0x13, 0x72, 0xfe, 0x64, 0x00, 0x8f, 0xfe,
+ 0xc6, 0x13, 0x0e, 0xfe, 0x64, 0x00, 0x09, 0x88, 0x08, 0x06, 0xfe,
+ 0x28, 0x10, 0xb1, 0x06, 0xfe, 0x60, 0x13, 0x72, 0xfe, 0xc8, 0x00,
+ 0x8f, 0xfe, 0xc6, 0x13, 0x0e, 0xfe, 0xc8, 0x00, 0x09, 0x55, 0x08,
+ 0x06, 0xa8, 0x72, 0xfe, 0x90, 0x01, 0xed, 0xfe, 0xd2, 0x13, 0x95,
+ 0xaa, 0xfe, 0x43, 0xf4, 0xad, 0xfe, 0x56, 0xf0, 0xfe, 0xe4, 0x13,
+ 0xfe, 0x04, 0xf4, 0x63, 0xfe, 0x43, 0xf4, 0x88, 0xfe, 0xf3, 0x10,
+ 0xb0, 0x01, 0xfe, 0xae, 0x12, 0x1b, 0x50, 0xd4, 0xfe, 0x00, 0x17,
+ 0xfe, 0x4d, 0xe4, 0x6c, 0xed, 0xfe, 0x18, 0x14, 0xa3, 0x6c, 0xfe,
+ 0x14, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x1a, 0xed, 0xfe,
+ 0x18, 0x14, 0xa3, 0x1a, 0x9e, 0x57, 0x95, 0x08, 0x06, 0xfe, 0xb4,
+ 0x56, 0xfe, 0xc3, 0x58, 0x03, 0x57, 0x08, 0x0c, 0x03, 0x14, 0x06,
+ 0x01, 0x0b, 0x25, 0xec, 0x14, 0x0c, 0x01, 0x0b, 0x25, 0xec, 0x14,
+ 0x19, 0x01, 0x0b, 0x25, 0xec, 0x73, 0xfe, 0x89, 0x49, 0x01, 0x0b,
+ 0x03, 0x14, 0x06, 0x01, 0x0b, 0x25, 0xb7, 0x14, 0x19, 0x01, 0x0b,
+ 0x25, 0xb7, 0x14, 0x06, 0x01, 0x0b, 0x25, 0xb7, 0xfe, 0x89, 0x49,
+ 0x01, 0x0b, 0x25, 0xb7, 0x73, 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x03,
+ 0x57, 0x03, 0x21, 0xe0, 0x05, 0x06, 0xfe, 0x44, 0x13, 0xaf, 0x16,
+ 0xe0, 0xfe, 0x49, 0xf4, 0x00, 0x4b, 0x73, 0xc6, 0x5a, 0xfe, 0x01,
+ 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x0b, 0x3f, 0x05, 0xfe, 0xe3,
+ 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0xd6, 0x14, 0x2d, 0x16, 0xf3,
+ 0x01, 0x4c, 0x21, 0xf3, 0x05, 0x06, 0x40, 0x0a, 0x41, 0x06, 0x38,
+ 0x03, 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x15, 0x05,
+ 0x10, 0xfe, 0x1e, 0x12, 0x48, 0xe7, 0x8e, 0x01, 0x2c, 0xfe, 0x90,
+ 0x4d, 0xde, 0x10, 0xfe, 0xc5, 0x59, 0x01, 0x2c, 0xfe, 0x8d, 0x56,
+ 0xb6, 0x48, 0x03, 0x48, 0x31, 0x8a, 0x01, 0x15, 0x48, 0x8e, 0x01,
+ 0x2c, 0xe2, 0x10, 0xde, 0x10, 0x31, 0x54, 0x72, 0x1c, 0x84, 0x0e,
+ 0x56, 0x01, 0xab, 0x03, 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0xc3, 0x58,
+ 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1a, 0x12, 0x48, 0xe7, 0x8e, 0x01,
+ 0x2c, 0xe2, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, 0x59, 0x01, 0x2c,
+ 0x48, 0x03, 0x48, 0x31, 0x54, 0x01, 0x15, 0x48, 0x8e, 0x01, 0x2c,
+ 0xe2, 0x10, 0xde, 0x10, 0x31, 0x54, 0x72, 0x1c, 0x84, 0x0e, 0x56,
+ 0x01, 0xab, 0x03, 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0x43, 0x58, 0x01,
+ 0x15, 0xfe, 0x42, 0x48, 0x8e, 0x01, 0x2c, 0xfe, 0xc0, 0x5a, 0xb0,
+ 0xfe, 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, 0x4a, 0x46, 0xdc, 0x93,
+ 0x7d, 0x05, 0x10, 0xfe, 0x2e, 0x13, 0x69, 0x54, 0xfe, 0x4d, 0xf4,
+ 0x1c, 0xfe, 0x1c, 0x13, 0x0e, 0x56, 0x01, 0x8b, 0xaa, 0xfe, 0x40,
+ 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x2c, 0xfe, 0x00, 0x07, 0x7d, 0x05,
+ 0x10, 0x84, 0x69, 0x8a, 0xfe, 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe,
+ 0x45, 0x58, 0x01, 0x2c, 0xfe, 0x8d, 0x56, 0xb6, 0xfe, 0x80, 0x4c,
+ 0xfe, 0x05, 0x17, 0x03, 0x09, 0x10, 0x6f, 0x67, 0xfe, 0x60, 0x01,
+ 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xdb, 0x37,
+ 0x94, 0xfe, 0x1a, 0x16, 0x01, 0xfe, 0x28, 0x17, 0xfe, 0x0c, 0x13,
+ 0x87, 0x37, 0x67, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xba,
+ 0x27, 0xfe, 0x0a, 0x16, 0xfe, 0xe2, 0x10, 0x09, 0x10, 0x6f, 0x04,
+ 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1a, 0xfe, 0x18, 0x58, 0x04,
+ 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x87, 0x1a, 0xfe, 0x3c, 0x90,
+ 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x67, 0xfe, 0x38, 0x00,
+ 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1a, 0x94, 0xfe, 0x64, 0x16,
+ 0xfe, 0xbe, 0x14, 0x35, 0x03, 0xba, 0x27, 0xfe, 0x3c, 0x16, 0xfe,
+ 0xa4, 0x10, 0x09, 0x10, 0x6f, 0xb6, 0xfe, 0x18, 0xdf, 0xfe, 0x19,
+ 0xdf, 0xdb, 0x42, 0x94, 0xfe, 0x86, 0x16, 0xfe, 0x9c, 0x14, 0xfe,
+ 0x18, 0x13, 0x87, 0x42, 0x67, 0x1e, 0xfe, 0xaf, 0x19, 0xfe, 0x98,
+ 0xe7, 0x00, 0xa2, 0x07, 0xfe, 0x7f, 0x00, 0xfe, 0x05, 0x40, 0x03,
+ 0xba, 0x27, 0xfe, 0x7a, 0x16, 0xfe, 0x6c, 0x10, 0x09, 0x10, 0x6f,
+ 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x87, 0xd9, 0x67, 0x1e, 0xfe,
+ 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xd9, 0x94, 0xfe, 0xc6, 0x16, 0xfe,
+ 0x5c, 0x14, 0x35, 0x03, 0xba, 0x27, 0xfe, 0xb2, 0x16, 0xfe, 0x42,
+ 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x6f, 0xfe, 0x18, 0xfe, 0x5d, 0xfe,
+ 0x19, 0xfe, 0x5e, 0xc8, 0xdb, 0x45, 0x94, 0xfe, 0xec, 0x16, 0xfe,
+ 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x87, 0x45, 0x4e, 0xfe, 0x83, 0x58,
+ 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10,
+ 0x11, 0xfe, 0xdd, 0x00, 0x64, 0x2f, 0x03, 0x64, 0x2f, 0xfe, 0x12,
+ 0x45, 0x27, 0xfe, 0xdc, 0x16, 0x17, 0x06, 0x4a, 0xf4, 0xdd, 0x02,
+ 0x26, 0xfe, 0x39, 0xf0, 0xfe, 0x30, 0x17, 0x2d, 0x03, 0xfe, 0x7e,
+ 0x18, 0x1b, 0x19, 0x83, 0x08, 0x0d, 0x03, 0x6f, 0x04, 0xdf, 0x1b,
+ 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x1d, 0x0e, 0x1c, 0x01,
+ 0x15, 0x05, 0x10, 0x40, 0x3e, 0xfe, 0x78, 0x14, 0xfe, 0x34, 0x12,
+ 0x50, 0x86, 0x36, 0x37, 0xbf, 0xfe, 0xe9, 0x13, 0x1d, 0x0e, 0x3d,
+ 0x01, 0x15, 0x05, 0x10, 0x40, 0x3e, 0xfe, 0x56, 0x14, 0xe1, 0x50,
+ 0x86, 0x36, 0x37, 0xbf, 0xfe, 0xe9, 0x13, 0x09, 0x0c, 0x03, 0xfe,
+ 0x9c, 0xe7, 0x0c, 0x13, 0xfe, 0x15, 0x00, 0x90, 0x9f, 0x2f, 0x01,
+ 0xea, 0x09, 0x06, 0x03, 0x0a, 0x41, 0x37, 0x38, 0x08, 0x3d, 0x09,
+ 0x99, 0x01, 0x46, 0x11, 0x47, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b,
+ 0x09, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x65, 0xf7,
+ 0x31, 0x76, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x03, 0x21,
+ 0xbe, 0x52, 0x16, 0xbe, 0x03, 0x0e, 0xc0, 0x01, 0x15, 0xe6, 0x0e,
+ 0x79, 0x01, 0x15, 0xfe, 0x49, 0x44, 0x27, 0xfe, 0x26, 0x18, 0x0e,
+ 0x1c, 0x01, 0x15, 0x05, 0x10, 0x40, 0x0e, 0x56, 0x01, 0xab, 0x0e,
+ 0x79, 0x01, 0x15, 0x52, 0x7d, 0x03, 0xfe, 0x40, 0x5e, 0xfe, 0xe2,
+ 0x08, 0xfe, 0xc0, 0x4c, 0x21, 0x3c, 0x05, 0x10, 0xfe, 0x52, 0x12,
+ 0x3e, 0x05, 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, 0x19,
+ 0xf4, 0xfe, 0x7f, 0x00, 0xd4, 0xfe, 0xe2, 0x08, 0x52, 0x3e, 0x3f,
+ 0x05, 0x76, 0xa5, 0xfe, 0x82, 0x48, 0xfe, 0x01, 0x80, 0xfe, 0xd7,
+ 0x10, 0xfe, 0xc4, 0x48, 0x08, 0x2a, 0x09, 0x3c, 0xfe, 0x40, 0x5f,
+ 0x1d, 0x01, 0x46, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x14, 0x46, 0x08,
+ 0x2a, 0x09, 0x3c, 0x01, 0x46, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x40,
+ 0x4a, 0x6a, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, 0xfe, 0x82, 0x48,
+ 0xfe, 0x04, 0x17, 0x03, 0xeb, 0x19, 0x74, 0xfe, 0xae, 0x18, 0x04,
+ 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xeb, 0xcc,
+ 0x74, 0xfe, 0xc0, 0x18, 0x04, 0xfe, 0x92, 0x00, 0xc7, 0x1e, 0xd8,
+ 0xeb, 0xfe, 0x0b, 0x00, 0x74, 0xfe, 0xd2, 0x18, 0x04, 0xfe, 0x94,
+ 0x00, 0xc7, 0x1a, 0xfe, 0x08, 0x10, 0x04, 0xfe, 0x96, 0x00, 0xc7,
+ 0x85, 0xfe, 0x4e, 0x45, 0xd1, 0xfe, 0x0a, 0x45, 0xff, 0x04, 0x68,
+ 0x54, 0xfe, 0xf1, 0x10, 0x1b, 0x6c, 0x03, 0x05, 0x80, 0xfe, 0x5a,
+ 0xf0, 0xfe, 0xfe, 0x18, 0x20, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
+ 0x05, 0x1e, 0xfe, 0x5a, 0xf0, 0xfe, 0x0c, 0x19, 0x20, 0xcd, 0xfe,
+ 0x26, 0x10, 0x05, 0x19, 0x83, 0x20, 0x85, 0xd8, 0x05, 0x0c, 0x83,
+ 0x20, 0x88, 0xfe, 0x0e, 0x10, 0x05, 0x06, 0x83, 0x20, 0x55, 0xc6,
+ 0xaf, 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01, 0x44, 0x2e, 0xfe, 0x3c,
+ 0x19, 0x04, 0x6e, 0xb0, 0x03, 0x22, 0xfe, 0x54, 0x19, 0xfe, 0x14,
+ 0xf0, 0x0b, 0x2e, 0xfe, 0x50, 0x19, 0x03, 0xff, 0x15, 0x00, 0x00,
+};
+
+const struct adw_mcode adw_asc3550_mcode_data =
+{
+ adw_asc3550_mcode,
+ 0x04FFFF0E,
+ sizeof(adw_asc3550_mcode)
+};
+
+const u_int8_t adw_asc38C0800_mcode[] =
+{
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48,
+ 0xe4, 0x01, 0x00, 0x18, 0xe4, 0x00, 0xf6, 0x01, 0xf6, 0x18, 0x80,
+ 0x02, 0x00, 0x40, 0x1a, 0x00, 0xfa, 0xff, 0xff, 0x03, 0xf6, 0xff,
+ 0x00, 0x82, 0xe7, 0x01, 0xfa, 0x9e, 0xe7, 0x09, 0xe7, 0x1a, 0x0f,
+ 0x00, 0xea, 0x01, 0xe6, 0x03, 0x00, 0x55, 0xf0, 0x18, 0xf4, 0x1e,
+ 0xf0, 0x3e, 0x57, 0x04, 0x00, 0x3e, 0x01, 0x85, 0xf0, 0x00, 0xe6,
+ 0x03, 0xfc, 0x08, 0x00, 0x2c, 0x1a, 0x32, 0xf0, 0x86, 0xf0, 0xbe,
+ 0x0d, 0xd4, 0x01, 0xd5, 0xf0, 0x00, 0xec, 0x01, 0xfc, 0x38, 0x54,
+ 0x98, 0x57, 0xbc, 0x00, 0x0c, 0x1c, 0xb1, 0xf0, 0x3c, 0x00, 0xb4,
+ 0x00, 0xb8, 0x0d, 0x00, 0x57, 0x01, 0xf0, 0x02, 0x13, 0x02, 0xfc,
+ 0x03, 0xe6, 0x10, 0x00, 0x18, 0x40, 0x3e, 0x1c, 0x44, 0x13, 0x6c,
+ 0x01, 0x6e, 0x01, 0xbd, 0x00, 0xe0, 0x00, 0x02, 0x80, 0x30, 0xe4,
+ 0x3e, 0x00, 0x74, 0x01, 0x76, 0x01, 0x7c, 0x16, 0x80, 0x00, 0xb9,
+ 0x54, 0xbb, 0x00, 0xee, 0x13, 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea,
+ 0x02, 0x48, 0x02, 0xfa, 0x04, 0x12, 0x08, 0x12, 0x3c, 0x56, 0x4e,
+ 0x01, 0x5d, 0xf0, 0x7a, 0x01, 0x7e, 0x10, 0xb6, 0x00, 0xc2, 0x10,
+ 0xee, 0x08, 0x00, 0x80, 0x05, 0xfc, 0x10, 0x44, 0x24, 0x01, 0x28,
+ 0x01, 0x32, 0x00, 0x3c, 0x01, 0x40, 0x00, 0x4b, 0xe4, 0x4b, 0xf4,
+ 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x78,
+ 0x01, 0x7c, 0x01, 0xbb, 0x55, 0xc2, 0x0d, 0x00, 0x01, 0x02, 0xee,
+ 0x03, 0x58, 0x03, 0xf7, 0x03, 0xfa, 0x04, 0x80, 0x08, 0x44, 0x09,
+ 0xf0, 0x0f, 0x00, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, 0x4e, 0x1c,
+ 0x5b, 0xf0, 0x62, 0x0a, 0xaa, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc0,
+ 0x15, 0xcc, 0x10, 0x00, 0x4c, 0x00, 0xdc, 0x02, 0x4a, 0x04, 0xfc,
+ 0x05, 0x00, 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, 0x06, 0xf7, 0x08,
+ 0x13, 0x0a, 0x10, 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, 0x10, 0x0f,
+ 0x20, 0x00, 0x20, 0x16, 0x2a, 0x01, 0x32, 0x1c, 0x36, 0x00, 0x42,
+ 0x54, 0x44, 0x55, 0x45, 0x5a, 0x52, 0x0c, 0x59, 0xf0, 0x5c, 0xf0,
+ 0x69, 0x08, 0x6e, 0x0b, 0x83, 0x59, 0xb8, 0xf0, 0xbd, 0x56, 0xcc,
+ 0x18, 0xce, 0x10, 0xd8, 0x18, 0xf0, 0x00, 0x01, 0x48, 0x04, 0x10,
+ 0x04, 0xea, 0x04, 0xf6, 0x05, 0x80, 0x05, 0xe6, 0x06, 0x00, 0x06,
+ 0x0f, 0x06, 0x12, 0x0b, 0xf0, 0x0c, 0x10, 0x0c, 0xf0, 0x10, 0x13,
+ 0x12, 0x10, 0x19, 0x00, 0x19, 0xe4, 0x30, 0x1c, 0x33, 0x00, 0x34,
+ 0x00, 0x38, 0x44, 0x40, 0x5c, 0x4a, 0xe4, 0x62, 0x1a, 0x68, 0x08,
+ 0x68, 0x54, 0x6c, 0x15, 0x70, 0x15, 0x83, 0x55, 0x83, 0x5a, 0x91,
+ 0x44, 0xa4, 0x00, 0xac, 0x13, 0xb0, 0x57, 0xb5, 0x00, 0xb8, 0x17,
+ 0xba, 0x00, 0xce, 0x45, 0xd0, 0x00, 0xe1, 0x00, 0xe5, 0x55, 0xe7,
+ 0x00, 0x00, 0x54, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6, 0x03, 0xa1,
+ 0x04, 0x13, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a,
+ 0x12, 0x0a, 0xf0, 0x0c, 0x12, 0x0c, 0x13, 0x0c, 0x90, 0x0e, 0x13,
+ 0x10, 0x04, 0x10, 0x10, 0x12, 0x1c, 0x19, 0x81, 0x1a, 0x10, 0x1c,
+ 0x00, 0x1c, 0x12, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c, 0x20, 0xe7,
+ 0x22, 0x01, 0x26, 0x01, 0x2a, 0x12, 0x2c, 0x0f, 0x30, 0xe7, 0x32,
+ 0x15, 0x34, 0x1c, 0x36, 0x1c, 0x38, 0x12, 0x3a, 0x55, 0x3f, 0x00,
+ 0x41, 0x58, 0x43, 0x48, 0x46, 0x1c, 0x4e, 0xe4, 0x76, 0x02, 0x77,
+ 0x57, 0x78, 0x03, 0x89, 0x48, 0x8e, 0x90, 0x98, 0x80, 0x99, 0x00,
+ 0xfe, 0x9c, 0xf0, 0x27, 0x02, 0xfe, 0xe0, 0x0d, 0xff, 0x10, 0x00,
+ 0x00, 0xfe, 0xc6, 0x01, 0xfe, 0x56, 0x1a, 0x00, 0xfe, 0xc4, 0x01,
+ 0xfe, 0x84, 0x01, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x6a, 0x13, 0xfe,
+ 0x05, 0x05, 0xff, 0x40, 0x00, 0x00, 0x0e, 0xff, 0x09, 0x00, 0x00,
+ 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, 0x00,
+ 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, 0x00, 0x00, 0xfe, 0x78,
+ 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7,
+ 0xfe, 0xc4, 0x01, 0x2e, 0x88, 0x0b, 0x01, 0xfe, 0xca, 0x0f, 0xfe,
+ 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x88, 0x0b, 0x1c, 0x2e, 0xfe, 0x3d,
+ 0xf0, 0xfe, 0xfc, 0x01, 0xfe, 0x20, 0xf0, 0xdc, 0x04, 0x5f, 0x4f,
+ 0x02, 0xfe, 0xfc, 0x0d, 0x01, 0xfe, 0x5c, 0x0e, 0xfe, 0xe9, 0x12,
+ 0x02, 0xfe, 0x08, 0x03, 0xfe, 0x28, 0x1c, 0x04, 0xfe, 0xa6, 0x00,
+ 0xfe, 0xdd, 0x12, 0x47, 0x12, 0xfe, 0xa6, 0x00, 0xcd, 0xfe, 0x48,
+ 0xf0, 0xfe, 0x80, 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0x9a, 0x02, 0xfe,
+ 0x4a, 0xf0, 0xfe, 0xb8, 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x4a, 0x02,
+ 0xfe, 0x47, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x3e,
+ 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x42, 0x02, 0xfe, 0x45, 0xf0, 0xfe,
+ 0x46, 0x02, 0x09, 0x0b, 0xa4, 0x09, 0x06, 0x12, 0xc1, 0x02, 0x27,
+ 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xfe, 0xed,
+ 0x10, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x2c, 0x18,
+ 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xfe, 0xa8, 0x00, 0x0f, 0x7c,
+ 0x01, 0xaa, 0x02, 0x27, 0x17, 0x5e, 0x4c, 0xc4, 0x01, 0xfe, 0x40,
+ 0x10, 0x0f, 0x7c, 0x01, 0x8e, 0xfe, 0xbd, 0x10, 0x0f, 0x7c, 0x01,
+ 0x8e, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x09,
+ 0x06, 0x12, 0xc1, 0x2e, 0x1b, 0x27, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc,
+ 0x01, 0x28, 0xfe, 0x8e, 0x02, 0xfe, 0x5a, 0x1c, 0xde, 0xfe, 0x14,
+ 0x1c, 0x17, 0xfe, 0x30, 0x00, 0x4c, 0xc4, 0x01, 0xfe, 0x30, 0x10,
+ 0x09, 0x06, 0x12, 0xc1, 0x02, 0xfe, 0xc6, 0x01, 0x29, 0x2d, 0x05,
+ 0x10, 0x35, 0xfe, 0x69, 0x10, 0x09, 0x06, 0x12, 0xc1, 0xfe, 0x04,
+ 0xec, 0x2d, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x01, 0x45, 0x82, 0xfe,
+ 0x05, 0xf6, 0xfe, 0xa8, 0x00, 0x01, 0xfe, 0x56, 0x17, 0x0a, 0x41,
+ 0x8f, 0x39, 0x11, 0x48, 0x1c, 0xd2, 0x08, 0x1e, 0x09, 0x52, 0x01,
+ 0x90, 0x02, 0x27, 0x0f, 0x3f, 0x01, 0x15, 0x05, 0x10, 0xdb, 0x08,
+ 0x1e, 0x09, 0x52, 0x01, 0x7e, 0xfe, 0x28, 0x10, 0x0f, 0xc8, 0x01,
+ 0x15, 0xf2, 0x0f, 0x7d, 0x01, 0x15, 0xfe, 0x49, 0x54, 0x79, 0xfe,
+ 0x16, 0x03, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x90, 0x02, 0x27, 0x2e,
+ 0x82, 0xfe, 0x02, 0xe8, 0x31, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
+ 0xf7, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xdc, 0xfe, 0x40, 0x1c,
+ 0x1b, 0xf8, 0xfe, 0x26, 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0xa0, 0xf0,
+ 0xfe, 0x62, 0x03, 0xfe, 0x11, 0xf0, 0xdc, 0xfe, 0x0e, 0x10, 0xfe,
+ 0x9f, 0xf0, 0xfe, 0x82, 0x03, 0xf4, 0x13, 0xfe, 0x11, 0x00, 0x02,
+ 0x6b, 0x2e, 0xfe, 0x48, 0x1c, 0xf4, 0x1b, 0xf8, 0x34, 0xf8, 0xfe,
+ 0x82, 0xf0, 0xfe, 0x88, 0x03, 0x2b, 0x29, 0xc6, 0x72, 0x16, 0xc6,
+ 0x0f, 0x7d, 0x01, 0x15, 0x72, 0x80, 0x08, 0x1e, 0x09, 0x52, 0x01,
+ 0x45, 0x11, 0x3f, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x90, 0xfe, 0x9c,
+ 0x32, 0x11, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xce, 0x03, 0x1b, 0x32,
+ 0x1f, 0xfe, 0xde, 0x03, 0x01, 0x55, 0xd3, 0xfe, 0xee, 0x03, 0x73,
+ 0x97, 0xd7, 0xfe, 0xae, 0x06, 0x02, 0x26, 0x04, 0x7c, 0x2c, 0x19,
+ 0xfe, 0x20, 0x05, 0x17, 0x8b, 0x01, 0x3b, 0x01, 0x9f, 0x01, 0xa1,
+ 0x34, 0xfe, 0x60, 0x02, 0x02, 0xf6, 0xf4, 0x2e, 0x88, 0x18, 0xfe,
+ 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xf7, 0xfe, 0x48, 0x1c, 0x92, 0x01,
+ 0xfe, 0x9c, 0x13, 0xb3, 0xfe, 0x96, 0xf0, 0xfe, 0x28, 0x04, 0x2f,
+ 0xfe, 0x2c, 0x04, 0x34, 0x27, 0x0f, 0x3f, 0x01, 0x15, 0x05, 0x10,
+ 0x19, 0xfe, 0x0c, 0x05, 0x4d, 0x7a, 0xa5, 0x31, 0x86, 0x76, 0x1b,
+ 0x32, 0x1f, 0x26, 0x04, 0x7c, 0x2c, 0xfe, 0x10, 0x12, 0x17, 0x8b,
+ 0x01, 0x3b, 0x34, 0xfe, 0x60, 0x02, 0x02, 0xf6, 0x21, 0xfe, 0xa0,
+ 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e, 0x12, 0x0a, 0x07, 0x06, 0xfe,
+ 0x56, 0x12, 0x24, 0x23, 0x9a, 0x01, 0x0c, 0x86, 0x76, 0x1f, 0xfe,
+ 0xdc, 0x04, 0x24, 0x23, 0x9a, 0x01, 0x0c, 0x1f, 0x26, 0x24, 0x23,
+ 0xba, 0xfe, 0x4c, 0x44, 0xfe, 0x32, 0x12, 0x51, 0xfe, 0x44, 0x48,
+ 0x08, 0xfe, 0x93, 0x00, 0xfe, 0x4c, 0x54, 0x79, 0xfe, 0x0c, 0x05,
+ 0x82, 0xa5, 0x31, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x48,
+ 0x13, 0x40, 0x05, 0xfe, 0xcc, 0x00, 0xfe, 0x40, 0x13, 0x0a, 0x07,
+ 0x06, 0xef, 0xfe, 0x06, 0x10, 0x24, 0x23, 0xba, 0x0a, 0x07, 0x38,
+ 0xe2, 0x17, 0xa9, 0x0a, 0x07, 0x06, 0x4f, 0x17, 0xfe, 0x0d, 0x00,
+ 0x01, 0x3b, 0x34, 0xfe, 0xa0, 0x0d, 0x02, 0x26, 0x3a, 0x11, 0xfe,
+ 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xb7, 0x03, 0x17, 0xa9, 0x01, 0x3b,
+ 0x34, 0x27, 0x1b, 0x27, 0x02, 0xfe, 0x14, 0x05, 0xfe, 0x42, 0x5b,
+ 0x88, 0x18, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xf7, 0x17, 0x46,
+ 0xfe, 0x07, 0x80, 0xfe, 0x31, 0x44, 0x0a, 0x07, 0x0b, 0xfe, 0x78,
+ 0x13, 0xfe, 0x20, 0x80, 0x05, 0x18, 0xfe, 0x70, 0x12, 0x75, 0x07,
+ 0x06, 0xfe, 0x60, 0x13, 0x04, 0xfe, 0xa2, 0x00, 0x2c, 0x19, 0xfe,
+ 0xac, 0x05, 0xfe, 0x31, 0xe4, 0x60, 0x75, 0x07, 0x0b, 0xfe, 0x4a,
+ 0x13, 0x04, 0xfe, 0xa0, 0x00, 0x2c, 0xfe, 0x42, 0x12, 0x63, 0x2f,
+ 0xfe, 0x6c, 0x05, 0x1b, 0x32, 0xf9, 0x01, 0x0c, 0x25, 0xfe, 0xc4,
+ 0x05, 0x11, 0xfe, 0xe3, 0x00, 0x2b, 0x75, 0xfe, 0x4a, 0xf0, 0xfe,
+ 0x96, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x90, 0x05, 0xad, 0x20, 0xfe,
+ 0x21, 0x00, 0x8a, 0x20, 0xfe, 0x22, 0x00, 0xa4, 0x20, 0x8f, 0xfe,
+ 0x09, 0x48, 0x01, 0x0c, 0x25, 0xfe, 0xc4, 0x05, 0xfe, 0xe2, 0x08,
+ 0x75, 0x07, 0xe1, 0x4f, 0x01, 0xc2, 0x20, 0x06, 0x16, 0xe8, 0x4c,
+ 0xfe, 0x27, 0x01, 0x0a, 0x07, 0x38, 0xe9, 0x47, 0x01, 0xbd, 0x17,
+ 0xa9, 0x0a, 0x07, 0x06, 0x4f, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x3b,
+ 0x01, 0x9f, 0x01, 0xa1, 0x34, 0xfe, 0xa0, 0x0d, 0x02, 0x26, 0x04,
+ 0xfe, 0x9c, 0x00, 0x2c, 0xfe, 0x3e, 0x12, 0x04, 0x5c, 0x2c, 0xfe,
+ 0x36, 0x13, 0x47, 0x01, 0xbd, 0x25, 0xfe, 0x3c, 0x06, 0x0f, 0x06,
+ 0x75, 0x07, 0x22, 0xfe, 0x02, 0x12, 0x6a, 0x01, 0xfe, 0x06, 0x15,
+ 0x1f, 0xfe, 0x32, 0x06, 0x11, 0xc9, 0x01, 0x55, 0x11, 0xfe, 0xe5,
+ 0x00, 0x04, 0x5c, 0xc3, 0x0d, 0x5c, 0x04, 0xfe, 0x9e, 0x00, 0x2c,
+ 0xfe, 0x62, 0x12, 0x04, 0x56, 0x2c, 0xfe, 0x5a, 0x13, 0x01, 0xfe,
+ 0x7e, 0x19, 0x01, 0xfe, 0xe8, 0x19, 0xf3, 0xa8, 0xf1, 0x08, 0x6c,
+ 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0x1a, 0x59, 0xd1, 0xa8, 0x74,
+ 0x47, 0x01, 0xbd, 0x25, 0xfe, 0xa6, 0x06, 0x75, 0x07, 0x1d, 0xab,
+ 0x9e, 0x0f, 0x5e, 0x01, 0xfe, 0x34, 0x15, 0x1f, 0xfe, 0x9c, 0x06,
+ 0x11, 0xc9, 0x01, 0x55, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x56, 0xc3,
+ 0x0d, 0x56, 0x09, 0x06, 0x01, 0xbd, 0xfe, 0x9c, 0x32, 0x78, 0x92,
+ 0x01, 0xfe, 0x9c, 0x13, 0xb3, 0x11, 0xfe, 0xe2, 0x00, 0x2f, 0xfe,
+ 0xbe, 0x06, 0x1b, 0x32, 0xd7, 0xfe, 0xda, 0x06, 0x85, 0xfe, 0x78,
+ 0x07, 0xd3, 0xfe, 0x80, 0x07, 0x73, 0x97, 0x02, 0x26, 0x0a, 0x07,
+ 0x0b, 0xfe, 0x2e, 0x12, 0x14, 0x18, 0x01, 0x0c, 0x14, 0x00, 0x01,
+ 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0xfe, 0x99,
+ 0xa4, 0x01, 0x0c, 0x14, 0x00, 0x02, 0xfe, 0x50, 0x08, 0x71, 0x07,
+ 0x1d, 0xef, 0x0a, 0x07, 0x1d, 0xfe, 0x30, 0x13, 0x14, 0xfe, 0x1b,
+ 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c,
+ 0x14, 0x00, 0x01, 0x0c, 0x14, 0x06, 0x01, 0x0c, 0x14, 0x00, 0x02,
+ 0xfe, 0x0a, 0x0c, 0x6a, 0xfe, 0x9a, 0x81, 0x6f, 0x8f, 0xfe, 0x09,
+ 0x6f, 0xfe, 0x93, 0x45, 0x19, 0xfe, 0x88, 0x07, 0x2f, 0xfe, 0x60,
+ 0x07, 0x1b, 0x32, 0xd7, 0xfe, 0x58, 0x07, 0x73, 0x97, 0x85, 0xfe,
+ 0x78, 0x07, 0x02, 0x26, 0x01, 0x55, 0x02, 0xfe, 0xbe, 0x06, 0x14,
+ 0x22, 0x02, 0xfe, 0xbe, 0x06, 0xfe, 0x9c, 0xf7, 0xfe, 0xf0, 0x07,
+ 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x53, 0xfe, 0xd6, 0x07, 0x0d,
+ 0x66, 0x12, 0x67, 0x0a, 0x41, 0x60, 0x39, 0x01, 0xfe, 0x14, 0x19,
+ 0x05, 0x10, 0x87, 0xfe, 0x83, 0xe7, 0xfe, 0x95, 0x00, 0x8a, 0xfe,
+ 0x03, 0x40, 0x0a, 0x41, 0x46, 0x39, 0x01, 0xc5, 0xb6, 0xfe, 0x1f,
+ 0x40, 0x16, 0x68, 0x01, 0xfe, 0xbe, 0x13, 0xfe, 0x08, 0x50, 0xfe,
+ 0x8a, 0x50, 0xfe, 0x34, 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90,
+ 0xfe, 0x8a, 0x90, 0x0d, 0x64, 0x12, 0x65, 0xda, 0xfa, 0x0d, 0x3c,
+ 0x12, 0x3d, 0xfe, 0x60, 0x10, 0x0a, 0x07, 0x60, 0xe9, 0xfe, 0x2c,
+ 0x90, 0xfe, 0xae, 0x90, 0x0d, 0x66, 0x12, 0x67, 0x0a, 0x07, 0x46,
+ 0xd1, 0x01, 0xc5, 0xfe, 0x1f, 0x80, 0x16, 0x68, 0xfe, 0x34, 0x90,
+ 0xfe, 0xb6, 0x90, 0x0d, 0x43, 0x12, 0x44, 0xfe, 0x08, 0x90, 0xfe,
+ 0x8a, 0x90, 0x0d, 0x64, 0x12, 0x65, 0xa7, 0x07, 0x46, 0xdb, 0xda,
+ 0xfa, 0x0d, 0x3c, 0x12, 0x3d, 0xad, 0xfe, 0x28, 0x90, 0xfe, 0xaa,
+ 0x90, 0x0d, 0x3c, 0x12, 0x3d, 0x0d, 0x30, 0x12, 0x42, 0x2b, 0x0d,
+ 0x54, 0x0d, 0x69, 0x0a, 0x41, 0x22, 0x39, 0x2e, 0x08, 0x84, 0x2f,
+ 0xfe, 0x70, 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x84, 0x08, 0xa3, 0x19,
+ 0x32, 0x2e, 0x5b, 0xfe, 0xed, 0x10, 0xac, 0xfe, 0xa8, 0x08, 0xae,
+ 0xfe, 0xc4, 0x08, 0x85, 0xfe, 0x9c, 0x08, 0xd3, 0xfe, 0xa2, 0x08,
+ 0x73, 0x97, 0x02, 0x26, 0x01, 0x55, 0xfe, 0xc9, 0x10, 0x14, 0x22,
+ 0xfe, 0xc9, 0x10, 0x71, 0x07, 0x06, 0xfe, 0x10, 0x12, 0x71, 0x07,
+ 0x0b, 0x50, 0x0a, 0x07, 0x0b, 0xfe, 0xa6, 0x12, 0xfe, 0x2e, 0x1c,
+ 0xb0, 0x71, 0x07, 0x06, 0x50, 0x71, 0x07, 0x0b, 0xfe, 0x92, 0x12,
+ 0xfe, 0x2c, 0x1c, 0xa7, 0x07, 0x46, 0xaf, 0xa7, 0x41, 0x46, 0xfe,
+ 0x05, 0x40, 0xda, 0xfa, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0xfe,
+ 0xaa, 0xf0, 0xfe, 0xf6, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x24, 0x09,
+ 0x02, 0xfe, 0x02, 0x0a, 0xfe, 0xb7, 0xf0, 0xfe, 0x20, 0x09, 0xfe,
+ 0x02, 0xf6, 0x1d, 0x6a, 0xfe, 0x70, 0x18, 0xfe, 0xf1, 0x18, 0xfe,
+ 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
+ 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1b, 0x9b, 0xfe, 0x8c, 0xf0,
+ 0xfe, 0x20, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x14, 0x09, 0xed, 0xfe,
+ 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x30, 0x09, 0x02, 0xfe, 0x3c,
+ 0x0b, 0xee, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x9b, 0xfe, 0x6b,
+ 0x18, 0x1a, 0xfe, 0x00, 0xfe, 0xe2, 0xcd, 0xfe, 0xd2, 0xf0, 0x9b,
+ 0xfe, 0x76, 0x18, 0x1a, 0x18, 0x19, 0x9b, 0x04, 0xe7, 0x1a, 0x06,
+ 0x19, 0x9b, 0xac, 0x58, 0xae, 0x58, 0xed, 0xee, 0xfe, 0x89, 0x10,
+ 0x92, 0x63, 0x3a, 0x17, 0xa9, 0x01, 0x3b, 0x13, 0xfe, 0x35, 0x00,
+ 0x34, 0x6b, 0x13, 0x93, 0x02, 0x6b, 0xfb, 0xb2, 0x0b, 0xfe, 0x1a,
+ 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54,
+ 0xf0, 0xdf, 0xfe, 0x74, 0x18, 0x94, 0x95, 0x19, 0xfe, 0xf2, 0x08,
+ 0x02, 0x58, 0x0a, 0x07, 0x60, 0xaf, 0x04, 0x30, 0x2a, 0x42, 0x0d,
+ 0x43, 0x12, 0x44, 0x83, 0x30, 0x5a, 0x42, 0xfe, 0x6c, 0x18, 0xfe,
+ 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x36, 0x43, 0x21,
+ 0x44, 0x04, 0x54, 0x2a, 0x69, 0x94, 0xfe, 0xe3, 0x54, 0xfe, 0x74,
+ 0x18, 0xfe, 0xf5, 0x18, 0x94, 0xfe, 0xe3, 0x54, 0x95, 0xca, 0x53,
+ 0xfe, 0xf2, 0x08, 0x02, 0x58, 0xfe, 0x37, 0xf0, 0xfe, 0xfe, 0x09,
+ 0xfe, 0x8b, 0xf0, 0xfe, 0x84, 0x09, 0x02, 0x58, 0xfb, 0xb2, 0x0b,
+ 0x28, 0xfe, 0x1e, 0x0b, 0x36, 0x54, 0x21, 0x69, 0x53, 0x7a, 0x08,
+ 0xfe, 0xc0, 0x07, 0x47, 0x62, 0x00, 0xd9, 0xfe, 0x01, 0x59, 0xfe,
+ 0x52, 0xf0, 0xfe, 0x30, 0x0a, 0x94, 0x99, 0xfe, 0x48, 0x0a, 0x36,
+ 0x54, 0x94, 0xfe, 0xe3, 0x54, 0x4e, 0x54, 0x70, 0x69, 0xfe, 0x14,
+ 0x58, 0xfe, 0x95, 0x58, 0x02, 0x58, 0x36, 0x54, 0x21, 0x69, 0xfe,
+ 0x14, 0x59, 0xfe, 0x95, 0x59, 0xf0, 0x4e, 0x54, 0x4e, 0x69, 0x02,
+ 0x58, 0x0a, 0x07, 0x60, 0xfe, 0x82, 0x12, 0x0a, 0x07, 0x22, 0xfe,
+ 0x66, 0x13, 0x29, 0x68, 0x72, 0xd0, 0xfe, 0x83, 0x80, 0xfe, 0xc8,
+ 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6d,
+ 0x31, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x53, 0xfe, 0xfa, 0x08,
+ 0x04, 0x66, 0x2a, 0x67, 0x0d, 0xb5, 0x12, 0x93, 0x4e, 0x66, 0x70,
+ 0x67, 0x01, 0xc5, 0xb6, 0x6d, 0x31, 0x16, 0x68, 0x83, 0x30, 0x5a,
+ 0x42, 0x36, 0x43, 0x21, 0x44, 0x95, 0xca, 0xfe, 0x04, 0xfa, 0x30,
+ 0xfe, 0x05, 0xfa, 0x42, 0x01, 0xfe, 0xbe, 0x13, 0xfe, 0x36, 0x10,
+ 0x2b, 0x0d, 0xb5, 0x0d, 0x93, 0x36, 0x43, 0x21, 0x44, 0xb0, 0x0a,
+ 0x07, 0x22, 0x19, 0xfe, 0xfa, 0x08, 0x36, 0x3c, 0x21, 0x3d, 0x0a,
+ 0x07, 0xfe, 0xf7, 0x00, 0x39, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x10,
+ 0x58, 0xfe, 0x91, 0x58, 0x4e, 0x54, 0x70, 0x69, 0x02, 0xfe, 0x18,
+ 0x0a, 0x0a, 0x07, 0x22, 0x19, 0xfe, 0xfa, 0x08, 0x0a, 0x07, 0xfe,
+ 0xf7, 0x00, 0x39, 0xf0, 0xdf, 0x6a, 0xfe, 0x10, 0x90, 0xfe, 0x92,
+ 0x90, 0xfe, 0xd3, 0x10, 0x40, 0x05, 0xcb, 0x19, 0xfe, 0x2c, 0x09,
+ 0x11, 0xcb, 0xfb, 0xb2, 0x0b, 0xfe, 0x14, 0x13, 0x04, 0x3c, 0x2a,
+ 0x3d, 0x53, 0xfe, 0x2c, 0x09, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58,
+ 0x02, 0x58, 0x2b, 0x47, 0xfe, 0x19, 0x80, 0xfe, 0xf1, 0x10, 0x0a,
+ 0x07, 0x0b, 0xab, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x8e,
+ 0x10, 0xfe, 0x6c, 0x19, 0x4e, 0x3c, 0xfe, 0xed, 0x19, 0x70, 0x3d,
+ 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x1a, 0xfe,
+ 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xcd, 0xfe, 0xd2, 0xf0, 0xfe,
+ 0xb6, 0x0b, 0xfe, 0x76, 0x18, 0x1a, 0x18, 0xd6, 0x04, 0xe7, 0x1a,
+ 0x06, 0x89, 0x13, 0xfe, 0x16, 0x00, 0x02, 0x6b, 0xfe, 0xd1, 0xf0,
+ 0xfe, 0xc8, 0x0b, 0x17, 0x84, 0x01, 0x3b, 0x13, 0xfe, 0x17, 0x00,
+ 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xce, 0x0b, 0xfe, 0x3c,
+ 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xda, 0x0b, 0x13, 0xfe, 0x22, 0x00,
+ 0x02, 0x6b, 0xfe, 0xcb, 0xf0, 0xfe, 0xe6, 0x0b, 0x13, 0xfe, 0x24,
+ 0x00, 0x02, 0x6b, 0xfe, 0xd0, 0xf0, 0xfe, 0xf0, 0x0b, 0x13, 0xb1,
+ 0xe0, 0xfe, 0xcf, 0xf0, 0xfe, 0xfa, 0x0b, 0x13, 0x8f, 0xdd, 0xfe,
+ 0xcc, 0xf0, 0xfe, 0x0a, 0x0c, 0xfe, 0x84, 0x80, 0xb2, 0x22, 0x4f,
+ 0x13, 0xfe, 0x12, 0x00, 0x2e, 0x08, 0x84, 0x2f, 0xfe, 0x10, 0x0c,
+ 0xfe, 0x9e, 0xf0, 0xfe, 0x24, 0x0c, 0xa3, 0x19, 0x32, 0x2e, 0x5b,
+ 0xfe, 0xed, 0x10, 0xac, 0x26, 0xae, 0x26, 0x2e, 0xfe, 0x9c, 0x32,
+ 0x2f, 0xfe, 0x30, 0x0c, 0x1b, 0x32, 0x85, 0xfe, 0x4c, 0x0c, 0x73,
+ 0x97, 0xac, 0xfe, 0xf0, 0x07, 0xae, 0xfe, 0xf0, 0x07, 0x02, 0x26,
+ 0x01, 0x55, 0xfe, 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xed, 0xee,
+ 0x92, 0x86, 0x76, 0xfe, 0x89, 0xf0, 0x26, 0x24, 0x23, 0xfe, 0xe9,
+ 0x09, 0x01, 0x0c, 0x86, 0x76, 0x1f, 0x26, 0x24, 0x23, 0x9a, 0x34,
+ 0xfe, 0x88, 0x0c, 0x1b, 0x32, 0x02, 0xfe, 0x7c, 0x0c, 0xa3, 0x50,
+ 0x13, 0xfe, 0x42, 0x00, 0x02, 0x6b, 0xa6, 0x06, 0xfe, 0x81, 0x49,
+ 0xfe, 0xcc, 0x12, 0x0a, 0x07, 0x0b, 0xfe, 0x5a, 0x13, 0x13, 0x00,
+ 0x61, 0x0b, 0xfe, 0x6a, 0x12, 0x61, 0xfe, 0x28, 0x00, 0x28, 0xfe,
+ 0xce, 0x0d, 0x0f, 0x7d, 0x01, 0x15, 0x05, 0x00, 0x89, 0x37, 0xfe,
+ 0x28, 0x00, 0x02, 0xfe, 0xce, 0x0d, 0x01, 0x9f, 0x01, 0xa1, 0x0f,
+ 0xc8, 0x01, 0xfe, 0x24, 0x0f, 0xb9, 0x08, 0x3f, 0x09, 0xa2, 0x01,
+ 0x45, 0x11, 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x02, 0x27,
+ 0x13, 0xfe, 0x44, 0x00, 0x61, 0x0b, 0xab, 0x37, 0x0b, 0xfe, 0xc0,
+ 0x10, 0x01, 0xc2, 0x37, 0x0b, 0xfe, 0xb6, 0x10, 0x01, 0xc2, 0xfe,
+ 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x37, 0x0b, 0x13,
+ 0xfe, 0x43, 0x00, 0xfe, 0xa2, 0x10, 0x0a, 0x41, 0x0b, 0x39, 0x01,
+ 0x9f, 0x01, 0xa1, 0xb9, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, 0x11,
+ 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x88, 0x0b, 0xb9, 0x1c,
+ 0xd2, 0x02, 0xfe, 0x4c, 0x03, 0x0a, 0x07, 0x0b, 0xd6, 0x37, 0x0b,
+ 0x13, 0x00, 0xfe, 0x54, 0x10, 0x71, 0x07, 0x1d, 0xfe, 0x50, 0x12,
+ 0x0a, 0x07, 0x1d, 0xfe, 0x48, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
+ 0xf0, 0xfe, 0x8c, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe,
+ 0x92, 0x0d, 0x0a, 0x41, 0x1d, 0x39, 0xfe, 0x95, 0x10, 0x13, 0xfe,
+ 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x6a, 0xfe, 0x26, 0x10, 0x13,
+ 0xfe, 0x13, 0x00, 0xdd, 0x13, 0xfe, 0x47, 0x00, 0x8a, 0x13, 0xfe,
+ 0x41, 0x00, 0xa4, 0x13, 0xfe, 0x24, 0x00, 0x04, 0x7c, 0x2c, 0x28,
+ 0xf6, 0x6a, 0xfe, 0x04, 0xe6, 0x1d, 0xfe, 0x9d, 0x41, 0xfe, 0x1c,
+ 0x42, 0xb9, 0x01, 0xea, 0x02, 0x27, 0xde, 0x17, 0x0b, 0x4c, 0xfe,
+ 0x9b, 0x00, 0xe5, 0x17, 0xfe, 0x31, 0x00, 0x4c, 0xc4, 0x01, 0xfe,
+ 0x30, 0x10, 0x02, 0xfe, 0xc6, 0x01, 0x1c, 0xfe, 0x06, 0xec, 0xfe,
+ 0xb9, 0x00, 0x8c, 0x37, 0x38, 0xc7, 0x35, 0x1c, 0xfe, 0x06, 0xea,
+ 0xfe, 0xb9, 0x00, 0xfe, 0x47, 0x4b, 0x9e, 0xfe, 0x75, 0x57, 0x04,
+ 0x5f, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0f, 0x7d, 0xfe, 0xf4,
+ 0x14, 0x47, 0xf2, 0x0f, 0xc8, 0xfe, 0xea, 0x14, 0xfe, 0x49, 0x54,
+ 0x98, 0xfe, 0x42, 0x0e, 0x0f, 0x1e, 0xfe, 0xde, 0x14, 0xfe, 0x44,
+ 0x48, 0x02, 0xfe, 0x4c, 0x03, 0x0f, 0x5f, 0xfe, 0xc8, 0x14, 0x8c,
+ 0x37, 0x38, 0xc7, 0x35, 0x1c, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13,
+ 0x02, 0x27, 0x29, 0x2d, 0x05, 0x10, 0xfe, 0x78, 0x12, 0x2b, 0x16,
+ 0x5e, 0x16, 0xb4, 0x29, 0x48, 0x47, 0x4c, 0x48, 0xa3, 0xd9, 0xfe,
+ 0xbc, 0xf0, 0xfe, 0xde, 0x0e, 0x08, 0x06, 0x16, 0x5e, 0x01, 0xfe,
+ 0xe6, 0x16, 0x04, 0xfe, 0x38, 0x01, 0x2a, 0xfe, 0x3a, 0x01, 0x53,
+ 0xfe, 0xe2, 0x0e, 0x04, 0xfe, 0x38, 0x01, 0x1a, 0xfe, 0xf0, 0xff,
+ 0x0d, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0d, 0xfe, 0x62,
+ 0x01, 0x20, 0x06, 0x16, 0x48, 0xfe, 0x04, 0xec, 0x2d, 0x08, 0x2d,
+ 0x09, 0x3e, 0x1c, 0x01, 0x45, 0x82, 0xfe, 0x05, 0xf6, 0xfe, 0x34,
+ 0x01, 0x01, 0xfe, 0x56, 0x17, 0x11, 0x48, 0xd2, 0x08, 0x06, 0x03,
+ 0x2b, 0x03, 0x29, 0x5e, 0xfe, 0xf7, 0x12, 0x29, 0xb4, 0x72, 0x16,
+ 0xb4, 0x05, 0x84, 0xfe, 0x93, 0x13, 0xfe, 0x24, 0x1c, 0x17, 0x18,
+ 0x4c, 0xfe, 0x9b, 0x00, 0xe5, 0xfe, 0xd9, 0x10, 0x9c, 0xfe, 0x03,
+ 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x9c, 0xfe, 0x03,
+ 0xdc, 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57,
+ 0x9c, 0x2b, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0x9c, 0x80,
+ 0x03, 0x01, 0xfe, 0x8e, 0x17, 0x40, 0x05, 0x48, 0xfe, 0x0a, 0x13,
+ 0x08, 0x1e, 0x09, 0x52, 0xdd, 0x01, 0x9f, 0x01, 0xa1, 0x08, 0x3f,
+ 0x09, 0xa2, 0x01, 0x45, 0x11, 0xfe, 0xe9, 0x00, 0x0a, 0x07, 0x8f,
+ 0xfe, 0x52, 0x13, 0x01, 0xfe, 0x18, 0x17, 0xfe, 0x1e, 0x1c, 0xfe,
+ 0x14, 0x90, 0x0d, 0xfe, 0x64, 0x01, 0xfe, 0x16, 0x90, 0x0d, 0xfe,
+ 0x66, 0x01, 0x0a, 0x07, 0x46, 0xef, 0xfe, 0x03, 0x80, 0x5b, 0x4d,
+ 0x11, 0x7b, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x7a, 0x01, 0x90, 0xfe,
+ 0x62, 0x08, 0x72, 0x4d, 0x11, 0x7b, 0x08, 0x2d, 0x09, 0x3e, 0x1c,
+ 0x7a, 0x01, 0x90, 0x6d, 0x31, 0x11, 0x7b, 0x08, 0x2d, 0x09, 0x3e,
+ 0x1c, 0x7a, 0x01, 0x7e, 0x03, 0xfe, 0x08, 0x1c, 0x04, 0xfe, 0xac,
+ 0x00, 0xfe, 0x06, 0x58, 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58,
+ 0x04, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x04, 0xfe, 0xb2, 0x00,
+ 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x20, 0x74, 0x16, 0xfe, 0xb9,
+ 0x00, 0x2b, 0x0d, 0x5c, 0x0d, 0x56, 0x20, 0x10, 0x16, 0x2d, 0x16,
+ 0x3e, 0x51, 0xa6, 0xfe, 0x93, 0x00, 0x08, 0x2d, 0x09, 0x3e, 0x1c,
+ 0x01, 0x7e, 0x82, 0x11, 0x7b, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
+ 0x8a, 0xde, 0x92, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18,
+ 0x1c, 0x03, 0x1c, 0xfe, 0x0c, 0x14, 0x8c, 0xfe, 0x07, 0xe6, 0x38,
+ 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0xc2, 0x0f, 0x3f,
+ 0x01, 0x15, 0x05, 0x10, 0xdb, 0x0f, 0x1e, 0x01, 0x15, 0x05, 0x10,
+ 0xe2, 0xfe, 0x44, 0x58, 0x4d, 0xfe, 0x01, 0xec, 0xc4, 0xfe, 0x9e,
+ 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1d, 0xa5, 0x31,
+ 0x01, 0xea, 0xfe, 0xc9, 0x10, 0x03, 0x2e, 0x86, 0x76, 0x24, 0x23,
+ 0xba, 0x05, 0x1d, 0xfe, 0x48, 0x12, 0x05, 0x0b, 0xfe, 0x4c, 0x12,
+ 0x05, 0x18, 0xfe, 0x30, 0x12, 0x05, 0xd4, 0x19, 0xfe, 0xd4, 0x11,
+ 0x05, 0xfe, 0x23, 0x00, 0x19, 0xfe, 0xe0, 0x11, 0x05, 0x06, 0x19,
+ 0xfe, 0x3e, 0x12, 0x05, 0x22, 0xfe, 0x12, 0x12, 0x05, 0x00, 0x19,
+ 0x26, 0x17, 0xd4, 0x01, 0x3b, 0xce, 0x3a, 0x01, 0x0c, 0x85, 0x55,
+ 0x03, 0x3a, 0x11, 0xfe, 0xcc, 0x00, 0x02, 0x27, 0x3a, 0x40, 0x05,
+ 0xcb, 0xfe, 0xe3, 0x13, 0x36, 0x3c, 0x21, 0x3d, 0x53, 0xfe, 0x92,
+ 0x11, 0x0a, 0x07, 0x60, 0xfe, 0x72, 0x12, 0x83, 0x30, 0x5a, 0x42,
+ 0x95, 0xca, 0x98, 0xfe, 0x5c, 0x11, 0x29, 0x68, 0xfe, 0x26, 0x13,
+ 0x04, 0xb5, 0x2a, 0x93, 0x53, 0xfe, 0xb2, 0x0d, 0x0d, 0x66, 0x12,
+ 0x67, 0x2b, 0x0d, 0xb5, 0x0d, 0x93, 0x01, 0xc5, 0x20, 0x74, 0x5b,
+ 0x16, 0x68, 0x01, 0xfe, 0xbe, 0x13, 0x83, 0x30, 0x5a, 0x42, 0xfe,
+ 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x30, 0xfe, 0x05,
+ 0xfa, 0x42, 0xfe, 0x91, 0x10, 0x04, 0x43, 0x2a, 0x44, 0xfe, 0x40,
+ 0x56, 0xfe, 0xe1, 0x56, 0x0d, 0x43, 0x12, 0x44, 0xad, 0x83, 0x30,
+ 0x5a, 0x42, 0x95, 0xca, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x00, 0x56,
+ 0xfe, 0xa1, 0x56, 0x0d, 0x64, 0x12, 0x65, 0x0a, 0x07, 0x60, 0xfe,
+ 0x1e, 0x12, 0x29, 0x68, 0xfe, 0x1f, 0x40, 0x04, 0x66, 0x2a, 0x67,
+ 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04, 0x43, 0x2a, 0x44, 0xfe,
+ 0x34, 0x50, 0xfe, 0xb6, 0x50, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x08,
+ 0x50, 0xfe, 0x8a, 0x50, 0x04, 0x3c, 0x2a, 0x3d, 0xfe, 0x28, 0x50,
+ 0xfe, 0xaa, 0x50, 0x02, 0xa0, 0x20, 0x06, 0x16, 0xfc, 0x02, 0x7f,
+ 0x3a, 0x01, 0x0c, 0x1f, 0x57, 0x24, 0x23, 0xba, 0x05, 0x06, 0x28,
+ 0x57, 0x40, 0x05, 0xcb, 0x28, 0x7f, 0x01, 0xfe, 0x9c, 0x13, 0x1a,
+ 0x59, 0x19, 0x57, 0x0a, 0x07, 0x0b, 0xe4, 0x36, 0x3c, 0x21, 0x3d,
+ 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x4e, 0x3c, 0x70, 0x3d,
+ 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x7f, 0xdf, 0xfe, 0x0a,
+ 0x45, 0xfe, 0x19, 0x41, 0x02, 0x7f, 0x3a, 0x01, 0x0c, 0x1f, 0xfe,
+ 0xd6, 0x10, 0x24, 0x23, 0xfe, 0xe9, 0x09, 0x61, 0x18, 0xfe, 0x94,
+ 0x12, 0x61, 0x0b, 0x4f, 0x02, 0x57, 0x2f, 0xfe, 0x5e, 0x12, 0x1b,
+ 0x32, 0x1f, 0xfe, 0xd6, 0x10, 0x24, 0x23, 0x9a, 0x05, 0x18, 0x28,
+ 0x57, 0x01, 0x0c, 0x1f, 0xfe, 0xd6, 0x10, 0x24, 0x23, 0xfe, 0xe8,
+ 0x09, 0x51, 0x04, 0xfe, 0x9c, 0x00, 0x2c, 0x35, 0xfe, 0xbb, 0x45,
+ 0x61, 0x00, 0x50, 0x37, 0x06, 0xa6, 0x59, 0xfe, 0xc0, 0x14, 0xfe,
+ 0xf8, 0x14, 0xb3, 0x40, 0x05, 0xc9, 0xfe, 0x16, 0x13, 0x04, 0xfe,
+ 0x9e, 0x00, 0x2c, 0xd6, 0x04, 0x56, 0x2c, 0x35, 0x63, 0x02, 0x7f,
+ 0xfe, 0xc0, 0x5d, 0xfe, 0xe4, 0x14, 0xfe, 0x03, 0x17, 0x04, 0x5c,
+ 0xc3, 0x0d, 0x5c, 0x63, 0x3a, 0x01, 0x0c, 0x25, 0xa0, 0x01, 0xfe,
+ 0x06, 0x15, 0x02, 0xa0, 0x2f, 0xfe, 0xe8, 0x12, 0x1b, 0x32, 0x1f,
+ 0x57, 0x24, 0x23, 0x9a, 0x05, 0x06, 0x28, 0x57, 0xfe, 0xf6, 0x14,
+ 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, 0x92, 0x14, 0xb3, 0xfe,
+ 0x4a, 0xf4, 0x0b, 0x19, 0x57, 0xfe, 0x4a, 0xf4, 0x06, 0xd8, 0x40,
+ 0x05, 0xc9, 0xd1, 0x02, 0x7f, 0x04, 0x56, 0xc3, 0x0d, 0x56, 0x63,
+ 0x3a, 0x01, 0x0c, 0x25, 0xa0, 0x01, 0xfe, 0x34, 0x15, 0x02, 0xa0,
+ 0x25, 0xfe, 0x50, 0x13, 0x78, 0xf9, 0x78, 0x03, 0x34, 0xfe, 0x4c,
+ 0x13, 0x73, 0xfe, 0x4c, 0x13, 0x63, 0x3a, 0x01, 0x0c, 0xfe, 0xe3,
+ 0x10, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0x1a, 0xfe,
+ 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x6c,
+ 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0x1a, 0x59, 0xfe, 0x30, 0x56,
+ 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x6e,
+ 0x81, 0x03, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0xfe,
+ 0x0b, 0x58, 0x03, 0x0f, 0x5c, 0x01, 0x8e, 0x0f, 0x56, 0x01, 0x8e,
+ 0x03, 0xd0, 0x1a, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4,
+ 0x22, 0x6e, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d,
+ 0xfe, 0x03, 0x7c, 0x6d, 0x31, 0x0d, 0x64, 0x12, 0x65, 0x4e, 0x43,
+ 0x70, 0x44, 0x03, 0xfe, 0x62, 0x18, 0xfe, 0x82, 0x5a, 0xfe, 0xe1,
+ 0x1a, 0xbf, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x7e, 0x19, 0xfe,
+ 0x42, 0x48, 0x6a, 0x51, 0x9e, 0x01, 0x0c, 0x1f, 0xfe, 0xfe, 0x14,
+ 0x24, 0x23, 0xfe, 0xe9, 0x09, 0xfe, 0xc1, 0x59, 0x01, 0x0c, 0x1f,
+ 0xfe, 0xfe, 0x14, 0x24, 0x23, 0xfe, 0xe8, 0x0a, 0x04, 0xfe, 0x9e,
+ 0x00, 0x2c, 0xfe, 0xc4, 0x12, 0x2b, 0xb8, 0x1d, 0xe4, 0x61, 0xd5,
+ 0x79, 0xfe, 0x4c, 0x14, 0x4f, 0x08, 0x06, 0x09, 0xd5, 0xa6, 0xfe,
+ 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0x8a, 0xff,
+ 0x02, 0x83, 0x55, 0xb8, 0x18, 0xfe, 0x12, 0x13, 0x62, 0xfe, 0x30,
+ 0x00, 0x98, 0xfe, 0xa6, 0x14, 0x09, 0x8b, 0x08, 0x06, 0xfe, 0x56,
+ 0x10, 0xb8, 0x0b, 0xfe, 0x16, 0x13, 0x62, 0xfe, 0x64, 0x00, 0x98,
+ 0xfe, 0xa6, 0x14, 0x0f, 0xfe, 0x64, 0x00, 0x09, 0xb1, 0x08, 0x06,
+ 0xfe, 0x28, 0x10, 0xb8, 0x06, 0xfe, 0x60, 0x13, 0x62, 0xfe, 0xc8,
+ 0x00, 0x98, 0xfe, 0xa6, 0x14, 0x0f, 0xfe, 0xc8, 0x00, 0x09, 0x5e,
+ 0x08, 0x06, 0xad, 0x62, 0xfe, 0x90, 0x01, 0x99, 0xfe, 0xb2, 0x14,
+ 0x9e, 0xb0, 0xfe, 0x43, 0xf4, 0xb4, 0xfe, 0x56, 0xf0, 0xfe, 0xc4,
+ 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0xb1, 0xfe, 0xf3,
+ 0x10, 0xb7, 0x01, 0xfe, 0x8e, 0x13, 0x1a, 0x59, 0xaf, 0xfe, 0x00,
+ 0x17, 0xfe, 0x4d, 0xe4, 0x74, 0x99, 0xfe, 0xf8, 0x14, 0xa8, 0x74,
+ 0xfe, 0x14, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0xf1, 0x99,
+ 0xfe, 0xf8, 0x14, 0xa8, 0xf1, 0xa4, 0x51, 0x9e, 0x08, 0x06, 0xfe,
+ 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x03, 0x51, 0x08, 0x0b, 0x03, 0x14,
+ 0x06, 0x01, 0x0c, 0x25, 0xec, 0x14, 0x0b, 0x01, 0x0c, 0x25, 0xec,
+ 0x14, 0x18, 0x01, 0x0c, 0x25, 0xec, 0x78, 0xfe, 0x89, 0x49, 0x01,
+ 0x0c, 0x03, 0x14, 0x06, 0x01, 0x0c, 0x25, 0xbc, 0x14, 0x18, 0x01,
+ 0x0c, 0x25, 0xbc, 0x14, 0x06, 0x01, 0x0c, 0x25, 0xbc, 0xfe, 0x89,
+ 0x49, 0x01, 0x0c, 0x25, 0xbc, 0x78, 0xfe, 0x89, 0x4a, 0x01, 0x0c,
+ 0x03, 0x51, 0x03, 0x29, 0xe8, 0x05, 0x06, 0x3b, 0xb6, 0x16, 0xe8,
+ 0xfe, 0x49, 0xf4, 0x00, 0x4f, 0x78, 0xce, 0x63, 0xfe, 0x01, 0xec,
+ 0xfe, 0x27, 0x01, 0xf9, 0x01, 0x0c, 0x40, 0x05, 0xfe, 0xe3, 0x00,
+ 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0xb6, 0x15, 0x2b, 0x16, 0xfc, 0x01,
+ 0x55, 0x29, 0xfc, 0x05, 0x06, 0x50, 0x0a, 0x41, 0x06, 0x39, 0x03,
+ 0x0d, 0x5d, 0x12, 0x91, 0xfe, 0x43, 0x58, 0x01, 0x15, 0x05, 0x10,
+ 0xfe, 0x1e, 0x12, 0x4a, 0xf3, 0x96, 0x01, 0x49, 0xfe, 0x90, 0x4d,
+ 0xe6, 0x10, 0xfe, 0xc5, 0x59, 0x01, 0x49, 0xfe, 0x8d, 0x56, 0xbf,
+ 0x4a, 0x03, 0x4a, 0x21, 0x91, 0x01, 0x15, 0x4a, 0x96, 0x01, 0x49,
+ 0xeb, 0x10, 0xe6, 0x10, 0x21, 0x5d, 0x62, 0x1e, 0x89, 0x0f, 0x5f,
+ 0x01, 0xaa, 0x03, 0x0d, 0x5d, 0x12, 0x91, 0xfe, 0xc3, 0x58, 0x01,
+ 0x15, 0x05, 0x10, 0xfe, 0x1a, 0x12, 0x4a, 0xf3, 0x96, 0x01, 0x49,
+ 0xeb, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, 0x59, 0x01, 0x49, 0x4a,
+ 0x03, 0x4a, 0x21, 0x5d, 0x01, 0x15, 0x4a, 0x96, 0x01, 0x49, 0xeb,
+ 0x10, 0xe6, 0x10, 0x21, 0x5d, 0x62, 0x1e, 0x89, 0x0f, 0x5f, 0x01,
+ 0xaa, 0x03, 0x0d, 0x5d, 0x12, 0x91, 0xfe, 0x43, 0x58, 0x01, 0x15,
+ 0xfe, 0x42, 0x48, 0x96, 0x01, 0x49, 0xfe, 0xc0, 0x5a, 0xb7, 0xfe,
+ 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, 0x4a, 0x46, 0xe4, 0x9c, 0x80,
+ 0x05, 0x10, 0xfe, 0x2e, 0x13, 0x5a, 0x5d, 0xfe, 0x4d, 0xf4, 0x1e,
+ 0xfe, 0x1c, 0x13, 0x0f, 0x5f, 0x01, 0x8e, 0xb0, 0xfe, 0x40, 0x4c,
+ 0xfe, 0xc5, 0x58, 0x01, 0x49, 0xfe, 0x00, 0x07, 0x80, 0x05, 0x10,
+ 0x89, 0x5a, 0x91, 0xfe, 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, 0x45,
+ 0x58, 0x01, 0x49, 0xfe, 0x8d, 0x56, 0xbf, 0xfe, 0x80, 0x4c, 0xfe,
+ 0x05, 0x17, 0x03, 0x09, 0x10, 0x77, 0x6f, 0xfe, 0x60, 0x01, 0xfe,
+ 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xe3, 0x38, 0x9d,
+ 0xfe, 0xfa, 0x16, 0x01, 0xfe, 0x08, 0x18, 0xd9, 0x8d, 0x38, 0x6f,
+ 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xc0, 0x28, 0xfe, 0xea,
+ 0x16, 0xfe, 0xe2, 0x10, 0x09, 0x10, 0x77, 0x04, 0xfe, 0x64, 0x01,
+ 0xfe, 0x00, 0xf4, 0x22, 0xfe, 0x18, 0x58, 0x04, 0xfe, 0x66, 0x01,
+ 0xfe, 0x19, 0x58, 0x8d, 0x22, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+ 0x06, 0xfe, 0x3c, 0x50, 0x6f, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79,
+ 0xfe, 0x1c, 0xf7, 0x22, 0x9d, 0xfe, 0x44, 0x17, 0xfe, 0xbe, 0x14,
+ 0x35, 0x03, 0xc0, 0x28, 0xfe, 0x1c, 0x17, 0xfe, 0xa4, 0x10, 0x09,
+ 0x10, 0x77, 0xbf, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xdf, 0xe3, 0x30,
+ 0x9d, 0xfe, 0x66, 0x17, 0xfe, 0x9c, 0x14, 0xfe, 0x18, 0x13, 0x8d,
+ 0x30, 0x6f, 0x1d, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0xa7,
+ 0x07, 0xfe, 0x7f, 0x00, 0xfe, 0x05, 0x40, 0x03, 0xc0, 0x28, 0xfe,
+ 0x5a, 0x17, 0xfe, 0x6c, 0x10, 0x09, 0x10, 0x77, 0xfe, 0x30, 0xbc,
+ 0xfe, 0xb2, 0xbc, 0x8d, 0xe1, 0x6f, 0x1d, 0xfe, 0x0f, 0x79, 0xfe,
+ 0x1c, 0xf7, 0xe1, 0x9d, 0xfe, 0xa6, 0x17, 0xfe, 0x5c, 0x14, 0x35,
+ 0x03, 0xc0, 0x28, 0xfe, 0x92, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02,
+ 0xf6, 0x10, 0x77, 0xfe, 0x18, 0xfe, 0x66, 0xfe, 0x19, 0xfe, 0x67,
+ 0xd0, 0xe3, 0x46, 0x9d, 0xfe, 0xcc, 0x17, 0xfe, 0x36, 0x14, 0xfe,
+ 0x1c, 0x13, 0x8d, 0x46, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
+ 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd,
+ 0x00, 0x6d, 0x31, 0x03, 0x6d, 0x31, 0xfe, 0x12, 0x45, 0x28, 0xfe,
+ 0xbc, 0x17, 0x17, 0x06, 0x4c, 0xfe, 0x9b, 0x00, 0xe5, 0x02, 0x27,
+ 0xfe, 0x39, 0xf0, 0xfe, 0x10, 0x18, 0x2b, 0x03, 0xfe, 0x7e, 0x18,
+ 0x1a, 0x18, 0x87, 0x08, 0x0e, 0x03, 0x77, 0x04, 0xe7, 0x1a, 0x06,
+ 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x1c, 0x0f, 0x1e, 0x01, 0x15,
+ 0x05, 0x10, 0x50, 0x4d, 0xfe, 0x78, 0x14, 0xfe, 0x34, 0x12, 0x59,
+ 0x8c, 0x37, 0x38, 0xc7, 0xfe, 0xe9, 0x13, 0x1c, 0x0f, 0x3f, 0x01,
+ 0x15, 0x05, 0x10, 0x50, 0x4d, 0xfe, 0x56, 0x14, 0xe9, 0x59, 0x8c,
+ 0x37, 0x38, 0xc7, 0xfe, 0xe9, 0x13, 0x09, 0x0b, 0x03, 0xfe, 0x9c,
+ 0xe7, 0x0b, 0x13, 0xfe, 0x15, 0x00, 0x7a, 0xa5, 0x31, 0x01, 0xea,
+ 0x09, 0x06, 0x03, 0x0a, 0x41, 0x38, 0x39, 0x08, 0x3f, 0x09, 0xa2,
+ 0x01, 0x45, 0x11, 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x09,
+ 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x36, 0xfe, 0xa8,
+ 0x00, 0x21, 0x7b, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x03,
+ 0x29, 0xc6, 0x5b, 0x16, 0xc6, 0x03, 0x0f, 0xc8, 0x01, 0x15, 0xf2,
+ 0x0f, 0x7d, 0x01, 0x15, 0xfe, 0x49, 0x44, 0x28, 0xfe, 0x06, 0x19,
+ 0x0f, 0x1e, 0x01, 0x15, 0x05, 0x10, 0x50, 0x0f, 0x5f, 0x01, 0xaa,
+ 0x0f, 0x7d, 0x01, 0x15, 0x5b, 0x80, 0x03, 0xfe, 0x40, 0x5e, 0xfe,
+ 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x29, 0x3e, 0x05, 0x10, 0xfe, 0x52,
+ 0x12, 0x4d, 0x05, 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe,
+ 0x19, 0xf4, 0xfe, 0x7f, 0x00, 0xaf, 0xfe, 0xe2, 0x08, 0x5b, 0x4d,
+ 0x40, 0x05, 0x7b, 0xab, 0xfe, 0x82, 0x48, 0xfe, 0x01, 0x80, 0xfe,
+ 0xd7, 0x10, 0xfe, 0xc4, 0x48, 0x08, 0x2d, 0x09, 0x3e, 0xfe, 0x40,
+ 0x5f, 0x1c, 0x01, 0x45, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x14, 0x46,
+ 0x08, 0x2d, 0x09, 0x3e, 0x01, 0x45, 0x11, 0xfe, 0xdd, 0x00, 0xfe,
+ 0x40, 0x4a, 0x72, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, 0xfe, 0x82,
+ 0x48, 0xfe, 0x04, 0x17, 0x03, 0xf5, 0x18, 0x79, 0xfe, 0x8e, 0x19,
+ 0x04, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xf5,
+ 0xd4, 0x79, 0xfe, 0xa0, 0x19, 0x04, 0xfe, 0x92, 0x00, 0xcf, 0x1d,
+ 0xe0, 0xf5, 0xfe, 0x0b, 0x00, 0x79, 0xfe, 0xb2, 0x19, 0x04, 0xfe,
+ 0x94, 0x00, 0xcf, 0x22, 0xfe, 0x08, 0x10, 0x04, 0xfe, 0x96, 0x00,
+ 0xcf, 0x8b, 0xfe, 0x4e, 0x45, 0xd8, 0xfe, 0x0a, 0x45, 0xff, 0x04,
+ 0x68, 0x54, 0xfe, 0xf1, 0x10, 0x1a, 0x74, 0xfe, 0x08, 0x1c, 0xfe,
+ 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04,
+ 0xd8, 0xfe, 0x48, 0xf4, 0x18, 0x99, 0xfe, 0xe6, 0x19, 0x08, 0x18,
+ 0x03, 0x05, 0x84, 0xfe, 0x5a, 0xf0, 0xfe, 0xf6, 0x19, 0x20, 0xfe,
+ 0x09, 0x00, 0xfe, 0x34, 0x10, 0x05, 0x1d, 0xfe, 0x5a, 0xf0, 0xfe,
+ 0x04, 0x1a, 0x20, 0xd5, 0xfe, 0x26, 0x10, 0x05, 0x18, 0x87, 0x20,
+ 0x8b, 0xe0, 0x05, 0x0b, 0x87, 0x20, 0xb1, 0xfe, 0x0e, 0x10, 0x05,
+ 0x06, 0x87, 0x20, 0x5e, 0xce, 0xb6, 0x03, 0x17, 0xfe, 0x09, 0x00,
+ 0x01, 0x3b, 0x2f, 0xfe, 0x34, 0x1a, 0x04, 0x76, 0xb7, 0x03, 0x1b,
+ 0xfe, 0x54, 0x1a, 0xfe, 0x14, 0xf0, 0x0c, 0x2f, 0xfe, 0x48, 0x1a,
+ 0x1b, 0xfe, 0x54, 0x1a, 0xfe, 0x82, 0xf0, 0xfe, 0x4c, 0x1a, 0x03,
+ 0xff, 0x15, 0x00, 0x00,
+};
+const struct adw_mcode adw_asc38C0800_mcode_data =
+{
+ adw_asc38C0800_mcode,
+ 0x053503A5,
+ sizeof(adw_asc38C0800_mcode)
+};
diff --git a/sys/dev/advansys/adwmcode.h b/sys/dev/advansys/adwmcode.h
new file mode 100644
index 0000000..2218454
--- /dev/null
+++ b/sys/dev/advansys/adwmcode.h
@@ -0,0 +1,135 @@
+/*
+ * Exported interface to downloadable microcode for AdvanSys SCSI Adapters
+ *
+ * $FreeBSD$
+ *
+ * Obtained from:
+ *
+ * Copyright (c) 1995-1999 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 _ADMCODE_H_
+#define _ADMCODE_H_
+
+struct adw_mcode
+{
+ const u_int8_t* mcode_buf;
+ const u_int32_t mcode_chksum;
+ const u_int16_t mcode_size;
+};
+
+extern const struct adw_mcode adw_asc3550_mcode_data;
+extern const struct adw_mcode adw_asc38C0800_mcode_data;
+
+/*
+ * Fixed LRAM locations of microcode operating variables.
+ */
+#define ADW_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
+#define ADW_MC_CODE_END_ADDR 0x002A /* microcode end address */
+#define ADW_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
+#define ADW_MC_VERSION_DATE 0x0038 /* microcode version */
+#define ADW_MC_VERSION_NUM 0x003A /* microcode number */
+#define ADW_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
+#define ADW_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
+#define ADW_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
+#define ADW_MC_BIOS_VERSION 0x005A /* BIOS Version (2 Bytes) */
+#define ADW_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
+#define ADW_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
+#define ADW_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
+#define ADW_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
+#define ADW_MC_CHIP_TYPE 0x009A
+#define ADW_MC_INTRB_CODE 0x009B
+#define ADW_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
+#define ADW_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected Bus Reset. */
+#define ADW_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure.*/
+#define ADW_ASYNC_HOST_SCSI_BUS_RESET 0x80 /*
+ * Host Initiated
+ * SCSI Bus Reset.
+ */
+#define ADW_MC_WDTR_ABLE_BIOS_31 0x0120
+#define ADW_MC_WDTR_ABLE 0x009C
+#define ADW_MC_SDTR_ABLE 0x009E
+#define ADW_MC_TAGQNG_ABLE 0x00A0
+#define ADW_MC_DISC_ENABLE 0x00A2
+#define ADW_MC_IDLE_CMD_STATUS 0x00A4
+#define ADW_MC_IDLE_CMD 0x00A6
+#define ADW_MC_IDLE_CMD_PARAMETER 0x00A8
+#define ADW_MC_DEFAULT_SCSI_CFG0 0x00AC
+#define ADW_MC_DEFAULT_SCSI_CFG1 0x00AE
+#define ADW_MC_DEFAULT_MEM_CFG 0x00B0
+#define ADW_MC_DEFAULT_SEL_MASK 0x00B2
+#define ADW_MC_RISC_NEXT_READY 0x00B4
+#define ADW_MC_RISC_NEXT_DONE 0x00B5
+#define ADW_MC_SDTR_DONE 0x00B6
+#define ADW_MC_NUMBER_OF_QUEUED_CMD 0x00C0
+#define ADW_MC_NUMBER_OF_MAX_CMD 0x00D0
+#define ADW_MC_DEVICE_HSHK_CFG_TABLE 0x0100
+#define ADW_HSHK_CFG_WIDE_XFR 0x8000
+#define ADW_HSHK_CFG_RATE_MASK 0x7F00
+#define ADW_HSHK_CFG_RATE_SHIFT 8
+#define ADW_HSHK_CFG_OFFSET 0x001F
+#define ADW_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
+#define ADW_MC_CONTROL_IGN_PERR 0x0001 /* Ignore DMA Parity Errors */
+#define ADW_MC_WDTR_DONE 0x0124
+#define ADW_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
+#define ADW_MC_ICQ 0x0160
+#define ADW_MC_IRQ 0x0164
+
+/* ADW_SCSI_REQ_Q 'cntl' field values */
+#define ADW_QC_DATA_CHECK 0x01 /* Require ADW_QC_DATA_OUT set or clear. */
+#define ADW_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
+#define ADW_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
+#define ADW_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
+#define ADW_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request.XXXTBD */
+
+#define ADW_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
+#define ADW_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
+#define ADW_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request.*/
+#define ADW_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
+#define ADW_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request.*/
+/*
+ * Note: If a Tag Message is to be sent and neither ADW_QSC_HEAD_TAG or
+ * ADW_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
+ */
+#define ADW_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
+#define ADW_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
+
+struct adw_carrier
+{
+ u_int32_t carr_offset; /* Carrier byte offset into our array */
+ u_int32_t carr_ba; /* Carrier Bus Address */
+ u_int32_t areq_ba; /* SCSI Req Queue Bus Address */
+ u_int32_t next_ba;
+#define ADW_RQ_DONE 0x00000001
+#define ADW_CQ_STOPPER 0x00000000
+#define ADW_NEXT_BA_MASK 0xFFFFFFF0
+};
+
+/*
+ * Microcode idle loop commands
+ */
+typedef enum {
+ ADW_IDLE_CMD_COMPLETED = 0x0000,
+ ADW_IDLE_CMD_STOP_CHIP = 0x0001,
+ ADW_IDLE_CMD_STOP_CHIP_SEND_INT = 0x0002,
+ ADW_IDLE_CMD_SEND_INT = 0x0004,
+ ADW_IDLE_CMD_ABORT = 0x0008,
+ ADW_IDLE_CMD_DEVICE_RESET = 0x0010,
+ ADW_IDLE_CMD_SCSI_RESET_START = 0x0020,
+ ADW_IDLE_CMD_SCSI_RESET_END = 0x0040,
+ ADW_IDLE_CMD_SCSIREQ = 0x0080
+} adw_idle_cmd_t;
+
+typedef enum {
+ ADW_IDLE_CMD_FAILURE = 0x0000,
+ ADW_IDLE_CMD_SUCCESS = 0x0001
+} adw_idle_cmd_status_t;
+
+
+#endif /* _ADMCODE_H_ */
diff --git a/sys/dev/advansys/adwvar.h b/sys/dev/advansys/adwvar.h
new file mode 100644
index 0000000..f4244f9
--- /dev/null
+++ b/sys/dev/advansys/adwvar.h
@@ -0,0 +1,55 @@
+/*
+ * Generic driver definitions and exported functions for the Advanced
+ * Systems Inc. Second Generation SCSI controllers
+ *
+ * Copyright (c) 1998, 1999, 2000 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * All rights reserved.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ADWVAR_H_
+#define _ADWVAR_H_
+
+#include <dev/advansys/adwlib.h>
+
+struct adw_softc * adw_alloc(device_t dev, struct resource *regs,
+ int regs_type, int regs_id);
+void adw_map(void *arg, bus_dma_segment_t *segs,
+ int nseg, int error);
+void adw_free(struct adw_softc *adw);
+int adw_init(struct adw_softc *adw);
+void adw_intr(void *arg);
+int adw_attach(struct adw_softc *adw);
+void adw_done(struct adw_softc *adw, union ccb* ccb,
+ u_int done_stat, u_int host_stat,
+ u_int scsi_stat, u_int q_no);
+timeout_t adw_timeout;
+
+extern u_long adw_unit;
+#endif /* _ADWVAR_H_ */
OpenPOWER on IntegriCloud