diff options
Diffstat (limited to 'sys/dev/advansys')
-rw-r--r-- | sys/dev/advansys/adv_eisa.c | 346 | ||||
-rw-r--r-- | sys/dev/advansys/adv_isa.c | 419 | ||||
-rw-r--r-- | sys/dev/advansys/adv_pci.c | 327 | ||||
-rw-r--r-- | sys/dev/advansys/advansys.c | 1424 | ||||
-rw-r--r-- | sys/dev/advansys/advansys.h | 55 | ||||
-rw-r--r-- | sys/dev/advansys/advlib.c | 2082 | ||||
-rw-r--r-- | sys/dev/advansys/advlib.h | 876 | ||||
-rw-r--r-- | sys/dev/advansys/advmcode.c | 282 | ||||
-rw-r--r-- | sys/dev/advansys/advmcode.h | 19 | ||||
-rw-r--r-- | sys/dev/advansys/adw_pci.c | 396 | ||||
-rw-r--r-- | sys/dev/advansys/adwcam.c | 1540 | ||||
-rw-r--r-- | sys/dev/advansys/adwlib.c | 893 | ||||
-rw-r--r-- | sys/dev/advansys/adwlib.h | 878 | ||||
-rw-r--r-- | sys/dev/advansys/adwmcode.c | 994 | ||||
-rw-r--r-- | sys/dev/advansys/adwmcode.h | 135 | ||||
-rw-r--r-- | sys/dev/advansys/adwvar.h | 55 |
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, + ®s_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, + ®s_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_ */ |