diff options
author | gibbs <gibbs@FreeBSD.org> | 1998-09-15 07:03:43 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1998-09-15 07:03:43 +0000 |
commit | 0a5c401474482bc7ad9d6fa07c5056d624e2ed2c (patch) | |
tree | a227ffcca46b316cbf6791d68256c3726bd35670 /sys | |
parent | c3636169750363290acb8611ce6da6ab2b71dec1 (diff) | |
download | FreeBSD-src-0a5c401474482bc7ad9d6fa07c5056d624e2ed2c.zip FreeBSD-src-0a5c401474482bc7ad9d6fa07c5056d624e2ed2c.tar.gz |
Advance Systems SCSI Host Adapter driver for CAM. Currently only support
the 8bit SCSI AdvanSys products.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/advansys/adv_isa.c | 264 | ||||
-rw-r--r-- | sys/dev/advansys/adv_pci.c | 275 | ||||
-rw-r--r-- | sys/dev/advansys/advansys.c | 1281 | ||||
-rw-r--r-- | sys/dev/advansys/advansys.h | 59 | ||||
-rw-r--r-- | sys/dev/advansys/advlib.c | 1518 | ||||
-rw-r--r-- | sys/dev/advansys/advlib.h | 558 | ||||
-rw-r--r-- | sys/dev/advansys/advmcode.c | 358 | ||||
-rw-r--r-- | sys/dev/advansys/advmcode.h | 4 | ||||
-rw-r--r-- | sys/i386/isa/adv_isa.c | 264 | ||||
-rw-r--r-- | sys/pci/adv_pci.c | 275 |
10 files changed, 3791 insertions, 1065 deletions
diff --git a/sys/dev/advansys/adv_isa.c b/sys/dev/advansys/adv_isa.c index e7c8915..aa311d6 100644 --- a/sys/dev/advansys/adv_isa.c +++ b/sys/dev/advansys/adv_isa.c @@ -2,30 +2,34 @@ * Device probe and attach routines for the following * Advanced Systems Inc. SCSI controllers: * - * Connectivity Products: - * ABP5140 - Bus-Master PnP ISA 16 CDB + * 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 240 CDB - * ABP5150 - Bus-Master ISA 240 CDB (shipped by HP with the 4020i CD-R drive) - * ABP842 - Bus-Master VL 240 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 + * Dual Channel Products: + * ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) * - * Copyright (c) 1996 Justin T. Gibbs. + * * 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 immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products + * 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 @@ -40,16 +44,22 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: adv_isa.c,v 1.3 1997/02/22 09:35:51 peter Exp $ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> + +#include <machine/bus_pio.h> +#include <machine/bus.h> #include <i386/isa/isa.h> #include <i386/isa/isa_device.h> -#include <i386/scsi/advansys.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) @@ -57,6 +67,14 @@ #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; +bus_dma_tag_t overrun_dmat; +bus_dmamap_t overrun_dmamap; +bus_addr_t overrun_physbase; + /* Possible port addresses an ISA or VL adapter can live at */ u_int16_t adv_isa_ioports[] = { @@ -73,14 +91,15 @@ u_int16_t adv_isa_ioports[] = 0x330 /* Eighth and default selection in BIOS setup */ }; -#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_short) - 1) +#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_int16_t) - 1) -static int advisaprobe __P((struct isa_device *id)); -static int advisaattach __P((struct isa_device *id)); -static void adv_set_isapnp_wait_for_key __P((void)); -static int adv_find_signature __P((u_int16_t iobase)); +static int advisaprobe(struct isa_device *id); +static int advisaattach(struct isa_device *id); +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); -void adv_isa_intr __P((int unit)); +void adv_isa_intr(void *unit); struct isa_driver advdriver = { @@ -90,8 +109,7 @@ struct isa_driver advdriver = }; static int -advisaprobe(id) - struct isa_device *id; +advisaprobe(struct isa_device *id) { int port_index; int max_port_index; @@ -123,65 +141,173 @@ advisaprobe(id) 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; + if (port_addr == 0) /* Already been attached */ continue; - if (adv_find_signature(port_addr)) { + if (adv_find_signature(I386_BUS_SPACE_IO, port_addr)) { /* * Got one. Now allocate our softc * and see if we can initialize the card. */ struct adv_softc *adv; - adv = adv_alloc(id->id_unit, port_addr); + adv = adv_alloc(id->id_unit, I386_BUS_SPACE_IO, + port_addr); if (adv == NULL) return (0); - id->id_iobase = adv->iobase; + adv_unit++; + + id->id_iobase = adv->bsh; + + /* + * 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; + id->id_drq = -1; + } 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); + id->id_drq = adv->isa_dma_channel; + } 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*/0, + /*boundary*/0, + lowaddr, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, + /*filterarg*/NULL, + maxsize, + /*nsegs*/BUS_SPACE_UNRESTRICTED, + 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); + return (0); + } + + adv->init_level++; + + if (overrun_buf == NULL) { + /* Need to allocate our overrun buffer */ + if (bus_dma_tag_create(adv->parent_dmat, + /*alignment*/8, + /*boundary*/0, + ADV_ISA_MAX_DMA_ADDR, + BUS_SPACE_MAXADDR, + /*filter*/NULL, + /*filterarg*/NULL, + ADV_OVERRUN_BSIZE, + /*nsegments*/1, + BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, + &overrun_dmat) != 0) { + adv_free(adv); + return (0); + } + if (bus_dmamem_alloc(overrun_dmat, + (void **)&overrun_buf, + BUS_DMA_NOWAIT, + &overrun_dmamap) != 0) { + bus_dma_tag_destroy(overrun_dmat); + adv_free(adv); + return (0); + } + /* 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) { adv_free(adv); return (0); } + switch (adv->type) { case ADV_ISAPNP: - if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG) - adv->needs_async_bug_fix = TARGET_BIT_VECTOR_SET; + 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"); } - if ((adv->type & ADV_ISAPNP) == ADV_ISAPNP) { - } - /* Determine our IRQ */ if (id->id_irq == 0 /* irq ? */) id->id_irq = 1 << adv_get_chip_irq(adv); else adv_set_chip_irq(adv, ffs(id->id_irq) - 1); + id->id_intr = adv_isa_intr; /* Mark as probed */ adv_isa_ioports[port_index] = 0; - break; + return 1; } } - return 1; + return 0; } static int -advisaattach(id) - struct isa_device *id; +advisaattach(struct isa_device *id) { struct adv_softc *adv; @@ -189,6 +315,44 @@ advisaattach(id) 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) { @@ -202,35 +366,13 @@ adv_set_isapnp_wait_for_key(void) } /* - * Determine if there is a board at "iobase" by looking - * for the AdvanSys signatures. Return 1 if a board is - * found, 0 otherwise. - */ -static int -adv_find_signature(iobase) - u_int16_t iobase; -{ - u_int16_t signature; - - if (inb(iobase + ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) { - signature = inw(iobase + ADV_SIGNATURE_WORD ); - if ((signature == ADV_1000_ID0W) - || (signature == ADV_1000_ID0W_FIX)) - return (1); - } - return (0); -} - - -/* * Handle an ISA interrupt. * XXX should go away as soon as ISA interrupt handlers * take a (void *) arg. */ void -adv_isa_intr(unit) - int unit; +adv_isa_intr(void *unit) { - struct adv_softc *arg = advsoftcs[unit]; + struct adv_softc *arg = advsoftcs[(int)unit]; adv_intr((void *)arg); } diff --git a/sys/dev/advansys/adv_pci.c b/sys/dev/advansys/adv_pci.c new file mode 100644 index 0000000..2f9e4e1 --- /dev/null +++ b/sys/dev/advansys/adv_pci.c @@ -0,0 +1,275 @@ +/* + * Device probe and attach routines for the following + * Advanced Systems Inc. SCSI controllers: + * + * Connectivity Products: + * ABP920 - 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 Ultra (16 CDB) + * + * Single Channel Products: + * ABP940 - Bus-Master PCI (240 CDB) + * ABP940U - Bus-Master PCI Ultra (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) + * + * 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, 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. + * + * $Id$ + */ + +#include <pci.h> +#if NPCI > 0 +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> + +#include <machine/bus_pio.h> +#include <machine/bus.h> + +#include <pci/pcireg.h> +#include <pci/pcivar.h> + +#include <dev/advansys/advansys.h> + +#define PCI_BASEADR0 PCI_MAP_REG_START /* I/O Address */ +#define PCI_BASEADR1 PCI_MAP_REG_START + 4 /* Mem I/O Address */ + +#define PCI_DEVICE_ID_ADVANSYS_1200A 0x110010CD +#define PCI_DEVICE_ID_ADVANSYS_1200B 0x120010CD +#define PCI_DEVICE_ID_ADVANSYS_ULTRA 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 char* advpciprobe(pcici_t tag, pcidi_t type); +static void advpciattach(pcici_t config_id, int unit); + +/* + * The overrun buffer shared amongst all PCI adapters. + */ +static u_int8_t* overrun_buf; +bus_dma_tag_t overrun_dmat; +bus_dmamap_t overrun_dmamap; +bus_addr_t overrun_physbase; + +static struct pci_device adv_pci_driver = { + "adv", + advpciprobe, + advpciattach, + &adv_unit, + NULL +}; + +DATA_SET (pcidevice_set, adv_pci_driver); + +static char* +advpciprobe(pcici_t tag, pcidi_t type) +{ + int rev = pci_conf_read(tag, PCI_CLASS_REG) & 0xff; + switch (type) { + case PCI_DEVICE_ID_ADVANSYS_1200A: + return ("AdvanSys ASC1200A SCSI controller"); + case PCI_DEVICE_ID_ADVANSYS_1200B: + return ("AdvanSys ASC1200B SCSI controller"); + case PCI_DEVICE_ID_ADVANSYS_ULTRA: + if (rev == PCI_DEVICE_REV_ADVANSYS_3150) + return ("AdvanSys ASC3150 Ultra SCSI controller"); + else + return ("AdvanSys ASC3050 Ultra SCSI controller"); + break; + default: + break; + } + return (NULL); +} + +static void +advpciattach(pcici_t config_id, int unit) +{ + u_int16_t io_port; + u_int16_t config_msw; + struct adv_softc *adv; + u_int32_t id; + u_int32_t command; + int error; + + /* + * Determine the chip version. + */ + id = pci_cfgread(config_id, PCI_ID_REG, /*bytes*/4); + command = pci_cfgread(config_id, 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_cfgwrite(config_id, 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_cfgwrite(config_id, PCIR_LATTIMER, /*value*/0, /*bytes*/1); + } + + + if (pci_map_port(config_id, PCI_BASEADR0, &io_port) == 0) + return; + + if (adv_find_signature(I386_BUS_SPACE_IO, io_port) == 0) + return; + + adv = adv_alloc(unit, I386_BUS_SPACE_IO, io_port); + if (adv == NULL) + return; + + /* 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*/0, + /*boundary*/0, + /*lowaddr*/ADV_PCI_MAX_DMA_ADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, + /*nsegments*/BUS_SPACE_UNRESTRICTED, + /*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); + return; + } + + adv->init_level++; + + if (overrun_buf == NULL) { + /* Need to allocate our overrun buffer */ + if (bus_dma_tag_create(adv->parent_dmat, + /*alignment*/8, /*boundary*/0, + ADV_PCI_MAX_DMA_ADDR, BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + ADV_OVERRUN_BSIZE, /*nsegments*/1, + BUS_SPACE_MAXSIZE_32BIT, /*flags*/0, + &overrun_dmat) != 0) { + bus_dma_tag_destroy(adv->parent_dmat); + adv_free(adv); + return; + } + 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); + return; + } + /* 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_3150) + extra_cfg = ADV_IFC_ACT_NEG | ADV_IFC_SLEW_RATE; + else 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); + return; + } + + adv->max_dma_count = ADV_PCI_MAX_DMA_COUNT; + adv->max_dma_addr = ADV_PCI_MAX_DMA_ADDR; + +#if CC_DISABLE_PCI_PARITY_INT + 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; + } + + if ((pci_map_int(config_id, adv_intr, (void *)adv, &cam_imask)) == 0) { + adv_free(adv); + return; + } + + adv_attach(adv); +} + +#endif /* NPCI > 0 */ diff --git a/sys/dev/advansys/advansys.c b/sys/dev/advansys/advansys.c new file mode 100644 index 0000000..2258035 --- /dev/null +++ b/sys/dev/advansys/advansys.c @@ -0,0 +1,1281 @@ +/* + * 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-1998 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. + * + * $Id: advansys.c,v 1.4 1997/02/22 09:38:38 peter Exp $ + */ +/* + * 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/buf.h> +#include <sys/kernel.h> + +#include <machine/bus_pio.h> +#include <machine/bus.h> +#include <machine/clock.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> + +u_long adv_unit; + +static void advminphys(struct buf *bp); +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); + + +struct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */ + +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); +} + +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]; + + sprintf(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); + cinfo->state |= ACCB_ACTIVE; + + if (cinfo == NULL) + panic("XXX Handle CCB info error!!!"); + + ccb_h->ccb_cinfo_ptr = cinfo; + + /* 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. + */ + xpt_freeze_simq(adv->sim, + /*count*/1); + cinfo->state |= + ACCB_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; + 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; + u_int offset; + target_bit_vector targ_mask; + struct adv_target_transinfo *tconf; + u_int update_type; + int s; + + cts = &ccb->cts; + targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id); + tconf = &adv->tinfo[cts->ccb_h.target_id]; + update_type = 0; + if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) + update_type |= ADV_TRANS_GOAL; + if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) + update_type |= ADV_TRANS_USER; + + 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 ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) { + if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) + cts->sync_offset = 0; + + 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: + { + struct ccb_calc_geometry *ccg; + u_int32_t size_mb; + u_int32_t secs_per_cylinder; + int extended; + + ccg = &ccb->ccg; + size_mb = ccg->volume_size + / ((1024L * 1024L) / ccg->block_size); + extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0; + + if (size_mb > 1024 && extended) { + ccg->heads = 255; + ccg->secs_per_track = 63; + } else { + ccg->heads = 64; + ccg->secs_per_track = 32; + } + secs_per_cylinder = ccg->heads * ccg->secs_per_track; + ccg->cylinders = ccg->volume_size / secs_per_cylinder; + ccb->ccb_h.status = CAM_REQ_CMP; + 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); + 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); + 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; + + 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_ptr = (u_int32_t)csio; + 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; + + 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); + } + if ((cinfo->state & ACCB_RELEASE_SIMQ) != 0) { + ccb_h->status |= CAM_RELEASE_SIMQ; + } + adv_free_ccb_info(adv, cinfo); + xpt_done((union ccb *)csio); + splx(s); + return; + } + + 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; + } + + if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) { + /* Temporary resource shortage */ + if (nsegments != 0) { + bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); + } + ccb_h->status = CAM_REQUEUE_REQ; + if ((cinfo->state & ACCB_RELEASE_SIMQ) != 0) + ccb_h->status |= CAM_RELEASE_SIMQ; + + /* Unfreeze when resources are available */ + xpt_freeze_simq(adv->sim, /*count*/1); + + adv_free_ccb_info(adv, cinfo); + xpt_done((union ccb *)csio); + splx(s); + return; + } + 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 = malloc(sizeof(*cinfo), M_DEVBUF, M_NOWAIT); + if (cinfo == NULL) + printf("%s: Can't malloc CCB info\n", adv_name(adv)); + 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); + free(cinfo, M_DEVBUF); + cinfo = NULL; + } + 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); + free(cinfo, M_DEVBUF); +} + +static void +advminphys(struct buf *bp) +{ + if (bp->b_bcount > ((ADV_MAX_SG_LIST - 1) * PAGE_SIZE)) + bp->b_bcount = ((ADV_MAX_SG_LIST - 1) * PAGE_SIZE); +} + +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. + */ + if ((cinfo->state & ACCB_RELEASE_SIMQ) == 0) { + xpt_freeze_simq(adv->sim, /*count*/1); + cinfo->state |= ACCB_RELEASE_SIMQ; + } + + /* 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); + } + adv_start_execution(adv); + splx(s); +} + +struct adv_softc * +adv_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh) +{ + struct adv_softc *adv; + int i; + + if (unit >= NADV) { + printf("adv: unit number (%d) too high\n", unit); + return NULL; + } + + /* + * Allocate a storage area for us + */ + if (advsoftcs[unit]) { + printf("adv%d: memory already allocated\n", unit); + return NULL; + } + + adv = malloc(sizeof(struct adv_softc), M_DEVBUF, M_NOWAIT); + if (!adv) { + printf("adv%d: cannot malloc!\n", unit); + return NULL; + } + bzero(adv, sizeof(struct adv_softc)); + LIST_INIT(&adv->pending_ccbs); + SLIST_INIT(&adv->free_ccb_infos); + advsoftcs[unit] = adv; + adv->unit = unit; + adv->tag = tag; + adv->bsh = bsh; + + return(adv); +} + +void +adv_free(struct adv_softc *adv) +{ + switch (adv->init_level) { + case 5: + { + struct adv_ccb_info *cinfo; + + while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) { + SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links); + adv_free_ccb_info(adv, cinfo); + } + + bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap); + } + case 4: + bus_dmamem_free(adv->sense_dmat, adv->sense_buffers, + adv->sense_dmamap); + case 3: + bus_dma_tag_destroy(adv->sense_dmat); + case 2: + bus_dma_tag_destroy(adv->buffer_dmat); + case 1: + bus_dma_tag_destroy(adv->parent_dmat); + case 0: + break; + } + free(adv, M_DEVBUF); +} + +int +adv_init(struct adv_softc *adv) +{ + struct adv_eeprom_config eeprom_config; + int checksum, i; + u_int16_t config_lsw; + u_int16_t config_msw; + + adv_reset_chip_and_scsi_bus(adv); + adv_lib_init(adv); + + /* + * Stop script execution. + */ + adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE); + adv_stop_execution(adv); + if (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); + + eeprom_config.cfg_msw &= (~(ADV_CFG_MSW_CLR_MASK)); + + 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 = + ADV_INW(adv, ADV_CONFIG_LSW); + } + if (eeprom_config.cfg_msw != config_msw) { + eeprom_config.cfg_msw = + ADV_INW(adv, ADV_CONFIG_MSW); + } + } + } + eeprom_config.cfg_lsw |= ADV_CFG_LSW_HOST_INT_ON; + if (adv_test_external_lram(adv) == 0) { + /* + * XXX What about non PCI cards with no + * external LRAM???? + */ + 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; + ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); + 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; + } + 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++) + adv_sdtr_to_period_offset(adv, + eeprom_config.sdtr_data[i], + &adv->tinfo[i].user.period, + &adv->tinfo[i].user.offset, + i); + } 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; + + 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); + } + + if (adv_set_eeprom_config(adv, &eeprom_config) != 0) + printf("%s: WARNING! Failure writing to EEPROM.\n", + adv_name(adv)); + + 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) ? "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; + int status; + u_int8_t host_flag; + + adv = (struct adv_softc *)arg; + + 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_INW(adv, ADV_CHIP_STATUS)) & ADV_CSW_INT_PENDING) { + + 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) + && (ctrl_reg & ADV_CC_SINGLE_STEP)) { + 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); +} + +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; + 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); + + done_qaddr = ADV_QNO_TO_QADDR(done_qno); +#ifdef DIAGNOSTIC + if (sg_list_qp == ASC_QLINK_END) { + panic("adv_qdone: Corrupted SG " + "list encountered"); + } +#endif + /* 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_total_qng < n_q_used) + 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; + } + } + + ccb = (union ccb *)scsiq.d2.ccb_ptr; + ccb->csio.resid = scsiq.remain_bytes; + adv_done(adv, (union ccb *)scsiq.d2.ccb_ptr, + 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; + /* + * Null this out so that we catch driver bugs that cause a + * ccb to be completed twice. + */ + ccb->ccb_h.ccb_cinfo_ptr = NULL; + 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: + switch (host_stat) { + case QHSTA_NO_ERROR: + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case QHSTA_M_SEL_TIMEOUT: + ccb->ccb_h.status = CAM_SEL_TIMEOUT; + break; + default: + /* QHSTA error occurred */ + /* XXX Can I get more explicit information here? */ + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; + } + break; + + case QD_WITH_ERROR: + switch (host_stat) { + 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; + default: + /* XXX Can I get more explicit information here? */ + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; + } + 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: + printf("adv_done: Unknown done status 0x%x\n", done_stat); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; + } + if ((cinfo->state & ACCB_RELEASE_SIMQ) != 0) + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + else if (adv->openings_needed > 0) { + int openings; + + openings = adv->max_openings - adv->cur_active - ADV_MIN_FREE_Q; + if (openings >= adv->openings_needed) { + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + adv->openings_needed = 0; + } + } + /* Remove from the pending list */ + LIST_REMOVE(&ccb->ccb_h, sim_links.le); + + untimeout(adv_timeout, ccb, ccb->ccb_h.timeout_ch); + if ((cinfo->state & ACCB_RECOVERY_CCB) != 0) { + /* + * We now traverse our list of pending CCBs and reinstate + * their timeouts. + */ + struct cam_path *path; + struct ccb_hdr *ccb_h; + cam_status error; + + 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); + } + printf("%s: No longer in timeout\n", adv_name(adv)); + } + 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); + 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; + + /* + * Create our DMA tags. These tags define the kinds of device + * accessable 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. + */ + + /* DMA tag for mapping buffers into device visible space. */ + if (bus_dma_tag_create(adv->parent_dmat, /*alignment*/0, /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/MAXBSIZE, + /*nsegments*/ADV_MAX_SG_LIST, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/BUS_DMA_ALLOCNOW, + &adv->buffer_dmat) != 0) { + goto error_exit; + } + adv->init_level++; + + /* DMA tag for our sense buffers */ + if (bus_dma_tag_create(adv->parent_dmat, /*alignment*/0, /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + sizeof(struct scsi_sense_data)*adv->max_openings, + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &adv->sense_dmat) != 0) { + goto error_exit; + } + + 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) { + goto error_exit; + } + + 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 (0); + } + + /* + * Create the device queue for our SIM. + */ + devq = cam_simq_alloc(adv->max_openings); + if (devq == NULL) + return (0); + + /* + * 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 (0); + + /* + * 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 (0); + } + + if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) + == CAM_REQ_CMP) { + 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 (1); + +error_exit: + return (0); +} diff --git a/sys/dev/advansys/advansys.h b/sys/dev/advansys/advansys.h new file mode 100644 index 0000000..5151923 --- /dev/null +++ b/sys/dev/advansys/advansys.h @@ -0,0 +1,59 @@ +/* + * 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. + * + * $Id: advansys.h,v 1.3 1997/02/22 09:38:38 peter Exp $ + */ + +#ifndef _ADVANSYS_H_ +#define _ADVANSYS_H_ + +#include "adv.h" +#include <dev/advansys/advlib.h> + +struct adv_softc * adv_alloc(int unit, 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; + +extern struct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */ + +extern u_long adv_unit; +#endif /* _ADVANSYS_H_ */ diff --git a/sys/dev/advansys/advlib.c b/sys/dev/advansys/advlib.c index 9921cc8..f5881f0 100644 --- a/sys/dev/advansys/advlib.c +++ b/sys/dev/advansys/advlib.c @@ -1,15 +1,15 @@ /* * Low level routines for the Advanced Systems Inc. SCSI controllers chips * - * Copyright (c) 1996 Justin T. Gibbs. + * 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 immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. + * 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. @@ -46,19 +46,79 @@ #include <sys/param.h> #include <sys/systm.h> +#include <machine/bus_pio.h> +#include <machine/bus.h> #include <machine/clock.h> -#include <scsi/scsi_all.h> -#include <scsi/scsi_message.h> -#include <scsi/scsi_disk.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/advlib.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 */ @@ -74,116 +134,251 @@ u_int8_t adv_sdtr_period_tbl[] = 85 }; -struct sdtr_xmsg { - u_int8_t msg_type; - u_int8_t msg_len; - u_int8_t msg_req; - u_int8_t xfer_period; - u_int8_t req_ack_offset; - u_int8_t res; +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 try to use an offset of - * 1. + * async transfers. Instead use an offset of 1. */ -#define ASYN_SDTR_DATA_FIX 0x41 +#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 /* LRAM routines */ -static void adv_read_lram_16_multi __P((struct adv_softc *adv, u_int16_t s_addr, - u_int16_t *buffer, int count)); -static void adv_write_lram_16_multi __P((struct adv_softc *adv, - u_int16_t s_addr, u_int16_t *buffer, - int count)); -static void adv_mset_lram_16 __P((struct adv_softc *adv, - u_int16_t s_addr, u_int16_t set_value, - int count)); -static u_int32_t adv_msum_lram_16 __P((struct adv_softc *adv, u_int16_t s_addr, int count)); - -static int adv_write_and_verify_lram_16 __P((struct adv_softc *adv, - u_int16_t addr, u_int16_t value)); -static u_int32_t adv_read_lram_32 __P((struct adv_softc *adv, u_int16_t addr)); - - -static void adv_write_lram_32 __P((struct adv_softc *adv, u_int16_t addr, - u_int32_t value)); -static void adv_write_lram_32_multi __P((struct adv_softc *adv, u_int16_t s_addr, - u_int32_t *buffer, int count)); +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 __P((struct adv_softc *adv, u_int8_t addr)); -static u_int16_t adv_write_eeprom_16 __P((struct adv_softc *adv, u_int8_t addr, u_int16_t value)); -static int adv_write_eeprom_cmd_reg __P((struct adv_softc *adv, u_int8_t cmd_reg)); -static int adv_set_eeprom_config_once __P((struct adv_softc *adv, - struct adv_eeprom_config *eeprom_config)); +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 __P((struct adv_softc *adv, - u_int16_t s_addr, u_int16_t *mcode_buf, u_int16_t mcode_size)); -static void adv_init_lram __P((struct adv_softc *adv)); -static int adv_init_microcode_var __P((struct adv_softc *adv)); -static void adv_init_qlink_var __P((struct adv_softc *adv)); +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 __P((struct adv_softc *adv)); -static void adv_enable_interrupt __P((struct adv_softc *adv)); -static void adv_toggle_irq_act __P((struct adv_softc *adv)); +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_stop_chip(struct adv_softc *adv); +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 void adv_start_execution __P((struct adv_softc *adv)); -#endif -static int adv_start_chip __P((struct adv_softc *adv)); -static int adv_stop_chip __P((struct adv_softc *adv)); -static void adv_set_chip_ih __P((struct adv_softc *adv, - u_int16_t ins_code)); -static void adv_set_bank __P((struct adv_softc *adv, u_int8_t bank)); -#if UNUSED -static u_int8_t adv_get_chip_scsi_ctrl __P((struct adv_softc *adv)); +static u_int8_t adv_get_chip_scsi_ctrl(struct adv_softc *adv); #endif /* Queue handling and execution */ -static int adv_sgcount_to_qcount __P((int sgcount)); -static void adv_get_q_info __P((struct adv_softc *adv, u_int16_t s_addr, u_int16_t *inbuf, - int words)); -static u_int adv_get_num_free_queues __P((struct adv_softc *adv, - u_int8_t n_qs)); -static u_int8_t adv_alloc_free_queues __P((struct adv_softc *adv, - u_int8_t free_q_head, - u_int8_t n_free_q)); -static u_int8_t adv_alloc_free_queue __P((struct adv_softc *adv, - u_int8_t free_q_head)); -static int adv_send_scsi_queue __P((struct adv_softc *adv, - struct adv_scsi_q *scsiq, - u_int8_t n_q_required)); -static void adv_put_ready_sg_list_queue __P((struct adv_softc *adv, - struct adv_scsi_q *scsiq, - u_int8_t q_no)); -static void adv_put_ready_queue __P((struct adv_softc *adv, - struct adv_scsi_q *scsiq, - u_int8_t q_no)); -static void adv_put_scsiq __P((struct adv_softc *adv, u_int16_t s_addr, - u_int16_t *buffer, int words)); - -/* SDTR */ -static u_int8_t adv_msgout_sdtr __P((struct adv_softc *adv, - u_int8_t sdtr_period, - u_int8_t sdtr_offset)); -static u_int8_t adv_get_card_sync_setting __P((u_int8_t period, - u_int8_t offset)); -static void adv_set_chip_sdtr __P((struct adv_softc *adv, - u_int8_t sdtr_data, - u_int8_t tid_no)); +static int adv_sgcount_to_qcount(int sgcount); +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 */ -u_int8_t -adv_read_lram_8(adv, addr) +void +advasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) +{ struct adv_softc *adv; - u_int16_t addr; - + + 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; @@ -210,10 +405,7 @@ adv_read_lram_8(adv, addr) } void -adv_write_lram_8(adv, addr, value) - struct adv_softc *adv; - u_int16_t addr; - u_int8_t value; +adv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value) { u_int16_t word_data; @@ -230,57 +422,53 @@ adv_write_lram_8(adv, addr, value) u_int16_t -adv_read_lram_16(adv, addr) - struct adv_softc *adv; - u_int16_t addr; +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(adv, addr, value) - struct adv_softc *adv; - u_int16_t addr; - u_int16_t value; +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); } - /* - * Return the fully qualified board type for the adapter. - * The chip_revision must be set before this function is called. + * 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_get_board_type(adv) - struct adv_softc *adv; +adv_lib_init(struct adv_softc *adv) { - if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL) && - (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) { - if (((adv->iobase & 0x0C30) == 0x0C30) || - ((adv->iobase & 0x0C50) == 0x0C50)) { - adv->type = ADV_EISA; - } else - adv->type = ADV_VL; - } 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; - } else - adv->type = ADV_ISA; - } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_PCI) && - (adv->chip_version <= ADV_CHIP_MAX_VER_PCI)) { - adv->type = ADV_PCI; - } else - panic("adv_get_board_type: Unknown board type encountered"); + 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(adv, eeprom_config) - struct adv_softc *adv; - struct adv_eeprom_config *eeprom_config; +adv_get_eeprom_config(struct adv_softc *adv, struct + adv_eeprom_config *eeprom_config) { u_int16_t sum; u_int16_t *wbuf; @@ -316,9 +504,8 @@ adv_get_eeprom_config(adv, eeprom_config) } int -adv_set_eeprom_config(adv, eeprom_config) - struct adv_softc *adv; - struct adv_eeprom_config *eeprom_config; +adv_set_eeprom_config(struct adv_softc *adv, + struct adv_eeprom_config *eeprom_config) { int retry; @@ -335,11 +522,11 @@ adv_set_eeprom_config(adv, eeprom_config) } int -adv_reset_chip_and_scsi_bus(adv) - struct adv_softc *adv; +adv_reset_chip_and_scsi_bus(struct adv_softc *adv) { adv_stop_chip(adv); - ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_SCSI_RESET | ADV_CC_HALT); + ADV_OUTB(adv, ADV_CHIP_CTRL, + ADV_CC_CHIP_RESET | ADV_CC_SCSI_RESET | ADV_CC_HALT); DELAY(200 * 1000); adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); @@ -352,8 +539,7 @@ adv_reset_chip_and_scsi_bus(adv) } int -adv_test_external_lram(adv) - struct adv_softc* adv; +adv_test_external_lram(struct adv_softc* adv) { u_int16_t q_addr; u_int16_t saved_value; @@ -361,7 +547,6 @@ adv_test_external_lram(adv) success = 0; - /* XXX Why 241? */ 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) { @@ -373,15 +558,16 @@ adv_test_external_lram(adv) int -adv_init_lram_and_mcode(adv) - struct adv_softc *adv; +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); + 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); @@ -396,8 +582,7 @@ adv_init_lram_and_mcode(adv) } u_int8_t -adv_get_chip_irq(adv) - struct adv_softc *adv; +adv_get_chip_irq(struct adv_softc *adv) { u_int16_t cfg_lsw; u_int8_t chip_irq; @@ -420,15 +605,14 @@ adv_get_chip_irq(adv) } u_int8_t -adv_set_chip_irq(adv, irq_no) - struct adv_softc *adv; - u_int8_t irq_no; +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)) { + if ((irq_no < ADV_MIN_IRQ_NO) + || (irq_no > ADV_MAX_IRQ_NO)) { irq_no = 0; } else { irq_no -= ADV_MIN_IRQ_NO - 1; @@ -454,40 +638,49 @@ adv_set_chip_irq(adv, irq_no) 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(adv, scsiq) - struct adv_softc *adv; - struct adv_scsi_q *scsiq; +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; - int s; 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; - u_int8_t sdtr_data; - u_int32_t *p_data_addr; - u_int32_t *p_data_bcount; 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); - - n_q_required = 1; - - s = splbio(); - if (scsiq->cdbptr->opcode == REQUEST_SENSE) { - if (((adv->initiate_sdtr & scsiq->q1.target_id) != 0) - && ((adv->sdtr_done & scsiq->q1.target_id) != 0)) { - int sdtr_index; - - sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no); - sdtr_index = (sdtr_data >> 4); - adv_msgout_sdtr(adv, adv_sdtr_period_tbl[sdtr_index], - (sdtr_data & ADV_SYN_MAX_OFFSET)); + 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); } } @@ -498,10 +691,12 @@ adv_execute_scsi_queue(adv, scsiq) #ifdef DIAGNOSTIC if (sg_entry_cnt <= 1) - panic("adv_execute_scsi_queue: Queue with QC_SG_HEAD set but %d segs.", sg_entry_cnt); + 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."); + panic("adv_execute_scsi_queue: " + "Queue with too many segs."); if (adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) { for (i = 0; i < sg_entry_cnt_minus_one; i++) { @@ -509,12 +704,15 @@ adv_execute_scsi_queue(adv, scsiq) scsiq->sg_head->sg_list[i].bytes; if ((addr & 0x0003) != 0) - panic("adv_execute_scsi_queue: SG with odd address or byte count"); + 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; + 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; @@ -524,44 +722,65 @@ adv_execute_scsi_queue(adv, scsiq) n_q_required = 1; } - if (adv->bug_fix_control & ADV_BUG_FIX_ADD_ONE_BYTE) { - addr = *p_data_addr + *p_data_bcount; - if ((addr & 0x0003) != 0) { - /* - * XXX Is this extra test (the one on data_cnt) really only supposed to apply - * to the non SG case or was it a bug due to code duplication? - */ - if ((scsiq->q1.cntl & QC_SG_HEAD) != 0 || (scsiq->q1.data_cnt & 0x01FF) == 0) { - if ((scsiq->cdbptr->opcode == READ_COMMAND) || - (scsiq->cdbptr->opcode == READ_BIG)) { - if ((scsiq->q2.tag_code & ADV_TAG_FLAG_ADD_ONE_BYTE) == 0) { - (*p_data_bcount)++; - scsiq->q2.tag_code |= ADV_TAG_FLAG_ADD_ONE_BYTE; - } + 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)) + || ((scsiq->q1.cntl & QC_URGENT) != 0)) retval = adv_send_scsi_queue(adv, scsiq, n_q_required); - splx(s); return (retval); } u_int8_t -adv_copy_lram_doneq(adv, q_addr, scsiq, max_dma_count) - struct adv_softc *adv; - u_int16_t q_addr; - struct adv_q_done_info *scsiq; - u_int32_t max_dma_count; +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; + 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, @@ -581,10 +800,10 @@ adv_copy_lram_doneq(adv, q_addr, scsiq, max_dma_count) val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN); scsiq->sense_len = val & 0xFF; - scsiq->user_def = (val >> 8) & 0xFF; + scsiq->extra_bytes = (val >> 8) & 0xFF; - scsiq->remain_bytes = adv_read_lram_32(adv, - q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT); + scsiq->remain_bytes = + adv_read_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT); /* * XXX Is this just a safeguard or will the counter really * have bogus upper bits? @@ -595,8 +814,16 @@ adv_copy_lram_doneq(adv, q_addr, scsiq, max_dma_count) } int -adv_stop_execution(adv) - struct adv_softc *adv; +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; @@ -616,8 +843,7 @@ adv_stop_execution(adv) } int -adv_is_chip_halted(adv) - struct adv_softc *adv; +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) { @@ -632,8 +858,7 @@ adv_is_chip_halted(adv) * need to be documented. */ void -adv_ack_interrupt(adv) - struct adv_softc *adv; +adv_ack_interrupt(struct adv_softc *adv) { u_int8_t host_flag; u_int8_t risc_flag; @@ -668,19 +893,16 @@ adv_ack_interrupt(adv) * for us to intervene. */ void -adv_isr_chip_halted(adv) - struct adv_softc *adv; +adv_isr_chip_halted(struct adv_softc *adv) { u_int16_t int_halt_code; - u_int8_t halt_qp; 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; - target_bit_vector target_id; - target_bit_vector scsi_busy; - u_int8_t asyn_sdtr; - u_int8_t sdtr_data; int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W); halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B); @@ -688,224 +910,304 @@ adv_isr_chip_halted(adv) 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_id = ADV_TID_TO_TARGET_ID(tid_no); - if (adv->needs_async_bug_fix & target_id) - asyn_sdtr = ASYN_SDTR_DATA_FIX; - else - asyn_sdtr = 0; - if (int_halt_code == ADV_HALT_EXTMSG_IN) { - struct sdtr_xmsg sdtr_xmsg; - int sdtr_accept; - - adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, - (u_int16_t *) &sdtr_xmsg, - sizeof(sdtr_xmsg) >> 1); - if ((sdtr_xmsg.msg_type == MSG_EXTENDED) && - (sdtr_xmsg.msg_len == MSG_EXT_SDTR_LEN)) { - sdtr_accept = TRUE; - if (sdtr_xmsg.msg_req == MSG_EXT_SDTR) { - if (sdtr_xmsg.req_ack_offset > ADV_SYN_MAX_OFFSET) { - - sdtr_accept = FALSE; - sdtr_xmsg.req_ack_offset = ADV_SYN_MAX_OFFSET; - } - sdtr_data = adv_get_card_sync_setting(sdtr_xmsg.xfer_period, - sdtr_xmsg.req_ack_offset); - if (sdtr_xmsg.req_ack_offset == 0) { - q_cntl &= ~QC_MSG_OUT; - adv->initiate_sdtr &= ~target_id; - adv->sdtr_done &= ~target_id; - adv_set_chip_sdtr(adv, asyn_sdtr, tid_no); - } else if (sdtr_data == 0) { - q_cntl |= QC_MSG_OUT; - adv->initiate_sdtr &= ~target_id; - adv->sdtr_done &= ~target_id; - adv_set_chip_sdtr(adv, asyn_sdtr, tid_no); - } else { - if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { - q_cntl &= ~QC_MSG_OUT; - adv->sdtr_done |= target_id; - adv->initiate_sdtr |= target_id; - adv->needs_async_bug_fix &= ~target_id; - adv_set_chip_sdtr(adv, sdtr_data, tid_no); - } else { - - q_cntl |= QC_MSG_OUT; - - adv_msgout_sdtr(adv, - sdtr_xmsg.xfer_period, - sdtr_xmsg.req_ack_offset); - adv->needs_async_bug_fix &= ~target_id; - adv_set_chip_sdtr(adv, sdtr_data, tid_no); - adv->sdtr_done |= target_id; - adv->initiate_sdtr |= target_id; - } - } - - adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); - } - } + target_mask = ADV_TID_TO_TARGET_MASK(tid_no); + if (int_halt_code == ADV_HALT_DISABLE_ASYN_USE_SYN_FIX) { /* - * XXX Hey, shouldn't we be rejecting any messages we don't understand? - * The old code also did not un-halt the processor if it recieved - * an extended message that it didn't understand. That didn't - * seem right, so I changed this routine to always un-halt the - * processor at the end. + * 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) { - u_int8_t tag_code; - u_int8_t q_status; + struct adv_target_transinfo* tinfo; + union ccb *ccb; + u_int8_t tag_code; + u_int8_t q_status; + tinfo = &adv->tinfo[tid_no]; q_cntl |= QC_REQ_SENSE; - if (((adv->initiate_sdtr & target_id) != 0) && - ((adv->sdtr_done & target_id) != 0)) { - sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no); - /* XXX Macrotize the extraction of the index from sdtr_data ??? */ - adv_msgout_sdtr(adv, adv_sdtr_period_tbl[(sdtr_data >> 4) & 0x0F], - sdtr_data & ADV_SYN_MAX_OFFSET); + /* 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); - 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); + 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); - + adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS, + q_status); + /* + * Freeze the devq until we can handle the sense condition. + */ + ccb = (union ccb *) adv_read_lram_32(adv, halt_q_addr + + ADV_SCSIQ_D_CCBPTR); + 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_id; + scsi_busy &= ~target_mask; adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); } else if (int_halt_code == ADV_HALT_SDTR_REJECTED) { - struct sdtr_xmsg out_msg; + 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)) { + if ((out_msg.msg_type == MSG_EXTENDED) + && (out_msg.msg_len == MSG_EXT_SDTR_LEN) + && (out_msg.msg_req == MSG_EXT_SDTR)) { - adv->initiate_sdtr &= ~target_id; - adv->sdtr_done &= ~target_id; - adv_set_chip_sdtr(adv, asyn_sdtr, tid_no); + /* 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 cur_dvc_qng; - u_int8_t scsi_status; + u_int8_t scsi_status; + union ccb *ccb; + + scsi_status = adv_read_lram_8(adv, halt_q_addr + + ADV_SCSIQ_SCSI_STATUS); + ccb = (union ccb *) adv_read_lram_32(adv, halt_q_addr + + ADV_SCSIQ_D_CCBPTR); + 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); + } + 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); /* - * XXX It would be nice if we could push the responsibility for handling - * this situation onto the generic SCSI layer as other drivers do. - * This would be done by completing the command with the status byte - * set to QUEUE_FULL, whereupon it will request that any transactions - * pending on the target that where scheduled after this one be aborted - * (so as to maintain queue ordering) and the number of requests the - * upper level will attempt to send this target will be reduced. - * - * With this current strategy, am I guaranteed that once I unbusy the - * target the queued up transactions will be sent in the order they - * were queued? If the ASC chip does a round-robin on all queued - * transactions looking for queues to run, the order is not guaranteed. + * If a target can run in sync mode, we don't need + * to check it for sync problems. */ - scsi_status = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_SCSI_STATUS); - cur_dvc_qng = adv_read_lram_8(adv, ADV_QADR_BEG + target_ix); - printf("adv%d: Queue full - target %d, active transactions %d\n", adv->unit, - tid_no, cur_dvc_qng); -#if 0 - /* XXX FIX LATER */ - if ((cur_dvc_qng > 0) && (adv->cur_dvc_qng[tid_no] > 0)) { - scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); - scsi_busy |= target_id; - adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); - asc_dvc->queue_full_or_busy |= target_id; - - if (scsi_status == SS_QUEUE_FULL) { - if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) { - cur_dvc_qng -= 1; - asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng; - - adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + tid_no, - cur_dvc_qng); - } + 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; + } + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + + *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); } } -#endif } - adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); + + /* 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(adv, s_addr, buffer, count) - struct adv_softc *adv; - u_int16_t s_addr; - u_int16_t *buffer; - int count; +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(adv, s_addr, buffer, count) - struct adv_softc *adv; - u_int16_t s_addr; - u_int16_t *buffer; - int count; +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(adv, s_addr, set_value, count) - struct adv_softc *adv; - u_int16_t s_addr; - u_int16_t set_value; - int count; +adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, + u_int16_t set_value, int count) { - int i; - ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); - for (i = 0; i < count; i++) - ADV_OUTW(adv, ADV_LRAM_DATA, set_value); + bus_space_set_multi_2(adv->tag, adv->bsh, ADV_LRAM_DATA, + set_value, count); } static u_int32_t -adv_msum_lram_16(adv, s_addr, count) - struct adv_softc *adv; - u_int16_t s_addr; - int count; +adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count) { u_int32_t sum; int i; sum = 0; - for (i = 0; i < count; i++, s_addr += 2) - sum += adv_read_lram_16(adv, s_addr); + 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(adv, addr, value) - struct adv_softc *adv; - u_int16_t addr; - u_int16_t value; +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; @@ -913,9 +1215,7 @@ adv_write_and_verify_lram_16(adv, addr, value) } static u_int32_t -adv_read_lram_32(adv, addr) - struct adv_softc *adv; - u_int16_t addr; +adv_read_lram_32(struct adv_softc *adv, u_int16_t addr) { u_int16_t val_low, val_high; @@ -933,10 +1233,7 @@ adv_read_lram_32(adv, addr) } static void -adv_write_lram_32(adv, addr, value) - struct adv_softc *adv; - u_int16_t addr; - u_int32_t value; +adv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value) { ADV_OUTW(adv, ADV_LRAM_ADDR, addr); @@ -950,20 +1247,15 @@ adv_write_lram_32(adv, addr, value) } static void -adv_write_lram_32_multi(adv, s_addr, buffer, count) - struct adv_softc *adv; - u_int16_t s_addr; - u_int32_t *buffer; - int count; +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, buffer, count * 2); + ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2); } static u_int16_t -adv_read_eeprom_16(adv, addr) - struct adv_softc *adv; - u_int8_t addr; +adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr) { u_int16_t read_wval; u_int8_t cmd_reg; @@ -979,10 +1271,7 @@ adv_read_eeprom_16(adv, addr) } static u_int16_t -adv_write_eeprom_16(adv, addr, value) - struct adv_softc *adv; - u_int8_t addr; - u_int16_t value; +adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value) { u_int16_t read_value; @@ -1005,9 +1294,7 @@ adv_write_eeprom_16(adv, addr, value) } static int -adv_write_eeprom_cmd_reg(adv, cmd_reg) - struct adv_softc *adv; - u_int8_t cmd_reg; +adv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg) { u_int8_t read_back; int retry; @@ -1027,9 +1314,8 @@ adv_write_eeprom_cmd_reg(adv, cmd_reg) } static int -adv_set_eeprom_config_once(adv, eeprom_config) - struct adv_softc *adv; - struct adv_eeprom_config *eeprom_config; +adv_set_eeprom_config_once(struct adv_softc *adv, + struct adv_eeprom_config *eeprom_config) { int n_error; u_int16_t *wbuf; @@ -1080,38 +1366,41 @@ adv_set_eeprom_config_once(adv, eeprom_config) } static u_int32_t -adv_load_microcode(adv, s_addr, mcode_buf, mcode_size) - struct adv_softc *adv; - u_int16_t s_addr; - u_int16_t *mcode_buf; - u_int16_t mcode_size; +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; + 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_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)); + ((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_init_lram(adv) - struct adv_softc *adv; +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; + u_int8_t i; + u_int16_t s_addr; adv_mset_lram_16(adv, ADV_QADR_BEG, 0, - (u_int16_t)((((int)adv->max_openings + 2 + 1) * 64) >> 1)); + (((adv->max_openings + 2 + 1) * 64) >> 1)); i = ADV_MIN_ACTIVE_QNO; s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE; @@ -1141,39 +1430,30 @@ adv_init_lram(adv) } static int -adv_init_microcode_var(adv) - struct adv_softc *adv; +adv_init_microcode_var(struct adv_softc *adv) { - int i; + int i; for (i = 0; i <= ADV_MAX_TID; i++) { - adv_write_lram_8(adv, ADVV_SDTR_DATA_BEG + i, - adv->sdtr_data[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); - /* XXX Again, what about wide busses??? */ 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); - /* What are the extra 8 bytes for?? */ - adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, vtophys(&(adv->overrun_buf[0])) + 8); + adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase); - adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE - 8); + adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE); -#if 0 - /* If we're going to print anything, RCS ids are more meaningful */ - mcode_date = adv_read_lram_16(adv, ADVV_MC_DATE_W); - mcode_version = adv_read_lram_16(adv, ADVV_MC_VER_W); -#endif 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); - } - if (adv_start_chip(adv) != 1) { - printf("adv%d: Unable to start on board processor. Aborting.\n", + printf("adv%d: Unable to set program counter. Aborting.\n", adv->unit); return (1); } @@ -1181,8 +1461,7 @@ adv_init_microcode_var(adv) } static void -adv_init_qlink_var(adv) - struct adv_softc *adv; +adv_init_qlink_var(struct adv_softc *adv) { int i; u_int16_t lram_addr; @@ -1205,16 +1484,15 @@ adv_init_qlink_var(adv) 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_CDBCNT_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(adv) - struct adv_softc *adv; +adv_disable_interrupt(struct adv_softc *adv) { u_int16_t cfg; @@ -1223,8 +1501,7 @@ adv_disable_interrupt(adv) } static void -adv_enable_interrupt(adv) - struct adv_softc *adv; +adv_enable_interrupt(struct adv_softc *adv) { u_int16_t cfg; @@ -1233,37 +1510,22 @@ adv_enable_interrupt(adv) } static void -adv_toggle_irq_act(adv) - struct adv_softc *adv; +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); } -#if UNUSED -static void -adv_start_execution(adv) - struct adv_softc *adv; +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); } } -#endif - -static int -adv_start_chip(adv) - 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); -} static int -adv_stop_chip(adv) - struct adv_softc *adv; +adv_stop_chip(struct adv_softc *adv) { u_int8_t cc_val; @@ -1278,42 +1540,38 @@ adv_stop_chip(adv) 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(adv, ins_code) - struct adv_softc *adv; - u_int16_t ins_code; +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); } -static void -adv_set_bank(adv, 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); -} - #if UNUSED static u_int8_t -adv_get_chip_scsi_ctrl(adv) - struct adv_softc *adv; +adv_get_chip_scsi_ctrl(struct adv_softc *adv) { u_int8_t scsi_ctrl; @@ -1325,8 +1583,7 @@ adv_get_chip_scsi_ctrl(adv) #endif static int -adv_sgcount_to_qcount(sgcount) - int sgcount; +adv_sgcount_to_qcount(int sgcount) { int n_sg_list_qs; @@ -1341,11 +1598,8 @@ adv_sgcount_to_qcount(sgcount) * There has to be a way to turn this into an insw. */ static void -adv_get_q_info(adv, s_addr, inbuf, words) - struct adv_softc *adv; - u_int16_t s_addr; - u_int16_t *inbuf; - int words; +adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, + u_int16_t *inbuf, int words) { int i; @@ -1359,36 +1613,24 @@ adv_get_q_info(adv, s_addr, inbuf, words) } static u_int -adv_get_num_free_queues(adv, n_qs) - struct adv_softc *adv; - u_int8_t n_qs; +adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs) { u_int cur_used_qs; u_int cur_free_qs; - if (n_qs == 1) - cur_used_qs = adv->cur_active + - adv->openings_needed + - ADV_MIN_FREE_Q; - else - cur_used_qs = adv->cur_active + - ADV_MIN_FREE_Q; + 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); } - if (n_qs > 1) - if (n_qs > adv->openings_needed) - adv->openings_needed = n_qs; + adv->openings_needed = n_qs; return (0); } static u_int8_t -adv_alloc_free_queues(adv, free_q_head, n_free_q) - struct adv_softc *adv; - u_int8_t free_q_head; - u_int8_t n_free_q; +adv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head, + u_int8_t n_free_q) { int i; @@ -1401,9 +1643,7 @@ adv_alloc_free_queues(adv, free_q_head, n_free_q) } static u_int8_t -adv_alloc_free_queue(adv, free_q_head) - struct adv_softc *adv; - u_int8_t free_q_head; +adv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head) { u_int16_t q_addr; u_int8_t next_qp; @@ -1420,10 +1660,8 @@ adv_alloc_free_queue(adv, free_q_head) } static int -adv_send_scsi_queue(adv, scsiq, n_q_required) - struct adv_softc *adv; - struct adv_scsi_q *scsiq; - u_int8_t n_q_required; +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; @@ -1437,25 +1675,15 @@ adv_send_scsi_queue(adv, scsiq, n_q_required) 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) { - if (n_q_required > 1) { - /* - * Only reset the shortage value when processing - * a "normal" request and not error recovery or - * other requests that dip into our reserved queues. - * Generally speaking, a normal request will need more - * than one queue. - */ - adv->openings_needed = 0; - } scsiq->q1.q_no = free_q_head; /* * Now that we know our Q number, point our sense - * buffer pointer to an area below 16M if we are - * an ISA adapter. + * buffer pointer to a bus dma mapped area where + * we can dma the data to. */ - if (adv->sense_buffers != NULL) - scsiq->q1.sense_addr = (u_int32_t)vtophys(&(adv->sense_buffers[free_q_head])); + 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; @@ -1466,10 +1694,8 @@ adv_send_scsi_queue(adv, scsiq, n_q_required) static void -adv_put_ready_sg_list_queue(adv, scsiq, q_no) - struct adv_softc *adv; - struct adv_scsi_q *scsiq; - u_int8_t q_no; +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; @@ -1485,9 +1711,11 @@ adv_put_ready_sg_list_queue(adv, scsiq, q_no) 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"); + 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"); + 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; @@ -1505,7 +1733,7 @@ adv_put_ready_sg_list_queue(adv, scsiq, q_no) scsi_sg_q.cntl |= QCSG_SG_XFER_END; } scsi_sg_q.seq_no = i + 1; - sg_list_dwords = segs_this_q * 2; + 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; @@ -1517,7 +1745,8 @@ adv_put_ready_sg_list_queue(adv, scsiq, q_no) 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, + 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, @@ -1531,28 +1760,18 @@ adv_put_ready_sg_list_queue(adv, scsiq, q_no) } static void -adv_put_ready_queue(adv, scsiq, q_no) - struct adv_softc *adv; - struct adv_scsi_q *scsiq; - u_int8_t q_no; +adv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, + u_int q_no) { - u_int16_t q_addr; - u_int8_t tid_no; - u_int8_t sdtr_data; - u_int8_t syn_period_ix; - u_int8_t syn_offset; - - if (((adv->initiate_sdtr & scsiq->q1.target_id) != 0) && - ((adv->sdtr_done & scsiq->q1.target_id) == 0)) { + struct adv_target_transinfo* tinfo; + u_int q_addr; + u_int tid_no; - tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix); - - sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no); - syn_period_ix = (sdtr_data >> 4) & (ADV_SYN_XFER_NO - 1); - syn_offset = sdtr_data & ADV_SYN_MAX_OFFSET; - adv_msgout_sdtr(adv, adv_sdtr_period_tbl[syn_period_ix], - syn_offset); + tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix); + tinfo = &adv->tinfo[tid_no]; + if (tinfo->current.period != tinfo->goal.period) { + adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset); scsiq->q1.cntl |= QC_MSG_OUT; } q_addr = ADV_QNO_TO_QADDR(q_no); @@ -1587,11 +1806,8 @@ adv_put_ready_queue(adv, scsiq, q_no) } static void -adv_put_scsiq(adv, s_addr, buffer, words) - struct adv_softc *adv; - u_int16_t s_addr; - u_int16_t *buffer; - int words; +adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, + u_int16_t *buffer, int words) { int i; @@ -1619,13 +1835,88 @@ adv_put_scsiq(adv, s_addr, buffer, words) } } -static u_int8_t -adv_msgout_sdtr(adv, sdtr_period, sdtr_offset) - struct adv_softc *adv; - u_int8_t sdtr_period; - u_int8_t sdtr_offset; +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_int period; + u_int offset; + int sdtr_accept; + u_int8_t orig_offset; + + ccb = (union ccb *) adv_read_lram_32(adv, halt_q_addr + + ADV_SCSIQ_D_CCBPTR); + 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 sdtr_xmsg sdtr_buf; + struct ext_msg sdtr_buf; sdtr_buf.msg_type = MSG_EXTENDED; sdtr_buf.msg_len = MSG_EXT_SDTR_LEN; @@ -1636,32 +1927,101 @@ adv_msgout_sdtr(adv, sdtr_period, sdtr_offset) adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, (u_int16_t *) &sdtr_buf, sizeof(sdtr_buf) / 2); - - return (adv_get_card_sync_setting(sdtr_period, sdtr_offset)); } -static u_int8_t -adv_get_card_sync_setting(period, offset) - u_int8_t period; - u_int8_t offset; +int +adv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb, + u_int32_t status, int queued_only) { - u_int i; + 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++) { + q_addr = ADV_QNO_TO_QADDR(q_no); - if (period >= adv_sdtr_period_tbl[0]) { - for (i = 0; i < sizeof(adv_sdtr_period_tbl); i++) { - if (period <= adv_sdtr_period_tbl[i]) - return ((adv_sdtr_period_tbl[i] << 4) | offset); + adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count); + 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 == (union ccb *)scsiq->d2.ccb_ptr))) { + union ccb *aborted_ccb; + struct adv_ccb_info *cinfo; + + scsiq->q_status |= QS_ABORTED; + scsiq->d3.done_stat = QD_ABORTED_BY_HOST; + adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS, + scsiq->q_status); + aborted_ccb = (union ccb *)scsiq->d2.ccb_ptr; + /* 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 (0); + return (count); +} + +int +adv_reset_bus(struct adv_softc *adv) +{ + int count; + int i; + union ccb *ccb; + + adv_reset_chip_and_scsi_bus(adv); + adv_reinit_lram(adv); + for (i = 0; i <= ADV_MAX_TID; i++) { + if (adv->fix_asyn_xfer & (0x01 << i)) + adv_set_sdtr_reg_at_id(adv, i, + ASYN_SDTR_DATA_FIX_PCI_REV_AB); + } + 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) { + struct adv_ccb_info *cinfo; + + 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_chip_sdtr(adv, sdtr_data, tid_no) - struct adv_softc *adv; - u_int8_t sdtr_data; - u_int8_t tid_no; +adv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data) { - ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data); - adv_write_lram_8(adv, ADVV_SDTR_DONE_BEG + tid_no, 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 index 9e18137..294618a 100644 --- a/sys/dev/advansys/advlib.h +++ b/sys/dev/advansys/advlib.h @@ -2,15 +2,15 @@ * Definitions for low level routines and data structures * for the Advanced Systems Inc. SCSI controllers chips. * - * Copyright (c) 1996 Justin T. Gibbs. + * 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 immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. + * 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. @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: advlib.h,v 1.3 1997/02/22 09:28:47 peter Exp $ */ /* * Ported from: @@ -44,61 +44,70 @@ * modification. */ +#ifndef _ADVLIB_H_ +#define _ADVLIB_H_ + +#include <sys/queue.h> + +struct cam_path; + 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_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_btype; + 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 = 0x000 -}adv_state; + ADV_STATE_NONE = 0x00 +} adv_state; + +typedef enum { + ACCB_FREE = 0x00, + ACCB_ACTIVE = 0x01, + ACCB_ABORT_QUEUED = 0x02, + ACCB_RECOVERY_CCB = 0x04, + ACCB_RELEASE_SIMQ = 0x08 +} adv_ccb_state; + +struct adv_ccb_info { + adv_ccb_state state; + bus_dmamap_t dmamap; + 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 0x00000048 +#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_ID(tid) (0x01 << (tid)) -#define ADV_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ADV_MAX_TID)) +#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 ) -#define ADV_INB(adv, offset) \ - inb((adv)->iobase + (offset)) -#define ADV_INW(adv, offset) \ - inw((adv)->iobase + (offset)) -#define ADV_INSB(adv, offset, valp, size) \ - insb((adv)->iobase + (offset), (valp), (size)) -#define ADV_INSW(adv, offset, valp, size) \ - insw((adv)->iobase + (offset), (valp), (size)) -#define ADV_INSL(adv, offset, valp, size) \ - insl((adv)->iobase + (offset), (valp), (size)) -#define ADV_OUTB(adv, offset, val) \ - outb((adv)->iobase + (offset), (val)) -#define ADV_OUTW(adv, offset, val) \ - outw((adv)->iobase + (offset), (val)) -#define ADV_OUTSB(adv, offset, valp, size) \ - outsb((adv)->iobase + (offset), (valp), (size)) -#define ADV_OUTSW(adv, offset, valp, size) \ - outsw((adv)->iobase + (offset), (valp), (size)) -#define ADV_OUTSL(adv, offset, valp, size) \ - outsl((adv)->iobase + (offset), (valp), (size)) /* * XXX @@ -108,53 +117,89 @@ typedef enum { */ #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_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_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_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_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_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_TEST 0x04 -#define ADV_CC_BANK_ONE 0x02 -#define ADV_CC_DIAG 0x01 +#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 @@ -184,38 +229,25 @@ typedef enum { #define ADV_CIW_TEST2 0x0400 #define ADV_CIW_SEL_33MHZ 0x0800 #define ADV_CIW_IRQ_ACT 0x1000 - -#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_CIW_CLR_SCSI_RESET_INT 0x1000 -#define ADV_REG_SC 0x0009 +#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_REG_PROG_COUNTER 0x000C -#define ADV_MCODE_START_ADDR 0x0080 - -#define ADV_CONFIG_LSW 0x0002 -#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_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 0xF0C0 - - -#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_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 @@ -249,10 +281,16 @@ struct adv_eeprom_config { 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) >> 8) +#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)) +#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) /* XXX What about wide controllers??? */ u_int8_t sdtr_data[8]; u_int8_t adapter_info[6]; @@ -262,6 +300,27 @@ struct adv_eeprom_config { 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). @@ -288,7 +347,7 @@ struct adv_eeprom_config { #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 0x40 +#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 @@ -296,6 +355,8 @@ struct adv_eeprom_config { #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 @@ -304,25 +365,41 @@ struct adv_eeprom_config { #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_LRAM_ADDR 0x000A -#define ADV_LRAM_DATA 0x0008 - -#define ADV_SYN_OFFSET 0x000B +#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_CCBPTR 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_SG_WK_QP 49 +#define ADV_SCSIQ_B_SG_WK_IX 50 +#define ADV_SCSIQ_W_REQ_COUNT 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) @@ -331,6 +408,11 @@ struct adv_eeprom_config { #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 @@ -341,10 +423,12 @@ struct adv_eeprom_config { #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_SDTR_REJECTED 0x4000 +#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 ADVV_CHKSUM_W 0x0042 #define ADVV_MC_DATE_W 0x0044 @@ -353,7 +437,7 @@ struct adv_eeprom_config { #define ADVV_DONENEXT_B 0x0049 #define ADVV_USE_TAGGED_QNG_B 0x004A #define ADVV_SCSIBUSY_B 0x004B -#define ADVV_CDBCNT_B 0x004C +#define ADVV_Q_DONE_IN_PROGRESS_B 0x004C #define ADVV_CURCDB_B 0x004D #define ADVV_RCLUN_B 0x004E #define ADVV_BUSY_QHEAD_B 0x004F @@ -384,28 +468,48 @@ struct adv_eeprom_config { #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 { - /* The overrun buffer must be quad word aligned */ - u_int8_t overrun_buf[ADV_OVERRUN_BSIZE]; - int unit; - u_int32_t iobase; + bus_space_tag_t tag; + bus_space_handle_t bsh; + 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; - target_bit_vector needs_async_bug_fix; - target_bit_vector initiate_sdtr; - target_bit_vector sdtr_done; - target_bit_vector cmd_qng_enabled; - target_bit_vector unit_not_ready; - target_bit_vector start_motor; - target_bit_vector no_scam; + 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_NO_PCI_FIX_ASYN_XFER 0x0020 #define ADV_CNTL_INT_MULTI_Q 0x0080 #define ADV_CNTL_NO_LUN_SUPPORT 0x0040 #define ADV_CNTL_NO_VERIFY_COPY 0x0100 @@ -414,22 +518,31 @@ struct adv_softc #define ADV_CNTL_INIT_VERBOSE 0x0800 #define ADV_CNTL_SCSI_PARITY 0x1000 #define ADV_CNTL_BURST_MODE 0x2000 -#define ADV_CNTL_USE_8_IOP_BASE 0x4000 +#define ADV_CNTL_SDTR_ENABLE_ULTRA 0x4000 u_int16_t bug_fix_control; -#define ADV_BUG_FIX_ADD_ONE_BYTE 0x0001 +#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 sdtr_data[16]; - struct scsi_sense_data *sense_buffers; + u_int8_t *sdtr_period_tbl; + u_int8_t sdtr_period_tbl_size; + struct cam_sim *sim; + LIST_HEAD(, ccb_hdr) pending_ccbs; + SLIST_HEAD(, adv_ccb_info) free_ccb_infos; }; /* @@ -479,11 +592,11 @@ struct adv_scsiq_1 { * buffer. */ u_int8_t sense_len; /* length of sense buffer */ - u_int8_t user_def; + u_int8_t extra_bytes; }; struct adv_scsiq_2 { - u_int32_t xs_ptr; /* Pointer to our scsi_xfer */ + u_int32_t ccb_ptr; /* Pointer to our CCB */ u_int8_t target_ix; /* Combined TID and LUN */ u_int8_t flag; @@ -495,8 +608,10 @@ struct adv_scsiq_2 { * Tag type for this transaction * (SIMPLE, ORDERED, HEAD ) */ -#define ADV_TAG_FLAG_ADD_ONE_BYTE 0x10 -#define ADV_TAG_FLAG_ISAPNP_ADD_BYTES 0x40 +#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; }; @@ -535,6 +650,7 @@ struct adv_scsiq_3 { #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 @@ -549,7 +665,7 @@ struct adv_scsiq_4 { 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_cntl; + u_int8_t y_res; u_int16_t x_req_count; u_int16_t x_reconnect_rtn; u_int32_t x_saved_data_addr; @@ -563,7 +679,7 @@ struct adv_q_done_info { u_int8_t q_no; u_int8_t cntl; u_int8_t sense_len; - u_int8_t user_def; + u_int8_t extra_bytes; u_int8_t res; u_int32_t remain_bytes; }; @@ -574,53 +690,32 @@ struct adv_sg_entry { }; struct adv_sg_head { - u_int8_t entry_cnt; /* Number of SG entries in this list */ - - u_int8_t queue_cnt; /* - * Number of queues required to store - * entry_cnt SG entries. + u_int16_t entry_cnt; /* + * Number of SG entries + * in this list */ - u_int8_t entry_to_copy; /* - * Number of SG entries to copy to the - * board. + u_int16_t queue_cnt; /* + * Number of queues required + * to store entry_cnt + * SG entries. */ - u_int8_t res; - struct adv_sg_entry sg_list[ADV_MAX_SG_LIST]; -}; - -#define ADV_MIN_SG_LIST 2 - -struct adv_min_sg_head { - u_int8_t entry_cnt; - u_int8_t queue_cnt; - - u_int8_t entry_to_copy; - u_int8_t res; - struct adv_sg_entry sg_list[ADV_MIN_SG_LIST]; + 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) -#if CC_LINK_BUSY_Q -struct asc_ext_scsi_q { - u_int32_t lba; - u_int16_t lba_len; - struct adv_scsi_q *next; - struct adv_scsi_q *join; - u_int16_t cntl; - u_int16_t buffer_id; - u_int8_t q_required; - u_int8_t res; -}; -#endif - struct adv_scsi_q { struct adv_scsiq_1 q1; struct adv_scsiq_2 q2; - struct scsi_generic *cdbptr; /* + u_int8_t *cdbptr; /* * Pointer to the SCSI command * to execute. */ @@ -628,45 +723,14 @@ struct adv_scsi_q { struct adv_sg_head *sg_head; /* * Pointer to possible SG list */ -#if CC_LINK_BUSY_Q - struct adv_ext_scsi_q ext; -#endif - }; -#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_SRBPTR 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_DW_REMAIN_XFER_ADDR 56 -#define ADV_SCSIQ_DW_REMAIN_XFER_CNT 60 -#define ADV_SCSIQ_B_SG_WK_QP 49 -#define ADV_SCSIQ_B_SG_WK_IX 50 -#define ADV_SCSIQ_W_REQ_COUNT 52 -#define ADV_SCSIQ_B_LIST_CNT 6 -#define ADV_SCSIQ_B_CUR_LIST_CNT 7 - 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; - -#if CC_LINK_BUSY_Q - struct adv_ext_scsi_q ext; -#endif - 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]; @@ -703,39 +767,99 @@ 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[7]; + 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 __P((struct adv_softc *adv, u_int16_t addr)); -void adv_write_lram_8 __P((struct adv_softc *adv, u_int16_t addr, - u_int8_t value)); -u_int16_t adv_read_lram_16 __P((struct adv_softc *adv, u_int16_t addr)); -void adv_write_lram_16 __P((struct adv_softc *adv, u_int16_t addr, - u_int16_t value)); +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 */ -void adv_get_board_type __P((struct adv_softc *adv)); -u_int16_t adv_get_eeprom_config __P((struct adv_softc *adv, - struct adv_eeprom_config *eeprom_config)); -int adv_set_eeprom_config __P((struct adv_softc *adv, - struct adv_eeprom_config *eeprom_config)); -int adv_reset_chip_and_scsi_bus __P((struct adv_softc *adv)); -int adv_test_external_lram __P((struct adv_softc* adv)); -int adv_init_lram_and_mcode __P((struct adv_softc *adv)); -u_int8_t adv_get_chip_irq __P((struct adv_softc *adv)); -u_int8_t adv_set_chip_irq __P((struct adv_softc *adv, u_int8_t irq_no)); +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_and_scsi_bus(struct adv_softc *adv); +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 __P((struct adv_softc *adv, struct adv_scsi_q *scsiq)); -u_int8_t adv_copy_lram_doneq __P((struct adv_softc *adv, u_int16_t q_addr, - struct adv_q_done_info *scsiq, u_int32_t max_dma_count)); +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_stop_execution __P((struct adv_softc *adv)); -int adv_is_chip_halted __P((struct adv_softc *adv)); +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_is_chip_halted(struct adv_softc *adv); /* Interrupt processing */ -void adv_ack_interrupt __P((struct adv_softc *adv)); -void adv_isr_chip_halted __P((struct adv_softc *adv)); +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 */ +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); + +/* 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 index 37fd53c..28084e9 100644 --- a/sys/dev/advansys/advmcode.c +++ b/sys/dev/advansys/advmcode.c @@ -1,14 +1,14 @@ /* * Downloadable microcode for Advanced Systems Inc. SCSI controllers * - * $Id$ + * $Id: advmcode.c,v 1.3 1997/02/22 09:28:48 peter Exp $ * * Obtained from: * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters - * - * Copyright (c) 1995-1996 Advanced System Products, Inc. + * + * 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 @@ -20,147 +20,215 @@ 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, 0xDD, 0x0A, 0x01, 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, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x88, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC8, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, - 0xB6, 0x00, 0x36, 0x00, 0x06, 0xD6, 0x0D, 0xD2, 0x15, 0xDE, 0x12, 0xDA, 0x00, 0xA2, 0xC8, 0x00, - 0x92, 0x80, 0xE0, 0x97, 0x50, 0x00, 0xF5, 0x00, 0x0A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, - 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00, 0x0A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, - 0x80, 0x62, 0x92, 0x80, 0x00, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, - 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDC, 0x00, 0x68, 0x97, 0x7F, 0x23, 0x04, 0x61, - 0x84, 0x01, 0xB2, 0x84, 0xCF, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE8, 0x01, - 0x68, 0x97, 0xD4, 0x81, 0x00, 0x33, 0x02, 0x00, 0x82, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, - 0x01, 0xA1, 0x08, 0x01, 0x4F, 0x00, 0x46, 0x97, 0x07, 0xA6, 0x12, 0x01, 0x00, 0x33, 0x03, 0x00, - 0x82, 0x88, 0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, 0x00, 0x82, 0x88, 0xCE, 0x00, 0x69, 0x60, - 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x86, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x32, 0x01, - 0x86, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x42, 0x01, 0x00, 0x33, 0x04, 0x00, - 0x82, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x2A, 0x98, 0x4D, 0x04, 0xD0, 0x84, - 0x05, 0xD8, 0x0D, 0x23, 0x2A, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xB8, 0x88, 0xFB, 0x23, 0x02, 0x61, - 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x70, 0x01, 0x00, 0x33, 0x0A, 0x00, 0x82, 0x88, - 0x4E, 0x00, 0x07, 0xA3, 0x7C, 0x01, 0x00, 0x33, 0x0B, 0x00, 0x82, 0x88, 0xCD, 0x04, 0x36, 0x2D, - 0x00, 0x33, 0x1A, 0x00, 0x82, 0x88, 0x50, 0x04, 0x96, 0x81, 0x06, 0xAB, 0x90, 0x01, 0x96, 0x81, - 0x4E, 0x00, 0x07, 0xA3, 0xA0, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x4A, 0x01, 0x00, 0x05, 0x8A, 0x81, - 0x08, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xCC, 0x81, - 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xC2, 0x01, - 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0x82, 0x88, 0x06, 0x23, 0x2A, 0x98, - 0xCD, 0x04, 0xB2, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xE2, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE8, 0x01, - 0xB2, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xB2, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, - 0x10, 0x02, 0x04, 0x01, 0x0D, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x46, 0x97, 0x0A, 0x82, - 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x24, 0x97, 0x48, 0x04, 0xFF, 0x23, 0x84, 0x80, - 0xB2, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, - 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x66, 0xEB, 0x11, 0x23, 0xB8, 0x88, 0xC6, 0x97, 0xFA, 0x80, - 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x3E, 0x02, 0x00, 0x33, 0x31, 0x00, 0x82, 0x88, 0x04, 0x01, - 0x03, 0xD8, 0x74, 0x98, 0x02, 0x96, 0x50, 0x82, 0xA2, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, - 0xB6, 0x2D, 0x02, 0xA6, 0x7A, 0x02, 0x07, 0xA6, 0x68, 0x02, 0x06, 0xA6, 0x6C, 0x02, 0x03, 0xA6, - 0x70, 0x02, 0x00, 0x33, 0x10, 0x00, 0x82, 0x88, 0x4A, 0x95, 0x52, 0x82, 0xF8, 0x95, 0x52, 0x82, - 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x16, 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, 0xAC, 0x02, 0x07, 0xA6, - 0x68, 0x02, 0x06, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x12, 0x00, 0x82, 0x88, 0x00, 0x0E, 0x80, 0x63, - 0x00, 0x43, 0x00, 0xA0, 0x9A, 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, - 0xEC, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE4, 0x02, 0x04, 0x01, 0x8E, 0xC8, 0x00, 0x33, - 0x1F, 0x00, 0x82, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x40, 0x98, 0xB6, 0x2D, - 0x01, 0xA6, 0x0E, 0x03, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x2A, 0x03, 0x06, 0xA6, 0x2E, 0x03, - 0x03, 0xA6, 0xFA, 0x03, 0x02, 0xA6, 0x7A, 0x02, 0x00, 0x33, 0x33, 0x00, 0x82, 0x88, 0x08, 0x23, - 0xB3, 0x01, 0x04, 0x01, 0x0E, 0xD0, 0x00, 0x33, 0x14, 0x00, 0x82, 0x88, 0x10, 0x23, 0xB3, 0x01, - 0x04, 0x01, 0x07, 0xCC, 0x00, 0x33, 0x15, 0x00, 0x82, 0x88, 0x4A, 0x95, 0xF0, 0x82, 0xF8, 0x95, - 0xF0, 0x82, 0x44, 0x98, 0x80, 0x42, 0x40, 0x98, 0x48, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, - 0x07, 0x01, 0x00, 0xA2, 0x72, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x48, 0x98, 0x40, 0x98, - 0x00, 0xA6, 0x34, 0x03, 0x07, 0xA6, 0x6A, 0x03, 0x03, 0xA6, 0x16, 0x04, 0x06, 0xA6, 0x6E, 0x03, - 0x01, 0xA6, 0x34, 0x03, 0x00, 0x33, 0x25, 0x00, 0x82, 0x88, 0x4A, 0x95, 0x50, 0x83, 0xF8, 0x95, - 0x50, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0x82, 0x88, 0x00, 0x01, - 0x05, 0x05, 0xFF, 0xA2, 0x90, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x4C, 0x83, 0x05, 0x05, - 0x01, 0xA6, 0x9A, 0x03, 0x00, 0xA6, 0xAA, 0x03, 0xF0, 0x83, 0x68, 0x98, 0x80, 0x42, 0x01, 0xA6, - 0x9A, 0x03, 0xBA, 0x83, 0x00, 0x33, 0x2F, 0x00, 0x82, 0x88, 0x68, 0x98, 0x80, 0x42, 0x00, 0xA6, - 0xAA, 0x03, 0xBA, 0x83, 0x00, 0x33, 0x26, 0x00, 0x82, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, - 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0xF0, 0x83, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, - 0x20, 0x00, 0x82, 0x88, 0x03, 0xA6, 0xEE, 0x03, 0x07, 0xA6, 0xE6, 0x03, 0x06, 0xA6, 0xEA, 0x03, - 0x00, 0x33, 0x17, 0x00, 0x82, 0x88, 0x4A, 0x95, 0xD4, 0x83, 0xF8, 0x95, 0xD4, 0x83, 0xFA, 0x83, - 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0x82, 0x88, 0xB6, 0x2D, 0x03, 0xA6, 0x16, 0x04, - 0x07, 0xA6, 0x0E, 0x04, 0x06, 0xA6, 0x12, 0x04, 0x00, 0x33, 0x30, 0x00, 0x82, 0x88, 0x4A, 0x95, - 0xFA, 0x83, 0xF8, 0x95, 0xFA, 0x83, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x24, 0x04, 0x00, 0x33, - 0x18, 0x00, 0x82, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x2E, 0x04, 0x23, 0x01, - 0x00, 0xA2, 0x50, 0x04, 0x0A, 0xA0, 0x40, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0x82, 0x88, - 0x0B, 0xA0, 0x4C, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0x82, 0x88, 0x42, 0x23, 0xB8, 0x88, - 0x00, 0x23, 0x22, 0xA3, 0xB2, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x6C, 0x04, 0x28, 0x23, 0x22, 0xA3, - 0x78, 0x04, 0x02, 0x23, 0x22, 0xA3, 0x8E, 0x04, 0x42, 0x23, 0xB8, 0x88, 0x4A, 0x00, 0x06, 0x61, - 0x00, 0xA0, 0x78, 0x04, 0x45, 0x23, 0xB8, 0x88, 0xC6, 0x97, 0x00, 0xA2, 0x8A, 0x04, 0x74, 0x98, - 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF6, 0x81, 0x47, 0x23, 0xB8, 0x88, 0x04, 0x01, - 0x0C, 0xDE, 0x14, 0x01, 0x00, 0xA2, 0xA6, 0x04, 0xC6, 0x97, 0x74, 0x98, 0x00, 0x33, 0x00, 0x81, - 0xC0, 0x20, 0x81, 0x62, 0x10, 0x82, 0x43, 0x23, 0xB8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, - 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xC0, 0x04, 0x00, 0x33, 0x27, 0x00, 0x82, 0x88, - 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xC6, 0x97, 0xF4, 0x94, - 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0xEE, 0x04, 0x00, 0x05, 0x76, 0x00, - 0x06, 0x61, 0x00, 0xA2, 0xE8, 0x04, 0xD6, 0x84, 0x08, 0x97, 0xCD, 0x04, 0xF2, 0x84, 0x48, 0x04, - 0xFF, 0x23, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x02, 0x85, 0x02, 0x23, - 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 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, 0x2E, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, - 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xA0, 0x05, 0x03, 0x03, - 0x02, 0xA0, 0x5C, 0x05, 0x9C, 0x85, 0x00, 0x33, 0x2D, 0x00, 0x82, 0x88, 0x04, 0xA0, 0x82, 0x05, - 0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x6E, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, - 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x24, 0x97, 0xD0, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, - 0xD0, 0x84, 0x08, 0xA0, 0x88, 0x05, 0x9C, 0x85, 0x03, 0xA0, 0x8E, 0x05, 0x9C, 0x85, 0x01, 0xA0, - 0x9A, 0x05, 0x88, 0x00, 0x80, 0x63, 0x78, 0x96, 0x4A, 0x85, 0x88, 0x86, 0x80, 0x63, 0x4A, 0x85, - 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xDE, 0x05, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, - 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0xC0, 0x05, 0x00, 0x33, 0x37, 0x00, 0x82, 0x88, - 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, 0xB8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, - 0xD8, 0x05, 0x00, 0x33, 0x38, 0x00, 0x82, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, - 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xF2, 0x05, 0xC0, 0x23, 0x07, 0x41, - 0x00, 0x63, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, - 0x00, 0x63, 0x06, 0xA6, 0x14, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x02, 0xA6, 0xBC, 0x06, 0x00, 0x33, - 0x39, 0x00, 0x82, 0x88, 0x00, 0x00, 0x01, 0xA0, 0xD6, 0x06, 0xA2, 0x95, 0x83, 0x03, 0x80, 0x63, - 0x06, 0xA6, 0x28, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, - 0x01, 0x00, 0x06, 0xA6, 0x40, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x33, 0x3A, 0x00, 0x82, 0x88, - 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x32, 0x06, 0x06, 0xA6, 0x58, 0x06, 0x07, 0xA6, - 0x64, 0x06, 0x00, 0x33, 0x3B, 0x00, 0x82, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, - 0x64, 0x06, 0x00, 0x63, 0x03, 0x03, 0x80, 0x63, 0x88, 0x00, 0x01, 0xA2, 0x78, 0x06, 0x07, 0xA2, - 0xBC, 0x06, 0x00, 0x33, 0x35, 0x00, 0x82, 0x88, 0x07, 0xA6, 0x82, 0x06, 0x00, 0x33, 0x2A, 0x00, - 0x82, 0x88, 0x03, 0x03, 0x03, 0xA2, 0x8E, 0x06, 0x07, 0x23, 0x80, 0x00, 0xC8, 0x86, 0x80, 0x63, - 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0x9E, 0x06, 0x00, 0x33, 0x29, 0x00, 0x82, 0x88, 0x00, 0x43, - 0x00, 0xA2, 0xAA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0x94, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, - 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x00, 0x63, 0x80, 0x67, 0x00, 0x33, - 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x20, 0x06, - 0x00, 0x33, 0x2C, 0x00, 0x82, 0x88, 0x0C, 0xA2, 0xF0, 0x06, 0xA2, 0x95, 0x83, 0x03, 0x80, 0x63, - 0x06, 0xA6, 0xEE, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x33, 0x3D, 0x00, 0x82, 0x88, 0x00, 0x00, - 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x06, 0x07, 0x07, 0xA6, 0x64, 0x06, 0xBF, 0x23, - 0x04, 0x61, 0x84, 0x01, 0xB2, 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, 0x86, 0x07, - 0x00, 0x33, 0x07, 0x00, 0x82, 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, - 0xA6, 0x07, 0x00, 0x05, 0x9C, 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, 0xD6, 0x07, 0xD8, 0x87, 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, - 0x06, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0xE6, 0x07, - 0xC6, 0x97, 0xF4, 0x94, 0xE6, 0x87, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x1C, 0x88, - 0x02, 0x01, 0x04, 0xD8, 0x08, 0x97, 0xC6, 0x97, 0xF4, 0x94, 0x0C, 0x88, 0x75, 0x00, 0x00, 0xA3, - 0x26, 0x08, 0x00, 0x05, 0x10, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, - 0x38, 0x08, 0x00, 0x33, 0x3E, 0x00, 0x82, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, - 0x38, 0x2B, 0x5E, 0x88, 0x38, 0x2B, 0x54, 0x88, 0x32, 0x09, 0x31, 0x05, 0x54, 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, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, - 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0x74, 0x08, 0x5D, 0x00, 0xFE, 0xC3, - 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, - 0x13, 0x23, 0xB8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, - 0x81, 0x62, 0xA2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, - 0xF1, 0xC7, 0x41, 0x23, 0xB8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xB2, 0x84, + 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, 0x79, 0x0D, 0x09, 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, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xCC, 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, 0x08, 0x98, 0x50, 0x00, 0xF5, + 0x00, 0x32, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, + 0x4F, 0x00, 0xF5, 0x00, 0x32, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, + 0x00, 0x92, 0x80, 0x80, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, + 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, 0x00, + 0xA3, 0xD6, 0x00, 0x90, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, + 0xD8, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, + 0xA3, 0xE2, 0x01, 0x90, 0x97, 0xCE, 0x81, 0x00, 0x33, 0x02, 0x00, + 0xAA, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, + 0x01, 0x4F, 0x00, 0x6E, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, + 0x03, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, + 0x00, 0xAA, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, + 0x4A, 0x60, 0x00, 0xA2, 0x80, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x2C, + 0x01, 0x80, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, + 0x3C, 0x01, 0x00, 0x33, 0x04, 0x00, 0xAA, 0x88, 0x03, 0x07, 0x02, + 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x52, 0x98, 0x4D, 0x04, 0xF6, 0x84, + 0x05, 0xD8, 0x0D, 0x23, 0x52, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xE0, + 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, + 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xAA, 0x88, 0x4E, + 0x00, 0x07, 0xA3, 0x76, 0x01, 0x00, 0x33, 0x0B, 0x00, 0xAA, 0x88, + 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xAA, 0x88, 0x50, + 0x04, 0x90, 0x81, 0x06, 0xAB, 0x8A, 0x01, 0x90, 0x81, 0x4E, 0x00, + 0x07, 0xA3, 0x9A, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x44, 0x01, 0x00, + 0x05, 0x84, 0x81, 0x30, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, + 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xC6, 0x81, 0xFD, 0x23, 0x02, + 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, + 0xBC, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, + 0x00, 0xAA, 0x88, 0x06, 0x23, 0x52, 0x98, 0xCD, 0x04, 0xD8, 0x84, + 0x06, 0x01, 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, + 0x01, 0xD8, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xD8, 0x84, 0x80, 0x73, + 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, + 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x6E, 0x97, 0x04, 0x82, + 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x4C, 0x97, 0x48, + 0x04, 0x84, 0x80, 0xDA, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, + 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, 0x06, + 0xE2, 0x03, 0xEE, 0x67, 0xEB, 0x11, 0x23, 0xE0, 0x88, 0xEE, 0x97, + 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x36, 0x02, 0x00, + 0x33, 0x31, 0x00, 0xAA, 0x88, 0x04, 0x01, 0x03, 0xD8, 0x9C, 0x98, + 0x44, 0x96, 0x48, 0x82, 0xD4, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, + 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x72, 0x02, 0x07, 0xA6, 0x60, 0x02, + 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, 0x68, 0x02, 0x00, 0x33, 0x10, + 0x00, 0xAA, 0x88, 0x6E, 0x95, 0x4A, 0x82, 0x3A, 0x96, 0x4A, 0x82, + 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x2E, 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, + 0xB0, 0x02, 0x07, 0xA6, 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, + 0xA6, 0x12, 0x04, 0x01, 0xA6, 0xBA, 0x02, 0x00, 0xA6, 0xBA, 0x02, + 0x00, 0x33, 0x12, 0x00, 0xAA, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, + 0x43, 0x00, 0xA0, 0x92, 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, 0xF0, 0x82, + 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE8, 0x02, 0x04, 0x01, 0x98, + 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xAA, 0x88, 0x08, 0x31, 0x0A, 0x35, + 0x0C, 0x39, 0x0E, 0x3D, 0x68, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x1A, + 0x03, 0x00, 0xA6, 0x1A, 0x03, 0x07, 0xA6, 0x12, 0x03, 0x06, 0xA6, + 0x16, 0x03, 0x03, 0xA6, 0x12, 0x04, 0x02, 0xA6, 0x72, 0x02, 0x00, + 0x33, 0x33, 0x00, 0xAA, 0x88, 0x6E, 0x95, 0xF4, 0x82, 0x3A, 0x96, + 0xF4, 0x82, 0x6C, 0x98, 0x80, 0x42, 0x68, 0x98, 0x60, 0xE4, 0x04, + 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x5A, 0x03, + 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x70, 0x98, 0x68, 0x98, 0x00, + 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x52, 0x03, 0x03, 0xA6, 0x2E, 0x04, + 0x06, 0xA6, 0x56, 0x03, 0x01, 0xA6, 0x1C, 0x03, 0x00, 0x33, 0x25, + 0x00, 0xAA, 0x88, 0x6E, 0x95, 0x38, 0x83, 0x3A, 0x96, 0x38, 0x83, + 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0xAA, + 0x88, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x78, 0x03, 0xB1, 0x01, + 0x08, 0x23, 0xB2, 0x01, 0x34, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, + 0xA2, 0x98, 0x03, 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, + 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x94, 0x03, 0x00, 0xA6, 0x94, + 0x03, 0x08, 0x84, 0x80, 0x42, 0x68, 0x98, 0x01, 0xA6, 0xA2, 0x03, + 0x00, 0xA6, 0xBA, 0x03, 0x08, 0x84, 0x90, 0x98, 0x80, 0x42, 0x01, + 0xA6, 0xA2, 0x03, 0x07, 0xA6, 0xB0, 0x03, 0xD2, 0x83, 0x6E, 0x95, + 0xA6, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xAA, 0x88, 0x90, 0x98, 0x80, + 0x42, 0x00, 0xA6, 0xBA, 0x03, 0x07, 0xA6, 0xC8, 0x03, 0xD2, 0x83, + 0x6E, 0x95, 0xBE, 0x83, 0x00, 0x33, 0x26, 0x00, 0xAA, 0x88, 0x38, + 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, + 0xA1, 0x01, 0x08, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, + 0x00, 0xAA, 0x88, 0x03, 0xA6, 0x06, 0x04, 0x07, 0xA6, 0xFE, 0x03, + 0x06, 0xA6, 0x02, 0x04, 0x00, 0x33, 0x17, 0x00, 0xAA, 0x88, 0x6E, + 0x95, 0xEC, 0x83, 0x3A, 0x96, 0xEC, 0x83, 0x12, 0x84, 0x04, 0xF0, + 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0xAA, 0x88, 0xB6, 0x2D, 0x03, + 0xA6, 0x2E, 0x04, 0x07, 0xA6, 0x26, 0x04, 0x06, 0xA6, 0x2A, 0x04, + 0x00, 0x33, 0x30, 0x00, 0xAA, 0x88, 0x6E, 0x95, 0x12, 0x84, 0x3A, + 0x96, 0x12, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, + 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, + 0x63, 0x07, 0xA6, 0x4C, 0x04, 0x00, 0x33, 0x18, 0x00, 0xAA, 0x88, + 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x56, 0x04, 0x23, + 0x01, 0x00, 0xA2, 0x78, 0x04, 0x0A, 0xA0, 0x68, 0x04, 0xE0, 0x00, + 0x00, 0x33, 0x1D, 0x00, 0xAA, 0x88, 0x0B, 0xA0, 0x74, 0x04, 0xE0, + 0x00, 0x00, 0x33, 0x1E, 0x00, 0xAA, 0x88, 0x42, 0x23, 0xE0, 0x88, + 0x00, 0x23, 0x22, 0xA3, 0xD8, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x94, + 0x04, 0x28, 0x23, 0x22, 0xA3, 0xA0, 0x04, 0x02, 0x23, 0x22, 0xA3, + 0xB6, 0x04, 0x42, 0x23, 0xE0, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, + 0xA0, 0xA0, 0x04, 0x45, 0x23, 0xE0, 0x88, 0xEE, 0x97, 0x00, 0xA2, + 0xB2, 0x04, 0x9C, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, + 0x62, 0xF0, 0x81, 0x47, 0x23, 0xE0, 0x88, 0x04, 0x01, 0x0B, 0xDE, + 0xEE, 0x97, 0x9C, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, + 0x62, 0x14, 0x01, 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xE0, 0x88, + 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, + 0x00, 0x03, 0xA3, 0xE6, 0x04, 0x00, 0x33, 0x27, 0x00, 0xAA, 0x88, + 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, + 0x01, 0xEE, 0x97, 0x18, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, + 0x4F, 0x00, 0x00, 0xA3, 0x14, 0x05, 0x00, 0x05, 0x76, 0x00, 0x06, + 0x61, 0x00, 0xA2, 0x0E, 0x05, 0xFC, 0x84, 0x30, 0x97, 0xCD, 0x04, + 0x16, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, + 0x23, 0x82, 0x01, 0x26, 0x85, 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x32, 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, 0x52, 0x05, 0x77, 0x04, 0x01, + 0x23, 0xEA, 0x00, 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, + 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xD2, 0x05, 0x03, 0x03, 0x02, + 0xA0, 0x80, 0x05, 0xCE, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xAA, 0x88, + 0x04, 0xA0, 0xA6, 0x05, 0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, + 0xA2, 0x92, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, + 0x82, 0x01, 0x50, 0x00, 0x4C, 0x97, 0xF6, 0x84, 0x04, 0x23, 0x02, + 0x41, 0x82, 0x01, 0xF6, 0x84, 0x08, 0xA0, 0xAC, 0x05, 0xCE, 0x85, + 0x03, 0xA0, 0xB2, 0x05, 0xCE, 0x85, 0x01, 0xA0, 0xBC, 0x05, 0x88, + 0x00, 0x80, 0x63, 0xAA, 0x86, 0x07, 0xA0, 0xC8, 0x05, 0x06, 0x23, + 0x52, 0x98, 0x48, 0x23, 0xE0, 0x88, 0x07, 0x23, 0x80, 0x00, 0xF0, + 0x86, 0x80, 0x63, 0x6E, 0x85, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, + 0x00, 0xA2, 0x10, 0x06, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, 0x07, + 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0xF2, 0x05, 0x00, 0x33, + 0x37, 0x00, 0xAA, 0x88, 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, 0xE0, + 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x0A, 0x06, + 0x00, 0x33, 0x38, 0x00, 0xAA, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, + 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, + 0x00, 0xA2, 0x28, 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, 0x06, 0xA6, + 0x56, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x02, 0xA6, 0xE4, 0x06, 0x00, + 0x33, 0x39, 0x00, 0xAA, 0x88, 0x00, 0x00, 0x01, 0xA0, 0xFE, 0x06, + 0xD4, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x6A, 0x06, 0x07, + 0xA6, 0x6E, 0x05, 0x00, 0x00, 0x01, 0xA0, 0xFE, 0x06, 0x00, 0x2B, + 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0x86, 0x06, 0x07, + 0xA6, 0x6E, 0x05, 0x00, 0x33, 0x3A, 0x00, 0xAA, 0x88, 0x40, 0x0E, + 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x78, 0x06, 0x06, 0xA6, 0x9E, + 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x33, 0x3B, 0x00, 0xAA, 0x88, + 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, 0x6E, 0x05, 0x00, + 0x63, 0x07, 0xA6, 0xB4, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xAA, 0x88, + 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xC6, + 0x06, 0x00, 0x33, 0x29, 0x00, 0xAA, 0x88, 0x00, 0x43, 0x00, 0xA2, + 0xD2, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xBC, 0x86, 0xC0, 0x0E, 0x00, + 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, + 0x80, 0x63, 0x6E, 0x85, 0x80, 0x67, 0x00, 0x33, 0x00, 0x40, 0xC0, + 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, + 0x62, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xAA, 0x88, 0x0C, 0xA2, 0x18, + 0x07, 0xD4, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x16, 0x07, + 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xAA, 0x88, 0x00, + 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x2E, 0x07, + 0x07, 0xA6, 0x6E, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xD8, + 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, + 0xAE, 0x07, 0x00, 0x33, 0x07, 0x00, 0xAA, 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, 0xCE, 0x07, 0x00, 0x05, 0xC4, 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, 0xFE, 0x07, 0x00, 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, 0x2E, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, + 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x0E, 0x08, 0xEE, 0x97, + 0x18, 0x95, 0x0E, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, + 0x04, 0x44, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x30, 0x97, 0xEE, 0x97, + 0x18, 0x95, 0x34, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x4E, 0x08, 0x00, + 0x05, 0x38, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, + 0x06, 0xA6, 0x60, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xAA, 0x88, 0x80, + 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B, 0x86, 0x88, + 0x38, 0x2B, 0x7C, 0x88, 0x32, 0x09, 0x31, 0x05, 0x7C, 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, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, + 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0x9C, + 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, + 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, 0x13, + 0x23, 0xE0, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, + 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xCA, 0x88, 0x80, 0x73, 0x80, + 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, + 0x41, 0x23, 0xE0, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, + 0x01, 0xD8, 0x84, }; u_int16_t adv_mcode_size = sizeof(adv_mcode); -u_int32_t adv_mcode_chksum = 0x012258FB; +u_int32_t adv_mcode_chksum = 0x01297F32; diff --git a/sys/dev/advansys/advmcode.h b/sys/dev/advansys/advmcode.h index c5688e5..c379469 100644 --- a/sys/dev/advansys/advmcode.h +++ b/sys/dev/advansys/advmcode.h @@ -1,11 +1,11 @@ /* * Exported interface to downloadable microcode for AdvanSys SCSI Adapters * - * $Id$ + * $Id: advmcode.h,v 1.3 1997/02/22 09:28:48 peter Exp $ * * Obtained from: * - * Copyright (c) 1995-1996 Advanced System Products, Inc. + * Copyright (c) 1995-1997 Advanced System Products, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/i386/isa/adv_isa.c b/sys/i386/isa/adv_isa.c index e7c8915..aa311d6 100644 --- a/sys/i386/isa/adv_isa.c +++ b/sys/i386/isa/adv_isa.c @@ -2,30 +2,34 @@ * Device probe and attach routines for the following * Advanced Systems Inc. SCSI controllers: * - * Connectivity Products: - * ABP5140 - Bus-Master PnP ISA 16 CDB + * 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 240 CDB - * ABP5150 - Bus-Master ISA 240 CDB (shipped by HP with the 4020i CD-R drive) - * ABP842 - Bus-Master VL 240 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 + * Dual Channel Products: + * ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) * - * Copyright (c) 1996 Justin T. Gibbs. + * * 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 immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products + * 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 @@ -40,16 +44,22 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: adv_isa.c,v 1.3 1997/02/22 09:35:51 peter Exp $ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> + +#include <machine/bus_pio.h> +#include <machine/bus.h> #include <i386/isa/isa.h> #include <i386/isa/isa_device.h> -#include <i386/scsi/advansys.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) @@ -57,6 +67,14 @@ #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; +bus_dma_tag_t overrun_dmat; +bus_dmamap_t overrun_dmamap; +bus_addr_t overrun_physbase; + /* Possible port addresses an ISA or VL adapter can live at */ u_int16_t adv_isa_ioports[] = { @@ -73,14 +91,15 @@ u_int16_t adv_isa_ioports[] = 0x330 /* Eighth and default selection in BIOS setup */ }; -#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_short) - 1) +#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_int16_t) - 1) -static int advisaprobe __P((struct isa_device *id)); -static int advisaattach __P((struct isa_device *id)); -static void adv_set_isapnp_wait_for_key __P((void)); -static int adv_find_signature __P((u_int16_t iobase)); +static int advisaprobe(struct isa_device *id); +static int advisaattach(struct isa_device *id); +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); -void adv_isa_intr __P((int unit)); +void adv_isa_intr(void *unit); struct isa_driver advdriver = { @@ -90,8 +109,7 @@ struct isa_driver advdriver = }; static int -advisaprobe(id) - struct isa_device *id; +advisaprobe(struct isa_device *id) { int port_index; int max_port_index; @@ -123,65 +141,173 @@ advisaprobe(id) 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; + if (port_addr == 0) /* Already been attached */ continue; - if (adv_find_signature(port_addr)) { + if (adv_find_signature(I386_BUS_SPACE_IO, port_addr)) { /* * Got one. Now allocate our softc * and see if we can initialize the card. */ struct adv_softc *adv; - adv = adv_alloc(id->id_unit, port_addr); + adv = adv_alloc(id->id_unit, I386_BUS_SPACE_IO, + port_addr); if (adv == NULL) return (0); - id->id_iobase = adv->iobase; + adv_unit++; + + id->id_iobase = adv->bsh; + + /* + * 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; + id->id_drq = -1; + } 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); + id->id_drq = adv->isa_dma_channel; + } 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*/0, + /*boundary*/0, + lowaddr, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, + /*filterarg*/NULL, + maxsize, + /*nsegs*/BUS_SPACE_UNRESTRICTED, + 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); + return (0); + } + + adv->init_level++; + + if (overrun_buf == NULL) { + /* Need to allocate our overrun buffer */ + if (bus_dma_tag_create(adv->parent_dmat, + /*alignment*/8, + /*boundary*/0, + ADV_ISA_MAX_DMA_ADDR, + BUS_SPACE_MAXADDR, + /*filter*/NULL, + /*filterarg*/NULL, + ADV_OVERRUN_BSIZE, + /*nsegments*/1, + BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, + &overrun_dmat) != 0) { + adv_free(adv); + return (0); + } + if (bus_dmamem_alloc(overrun_dmat, + (void **)&overrun_buf, + BUS_DMA_NOWAIT, + &overrun_dmamap) != 0) { + bus_dma_tag_destroy(overrun_dmat); + adv_free(adv); + return (0); + } + /* 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) { adv_free(adv); return (0); } + switch (adv->type) { case ADV_ISAPNP: - if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG) - adv->needs_async_bug_fix = TARGET_BIT_VECTOR_SET; + 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"); } - if ((adv->type & ADV_ISAPNP) == ADV_ISAPNP) { - } - /* Determine our IRQ */ if (id->id_irq == 0 /* irq ? */) id->id_irq = 1 << adv_get_chip_irq(adv); else adv_set_chip_irq(adv, ffs(id->id_irq) - 1); + id->id_intr = adv_isa_intr; /* Mark as probed */ adv_isa_ioports[port_index] = 0; - break; + return 1; } } - return 1; + return 0; } static int -advisaattach(id) - struct isa_device *id; +advisaattach(struct isa_device *id) { struct adv_softc *adv; @@ -189,6 +315,44 @@ advisaattach(id) 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) { @@ -202,35 +366,13 @@ adv_set_isapnp_wait_for_key(void) } /* - * Determine if there is a board at "iobase" by looking - * for the AdvanSys signatures. Return 1 if a board is - * found, 0 otherwise. - */ -static int -adv_find_signature(iobase) - u_int16_t iobase; -{ - u_int16_t signature; - - if (inb(iobase + ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) { - signature = inw(iobase + ADV_SIGNATURE_WORD ); - if ((signature == ADV_1000_ID0W) - || (signature == ADV_1000_ID0W_FIX)) - return (1); - } - return (0); -} - - -/* * Handle an ISA interrupt. * XXX should go away as soon as ISA interrupt handlers * take a (void *) arg. */ void -adv_isa_intr(unit) - int unit; +adv_isa_intr(void *unit) { - struct adv_softc *arg = advsoftcs[unit]; + struct adv_softc *arg = advsoftcs[(int)unit]; adv_intr((void *)arg); } diff --git a/sys/pci/adv_pci.c b/sys/pci/adv_pci.c new file mode 100644 index 0000000..2f9e4e1 --- /dev/null +++ b/sys/pci/adv_pci.c @@ -0,0 +1,275 @@ +/* + * Device probe and attach routines for the following + * Advanced Systems Inc. SCSI controllers: + * + * Connectivity Products: + * ABP920 - 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 Ultra (16 CDB) + * + * Single Channel Products: + * ABP940 - Bus-Master PCI (240 CDB) + * ABP940U - Bus-Master PCI Ultra (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) + * + * 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, 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. + * + * $Id$ + */ + +#include <pci.h> +#if NPCI > 0 +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> + +#include <machine/bus_pio.h> +#include <machine/bus.h> + +#include <pci/pcireg.h> +#include <pci/pcivar.h> + +#include <dev/advansys/advansys.h> + +#define PCI_BASEADR0 PCI_MAP_REG_START /* I/O Address */ +#define PCI_BASEADR1 PCI_MAP_REG_START + 4 /* Mem I/O Address */ + +#define PCI_DEVICE_ID_ADVANSYS_1200A 0x110010CD +#define PCI_DEVICE_ID_ADVANSYS_1200B 0x120010CD +#define PCI_DEVICE_ID_ADVANSYS_ULTRA 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 char* advpciprobe(pcici_t tag, pcidi_t type); +static void advpciattach(pcici_t config_id, int unit); + +/* + * The overrun buffer shared amongst all PCI adapters. + */ +static u_int8_t* overrun_buf; +bus_dma_tag_t overrun_dmat; +bus_dmamap_t overrun_dmamap; +bus_addr_t overrun_physbase; + +static struct pci_device adv_pci_driver = { + "adv", + advpciprobe, + advpciattach, + &adv_unit, + NULL +}; + +DATA_SET (pcidevice_set, adv_pci_driver); + +static char* +advpciprobe(pcici_t tag, pcidi_t type) +{ + int rev = pci_conf_read(tag, PCI_CLASS_REG) & 0xff; + switch (type) { + case PCI_DEVICE_ID_ADVANSYS_1200A: + return ("AdvanSys ASC1200A SCSI controller"); + case PCI_DEVICE_ID_ADVANSYS_1200B: + return ("AdvanSys ASC1200B SCSI controller"); + case PCI_DEVICE_ID_ADVANSYS_ULTRA: + if (rev == PCI_DEVICE_REV_ADVANSYS_3150) + return ("AdvanSys ASC3150 Ultra SCSI controller"); + else + return ("AdvanSys ASC3050 Ultra SCSI controller"); + break; + default: + break; + } + return (NULL); +} + +static void +advpciattach(pcici_t config_id, int unit) +{ + u_int16_t io_port; + u_int16_t config_msw; + struct adv_softc *adv; + u_int32_t id; + u_int32_t command; + int error; + + /* + * Determine the chip version. + */ + id = pci_cfgread(config_id, PCI_ID_REG, /*bytes*/4); + command = pci_cfgread(config_id, 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_cfgwrite(config_id, 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_cfgwrite(config_id, PCIR_LATTIMER, /*value*/0, /*bytes*/1); + } + + + if (pci_map_port(config_id, PCI_BASEADR0, &io_port) == 0) + return; + + if (adv_find_signature(I386_BUS_SPACE_IO, io_port) == 0) + return; + + adv = adv_alloc(unit, I386_BUS_SPACE_IO, io_port); + if (adv == NULL) + return; + + /* 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*/0, + /*boundary*/0, + /*lowaddr*/ADV_PCI_MAX_DMA_ADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, + /*nsegments*/BUS_SPACE_UNRESTRICTED, + /*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); + return; + } + + adv->init_level++; + + if (overrun_buf == NULL) { + /* Need to allocate our overrun buffer */ + if (bus_dma_tag_create(adv->parent_dmat, + /*alignment*/8, /*boundary*/0, + ADV_PCI_MAX_DMA_ADDR, BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + ADV_OVERRUN_BSIZE, /*nsegments*/1, + BUS_SPACE_MAXSIZE_32BIT, /*flags*/0, + &overrun_dmat) != 0) { + bus_dma_tag_destroy(adv->parent_dmat); + adv_free(adv); + return; + } + 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); + return; + } + /* 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_3150) + extra_cfg = ADV_IFC_ACT_NEG | ADV_IFC_SLEW_RATE; + else 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); + return; + } + + adv->max_dma_count = ADV_PCI_MAX_DMA_COUNT; + adv->max_dma_addr = ADV_PCI_MAX_DMA_ADDR; + +#if CC_DISABLE_PCI_PARITY_INT + 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; + } + + if ((pci_map_int(config_id, adv_intr, (void *)adv, &cam_imask)) == 0) { + adv_free(adv); + return; + } + + adv_attach(adv); +} + +#endif /* NPCI > 0 */ |