diff options
author | Steve Murphree <smurph@cvs.openbsd.org> | 2000-03-22 02:50:51 +0000 |
---|---|---|
committer | Steve Murphree <smurph@cvs.openbsd.org> | 2000-03-22 02:50:51 +0000 |
commit | e604a02d72f1fcf0475a404d1785dfcff9b037ed (patch) | |
tree | c4c76fbc8e8afb9e4377047b36f861d8938b845a /sys/dev/microcode/aic7xxx | |
parent | 40a43c4521970d68d23d82ca60be453ac590d699 (diff) |
new ahc driver. Adds support for newer Adaptec controllers. This represents two months of work.
Diffstat (limited to 'sys/dev/microcode/aic7xxx')
-rw-r--r-- | sys/dev/microcode/aic7xxx/Makefile | 44 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/Makefile.inc | 17 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic7xxx.reg | 1485 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic7xxx.seq | 2446 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic7xxx_asm.1 | 71 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic7xxx_asm.c | 687 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic7xxx_reg.h | 784 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic7xxx_seq.h | 1393 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aicasm.c | 721 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aicasm.h | 68 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aicasm_gram.y | 1410 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aicasm_scan.l | 283 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aicasm_symbol.c | 473 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aicasm_symbol.h | 162 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/sequencer.h | 96 |
15 files changed, 7363 insertions, 2777 deletions
diff --git a/sys/dev/microcode/aic7xxx/Makefile b/sys/dev/microcode/aic7xxx/Makefile new file mode 100644 index 00000000000..2b91caf6dcd --- /dev/null +++ b/sys/dev/microcode/aic7xxx/Makefile @@ -0,0 +1,44 @@ +# $OpenBSD: Makefile,v 1.1 2000/03/22 02:50:49 smurph Exp $ +# $FreeBSD: src/sys/dev/aic7xxx/Makefile,v 1.6 1999/08/28 00:41:22 peter Exp $ + +PROG= aicasm + +CSRCS= aicasm.c aicasm_symbol.c +GENSRCS= aicasm_gram.c aicasm_scan.c + +GENHDRS= y.tab.h + +SRCS= ${GENSRCS} ${CSRCS} +CLEANFILES+= ${GENSRCS} ${GENHDRS} y.output +DPADD+= ${LIBL} +LDADD+= -ll + +# Correct path for kernel builds +# Don't rely on the kernel's .depend file +.ifdef MAKESRCPATH +.PATH: ${MAKESRCPATH} +DEPENDFILE= +.endif + +CFLAGS+= -I/usr/include -I. +NOMAN= noman + +.ifdef DEBUG +CFLAGS+= -DDEBUG -g +YFLAGS+= -t +LFLAGS+= -d +MFLAGS= -l seq.lst +.endif + +microcode aic7xxxreg.h aic7xxx_seq.h: aic7xxx.seq aic7xxx.reg + ./aicasm -I/sys ${MFLAGS} -r tempreg.h -o tempseq.h ${.CURDIR}/aic7xxx.seq + grep OpenBSD: ${.CURDIR}/aic7xxx.seq | cat - tempseq.h > aic7xxx_seq.h + grep OpenBSD: ${.CURDIR}/aic7xxx.reg | cat - tempreg.h > aic7xxxreg.h + mv aic7xxx_seq.h /sys/dev/microcode/aic7xxx/ +.ifdef DEBUG + mv seq.lst /sys/dev/microcode/aic7xxx/ +.endif + cp aic7xxxreg.h /sys/dev/ic/ + rm -f tempseq.h tempreg.h + +.include <bsd.prog.mk> diff --git a/sys/dev/microcode/aic7xxx/Makefile.inc b/sys/dev/microcode/aic7xxx/Makefile.inc deleted file mode 100644 index 7e89b517581..00000000000 --- a/sys/dev/microcode/aic7xxx/Makefile.inc +++ /dev/null @@ -1,17 +0,0 @@ -# $OpenBSD: Makefile.inc,v 1.5 1996/11/28 23:27:58 niklas Exp $ -# $NetBSD: Makefile.inc,v 1.4 1996/05/20 00:48:43 thorpej Exp $ - -.if target(aic7xxx.o) -PATH: $S/dev/microcode/aic7xxx - -aic7xxx.o: aic7xxx_seq.h - -aic7xxx_seq.h: aic7xxx_asm $S/dev/microcode/aic7xxx/aic7xxx.seq - ./aic7xxx_asm -o ${.TARGET} $S/dev/microcode/aic7xxx/aic7xxx.seq - -aic7xxx_asm: $S/dev/microcode/aic7xxx/aic7xxx_asm.c - ${HOSTCC} -U_KERNEL -o ${.TARGET} $< - -clean:: - rm -f aic7xxx_asm -.endif diff --git a/sys/dev/microcode/aic7xxx/aic7xxx.reg b/sys/dev/microcode/aic7xxx/aic7xxx.reg new file mode 100644 index 00000000000..e85bfc7943e --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aic7xxx.reg @@ -0,0 +1,1485 @@ +/* $NetBSD$ */ + +/* + * Aic7xxx register and scratch ram definitions. + * + * Copyright (c) 1994-2000 Justin Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.20 2000/02/09 21:24:59 gibbs Exp $ + */ + +/* + * This file is processed by the aic7xxx_asm utility for use in assembling + * firmware for the aic7xxx family of SCSI host adapters as well as to generate + * a C header file for use in the kernel portion of the Aic7xxx driver. + * + * All page numbers refer to the Adaptec AIC-7770 Data Book available from + * Adaptec's Technical Documents Department 1-800-934-2766 + */ + +/* + * SCSI Sequence Control (p. 3-11). + * Each bit, when set starts a specific SCSI sequence on the bus + */ +register SCSISEQ { + address 0x000 + access_mode RW + bit TEMODE 0x80 + bit ENSELO 0x40 + bit ENSELI 0x20 + bit ENRSELI 0x10 + bit ENAUTOATNO 0x08 + bit ENAUTOATNI 0x04 + bit ENAUTOATNP 0x02 + bit SCSIRSTO 0x01 +} + +/* + * SCSI Transfer Control 0 Register (pp. 3-13). + * Controls the SCSI module data path. + */ +register SXFRCTL0 { + address 0x001 + access_mode RW + bit DFON 0x80 + bit DFPEXP 0x40 + bit FAST20 0x20 + bit CLRSTCNT 0x10 + bit SPIOEN 0x08 + bit SCAMEN 0x04 + bit CLRCHN 0x02 +} + +/* + * SCSI Transfer Control 1 Register (pp. 3-14,15). + * Controls the SCSI module data path. + */ +register SXFRCTL1 { + address 0x002 + access_mode RW + bit BITBUCKET 0x80 + bit SWRAPEN 0x40 + bit ENSPCHK 0x20 + mask STIMESEL 0x18 + bit ENSTIMER 0x04 + bit ACTNEGEN 0x02 + bit STPWEN 0x01 /* Powered Termination */ +} + +/* + * SCSI Control Signal Read Register (p. 3-15). + * Reads the actual state of the SCSI bus pins + */ +register SCSISIGI { + address 0x003 + access_mode RO + bit CDI 0x80 + bit IOI 0x40 + bit MSGI 0x20 + bit ATNI 0x10 + bit SELI 0x08 + bit BSYI 0x04 + bit REQI 0x02 + bit ACKI 0x01 +/* + * Possible phases in SCSISIGI + */ + mask PHASE_MASK CDI|IOI|MSGI + mask P_DATAOUT 0x00 + mask P_DATAIN IOI + mask P_COMMAND CDI + mask P_MESGOUT CDI|MSGI + mask P_STATUS CDI|IOI + mask P_MESGIN CDI|IOI|MSGI +} + +/* + * SCSI Control Signal Write Register (p. 3-16). + * Writing to this register modifies the control signals on the bus. Only + * those signals that are allowed in the current mode (Initiator/Target) are + * asserted. + */ +register SCSISIGO { + address 0x003 + access_mode WO + bit CDO 0x80 + bit IOO 0x40 + bit MSGO 0x20 + bit ATNO 0x10 + bit SELO 0x08 + bit BSYO 0x04 + bit REQO 0x02 + bit ACKO 0x01 +/* + * Possible phases to write into SCSISIG0 + */ + mask PHASE_MASK CDI|IOI|MSGI + mask P_DATAOUT 0x00 + mask P_DATAIN IOI + mask P_COMMAND CDI + mask P_MESGOUT CDI|MSGI + mask P_STATUS CDI|IOI + mask P_MESGIN CDI|IOI|MSGI +} + +/* + * SCSI Rate Control (p. 3-17). + * Contents of this register determine the Synchronous SCSI data transfer + * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the + * SOFS (3:0) bits disables synchronous data transfers. Any offset value + * greater than 0 enables synchronous transfers. + */ +register SCSIRATE { + address 0x004 + access_mode RW + bit WIDEXFER 0x80 /* Wide transfer control */ + bit ENABLE_CRC 0x40 /* CRC for D-Phases */ + bit SINGLE_EDGE 0x10 /* Disable DT Transfers */ + mask SXFR 0x70 /* Sync transfer rate */ + mask SXFR_ULTRA2 0x0f /* Sync transfer rate */ + mask SOFS 0x0f /* Sync offset */ +} + +/* + * SCSI ID (p. 3-18). + * Contains the ID of the board and the current target on the + * selected channel. + */ +register SCSIID { + address 0x005 + access_mode RW + mask TID 0xf0 /* Target ID mask */ + mask OID 0x0f /* Our ID mask */ + /* + * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book) + * The aic7890/91 allow an offset of up to 127 transfers in both wide + * and narrow mode. + */ + alias SCSIOFFSET + mask SOFS_ULTRA2 0x7f /* Sync offset U2 chips */ +} + +/* + * SCSI Latched Data (p. 3-19). + * Read/Write latches used to transfer data on the SCSI bus during + * Automatic or Manual PIO mode. SCSIDATH can be used for the + * upper byte of a 16bit wide asynchronouse data phase transfer. + */ +register SCSIDATL { + address 0x006 + access_mode RW +} + +register SCSIDATH { + address 0x007 + access_mode RW +} + +/* + * SCSI Transfer Count (pp. 3-19,20) + * These registers count down the number of bytes transferred + * across the SCSI bus. The counter is decremented only once + * the data has been safely transferred. SDONE in SSTAT0 is + * set when STCNT goes to 0 + */ +register STCNT { + address 0x008 + size 3 + access_mode RW +} + +/* ALT_MODE register on Ultra160 chips */ +register OPTIONMODE { + address 0x008 + access_mode RW + bit AUTORATEEN 0x80 + bit AUTOACKEN 0x40 + bit ATNMGMNTEN 0x20 + bit BUSFREEREV 0x10 + bit EXPPHASEDIS 0x08 + bit SCSIDATL_IMGEN 0x04 + bit AUTO_MSGOUT_DE 0x02 + bit DIS_MSGIN_DUALEDGE 0x01 + mask OPTIONMODE_DEFAULTS AUTO_MSGOUT_DE|DIS_MSGIN_DUALEDGE +} + +/* ALT_MODE register on Ultra160 chips */ +register TARGCRCCNT { + address 0x00a + size 2 + access_mode RW +} + +/* + * Clear SCSI Interrupt 0 (p. 3-20) + * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0. + */ +register CLRSINT0 { + address 0x00b + access_mode WO + bit CLRSELDO 0x40 + bit CLRSELDI 0x20 + bit CLRSELINGO 0x10 + bit CLRSWRAP 0x08 + bit CLRSPIORDY 0x02 +} + +/* + * SCSI Status 0 (p. 3-21) + * Contains one set of SCSI Interrupt codes + * These are most likely of interest to the sequencer + */ +register SSTAT0 { + address 0x00b + access_mode RO + bit TARGET 0x80 /* Board acting as target */ + bit SELDO 0x40 /* Selection Done */ + bit SELDI 0x20 /* Board has been selected */ + bit SELINGO 0x10 /* Selection In Progress */ + bit SWRAP 0x08 /* 24bit counter wrap */ + bit IOERR 0x08 /* LVD Tranceiver mode changed */ + bit SDONE 0x04 /* STCNT = 0x000000 */ + bit SPIORDY 0x02 /* SCSI PIO Ready */ + bit DMADONE 0x01 /* DMA transfer completed */ +} + +/* + * Clear SCSI Interrupt 1 (p. 3-23) + * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. + */ +register CLRSINT1 { + address 0x00c + access_mode WO + bit CLRSELTIMEO 0x80 + bit CLRATNO 0x40 + bit CLRSCSIRSTI 0x20 + bit CLRBUSFREE 0x08 + bit CLRSCSIPERR 0x04 + bit CLRPHASECHG 0x02 + bit CLRREQINIT 0x01 +} + +/* + * SCSI Status 1 (p. 3-24) + */ +register SSTAT1 { + address 0x00c + access_mode RO + bit SELTO 0x80 + bit ATNTARG 0x40 + bit SCSIRSTI 0x20 + bit PHASEMIS 0x10 + bit BUSFREE 0x08 + bit SCSIPERR 0x04 + bit PHASECHG 0x02 + bit REQINIT 0x01 +} + +/* + * SCSI Status 2 (pp. 3-25,26) + */ +register SSTAT2 { + address 0x00d + access_mode RO + bit OVERRUN 0x80 + bit EXP_ACTIVE 0x10 /* SCSI Expander Active */ + mask SFCNT 0x1f +} + +/* + * SCSI Status 3 (p. 3-26) + */ +register SSTAT3 { + address 0x00e + access_mode RO + mask SCSICNT 0xf0 + mask OFFCNT 0x0f +} + +/* + * SCSI ID for the aic7890/91 chips + */ +register SCSIID_ULTRA2 { + address 0x00f + access_mode RW + mask TID 0xf0 /* Target ID mask */ + mask OID 0x0f /* Our ID mask */ +} + +/* + * SCSI Interrupt Mode 1 (p. 3-28) + * Setting any bit will enable the corresponding function + * in SIMODE0 to interrupt via the IRQ pin. + */ +register SIMODE0 { + address 0x010 + access_mode RW + bit ENSELDO 0x40 + bit ENSELDI 0x20 + bit ENSELINGO 0x10 + bit ENSWRAP 0x08 + bit ENIOERR 0x08 /* LVD Tranceiver mode changes */ + bit ENSDONE 0x04 + bit ENSPIORDY 0x02 + bit ENDMADONE 0x01 +} + +/* + * SCSI Interrupt Mode 1 (pp. 3-28,29) + * Setting any bit will enable the corresponding function + * in SIMODE1 to interrupt via the IRQ pin. + */ +register SIMODE1 { + address 0x011 + access_mode RW + bit ENSELTIMO 0x80 + bit ENATNTARG 0x40 + bit ENSCSIRST 0x20 + bit ENPHASEMIS 0x10 + bit ENBUSFREE 0x08 + bit ENSCSIPERR 0x04 + bit ENPHASECHG 0x02 + bit ENREQINIT 0x01 +} + +/* + * SCSI Data Bus (High) (p. 3-29) + * This register reads data on the SCSI Data bus directly. + */ +register SCSIBUSL { + address 0x012 + access_mode RO +} + +register SCSIBUSH { + address 0x013 + access_mode RO +} + +/* + * SCSI/Host Address (p. 3-30) + * These registers hold the host address for the byte about to be + * transferred on the SCSI bus. They are counted up in the same + * manner as STCNT is counted down. SHADDR should always be used + * to determine the address of the last byte transferred since HADDR + * can be skewed by write ahead. + */ +register SHADDR { + address 0x014 + size 4 + access_mode RO +} + +/* + * Selection Timeout Timer (p. 3-30) + */ +register SELTIMER { + address 0x018 + access_mode RW + bit STAGE6 0x20 + bit STAGE5 0x10 + bit STAGE4 0x08 + bit STAGE3 0x04 + bit STAGE2 0x02 + bit STAGE1 0x01 + alias TARGIDIN +} + +/* + * Selection/Reselection ID (p. 3-31) + * Upper four bits are the device id. The ONEBIT is set when the re/selecting + * device did not set its own ID. + */ +register SELID { + address 0x019 + access_mode RW + mask SELID_MASK 0xf0 + bit ONEBIT 0x08 +} + +register SCAMCTL { + address 0x01a + access_mode RW + bit ENSCAMSELO 0x80 + bit CLRSCAMSELID 0x40 + bit ALTSTIM 0x20 + bit DFLTTID 0x10 + mask SCAMLVL 0x03 +} + +/* + * Target Mode Selecting in ID bitmask (aic7890/91/96/97) + */ +register TARGID { + address 0x01b + size 2 + access_mode RW +} + +/* + * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book) + * Indicates if external logic has been attached to the chip to + * perform the tasks of accessing a serial eeprom, testing termination + * strength, and performing cable detection. On the aic7860, most of + * these features are handled on chip, but on the aic7855 an attached + * aic3800 does the grunt work. + */ +register SPIOCAP { + address 0x01b + access_mode RW + bit SOFT1 0x80 + bit SOFT0 0x40 + bit SOFTCMDEN 0x20 + bit HAS_BRDCTL 0x10 /* External Board control */ + bit SEEPROM 0x08 /* External serial eeprom logic */ + bit EEPROM 0x04 /* Writable external BIOS ROM */ + bit ROM 0x02 /* Logic for accessing external ROM */ + bit SSPIOCPS 0x01 /* Termination and cable detection */ +} + +register BRDCTL { + address 0x01d + bit BRDDAT7 0x80 + bit BRDDAT6 0x40 + bit BRDDAT5 0x20 + bit BRDSTB 0x10 + bit BRDCS 0x08 + bit BRDRW 0x04 + bit BRDCTL1 0x02 + bit BRDCTL0 0x01 + /* 7890 Definitions */ + bit BRDDAT4 0x10 + bit BRDDAT3 0x08 + bit BRDDAT2 0x04 + bit BRDRW_ULTRA2 0x02 + bit BRDSTB_ULTRA2 0x01 +} + +/* + * Serial EEPROM Control (p. 4-92 in 7870 Databook) + * Controls the reading and writing of an external serial 1-bit + * EEPROM Device. In order to access the serial EEPROM, you must + * first set the SEEMS bit that generates a request to the memory + * port for access to the serial EEPROM device. When the memory + * port is not busy servicing another request, it reconfigures + * to allow access to the serial EEPROM. When this happens, SEERDY + * gets set high to verify that the memory port access has been + * granted. + * + * After successful arbitration for the memory port, the SEECS bit of + * the SEECTL register is connected to the chip select. The SEECK, + * SEEDO, and SEEDI are connected to the clock, data out, and data in + * lines respectively. The SEERDY bit of SEECTL is useful in that it + * gives us an 800 nsec timer. After a write to the SEECTL register, + * the SEERDY goes high 800 nsec later. The one exception to this is + * when we first request access to the memory port. The SEERDY goes + * high to signify that access has been granted and, for this case, has + * no implied timing. + * + * See 93cx6.c for detailed information on the protocol necessary to + * read the serial EEPROM. + */ +register SEECTL { + address 0x01e + bit EXTARBACK 0x80 + bit EXTARBREQ 0x40 + bit SEEMS 0x20 + bit SEERDY 0x10 + bit SEECS 0x08 + bit SEECK 0x04 + bit SEEDO 0x02 + bit SEEDI 0x01 +} +/* + * SCSI Block Control (p. 3-32) + * Controls Bus type and channel selection. In a twin channel configuration + * addresses 0x00-0x1e are gated to the appropriate channel based on this + * register. SELWIDE allows for the coexistence of 8bit and 16bit devices + * on a wide bus. + */ +register SBLKCTL { + address 0x01f + access_mode RW + bit DIAGLEDEN 0x80 /* Aic78X0 only */ + bit DIAGLEDON 0x40 /* Aic78X0 only */ + bit AUTOFLUSHDIS 0x20 + bit SELBUSB 0x08 + bit ENAB40 0x08 /* LVD transceiver active */ + bit ENAB20 0x04 /* SE/HVD transceiver active */ + bit SELWIDE 0x02 + bit XCVR 0x01 /* External transceiver active */ +} + +/* + * Sequencer Control (p. 3-33) + * Error detection mode and speed configuration + */ +register SEQCTL { + address 0x060 + access_mode RW + bit PERRORDIS 0x80 + bit PAUSEDIS 0x40 + bit FAILDIS 0x20 + bit FASTMODE 0x10 + bit BRKADRINTEN 0x08 + bit STEP 0x04 + bit SEQRESET 0x02 + bit LOADRAM 0x01 +} + +/* + * Sequencer RAM Data (p. 3-34) + * Single byte window into the Scratch Ram area starting at the address + * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write + * four bytes in succession. The SEQADDRs will increment after the most + * significant byte is written + */ +register SEQRAM { + address 0x061 + access_mode RW +} + +/* + * Sequencer Address Registers (p. 3-35) + * Only the first bit of SEQADDR1 holds addressing information + */ +register SEQADDR0 { + address 0x062 + access_mode RW +} + +register SEQADDR1 { + address 0x063 + access_mode RW + mask SEQADDR1_MASK 0x01 +} + +/* + * Accumulator + * We cheat by passing arguments in the Accumulator up to the kernel driver + */ +register ACCUM { + address 0x064 + access_mode RW + accumulator +} + +register SINDEX { + address 0x065 + access_mode RW + sindex +} + +register DINDEX { + address 0x066 + access_mode RW +} + +register ALLONES { + address 0x069 + access_mode RO + allones +} + +register ALLZEROS { + address 0x06a + access_mode RO + allzeros +} + +register NONE { + address 0x06a + access_mode WO + none +} + +register FLAGS { + address 0x06b + access_mode RO + bit ZERO 0x02 + bit CARRY 0x01 +} + +register SINDIR { + address 0x06c + access_mode RO +} + +register DINDIR { + address 0x06d + access_mode WO +} + +register FUNCTION1 { + address 0x06e + access_mode RW +} + +register STACK { + address 0x06f + access_mode RO +} + +/* + * Board Control (p. 3-43) + */ +register BCTL { + address 0x084 + access_mode RW + bit ACE 0x08 + bit ENABLE 0x01 +} + +/* + * On the aic78X0 chips, Board Control is replaced by the DSCommand + * register (p. 4-64) + */ +register DSCOMMAND0 { + address 0x084 + access_mode RW + bit CACHETHEN 0x80 /* Cache Threshold enable */ + bit DPARCKEN 0x40 /* Data Parity Check Enable */ + bit MPARCKEN 0x20 /* Memory Parity Check Enable */ + bit EXTREQLCK 0x10 /* External Request Lock */ + /* aic7890/91/96/97 only */ + bit INTSCBRAMSEL 0x08 /* Internal SCB RAM Select */ + bit RAMPS 0x04 /* External SCB RAM Present */ + bit USCBSIZE32 0x02 /* Use 32byte SCB Page Size */ + bit CIOPARCKEN 0x01 /* Internal bus parity error enable */ +} + +/* + * Bus On/Off Time (p. 3-44) + */ +register BUSTIME { + address 0x085 + access_mode RW + mask BOFF 0xf0 + mask BON 0x0f +} + +/* + * Bus Speed (p. 3-45) aic7770 only + */ +register BUSSPD { + address 0x086 + access_mode RW + mask DFTHRSH 0xc0 + mask STBOFF 0x38 + mask STBON 0x07 + mask DFTHRSH_100 0xc0 +} + +/* aic7850/55/60/70/80/95 only */ +register DSPCISTATUS { + address 0x086 + mask DFTHRSH_100 0xc0 +} + +/* aic7890/91/96/97 only */ +register HS_MAILBOX { + address 0x086 + mask HOST_MAILBOX 0xF0 + mask SEQ_MAILBOX 0x0F +} + +const HOST_MAILBOX_SHIFT 4 +const SEQ_MAILBOX_SHIFT 0 + +/* + * Host Control (p. 3-47) R/W + * Overall host control of the device. + */ +register HCNTRL { + address 0x087 + access_mode RW + bit POWRDN 0x40 + bit SWINT 0x10 + bit IRQMS 0x08 + bit PAUSE 0x04 + bit INTEN 0x02 + bit CHIPRST 0x01 + bit CHIPRSTACK 0x01 +} + +/* + * Host Address (p. 3-48) + * This register contains the address of the byte about + * to be transferred across the host bus. + */ +register HADDR { + address 0x088 + size 4 + access_mode RW +} + +register HCNT { + address 0x08c + size 3 + access_mode RW +} + +/* + * SCB Pointer (p. 3-49) + * Gate one of the four SCBs into the SCBARRAY window. + */ +register SCBPTR { + address 0x090 + access_mode RW +} + +/* + * Interrupt Status (p. 3-50) + * Status for system interrupts + */ +register INTSTAT { + address 0x091 + access_mode RW + bit BRKADRINT 0x08 + bit SCSIINT 0x04 + bit CMDCMPLT 0x02 + bit SEQINT 0x01 + mask BAD_PHASE SEQINT /* unknown scsi bus phase */ + mask SEND_REJECT 0x10|SEQINT /* sending a message reject */ + mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/ + mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */ + mask UPDATE_TMSG_REQ 0x60|SEQINT /* Update TMSG_REQ values */ + mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ + mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */ + mask TRACE_POINT 0x90|SEQINT + mask HOST_MSG_LOOP 0xa0|SEQINT /* + * The bus is ready for the + * host to perform another + * message transaction. This + * mechanism is used for things + * like sync/wide negotiation + * that require a kernel based + * message state engine. + */ + mask PERR_DETECTED 0xb0|SEQINT /* + * Either the phase_lock + * or inb_next routine has + * noticed a parity error. + */ + mask TRACEPOINT 0xd0|SEQINT + mask MSGIN_PHASEMIS 0xe0|SEQINT /* + * Target changed phase on us + * when we were expecting + * another msgin byte. + */ + mask DATA_OVERRUN 0xf0|SEQINT /* + * Target attempted to write + * beyond the bounds of its + * command. + */ + + mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */ + mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT) +} + +/* + * Hard Error (p. 3-53) + * Reporting of catastrophic errors. You usually cannot recover from + * these without a full board reset. + */ +register ERROR { + address 0x092 + access_mode RO + bit CIOPARERR 0x80 /* Ultra2 only */ + bit PCIERRSTAT 0x40 /* PCI only */ + bit MPARERR 0x20 /* PCI only */ + bit DPARERR 0x10 /* PCI only */ + bit SQPARERR 0x08 + bit ILLOPCODE 0x04 + bit ILLSADDR 0x02 + bit ILLHADDR 0x01 +} + +/* + * Clear Interrupt Status (p. 3-52) + */ +register CLRINT { + address 0x092 + access_mode WO + bit CLRPARERR 0x10 /* PCI only */ + bit CLRBRKADRINT 0x08 + bit CLRSCSIINT 0x04 + bit CLRCMDINT 0x02 + bit CLRSEQINT 0x01 +} + +register DFCNTRL { + address 0x093 + access_mode RW + bit PRELOADEN 0x80 /* aic7890 only */ + bit WIDEODD 0x40 + bit SCSIEN 0x20 + bit SDMAEN 0x10 + bit SDMAENACK 0x10 + bit HDMAEN 0x08 + bit HDMAENACK 0x08 + bit DIRECTION 0x04 + bit FIFOFLUSH 0x02 + bit FIFORESET 0x01 +} + +register DFSTATUS { + address 0x094 + access_mode RO + bit PRELOAD_AVAIL 0x80 + bit DWORDEMP 0x20 + bit MREQPEND 0x10 + bit HDONE 0x08 + bit DFTHRESH 0x04 + bit FIFOFULL 0x02 + bit FIFOEMP 0x01 +} + +register DFWADDR { + address 0x95 + access_mode RW +} + +register DFRADDR { + address 0x97 + access_mode RW +} + +register DFDAT { + address 0x099 + access_mode RW +} + +/* + * SCB Auto Increment (p. 3-59) + * Byte offset into the SCB Array and an optional bit to allow auto + * incrementing of the address during download and upload operations + */ +register SCBCNT { + address 0x09a + access_mode RW + bit SCBAUTO 0x80 + mask SCBCNT_MASK 0x1f +} + +/* + * Queue In FIFO (p. 3-60) + * Input queue for queued SCBs (commands that the seqencer has yet to start) + */ +register QINFIFO { + address 0x09b + access_mode RW +} + +/* + * Queue In Count (p. 3-60) + * Number of queued SCBs + */ +register QINCNT { + address 0x09c + access_mode RO +} + +/* + * Queue Out FIFO (p. 3-61) + * Queue of SCBs that have completed and await the host + */ +register QOUTFIFO { + address 0x09d + access_mode WO +} + +register CRCCONTROL1 { + address 0x09d + access_mode RW + bit CRCONSEEN 0x80 + bit CRCVALCHKEN 0x40 + bit CRCENDCHKEN 0x20 + bit CRCREQCHKEN 0x10 + bit TARGCRCENDEN 0x08 + bit TARGCRCCNTEN 0x04 +} + + +/* + * Queue Out Count (p. 3-61) + * Number of queued SCBs in the Out FIFO + */ +register QOUTCNT { + address 0x09e + access_mode RO +} + +register SCSIPHASE { + address 0x09e + access_mode RO + bit STATUS_PHASE 0x20 + bit COMMAND_PHASE 0x10 + bit MSG_IN_PHASE 0x08 + bit MSG_OUT_PHASE 0x04 + bit DATA_IN_PHASE 0x02 + bit DATA_OUT_PHASE 0x01 +} + +/* + * Special Function + */ +register SFUNCT { + address 0x09f + access_mode RW + bit ALT_MODE 0x80 +} + +/* + * SCB Definition (p. 5-4) + */ +scb { + address 0x0a0 + SCB_CONTROL { + size 1 + bit TARGET_SCB 0x80 + bit DISCENB 0x40 + bit TAG_ENB 0x20 + bit MK_MESSAGE 0x10 + bit ULTRAENB 0x08 + bit DISCONNECTED 0x04 + mask SCB_TAG_TYPE 0x03 + } + SCB_TCL { + size 1 + bit SELBUSB 0x08 + mask TID 0xf0 + mask LID 0x07 + } + SCB_TARGET_STATUS { + size 1 + } + SCB_SGCOUNT { + size 1 + } + SCB_SGPTR { + size 4 + } + SCB_RESID_SGCNT { + size 1 + } + SCB_RESID_DCNT { + size 3 + } + SCB_DATAPTR { + size 4 + } + SCB_DATACNT { + /* + * Really only 3 bytes, but padded to make + * the kernel's job easier. + */ + size 4 + } + SCB_CMDPTR { + alias SCB_TARGET_PHASES + bit TARGET_DATA_IN 0x1 /* In the second byte */ + size 4 + } + SCB_CMDLEN { + alias SCB_INITIATOR_TAG + size 1 + } + SCB_TAG { + size 1 + } + SCB_NEXT { + size 1 + } + SCB_SCSIRATE { + size 1 + } + SCB_SCSIOFFSET { + size 1 + } + SCB_SPARE { + size 3 + } + SCB_CMDSTORE { + size 16 + } + SCB_CMDSTORE_BUSADDR { + size 4 + } + SCB_64BYTE_SPARE { + size 12 + } +} + +const SCB_32BYTE_SIZE 28 +const SCB_64BYTE_SIZE 48 + +const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ + +/* --------------------- AHA-2840-only definitions -------------------- */ + +register SEECTL_2840 { + address 0x0c0 + access_mode RW + bit CS_2840 0x04 + bit CK_2840 0x02 + bit DO_2840 0x01 +} + +register STATUS_2840 { + address 0x0c1 + access_mode RW + bit EEPROM_TF 0x80 + mask BIOS_SEL 0x60 + mask ADSEL 0x1e + bit DI_2840 0x01 +} + +/* --------------------- AIC-7870-only definitions -------------------- */ + +register CCHADDR { + address 0x0E0 + size 8 +} + +register CCHCNT { + address 0x0E8 +} + +register CCSGRAM { + address 0x0E9 +} + +register CCSGADDR { + address 0x0EA +} + +register CCSGCTL { + address 0x0EB + bit CCSGDONE 0x80 + bit CCSGEN 0x08 + bit FLAG 0x02 + bit CCSGRESET 0x01 +} + +register CCSCBCNT { + address 0xEF +} + +register CCSCBCTL { + address 0x0EE + bit CCSCBDONE 0x80 + bit ARRDONE 0x40 /* SCB Array prefetch done */ + bit CCARREN 0x10 + bit CCSCBEN 0x08 + bit CCSCBDIR 0x04 + bit CCSCBRESET 0x01 +} + +register CCSCBADDR { + address 0x0ED +} + +register CCSCBRAM { + address 0xEC +} + +/* + * SCB bank address (7895/7896/97 only) + */ +register SCBBADDR { + address 0x0F0 + access_mode RW +} + +register CCSCBPTR { + address 0x0F1 +} + +register HNSCB_QOFF { + address 0x0F4 +} + +register SNSCB_QOFF { + address 0x0F6 +} + +register SDSCB_QOFF { + address 0x0F8 +} + +register QOFF_CTLSTA { + address 0x0FA + bit SCB_AVAIL 0x40 + bit SNSCB_ROLLOVER 0x20 + bit SDSCB_ROLLOVER 0x10 + mask SCB_QSIZE 0x07 + mask SCB_QSIZE_256 0x06 +} + +register DFF_THRSH { + address 0x0FB + mask WR_DFTHRSH 0x70 + mask RD_DFTHRSH 0x07 + mask RD_DFTHRSH_MIN 0x00 + mask RD_DFTHRSH_25 0x01 + mask RD_DFTHRSH_50 0x02 + mask RD_DFTHRSH_63 0x03 + mask RD_DFTHRSH_75 0x04 + mask RD_DFTHRSH_85 0x05 + mask RD_DFTHRSH_90 0x06 + mask RD_DFTHRSH_MAX 0x07 + mask WR_DFTHRSH_MIN 0x00 + mask WR_DFTHRSH_25 0x10 + mask WR_DFTHRSH_50 0x20 + mask WR_DFTHRSH_63 0x30 + mask WR_DFTHRSH_75 0x40 + mask WR_DFTHRSH_85 0x50 + mask WR_DFTHRSH_90 0x60 + mask WR_DFTHRSH_MAX 0x70 +} + +register SG_CACHEPTR { + access_mode RW + address 0x0fc + mask SG_USER_DATA 0xfc + bit LAST_SEG 0x02 + bit LAST_SEG_DONE 0x01 +} + +/* ---------------------- Scratch RAM Offsets ------------------------- */ +/* These offsets are either to values that are initialized by the board's + * BIOS or are specified by the sequencer code. + * + * The host adapter card (at least the BIOS) uses 20-2f for SCSI + * device information, 32-33 and 5a-5f as well. As it turns out, the + * BIOS trashes 20-2f, writing the synchronous negotiation results + * on top of the BIOS values, so we re-use those for our per-target + * scratchspace (actually a value that can be copied directly into + * SCSIRATE). The kernel driver will enable synchronous negotiation + * for all targets that have a value other than 0 in the lower four + * bits of the target scratch space. This should work regardless of + * whether the bios has been installed. + */ + +scratch_ram { + address 0x020 + + /* + * 1 byte per target starting at this address for configuration values + */ + TARG_SCSIRATE { + alias CMDSIZE_TABLE + size 16 + } + /* + * Bit vector of targets that have ULTRA enabled. + */ + ULTRA_ENB { + size 2 + } + /* + * Bit vector of targets that have disconnection disabled. + */ + DISC_DSB { + size 2 + } + /* + * Single byte buffer used to designate the type or message + * to send to a target. + */ + MSG_OUT { + size 1 + } + /* Parameters for DMA Logic */ + DMAPARAMS { + size 1 + bit PRELOADEN 0x80 + bit WIDEODD 0x40 + bit SCSIEN 0x20 + bit SDMAEN 0x10 + bit SDMAENACK 0x10 + bit HDMAEN 0x08 + bit HDMAENACK 0x08 + bit DIRECTION 0x04 + bit FIFOFLUSH 0x02 + bit FIFORESET 0x01 + } + SEQ_FLAGS { + size 1 + bit IDENTIFY_SEEN 0x80 + bit SCBPTR_VALID 0x40 + bit DPHASE 0x20 + /* Target flags */ + bit TARG_CMD_PENDING 0x10 + bit CMDPHASE_PENDING 0x08 + bit DPHASE_PENDING 0x04 + bit SPHASE_PENDING 0x02 + bit NO_DISCONNECT 0x01 + } + /* + * Temporary storage for the + * target/channel/lun of a + * reconnecting target + */ + SAVED_TCL { + size 1 + } + /* Working value of the number of SG segments left */ + SG_COUNT { + size 1 + } + /* Working value of SG pointer */ + SG_NEXT { + size 4 + } + /* + * The last bus phase as seen by the sequencer. + */ + LASTPHASE { + size 1 + bit CDI 0x80 + bit IOI 0x40 + bit MSGI 0x20 + mask PHASE_MASK CDI|IOI|MSGI + mask P_DATAOUT 0x00 + mask P_DATAIN IOI + mask P_COMMAND CDI + mask P_MESGOUT CDI|MSGI + mask P_STATUS CDI|IOI + mask P_MESGIN CDI|IOI|MSGI + mask P_BUSFREE 0x01 + } + /* + * head of list of SCBs awaiting + * selection + */ + WAITING_SCBH { + size 1 + } + /* + * head of list of SCBs that are + * disconnected. Used for SCB + * paging. + */ + DISCONNECTED_SCBH { + size 1 + } + /* + * head of list of SCBs that are + * not in use. Used for SCB paging. + */ + FREE_SCBH { + size 1 + } + /* + * Address of the hardware scb array in the host. + */ + HSCB_ADDR { + size 4 + } + /* + * Address of the 256 byte array storing the SCBID of outstanding + * untagged SCBs indexed by TCL. + */ + SCBID_ADDR { + size 4 + } + /* + * Address of the array of command descriptors used to store + * information about incoming selections. + */ + TMODE_CMDADDR { + size 4 + } + KERNEL_QINPOS { + size 1 + } + QINPOS { + size 1 + } + QOUTPOS { + size 1 + } + /* + * Kernel and sequencer offsets into the queue of + * incoming target mode command descriptors. The + * queue is full when the KERNEL_TQINPOS == TQINPOS. + */ + KERNEL_TQINPOS { + size 1 + } + TQINPOS { + size 1 + } + ARG_1 { + size 1 + mask SEND_MSG 0x80 + mask SEND_SENSE 0x40 + mask SEND_REJ 0x20 + mask MSGOUT_PHASEMIS 0x10 + mask EXIT_MSG_LOOP 0x08 + mask CONT_MSG_LOOP 0x04 + mask CONT_TARG_SESSION 0x02 + alias RETURN_1 + } + ARG_2 { + size 1 + alias RETURN_2 + } + + /* + * Snapshot of MSG_OUT taken after each message is sent. + */ + LAST_MSG { + size 1 + } + + /* + * Number of times we have filled the CCSGRAM with prefetched + * SG elements. + */ + PREFETCH_CNT { + size 1 + } + + /* + * Interrupt kernel for a message to this target on + * the next transaction. This is usually used for + * negotiation requests. + */ + TARGET_MSG_REQUEST { + size 2 + } + + /* + * Sequences the kernel driver has okayed for us. This allows + * the driver to do things like prevent initiator or target + * operations. + */ + SCSISEQ_TEMPLATE { + size 1 + bit ENSELO 0x40 + bit ENSELI 0x20 + bit ENRSELI 0x10 + bit ENAUTOATNO 0x08 + bit ENAUTOATNI 0x04 + bit ENAUTOATNP 0x02 + } + + /* + * Track whether the transfer byte count for + * the current data phase is odd. + */ + DATA_COUNT_ODD { + size 1 + } + + /* + * The initiator specified tag for this target mode transaction. + */ + INITIATOR_TAG { + size 1 + } + + /* + * These are reserved registers in the card's scratch ram. Some of + * the values are specified in the AHA2742 technical reference manual + * and are initialized by the BIOS at boot time. + */ + SCSICONF { + address 0x05a + size 1 + bit TERM_ENB 0x80 + bit RESET_SCSI 0x40 + bit ENSPCHK 0x20 + mask HSCSIID 0x07 /* our SCSI ID */ + mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ + } + HOSTCONF { + address 0x05d + size 1 + } + HA_274_BIOSCTRL { + address 0x05f + size 1 + mask BIOSMODE 0x30 + mask BIOSDISABLED 0x30 + bit CHANNEL_B_PRIMARY 0x08 + } + /* + * Per target SCSI offset values for Ultra2 controllers. + */ + TARG_OFFSET { + address 0x070 + size 16 + } +} + +const SCB_LIST_NULL 0xff +const TARGET_CMD_CMPLT 0xfe + +const CCSGADDR_MAX 0x80 +const CCSGRAM_MAXSEGS 16 + +/* Offsets into the SCBID array where different data is stored */ +const QOUTFIFO_OFFSET 0 +const QINFIFO_OFFSET 1 +const UNTAGGEDSCB_OFFSET 2 + +/* WDTR Message values */ +const BUS_8_BIT 0x00 +const BUS_16_BIT 0x01 +const BUS_32_BIT 0x02 + +/* Offset maximums */ +const MAX_OFFSET_8BIT 0x0f +const MAX_OFFSET_16BIT 0x08 +const MAX_OFFSET_ULTRA2 0x7f +const HOST_MSG 0xff + +/* Target mode command processing constants */ +const CMD_GROUP_CODE_SHIFT 0x05 + +const TCL_TARGET_SHIFT 4 +/* The update interval must be a power of 2 */ +const TQINFIFO_UPDATE_CNT 32 + +const STATUS_BUSY 0x08 +const STATUS_QUEUE_FULL 0x28 + +/* + * Downloaded (kernel inserted) constants + */ + +/* + * Number of command descriptors in the command descriptor array. + * No longer used, but left here as an example for how downloaded + * constantants can be defined. +const TMODE_NUMCMDS download + */ diff --git a/sys/dev/microcode/aic7xxx/aic7xxx.seq b/sys/dev/microcode/aic7xxx/aic7xxx.seq index 97c3f615375..6f5210b2497 100644 --- a/sys/dev/microcode/aic7xxx/aic7xxx.seq +++ b/sys/dev/microcode/aic7xxx/aic7xxx.seq @@ -1,71 +1,45 @@ -/* $OpenBSD: aic7xxx.seq,v 1.6 1996/12/03 11:28:32 niklas Exp $ */ -/* $NetBSD: aic7xxx.seq,v 1.6 1996/10/08 03:04:06 gibbs Exp $ */ - -/*+M*********************************************************************** - *Adaptec 274x/284x/294x device driver for Linux and FreeBSD. - * - *Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * All rights reserved. +/* + * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. * - *FreeBSD, Twin, Wide, 2 command per target support, tagged queuing, - *SCB paging and other optimizations: - *Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved. + * Copyright (c) 1994-2000 Justin Gibbs. + * All rights reserved. * - *Redistribution and use in source and binary forms, with or without - *modification, are permitted provided that the following conditions - *are met: - *1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer. - *2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - *3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of Calgary - * Department of Computer Science and its contributors. - *4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. * - *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - *ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - *DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - *OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - *HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - *OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - *SUCH DAMAGE. + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). * - * from Id: aic7xxx.seq,v 1.42 1996/06/09 17:29:11 gibbs Exp + * 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. * - *-M************************************************************************/ - -VERSION AIC7XXX_SEQ_VER "$NetBSD: aic7xxx.seq,v 1.6 1996/10/08 03:04:06 gibbs Exp $" + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.93 2000/01/07 23:08:20 gibbs Exp $ + */ -#if defined(__OpenBSD__) -#include <dev/ic/aic7xxxreg.h> +#include <dev/microcode/aic7xxx/aic7xxx.reg> #include <scsi/scsi_message.h> -#elif defined(__NetBSD__) -#include "../../ic/aic7xxxreg.h" -#include "../../../scsi/scsi_message.h" -#elif defined(__FreeBSD__) -#include "../../dev/aic7xxx/aic7xxx_reg.h" -#include "../../scsi/scsi_message.h" -#endif - /* - * We can't just use ACCUM in the sequencer code because it - * must be treated specially by the assembler, and it currently - * looks for the symbol 'A'. This is the only register defined in - * the assembler's symbol space. - */ -A = ACCUM +#include <cam/scsi/scsi_message.h> +*/ -/* After starting the selection hardware, we check for reconnecting targets +/* + * A few words on the waiting SCB list: + * After starting the selection hardware, we check for reconnecting targets * as well as for our selection to complete just in case the reselection wins * bus arbitration. The problem with this is that we must keep track of the * SCB that we've already pulled from the QINFIFO and started the selection @@ -74,311 +48,762 @@ A = ACCUM * in scratch ram since a reconnecting target can request sense and this will * create yet another SCB waiting for selection. The solution used here is to * use byte 27 of the SCB as a psuedo-next pointer and to thread a list - * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB offsets, - * SCB_LIST_NULL is 0xff which is out of range. The kernel driver must - * add an entry to this list everytime a request sense occurs. The sequencer - * will automatically consume the entries. + * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, + * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to + * this list everytime a request sense occurs or after completing a non-tagged + * command for which a second SCB has been queued. The sequencer will + * automatically consume the entries. */ -/* - * We assume that the kernel driver may reset us at any time, even in the - * middle of a DMA, so clear DFCNTRL too. - */ reset: - clr DFCNTRL - clr SCSISIGO /* De-assert BSY */ -/* - * We jump to start after every bus free. - */ -start: - and FLAGS,0x0f /* clear target specific flags */ - mvi SCSISEQ,ENRSELI /* Always allow reselection */ - clr SCSIRATE /* - * We don't know the target we will - * connect to, so default to narrow - * transfers to avoid parity problems. - */ + clr SCSISIGO; /* De-assert BSY */ + mvi MSG_OUT, MSG_NOOP; /* No message to send */ + and SXFRCTL1, ~BITBUCKET; + /* Always allow reselection */ + and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Ensure that no DMA operations are in progress */ + clr CCSGCTL; + clr CCSCBCTL; + } + poll_for_work: - /* - * Are we a twin channel device? - * For fairness, we check the other bus first, - * since we just finished a transaction on the - * current channel. - */ - test FLAGS,TWIN_BUS jz start2 - xor SBLKCTL,SELBUSB /* Toggle to the other bus */ - test SSTAT0,SELDI jnz reselect - xor SBLKCTL,SELBUSB /* Toggle to the original bus */ -start2: - test SSTAT0,SELDI jnz reselect - cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting - mov A, QCNTMASK - test QINCNT,A jz poll_for_work + call clear_target_state; + and SXFRCTL0, ~SPIOEN; + if ((ahc->features & AHC_QUEUE_REGS) == 0) { + mov A, QINPOS; + } +poll_for_work_loop: + if ((ahc->features & AHC_QUEUE_REGS) == 0) { + and SEQCTL, ~PAUSEDIS; + } + test SSTAT0, SELDO|SELDI jnz selection; + test SCSISEQ, ENSELO jnz poll_for_work; + if ((ahc->features & AHC_TWIN) != 0) { + /* + * Twin channel devices cannot handle things like SELTO + * interrupts on the "background" channel. So, if we + * are selecting, keep polling the current channel util + * either a selection or reselection occurs. + */ + xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ + test SSTAT0, SELDO|SELDI jnz selection; + test SCSISEQ, ENSELO jnz poll_for_work; + xor SBLKCTL,SELBUSB; /* Toggle back */ + } + cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; +test_queue: + /* Has the driver posted any work for us? */ + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; + mov NONE, SNSCB_QOFF; + inc QINPOS; + } else { + or SEQCTL, PAUSEDIS; + cmp KERNEL_QINPOS, A je poll_for_work_loop; + inc QINPOS; + and SEQCTL, ~PAUSEDIS; + } /* * We have at least one queued SCB now and we don't have any - * SCBs in the list of SCBs awaiting selection. Set the SCB - * pointer from the FIFO so we see the right bank of SCB - * registers. + * SCBs in the list of SCBs awaiting selection. If we have + * any SCBs available for use, pull the tag from the QINFIFO + * and get to work on it. */ - mov SCBPTR,QINFIFO + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } +dequeue_scb: + add A, -1, QINPOS; + mvi QINFIFO_OFFSET call fetch_byte; + + if ((ahc->flags & AHC_PAGESCBS) == 0) { + /* In the non-paging case, the SCBID == hardware SCB index */ + mov SCBPTR, RETURN_2; + } +dma_queued_scb: /* - * See if there is not already an active SCB for this target. This code - * locks out on a per target basis instead of target/lun. Although this - * is not ideal for devices that have multiple luns active at the same - * time, it is faster than looping through all SCB's looking for active - * commands. It may be benificial to make findscb a more general procedure - * to see if the added cost of the search is negligible. This code also - * assumes that the kernel driver will clear the active flags on board - * initialization, board reset, and a target SELTO. Tagged commands - * don't set the active bits since you can queue more than one command - * at a time. We do, however, look to see if there are any non-tagged - * I/Os in progress, and requeue the command if there are. Tagged and - * non-tagged commands cannot be mixed to a single target. + * DMA the SCB from host ram into the current SCB location. */ - -test_busy: - mov FUNCTION1,SCB_TCL - mov A,FUNCTION1 - test SCB_TCL,0x88 jz test_a /* Id < 8 && A channel */ - - test ACTIVE_B,A jnz requeue - test SCB_CONTROL,TAG_ENB jnz start_scb - /* Mark the current target as busy */ - or ACTIVE_B,A - jmp start_scb - -/* Place the currently active SCB back on the queue for later processing */ -requeue: - mov QINFIFO, SCBPTR - jmp poll_for_work + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + mov RETURN_2 call dma_scb; /* - * Pull the first entry off of the waiting for selection list - * We don't have to "test_busy" because only transactions that - * have passed that test can be in the waiting_scb list. + * Preset the residual fields in case we never go through a data phase. + * This isn't done by the host so we can avoid a DMA to clear these + * fields for the normal case of I/O that completes without underrun + * or overrun conditions. */ -start_waiting: - mov SCBPTR,WAITING_SCBH - jmp start_scb2 - -test_a: - test ACTIVE_A,A jnz requeue - test SCB_CONTROL,TAG_ENB jnz start_scb - /* Mark the current target as busy */ - or ACTIVE_A,A + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, SCB_DATACNT, 3; + } else { + mov SCB_RESID_DCNT[0],SCB_DATACNT[0]; + mov SCB_RESID_DCNT[1],SCB_DATACNT[1]; + mov SCB_RESID_DCNT[2],SCB_DATACNT[2]; + } + mov SCB_RESID_SGCNT, SCB_SGCOUNT; start_scb: - mov SCB_NEXT,WAITING_SCBH - mov WAITING_SCBH, SCBPTR -start_scb2: - and SINDEX,0xf7,SBLKCTL /* Clear the channel select bit */ - and A,0x08,SCB_TCL /* Get new channel bit */ - or SINDEX,A - mov SBLKCTL,SINDEX /* select channel */ - mov SCB_TCL call initialize_scsiid + /* + * Place us on the waiting list in case our selection + * doesn't win during bus arbitration. + */ + mov SCB_NEXT,WAITING_SCBH; + mov WAITING_SCBH, SCBPTR; +start_waiting: + /* + * Pull the first entry off of the waiting SCB list. + */ + mov SCBPTR, WAITING_SCBH; + call start_selection; + jmp poll_for_work; -/* - * Enable selection phase as an initiator, and do automatic ATN - * after the selection. We do this now so that we can overlap the - * rest of our work to set up this target with the arbitration and - * selection bus phases. - */ start_selection: - mvi SCSISEQ,0x58 /* ENSELO|ENAUTOATNO|ENRSELI */ - -/* - * As soon as we get a successful selection, the target should go - * into the message out phase since we have ATN asserted. Prepare - * the message to send. - * - * Messages are stored in scratch RAM starting with a length byte - * followed by the message itself. - */ - -mk_identify: - and A,DISCENB,SCB_CONTROL /* mask off disconnect privledge */ - - and MSG0,0x7,SCB_TCL /* lun */ - or MSG0,A /* or in disconnect privledge */ - or MSG0,MSG_IDENTIFYFLAG - mvi MSG_LEN, 1 - -/* - * Send a tag message if TAG_ENB is set in the SCB control block. - * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. - */ -mk_tag: - test SCB_CONTROL,TAG_ENB jz mk_message - mvi DINDEX, MSG1 - and DINDIR,0x23,SCB_CONTROL - mov DINDIR,SCB_TAG - - add MSG_LEN,COMP_MSG0,DINDEX /* update message length */ - + if ((ahc->features & AHC_TWIN) != 0) { + and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ + and A,SELBUSB,SCB_TCL; /* Get new channel bit */ + or SINDEX,A; + mov SBLKCTL,SINDEX; /* select channel */ + } +initialize_scsiid: + mov SINDEX, SCSISEQ_TEMPLATE; + if ((ahc->flags & AHC_TARGETMODE) != 0) { + test SCB_CONTROL, TARGET_SCB jz . + 4; + if ((ahc->features & AHC_ULTRA2) != 0) { + mov SCSIID_ULTRA2, SCB_CMDPTR[2]; + } else { + mov SCSIID, SCB_CMDPTR[2]; + } + or SINDEX, TEMODE; + jmp initialize_scsiid_fini; + } + if ((ahc->features & AHC_ULTRA2) != 0) { + and A, TID, SCB_TCL; /* Get target ID */ + and SCSIID_ULTRA2, OID; /* Clear old target */ + or SCSIID_ULTRA2, A; + } else { + and A, TID, SCB_TCL; /* Get target ID */ + and SCSIID, OID; /* Clear old target */ + or SCSIID, A; + } +initialize_scsiid_fini: + mov SCSISEQ, SINDEX ret; + +/* + * Initialize transfer settings and clear the SCSI channel. + * SINDEX should contain any additional bit's the client wants + * set in SXFRCTL0. We also assume that the current SCB is + * a valid SCB for the target we wish to talk to. + */ +initialize_channel: + or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; +set_transfer_settings: + if ((ahc->features & AHC_ULTRA) != 0) { + test SCB_CONTROL, ULTRAENB jz . + 2; + or SXFRCTL0, FAST20; + } /* - * Interrupt the driver, and allow it to tweak the message buffer - * if it asks. + * Initialize SCSIRATE with the appropriate value for this target. */ -mk_message: - test SCB_CONTROL,MK_MESSAGE jz wait_for_selection - - mvi INTSTAT,AWAITING_MSG - -wait_for_selection: - test SSTAT0,SELDO jnz select - test SSTAT0,SELDI jz wait_for_selection - + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov SCSIRATE, SCB_SCSIRATE, 2 ret; + } else { + mov SCSIRATE, SCB_SCSIRATE ret; + } + +selection: + test SSTAT0,SELDO jnz select_out; + mvi CLRSINT0, CLRSELDI; +select_in: + if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->flags & AHC_INITIATORMODE) != 0) { + test SSTAT0, TARGET jz initiator_reselect; + } + + /* + * We've just been selected. Assert BSY and + * setup the phase for receiving messages + * from the target. + */ + mvi SCSISIGO, P_MESGOUT|BSYO; + mvi CLRSINT1, CLRBUSFREE; + + /* + * Setup the DMA for sending the identify and + * command information. + */ + or SEQ_FLAGS, CMDPHASE_PENDING; + + mov A, TQINPOS; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi TMODE_CMDADDR call set_32byte_addr; + mvi CCSCBCTL, CCSCBRESET; + } else { + mvi DINDEX, HADDR; + mvi TMODE_CMDADDR call set_32byte_addr; + mvi DFCNTRL, FIFORESET; + } + + /* Initiator that selected us */ + and SAVED_TCL, SELID_MASK, SELID; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, SAVED_TCL; + } else { + mov DFDAT, SAVED_TCL; + } + + /* The Target ID we were selected at */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + if ((ahc->features & AHC_MULTI_TID) != 0) { + and CCSCBRAM, OID, TARGIDIN; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + and CCSCBRAM, OID, SCSIID_ULTRA2; + } else { + and CCSCBRAM, OID, SCSIID; + } + } else { + if ((ahc->features & AHC_MULTI_TID) != 0) { + and DFDAT, OID, TARGIDIN; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + and DFDAT, OID, SCSIID_ULTRA2; + } else { + and DFDAT, OID, SCSIID; + } + } + + /* No tag yet */ + mvi INITIATOR_TAG, SCB_LIST_NULL; + + /* + * If ATN isn't asserted, the target isn't interested + * in talking to us. Go directly to bus free. + */ + test SCSISIGI, ATNI jz target_busfree; + + /* + * Watch ATN closely now as we pull in messages from the + * initiator. We follow the guidlines from section 6.5 + * of the SCSI-2 spec for what messages are allowed when. + */ + call target_inb; + + /* + * Our first message must be one of IDENTIFY, ABORT, or + * BUS_DEVICE_RESET. + */ + /* XXX May need to be more lax here for older initiators... */ + test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; + /* Store for host */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, DINDEX; + } else { + mov DFDAT, DINDEX; + } + + /* Remember for disconnection decision */ + test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; + /* XXX Honor per target settings too */ + or SEQ_FLAGS, NO_DISCONNECT; + + test SCSISIGI, ATNI jz ident_messages_done; + call target_inb; + /* + * If this is a tagged request, the tagged message must + * immediately follow the identify. We test for a valid + * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and + * < MSG_IGN_WIDE_RESIDUE. + */ + add A, -MSG_SIMPLE_Q_TAG, DINDEX; + jnc ident_messages_done; + add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; + jc ident_messages_done; + /* Store for host */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, DINDEX; + } else { + mov DFDAT, DINDEX; + } + + /* + * If the initiator doesn't feel like providing a tag number, + * we've got a failed selection and must transition to bus + * free. + */ + test SCSISIGI, ATNI jz target_busfree; + + /* + * Store the tag for the host. + */ + call target_inb; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, DINDEX; + } else { + mov DFDAT, DINDEX; + } + mov INITIATOR_TAG, DINDEX; + jmp ident_messages_done; + + /* + * Pushed message loop to allow the kernel to + * run it's own target mode message state engine. + */ +host_target_message_loop: + mvi INTSTAT, HOST_MSG_LOOP; + nop; + cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; + test SSTAT0, SPIORDY jz .; + jmp host_target_message_loop; + +ident_messages_done: + /* If ring buffer is full, return busy or queue full */ + mov A, KERNEL_TQINPOS; + cmp TQINPOS, A jne tqinfifo_has_space; + mvi P_STATUS|BSYO call change_phase; + cmp INITIATOR_TAG, SCB_LIST_NULL je . + 3; + mvi STATUS_QUEUE_FULL call target_outb; + jmp target_busfree_wait; + mvi STATUS_BUSY call target_outb; + jmp target_busfree_wait; +tqinfifo_has_space: + /* Terminate the ident list */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mvi CCSCBRAM, SCB_LIST_NULL; + } else { + mvi DFDAT, SCB_LIST_NULL; + } + or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN; + test SCSISIGI, ATNI jnz target_mesgout_pending_msg; + jmp target_ITloop; + +/* + * We carefully toggle SPIOEN to allow us to return the + * message byte we receive so it can be checked prior to + * driving REQ on the bus for the next byte. + */ +target_inb: + /* + * Drive REQ on the bus by enabling SCSI PIO. + */ + or SXFRCTL0, SPIOEN; + /* Wait for the byte */ + test SSTAT0, SPIORDY jz .; + /* Prevent our read from triggering another REQ */ + and SXFRCTL0, ~SPIOEN; + /* Save latched contents */ + mov DINDEX, SCSIDATL ret; + } + +if ((ahc->flags & AHC_INITIATORMODE) != 0) { /* * Reselection has been initiated by a target. Make a note that we've been - * reselected, but haven't seen an IDENTIFY message from the target - * yet. - */ -reselect: - clr MSG_LEN /* Don't have anything in the mesg buffer */ - mov SELID call initialize_scsiid - or FLAGS,RESELECTED - jmp select2 + * reselected, but haven't seen an IDENTIFY message from the target yet. + */ +initiator_reselect: + /* XXX test for and handle ONE BIT condition */ + and SAVED_TCL, SELID_MASK, SELID; + if ((ahc->features & AHC_TWIN) != 0) { + test SBLKCTL, SELBUSB jz . + 2; + or SAVED_TCL, SELBUSB; + } + or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; /* + * We aren't expecting a + * bus free, so interrupt + * the kernel driver if it + * happens. + */ + jmp ITloop; +} /* - * After the selection, remove this SCB from the "waiting for selection" + * After the selection, remove this SCB from the "waiting SCB" * list. This is achieved by simply moving our "next" pointer into * WAITING_SCBH. Our next pointer will be set to null the next time this * SCB is used, so don't bother with it now. */ -select: - mov WAITING_SCBH,SCB_NEXT - or FLAGS,SELECTED -select2: -/* - * Set CLRCHN here before the target has entered a data transfer mode - - * with synchronous SCSI, if you do it later, you blow away some - * data in the SCSI FIFO that the target has already sent to you. - */ - or SXFRCTL0,CLRCHN -/* - * Initialize SCSIRATE with the appropriate value for this target. - */ - call ndx_dtr - mov SCSIRATE,SINDIR +select_out: + /* Turn off the selection hardware */ + and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP,SCSISEQ_TEMPLATE; + mvi CLRSINT0, CLRSELDO; + mov SCBPTR, WAITING_SCBH; + mov WAITING_SCBH,SCB_NEXT; + mov SAVED_TCL, SCB_TCL; + if ((ahc->flags & AHC_TARGETMODE) != 0) { + test SSTAT0, TARGET jz initiator_select; + + /* + * We've just re-selected an initiator. + * Assert BSY and setup the phase for + * sending our identify messages. + */ + mvi P_MESGIN|BSYO call change_phase; + mvi CLRSINT1,CLRBUSFREE; + + /* + * Start out with a simple identify message. + */ + and A, LID, SCB_TCL; + or A, MSG_IDENTIFYFLAG call target_outb; + + /* + * If we are the result of a tagged command, send + * a simple Q tag and the tag id. + */ + test SCB_CONTROL, TAG_ENB jz . + 3; + mvi MSG_SIMPLE_Q_TAG call target_outb; + mov SCB_INITIATOR_TAG call target_outb; + mov INITIATOR_TAG, SCB_INITIATOR_TAG; +target_synccmd: + /* + * Now determine what phases the host wants us + * to go through. + */ + mov SEQ_FLAGS, SCB_TARGET_PHASES; + + +target_ITloop: + /* + * Start honoring ATN signals now that + * we properly identified ourselves. + */ + test SCSISIGI, ATNI jnz target_mesgout; + test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; + test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; + test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; + + /* + * No more work to do. Either disconnect or not depending + * on the state of NO_DISCONNECT. + */ + test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } + mov RETURN_1, ALLZEROS; + call complete_target_cmd; + cmp RETURN_1, CONT_MSG_LOOP jne .; + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + mov SCB_TAG call dma_scb; + jmp target_synccmd; + +target_mesgout: + mvi SCSISIGO, P_MESGOUT|BSYO; + call target_inb; + /* Local Processing goes here... */ +target_mesgout_pending_msg: + jmp host_target_message_loop; + +target_disconnect: + mvi P_MESGIN|BSYO call change_phase; + test SEQ_FLAGS, DPHASE jz . + 2; + mvi MSG_SAVEDATAPOINTER call target_outb; + mvi MSG_DISCONNECT call target_outb; + +target_busfree_wait: + /* Wait for preceeding I/O session to complete. */ + test SCSISIGI, ACKI jnz .; +target_busfree: + clr SCSISIGO; + mvi LASTPHASE, P_BUSFREE; + call complete_target_cmd; + jmp poll_for_work; + +target_cmdphase: + mvi P_COMMAND|BSYO call change_phase; + call target_inb; + mov A, DINDEX; + /* Store for host */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, A; + } else { + mov DFDAT, A; + } + + /* + * Determine the number of bytes to read + * based on the command group code via table lookup. + * We reuse the first 8 bytes of the TARG_SCSIRATE + * BIOS array for this table. Count is one less than + * the total for the command since we've already fetched + * the first byte. + */ + shr A, CMD_GROUP_CODE_SHIFT; + add SINDEX, TARG_SCSIRATE, A; + mov A, SINDIR; + + test A, 0xFF jz command_phase_done; +command_loop: + or SXFRCTL0, SPIOEN; + test SSTAT0, SPIORDY jz .; + cmp A, 1 jne . + 2; + and SXFRCTL0, ~SPIOEN; /* Last Byte */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, SCSIDATL; + } else { + mov DFDAT, SCSIDATL; + } + dec A; + test A, 0xFF jnz command_loop; + +command_phase_done: + and SEQ_FLAGS, ~CMDPHASE_PENDING; + jmp target_ITloop; + +target_dphase: + /* + * Data direction flags are from the + * perspective of the initiator. + */ + test SCB_TARGET_PHASES[1], TARGET_DATA_IN jz . + 4; + mvi LASTPHASE, P_DATAOUT; + mvi P_DATAIN|BSYO call change_phase; + jmp . + 3; + mvi LASTPHASE, P_DATAIN; + mvi P_DATAOUT|BSYO call change_phase; + mov ALLZEROS call initialize_channel; + jmp p_data; + +target_sphase: + mvi P_STATUS|BSYO call change_phase; + mvi LASTPHASE, P_STATUS; + mov SCB_TARGET_STATUS call target_outb; + /* XXX Watch for ATN or parity errors??? */ + mvi SCSISIGO, P_MESGIN|BSYO; + /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ + mov ALLZEROS call target_outb; + jmp target_busfree_wait; + +complete_target_cmd: + test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; + mov SCB_TAG jmp complete_post; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Set the valid byte */ + mvi CCSCBADDR, 24; + mov CCSCBRAM, ALLONES; + mvi CCHCNT, 28; + or CCSCBCTL, CCSCBEN|CCSCBRESET; + test CCSCBCTL, CCSCBDONE jz .; + clr CCSCBCTL; + } else { + /* Set the valid byte */ + or DFCNTRL, FIFORESET; + mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ + mov DFDAT, ALLONES; + mvi HCNT[0], 28; + clr HCNT[1]; + clr HCNT[2]; + or DFCNTRL, HDMAEN|FIFOFLUSH; + call dma_finish; + } + inc TQINPOS; + mvi INTSTAT,CMDCMPLT ret; + } + +if ((ahc->flags & AHC_INITIATORMODE) != 0) { +initiator_select: + mvi SPIOEN call initialize_channel; -/* - * Initialize Ultra mode setting. - */ - mov FUNCTION1,SCSIID - mov A,FUNCTION1 - and SINDEX,0xdf,SXFRCTL0 /* default to Ultra disabled */ - test SCSIID, 0x80 jnz ultra_b /* Target ID > 7 */ - test SBLKCTL, SELBUSB jnz ultra_b /* Second channel device */ - test ULTRA_ENB,A jz set_sxfrctl0 - or SINDEX, ULTRAEN jmp set_sxfrctl0 -ultra_b: - test ULTRA_ENB_B,A jz set_sxfrctl0 - or SINDEX, ULTRAEN - -set_sxfrctl0: - mov SXFRCTL0,SINDEX - - mvi SCSISEQ,ENAUTOATNP /* - * ATN on parity errors - * for "in" phases - */ - mvi CLRSINT1,CLRBUSFREE - mvi CLRSINT0,0x60 /* CLRSELDI|CLRSELDO */ -/* - * Main loop for information transfer phases. If BSY is false, then - * we have a bus free condition, expected or not. Otherwise, wait - * for the target to assert REQ before checking MSG, C/D and I/O - * for the bus phase. - * - */ + /* + * We aren't expecting a bus free, so interrupt + * the kernel driver if it happens. + */ + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; + + /* + * As soon as we get a successful selection, the target + * should go into the message out phase since we have ATN + * asserted. + */ + mvi MSG_OUT, MSG_IDENTIFYFLAG; + or SEQ_FLAGS, IDENTIFY_SEEN; + + /* + * Main loop for information transfer phases. Wait for the + * target to assert REQ before checking MSG, C/D and I/O for + * the bus phase. + */ ITloop: - test SSTAT1,BUSFREE jnz p_busfree - test SSTAT1,REQINIT jz ITloop - - and A,PHASE_MASK,SCSISIGI - mov LASTPHASE,A - mov SCSISIGO,A - - cmp ALLZEROS,A je p_dataout - cmp A,P_DATAIN je p_datain - cmp A,P_COMMAND je p_command - cmp A,P_MESGOUT je p_mesgout - cmp A,P_STATUS je p_status - cmp A,P_MESGIN je p_mesgin - - mvi INTSTAT,BAD_PHASE /* unknown phase - signal driver */ - jmp ITloop /* Try reading the bus again. */ - -p_dataout: - mvi DMAPARAMS,0x7d /* - * WIDEODD|SCSIEN|SDMAEN|HDMAEN| - * DIRECTION|FIFORESET - */ - jmp data_phase_init + call phase_lock; + + mov A, LASTPHASE; + + test A, ~P_DATAIN jz p_data; + cmp A,P_COMMAND je p_command; + cmp A,P_MESGOUT je p_mesgout; + cmp A,P_STATUS je p_status; + cmp A,P_MESGIN je p_mesgin; + + mvi INTSTAT,BAD_PHASE; + jmp ITloop; /* Try reading the bus again. */ + +await_busfree: + and SIMODE1, ~ENBUSFREE; + mov NONE, SCSIDATL; /* Ack the last byte */ + and SXFRCTL0, ~SPIOEN; + test SSTAT1,REQINIT|BUSFREE jz .; + test SSTAT1, BUSFREE jnz poll_for_work; + mvi INTSTAT, BAD_PHASE; +} + +clear_target_state: + /* + * We assume that the kernel driver may reset us + * at any time, even in the middle of a DMA, so + * clear DFCNTRL too. + */ + clr DFCNTRL; + + /* + * We don't know the target we will connect to, + * so default to narrow transfers to avoid + * parity problems. + */ + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov SCSIRATE, ALLZEROS, 2; + } else { + clr SCSIRATE; + and SXFRCTL0, ~(FAST20); + } + mvi LASTPHASE, P_BUSFREE; + /* clear target specific flags */ + clr SEQ_FLAGS ret; /* * If we re-enter the data phase after going through another phase, the * STCNT may have been cleared, so restore it from the residual field. */ data_phase_reinit: - mov STCNT0,SCB_RESID_DCNT0 - mov STCNT1,SCB_RESID_DCNT1 - mov STCNT2,SCB_RESID_DCNT2 - jmp data_phase_loop - -p_datain: - mvi DMAPARAMS,0x79 /* - * WIDEODD|SCSIEN|SDMAEN|HDMAEN| - * !DIRECTION|FIFORESET + if ((ahc->features & AHC_ULTRA2) != 0) { + /* + * The preload circuitry requires us to + * reload the address too, so pull it from + * the shaddow address. + */ + bmov HADDR, SHADDR, 4; + bmov HCNT, SCB_RESID_DCNT, 3; + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT, SCB_RESID_DCNT, 3; + } else { + mvi DINDEX, STCNT; + mvi SCB_RESID_DCNT call bcopy_3; + } + and DATA_COUNT_ODD, 0x1, SCB_RESID_DCNT[0]; + jmp data_phase_loop; + +p_data: + if ((ahc->features & AHC_ULTRA2) != 0) { + mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; + } else { + mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; + } + test LASTPHASE, IOI jnz . + 2; + or DMAPARAMS, DIRECTION; + call assert; /* + * Ensure entering a data + * phase is okay - seen identify, etc. */ -data_phase_init: - call assert + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mvi CCSGADDR, CCSGADDR_MAX; + } + test SEQ_FLAGS, DPHASE jnz data_phase_reinit; + + /* We have seen a data phase */ + or SEQ_FLAGS, DPHASE; - test FLAGS, DPHASE jnz data_phase_reinit - call sg_scb2ram - or FLAGS, DPHASE /* We have seen a data phase */ + /* + * Initialize the DMA address and counter from the SCB. + * Also set SG_COUNT and SG_NEXT in memory since we cannot + * modify the values in the SCB itself until we see a + * save data pointers message. + */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov HADDR, SCB_DATAPTR, 7; + } else { + mvi DINDEX, HADDR; + mvi SCB_DATAPTR call bcopy_7; + } + and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0]; + + if ((ahc->features & AHC_ULTRA2) == 0) { + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT, HCNT, 3; + } else { + call set_stcnt_from_hcnt; + } + } + + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov SG_COUNT, SCB_SGCOUNT, 5; + } else { + mvi DINDEX, SG_COUNT; + mvi SCB_SGCOUNT call bcopy_5; + } data_phase_loop: /* Guard against overruns */ - test SG_COUNT, 0xff jnz data_phase_inbounds + test SG_COUNT, 0xff jnz data_phase_inbounds; /* * Turn on 'Bit Bucket' mode, set the transfer count to * 16meg and let the target run until it changes phase. * When the transfer completes, notify the host that we * had an overrun. */ - or SXFRCTL1,BITBUCKET - mvi STCNT0,0xff - mvi STCNT1,0xff - mvi STCNT2,0xff - + or SXFRCTL1,BITBUCKET; + and DMAPARAMS, ~(HDMAEN|SDMAEN); + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov HCNT, ALLONES, 3; + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT, ALLONES, 3; + } else { + mvi STCNT[0], 0xFF; + mvi STCNT[1], 0xFF; + mvi STCNT[2], 0xFF; + } data_phase_inbounds: -/* If we are the last SG block, don't set wideodd. */ - cmp SG_COUNT,0x01 jne data_phase_wideodd - and DMAPARAMS, 0xbf /* Turn off WIDEODD */ +/* If we are the last SG block, tell the hardware. */ + cmp SG_COUNT,0x01 jne data_phase_wideodd; + if ((ahc->features & AHC_ULTRA2) != 0) { + or SG_CACHEPTR, LAST_SEG; + } else { + if ((ahc->flags & AHC_TARGETMODE) != 0) { + test SSTAT0, TARGET jz . + 2; + test DMAPARAMS, DIRECTION jz data_phase_wideodd; + } + and DMAPARAMS, ~WIDEODD; + } data_phase_wideodd: - mov DMAPARAMS call dma - + if ((ahc->features & AHC_ULTRA2) != 0) { + mov SINDEX, ALLONES; + mov DFCNTRL, DMAPARAMS; + test SSTAT0, SDONE jnz .;/* Wait for preload to complete */ +data_phase_dma_loop: + test SSTAT0, SDONE jnz data_phase_dma_done; + test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ + } else { + mov DMAPARAMS call dma; + } + +data_phase_dma_done: /* Go tell the host about any overruns */ - test SXFRCTL1,BITBUCKET jnz data_phase_overrun + test SXFRCTL1,BITBUCKET jnz data_phase_overrun; -/* Exit if we had an underrun */ - test SSTAT0,SDONE jz data_phase_finish /* underrun STCNT != 0 */ +/* See if we completed this segment */ + test STCNT[0], 0xff jnz data_phase_finish; + test STCNT[1], 0xff jnz data_phase_finish; + test STCNT[2], 0xff jnz data_phase_finish; /* * Advance the scatter-gather pointers if needed */ sg_advance: - dec SG_COUNT /* one less segment to go */ - - test SG_COUNT, 0xff jz data_phase_finish /* Are we done? */ - - clr A /* add sizeof(struct scatter) */ - add SG_NEXT0,SG_SIZEOF,SG_NEXT0 - adc SG_NEXT1,A,SG_NEXT1 + dec SG_COUNT; /* one less segment to go */ + test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ /* * Load a struct scatter and set up the data address and length. * If the working value of the SG count is nonzero, then @@ -387,351 +812,475 @@ sg_advance: * This, like all DMA's, assumes little-endian host data storage. */ sg_load: - clr HCNT2 - clr HCNT1 - mvi HCNT0,SG_SIZEOF - - mov HADDR0,SG_NEXT0 - mov HADDR1,SG_NEXT1 - mov HADDR2,SG_NEXT2 - mov HADDR3,SG_NEXT3 - - or DFCNTRL,0xd /* HDMAEN|DIRECTION|FIFORESET */ - -/* - * Wait for DMA from host memory to data FIFO to complete, then disable - * DMA and wait for it to acknowledge that it's off. - */ -dma_finish: - test DFSTATUS,HDONE jz dma_finish - /* Turn off DMA preserving WIDEODD */ - and DFCNTRL,WIDEODD -dma_finish2: - test DFCNTRL,HDMAENACK jnz dma_finish2 - -/* - * Copy data from FIFO into SCB data pointer and data count. This assumes - * that the struct scatterlist has this structure (this and sizeof(struct - * scatterlist) == 12 are asserted in aic7xxx.c for the Linux driver): - * - * struct scatterlist { - * char *address; four bytes, little-endian order - * ... four bytes, ignored - * unsigned short length; two bytes, little-endian order - * } - * - * - * In FreeBSD, the scatter list entry is only 8 bytes. - * - * struct ahc_dma_seg { - * physaddr addr; four bytes, little-endian order - * long len; four bytes, little endian order - * }; - */ - - mov HADDR0,DFDAT - mov HADDR1,DFDAT - mov HADDR2,DFDAT - mov HADDR3,DFDAT -/* - * For Linux, we must throw away four bytes since there is a 32bit gap - * in the middle of a struct scatterlist. - */ -#ifdef __linux__ - mov NONE,DFDAT - mov NONE,DFDAT - mov NONE,DFDAT - mov NONE,DFDAT -#endif - mov HCNT0,DFDAT - mov HCNT1,DFDAT - mov HCNT2,DFDAT - -/* Load STCNT as well. It is a mirror of HCNT */ - mov STCNT0,HCNT0 - mov STCNT1,HCNT1 - mov STCNT2,HCNT2 - test SSTAT1,PHASEMIS jz data_phase_loop + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* + * Do we have any prefetch left??? + */ + cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; + + /* + * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. + */ + add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; + mvi A, CCSGADDR_MAX; + jc . + 2; + shl A, 3, SG_COUNT; + mov CCHCNT, A; + bmov CCHADDR, SG_NEXT, 4; + mvi CCSGCTL, CCSGEN|CCSGRESET; + test CCSGCTL, CCSGDONE jz .; + and CCSGCTL, ~CCSGEN; + test CCSGCTL, CCSGEN jnz .; + mvi CCSGCTL, CCSGRESET; +prefetched_segs_avail: + bmov HADDR, CCSGRAM, 8; + } else { + mvi DINDEX, HADDR; + mvi SG_NEXT call bcopy_4; + + mvi HCNT[0],SG_SIZEOF; + clr HCNT[1]; + clr HCNT[2]; + + or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; + + call dma_finish; + + /* + * Copy data from FIFO into SCB data pointer and data count. + * This assumes that the SG segments are of the form: + * struct ahc_dma_seg { + * u_int32_t addr; four bytes, little-endian order + * u_int32_t len; four bytes, little endian order + * }; + */ + mvi HADDR call dfdat_in_7; + } + + /* Track odd'ness */ + test HCNT[0], 0x1 jz . + 2; + xor DATA_COUNT_ODD, 0x1; + + if ((ahc->features & AHC_ULTRA2) == 0) { + /* Load STCNT as well. It is a mirror of HCNT */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT, HCNT, 3; + } else { + call set_stcnt_from_hcnt; + } + } + +/* Advance the SG pointer */ + clr A; /* add sizeof(struct scatter) */ + add SG_NEXT[0],SG_SIZEOF; + adc SG_NEXT[1],A; + + if ((ahc->flags & AHC_TARGETMODE) != 0) { + test SSTAT0, TARGET jnz data_phase_loop; + } + test SSTAT1, REQINIT jz .; + test SSTAT1,PHASEMIS jz data_phase_loop; + + /* Ensure the last seg is visable at the shaddow layer */ + if ((ahc->features & AHC_ULTRA2) != 0) { + mov DFCNTRL, DMAPARAMS; + test SSTAT0, SDONE jnz .;/* Wait for preload to complete */ + } data_phase_finish: + if ((ahc->features & AHC_ULTRA2) != 0) { + call ultra2_dmafinish; + } /* * After a DMA finishes, save the SG and STCNT residuals back into the SCB * We use STCNT instead of HCNT, since it's a reflection of how many bytes * were transferred on the SCSI (as opposed to the host) bus. */ - mov SCB_RESID_DCNT0,STCNT0 - mov SCB_RESID_DCNT1,STCNT1 - mov SCB_RESID_DCNT2,STCNT2 - mov SCB_RESID_SGCNT, SG_COUNT - jmp ITloop + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, STCNT, 3; + } else { + mov SCB_RESID_DCNT[0],STCNT[0]; + mov SCB_RESID_DCNT[1],STCNT[1]; + mov SCB_RESID_DCNT[2],STCNT[2]; + } + mov SCB_RESID_SGCNT, SG_COUNT; + + if ((ahc->features & AHC_ULTRA2) != 0) { + or SXFRCTL0, CLRSTCNT|CLRCHN; + } + + if ((ahc->flags & AHC_TARGETMODE) != 0) { + test SEQ_FLAGS, DPHASE_PENDING jz ITloop; + and SEQ_FLAGS, ~DPHASE_PENDING; + /* + * For data-in phases, wait for any pending acks from the + * initiator before changing phase. + */ + test DFCNTRL, DIRECTION jz target_ITloop; + test SSTAT1, REQINIT jnz .; + jmp target_ITloop; + } + jmp ITloop; data_phase_overrun: + if ((ahc->features & AHC_ULTRA2) != 0) { + call ultra2_dmafinish; + or SXFRCTL0, CLRSTCNT|CLRCHN; + } /* * Turn off BITBUCKET mode and notify the host */ - and SXFRCTL1,0x7f /* ~BITBUCKET */ - mvi INTSTAT,DATA_OVERRUN - jmp ITloop - + and SXFRCTL1, ~BITBUCKET; + mvi INTSTAT,DATA_OVERRUN; + jmp ITloop; + +ultra2_dmafinish: + if ((ahc->features & AHC_ULTRA2) != 0) { + test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; + and DFCNTRL, ~SCSIEN; + test DFCNTRL, SCSIEN jnz .; +ultra2_dmafifoflush: + or DFCNTRL, FIFOFLUSH; + /* + * The FIFOEMP status bit on the Ultra2 class + * of controllers seems to be a bit flaky. + * It appears that if the FIFO is full and the + * transfer ends with some data in the REQ/ACK + * FIFO, FIFOEMP will fall temporarily + * as the data is transferred to the PCI bus. + * This glitch lasts for fewer than 5 clock cycles, + * so we work around the problem by ensuring the + * status bit stays false through a full glitch + * window. + */ + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + +ultra2_dmafifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; + +ultra2_dmahalt: + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, HDMAEN jnz .; + ret; + } + +if ((ahc->flags & AHC_INITIATORMODE) != 0) { /* * Command phase. Set up the DMA registers and let 'er rip. */ p_command: - call assert - -/* - * Load HADDR and HCNT. - */ - mov HADDR0, SCB_CMDPTR0 - mov HADDR1, SCB_CMDPTR1 - mov HADDR2, SCB_CMDPTR2 - mov HADDR3, SCB_CMDPTR3 - mov HCNT0, SCB_CMDLEN - clr HCNT1 - clr HCNT2 - - mov STCNT0, HCNT0 - mov STCNT1, HCNT1 - mov STCNT2, HCNT2 - - mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN| - # DIRECTION|FIFORESET - jmp ITloop + call assert; + + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov HCNT[0], SCB_CMDLEN; + bmov HCNT[1], ALLZEROS, 2; + if ((ahc->features & AHC_ULTRA2) == 0) { + bmov STCNT, HCNT, 3; + } + add NONE, -17, SCB_CMDLEN; + jc dma_cmd_data; + /* + * The data fifo seems to require 4 byte alligned + * transfers from the sequencer. Force this to + * be the case by clearing HADDR[0] even though + * we aren't going to touch host memeory. + */ + bmov HADDR[0], ALLZEROS, 1; + if ((ahc->features & AHC_ULTRA2) != 0) { + mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); + } else { + mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); + } + bmov DFDAT, SCB_CMDSTORE, 16; + jmp cmd_loop; +dma_cmd_data: + bmov HADDR, SCB_CMDPTR, 4; + } else { + mvi DINDEX, HADDR; + mvi SCB_CMDPTR call bcopy_5; + clr HCNT[1]; + clr HCNT[2]; + } + + if ((ahc->features & AHC_ULTRA2) == 0) { + if ((ahc->features & AHC_CMD_CHAN) == 0) { + call set_stcnt_from_hcnt; + } + mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); + } else { + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); + } +cmd_loop: + test SSTAT0, SDONE jnz . + 2; + test SSTAT1, PHASEMIS jz cmd_loop; + /* + * Wait for our ACK to go-away on it's own + * instead of being killed by SCSIEN getting cleared. + */ + test SCSISIGI, ACKI jnz .; + and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); + test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; + jmp ITloop; /* * Status phase. Wait for the data byte to appear, then read it * and store it into the SCB. */ p_status: - mvi SCB_TARGET_STATUS call inb_first - jmp mesgin_done + call assert; + + mov SCB_TARGET_STATUS, SCSIDATL; + jmp ITloop; /* - * Message out phase. If there is not an active message, but the target - * took us into this phase anyway, build a no-op message and send it. + * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full + * indentify message sequence and send it to the target. The host may + * override this behavior by setting the MK_MESSAGE bit in the SCB + * control byte. This will cause us to interrupt the host and allow + * it to handle the message phase completely on its own. If the bit + * associated with this target is set, we will also interrupt the host, + * thereby allowing it to send a message on the next selection regardless + * of the transaction being sent. + * + * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. + * This is done to allow the host to send messages outside of an identify + * sequence while protecting the seqencer from testing the MK_MESSAGE bit + * on an SCB that might not be for the current nexus. (For example, a + * BDR message in responce to a bad reselection would leave us pointed to + * an SCB that doesn't have anything to do with the current target). + * + * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, + * bus device reset). + * + * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, + * in case the target decides to put us in this phase for some strange + * reason. */ +p_mesgout_retry: + or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ p_mesgout: - test MSG_LEN, 0xff jnz p_mesgout_start - mvi MSG_NOOP call mk_mesg /* build NOP message */ - -p_mesgout_start: + mov SINDEX, MSG_OUT; + cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; + test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; + mov FUNCTION1, SCB_TCL; + mov A, FUNCTION1; + if ((ahc->features & AHC_HS_MAILBOX) != 0) { + /* + * Work around a pausing bug in at least the aic7890. + * If the host needs to update the TARGET_MSG_REQUEST + * bit field, it will set the HS_MAILBOX to 1. In + * response, we pause with a specific interrupt code + * asking for the mask to be updated before we continue. + * Ugh. + */ + test HS_MAILBOX, 0xF0 jz . + 2; + mvi INTSTAT, UPDATE_TMSG_REQ; + nop; + } + mov SINDEX, TARGET_MSG_REQUEST[0]; + if ((ahc->features & AHC_TWIN) != 0) { + /* Second Channel uses high byte bits */ + test SCB_TCL, SELBUSB jz . + 2; + mov SINDEX, TARGET_MSG_REQUEST[1]; + } else if ((ahc->features & AHC_WIDE) != 0) { + test SCB_TCL, 0x80 jz . + 2; /* target > 7 */ + mov SINDEX, TARGET_MSG_REQUEST[1]; + } + test SINDEX, A jnz host_message_loop; +p_mesgout_identify: + and SINDEX,LID,SCB_TCL; /* lun */ + and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ + or SINDEX,A; /* or in disconnect privledge */ + or SINDEX,MSG_IDENTIFYFLAG; /* - * Set up automatic PIO transfer from MSG0. Bit 3 in - * SXFRCTL0 (SPIOEN) is already on. + * Send a tag message if TAG_ENB is set in the SCB control block. + * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. */ - mvi SINDEX,MSG0 - mov DINDEX,MSG_LEN - +p_mesgout_tag: + test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; + mov SCSIDATL, SINDEX; /* Send the identify message */ + call phase_lock; + cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; + and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; + call phase_lock; + cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; + mov SCB_TAG jmp p_mesgout_onebyte; /* - * When target asks for a byte, drop ATN if it's the last one in - * the message. Otherwise, keep going until the message is exhausted. - * - * Keep an eye out for a phase change, in case the target issues - * a MESSAGE REJECT. + * Interrupt the driver, and allow it to handle this message + * phase and any required retries. */ -p_mesgout_loop: - test SSTAT1,PHASEMIS jnz p_mesgout_phasemis - test SSTAT0,SPIORDY jz p_mesgout_loop - test SSTAT1,PHASEMIS jnz p_mesgout_phasemis - cmp DINDEX,1 jne p_mesgout_outb /* last byte? */ - mvi CLRSINT1,CLRATNO /* drop ATN */ -p_mesgout_outb: - dec DINDEX - or CLRSINT0, CLRSPIORDY - mov SCSIDATL,SINDIR - -p_mesgout4: - test DINDEX,0xff jnz p_mesgout_loop +p_mesgout_from_host: + cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; + jmp host_message_loop; + +p_mesgout_onebyte: + mvi CLRSINT1, CLRATNO; + mov SCSIDATL, SINDEX; /* - * If the next bus phase after ATN drops is a message out, it means + * If the next bus phase after ATN drops is message out, it means * that the target is requesting that the last message(s) be resent. */ -p_mesgout_snoop: - test SSTAT1,BUSFREE jnz p_mesgout_done - test SSTAT1,REQINIT jz p_mesgout_snoop - - test SSTAT1,PHASEMIS jnz p_mesgout_done - - or SCSISIGO,ATNO /* turn on ATNO */ + call phase_lock; + cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; - jmp ITloop - -p_mesgout_phasemis: - mvi CLRSINT1,CLRATNO /* Be sure to turn ATNO off */ p_mesgout_done: - clr MSG_LEN /* no active msg */ - jmp ITloop + mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ + mov LAST_MSG, MSG_OUT; + mvi MSG_OUT, MSG_NOOP; /* No message left */ + jmp ITloop; /* * Message in phase. Bytes are read using Automatic PIO mode. */ p_mesgin: - mvi A call inb_first /* read the 1st message byte */ - mov REJBYTE,A /* save it for the driver */ - - test A,MSG_IDENTIFYFLAG jnz mesgin_identify - cmp A,MSG_DISCONNECT je mesgin_disconnect - cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs - cmp ALLZEROS,A je mesgin_complete - cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs - cmp A,MSG_EXTENDED je mesgin_extended - cmp A,MSG_MESSAGE_REJECT je mesgin_reject - -rej_mesgin: -/* - * We have no idea what this message in is, and there's no way - * to pass it up to the kernel, so we issue a message reject and - * hope for the best. Since we're now using manual PIO mode to - * read in the message, there should no longer be a race condition - * present when we assert ATN. In any case, rejection should be a - * rare occurrence - signal the driver when it happens. - */ - or SCSISIGO,ATNO /* turn on ATNO */ - mvi INTSTAT,SEND_REJECT /* let driver know */ - - mvi MSG_MESSAGE_REJECT call mk_mesg + mvi ACCUM call inb_first; /* read the 1st message byte */ + + test A,MSG_IDENTIFYFLAG jnz mesgin_identify; + cmp A,MSG_DISCONNECT je mesgin_disconnect; + cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; + cmp ALLZEROS,A je mesgin_complete; + cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; + cmp A,MSG_NOOP je mesgin_done; + +/* + * Pushed message loop to allow the kernel to + * run it's own message state engine. To avoid an + * extra nop instruction after signaling the kernel, + * we perform the phase_lock before checking to see + * if we should exit the loop and skip the phase_lock + * in the ITloop. Performing back to back phase_locks + * shouldn't hurt, but why do it twice... + */ +host_message_loop: + mvi INTSTAT, HOST_MSG_LOOP; + call phase_lock; + cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; + jmp host_message_loop; mesgin_done: - call inb_last /*ack & turn auto PIO back on*/ - jmp ITloop + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + jmp ITloop; mesgin_complete: /* - * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT, - * and trigger a completion interrupt. Check status for non zero return - * and interrupt driver if needed. This allows the driver to interpret - * errors only when they occur instead of always uploading the scb. If - * the status is SCSI_CHECK, the driver will download a new scb requesting - * sense to replace the old one, modify the "waiting for selection" SCB list - * and set RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE the - * sequencer imediately jumps to main loop where it will run down the waiting - * SCB list and process the sense request. If the kernel driver does not - * wish to request sense, it need only clear RETURN_1, and the command is - * allowed to complete. We don't bother to post to the QOUTFIFO in the - * error case since it would require extra work in the kernel driver to - * ensure that the entry was removed before the command complete code tried - * processing it. - * - * First check for residuals + * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, + * and trigger a completion interrupt. Before doing so, check to see if there + * is a residual or the status byte is something other than STATUS_GOOD (0). + * In either of these conditions, we upload the SCB back to the host so it can + * process this information. In the case of a non zero status byte, we + * additionally interrupt the kernel driver synchronously, allowing it to + * decide if sense should be retrieved. If the kernel driver wishes to request + * sense, it will fill the kernel SCB with a request sense command and set + * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload + * the SCB, and process it as the next command by adding it to the waiting list. + * If the kernel driver does not wish to request sense, it need only clear + * RETURN_1, and the command is allowed to complete normally. We don't bother + * to post to the QOUTFIFO in the error cases since it would require extra + * work in the kernel driver to ensure that the entry was removed before the + * command complete code tried processing it. */ - test SCB_RESID_SGCNT,0xff jz check_status -/* - * If we have a residual count, interrupt and tell the host. Other - * alternatives are to pause the sequencer on all command completes (yuck), - * dma the resid directly to the host (slick, we may have space to do it now) - * or have the sequencer pause itself when it encounters a non-zero resid - * (unecessary pause just to flag the command -yuck-, but takes one instruction - * and since it shouldn't happen that often is good enough for our purposes). - */ -resid: - mvi INTSTAT,RESIDUAL -check_status: - test SCB_TARGET_STATUS,0xff jz status_ok /* Good Status? */ - mvi INTSTAT,BAD_STATUS /* let driver know */ - cmp RETURN_1, SEND_SENSE jne status_ok - jmp mesgin_done - -status_ok: -/* First, mark this target as free. */ - test SCB_CONTROL,TAG_ENB jnz test_immediate /* - * Tagged commands - * don't busy the - * target. - */ - mov FUNCTION1,SCB_TCL - mov A,FUNCTION1 - test SCB_TCL,0x88 jz clear_a - xor ACTIVE_B,A - jmp test_immediate - -clear_a: - xor ACTIVE_A,A - -test_immediate: - test SCB_CMDLEN,0xff jnz complete /* Immediate message complete */ /* - * Pause the sequencer until the driver gets around to handling the command - * complete. This is so that any action that might require carefull timing - * with the completion of this command can occur. - */ - mvi INTSTAT,IMMEDDONE - jmp start -complete: - mov QOUTFIFO,SCB_TAG - mvi INTSTAT,CMDCMPLT - jmp mesgin_done - - -/* - * Is it an extended message? Copy the message to our message buffer and - * notify the host. The host will tell us whether to reject this message, - * respond to it with the message that the host placed in our message buffer, - * or simply to do nothing. - */ -mesgin_extended: - mvi MSGIN_EXT_LEN call inb_next - mvi MSGIN_EXT_OPCODE call inb_next - mov A, MSGIN_EXT_LEN - dec A /* Length counts the op code */ - mvi SINDEX, MSGIN_EXT_BYTE0 -mesgin_extended_loop: - test A, 0xFF jz mesgin_extended_intr - cmp SINDEX, MSGIN_EXT_LASTBYTE je mesgin_extended_dump - call inb_next - dec A -/* - * We pass the arg to inb in SINDEX, but DINDEX is the one incremented - * so update SINDEX with DINDEX's value before looping again. + * First check for residuals */ - mov DINDEX jmp mesgin_extended_loop -mesgin_extended_dump: -/* We have no more storage space, so dump the rest */ - test A, 0xFF jz mesgin_extended_intr - mvi NONE call inb_next - dec A - jmp mesgin_extended_dump -mesgin_extended_intr: - mvi INTSTAT,EXTENDED_MSG /* let driver know */ - cmp RETURN_1,SEND_REJ je rej_mesgin - cmp RETURN_1,SEND_MSG jne mesgin_done -/* The kernel has setup a message to be sent */ - or SCSISIGO,ATNO /* turn on ATNO */ - jmp mesgin_done + test SCB_RESID_SGCNT,0xff jnz upload_scb; + test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */ +upload_scb: + mvi DMAPARAMS, FIFORESET; + mov SCB_TAG call dma_scb; +check_status: + test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ + mvi INTSTAT,BAD_STATUS; /* let driver know */ + nop; + cmp RETURN_1, SEND_SENSE jne complete; + /* This SCB becomes the next to execute as it will retrieve sense */ + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + mov SCB_TAG call dma_scb; +add_to_waiting_list: + mov SCB_NEXT,WAITING_SCBH; + mov WAITING_SCBH, SCBPTR; + /* + * Prepare our selection hardware before the busfree so we have a + * high probability of winning arbitration. + */ + call start_selection; + jmp await_busfree; +complete: + /* If we are untagged, clear our address up in host ram */ + test SCB_CONTROL, TAG_ENB jnz complete_queue; + mov A, SAVED_TCL; + /* fvdl - let ahc_intr clear this to avoid race conditions */ + /* mvi UNTAGGEDSCB_OFFSET call post_byte_setup; */ + /* mvi SCB_LIST_NULL call post_byte; */ + +complete_queue: + mov SCB_TAG call complete_post; + jmp await_busfree; +} + +complete_post: + /* Post the SCBID in SINDEX and issue an interrupt */ + call add_scb_to_free_list; + mov ARG_1, SINDEX; + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + mov A, SDSCB_QOFF; + } else { + mov A, QOUTPOS; + } + mvi QOUTFIFO_OFFSET call post_byte_setup; + mov ARG_1 call post_byte; + if ((ahc->features & AHC_QUEUE_REGS) == 0) { + inc QOUTPOS; + } + mvi INTSTAT,CMDCMPLT ret; + +if ((ahc->flags & AHC_INITIATORMODE) != 0) { /* * Is it a disconnect message? Set a flag in the SCB to remind us * and await the bus going free. */ mesgin_disconnect: - or SCB_CONTROL,DISCONNECTED - test FLAGS, PAGESCBS jz mesgin_done -/* - * Link this SCB into the DISCONNECTED list. This list holds the - * candidates for paging out an SCB if one is needed for a new command. - * Modifying the disconnected list is a critical(pause dissabled) section. - */ - mvi SCB_PREV, SCB_LIST_NULL - mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */ - mov SCB_NEXT, DISCONNECTED_SCBH - mov DISCONNECTED_SCBH, SCBPTR - cmp SCB_NEXT,SCB_LIST_NULL je linkdone - mov SCBPTR,SCB_NEXT - mov SCB_PREV,DISCONNECTED_SCBH - mov SCBPTR,DISCONNECTED_SCBH -linkdone: - mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */ - jmp mesgin_done + or SCB_CONTROL,DISCONNECTED; + call add_scb_to_disc_list; + jmp await_busfree; /* - * Save data pointers message? Copy working values into the SCB, - * usually in preparation for a disconnect. + * Save data pointers message: + * Copying RAM values back to SCB, for Save Data Pointers message, but + * only if we've actually been into a data phase to change them. This + * protects against bogus data in scratch ram and the residual counts + * since they are only initialized when we go into data_in or data_out. */ mesgin_sdptrs: - call sg_ram2scb - jmp mesgin_done + test SEQ_FLAGS, DPHASE jz mesgin_done; + + /* + * The SCB SGPTR becomes the next one we'll download, + * and the SCB DATAPTR becomes the current SHADDR. + * Use the residual number since STCNT is corrupted by + * any message transfer. + */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov SCB_SGCOUNT, SG_COUNT, 5; + bmov SCB_DATAPTR, SHADDR, 4; + bmov SCB_DATACNT, SCB_RESID_DCNT, 3; + } else { + mvi DINDEX, SCB_SGCOUNT; + mvi SG_COUNT call bcopy_5; + + mvi DINDEX, SCB_DATAPTR; + mvi SHADDR call bcopy_4; + mvi SCB_RESID_DCNT call bcopy_3; + } + jmp mesgin_done; /* * Restore pointers message? Data pointers are recopied from the @@ -740,11 +1289,12 @@ mesgin_sdptrs: * code do the rest. */ mesgin_rdptrs: - and FLAGS,0xef /* - * !DPHASE we'll reload them + and SEQ_FLAGS, ~DPHASE; /* + * We'll reload them * the next time through + * the dataphase. */ - jmp mesgin_done + jmp mesgin_done; /* * Identify message? For a reconnecting target, this tells us the lun @@ -752,118 +1302,83 @@ mesgin_rdptrs: * clearing the "disconnected" bit so we don't "find" it by accident later. */ mesgin_identify: - test A,0x78 jnz rej_mesgin /*!DiscPriv|!LUNTAR|!Reserved*/ - - and A,0x07 /* lun in lower three bits */ - or SAVED_TCL,A,SELID - and SAVED_TCL,0xf7 - and A,SELBUSB,SBLKCTL /* B Channel?? */ - or SAVED_TCL,A - call inb_last /* ACK */ - + if ((ahc->features & AHC_WIDE) != 0) { + and A,0x0f; /* lun in lower four bits */ + } else { + and A,0x07; /* lun in lower three bits */ + } + or SAVED_TCL,A; /* SAVED_TCL should be complete now */ + + mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ + call get_untagged_SCBID; + cmp ARG_1, SCB_LIST_NULL je snoop_tag; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; + } + /* + * If the SCB was found in the disconnected list (as is + * always the case in non-paging scenarios), SCBPTR is already + * set to the correct SCB. So, simply setup the SCB and get + * on with things. + */ + call rem_scb_from_disc_list; + jmp setup_SCB; /* * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. - * If we get one, we use the tag returned to switch to find the proper - * SCB. With SCB paging, this requires using findSCB for both tagged + * If we get one, we use the tag returned to find the proper + * SCB. With SCB paging, this requires using search for both tagged * and non-tagged transactions since the SCB may exist in any slot. * If we're not using SCB paging, we can use the tag as the direct * index to the SCB. */ - mvi ARG_1,SCB_LIST_NULL /* Default to no-tag */ +snoop_tag: + mov NONE,SCSIDATL; /* ACK Identify MSG */ snoop_tag_loop: - test SSTAT1,BUSFREE jnz use_findSCB - test SSTAT1,REQINIT jz snoop_tag_loop - test SSTAT1,PHASEMIS jnz use_findSCB - mvi A call inb_first - cmp A,MSG_SIMPLE_Q_TAG jne use_findSCB + call phase_lock; + cmp LASTPHASE, P_MESGIN jne not_found; + cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; get_tag: - mvi ARG_1 call inb_next /* tag value */ -/* - * See if the tag is in range. The tag is < SCBCOUNT if we add - * the complement of SCBCOUNT to the incomming tag and there is - * no carry. - */ - mov A,COMP_SCBCOUNT - add SINDEX,A,ARG_1 - jc abort_tag + mvi ARG_1 call inb_next; /* tag value */ -/* - * Ensure that the SCB the tag points to is for an SCB transaction - * to the reconnecting target. - */ - test FLAGS, PAGESCBS jz index_by_tag - call inb_last /* Ack Tag */ -use_findSCB: - mov ALLZEROS call findSCB /* Have to search */ + /* + * Ensure that the SCB the tag points to is for + * an SCB transaction to the reconnecting target. + */ +use_retrieveSCB: + call retrieveSCB; setup_SCB: - and SCB_CONTROL,0xfb /* clear disconnect bit in SCB */ - or FLAGS,IDENTIFY_SEEN /* make note of IDENTIFY */ - jmp ITloop -index_by_tag: - mov SCBPTR,ARG_1 - mov A,SAVED_TCL - cmp SCB_TCL,A jne abort_tag - test SCB_CONTROL,TAG_ENB jz abort_tag - call inb_last /* Ack Successful tag */ - jmp setup_SCB - -abort_tag: - or SCSISIGO,ATNO /* turn on ATNO */ - mvi INTSTAT,ABORT_TAG /* let driver know */ - mvi MSG_ABORT_TAG call mk_mesg /* ABORT TAG message */ - jmp mesgin_done - -/* - * Message reject? Let the kernel driver handle this. If we have an - * outstanding WDTR or SDTR negotiation, assume that it's a response from - * the target selecting 8bit or asynchronous transfer, otherwise just ignore - * it since we have no clue what it pertains to. - */ -mesgin_reject: - mvi INTSTAT, REJECT_MSG - jmp mesgin_done + mov A, SAVED_TCL; + cmp SCB_TCL, A jne not_found_cleanup_scb; + test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; + and SCB_CONTROL,~DISCONNECTED; + or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ + call set_transfer_settings; + /* See if the host wants to send a message upon reconnection */ + test SCB_CONTROL, MK_MESSAGE jz mesgin_done; + and SCB_CONTROL, ~MK_MESSAGE; + mvi HOST_MSG call mk_mesg; + jmp mesgin_done; + +not_found_cleanup_scb: + test SCB_CONTROL, DISCONNECTED jz . + 3; + call add_scb_to_disc_list; + jmp not_found; + call add_scb_to_free_list; +not_found: + mvi INTSTAT, NO_MATCH; + jmp mesgin_done; /* * [ ADD MORE MESSAGE HANDLING HERE ] */ /* - * Bus free phase. It might be useful to interrupt the device - * driver if we aren't expecting this. For now, make sure that - * ATN isn't being asserted and look for a new command. - */ -p_busfree: - mvi CLRSINT1,CLRATNO - clr LASTPHASE - -/* - * if this is an immediate command, perform a psuedo command complete to - * notify the driver. - */ - test SCB_CMDLEN,0xff jz status_ok - jmp start - -/* * Locking the driver out, build a one-byte message passed in SINDEX * if there is no active message already. SINDEX is returned intact. */ mk_mesg: - mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */ - test MSG_LEN,0xff jz mk_mesg1 /* Should always succeed */ - - /* - * Hmmm. For some reason the mesg buffer is in use. - * Tell the driver. It should look at SINDEX to find - * out what we wanted to use the buffer for and resolve - * the conflict. - */ - mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */ - mvi INTSTAT,MSG_BUFFER_BUSY - -mk_mesg1: - mvi MSG_LEN,1 /* length = 1 */ - mov MSG0,SINDEX /* 1-byte message */ - mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */ + or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ + mov MSG_OUT,SINDEX ret; /* * Functions to read data in Automatic PIO mode. @@ -880,26 +1395,75 @@ mk_mesg1: * and that REQ is already set when inb_first is called. inb_{first,next} * use the same calling convention as inb. */ - +inb_next_wait_perr: + mvi INTSTAT, PERR_DETECTED; + jmp inb_next_wait; inb_next: - or CLRSINT0, CLRSPIORDY - mov NONE,SCSIDATL /*dummy read from latch to ACK*/ + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ inb_next_wait: - test SSTAT1,PHASEMIS jnz mesgin_phasemis - test SSTAT0,SPIORDY jz inb_next_wait /* wait for next byte */ + /* + * If there is a parity error, wait for the kernel to + * see the interrupt and prepare our message response + * before continuing. + */ + test SSTAT1, REQINIT jz inb_next_wait; + test SSTAT1, SCSIPERR jnz inb_next_wait_perr; +inb_next_check_phase: + and LASTPHASE, PHASE_MASK, SCSISIGI; + cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; inb_first: - mov DINDEX,SINDEX - test SSTAT1,PHASEMIS jnz mesgin_phasemis - mov DINDIR,SCSIBUSL ret /*read byte directly from bus*/ + mov DINDEX,SINDEX; + mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ inb_last: - mov NONE,SCSIDATL ret /*dummy read from latch to ACK*/ + mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ +} +if ((ahc->flags & AHC_TARGETMODE) != 0) { +/* + * Change to a new phase. If we are changing the state of the I/O signal, + * from out to in, wait an additional data release delay before continuing. + */ +change_phase: + /* Wait for preceeding I/O session to complete. */ + test SCSISIGI, ACKI jnz .; + + /* Change the phase */ + and DINDEX, IOI, SCSISIGI; + mov SCSISIGO, SINDEX; + and A, IOI, SINDEX; + + /* + * If the data direction has changed, from + * out (initiator driving) to in (target driving), + * we must waitat least a data release delay plus + * the normal bus settle delay. [SCSI III SPI 10.11.0] + */ + cmp DINDEX, A je change_phase_wait; + test SINDEX, IOI jz change_phase_wait; + call change_phase_wait; +change_phase_wait: + nop; + nop; + nop; + nop ret; + +/* + * Send a byte to an initiator in Automatic PIO mode. + */ +target_outb: + or SXFRCTL0, SPIOEN; + test SSTAT0, SPIORDY jz .; + mov SCSIDATL, SINDEX; + test SSTAT0, SPIORDY jz .; + and SXFRCTL0, ~SPIOEN ret; +} + mesgin_phasemis: /* * We expected to receive another byte, but the target changed phase */ - mvi INTSTAT, MSGIN_PHASEMIS - jmp ITloop + mvi INTSTAT, MSGIN_PHASEMIS; + jmp ITloop; /* * DMA data transfer. HADDR and HCNT must be loaded first, and @@ -908,10 +1472,11 @@ mesgin_phasemis: * during initialization. */ dma: - mov DFCNTRL,SINDEX -dma1: - test SSTAT0,DMADONE jnz dma3 - test SSTAT1,PHASEMIS jz dma1 /* ie. underrun */ + mov DFCNTRL,SINDEX; +dma_loop: + test SSTAT0,DMADONE jnz dma_dmadone; + test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ +dma_phasemis: /* * We will be "done" DMAing when the transfer count goes to zero, or @@ -921,157 +1486,378 @@ dma1: * magically on STCNT=0 or a phase change, so just wait for FIFO empty * status. */ -dma3: - test SINDEX,DIRECTION jnz dma5 -dma4: - test DFSTATUS,FIFOEMP jz dma4 +dma_checkfifo: + test DFCNTRL,DIRECTION jnz dma_fifoempty; +dma_fifoflush: + test DFSTATUS,FIFOEMP jz dma_fifoflush; +dma_fifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz dma_fifoempty; /* * Now shut the DMA enables off and make sure that the DMA enables are * actually off first lest we get an ILLSADDR. */ -dma5: - /* disable DMA, but maintain WIDEODD */ - and DFCNTRL,WIDEODD -dma6: - test DFCNTRL,0x38 jnz dma6 /* SCSIENACK|SDMAENACK|HDMAENACK */ +dma_dmadone: + and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); +dma_halt: + /* + * Some revisions of the aic7880 have a problem where, if the + * data fifo is full, but the PCI input latch is not empty, + * HDMAEN cannot be cleared. The fix used here is to attempt + * to drain the data fifo until there is space for the input + * latch to drain and HDMAEN de-asserts. + */ + if ((ahc->features & AHC_ULTRA2) == 0) { + mov NONE, DFDAT; + } + test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; return: - ret - -/* - * Common SCSI initialization for selection and reselection. Expects - * the target SCSI ID to be in the upper four bits of SINDEX, and A's - * contents are stomped on return. - */ -initialize_scsiid: - and SINDEX,0xf0 /* Get target ID */ - and A,0x0f,SCSIID - or SINDEX,A - mov SCSIID,SINDEX ret + ret; /* * Assert that if we've been reselected, then we've seen an IDENTIFY * message. */ assert: - test FLAGS,RESELECTED jz return /* reselected? */ - test FLAGS,IDENTIFY_SEEN jnz return /* seen IDENTIFY? */ + test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ - mvi INTSTAT,NO_IDENT ret /* no - cause a kernel panic */ + mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ /* - * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag - * value in ARG_1. If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged - * SCB. Have the kernel print a warning message if it can't be found, and - * generate an ABORT/ABORT_TAG message to the target. SINDEX should be - * cleared on call. + * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) + * or by the SCBID ARG_1. The search begins at the SCB index passed in + * via SINDEX which is an SCB that must be on the disconnected list. If + * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR + * is set to the proper SCB. */ findSCB: - mov A,SAVED_TCL - mov SCBPTR,SINDEX /* switch to next SCB */ - mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */ - cmp SCB_TCL,A jne findSCB1 /* target ID/channel/lun match? */ - test SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/ - test SCB_CONTROL,TAG_ENB jnz findTaggedSCB - cmp ARG_1,SCB_LIST_NULL je foundSCB - jmp findSCB1 -findTaggedSCB: - mov A, ARG_1 /* Tag passed in ARG_1 */ - cmp SCB_TAG,A jne findSCB1 /* Found it? */ -foundSCB: - test FLAGS,PAGESCBS jz foundSCB_ret + mov SCBPTR,SINDEX; /* Initialize SCBPTR */ + cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; + mov A, SAVED_TCL; + mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */ +findSCB_by_SCBID: + mov A, ARG_1; /* Tag passed in ARG_1 */ + mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ +findSCB_next: + mov ARG_2, SCBPTR; + cmp SCB_NEXT, SCB_LIST_NULL je notFound; + mov SCBPTR,SCB_NEXT; + dec SINDEX; /* Last comparison moved us too far */ +findSCB_loop: + cmp SINDIR, A jne findSCB_next; + mov SINDEX, SCBPTR ret; +notFound: + mvi SINDEX, SCB_LIST_NULL ret; + +/* + * Retrieve an SCB by SCBID first searching the disconnected list falling + * back to DMA'ing the SCB down from the host. This routine assumes that + * ARG_1 is the SCBID of interrest and that SINDEX is the position in the + * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, + * we go directly to the host for the SCB. + */ +retrieveSCB: + test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; + mov SCBPTR call findSCB; /* Continue the search */ + cmp SINDEX, SCB_LIST_NULL je retrieve_from_host; + +/* + * This routine expects SINDEX to contain the index of the SCB to be + * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the + * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL + * if it is at the head. + */ +rem_scb_from_disc_list: /* Remove this SCB from the disconnection list */ - cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev - mov SAVED_LINKPTR, SCB_PREV - mov SCBPTR, SCB_NEXT - mov SCB_PREV, SAVED_LINKPTR - mov SCBPTR, SINDEX -unlink_prev: - cmp SCB_PREV,SCB_LIST_NULL je rHead/* At the head of the list */ - mov SAVED_LINKPTR, SCB_NEXT - mov SCBPTR, SCB_PREV - mov SCB_NEXT, SAVED_LINKPTR - mov SCBPTR, SINDEX - mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */ + cmp ARG_2, SCB_LIST_NULL je rHead; + mov DINDEX, SCB_NEXT; + mov SCBPTR, ARG_2; + mov SCB_NEXT, DINDEX; + mov SCBPTR, SINDEX ret; rHead: - mov DISCONNECTED_SCBH,SCB_NEXT -foundSCB_ret: - mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */ - -findSCB1: - mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */ - inc SINDEX - mov A,SCBCOUNT - cmp SINDEX,A jne findSCB - - mvi INTSTAT,NO_MATCH /* not found - signal kernel */ - cmp RETURN_1,SCB_PAGEDIN je return - or SCSISIGO,ATNO /* assert ATNO */ - cmp ARG_1,SCB_LIST_NULL jne find_abort_tag - mvi MSG_ABORT call mk_mesg - jmp ITloop -find_abort_tag: - mvi MSG_ABORT_TAG call mk_mesg - jmp ITloop - -/* - * Make a working copy of the scatter-gather parameters from the SCB. - */ -sg_scb2ram: - mov HADDR0, SCB_DATAPTR0 - mov HADDR1, SCB_DATAPTR1 - mov HADDR2, SCB_DATAPTR2 - mov HADDR3, SCB_DATAPTR3 - mov HCNT0, SCB_DATACNT0 - mov HCNT1, SCB_DATACNT1 - mov HCNT2, SCB_DATACNT2 - - mov STCNT0, HCNT0 - mov STCNT1, HCNT1 - mov STCNT2, HCNT2 - - mov SG_COUNT,SCB_SGCOUNT - - mov SG_NEXT0, SCB_SGPTR0 - mov SG_NEXT1, SCB_SGPTR1 - mov SG_NEXT2, SCB_SGPTR2 - mov SG_NEXT3, SCB_SGPTR3 ret + mov DISCONNECTED_SCBH,SCB_NEXT ret; + +retrieve_from_host: +/* + * We didn't find it. Pull an SCB and DMA down the one we want. + * We should never get here in the non-paging case. + */ + mov ALLZEROS call get_free_or_disc_scb; + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + /* Jump instead of call as we want to return anyway */ + mov ARG_1 jmp dma_scb; + +/* + * Determine whether a target is using tagged or non-tagged transactions + * by first looking for a matching transaction based on the TCL and if + * that fails, looking up this device in the host's untagged SCB array. + * The TCL to search for is assumed to be in SAVED_TCL. The value is + * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). + * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information + * in an SCB instead of having to go to the host. + */ +get_untagged_SCBID: + cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; + mvi ARG_1, SCB_LIST_NULL; + mov DISCONNECTED_SCBH call findSCB; + cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; + or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ + test SCB_CONTROL, TAG_ENB jnz . + 2; + mov ARG_1, SCB_TAG ret; + mvi ARG_1, SCB_LIST_NULL ret; + +/* + * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) + * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. + */ +fetch_byte: + mov ARG_2, SINDEX; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi CCHCNT, 1; + mvi CCSGCTL, CCSGEN|CCSGRESET; + test CCSGCTL, CCSGDONE jz .; + mvi CCSGCTL, CCSGRESET; + bmov RETURN_2, CCSGRAM, 1 ret; + } else { + mvi DINDEX, HADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi HCNT[0], 1; + clr HCNT[1]; + clr HCNT[2]; + mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; + call dma_finish; + mov RETURN_2, DFDAT ret; + } + +/* + * Prepare the hardware to post a byte to host memory given an + * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. + */ +post_byte_setup: + mov ARG_2, SINDEX; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi CCHCNT, 1; + mvi CCSCBCTL, CCSCBRESET ret; + } else { + mvi DINDEX, HADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi HCNT[0], 1; + clr HCNT[1]; + clr HCNT[2]; + mvi DFCNTRL, FIFORESET ret; + } + +post_byte: + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov CCSCBRAM, SINDEX, 1; + or CCSCBCTL, CCSCBEN|CCSCBRESET; + test CCSCBCTL, CCSCBDONE jz .; + clr CCSCBCTL ret; + } else { + mov DFDAT, SINDEX; + or DFCNTRL, HDMAEN|FIFOFLUSH; + jmp dma_finish; + } + +get_SCBID_from_host: + mov A, SAVED_TCL; + mvi UNTAGGEDSCB_OFFSET call fetch_byte; + mov RETURN_1, RETURN_2 ret; + +phase_lock_perr: + mvi INTSTAT, PERR_DETECTED; +phase_lock: + /* + * If there is a parity error, wait for the kernel to + * see the interrupt and prepare our message response + * before continuing. + */ + test SSTAT1, REQINIT jz phase_lock; + test SSTAT1, SCSIPERR jnz phase_lock_perr; +phase_lock_latch_phase: + and SCSISIGO, PHASE_MASK, SCSISIGI; + and LASTPHASE, PHASE_MASK, SCSISIGI ret; + +if ((ahc->features & AHC_CMD_CHAN) == 0) { +set_stcnt_from_hcnt: + mov STCNT[0], HCNT[0]; + mov STCNT[1], HCNT[1]; + mov STCNT[2], HCNT[2] ret; + +bcopy_7: + mov DINDIR, SINDIR; + mov DINDIR, SINDIR; +bcopy_5: + mov DINDIR, SINDIR; +bcopy_4: + mov DINDIR, SINDIR; +bcopy_3: + mov DINDIR, SINDIR; + mov DINDIR, SINDIR; + mov DINDIR, SINDIR ret; +} + +if ((ahc->flags & AHC_TARGETMODE) != 0) { +/* + * Setup addr assuming that A is an index into + * an array of 32byte objects, SINDEX contains + * the base address of that array, and DINDEX + * contains the base address of the location + * to store the indexed address. + */ +set_32byte_addr: + shr ARG_2, 3, A; + shl A, 5; + jmp set_1byte_addr; +} + +/* + * Setup addr assuming that A is an index into + * an array of 64byte objects, SINDEX contains + * the base address of that array, and DINDEX + * contains the base address of the location + * to store the indexed address. + */ +set_64byte_addr: + shr ARG_2, 2, A; + shl A, 6; + +/* + * Setup addr assuming that A + (ARG_1 * 256) is an + * index into an array of 1byte objects, SINDEX contains + * the base address of that array, and DINDEX contains + * the base address of the location to store the computed + * address. + */ +set_1byte_addr: + add DINDIR, A, SINDIR; + mov A, ARG_2; + adc DINDIR, A, SINDIR; + clr A; + adc DINDIR, A, SINDIR; + adc DINDIR, A, SINDIR ret; + +/* + * Either post or fetch and SCB from host memory based on the + * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. + */ +dma_scb: + mov A, SINDEX; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi HSCB_ADDR call set_64byte_addr; + mov CCSCBPTR, SCBPTR; + test DMAPARAMS, DIRECTION jz dma_scb_tohost; + mvi CCHCNT, SCB_64BYTE_SIZE; + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; + jmp dma_scb_finish; +dma_scb_tohost: + mvi CCHCNT, SCB_32BYTE_SIZE; + if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + mvi CCSCBCTL, CCSCBRESET; + bmov CCSCBRAM, SCB_CONTROL, SCB_32BYTE_SIZE; + or CCSCBCTL, CCSCBEN|CCSCBRESET; + test CCSCBCTL, CCSCBDONE jz .; + } else { + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } +dma_scb_finish: + clr CCSCBCTL; + test CCSCBCTL, CCARREN|CCSCBEN jnz .; + ret; + } else { + mvi DINDEX, HADDR; + mvi HSCB_ADDR call set_64byte_addr; + mvi HCNT[0], SCB_32BYTE_SIZE; + clr HCNT[1]; + clr HCNT[2]; + mov DFCNTRL, DMAPARAMS; + test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; + /* Fill it with the SCB data */ +copy_scb_tofifo: + mvi SINDEX, SCB_CONTROL; + add A, SCB_32BYTE_SIZE, SINDEX; +copy_scb_tofifo_loop: + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + cmp SINDEX, A jne copy_scb_tofifo_loop; + or DFCNTRL, HDMAEN|FIFOFLUSH; +dma_scb_fromhost: + call dma_finish; + /* If we were putting the SCB, we are done */ + test DMAPARAMS, DIRECTION jz return; + mvi SCB_CONTROL call dfdat_in_7; + call dfdat_in_7_continued; + call dfdat_in_7_continued; + jmp dfdat_in_7_continued; +dfdat_in_7: + mov DINDEX,SINDEX; +dfdat_in_7_continued: + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT ret; + } -/* - * Copying RAM values back to SCB, for Save Data Pointers message, but - * only if we've actually been into a data phase to change them. This - * protects against bogus data in scratch ram and the residual counts - * since they are only initialized when we go into data_in or data_out. - */ -sg_ram2scb: - test FLAGS, DPHASE jz return - mov SCB_SGCOUNT,SG_COUNT - - mov SCB_SGPTR0,SG_NEXT0 - mov SCB_SGPTR1,SG_NEXT1 - mov SCB_SGPTR2,SG_NEXT2 - mov SCB_SGPTR3,SG_NEXT3 - - mov SCB_DATAPTR0,SHADDR0 - mov SCB_DATAPTR1,SHADDR1 - mov SCB_DATAPTR2,SHADDR2 - mov SCB_DATAPTR3,SHADDR3 /* - * Use the residual number since STCNT is corrupted by any message transfer + * Wait for DMA from host memory to data FIFO to complete, then disable + * DMA and wait for it to acknowledge that it's off. */ - mov SCB_DATACNT0,SCB_RESID_DCNT0 - mov SCB_DATACNT1,SCB_RESID_DCNT1 - mov SCB_DATACNT2,SCB_RESID_DCNT2 ret - +dma_finish: + test DFSTATUS,HDONE jz dma_finish; + /* Turn off DMA */ + and DFCNTRL, ~HDMAEN; + test DFCNTRL, HDMAEN jnz .; + ret; + +add_scb_to_free_list: + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov SCB_NEXT, FREE_SCBH; + mvi SCB_TAG, SCB_LIST_NULL; + mov FREE_SCBH, SCBPTR ret; + } else { + mvi SCB_TAG, SCB_LIST_NULL ret; + } + +if ((ahc->flags & AHC_PAGESCBS) != 0) { +get_free_or_disc_scb: + cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; + cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; +return_error: + mvi SINDEX, SCB_LIST_NULL ret; +dequeue_disc_scb: + mov SCBPTR, DISCONNECTED_SCBH; +dma_up_scb: + mvi DMAPARAMS, FIFORESET; + mov SCB_TAG call dma_scb; +unlink_disc_scb: + mov DISCONNECTED_SCBH, SCB_NEXT ret; +dequeue_free_scb: + mov SCBPTR, FREE_SCBH; + mov FREE_SCBH, SCB_NEXT ret; +} + +add_scb_to_disc_list: /* - * Add the array base TARG_SCRATCH to the target offset (the target address - * is in SCSIID), and return the result in SINDEX. The accumulator - * contains the 3->8 decoding of the target ID on return. + * Link this SCB into the DISCONNECTED list. This list holds the + * candidates for paging out an SCB if one is needed for a new command. + * Modifying the disconnected list is a critical(pause dissabled) section. */ -ndx_dtr: - shr A,SCSIID,4 - test SBLKCTL,SELBUSB jz ndx_dtr_2 - or A,0x08 /* Channel B entries add 8 */ -ndx_dtr_2: - add SINDEX,TARG_SCRATCH,A ret + mov SCB_NEXT, DISCONNECTED_SCBH; + mov DISCONNECTED_SCBH, SCBPTR ret; diff --git a/sys/dev/microcode/aic7xxx/aic7xxx_asm.1 b/sys/dev/microcode/aic7xxx/aic7xxx_asm.1 deleted file mode 100644 index 6ba7a14b327..00000000000 --- a/sys/dev/microcode/aic7xxx/aic7xxx_asm.1 +++ /dev/null @@ -1,71 +0,0 @@ -.\" $OpenBSD: aic7xxx_asm.1,v 1.6 1999/07/09 13:35:34 aaron Exp $ -.\" -.\" Copyright (c) 1994, 1995 -.\" Justin T. Gibbs. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 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 ``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 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. -.\" -.\" -.Dd November 11, 1994 -.Dt AIC7XXX_ASM 1 -.Os -.Sh NAME -.Nm aic7xxx_asm -.Nd Assembler for the Adaptec aic7xxx family of asics -.Sh SYNOPSIS -.Nm aic7xxx_asm -.Op Fl d -.Op Fl D Ar variable=value -.Op Fl v -.Op Fl o Ar file -.Ar source-file -.Sh DESCRIPTION -The Adaptec aic7xxx family of asics are single chip SCSI controllers with a -RISC like command processor. This assembler parses the language outlined -in the Adaptec technical document -.%T "AIC-7770 (EISA/ISA Bus Master Single-Chip SCSI Host Adaptor) Data Book" -and produces ascii output intended for a C byte array. -.Pp -The aic7xxx assembler is required to compile kernels with aic7xxx SCSI -adaptor support (AHA-274x, AHA-284x, AHA-294x controllers) and is compiled, -installed, and used automatically in the kernel compile directory when -necessary. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl D Ar variable=value -Define -.Ar variable -to be -.Ar value -in the global context -.It Fl d -Turn on debugging -.It Fl v -Print version information -.It Fl o Ar file -Redirect assembler output to -.Ar file -.Sh AUTHOR -This aic7770 assembler was written by -John Aycock (aycock@cpsc.ucalgary.ca) diff --git a/sys/dev/microcode/aic7xxx/aic7xxx_asm.c b/sys/dev/microcode/aic7xxx/aic7xxx_asm.c deleted file mode 100644 index 39df041368a..00000000000 --- a/sys/dev/microcode/aic7xxx/aic7xxx_asm.c +++ /dev/null @@ -1,687 +0,0 @@ -/* $OpenBSD: aic7xxx_asm.c,v 1.7 1997/01/15 23:42:08 millert Exp $ */ - -/*+M************************************************************************* - * Adaptec AIC7770/AIC7870 sequencer code assembler. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * 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. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of Calgary - * Department of Computer Science and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE 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. - * - * Comments are started by `#' and continue to the end of the line; lines - * may be of the form: - * <label>* - * <label>* <undef-sym> = <value> - * <label>* <opcode> <operand>* - * - * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas - * are token separators. - * - *-M*************************************************************************/ -static char id[] = "$Id: aic7xxx_asm.c,v 1.7 1997/01/15 23:42:08 millert Exp $"; -#include <ctype.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> - -#define MEMORY 448 -#define MAXLINE 1024 -#define MAXTOKEN 32 -#define ADOTOUT "a.out" -#define NOVALUE -1 - -/* - * AIC-7770/AIC-7870 register definitions - */ -#define R_SINDEX 0x65 -#define R_ALLONES 0x69 -#define R_ALLZEROS 0x6a -#define R_NONE 0x6a - -int debug; -int lineno, LC; -char *filename; -unsigned char M[MEMORY][4]; - -void -error(char *s) -{ - fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno); - exit(EXIT_FAILURE); -} - -void * -Malloc(size_t size) -{ - void *p = malloc(size); - if (!p) - error("out of memory"); - return(p); -} - -void * -Realloc(void *ptr, size_t size) -{ - void *p = realloc(ptr, size); - if (!p) - error("out of memory"); - return(p); -} - -char * -Strdup(char *s) -{ - char *p = (char *)Malloc(strlen(s) + 1); - strcpy(p, s); - return(p); -} - -typedef struct sym_t { - struct sym_t *next; /* MUST BE FIRST */ - char *name; - int value; - int npatch; - int *patch; -} sym_t; - -sym_t *head; - -void -define(char *name, int value) -{ - sym_t *p, *q; - - for (p = head, q = (sym_t *)&head; p; p = p->next) { - if (!strcmp(p->name, name)) - error("redefined symbol"); - q = p; - } - - p = q->next = (sym_t *)Malloc(sizeof(sym_t)); - p->next = NULL; - p->name = Strdup(name); - p->value = value; - p->npatch = 0; - p->patch = NULL; - - if (debug) { - fprintf(stderr, "\"%s\" ", p->name); - if (p->value != NOVALUE) - fprintf(stderr, "defined as 0x%x\n", p->value); - else - fprintf(stderr, "undefined\n"); - } -} - -sym_t * -lookup(char *name) -{ - sym_t *p; - - for (p = head; p; p = p->next) - if (!strcmp(p->name, name)) - return(p); - return(NULL); -} - -void -patch(sym_t *p, int location) -{ - p->npatch += 1; - p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *)); - - p->patch[p->npatch - 1] = location; -} - -void backpatch(void) -{ - int i; - sym_t *p; - - for (p = head; p; p = p->next) { - - if (p->value == NOVALUE) { - fprintf(stderr, - "%s: undefined symbol \"%s\"\n", - filename, p->name); - exit(EXIT_FAILURE); - } - - if (p->npatch) { - if (debug) - fprintf(stderr, - "\"%s\" (0x%x) patched at", - p->name, p->value); - - for (i = 0; i < p->npatch; i++) { - M[p->patch[i]][0] &= ~1; - M[p->patch[i]][0] |= ((p->value >> 8) & 1); - M[p->patch[i]][1] = p->value & 0xff; - - if (debug) - fprintf(stderr, " 0x%x", p->patch[i]); - } - - if (debug) - fputc('\n', stderr); - } - } -} - -/* - * Output words in byte-reversed order (least significant first) - * since the sequencer RAM is loaded that way. - */ -void -output(FILE *fp) -{ - int i; - - for (i = 0; i < LC; i++) - fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n", - M[i][3], - M[i][2], - M[i][1], - M[i][0]); - printf("%d out of %d instructions used.\n", LC, MEMORY); -} - -char ** -getl(int *n) -{ - int i; - char *p, *quote; - static char buf[MAXLINE]; - static char *a[MAXTOKEN]; - - i = 0; - - while (fgets(buf, sizeof(buf), stdin)) { - - lineno += 1; - - if (buf[strlen(buf)-1] != '\n') - error("line too long"); - - p = strchr(buf, '#'); - if (p) - *p = '\0'; - p = buf; -rescan: - quote = strchr(p, '\"'); - if (quote) - *quote = '\0'; - for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n")) - if (i < MAXTOKEN-1) - a[i++] = p; - else - error("too many tokens"); - if (quote) { - quote++; - p = strchr(quote, '\"'); - if (!p) - error("unterminated string constant"); - else if (i < MAXTOKEN-1) { - a[i++] = quote; - *p = '\0'; - p++; - } - else - error("too many tokens"); - goto rescan; - } - if (i) { - *n = i; - return(a); - } - } - return(NULL); -} - -#define A 0x8000 /* `A'ccumulator ok */ -#define I 0x4000 /* use as immediate value */ -#define SL 0x2000 /* shift left */ -#define SR 0x1000 /* shift right */ -#define RL 0x0800 /* rotate left */ -#define RR 0x0400 /* rotate right */ -#define LO 0x8000 /* lookup: ori-{jmp,jc,jnc,call} */ -#define LA 0x4000 /* lookup: and-{jz,jnz} */ -#define LX 0x2000 /* lookup: xor-{je,jne} */ -#define NA -1 /* not applicable */ - -struct { - char *name; - int n; /* number of operands, including opcode */ - unsigned int op; /* immediate or L?|pos_from_0 */ - unsigned int dest; /* NA, pos_from_0, or I|immediate */ - unsigned int src; /* NA, pos_from_0, or I|immediate */ - unsigned int imm; /* pos_from_0, A|pos_from_0, or I|immediate */ - unsigned int addr; /* NA or pos_from_0 */ - int fmt; /* instruction format - 1, 2, or 3 */ -} instr[] = { -/* - * N OP DEST SRC IMM ADDR FMT - */ - { "mov", 3, 1, 1, 2, I|0xff, NA, 1 }, - { "mov", 4, LO|2, NA, 1, I|0, 3, 3 }, - { "mvi", 3, 0, 1, I|R_ALLZEROS, A|2, NA, 1 }, - { "mvi", 4, LO|2, NA, I|R_ALLZEROS, 1, 3, 3 }, - { "not", 2, 2, 1, 1, I|0xff, NA, 1 }, - { "and", 3, 1, 1, 1, A|2, NA, 1 }, - { "and", 4, 1, 1, 3, A|2, NA, 1 }, - { "or", 3, 0, 1, 1, A|2, NA, 1 }, - { "or", 4, 0, 1, 3, A|2, NA, 1 }, - { "or", 5, LO|3, NA, 1, 2, 4, 3 }, - { "xor", 3, 2, 1, 1, A|2, NA, 1 }, - { "xor", 4, 2, 1, 3, A|2, NA, 1 }, - { "nop", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 }, - { "inc", 2, 3, 1, 1, I|1, NA, 1 }, - { "inc", 3, 3, 1, 2, I|1, NA, 1 }, - { "dec", 2, 3, 1, 1, I|0xff, NA, 1 }, - { "dec", 3, 3, 1, 2, I|0xff, NA, 1 }, - { "jmp", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 }, - { "jc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 }, - { "jnc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 }, - { "call", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 }, - { "test", 5, LA|3, NA, 1, A|2, 4, 3 }, - { "cmp", 5, LX|3, NA, 1, A|2, 4, 3 }, - { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 }, - { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 }, - { "clc", 1, 3, I|R_NONE, I|R_ALLZEROS, I|1, NA, 1 }, - { "clc", 4, 3, 2, I|R_ALLZEROS, A|3, NA, 1 }, - { "stc", 2, 3, 1, I|R_ALLONES, I|1, NA, 1 }, - { "add", 3, 3, 1, 1, A|2, NA, 1 }, - { "add", 4, 3, 1, 3, A|2, NA, 1 }, - { "adc", 3, 4, 1, 1, A|2, NA, 1 }, - { "adc", 4, 4, 1, 3, A|2, NA, 1 }, - { "shl", 3, 5, 1, 1, SL|2, NA, 2 }, - { "shl", 4, 5, 1, 2, SL|3, NA, 2 }, - { "shr", 3, 5, 1, 1, SR|2, NA, 2 }, - { "shr", 4, 5, 1, 2, SR|3, NA, 2 }, - { "rol", 3, 5, 1, 1, RL|2, NA, 2 }, - { "rol", 4, 5, 1, 2, RL|3, NA, 2 }, - { "ror", 3, 5, 1, 1, RR|2, NA, 2 }, - { "ror", 4, 5, 1, 2, RR|3, NA, 2 }, - /* - * Extensions (note also that mvi allows A) - */ - { "clr", 2, 1, 1, I|R_ALLZEROS, I|0xff, NA, 1 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } -}; - -int -eval_operand(char **a, int spec) -{ - int i; - unsigned int want = spec & (LO|LA|LX); - - static struct { - unsigned int what; - char *name; - int value; - } jmptab[] = { - { LO, "jmp", 8 }, - { LO, "jc", 9 }, - { LO, "jnc", 10 }, - { LO, "call", 11 }, - { LA, "jz", 15 }, - { LA, "jnz", 13 }, - { LX, "je", 14 }, - { LX, "jne", 12 }, - }; - - spec &= ~(LO|LA|LX); - - for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++) - if (jmptab[i].what == want && - !strcmp(jmptab[i].name, a[spec])) - { - return(jmptab[i].value); - } - - if (want) - error("invalid jump"); - - return(spec); /* "case 0" - no flags set */ -} - -int -eval_sdi(char **a, int spec) -{ - sym_t *p; - unsigned val; - - if (spec == NA) - return(NA); - - switch (spec & (A|I|SL|SR|RL|RR)) { - case SL: - case SR: - case RL: - case RR: - if (isdigit(*a[spec &~ (SL|SR|RL|RR)])) - val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0); - else { - p = lookup(a[spec &~ (SL|SR|RL|RR)]); - if (!p) - error("undefined symbol used"); - val = p->value; - } - - switch (spec & (SL|SR|RL|RR)) { /* blech */ - case SL: - if (val > 7) - return(0xf0); - return(((val % 8) << 4) | - (val % 8)); - case SR: - if (val > 7) - return(0xf0); - return(((val % 8) << 4) | - (1 << 3) | - ((8 - (val % 8)) % 8)); - case RL: - return(val % 8); - case RR: - return((8 - (val % 8)) % 8); - } - case I: - return(spec &~ I); - case A: - /* - * An immediate field of zero selects - * the accumulator. Vigorously object - * if zero is given otherwise - it's - * most likely an error. - */ - spec &= ~A; - if (!strcmp("A", a[spec])) - return(0); - if (isdigit(*a[spec]) && - strtol(a[spec], NULL, 0) == 0) - { - error("immediate value of zero selects accumulator"); - } - /* falls through */ - case 0: - if (isdigit(*a[spec])) - return(strtol(a[spec], NULL, 0)); - p = lookup(a[spec]); - if (p) - return(p->value); - error("undefined symbol used"); - } - - return(NA); /* shut the compiler up */ -} - -int -eval_addr(char **a, int spec) -{ - sym_t *p; - - if (spec == NA) - return(NA); - if (isdigit(*a[spec])) - return(strtol(a[spec], NULL, 0)); - - p = lookup(a[spec]); - - if (p) { - if (p->value != NOVALUE) - return(p->value); - patch(p, LC); - } else { - define(a[spec], NOVALUE); - p = lookup(a[spec]); - patch(p, LC); - } - - return(NA); /* will be patched in later */ -} - -int -crack(char **a, int n) -{ - int i; - int I_imm, I_addr; - int I_op, I_dest, I_src, I_ret; - - /* - * Check for "ret" at the end of the line; remove - * it unless it's "ret" alone - we still want to - * look it up in the table. - */ - I_ret = (strcmp(a[n-1], "ret") ? 0 : !0); - if (I_ret && n > 1) - n -= 1; - - for (i = 0; instr[i].name; i++) { - /* - * Look for match in table given constraints, - * currently just the name and the number of - * operands. - */ - if (!strcmp(instr[i].name, *a) && instr[i].n == n) - break; - } - if (!instr[i].name) - error("unknown opcode or wrong number of operands"); - - I_op = eval_operand(a, instr[i].op); - I_src = eval_sdi(a, instr[i].src); - I_imm = eval_sdi(a, instr[i].imm); - I_dest = eval_sdi(a, instr[i].dest); - I_addr = eval_addr(a, instr[i].addr); - - if( LC >= MEMORY ) - error("Memory exhausted!\n"); - - switch (instr[i].fmt) { - case 1: - case 2: - M[LC][0] = (I_op << 1) | I_ret; - M[LC][1] = I_dest; - M[LC][2] = I_src; - M[LC][3] = I_imm; - break; - case 3: - if (I_ret) - error("illegal use of \"ret\""); - M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1); - M[LC][1] = I_addr & 0xff; - M[LC][2] = I_src; - M[LC][3] = I_imm; - break; - } - - return (1); /* no two-byte instructions yet */ -} - -#undef SL -#undef SR -#undef RL -#undef RR -#undef LX -#undef LA -#undef LO -#undef I -#undef A - -void -assemble(FILE *ofile) -{ - int n; - char **a; - sym_t *p; - - while ((a = getl(&n))) { - - while (a[0][strlen(*a)-1] == ':') { - a[0][strlen(*a)-1] = '\0'; - p = lookup(*a); - if (p) - p->value = LC; - else - define(*a, LC); - a += 1; - n -= 1; - } - - if (!n) /* line was all labels */ - continue; - - if (n == 3 && !strcmp("VERSION", *a)) - fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]); - else { - if (n == 3 && !strcmp("=", a[1])) - define(*a, strtol(a[2], NULL, 0)); - else - LC += crack(a, n); - } - } - - backpatch(); - output(ofile); - - if (debug) - output(stderr); -} - -int -main(int argc, char **argv) -{ - int c; - int pid; - int ifile; - FILE *ofile; - int fd[2]; - - ofile = NULL; - while ((c = getopt(argc, argv, "dho:vD:")) != -1) { - switch (c) { - case 'd': - debug = !0; - break; - case 'D': - { - char *p; - if ((p = strchr(optarg, '=')) != NULL) { - *p = '\0'; - define(optarg, strtol(p + 1, NULL, 0)); - } - else - define(optarg, 1); - break; - } - case 'o': - - if ((ofile = fopen(optarg, "w")) == NULL) { - perror(optarg); - exit(EXIT_FAILURE); - } - break; - case 'h': - printf("usage: %s [-d] [-Dname] [-ooutput] input\n", - *argv); - exit(EXIT_SUCCESS); - break; - case 'v': - printf("%s\n", id); - exit(EXIT_SUCCESS); - break; - default: - exit(EXIT_FAILURE); - break; - } - } - - if (argc - optind != 1) { - fprintf(stderr, "%s: must have one input file\n", *argv); - exit(EXIT_FAILURE); - } - filename = argv[optind]; - - - if ((ifile = open(filename, O_RDONLY)) < 0) { - perror(filename); - exit(EXIT_FAILURE); - } - - if (!ofile) { - if ((ofile = fopen(ADOTOUT, "w")) == NULL) { - perror(ADOTOUT); - exit(EXIT_FAILURE); - } - } - - if (pipe(fd) < 0) { - perror("pipe failed"); - exit(1); - } - - if ((pid = fork()) < 0 ) { - perror("fork failed"); - exit(1); - } - else if (pid > 0) { /* Parent */ - close(fd[1]); /* Close write end */ - if (fd[0] != STDIN_FILENO) { - if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) { - perror("dup2 error on stdin"); - exit(EXIT_FAILURE); - } - close(fd[0]); - } - assemble(ofile); - exit(EXIT_SUCCESS); - } - else { /* Child */ - close(fd[0]); /* Close Read end */ - if (fd[1] != STDOUT_FILENO) { - if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) { - perror("dup2 error on stdout"); - exit(EXIT_FAILURE); - } - close(fd[1]); - } - if (ifile != STDIN_FILENO) { - if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) { - perror("dup2 error on stdin"); - exit(EXIT_FAILURE); - } - close(ifile); - } - execl("/usr/bin/cpp", "/usr/bin/cpp", "-P", "-", "-", NULL); - } - return(EXIT_SUCCESS); -} diff --git a/sys/dev/microcode/aic7xxx/aic7xxx_reg.h b/sys/dev/microcode/aic7xxx/aic7xxx_reg.h deleted file mode 100644 index b29f23efd03..00000000000 --- a/sys/dev/microcode/aic7xxx/aic7xxx_reg.h +++ /dev/null @@ -1,784 +0,0 @@ -/* $OpenBSD: aic7xxx_reg.h,v 1.3 1997/11/07 08:07:16 niklas Exp $*/ - -/* - * Aic7xxx register and scratch ram definitions. - * - * Copyright (c) 1994, 1995, 1996 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 - * 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. - * - */ - -/* - * This header is shared by the sequencer code and the kernel level driver. - * - * All page numbers refer to the Adaptec AIC-7770 Data Book availible from - * Adaptec's Technical Documents Department 1-800-934-2766 - */ - -/* - * SCSI Sequence Control (p. 3-11). - * Each bit, when set starts a specific SCSI sequence on the bus - */ -#define SCSISEQ 0x000 -#define TEMODEO 0x80 -#define ENSELO 0x40 -#define ENSELI 0x20 -#define ENRSELI 0x10 -#define ENAUTOATNO 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNP 0x02 -#define SCSIRSTO 0x01 - -/* - * SCSI Transfer Control 0 Register (pp. 3-13). - * Controls the SCSI module data path. - */ -#define SXFRCTL0 0x001 -#define DFON 0x80 -#define DFPEXP 0x40 -#define ULTRAEN 0x20 -#define CLRSTCNT 0x10 -#define SPIOEN 0x08 -#define SCAMEN 0x04 -#define CLRCHN 0x02 -/* UNUSED 0x01 */ - -/* - * SCSI Transfer Control 1 Register (pp. 3-14,15). - * Controls the SCSI module data path. - */ -#define SXFRCTL1 0x002 -#define BITBUCKET 0x80 -#define SWRAPEN 0x40 -#define ENSPCHK 0x20 -#define STIMESEL 0x18 -#define ENSTIMER 0x04 -#define ACTNEGEN 0x02 -#define STPWEN 0x01 /* Powered Termination */ - -/* - * SCSI Control Signal Read Register (p. 3-15). - * Reads the actual state of the SCSI bus pins - */ -#define SCSISIGI 0x003 -#define CDI 0x80 -#define IOI 0x40 -#define MSGI 0x20 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 - -/* - * Possible phases in SCSISIGI - */ -#define PHASE_MASK 0xe0 -#define P_DATAOUT 0x00 -#define P_DATAIN 0x40 -#define P_COMMAND 0x80 -#define P_MESGOUT 0xa0 -#define P_STATUS 0xc0 -#define P_MESGIN 0xe0 -/* - * SCSI Contol Signal Write Register (p. 3-16). - * Writing to this register modifies the control signals on the bus. Only - * those signals that are allowed in the current mode (Initiator/Target) are - * asserted. - */ -#define SCSISIGO 0x003 -#define CDO 0x80 -#define IOO 0x40 -#define MSGO 0x20 -#define ATNO 0x10 -#define SELO 0x08 -#define BSYO 0x04 -#define REQO 0x02 -#define ACKO 0x01 - -/* - * SCSI Rate Control (p. 3-17). - * Contents of this register determine the Synchronous SCSI data transfer - * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the - * SOFS (3:0) bits disables synchronous data transfers. Any offset value - * greater than 0 enables synchronous transfers. - */ -#define SCSIRATE 0x004 -#define WIDEXFER 0x80 /* Wide transfer control */ -#define SXFR 0x70 /* Sync transfer rate */ -#define SOFS 0x0f /* Sync offset */ - -/* - * SCSI ID (p. 3-18). - * Contains the ID of the board and the current target on the - * selected channel. - */ -#define SCSIID 0x005 -#define TID 0xf0 /* Target ID mask */ -#define OID 0x0f /* Our ID mask */ - -/* - * SCSI Latched Data (p. 3-19). - * Read/Write latchs used to transfer data on the SCSI bus during - * Automatic or Manual PIO mode. SCSIDATH can be used for the - * upper byte of a 16bit wide asyncronouse data phase transfer. - */ -#define SCSIDATL 0x006 -#define SCSIDATH 0x007 - -/* - * SCSI Transfer Count (pp. 3-19,20) - * These registers count down the number of bytes transfered - * across the SCSI bus. The counter is decremented only once - * the data has been safely transfered. SDONE in SSTAT0 is - * set when STCNT goes to 0 - */ -#define STCNT 0x008 -#define STCNT0 0x008 -#define STCNT1 0x009 -#define STCNT2 0x00a - -/* - * Clear SCSI Interrupt 0 (p. 3-20) - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0. - */ -#define CLRSINT0 0x00b -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRSWRAP 0x08 -/* UNUSED 0x04 */ -#define CLRSPIORDY 0x02 -/* UNUSED 0x01 */ - -/* - * SCSI Status 0 (p. 3-21) - * Contains one set of SCSI Interrupt codes - * These are most likely of interest to the sequencer - */ -#define SSTAT0 0x00b -#define TARGET 0x80 /* Board acting as target */ -#define SELDO 0x40 /* Selection Done */ -#define SELDI 0x20 /* Board has been selected */ -#define SELINGO 0x10 /* Selection In Progress */ -#define SWRAP 0x08 /* 24bit counter wrap */ -#define SDONE 0x04 /* STCNT = 0x000000 */ -#define SPIORDY 0x02 /* SCSI PIO Ready */ -#define DMADONE 0x01 /* DMA transfer completed */ - -/* - * Clear SCSI Interrupt 1 (p. 3-23) - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. - */ -#define CLRSINT1 0x00c -#define CLRSELTIMEO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -/* UNUSED 0x10 */ -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRPHASECHG 0x02 -#define CLRREQINIT 0x01 - -/* - * SCSI Status 1 (p. 3-24) - */ -#define SSTAT1 0x00c -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define PHASECHG 0x02 -#define REQINIT 0x01 - -/* - * SCSI Interrupt Mode 1 (pp. 3-28,29) - * Setting any bit will enable the corresponding function - * in SIMODE1 to interrupt via the IRQ pin. - */ -#define SIMODE1 0x011 -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENPHASECHG 0x02 -#define ENREQINIT 0x01 - -/* - * SCSI Data Bus (High) (p. 3-29) - * This register reads data on the SCSI Data bus directly. - */ -#define SCSIBUSL 0x012 -#define SCSIBUSH 0x013 - -/* - * SCSI/Host Address (p. 3-30) - * These registers hold the host address for the byte about to be - * transfered on the SCSI bus. They are counted up in the same - * manner as STCNT is counted down. SHADDR should always be used - * to determine the address of the last byte transfered since HADDR - * can be squewed by write ahead. - */ -#define SHADDR 0x014 -#define SHADDR0 0x014 -#define SHADDR1 0x015 -#define SHADDR2 0x016 -#define SHADDR3 0x017 - -/* - * Selection/Reselection ID (p. 3-31) - * Upper four bits are the device id. The ONEBIT is set when the re/selecting - * device did not set its own ID. - */ -#define SELID 0x019 -#define SELID_MASK 0xf0 -#define ONEBIT 0x08 -/* UNUSED 0x07 */ - -/* - * SCSI Block Control (p. 3-32) - * Controls Bus type and channel selection. In a twin channel configuration - * addresses 0x00-0x1e are gated to the appropriate channel based on this - * register. SELWIDE allows for the coexistence of 8bit and 16bit devices - * on a wide bus. - */ -#define SBLKCTL 0x01f -#define DIAGLEDEN 0x80 /* Aic78X0 only */ -#define DIAGLEDON 0x40 /* Aic78X0 only */ -#define AUTOFLUSHDIS 0x20 -/* UNUSED 0x10 */ -#define SELBUS_MASK 0x0a -#define SELBUSB 0x08 -/* UNUSED 0x04 */ -#define SELWIDE 0x02 -/* UNUSED 0x01 */ -#define SELNARROW 0x00 - -/* - * Sequencer Control (p. 3-33) - * Error detection mode and speed configuration - */ -#define SEQCTL 0x060 -#define PERRORDIS 0x80 -#define PAUSEDIS 0x40 -#define FAILDIS 0x20 -#define FASTMODE 0x10 -#define BRKADRINTEN 0x08 -#define STEP 0x04 -#define SEQRESET 0x02 -#define LOADRAM 0x01 - -/* - * Sequencer RAM Data (p. 3-34) - * Single byte window into the Scratch Ram area starting at the address - * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write - * four bytes in sucessesion. The SEQADDRs will increment after the most - * significant byte is written - */ -#define SEQRAM 0x061 - -/* - * Sequencer Address Registers (p. 3-35) - * Only the first bit of SEQADDR1 holds addressing information - */ -#define SEQADDR0 0x062 -#define SEQADDR1 0x063 -#define SEQADDR1_MASK 0x01 - -/* - * Accumulator - * We cheat by passing arguments in the Accumulator up to the kernel driver - */ -#define ACCUM 0x064 - -#define SINDEX 0x065 -#define DINDEX 0x066 -#define ALLZEROS 0x06a -#define NONE 0x06a -#define SINDIR 0x06c -#define DINDIR 0x06d -#define FUNCTION1 0x06e - -/* - * Host Address (p. 3-48) - * This register contains the address of the byte about - * to be transfered across the host bus. - */ -#define HADDR 0x088 -#define HADDR0 0x088 -#define HADDR1 0x089 -#define HADDR2 0x08a -#define HADDR3 0x08b - -#define HCNT 0x08c -#define HCNT0 0x08c -#define HCNT1 0x08d -#define HCNT2 0x08e -/* - * SCB Pointer (p. 3-49) - * Gate one of the four SCBs into the SCBARRAY window. - */ -#define SCBPTR 0x090 - -/* - * Board Control (p. 3-43) - */ -#define BCTL 0x084 -/* RSVD 0xf0 */ -#define ACE 0x08 /* Support for external processors */ -/* RSVD 0x06 */ -#define ENABLE 0x01 - -/* - * On the aic78X0 chips, Board Control is replaced by the DSCommand - * register (p. 4-64) - */ -#define DSCOMMAND 0x084 -#define CACHETHEN 0x80 /* Cache Threshold enable */ -#define DPARCKEN 0x40 /* Data Parity Check Enable */ -#define MPARCKEN 0x20 /* Memory Parity Check Enable */ -#define EXTREQLCK 0x10 /* External Request Lock */ - -/* - * Bus On/Off Time (p. 3-44) - */ -#define BUSTIME 0x085 -#define BOFF 0xf0 -#define BON 0x0f - -/* - * Bus Speed (p. 3-45) - */ -#define BUSSPD 0x086 -#define DFTHRSH 0xc0 -#define STBOFF 0x38 -#define STBON 0x07 -#define DFTHRSH_100 0xc0 - -/* - * Host Control (p. 3-47) R/W - * Overal host control of the device. - */ -#define HCNTRL 0x087 -/* UNUSED 0x80 */ -#define POWRDN 0x40 -/* UNUSED 0x20 */ -#define SWINT 0x10 -#define IRQMS 0x08 -#define PAUSE 0x04 -#define INTEN 0x02 -#define CHIPRST 0x01 -#define CHIPRSTACK 0x01 - -/* - * Interrupt Status (p. 3-50) - * Status for system interrupts - */ -#define INTSTAT 0x091 -#define SEQINT_MASK 0xf1 /* SEQINT Status Codes */ -#define BAD_PHASE 0x01 /* unknown scsi bus phase */ -#define SEND_REJECT 0x11 /* sending a message reject */ -#define NO_IDENT 0x21 /* no IDENTIFY after reconnect*/ -#define NO_MATCH 0x31 /* no cmd match for reconnect */ -#define SDTR_MSG 0x41 /* SDTR message received */ -#define WDTR_MSG 0x51 /* WDTR message received */ -#define REJECT_MSG 0x61 /* Reject message received */ -#define BAD_STATUS 0x71 /* Bad status from target */ -#define RESIDUAL 0x81 /* Residual byte count != 0 */ -#define ABORT_TAG 0x91 /* Sent an ABORT_TAG message */ -#define AWAITING_MSG 0xa1 /* - * Kernel requested to specify - * a message to this target - * (command was null), so tell - * it that it can fill the - * message buffer. - */ -#define IMMEDDONE 0xb1 /* - * An immediate command has - * completed - */ -#define MSG_BUFFER_BUSY 0xc1 /* - * Sequencer wants to use the - * message buffer, but it - * already contains a message - */ -#define MSGIN_PHASEMIS 0xd1 /* - * Target changed phase on us - * when we were expecting - * another msgin byte. - */ -#define DATA_OVERRUN 0xe1 /* - * Target attempted to write - * beyond the bounds of its - * command. - */ -#define BRKADRINT 0x08 -#define SCSIINT 0x04 -#define CMDCMPLT 0x02 -#define SEQINT 0x01 -#define INT_PEND (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT) - -/* - * Hard Error (p. 3-53) - * Reporting of catastrophic errors. You usually cannot recover from - * these without a full board reset. - */ -#define ERROR 0x092 -/* UNUSED 0xf0 */ -#define PARERR 0x08 -#define ILLOPCODE 0x04 -#define ILLSADDR 0x02 -#define ILLHADDR 0x01 - -/* - * Clear Interrupt Status (p. 3-52) - */ -#define CLRINT 0x092 -#define CLRBRKADRINT 0x08 -#define CLRSCSIINT 0x04 -#define CLRCMDINT 0x02 -#define CLRSEQINT 0x01 - -#define DFCNTRL 0x093 -#define WIDEODD 0x40 -#define SCSIEN 0x20 -#define SDMAEN 0x10 -#define SDMAENACK 0x10 -#define HDMAEN 0x08 -#define HDMAENACK 0x08 -#define DIRECTION 0x04 -#define FIFOFLUSH 0x02 -#define FIFORESET 0x01 - -#define DFSTATUS 0x094 -#define HDONE 0x08 -#define FIFOEMP 0x01 - -#define DFDAT 0x099 - -/* - * SCB Auto Increment (p. 3-59) - * Byte offset into the SCB Array and an optional bit to allow auto - * incrementing of the address during download and upload operations - */ -#define SCBCNT 0x09a -#define SCBAUTO 0x80 -#define SCBCNT_MASK 0x1f - -/* - * Queue In FIFO (p. 3-60) - * Input queue for queued SCBs (commands that the seqencer has yet to start) - */ -#define QINFIFO 0x09b - -/* - * Queue In Count (p. 3-60) - * Number of queued SCBs - */ -#define QINCNT 0x09c - -/* - * Queue Out FIFO (p. 3-61) - * Queue of SCBs that have completed and await the host - */ -#define QOUTFIFO 0x09d - -/* - * Queue Out Count (p. 3-61) - * Number of queued SCBs in the Out FIFO - */ -#define QOUTCNT 0x09e - -/* - * SCB Definition (p. 5-4) - * The two reserved bytes at SCBARRAY+1[23] are expected to be set to - * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate - * whether or not to DMA an SCB from host ram. This flag prevents the - * "re-fetching" of transactions that are requed because the target is - * busy with another command. We also use bits 6 & 7 to indicate whether - * or not to initiate SDTR or WDTR repectively when starting this command. - */ -#define SCBARRAY 0x0a0 -#define SCB_CONTROL 0x0a0 -#define NEEDWDTR 0x80 -#define DISCENB 0x40 -#define TAG_ENB 0x20 -#define NEEDSDTR 0x10 -#define DISCONNECTED 0x04 -#define SCB_TAG_TYPE 0x03 -#define SCB_TCL 0x0a1 -#define SCB_TARGET_STATUS 0x0a2 -#define SCB_SGCOUNT 0x0a3 -#define SCB_SGPTR 0x0a4 -#define SCB_SGPTR0 0x0a4 -#define SCB_SGPTR1 0x0a5 -#define SCB_SGPTR2 0x0a6 -#define SCB_SGPTR3 0x0a7 -#define SCB_RESID_SGCNT 0x0a8 -#define SCB_RESID_DCNT 0x0a9 -#define SCB_RESID_DCNT0 0x0a9 -#define SCB_RESID_DCNT1 0x0aa -#define SCB_RESID_DCNT2 0x0ab -#define SCB_DATAPTR 0x0ac -#define SCB_DATAPTR0 0x0ac -#define SCB_DATAPTR1 0x0ad -#define SCB_DATAPTR2 0x0ae -#define SCB_DATAPTR3 0x0af -#define SCB_DATACNT 0x0b0 -#define SCB_DATACNT0 0x0b0 -#define SCB_DATACNT1 0x0b1 -#define SCB_DATACNT2 0x0b2 -/* UNUSED - QUAD PADDING 0x0b3 */ -#define SCB_CMDPTR 0x0b4 -#define SCB_CMDPTR0 0x0b4 -#define SCB_CMDPTR1 0x0b5 -#define SCB_CMDPTR2 0x0b6 -#define SCB_CMDPTR3 0x0b7 -#define SCB_CMDLEN 0x0b8 -#define SCB_TAG 0x0b9 -#define SCB_NEXT 0x0ba -#define SCB_PREV 0x0bb - -#ifdef __linux__ -#define SG_SIZEOF 0x0c /* sizeof(struct scatterlist) */ -#else -#define SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ -#endif - -/* --------------------- AHA-2840-only definitions -------------------- */ - -#define SEECTL_2840 0x0c0 -/* UNUSED 0xf8 */ -#define CS_2840 0x04 -#define CK_2840 0x02 -#define DO_2840 0x01 - -#define STATUS_2840 0x0c1 -#define EEPROM_TF 0x80 -#define BIOS_SEL 0x60 -#define ADSEL 0x1e -#define DI_2840 0x01 - -/* --------------------- AIC-7870-only definitions -------------------- */ - -#define DSPCISTATUS 0x086 - -/* - * Serial EEPROM Control (p. 4-92 in 7870 Databook) - * Controls the reading and writing of an external serial 1-bit - * EEPROM Device. In order to access the serial EEPROM, you must - * first set the SEEMS bit that generates a request to the memory - * port for access to the serial EEPROM device. When the memory - * port is not busy servicing another request, it reconfigures - * to allow access to the serial EEPROM. When this happens, SEERDY - * gets set high to verify that the memory port access has been - * granted. - * - * After successful arbitration for the memory port, the SEECS bit of - * the SEECTL register is connected to the chip select. The SEECK, - * SEEDO, and SEEDI are connected to the clock, data out, and data in - * lines respectively. The SEERDY bit of SEECTL is useful in that it - * gives us an 800 nsec timer. After a write to the SEECTL register, - * the SEERDY goes high 800 nsec later. The one exception to this is - * when we first request access to the memory port. The SEERDY goes - * high to signify that access has been granted and, for this case, has - * no implied timing. - * - * See 93cx6.c for detailed information on the protocol necessary to - * read the serial EEPROM. - */ -#define SEECTL 0x01e -#define EXTARBACK 0x80 -#define EXTARBREQ 0x40 -#define SEEMS 0x20 -#define SEERDY 0x10 -#define SEECS 0x08 -#define SEECK 0x04 -#define SEEDO 0x02 -#define SEEDI 0x01 - -/* ---------------------- Scratch RAM Offsets ------------------------- */ -/* These offsets are either to values that are initialized by the board's - * BIOS or are specified by the sequencer code. - * - * The host adapter card (at least the BIOS) uses 20-2f for SCSI - * device information, 32-33 and 5a-5f as well. As it turns out, the - * BIOS trashes 20-2f, writing the synchronous negotiation results - * on top of the BIOS values, so we re-use those for our per-target - * scratchspace (actually a value that can be copied directly into - * SCSIRATE). The kernel driver will enable synchronous negotiation - * for all targets that have a value other than 0 in the lower four - * bits of the target scratch space. This should work regardless of - * whether the bios has been installed. - */ - -/* - * 1 byte per target starting at this address for configuration values - */ -#define TARG_SCRATCH 0x020 - -/* - * The sequencer will stick the frist byte of any rejected message here so - * we can see what is getting thrown away. Extended messages put the - * extended message type in REJBYTE_EXT. - */ -#define REJBYTE 0x030 -#define REJBYTE_EXT 0x031 - -/* - * Bit vector of targets that have disconnection disabled. - */ -#define DISC_DSB 0x032 -#define DISC_DSB_A 0x032 -#define DISC_DSB_B 0x033 - -/* - * Length of pending message - */ -#define MSG_LEN 0x034 - -/* We reserve 8bytes to store outgoing messages */ -#define MSG0 0x035 -#define COMP_MSG0 0xcb /* 2's complement of MSG0 */ -#define MSG1 0x036 -#define MSG2 0x037 -#define MSG3 0x038 -#define MSG4 0x039 -#define MSG5 0x03a -#define MSG6 0x03b -#define MSG7 0x03c - -/* - * These are offsets into the card's scratch ram. Some of the values are - * specified in the AHA2742 technical reference manual and are initialized - * by the BIOS at boot time. - */ -#define LASTPHASE 0x03d -#define ARG_1 0x03e -#define MAXOFFSET 0x01 -#define RETURN_1 0x03f -#define SEND_WDTR 0x80 -#define SEND_SDTR 0x60 -#define SEND_SENSE 0x40 -#define SEND_REJ 0x20 -#define SCB_PAGEDIN 0x10 - -#define SIGSTATE 0x040 - -#define DMAPARAMS 0x041 /* Parameters for DMA Logic */ - -#define SG_COUNT 0x042 -#define SG_NEXT 0x043 /* working value of SG pointer */ -#define SG_NEXT0 0x043 -#define SG_NEXT1 0x044 -#define SG_NEXT2 0x045 -#define SG_NEXT3 0x046 - -#define SCBCOUNT 0x047 /* - * Number of SCBs supported by - * this card. - */ -#define COMP_SCBCOUNT 0x048 /* - * Two's compliment of SCBCOUNT - */ -#define QCNTMASK 0x049 /* - * Mask of bits to test against - * when looking at the Queue Count - * registers. Works around a bug - * on aic7850 chips. - */ -#define FLAGS 0x04a -#define SINGLE_BUS 0x00 -#define TWIN_BUS 0x01 -#define WIDE_BUS 0x02 -#define PAGESCBS 0x04 -#define DPHASE 0x10 -#define SELECTED 0x20 -#define IDENTIFY_SEEN 0x40 -#define RESELECTED 0x80 - -#define SAVED_TCL 0x04b /* - * Temporary storage for the - * target/channel/lun of a - * reconnecting target - */ -#define ACTIVE_A 0x04c -#define ACTIVE_B 0x04d -#define WAITING_SCBH 0x04e /* - * head of list of SCBs awaiting - * selection - */ -#define DISCONNECTED_SCBH 0x04f /* - * head of list of SCBs that are - * disconnected. Used for SCB - * paging. - */ -#define SCB_LIST_NULL 0xff - -#define SAVED_LINKPTR 0x050 -#define SAVED_SCBPTR 0x051 -#define ULTRA_ENB 0x052 -#define ULTRA_ENB_B 0x053 - -#define SCSICONF 0x05a -#define RESET_SCSI 0x40 - -#define HOSTCONF 0x05d - -#define HA_274_BIOSCTRL 0x05f -#define BIOSMODE 0x30 -#define BIOSDISABLED 0x30 -#define CHANNEL_B_PRIMARY 0x08 - -/* Message codes */ -#define MSG_EXTENDED 0x01 -#define MSG_SDTR 0x01 -#define MSG_WDTR 0x03 -#define MSG_SDPTRS 0x02 -#define MSG_RDPTRS 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_INITIATOR_DET_ERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT 0x07 -#define MSG_NOP 0x08 -#define MSG_MSG_PARITY_ERROR 0x09 -#define MSG_BUS_DEVICE_RESET 0x0c -#define MSG_ABORT_TAG 0x0d -#define MSG_SIMPLE_TAG 0x20 -#define MSG_IDENTIFY 0x80 - -/* WDTR Message values */ -#define BUS_8_BIT 0x00 -#define BUS_16_BIT 0x01 -#define BUS_32_BIT 0x02 - -#define MAX_OFFSET_8BIT 0x0f -#define MAX_OFFSET_16BIT 0x08 diff --git a/sys/dev/microcode/aic7xxx/aic7xxx_seq.h b/sys/dev/microcode/aic7xxx/aic7xxx_seq.h index 1380773d842..b4ac8f152bc 100644 --- a/sys/dev/microcode/aic7xxx/aic7xxx_seq.h +++ b/sys/dev/microcode/aic7xxx/aic7xxx_seq.h @@ -1,388 +1,1005 @@ -#define AIC7XXX_SEQ_VER "$OpenBSD: aic7xxx_seq.h,v 1.1 1996/11/28 23:28:00 niklas Exp $" -#if 0 -#define AIC7XXX_SEQ_VER "$NetBSD: aic7xxx_seq.h,v 1.2 1996/10/08 03:04:07 gibbs Exp $" -#endif - 0xff, 0x6a, 0x93, 0x02, - 0xff, 0x6a, 0x03, 0x02, - 0x0f, 0x4a, 0x4a, 0x02, - 0x10, 0x6a, 0x00, 0x00, - 0xff, 0x6a, 0x04, 0x02, - 0x01, 0x4a, 0x09, 0x1e, - 0x08, 0x1f, 0x1f, 0x04, - 0x20, 0x0b, 0x32, 0x1a, - 0x08, 0x1f, 0x1f, 0x04, - 0x20, 0x0b, 0x32, 0x1a, - 0xff, 0x4e, 0x17, 0x18, - 0xff, 0x49, 0x64, 0x02, - 0x00, 0x9c, 0x05, 0x1e, - 0xff, 0x9b, 0x90, 0x02, - 0xff, 0xa1, 0x6e, 0x02, - 0xff, 0x6e, 0x64, 0x02, - 0x88, 0xa1, 0x19, 0x1e, - 0x00, 0x4d, 0x15, 0x1a, - 0x20, 0xa0, 0x1c, 0x1a, - 0x00, 0x4d, 0x4d, 0x00, - 0x00, 0x65, 0x1c, 0x10, - 0xff, 0x90, 0x9b, 0x02, - 0x00, 0x65, 0x05, 0x10, - 0xff, 0x4e, 0x90, 0x02, - 0x00, 0x65, 0x1e, 0x10, - 0x00, 0x4c, 0x15, 0x1a, - 0x20, 0xa0, 0x1c, 0x1a, - 0x00, 0x4c, 0x4c, 0x00, - 0xff, 0x4e, 0xba, 0x02, - 0xff, 0x90, 0x4e, 0x02, - 0xf7, 0x1f, 0x65, 0x02, - 0x08, 0xa1, 0x64, 0x02, - 0x00, 0x65, 0x65, 0x00, - 0xff, 0x65, 0x1f, 0x02, - 0x00, 0xa1, 0x35, 0x17, - 0x58, 0x6a, 0x00, 0x00, - 0x40, 0xa0, 0x64, 0x02, - 0x07, 0xa1, 0x35, 0x02, - 0x00, 0x35, 0x35, 0x00, - 0x80, 0x35, 0x35, 0x00, - 0x01, 0x6a, 0x34, 0x00, - 0x20, 0xa0, 0x2e, 0x1e, - 0x36, 0x6a, 0x66, 0x00, - 0x23, 0xa0, 0x6d, 0x02, - 0xff, 0xb9, 0x6d, 0x02, - 0xcb, 0x66, 0x34, 0x06, - 0x80, 0xa0, 0x30, 0x1e, - 0xa1, 0x6a, 0x91, 0x00, - 0x40, 0x0b, 0x36, 0x1a, - 0x20, 0x0b, 0x30, 0x1e, - 0xff, 0x6a, 0x34, 0x02, - 0x00, 0x19, 0x35, 0x17, - 0x80, 0x4a, 0x4a, 0x00, - 0x00, 0x65, 0x38, 0x10, - 0xff, 0xba, 0x4e, 0x02, - 0x20, 0x4a, 0x4a, 0x00, - 0x02, 0x01, 0x01, 0x00, - 0x00, 0x65, 0x7c, 0x17, - 0xff, 0x6c, 0x04, 0x02, - 0xff, 0x05, 0x6e, 0x02, - 0xff, 0x6e, 0x64, 0x02, - 0xdf, 0x01, 0x65, 0x02, - 0x80, 0x05, 0x42, 0x1a, - 0x08, 0x1f, 0x42, 0x1a, - 0x00, 0x52, 0x44, 0x1e, - 0x20, 0x65, 0x44, 0x10, - 0x00, 0x53, 0x44, 0x1e, - 0x20, 0x65, 0x65, 0x00, - 0xff, 0x65, 0x01, 0x02, - 0x02, 0x6a, 0x00, 0x00, - 0x08, 0x6a, 0x0c, 0x00, - 0x60, 0x6a, 0x0b, 0x00, - 0x08, 0x0c, 0x18, 0x1b, - 0x01, 0x0c, 0x48, 0x1e, - 0xe0, 0x03, 0x64, 0x02, - 0xff, 0x64, 0x3d, 0x02, - 0xff, 0x64, 0x03, 0x02, - 0x00, 0x6a, 0x55, 0x1c, - 0x40, 0x64, 0x5b, 0x1c, - 0x80, 0x64, 0x8d, 0x1c, - 0xa0, 0x64, 0x9c, 0x1c, - 0xc0, 0x64, 0x9a, 0x1c, - 0xe0, 0x64, 0xb1, 0x1c, - 0x01, 0x6a, 0x91, 0x00, - 0x00, 0x65, 0x48, 0x10, - 0x7d, 0x6a, 0x41, 0x00, - 0x00, 0x65, 0x5c, 0x10, - 0xff, 0xa9, 0x08, 0x02, - 0xff, 0xaa, 0x09, 0x02, - 0xff, 0xab, 0x0a, 0x02, - 0x00, 0x65, 0x60, 0x10, - 0x79, 0x6a, 0x41, 0x00, - 0x00, 0x65, 0x39, 0x17, - 0x10, 0x4a, 0x57, 0x1a, - 0x00, 0x65, 0x60, 0x17, - 0x10, 0x4a, 0x4a, 0x00, - 0xff, 0x42, 0x65, 0x1a, - 0x80, 0x02, 0x02, 0x00, - 0xff, 0x6a, 0x08, 0x00, - 0xff, 0x6a, 0x09, 0x00, - 0xff, 0x6a, 0x0a, 0x00, - 0x01, 0x42, 0x67, 0x18, - 0xbf, 0x41, 0x41, 0x02, - 0x00, 0x41, 0x2d, 0x17, - 0x80, 0x02, 0x8a, 0x1a, - 0x04, 0x0b, 0x85, 0x1e, - 0xff, 0x42, 0x42, 0x06, - 0xff, 0x42, 0x85, 0x1e, - 0xff, 0x6a, 0x64, 0x02, - 0x08, 0x43, 0x43, 0x06, - 0x00, 0x44, 0x44, 0x08, - 0xff, 0x6a, 0x8e, 0x02, - 0xff, 0x6a, 0x8d, 0x02, - 0x08, 0x6a, 0x8c, 0x00, - 0xff, 0x43, 0x88, 0x02, - 0xff, 0x44, 0x89, 0x02, - 0xff, 0x45, 0x8a, 0x02, - 0xff, 0x46, 0x8b, 0x02, - 0x0d, 0x93, 0x93, 0x00, - 0x08, 0x94, 0x77, 0x1e, - 0x40, 0x93, 0x93, 0x02, - 0x08, 0x93, 0x79, 0x1a, - 0xff, 0x99, 0x88, 0x02, - 0xff, 0x99, 0x89, 0x02, - 0xff, 0x99, 0x8a, 0x02, - 0xff, 0x99, 0x8b, 0x02, - 0xff, 0x99, 0x8c, 0x02, - 0xff, 0x99, 0x8d, 0x02, - 0xff, 0x99, 0x8e, 0x02, - 0xff, 0x8c, 0x08, 0x02, - 0xff, 0x8d, 0x09, 0x02, - 0xff, 0x8e, 0x0a, 0x02, - 0x10, 0x0c, 0x60, 0x1e, - 0xff, 0x08, 0xa9, 0x02, - 0xff, 0x09, 0xaa, 0x02, - 0xff, 0x0a, 0xab, 0x02, - 0xff, 0x42, 0xa8, 0x02, - 0x00, 0x65, 0x48, 0x10, - 0x7f, 0x02, 0x02, 0x02, - 0xe1, 0x6a, 0x91, 0x00, - 0x00, 0x65, 0x48, 0x10, - 0x00, 0x65, 0x39, 0x17, - 0xff, 0xb4, 0x88, 0x02, - 0xff, 0xb5, 0x89, 0x02, - 0xff, 0xb6, 0x8a, 0x02, - 0xff, 0xb7, 0x8b, 0x02, - 0xff, 0xb8, 0x8c, 0x02, - 0xff, 0x6a, 0x8d, 0x02, - 0xff, 0x6a, 0x8e, 0x02, - 0xff, 0x8c, 0x08, 0x02, - 0xff, 0x8d, 0x09, 0x02, - 0xff, 0x8e, 0x0a, 0x02, - 0x3d, 0x6a, 0x2d, 0x17, - 0x00, 0x65, 0x48, 0x10, - 0xa2, 0x6a, 0x27, 0x17, - 0x00, 0x65, 0xbd, 0x10, - 0xff, 0x34, 0x9e, 0x1a, - 0x08, 0x6a, 0x1c, 0x17, - 0x35, 0x6a, 0x65, 0x00, - 0xff, 0x34, 0x66, 0x02, - 0x10, 0x0c, 0xae, 0x1a, - 0x02, 0x0b, 0xa0, 0x1e, - 0x10, 0x0c, 0xae, 0x1a, - 0x01, 0x66, 0xa5, 0x18, - 0x40, 0x6a, 0x0c, 0x00, - 0xff, 0x66, 0x66, 0x06, - 0x02, 0x0b, 0x0b, 0x00, - 0xff, 0x6c, 0x06, 0x02, - 0xff, 0x66, 0xa0, 0x1a, - 0x08, 0x0c, 0xaf, 0x1a, - 0x01, 0x0c, 0xa9, 0x1e, - 0x10, 0x0c, 0xaf, 0x1a, - 0x10, 0x03, 0x03, 0x00, - 0x00, 0x65, 0x48, 0x10, - 0x40, 0x6a, 0x0c, 0x00, - 0xff, 0x6a, 0x34, 0x02, - 0x00, 0x65, 0x48, 0x10, - 0x64, 0x6a, 0x27, 0x17, - 0xff, 0x64, 0x30, 0x02, - 0x80, 0x64, 0xf5, 0x1a, - 0x04, 0x64, 0xe5, 0x1c, - 0x02, 0x64, 0xf1, 0x1c, - 0x00, 0x6a, 0xbf, 0x1c, - 0x03, 0x64, 0xf3, 0x1c, - 0x01, 0x64, 0xd2, 0x1c, - 0x07, 0x64, 0x16, 0x1d, - 0x10, 0x03, 0x03, 0x00, - 0x11, 0x6a, 0x91, 0x00, - 0x07, 0x6a, 0x1c, 0x17, - 0x00, 0x65, 0x2a, 0x17, - 0x00, 0x65, 0x48, 0x10, - 0xff, 0xa8, 0xc1, 0x1e, - 0x81, 0x6a, 0x91, 0x00, - 0xff, 0xa2, 0xc5, 0x1e, - 0x71, 0x6a, 0x91, 0x00, - 0x40, 0x3f, 0xc5, 0x18, - 0x00, 0x65, 0xbd, 0x10, - 0x20, 0xa0, 0xcc, 0x1a, - 0xff, 0xa1, 0x6e, 0x02, - 0xff, 0x6e, 0x64, 0x02, - 0x88, 0xa1, 0xcb, 0x1e, - 0x00, 0x4d, 0x4d, 0x04, - 0x00, 0x65, 0xcc, 0x10, - 0x00, 0x4c, 0x4c, 0x04, - 0xff, 0xb8, 0xcf, 0x1a, - 0xb1, 0x6a, 0x91, 0x00, - 0x00, 0x65, 0x02, 0x10, - 0xff, 0xb9, 0x9d, 0x02, - 0x02, 0x6a, 0x91, 0x00, - 0x00, 0x65, 0xbd, 0x10, - 0x54, 0x6a, 0x23, 0x17, - 0x55, 0x6a, 0x23, 0x17, - 0xff, 0x54, 0x64, 0x02, - 0xff, 0x64, 0x64, 0x06, - 0x56, 0x6a, 0x65, 0x00, - 0xff, 0x64, 0xe0, 0x1e, - 0x58, 0x65, 0xdc, 0x1c, - 0x00, 0x65, 0x23, 0x17, - 0xff, 0x64, 0x64, 0x06, - 0x00, 0x66, 0xd7, 0x10, - 0xff, 0x64, 0xe0, 0x1e, - 0x6a, 0x6a, 0x23, 0x17, - 0xff, 0x64, 0x64, 0x06, - 0x00, 0x65, 0xdc, 0x10, - 0x41, 0x6a, 0x91, 0x00, - 0x20, 0x3f, 0xba, 0x1c, - 0x80, 0x3f, 0xbd, 0x18, - 0x10, 0x03, 0x03, 0x00, - 0x00, 0x65, 0xbd, 0x10, - 0x04, 0xa0, 0xa0, 0x00, - 0x04, 0x4a, 0xbd, 0x1e, - 0xff, 0x6a, 0xbb, 0x00, - 0x50, 0x6a, 0x60, 0x00, - 0xff, 0x4f, 0xba, 0x02, - 0xff, 0x90, 0x4f, 0x02, - 0xff, 0xba, 0xef, 0x1c, - 0xff, 0xba, 0x90, 0x02, - 0xff, 0x4f, 0xbb, 0x02, - 0xff, 0x4f, 0x90, 0x02, - 0x10, 0x6a, 0x60, 0x00, - 0x00, 0x65, 0xbd, 0x10, - 0x00, 0x65, 0x6f, 0x17, - 0x00, 0x65, 0xbd, 0x10, - 0xef, 0x4a, 0x4a, 0x02, - 0x00, 0x65, 0xbd, 0x10, - 0x78, 0x64, 0xba, 0x1a, - 0x07, 0x64, 0x64, 0x02, - 0x00, 0x19, 0x4b, 0x00, - 0xf7, 0x4b, 0x4b, 0x02, - 0x08, 0x1f, 0x64, 0x02, - 0x00, 0x4b, 0x4b, 0x00, - 0x00, 0x65, 0x2a, 0x17, - 0xff, 0x6a, 0x3e, 0x00, - 0x08, 0x0c, 0x08, 0x1b, - 0x01, 0x0c, 0xfd, 0x1e, - 0x10, 0x0c, 0x08, 0x1b, - 0x64, 0x6a, 0x27, 0x17, - 0x20, 0x64, 0x08, 0x19, - 0x3e, 0x6a, 0x23, 0x17, - 0xff, 0x48, 0x64, 0x02, - 0x00, 0x3e, 0x65, 0x06, - 0x00, 0x65, 0x12, 0x13, - 0x04, 0x4a, 0x0c, 0x1f, - 0x00, 0x65, 0x2a, 0x17, - 0x00, 0x6a, 0x3c, 0x17, - 0xfb, 0xa0, 0xa0, 0x02, - 0x40, 0x4a, 0x4a, 0x00, - 0x00, 0x65, 0x48, 0x10, - 0xff, 0x3e, 0x90, 0x02, - 0xff, 0x4b, 0x64, 0x02, - 0x00, 0xa1, 0x12, 0x19, - 0x20, 0xa0, 0x12, 0x1f, - 0x00, 0x65, 0x2a, 0x17, - 0x00, 0x65, 0x09, 0x11, - 0x10, 0x03, 0x03, 0x00, - 0x91, 0x6a, 0x91, 0x00, - 0x0d, 0x6a, 0x1c, 0x17, - 0x00, 0x65, 0xbd, 0x10, - 0x61, 0x6a, 0x91, 0x00, - 0x00, 0x65, 0xbd, 0x10, - 0x40, 0x6a, 0x0c, 0x00, - 0xff, 0x6a, 0x3d, 0x02, - 0xff, 0xb8, 0xc5, 0x1e, - 0x00, 0x65, 0x02, 0x10, - 0x50, 0x6a, 0x60, 0x00, - 0xff, 0x34, 0x20, 0x1f, - 0x10, 0x6a, 0x60, 0x00, - 0xc1, 0x6a, 0x91, 0x00, - 0x01, 0x6a, 0x34, 0x00, - 0xff, 0x65, 0x35, 0x02, - 0x10, 0x6a, 0x60, 0x01, - 0x02, 0x0b, 0x0b, 0x00, - 0xff, 0x06, 0x6a, 0x02, - 0x10, 0x0c, 0x2b, 0x1b, - 0x02, 0x0b, 0x25, 0x1f, - 0xff, 0x65, 0x66, 0x02, - 0x10, 0x0c, 0x2b, 0x1b, - 0xff, 0x12, 0x6d, 0x03, - 0xff, 0x06, 0x6a, 0x03, - 0xd1, 0x6a, 0x91, 0x00, - 0x00, 0x65, 0x48, 0x10, - 0xff, 0x65, 0x93, 0x02, - 0x01, 0x0b, 0x30, 0x1b, - 0x10, 0x0c, 0x2e, 0x1f, - 0x04, 0x65, 0x32, 0x1b, - 0x01, 0x94, 0x31, 0x1f, - 0x40, 0x93, 0x93, 0x02, - 0x38, 0x93, 0x33, 0x1b, - 0xff, 0x6a, 0x6a, 0x03, - 0xf0, 0x65, 0x65, 0x02, - 0x0f, 0x05, 0x64, 0x02, - 0x00, 0x65, 0x65, 0x00, - 0xff, 0x65, 0x05, 0x03, - 0x80, 0x4a, 0x34, 0x1f, - 0x40, 0x4a, 0x34, 0x1b, - 0x21, 0x6a, 0x91, 0x01, - 0xff, 0x4b, 0x64, 0x02, - 0xff, 0x65, 0x90, 0x02, - 0x50, 0x6a, 0x60, 0x00, - 0x00, 0xa1, 0x54, 0x19, - 0x04, 0xa0, 0x54, 0x1f, - 0x20, 0xa0, 0x44, 0x1b, - 0xff, 0x3e, 0x46, 0x1d, - 0x00, 0x65, 0x54, 0x11, - 0xff, 0x3e, 0x64, 0x02, - 0x00, 0xb9, 0x54, 0x19, - 0x04, 0x4a, 0x53, 0x1f, - 0xff, 0xba, 0x4c, 0x1d, - 0xff, 0xbb, 0x50, 0x02, - 0xff, 0xba, 0x90, 0x02, - 0xff, 0x50, 0xbb, 0x02, - 0xff, 0x65, 0x90, 0x02, - 0xff, 0xbb, 0x52, 0x1d, - 0xff, 0xba, 0x50, 0x02, - 0xff, 0xbb, 0x90, 0x02, - 0xff, 0x50, 0xba, 0x02, - 0xff, 0x65, 0x90, 0x02, - 0x10, 0x6a, 0x60, 0x01, - 0xff, 0xba, 0x4f, 0x02, - 0x10, 0x6a, 0x60, 0x01, - 0x10, 0x6a, 0x60, 0x00, - 0x01, 0x65, 0x65, 0x06, - 0xff, 0x47, 0x64, 0x02, - 0x00, 0x65, 0x3c, 0x19, - 0x31, 0x6a, 0x91, 0x00, - 0x10, 0x3f, 0x34, 0x1d, - 0x10, 0x03, 0x03, 0x00, - 0xff, 0x3e, 0x5e, 0x19, - 0x06, 0x6a, 0x1c, 0x17, - 0x00, 0x65, 0x48, 0x10, - 0x0d, 0x6a, 0x1c, 0x17, - 0x00, 0x65, 0x48, 0x10, - 0xff, 0xac, 0x88, 0x02, - 0xff, 0xad, 0x89, 0x02, - 0xff, 0xae, 0x8a, 0x02, - 0xff, 0xaf, 0x8b, 0x02, - 0xff, 0xb0, 0x8c, 0x02, - 0xff, 0xb1, 0x8d, 0x02, - 0xff, 0xb2, 0x8e, 0x02, - 0xff, 0x8c, 0x08, 0x02, - 0xff, 0x8d, 0x09, 0x02, - 0xff, 0x8e, 0x0a, 0x02, - 0xff, 0xa3, 0x42, 0x02, - 0xff, 0xa4, 0x43, 0x02, - 0xff, 0xa5, 0x44, 0x02, - 0xff, 0xa6, 0x45, 0x02, - 0xff, 0xa7, 0x46, 0x03, - 0x10, 0x4a, 0x34, 0x1f, - 0xff, 0x42, 0xa3, 0x02, - 0xff, 0x43, 0xa4, 0x02, - 0xff, 0x44, 0xa5, 0x02, - 0xff, 0x45, 0xa6, 0x02, - 0xff, 0x46, 0xa7, 0x02, - 0xff, 0x14, 0xac, 0x02, - 0xff, 0x15, 0xad, 0x02, - 0xff, 0x16, 0xae, 0x02, - 0xff, 0x17, 0xaf, 0x02, - 0xff, 0xa9, 0xb0, 0x02, - 0xff, 0xaa, 0xb1, 0x02, - 0xff, 0xab, 0xb2, 0x03, - 0x4c, 0x05, 0x64, 0x0a, - 0x08, 0x1f, 0x7f, 0x1f, - 0x08, 0x64, 0x64, 0x00, - 0x20, 0x64, 0x65, 0x07, +/* + * DO NOT EDIT - This file is automatically generated. + */ +static u_int8_t seqprog[] = { + 0xff, 0x6a, 0x06, 0x08, + 0x08, 0x6a, 0x68, 0x00, + 0x7f, 0x02, 0x04, 0x08, + 0x32, 0x58, 0x00, 0x08, + 0xff, 0x6a, 0xd6, 0x09, + 0xff, 0x6a, 0xdc, 0x09, + 0x00, 0x65, 0xea, 0x59, + 0xf7, 0x01, 0x02, 0x08, + 0xff, 0x4e, 0xc8, 0x08, + 0xbf, 0x60, 0xc0, 0x08, + 0x60, 0x0b, 0x7c, 0x68, + 0x40, 0x00, 0x0c, 0x68, + 0x08, 0x1f, 0x3e, 0x10, + 0x60, 0x0b, 0x7c, 0x68, + 0x40, 0x00, 0x0c, 0x68, + 0x08, 0x1f, 0x3e, 0x10, + 0xff, 0x3e, 0x4a, 0x60, + 0x40, 0xfa, 0x12, 0x78, + 0xff, 0xf6, 0xd4, 0x08, + 0x01, 0x4e, 0x9c, 0x18, + 0x40, 0x60, 0xc0, 0x00, + 0x00, 0x4d, 0x12, 0x70, + 0x01, 0x4e, 0x9c, 0x18, + 0xbf, 0x60, 0xc0, 0x08, + 0x00, 0x6a, 0x8e, 0x5d, + 0xff, 0x4e, 0xc8, 0x18, + 0x01, 0x6a, 0x9a, 0x5c, + 0xff, 0x53, 0x20, 0x09, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0x53, 0x18, 0x5d, + 0x03, 0xb0, 0x52, 0x31, + 0xff, 0xb0, 0x52, 0x09, + 0xff, 0xb1, 0x54, 0x09, + 0xff, 0xb2, 0x56, 0x09, + 0xff, 0xa3, 0x50, 0x09, + 0xff, 0x3e, 0x74, 0x09, + 0xff, 0x90, 0x7c, 0x08, + 0xff, 0x3e, 0x20, 0x09, + 0x00, 0x65, 0x50, 0x58, + 0x00, 0x65, 0x0c, 0x40, + 0xf7, 0x1f, 0xca, 0x08, + 0x08, 0xa1, 0xc8, 0x08, + 0x00, 0x65, 0xca, 0x00, + 0xff, 0x65, 0x3e, 0x08, + 0xff, 0x58, 0xca, 0x08, + 0x80, 0xa0, 0x62, 0x78, + 0xff, 0xb6, 0x1e, 0x08, + 0xff, 0xb6, 0x0a, 0x08, + 0x80, 0x65, 0xca, 0x00, + 0x00, 0x65, 0x70, 0x40, + 0xf0, 0xa1, 0xc8, 0x08, + 0x0f, 0x0f, 0x1e, 0x08, + 0x00, 0x0f, 0x1e, 0x00, + 0xf0, 0xa1, 0xc8, 0x08, + 0x0f, 0x05, 0x0a, 0x08, + 0x00, 0x05, 0x0a, 0x00, + 0xff, 0x65, 0x00, 0x0c, + 0x12, 0x65, 0x02, 0x00, + 0x08, 0xa0, 0x78, 0x78, + 0x20, 0x01, 0x02, 0x00, + 0x02, 0xbb, 0x08, 0x34, + 0xff, 0xbb, 0x08, 0x0c, + 0x40, 0x0b, 0x0e, 0x69, + 0x20, 0x6a, 0x16, 0x00, + 0x80, 0x0b, 0x00, 0x79, + 0xa4, 0x6a, 0x06, 0x00, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x36, 0x6c, 0x00, + 0xff, 0x51, 0xc8, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x49, 0x6a, 0x02, 0x5d, + 0x01, 0x6a, 0xdc, 0x01, + 0x88, 0x6a, 0xcc, 0x00, + 0x49, 0x6a, 0x02, 0x5d, + 0x01, 0x6a, 0x26, 0x01, + 0xf0, 0x19, 0x6e, 0x08, + 0xff, 0x37, 0xd8, 0x09, + 0xff, 0x37, 0x32, 0x09, + 0x0f, 0x18, 0xd8, 0x09, + 0x0f, 0x0f, 0xd8, 0x09, + 0x0f, 0x05, 0xd8, 0x09, + 0x0f, 0x18, 0x32, 0x09, + 0x0f, 0x0f, 0x32, 0x09, + 0x0f, 0x05, 0x32, 0x09, + 0xff, 0x6a, 0xb4, 0x00, + 0x10, 0x03, 0x54, 0x79, + 0x00, 0x65, 0xf8, 0x58, + 0x80, 0x66, 0xd4, 0x78, + 0xff, 0x66, 0xd8, 0x09, + 0xff, 0x66, 0x32, 0x09, + 0x40, 0x66, 0xb8, 0x68, + 0x01, 0x36, 0x6c, 0x00, + 0x10, 0x03, 0xde, 0x78, + 0x00, 0x65, 0xf8, 0x58, + 0xe0, 0x66, 0xc8, 0x18, + 0x00, 0x65, 0xde, 0x50, + 0xdd, 0x66, 0xc8, 0x18, + 0x00, 0x65, 0xde, 0x48, + 0xff, 0x66, 0xd8, 0x09, + 0xff, 0x66, 0x32, 0x09, + 0x10, 0x03, 0x54, 0x79, + 0x00, 0x65, 0xf8, 0x58, + 0xff, 0x66, 0xd8, 0x09, + 0xff, 0x66, 0x32, 0x09, + 0xff, 0x66, 0xb4, 0x08, + 0x00, 0x65, 0xde, 0x40, + 0xa1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x08, 0x52, 0x2c, 0x71, + 0x02, 0x0b, 0xda, 0x78, + 0x00, 0x65, 0xd4, 0x40, + 0xff, 0x50, 0xc8, 0x08, + 0x00, 0x51, 0xee, 0x60, + 0xc4, 0x6a, 0x1c, 0x5c, + 0xff, 0x5a, 0xea, 0x70, + 0x28, 0x6a, 0x32, 0x5c, + 0x00, 0x65, 0x52, 0x41, + 0x08, 0x6a, 0x32, 0x5c, + 0x00, 0x65, 0x52, 0x41, + 0xff, 0x6a, 0xd8, 0x01, + 0xff, 0x6a, 0x32, 0x01, + 0x90, 0x36, 0x6c, 0x00, + 0x10, 0x03, 0x48, 0x69, + 0x00, 0x65, 0x2c, 0x41, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0xfa, 0x78, + 0xf7, 0x01, 0x02, 0x08, + 0xff, 0x06, 0xcc, 0x0c, + 0xf0, 0x19, 0x6e, 0x08, + 0x08, 0x1f, 0x06, 0x79, + 0x08, 0x37, 0x6e, 0x00, + 0x1a, 0x01, 0x02, 0x00, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x11, 0x22, 0x00, + 0x00, 0x65, 0xcc, 0x41, + 0x32, 0x58, 0x00, 0x08, + 0x40, 0x6a, 0x16, 0x00, + 0xff, 0x3e, 0x20, 0x09, + 0xff, 0xba, 0x7c, 0x08, + 0xff, 0xa1, 0x6e, 0x08, + 0x80, 0x0b, 0xc2, 0x79, + 0xe4, 0x6a, 0x1c, 0x5c, + 0x08, 0x6a, 0x18, 0x00, + 0x07, 0xa1, 0xc8, 0x08, + 0x80, 0x64, 0x32, 0x5c, + 0x20, 0xa0, 0x28, 0x79, + 0x20, 0x6a, 0x32, 0x5c, + 0x00, 0xb8, 0x32, 0x5c, + 0xff, 0xb8, 0xb4, 0x08, + 0xff, 0xb4, 0x6c, 0x08, + 0x10, 0x03, 0x44, 0x69, + 0x08, 0x36, 0x5c, 0x69, + 0x04, 0x36, 0x82, 0x69, + 0x02, 0x36, 0x92, 0x69, + 0x01, 0x36, 0x4a, 0x79, + 0x00, 0x6a, 0x8e, 0x5d, + 0xff, 0x6a, 0xa4, 0x08, + 0x00, 0x65, 0x9e, 0x59, + 0x04, 0x52, 0x3c, 0x61, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0x18, 0x5d, + 0x00, 0x65, 0x2a, 0x41, + 0xa4, 0x6a, 0x06, 0x00, + 0x00, 0x65, 0xf8, 0x58, + 0x00, 0x65, 0xd4, 0x40, + 0xe4, 0x6a, 0x1c, 0x5c, + 0x20, 0x36, 0x50, 0x79, + 0x02, 0x6a, 0x32, 0x5c, + 0x04, 0x6a, 0x32, 0x5c, + 0x01, 0x03, 0x52, 0x69, + 0xff, 0x6a, 0x06, 0x08, + 0x01, 0x6a, 0x7a, 0x00, + 0x00, 0x65, 0x9e, 0x59, + 0x00, 0x65, 0x0c, 0x40, + 0x84, 0x6a, 0x1c, 0x5c, + 0x00, 0x65, 0xf8, 0x58, + 0xff, 0x66, 0xc8, 0x08, + 0xff, 0x64, 0xd8, 0x09, + 0xff, 0x64, 0x32, 0x09, + 0x5b, 0x64, 0xc8, 0x28, + 0x20, 0x64, 0xca, 0x18, + 0xff, 0x6c, 0xc8, 0x08, + 0xff, 0x64, 0x7e, 0x79, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0x70, 0x79, + 0x01, 0x64, 0x76, 0x61, + 0xf7, 0x01, 0x02, 0x08, + 0xff, 0x06, 0xd8, 0x09, + 0xff, 0x06, 0x32, 0x09, + 0xff, 0x64, 0xc8, 0x18, + 0xff, 0x64, 0x6e, 0x69, + 0xf7, 0x36, 0x6c, 0x08, + 0x00, 0x65, 0x2c, 0x41, + 0x01, 0xb5, 0x8a, 0x79, + 0x00, 0x6a, 0x7a, 0x00, + 0x44, 0x6a, 0x1c, 0x5c, + 0x00, 0x65, 0x8e, 0x41, + 0x40, 0x6a, 0x7a, 0x00, + 0x04, 0x6a, 0x1c, 0x5c, + 0x00, 0x6a, 0x72, 0x58, + 0x00, 0x65, 0x04, 0x42, + 0xc4, 0x6a, 0x1c, 0x5c, + 0xc0, 0x6a, 0x7a, 0x00, + 0x00, 0xa2, 0x32, 0x5c, + 0xe4, 0x6a, 0x06, 0x00, + 0x00, 0x6a, 0x32, 0x5c, + 0x00, 0x65, 0x52, 0x41, + 0x10, 0x36, 0xa2, 0x69, + 0x00, 0xb9, 0x98, 0x43, + 0x18, 0x6a, 0xda, 0x01, + 0xff, 0x69, 0xd8, 0x09, + 0x1c, 0x6a, 0xd0, 0x01, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xaa, 0x79, + 0xff, 0x6a, 0xdc, 0x09, + 0x01, 0x93, 0x26, 0x01, + 0x03, 0x6a, 0x2a, 0x01, + 0xff, 0x69, 0x32, 0x09, + 0x1c, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x7e, 0x5d, + 0x01, 0x51, 0xa2, 0x18, + 0x02, 0x6a, 0x22, 0x05, + 0x08, 0x6a, 0x72, 0x58, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x11, 0x22, 0x00, + 0x80, 0x6a, 0x68, 0x00, + 0x80, 0x36, 0x6c, 0x00, + 0x00, 0x65, 0xe6, 0x5c, + 0xff, 0x3d, 0xc8, 0x08, + 0xbf, 0x64, 0x04, 0x7a, + 0x80, 0x64, 0xd8, 0x72, + 0xa0, 0x64, 0x12, 0x73, + 0xc0, 0x64, 0x0a, 0x73, + 0xe0, 0x64, 0x5a, 0x73, + 0x01, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xcc, 0x41, + 0xf7, 0x11, 0x22, 0x08, + 0xff, 0x06, 0xd4, 0x08, + 0xf7, 0x01, 0x02, 0x08, + 0x09, 0x0c, 0xe4, 0x79, + 0x08, 0x0c, 0x0c, 0x68, + 0x01, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0x26, 0x09, + 0x02, 0x6a, 0x08, 0x30, + 0xff, 0x6a, 0x08, 0x08, + 0xdf, 0x01, 0x02, 0x08, + 0x01, 0x6a, 0x7a, 0x00, + 0xff, 0x6a, 0x6c, 0x0c, + 0x04, 0x14, 0x10, 0x31, + 0x03, 0xa9, 0x18, 0x31, + 0x03, 0xa9, 0x10, 0x30, + 0x08, 0x6a, 0xcc, 0x00, + 0xa9, 0x6a, 0xfc, 0x5c, + 0x01, 0xa9, 0xb2, 0x08, + 0x00, 0x65, 0x26, 0x42, + 0xa8, 0x6a, 0x6a, 0x00, + 0x79, 0x6a, 0x6a, 0x00, + 0x40, 0x3d, 0x0c, 0x6a, + 0x04, 0x35, 0x6a, 0x00, + 0x00, 0x65, 0x54, 0x5c, + 0x80, 0x6a, 0xd4, 0x01, + 0x20, 0x36, 0xf6, 0x69, + 0x20, 0x36, 0x6c, 0x00, + 0x07, 0xac, 0x10, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0xac, 0x6a, 0xf4, 0x5c, + 0x01, 0xb0, 0xb2, 0x08, + 0x03, 0x8c, 0x10, 0x30, + 0x00, 0x65, 0xee, 0x5c, + 0x05, 0xa3, 0x70, 0x30, + 0x38, 0x6a, 0xcc, 0x00, + 0xa3, 0x6a, 0xf8, 0x5c, + 0xff, 0x38, 0x36, 0x6a, + 0x80, 0x02, 0x04, 0x00, + 0xe7, 0x35, 0x6a, 0x08, + 0x03, 0x69, 0x18, 0x31, + 0x03, 0x69, 0x10, 0x30, + 0xff, 0x6a, 0x10, 0x00, + 0xff, 0x6a, 0x12, 0x00, + 0xff, 0x6a, 0x14, 0x00, + 0x01, 0x38, 0x40, 0x62, + 0x02, 0xfc, 0xf8, 0x01, + 0x80, 0x0b, 0x3e, 0x7a, + 0x04, 0x35, 0x40, 0x7a, + 0xbf, 0x35, 0x6a, 0x08, + 0xff, 0x69, 0xca, 0x08, + 0xff, 0x35, 0x26, 0x09, + 0x04, 0x0b, 0x44, 0x6a, + 0x04, 0x0b, 0x4c, 0x6a, + 0x10, 0x0c, 0x46, 0x7a, + 0x00, 0x35, 0x40, 0x5c, + 0x80, 0x02, 0xb4, 0x6a, + 0xff, 0x08, 0x9a, 0x6a, + 0xff, 0x09, 0x9a, 0x6a, + 0xff, 0x0a, 0x9a, 0x6a, + 0xff, 0x38, 0x70, 0x18, + 0xff, 0x38, 0x9a, 0x7a, + 0x80, 0xea, 0x70, 0x62, + 0xef, 0x38, 0xc8, 0x18, + 0x80, 0x6a, 0xc8, 0x00, + 0x00, 0x65, 0x62, 0x4a, + 0x33, 0x38, 0xc8, 0x28, + 0xff, 0x64, 0xd0, 0x09, + 0x04, 0x39, 0xc0, 0x31, + 0x09, 0x6a, 0xd6, 0x01, + 0x80, 0xeb, 0x68, 0x7a, + 0xf7, 0xeb, 0xd6, 0x09, + 0x08, 0xeb, 0x6c, 0x6a, + 0x01, 0x6a, 0xd6, 0x01, + 0x08, 0xe9, 0x10, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0x39, 0x6a, 0xfa, 0x5c, + 0x08, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x0d, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x7e, 0x5d, + 0x88, 0x6a, 0x6e, 0x5d, + 0x01, 0x8c, 0x86, 0x7a, + 0x01, 0x59, 0xb2, 0x10, + 0x03, 0x8c, 0x10, 0x30, + 0x00, 0x65, 0xee, 0x5c, + 0xff, 0x6a, 0xc8, 0x08, + 0x08, 0x39, 0x72, 0x18, + 0x00, 0x3a, 0x74, 0x20, + 0x80, 0x0b, 0x26, 0x6a, + 0x01, 0x0c, 0x92, 0x7a, + 0x10, 0x0c, 0x26, 0x7a, + 0xff, 0x35, 0x26, 0x09, + 0x04, 0x0b, 0x98, 0x6a, + 0x00, 0x65, 0xbe, 0x5a, + 0x03, 0x08, 0x52, 0x31, + 0xff, 0x08, 0x52, 0x09, + 0xff, 0x09, 0x54, 0x09, + 0xff, 0x0a, 0x56, 0x09, + 0xff, 0x38, 0x50, 0x09, + 0x12, 0x01, 0x02, 0x00, + 0x04, 0x36, 0xcc, 0x79, + 0xfb, 0x36, 0x6c, 0x08, + 0x04, 0x93, 0x2c, 0x79, + 0x01, 0x0c, 0xae, 0x6a, + 0x00, 0x65, 0x2c, 0x41, + 0x00, 0x65, 0xcc, 0x41, + 0x00, 0x65, 0xbe, 0x5a, + 0x12, 0x01, 0x02, 0x00, + 0x7f, 0x02, 0x04, 0x08, + 0xf1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xcc, 0x41, + 0x04, 0x93, 0xd0, 0x6a, + 0xdf, 0x93, 0x26, 0x09, + 0x20, 0x93, 0xc2, 0x6a, + 0x02, 0x93, 0x26, 0x01, + 0x01, 0x94, 0xc4, 0x7a, + 0x01, 0x94, 0xc4, 0x7a, + 0x01, 0x94, 0xc4, 0x7a, + 0x01, 0x94, 0xc4, 0x7a, + 0x01, 0x94, 0xc4, 0x7a, + 0x10, 0x94, 0xd0, 0x6a, + 0xd7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0xd4, 0x6a, + 0xff, 0x6a, 0xd4, 0x0c, + 0x00, 0x65, 0x54, 0x5c, + 0xff, 0xb8, 0x18, 0x09, + 0x02, 0x6a, 0x1a, 0x31, + 0x03, 0x8c, 0x10, 0x30, + 0xef, 0xb8, 0xd4, 0x18, + 0x00, 0x65, 0xee, 0x4a, + 0x01, 0x6a, 0x10, 0x31, + 0xa4, 0x6a, 0x26, 0x01, + 0x35, 0x6a, 0x26, 0x01, + 0x10, 0xc0, 0x32, 0x31, + 0x00, 0x65, 0xfe, 0x42, + 0x04, 0xb4, 0x10, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0xb4, 0x6a, 0xf8, 0x5c, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x00, 0x65, 0xee, 0x5c, + 0x3d, 0x6a, 0x26, 0x01, + 0xac, 0x6a, 0x26, 0x01, + 0x04, 0x0b, 0x02, 0x6b, + 0x10, 0x0c, 0xfe, 0x7a, + 0x01, 0x03, 0x02, 0x6b, + 0xc7, 0x93, 0x26, 0x09, + 0x38, 0x93, 0x06, 0x6b, + 0x00, 0x65, 0xcc, 0x41, + 0x00, 0x65, 0x54, 0x5c, + 0xff, 0x06, 0x44, 0x09, + 0x00, 0x65, 0xcc, 0x41, + 0x10, 0x3d, 0x06, 0x00, + 0xff, 0x34, 0xca, 0x08, + 0x80, 0x65, 0x46, 0x63, + 0x10, 0xa0, 0x68, 0x6b, + 0xff, 0xa1, 0xdc, 0x08, + 0xff, 0x6e, 0xc8, 0x08, + 0xf0, 0x86, 0x20, 0x7b, + 0x61, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x56, 0xca, 0x08, + 0x08, 0xa1, 0x28, 0x7b, + 0xff, 0x57, 0xca, 0x08, + 0x80, 0xa1, 0x2c, 0x7b, + 0xff, 0x57, 0xca, 0x08, + 0x00, 0x65, 0x68, 0x6b, + 0x07, 0xa1, 0xca, 0x08, + 0x40, 0xa0, 0xc8, 0x08, + 0x00, 0x65, 0xca, 0x00, + 0x80, 0x65, 0xca, 0x00, + 0x20, 0xa0, 0x4a, 0x7b, + 0xff, 0x65, 0x0c, 0x08, + 0x00, 0x65, 0xe6, 0x5c, + 0xa0, 0x3d, 0x52, 0x63, + 0x23, 0xa0, 0x0c, 0x08, + 0x00, 0x65, 0xe6, 0x5c, + 0xa0, 0x3d, 0x52, 0x63, + 0x00, 0xb9, 0x4a, 0x43, + 0xff, 0x65, 0x4a, 0x63, + 0x00, 0x65, 0x68, 0x43, + 0x40, 0x6a, 0x18, 0x00, + 0xff, 0x65, 0x0c, 0x08, + 0x00, 0x65, 0xe6, 0x5c, + 0xa0, 0x3d, 0x10, 0x73, + 0x40, 0x6a, 0x18, 0x00, + 0xff, 0x34, 0xa8, 0x08, + 0x08, 0x6a, 0x68, 0x00, + 0x00, 0x65, 0xcc, 0x41, + 0x64, 0x6a, 0x16, 0x5c, + 0x80, 0x64, 0xc6, 0x6b, + 0x04, 0x64, 0xa8, 0x73, + 0x02, 0x64, 0xae, 0x73, + 0x00, 0x6a, 0x74, 0x73, + 0x03, 0x64, 0xc2, 0x73, + 0x08, 0x64, 0x70, 0x73, + 0xa1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xe6, 0x5c, + 0x08, 0x52, 0xce, 0x71, + 0x00, 0x65, 0x68, 0x43, + 0xff, 0x06, 0xd4, 0x08, + 0x00, 0x65, 0xcc, 0x41, + 0xff, 0xa8, 0x78, 0x6b, + 0xff, 0xa2, 0x90, 0x7b, + 0x01, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0x18, 0x5d, + 0xff, 0xa2, 0x90, 0x7b, + 0x71, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x40, 0x52, 0x90, 0x63, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0x18, 0x5d, + 0xff, 0x3e, 0x74, 0x09, + 0xff, 0x90, 0x7c, 0x08, + 0x00, 0x65, 0x50, 0x58, + 0x00, 0x65, 0xde, 0x41, + 0x20, 0xa0, 0x94, 0x6b, + 0xff, 0x37, 0xc8, 0x08, + 0x00, 0xb9, 0x98, 0x5b, + 0x00, 0x65, 0xde, 0x41, + 0x00, 0x65, 0x86, 0x5d, + 0xff, 0x65, 0xa4, 0x08, + 0xff, 0xf8, 0xc8, 0x08, + 0xff, 0x4f, 0xc8, 0x08, + 0x00, 0x6a, 0xba, 0x5c, + 0x00, 0x52, 0xd0, 0x5c, + 0x01, 0x4f, 0x9e, 0x18, + 0x02, 0x6a, 0x22, 0x05, + 0x04, 0xa0, 0x40, 0x01, + 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0xde, 0x41, + 0x20, 0x36, 0x70, 0x7b, + 0x05, 0x38, 0x46, 0x31, + 0x04, 0x14, 0x58, 0x31, + 0x03, 0xa9, 0x60, 0x31, + 0xa3, 0x6a, 0xcc, 0x00, + 0x38, 0x6a, 0xf8, 0x5c, + 0xac, 0x6a, 0xcc, 0x00, + 0x14, 0x6a, 0xfa, 0x5c, + 0xa9, 0x6a, 0xfc, 0x5c, + 0x00, 0x65, 0x70, 0x43, + 0xdf, 0x36, 0x6c, 0x08, + 0x00, 0x65, 0x70, 0x43, + 0x0f, 0x64, 0xc8, 0x08, + 0x07, 0x64, 0xc8, 0x08, + 0x00, 0x37, 0x6e, 0x00, + 0xff, 0x6a, 0xa6, 0x00, + 0x00, 0x65, 0x8a, 0x5c, + 0xff, 0x52, 0xd8, 0x73, + 0x40, 0x36, 0xe2, 0x7b, + 0x00, 0x65, 0x78, 0x5c, + 0x00, 0x65, 0xe4, 0x43, + 0xff, 0x06, 0xd4, 0x08, + 0x00, 0x65, 0xe6, 0x5c, + 0xe0, 0x3d, 0x00, 0x64, + 0x20, 0x12, 0x00, 0x64, + 0x52, 0x6a, 0x0c, 0x5c, + 0x00, 0x65, 0x72, 0x5c, + 0xff, 0x37, 0xc8, 0x08, + 0x00, 0xa1, 0xf8, 0x63, + 0x04, 0xa0, 0xf8, 0x7b, + 0xfb, 0xa0, 0x40, 0x09, + 0x80, 0x36, 0x6c, 0x00, + 0x00, 0x65, 0x74, 0x58, + 0x10, 0xa0, 0x70, 0x7b, + 0xef, 0xa0, 0x40, 0x09, + 0xff, 0x6a, 0x04, 0x5c, + 0x00, 0x65, 0x70, 0x43, + 0x04, 0xa0, 0xfe, 0x7b, + 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0x00, 0x44, + 0x00, 0x65, 0x86, 0x5d, + 0x31, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x70, 0x43, + 0x10, 0x3d, 0x06, 0x00, + 0xff, 0x65, 0x68, 0x0c, + 0xb1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x0e, 0x44, + 0xff, 0x06, 0xd4, 0x08, + 0x01, 0x0c, 0x0e, 0x7c, + 0x04, 0x0c, 0x08, 0x6c, + 0xe0, 0x03, 0x7a, 0x08, + 0xe0, 0x3d, 0x3c, 0x64, + 0xff, 0x65, 0xcc, 0x08, + 0xff, 0x12, 0xda, 0x0c, + 0xff, 0x06, 0xd4, 0x0c, + 0x01, 0x03, 0x1c, 0x6c, + 0x40, 0x03, 0xcc, 0x08, + 0xff, 0x65, 0x06, 0x08, + 0x40, 0x65, 0xc8, 0x08, + 0x00, 0x66, 0x2a, 0x74, + 0x40, 0x65, 0x2a, 0x7c, + 0x00, 0x65, 0x2a, 0x5c, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x0c, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0x34, 0x7c, + 0xff, 0x65, 0x0c, 0x08, + 0x02, 0x0b, 0x38, 0x7c, + 0xf7, 0x01, 0x02, 0x0c, + 0xe1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xcc, 0x41, + 0xff, 0x65, 0x26, 0x09, + 0x01, 0x0b, 0x4c, 0x6c, + 0x10, 0x0c, 0x42, 0x7c, + 0x04, 0x93, 0x4a, 0x6c, + 0x01, 0x94, 0x48, 0x7c, + 0x10, 0x94, 0x4a, 0x6c, + 0xc7, 0x93, 0x26, 0x09, + 0xff, 0x99, 0xd4, 0x08, + 0x38, 0x93, 0x4e, 0x6c, + 0xff, 0x6a, 0xd4, 0x0c, + 0x80, 0x36, 0x52, 0x6c, + 0x21, 0x6a, 0x22, 0x05, + 0xff, 0x65, 0x20, 0x09, + 0xff, 0x52, 0x60, 0x64, + 0xff, 0x37, 0xc8, 0x08, + 0xa1, 0x6a, 0x6c, 0x44, + 0xff, 0x52, 0xc8, 0x08, + 0xb9, 0x6a, 0x6c, 0x44, + 0xff, 0x90, 0xa6, 0x08, + 0xff, 0xba, 0x70, 0x74, + 0xff, 0xba, 0x20, 0x09, + 0xff, 0x65, 0xca, 0x18, + 0x00, 0x6c, 0x64, 0x64, + 0xff, 0x90, 0xca, 0x0c, + 0xff, 0x6a, 0xca, 0x04, + 0x40, 0x36, 0x84, 0x7c, + 0x00, 0x90, 0x58, 0x5c, + 0xff, 0x65, 0x84, 0x74, + 0xff, 0x53, 0x82, 0x74, + 0xff, 0xba, 0xcc, 0x08, + 0xff, 0x53, 0x20, 0x09, + 0xff, 0x66, 0x74, 0x09, + 0xff, 0x65, 0x20, 0x0d, + 0xff, 0xba, 0x7e, 0x0c, + 0x00, 0x6a, 0x8e, 0x5d, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0x52, 0x18, 0x45, + 0xff, 0x3f, 0xde, 0x74, + 0xff, 0x6a, 0xa4, 0x00, + 0x00, 0x3f, 0x58, 0x5c, + 0xff, 0x65, 0xde, 0x74, + 0x40, 0x36, 0x6c, 0x00, + 0x20, 0xa0, 0x98, 0x6c, + 0xff, 0xb9, 0xa4, 0x0c, + 0xff, 0x6a, 0xa4, 0x04, + 0xff, 0x65, 0xa6, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0x0c, 0x5d, + 0x01, 0x6a, 0xd0, 0x01, + 0x09, 0x6a, 0xd6, 0x01, + 0x80, 0xeb, 0xa4, 0x7c, + 0x01, 0x6a, 0xd6, 0x01, + 0x01, 0xe9, 0xa6, 0x34, + 0x88, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0x0c, 0x5d, + 0x01, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x0d, 0x6a, 0x26, 0x01, + 0x00, 0x65, 0x7e, 0x5d, + 0xff, 0x99, 0xa6, 0x0c, + 0xff, 0x65, 0xa6, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0x0c, 0x5d, + 0x01, 0x6a, 0xd0, 0x01, + 0x01, 0x6a, 0xdc, 0x05, + 0x88, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0x0c, 0x5d, + 0x01, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x01, 0x6a, 0x26, 0x05, + 0x01, 0x65, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xd4, 0x7c, + 0xff, 0x6a, 0xdc, 0x0d, + 0xff, 0x65, 0x32, 0x09, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x7e, 0x45, + 0xff, 0x37, 0xc8, 0x08, + 0x02, 0x6a, 0x9a, 0x5c, + 0xff, 0x53, 0xa4, 0x0c, + 0xb1, 0x6a, 0x22, 0x01, + 0x01, 0x0c, 0xe6, 0x7c, + 0x04, 0x0c, 0xe4, 0x6c, + 0xe0, 0x03, 0x06, 0x08, + 0xe0, 0x03, 0x7a, 0x0c, + 0xff, 0x8c, 0x10, 0x08, + 0xff, 0x8d, 0x12, 0x08, + 0xff, 0x8e, 0x14, 0x0c, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x0c, + 0x3d, 0x64, 0xa6, 0x28, + 0x55, 0x64, 0xc8, 0x28, + 0x00, 0x65, 0x0c, 0x45, + 0x2e, 0x64, 0xa6, 0x28, + 0x66, 0x64, 0xc8, 0x28, + 0x00, 0x6c, 0xda, 0x18, + 0xff, 0x53, 0xc8, 0x08, + 0x00, 0x6c, 0xda, 0x20, + 0xff, 0x6a, 0xc8, 0x08, + 0x00, 0x6c, 0xda, 0x20, + 0x00, 0x6c, 0xda, 0x24, + 0xff, 0x65, 0xc8, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x41, 0x6a, 0x08, 0x5d, + 0xff, 0x90, 0xe2, 0x09, + 0x04, 0x35, 0x2a, 0x7d, + 0x30, 0x6a, 0xd0, 0x01, + 0x1d, 0x6a, 0xdc, 0x01, + 0xdc, 0xee, 0x26, 0x65, + 0x00, 0x65, 0x38, 0x45, + 0x1c, 0x6a, 0xd0, 0x01, + 0x01, 0x6a, 0xdc, 0x01, + 0x1c, 0xa0, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0x32, 0x7d, + 0x19, 0x6a, 0xdc, 0x01, + 0xd8, 0xee, 0x36, 0x65, + 0xff, 0x6a, 0xdc, 0x09, + 0x18, 0xee, 0x3a, 0x6d, + 0xff, 0x6a, 0xd4, 0x0c, + 0x88, 0x6a, 0xcc, 0x00, + 0x41, 0x6a, 0x08, 0x5d, + 0x1c, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0xff, 0x35, 0x26, 0x09, + 0x04, 0x35, 0x62, 0x6d, + 0xa0, 0x6a, 0xca, 0x00, + 0x1c, 0x65, 0xc8, 0x18, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0x00, 0x65, 0x50, 0x65, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x7e, 0x5d, + 0x04, 0x35, 0x52, 0x7c, + 0xa0, 0x6a, 0x6e, 0x5d, + 0x00, 0x65, 0x70, 0x5d, + 0x00, 0x65, 0x70, 0x5d, + 0x00, 0x65, 0x70, 0x45, + 0xff, 0x65, 0xcc, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x0c, + 0x08, 0x94, 0x7e, 0x7d, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x82, 0x6d, + 0xff, 0x6a, 0xd4, 0x0c, + 0xff, 0x40, 0x74, 0x09, + 0xff, 0x6a, 0x72, 0x01, + 0xff, 0x90, 0x80, 0x0c, + 0xff, 0x6a, 0x72, 0x05, + 0xff, 0x40, 0x9c, 0x65, + 0xff, 0x3f, 0x94, 0x65, + 0xff, 0x6a, 0xca, 0x04, + 0xff, 0x3f, 0x20, 0x09, + 0x01, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0x18, 0x5d, + 0xff, 0xba, 0x7e, 0x0c, + 0xff, 0x40, 0x20, 0x09, + 0xff, 0xba, 0x80, 0x0c, + 0xff, 0x3f, 0x74, 0x09, + 0xff, 0x90, 0x7e, 0x0c, +}; + +static int ahc_patch16_func(struct ahc_softc *ahc); + +static int +ahc_patch16_func(struct ahc_softc *ahc) +{ + return ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895); +} + +static int ahc_patch15_func(struct ahc_softc *ahc); + +static int +ahc_patch15_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_WIDE) != 0); +} + +static int ahc_patch14_func(struct ahc_softc *ahc); + +static int +ahc_patch14_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_HS_MAILBOX) != 0); +} + +static int ahc_patch13_func(struct ahc_softc *ahc); + +static int +ahc_patch13_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_CMD_CHAN) == 0); +} + +static int ahc_patch12_func(struct ahc_softc *ahc); + +static int +ahc_patch12_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA2) == 0); +} + +static int ahc_patch11_func(struct ahc_softc *ahc); + +static int +ahc_patch11_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_MULTI_TID) != 0); +} + +static int ahc_patch10_func(struct ahc_softc *ahc); + +static int +ahc_patch10_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_INITIATORMODE) != 0); +} + +static int ahc_patch9_func(struct ahc_softc *ahc); + +static int +ahc_patch9_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA) != 0); +} + +static int ahc_patch8_func(struct ahc_softc *ahc); + +static int +ahc_patch8_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA2) != 0); +} + +static int ahc_patch7_func(struct ahc_softc *ahc); + +static int +ahc_patch7_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_TARGETMODE) != 0); +} + +static int ahc_patch6_func(struct ahc_softc *ahc); + +static int +ahc_patch6_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_PAGESCBS) == 0); +} + +static int ahc_patch5_func(struct ahc_softc *ahc); + +static int +ahc_patch5_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_PAGESCBS) != 0); +} + +static int ahc_patch4_func(struct ahc_softc *ahc); + +static int +ahc_patch4_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_QUEUE_REGS) != 0); +} + +static int ahc_patch3_func(struct ahc_softc *ahc); + +static int +ahc_patch3_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_TWIN) != 0); +} + +static int ahc_patch2_func(struct ahc_softc *ahc); + +static int +ahc_patch2_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_QUEUE_REGS) == 0); +} + +static int ahc_patch1_func(struct ahc_softc *ahc); + +static int +ahc_patch1_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_CMD_CHAN) != 0); +} + +static int ahc_patch0_func(struct ahc_softc *ahc); + +static int +ahc_patch0_func(struct ahc_softc *ahc) +{ + return (0); +} + +typedef int patch_func_t __P((struct ahc_softc *)); +struct patch { + patch_func_t *patch_func; + u_int32_t begin :10, + skip_instr :10, + skip_patch :12; +} patches[] = { + { ahc_patch1_func, 4, 2, 1 }, + { ahc_patch2_func, 8, 1, 1 }, + { ahc_patch2_func, 9, 1, 1 }, + { ahc_patch3_func, 12, 4, 1 }, + { ahc_patch4_func, 17, 3, 2 }, + { ahc_patch0_func, 20, 4, 1 }, + { ahc_patch5_func, 24, 1, 1 }, + { ahc_patch6_func, 27, 1, 1 }, + { ahc_patch1_func, 30, 1, 2 }, + { ahc_patch0_func, 31, 3, 1 }, + { ahc_patch3_func, 40, 4, 1 }, + { ahc_patch7_func, 45, 5, 3 }, + { ahc_patch8_func, 46, 1, 2 }, + { ahc_patch0_func, 47, 1, 1 }, + { ahc_patch8_func, 50, 3, 2 }, + { ahc_patch0_func, 53, 3, 1 }, + { ahc_patch9_func, 58, 2, 1 }, + { ahc_patch8_func, 60, 1, 2 }, + { ahc_patch0_func, 61, 1, 1 }, + { ahc_patch7_func, 64, 64, 24 }, + { ahc_patch10_func, 64, 1, 1 }, + { ahc_patch1_func, 69, 3, 2 }, + { ahc_patch0_func, 72, 3, 1 }, + { ahc_patch1_func, 76, 1, 2 }, + { ahc_patch0_func, 77, 1, 1 }, + { ahc_patch1_func, 78, 3, 6 }, + { ahc_patch11_func, 78, 1, 2 }, + { ahc_patch0_func, 79, 2, 3 }, + { ahc_patch8_func, 79, 1, 2 }, + { ahc_patch0_func, 80, 1, 1 }, + { ahc_patch0_func, 81, 3, 5 }, + { ahc_patch11_func, 81, 1, 2 }, + { ahc_patch0_func, 82, 2, 3 }, + { ahc_patch8_func, 82, 1, 2 }, + { ahc_patch0_func, 83, 1, 1 }, + { ahc_patch1_func, 88, 1, 2 }, + { ahc_patch0_func, 89, 1, 1 }, + { ahc_patch1_func, 98, 1, 2 }, + { ahc_patch0_func, 99, 1, 1 }, + { ahc_patch1_func, 102, 1, 2 }, + { ahc_patch0_func, 103, 1, 1 }, + { ahc_patch1_func, 119, 1, 2 }, + { ahc_patch0_func, 120, 1, 1 }, + { ahc_patch10_func, 128, 7, 2 }, + { ahc_patch3_func, 129, 2, 1 }, + { ahc_patch7_func, 140, 85, 8 }, + { ahc_patch5_func, 155, 1, 1 }, + { ahc_patch1_func, 177, 1, 2 }, + { ahc_patch0_func, 178, 1, 1 }, + { ahc_patch1_func, 187, 1, 2 }, + { ahc_patch0_func, 188, 1, 1 }, + { ahc_patch1_func, 209, 6, 2 }, + { ahc_patch0_func, 215, 8, 1 }, + { ahc_patch10_func, 225, 20, 1 }, + { ahc_patch8_func, 246, 1, 2 }, + { ahc_patch0_func, 247, 2, 1 }, + { ahc_patch8_func, 251, 2, 2 }, + { ahc_patch0_func, 253, 3, 3 }, + { ahc_patch1_func, 253, 1, 2 }, + { ahc_patch0_func, 254, 2, 1 }, + { ahc_patch8_func, 258, 1, 2 }, + { ahc_patch0_func, 259, 1, 1 }, + { ahc_patch1_func, 263, 1, 1 }, + { ahc_patch1_func, 266, 1, 2 }, + { ahc_patch0_func, 267, 2, 1 }, + { ahc_patch12_func, 270, 2, 3 }, + { ahc_patch1_func, 270, 1, 2 }, + { ahc_patch0_func, 271, 1, 1 }, + { ahc_patch1_func, 272, 1, 2 }, + { ahc_patch0_func, 273, 2, 1 }, + { ahc_patch8_func, 278, 1, 2 }, + { ahc_patch0_func, 279, 4, 3 }, + { ahc_patch1_func, 279, 1, 2 }, + { ahc_patch0_func, 280, 3, 1 }, + { ahc_patch8_func, 284, 1, 2 }, + { ahc_patch0_func, 285, 3, 2 }, + { ahc_patch7_func, 285, 2, 1 }, + { ahc_patch8_func, 288, 5, 2 }, + { ahc_patch0_func, 293, 1, 1 }, + { ahc_patch1_func, 300, 13, 2 }, + { ahc_patch0_func, 313, 8, 1 }, + { ahc_patch12_func, 323, 2, 3 }, + { ahc_patch1_func, 323, 1, 2 }, + { ahc_patch0_func, 324, 1, 1 }, + { ahc_patch7_func, 328, 1, 1 }, + { ahc_patch8_func, 331, 2, 1 }, + { ahc_patch8_func, 333, 1, 1 }, + { ahc_patch1_func, 334, 1, 2 }, + { ahc_patch0_func, 335, 3, 1 }, + { ahc_patch8_func, 339, 1, 1 }, + { ahc_patch7_func, 340, 5, 1 }, + { ahc_patch8_func, 346, 2, 1 }, + { ahc_patch8_func, 351, 13, 1 }, + { ahc_patch10_func, 364, 96, 13 }, + { ahc_patch1_func, 365, 11, 5 }, + { ahc_patch12_func, 367, 1, 1 }, + { ahc_patch8_func, 371, 1, 2 }, + { ahc_patch0_func, 372, 1, 1 }, + { ahc_patch0_func, 376, 4, 1 }, + { ahc_patch12_func, 380, 2, 3 }, + { ahc_patch13_func, 380, 1, 1 }, + { ahc_patch0_func, 382, 1, 1 }, + { ahc_patch14_func, 398, 3, 1 }, + { ahc_patch3_func, 402, 2, 2 }, + { ahc_patch0_func, 404, 2, 2 }, + { ahc_patch15_func, 404, 2, 1 }, + { ahc_patch4_func, 462, 1, 2 }, + { ahc_patch0_func, 463, 1, 1 }, + { ahc_patch2_func, 466, 1, 1 }, + { ahc_patch10_func, 468, 58, 6 }, + { ahc_patch1_func, 472, 3, 2 }, + { ahc_patch0_func, 475, 5, 1 }, + { ahc_patch15_func, 483, 1, 2 }, + { ahc_patch0_func, 484, 1, 1 }, + { ahc_patch5_func, 489, 1, 1 }, + { ahc_patch7_func, 526, 16, 1 }, + { ahc_patch12_func, 551, 1, 1 }, + { ahc_patch1_func, 590, 7, 2 }, + { ahc_patch0_func, 597, 8, 1 }, + { ahc_patch1_func, 606, 4, 2 }, + { ahc_patch0_func, 610, 6, 1 }, + { ahc_patch1_func, 616, 4, 2 }, + { ahc_patch0_func, 620, 3, 1 }, + { ahc_patch13_func, 631, 10, 1 }, + { ahc_patch7_func, 641, 3, 1 }, + { ahc_patch1_func, 653, 18, 4 }, + { ahc_patch16_func, 662, 4, 2 }, + { ahc_patch0_func, 666, 2, 1 }, + { ahc_patch0_func, 671, 32, 1 }, + { ahc_patch5_func, 707, 3, 2 }, + { ahc_patch0_func, 710, 1, 1 }, + { ahc_patch5_func, 711, 9, 1 }, + +}; diff --git a/sys/dev/microcode/aic7xxx/aicasm.c b/sys/dev/microcode/aic7xxx/aicasm.c new file mode 100644 index 00000000000..c293601fe8a --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aicasm.c @@ -0,0 +1,721 @@ +/* $OpenBSD: aicasm.c,v 1.1 2000/03/22 02:50:49 smurph Exp $ */ +/* + * Aic7xxx SCSI host adapter firmware asssembler + * + * Copyright (c) 1997, 1998 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm.c,v 1.23 1999/08/28 00:41:25 peter Exp $ + */ +#include <sys/types.h> +#include <sys/mman.h> + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "sequencer.h" + +typedef struct patch { + TAILQ_ENTRY(patch) links; + int patch_func; + u_int begin; + u_int skip_instr; + u_int skip_patch; +} patch_t; + +TAILQ_HEAD(patch_list, patch) patches; + +static void usage(void); +static void back_patch(void); +static void output_code(FILE *ofile); +static void output_listing(FILE *listfile, char *ifilename); +static void dump_scope(scope_t *scope); +static void emit_patch(scope_t *scope, int patch); +static int check_patch(patch_t **start_patch, int start_instr, + int *skip_addr, int *func_vals); + +struct path_list search_path; +int includes_search_curdir; +char *appname; +FILE *ofile; +char *ofilename; +char *regfilename; +FILE *regfile; +char *listfilename; +FILE *listfile; + +static TAILQ_HEAD(,instruction) seq_program; +struct scope_list scope_stack; +symlist_t patch_functions; + +#if DEBUG +extern int yy_flex_debug; +extern int yydebug; +#endif +extern FILE *yyin; +extern int yyparse __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + int ch; + int retval; + char *inputfilename; + scope_t *sentinal; + + TAILQ_INIT(&patches); + SLIST_INIT(&search_path); + TAILQ_INIT(&seq_program); + SLIST_INIT(&scope_stack); + + /* Set Sentinal scope node */ + sentinal = scope_alloc(); + sentinal->type = SCOPE_ROOT; + + includes_search_curdir = 1; + appname = *argv; + regfile = NULL; + listfile = NULL; +#if DEBUG + yy_flex_debug = 0; + yydebug = 0; +#endif + while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) { + switch(ch) { + case 'd': +#if DEBUG + if (strcmp(optarg, "s") == 0) { + yy_flex_debug = 1; + } else if (strcmp(optarg, "p") == 0) { + yydebug = 1; + } else { + fprintf(stderr, "%s: -d Requires either an " + "'s' or 'p' argument\n", appname); + usage(); + } +#else + stop("-d: Assembler not built with debugging " + "information", EX_SOFTWARE); +#endif + break; + case 'l': + /* Create a program listing */ + if ((listfile = fopen(optarg, "w")) == NULL) { + perror(optarg); + stop(NULL, EX_CANTCREAT); + } + listfilename = optarg; + break; + case 'n': + /* Don't complain about the -nostdinc directrive */ + if (strcmp(optarg, "ostdinc")) { + fprintf(stderr, "%s: Unknown option -%c%s\n", + appname, ch, optarg); + usage(); + /* NOTREACHED */ + } + break; + case 'o': + if ((ofile = fopen(optarg, "w")) == NULL) { + perror(optarg); + stop(NULL, EX_CANTCREAT); + } + ofilename = optarg; + break; + case 'r': + if ((regfile = fopen(optarg, "w")) == NULL) { + perror(optarg); + stop(NULL, EX_CANTCREAT); + } + regfilename = optarg; + break; + case 'I': + { + path_entry_t include_dir; + + if (strcmp(optarg, "-") == 0) { + if (includes_search_curdir == 0) { + fprintf(stderr, "%s: Warning - '-I-' " + "specified multiple " + "times\n", appname); + } + includes_search_curdir = 0; + for (include_dir = search_path.slh_first; + include_dir != NULL; + include_dir = include_dir->links.sle_next) + /* + * All entries before a '-I-' only + * apply to includes specified with + * quotes instead of "<>". + */ + include_dir->quoted_includes_only = 1; + } else { + include_dir = + (path_entry_t)malloc(sizeof(*include_dir)); + if (include_dir == NULL) { + perror(optarg); + stop(NULL, EX_OSERR); + } + include_dir->directory = strdup(optarg); + if (include_dir->directory == NULL) { + perror(optarg); + stop(NULL, EX_OSERR); + } + include_dir->quoted_includes_only = 0; + SLIST_INSERT_HEAD(&search_path, include_dir, + links); + } + break; + } + case '?': + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc != 1) { + fprintf(stderr, "%s: No input file specifiled\n", appname); + usage(); + /* NOTREACHED */ + } + + symtable_open(); + inputfilename = *argv; + include_file(*argv, SOURCE_FILE); + retval = yyparse(); + if (retval == 0) { + if (SLIST_FIRST(&scope_stack) == NULL + || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { + stop("Unterminated conditional expression", + EX_DATAERR); + /* NOTREACHED */ + } + + /* Process outmost scope */ + process_scope(SLIST_FIRST(&scope_stack)); + /* + * Decend the tree of scopes and insert/emit + * patches as appropriate. We perform a depth first + * tranversal, recursively handling each scope. + */ + /* start at the root scope */ + dump_scope(SLIST_FIRST(&scope_stack)); + + /* Patch up forward jump addresses */ + back_patch(); + + if (ofile != NULL) + output_code(ofile); + if (regfile != NULL) { + symtable_dump(regfile); + } + if (listfile != NULL) + output_listing(listfile, inputfilename); + } + + stop(NULL, 0); + /* NOTREACHED */ + return (0); +} + +static void +usage() +{ + + (void)fprintf(stderr, +"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file] + [-r register_output_file] [-l program_list_file] + input_file\n", + appname); + exit(EX_USAGE); +} + +static void +back_patch() +{ + struct instruction *cur_instr; + + for(cur_instr = seq_program.tqh_first; + cur_instr != NULL; + cur_instr = cur_instr->links.tqe_next) { + if (cur_instr->patch_label != NULL) { + struct ins_format3 *f3_instr; + u_int address; + + if (cur_instr->patch_label->type != LABEL) { + char buf[255]; + + snprintf(buf, sizeof(buf), + "Undefined label %s", + cur_instr->patch_label->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + } + f3_instr = &cur_instr->format.format3; + address = f3_instr->address; + address += cur_instr->patch_label->info.linfo->address; + f3_instr->address = address; + } + } +} + +static void +output_code(ofile) + FILE *ofile; +{ + struct instruction *cur_instr; + patch_t *cur_patch; + symbol_node_t *cur_node; + int instrcount; + + instrcount = 0; + fprintf(ofile, +"/* + * DO NOT EDIT - This file is automatically generated. + */\n"); + + fprintf(ofile, "static u_int8_t seqprog[] = {\n"); + for(cur_instr = seq_program.tqh_first; + cur_instr != NULL; + cur_instr = cur_instr->links.tqe_next) { + + fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n", + cur_instr->format.bytes[0], + cur_instr->format.bytes[1], + cur_instr->format.bytes[2], + cur_instr->format.bytes[3]); + instrcount++; + } + fprintf(ofile, "};\n\n"); + + /* + * Output patch information. Patch functions first. + */ + for(cur_node = SLIST_FIRST(&patch_functions); + cur_node != NULL; + cur_node = SLIST_NEXT(cur_node,links)) { + fprintf(ofile, +"static int ahc_patch%d_func(struct ahc_softc *ahc); + +static int +ahc_patch%d_func(struct ahc_softc *ahc) +{ + return (%s); +}\n\n", + cur_node->symbol->info.condinfo->func_num, + cur_node->symbol->info.condinfo->func_num, + cur_node->symbol->name); + } + + fprintf(ofile, +"typedef int patch_func_t __P((struct ahc_softc *)); +struct patch { + patch_func_t *patch_func; + u_int32_t begin :10, + skip_instr :10, + skip_patch :12; +} patches[] = {\n"); + + for(cur_patch = TAILQ_FIRST(&patches); + cur_patch != NULL; + cur_patch = TAILQ_NEXT(cur_patch,links)) { + fprintf(ofile, "\t{ ahc_patch%d_func, %d, %d, %d },\n", + cur_patch->patch_func, cur_patch->begin, + cur_patch->skip_instr, cur_patch->skip_patch); + } + + fprintf(ofile, "\n};\n"); + + fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); +} + +static void +dump_scope(scope_t *scope) +{ + scope_t *cur_scope; + + /* + * Emit the first patch for this scope + */ + emit_patch(scope, 0); + + /* + * Dump each scope within this one. + */ + cur_scope = TAILQ_FIRST(&scope->inner_scope); + + while (cur_scope != NULL) { + + dump_scope(cur_scope); + + cur_scope = TAILQ_NEXT(cur_scope, scope_links); + } + + /* + * Emit the second, closing, patch for this scope + */ + emit_patch(scope, 1); +} + +void +emit_patch(scope_t *scope, int patch) +{ + patch_info_t *pinfo; + patch_t *new_patch; + + pinfo = &scope->patches[patch]; + + if (pinfo->skip_instr == 0) + /* No-Op patch */ + return; + + new_patch = (patch_t *)malloc(sizeof(*new_patch)); + + if (new_patch == NULL) + stop("Could not malloc patch structure", EX_OSERR); + + memset(new_patch, 0, sizeof(*new_patch)); + + if (patch == 0) { + new_patch->patch_func = scope->func_num; + new_patch->begin = scope->begin_addr; + } else { + new_patch->patch_func = 0; + new_patch->begin = scope->end_addr; + } + new_patch->skip_instr = pinfo->skip_instr; + new_patch->skip_patch = pinfo->skip_patch; + TAILQ_INSERT_TAIL(&patches, new_patch, links); +} + +void +output_listing(FILE *listfile, char *ifilename) +{ + char buf[1024]; + FILE *ifile; + struct instruction *cur_instr; + patch_t *cur_patch; + symbol_node_t *cur_func; + int *func_values; + int instrcount; + int instrptr; + int line; + int func_count; + int skip_addr; + + instrcount = 0; + instrptr = 0; + line = 1; + skip_addr = 0; + if ((ifile = fopen(ifilename, "r")) == NULL) { + perror(ifilename); + stop(NULL, EX_DATAERR); + } + + /* + * Determine which options to apply to this listing. + */ + for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions); + cur_func != NULL; + cur_func = SLIST_NEXT(cur_func, links)) + func_count++; + + if (func_count != 0) { + func_values = (int *)malloc(func_count * sizeof(int)); + + if (func_values == NULL) + stop("Could not malloc", EX_OSERR); + + func_values[0] = 0; /* FALSE func */ + func_count--; + + /* + * Ask the user to fill in the return values for + * the rest of the functions. + */ + + + for (cur_func = SLIST_FIRST(&patch_functions); + cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL; + cur_func = SLIST_NEXT(cur_func, links), func_count--) { + int input; + + fprintf(stdout, "\n(%s)\n", cur_func->symbol->name); + fprintf(stdout, + "Enter the return value for " + "this expression[T/F]:"); + + while (1) { + + input = getchar(); + input = toupper(input); + + if (input == 'T') { + func_values[func_count] = 1; + break; + } else if (input == 'F') { + func_values[func_count] = 0; + break; + } + } + if (isatty(fileno(stdin)) == 0) + putchar(input); + } + fprintf(stdout, "\nThanks!\n"); + } + + /* Now output the listing */ + cur_patch = TAILQ_FIRST(&patches); + for(cur_instr = TAILQ_FIRST(&seq_program); + cur_instr != NULL; + cur_instr = TAILQ_NEXT(cur_instr, links), instrcount++) { + + if (check_patch(&cur_patch, instrcount, + &skip_addr, func_values) == 0) { + /* Don't count this instruction as it is in a patch + * that was removed. + */ + continue; + } + + while (line < cur_instr->srcline) { + fgets(buf, sizeof(buf), ifile); + fprintf(listfile, "\t\t%s", buf); + line++; + } + fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, + cur_instr->format.bytes[0], + cur_instr->format.bytes[1], + cur_instr->format.bytes[2], + cur_instr->format.bytes[3]); + fgets(buf, sizeof(buf), ifile); + fprintf(listfile, "\t%s", buf); + line++; + instrptr++; + } + /* Dump the remainder of the file */ + while(fgets(buf, sizeof(buf), ifile) != NULL) + fprintf(listfile, "\t\t%s", buf); + + fclose(ifile); +} + +static int +check_patch(patch_t **start_patch, int start_instr, + int *skip_addr, int *func_vals) +{ + patch_t *cur_patch; + + cur_patch = *start_patch; + + while (cur_patch != NULL && start_instr == cur_patch->begin) { + if (func_vals[cur_patch->patch_func] == 0) { + int skip; + + /* Start rejecting code */ + *skip_addr = start_instr + cur_patch->skip_instr; + for (skip = cur_patch->skip_patch; + skip > 0 && cur_patch != NULL; + skip--) + cur_patch = TAILQ_NEXT(cur_patch, links); + } else { + /* Accepted this patch. Advance to the next + * one and wait for our intruction pointer to + * hit this point. + */ + cur_patch = TAILQ_NEXT(cur_patch, links); + } + } + + *start_patch = cur_patch; + if (start_instr < *skip_addr) + /* Still skipping */ + return (0); + + return (1); +} + +/* + * Print out error information if appropriate, and clean up before + * terminating the program. + */ +void +stop(string, err_code) + const char *string; + int err_code; +{ + if (string != NULL) { + fprintf(stderr, "%s: ", appname); + if (yyfilename != NULL) { + fprintf(stderr, "Stopped at file %s, line %d - ", + yyfilename, yylineno); + } + fprintf(stderr, "%s\n", string); + } + + if (ofile != NULL) { + fclose(ofile); + if (err_code != 0) { + fprintf(stderr, "%s: Removing %s due to error\n", + appname, ofilename); + unlink(ofilename); + } + } + + if (regfile != NULL) { + fclose(regfile); + if (err_code != 0) { + fprintf(stderr, "%s: Removing %s due to error\n", + appname, regfilename); + unlink(regfilename); + } + } + + if (listfile != NULL) { + fclose(listfile); + if (err_code != 0) { + fprintf(stderr, "%s: Removing %s due to error\n", + appname, listfilename); + unlink(listfilename); + } + } + + symlist_free(&patch_functions); + symtable_close(); + + exit(err_code); +} + +struct instruction * +seq_alloc() +{ + struct instruction *new_instr; + + new_instr = (struct instruction *)malloc(sizeof(struct instruction)); + if (new_instr == NULL) + stop("Unable to malloc instruction object", EX_SOFTWARE); + memset(new_instr, 0, sizeof(*new_instr)); + TAILQ_INSERT_TAIL(&seq_program, new_instr, links); + new_instr->srcline = yylineno; + return new_instr; +} + +scope_t * +scope_alloc() +{ + scope_t *new_scope; + + new_scope = (scope_t *)malloc(sizeof(scope_t)); + if (new_scope == NULL) + stop("Unable to malloc scope object", EX_SOFTWARE); + memset(new_scope, 0, sizeof(*new_scope)); + TAILQ_INIT(&new_scope->inner_scope); + + if (SLIST_FIRST(&scope_stack) != NULL) { + TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope, + new_scope, scope_links); + } + /* This patch is now the current scope */ + SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links); + return new_scope; +} + +void +process_scope(scope_t *scope) +{ + /* + * We are "leaving" this scope. We should now have + * enough information to process the lists of scopes + * we encapsulate. + */ + scope_t *cur_scope; + u_int skip_patch_count; + u_int skip_instr_count; + + cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq); + skip_patch_count = 0; + skip_instr_count = 0; + while (cur_scope != NULL) { + u_int patch0_patch_skip; + + patch0_patch_skip = 0; + switch (cur_scope->type) { + case SCOPE_IF: + case SCOPE_ELSE_IF: + if (skip_instr_count != 0) { + /* Create a tail patch */ + patch0_patch_skip++; + cur_scope->patches[1].skip_patch = + skip_patch_count + 1; + cur_scope->patches[1].skip_instr = + skip_instr_count; + } + + /* Count Head patch */ + patch0_patch_skip++; + + /* Count any patches contained in our inner scope */ + patch0_patch_skip += cur_scope->inner_scope_patches; + + cur_scope->patches[0].skip_patch = patch0_patch_skip; + cur_scope->patches[0].skip_instr = + cur_scope->end_addr - cur_scope->begin_addr; + + skip_instr_count += cur_scope->patches[0].skip_instr; + + skip_patch_count += patch0_patch_skip; + if (cur_scope->type == SCOPE_IF) { + scope->inner_scope_patches += skip_patch_count; + skip_patch_count = 0; + skip_instr_count = 0; + } + break; + case SCOPE_ELSE: + /* Count any patches contained in our innter scope */ + skip_patch_count += cur_scope->inner_scope_patches; + + skip_instr_count += cur_scope->end_addr + - cur_scope->begin_addr; + break; + case SCOPE_ROOT: + stop("Unexpected scope type encountered", EX_SOFTWARE); + /* NOTREACHED */ + } + + cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links); + } +} diff --git a/sys/dev/microcode/aic7xxx/aicasm.h b/sys/dev/microcode/aic7xxx/aicasm.h new file mode 100644 index 00000000000..92f7e17a62b --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aicasm.h @@ -0,0 +1,68 @@ +/* $OpenBSD: aicasm.h,v 1.1 2000/03/22 02:50:49 smurph Exp $ */ +/* + * Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm.h,v 1.6 1999/12/06 18:23:30 gibbs Exp $ + */ + +#include <sys/queue.h> + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +typedef struct path_entry { + char *directory; + int quoted_includes_only; + SLIST_ENTRY(path_entry) links; +} *path_entry_t; + +typedef enum { + QUOTED_INCLUDE, + BRACKETED_INCLUDE, + SOURCE_FILE +} include_type; + +SLIST_HEAD(path_list, path_entry); + +extern struct path_list search_path; +extern struct scope_list scope_stack; +extern struct symlist patch_functions; +extern int includes_search_curdir; /* False if we've seen -I- */ +extern char *appname; +extern int yylineno; +extern char *yyfilename; + +void stop(const char *errstring, int err_code); +void include_file(char *file_name, include_type type); +struct instruction *seq_alloc(void); +struct scope *scope_alloc(void); +void process_scope(struct scope *); diff --git a/sys/dev/microcode/aic7xxx/aicasm_gram.y b/sys/dev/microcode/aic7xxx/aicasm_gram.y new file mode 100644 index 00000000000..38b0dbcb53e --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aicasm_gram.y @@ -0,0 +1,1410 @@ +%{ +/* + * Parser for the Aic7xxx SCSI Host adapter sequencer assembler. + * + * Copyright (c) 1997-1998 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm_gram.y,v 1.8 1999/12/06 18:23:30 gibbs Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> + +#include <sys/types.h> +#include <sys/queue.h> + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "sequencer.h" + +int yylineno; +char *yyfilename; +static symbol_t *cur_symbol; +static symtype cur_symtype; +static symbol_t *accumulator; +static symbol_ref_t allones; +static symbol_ref_t allzeros; +static symbol_ref_t none; +static symbol_ref_t sindex; +static int instruction_ptr; +static int sram_or_scb_offset; +static int download_constant_count; + +static void process_bitmask __P((int mask_type, symbol_t *sym, int mask)); +static void initialize_symbol __P((symbol_t *symbol)); +static void process_register __P((symbol_t **p_symbol)); +static void format_1_instr __P((int opcode, symbol_ref_t *dest, + expression_t *immed, symbol_ref_t *src, + int ret)); +static void format_2_instr __P((int opcode, symbol_ref_t *dest, + expression_t *places, symbol_ref_t *src, + int ret)); +static void format_3_instr __P((int opcode, symbol_ref_t *src, + expression_t *immed, symbol_ref_t *address)); +static void test_readable_symbol __P((symbol_t *symbol)); +static void test_writable_symbol __P((symbol_t *symbol)); +static void type_check __P((symbol_t *symbol, expression_t *expression, + int and_op)); +static void make_expression __P((expression_t *immed, int value)); +static void add_conditional __P((symbol_t *symbol)); +static int is_download_const __P((expression_t *immed)); + +#define YYDEBUG 1 +#define SRAM_SYMNAME "SRAM_BASE" +#define SCB_SYMNAME "SCB_BASE" +%} + +%union { + int value; + char *str; + symbol_t *sym; + symbol_ref_t sym_ref; + expression_t expression; +} + +%token T_REGISTER + +%token <value> T_CONST + +%token T_DOWNLOAD + +%token T_SCB + +%token T_SRAM + +%token T_ALIAS + +%token T_SIZE + +%token <value> T_ADDRESS + +%token T_ACCESS_MODE + +%token <value> T_MODE + +%token T_BIT + +%token T_MASK + +%token <value> T_NUMBER + +%token <str> T_PATH + +%token <sym> T_CEXPR + +%token T_EOF T_INCLUDE + +%token <value> T_SHR T_SHL T_ROR T_ROL + +%token <value> T_MVI T_MOV T_CLR T_BMOV + +%token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL + +%token <value> T_ADD T_ADC + +%token <value> T_INC T_DEC + +%token <value> T_STC T_CLC + +%token <value> T_CMP T_XOR + +%token <value> T_TEST T_AND + +%token <value> T_OR + +%token T_RET + +%token T_NOP + +%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX + +%token T_A + +%token <sym> T_SYMBOL + +%token T_NL + +%token T_IF T_ELSE T_ELSE_IF T_ENDIF + +%type <sym_ref> reg_symbol address destination source opt_source + +%type <expression> expression immediate immediate_or_a + +%type <value> ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne + +%type <value> numerical_value + +%left '|' +%left '&' +%left '+' '-' +%right '~' +%nonassoc UMINUS +%% + +program: + include +| program include +| register +| program register +| constant +| program constant +| scratch_ram +| program scratch_ram +| scb +| program scb +| label +| program label +| conditional +| program conditional +| code +| program code +; + +include: + T_INCLUDE '<' T_PATH '>' + { include_file($3, BRACKETED_INCLUDE); } +| T_INCLUDE '"' T_PATH '"' + { include_file($3, QUOTED_INCLUDE); } +; + +register: + T_REGISTER { cur_symtype = REGISTER; } reg_definition +; + +reg_definition: + T_SYMBOL '{' + { + if ($1->type != UNINITIALIZED) { + stop("Register multiply defined", EX_DATAERR); + /* NOTREACHED */ + } + cur_symbol = $1; + cur_symbol->type = cur_symtype; + initialize_symbol(cur_symbol); + } + reg_attribute_list + '}' + { + /* + * Default to allowing everything in for registers + * with no bit or mask definitions. + */ + if (cur_symbol->info.rinfo->valid_bitmask == 0) + cur_symbol->info.rinfo->valid_bitmask = 0xFF; + + if (cur_symbol->info.rinfo->size == 0) + cur_symbol->info.rinfo->size = 1; + + /* + * This might be useful for registers too. + */ + if (cur_symbol->type != REGISTER) { + if (cur_symbol->info.rinfo->address == 0) + cur_symbol->info.rinfo->address = + sram_or_scb_offset; + sram_or_scb_offset += + cur_symbol->info.rinfo->size; + } + cur_symbol = NULL; + } +; + +reg_attribute_list: + reg_attribute +| reg_attribute_list reg_attribute +; + +reg_attribute: + reg_address +| size +| access_mode +| bit_defn +| mask_defn +| alias +| accumulator +| allones +| allzeros +| none +| sindex +; + +reg_address: + T_ADDRESS T_NUMBER + { + cur_symbol->info.rinfo->address = $2; + } +; + +size: + T_SIZE T_NUMBER + { + cur_symbol->info.rinfo->size = $2; + } +; + +access_mode: + T_ACCESS_MODE T_MODE + { + cur_symbol->info.rinfo->mode = $2; + } +; + +bit_defn: + T_BIT T_SYMBOL T_NUMBER + { + process_bitmask(BIT, $2, $3); + } +; + +mask_defn: + T_MASK T_SYMBOL expression + { + process_bitmask(MASK, $2, $3.value); + } +; + +alias: + T_ALIAS T_SYMBOL + { + if ($2->type != UNINITIALIZED) { + stop("Re-definition of register alias", + EX_DATAERR); + /* NOTREACHED */ + } + $2->type = ALIAS; + initialize_symbol($2); + $2->info.ainfo->parent = cur_symbol; + } +; + +accumulator: + T_ACCUM + { + if (accumulator != NULL) { + stop("Only one accumulator definition allowed", + EX_DATAERR); + /* NOTREACHED */ + } + accumulator = cur_symbol; + } +; + +allones: + T_ALLONES + { + if (allones.symbol != NULL) { + stop("Only one definition of allones allowed", + EX_DATAERR); + /* NOTREACHED */ + } + allones.symbol = cur_symbol; + } +; + +allzeros: + T_ALLZEROS + { + if (allzeros.symbol != NULL) { + stop("Only one definition of allzeros allowed", + EX_DATAERR); + /* NOTREACHED */ + } + allzeros.symbol = cur_symbol; + } +; + +none: + T_NONE + { + if (none.symbol != NULL) { + stop("Only one definition of none allowed", + EX_DATAERR); + /* NOTREACHED */ + } + none.symbol = cur_symbol; + } +; + +sindex: + T_SINDEX + { + if (sindex.symbol != NULL) { + stop("Only one definition of sindex allowed", + EX_DATAERR); + /* NOTREACHED */ + } + sindex.symbol = cur_symbol; + } +; + +expression: + expression '|' expression + { + $$.value = $1.value | $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } +| expression '&' expression + { + $$.value = $1.value & $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } +| expression '+' expression + { + $$.value = $1.value + $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } +| expression '-' expression + { + $$.value = $1.value - $3.value; + symlist_merge(&($$.referenced_syms), + &($1.referenced_syms), + &($3.referenced_syms)); + } +| '(' expression ')' + { + $$ = $2; + } +| '~' expression + { + $$ = $2; + $$.value = (~$$.value) & 0xFF; + } +| '-' expression %prec UMINUS + { + $$ = $2; + $$.value = -$$.value; + } +| T_NUMBER + { + $$.value = $1; + SLIST_INIT(&$$.referenced_syms); + } +| T_SYMBOL + { + symbol_t *symbol; + + symbol = $1; + switch (symbol->type) { + case ALIAS: + symbol = $1->info.ainfo->parent; + case REGISTER: + case SCBLOC: + case SRAMLOC: + $$.value = symbol->info.rinfo->address; + break; + case MASK: + case BIT: + $$.value = symbol->info.minfo->mask; + break; + case DOWNLOAD_CONST: + case CONST: + $$.value = symbol->info.cinfo->value; + break; + case UNINITIALIZED: + default: + { + char buf[255]; + + snprintf(buf, sizeof(buf), + "Undefined symbol %s referenced", + symbol->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + break; + } + } + SLIST_INIT(&$$.referenced_syms); + symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD); + } +; + +constant: + T_CONST T_SYMBOL numerical_value + { + if ($2->type != UNINITIALIZED) { + stop("Re-definition of symbol as a constant", + EX_DATAERR); + /* NOTREACHED */ + } + $2->type = CONST; + initialize_symbol($2); + $2->info.cinfo->value = $3; + $2->info.cinfo->define = $1; + } +| T_CONST T_SYMBOL T_DOWNLOAD + { + if ($1) { + stop("Invalid downloaded constant declaration", + EX_DATAERR); + /* NOTREACHED */ + } + if ($2->type != UNINITIALIZED) { + stop("Re-definition of symbol as a downloaded constant", + EX_DATAERR); + /* NOTREACHED */ + } + $2->type = DOWNLOAD_CONST; + initialize_symbol($2); + $2->info.cinfo->value = download_constant_count++; + $2->info.cinfo->define = FALSE; + } +; + +numerical_value: + T_NUMBER + { + $$ = $1; + } +| '-' T_NUMBER + { + $$ = -$2; + } +; + +scratch_ram: + T_SRAM '{' + { + cur_symbol = symtable_get(SRAM_SYMNAME); + cur_symtype = SRAMLOC; + if (cur_symbol->type != UNINITIALIZED) { + stop("Only one SRAM definition allowed", + EX_DATAERR); + /* NOTREACHED */ + } + cur_symbol->type = SRAMLOC; + initialize_symbol(cur_symbol); + } + reg_address + { + sram_or_scb_offset = cur_symbol->info.rinfo->address; + } + scb_or_sram_reg_list + '}' + { + cur_symbol = NULL; + } +; + +scb: + T_SCB '{' + { + cur_symbol = symtable_get(SCB_SYMNAME); + cur_symtype = SCBLOC; + if (cur_symbol->type != UNINITIALIZED) { + stop("Only one SRAM definition allowed", + EX_SOFTWARE); + /* NOTREACHED */ + } + cur_symbol->type = SCBLOC; + initialize_symbol(cur_symbol); + } + reg_address + { + sram_or_scb_offset = cur_symbol->info.rinfo->address; + } + scb_or_sram_reg_list + '}' + { + cur_symbol = NULL; + } +; + +scb_or_sram_reg_list: + reg_definition +| scb_or_sram_reg_list reg_definition +; + +reg_symbol: + T_SYMBOL + { + process_register(&$1); + $$.symbol = $1; + $$.offset = 0; + } +| T_SYMBOL '[' T_NUMBER ']' + { + process_register(&$1); + if (($3 + 1) > $1->info.rinfo->size) { + stop("Accessing offset beyond range of register", + EX_DATAERR); + /* NOTREACHED */ + } + $$.symbol = $1; + $$.offset = $3; + } +| T_A + { + if (accumulator == NULL) { + stop("No accumulator has been defined", EX_DATAERR); + /* NOTREACHED */ + } + $$.symbol = accumulator; + $$.offset = 0; + } +; + +destination: + reg_symbol + { + test_writable_symbol($1.symbol); + $$ = $1; + } +; + +immediate: + expression + { $$ = $1; } +; + +immediate_or_a: + expression + { + $$ = $1; + } +| T_A + { + SLIST_INIT(&$$.referenced_syms); + $$.value = 0; + } +; + +source: + reg_symbol + { + test_readable_symbol($1.symbol); + $$ = $1; + } +; + +opt_source: + { + $$.symbol = NULL; + $$.offset = 0; + } +| ',' source + { $$ = $2; } +; + +ret: + { $$ = 0; } +| T_RET + { $$ = 1; } +; + +label: + T_SYMBOL ':' + { + if ($1->type != UNINITIALIZED) { + stop("Program label multiply defined", EX_DATAERR); + /* NOTREACHED */ + } + $1->type = LABEL; + initialize_symbol($1); + $1->info.linfo->address = instruction_ptr; + } +; + +address: + T_SYMBOL + { + $$.symbol = $1; + $$.offset = 0; + } +| T_SYMBOL '+' T_NUMBER + { + $$.symbol = $1; + $$.offset = $3; + } +| T_SYMBOL '-' T_NUMBER + { + $$.symbol = $1; + $$.offset = -$3; + } +| '.' + { + $$.symbol = NULL; + $$.offset = 0; + } +| '.' '+' T_NUMBER + { + $$.symbol = NULL; + $$.offset = $3; + } +| '.' '-' T_NUMBER + { + $$.symbol = NULL; + $$.offset = -$3; + } +; + +conditional: + T_IF T_CEXPR '{' + { + scope_t *new_scope; + + add_conditional($2); + new_scope = scope_alloc(); + new_scope->type = SCOPE_IF; + new_scope->begin_addr = instruction_ptr; + new_scope->func_num = $2->info.condinfo->func_num; + } +| T_ELSE T_IF T_CEXPR '{' + { + scope_t *new_scope; + scope_t *scope_context; + scope_t *last_scope; + + /* + * Ensure that the previous scope is either an + * if or and else if. + */ + scope_context = SLIST_FIRST(&scope_stack); + last_scope = TAILQ_LAST(&scope_context->inner_scope, + scope_tailq); + if (last_scope == NULL + || last_scope->type == T_ELSE) { + + stop("'else if' without leading 'if'", EX_DATAERR); + /* NOTREACHED */ + } + add_conditional($3); + new_scope = scope_alloc(); + new_scope->type = SCOPE_ELSE_IF; + new_scope->begin_addr = instruction_ptr; + new_scope->func_num = $3->info.condinfo->func_num; + } +| T_ELSE '{' + { + scope_t *new_scope; + scope_t *scope_context; + scope_t *last_scope; + + /* + * Ensure that the previous scope is either an + * if or and else if. + */ + scope_context = SLIST_FIRST(&scope_stack); + last_scope = TAILQ_LAST(&scope_context->inner_scope, + scope_tailq); + if (last_scope == NULL + || last_scope->type == SCOPE_ELSE) { + + stop("'else' without leading 'if'", EX_DATAERR); + /* NOTREACHED */ + } + new_scope = scope_alloc(); + new_scope->type = SCOPE_ELSE; + new_scope->begin_addr = instruction_ptr; + } +; + +conditional: + '}' + { + scope_t *scope_context; + scope_t *last_scope; + + scope_context = SLIST_FIRST(&scope_stack); + if (scope_context->type == SCOPE_ROOT) { + stop("Unexpected '}' encountered", EX_DATAERR); + /* NOTREACHED */ + } + + scope_context->end_addr = instruction_ptr; + + /* Pop the scope */ + SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links); + + process_scope(scope_context); + + if (SLIST_FIRST(&scope_stack) == NULL) { + stop("Unexpected '}' encountered", EX_DATAERR); + /* NOTREACHED */ + } + } +; + +f1_opcode: + T_AND { $$ = AIC_OP_AND; } +| T_XOR { $$ = AIC_OP_XOR; } +| T_ADD { $$ = AIC_OP_ADD; } +| T_ADC { $$ = AIC_OP_ADC; } +; + +code: + f1_opcode destination ',' immediate_or_a opt_source ret ';' + { + format_1_instr($1, &$2, &$4, &$5, $6); + } +; + +code: + T_OR reg_symbol ',' immediate_or_a opt_source ret ';' + { + format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6); + } +; + +code: + T_INC destination opt_source ret ';' + { + expression_t immed; + + make_expression(&immed, 1); + format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); + } +; + +code: + T_DEC destination opt_source ret ';' + { + expression_t immed; + + make_expression(&immed, -1); + format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); + } +; + +code: + T_CLC ret ';' + { + expression_t immed; + + make_expression(&immed, -1); + format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2); + } +| T_CLC T_MVI destination ',' immediate_or_a ret ';' + { + format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6); + } +; + +code: + T_STC ret ';' + { + expression_t immed; + + make_expression(&immed, 1); + format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2); + } +| T_STC destination ret ';' + { + expression_t immed; + + make_expression(&immed, 1); + format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3); + } +; + +code: + T_BMOV destination ',' source ',' immediate ret ';' + { + format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7); + } +; + +code: + T_MOV destination ',' source ret ';' + { + expression_t immed; + + make_expression(&immed, 0xff); + format_1_instr(AIC_OP_AND, &$2, &immed, &$4, $5); + } +; + +code: + T_MVI destination ',' immediate_or_a ret ';' + { + format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5); + } +; + +code: + T_CLR destination ret ';' + { + expression_t immed; + + make_expression(&immed, 0xff); + format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3); + } +; + +code: + T_NOP ret ';' + { + expression_t immed; + + make_expression(&immed, 0xff); + format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2); + } +; + +code: + T_RET ';' + { + expression_t immed; + + make_expression(&immed, 0xff); + format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE); + } +; + + /* + * This grammer differs from the one in the aic7xxx + * reference manual since the grammer listed there is + * ambiguous and causes a shift/reduce conflict. + * It also seems more logical as the "immediate" + * argument is listed as the second arg like the + * other formats. + */ + +f2_opcode: + T_SHL { $$ = AIC_OP_SHL; } +| T_SHR { $$ = AIC_OP_SHR; } +| T_ROL { $$ = AIC_OP_ROL; } +| T_ROR { $$ = AIC_OP_ROR; } +; + +code: + f2_opcode destination ',' expression opt_source ret ';' + { + format_2_instr($1, &$2, &$4, &$5, $6); + } +; + +jmp_jc_jnc_call: + T_JMP { $$ = AIC_OP_JMP; } +| T_JC { $$ = AIC_OP_JC; } +| T_JNC { $$ = AIC_OP_JNC; } +| T_CALL { $$ = AIC_OP_CALL; } +; + +jz_jnz: + T_JZ { $$ = AIC_OP_JZ; } +| T_JNZ { $$ = AIC_OP_JNZ; } +; + +je_jne: + T_JE { $$ = AIC_OP_JE; } +| T_JNE { $$ = AIC_OP_JNE; } +; + +code: + jmp_jc_jnc_call address ';' + { + expression_t immed; + + make_expression(&immed, 0); + format_3_instr($1, &sindex, &immed, &$2); + } +; + +code: + T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';' + { + format_3_instr($5, &$2, &$4, &$6); + } +; + +code: + T_TEST source ',' immediate_or_a jz_jnz address ';' + { + format_3_instr($5, &$2, &$4, &$6); + } +; + +code: + T_CMP source ',' immediate_or_a je_jne address ';' + { + format_3_instr($5, &$2, &$4, &$6); + } +; + +code: + T_MOV source jmp_jc_jnc_call address ';' + { + expression_t immed; + + make_expression(&immed, 0); + format_3_instr($3, &$2, &immed, &$4); + } +; + +code: + T_MVI immediate jmp_jc_jnc_call address ';' + { + format_3_instr($3, &allzeros, &$2, &$4); + } +; + +%% + +static void +process_bitmask(mask_type, sym, mask) + int mask_type; + symbol_t *sym; + int mask; +{ + /* + * Add the current register to its + * symbol list, if it already exists, + * warn if we are setting it to a + * different value, or in the bit to + * the "allowed bits" of this register. + */ + if (sym->type == UNINITIALIZED) { + sym->type = mask_type; + initialize_symbol(sym); + if (mask_type == BIT) { + if (mask == 0) { + stop("Bitmask with no bits set", EX_DATAERR); + /* NOTREACHED */ + } + if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) { + stop("Bitmask with more than one bit set", + EX_DATAERR); + /* NOTREACHED */ + } + } + sym->info.minfo->mask = mask; + } else if (sym->type != mask_type) { + stop("Bit definition mirrors a definition of the same " + " name, but a different type", EX_DATAERR); + /* NOTREACHED */ + } else if (mask != sym->info.minfo->mask) { + stop("Bitmask redefined with a conflicting value", EX_DATAERR); + /* NOTREACHED */ + } + /* Fail if this symbol is already listed */ + if (symlist_search(&(sym->info.minfo->symrefs), + cur_symbol->name) != NULL) { + stop("Bitmask defined multiple times for register", EX_DATAERR); + /* NOTREACHED */ + } + symlist_add(&(sym->info.minfo->symrefs), cur_symbol, + SYMLIST_INSERT_HEAD); + cur_symbol->info.rinfo->valid_bitmask |= mask; + cur_symbol->info.rinfo->typecheck_masks = TRUE; +} + +static void +initialize_symbol(symbol) + symbol_t *symbol; +{ + switch (symbol->type) { + case UNINITIALIZED: + stop("Call to initialize_symbol with type field unset", + EX_SOFTWARE); + /* NOTREACHED */ + break; + case REGISTER: + case SRAMLOC: + case SCBLOC: + symbol->info.rinfo = + (struct reg_info *)malloc(sizeof(struct reg_info)); + if (symbol->info.rinfo == NULL) { + stop("Can't create register info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.rinfo, 0, + sizeof(struct reg_info)); + break; + case ALIAS: + symbol->info.ainfo = + (struct alias_info *)malloc(sizeof(struct alias_info)); + if (symbol->info.ainfo == NULL) { + stop("Can't create alias info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.ainfo, 0, + sizeof(struct alias_info)); + break; + case MASK: + case BIT: + symbol->info.minfo = + (struct mask_info *)malloc(sizeof(struct mask_info)); + if (symbol->info.minfo == NULL) { + stop("Can't create bitmask info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.minfo, 0, sizeof(struct mask_info)); + SLIST_INIT(&(symbol->info.minfo->symrefs)); + break; + case CONST: + case DOWNLOAD_CONST: + symbol->info.cinfo = + (struct const_info *)malloc(sizeof(struct const_info)); + if (symbol->info.cinfo == NULL) { + stop("Can't create alias info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.cinfo, 0, + sizeof(struct const_info)); + break; + case LABEL: + symbol->info.linfo = + (struct label_info *)malloc(sizeof(struct label_info)); + if (symbol->info.linfo == NULL) { + stop("Can't create label info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.linfo, 0, + sizeof(struct label_info)); + break; + case CONDITIONAL: + symbol->info.condinfo = + (struct cond_info *)malloc(sizeof(struct cond_info)); + if (symbol->info.condinfo == NULL) { + stop("Can't create conditional info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.condinfo, 0, + sizeof(struct cond_info)); + break; + default: + stop("Call to initialize_symbol with invalid symbol type", + EX_SOFTWARE); + /* NOTREACHED */ + break; + } +} + +static void +process_register(p_symbol) + symbol_t **p_symbol; +{ + char buf[255]; + symbol_t *symbol = *p_symbol; + + if (symbol->type == UNINITIALIZED) { + snprintf(buf, sizeof(buf), "Undefined register %s", + symbol->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + } else if (symbol->type == ALIAS) { + *p_symbol = symbol->info.ainfo->parent; + } else if ((symbol->type != REGISTER) + && (symbol->type != SCBLOC) + && (symbol->type != SRAMLOC)) { + snprintf(buf, sizeof(buf), + "Specified symbol %s is not a register", + symbol->name); + stop(buf, EX_DATAERR); + } +} + +static void +format_1_instr(opcode, dest, immed, src, ret) + int opcode; + symbol_ref_t *dest; + expression_t *immed; + symbol_ref_t *src; + int ret; +{ + struct instruction *instr; + struct ins_format1 *f1_instr; + + if (src->symbol == NULL) + src = dest; + + /* Test register permissions */ + test_writable_symbol(dest->symbol); + test_readable_symbol(src->symbol); + + /* Ensure that immediate makes sense for this destination */ + type_check(dest->symbol, immed, opcode); + + /* Allocate sequencer space for the instruction and fill it out */ + instr = seq_alloc(); + f1_instr = &instr->format.format1; + f1_instr->ret = ret ? 1 : 0; + f1_instr->opcode = opcode; + f1_instr->destination = dest->symbol->info.rinfo->address + + dest->offset; + f1_instr->source = src->symbol->info.rinfo->address + + src->offset; + f1_instr->immediate = immed->value; + + if (is_download_const(immed)) + f1_instr->parity = 1; + + symlist_free(&immed->referenced_syms); + instruction_ptr++; +} + +static void +format_2_instr(opcode, dest, places, src, ret) + int opcode; + symbol_ref_t *dest; + expression_t *places; + symbol_ref_t *src; + int ret; +{ + struct instruction *instr; + struct ins_format2 *f2_instr; + u_int8_t shift_control; + + if (src->symbol == NULL) + src = dest; + + /* Test register permissions */ + test_writable_symbol(dest->symbol); + test_readable_symbol(src->symbol); + + /* Allocate sequencer space for the instruction and fill it out */ + instr = seq_alloc(); + f2_instr = &instr->format.format2; + f2_instr->ret = ret ? 1 : 0; + f2_instr->opcode = AIC_OP_ROL; + f2_instr->destination = dest->symbol->info.rinfo->address + + dest->offset; + f2_instr->source = src->symbol->info.rinfo->address + + src->offset; + if (places->value > 8 || places->value <= 0) { + stop("illegal shift value", EX_DATAERR); + /* NOTREACHED */ + } + switch (opcode) { + case AIC_OP_SHL: + if (places->value == 8) + shift_control = 0xf0; + else + shift_control = (places->value << 4) | places->value; + break; + case AIC_OP_SHR: + if (places->value == 8) { + shift_control = 0xf8; + } else { + shift_control = (places->value << 4) + | (8 - places->value) + | 0x08; + } + break; + case AIC_OP_ROL: + shift_control = places->value & 0x7; + break; + case AIC_OP_ROR: + shift_control = (8 - places->value) | 0x08; + break; + default: + shift_control = 0; /* Quiet Compiler */ + stop("Invalid shift operation specified", EX_SOFTWARE); + /* NOTREACHED */ + break; + }; + f2_instr->shift_control = shift_control; + symlist_free(&places->referenced_syms); + instruction_ptr++; +} + +static void +format_3_instr(opcode, src, immed, address) + int opcode; + symbol_ref_t *src; + expression_t *immed; + symbol_ref_t *address; +{ + struct instruction *instr; + struct ins_format3 *f3_instr; + int addr; + + /* Test register permissions */ + test_readable_symbol(src->symbol); + + /* Ensure that immediate makes sense for this source */ + type_check(src->symbol, immed, opcode); + + /* Allocate sequencer space for the instruction and fill it out */ + instr = seq_alloc(); + f3_instr = &instr->format.format3; + if (address->symbol == NULL) { + /* 'dot' referrence. Use the current instruction pointer */ + addr = instruction_ptr + address->offset; + } else if (address->symbol->type == UNINITIALIZED) { + /* forward reference */ + addr = address->offset; + instr->patch_label = address->symbol; + } else + addr = address->symbol->info.linfo->address + address->offset; + f3_instr->opcode = opcode; + f3_instr->address = addr; + f3_instr->source = src->symbol->info.rinfo->address + + src->offset; + f3_instr->immediate = immed->value; + + if (is_download_const(immed)) + f3_instr->parity = 1; + + symlist_free(&immed->referenced_syms); + instruction_ptr++; +} + +static void +test_readable_symbol(symbol) + symbol_t *symbol; +{ + if (symbol->info.rinfo->mode == WO) { + stop("Write Only register specified as source", + EX_DATAERR); + /* NOTREACHED */ + } +} + +static void +test_writable_symbol(symbol) + symbol_t *symbol; +{ + if (symbol->info.rinfo->mode == RO) { + stop("Read Only register specified as destination", + EX_DATAERR); + /* NOTREACHED */ + } +} + +static void +type_check(symbol, expression, opcode) + symbol_t *symbol; + expression_t *expression; + int opcode; +{ + symbol_node_t *node; + int and_op; + char buf[255]; + + and_op = FALSE; + if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ) + and_op = TRUE; + + /* + * Make sure that we aren't attempting to write something + * that hasn't been defined. If this is an and operation, + * this is a mask, so "undefined" bits are okay. + */ + if (and_op == FALSE + && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) { + snprintf(buf, sizeof(buf), + "Invalid bit(s) 0x%x in immediate written to %s", + expression->value & ~symbol->info.rinfo->valid_bitmask, + symbol->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + } + + /* + * Now make sure that all of the symbols referenced by the + * expression are defined for this register. + */ + if(symbol->info.rinfo->typecheck_masks != FALSE) { + for(node = expression->referenced_syms.slh_first; + node != NULL; + node = node->links.sle_next) { + if ((node->symbol->type == MASK + || node->symbol->type == BIT) + && symlist_search(&node->symbol->info.minfo->symrefs, + symbol->name) == NULL) { + snprintf(buf, sizeof(buf), + "Invalid bit or mask %s " + "for register %s", + node->symbol->name, symbol->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + } + } + } +} + +static void +make_expression(immed, value) + expression_t *immed; + int value; +{ + SLIST_INIT(&immed->referenced_syms); + immed->value = value & 0xff; +} + +static void +add_conditional(symbol) + symbol_t *symbol; +{ + static int numfuncs; + + if (numfuncs == 0) { + /* add a special conditional, "0" */ + symbol_t *false_func; + + false_func = symtable_get("0"); + if (false_func->type != UNINITIALIZED) { + stop("Conditional expression '0' " + "conflicts with a symbol", EX_DATAERR); + /* NOTREACHED */ + } + false_func->type = CONDITIONAL; + initialize_symbol(false_func); + false_func->info.condinfo->func_num = numfuncs++; + symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD); + } + + /* This condition has occurred before */ + if (symbol->type == CONDITIONAL) + return; + + if (symbol->type != UNINITIALIZED) { + stop("Conditional expression conflicts with a symbol", + EX_DATAERR); + /* NOTREACHED */ + } + + symbol->type = CONDITIONAL; + initialize_symbol(symbol); + symbol->info.condinfo->func_num = numfuncs++; + symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD); +} + +void +yyerror(string) + const char *string; +{ + stop(string, EX_DATAERR); +} + +static int +is_download_const(immed) + expression_t *immed; +{ + if ((immed->referenced_syms.slh_first != NULL) + && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST)) + return (TRUE); + + return (FALSE); +} diff --git a/sys/dev/microcode/aic7xxx/aicasm_scan.l b/sys/dev/microcode/aic7xxx/aicasm_scan.l new file mode 100644 index 00000000000..20cae61b096 --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aicasm_scan.l @@ -0,0 +1,283 @@ +%{ +/* + * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler. + * + * Copyright (c) 1997-1998 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm_scan.l,v 1.8 1999/12/06 18:23:30 gibbs Exp $ + */ + +#include <sys/types.h> + +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <sysexits.h> +#include <sys/queue.h> + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "y.tab.h" + +#define MAX_STR_CONST 256 +char string_buf[MAX_STR_CONST]; +char *string_buf_ptr; +int parren_count; +%} + +PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]* +WORD [A-Za-z_][-A-Za-z_0-9]* +SPACE [ \t]+ + +%x COMMENT +%x CEXPR +%x INCLUDE + +%% +\n { ++yylineno; } +"/*" { BEGIN COMMENT; /* Enter comment eating state */ } +<COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); } +<COMMENT>\n { ++yylineno; } +<COMMENT>[^*/\n]* ; +<COMMENT>"*"+[^*/\n]* ; +<COMMENT>"/"+[^*/\n]* ; +<COMMENT>"*"+"/" { BEGIN INITIAL; } +if[ \t]*\( { + string_buf_ptr = string_buf; + parren_count = 1; + BEGIN CEXPR; + return T_IF; + } +<CEXPR>\( { *string_buf_ptr++ = '('; parren_count++; } +<CEXPR>\) { + parren_count--; + if (parren_count == 0) { + /* All done */ + BEGIN INITIAL; + *string_buf_ptr = '\0'; + yylval.sym = symtable_get(string_buf); + return T_CEXPR; + } else { + *string_buf_ptr++ = ')'; + } + } +<CEXPR>\n { ++yylineno; } +<CEXPR>[^()\n]+ { + char *yptr = yytext; + + while (*yptr != '\0') + *string_buf_ptr++ = *yptr++; + } + +{SPACE} ; + + /* Register/SCB/SRAM definition keywords */ +register { return T_REGISTER; } +const { yylval.value = FALSE; return T_CONST; } +download { return T_DOWNLOAD; } +address { return T_ADDRESS; } +access_mode { return T_ACCESS_MODE; } +RW|RO|WO { + if (strcmp(yytext, "RW") == 0) + yylval.value = RW; + else if (strcmp(yytext, "RO") == 0) + yylval.value = RO; + else + yylval.value = WO; + return T_MODE; + } +bit { return T_BIT; } +mask { return T_MASK; } +alias { return T_ALIAS; } +size { return T_SIZE; } +scb { return T_SCB; } +scratch_ram { return T_SRAM; } +accumulator { return T_ACCUM; } +allones { return T_ALLONES; } +allzeros { return T_ALLZEROS; } +none { return T_NONE; } +sindex { return T_SINDEX; } +A { return T_A; } + + /* Opcodes */ +shl { return T_SHL; } +shr { return T_SHR; } +ror { return T_ROR; } +rol { return T_ROL; } +mvi { return T_MVI; } +mov { return T_MOV; } +clr { return T_CLR; } +jmp { return T_JMP; } +jc { return T_JC; } +jnc { return T_JNC; } +je { return T_JE; } +jne { return T_JNE; } +jz { return T_JZ; } +jnz { return T_JNZ; } +call { return T_CALL; } +add { return T_ADD; } +adc { return T_ADC; } +bmov { return T_BMOV; } +inc { return T_INC; } +dec { return T_DEC; } +stc { return T_STC; } +clc { return T_CLC; } +cmp { return T_CMP; } +xor { return T_XOR; } +test { return T_TEST;} +and { return T_AND; } +or { return T_OR; } +ret { return T_RET; } +nop { return T_NOP; } +else { return T_ELSE; } + + /* Allowed Symbols */ +[-+,:()~|&."{};<>[\]!] { return yytext[0]; } + + /* Number processing */ +0[0-7]* { + yylval.value = strtol(yytext, NULL, 8); + return T_NUMBER; + } + +0[xX][0-9a-fA-F]+ { + yylval.value = strtoul(yytext + 2, NULL, 16); + return T_NUMBER; + } + +[1-9][0-9]* { + yylval.value = strtol(yytext, NULL, 10); + return T_NUMBER; + } + + /* Include Files */ +#include { return T_INCLUDE; BEGIN INCLUDE;} +<INCLUDE>[<>\"] { return yytext[0]; } +<INCLUDE>{PATH} { yylval.str = strdup(yytext); return T_PATH; } +<INCLUDE>; { BEGIN INITIAL; return yytext[0]; } +<INCLUDE>. { stop("Invalid include line", EX_DATAERR); } + + /* For parsing C include files with #define foo */ +#define { yylval.value = TRUE; return T_CONST; } + /* Throw away macros */ +#define[^\n]*[()]+[^\n]* ; +{PATH} { yylval.str = strdup(yytext); return T_PATH; } + +{WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; } + +. { + char buf[255]; + + snprintf(buf, sizeof(buf), "Invalid character " + "'%c'", yytext[0]); + stop(buf, EX_DATAERR); + } +%% + +typedef struct include { + YY_BUFFER_STATE buffer; + int lineno; + char *filename; + SLIST_ENTRY(include) links; +}include_t; + +SLIST_HEAD(, include) include_stack; + +void +include_file(file_name, type) + char *file_name; + include_type type; +{ + FILE *newfile; + include_t *include; + + newfile = NULL; + /* Try the current directory first */ + if (includes_search_curdir != 0 || type == SOURCE_FILE) + newfile = fopen(file_name, "r"); + + if (newfile == NULL && type != SOURCE_FILE) { + path_entry_t include_dir; + for (include_dir = search_path.slh_first; + include_dir != NULL; + include_dir = include_dir->links.sle_next) { + char fullname[PATH_MAX]; + + if ((include_dir->quoted_includes_only == TRUE) + && (type != QUOTED_INCLUDE)) + continue; + + snprintf(fullname, sizeof(fullname), + "%s/%s", include_dir->directory, file_name); + + if ((newfile = fopen(fullname, "r")) != NULL) + break; + } + } + + if (newfile == NULL) { + perror(file_name); + stop("Unable to open input file", EX_SOFTWARE); + /* NOTREACHED */ + } + + if (type != SOURCE_FILE) { + include = (include_t *)malloc(sizeof(include_t)); + if (include == NULL) { + stop("Unable to allocate include stack entry", + EX_SOFTWARE); + /* NOTREACHED */ + } + include->buffer = YY_CURRENT_BUFFER; + include->lineno = yylineno; + include->filename = yyfilename; + SLIST_INSERT_HEAD(&include_stack, include, links); + } + yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); + yylineno = 1; + yyfilename = strdup(file_name); +} + +int +yywrap() +{ + include_t *include; + + yy_delete_buffer(YY_CURRENT_BUFFER); + (void)fclose(yyin); + if (yyfilename != NULL) + free(yyfilename); + yyfilename = NULL; + include = include_stack.slh_first; + if (include != NULL) { + yy_switch_to_buffer(include->buffer); + yylineno = include->lineno; + yyfilename = include->filename; + SLIST_REMOVE_HEAD(&include_stack, links); + free(include); + return (0); + } + return (1); +} diff --git a/sys/dev/microcode/aic7xxx/aicasm_symbol.c b/sys/dev/microcode/aic7xxx/aicasm_symbol.c new file mode 100644 index 00000000000..4f799bcbc50 --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aicasm_symbol.c @@ -0,0 +1,473 @@ +/* $OpenBSD: aicasm_symbol.c,v 1.1 2000/03/22 02:50:49 smurph Exp $ */ +/* + * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm_symbol.c,v 1.8 1999/12/06 18:23:30 gibbs Exp $ + */ + + +#include <sys/types.h> + +#include <db.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> + +#include "aicasm_symbol.h" +#include "aicasm.h" + +static DB *symtable; + +symbol_t * +symbol_create(name) + char *name; +{ + symbol_t *new_symbol; + + new_symbol = (symbol_t *)malloc(sizeof(symbol_t)); + if (new_symbol == NULL) { + perror("Unable to create new symbol"); + exit(EX_SOFTWARE); + } + memset(new_symbol, 0, sizeof(*new_symbol)); + new_symbol->name = strdup(name); + new_symbol->type = UNINITIALIZED; + return (new_symbol); +} + +void +symbol_delete(symbol) + symbol_t *symbol; +{ + if (symtable != NULL) { + DBT key; + + key.data = symbol->name; + key.size = strlen(symbol->name); + symtable->del(symtable, &key, /*flags*/0); + } + switch(symbol->type) { + case SCBLOC: + case SRAMLOC: + case REGISTER: + if (symbol->info.rinfo != NULL) + free(symbol->info.rinfo); + break; + case ALIAS: + if (symbol->info.ainfo != NULL) + free(symbol->info.ainfo); + break; + case MASK: + case BIT: + if (symbol->info.minfo != NULL) { + symlist_free(&symbol->info.minfo->symrefs); + free(symbol->info.minfo); + } + break; + case DOWNLOAD_CONST: + case CONST: + if (symbol->info.cinfo != NULL) + free(symbol->info.cinfo); + break; + case LABEL: + if (symbol->info.linfo != NULL) + free(symbol->info.linfo); + break; + case UNINITIALIZED: + default: + break; + } + free(symbol->name); + free(symbol); +} + +void +symtable_open() +{ + symtable = dbopen(/*filename*/NULL, + O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH, + /*openinfo*/NULL); + + if (symtable == NULL) { + perror("Symbol table creation failed"); + exit(EX_SOFTWARE); + /* NOTREACHED */ + } +} + +void +symtable_close() +{ + if (symtable != NULL) { + DBT key; + DBT data; + + while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { + symbol_t *stored_ptr; + + memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); + symbol_delete(stored_ptr); + } + symtable->close(symtable); + } +} + +/* + * The semantics of get is to return an uninitialized symbol entry + * if a lookup fails. + */ +symbol_t * +symtable_get(name) + char *name; +{ + symbol_t *stored_ptr; + DBT key; + DBT data; + int retval; + + key.data = (void *)name; + key.size = strlen(name); + + if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) { + if (retval == -1) { + perror("Symbol table get operation failed"); + exit(EX_SOFTWARE); + /* NOTREACHED */ + } else if (retval == 1) { + /* Symbol wasn't found, so create a new one */ + symbol_t *new_symbol; + + new_symbol = symbol_create(name); + data.data = &new_symbol; + data.size = sizeof(new_symbol); + if (symtable->put(symtable, &key, &data, + /*flags*/0) !=0) { + perror("Symtable put failed"); + exit(EX_SOFTWARE); + } + return (new_symbol); + } else { + perror("Unexpected return value from db get routine"); + exit(EX_SOFTWARE); + /* NOTREACHED */ + } + } + memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); + return (stored_ptr); +} + +symbol_node_t * +symlist_search(symlist, symname) + symlist_t *symlist; + char *symname; +{ + symbol_node_t *curnode; + + curnode = symlist->slh_first; + while(curnode != NULL) { + if (strcmp(symname, curnode->symbol->name) == 0) + break; + curnode = curnode->links.sle_next; + } + return (curnode); +} + +void +symlist_add(symlist, symbol, how) + symlist_t *symlist; + symbol_t *symbol; + int how; +{ + symbol_node_t *newnode; + + newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t)); + if (newnode == NULL) { + stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE); + /* NOTREACHED */ + } + newnode->symbol = symbol; + if (how == SYMLIST_SORT) { + symbol_node_t *curnode; + int mask; + + mask = FALSE; + switch(symbol->type) { + case REGISTER: + case SCBLOC: + case SRAMLOC: + break; + case BIT: + case MASK: + mask = TRUE; + break; + default: + stop("symlist_add: Invalid symbol type for sorting", + EX_SOFTWARE); + /* NOTREACHED */ + } + + curnode = symlist->slh_first; + if (curnode == NULL + || (mask && (curnode->symbol->info.minfo->mask > + newnode->symbol->info.minfo->mask)) + || (!mask && (curnode->symbol->info.rinfo->address > + newnode->symbol->info.rinfo->address))) { + SLIST_INSERT_HEAD(symlist, newnode, links); + return; + } + + while (1) { + if (curnode->links.sle_next == NULL) { + SLIST_INSERT_AFTER(curnode, newnode, + links); + break; + } else { + symbol_t *cursymbol; + + cursymbol = curnode->links.sle_next->symbol; + if ((mask && (cursymbol->info.minfo->mask > + symbol->info.minfo->mask)) + || (!mask &&(cursymbol->info.rinfo->address > + symbol->info.rinfo->address))){ + SLIST_INSERT_AFTER(curnode, newnode, + links); + break; + } + } + curnode = curnode->links.sle_next; + } + } else { + SLIST_INSERT_HEAD(symlist, newnode, links); + } +} + +void +symlist_free(symlist) + symlist_t *symlist; +{ + symbol_node_t *node1, *node2; + + node1 = symlist->slh_first; + while (node1 != NULL) { + node2 = node1->links.sle_next; + free(node1); + node1 = node2; + } + SLIST_INIT(symlist); +} + +void +symlist_merge(symlist_dest, symlist_src1, symlist_src2) + symlist_t *symlist_dest; + symlist_t *symlist_src1; + symlist_t *symlist_src2; +{ + symbol_node_t *node; + + *symlist_dest = *symlist_src1; + while((node = symlist_src2->slh_first) != NULL) { + SLIST_REMOVE_HEAD(symlist_src2, links); + SLIST_INSERT_HEAD(symlist_dest, node, links); + } + + /* These are now empty */ + SLIST_INIT(symlist_src1); + SLIST_INIT(symlist_src2); +} + +void +symtable_dump(ofile) + FILE *ofile; +{ + /* + * Sort the registers by address with a simple insertion sort. + * Put bitmasks next to the first register that defines them. + * Put constants at the end. + */ + symlist_t registers; + symlist_t masks; + symlist_t constants; + symlist_t download_constants; + symlist_t aliases; + + SLIST_INIT(®isters); + SLIST_INIT(&masks); + SLIST_INIT(&constants); + SLIST_INIT(&download_constants); + SLIST_INIT(&aliases); + + if (symtable != NULL) { + DBT key; + DBT data; + int flag = R_FIRST; + + while (symtable->seq(symtable, &key, &data, flag) == 0) { + symbol_t *cursym; + + memcpy(&cursym, data.data, sizeof(cursym)); + switch(cursym->type) { + case REGISTER: + case SCBLOC: + case SRAMLOC: + symlist_add(®isters, cursym, SYMLIST_SORT); + break; + case MASK: + case BIT: + symlist_add(&masks, cursym, SYMLIST_SORT); + break; + case CONST: + if (cursym->info.cinfo->define == FALSE) { + symlist_add(&constants, cursym, + SYMLIST_INSERT_HEAD); + } + break; + case DOWNLOAD_CONST: + symlist_add(&download_constants, cursym, + SYMLIST_INSERT_HEAD); + break; + case ALIAS: + symlist_add(&aliases, cursym, + SYMLIST_INSERT_HEAD); + break; + default: + break; + } + flag = R_NEXT; + } + + /* Put in the masks and bits */ + while (masks.slh_first != NULL) { + symbol_node_t *curnode; + symbol_node_t *regnode; + char *regname; + + curnode = masks.slh_first; + SLIST_REMOVE_HEAD(&masks, links); + + regnode = + curnode->symbol->info.minfo->symrefs.slh_first; + regname = regnode->symbol->name; + regnode = symlist_search(®isters, regname); + SLIST_INSERT_AFTER(regnode, curnode, links); + } + + /* Add the aliases */ + while (aliases.slh_first != NULL) { + symbol_node_t *curnode; + symbol_node_t *regnode; + char *regname; + + curnode = aliases.slh_first; + SLIST_REMOVE_HEAD(&aliases, links); + + regname = curnode->symbol->info.ainfo->parent->name; + regnode = symlist_search(®isters, regname); + SLIST_INSERT_AFTER(regnode, curnode, links); + } + + /* Output what we have */ + fprintf(ofile, +"/* + * DO NOT EDIT - This file is automatically generated. + */\n"); + while (registers.slh_first != NULL) { + symbol_node_t *curnode; + u_int8_t value; + char *tab_str; + char *tab_str2; + + curnode = registers.slh_first; + SLIST_REMOVE_HEAD(®isters, links); + switch(curnode->symbol->type) { + case REGISTER: + case SCBLOC: + case SRAMLOC: + fprintf(ofile, "\n"); + value = curnode->symbol->info.rinfo->address; + tab_str = "\t"; + tab_str2 = "\t\t"; + break; + case ALIAS: + { + symbol_t *parent; + + parent = curnode->symbol->info.ainfo->parent; + value = parent->info.rinfo->address; + tab_str = "\t"; + tab_str2 = "\t\t"; + break; + } + case MASK: + case BIT: + value = curnode->symbol->info.minfo->mask; + tab_str = "\t\t"; + tab_str2 = "\t"; + break; + default: + value = 0; /* Quiet compiler */ + tab_str = NULL; + tab_str2 = NULL; + stop("symtable_dump: Invalid symbol type " + "encountered", EX_SOFTWARE); + break; + } + fprintf(ofile, "#define%s%-16s%s0x%02x\n", + tab_str, curnode->symbol->name, tab_str2, + value); + free(curnode); + } + fprintf(ofile, "\n\n"); + + while (constants.slh_first != NULL) { + symbol_node_t *curnode; + + curnode = constants.slh_first; + SLIST_REMOVE_HEAD(&constants, links); + fprintf(ofile, "#define\t%-8s\t0x%02x\n", + curnode->symbol->name, + curnode->symbol->info.cinfo->value); + free(curnode); + } + + + fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); + + while (download_constants.slh_first != NULL) { + symbol_node_t *curnode; + + curnode = download_constants.slh_first; + SLIST_REMOVE_HEAD(&download_constants, links); + fprintf(ofile, "#define\t%-8s\t0x%02x\n", + curnode->symbol->name, + curnode->symbol->info.cinfo->value); + free(curnode); + } + } +} + diff --git a/sys/dev/microcode/aic7xxx/aicasm_symbol.h b/sys/dev/microcode/aic7xxx/aicasm_symbol.h new file mode 100644 index 00000000000..201b1c043f0 --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aicasm_symbol.h @@ -0,0 +1,162 @@ +/* $OpenBSD: aicasm_symbol.h,v 1.1 2000/03/22 02:50:50 smurph Exp $ */ +/* + * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm_symbol.h,v 1.6 1999/12/06 18:23:31 gibbs Exp $ + */ + +#include <sys/queue.h> + +typedef enum { + UNINITIALIZED, + REGISTER, + ALIAS, + SCBLOC, + SRAMLOC, + MASK, + BIT, + CONST, + DOWNLOAD_CONST, + LABEL, + CONDITIONAL +}symtype; + +typedef enum { + RO = 0x01, + WO = 0x02, + RW = 0x03 +}amode_t; + +struct reg_info { + u_int8_t address; + int size; + amode_t mode; + u_int8_t valid_bitmask; + int typecheck_masks; +}; + +typedef SLIST_HEAD(symlist, symbol_node) symlist_t; + +struct mask_info { + symlist_t symrefs; + u_int8_t mask; +}; + +struct const_info { + u_int8_t value; + int define; +}; + +struct alias_info { + struct symbol *parent; +}; + +struct label_info { + int address; +}; + +struct cond_info { + int func_num; +}; + +typedef struct expression_info { + symlist_t referenced_syms; + int value; +} expression_t; + +typedef struct symbol { + char *name; + symtype type; + union { + struct reg_info *rinfo; + struct mask_info *minfo; + struct const_info *cinfo; + struct alias_info *ainfo; + struct label_info *linfo; + struct cond_info *condinfo; + }info; +} symbol_t; + +typedef struct symbol_ref { + symbol_t *symbol; + int offset; +} symbol_ref_t; + +typedef struct symbol_node { + SLIST_ENTRY(symbol_node) links; + symbol_t *symbol; +}symbol_node_t; + +typedef enum { + SCOPE_ROOT, + SCOPE_IF, + SCOPE_ELSE_IF, + SCOPE_ELSE +} scope_type; + +typedef struct patch_info { + int skip_patch; + int skip_instr; +} patch_info_t; + +typedef struct scope { + SLIST_ENTRY(scope) scope_stack_links; + TAILQ_ENTRY(scope) scope_links; + TAILQ_HEAD(, scope) inner_scope; + scope_type type; + int inner_scope_patches; + int begin_addr; + int end_addr; + patch_info_t patches[2]; + int func_num; +} scope_t; + +SLIST_HEAD(scope_list, scope); +TAILQ_HEAD(scope_tailq, scope); + +void symbol_delete __P((symbol_t *symbol)); + +void symtable_open __P((void)); + +void symtable_close __P((void)); + +symbol_t * + symtable_get __P((char *name)); + +symbol_node_t * + symlist_search __P((symlist_t *symlist, char *symname)); + +void + symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how)); +#define SYMLIST_INSERT_HEAD 0x00 +#define SYMLIST_SORT 0x01 + +void symlist_free __P((symlist_t *symlist)); + +void symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1, + symlist_t *symlist_src2)); +void symtable_dump __P((FILE *ofile)); diff --git a/sys/dev/microcode/aic7xxx/sequencer.h b/sys/dev/microcode/aic7xxx/sequencer.h new file mode 100644 index 00000000000..4c57a8d5405 --- /dev/null +++ b/sys/dev/microcode/aic7xxx/sequencer.h @@ -0,0 +1,96 @@ +/* $OpenBSD: sequencer.h,v 1.1 2000/03/22 02:50:50 smurph Exp $ */ +/* + * Instruction formats for the sequencer program downloaded to + * Aic7xxx SCSI host adapters + * + * Copyright (c) 1997, 1998 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/aic7xxx/sequencer.h,v 1.6 1999/12/06 18:23:31 gibbs Exp $ + */ + +struct ins_format1 { + u_int32_t immediate : 8, + source : 9, + destination : 9, + ret : 1, + opcode : 4, + parity : 1; +}; + +struct ins_format2 { + u_int32_t shift_control : 8, + source : 9, + destination : 9, + ret : 1, + opcode : 4, + parity : 1; +}; + +struct ins_format3 { + u_int32_t immediate : 8, + source : 9, + address : 10, + opcode : 4, + parity : 1; +}; + +union ins_formats { + struct ins_format1 format1; + struct ins_format2 format2; + struct ins_format3 format3; + u_int8_t bytes[4]; + u_int32_t integer; +}; +struct instruction { + union ins_formats format; + u_int srcline; + struct symbol *patch_label; + TAILQ_ENTRY(instruction) links; +}; + +#define AIC_OP_OR 0x0 +#define AIC_OP_AND 0x1 +#define AIC_OP_XOR 0x2 +#define AIC_OP_ADD 0x3 +#define AIC_OP_ADC 0x4 +#define AIC_OP_ROL 0x5 +#define AIC_OP_BMOV 0x6 + +#define AIC_OP_JMP 0x8 +#define AIC_OP_JC 0x9 +#define AIC_OP_JNC 0xa +#define AIC_OP_CALL 0xb +#define AIC_OP_JNE 0xc +#define AIC_OP_JNZ 0xd +#define AIC_OP_JE 0xe +#define AIC_OP_JZ 0xf + +/* Pseudo Ops */ +#define AIC_OP_SHL 0x10 +#define AIC_OP_SHR 0x20 +#define AIC_OP_ROR 0x30 |