summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1998-09-15 07:03:43 +0000
committergibbs <gibbs@FreeBSD.org>1998-09-15 07:03:43 +0000
commit0a5c401474482bc7ad9d6fa07c5056d624e2ed2c (patch)
treea227ffcca46b316cbf6791d68256c3726bd35670
parentc3636169750363290acb8611ce6da6ab2b71dec1 (diff)
downloadFreeBSD-src-0a5c401474482bc7ad9d6fa07c5056d624e2ed2c.zip
FreeBSD-src-0a5c401474482bc7ad9d6fa07c5056d624e2ed2c.tar.gz
Advance Systems SCSI Host Adapter driver for CAM. Currently only support
the 8bit SCSI AdvanSys products.
-rw-r--r--sys/dev/advansys/adv_isa.c264
-rw-r--r--sys/dev/advansys/adv_pci.c275
-rw-r--r--sys/dev/advansys/advansys.c1281
-rw-r--r--sys/dev/advansys/advansys.h59
-rw-r--r--sys/dev/advansys/advlib.c1518
-rw-r--r--sys/dev/advansys/advlib.h558
-rw-r--r--sys/dev/advansys/advmcode.c358
-rw-r--r--sys/dev/advansys/advmcode.h4
-rw-r--r--sys/i386/isa/adv_isa.c264
-rw-r--r--sys/pci/adv_pci.c275
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 */
OpenPOWER on IntegriCloud