diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/microcode/aic7xxx/Makefile | 10 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic79xx.reg | 3961 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic79xx.seq | 2034 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic79xx_seq.h | 1140 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic7xxx.reg | 956 | ||||
-rw-r--r-- | sys/dev/microcode/aic7xxx/aic7xxx.seq | 2448 |
6 files changed, 8894 insertions, 1655 deletions
diff --git a/sys/dev/microcode/aic7xxx/Makefile b/sys/dev/microcode/aic7xxx/Makefile index 1234df894d6..727fca11b29 100644 --- a/sys/dev/microcode/aic7xxx/Makefile +++ b/sys/dev/microcode/aic7xxx/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.5 2002/06/30 18:25:58 smurph Exp $ +# $OpenBSD: Makefile,v 1.6 2003/12/24 22:40:16 krw Exp $ # $FreeBSD: src/sys/dev/aic7xxx/Makefile,v 1.6 1999/08/28 00:41:22 peter Exp $ PROG= aicasm @@ -9,7 +9,7 @@ GENSRCS= aicasm_gram.c aicasm_scan.c aicasm_macro_gram.c aicasm_macro_scan.c GENHDRS= y.tab.h SRCS= ${GENSRCS} ${CSRCS} -CLEANFILES+= ${GENSRCS} ${GENHDRS} y.output aic7xxxreg.h +CLEANFILES+= ${GENSRCS} ${GENHDRS} y.output DPADD+= ${LIBL} LDADD+= -ll @@ -32,15 +32,15 @@ LFLAGS+= -d SEQFLAGS= -l seq.lst .endif -microcode aic7xxxreg.h aic7xxx_seq.h: aic7xxx.seq aic7xxx.reg +microcode aic7xxx_reg.h aic7xxx_seq.h: aic7xxx.seq aic7xxx.reg ${OBJDIR}./aicasm -I/sys ${SEQFLAGS} -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 + grep OpenBSD: ${.CURDIR}/aic7xxx.reg | cat - tempreg.h > aic7xxx_reg.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/ + mv aic7xxx_reg.h /sys/dev/microcode/aic7xxx/ rm -f tempseq.h tempreg.h .include <bsd.prog.mk> diff --git a/sys/dev/microcode/aic7xxx/aic79xx.reg b/sys/dev/microcode/aic7xxx/aic79xx.reg new file mode 100644 index 00000000000..927974e69ab --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aic79xx.reg @@ -0,0 +1,3961 @@ +/* $OpenBSD: aic79xx.reg,v 1.1 2003/12/24 22:40:16 krw Exp $ */ +/* $NetBSD: aic79xx.reg,v 1.8 2003/08/29 03:45:59 thorpej Exp $ */ + +/* + * Aic79xx register and scratch ram definitions. + * + * Copyright (c) 1994-2001 Justin T. Gibbs. + * Copyright (c) 2000-2002 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may 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 + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.reg,v 1.15 2003/06/10 03:25:24 gibbs Exp $ + */ +VERSION = "Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $" + +/* + * This file is processed by the aic7xxx_asm utility for use in assembling + * firmware for the aic79xx family of SCSI host adapters as well as to generate + * a C header file for use in the kernel portion of the Aic79xx driver. + */ + +/* Register window Modes */ +#define M_DFF0 0 +#define M_DFF1 1 +#define M_CCHAN 2 +#define M_SCSI 3 +#define M_CFG 4 +#define M_DST_SHIFT 4 + +#define MK_MODE(src, dst) ((src) | ((dst) << M_DST_SHIFT)) +#define SET_MODE(src, dst) \ + SET_SRC_MODE src; \ + SET_DST_MODE dst; \ + if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \ + mvi MK_MODE(src, dst) call set_mode_work_around; \ + } else { \ + mvi MODE_PTR, MK_MODE(src, dst); \ + } + +#define TOGGLE_DFF_MODE \ + if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \ + call toggle_dff_mode_work_around; \ + } else { \ + xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); \ + } + +#define RESTORE_MODE(mode) \ + if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \ + mov mode call set_mode_work_around; \ + } else { \ + mov MODE_PTR, mode; \ + } + +#define SET_SEQINTCODE(code) \ + if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { \ + mvi code call set_seqint_work_around; \ + } else { \ + mvi SEQINTCODE, code; \ + } + +/* + * Mode Pointer + * Controls which of the 5, 512byte, address spaces should be used + * as the source and destination of any register accesses in our + * register window. + */ +register MODE_PTR { + address 0x000 + access_mode RW + field DST_MODE 0x70 + field SRC_MODE 0x07 + mode_pointer +} + +const SRC_MODE_SHIFT 0 +const DST_MODE_SHIFT 4 + +/* + * Host Interrupt Status + */ +register INTSTAT { + address 0x001 + access_mode RW + field HWERRINT 0x80 + field BRKADRINT 0x40 + field SWTMINT 0x20 + field PCIINT 0x10 + field SCSIINT 0x08 + field SEQINT 0x04 + field CMDCMPLT 0x02 + field SPLTINT 0x01 + mask INT_PEND 0xFF +} + +/* + * Sequencer Interrupt Code + */ +register SEQINTCODE { + address 0x002 + access_mode RW + field { + NO_SEQINT, /* No seqint pending. */ + BAD_PHASE, /* unknown scsi bus phase */ + SEND_REJECT, /* sending a message reject */ + PROTO_VIOLATION, /* Protocol Violation */ + NO_MATCH, /* no cmd match for reconnect */ + IGN_WIDE_RES, /* Complex IGN Wide Res Msg */ + PDATA_REINIT, /* + * Returned to data phase + * that requires data + * transfer pointers to be + * recalculated from the + * transfer residual. + */ + HOST_MSG_LOOP, /* + * 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. + */ + BAD_STATUS, /* Bad status from target */ + DATA_OVERRUN, /* + * Target attempted to write + * beyond the bounds of its + * command. + */ + MKMSG_FAILED, /* + * Target completed command + * without honoring our ATN + * request to issue a message. + */ + MISSED_BUSFREE, /* + * The sequencer never saw + * the bus go free after + * either a command complete + * or disconnect message. + */ + DUMP_CARD_STATE, + ILLEGAL_PHASE, + INVALID_SEQINT, + CFG4ISTAT_INTR, + STATUS_OVERRUN, + CFG4OVERRUN, + ENTERING_NONPACK, + TASKMGMT_FUNC_COMPLETE, /* + * Task management function + * request completed with + * an expected busfree. + */ + TASKMGMT_CMD_CMPLT_OKAY, /* + * A command with a non-zero + * task management function + * has completed via the normal + * command completion method + * for commands with a zero + * task management function. + * This happens when an attempt + * to abort a command loses + * the race for the command to + * complete normally. + */ + TRACEPOINT0, + TRACEPOINT1, + TRACEPOINT2, + TRACEPOINT3, + SAW_HWERR, + BAD_SCB_STATUS + } +} + +/* + * Clear Host Interrupt + */ +register CLRINT { + address 0x003 + access_mode WO + field CLRHWERRINT 0x80 /* Rev B or greater */ + field CLRBRKADRINT 0x40 + field CLRSWTMINT 0x20 + field CLRPCIINT 0x10 + field CLRSCSIINT 0x08 + field CLRSEQINT 0x04 + field CLRCMDINT 0x02 + field CLRSPLTINT 0x01 +} + +/* + * Error Register + */ +register ERROR { + address 0x004 + access_mode RO + field CIOPARERR 0x80 + field CIOACCESFAIL 0x40 /* Rev B or greater */ + field MPARERR 0x20 + field DPARERR 0x10 + field SQPARERR 0x08 + field ILLOPCODE 0x04 + field DSCTMOUT 0x02 +} + +/* + * Clear Error + */ +register CLRERR { + address 0x004 + access_mode WO + field CLRCIOPARERR 0x80 + field CLRCIOACCESFAIL 0x40 /* Rev B or greater */ + field CLRMPARERR 0x20 + field CLRDPARERR 0x10 + field CLRSQPARERR 0x08 + field CLRILLOPCODE 0x04 + field CLRDSCTMOUT 0x02 +} + +/* + * Host Control Register + * Overall host control of the device. + */ +register HCNTRL { + address 0x005 + access_mode RW + field SEQ_RESET 0x80 /* Rev B or greater */ + field POWRDN 0x40 + field SWINT 0x10 + field SWTIMER_START_B 0x08 /* Rev B or greater */ + field PAUSE 0x04 + field INTEN 0x02 + field CHIPRST 0x01 + field CHIPRSTACK 0x01 +} + +/* + * Host New SCB Queue Offset + */ +register HNSCB_QOFF { + address 0x006 + access_mode RW + size 2 +} + +/* + * Host Empty SCB Queue Offset + */ +register HESCB_QOFF { + address 0x008 + access_mode RW +} + +/* + * Host Mailbox + */ +register HS_MAILBOX { + address 0x00B + access_mode RW + mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */ + mask ENINT_COALESCE 0x40 /* Perform interrupt coalescing */ +} + +/* + * Sequencer Interupt Status + */ +register SEQINTSTAT { + address 0x00C + access_mode RO + field SEQ_SWTMRTO 0x10 + field SEQ_SEQINT 0x08 + field SEQ_SCSIINT 0x04 + field SEQ_PCIINT 0x02 + field SEQ_SPLTINT 0x01 +} + +/* + * Clear SEQ Interrupt + */ +register CLRSEQINTSTAT { + address 0x00C + access_mode WO + field CLRSEQ_SWTMRTO 0x10 + field CLRSEQ_SEQINT 0x08 + field CLRSEQ_SCSIINT 0x04 + field CLRSEQ_PCIINT 0x02 + field CLRSEQ_SPLTINT 0x01 +} + +/* + * Software Timer + */ +register SWTIMER { + address 0x00E + access_mode RW + size 2 +} + +/* + * SEQ New SCB Queue Offset + */ +register SNSCB_QOFF { + address 0x010 + access_mode RW + size 2 + modes M_CCHAN +} + +/* + * SEQ Empty SCB Queue Offset + */ +register SESCB_QOFF { + address 0x012 + access_mode RW + modes M_CCHAN +} + +/* + * SEQ Done SCB Queue Offset + */ +register SDSCB_QOFF { + address 0x014 + access_mode RW + modes M_CCHAN + size 2 +} + +/* + * Queue Offset Control & Status + */ +register QOFF_CTLSTA { + address 0x016 + access_mode RW + modes M_CCHAN + field EMPTY_SCB_AVAIL 0x80 + field NEW_SCB_AVAIL 0x40 + field SDSCB_ROLLOVR 0x20 + field HS_MAILBOX_ACT 0x10 + field SCB_QSIZE 0x0F { + SCB_QSIZE_4, + SCB_QSIZE_8, + SCB_QSIZE_16, + SCB_QSIZE_32, + SCB_QSIZE_64, + SCB_QSIZE_128, + SCB_QSIZE_256, + SCB_QSIZE_512, + SCB_QSIZE_1024, + SCB_QSIZE_2048, + SCB_QSIZE_4096, + SCB_QSIZE_8192, + SCB_QSIZE_16384 + } +} + +/* + * Interrupt Control + */ +register INTCTL { + address 0x018 + access_mode RW + field SWTMINTMASK 0x80 + field SWTMINTEN 0x40 + field SWTIMER_START 0x20 + field AUTOCLRCMDINT 0x10 + field PCIINTEN 0x08 + field SCSIINTEN 0x04 + field SEQINTEN 0x02 + field SPLTINTEN 0x01 +} + +/* + * Data FIFO Control + */ +register DFCNTRL { + address 0x019 + access_mode RW + modes M_DFF0, M_DFF1 + field PRELOADEN 0x80 + field SCSIENWRDIS 0x40 /* Rev B only. */ + field SCSIEN 0x20 + field SCSIENACK 0x20 + field HDMAEN 0x08 + field HDMAENACK 0x08 + field DIRECTION 0x04 + field DIRECTIONACK 0x04 + field FIFOFLUSH 0x02 + field FIFOFLUSHACK 0x02 + field DIRECTIONEN 0x01 +} + +/* + * Device Space Command 0 + */ +register DSCOMMAND0 { + address 0x019 + access_mode RW + modes M_CFG + field CACHETHEN 0x80 /* Cache Threshold enable */ + field DPARCKEN 0x40 /* Data Parity Check Enable */ + field MPARCKEN 0x20 /* Memory Parity Check Enable */ + field EXTREQLCK 0x10 /* External Request Lock */ + field DISABLE_TWATE 0x02 /* Rev B or greater */ + field CIOPARCKEN 0x01 /* Internal bus parity error enable */ +} + +/* + * Data FIFO Status + */ +register DFSTATUS { + address 0x01A + access_mode RO + modes M_DFF0, M_DFF1 + field PRELOAD_AVAIL 0x80 + field PKT_PRELOAD_AVAIL 0x40 + field MREQPEND 0x10 + field HDONE 0x08 + field DFTHRESH 0x04 + field FIFOFULL 0x02 + field FIFOEMP 0x01 +} + +/* + * S/G Cache Pointer + */ +register SG_CACHE_PRE { + address 0x01B + access_mode WO + modes M_DFF0, M_DFF1 + field SG_ADDR_MASK 0xf8 + field ODD_SEG 0x04 + field LAST_SEG 0x02 +} + +register SG_CACHE_SHADOW { + address 0x01B + access_mode RO + modes M_DFF0, M_DFF1 + field SG_ADDR_MASK 0xf8 + field ODD_SEG 0x04 + field LAST_SEG 0x02 + field LAST_SEG_DONE 0x01 +} + +/* + * Arbiter Control + */ +register ARBCTL { + address 0x01B + access_mode RW + modes M_CFG + field RESET_HARB 0x80 + field RETRY_SWEN 0x08 + field USE_TIME 0x07 +} + +/* + * Data Channel Host Address + */ +register HADDR { + address 0x070 + access_mode RW + size 8 + modes M_DFF0, M_DFF1 +} + +/* + * Host Overlay DMA Address + */ +register HODMAADR { + address 0x070 + access_mode RW + size 8 + modes M_SCSI +} + +/* + * PCI PLL Delay. + */ +register PLLDELAY { + address 0x070 + access_mode RW + size 1 + modes M_CFG + field SPLIT_DROP_REQ 0x80 +} + +/* + * Data Channel Host Count + */ +register HCNT { + address 0x078 + access_mode RW + size 3 + modes M_DFF0, M_DFF1 +} + +/* + * Host Overlay DMA Count + */ +register HODMACNT { + address 0x078 + access_mode RW + size 2 + modes M_SCSI +} + +/* + * Host Overlay DMA Enable + */ +register HODMAEN { + address 0x07A + access_mode RW + modes M_SCSI +} + +/* + * Scatter/Gather Host Address + */ +register SGHADDR { + address 0x07C + access_mode RW + size 8 + modes M_DFF0, M_DFF1 +} + +/* + * SCB Host Address + */ +register SCBHADDR { + address 0x07C + access_mode RW + size 8 + modes M_CCHAN +} + +/* + * Scatter/Gather Host Count + */ +register SGHCNT { + address 0x084 + access_mode RW + modes M_DFF0, M_DFF1 +} + +/* + * SCB Host Count + */ +register SCBHCNT { + address 0x084 + access_mode RW + modes M_CCHAN +} + +/* + * Data FIFO Threshold + */ +register DFF_THRSH { + address 0x088 + access_mode RW + modes M_CFG + field WR_DFTHRSH 0x70 { + WR_DFTHRSH_MIN, + WR_DFTHRSH_25, + WR_DFTHRSH_50, + WR_DFTHRSH_63, + WR_DFTHRSH_75, + WR_DFTHRSH_85, + WR_DFTHRSH_90, + WR_DFTHRSH_MAX + } + field RD_DFTHRSH 0x07 { + RD_DFTHRSH_MIN, + RD_DFTHRSH_25, + RD_DFTHRSH_50, + RD_DFTHRSH_63, + RD_DFTHRSH_75, + RD_DFTHRSH_85, + RD_DFTHRSH_90, + RD_DFTHRSH_MAX + } +} + +/* + * ROM Address + */ +register ROMADDR { + address 0x08A + access_mode RW + size 3 +} + +/* + * ROM Control + */ +register ROMCNTRL { + address 0x08D + access_mode RW + field ROMOP 0xE0 + field ROMSPD 0x18 + field REPEAT 0x02 + field RDY 0x01 +} + +/* + * ROM Data + */ +register ROMDATA { + address 0x08E + access_mode RW +} + +/* + * Data Channel Receive Message 0 + */ +register DCHRXMSG0 { + address 0x090 + access_mode RO + modes M_DFF0, M_DFF1 + field CDNUM 0xF8 + field CFNUM 0x07 +} + +/* + * CMC Recieve Message 0 + */ +register CMCRXMSG0 { + address 0x090 + access_mode RO + modes M_CCHAN + field CDNUM 0xF8 + field CFNUM 0x07 +} + +/* + * Overlay Recieve Message 0 + */ +register OVLYRXMSG0 { + address 0x090 + access_mode RO + modes M_SCSI + field CDNUM 0xF8 + field CFNUM 0x07 +} + +/* + * Relaxed Order Enable + */ +register ROENABLE { + address 0x090 + access_mode RW + modes M_CFG + field MSIROEN 0x20 + field OVLYROEN 0x10 + field CMCROEN 0x08 + field SGROEN 0x04 + field DCH1ROEN 0x02 + field DCH0ROEN 0x01 +} + +/* + * Data Channel Receive Message 1 + */ +register DCHRXMSG1 { + address 0x091 + access_mode RO + modes M_DFF0, M_DFF1 + field CBNUM 0xFF +} + +/* + * CMC Recieve Message 1 + */ +register CMCRXMSG1 { + address 0x091 + access_mode RO + modes M_CCHAN + field CBNUM 0xFF +} + +/* + * Overlay Recieve Message 1 + */ +register OVLYRXMSG1 { + address 0x091 + access_mode RO + modes M_SCSI + field CBNUM 0xFF +} + +/* + * No Snoop Enable + */ +register NSENABLE { + address 0x091 + access_mode RW + modes M_CFG + field MSINSEN 0x20 + field OVLYNSEN 0x10 + field CMCNSEN 0x08 + field SGNSEN 0x04 + field DCH1NSEN 0x02 + field DCH0NSEN 0x01 +} + +/* + * Data Channel Receive Message 2 + */ +register DCHRXMSG2 { + address 0x092 + access_mode RO + modes M_DFF0, M_DFF1 + field MINDEX 0xFF +} + +/* + * CMC Recieve Message 2 + */ +register CMCRXMSG2 { + address 0x092 + access_mode RO + modes M_CCHAN + field MINDEX 0xFF +} + +/* + * Overlay Recieve Message 2 + */ +register OVLYRXMSG2 { + address 0x092 + access_mode RO + modes M_SCSI + field MINDEX 0xFF +} + +/* + * Outstanding Split Transactions + */ +register OST { + address 0x092 + access_mode RW + modes M_CFG +} + +/* + * Data Channel Receive Message 3 + */ +register DCHRXMSG3 { + address 0x093 + access_mode RO + modes M_DFF0, M_DFF1 + field MCLASS 0x0F +} + +/* + * CMC Recieve Message 3 + */ +register CMCRXMSG3 { + address 0x093 + access_mode RO + modes M_CCHAN + field MCLASS 0x0F +} + +/* + * Overlay Recieve Message 3 + */ +register OVLYRXMSG3 { + address 0x093 + access_mode RO + modes M_SCSI + field MCLASS 0x0F +} + +/* + * PCI-X Control + */ +register PCIXCTL { + address 0x093 + access_mode RW + modes M_CFG + field SERRPULSE 0x80 + field UNEXPSCIEN 0x20 + field SPLTSMADIS 0x10 + field SPLTSTADIS 0x08 + field SRSPDPEEN 0x04 + field TSCSERREN 0x02 + field CMPABCDIS 0x01 +} + +/* + * CMC Sequencer Byte Count + */ +register CMCSEQBCNT { + address 0x094 + access_mode RO + modes M_CCHAN +} + +/* + * Overlay Sequencer Byte Count + */ +register OVLYSEQBCNT { + address 0x094 + access_mode RO + modes M_SCSI +} + +/* + * Data Channel Sequencer Byte Count + */ +register DCHSEQBCNT { + address 0x094 + access_mode RO + size 2 + modes M_DFF0, M_DFF1 +} + +/* + * Data Channel Split Status 0 + */ +register DCHSPLTSTAT0 { + address 0x096 + access_mode RW + modes M_DFF0, M_DFF1 + field STAETERM 0x80 + field SCBCERR 0x40 + field SCADERR 0x20 + field SCDATBUCKET 0x10 + field CNTNOTCMPLT 0x08 + field RXOVRUN 0x04 + field RXSCEMSG 0x02 + field RXSPLTRSP 0x01 +} + +/* + * CMC Split Status 0 + */ +register CMCSPLTSTAT0 { + address 0x096 + access_mode RW + modes M_CCHAN + field STAETERM 0x80 + field SCBCERR 0x40 + field SCADERR 0x20 + field SCDATBUCKET 0x10 + field CNTNOTCMPLT 0x08 + field RXOVRUN 0x04 + field RXSCEMSG 0x02 + field RXSPLTRSP 0x01 +} + +/* + * Overlay Split Status 0 + */ +register OVLYSPLTSTAT0 { + address 0x096 + access_mode RW + modes M_SCSI + field STAETERM 0x80 + field SCBCERR 0x40 + field SCADERR 0x20 + field SCDATBUCKET 0x10 + field CNTNOTCMPLT 0x08 + field RXOVRUN 0x04 + field RXSCEMSG 0x02 + field RXSPLTRSP 0x01 +} + +/* + * Data Channel Split Status 1 + */ +register DCHSPLTSTAT1 { + address 0x097 + access_mode RW + modes M_DFF0, M_DFF1 + field RXDATABUCKET 0x01 +} + +/* + * CMC Split Status 1 + */ +register CMCSPLTSTAT1 { + address 0x097 + access_mode RW + modes M_CCHAN + field RXDATABUCKET 0x01 +} + +/* + * Overlay Split Status 1 + */ +register OVLYSPLTSTAT1 { + address 0x097 + access_mode RW + modes M_SCSI + field RXDATABUCKET 0x01 +} + +/* + * S/G Receive Message 0 + */ +register SGRXMSG0 { + address 0x098 + access_mode RO + modes M_DFF0, M_DFF1 + field CDNUM 0xF8 + field CFNUM 0x07 +} + +/* + * S/G Receive Message 1 + */ +register SGRXMSG1 { + address 0x099 + access_mode RO + modes M_DFF0, M_DFF1 + field CBNUM 0xFF +} + +/* + * S/G Receive Message 2 + */ +register SGRXMSG2 { + address 0x09A + access_mode RO + modes M_DFF0, M_DFF1 + field MINDEX 0xFF +} + +/* + * S/G Receive Message 3 + */ +register SGRXMSG3 { + address 0x09B + access_mode RO + modes M_DFF0, M_DFF1 + field MCLASS 0x0F +} + +/* + * Slave Split Out Address 0 + */ +register SLVSPLTOUTADR0 { + address 0x098 + access_mode RO + modes M_SCSI + field LOWER_ADDR 0x7F +} + +/* + * Slave Split Out Address 1 + */ +register SLVSPLTOUTADR1 { + address 0x099 + access_mode RO + modes M_SCSI + field REQ_DNUM 0xF8 + field REQ_FNUM 0x07 +} + +/* + * Slave Split Out Address 2 + */ +register SLVSPLTOUTADR2 { + address 0x09A + access_mode RO + modes M_SCSI + field REQ_BNUM 0xFF +} + +/* + * Slave Split Out Address 3 + */ +register SLVSPLTOUTADR3 { + address 0x09B + access_mode RO + modes M_SCSI + field RLXORD 020 + field TAG_NUM 0x1F +} + +/* + * SG Sequencer Byte Count + */ +register SGSEQBCNT { + address 0x09C + access_mode RO + modes M_DFF0, M_DFF1 +} + +/* + * Slave Split Out Attribute 0 + */ +register SLVSPLTOUTATTR0 { + address 0x09C + access_mode RO + modes M_SCSI + field LOWER_BCNT 0xFF +} + +/* + * Slave Split Out Attribute 1 + */ +register SLVSPLTOUTATTR1 { + address 0x09D + access_mode RO + modes M_SCSI + field CMPLT_DNUM 0xF8 + field CMPLT_FNUM 0x07 +} + +/* + * Slave Split Out Attribute 2 + */ +register SLVSPLTOUTATTR2 { + address 0x09E + access_mode RO + size 2 + modes M_SCSI + field CMPLT_BNUM 0xFF +} +/* + * S/G Split Status 0 + */ +register SGSPLTSTAT0 { + address 0x09E + access_mode RW + modes M_DFF0, M_DFF1 + field STAETERM 0x80 + field SCBCERR 0x40 + field SCADERR 0x20 + field SCDATBUCKET 0x10 + field CNTNOTCMPLT 0x08 + field RXOVRUN 0x04 + field RXSCEMSG 0x02 + field RXSPLTRSP 0x01 +} + +/* + * S/G Split Status 1 + */ +register SGSPLTSTAT1 { + address 0x09F + access_mode RW + modes M_DFF0, M_DFF1 + field RXDATABUCKET 0x01 +} + +/* + * Special Function + */ +register SFUNCT { + address 0x09f + access_mode RW + modes M_CFG + field TEST_GROUP 0xF0 + field TEST_NUM 0x0F +} + +/* + * Data FIFO 0 PCI Status + */ +register DF0PCISTAT { + address 0x0A0 + access_mode RW + modes M_CFG + field DPE 0x80 + field SSE 0x40 + field RMA 0x20 + field RTA 0x10 + field SCAAPERR 0x08 + field RDPERR 0x04 + field TWATERR 0x02 + field DPR 0x01 +} + +/* + * Data FIFO 1 PCI Status + */ +register DF1PCISTAT { + address 0x0A1 + access_mode RW + modes M_CFG + field DPE 0x80 + field SSE 0x40 + field RMA 0x20 + field RTA 0x10 + field SCAAPERR 0x08 + field RDPERR 0x04 + field TWATERR 0x02 + field DPR 0x01 +} + +/* + * S/G PCI Status + */ +register SGPCISTAT { + address 0x0A2 + access_mode RW + modes M_CFG + field DPE 0x80 + field SSE 0x40 + field RMA 0x20 + field RTA 0x10 + field SCAAPERR 0x08 + field RDPERR 0x04 + field DPR 0x01 +} + +/* + * CMC PCI Status + */ +register CMCPCISTAT { + address 0x0A3 + access_mode RW + modes M_CFG + field DPE 0x80 + field SSE 0x40 + field RMA 0x20 + field RTA 0x10 + field SCAAPERR 0x08 + field RDPERR 0x04 + field TWATERR 0x02 + field DPR 0x01 +} + +/* + * Overlay PCI Status + */ +register OVLYPCISTAT { + address 0x0A4 + access_mode RW + modes M_CFG + field DPE 0x80 + field SSE 0x40 + field RMA 0x20 + field RTA 0x10 + field SCAAPERR 0x08 + field RDPERR 0x04 + field DPR 0x01 +} + +/* + * PCI Status for MSI Master DMA Transfer + */ +register MSIPCISTAT { + address 0x0A6 + access_mode RW + modes M_CFG + field SSE 0x40 + field RMA 0x20 + field RTA 0x10 + field CLRPENDMSI 0x08 + field TWATERR 0x02 + field DPR 0x01 +} + +/* + * PCI Status for Target + */ +register TARGPCISTAT { + address 0x0A7 + access_mode RW + modes M_CFG + field DPE 0x80 + field SSE 0x40 + field STA 0x08 + field TWATERR 0x02 +} + +/* + * LQ Packet In + * The last LQ Packet recieved + */ +register LQIN { + address 0x020 + access_mode RW + size 20 + modes M_DFF0, M_DFF1, M_SCSI +} + +/* + * SCB Type Pointer + * SCB offset for Target Mode SCB type information + */ +register TYPEPTR { + address 0x020 + access_mode RW + modes M_CFG +} + +/* + * Queue Tag Pointer + * SCB offset to the Two Byte tag identifier used for target mode. + */ +register TAGPTR { + address 0x021 + access_mode RW + modes M_CFG +} + +/* + * Logical Unit Number Pointer + * SCB offset to the LSB (little endian) of the lun field. + */ +register LUNPTR { + address 0x022 + access_mode RW + modes M_CFG +} + +/* + * Data Length Pointer + * SCB offset for the 4 byte data length field in target mode. + */ +register DATALENPTR { + address 0x023 + access_mode RW + modes M_CFG +} + +/* + * Status Length Pointer + * SCB offset to the two byte status field in target SCBs. + */ +register STATLENPTR { + address 0x024 + access_mode RW + modes M_CFG +} + +/* + * Command Length Pointer + * Scb offset for the CDB length field in initiator SCBs. + */ +register CMDLENPTR { + address 0x025 + access_mode RW + modes M_CFG +} + +/* + * Task Attribute Pointer + * Scb offset for the byte field specifying the attribute byte + * to be used in command packets. + */ +register ATTRPTR { + address 0x026 + access_mode RW + modes M_CFG +} + +/* + * Task Management Flags Pointer + * Scb offset for the byte field specifying the attribute flags + * byte to be used in command packets. + */ +register FLAGPTR { + address 0x027 + access_mode RW + modes M_CFG +} + +/* + * Command Pointer + * Scb offset for the first byte in the CDB for initiator SCBs. + */ +register CMDPTR { + address 0x028 + access_mode RW + modes M_CFG +} + +/* + * Queue Next Pointer + * Scb offset for the 2 byte "next scb link". + */ +register QNEXTPTR { + address 0x029 + access_mode RW + modes M_CFG +} + +/* + * SCSI ID Pointer + * Scb offset to the value to place in the SCSIID register + * during target mode connections. + */ +register IDPTR { + address 0x02A + access_mode RW + modes M_CFG +} + +/* + * Command Aborted Byte Pointer + * Offset to the SCB flags field that includes the + * "SCB aborted" status bit. + */ +register ABRTBYTEPTR { + address 0x02B + access_mode RW + modes M_CFG +} + +/* + * Command Aborted Bit Pointer + * Bit offset in the SCB flags field for "SCB aborted" status. + */ +register ABRTBITPTR { + address 0x02C + access_mode RW + modes M_CFG +} + +/* + * Rev B or greater. + */ +register MAXCMDBYTES { + address 0x02D + access_mode RW + modes M_CFG +} + +/* + * Rev B or greater. + */ +register MAXCMD2RCV { + address 0x02E + access_mode RW + modes M_CFG +} + +/* + * Rev B or greater. + */ +register SHORTTHRESH { + address 0x02F + access_mode RW + modes M_CFG +} + +/* + * Logical Unit Number Length + * The length, in bytes, of the SCB lun field. + */ +register LUNLEN { + address 0x030 + access_mode RW + modes M_CFG + mask ILUNLEN 0x0F + mask TLUNLEN 0xF0 +} +const LUNLEN_SINGLE_LEVEL_LUN 0xF + +/* + * CDB Limit + * The size, in bytes, of the embedded CDB field in initator SCBs. + */ +register CDBLIMIT { + address 0x031 + access_mode RW + modes M_CFG +} + +/* + * Maximum Commands + * The maximum number of commands to issue during a + * single packetized connection. + */ +register MAXCMD { + address 0x032 + access_mode RW + modes M_CFG +} + +/* + * Maximum Command Counter + * The number of commands already sent during this connection + */ +register MAXCMDCNT { + address 0x033 + access_mode RW + modes M_CFG +} + +/* + * LQ Packet Reserved Bytes + * The bytes to be sent in the currently reserved fileds + * of all LQ packets. + */ +register LQRSVD01 { + address 0x034 + access_mode RW + modes M_SCSI +} +register LQRSVD16 { + address 0x035 + access_mode RW + modes M_SCSI +} +register LQRSVD17 { + address 0x036 + access_mode RW + modes M_SCSI +} + +/* + * Command Reserved 0 + * The byte to be sent for the reserved byte 0 of + * outgoing command packets. + */ +register CMDRSVD0 { + address 0x037 + access_mode RW + modes M_CFG +} + +/* + * LQ Manager Control 0 + */ +register LQCTL0 { + address 0x038 + access_mode RW + modes M_CFG + field LQITARGCLT 0xC0 + field LQIINITGCLT 0x30 + field LQ0TARGCLT 0x0C + field LQ0INITGCLT 0x03 +} + +/* + * LQ Manager Control 1 + */ +register LQCTL1 { + address 0x038 + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + field PCI2PCI 0x04 + field SINGLECMD 0x02 + field ABORTPENDING 0x01 +} + +/* + * LQ Manager Control 2 + */ +register LQCTL2 { + address 0x039 + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + field LQIRETRY 0x80 + field LQICONTINUE 0x40 + field LQITOIDLE 0x20 + field LQIPAUSE 0x10 + field LQORETRY 0x08 + field LQOCONTINUE 0x04 + field LQOTOIDLE 0x02 + field LQOPAUSE 0x01 +} + +/* + * SCSI RAM BIST0 + */ +register SCSBIST0 { + address 0x039 + access_mode RW + modes M_CFG + field GSBISTERR 0x40 + field GSBISTDONE 0x20 + field GSBISTRUN 0x10 + field OSBISTERR 0x04 + field OSBISTDONE 0x02 + field OSBISTRUN 0x01 +} + +/* + * SCSI Sequence Control0 + */ +register SCSISEQ0 { + address 0x03A + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + field TEMODEO 0x80 + field ENSELO 0x40 + field ENARBO 0x20 + field FORCEBUSFREE 0x10 + field SCSIRSTO 0x01 +} + +/* + * SCSI RAM BIST 1 + */ +register SCSBIST1 { + address 0x03A + access_mode RW + modes M_CFG + field NTBISTERR 0x04 + field NTBISTDONE 0x02 + field NTBISTRUN 0x01 +} + +/* + * SCSI Sequence Control 1 + */ +register SCSISEQ1 { + address 0x03B + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + field MANUALCTL 0x40 + field ENSELI 0x20 + field ENRSELI 0x10 + field MANUALP 0x0C + field ENAUTOATNP 0x02 + field ALTSTIM 0x01 +} + +/* + * SCSI Transfer Control 0 + */ +register SXFRCTL0 { + address 0x03C + access_mode RW + modes M_SCSI + field DFON 0x80 + field DFPEXP 0x40 + field BIOSCANCELEN 0x10 + field SPIOEN 0x08 +} + +/* + * SCSI Transfer Control 1 + */ +register SXFRCTL1 { + address 0x03D + access_mode RW + modes M_SCSI + field BITBUCKET 0x80 + field ENSACHK 0x40 + field ENSPCHK 0x20 + field STIMESEL 0x18 + field ENSTIMER 0x04 + field ACTNEGEN 0x02 + field STPWEN 0x01 +} + +/* + * SCSI Transfer Control 2 + */ +register SXFRCTL2 { + address 0x03E + access_mode RW + modes M_SCSI + field AUTORSTDIS 0x10 + field CMDDMAEN 0x08 + field ASU 0x07 +} + +/* + * SCSI Bus Initiator IDs + * Bitmask of observed initiators on the bus. + */ +register BUSINITID { + address 0x03C + access_mode RW + modes M_CFG + size 2 +} + +/* + * Data Length Counters + * Packet byte counter. + */ +register DLCOUNT { + address 0x03C + access_mode RW + modes M_DFF0, M_DFF1 + size 3 +} + +/* + * Data FIFO Status + */ +register DFFSTAT { + address 0x03F + access_mode RW + modes M_SCSI + field FIFO1FREE 0x20 + field FIFO0FREE 0x10 + /* + * On the B, this enum only works + * in the read direction. For writes, + * you must use the B version of the + * CURRFIFO_0 definition which is defined + * as a constant outside of this register + * definition to avoid confusing the + * register pretty printing code. + */ + enum CURRFIFO 0x03 { + CURRFIFO_0, + CURRFIFO_1, + CURRFIFO_NONE 0x3 + } +} + +const B_CURRFIFO_0 0x2 + +/* + * SCSI Bus Target IDs + * Bitmask of observed targets on the bus. + */ +register BUSTARGID { + address 0x03E + access_mode RW + modes M_CFG + size 2 +} + +/* + * SCSI Control Signal Out + */ +register SCSISIGO { + address 0x040 + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + field CDO 0x80 + field IOO 0x40 + field MSGO 0x20 + field ATNO 0x10 + field SELO 0x08 + field BSYO 0x04 + field REQO 0x02 + field ACKO 0x01 +/* + * Possible phases to write into SCSISIG0 + */ + enum PHASE_MASK CDO|IOO|MSGO { + P_DATAOUT 0x0, + P_DATAIN IOO, + P_DATAOUT_DT P_DATAOUT|MSGO, + P_DATAIN_DT P_DATAIN|MSGO, + P_COMMAND CDO, + P_MESGOUT CDO|MSGO, + P_STATUS CDO|IOO, + P_MESGIN CDO|IOO|MSGO + } +} + +register SCSISIGI { + address 0x041 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field CDI 0x80 + field IOI 0x40 + field MSGI 0x20 + field ATNI 0x10 + field SELI 0x08 + field BSYI 0x04 + field REQI 0x02 + field ACKI 0x01 +/* + * Possible phases in SCSISIGI + */ + enum PHASE_MASK CDO|IOO|MSGO { + P_DATAOUT 0x0, + P_DATAIN IOO, + P_DATAOUT_DT P_DATAOUT|MSGO, + P_DATAIN_DT P_DATAIN|MSGO, + P_COMMAND CDO, + P_MESGOUT CDO|MSGO, + P_STATUS CDO|IOO, + P_MESGIN CDO|IOO|MSGO + } +} + +/* + * Multiple Target IDs + * Bitmask of ids to respond as a target. + */ +register MULTARGID { + address 0x040 + access_mode RW + modes M_CFG + size 2 +} + +/* + * SCSI Phase + */ +register SCSIPHASE { + address 0x042 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field STATUS_PHASE 0x20 + field COMMAND_PHASE 0x10 + field MSG_IN_PHASE 0x08 + field MSG_OUT_PHASE 0x04 + field DATA_PHASE_MASK 0x03 { + DATA_OUT_PHASE 0x01, + DATA_IN_PHASE 0x02 + } +} + +/* + * SCSI Data 0 Image + */ +register SCSIDAT0_IMG { + address 0x043 + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI +} + +/* + * SCSI Latched Data + */ +register SCSIDAT { + address 0x044 + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + size 2 +} + +/* + * SCSI Data Bus + */ +register SCSIBUS { + address 0x046 + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + size 2 +} + +/* + * Target ID In + */ +register TARGIDIN { + address 0x048 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field CLKOUT 0x80 + field TARGID 0x0F +} + +/* + * Selection/Reselection ID + * 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 0x049 + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + field SELID_MASK 0xf0 + field ONEBIT 0x08 +} + +/* + * SCSI Block Control + * Controls Bus type and channel selection. SELWIDE allows for the + * coexistence of 8bit and 16bit devices on a wide bus. + */ +register SBLKCTL { + address 0x04A + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + field DIAGLEDEN 0x80 + field DIAGLEDON 0x40 + field ENAB40 0x08 /* LVD transceiver active */ + field ENAB20 0x04 /* SE/HVD transceiver active */ + field SELWIDE 0x02 +} + +/* + * Option Mode + */ +register OPTIONMODE { + address 0x04A + access_mode RW + modes M_CFG + field BIOSCANCTL 0x80 + field AUTOACKEN 0x40 + field BIASCANCTL 0x20 + field BUSFREEREV 0x10 + field ENDGFORMCHK 0x04 + field AUTO_MSGOUT_DE 0x02 + mask OPTIONMODE_DEFAULTS AUTO_MSGOUT_DE +} + +/* + * SCSI Status 0 + */ +register SSTAT0 { + address 0x04B + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field TARGET 0x80 /* Board acting as target */ + field SELDO 0x40 /* Selection Done */ + field SELDI 0x20 /* Board has been selected */ + field SELINGO 0x10 /* Selection In Progress */ + field IOERR 0x08 /* LVD Tranceiver mode changed */ + field OVERRUN 0x04 /* SCSI Offset overrun detected */ + field SPIORDY 0x02 /* SCSI PIO Ready */ + field ARBDO 0x01 /* Arbitration Done Out */ +} + +/* + * Clear SCSI Interrupt 0 + * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0. + */ +register CLRSINT0 { + address 0x04B + access_mode WO + modes M_DFF0, M_DFF1, M_SCSI + field CLRSELDO 0x40 + field CLRSELDI 0x20 + field CLRSELINGO 0x10 + field CLRIOERR 0x08 + field CLROVERRUN 0x04 + field CLRSPIORDY 0x02 + field CLRARBDO 0x01 +} + +/* + * SCSI Interrupt Mode 0 + * Setting any bit will enable the corresponding function + * in SIMODE0 to interrupt via the IRQ pin. + */ +register SIMODE0 { + address 0x04B + access_mode RW + modes M_CFG + field ENSELDO 0x40 + field ENSELDI 0x20 + field ENSELINGO 0x10 + field ENIOERR 0x08 + field ENOVERRUN 0x04 + field ENSPIORDY 0x02 + field ENARBDO 0x01 +} + +/* + * SCSI Status 1 + */ +register SSTAT1 { + address 0x04C + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field SELTO 0x80 + field ATNTARG 0x40 + field SCSIRSTI 0x20 + field PHASEMIS 0x10 + field BUSFREE 0x08 + field SCSIPERR 0x04 + field STRB2FAST 0x02 + field REQINIT 0x01 +} + +/* + * Clear SCSI Interrupt 1 + * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. + */ +register CLRSINT1 { + address 0x04C + access_mode WO + modes M_DFF0, M_DFF1, M_SCSI + field CLRSELTIMEO 0x80 + field CLRATNO 0x40 + field CLRSCSIRSTI 0x20 + field CLRBUSFREE 0x08 + field CLRSCSIPERR 0x04 + field CLRSTRB2FAST 0x02 + field CLRREQINIT 0x01 +} + +/* + * SCSI Status 2 + */ +register SSTAT2 { + address 0x04d + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field BUSFREETIME 0xc0 { + BUSFREE_LQO 0x40, + BUSFREE_DFF0 0x80, + BUSFREE_DFF1 0xC0 + } + field NONPACKREQ 0x20 + field EXP_ACTIVE 0x10 /* SCSI Expander Active */ + field BSYX 0x08 /* Busy Expander */ + field WIDE_RES 0x04 /* Modes 0 and 1 only */ + field SDONE 0x02 /* Modes 0 and 1 only */ + field DMADONE 0x01 /* Modes 0 and 1 only */ +} + +/* + * Clear SCSI Interrupt 2 + */ +register CLRSINT2 { + address 0x04D + access_mode WO + modes M_DFF0, M_DFF1, M_SCSI + field CLRNONPACKREQ 0x20 + field CLRWIDE_RES 0x04 /* Modes 0 and 1 only */ + field CLRSDONE 0x02 /* Modes 0 and 1 only */ + field CLRDMADONE 0x01 /* Modes 0 and 1 only */ +} + +/* + * SCSI Interrupt Mode 2 + */ +register SIMODE2 { + address 0x04D + access_mode RW + modes M_CFG + field ENWIDE_RES 0x04 + field ENSDONE 0x02 + field ENDMADONE 0x01 +} + +/* + * Physical Error Diagnosis + */ +register PERRDIAG { + address 0x04E + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field HIZERO 0x80 + field HIPERR 0x40 + field PREVPHASE 0x20 + field PARITYERR 0x10 + field AIPERR 0x08 + field CRCERR 0x04 + field DGFORMERR 0x02 + field DTERR 0x01 +} + +/* + * LQI Manager Current State + */ +register LQISTATE { + address 0x04E + access_mode RO + modes M_CFG +} + +/* + * SCSI Offset Count + */ +register SOFFCNT { + address 0x04F + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI +} + +/* + * LQO Manager Current State + */ +register LQOSTATE { + address 0x04F + access_mode RO + modes M_CFG +} + +/* + * LQI Manager Status + */ +register LQISTAT0 { + address 0x050 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field LQIATNQAS 0x20 + field LQICRCT1 0x10 + field LQICRCT2 0x08 + field LQIBADLQT 0x04 + field LQIATNLQ 0x02 + field LQIATNCMD 0x01 +} + +/* + * Clear LQI Interrupts 0 + */ +register CLRLQIINT0 { + address 0x050 + access_mode WO + modes M_DFF0, M_DFF1, M_SCSI + field CLRLQIATNQAS 0x20 + field CLRLQICRCT1 0x10 + field CLRLQICRCT2 0x08 + field CLRLQIBADLQT 0x04 + field CLRLQIATNLQ 0x02 + field CLRLQIATNCMD 0x01 +} + +/* + * LQI Manager Interrupt Mode 0 + */ +register LQIMODE0 { + address 0x050 + access_mode RW + modes M_CFG + field ENLQIATNQASK 0x20 + field ENLQICRCT1 0x10 + field ENLQICRCT2 0x08 + field ENLQIBADLQT 0x04 + field ENLQIATNLQ 0x02 + field ENLQIATNCMD 0x01 +} + +/* + * LQI Manager Status 1 + */ +register LQISTAT1 { + address 0x051 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field LQIPHASE_LQ 0x80 + field LQIPHASE_NLQ 0x40 + field LQIABORT 0x20 + field LQICRCI_LQ 0x10 + field LQICRCI_NLQ 0x08 + field LQIBADLQI 0x04 + field LQIOVERI_LQ 0x02 + field LQIOVERI_NLQ 0x01 +} + +/* + * Clear LQI Manager Interrupts1 + */ +register CLRLQIINT1 { + address 0x051 + access_mode WO + modes M_DFF0, M_DFF1, M_SCSI + field CLRLQIPHASE_LQ 0x80 + field CLRLQIPHASE_NLQ 0x40 + field CLRLIQABORT 0x20 + field CLRLQICRCI_LQ 0x10 + field CLRLQICRCI_NLQ 0x08 + field CLRLQIBADLQI 0x04 + field CLRLQIOVERI_LQ 0x02 + field CLRLQIOVERI_NLQ 0x01 +} + +/* + * LQI Manager Interrupt Mode 1 + */ +register LQIMODE1 { + address 0x051 + access_mode RW + modes M_CFG + field ENLQIPHASE_LQ 0x80 /* LQIPHASE1 */ + field ENLQIPHASE_NLQ 0x40 /* LQIPHASE2 */ + field ENLIQABORT 0x20 + field ENLQICRCI_LQ 0x10 /* LQICRCI1 */ + field ENLQICRCI_NLQ 0x08 /* LQICRCI2 */ + field ENLQIBADLQI 0x04 + field ENLQIOVERI_LQ 0x02 /* LQIOVERI1 */ + field ENLQIOVERI_NLQ 0x01 /* LQIOVERI2 */ +} + +/* + * LQI Manager Status 2 + */ +register LQISTAT2 { + address 0x052 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field PACKETIZED 0x80 + field LQIPHASE_OUTPKT 0x40 + field LQIWORKONLQ 0x20 + field LQIWAITFIFO 0x10 + field LQISTOPPKT 0x08 + field LQISTOPLQ 0x04 + field LQISTOPCMD 0x02 + field LQIGSAVAIL 0x01 +} + +/* + * SCSI Status 3 + */ +register SSTAT3 { + address 0x053 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field NTRAMPERR 0x02 + field OSRAMPERR 0x01 +} + +/* + * Clear SCSI Status 3 + */ +register CLRSINT3 { + address 0x053 + access_mode WO + modes M_DFF0, M_DFF1, M_SCSI + field CLRNTRAMPERR 0x02 + field CLROSRAMPERR 0x01 +} + +/* + * SCSI Interrupt Mode 3 + */ +register SIMODE3 { + address 0x053 + access_mode RW + modes M_CFG + field ENNTRAMPERR 0x02 + field ENOSRAMPERR 0x01 +} + +/* + * LQO Manager Status 0 + */ +register LQOSTAT0 { + address 0x054 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field LQOTARGSCBPERR 0x10 + field LQOSTOPT2 0x08 + field LQOATNLQ 0x04 + field LQOATNPKT 0x02 + field LQOTCRC 0x01 +} + +/* + * Clear LQO Manager interrupt 0 + */ +register CLRLQOINT0 { + address 0x054 + access_mode WO + modes M_DFF0, M_DFF1, M_SCSI + field CLRLQOTARGSCBPERR 0x10 + field CLRLQOSTOPT2 0x08 + field CLRLQOATNLQ 0x04 + field CLRLQOATNPKT 0x02 + field CLRLQOTCRC 0x01 +} + +/* + * LQO Manager Interrupt Mode 0 + */ +register LQOMODE0 { + address 0x054 + access_mode RW + modes M_CFG + field ENLQOTARGSCBPERR 0x10 + field ENLQOSTOPT2 0x08 + field ENLQOATNLQ 0x04 + field ENLQOATNPKT 0x02 + field ENLQOTCRC 0x01 +} + +/* + * LQO Manager Status 1 + */ +register LQOSTAT1 { + address 0x055 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field LQOINITSCBPERR 0x10 + field LQOSTOPI2 0x08 + field LQOBADQAS 0x04 + field LQOBUSFREE 0x02 + field LQOPHACHGINPKT 0x01 +} + +/* + * Clear LOQ Interrupt 1 + */ +register CLRLQOINT1 { + address 0x055 + access_mode WO + modes M_DFF0, M_DFF1, M_SCSI + field CLRLQOINITSCBPERR 0x10 + field CLRLQOSTOPI2 0x08 + field CLRLQOBADQAS 0x04 + field CLRLQOBUSFREE 0x02 + field CLRLQOPHACHGINPKT 0x01 +} + +/* + * LQO Manager Interrupt Mode 1 + */ +register LQOMODE1 { + address 0x055 + access_mode RW + modes M_CFG + field ENLQOINITSCBPERR 0x10 + field ENLQOSTOPI2 0x08 + field ENLQOBADQAS 0x04 + field ENLQOBUSFREE 0x02 + field ENLQOPHACHGINPKT 0x01 +} + +/* + * LQO Manager Status 2 + */ +register LQOSTAT2 { + address 0x056 + access_mode RO + modes M_DFF0, M_DFF1, M_SCSI + field LQOPKT 0xE0 + field LQOWAITFIFO 0x10 + field LQOPHACHGOUTPKT 0x02 /* outside of packet boundaries. */ + field LQOSTOP0 0x01 /* Stopped after sending all packets */ +} + +/* + * Output Synchronizer Space Count + */ +register OS_SPACE_CNT { + address 0x056 + access_mode RO + modes M_CFG +} + +/* + * SCSI Interrupt Mode 1 + * Setting any bit will enable the corresponding function + * in SIMODE1 to interrupt via the IRQ pin. + */ +register SIMODE1 { + address 0x057 + access_mode RW + modes M_DFF0, M_DFF1, M_SCSI + field ENSELTIMO 0x80 + field ENATNTARG 0x40 + field ENSCSIRST 0x20 + field ENPHASEMIS 0x10 + field ENBUSFREE 0x08 + field ENSCSIPERR 0x04 + field ENSTRB2FAST 0x02 + field ENREQINIT 0x01 +} + +/* + * Good Status FIFO + */ +register GSFIFO { + address 0x058 + access_mode RO + size 2 + modes M_DFF0, M_DFF1, M_SCSI +} + +/* + * Data FIFO SCSI Transfer Control + */ +register DFFSXFRCTL { + address 0x05A + access_mode RW + modes M_DFF0, M_DFF1 + field DFFBITBUCKET 0x08 + field CLRSHCNT 0x04 + field CLRCHN 0x02 + field RSTCHN 0x01 +} + +/* + * Next SCSI Control Block + */ +register NEXTSCB { + address 0x05A + access_mode RW + size 2 + modes M_SCSI +} + +/* Rev B only. */ +register LQOSCSCTL { + address 0x05A + access_mode RW + size 1 + modes M_CFG + field LQOH2A_VERSION 0x80 + field LQONOCHKOVER 0x01 +} + +/* + * SEQ Interrupts + */ +register SEQINTSRC { + address 0x05B + access_mode RO + modes M_DFF0, M_DFF1 + field CTXTDONE 0x40 + field SAVEPTRS 0x20 + field CFG4DATA 0x10 + field CFG4ISTAT 0x08 + field CFG4TSTAT 0x04 + field CFG4ICMD 0x02 + field CFG4TCMD 0x01 +} + +/* + * Clear Arp Interrupts + */ +register CLRSEQINTSRC { + address 0x05B + access_mode WO + modes M_DFF0, M_DFF1 + field CLRCTXTDONE 0x40 + field CLRSAVEPTRS 0x20 + field CLRCFG4DATA 0x10 + field CLRCFG4ISTAT 0x08 + field CLRCFG4TSTAT 0x04 + field CLRCFG4ICMD 0x02 + field CLRCFG4TCMD 0x01 +} + +/* + * SEQ Interrupt Enabled (Shared) + */ +register SEQIMODE { + address 0x05C + access_mode RW + modes M_DFF0, M_DFF1 + field ENCTXTDONE 0x40 + field ENSAVEPTRS 0x20 + field ENCFG4DATA 0x10 + field ENCFG4ISTAT 0x08 + field ENCFG4TSTAT 0x04 + field ENCFG4ICMD 0x02 + field ENCFG4TCMD 0x01 +} + +/* + * Current SCSI Control Block + */ +register CURRSCB { + address 0x05C + access_mode RW + size 2 + modes M_SCSI +} + +/* + * Data FIFO Status + */ +register MDFFSTAT { + address 0x05D + access_mode RO + modes M_DFF0, M_DFF1 + field SHCNTNEGATIVE 0x40 /* Rev B or higher */ + field SHCNTMINUS1 0x20 /* Rev B or higher */ + field LASTSDONE 0x10 + field SHVALID 0x08 + field DLZERO 0x04 /* FIFO data ends on packet boundary. */ + field DATAINFIFO 0x02 + field FIFOFREE 0x01 +} + +/* + * CRC Control + */ +register CRCCONTROL { + address 0x05d + access_mode RW + modes M_CFG + field CRCVALCHKEN 0x40 +} + +/* + * SCSI Test Control + */ +register SCSITEST { + address 0x05E + access_mode RW + modes M_CFG + field CNTRTEST 0x08 + field SEL_TXPLL_DEBUG 0x04 +} + +/* + * Data FIFO Queue Tag + */ +register DFFTAG { + address 0x05E + access_mode RW + size 2 + modes M_DFF0, M_DFF1 +} + +/* + * Last SCSI Control Block + */ +register LASTSCB { + address 0x05E + access_mode RW + size 2 + modes M_SCSI +} + +/* + * SCSI I/O Cell Power-down Control + */ +register IOPDNCTL { + address 0x05F + access_mode RW + modes M_CFG + field DISABLE_OE 0x80 + field PDN_IDIST 0x04 + field PDN_DIFFSENSE 0x01 +} + +/* + * Shaddow Host Address. + */ +register SHADDR { + address 0x060 + access_mode RO + size 8 + modes M_DFF0, M_DFF1 +} + +/* + * Data Group CRC Interval. + */ +register DGRPCRCI { + address 0x060 + access_mode RW + size 2 + modes M_CFG +} + +/* + * Data Transfer Negotiation Address + */ +register NEGOADDR { + address 0x060 + access_mode RW + modes M_SCSI +} + +/* + * Data Transfer Negotiation Data - Period Byte + */ +register NEGPERIOD { + address 0x061 + access_mode RW + modes M_SCSI +} + +/* + * Packetized CRC Interval + */ +register PACKCRCI { + address 0x062 + access_mode RW + size 2 + modes M_CFG +} + +/* + * Data Transfer Negotiation Data - Offset Byte + */ +register NEGOFFSET { + address 0x062 + access_mode RW + modes M_SCSI +} + +/* + * Data Transfer Negotiation Data - PPR Options + */ +register NEGPPROPTS { + address 0x063 + access_mode RW + modes M_SCSI + field PPROPT_PACE 0x08 + field PPROPT_QAS 0x04 + field PPROPT_DT 0x02 + field PPROPT_IUT 0x01 +} + +/* + * Data Transfer Negotiation Data - Connection Options + */ +register NEGCONOPTS { + address 0x064 + access_mode RW + modes M_SCSI + field ENSNAPSHOT 0x40 + field RTI_WRTDIS 0x20 + field RTI_OVRDTRN 0x10 + field ENSLOWCRC 0x08 + field ENAUTOATNI 0x04 + field ENAUTOATNO 0x02 + field WIDEXFER 0x01 +} + +/* + * Negotiation Table Annex Column Index. + */ +register ANNEXCOL { + address 0x065 + access_mode RW + modes M_SCSI +} + +register SCSCHKN { + address 0x066 + access_mode RW + modes M_CFG + field STSELSKIDDIS 0x40 + field CURRFIFODEF 0x20 + field WIDERESEN 0x10 + field SDONEMSKDIS 0x08 + field DFFACTCLR 0x04 + field SHVALIDSTDIS 0x02 + field LSTSGCLRDIS 0x01 +} + +const AHD_ANNEXCOL_PER_DEV0 4 +const AHD_NUM_PER_DEV_ANNEXCOLS 4 +const AHD_ANNEXCOL_PRECOMP_SLEW 4 +const AHD_PRECOMP_MASK 0x07 +const AHD_PRECOMP_SHIFT 0 +const AHD_PRECOMP_CUTBACK_17 0x04 +const AHD_PRECOMP_CUTBACK_29 0x06 +const AHD_PRECOMP_CUTBACK_37 0x07 +const AHD_SLEWRATE_MASK 0x78 +const AHD_SLEWRATE_SHIFT 3 +/* + * Rev A has only a single bit (high bit of field) of slew adjustment. + * Rev B has 4 bits. The current default happens to be the same for both. + */ +const AHD_SLEWRATE_DEF_REVA 0x08 +const AHD_SLEWRATE_DEF_REVB 0x08 + +/* Rev A does not have any amplitude setting. */ +const AHD_ANNEXCOL_AMPLITUDE 6 +const AHD_AMPLITUDE_MASK 0x7 +const AHD_AMPLITUDE_SHIFT 0 +const AHD_AMPLITUDE_DEF 0x7 + +/* + * Negotiation Table Annex Data Port. + */ +register ANNEXDAT { + address 0x066 + access_mode RW + modes M_SCSI +} + +/* + * Initiator's Own Id. + * The SCSI ID to use for Selection Out and seen during a reselection.. + */ +register IOWNID { + address 0x067 + access_mode RW + modes M_SCSI +} + +/* + * 960MHz Phase-Locked Loop Control 0 + */ +register PLL960CTL0 { + address 0x068 + access_mode RW + modes M_CFG + field PLL_VCOSEL 0x80 + field PLL_PWDN 0x40 + field PLL_NS 0x30 + field PLL_ENLUD 0x08 + field PLL_ENLPF 0x04 + field PLL_DLPF 0x02 + field PLL_ENFBM 0x01 +} + +/* + * Target Own Id + */ +register TOWNID { + address 0x069 + access_mode RW + modes M_SCSI +} + +/* + * 960MHz Phase-Locked Loop Control 1 + */ +register PLL960CTL1 { + address 0x069 + access_mode RW + modes M_CFG + field PLL_CNTEN 0x80 + field PLL_CNTCLR 0x40 + field PLL_RST 0x01 +} + +/* + * Expander Signature + */ +register XSIG { + address 0x06A + access_mode RW + modes M_SCSI +} + +/* + * Shadow Byte Count + */ +register SHCNT { + address 0x068 + access_mode RW + size 3 + modes M_DFF0, M_DFF1 +} + +/* + * Selection Out ID + */ +register SELOID { + address 0x06B + access_mode RW + modes M_SCSI +} + +/* + * 960-MHz Phase-Locked Loop Test Count + */ +register PLL960CNT0 { + address 0x06A + access_mode RO + size 2 + modes M_CFG +} + +/* + * 400-MHz Phase-Locked Loop Control 0 + */ +register PLL400CTL0 { + address 0x06C + access_mode RW + modes M_CFG + field PLL_VCOSEL 0x80 + field PLL_PWDN 0x40 + field PLL_NS 0x30 + field PLL_ENLUD 0x08 + field PLL_ENLPF 0x04 + field PLL_DLPF 0x02 + field PLL_ENFBM 0x01 +} + +/* + * Arbitration Fairness + */ +register FAIRNESS { + address 0x06C + access_mode RW + size 2 + modes M_SCSI +} + +/* + * 400-MHz Phase-Locked Loop Control 1 + */ +register PLL400CTL1 { + address 0x06D + access_mode RW + modes M_CFG + field PLL_CNTEN 0x80 + field PLL_CNTCLR 0x40 + field PLL_RST 0x01 +} + +/* + * Arbitration Unfairness + */ +register UNFAIRNESS { + address 0x06E + access_mode RW + size 2 + modes M_SCSI +} + +/* + * 400-MHz Phase-Locked Loop Test Count + */ +register PLL400CNT0 { + address 0x06E + access_mode RO + size 2 + modes M_CFG +} + +/* + * SCB Page Pointer + */ +register SCBPTR { + address 0x0A8 + access_mode RW + size 2 + modes M_DFF0, M_DFF1, M_CCHAN, M_SCSI +} + +/* + * CMC SCB Array Count + * Number of bytes to transfer between CMC SCB memory and SCBRAM. + * Transfers must be 8byte aligned and sized. + */ +register CCSCBACNT { + address 0x0AB + access_mode RW + modes M_CCHAN +} + +/* + * SCB Autopointer + * SCB-Next Address Snooping logic. When an SCB is transferred to + * the card, the next SCB address to be used by the CMC array can + * be autoloaded from that transfer. + */ +register SCBAUTOPTR { + address 0x0AB + access_mode RW + modes M_CFG + field AUSCBPTR_EN 0x80 + field SCBPTR_ADDR 0x38 + field SCBPTR_OFF 0x07 +} + +/* + * CMC SG Ram Address Pointer + */ +register CCSGADDR { + address 0x0AC + access_mode RW + modes M_DFF0, M_DFF1 +} + +/* + * CMC SCB RAM Address Pointer + */ +register CCSCBADDR { + address 0x0AC + access_mode RW + modes M_CCHAN +} + +/* + * CMC SCB Ram Back-up Address Pointer + * Indicates the true stop location of transfers halted prior + * to SCBHCNT going to 0. + */ +register CCSCBADR_BK { + address 0x0AC + access_mode RO + modes M_CFG +} + +/* + * CMC SG Control + */ +register CCSGCTL { + address 0x0AD + access_mode RW + modes M_DFF0, M_DFF1 + field CCSGDONE 0x80 + field SG_CACHE_AVAIL 0x10 + field CCSGENACK 0x08 + mask CCSGEN 0x0C + field SG_FETCH_REQ 0x02 + field CCSGRESET 0x01 +} + +/* + * CMD SCB Control + */ +register CCSCBCTL { + address 0x0AD + access_mode RW + modes M_CCHAN + field CCSCBDONE 0x80 + field ARRDONE 0x40 + field CCARREN 0x10 + field CCSCBEN 0x08 + field CCSCBDIR 0x04 + field CCSCBRESET 0x01 +} + +/* + * CMC Ram BIST + */ +register CMC_RAMBIST { + address 0x0AD + access_mode RW + modes M_CFG + field SG_ELEMENT_SIZE 0x80 + field SCBRAMBIST_FAIL 0x40 + field SG_BIST_FAIL 0x20 + field SG_BIST_EN 0x10 + field CMC_BUFFER_BIST_FAIL 0x02 + field CMC_BUFFER_BIST_EN 0x01 +} + +/* + * CMC SG RAM Data Port + */ +register CCSGRAM { + address 0x0B0 + access_mode RW + modes M_DFF0, M_DFF1 +} + +/* + * CMC SCB RAM Data Port + */ +register CCSCBRAM { + address 0x0B0 + access_mode RW + modes M_CCHAN +} + +/* + * Flex DMA Address. + */ +register FLEXADR { + address 0x0B0 + access_mode RW + size 3 + modes M_SCSI +} + +/* + * Flex DMA Byte Count + */ +register FLEXCNT { + address 0x0B3 + access_mode RW + size 2 + modes M_SCSI +} + +/* + * Flex DMA Status + */ +register FLEXDMASTAT { + address 0x0B5 + access_mode RW + modes M_SCSI + field FLEXDMAERR 0x02 + field FLEXDMADONE 0x01 +} + +/* + * Flex DMA Data Port + */ +register FLEXDATA { + address 0x0B6 + access_mode RW + modes M_SCSI +} + +/* + * Board Data + */ +register BRDDAT { + address 0x0B8 + access_mode RW + modes M_SCSI +} + +/* + * Board Control + */ +register BRDCTL { + address 0x0B9 + access_mode RW + modes M_SCSI + field FLXARBACK 0x80 + field FLXARBREQ 0x40 + field BRDADDR 0x38 + field BRDEN 0x04 + field BRDRW 0x02 + field BRDSTB 0x01 +} + +/* + * Serial EEPROM Address + */ +register SEEADR { + address 0x0BA + access_mode RW + modes M_SCSI +} + +/* + * Serial EEPROM Data + */ +register SEEDAT { + address 0x0BC + access_mode RW + size 2 + modes M_SCSI +} + +/* + * Serial EEPROM Status + */ +register SEESTAT { + address 0x0BE + access_mode RO + modes M_SCSI + field INIT_DONE 0x80 + field SEEOPCODE 0x70 + field LDALTID_L 0x08 + field SEEARBACK 0x04 + field SEEBUSY 0x02 + field SEESTART 0x01 +} + +/* + * Serial EEPROM Control + */ +register SEECTL { + address 0x0BE + access_mode RW + modes M_SCSI + field SEEOPCODE 0x70 { + SEEOP_ERASE 0x70, + SEEOP_READ 0x60, + SEEOP_WRITE 0x50, + /* + * The following four commands use special + * addresses for differentiation. + */ + SEEOP_ERAL 0x40 + } + mask SEEOP_EWEN 0x40 + mask SEEOP_WALL 0x40 + mask SEEOP_EWDS 0x40 + field SEERST 0x02 + field SEESTART 0x01 +} + +const SEEOP_ERAL_ADDR 0x80 +const SEEOP_EWEN_ADDR 0xC0 +const SEEOP_WRAL_ADDR 0x40 +const SEEOP_EWDS_ADDR 0x00 + +/* + * SCB Counter + */ +register SCBCNT { + address 0x0BF + access_mode RW + modes M_SCSI +} + +/* + * Data FIFO Write Address + * Pointer to the next QWD location to be written to the data FIFO. + */ +register DFWADDR { + address 0x0C0 + access_mode RW + size 2 + modes M_DFF0, M_DFF1 +} + +/* + * DSP Filter Control + */ +register DSPFLTRCTL { + address 0x0C0 + access_mode RW + modes M_CFG + field FLTRDISABLE 0x20 + field EDGESENSE 0x10 + field DSPFCNTSEL 0x0F +} + +/* + * DSP Data Channel Control + */ +register DSPDATACTL { + address 0x0C1 + access_mode RW + modes M_CFG + field BYPASSENAB 0x80 + field DESQDIS 0x10 + field RCVROFFSTDIS 0x04 + field XMITOFFSTDIS 0x02 +} + +/* + * Data FIFO Read Address + * Pointer to the next QWD location to be read from the data FIFO. + */ +register DFRADDR { + address 0x0C2 + access_mode RW + size 2 + modes M_DFF0, M_DFF1 +} + +/* + * DSP REQ Control + */ +register DSPREQCTL { + address 0x0C2 + access_mode RW + modes M_CFG + field MANREQCTL 0xC0 + field MANREQDLY 0x3F +} + +/* + * DSP ACK Control + */ +register DSPACKCTL { + address 0x0C3 + access_mode RW + modes M_CFG + field MANACKCTL 0xC0 + field MANACKDLY 0x3F +} + +/* + * Data FIFO Data + * Read/Write byte port into the data FIFO. The read and write + * FIFO pointers increment with each read and write respectively + * to this port. + */ +register DFDAT { + address 0x0C4 + access_mode RW + modes M_DFF0, M_DFF1 +} + +/* + * DSP Channel Select + */ +register DSPSELECT { + address 0x0C4 + access_mode RW + modes M_CFG + field AUTOINCEN 0x80 + field DSPSEL 0x1F +} + +const NUMDSPS 0x14 + +/* + * Write Bias Control + */ +register WRTBIASCTL { + address 0x0C5 + access_mode WO + modes M_CFG + field AUTOXBCDIS 0x80 + field XMITMANVAL 0x3F +} + +/* + * Currently the WRTBIASCTL is the same as the default. + */ +const WRTBIASCTL_HP_DEFAULT 0x0 + +/* + * Receiver Bias Control + */ +register RCVRBIOSCTL { + address 0x0C6 + access_mode WO + modes M_CFG + field AUTORBCDIS 0x80 + field RCVRMANVAL 0x3F +} + +/* + * Write Bias Calculator + */ +register WRTBIASCALC { + address 0x0C7 + access_mode RO + modes M_CFG +} + +/* + * Data FIFO Pointers + * Contains the byte offset from DFWADDR and DWRADDR to the current + * FIFO write/read locations. + */ +register DFPTRS { + address 0x0C8 + access_mode RW + modes M_DFF0, M_DFF1 +} + +/* + * Receiver Bias Calculator + */ +register RCVRBIASCALC { + address 0x0C8 + access_mode RO + modes M_CFG +} + +/* + * Data FIFO Backup Read Pointer + * Contains the data FIFO address to be restored if the last + * data accessed from the data FIFO was not transferred successfully. + */ +register DFBKPTR { + address 0x0C9 + access_mode RW + size 2 + modes M_DFF0, M_DFF1 +} + +/* + * Skew Calculator + */ +register SKEWCALC { + address 0x0C9 + access_mode RO + modes M_CFG +} + +/* + * Data FIFO Debug Control + */ +register DFDBCTL { + address 0x0CB + access_mode RW + modes M_DFF0, M_DFF1 + field DFF_CIO_WR_RDY 0x20 + field DFF_CIO_RD_RDY 0x10 + field DFF_DIR_ERR 0x08 + field DFF_RAMBIST_FAIL 0x04 + field DFF_RAMBIST_DONE 0x02 + field DFF_RAMBIST_EN 0x01 +} + +/* + * Data FIFO Space Count + * Number of FIFO locations that are free. + */ +register DFSCNT { + address 0x0CC + access_mode RO + size 2 + modes M_DFF0, M_DFF1 +} + +/* + * Data FIFO Byte Count + * Number of filled FIFO locations. + */ +register DFBCNT { + address 0x0CE + access_mode RO + size 2 + modes M_DFF0, M_DFF1 +} + +/* + * Sequencer Program Overlay Address. + * Low address must be written prior to high address. + */ +register OVLYADDR { + address 0x0D4 + modes M_SCSI + size 2 + access_mode RW +} + +/* + * Sequencer Control 0 + * Error detection mode, speed configuration, + * single step, breakpoints and program load. + */ +register SEQCTL0 { + address 0x0D6 + access_mode RW + field PERRORDIS 0x80 + field PAUSEDIS 0x40 + field FAILDIS 0x20 + field FASTMODE 0x10 + field BRKADRINTEN 0x08 + field STEP 0x04 + field SEQRESET 0x02 + field LOADRAM 0x01 +} + +/* + * Sequencer Control 1 + * Instruction RAM Diagnostics + */ +register SEQCTL1 { + address 0x0D7 + access_mode RW + field OVRLAY_DATA_CHK 0x08 + field RAMBIST_DONE 0x04 + field RAMBIST_FAIL 0x02 + field RAMBIST_EN 0x01 +} + +/* + * Sequencer Flags + * Zero and Carry state of the ALU. + */ +register FLAGS { + address 0x0D8 + access_mode RO + field ZERO 0x02 + field CARRY 0x01 +} + +/* + * Sequencer Interrupt Control + */ +register SEQINTCTL { + address 0x0D9 + access_mode RW + field INTVEC1DSL 0x80 + field INT1_CONTEXT 0x20 + field SCS_SEQ_INT1M1 0x10 + field SCS_SEQ_INT1M0 0x08 + field INTMASK2 0x04 + field INTMASK1 0x02 + field IRET 0x01 +} + +/* + * Sequencer RAM Data Port + * Single byte window into the Sequencer Instruction Ram area starting + * at the address specified by OVLYADDR. To write a full instruction word, + * simply write four bytes in succession. OVLYADDR will increment after the + * most significant instrution byte (the byte with the parity bit) is written. + */ +register SEQRAM { + address 0x0DA + access_mode RW +} + +/* + * Sequencer Program Counter + * Low byte must be written prior to high byte. + */ +register PRGMCNT { + address 0x0DE + access_mode RW + size 2 +} + +/* + * Accumulator + */ +register ACCUM { + address 0x0E0 + access_mode RW + accumulator +} + +/* + * Source Index Register + * Incrementing index for reads of SINDIR and the destination (low byte only) + * for any immediate operands passed in jmp, jc, jnc, call instructions. + * Example: + * mvi 0xFF call some_routine; + * + * Will set SINDEX[0] to 0xFF and call the routine "some_routine. + */ +register SINDEX { + address 0x0E2 + access_mode RW + size 2 + sindex +} + +/* + * Destination Index Register + * Incrementing index for writes to DINDIR. Can be used as a scratch register. + */ +register DINDEX { + address 0x0E4 + access_mode RW + size 2 +} + +/* + * Break Address + * Sequencer instruction breakpoint address address. + */ +register BRKADDR0 { + address 0x0E6 + access_mode RW +} + +register BRKADDR1 { + address 0x0E6 + access_mode RW + field BRKDIS 0x80 /* Disable Breakpoint */ +} + +/* + * All Ones + * All reads to this register return the value 0xFF. + */ +register ALLONES { + address 0x0E8 + access_mode RO + allones +} + +/* + * All Zeros + * All reads to this register return the value 0. + */ +register ALLZEROS { + address 0x0EA + access_mode RO + allzeros +} + +/* + * No Destination + * Writes to this register have no effect. + */ +register NONE { + address 0x0EA + access_mode WO + none +} + +/* + * Source Index Indirect + * Reading this register is equivalent to reading (register_base + SINDEX) and + * incrementing SINDEX by 1. + */ +register SINDIR { + address 0x0EC + access_mode RO +} + +/* + * Destination Index Indirect + * Writing this register is equivalent to writing to (register_base + DINDEX) + * and incrementing DINDEX by 1. + */ +register DINDIR { + address 0x0ED + access_mode WO +} + +/* + * Function One + * 2's complement to bit value conversion. Write the 2's complement value + * (0-7 only) to the top nibble and retrieve the bit indexed by that value + * on the next read of this register. + * Example: + * Write 0x60 + * Read 0x40 + */ +register FUNCTION1 { + address 0x0F0 + access_mode RW +} + +/* + * Stack + * Window into the stack. Each stack location is 10 bits wide reported + * low byte followed by high byte. There are 8 stack locations. + */ +register STACK { + address 0x0F2 + access_mode RW +} + +/* + * Interrupt Vector 1 Address + * Interrupt branch address for SCS SEQ_INT1 mode 0 and 1 interrupts. + */ +register INTVEC1_ADDR { + address 0x0F4 + access_mode RW + size 2 + modes M_CFG +} + +/* + * Current Address + * Address of the SEQRAM instruction currently executing instruction. + */ +register CURADDR { + address 0x0F4 + access_mode RW + size 2 + modes M_SCSI +} + +/* + * Interrupt Vector 2 Address + * Interrupt branch address for HST_SEQ_INT2 interrupts. + */ +register INTVEC2_ADDR { + address 0x0F6 + access_mode RW + size 2 + modes M_CFG +} + +/* + * Last Address + * Address of the SEQRAM instruction executed prior to the current instruction. + */ +register LASTADDR { + address 0x0F6 + access_mode RW + size 2 + modes M_SCSI +} + +register AHD_PCI_CONFIG_BASE { + address 0x100 + access_mode RW + size 256 + modes M_CFG +} + +/* ---------------------- Scratch RAM Offsets ------------------------- */ +scratch_ram { + /* Mode Specific */ + address 0x0A0 + size 8 + modes 0, 1, 2, 3 + REG0 { + size 2 + } + REG1 { + size 2 + } + REG_ISR { + size 2 + } + SG_STATE { + size 1 + field SEGS_AVAIL 0x01 + field LOADING_NEEDED 0x02 + field FETCH_INPROG 0x04 + } + /* + * Track whether the transfer byte count for + * the current data phase is odd. + */ + DATA_COUNT_ODD { + size 1 + } +} + +scratch_ram { + /* Mode Specific */ + address 0x0F8 + size 8 + modes 0, 1, 2, 3 + LONGJMP_ADDR { + size 2 + } + ACCUM_SAVE { + size 1 + } +} + + +scratch_ram { + address 0x100 + size 128 + modes 0, 1, 2, 3 + /* + * Per "other-id" execution queues. We use an array of + * tail pointers into lists of SCBs sorted by "other-id". + * The execution head pointer threads the head SCBs for + * each list. + */ + WAITING_SCB_TAILS { + size 32 + } + WAITING_TID_HEAD { + size 2 + } + WAITING_TID_TAIL { + size 2 + } + /* + * SCBID of the next SCB in the new SCB queue. + */ + NEXT_QUEUED_SCB_ADDR { + size 4 + } + /* + * head of list of SCBs that have + * completed but have not been + * put into the qoutfifo. + */ + COMPLETE_SCB_HEAD { + size 2 + } + /* + * The list of completed SCBs in + * the active DMA. + */ + COMPLETE_SCB_DMAINPROG_HEAD { + size 2 + } + /* + * head of list of SCBs that have + * completed but need to be uploaded + * to the host prior to being completed. + */ + COMPLETE_DMA_SCB_HEAD { + size 2 + } + /* Counting semaphore to prevent new select-outs */ + QFREEZE_COUNT { + size 2 + } + /* + * Mode to restore on legacy idle loop exit. + */ + SAVED_MODE { + size 1 + } + /* + * 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 + field PRELOADEN 0x80 + field WIDEODD 0x40 + field SCSIEN 0x20 + field SDMAEN 0x10 + field SDMAENACK 0x10 + field HDMAEN 0x08 + field HDMAENACK 0x08 + field DIRECTION 0x04 /* Set indicates PCI->SCSI */ + field FIFOFLUSH 0x02 + field FIFORESET 0x01 + } + SEQ_FLAGS { + size 1 + field NOT_IDENTIFIED 0x80 + field NO_CDB_SENT 0x40 + field TARGET_CMD_IS_TAGGED 0x40 + field DPHASE 0x20 + /* Target flags */ + field TARG_CMD_PENDING 0x10 + field CMDPHASE_PENDING 0x08 + field DPHASE_PENDING 0x04 + field SPHASE_PENDING 0x02 + field NO_DISCONNECT 0x01 + } + /* + * Temporary storage for the + * target/channel/lun of a + * reconnecting target + */ + SAVED_SCSIID { + size 1 + } + SAVED_LUN { + size 1 + } + /* + * The last bus phase as seen by the sequencer. + */ + LASTPHASE { + size 1 + field CDI 0x80 + field IOI 0x40 + field MSGI 0x20 + field P_BUSFREE 0x01 + enum PHASE_MASK CDO|IOO|MSGO { + P_DATAOUT 0x0, + P_DATAIN IOO, + P_DATAOUT_DT P_DATAOUT|MSGO, + P_DATAIN_DT P_DATAIN|MSGO, + P_COMMAND CDO, + P_MESGOUT CDO|MSGO, + P_STATUS CDO|IOO, + P_MESGIN CDO|IOO|MSGO + } + } + /* + * Value to "or" into the SCBPTR[1] value to + * indicate that an entry in the QINFIFO is valid. + */ + QOUTFIFO_ENTRY_VALID_TAG { + size 1 + } + /* + * Base address of our shared data with the kernel driver in host + * memory. This includes the qoutfifo and target mode + * incoming command queue. + */ + SHARED_DATA_ADDR { + size 4 + } + /* + * Pointer to location in host memory for next + * position in the qoutfifo. + */ + QOUTFIFO_NEXT_ADDR { + size 4 + } + /* + * 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_WRITE 0x04 + mask CONT_MSG_LOOP_READ 0x03 + mask CONT_MSG_LOOP_TARG 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 + } + + /* + * 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 + field MANUALCTL 0x40 + field ENSELI 0x20 + field ENRSELI 0x10 + field MANUALP 0x0C + field ENAUTOATNP 0x02 + field ALTSTIM 0x01 + } + + /* + * The initiator specified tag for this target mode transaction. + */ + INITIATOR_TAG { + size 1 + } + + SEQ_FLAGS2 { + size 1 + field TARGET_MSG_PENDING 0x02 + field SELECTOUT_QFROZEN 0x04 + } + + ALLOCFIFO_SCBPTR { + size 2 + } + + /* + * The maximum amount of time to wait, when interrupt coalescing + * is enabled, before issueing a CMDCMPLT interrupt for a completed + * command. + */ + INT_COALESCING_TIMER { + size 2 + } + + /* + * The maximum number of commands to coalesce into a single interrupt. + * Actually the 2's complement of that value to simplify sequencer + * code. + */ + INT_COALESCING_MAXCMDS { + size 1 + } + + /* + * The minimum number of commands still outstanding required + * to continue coalescing (2's complement of value). + */ + INT_COALESCING_MINCMDS { + size 1 + } + + /* + * Number of commands "in-flight". + */ + CMDS_PENDING { + size 2 + } + + /* + * The count of commands that have been coalesced. + */ + INT_COALESCING_CMDCOUNT { + size 1 + } + + /* + * Since the HS_MAIBOX is self clearing, copy its contents to + * this position in scratch ram every time it changes. + */ + LOCAL_HS_MAILBOX { + size 1 + } + /* + * Target-mode CDB type to CDB length table used + * in non-packetized operation. + */ + CMDSIZE_TABLE { + size 8 + } +} + +/************************* Hardware SCB Definition ****************************/ +scb { + address 0x180 + size 64 + modes 0, 1, 2, 3 + SCB_RESIDUAL_DATACNT { + size 4 + alias SCB_CDB_STORE + alias SCB_HOST_CDB_PTR + } + SCB_RESIDUAL_SGPTR { + size 4 + field SG_ADDR_MASK 0xf8 /* In the last byte */ + field SG_OVERRUN_RESID 0x02 /* In the first byte */ + field SG_LIST_NULL 0x01 /* In the first byte */ + } + SCB_SCSI_STATUS { + size 1 + alias SCB_HOST_CDB_LEN + } + SCB_TARGET_PHASES { + size 1 + } + SCB_TARGET_DATA_DIR { + size 1 + } + SCB_TARGET_ITAG { + size 1 + } + SCB_SENSE_BUSADDR { + /* + * Only valid if CDB length is less than 13 bytes or + * we are using a CDB pointer. Otherwise contains + * the last 4 bytes of embedded cdb information. + */ + size 4 + alias SCB_NEXT_COMPLETE + } + SCB_TAG { + alias SCB_FIFO_USE_COUNT + size 2 + } + SCB_CONTROL { + size 1 + field TARGET_SCB 0x80 + field DISCENB 0x40 + field TAG_ENB 0x20 + field MK_MESSAGE 0x10 + field STATUS_RCVD 0x08 + field DISCONNECTED 0x04 + field SCB_TAG_TYPE 0x03 + } + SCB_SCSIID { + size 1 + field TID 0xF0 + field OID 0x0F + } + SCB_LUN { + size 1 + field LID 0xff + } + SCB_TASK_ATTRIBUTE { + size 1 + /* + * Overloaded field for non-packetized + * ignore wide residue message handling. + */ + field SCB_XFERLEN_ODD 0x01 + } + SCB_CDB_LEN { + size 1 + field SCB_CDB_LEN_PTR 0x80 /* CDB in host memory */ + } + SCB_TASK_MANAGEMENT { + size 1 + } + SCB_DATAPTR { + size 8 + } + SCB_DATACNT { + /* + * The last byte is really the high address bits for + * the data address. + */ + size 4 + field SG_LAST_SEG 0x80 /* In the fourth byte */ + field SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ + } + SCB_SGPTR { + size 4 + field SG_STATUS_VALID 0x04 /* In the first byte */ + field SG_FULL_RESID 0x02 /* In the first byte */ + field SG_LIST_NULL 0x01 /* In the first byte */ + } + SCB_BUSADDR { + size 4 + } + SCB_NEXT { + alias SCB_NEXT_SCB_BUSADDR + size 2 + } + SCB_NEXT2 { + size 2 + } + SCB_SPARE { + size 8 + alias SCB_PKT_LUN + } + SCB_DISCONNECTED_LISTS { + size 8 + } +} + +/*********************************** Constants ********************************/ +const MK_MESSAGE_BIT_OFFSET 4 +const TID_SHIFT 4 +const TARGET_CMD_CMPLT 0xfe +const INVALID_ADDR 0x80 +#define SCB_LIST_NULL 0xff +#define QOUTFIFO_ENTRY_VALID_TOGGLE 0x80 + +const CCSGADDR_MAX 0x80 +const CCSCBADDR_MAX 0x80 +const CCSGRAM_MAXSEGS 16 + +/* Selection Timeout Timer Constants */ +const STIMESEL_SHIFT 3 +const STIMESEL_MIN 0x18 +const STIMESEL_BUG_ADJ 0x8 + +/* WDTR Message values */ +const BUS_8_BIT 0x00 +const BUS_16_BIT 0x01 +const BUS_32_BIT 0x02 + +/* Offset maximums */ +const MAX_OFFSET 0xfe +const MAX_OFFSET_PACED 0xfe +const MAX_OFFSET_PACED_BUG 0x7f +/* + * Some 160 devices incorrectly accept 0xfe as a + * sync offset, but will overrun this value. Limit + * to 0x7f for speed lower than U320 which will + * avoid the persistent sync offset overruns. + */ +const MAX_OFFSET_NON_PACED 0x7f +const HOST_MSG 0xff + +/* + * The size of our sense buffers. + * Sense buffer mapping can be handled in either of two ways. + * The first is to allocate a dmamap for each transaction. + * Depending on the architecture, dmamaps can be costly. The + * alternative is to statically map the buffers in much the same + * way we handle our scatter gather lists. The driver implements + * the later. + */ +const AHD_SENSE_BUFSIZE 256 + +/* Target mode command processing constants */ +const CMD_GROUP_CODE_SHIFT 0x05 + +const STATUS_BUSY 0x08 +const STATUS_QUEUE_FULL 0x28 +const STATUS_PKT_SENSE 0xFF +const TARGET_DATA_IN 1 + +const SCB_TRANSFER_SIZE_FULL_LUN 56 +const SCB_TRANSFER_SIZE_1BYTE_LUN 48 +/* PKT_OVERRUN_BUFSIZE must be a multiple of 256 less than 64K */ +const PKT_OVERRUN_BUFSIZE 512 + +/* + * Timer parameters. + */ +const AHD_TIMER_US_PER_TICK 25 +const AHD_TIMER_MAX_TICKS 0xFFFF +const AHD_TIMER_MAX_US (AHD_TIMER_MAX_TICKS * AHD_TIMER_US_PER_TICK) + +/* + * Downloaded (kernel inserted) constants + */ +const SG_PREFETCH_CNT download +const SG_PREFETCH_CNT_LIMIT download +const SG_PREFETCH_ALIGN_MASK download +const SG_PREFETCH_ADDR_MASK download +const SG_SIZEOF download +const PKT_OVERRUN_BUFOFFSET download +const SCB_TRANSFER_SIZE download + +/* + * BIOS SCB offsets + */ +const NVRAM_SCB_OFFSET 0x2C diff --git a/sys/dev/microcode/aic7xxx/aic79xx.seq b/sys/dev/microcode/aic7xxx/aic79xx.seq new file mode 100644 index 00000000000..456d9b07000 --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aic79xx.seq @@ -0,0 +1,2034 @@ +/* $OpenBSD: aic79xx.seq,v 1.1 2003/12/24 22:40:16 krw Exp $ */ +/* $NetBSD: aic79xx.seq,v 1.8 2003/08/29 03:54:06 thorpej Exp $ */ + +/* + * Adaptec U320 device driver firmware for Linux and FreeBSD. + * + * Copyright (c) 1994-2001 Justin T. Gibbs. + * Copyright (c) 2000-2002 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may 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 + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.seq,v 1.13 2003/06/28 04:44:10 gibbs Exp $ + */ + +VERSION = "Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#96 $" +PATCH_ARG_LIST = "struct ahd_softc *ahd" +PREFIX = "ahd_" + +#include <dev/microcode/aic7xxx/aic79xx.reg> +#include <scsi/scsi_message.h> + +restart: +if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { + test SEQINTCODE, 0xFF jz idle_loop; + SET_SEQINTCODE(NO_SEQINT) +} + +idle_loop: + + if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { + /* + * Convert ERROR status into a sequencer + * interrupt to handle the case of an + * interrupt collision on the hardware + * setting of HWERR. + */ + test ERROR, 0xFF jz no_error_set; + SET_SEQINTCODE(SAW_HWERR) +no_error_set: + } + SET_MODE(M_SCSI, M_SCSI) + test SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus; + test SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus; + cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je idle_loop_checkbus; + /* + * ENSELO is cleared by a SELDO, so we must test for SELDO + * one last time. + */ +BEGIN_CRITICAL; + test SSTAT0, SELDO jnz select_out; +END_CRITICAL; + call start_selection; +idle_loop_checkbus: +BEGIN_CRITICAL; + test SSTAT0, SELDO jnz select_out; +END_CRITICAL; + test SSTAT0, SELDI jnz select_in; + test SCSIPHASE, ~DATA_PHASE_MASK jz idle_loop_check_nonpackreq; + test SCSISIGO, ATNO jz idle_loop_check_nonpackreq; + call unexpected_nonpkt_phase_find_ctxt; +idle_loop_check_nonpackreq: + test SSTAT2, NONPACKREQ jz . + 2; + call unexpected_nonpkt_phase_find_ctxt; + if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { + and A, FIFO0FREE|FIFO1FREE, DFFSTAT; + cmp A, FIFO0FREE|FIFO1FREE jne . + 3; + and SBLKCTL, ~DIAGLEDEN|DIAGLEDON; + jmp . + 2; + or SBLKCTL, DIAGLEDEN|DIAGLEDON; + } + call idle_loop_gsfifo_in_scsi_mode; + call idle_loop_service_fifos; + call idle_loop_cchan; + jmp idle_loop; + +BEGIN_CRITICAL; +idle_loop_gsfifo: + SET_MODE(M_SCSI, M_SCSI) +idle_loop_gsfifo_in_scsi_mode: + test LQISTAT2, LQIGSAVAIL jz return; + /* + * We have received good status for this transaction. There may + * still be data in our FIFOs draining to the host. Complete + * the SCB only if all data has transferred to the host. + */ +good_status_IU_done: + bmov SCBPTR, GSFIFO, 2; + clr SCB_SCSI_STATUS; + /* + * If a command completed before an attempted task management + * function completed, notify the host after disabling any + * pending select-outs. + */ + test SCB_TASK_MANAGEMENT, 0xFF jz gsfifo_complete_normally; + test SSTAT0, SELDO|SELINGO jnz . + 2; + and SCSISEQ0, ~ENSELO; + SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY) +gsfifo_complete_normally: + or SCB_CONTROL, STATUS_RCVD; + + /* + * Since this status did not consume a FIFO, we have to + * be a bit more dilligent in how we check for FIFOs pertaining + * to this transaction. There are two states that a FIFO still + * transferring data may be in. + * + * 1) Configured and draining to the host, with a FIFO handler. + * 2) Pending cfg4data, fifo not empty. + * + * Case 1 can be detected by noticing a non-zero FIFO active + * count in the SCB. In this case, we allow the routine servicing + * the FIFO to complete the SCB. + * + * Case 2 implies either a pending or yet to occur save data + * pointers for this same context in the other FIFO. So, if + * we detect case 1, we will properly defer the post of the SCB + * and achieve the desired result. The pending cfg4data will + * notice that status has been received and complete the SCB. + */ + test SCB_FIFO_USE_COUNT, 0xFF jnz idle_loop_gsfifo_in_scsi_mode; + call complete; +END_CRITICAL; + jmp idle_loop_gsfifo_in_scsi_mode; + +idle_loop_service_fifos: + SET_MODE(M_DFF0, M_DFF0) + test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo; + call longjmp; +idle_loop_next_fifo: + SET_MODE(M_DFF1, M_DFF1) + test LONGJMP_ADDR[1], INVALID_ADDR jz longjmp; +return: + ret; + +idle_loop_cchan: + SET_MODE(M_CCHAN, M_CCHAN) + test QOFF_CTLSTA, HS_MAILBOX_ACT jz hs_mailbox_empty; + mov LOCAL_HS_MAILBOX, HS_MAILBOX; + or QOFF_CTLSTA, HS_MAILBOX_ACT; +hs_mailbox_empty: +BEGIN_CRITICAL; + test CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle; + test CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog; + test CCSCBCTL, CCSCBDONE jz return; +END_CRITICAL; + /* FALLTHROUGH */ +scbdma_tohost_done: + test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone; + /* + * An SCB has been succesfully uploaded to the host. + * If the SCB was uploaded for some reason other than + * bad SCSI status (currently only for underruns), we + * queue the SCB for normal completion. Otherwise, we + * wait until any select-out activity has halted, and + * then notify the host so that the transaction can be + * dealt with. + */ + test SCB_SCSI_STATUS, 0xff jnz scbdma_notify_host; + and CCSCBCTL, ~(CCARREN|CCSCBEN); + bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2; + bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; + bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret; +scbdma_notify_host: + SET_MODE(M_SCSI, M_SCSI) + test SCSISEQ0, ENSELO jnz return; + test SSTAT0, (SELDO|SELINGO) jnz return; + SET_MODE(M_CCHAN, M_CCHAN) + /* + * Remove SCB and notify host. + */ + and CCSCBCTL, ~(CCARREN|CCSCBEN); + bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2; + SET_SEQINTCODE(BAD_SCB_STATUS) + ret; +fill_qoutfifo_dmadone: + and CCSCBCTL, ~(CCARREN|CCSCBEN); + call qoutfifo_updated; + mvi COMPLETE_SCB_DMAINPROG_HEAD[1], SCB_LIST_NULL; + bmov QOUTFIFO_NEXT_ADDR, SCBHADDR, 4; + test QOFF_CTLSTA, SDSCB_ROLLOVR jz return; + bmov QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4; + xor QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret; + +qoutfifo_updated: + /* + * If there are more commands waiting to be DMA'ed + * to the host, always coalesce. Otherwise honor the + * host's wishes. + */ + cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; + cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; + test LOCAL_HS_MAILBOX, ENINT_COALESCE jz issue_cmdcmplt; + + /* + * If we have relatively few commands outstanding, don't + * bother waiting for another command to complete. + */ + test CMDS_PENDING[1], 0xFF jnz coalesce_by_count; + /* Add -1 so that jnc means <= not just < */ + add A, -1, INT_COALESCING_MINCMDS; + add NONE, A, CMDS_PENDING; + jnc issue_cmdcmplt; + + /* + * If coalescing, only coalesce up to the limit + * provided by the host driver. + */ +coalesce_by_count: + mov A, INT_COALESCING_MAXCMDS; + add NONE, A, INT_COALESCING_CMDCOUNT; + jc issue_cmdcmplt; + /* + * If the timer is not currently active, + * fire it up. + */ + test INTCTL, SWTMINTMASK jz return; + bmov SWTIMER, INT_COALESCING_TIMER, 2; + mvi CLRSEQINTSTAT, CLRSEQ_SWTMRTO; + or INTCTL, SWTMINTEN|SWTIMER_START; + and INTCTL, ~SWTMINTMASK ret; + +issue_cmdcmplt: + mvi INTSTAT, CMDCMPLT; + clr INT_COALESCING_CMDCOUNT; + or INTCTL, SWTMINTMASK ret; + +BEGIN_CRITICAL; +fetch_new_scb_inprog: + test CCSCBCTL, ARRDONE jz return; +fetch_new_scb_done: + and CCSCBCTL, ~(CCARREN|CCSCBEN); + bmov REG0, SCBPTR, 2; + clr A; + add CMDS_PENDING, 1; + adc CMDS_PENDING[1], A; + if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { + /* + * "Short Luns" are not placed into outgoing LQ + * packets in the correct byte order. Use a full + * sized lun field instead and fill it with the + * one byte of lun information we support. + */ + mov SCB_PKT_LUN[6], SCB_LUN; + } + /* + * The FIFO use count field is shared with the + * tag set by the host so that our SCB dma engine + * knows the correct location to store the SCB. + * Set it to zero before processing the SCB. + */ + clr SCB_FIFO_USE_COUNT; + /* Update the next SCB address to download. */ + bmov NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4; + mvi SCB_NEXT[1], SCB_LIST_NULL; + mvi SCB_NEXT2[1], SCB_LIST_NULL; + /* Increment our position in the QINFIFO. */ + mov NONE, SNSCB_QOFF; + /* + * SCBs that want to send messages are always + * queued independently. This ensures that they + * are at the head of the SCB list to select out + * to a target and we will see the MK_MESSAGE flag. + */ + test SCB_CONTROL, MK_MESSAGE jnz first_new_target_scb; + shr SINDEX, 3, SCB_SCSIID; + and SINDEX, ~0x1; + mvi SINDEX[1], (WAITING_SCB_TAILS >> 8); + bmov DINDEX, SINDEX, 2; + bmov SCBPTR, SINDIR, 2; + bmov DINDIR, REG0, 2; + cmp SCBPTR[1], SCB_LIST_NULL je first_new_target_scb; + bmov SCB_NEXT, REG0, 2 ret; +first_new_target_scb: + cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je first_new_scb; + bmov SCBPTR, WAITING_TID_TAIL, 2; + bmov SCB_NEXT2, REG0, 2; + bmov WAITING_TID_TAIL, REG0, 2 ret; +first_new_scb: + bmov WAITING_TID_HEAD, REG0, 2; + bmov WAITING_TID_TAIL, REG0, 2 ret; +END_CRITICAL; + +scbdma_idle: + /* + * Give precedence to downloading new SCBs to execute + * unless select-outs are currently frozen. + */ + test SEQ_FLAGS2, SELECTOUT_QFROZEN jnz . + 2; +BEGIN_CRITICAL; + test QOFF_CTLSTA, NEW_SCB_AVAIL jnz fetch_new_scb; + cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne dma_complete_scb; + cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL je return; + /* FALLTHROUGH */ +fill_qoutfifo: + /* + * Keep track of the SCBs we are DMA'ing just + * in case the DMA fails or is aborted. + */ + mov A, QOUTFIFO_ENTRY_VALID_TAG; + bmov COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2; + mvi CCSCBCTL, CCSCBRESET; + bmov SCBHADDR, QOUTFIFO_NEXT_ADDR, 4; + bmov SCBPTR, COMPLETE_SCB_HEAD, 2; +fill_qoutfifo_loop: + mov CCSCBRAM, SCBPTR; + or CCSCBRAM, A, SCBPTR[1]; + mov NONE, SDSCB_QOFF; + inc INT_COALESCING_CMDCOUNT; + add CMDS_PENDING, -1; + adc CMDS_PENDING[1], -1; + cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done; + cmp CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done; + test QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done; + bmov SCBPTR, SCB_NEXT_COMPLETE, 2; + jmp fill_qoutfifo_loop; +fill_qoutfifo_done: + mov SCBHCNT, CCSCBADDR; + mvi CCSCBCTL, CCSCBEN|CCSCBRESET; + bmov COMPLETE_SCB_HEAD, SCB_NEXT_COMPLETE, 2; + mvi SCB_NEXT_COMPLETE[1], SCB_LIST_NULL ret; + +fetch_new_scb: + bmov SCBHADDR, NEXT_QUEUED_SCB_ADDR, 4; + mvi CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET jmp dma_scb; +dma_complete_scb: + bmov SCBPTR, COMPLETE_DMA_SCB_HEAD, 2; + bmov SCBHADDR, SCB_BUSADDR, 4; + mvi CCARREN|CCSCBEN|CCSCBRESET jmp dma_scb; +END_CRITICAL; + +/* + * Either post or fetch an SCB from host memory. The caller + * is responsible for polling for transfer completion. + * + * Prerequisits: Mode == M_CCHAN + * SINDEX contains CCSCBCTL flags + * SCBHADDR set to Host SCB address + * SCBPTR set to SCB src location on "push" operations + */ +SET_SRC_MODE M_CCHAN; +SET_DST_MODE M_CCHAN; +dma_scb: + mvi SCBHCNT, SCB_TRANSFER_SIZE; + mov CCSCBCTL, SINDEX ret; + +BEGIN_CRITICAL; +setjmp: + bmov LONGJMP_ADDR, STACK, 2 ret; +setjmp_inline: + bmov LONGJMP_ADDR, STACK, 2; +longjmp: + bmov STACK, LONGJMP_ADDR, 2 ret; +END_CRITICAL; + +/*************************** Chip Bug Work Arounds ****************************/ +/* + * Must disable interrupts when setting the mode pointer + * register as an interrupt occurring mid update will + * fail to store the new mode value for restoration on + * an iret. + */ +if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { +set_mode_work_around: + mvi SEQINTCTL, INTVEC1DSL; + mov MODE_PTR, SINDEX; + clr SEQINTCTL ret; + +toggle_dff_mode_work_around: + mvi SEQINTCTL, INTVEC1DSL; + xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); + clr SEQINTCTL ret; +} + + +if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { +set_seqint_work_around: + mov SEQINTCODE, SINDEX; + mvi SEQINTCODE, NO_SEQINT ret; +} + +/************************ Packetized LongJmp Routines *************************/ +SET_SRC_MODE M_SCSI; +SET_DST_MODE M_SCSI; +start_selection: +BEGIN_CRITICAL; + if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { + /* + * Razor #494 + * Rev A hardware fails to update LAST/CURR/NEXTSCB + * correctly after a packetized selection in several + * situations: + * + * 1) If only one command existed in the queue, the + * LAST/CURR/NEXTSCB are unchanged. + * + * 2) In a non QAS, protocol allowed phase change, + * the queue is shifted 1 too far. LASTSCB is + * the last SCB that was correctly processed. + * + * 3) In the QAS case, if the full list of commands + * was successfully sent, NEXTSCB is NULL and neither + * CURRSCB nor LASTSCB can be trusted. We must + * manually walk the list counting MAXCMDCNT elements + * to find the last SCB that was sent correctly. + * + * To simplify the workaround for this bug in SELDO + * handling, we initialize LASTSCB prior to enabling + * selection so we can rely on it even for case #1 above. + */ + bmov LASTSCB, WAITING_TID_HEAD, 2; + } + bmov CURRSCB, WAITING_TID_HEAD, 2; + bmov SCBPTR, WAITING_TID_HEAD, 2; + shr SELOID, 4, SCB_SCSIID; + /* + * If we want to send a message to the device, ensure + * we are selecting with atn irregardless of our packetized + * agreement. Since SPI4 only allows target reset or PPR + * messages if this is a packetized connection, the change + * to our negotiation table entry for this selection will + * be cleared when the message is acted on. + */ + test SCB_CONTROL, MK_MESSAGE jz . + 3; + mov NEGOADDR, SELOID; + or NEGCONOPTS, ENAUTOATNO; + or SCSISEQ0, ENSELO ret; +END_CRITICAL; + +/* + * Allocate a FIFO for a non-packetized transaction. + * In RevA hardware, both FIFOs must be free before we + * can allocate a FIFO for a non-packetized transaction. + */ +allocate_fifo_loop: + /* + * Do whatever work is required to free a FIFO. + */ + call idle_loop_service_fifos; + SET_MODE(M_SCSI, M_SCSI) +allocate_fifo: + if ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0) { + and A, FIFO0FREE|FIFO1FREE, DFFSTAT; + cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop; + } else { + test DFFSTAT, FIFO1FREE jnz allocate_fifo1; + test DFFSTAT, FIFO0FREE jz allocate_fifo_loop; + mvi DFFSTAT, B_CURRFIFO_0; + SET_MODE(M_DFF0, M_DFF0) + bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret; + } +SET_SRC_MODE M_SCSI; +SET_DST_MODE M_SCSI; +allocate_fifo1: + mvi DFFSTAT, CURRFIFO_1; + SET_MODE(M_DFF1, M_DFF1) + bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret; + +/* + * We have been reselected as an initiator + * or selected as a target. + */ +SET_SRC_MODE M_SCSI; +SET_DST_MODE M_SCSI; +select_in: + if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { + /* + * This exposes a window whereby a + * busfree just after a selection will + * be missed, but there is no other safe + * way to enable busfree detection if + * the busfreerev function is broken. + */ + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; + } + or SXFRCTL0, SPIOEN; + and SAVED_SCSIID, SELID_MASK, SELID; + and A, OID, IOWNID; + or SAVED_SCSIID, A; + mvi CLRSINT0, CLRSELDI; + jmp ITloop; + +/* + * We have successfully selected out. + * + * Clear SELDO. + * Dequeue all SCBs sent from the waiting queue + * Requeue all SCBs *not* sent to the tail of the waiting queue + * Take Razor #494 into account for above. + * + * In Packetized Mode: + * Return to the idle loop. Our interrupt handler will take + * care of any incoming L_Qs. + * + * In Non-Packetize Mode: + * Continue to our normal state machine. + */ +SET_SRC_MODE M_SCSI; +SET_DST_MODE M_SCSI; +select_out: +BEGIN_CRITICAL; + /* Clear out all SCBs that have been successfully sent. */ + if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { + /* + * For packetized, the LQO manager clears ENSELO on + * the assertion of SELDO. If we are non-packetized, + * LASTSCB and CURRSCB are accurate. + */ + test SCSISEQ0, ENSELO jnz use_lastscb; + + /* + * The update is correct for LQOSTAT1 errors. All + * but LQOBUSFREE are handled by kernel interrupts. + * If we see LQOBUSFREE, return to the idle loop. + * Once we are out of the select_out critical section, + * the kernel will cleanup the LQOBUSFREE and we will + * eventually restart the selection if appropriate. + */ + test LQOSTAT1, LQOBUSFREE jnz idle_loop; + + /* + * On a phase change oustside of packet boundaries, + * LASTSCB points to the currently active SCB context + * on the bus. + */ + test LQOSTAT2, LQOPHACHGOUTPKT jnz use_lastscb; + + /* + * If the hardware has traversed the whole list, NEXTSCB + * will be NULL, CURRSCB and LASTSCB cannot be trusted, + * but MAXCMDCNT is accurate. If we stop part way through + * the list or only had one command to issue, NEXTSCB[1] is + * not NULL and LASTSCB is the last command to go out. + */ + cmp NEXTSCB[1], SCB_LIST_NULL jne use_lastscb; + + /* + * Brute force walk. + */ + bmov SCBPTR, WAITING_TID_HEAD, 2; + mvi SEQINTCTL, INTVEC1DSL; + mvi MODE_PTR, MK_MODE(M_CFG, M_CFG); + mov A, MAXCMDCNT; + mvi MODE_PTR, MK_MODE(M_SCSI, M_SCSI); + clr SEQINTCTL; +find_lastscb_loop: + dec A; + test A, 0xFF jz found_last_sent_scb; + bmov SCBPTR, SCB_NEXT, 2; + jmp find_lastscb_loop; +use_lastscb: + bmov SCBPTR, LASTSCB, 2; +found_last_sent_scb: + bmov CURRSCB, SCBPTR, 2; +curscb_ww_done: + } else { + bmov SCBPTR, CURRSCB, 2; + } + + /* + * Requeue any SCBs not sent, to the tail of the waiting Q. + */ + cmp SCB_NEXT[1], SCB_LIST_NULL je select_out_list_done; + + /* + * We know that neither the per-TID list nor the list of + * TIDs is empty. Use this knowledge to our advantage. + */ + bmov REG0, SCB_NEXT, 2; + bmov SCBPTR, WAITING_TID_TAIL, 2; + bmov SCB_NEXT2, REG0, 2; + bmov WAITING_TID_TAIL, REG0, 2; + jmp select_out_inc_tid_q; + +select_out_list_done: + /* + * The whole list made it. Just clear our TID's tail pointer + * unless we were queued independently due to our need to + * send a message. + */ + test SCB_CONTROL, MK_MESSAGE jnz select_out_inc_tid_q; + shr DINDEX, 3, SCB_SCSIID; + or DINDEX, 1; /* Want only the second byte */ + mvi DINDEX[1], ((WAITING_SCB_TAILS) >> 8); + mvi DINDIR, SCB_LIST_NULL; +select_out_inc_tid_q: + bmov SCBPTR, WAITING_TID_HEAD, 2; + bmov WAITING_TID_HEAD, SCB_NEXT2, 2; + cmp WAITING_TID_HEAD[1], SCB_LIST_NULL jne . + 2; + mvi WAITING_TID_TAIL[1], SCB_LIST_NULL; + bmov SCBPTR, CURRSCB, 2; + mvi CLRSINT0, CLRSELDO; + test LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_phase; + test LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_phase; + + /* + * If this is a packetized connection, return to our + * idle_loop and let our interrupt handler deal with + * any connection setup/teardown issues. The only + * exceptions are the case of MK_MESSAGE and task management + * SCBs. + */ + if ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0) { + /* + * In the A, the LQO manager transitions to LQOSTOP0 even if + * we have selected out with ATN asserted and the target + * REQs in a non-packet phase. + */ + test SCB_CONTROL, MK_MESSAGE jz select_out_no_message; + test SCSISIGO, ATNO jnz select_out_non_packetized; +select_out_no_message: + } + test LQOSTAT2, LQOSTOP0 jz select_out_non_packetized; + test SCB_TASK_MANAGEMENT, 0xFF jz idle_loop; + SET_SEQINTCODE(TASKMGMT_FUNC_COMPLETE) + jmp idle_loop; + +select_out_non_packetized: + /* Non packetized request. */ + and SCSISEQ0, ~ENSELO; + if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { + /* + * This exposes a window whereby a + * busfree just after a selection will + * be missed, but there is no other safe + * way to enable busfree detection if + * the busfreerev function is broken. + */ + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; + } + mov SAVED_SCSIID, SCB_SCSIID; + mov SAVED_LUN, SCB_LUN; + mvi SEQ_FLAGS, NO_CDB_SENT; +END_CRITICAL; + or SXFRCTL0, SPIOEN; + + /* + * 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; + + /* + * 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. + */ +mesgin_phasemis: +ITloop: + call phase_lock; + + mov A, LASTPHASE; + + test A, ~P_DATAIN_DT 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; + + SET_SEQINTCODE(BAD_PHASE) + jmp ITloop; /* Try reading the bus again. */ + +/* + * Command phase. Set up the DMA registers and let 'er rip. + */ +p_command: + test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay; + SET_SEQINTCODE(PROTO_VIOLATION) +p_command_okay: + test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) + jnz p_command_allocate_fifo; + /* + * Command retry. Free our current FIFO and + * re-allocate a FIFO so transfer state is + * reset. + */ +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; + mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; + SET_MODE(M_SCSI, M_SCSI) +p_command_allocate_fifo: + bmov ALLOCFIFO_SCBPTR, SCBPTR, 2; + call allocate_fifo; +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; + add NONE, -17, SCB_CDB_LEN; + jnc p_command_embedded; +p_command_from_host: + bmov HADDR[0], SCB_HOST_CDB_PTR, 9; + mvi SG_CACHE_PRE, LAST_SEG; + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); + jmp p_command_xfer; +p_command_embedded: + bmov SHCNT[0], SCB_CDB_LEN, 1; + bmov DFDAT, SCB_CDB_STORE, 16; + mvi DFCNTRL, SCSIEN; +p_command_xfer: + and SEQ_FLAGS, ~NO_CDB_SENT; + test DFCNTRL, SCSIEN jnz .; + /* + * DMA Channel automatically disabled. + * Don't allow a data phase if the command + * was not fully transferred. + */ + test SSTAT2, SDONE jnz ITloop; + or SEQ_FLAGS, NO_CDB_SENT; + jmp ITloop; + + +/* + * Status phase. Wait for the data byte to appear, then read it + * and store it into the SCB. + */ +SET_SRC_MODE M_SCSI; +SET_DST_MODE M_SCSI; +p_status: + test SEQ_FLAGS,NOT_IDENTIFIED jnz mesgin_proto_violation; +p_status_okay: + mov SCB_SCSI_STATUS, SCSIDAT; + or SCB_CONTROL, STATUS_RCVD; + jmp ITloop; + +/* + * 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: + /* Turn on ATN for the retry */ + mvi SCSISIGO, ATNO; +p_mesgout: + mov SINDEX, MSG_OUT; + cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; + test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; +p_mesgout_identify: + or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; + test SCB_CONTROL, DISCENB jnz . + 2; + and SINDEX, ~DISCENB; +/* + * Send a tag message if TAG_ENB is set in the SCB control block. + * Use SCB_NONPACKET_TAG as the tag value. + */ +p_mesgout_tag: + test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; + mov SCSIDAT, SINDEX; /* Send the identify message */ + call phase_lock; + cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; + and SCSIDAT,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; + call phase_lock; + cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; + mov SCBPTR jmp p_mesgout_onebyte; +/* + * Interrupt the driver, and allow it to handle this message + * phase and any required retries. + */ +p_mesgout_from_host: + cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; + jmp host_message_loop; + +p_mesgout_onebyte: + mvi CLRSINT1, CLRATNO; + mov SCSIDAT, SINDEX; + +/* + * 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. + */ + call phase_lock; + cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; + +p_mesgout_done: + 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: + /* read the 1st message byte */ + mvi ACCUM call inb_first; + + 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_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; + 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: + call phase_lock; /* Benign the first time through. */ + SET_SEQINTCODE(HOST_MSG_LOOP) + cmp RETURN_1, EXIT_MSG_LOOP je ITloop; + cmp RETURN_1, CONT_MSG_LOOP_WRITE jne . + 3; + mov SCSIDAT, RETURN_2; + jmp host_message_loop; + /* Must be CONT_MSG_LOOP_READ */ + mov NONE, SCSIDAT; /* ACK Byte */ + jmp host_message_loop; + +mesgin_ign_wide_residue: + mov SAVED_MODE, MODE_PTR; + SET_MODE(M_SCSI, M_SCSI) + shr NEGOADDR, 4, SAVED_SCSIID; + mov A, NEGCONOPTS; + RESTORE_MODE(SAVED_MODE) + test A, WIDEXFER jz mesgin_reject; + /* Pull the residue byte */ + mvi REG0 call inb_next; + cmp REG0, 0x01 jne mesgin_reject; + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; + test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jnz mesgin_done; + SET_SEQINTCODE(IGN_WIDE_RES) + jmp mesgin_done; + +mesgin_proto_violation: + SET_SEQINTCODE(PROTO_VIOLATION) + jmp mesgin_done; +mesgin_reject: + mvi MSG_MESSAGE_REJECT call mk_mesg; +mesgin_done: + mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ + jmp ITloop; + +#define INDEX_DISC_LIST(scsiid, lun) \ + and A, 0xC0, scsiid; \ + or SCBPTR, A, lun; \ + clr SCBPTR[1]; \ + and SINDEX, 0x30, scsiid; \ + shr SINDEX, 3; /* Multiply by 2 */ \ + add SINDEX, (SCB_DISCONNECTED_LISTS & 0xFF); \ + mvi SINDEX[1], ((SCB_DISCONNECTED_LISTS >> 8) & 0xFF) + +mesgin_identify: + /* + * Determine whether a target is using tagged or non-tagged + * transactions by first looking at the transaction stored in + * the per-device, disconnected array. If there is no untagged + * transaction for this target, this must be a tagged transaction. + */ + and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; + INDEX_DISC_LIST(SAVED_SCSIID, SAVED_LUN); + bmov DINDEX, SINDEX, 2; + bmov REG0, SINDIR, 2; + cmp REG0[1], SCB_LIST_NULL je snoop_tag; + /* Untagged. Clear the busy table entry and setup the SCB. */ + bmov DINDIR, ALLONES, 2; + bmov SCBPTR, REG0, 2; + 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 find the proper + * SCB. After receiving the tag, look for the SCB at SCB locations tag and + * tag + 256. + */ +snoop_tag: + if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x80; + } + mov NONE, SCSIDAT; /* ACK Identify MSG */ + call phase_lock; + if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x1; + } + cmp LASTPHASE, P_MESGIN jne not_found_ITloop; + if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x2; + } + cmp SCSIBUS, MSG_SIMPLE_Q_TAG jne not_found; +get_tag: + clr SCBPTR[1]; + mvi SCBPTR call inb_next; /* tag value */ +verify_scb: + test SCB_CONTROL,DISCONNECTED jz verify_other_scb; + mov A, SAVED_SCSIID; + cmp SCB_SCSIID, A jne verify_other_scb; + mov A, SAVED_LUN; + cmp SCB_LUN, A je setup_SCB_disconnected; +verify_other_scb: + xor SCBPTR[1], 1; + test SCBPTR[1], 0xFF jnz verify_scb; + jmp not_found; + +/* + * Ensure that the SCB the tag points to is for + * an SCB transaction to the reconnecting target. + */ +setup_SCB: + if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x10; + } + test SCB_CONTROL,DISCONNECTED jz not_found; +setup_SCB_disconnected: + and SCB_CONTROL,~DISCONNECTED; + clr SEQ_FLAGS; /* make note of IDENTIFY */ + test SCB_SGPTR, SG_LIST_NULL jnz . + 3; + bmov ALLOCFIFO_SCBPTR, SCBPTR, 2; + call allocate_fifo; + /* See if the host wants to send a message upon reconnection */ + test SCB_CONTROL, MK_MESSAGE jz mesgin_done; + mvi HOST_MSG call mk_mesg; + jmp mesgin_done; + +not_found: + SET_SEQINTCODE(NO_MATCH) + jmp mesgin_done; + +not_found_ITloop: + SET_SEQINTCODE(NO_MATCH) + jmp ITloop; + +/* + * We received a "command complete" message. Put the SCB on the complete + * queue and trigger a completion interrupt via the idle loop. 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, requeue + * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting + * RETURN_1 to SEND_SENSE. + */ +mesgin_complete: + + /* + * If ATN is raised, we still want to give the target a message. + * Perhaps there was a parity error on this last message byte. + * Either way, the target should take us to message out phase + * and then attempt to complete the command again. We should use a + * critical section here to guard against a timeout triggering + * for this command and setting ATN while we are still processing + * the completion. + test SCSISIGI, ATNI jnz mesgin_done; + */ + + /* + * If we are identified and have successfully sent the CDB, + * any status will do. Optimize this fast path. + */ + test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation; + test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; + + /* + * If the target never sent an identify message but instead went + * to mesgin to give an invalid message, let the host abort us. + */ + test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; + + /* + * If we recevied good status but never successfully sent the + * cdb, abort the command. + */ + test SCB_SCSI_STATUS,0xff jnz complete_accepted; + test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation; +complete_accepted: + + /* + * See if we attempted to deliver a message but the target ingnored us. + */ + test SCB_CONTROL, MK_MESSAGE jz complete_nomsg; + SET_SEQINTCODE(MKMSG_FAILED) +complete_nomsg: + call queue_scb_completion; + jmp await_busfree; + +freeze_queue: + /* Cancel any pending select-out. */ + test SSTAT0, SELDO|SELINGO jnz . + 2; + and SCSISEQ0, ~ENSELO; + mov ACCUM_SAVE, A; + clr A; + add QFREEZE_COUNT, 1; + adc QFREEZE_COUNT[1], A; + or SEQ_FLAGS2, SELECTOUT_QFROZEN; + mov A, ACCUM_SAVE ret; + +/* + * Complete the current FIFO's SCB if data for this same + * SCB is not transferring in the other FIFO. + */ +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; +pkt_complete_scb_if_fifos_idle: + bmov ARG_1, SCBPTR, 2; + mvi DFFSXFRCTL, CLRCHN; + SET_MODE(M_SCSI, M_SCSI) + bmov SCBPTR, ARG_1, 2; + test SCB_FIFO_USE_COUNT, 0xFF jnz return; +queue_scb_completion: + test SCB_SCSI_STATUS,0xff jnz bad_status; + /* + * Check for residuals + */ + test SCB_SGPTR, SG_LIST_NULL jnz complete; /* No xfer */ + test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ + test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; +complete: + bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; + bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret; +bad_status: + cmp SCB_SCSI_STATUS, STATUS_PKT_SENSE je upload_scb; + call freeze_queue; +upload_scb: + /* + * Restore SCB TAG since we reuse this field + * in the sequencer. We don't want to corrupt + * it on the host. + */ + bmov SCB_TAG, SCBPTR, 2; + bmov SCB_NEXT_COMPLETE, COMPLETE_DMA_SCB_HEAD, 2; + bmov COMPLETE_DMA_SCB_HEAD, SCBPTR, 2; + or SCB_SGPTR, SG_STATUS_VALID ret; + +/* + * Is it a disconnect message? Set a flag in the SCB to remind us + * and await the bus going free. If this is an untagged transaction + * store the SCB id for it in our untagged target table for lookup on + * a reselction. + */ +mesgin_disconnect: + /* + * If ATN is raised, we still want to give the target a message. + * Perhaps there was a parity error on this last message byte + * or we want to abort this command. Either way, the target + * should take us to message out phase and then attempt to + * disconnect again. + * XXX - Wait for more testing. + test SCSISIGI, ATNI jnz mesgin_done; + */ + test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT + jnz mesgin_proto_violation; + or SCB_CONTROL,DISCONNECTED; + test SCB_CONTROL, TAG_ENB jnz await_busfree; +queue_disc_scb: + bmov REG0, SCBPTR, 2; + INDEX_DISC_LIST(SAVED_SCSIID, SAVED_LUN); + bmov DINDEX, SINDEX, 2; + bmov DINDIR, REG0, 2; + bmov SCBPTR, REG0, 2; + /* FALLTHROUGH */ +await_busfree: + and SIMODE1, ~ENBUSFREE; + if ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0) { + /* + * In the BUSFREEREV_BUG case, the + * busfree status was cleared at the + * beginning of the connection. + */ + mvi CLRSINT1,CLRBUSFREE; + } + mov NONE, SCSIDAT; /* Ack the last byte */ + test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) + jnz await_busfree_not_m_dff; +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; +await_busfree_clrchn: + mvi DFFSXFRCTL, CLRCHN; +await_busfree_not_m_dff: + call clear_target_state; + test SSTAT1,REQINIT|BUSFREE jz .; + test SSTAT1, BUSFREE jnz idle_loop; + SET_SEQINTCODE(MISSED_BUSFREE) + + +/* + * 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. + * Ack the message as soon as possible. + */ +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; +mesgin_sdptrs: + mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ + test SEQ_FLAGS, DPHASE jz ITloop; + call save_pointers; + jmp ITloop; + +save_pointers: + /* + * If we are asked to save our position at the end of the + * transfer, just mark us at the end rather than perform a + * full save. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz save_pointers_full; + or SCB_SGPTR, SG_LIST_NULL ret; + +save_pointers_full: + /* + * The SCB_DATAPTR becomes the current SHADDR. + * All other information comes directly from our residual + * state. + */ + bmov SCB_DATAPTR, SHADDR, 8; + bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8 ret; + +/* + * Restore pointers message? Data pointers are recopied from the + * SCB anytime we enter a data phase for the first time, so all + * we need to do is clear the DPHASE flag and let the data phase + * code do the rest. We also reset/reallocate the FIFO to make + * sure we have a clean start for the next data or command phase. + */ +mesgin_rdptrs: + and SEQ_FLAGS, ~DPHASE; + test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz msgin_rdptrs_get_fifo; + mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; + SET_MODE(M_SCSI, M_SCSI) +msgin_rdptrs_get_fifo: + call allocate_fifo; + jmp mesgin_done; + +clear_target_state: + mvi LASTPHASE, P_BUSFREE; + /* clear target specific flags */ + mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret; + +phase_lock: + if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) { + /* + * Don't ignore persistent REQ assertions just because + * they were asserted within the bus settle delay window. + * This allows us to tolerate devices like the GEM318 + * that violate the SCSI spec. We are careful not to + * count REQ while we are waiting for it to fall during + * an async phase due to our asserted ACK. Each + * sequencer instruction takes ~25ns, so the REQ must + * last at least 100ns in order to be counted as a true + * REQ. + */ + test SCSIPHASE, 0xFF jnz phase_locked; + test SCSISIGI, ACKI jnz phase_lock; + test SCSISIGI, REQI jz phase_lock; + test SCSIPHASE, 0xFF jnz phase_locked; + test SCSISIGI, ACKI jnz phase_lock; + test SCSISIGI, REQI jz phase_lock; +phase_locked: + } else { + test SCSIPHASE, 0xFF jz .; + } + test SSTAT1, SCSIPERR jnz phase_lock; +phase_lock_latch_phase: + and LASTPHASE, PHASE_MASK, SCSISIGI ret; + +/* + * Functions to read data in Automatic PIO mode. + * + * An ACK is not sent on input from the target until SCSIDATL is read from. + * So we wait until SCSIDATL is latched (the usual way), then read the data + * byte directly off the bus using SCSIBUSL. When we have pulled the ATN + * line, or we just want to acknowledge the byte, then we do a dummy read + * from SCISDATL. The SCSI spec guarantees that the target will hold the + * data byte on the bus until we send our ACK. + * + * The assumption here is that these are called in a particular sequence, + * and that REQ is already set when inb_first is called. inb_{first,next} + * use the same calling convention as inb. + */ +inb_next: + mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ +inb_next_wait: + /* + * If there is a parity error, wait for the kernel to + * see the interrupt and prepare our message response + * before continuing. + */ + test SCSIPHASE, 0xFF jz .; + test SSTAT1, SCSIPERR jnz inb_next_wait; +inb_next_check_phase: + and LASTPHASE, PHASE_MASK, SCSISIGI; + cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; +inb_first: + clr DINDEX[1]; + mov DINDEX,SINDEX; + mov DINDIR,SCSIBUS ret; /*read byte directly from bus*/ +inb_last: + mov NONE,SCSIDAT ret; /*dummy read from latch to ACK*/ + +mk_mesg: + mvi SCSISIGO, ATNO; + mov MSG_OUT,SINDEX ret; + +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; +disable_ccsgen: + test SG_STATE, FETCH_INPROG jz disable_ccsgen_fetch_done; + clr CCSGCTL; +disable_ccsgen_fetch_done: + clr SG_STATE ret; + +service_fifo: + /* + * Do we have any prefetch left??? + */ + test SG_STATE, SEGS_AVAIL jnz idle_sg_avail; + + /* + * Can this FIFO have access to the S/G cache yet? + */ + test CCSGCTL, SG_CACHE_AVAIL jz return; + + /* Did we just finish fetching segs? */ + test CCSGCTL, CCSGDONE jnz idle_sgfetch_complete; + + /* Are we actively fetching segments? */ + test CCSGCTL, CCSGENACK jnz return; + + /* + * We fetch a "cacheline aligned" and sized amount of data + * so we don't end up referencing a non-existant page. + * Cacheline aligned is in quotes because the kernel will + * set the prefetch amount to a reasonable level if the + * cacheline size is unknown. + */ + bmov SGHADDR, SCB_RESIDUAL_SGPTR, 4; + mvi SGHCNT, SG_PREFETCH_CNT; + if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) { + /* + * Need two instruction between "touches" of SGHADDR. + */ + nop; + } + and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; + mvi CCSGCTL, CCSGEN|CCSGRESET; + or SG_STATE, FETCH_INPROG ret; +idle_sgfetch_complete: + /* + * Guard against SG_CACHE_AVAIL activating during sg fetch + * request in the other FIFO. + */ + test SG_STATE, FETCH_INPROG jz return; + clr CCSGCTL; + and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; + mvi SG_STATE, SEGS_AVAIL|LOADING_NEEDED; +idle_sg_avail: + /* Does the hardware have space for another SG entry? */ + test DFSTATUS, PRELOAD_AVAIL jz return; + /* + * On the A, preloading a segment before HDMAENACK + * comes true can clobber the shaddow address of the + * first segment in the S/G FIFO. Wait until it is + * safe to proceed. + */ + if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0) { + test DFCNTRL, HDMAENACK jz return; + } + if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { + bmov HADDR, CCSGRAM, 8; + } else { + bmov HADDR, CCSGRAM, 4; + } + bmov HCNT, CCSGRAM, 3; + bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; + if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { + and HADDR[4], SG_HIGH_ADDR_BITS, SCB_RESIDUAL_DATACNT[3]; + } + if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { + /* Skip 4 bytes of pad. */ + add CCSGADDR, 4; + } +sg_advance: + clr A; /* add sizeof(struct scatter) */ + add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; + adc SCB_RESIDUAL_SGPTR[1],A; + adc SCB_RESIDUAL_SGPTR[2],A; + adc SCB_RESIDUAL_SGPTR[3],A; + mov SINDEX, SCB_RESIDUAL_SGPTR[0]; + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 3; + or SINDEX, LAST_SEG; + clr SG_STATE; + mov SG_CACHE_PRE, SINDEX; + if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) { + /* + * Use SCSIENWRDIS so that SCSIEN is never + * modified by this operation. + */ + or DFCNTRL, PRELOADEN|HDMAEN|SCSIENWRDIS; + } else { + or DFCNTRL, PRELOADEN|HDMAEN; + } + /* + * Do we have another segment in the cache? + */ + add NONE, SG_PREFETCH_CNT_LIMIT, CCSGADDR; + jnc return; + and SG_STATE, ~SEGS_AVAIL ret; + +/* + * Initialize the DMA address and counter from the SCB. + */ +load_first_seg: + bmov HADDR, SCB_DATAPTR, 11; + and REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0]; + test SCB_DATACNT[3], SG_LAST_SEG jz . + 2; + or REG_ISR, LAST_SEG; + mov SG_CACHE_PRE, REG_ISR; + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); + /* + * Since we've are entering a data phase, we will + * rely on the SCB_RESID* fields. Initialize the + * residual and clear the full residual flag. + */ + and SCB_SGPTR[0], ~SG_FULL_RESID; + bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; + /* If we need more S/G elements, tell the idle loop */ + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz . + 2; + mvi SG_STATE, LOADING_NEEDED ret; + clr SG_STATE ret; + +p_data_handle_xfer: + call setjmp; + test SG_STATE, LOADING_NEEDED jnz service_fifo; +p_data_clear_handler: + or LONGJMP_ADDR[1], INVALID_ADDR ret; + +p_data: + test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed; + SET_SEQINTCODE(PROTO_VIOLATION) +p_data_allowed: + + test SEQ_FLAGS, DPHASE jz data_phase_initialize; + + /* + * If we re-enter the data phase after going through another + * phase, our transfer location has almost certainly been + * corrupted by the interveining, non-data, transfers. Ask + * the host driver to fix us up based on the transfer residual + * unless we already know that we should be bitbucketing. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket; + SET_SEQINTCODE(PDATA_REINIT) + jmp data_phase_inbounds; + +p_data_bitbucket: + /* + * Turn on `Bit Bucket' mode, wait until the target takes + * us to another phase, and then notify the host. + */ + mov SAVED_MODE, MODE_PTR; + test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) + jnz bitbucket_not_m_dff; + /* + * Ensure that any FIFO contents are cleared out and the + * FIFO free'd prior to starting the BITBUCKET. BITBUCKET + * doesn't discard data already in the FIFO. + */ + mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; + SET_MODE(M_SCSI, M_SCSI) +bitbucket_not_m_dff: + or SXFRCTL1,BITBUCKET; + /* Wait for non-data phase. */ + test SCSIPHASE, ~DATA_PHASE_MASK jz .; + and SXFRCTL1, ~BITBUCKET; + RESTORE_MODE(SAVED_MODE) +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; + SET_SEQINTCODE(DATA_OVERRUN) + jmp ITloop; + +data_phase_initialize: + test SCB_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket; + call load_first_seg; +data_phase_inbounds: + /* We have seen a data phase at least once. */ + or SEQ_FLAGS, DPHASE; + mov SAVED_MODE, MODE_PTR; + test SG_STATE, LOADING_NEEDED jz data_group_dma_loop; + call p_data_handle_xfer; +data_group_dma_loop: + /* + * The transfer is complete if either the last segment + * completes or the target changes phase. Both conditions + * will clear SCSIEN. + */ + call idle_loop_service_fifos; + call idle_loop_cchan; + call idle_loop_gsfifo; + RESTORE_MODE(SAVED_MODE) + test DFCNTRL, SCSIEN jnz data_group_dma_loop; + +data_group_dmafinish: + /* + * The transfer has terminated either due to a phase + * change, and/or the completion of the last segment. + * We have two goals here. Do as much other work + * as possible while the data fifo drains on a read + * and respond as quickly as possible to the standard + * messages (save data pointers/disconnect and command + * complete) that usually follow a data phase. + */ + call calc_residual; + + /* + * Go ahead and shut down the DMA engine now. + */ + test DFCNTRL, DIRECTION jnz data_phase_finish; +data_group_fifoflush: + if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { + or DFCNTRL, FIFOFLUSH; + } + /* + * We have enabled the auto-ack feature. This means + * that the controller may have already transferred + * some overrun bytes into the data FIFO and acked them + * on the bus. The only way to detect this situation is + * to wait for LAST_SEG_DONE to come true on a completed + * transfer and then test to see if the data FIFO is + * non-empty. We know there is more data yet to transfer + * if SG_LIST_NULL is not yet set, thus there cannot be + * an overrun. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_finish; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; + test DFSTATUS, FIFOEMP jnz data_phase_finish; + /* Overrun */ + jmp p_data; +data_phase_finish: + /* + * If the target has left us in data phase, loop through + * the DMA code again. We will only loop if there is a + * data overrun. + */ + if ((ahd->flags & AHD_TARGETROLE) != 0) { + test SSTAT0, TARGET jnz data_phase_done; + } + if ((ahd->flags & AHD_INITIATORROLE) != 0) { + test SSTAT1, REQINIT jz .; + test SCSIPHASE, DATA_PHASE_MASK jnz p_data; + } + +data_phase_done: + /* Kill off any pending prefetch */ + call disable_ccsgen; + or LONGJMP_ADDR[1], INVALID_ADDR; + + if ((ahd->flags & AHD_TARGETROLE) != 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. We only need to + * send Ignore Wide Residue messages for data-in phases. + test DFCNTRL, DIRECTION jz target_ITloop; + test SSTAT1, REQINIT jnz .; + test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jz target_ITloop; + SET_MODE(M_SCSI, M_SCSI) + test NEGCONOPTS, WIDEXFER jz target_ITloop; + */ + /* + * Issue an Ignore Wide Residue Message. + mvi P_MESGIN|BSYO call change_phase; + mvi MSG_IGN_WIDE_RESIDUE call target_outb; + mvi 1 call target_outb; + jmp target_ITloop; + */ + } else { + jmp ITloop; + } + +/* + * We assume that, even though data may still be + * transferring to the host, that the SCSI side of + * the DMA engine is now in a static state. This + * allows us to update our notion of where we are + * in this transfer. + * + * If, by chance, we stopped before being able + * to fetch additional segments for this transfer, + * yet the last S/G was completely exhausted, + * call our idle loop until it is able to load + * another segment. This will allow us to immediately + * pickup on the next segment on the next data phase. + * + * If we happened to stop on the last segment, then + * our residual information is still correct from + * the idle loop and there is no need to perform + * any fixups. + */ +residual_before_last_seg: + test MDFFSTAT, SHVALID jnz sgptr_fixup; + /* + * Can never happen from an interrupt as the packetized + * hardware will only interrupt us once SHVALID or + * LAST_SEG_DONE. + */ + call idle_loop_service_fifos; + RESTORE_MODE(SAVED_MODE) + /* FALLTHROUGH */ +calc_residual: + test SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg; + /* Record if we've consumed all S/G entries */ + test MDFFSTAT, SHVALID jz . + 2; + bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; + or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret; + +sgptr_fixup: + /* + * Fixup the residual next S/G pointer. The S/G preload + * feature of the chip allows us to load two elements + * in addition to the currently active element. We + * store the bottom byte of the next S/G pointer in + * the SG_CACHE_PTR register so we can restore the + * correct value when the DMA completes. If the next + * sg ptr value has advanced to the point where higher + * bytes in the address have been affected, fix them + * too. + */ + test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; + test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; + add SCB_RESIDUAL_SGPTR[1], -1; + adc SCB_RESIDUAL_SGPTR[2], -1; + adc SCB_RESIDUAL_SGPTR[3], -1; +sgptr_fixup_done: + and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; + clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ + bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; + +export timer_isr: + call issue_cmdcmplt; + mvi CLRSEQINTSTAT, CLRSEQ_SWTMRTO; + if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { + /* + * In H2A4, the mode pointer is not saved + * for intvec2, but is restored on iret. + * This can lead to the restoration of a + * bogus mode ptr. Manually clear the + * intmask bits and do a normal return + * to compensate. + */ + and SEQINTCTL, ~(INTMASK2|INTMASK1) ret; + } else { + or SEQINTCTL, IRET ret; + } + +export seq_isr: + if ((ahd->features & AHD_RTI) == 0) { + /* + * On RevA Silicon, if the target returns us to data-out + * after we have already trained for data-out, it is + * possible for us to transition the free running clock to + * data-valid before the required 100ns P1 setup time (8 P1 + * assertions in fast-160 mode). This will only happen if + * this L-Q is a continuation of a data transfer for which + * we have already prefetched data into our FIFO (LQ/Data + * followed by LQ/Data for the same write transaction). + * This can cause some target implementations to miss the + * first few data transfers on the bus. We detect this + * situation by noticing that this is the first data transfer + * after an LQ (LQIWORKONLQ true), that the data transfer is + * a continuation of a transfer already setup in our FIFO + * (SAVEPTRS interrupt), and that the transaction is a write + * (DIRECTION set in DFCNTRL). The delay is performed by + * disabling SCSIEN until we see the first REQ from the + * target. + * + * First instruction in an ISR cannot be a branch on + * Rev A. Snapshot LQISTAT2 so the status is not missed + * and deffer the test by one instruction. + */ + mov REG_ISR, LQISTAT2; + test REG_ISR, LQIWORKONLQ jz main_isr; + test SEQINTSRC, SAVEPTRS jz main_isr; + test LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo; + /* + * Switch to the active FIFO after clearing the snapshot + * savepointer in the current FIFO. We do this so that + * a pending CTXTDONE or SAVEPTR is visible in the active + * FIFO. This status is the only way we can detect if we + * have lost the race (e.g. host paused us) and our attepts + * to disable the channel occurred after all REQs were + * already seen and acked (REQINIT never comes true). + */ + mvi DFFSXFRCTL, CLRCHN; + xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); + test DFCNTRL, DIRECTION jz interrupt_return; + and DFCNTRL, ~SCSIEN; +snapshot_wait_data_valid: + test SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz snapshot_data_valid; + test SSTAT1, REQINIT jz snapshot_wait_data_valid; +snapshot_data_valid: + or DFCNTRL, SCSIEN; + or SEQINTCTL, IRET ret; +snapshot_saveptr: + mvi DFFSXFRCTL, CLRCHN; + or SEQINTCTL, IRET ret; +main_isr: + } + test SEQINTSRC, CFG4DATA jnz cfg4data_intr; + test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr; + test SEQINTSRC, SAVEPTRS jnz saveptr_intr; + test SEQINTSRC, CFG4ICMD jnz cfg4icmd_intr; + SET_SEQINTCODE(INVALID_SEQINT) + +/* + * There are two types of save pointers interrupts: + * The first is a snapshot save pointers where the current FIFO is not + * active and contains a snapshot of the current poniter information. + * This happens between packets in a stream for a single L_Q. Since we + * are not performing a pointer save, we can safely clear the channel + * so it can be used for other transactions. On RTI capable controllers, + * where snapshots can, and are, disabled, the code to handle this type + * of snapshot is not active. + * + * The second case is a save pointers on an active FIFO which occurs + * if the target changes to a new L_Q or busfrees/QASes and the transfer + * has a residual. This should occur coincident with a ctxtdone. We + * disable the interrupt and allow our active routine to handle the + * save. + */ +saveptr_intr: + if ((ahd->features & AHD_RTI) == 0) { + test LONGJMP_ADDR[1], INVALID_ADDR jnz snapshot_saveptr; + } +saveptr_active_fifo: + and SEQIMODE, ~ENSAVEPTRS; + or SEQINTCTL, IRET ret; + +cfg4data_intr: + test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun_inc_use_count; + call load_first_seg; + call pkt_handle_xfer; + inc SCB_FIFO_USE_COUNT; +interrupt_return: + or SEQINTCTL, IRET ret; + +cfg4istat_intr: + call freeze_queue; + add NONE, -13, SCB_CDB_LEN; + jnc cfg4istat_have_sense_addr; + test SCB_CDB_LEN, SCB_CDB_LEN_PTR jnz cfg4istat_have_sense_addr; + /* + * Host sets up address/count and enables transfer. + */ + SET_SEQINTCODE(CFG4ISTAT_INTR) + jmp cfg4istat_setup_handler; +cfg4istat_have_sense_addr: + bmov HADDR, SCB_SENSE_BUSADDR, 4; + mvi HCNT[1], (AHD_SENSE_BUFSIZE >> 8); + mvi SG_CACHE_PRE, LAST_SEG; + mvi DFCNTRL, PRELOADEN|SCSIEN|HDMAEN; +cfg4istat_setup_handler: + /* + * Status pkt is transferring to host. + * Wait in idle loop for transfer to complete. + * If a command completed before an attempted + * task management function completed, notify the host. + */ + test SCB_TASK_MANAGEMENT, 0xFF jz cfg4istat_no_taskmgmt_func; + SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY) +cfg4istat_no_taskmgmt_func: + call pkt_handle_status; + or SEQINTCTL, IRET ret; + +cfg4icmd_intr: + /* + * In the case of DMAing a CDB from the host, the normal + * CDB buffer is formatted with an 8 byte address followed + * by a 1 byte count. + */ + bmov HADDR[0], SCB_HOST_CDB_PTR, 9; + mvi SG_CACHE_PRE, LAST_SEG; + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); + call pkt_handle_cdb; + or SEQINTCTL, IRET ret; + +/* + * See if the target has gone on in this context creating an + * overrun condition. For the write case, the hardware cannot + * ack bytes until data are provided. So, if the target begins + * another packet without changing contexts, implying we are + * not sitting on a packet boundary, we are in an overrun + * situation. For the read case, the hardware will continue to + * ack bytes into the FIFO, and may even ack the last overrun packet + * into the FIFO. If the FIFO should become non-empty, we are in + * a read overrun case. + */ +#define check_overrun \ + /* Not on a packet boundary. */ \ + test MDFFSTAT, DLZERO jz pkt_handle_overrun; \ + test DFSTATUS, FIFOEMP jz pkt_handle_overrun + +pkt_handle_xfer: + test SG_STATE, LOADING_NEEDED jz pkt_last_seg; + call setjmp; + test SEQINTSRC, SAVEPTRS jnz pkt_saveptrs; + test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; + test SCSISIGO, ATNO jnz . + 2; + test SSTAT2, NONPACKREQ jz pkt_service_fifo; + /* + * Defer handling of this NONPACKREQ until we + * can be sure it pertains to this FIFO. SAVEPTRS + * will not be asserted if the NONPACKREQ is for us, + * so we must simulate it if shaddow is valid. If + * shaddow is not valid, keep running this FIFO until we + * have satisfied the transfer by loading segments and + * waiting for either shaddow valid or last_seg_done. + */ + test MDFFSTAT, SHVALID jnz pkt_saveptrs; +pkt_service_fifo: + test SG_STATE, LOADING_NEEDED jnz service_fifo; +pkt_last_seg: + call setjmp; + test SEQINTSRC, SAVEPTRS jnz pkt_saveptrs; + test SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_last_seg_done; + test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; + test SCSISIGO, ATNO jnz . + 2; + test SSTAT2, NONPACKREQ jz return; + test MDFFSTAT, SHVALID jz return; + /* FALLTHROUGH */ + +/* + * Either a SAVEPTRS interrupt condition is pending for this FIFO + * or we have a pending NONPACKREQ for this FIFO. We differentiate + * between the two by capturing the state of the SAVEPTRS interrupt + * prior to clearing this status and executing the common code for + * these two cases. + */ +pkt_saveptrs: +BEGIN_CRITICAL; + if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { + or DFCNTRL, FIFOFLUSH; + } + mov REG0, SEQINTSRC; + call calc_residual; + call save_pointers; + mvi CLRSEQINTSRC, CLRSAVEPTRS; + call disable_ccsgen; + or SEQIMODE, ENSAVEPTRS; + test DFCNTRL, DIRECTION jnz pkt_saveptrs_check_status; + test DFSTATUS, FIFOEMP jnz pkt_saveptrs_check_status; + /* + * Keep a handler around for this FIFO until it drains + * to the host to guarantee that we don't complete the + * command to the host before the data arrives. + */ +pkt_saveptrs_wait_fifoemp: + call setjmp; + test DFSTATUS, FIFOEMP jz return; +pkt_saveptrs_check_status: + or LONGJMP_ADDR[1], INVALID_ADDR; + test REG0, SAVEPTRS jz unexpected_nonpkt_phase; + dec SCB_FIFO_USE_COUNT; + test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; + mvi DFFSXFRCTL, CLRCHN ret; +END_CRITICAL; + +/* + * LAST_SEG_DONE status has been seen in the current FIFO. + * This indicates that all of the allowed data for this + * command has transferred across the SCSI and host buses. + * Check for overrun and see if we can complete this command. + */ +pkt_last_seg_done: +BEGIN_CRITICAL; + /* + * Mark transfer as completed. + */ + or SCB_SGPTR, SG_LIST_NULL; + + /* + * Wait for the current context to finish to verify that + * no overrun condition has occurred. + */ + test SEQINTSRC, CTXTDONE jnz pkt_ctxt_done; + call setjmp; +pkt_wait_ctxt_done_loop: + test SEQINTSRC, CTXTDONE jnz pkt_ctxt_done; + /* + * A sufficiently large overrun or a NONPACKREQ may + * prevent CTXTDONE from ever asserting, so we must + * poll for these statuses too. + */ + check_overrun; + test SSTAT2, NONPACKREQ jz return; + test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase; + /* FALLTHROUGH */ + +pkt_ctxt_done: + check_overrun; + or LONGJMP_ADDR[1], INVALID_ADDR; + /* + * If status has been received, it is safe to skip + * the check to see if another FIFO is active because + * LAST_SEG_DONE has been observed. However, we check + * the FIFO anyway since it costs us only one extra + * instruction to leverage common code to perform the + * SCB completion. + */ + dec SCB_FIFO_USE_COUNT; + test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; + mvi DFFSXFRCTL, CLRCHN ret; +END_CRITICAL; + +/* + * Must wait until CDB xfer is over before issuing the + * clear channel. + */ +pkt_handle_cdb: + call setjmp; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz return; + or LONGJMP_ADDR[1], INVALID_ADDR; + mvi DFFSXFRCTL, CLRCHN ret; + +/* + * Watch over the status transfer. Our host sense buffer is + * large enough to take the maximum allowed status packet. + * None-the-less, we must still catch and report overruns to + * the host. Additionally, properly catch unexpected non-packet + * phases that are typically caused by CRC errors in status packet + * transmission. + */ +pkt_handle_status: + call setjmp; + test SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun; + test SEQINTSRC, CTXTDONE jz pkt_status_check_nonpackreq; + test SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun; +pkt_status_IU_done: + if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { + or DFCNTRL, FIFOFLUSH; + } + test DFSTATUS, FIFOEMP jz return; +BEGIN_CRITICAL; + or LONGJMP_ADDR[1], INVALID_ADDR; + mvi SCB_SCSI_STATUS, STATUS_PKT_SENSE; + or SCB_CONTROL, STATUS_RCVD; + jmp pkt_complete_scb_if_fifos_idle; +END_CRITICAL; +pkt_status_check_overrun: + /* + * Status PKT overruns are uncerimoniously recovered with a + * bus reset. If we've overrun, let the host know so that + * recovery can be performed. + * + * LAST_SEG_DONE has been observed. If either CTXTDONE or + * a NONPACKREQ phase change have occurred and the FIFO is + * empty, there is no overrun. + */ + test DFSTATUS, FIFOEMP jz pkt_status_report_overrun; + test SEQINTSRC, CTXTDONE jz . + 2; + test DFSTATUS, FIFOEMP jnz pkt_status_IU_done; + test SCSIPHASE, ~DATA_PHASE_MASK jz return; + test DFSTATUS, FIFOEMP jnz pkt_status_check_nonpackreq; +pkt_status_report_overrun: + SET_SEQINTCODE(STATUS_OVERRUN) + /* SEQUENCER RESTARTED */ +pkt_status_check_nonpackreq: + /* + * CTXTDONE may be held off if a NONPACKREQ is associated with + * the current context. If a NONPACKREQ is observed, decide + * if it is for the current context. If it is for the current + * context, we must defer NONPACKREQ processing until all data + * has transferred to the host. + */ + test SCSIPHASE, ~DATA_PHASE_MASK jz return; + test SCSISIGO, ATNO jnz . + 2; + test SSTAT2, NONPACKREQ jz return; + test SEQINTSRC, CTXTDONE jnz pkt_status_IU_done; + test DFSTATUS, FIFOEMP jz return; + /* + * The unexpected nonpkt phase handler assumes that any + * data channel use will have a FIFO reference count. It + * turns out that the status handler doesn't need a refernce + * count since the status received flag, and thus completion + * processing, cannot be set until the handler is finished. + * We increment the count here to make the nonpkt handler + * happy. + */ + inc SCB_FIFO_USE_COUNT; + /* FALLTHROUGH */ + +/* + * Nonpackreq is a polled status. It can come true in three situations: + * we have received an L_Q, we have sent one or more L_Qs, or there is no + * L_Q context associated with this REQ (REQ occurs immediately after a + * (re)selection). Routines that know that the context responsible for this + * nonpackreq call directly into unexpected_nonpkt_phase. In the case of the + * top level idle loop, we exhaust all active contexts prior to determining that + * we simply do not have the full I_T_L_Q for this phase. + */ +unexpected_nonpkt_phase_find_ctxt: + /* + * This nonpackreq is most likely associated with one of the tags + * in a FIFO or an outgoing LQ. Only treat it as an I_T only + * nonpackreq if we've cleared out the FIFOs and handled any + * pending SELDO. + */ +SET_SRC_MODE M_SCSI; +SET_DST_MODE M_SCSI; + and A, FIFO1FREE|FIFO0FREE, DFFSTAT; + cmp A, FIFO1FREE|FIFO0FREE jne return; + test SSTAT0, SELDO jnz return; + mvi SCBPTR[1], SCB_LIST_NULL; +unexpected_nonpkt_phase: + test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) + jnz unexpected_nonpkt_mode_cleared; +SET_SRC_MODE M_DFF0; +SET_DST_MODE M_DFF0; + or LONGJMP_ADDR[1], INVALID_ADDR; + dec SCB_FIFO_USE_COUNT; + mvi DFFSXFRCTL, CLRCHN; +unexpected_nonpkt_mode_cleared: + mvi CLRSINT2, CLRNONPACKREQ; + test SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase; + SET_SEQINTCODE(ENTERING_NONPACK) + jmp ITloop; + +illegal_phase: + SET_SEQINTCODE(ILLEGAL_PHASE) + jmp ITloop; + +/* + * We have entered an overrun situation. If we have working + * BITBUCKET, flip that on and let the hardware eat any overrun + * data. Otherwise use an overrun buffer in the host to simulate + * BITBUCKET. + */ +pkt_handle_overrun_inc_use_count: + inc SCB_FIFO_USE_COUNT; +pkt_handle_overrun: + SET_SEQINTCODE(CFG4OVERRUN) + call freeze_queue; + if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) { + or DFFSXFRCTL, DFFBITBUCKET; +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; + } else { + call load_overrun_buf; + mvi DFCNTRL, (HDMAEN|SCSIEN|PRELOADEN); + } + call setjmp; + if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { + test DFSTATUS, PRELOAD_AVAIL jz overrun_load_done; + call load_overrun_buf; + or DFCNTRL, PRELOADEN; +overrun_load_done: + test SEQINTSRC, CTXTDONE jnz pkt_overrun_end; + } else { + test DFFSXFRCTL, DFFBITBUCKET jz pkt_overrun_end; + } + test SSTAT2, NONPACKREQ jz return; +pkt_overrun_end: + or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID; + test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase; + dec SCB_FIFO_USE_COUNT; + or LONGJMP_ADDR[1], INVALID_ADDR; + test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; + mvi DFFSXFRCTL, CLRCHN ret; + +if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { +load_overrun_buf: + /* + * Load a dummy segment if preload space is available. + */ + mov HADDR[0], SHARED_DATA_ADDR; + add HADDR[1], PKT_OVERRUN_BUFOFFSET, SHARED_DATA_ADDR[1]; + mov ACCUM_SAVE, A; + clr A; + adc HADDR[2], A, SHARED_DATA_ADDR[2]; + adc HADDR[3], A, SHARED_DATA_ADDR[3]; + mov A, ACCUM_SAVE; + bmov HADDR[4], ALLZEROS, 4; + /* PKT_OVERRUN_BUFSIZE is a multiple of 256 */ + clr HCNT[0]; + mvi HCNT[1], ((PKT_OVERRUN_BUFSIZE >> 8) & 0xFF); + clr HCNT[2] ret; +} diff --git a/sys/dev/microcode/aic7xxx/aic79xx_seq.h b/sys/dev/microcode/aic7xxx/aic79xx_seq.h new file mode 100644 index 00000000000..a6458651968 --- /dev/null +++ b/sys/dev/microcode/aic7xxx/aic79xx_seq.h @@ -0,0 +1,1140 @@ +/* $OpenBSD: aic79xx_seq.h,v 1.1 2003/12/24 22:40:16 krw Exp $ */ +/* + * DO NOT EDIT - This file is automatically generated + * from the following source files: + * + * Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#96 $ + * Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $ + */ +static uint8_t seqprog[] = { + 0xff, 0x02, 0x06, 0x78, + 0x00, 0xea, 0x50, 0x59, + 0x01, 0xea, 0x04, 0x30, + 0xff, 0x04, 0x0c, 0x78, + 0x19, 0xea, 0x50, 0x59, + 0x19, 0xea, 0x04, 0x00, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x60, 0x3a, 0x1a, 0x68, + 0x04, 0x47, 0x1b, 0x68, + 0xff, 0x21, 0x1b, 0x70, + 0x40, 0x4b, 0x92, 0x69, + 0x00, 0xe2, 0x54, 0x59, + 0x40, 0x4b, 0x92, 0x69, + 0x20, 0x4b, 0x82, 0x69, + 0xfc, 0x42, 0x24, 0x78, + 0x10, 0x40, 0x24, 0x78, + 0x00, 0xe2, 0xc4, 0x5d, + 0x20, 0x4d, 0x28, 0x78, + 0x00, 0xe2, 0xc4, 0x5d, + 0x30, 0x3f, 0xc0, 0x09, + 0x30, 0xe0, 0x30, 0x60, + 0x7f, 0x4a, 0x94, 0x08, + 0x00, 0xe2, 0x32, 0x40, + 0xc0, 0x4a, 0x94, 0x00, + 0x00, 0xe2, 0x3e, 0x58, + 0x00, 0xe2, 0x56, 0x58, + 0x00, 0xe2, 0x66, 0x58, + 0x00, 0xe2, 0x06, 0x40, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x01, 0x52, 0x64, 0x78, + 0x02, 0x58, 0x50, 0x31, + 0xff, 0xea, 0x10, 0x0b, + 0xff, 0x97, 0x4f, 0x78, + 0x50, 0x4b, 0x4a, 0x68, + 0xbf, 0x3a, 0x74, 0x08, + 0x14, 0xea, 0x50, 0x59, + 0x14, 0xea, 0x04, 0x00, + 0x08, 0x92, 0x25, 0x03, + 0xff, 0x90, 0x3f, 0x68, + 0x00, 0xe2, 0x56, 0x5b, + 0x00, 0xe2, 0x3e, 0x40, + 0x00, 0xea, 0x44, 0x59, + 0x01, 0xea, 0x00, 0x30, + 0x80, 0xf9, 0x5e, 0x68, + 0x00, 0xe2, 0x42, 0x59, + 0x11, 0xea, 0x44, 0x59, + 0x11, 0xea, 0x00, 0x00, + 0x80, 0xf9, 0x42, 0x79, + 0xff, 0xea, 0xd4, 0x0d, + 0x22, 0xea, 0x44, 0x59, + 0x22, 0xea, 0x00, 0x00, + 0x10, 0x16, 0x70, 0x78, + 0x01, 0x0b, 0xa2, 0x32, + 0x10, 0x16, 0x2c, 0x00, + 0x18, 0xad, 0x00, 0x79, + 0x04, 0xad, 0xca, 0x68, + 0x80, 0xad, 0x64, 0x78, + 0x10, 0xad, 0x98, 0x78, + 0xff, 0x88, 0x83, 0x68, + 0xe7, 0xad, 0x5a, 0x09, + 0x02, 0x8c, 0x59, 0x32, + 0x02, 0x28, 0x19, 0x33, + 0x02, 0xa8, 0x50, 0x36, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x40, 0x3a, 0x64, 0x68, + 0x50, 0x4b, 0x64, 0x68, + 0x22, 0xea, 0x44, 0x59, + 0x22, 0xea, 0x00, 0x00, + 0xe7, 0xad, 0x5a, 0x09, + 0x02, 0x8c, 0x59, 0x32, + 0x1a, 0xea, 0x50, 0x59, + 0x1a, 0xea, 0x04, 0x00, + 0xff, 0xea, 0xd4, 0x0d, + 0xe7, 0xad, 0x5a, 0x09, + 0x00, 0xe2, 0xa6, 0x58, + 0xff, 0xea, 0x56, 0x02, + 0x04, 0x7c, 0x78, 0x32, + 0x20, 0x16, 0x64, 0x78, + 0x04, 0x38, 0x79, 0x32, + 0x80, 0x37, 0x6f, 0x16, + 0xff, 0x2d, 0xb5, 0x60, + 0xff, 0x29, 0xb5, 0x60, + 0x40, 0x51, 0xc5, 0x78, + 0xff, 0x4f, 0xb5, 0x68, + 0xff, 0x4d, 0xc1, 0x19, + 0x00, 0x4e, 0xd5, 0x19, + 0x00, 0xe2, 0xc4, 0x50, + 0x01, 0x4c, 0xc1, 0x31, + 0x00, 0x50, 0xd5, 0x19, + 0x00, 0xe2, 0xc4, 0x48, + 0x80, 0x18, 0x64, 0x78, + 0x02, 0x4a, 0x1d, 0x30, + 0x10, 0xea, 0x18, 0x00, + 0x60, 0x18, 0x30, 0x00, + 0x7f, 0x18, 0x30, 0x0c, + 0x02, 0xea, 0x02, 0x00, + 0xff, 0xea, 0xa0, 0x0a, + 0x80, 0x18, 0x30, 0x04, + 0x40, 0xad, 0x64, 0x78, + 0xe7, 0xad, 0x5a, 0x09, + 0x02, 0xa8, 0x40, 0x31, + 0xff, 0xea, 0xc0, 0x09, + 0x01, 0x4e, 0x9d, 0x1a, + 0x00, 0x4f, 0x9f, 0x22, + 0x01, 0x94, 0x6d, 0x33, + 0xff, 0xea, 0x20, 0x0b, + 0x04, 0xac, 0x49, 0x32, + 0xff, 0xea, 0x5a, 0x03, + 0xff, 0xea, 0x5e, 0x03, + 0x01, 0x10, 0xd4, 0x31, + 0x10, 0x92, 0xf5, 0x68, + 0x3d, 0x93, 0xc5, 0x29, + 0xfe, 0xe2, 0xc4, 0x09, + 0x01, 0xea, 0xc6, 0x01, + 0x02, 0xe2, 0xc8, 0x31, + 0x02, 0xec, 0x50, 0x31, + 0x02, 0xa0, 0xda, 0x31, + 0xff, 0xa9, 0xf4, 0x70, + 0x02, 0xa0, 0x58, 0x37, + 0xff, 0x21, 0xfd, 0x70, + 0x02, 0x22, 0x51, 0x31, + 0x02, 0xa0, 0x5c, 0x33, + 0x02, 0xa0, 0x44, 0x36, + 0x02, 0xa0, 0x40, 0x32, + 0x02, 0xa0, 0x44, 0x36, + 0x04, 0x47, 0x05, 0x69, + 0x40, 0x16, 0x30, 0x69, + 0xff, 0x2d, 0x35, 0x61, + 0xff, 0x29, 0x65, 0x70, + 0x01, 0x37, 0xc1, 0x31, + 0x02, 0x28, 0x55, 0x32, + 0x01, 0xea, 0x5a, 0x01, + 0x04, 0x3c, 0xf9, 0x30, + 0x02, 0x28, 0x51, 0x31, + 0x01, 0xa8, 0x60, 0x31, + 0x00, 0xa9, 0x60, 0x01, + 0x01, 0x14, 0xd4, 0x31, + 0x01, 0x50, 0xa1, 0x1a, + 0xff, 0x4e, 0x9d, 0x1a, + 0xff, 0x4f, 0x9f, 0x22, + 0xff, 0x8d, 0x29, 0x71, + 0x80, 0xac, 0x28, 0x71, + 0x20, 0x16, 0x28, 0x69, + 0x02, 0x8c, 0x51, 0x31, + 0x00, 0xe2, 0x12, 0x41, + 0x01, 0xac, 0x08, 0x31, + 0x09, 0xea, 0x5a, 0x01, + 0x02, 0x8c, 0x51, 0x32, + 0xff, 0xea, 0x1a, 0x07, + 0x04, 0x24, 0xf9, 0x30, + 0x1d, 0xea, 0x3a, 0x41, + 0x02, 0x2c, 0x51, 0x31, + 0x04, 0xa8, 0xf9, 0x30, + 0x19, 0xea, 0x3a, 0x41, + 0x06, 0xea, 0x08, 0x81, + 0x01, 0xe2, 0x5a, 0x35, + 0x02, 0xf2, 0xf0, 0x35, + 0x02, 0xf2, 0xf0, 0x31, + 0x02, 0xf8, 0xe4, 0x35, + 0x80, 0xea, 0xb2, 0x01, + 0x01, 0xe2, 0x00, 0x30, + 0xff, 0xea, 0xb2, 0x0d, + 0x80, 0xea, 0xb2, 0x01, + 0x11, 0x00, 0x00, 0x10, + 0xff, 0xea, 0xb2, 0x0d, + 0x01, 0xe2, 0x04, 0x30, + 0x01, 0xea, 0x04, 0x34, + 0x02, 0x20, 0xbd, 0x30, + 0x02, 0x20, 0xb9, 0x30, + 0x02, 0x20, 0x51, 0x31, + 0x4c, 0x93, 0xd7, 0x28, + 0x10, 0x92, 0x63, 0x79, + 0x01, 0x6b, 0xc0, 0x30, + 0x02, 0x64, 0xc8, 0x00, + 0x40, 0x3a, 0x74, 0x04, + 0x00, 0xe2, 0x56, 0x58, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x30, 0x3f, 0xc0, 0x09, + 0x30, 0xe0, 0x64, 0x61, + 0x20, 0x3f, 0x7a, 0x69, + 0x10, 0x3f, 0x64, 0x79, + 0x02, 0xea, 0x7e, 0x00, + 0x00, 0xea, 0x44, 0x59, + 0x01, 0xea, 0x00, 0x30, + 0x02, 0x48, 0x51, 0x35, + 0x01, 0xea, 0x7e, 0x00, + 0x11, 0xea, 0x44, 0x59, + 0x11, 0xea, 0x00, 0x00, + 0x02, 0x48, 0x51, 0x35, + 0x08, 0xea, 0x98, 0x00, + 0x08, 0x57, 0xae, 0x00, + 0x08, 0x3c, 0x78, 0x00, + 0xf0, 0x49, 0x68, 0x0a, + 0x0f, 0x67, 0xc0, 0x09, + 0x00, 0x34, 0x69, 0x02, + 0x20, 0xea, 0x96, 0x00, + 0x00, 0xe2, 0xf8, 0x41, + 0x40, 0x3a, 0xae, 0x69, + 0x02, 0x55, 0x06, 0x68, + 0x02, 0x56, 0xae, 0x69, + 0xff, 0x5b, 0xae, 0x61, + 0x02, 0x20, 0x51, 0x31, + 0x80, 0xea, 0xb2, 0x01, + 0x44, 0xea, 0x00, 0x00, + 0x01, 0x33, 0xc0, 0x31, + 0x33, 0xea, 0x00, 0x00, + 0xff, 0xea, 0xb2, 0x09, + 0xff, 0xe0, 0xc0, 0x19, + 0xff, 0xe0, 0xb0, 0x79, + 0x02, 0xac, 0x51, 0x31, + 0x00, 0xe2, 0xa6, 0x41, + 0x02, 0x5e, 0x50, 0x31, + 0x02, 0xa8, 0xb8, 0x30, + 0x02, 0x5c, 0x50, 0x31, + 0xff, 0xad, 0xc1, 0x71, + 0x02, 0xac, 0x41, 0x31, + 0x02, 0x22, 0x51, 0x31, + 0x02, 0xa0, 0x5c, 0x33, + 0x02, 0xa0, 0x44, 0x32, + 0x00, 0xe2, 0xca, 0x41, + 0x10, 0x92, 0xcb, 0x69, + 0x3d, 0x93, 0xc9, 0x29, + 0x01, 0xe4, 0xc8, 0x01, + 0x01, 0xea, 0xca, 0x01, + 0xff, 0xea, 0xda, 0x01, + 0x02, 0x20, 0x51, 0x31, + 0x02, 0xae, 0x41, 0x32, + 0xff, 0x21, 0xd3, 0x61, + 0xff, 0xea, 0x46, 0x02, + 0x02, 0x5c, 0x50, 0x31, + 0x40, 0xea, 0x96, 0x00, + 0x02, 0x56, 0xcc, 0x6d, + 0x01, 0x55, 0xcc, 0x6d, + 0x10, 0x92, 0xdf, 0x79, + 0x10, 0x40, 0xe8, 0x69, + 0x01, 0x56, 0xe8, 0x79, + 0xff, 0x97, 0x07, 0x78, + 0x13, 0xea, 0x50, 0x59, + 0x13, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0x06, 0x40, + 0xbf, 0x3a, 0x74, 0x08, + 0x08, 0xea, 0x98, 0x00, + 0x08, 0x57, 0xae, 0x00, + 0x01, 0x93, 0x69, 0x32, + 0x01, 0x94, 0x6b, 0x32, + 0x40, 0xea, 0x66, 0x02, + 0x08, 0x3c, 0x78, 0x00, + 0x80, 0xea, 0x62, 0x02, + 0x00, 0xe2, 0xb8, 0x5b, + 0x01, 0x36, 0xc1, 0x31, + 0x9f, 0xe0, 0x4c, 0x7c, + 0x80, 0xe0, 0x0c, 0x72, + 0xa0, 0xe0, 0x44, 0x72, + 0xc0, 0xe0, 0x3a, 0x72, + 0xe0, 0xe0, 0x74, 0x72, + 0x01, 0xea, 0x50, 0x59, + 0x01, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xf8, 0x41, + 0x80, 0x33, 0x13, 0x7a, + 0x03, 0xea, 0x50, 0x59, + 0x03, 0xea, 0x04, 0x00, + 0xee, 0x00, 0x1a, 0x6a, + 0x05, 0xea, 0xb4, 0x00, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x02, 0xa8, 0x90, 0x32, + 0x00, 0xe2, 0x6a, 0x59, + 0xef, 0x96, 0xd5, 0x19, + 0x00, 0xe2, 0x2a, 0x52, + 0x09, 0x80, 0xe1, 0x30, + 0x02, 0xea, 0x36, 0x00, + 0xa8, 0xea, 0x32, 0x00, + 0x00, 0xe2, 0x30, 0x42, + 0x01, 0x96, 0xd1, 0x30, + 0x10, 0x80, 0x89, 0x31, + 0x20, 0xea, 0x32, 0x00, + 0xbf, 0x33, 0x67, 0x0a, + 0x20, 0x19, 0x32, 0x6a, + 0x02, 0x4d, 0xf8, 0x69, + 0x40, 0x33, 0x67, 0x02, + 0x00, 0xe2, 0xf8, 0x41, + 0x80, 0x33, 0xb5, 0x6a, + 0x01, 0x44, 0x10, 0x33, + 0x08, 0x92, 0x25, 0x03, + 0x00, 0xe2, 0xf8, 0x41, + 0x10, 0xea, 0x80, 0x00, + 0x01, 0x31, 0xc5, 0x31, + 0x80, 0xe2, 0x60, 0x62, + 0x10, 0x92, 0x85, 0x6a, + 0xc0, 0x94, 0xc5, 0x01, + 0x40, 0x92, 0x51, 0x6a, + 0xbf, 0xe2, 0xc4, 0x09, + 0x20, 0x92, 0x65, 0x7a, + 0x01, 0xe2, 0x88, 0x30, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x6d, 0x62, + 0x23, 0x92, 0x89, 0x08, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x6d, 0x62, + 0x00, 0xa8, 0x64, 0x42, + 0xff, 0xe2, 0x64, 0x62, + 0x00, 0xe2, 0x84, 0x42, + 0x40, 0xea, 0x98, 0x00, + 0x01, 0xe2, 0x88, 0x30, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x43, 0x72, + 0x40, 0xea, 0x98, 0x00, + 0x01, 0x31, 0x89, 0x32, + 0x08, 0xea, 0x62, 0x02, + 0x00, 0xe2, 0xf8, 0x41, + 0xe0, 0xea, 0xd4, 0x5b, + 0x80, 0xe0, 0xc0, 0x6a, + 0x04, 0xe0, 0x66, 0x73, + 0x02, 0xe0, 0x96, 0x73, + 0x00, 0xea, 0x1e, 0x73, + 0x03, 0xe0, 0xa6, 0x73, + 0x23, 0xe0, 0x96, 0x72, + 0x08, 0xe0, 0xbc, 0x72, + 0x00, 0xe2, 0xb8, 0x5b, + 0x07, 0xea, 0x50, 0x59, + 0x07, 0xea, 0x04, 0x00, + 0x08, 0x42, 0xf9, 0x71, + 0x04, 0x42, 0x93, 0x62, + 0x01, 0x43, 0x89, 0x30, + 0x00, 0xe2, 0x84, 0x42, + 0x01, 0x44, 0xd4, 0x31, + 0x00, 0xe2, 0x84, 0x42, + 0x01, 0x00, 0x60, 0x32, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x4c, 0x34, 0xc1, 0x28, + 0x01, 0x64, 0xc0, 0x31, + 0x00, 0x30, 0x45, 0x59, + 0x01, 0x30, 0x01, 0x30, + 0x01, 0xe0, 0xba, 0x7a, + 0xa0, 0xea, 0xca, 0x5b, + 0x01, 0xa0, 0xba, 0x62, + 0x01, 0x84, 0xaf, 0x7a, + 0x01, 0x95, 0xbd, 0x6a, + 0x05, 0xea, 0x50, 0x59, + 0x05, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xbc, 0x42, + 0x03, 0xea, 0x50, 0x59, + 0x03, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xbc, 0x42, + 0x07, 0xea, 0xdc, 0x5b, + 0x01, 0x44, 0xd4, 0x31, + 0x00, 0xe2, 0xf8, 0x41, + 0x3f, 0xe0, 0x6a, 0x0a, + 0xc0, 0x34, 0xc1, 0x09, + 0x00, 0x35, 0x51, 0x01, + 0xff, 0xea, 0x52, 0x09, + 0x30, 0x34, 0xc5, 0x09, + 0x3d, 0xe2, 0xc4, 0x29, + 0xb8, 0xe2, 0xc4, 0x19, + 0x01, 0xea, 0xc6, 0x01, + 0x02, 0xe2, 0xc8, 0x31, + 0x02, 0xec, 0x40, 0x31, + 0xff, 0xa1, 0xdc, 0x72, + 0x02, 0xe8, 0xda, 0x31, + 0x02, 0xa0, 0x50, 0x31, + 0x00, 0xe2, 0xfe, 0x42, + 0x80, 0x33, 0x67, 0x02, + 0x01, 0x44, 0xd4, 0x31, + 0x00, 0xe2, 0xb8, 0x5b, + 0x01, 0x33, 0x67, 0x02, + 0xe0, 0x36, 0x19, 0x63, + 0x02, 0x33, 0x67, 0x02, + 0x20, 0x46, 0x12, 0x63, + 0xff, 0xea, 0x52, 0x09, + 0xa8, 0xea, 0xca, 0x5b, + 0x04, 0x92, 0xf9, 0x7a, + 0x01, 0x34, 0xc1, 0x31, + 0x00, 0x93, 0xf9, 0x62, + 0x01, 0x35, 0xc1, 0x31, + 0x00, 0x94, 0x03, 0x73, + 0x01, 0xa9, 0x52, 0x11, + 0xff, 0xa9, 0xee, 0x6a, + 0x00, 0xe2, 0x12, 0x43, + 0x10, 0x33, 0x67, 0x02, + 0x04, 0x92, 0x13, 0x7b, + 0xfb, 0x92, 0x25, 0x0b, + 0xff, 0xea, 0x66, 0x0a, + 0x01, 0xa4, 0x0d, 0x6b, + 0x02, 0xa8, 0x90, 0x32, + 0x00, 0xe2, 0x6a, 0x59, + 0x10, 0x92, 0xbd, 0x7a, + 0xff, 0xea, 0xdc, 0x5b, + 0x00, 0xe2, 0xbc, 0x42, + 0x04, 0xea, 0x50, 0x59, + 0x04, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xbc, 0x42, + 0x04, 0xea, 0x50, 0x59, + 0x04, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0x92, 0xb5, 0x7a, + 0xc0, 0x33, 0x29, 0x7b, + 0x80, 0x33, 0xb5, 0x6a, + 0xff, 0x88, 0x29, 0x6b, + 0x40, 0x33, 0xb5, 0x6a, + 0x10, 0x92, 0x2f, 0x7b, + 0x0a, 0xea, 0x50, 0x59, + 0x0a, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0x4e, 0x5b, + 0x00, 0xe2, 0x82, 0x43, + 0x50, 0x4b, 0x36, 0x6b, + 0xbf, 0x3a, 0x74, 0x08, + 0x01, 0xe0, 0xf4, 0x31, + 0xff, 0xea, 0xc0, 0x09, + 0x01, 0x2e, 0x5d, 0x1a, + 0x00, 0x2f, 0x5f, 0x22, + 0x04, 0x47, 0x8f, 0x02, + 0x01, 0xfa, 0xc0, 0x35, + 0x02, 0xa8, 0x84, 0x32, + 0x02, 0xea, 0xb4, 0x00, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x02, 0x42, 0x51, 0x31, + 0xff, 0x90, 0x65, 0x68, + 0xff, 0x88, 0x5b, 0x6b, + 0x01, 0xa4, 0x57, 0x6b, + 0x02, 0xa4, 0x5f, 0x6b, + 0x01, 0x84, 0x5f, 0x7b, + 0x02, 0x28, 0x19, 0x33, + 0x02, 0xa8, 0x50, 0x36, + 0xff, 0x88, 0x5f, 0x73, + 0x00, 0xe2, 0x32, 0x5b, + 0x02, 0xa8, 0x20, 0x33, + 0x02, 0x2c, 0x19, 0x33, + 0x02, 0xa8, 0x58, 0x32, + 0x04, 0xa4, 0x49, 0x07, + 0xc0, 0x33, 0xb5, 0x6a, + 0x04, 0x92, 0x25, 0x03, + 0x20, 0x92, 0x83, 0x6b, + 0x02, 0xa8, 0x40, 0x31, + 0xc0, 0x34, 0xc1, 0x09, + 0x00, 0x35, 0x51, 0x01, + 0xff, 0xea, 0x52, 0x09, + 0x30, 0x34, 0xc5, 0x09, + 0x3d, 0xe2, 0xc4, 0x29, + 0xb8, 0xe2, 0xc4, 0x19, + 0x01, 0xea, 0xc6, 0x01, + 0x02, 0xe2, 0xc8, 0x31, + 0x02, 0xa0, 0xda, 0x31, + 0x02, 0xa0, 0x50, 0x31, + 0xf7, 0x57, 0xae, 0x08, + 0x08, 0xea, 0x98, 0x00, + 0x01, 0x44, 0xd4, 0x31, + 0xee, 0x00, 0x8c, 0x6b, + 0x02, 0xea, 0xb4, 0x00, + 0x00, 0xe2, 0xb4, 0x5b, + 0x09, 0x4c, 0x8e, 0x7b, + 0x08, 0x4c, 0x06, 0x68, + 0x0b, 0xea, 0x50, 0x59, + 0x0b, 0xea, 0x04, 0x00, + 0x01, 0x44, 0xd4, 0x31, + 0x20, 0x33, 0xf9, 0x79, + 0x00, 0xe2, 0x9e, 0x5b, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0x84, 0xa3, 0x7b, + 0x01, 0xa4, 0x49, 0x07, + 0x08, 0x60, 0x30, 0x33, + 0x08, 0x80, 0x41, 0x37, + 0xdf, 0x33, 0x67, 0x0a, + 0xee, 0x00, 0xb0, 0x6b, + 0x05, 0xea, 0xb4, 0x00, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x00, 0xe2, 0x6a, 0x59, + 0x00, 0xe2, 0xbc, 0x42, + 0x01, 0xea, 0x6c, 0x02, + 0xc0, 0xea, 0x66, 0x06, + 0xff, 0x42, 0xc4, 0x6b, + 0x01, 0x41, 0xb8, 0x6b, + 0x02, 0x41, 0xb8, 0x7b, + 0xff, 0x42, 0xc4, 0x6b, + 0x01, 0x41, 0xb8, 0x6b, + 0x02, 0x41, 0xb8, 0x7b, + 0xff, 0x42, 0xc4, 0x7b, + 0x04, 0x4c, 0xb8, 0x6b, + 0xe0, 0x41, 0x6c, 0x0e, + 0x01, 0x44, 0xd4, 0x31, + 0xff, 0x42, 0xcc, 0x7b, + 0x04, 0x4c, 0xcc, 0x6b, + 0xe0, 0x41, 0x6c, 0x0a, + 0xe0, 0x36, 0xf9, 0x61, + 0xff, 0xea, 0xca, 0x09, + 0x01, 0xe2, 0xc8, 0x31, + 0x01, 0x46, 0xda, 0x35, + 0x01, 0x44, 0xd4, 0x35, + 0x10, 0xea, 0x80, 0x00, + 0x01, 0xe2, 0x62, 0x36, + 0x04, 0xa6, 0xe4, 0x7b, + 0xff, 0xea, 0x5a, 0x09, + 0xff, 0xea, 0x4c, 0x0d, + 0x01, 0xa6, 0x02, 0x6c, + 0x10, 0xad, 0x64, 0x78, + 0x80, 0xad, 0xfa, 0x6b, + 0x08, 0xad, 0x64, 0x68, + 0x04, 0x84, 0xf9, 0x30, + 0x00, 0xea, 0x08, 0x81, + 0xff, 0xea, 0xd4, 0x09, + 0x02, 0x84, 0xf9, 0x88, + 0x0d, 0xea, 0x5a, 0x01, + 0x04, 0xa6, 0x4c, 0x05, + 0x04, 0xa6, 0x64, 0x78, + 0xff, 0xea, 0x5a, 0x09, + 0x03, 0x84, 0x59, 0x89, + 0x03, 0xea, 0x4c, 0x01, + 0x80, 0x1a, 0x64, 0x78, + 0x08, 0x19, 0x64, 0x78, + 0x08, 0xb0, 0xe0, 0x30, + 0x04, 0xb0, 0xe0, 0x30, + 0x03, 0xb0, 0xf0, 0x30, + 0x01, 0xb0, 0x06, 0x33, + 0x7f, 0x83, 0xe9, 0x08, + 0x04, 0xac, 0x58, 0x19, + 0xff, 0xea, 0xc0, 0x09, + 0x04, 0x84, 0x09, 0x9b, + 0x00, 0x85, 0x0b, 0x23, + 0x00, 0x86, 0x0d, 0x23, + 0x00, 0x87, 0x0f, 0x23, + 0x01, 0x84, 0xc5, 0x31, + 0x80, 0x83, 0x25, 0x7c, + 0x02, 0xe2, 0xc4, 0x01, + 0xff, 0xea, 0x4c, 0x09, + 0x01, 0xe2, 0x36, 0x30, + 0xc8, 0x19, 0x32, 0x00, + 0x88, 0x19, 0x32, 0x00, + 0x01, 0xac, 0xd4, 0x99, + 0x00, 0xe2, 0x64, 0x50, + 0xfe, 0xa6, 0x4c, 0x0d, + 0x0b, 0x98, 0xe1, 0x30, + 0xfd, 0xa4, 0x49, 0x09, + 0x80, 0xa3, 0x39, 0x7c, + 0x02, 0xa4, 0x48, 0x01, + 0x01, 0xa4, 0x36, 0x30, + 0xa8, 0xea, 0x32, 0x00, + 0xfd, 0xa4, 0x49, 0x0b, + 0x05, 0xa3, 0x07, 0x33, + 0x80, 0x83, 0x45, 0x6c, + 0x02, 0xea, 0x4c, 0x05, + 0xff, 0xea, 0x4c, 0x0d, + 0x00, 0xe2, 0x3e, 0x59, + 0x02, 0xa6, 0xe6, 0x6b, + 0x80, 0xf9, 0xf2, 0x05, + 0xc0, 0x33, 0x53, 0x7c, + 0x03, 0xea, 0x50, 0x59, + 0x03, 0xea, 0x04, 0x00, + 0x20, 0x33, 0x77, 0x7c, + 0x01, 0x84, 0x5d, 0x6c, + 0x06, 0xea, 0x50, 0x59, + 0x06, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0x7a, 0x44, + 0x01, 0x00, 0x60, 0x32, + 0xee, 0x00, 0x66, 0x6c, + 0x05, 0xea, 0xb4, 0x00, + 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x00, 0x00, + 0x80, 0x3d, 0x7a, 0x00, + 0xfc, 0x42, 0x68, 0x7c, + 0x7f, 0x3d, 0x7a, 0x08, + 0x00, 0x30, 0x45, 0x59, + 0x01, 0x30, 0x01, 0x30, + 0x09, 0xea, 0x50, 0x59, + 0x09, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0xa4, 0x5d, 0x6c, + 0x00, 0xe2, 0x30, 0x5c, + 0x20, 0x33, 0x67, 0x02, + 0x01, 0x00, 0x60, 0x32, + 0x02, 0xa6, 0x82, 0x7c, + 0x00, 0xe2, 0x46, 0x5c, + 0x00, 0xe2, 0x56, 0x58, + 0x00, 0xe2, 0x66, 0x58, + 0x00, 0xe2, 0x3a, 0x58, + 0x00, 0x30, 0x45, 0x59, + 0x01, 0x30, 0x01, 0x30, + 0x20, 0x19, 0x82, 0x6c, + 0x00, 0xe2, 0xb2, 0x5c, + 0x04, 0x19, 0x9c, 0x6c, + 0x02, 0x19, 0x32, 0x00, + 0x01, 0x84, 0x9d, 0x7c, + 0x01, 0x1b, 0x96, 0x7c, + 0x01, 0x1a, 0x9c, 0x6c, + 0x00, 0xe2, 0x4c, 0x44, + 0x80, 0x4b, 0xa2, 0x6c, + 0x01, 0x4c, 0x9e, 0x7c, + 0x03, 0x42, 0x4c, 0x6c, + 0x00, 0xe2, 0xe0, 0x5b, + 0x80, 0xf9, 0xf2, 0x01, + 0x04, 0x33, 0xf9, 0x79, + 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0x5d, 0xba, 0x6c, + 0x00, 0xe2, 0x56, 0x58, + 0x00, 0x30, 0x45, 0x59, + 0x01, 0x30, 0x01, 0x30, + 0x02, 0x1b, 0xaa, 0x7c, + 0x08, 0x5d, 0xb8, 0x7c, + 0x03, 0x68, 0x00, 0x37, + 0x01, 0x84, 0x09, 0x07, + 0x80, 0x1b, 0xc4, 0x7c, + 0x80, 0x84, 0xc5, 0x6c, + 0xff, 0x85, 0x0b, 0x1b, + 0xff, 0x86, 0x0d, 0x23, + 0xff, 0x87, 0x0f, 0x23, + 0xf8, 0x1b, 0x08, 0x0b, + 0xff, 0xea, 0x06, 0x0b, + 0x03, 0x68, 0x00, 0x37, + 0x00, 0xe2, 0xc4, 0x58, + 0x10, 0xea, 0x18, 0x00, + 0xf9, 0xd9, 0xb2, 0x0d, + 0x01, 0xd9, 0xb2, 0x05, + 0x01, 0x52, 0x48, 0x31, + 0x20, 0xa4, 0xee, 0x7c, + 0x20, 0x5b, 0xee, 0x7c, + 0x80, 0xf9, 0xfc, 0x7c, + 0x02, 0xea, 0xb4, 0x00, + 0x11, 0x00, 0x00, 0x10, + 0x04, 0x19, 0x08, 0x7d, + 0xdf, 0x19, 0x32, 0x08, + 0x60, 0x5b, 0xe6, 0x6c, + 0x01, 0x4c, 0xe2, 0x7c, + 0x20, 0x19, 0x32, 0x00, + 0x01, 0xd9, 0xb2, 0x05, + 0x02, 0xea, 0xb4, 0x00, + 0x01, 0xd9, 0xb2, 0x05, + 0x10, 0x5b, 0x00, 0x6d, + 0x08, 0x5b, 0x0a, 0x6d, + 0x20, 0x5b, 0xfa, 0x6c, + 0x02, 0x5b, 0x2a, 0x6d, + 0x0e, 0xea, 0x50, 0x59, + 0x0e, 0xea, 0x04, 0x00, + 0x80, 0xf9, 0xea, 0x6c, + 0xdf, 0x5c, 0xb8, 0x08, + 0x01, 0xd9, 0xb2, 0x05, + 0x01, 0xa4, 0xe5, 0x6d, + 0x00, 0xe2, 0x30, 0x5c, + 0x00, 0xe2, 0x34, 0x5d, + 0x01, 0x90, 0x21, 0x1b, + 0x01, 0xd9, 0xb2, 0x05, + 0x00, 0xe2, 0x32, 0x5b, + 0xf3, 0x96, 0xd5, 0x19, + 0x00, 0xe2, 0x18, 0x55, + 0x80, 0x96, 0x19, 0x6d, + 0x0f, 0xea, 0x50, 0x59, + 0x0f, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0x20, 0x45, + 0x04, 0x8c, 0xe1, 0x30, + 0x01, 0xea, 0xf2, 0x00, + 0x02, 0xea, 0x36, 0x00, + 0xa8, 0xea, 0x32, 0x00, + 0xff, 0x97, 0x27, 0x7d, + 0x14, 0xea, 0x50, 0x59, + 0x14, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0x96, 0x5d, + 0x01, 0xd9, 0xb2, 0x05, + 0x09, 0x80, 0xe1, 0x30, + 0x02, 0xea, 0x36, 0x00, + 0xa8, 0xea, 0x32, 0x00, + 0x00, 0xe2, 0x8e, 0x5d, + 0x01, 0xd9, 0xb2, 0x05, + 0x02, 0xa6, 0x44, 0x7d, + 0x00, 0xe2, 0x3e, 0x59, + 0x20, 0x5b, 0x52, 0x6d, + 0xfc, 0x42, 0x3e, 0x7d, + 0x10, 0x40, 0x40, 0x6d, + 0x20, 0x4d, 0x42, 0x7d, + 0x08, 0x5d, 0x52, 0x6d, + 0x02, 0xa6, 0xe6, 0x6b, + 0x00, 0xe2, 0x3e, 0x59, + 0x20, 0x5b, 0x52, 0x6d, + 0x01, 0x1b, 0x72, 0x6d, + 0xfc, 0x42, 0x4e, 0x7d, + 0x10, 0x40, 0x50, 0x6d, + 0x20, 0x4d, 0x64, 0x78, + 0x08, 0x5d, 0x64, 0x78, + 0x02, 0x19, 0x32, 0x00, + 0x01, 0x5b, 0x40, 0x31, + 0x00, 0xe2, 0xb2, 0x5c, + 0x00, 0xe2, 0x9e, 0x5b, + 0x20, 0xea, 0xb6, 0x00, + 0x00, 0xe2, 0xe0, 0x5b, + 0x20, 0x5c, 0xb8, 0x00, + 0x04, 0x19, 0x68, 0x6d, + 0x01, 0x1a, 0x68, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, + 0x01, 0x1a, 0x64, 0x78, + 0x80, 0xf9, 0xf2, 0x01, + 0x20, 0xa0, 0xcc, 0x7d, + 0xff, 0x90, 0x21, 0x1b, + 0x08, 0x92, 0x43, 0x6b, + 0x02, 0xea, 0xb4, 0x04, + 0x01, 0xa4, 0x49, 0x03, + 0x40, 0x5b, 0x82, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, + 0x40, 0x5b, 0x82, 0x6d, + 0x04, 0x5d, 0xe6, 0x7d, + 0x01, 0x1a, 0xe6, 0x7d, + 0x20, 0x4d, 0x64, 0x78, + 0x40, 0x5b, 0xcc, 0x7d, + 0x04, 0x5d, 0xe6, 0x7d, + 0x01, 0x1a, 0xe6, 0x7d, + 0x80, 0xf9, 0xf2, 0x01, + 0xff, 0x90, 0x21, 0x1b, + 0x08, 0x92, 0x43, 0x6b, + 0x02, 0xea, 0xb4, 0x04, + 0x00, 0xe2, 0x3e, 0x59, + 0x01, 0x1b, 0x64, 0x78, + 0x80, 0xf9, 0xf2, 0x01, + 0x02, 0xea, 0xb4, 0x04, + 0x00, 0xe2, 0x3e, 0x59, + 0x01, 0x1b, 0xaa, 0x6d, + 0x40, 0x5b, 0xb8, 0x7d, + 0x01, 0x1b, 0xaa, 0x6d, + 0x02, 0x19, 0x32, 0x00, + 0x01, 0x1a, 0x64, 0x78, + 0x80, 0xf9, 0xf2, 0x01, + 0xff, 0xea, 0x10, 0x03, + 0x08, 0x92, 0x25, 0x03, + 0x00, 0xe2, 0x42, 0x43, + 0x01, 0x1a, 0xb4, 0x7d, + 0x40, 0x5b, 0xb0, 0x7d, + 0x01, 0x1a, 0x9e, 0x6d, + 0xfc, 0x42, 0x64, 0x78, + 0x01, 0x1a, 0xb8, 0x6d, + 0x10, 0xea, 0x50, 0x59, + 0x10, 0xea, 0x04, 0x00, + 0xfc, 0x42, 0x64, 0x78, + 0x10, 0x40, 0xbe, 0x6d, + 0x20, 0x4d, 0x64, 0x78, + 0x40, 0x5b, 0x9e, 0x6d, + 0x01, 0x1a, 0x64, 0x78, + 0x01, 0x90, 0x21, 0x1b, + 0x30, 0x3f, 0xc0, 0x09, + 0x30, 0xe0, 0x64, 0x60, + 0x40, 0x4b, 0x64, 0x68, + 0xff, 0xea, 0x52, 0x01, + 0xee, 0x00, 0xd4, 0x6d, + 0x80, 0xf9, 0xf2, 0x01, + 0xff, 0x90, 0x21, 0x1b, + 0x02, 0xea, 0xb4, 0x00, + 0x20, 0xea, 0x9a, 0x00, + 0xf3, 0x42, 0xde, 0x6d, + 0x12, 0xea, 0x50, 0x59, + 0x12, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xf8, 0x41, + 0x0d, 0xea, 0x50, 0x59, + 0x0d, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0x90, 0x21, 0x1b, + 0x11, 0xea, 0x50, 0x59, + 0x11, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0x32, 0x5b, + 0x08, 0x5a, 0xb4, 0x00, + 0x00, 0xe2, 0x0c, 0x5e, + 0xa8, 0xea, 0x32, 0x00, + 0x00, 0xe2, 0x3e, 0x59, + 0x80, 0x1a, 0xfa, 0x7d, + 0x00, 0xe2, 0x0c, 0x5e, + 0x80, 0x19, 0x32, 0x00, + 0x40, 0x5b, 0x00, 0x6e, + 0x08, 0x5a, 0x00, 0x7e, + 0x20, 0x4d, 0x64, 0x78, + 0x02, 0x84, 0x09, 0x03, + 0x40, 0x5b, 0xcc, 0x7d, + 0xff, 0x90, 0x21, 0x1b, + 0x80, 0xf9, 0xf2, 0x01, + 0x08, 0x92, 0x43, 0x6b, + 0x02, 0xea, 0xb4, 0x04, + 0x01, 0x38, 0xe1, 0x30, + 0x05, 0x39, 0xe3, 0x98, + 0x01, 0xe0, 0xf4, 0x31, + 0xff, 0xea, 0xc0, 0x09, + 0x00, 0x3a, 0xe5, 0x20, + 0x00, 0x3b, 0xe7, 0x20, + 0x01, 0xfa, 0xc0, 0x31, + 0x04, 0xea, 0xe8, 0x30, + 0xff, 0xea, 0xf0, 0x08, + 0x02, 0xea, 0xf2, 0x00, + 0xff, 0xea, 0xf4, 0x0c +}; + +typedef int ahd_patch_func_t (struct ahd_softc *ahd); +static ahd_patch_func_t ahd_patch22_func; + +static int +ahd_patch22_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch21_func; + +static int +ahd_patch21_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); +} + +static ahd_patch_func_t ahd_patch20_func; + +static int +ahd_patch20_func(struct ahd_softc *ahd) +{ + return ((ahd->features & AHD_RTI) == 0); +} + +static ahd_patch_func_t ahd_patch19_func; + +static int +ahd_patch19_func(struct ahd_softc *ahd) +{ + return ((ahd->flags & AHD_INITIATORROLE) != 0); +} + +static ahd_patch_func_t ahd_patch18_func; + +static int +ahd_patch18_func(struct ahd_softc *ahd) +{ + return ((ahd->flags & AHD_TARGETROLE) != 0); +} + +static ahd_patch_func_t ahd_patch17_func; + +static int +ahd_patch17_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch16_func; + +static int +ahd_patch16_func(struct ahd_softc *ahd) +{ + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); +} + +static ahd_patch_func_t ahd_patch15_func; + +static int +ahd_patch15_func(struct ahd_softc *ahd) +{ + return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); +} + +static ahd_patch_func_t ahd_patch14_func; + +static int +ahd_patch14_func(struct ahd_softc *ahd) +{ + return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); +} + +static ahd_patch_func_t ahd_patch13_func; + +static int +ahd_patch13_func(struct ahd_softc *ahd) +{ + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); +} + +static ahd_patch_func_t ahd_patch12_func; + +static int +ahd_patch12_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch11_func; + +static int +ahd_patch11_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch10_func; + +static int +ahd_patch10_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0); +} + +static ahd_patch_func_t ahd_patch9_func; + +static int +ahd_patch9_func(struct ahd_softc *ahd) +{ + return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); +} + +static ahd_patch_func_t ahd_patch8_func; + +static int +ahd_patch8_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch7_func; + +static int +ahd_patch7_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch6_func; + +static int +ahd_patch6_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch5_func; + +static int +ahd_patch5_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch4_func; + +static int +ahd_patch4_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_PKT_LUN_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch3_func; + +static int +ahd_patch3_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_FAINT_LED_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch2_func; + +static int +ahd_patch2_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_SET_MODE_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch1_func; + +static int +ahd_patch1_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0); +} + +static ahd_patch_func_t ahd_patch0_func; + +static int +ahd_patch0_func(struct ahd_softc *ahd) +{ + return (0); +} + +static struct patch { + ahd_patch_func_t *patch_func; + uint32_t begin :10, + skip_instr :10, + skip_patch :12; +} patches[] = { + { ahd_patch1_func, 0, 3, 3 }, + { ahd_patch1_func, 1, 1, 2 }, + { ahd_patch0_func, 2, 1, 1 }, + { ahd_patch1_func, 3, 3, 3 }, + { ahd_patch1_func, 4, 1, 2 }, + { ahd_patch0_func, 5, 1, 1 }, + { ahd_patch2_func, 6, 1, 2 }, + { ahd_patch0_func, 7, 1, 1 }, + { ahd_patch3_func, 20, 5, 1 }, + { ahd_patch2_func, 29, 1, 2 }, + { ahd_patch0_func, 30, 1, 1 }, + { ahd_patch1_func, 37, 1, 2 }, + { ahd_patch0_func, 38, 1, 1 }, + { ahd_patch2_func, 43, 1, 2 }, + { ahd_patch0_func, 44, 1, 1 }, + { ahd_patch2_func, 47, 1, 2 }, + { ahd_patch0_func, 48, 1, 1 }, + { ahd_patch2_func, 51, 1, 2 }, + { ahd_patch0_func, 52, 1, 1 }, + { ahd_patch2_func, 65, 1, 2 }, + { ahd_patch0_func, 66, 1, 1 }, + { ahd_patch2_func, 69, 1, 2 }, + { ahd_patch0_func, 70, 1, 1 }, + { ahd_patch1_func, 73, 1, 2 }, + { ahd_patch0_func, 74, 1, 1 }, + { ahd_patch4_func, 107, 1, 1 }, + { ahd_patch2_func, 162, 6, 1 }, + { ahd_patch1_func, 168, 2, 1 }, + { ahd_patch5_func, 170, 1, 1 }, + { ahd_patch2_func, 179, 1, 2 }, + { ahd_patch0_func, 180, 1, 1 }, + { ahd_patch6_func, 181, 2, 2 }, + { ahd_patch0_func, 183, 6, 3 }, + { ahd_patch2_func, 186, 1, 2 }, + { ahd_patch0_func, 187, 1, 1 }, + { ahd_patch2_func, 190, 1, 2 }, + { ahd_patch0_func, 191, 1, 1 }, + { ahd_patch7_func, 193, 2, 1 }, + { ahd_patch5_func, 201, 16, 2 }, + { ahd_patch0_func, 217, 1, 1 }, + { ahd_patch8_func, 237, 2, 1 }, + { ahd_patch1_func, 241, 1, 2 }, + { ahd_patch0_func, 242, 1, 1 }, + { ahd_patch7_func, 245, 2, 1 }, + { ahd_patch1_func, 259, 1, 2 }, + { ahd_patch0_func, 260, 1, 1 }, + { ahd_patch1_func, 263, 1, 2 }, + { ahd_patch0_func, 264, 1, 1 }, + { ahd_patch2_func, 267, 1, 2 }, + { ahd_patch0_func, 268, 1, 1 }, + { ahd_patch1_func, 323, 1, 2 }, + { ahd_patch0_func, 324, 1, 1 }, + { ahd_patch2_func, 332, 1, 2 }, + { ahd_patch0_func, 333, 1, 1 }, + { ahd_patch2_func, 336, 1, 2 }, + { ahd_patch0_func, 337, 1, 1 }, + { ahd_patch1_func, 343, 1, 2 }, + { ahd_patch0_func, 344, 1, 1 }, + { ahd_patch1_func, 346, 1, 2 }, + { ahd_patch0_func, 347, 1, 1 }, + { ahd_patch9_func, 366, 1, 1 }, + { ahd_patch9_func, 369, 1, 1 }, + { ahd_patch9_func, 371, 1, 1 }, + { ahd_patch9_func, 383, 1, 1 }, + { ahd_patch1_func, 393, 1, 2 }, + { ahd_patch0_func, 394, 1, 1 }, + { ahd_patch1_func, 396, 1, 2 }, + { ahd_patch0_func, 397, 1, 1 }, + { ahd_patch1_func, 405, 1, 2 }, + { ahd_patch0_func, 406, 1, 1 }, + { ahd_patch2_func, 419, 1, 2 }, + { ahd_patch0_func, 420, 1, 1 }, + { ahd_patch10_func, 450, 1, 1 }, + { ahd_patch1_func, 457, 1, 2 }, + { ahd_patch0_func, 458, 1, 1 }, + { ahd_patch2_func, 470, 1, 2 }, + { ahd_patch0_func, 471, 1, 1 }, + { ahd_patch11_func, 476, 6, 2 }, + { ahd_patch0_func, 482, 1, 1 }, + { ahd_patch12_func, 505, 1, 1 }, + { ahd_patch13_func, 514, 1, 1 }, + { ahd_patch14_func, 515, 1, 2 }, + { ahd_patch0_func, 516, 1, 1 }, + { ahd_patch15_func, 519, 1, 1 }, + { ahd_patch14_func, 520, 1, 1 }, + { ahd_patch16_func, 531, 1, 2 }, + { ahd_patch0_func, 532, 1, 1 }, + { ahd_patch1_func, 551, 1, 2 }, + { ahd_patch0_func, 552, 1, 1 }, + { ahd_patch1_func, 555, 1, 2 }, + { ahd_patch0_func, 556, 1, 1 }, + { ahd_patch2_func, 561, 1, 2 }, + { ahd_patch0_func, 562, 1, 1 }, + { ahd_patch2_func, 566, 1, 2 }, + { ahd_patch0_func, 567, 1, 1 }, + { ahd_patch1_func, 568, 1, 2 }, + { ahd_patch0_func, 569, 1, 1 }, + { ahd_patch2_func, 580, 1, 2 }, + { ahd_patch0_func, 581, 1, 1 }, + { ahd_patch17_func, 585, 1, 1 }, + { ahd_patch18_func, 590, 1, 1 }, + { ahd_patch19_func, 591, 2, 1 }, + { ahd_patch18_func, 595, 1, 2 }, + { ahd_patch0_func, 596, 1, 1 }, + { ahd_patch2_func, 599, 1, 2 }, + { ahd_patch0_func, 600, 1, 1 }, + { ahd_patch2_func, 615, 1, 2 }, + { ahd_patch0_func, 616, 1, 1 }, + { ahd_patch20_func, 617, 14, 1 }, + { ahd_patch1_func, 635, 1, 2 }, + { ahd_patch0_func, 636, 1, 1 }, + { ahd_patch20_func, 637, 1, 1 }, + { ahd_patch1_func, 649, 1, 2 }, + { ahd_patch0_func, 650, 1, 1 }, + { ahd_patch1_func, 657, 1, 2 }, + { ahd_patch0_func, 658, 1, 1 }, + { ahd_patch17_func, 681, 1, 1 }, + { ahd_patch17_func, 719, 1, 1 }, + { ahd_patch1_func, 730, 1, 2 }, + { ahd_patch0_func, 731, 1, 1 }, + { ahd_patch1_func, 748, 1, 2 }, + { ahd_patch0_func, 749, 1, 1 }, + { ahd_patch1_func, 751, 1, 2 }, + { ahd_patch0_func, 752, 1, 1 }, + { ahd_patch1_func, 755, 1, 2 }, + { ahd_patch0_func, 756, 1, 1 }, + { ahd_patch21_func, 758, 1, 2 }, + { ahd_patch0_func, 759, 2, 1 }, + { ahd_patch22_func, 762, 4, 2 }, + { ahd_patch0_func, 766, 1, 1 }, + { ahd_patch22_func, 774, 11, 1 } +}; + +static struct cs { + uint16_t begin; + uint16_t end; +} critical_sections[] = { + { 11, 12 }, + { 13, 14 }, + { 29, 42 }, + { 56, 59 }, + { 101, 128 }, + { 129, 157 }, + { 159, 162 }, + { 170, 178 }, + { 201, 250 }, + { 681, 697 }, + { 697, 711 }, + { 721, 725 } +}; + +static const int num_critical_sections = sizeof(critical_sections) + / sizeof(*critical_sections); diff --git a/sys/dev/microcode/aic7xxx/aic7xxx.reg b/sys/dev/microcode/aic7xxx/aic7xxx.reg index 481cb99aca0..65007a9ae77 100644 --- a/sys/dev/microcode/aic7xxx/aic7xxx.reg +++ b/sys/dev/microcode/aic7xxx/aic7xxx.reg @@ -1,8 +1,9 @@ -/* $OpenBSD: aic7xxx.reg,v 1.6 2002/06/30 18:25:58 smurph Exp $ */ +/* $OpenBSD: aic7xxx.reg,v 1.7 2003/12/24 22:40:16 krw Exp $ */ /* * Aic7xxx register and scratch ram definitions. * - * Copyright (c) 1994-2001 Justin Gibbs. + * Copyright (c) 1994-2001 Justin T. Gibbs. + * Copyright (c) 2000-2001 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,28 +12,35 @@ * 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. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may 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 - * GNU Public License ("GPL"). + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. * - * 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 + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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. + * 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 DAMAGES. * - * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.39 2001/07/18 21:39:47 gibbs Exp $ + * $FreeBSD: /repoman/r/ncvs/src/sys/dev/aic7xxx/aic7xxx.reg,v 1.43 2003/01/20 20:44:55 gibbs Exp $ */ - -VERSION = "$Id: aic7xxx.reg,v 1.6 2002/06/30 18:25:58 smurph Exp $" +VERSION = "$NetBSD: aic7xxx.reg,v 1.2 2003/04/19 19:26:10 fvdl Exp $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -50,14 +58,14 @@ VERSION = "$Id: aic7xxx.reg,v 1.6 2002/06/30 18:25:58 smurph Exp $" 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 + field TEMODE 0x80 + field ENSELO 0x40 + field ENSELI 0x20 + field ENRSELI 0x10 + field ENAUTOATNO 0x08 + field ENAUTOATNI 0x04 + field ENAUTOATNP 0x02 + field SCSIRSTO 0x01 } /* @@ -67,13 +75,13 @@ register SCSISEQ { 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 + field DFON 0x80 + field DFPEXP 0x40 + field FAST20 0x20 + field CLRSTCNT 0x10 + field SPIOEN 0x08 + field SCAMEN 0x04 + field CLRCHN 0x02 } /* @@ -83,13 +91,13 @@ register SXFRCTL0 { register SXFRCTL1 { address 0x002 access_mode RW - bit BITBUCKET 0x80 - bit SWRAPEN 0x40 - bit ENSPCHK 0x20 + field BITBUCKET 0x80 + field SWRAPEN 0x40 + field ENSPCHK 0x20 mask STIMESEL 0x18 - bit ENSTIMER 0x04 - bit ACTNEGEN 0x02 - bit STPWEN 0x01 /* Powered Termination */ + field ENSTIMER 0x04 + field ACTNEGEN 0x02 + field STPWEN 0x01 /* Powered Termination */ } /* @@ -99,22 +107,22 @@ register SXFRCTL1 { 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 + field CDI 0x80 + field IOI 0x40 + field MSGI 0x20 + field ATNI 0x10 + field SELI 0x08 + field BSYI 0x04 + field REQI 0x02 + field ACKI 0x01 /* * Possible phases in SCSISIGI */ mask PHASE_MASK CDI|IOI|MSGI mask P_DATAOUT 0x00 mask P_DATAIN IOI - mask P_DATAOUT_DT P_DATAOUT|MSGI - mask P_DATAIN_DT P_DATAIN|MSGI + mask P_DATAOUT_DT P_DATAOUT|MSGI + mask P_DATAIN_DT P_DATAIN|MSGI mask P_COMMAND CDI mask P_MESGOUT CDI|MSGI mask P_STATUS CDI|IOI @@ -130,14 +138,14 @@ register SCSISIGI { 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 + field CDO 0x80 + field IOO 0x40 + field MSGO 0x20 + field ATNO 0x10 + field SELO 0x08 + field BSYO 0x04 + field REQO 0x02 + field ACKO 0x01 /* * Possible phases to write into SCSISIG0 */ @@ -160,9 +168,9 @@ register SCSISIGO { 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 */ + field WIDEXFER 0x80 /* Wide transfer control */ + field ENABLE_CRC 0x40 /* CRC for D-Phases */ + field SINGLE_EDGE 0x10 /* Disable DT Transfers */ mask SXFR 0x70 /* Sync transfer rate */ mask SXFR_ULTRA2 0x0f /* Sync transfer rate */ mask SOFS 0x0f /* Sync offset */ @@ -177,8 +185,8 @@ register SCSIID { address 0x005 access_mode RW mask TID 0xf0 /* Target ID mask */ - mask TWIN_TID 0x70 - bit TWIN_CHNLB 0x80 + mask TWIN_TID 0x70 + field TWIN_CHNLB 0x80 mask OID 0x0f /* Our ID mask */ /* * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book) @@ -218,18 +226,27 @@ register STCNT { access_mode RW } +/* ALT_MODE registers (Ultra2 and Ultra160 chips) */ +register SXFRCTL2 { + address 0x013 + access_mode RW + field AUTORSTDIS 0x10 + field CMDDMAEN 0x08 + mask ASYNC_SETUP 0x07 +} + /* 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 + field AUTORATEEN 0x80 + field AUTOACKEN 0x40 + field ATNMGMNTEN 0x20 + field BUSFREEREV 0x10 + field EXPPHASEDIS 0x08 + field SCSIDATL_IMGEN 0x04 + field AUTO_MSGOUT_DE 0x02 + field DIS_MSGIN_DUALEDGE 0x01 mask OPTIONMODE_DEFAULTS AUTO_MSGOUT_DE|DIS_MSGIN_DUALEDGE } @@ -247,12 +264,12 @@ register TARGCRCCNT { register CLRSINT0 { address 0x00b access_mode WO - bit CLRSELDO 0x40 - bit CLRSELDI 0x20 - bit CLRSELINGO 0x10 - bit CLRSWRAP 0x08 - bit CLRIOERR 0x08 /* Ultra2 Only */ - bit CLRSPIORDY 0x02 + field CLRSELDO 0x40 + field CLRSELDI 0x20 + field CLRSELINGO 0x10 + field CLRSWRAP 0x08 + field CLRIOERR 0x08 /* Ultra2 Only */ + field CLRSPIORDY 0x02 } /* @@ -263,15 +280,15 @@ register CLRSINT0 { 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 */ + field TARGET 0x80 /* Board acting as target */ + field SELDO 0x40 /* Selection Done */ + field SELDI 0x20 /* Board has been selected */ + field SELINGO 0x10 /* Selection In Progress */ + field SWRAP 0x08 /* 24bit counter wrap */ + field IOERR 0x08 /* LVD Tranceiver mode changed */ + field SDONE 0x04 /* STCNT = 0x000000 */ + field SPIORDY 0x02 /* SCSI PIO Ready */ + field DMADONE 0x01 /* DMA transfer completed */ } /* @@ -281,13 +298,13 @@ register SSTAT0 { 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 + field CLRSELTIMEO 0x80 + field CLRATNO 0x40 + field CLRSCSIRSTI 0x20 + field CLRBUSFREE 0x08 + field CLRSCSIPERR 0x04 + field CLRPHASECHG 0x02 + field CLRREQINIT 0x01 } /* @@ -296,14 +313,14 @@ register CLRSINT1 { 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 + field SELTO 0x80 + field ATNTARG 0x40 + field SCSIRSTI 0x20 + field PHASEMIS 0x10 + field BUSFREE 0x08 + field SCSIPERR 0x04 + field PHASECHG 0x02 + field REQINIT 0x01 } /* @@ -312,13 +329,13 @@ register SSTAT1 { register SSTAT2 { address 0x00d access_mode RO - bit OVERRUN 0x80 - bit SHVALID 0x40 /* Shaddow Layer non-zero */ - bit EXP_ACTIVE 0x10 /* SCSI Expander Active */ - bit CRCVALERR 0x08 /* CRC doesn't match (U3 only) */ - bit CRCENDERR 0x04 /* No terminal CRC packet (U3 only) */ - bit CRCREQERR 0x02 /* Illegal CRC packet req (U3 only) */ - bit DUAL_EDGE_ERR 0x01 /* Incorrect data phase (U3 only) */ + field OVERRUN 0x80 + field SHVALID 0x40 /* Shaddow Layer non-zero */ + field EXP_ACTIVE 0x10 /* SCSI Expander Active */ + field CRCVALERR 0x08 /* CRC doesn't match (U3 only) */ + field CRCENDERR 0x04 /* No terminal CRC packet (U3 only) */ + field CRCREQERR 0x02 /* Illegal CRC packet req (U3 only) */ + field DUAL_EDGE_ERR 0x01 /* Incorrect data phase (U3 only) */ mask SFCNT 0x1f } @@ -330,6 +347,7 @@ register SSTAT3 { access_mode RO mask SCSICNT 0xf0 mask OFFCNT 0x0f + mask U2OFFCNT 0x7f } /* @@ -350,14 +368,14 @@ register SCSIID_ULTRA2 { 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 + field ENSELDO 0x40 + field ENSELDI 0x20 + field ENSELINGO 0x10 + field ENSWRAP 0x08 + field ENIOERR 0x08 /* LVD Tranceiver mode changes */ + field ENSDONE 0x04 + field ENSPIORDY 0x02 + field ENDMADONE 0x01 } /* @@ -368,14 +386,14 @@ register SIMODE0 { 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 + field ENSELTIMO 0x80 + field ENATNTARG 0x40 + field ENSCSIRST 0x20 + field ENPHASEMIS 0x10 + field ENBUSFREE 0x08 + field ENSCSIPERR 0x04 + field ENPHASECHG 0x02 + field ENREQINIT 0x01 } /* @@ -384,12 +402,12 @@ register SIMODE1 { */ register SCSIBUSL { address 0x012 - access_mode RW + access_mode RW } register SCSIBUSH { address 0x013 - access_mode RW + access_mode RW } /* @@ -412,12 +430,12 @@ register SHADDR { 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 + field STAGE6 0x20 + field STAGE5 0x10 + field STAGE4 0x08 + field STAGE3 0x04 + field STAGE2 0x02 + field STAGE1 0x01 alias TARGIDIN } @@ -430,16 +448,16 @@ register SELID { address 0x019 access_mode RW mask SELID_MASK 0xf0 - bit ONEBIT 0x08 + field ONEBIT 0x08 } register SCAMCTL { address 0x01a access_mode RW - bit ENSCAMSELO 0x80 - bit CLRSCAMSELID 0x40 - bit ALTSTIM 0x20 - bit DFLTTID 0x10 + field ENSCAMSELO 0x80 + field CLRSCAMSELID 0x40 + field ALTSTIM 0x20 + field DFLTTID 0x10 mask SCAMLVL 0x03 } @@ -463,32 +481,32 @@ register TARGID { 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 */ + field SOFT1 0x80 + field SOFT0 0x40 + field SOFTCMDEN 0x20 + field EXT_BRDCTL 0x10 /* External Board control */ + field SEEPROM 0x08 /* External serial eeprom logic */ + field EEPROM 0x04 /* Writable external BIOS ROM */ + field ROM 0x02 /* Logic for accessing external ROM */ + field 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 + field BRDDAT7 0x80 + field BRDDAT6 0x40 + field BRDDAT5 0x20 + field BRDSTB 0x10 + field BRDCS 0x08 + field BRDRW 0x04 + field BRDCTL1 0x02 + field BRDCTL0 0x01 /* 7890 Definitions */ - bit BRDDAT4 0x10 - bit BRDDAT3 0x08 - bit BRDDAT2 0x04 - bit BRDRW_ULTRA2 0x02 - bit BRDSTB_ULTRA2 0x01 + field BRDDAT4 0x10 + field BRDDAT3 0x08 + field BRDDAT2 0x04 + field BRDRW_ULTRA2 0x02 + field BRDSTB_ULTRA2 0x01 } /* @@ -517,14 +535,14 @@ register BRDCTL { */ 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 + field EXTARBACK 0x80 + field EXTARBREQ 0x40 + field SEEMS 0x20 + field SEERDY 0x10 + field SEECS 0x08 + field SEECK 0x04 + field SEEDO 0x02 + field SEEDI 0x01 } /* * SCSI Block Control (p. 3-32) @@ -536,14 +554,14 @@ register SEECTL { 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 */ + field DIAGLEDEN 0x80 /* Aic78X0 only */ + field DIAGLEDON 0x40 /* Aic78X0 only */ + field AUTOFLUSHDIS 0x20 + field SELBUSB 0x08 + field ENAB40 0x08 /* LVD transceiver active */ + field ENAB20 0x04 /* SE/HVD transceiver active */ + field SELWIDE 0x02 + field XCVR 0x01 /* External transceiver active */ } /* @@ -553,14 +571,14 @@ register SBLKCTL { 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 + field PERRORDIS 0x80 + field PAUSEDIS 0x40 + field FAILDIS 0x20 + field FASTMODE 0x10 + field BRKADRINTEN 0x08 + field STEP 0x04 + field SEQRESET 0x02 + field LOADRAM 0x01 } /* @@ -632,8 +650,8 @@ register NONE { register FLAGS { address 0x06b access_mode RO - bit ZERO 0x02 - bit CARRY 0x01 + field ZERO 0x02 + field CARRY 0x01 } register SINDIR { @@ -656,14 +674,16 @@ register STACK { access_mode RO } +const STACK_SIZE 4 + /* * Board Control (p. 3-43) */ register BCTL { address 0x084 access_mode RW - bit ACE 0x08 - bit ENABLE 0x01 + field ACE 0x08 + field ENABLE 0x01 } /* @@ -673,23 +693,23 @@ register BCTL { 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 */ + field CACHETHEN 0x80 /* Cache Threshold enable */ + field DPARCKEN 0x40 /* Data Parity Check Enable */ + field MPARCKEN 0x20 /* Memory Parity Check Enable */ + field 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 */ + field INTSCBRAMSEL 0x08 /* Internal SCB RAM Select */ + field RAMPS 0x04 /* External SCB RAM Present */ + field USCBSIZE32 0x02 /* Use 32byte SCB Page Size */ + field CIOPARCKEN 0x01 /* Internal bus parity error enable */ } register DSCOMMAND1 { - address 0x085 - access_mode RW - mask DSLATT 0xfc /* PCI latency timer (non-ultra2) */ - bit HADDLDSEL1 0x02 /* Host Address Load Select Bits */ - bit HADDLDSEL0 0x01 + address 0x085 + access_mode RW + mask DSLATT 0xfc /* PCI latency timer (non-ultra2) */ + field HADDLDSEL1 0x02 /* Host Address Load Select Bits */ + field HADDLDSEL0 0x01 } /* @@ -712,7 +732,7 @@ register BUSSPD { mask STBOFF 0x38 mask STBON 0x07 mask DFTHRSH_100 0xc0 - mask DFTHRSH_75 0x80 + mask DFTHRSH_75 0x80 } /* aic7850/55/60/70/80/95 only */ @@ -726,7 +746,6 @@ register HS_MAILBOX { address 0x086 mask HOST_MAILBOX 0xF0 mask SEQ_MAILBOX 0x0F - mask HOST_REQ_INT 0x10 mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */ } @@ -740,13 +759,13 @@ const SEQ_MAILBOX_SHIFT 0 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 + field POWRDN 0x40 + field SWINT 0x10 + field IRQMS 0x08 + field PAUSE 0x04 + field INTEN 0x02 + field CHIPRST 0x01 + field CHIPRSTACK 0x01 } /* @@ -782,23 +801,23 @@ register SCBPTR { register INTSTAT { address 0x091 access_mode RW - bit BRKADRINT 0x08 - bit SCSIINT 0x04 - bit CMDCMPLT 0x02 - bit SEQINT 0x01 + field BRKADRINT 0x08 + field SCSIINT 0x04 + field CMDCMPLT 0x02 + field 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 PROTO_VIOLATION 0x20|SEQINT /* SCSI protocol violation */ mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */ - mask IGN_WIDE_RES 0x40|SEQINT /* Complex IGN Wide Res Msg */ - mask PDATA_REINIT 0x50|SEQINT /* - * Returned to data phase - * that requires data - * transfer pointers to be - * recalculated from the - * transfer residual. - */ - mask HOST_MSG_LOOP 0x60|SEQINT /* + mask IGN_WIDE_RES 0x40|SEQINT /* Complex IGN Wide Res Msg */ + mask PDATA_REINIT 0x50|SEQINT /* + * Returned to data phase + * that requires data + * transfer pointers to be + * recalculated from the + * transfer residual. + */ + mask HOST_MSG_LOOP 0x60|SEQINT /* * The bus is ready for the * host to perform another * message transaction. This @@ -807,37 +826,37 @@ register INTSTAT { * that require a kernel based * message state engine. */ - mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ - mask PERR_DETECTED 0x80|SEQINT /* + mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ + mask PERR_DETECTED 0x80|SEQINT /* * Either the phase_lock * or inb_next routine has * noticed a parity error. */ - mask DATA_OVERRUN 0x90|SEQINT /* + mask DATA_OVERRUN 0x90|SEQINT /* * Target attempted to write * beyond the bounds of its * command. - */ - mask MKMSG_FAILED 0xa0|SEQINT /* - * Target completed command - * without honoring our ATN - * request to issue a message. */ - mask MISSED_BUSFREE 0xb0|SEQINT /* - * The sequencer never saw - * the bus go free after - * either a command complete - * or disconnect message. - */ - mask SCB_MISMATCH 0xc0|SEQINT /* - * Downloaded SCB's tag does - * not match the entry we - * intended to download. - */ - mask NO_FREE_SCB 0xd0|SEQINT /* - * get_free_or_disc_scb failed. - */ - mask OUT_OF_RANGE 0xe0|SEQINT + mask MKMSG_FAILED 0xa0|SEQINT /* + * Target completed command + * without honoring our ATN + * request to issue a message. + */ + mask MISSED_BUSFREE 0xb0|SEQINT /* + * The sequencer never saw + * the bus go free after + * either a command complete + * or disconnect message. + */ + mask SCB_MISMATCH 0xc0|SEQINT /* + * Downloaded SCB's tag does + * not match the entry we + * intended to download. + */ + mask NO_FREE_SCB 0xd0|SEQINT /* + * get_free_or_disc_scb failed. + */ + mask OUT_OF_RANGE 0xe0|SEQINT mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */ mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT) @@ -851,14 +870,14 @@ register INTSTAT { 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 + field CIOPARERR 0x80 /* Ultra2 only */ + field PCIERRSTAT 0x40 /* PCI only */ + field MPARERR 0x20 /* PCI only */ + field DPARERR 0x10 /* PCI only */ + field SQPARERR 0x08 + field ILLOPCODE 0x04 + field ILLSADDR 0x02 + field ILLHADDR 0x01 } /* @@ -867,39 +886,39 @@ register ERROR { register CLRINT { address 0x092 access_mode WO - bit CLRPARERR 0x10 /* PCI only */ - bit CLRBRKADRINT 0x08 - bit CLRSCSIINT 0x04 - bit CLRCMDINT 0x02 - bit CLRSEQINT 0x01 + field CLRPARERR 0x10 /* PCI only */ + field CLRBRKADRINT 0x08 + field CLRSCSIINT 0x04 + field CLRCMDINT 0x02 + field 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 + field PRELOADEN 0x80 /* aic7890 only */ + field WIDEODD 0x40 + field SCSIEN 0x20 + field SDMAEN 0x10 + field SDMAENACK 0x10 + field HDMAEN 0x08 + field HDMAENACK 0x08 + field DIRECTION 0x04 + field FIFOFLUSH 0x02 + field FIFORESET 0x01 } register DFSTATUS { address 0x094 access_mode RO - bit PRELOAD_AVAIL 0x80 - bit DFCACHETH 0x40 - bit FIFOQWDEMP 0x20 - bit MREQPEND 0x10 - bit HDONE 0x08 - bit DFTHRESH 0x04 - bit FIFOFULL 0x02 - bit FIFOEMP 0x01 + field PRELOAD_AVAIL 0x80 + field DFCACHETH 0x40 + field FIFOQWDEMP 0x20 + field MREQPEND 0x10 + field HDONE 0x08 + field DFTHRESH 0x04 + field FIFOFULL 0x02 + field FIFOEMP 0x01 } register DFWADDR { @@ -925,7 +944,7 @@ register DFDAT { register SCBCNT { address 0x09a access_mode RW - bit SCBAUTO 0x80 + field SCBAUTO 0x80 mask SCBCNT_MASK 0x1f } @@ -959,12 +978,12 @@ register QOUTFIFO { 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 + field CRCONSEEN 0x80 + field CRCVALCHKEN 0x40 + field CRCENDCHKEN 0x20 + field CRCREQCHKEN 0x10 + field TARGCRCENDEN 0x08 + field TARGCRCCNTEN 0x04 } @@ -980,13 +999,13 @@ register QOUTCNT { 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 - mask DATA_PHASE_MASK 0x03 + field STATUS_PHASE 0x20 + field COMMAND_PHASE 0x10 + field MSG_IN_PHASE 0x08 + field MSG_OUT_PHASE 0x04 + field DATA_IN_PHASE 0x02 + field DATA_OUT_PHASE 0x01 + mask DATA_PHASE_MASK 0x03 } /* @@ -995,7 +1014,7 @@ register SCSIPHASE { register SFUNCT { address 0x09f access_mode RW - bit ALT_MODE 0x80 + field ALT_MODE 0x80 } /* @@ -1004,64 +1023,71 @@ register SFUNCT { scb { address 0x0a0 size 64 - SCB_CDB_PTR { - size 4 - alias SCB_RESIDUAL_DATACNT - alias SCB_CDB_STORE - alias SCB_TARGET_INFO + + SCB_CDB_PTR { + size 4 + alias SCB_RESIDUAL_DATACNT + alias SCB_CDB_STORE } - SCB_RESIDUAL_SGPTR { + SCB_RESIDUAL_SGPTR { size 4 } - SCB_SCSI_STATUS { + SCB_SCSI_STATUS { size 1 } - SCB_CDB_STORE_PAD { - size 3 + SCB_TARGET_PHASES { + size 1 + } + SCB_TARGET_DATA_DIR { + size 1 + } + SCB_TARGET_ITAG { + size 1 } SCB_DATAPTR { size 4 } SCB_DATACNT { /* - * The last byte is really the high address bits for - * the data address. + * The last byte is really the high address bits for + * the data address. */ size 4 - bit SG_LAST_SEG 0x80 /* In the fourth byte */ - mask SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ + field SG_LAST_SEG 0x80 /* In the fourth byte */ + mask SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ } - SCB_SGPTR { + SCB_SGPTR { size 4 - bit SG_RESID_VALID 0x04 /* In the first byte */ - bit SG_FULL_RESID 0x02 /* In the first byte */ - bit SG_LIST_NULL 0x01 /* In the first byte */ - } - 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 + field SG_RESID_VALID 0x04 /* In the first byte */ + field SG_FULL_RESID 0x02 /* In the first byte */ + field SG_LIST_NULL 0x01 /* In the first byte */ + } + SCB_CONTROL { + size 1 + field TARGET_SCB 0x80 + field STATUS_RCVD 0x80 + field DISCENB 0x40 + field TAG_ENB 0x20 + field MK_MESSAGE 0x10 + field ULTRAENB 0x08 + field DISCONNECTED 0x04 + mask SCB_TAG_TYPE 0x03 } - SCB_SCSIID { - size 1 - bit TWIN_CHNLB 0x80 - mask TWIN_TID 0x70 - mask TID 0xf0 - mask OID 0x0f - } - SCB_LUN { - mask LID 0xff + SCB_SCSIID { + size 1 + field TWIN_CHNLB 0x80 + mask TWIN_TID 0x70 + mask TID 0xf0 + mask OID 0x0f + } + SCB_LUN { + mask LID 0xff size 1 } SCB_TAG { size 1 } - SCB_CDB_LEN { + SCB_CDB_LEN { size 1 } SCB_SCSIRATE { @@ -1070,20 +1096,20 @@ scb { SCB_SCSIOFFSET { size 1 } - SCB_NEXT { - size 1 + SCB_NEXT { + size 1 } - SCB_64_SPARE { + SCB_64_SPARE { size 16 } - SCB_64_BTT { - size 16 + SCB_64_BTT { + size 16 } } -const SCB_UPLOAD_SIZE 32 -const SCB_DOWNLOAD_SIZE 32 -const SCB_DOWNLOAD_SIZE_64 48 +const SCB_UPLOAD_SIZE 32 +const SCB_DOWNLOAD_SIZE 32 +const SCB_DOWNLOAD_SIZE_64 48 const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ @@ -1092,18 +1118,18 @@ const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ register SEECTL_2840 { address 0x0c0 access_mode RW - bit CS_2840 0x04 - bit CK_2840 0x02 - bit DO_2840 0x01 + field CS_2840 0x04 + field CK_2840 0x02 + field DO_2840 0x01 } register STATUS_2840 { address 0x0c1 access_mode RW - bit EEPROM_TF 0x80 + field EEPROM_TF 0x80 mask BIOS_SEL 0x60 mask ADSEL 0x1e - bit DI_2840 0x01 + field DI_2840 0x01 } /* --------------------- AIC-7870-only definitions -------------------- */ @@ -1127,10 +1153,10 @@ register CCSGADDR { register CCSGCTL { address 0x0EB - bit CCSGDONE 0x80 - bit CCSGEN 0x08 - bit SG_FETCH_NEEDED 0x02 /* Bit used for software state */ - bit CCSGRESET 0x01 + field CCSGDONE 0x80 + field CCSGEN 0x08 + field SG_FETCH_NEEDED 0x02 /* Bit used for software state */ + field CCSGRESET 0x01 } register CCSCBCNT { @@ -1139,12 +1165,12 @@ register CCSCBCNT { 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 + field CCSCBDONE 0x80 + field ARRDONE 0x40 /* SCB Array prefetch done */ + field CCARREN 0x10 + field CCSCBEN 0x08 + field CCSCBDIR 0x04 + field CCSCBRESET 0x01 } register CCSCBADDR { @@ -1181,9 +1207,9 @@ register SDSCB_QOFF { register QOFF_CTLSTA { address 0x0FA - bit SCB_AVAIL 0x40 - bit SNSCB_ROLLOVER 0x20 - bit SDSCB_ROLLOVER 0x10 + field SCB_AVAIL 0x40 + field SNSCB_ROLLOVER 0x20 + field SDSCB_ROLLOVER 0x10 mask SCB_QSIZE 0x07 mask SCB_QSIZE_256 0x06 } @@ -1211,21 +1237,21 @@ register DFF_THRSH { } register SG_CACHE_PRE { - access_mode WO + access_mode WO address 0x0fc - mask SG_ADDR_MASK 0xf8 - bit ODD_SEG 0x04 - bit LAST_SEG 0x02 - bit LAST_SEG_DONE 0x01 + mask SG_ADDR_MASK 0xf8 + field ODD_SEG 0x04 + field LAST_SEG 0x02 + field LAST_SEG_DONE 0x01 } register SG_CACHE_SHADOW { - access_mode RO - address 0x0fc - mask SG_ADDR_MASK 0xf8 - bit ODD_SEG 0x04 - bit LAST_SEG 0x02 - bit LAST_SEG_DONE 0x01 + access_mode RO + address 0x0fc + mask SG_ADDR_MASK 0xf8 + field ODD_SEG 0x04 + field LAST_SEG 0x02 + field LAST_SEG_DONE 0x01 } /* ---------------------- Scratch RAM Offsets ------------------------- */ /* These offsets are either to values that are initialized by the board's @@ -1249,45 +1275,46 @@ scratch_ram { /* * 1 byte per target starting at this address for configuration values */ - BUSY_TARGETS { - alias TARG_SCSIRATE + BUSY_TARGETS { + alias TARG_SCSIRATE size 16 } /* - * Bit vector of targets that have ULTRA enabled as set by - * the BIOS. The Sequencer relies on a per-SCB field to - * control whether to enable Ultra transfers or not. During - * initialization, we read this field and reuse it for 2 - * entries in the busy target table. + * Bit vector of targets that have ULTRA enabled as set by + * the BIOS. The Sequencer relies on a per-SCB field to + * control whether to enable Ultra transfers or not. During + * initialization, we read this field and reuse it for 2 + * entries in the busy target table. */ ULTRA_ENB { - alias CMDSIZE_TABLE + alias CMDSIZE_TABLE size 2 } /* - * Bit vector of targets that have disconnection disabled as set by - * the BIOS. The Sequencer relies in a per-SCB field to control the - * disconnect priveldge. During initialization, we read this field - * and reuse it for 2 entries in the busy target table. + * Bit vector of targets that have disconnection disabled as set by + * the BIOS. The Sequencer relies in a per-SCB field to control the + * disconnect priveldge. During initialization, we read this field + * and reuse it for 2 entries in the busy target table. */ DISC_DSB { size 2 - } - CMDSIZE_TABLE_TAIL { - size 4 - } - /* - * Partial transfer past cacheline end to be - * transferred using an extra S/G. - */ - MWI_RESIDUAL { - size 1 - } - /* - * SCBID of the next SCB to be started by the controller. - */ - NEXT_QUEUED_SCB { - size 1 + } + CMDSIZE_TABLE_TAIL { + size 4 + } + /* + * Partial transfer past cacheline end to be + * transferred using an extra S/G. + */ + MWI_RESIDUAL { + size 1 + alias TARG_IMMEDIATE_SCB + } + /* + * SCBID of the next SCB to be started by the controller. + */ + NEXT_QUEUED_SCB { + size 1 } /* * Single byte buffer used to designate the type or message @@ -1299,38 +1326,39 @@ scratch_ram { /* 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 /* Set indicates PCI->SCSI */ - bit FIFOFLUSH 0x02 - bit FIFORESET 0x01 + field PRELOADEN 0x80 + field WIDEODD 0x40 + field SCSIEN 0x20 + field SDMAEN 0x10 + field SDMAENACK 0x10 + field HDMAEN 0x08 + field HDMAENACK 0x08 + field DIRECTION 0x04 /* Set indicates PCI->SCSI */ + field FIFOFLUSH 0x02 + field FIFORESET 0x01 } SEQ_FLAGS { size 1 - bit IDENTIFY_SEEN 0x80 - bit TARGET_CMD_IS_TAGGED 0x40 - bit DPHASE 0x20 + field NOT_IDENTIFIED 0x80 + field NO_CDB_SENT 0x40 + field TARGET_CMD_IS_TAGGED 0x40 + field 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 + field TARG_CMD_PENDING 0x10 + field CMDPHASE_PENDING 0x08 + field DPHASE_PENDING 0x04 + field SPHASE_PENDING 0x02 + field NO_DISCONNECT 0x01 } /* * Temporary storage for the * target/channel/lun of a * reconnecting target */ - SAVED_SCSIID { + SAVED_SCSIID { size 1 } - SAVED_LUN { + SAVED_LUN { size 1 } /* @@ -1338,9 +1366,9 @@ scratch_ram { */ LASTPHASE { size 1 - bit CDI 0x80 - bit IOI 0x40 - bit MSGI 0x20 + field CDI 0x80 + field IOI 0x40 + field MSGI 0x20 mask PHASE_MASK CDI|IOI|MSGI mask P_DATAOUT 0x00 mask P_DATAIN IOI @@ -1373,25 +1401,25 @@ scratch_ram { size 1 } /* - * head of list of SCBs that have - * completed but have not been - * put into the qoutfifo. + * head of list of SCBs that have + * completed but have not been + * put into the qoutfifo. */ - COMPLETE_SCBH { - size 1 + COMPLETE_SCBH { + size 1 } /* - * Address of the hardware scb array in the host. + * Address of the hardware scb array in the host. */ - HSCB_ADDR { + HSCB_ADDR { size 4 } /* - * Base address of our shared data with the kernel driver in host - * memory. This includes the qoutfifo and target mode - * incoming command queue. + * Base address of our shared data with the kernel driver in host + * memory. This includes the qoutfifo and target mode + * incoming command queue. */ - SHARED_DATA_ADDR { + SHARED_DATA_ADDR { size 4 } KERNEL_QINPOS { @@ -1444,12 +1472,12 @@ scratch_ram { */ SCSISEQ_TEMPLATE { size 1 - bit ENSELO 0x40 - bit ENSELI 0x20 - bit ENRSELI 0x10 - bit ENAUTOATNO 0x08 - bit ENAUTOATNI 0x04 - bit ENAUTOATNP 0x02 + field ENSELO 0x40 + field ENSELI 0x20 + field ENRSELI 0x10 + field ENAUTOATNO 0x08 + field ENAUTOATNI 0x04 + field ENAUTOATNP 0x02 } /* @@ -1459,41 +1487,58 @@ scratch_ram { DATA_COUNT_ODD { size 1 } +} + +scratch_ram { + address 0x056 + size 4 + /* + * These scratch ram locations are initialized by the 274X BIOS. + * We reuse them after capturing the BIOS settings during + * initialization. + */ /* * The initiator specified tag for this target mode transaction. */ - INITIATOR_TAG { - size 1 + HA_274_BIOSGLOBAL { + size 1 + field HA_274_EXTENDED_TRANS 0x01 + alias INITIATOR_TAG } - SEQ_FLAGS2 { - size 1 - bit SCB_DMA 0x01 - } + SEQ_FLAGS2 { + size 1 + field SCB_DMA 0x01 + field TARGET_MSG_PENDING 0x02 + } } scratch_ram { address 0x05a size 6 /* - * 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. + * These are reserved registers in the card's scratch ram on the 2742. + * The EISA configuraiton chip is mapped here. On Rev E. of the + * aic7770, the sequencer can use this area for scratch, but the + * host cannot directly access these registers. On later chips, this + * area can be read and written by both the host and the sequencer. + * Even on later chips, many of these locations are initialized by + * the BIOS. */ SCSICONF { size 1 - bit TERM_ENB 0x80 - bit RESET_SCSI 0x40 - bit ENSPCHK 0x20 + field TERM_ENB 0x80 + field RESET_SCSI 0x40 + field ENSPCHK 0x20 mask HSCSIID 0x07 /* our SCSI ID */ mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ - } - INTDEF { - address 0x05c - size 1 - bit EDGE_TRIG 0x80 - mask VECTOR 0x0f + } + INTDEF { + address 0x05c + size 1 + field EDGE_TRIG 0x80 + mask VECTOR 0x0f } HOSTCONF { address 0x05d @@ -1504,7 +1549,7 @@ scratch_ram { size 1 mask BIOSMODE 0x30 mask BIOSDISABLED 0x30 - bit CHANNEL_B_PRIMARY 0x08 + field CHANNEL_B_PRIMARY 0x08 } } @@ -1520,7 +1565,7 @@ scratch_ram { } } -const TID_SHIFT 4 +const TID_SHIFT 4 const SCB_LIST_NULL 0xff const TARGET_CMD_CMPLT 0xfe @@ -1536,18 +1581,15 @@ const BUS_32_BIT 0x02 const MAX_OFFSET_8BIT 0x0f const MAX_OFFSET_16BIT 0x08 const MAX_OFFSET_ULTRA2 0x7f +const MAX_OFFSET 0xff const HOST_MSG 0xff /* Target mode command processing constants */ const CMD_GROUP_CODE_SHIFT 0x05 const STATUS_BUSY 0x08 -const STATUS_QUEUE_FULL 0x28 -const SCB_TARGET_PHASES 0 -const SCB_TARGET_DATA_DIR 1 -const SCB_TARGET_STATUS 2 -const SCB_INITIATOR_TAG 3 -const TARGET_DATA_IN 1 +const STATUS_QUEUE_FULL 0x28 +const TARGET_DATA_IN 1 /* * Downloaded (kernel inserted) constants diff --git a/sys/dev/microcode/aic7xxx/aic7xxx.seq b/sys/dev/microcode/aic7xxx/aic7xxx.seq index b8122d7ad5d..b42d25c26d4 100644 --- a/sys/dev/microcode/aic7xxx/aic7xxx.seq +++ b/sys/dev/microcode/aic7xxx/aic7xxx.seq @@ -1,8 +1,9 @@ -/* $OpenBSD: aic7xxx.seq,v 1.13 2002/07/05 05:41:03 smurph Exp $ */ +/* $OpenBSD: aic7xxx.seq,v 1.14 2003/12/24 22:40:16 krw Exp $ */ /* * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. * - * Copyright (c) 1994-2001 Justin Gibbs. + * Copyright (c) 1994-2001 Justin T. Gibbs. + * Copyright (c) 2000-2001 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,29 +12,38 @@ * 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. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may 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 - * GNU Public License ("GPL"). + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. * - * 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 + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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. + * 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 DAMAGES. * - * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.119 2001/08/05 22:20:12 gibbs Exp $ + * $FreeBSD: /repoman/r/ncvs/src/sys/dev/aic7xxx/aic7xxx.seq,v 1.123 2003/01/20 20:44:55 gibbs Exp $ */ -VERSION = "$Id: aic7xxx.seq,v 1.13 2002/07/05 05:41:03 smurph Exp $" +VERSION = "$NetBSD: aic7xxx.seq,v 1.15 2003/05/03 18:11:31 wiz Exp $" PATCH_ARG_LIST = "struct ahc_softc *ahc" +PREFIX = "ahc_" #include <dev/microcode/aic7xxx/aic7xxx.reg> #include <scsi/scsi_message.h> @@ -57,121 +67,121 @@ PATCH_ARG_LIST = "struct ahc_softc *ahc" */ bus_free_sel: - /* - * Turn off the selection hardware. We need to reset the - * selection request in order to perform a new selection. - */ - and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; - and SIMODE1, ~ENBUSFREE; + /* + * Turn off the selection hardware. We need to reset the + * selection request in order to perform a new selection. + */ + and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP; + and SIMODE1, ~ENBUSFREE; poll_for_work: call clear_target_state; and SXFRCTL0, ~SPIOEN; - if ((ahc->features & AHC_ULTRA2) != 0) { - clr SCSIBUSL; - } - test SCSISEQ, ENSELO jnz poll_for_selection; - if ((ahc->features & AHC_TWIN) != 0) { - xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ - test SCSISEQ, ENSELO jnz poll_for_selection; - } - cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; + if ((ahc->features & AHC_ULTRA2) != 0) { + clr SCSIBUSL; + } + test SCSISEQ, ENSELO jnz poll_for_selection; + if ((ahc->features & AHC_TWIN) != 0) { + xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ + test SCSISEQ, ENSELO jnz poll_for_selection; + } + cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; poll_for_work_loop: if ((ahc->features & AHC_TWIN) != 0) { xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ - } - test SSTAT0, SELDO|SELDI jnz selection; + } + test SSTAT0, SELDO|SELDI jnz selection; test_queue: /* Has the driver posted any work for us? */ BEGIN_CRITICAL; if ((ahc->features & AHC_QUEUE_REGS) != 0) { test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; } else { - mov A, QINPOS; + mov A, QINPOS; cmp KERNEL_QINPOS, A je poll_for_work_loop; } - mov ARG_1, NEXT_QUEUED_SCB; + mov ARG_1, NEXT_QUEUED_SCB; - /* - * We have at least one queued SCB now and we don't have any - * SCBs in the list of SCBs awaiting selection. Allocate a - * card SCB for the host's SCB and get to work on it. - */ + /* + * We have at least one queued SCB now and we don't have any + * SCBs in the list of SCBs awaiting selection. Allocate a + * card SCB for the host's SCB and get to work on it. + */ if ((ahc->flags & AHC_PAGESCBS) != 0) { mov ALLZEROS call get_free_or_disc_scb; - } else { + } else { /* In the non-paging case, the SCBID == hardware SCB index */ - mov SCBPTR, ARG_1; + mov SCBPTR, ARG_1; } - or SEQ_FLAGS2, SCB_DMA; + or SEQ_FLAGS2, SCB_DMA; END_CRITICAL; dma_queued_scb: - /* - * DMA the SCB from host ram into the current SCB location. - */ + /* + * DMA the SCB from host ram into the current SCB location. + */ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov ARG_1 call dma_scb; - /* - * Check one last time to see if this SCB was canceled - * before we completed the DMA operation. If it was, - * the QINFIFO next pointer will not match our saved - * value. - */ - mov A, ARG_1; + mov ARG_1 call dma_scb; + /* + * Check one last time to see if this SCB was canceled + * before we completed the DMA operation. If it was, + * the QINFIFO next pointer will not match our saved + * value. + */ + mov A, ARG_1; BEGIN_CRITICAL; - cmp NEXT_QUEUED_SCB, A jne abort_qinscb; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - cmp SCB_TAG, A je . + 2; - mvi SCB_MISMATCH call set_seqint; + cmp NEXT_QUEUED_SCB, A jne abort_qinscb; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + cmp SCB_TAG, A je . + 2; + mvi SCB_MISMATCH call set_seqint; } - mov NEXT_QUEUED_SCB, SCB_NEXT; + mov NEXT_QUEUED_SCB, SCB_NEXT; mov SCB_NEXT,WAITING_SCBH; mov WAITING_SCBH, SCBPTR; - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - mov NONE, SNSCB_QOFF; - } else { - inc QINPOS; - } - and SEQ_FLAGS2, ~SCB_DMA; + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + mov NONE, SNSCB_QOFF; + } else { + inc QINPOS; + } + and SEQ_FLAGS2, ~SCB_DMA; END_CRITICAL; start_waiting: /* - * Start the first entry on the waiting SCB list. + * Start the first entry on the waiting SCB list. */ mov SCBPTR, WAITING_SCBH; call start_selection; poll_for_selection: - /* - * Twin channel devices cannot handle things like SELTO - * interrupts on the "background" channel. So, while - * selecting, keep polling the current channel until - * either a selection or reselection occurs. - */ - test SSTAT0, SELDO|SELDI jz poll_for_selection; + /* + * Twin channel devices cannot handle things like SELTO + * interrupts on the "background" channel. So, while + * selecting, keep polling the current channel until + * either a selection or reselection occurs. + */ + test SSTAT0, SELDO|SELDI jz poll_for_selection; selection: - /* - * We aren't expecting a bus free, so interrupt - * the kernel driver if it happens. - */ - mvi CLRSINT1,CLRBUSFREE; - if ((ahc->features & AHC_DT) == 0) { - or SIMODE1, ENBUSFREE; - } - - /* - * Guard against a bus free after (re)selection - * but prior to enabling the busfree interrupt. SELDI - * and SELDO will be cleared in that case. - */ - test SSTAT0, SELDI|SELDO jz bus_free_sel; + /* + * We aren't expecting a bus free, so interrupt + * the kernel driver if it happens. + */ + mvi CLRSINT1,CLRBUSFREE; + if ((ahc->features & AHC_DT) == 0) { + or SIMODE1, ENBUSFREE; + } + + /* + * Guard against a bus free after (re)selection + * but prior to enabling the busfree interrupt. SELDI + * and SELDO will be cleared in that case. + */ + test SSTAT0, SELDI|SELDO jz bus_free_sel; test SSTAT0,SELDO jnz select_out; select_in: - if ((ahc->flags & AHC_TARGETROLE) != 0) { - if ((ahc->flags & AHC_INITIATORROLE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { + if ((ahc->flags & AHC_INITIATORROLE) != 0) { test SSTAT0, TARGET jz initiator_reselect; } - mvi CLRSINT0, CLRSELDI; + mvi CLRSINT0, CLRSELDI; /* * We've just been selected. Assert BSY and @@ -184,45 +194,45 @@ select_in: * Setup the DMA for sending the identify and * command information. */ - or SEQ_FLAGS, CMDPHASE_PENDING; + mvi SEQ_FLAGS, CMDPHASE_PENDING; mov A, TQINPOS; if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; - mvi SHARED_DATA_ADDR call set_32byte_addr; + mvi SHARED_DATA_ADDR call set_32byte_addr; mvi CCSCBCTL, CCSCBRESET; } else { mvi DINDEX, HADDR; - mvi SHARED_DATA_ADDR call set_32byte_addr; + mvi SHARED_DATA_ADDR call set_32byte_addr; mvi DFCNTRL, FIFORESET; } /* Initiator that selected us */ - and SAVED_SCSIID, SELID_MASK, SELID; + and SAVED_SCSIID, SELID_MASK, SELID; /* The Target ID we were selected at */ - if ((ahc->features & AHC_MULTI_TID) != 0) { - and A, OID, TARGIDIN; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - and A, OID, SCSIID_ULTRA2; - } else { - and A, OID, SCSIID; - } - or SAVED_SCSIID, A; - if ((ahc->features & AHC_TWIN) != 0) { - test SBLKCTL, SELBUSB jz . + 2; - or SAVED_SCSIID, TWIN_CHNLB; - } - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mov CCSCBRAM, SAVED_SCSIID; + if ((ahc->features & AHC_MULTI_TID) != 0) { + and A, OID, TARGIDIN; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + and A, OID, SCSIID_ULTRA2; } else { - mov DFDAT, SAVED_SCSIID; - } + and A, OID, SCSIID; + } + or SAVED_SCSIID, A; + if ((ahc->features & AHC_TWIN) != 0) { + test SBLKCTL, SELBUSB jz . + 2; + or SAVED_SCSIID, TWIN_CHNLB; + } + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, SAVED_SCSIID; + } else { + mov DFDAT, SAVED_SCSIID; + } /* * If ATN isn't asserted, the target isn't interested * in talking to us. Go directly to bus free. - * XXX SCSI-1 may require us to assume lun 0 if - * ATN is false. + * XXX SCSI-1 may require us to assume lun 0 if + * ATN is false. */ test SCSISIGI, ATNI jz target_busfree; @@ -244,6 +254,7 @@ select_in: } else { mov DFDAT, DINDEX; } + and SAVED_LUN, MSG_IDENTIFY_LUNMASK, DINDEX; /* Remember for disconnection decision */ test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; @@ -259,9 +270,10 @@ select_in: * < MSG_IGN_WIDE_RESIDUE. */ add A, -MSG_SIMPLE_Q_TAG, DINDEX; - jnc ident_messages_done; + jnc ident_messages_done_msg_pending; add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; - jc ident_messages_done; + jc ident_messages_done_msg_pending; + /* Store for host */ if ((ahc->features & AHC_CMD_CHAN) != 0) { mov CCSCBRAM, DINDEX; @@ -286,10 +298,24 @@ select_in: mov DFDAT, DINDEX; } mov INITIATOR_TAG, DINDEX; - or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; - test SCSISIGI, ATNI jz . + 2; - /* Initiator still wants to give us messages */ - call target_inb; + or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; + +ident_messages_done: + /* 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; + test SEQ_FLAGS2, TARGET_MSG_PENDING + jnz target_mesgout_pending; + test SCSISIGI, ATNI jnz target_mesgout_continue; + jmp target_ITloop; + + +ident_messages_done_msg_pending: + or SEQ_FLAGS2, TARGET_MSG_PENDING; jmp ident_messages_done; /* @@ -297,36 +323,11 @@ select_in: * run it's own target mode message state engine. */ host_target_message_loop: - mvi HOST_MSG_LOOP call set_seqint; + mvi HOST_MSG_LOOP call set_seqint; 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 */ - if ((ahc->features & AHC_HS_MAILBOX) != 0) { - and A, HOST_TQINPOS, HS_MAILBOX; - } else { - mov A, KERNEL_TQINPOS; - } - cmp TQINPOS, A jne tqinfifo_has_space; - mvi P_STATUS|BSYO call change_phase; - test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 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; - jmp target_ITloop; - } + } if ((ahc->flags & AHC_INITIATORROLE) != 0) { /* @@ -334,84 +335,77 @@ if ((ahc->flags & AHC_INITIATORROLE) != 0) { * reselected, but haven't seen an IDENTIFY message from the target yet. */ initiator_reselect: - /* XXX test for and handle ONE BIT condition */ - test SELID, ONEBIT jnz await_busfree; - - or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; - and SAVED_SCSIID, SELID_MASK, SELID; - if ((ahc->features & AHC_ULTRA2) != 0) { - and A, OID, SCSIID_ULTRA2; - } else { - and A, OID, SCSIID; - } - or SAVED_SCSIID, A; - if ((ahc->features & AHC_TWIN) != 0) { - test SBLKCTL, SELBUSB jz . + 2; - or SAVED_SCSIID, TWIN_CHNLB; - } - mvi CLRSINT0, CLRSELDI; - jmp ITloop; + /* XXX test for and handle ONE BIT condition */ + or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; + and SAVED_SCSIID, SELID_MASK, SELID; + if ((ahc->features & AHC_ULTRA2) != 0) { + and A, OID, SCSIID_ULTRA2; + } else { + and A, OID, SCSIID; + } + or SAVED_SCSIID, A; + if ((ahc->features & AHC_TWIN) != 0) { + test SBLKCTL, SELBUSB jz . + 2; + or SAVED_SCSIID, TWIN_CHNLB; + } + mvi CLRSINT0, CLRSELDI; + jmp ITloop; } abort_qinscb: - call add_scb_to_free_list; - jmp poll_for_work_loop; + call add_scb_to_free_list; + jmp poll_for_work_loop; start_selection: - /* - * If bus reset interrupts have been disabled (from a previous - * reset), re-enable them now. Resets are only of interest - * when we have outstanding transactions, so we can safely - * defer re-enabling the interrupt until, as an initiator, - * we start sending out transactions again. - */ - test SIMODE1, ENSCSIRST jnz . + 3; - mvi CLRSINT1, CLRSCSIRSTI; - or SIMODE1, ENSCSIRST; - if ((ahc->features & AHC_TWIN) != 0) { - and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ - test SCB_SCSIID, TWIN_CHNLB jz . + 2; - or SINDEX, SELBUSB; - mov SBLKCTL,SINDEX; /* select channel */ - } + /* + * If bus reset interrupts have been disabled (from a previous + * reset), re-enable them now. Resets are only of interest + * when we have outstanding transactions, so we can safely + * defer re-enabling the interrupt until, as an initiator, + * we start sending out transactions again. + */ + test SIMODE1, ENSCSIRST jnz . + 3; + mvi CLRSINT1, CLRSCSIRSTI; + or SIMODE1, ENSCSIRST; + if ((ahc->features & AHC_TWIN) != 0) { + and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ + test SCB_SCSIID, TWIN_CHNLB jz . + 2; + or SINDEX, SELBUSB; + mov SBLKCTL,SINDEX; /* select channel */ + } initialize_scsiid: - if ((ahc->features & AHC_ULTRA2) != 0) { - mov SCSIID_ULTRA2, SCB_SCSIID; - } else if ((ahc->features & AHC_TWIN) != 0) { - and SCSIID, TWIN_TID|OID, SCB_SCSIID; - } else { - mov SCSIID, SCB_SCSIID; - } - if ((ahc->flags & AHC_TARGETROLE) != 0) { - mov SINDEX, SCSISEQ_TEMPLATE; - test SCB_CONTROL, TARGET_SCB jz . + 2; - or SINDEX, TEMODE; - mov SCSISEQ, SINDEX ret; - } else { - mov SCSISEQ, SCSISEQ_TEMPLATE ret; - } + if ((ahc->features & AHC_ULTRA2) != 0) { + mov SCSIID_ULTRA2, SCB_SCSIID; + } else if ((ahc->features & AHC_TWIN) != 0) { + and SCSIID, TWIN_TID|OID, SCB_SCSIID; + } else { + mov SCSIID, SCB_SCSIID; + } + if ((ahc->flags & AHC_TARGETROLE) != 0) { + mov SINDEX, SCSISEQ_TEMPLATE; + test SCB_CONTROL, TARGET_SCB jz . + 2; + or SINDEX, TEMODE; + mov SCSISEQ, SINDEX ret; + } else { + mov SCSISEQ, SCSISEQ_TEMPLATE 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 transfer settings with SCB provided settings. */ -initialize_channel: - or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; set_transfer_settings: - if ((ahc->features & AHC_ULTRA) != 0) { - test SCB_CONTROL, ULTRAENB jz . + 2; - or SXFRCTL0, FAST20; - } - /* - * Initialize SCSIRATE with the appropriate value for this target. - */ - if ((ahc->features & AHC_ULTRA2) != 0) { - bmov SCSIRATE, SCB_SCSIRATE, 2 ret; - } else { - mov SCSIRATE, SCB_SCSIRATE ret; - } + if ((ahc->features & AHC_ULTRA) != 0) { + test SCB_CONTROL, ULTRAENB jz . + 2; + or SXFRCTL0, FAST20; + } + /* + * Initialize SCSIRATE with the appropriate value for this target. + */ + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov SCSIRATE, SCB_SCSIRATE, 2 ret; + } else { + mov SCSIRATE, SCB_SCSIRATE ret; + } if ((ahc->flags & AHC_TARGETROLE) != 0) { /* @@ -420,16 +414,16 @@ if ((ahc->flags & AHC_TARGETROLE) != 0) { * 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; + /* + * 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; } /* @@ -441,26 +435,34 @@ target_inb: select_out: /* Turn off the selection hardware */ and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; - mvi CLRSINT0, CLRSELDO; mov SCBPTR, WAITING_SCBH; mov WAITING_SCBH,SCB_NEXT; - mov SAVED_SCSIID, SCB_SCSIID; - mov SAVED_LUN, SCB_LUN; - call initialize_channel; - if ((ahc->flags & AHC_TARGETROLE) != 0) { + mov SAVED_SCSIID, SCB_SCSIID; + mov SAVED_LUN, SCB_LUN; + call set_transfer_settings; + if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz initiator_select; + or SXFRCTL0, CLRSTCNT|CLRCHN; + + /* + * Put tag in connonical location since not + * all connections have an SCB. + */ + mov INITIATOR_TAG, SCB_TARGET_ITAG; + /* * 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 CLRSINT0, CLRSELDO; /* * Start out with a simple identify message. */ - or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; + or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; /* * If we are the result of a tagged command, send @@ -468,17 +470,17 @@ select_out: */ test SCB_CONTROL, TAG_ENB jz . + 3; mvi MSG_SIMPLE_Q_TAG call target_outb; - mov SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb; + mov SCB_TARGET_ITAG call target_outb; target_synccmd: /* * Now determine what phases the host wants us * to go through. */ - mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; + mov SEQ_FLAGS, SCB_TARGET_PHASES; - test SCB_CONTROL, MK_MESSAGE jz target_ITloop; - mvi P_MESGIN|BSYO call change_phase; - jmp host_target_message_loop; + test SCB_CONTROL, MK_MESSAGE jz target_ITloop; + mvi P_MESGIN|BSYO call change_phase; + jmp host_target_message_loop; target_ITloop: /* * Start honoring ATN signals now that @@ -494,14 +496,16 @@ target_ITloop: * on the state of NO_DISCONNECT. */ test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; - mov RETURN_1, ALLZEROS; - call complete_target_cmd; - cmp RETURN_1, CONT_MSG_LOOP jne .; + mvi TARG_IMMEDIATE_SCB, SCB_LIST_NULL; + call complete_target_cmd; if ((ahc->flags & AHC_PAGESCBS) != 0) { mov ALLZEROS call get_free_or_disc_scb; } + cmp TARG_IMMEDIATE_SCB, SCB_LIST_NULL je .; mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov SCB_TAG call dma_scb; + mov TARG_IMMEDIATE_SCB call dma_scb; + call set_transfer_settings; + or SXFRCTL0, CLRSTCNT|CLRCHN; jmp target_synccmd; target_mesgout: @@ -509,6 +513,7 @@ target_mesgout: target_mesgout_continue: call target_inb; target_mesgout_pending: + and SEQ_FLAGS2, ~TARGET_MSG_PENDING; /* Local Processing goes here... */ jmp host_target_message_loop; @@ -519,19 +524,37 @@ target_disconnect: mvi MSG_DISCONNECT call target_outb; target_busfree_wait: - /* Wait for preceding I/O session to complete. */ + /* Wait for preceding I/O session to complete. */ test SCSISIGI, ACKI jnz .; target_busfree: - and SIMODE1, ~ENBUSFREE; - if ((ahc->features & AHC_ULTRA2) != 0) { - clr SCSIBUSL; - } + and SIMODE1, ~ENBUSFREE; + if ((ahc->features & AHC_ULTRA2) != 0) { + clr SCSIBUSL; + } clr SCSISIGO; mvi LASTPHASE, P_BUSFREE; call complete_target_cmd; jmp poll_for_work; target_cmdphase: + /* + * The target has dropped ATN (doesn't want to abort or BDR) + * and we believe this selection to be valid. If the ring + * buffer for new commands is full, return busy or queue full. + */ + if ((ahc->features & AHC_HS_MAILBOX) != 0) { + and A, HOST_TQINPOS, HS_MAILBOX; + } else { + mov A, KERNEL_TQINPOS; + } + cmp TQINPOS, A jne tqinfifo_has_space; + mvi P_STATUS|BSYO call change_phase; + test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 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: mvi P_COMMAND|BSYO call change_phase; call target_inb; mov A, DINDEX; @@ -551,11 +574,11 @@ target_cmdphase: * the first byte. */ shr A, CMD_GROUP_CODE_SHIFT; - add SINDEX, CMDSIZE_TABLE, A; + add SINDEX, CMDSIZE_TABLE, A; mov A, SINDIR; test A, 0xFF jz command_phase_done; - or SXFRCTL0, SPIOEN; + or SXFRCTL0, SPIOEN; command_loop: test SSTAT0, SPIORDY jz .; cmp A, 1 jne . + 2; @@ -574,21 +597,20 @@ command_phase_done: target_dphase: /* - * Data phases on the bus are from the - * perspective of the initiator. The dma - * code looks at LASTPHASE to determine the - * data direction of the DMA. Toggle it for - * target transfers. + * Data phases on the bus are from the + * perspective of the initiator. The DMA + * code looks at LASTPHASE to determine the + * data direction of the DMA. Toggle it for + * target transfers. */ - xor LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR]; - or SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO - call change_phase; + xor LASTPHASE, IOI, SCB_TARGET_DATA_DIR; + or SCB_TARGET_DATA_DIR, BSYO call change_phase; jmp p_data; target_sphase: mvi P_STATUS|BSYO call change_phase; mvi LASTPHASE, P_STATUS; - mov SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb; + mov SCB_SCSI_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 */ @@ -611,7 +633,7 @@ complete_target_cmd: or DFCNTRL, FIFORESET; mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ mov DFDAT, ALLONES; - mvi 28 call set_hcnt; + mvi 28 call set_hcnt; or DFCNTRL, HDMAEN|FIFOFLUSH; call dma_finish; } @@ -621,13 +643,15 @@ complete_target_cmd: if ((ahc->flags & AHC_INITIATORROLE) != 0) { initiator_select: + or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; /* * 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; + mvi SEQ_FLAGS, NO_CDB_SENT; + mvi CLRSINT0, CLRSELDO; /* * Main loop for information transfer phases. Wait for the @@ -646,19 +670,19 @@ ITloop: cmp A,P_STATUS je p_status; cmp A,P_MESGIN je p_mesgin; - mvi BAD_PHASE call set_seqint; + mvi BAD_PHASE call set_seqint; jmp ITloop; /* Try reading the bus again. */ await_busfree: and SIMODE1, ~ENBUSFREE; mov NONE, SCSIDATL; /* Ack the last byte */ - if ((ahc->features & AHC_ULTRA2) != 0) { - clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ - } + if ((ahc->features & AHC_ULTRA2) != 0) { + clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ + } and SXFRCTL0, ~SPIOEN; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz poll_for_work; - mvi MISSED_BUSFREE call set_seqint; + mvi MISSED_BUSFREE call set_seqint; } clear_target_state: @@ -668,7 +692,7 @@ clear_target_state: * clear DFCNTRL too. */ clr DFCNTRL; - or SXFRCTL0, CLRSTCNT|CLRCHN; + or SXFRCTL0, CLRSTCNT|CLRCHN; /* * We don't know the target we will connect to, @@ -679,89 +703,89 @@ clear_target_state: bmov SCSIRATE, ALLZEROS, 2; } else { clr SCSIRATE; - if ((ahc->features & AHC_ULTRA) != 0) { - and SXFRCTL0, ~(FAST20); - } + if ((ahc->features & AHC_ULTRA) != 0) { + and SXFRCTL0, ~(FAST20); + } } mvi LASTPHASE, P_BUSFREE; /* clear target specific flags */ - clr SEQ_FLAGS ret; + mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret; sg_advance: - clr A; /* add sizeof(struct scatter) */ - add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; - adc SCB_RESIDUAL_SGPTR[1],A; - adc SCB_RESIDUAL_SGPTR[2],A; - adc SCB_RESIDUAL_SGPTR[3],A ret; + clr A; /* add sizeof(struct scatter) */ + add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; + adc SCB_RESIDUAL_SGPTR[1],A; + adc SCB_RESIDUAL_SGPTR[2],A; + adc SCB_RESIDUAL_SGPTR[3],A ret; if ((ahc->features & AHC_CMD_CHAN) != 0) { disable_ccsgen: - test CCSGCTL, CCSGEN jz return; - test CCSGCTL, CCSGDONE jz .; + test CCSGCTL, CCSGEN jz return; + test CCSGCTL, CCSGDONE jz .; disable_ccsgen_fetch_done: - clr CCSGCTL; - test CCSGCTL, CCSGEN jnz .; - ret; + clr CCSGCTL; + test CCSGCTL, CCSGEN jnz .; + ret; idle_loop: - /* - * Do we need any more segments for this transfer? - */ - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; - - /* Did we just finish fetching segs? */ - cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; - - /* Are we actively fetching segments? */ - test CCSGCTL, CCSGEN jnz return; - - /* - * Do we have any prefetch left??? - */ - cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; - - /* - * Need to fetch segments, but we can only do that - * if the command channel is completely idle. Make - * sure we don't have an SCB prefetch going on. - */ - test CCSCBCTL, CCSCBEN jnz return; - - /* - * We fetch a "cacheline aligned" and sized amount of data - * so we don't end up referencing a non-existant page. - * Cacheline aligned is in quotes because the kernel will - * set the prefetch amount to a reasonable level if the - * cacheline size is unknown. - */ - mvi CCHCNT, SG_PREFETCH_CNT; - and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; - bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; - mvi CCSGCTL, CCSGEN|CCSGRESET ret; + /* + * Do we need any more segments for this transfer? + */ + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; + + /* Did we just finish fetching segs? */ + cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; + + /* Are we actively fetching segments? */ + test CCSGCTL, CCSGEN jnz return; + + /* + * Do we have any prefetch left??? + */ + cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; + + /* + * Need to fetch segments, but we can only do that + * if the command channel is completely idle. Make + * sure we don't have an SCB prefetch going on. + */ + test CCSCBCTL, CCSCBEN jnz return; + + /* + * We fetch a "cacheline aligned" and sized amount of data + * so we don't end up referencing a non-existant page. + * Cacheline aligned is in quotes because the kernel will + * set the prefetch amount to a reasonable level if the + * cacheline size is unknown. + */ + mvi CCHCNT, SG_PREFETCH_CNT; + and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; + bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; + mvi CCSGCTL, CCSGEN|CCSGRESET ret; idle_sgfetch_complete: - call disable_ccsgen_fetch_done; - and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; + call disable_ccsgen_fetch_done; + and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; idle_sg_avail: if ((ahc->features & AHC_ULTRA2) != 0) { - /* Does the hardware have space for another SG entry? */ - test DFSTATUS, PRELOAD_AVAIL jz return; - bmov HADDR, CCSGRAM, 7; - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; - bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; - } - call sg_advance; - mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or SINDEX, ODD_SEG; - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; - or SINDEX, LAST_SEG; - mov SG_CACHE_PRE, SINDEX; - /* Load the segment */ - or DFCNTRL, PRELOADEN; - } - ret; + /* Does the hardware have space for another SG entry? */ + test DFSTATUS, PRELOAD_AVAIL jz return; + bmov HADDR, CCSGRAM, 7; + test HCNT[0], 0x1 jz . + 2; + xor DATA_COUNT_ODD, 0x1; + bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; + } + call sg_advance; + mov SINDEX, SCB_RESIDUAL_SGPTR[0]; + test DATA_COUNT_ODD, 0x1 jz . + 2; + or SINDEX, ODD_SEG; + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; + or SINDEX, LAST_SEG; + mov SG_CACHE_PRE, SINDEX; + /* Load the segment */ + or DFCNTRL, PRELOADEN; + } + ret; } if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { @@ -771,37 +795,37 @@ if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { * XXX Can we optimize this for PCI writes only??? */ calc_mwi_residual: - /* - * If the ending address is on a cacheline boundary, - * there is no need for an extra segment. - */ - mov A, HCNT[0]; - add A, A, HADDR[0]; - and A, CACHESIZE_MASK; - test A, 0xFF jz return; - - /* - * If the transfer is less than a cachline, - * there is no need for an extra segment. - */ - test HCNT[1], 0xFF jnz calc_mwi_residual_final; - test HCNT[2], 0xFF jnz calc_mwi_residual_final; - add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; - jnc return; + /* + * If the ending address is on a cacheline boundary, + * there is no need for an extra segment. + */ + mov A, HCNT[0]; + add A, A, HADDR[0]; + and A, CACHESIZE_MASK; + test A, 0xFF jz return; + + /* + * If the transfer is less than a cachline, + * there is no need for an extra segment. + */ + test HCNT[1], 0xFF jnz calc_mwi_residual_final; + test HCNT[2], 0xFF jnz calc_mwi_residual_final; + add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; + jnc return; calc_mwi_residual_final: - mov MWI_RESIDUAL, A; - not A; - inc A; - add HCNT[0], A; - adc HCNT[1], -1; - adc HCNT[2], -1 ret; + mov MWI_RESIDUAL, A; + not A; + inc A; + add HCNT[0], A; + adc HCNT[1], -1; + adc HCNT[2], -1 ret; } p_data: - test SEQ_FLAGS,IDENTIFY_SEEN jnz p_data_okay; - mvi NO_IDENT jmp set_seqint; -p_data_okay: + test SEQ_FLAGS,NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed; + mvi PROTO_VIOLATION call set_seqint; +p_data_allowed: if ((ahc->features & AHC_ULTRA2) != 0) { mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; } else { @@ -810,412 +834,412 @@ p_data_okay: test LASTPHASE, IOI jnz . + 2; or DMAPARAMS, DIRECTION; if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* We don't have any valid S/G elements */ - mvi CCSGADDR, SG_PREFETCH_CNT; + /* We don't have any valid S/G elements */ + mvi CCSGADDR, SG_PREFETCH_CNT; } - test SEQ_FLAGS, DPHASE jz data_phase_initialize; + test SEQ_FLAGS, DPHASE jz data_phase_initialize; - /* - * If we re-enter the data phase after going through another - * phase, our transfer location has almost certainly been - * corrupted by the interveining, non-data, transfers. Ask - * the host driver to fix us up based on the transfer residual. - */ - mvi PDATA_REINIT call set_seqint; - jmp data_phase_loop; + /* + * If we re-enter the data phase after going through another + * phase, our transfer location has almost certainly been + * corrupted by the interveining, non-data, transfers. Ask + * the host driver to fix us up based on the transfer residual. + */ + mvi PDATA_REINIT call set_seqint; + jmp data_phase_loop; data_phase_initialize: - /* We have seen a data phase for the first time */ + /* We have seen a data phase for the first time */ or SEQ_FLAGS, DPHASE; /* * Initialize the DMA address and counter from the SCB. - * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG - * flag in the highest byte of the data count. We cannot - * modify the saved values in the SCB until we see a save - * data pointers message. + * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG + * flag in the highest byte of the data count. We cannot + * modify the saved values in the SCB until we see a save + * data pointers message. */ - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - /* The lowest address byte must be loaded last. */ - mov SCB_DATACNT[3] call set_hhaddr; - } + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + /* The lowest address byte must be loaded last. */ + mov SCB_DATACNT[3] call set_hhaddr; + } if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov HADDR, SCB_DATAPTR, 7; - bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; + bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; } else { mvi DINDEX, HADDR; mvi SCB_DATAPTR call bcopy_7; - mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; - mvi SCB_DATACNT + 3 call bcopy_5; + mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; + mvi SCB_DATACNT + 3 call bcopy_5; + } + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { + call calc_mwi_residual; } - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { - call calc_mwi_residual; - } - and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; - and DATA_COUNT_ODD, 0x1, HCNT[0]; + and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; + and DATA_COUNT_ODD, 0x1, HCNT[0]; if ((ahc->features & AHC_ULTRA2) == 0) { if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov STCNT, HCNT, 3; } else { call set_stcnt_from_hcnt; - } + } } data_phase_loop: - /* Guard against overruns */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; - - /* - * Turn on `Bit Bucket' mode, wait until the target takes - * us to another phase, and then notify the host. - */ - and DMAPARAMS, DIRECTION; - mov DFCNTRL, DMAPARAMS; + /* Guard against overruns */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; + + /* + * Turn on `Bit Bucket' mode, wait until the target takes + * us to another phase, and then notify the host. + */ + and DMAPARAMS, DIRECTION; + mov DFCNTRL, DMAPARAMS; or SXFRCTL1,BITBUCKET; - if ((ahc->features & AHC_DT) == 0) { - test SSTAT1,PHASEMIS jz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz .; } else { - test SCSIPHASE, DATA_PHASE_MASK jnz .; + test SCSIPHASE, DATA_PHASE_MASK jnz .; } - and SXFRCTL1, ~BITBUCKET; - mvi DATA_OVERRUN call set_seqint; - jmp ITloop; + and SXFRCTL1, ~BITBUCKET; + mvi DATA_OVERRUN call set_seqint; + jmp ITloop; data_phase_inbounds: if ((ahc->features & AHC_ULTRA2) != 0) { - mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; - or SINDEX, LAST_SEG; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or SINDEX, ODD_SEG; - mov SG_CACHE_PRE, SINDEX; - mov DFCNTRL, DMAPARAMS; + mov SINDEX, SCB_RESIDUAL_SGPTR[0]; + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; + or SINDEX, LAST_SEG; + test DATA_COUNT_ODD, 0x1 jz . + 2; + or SINDEX, ODD_SEG; + mov SG_CACHE_PRE, SINDEX; + mov DFCNTRL, DMAPARAMS; ultra2_dma_loop: - call idle_loop; - /* - * The transfer is complete if either the last segment - * completes or the target changes phase. - */ - test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; - if ((ahc->features & AHC_DT) == 0) { - if ((ahc->flags & AHC_TARGETROLE) != 0) { - /* - * As a target, we control the phases, - * so ignore PHASEMIS. - */ - test SSTAT0, TARGET jnz ultra2_dma_loop; - } - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT1,PHASEMIS jz ultra2_dma_loop; - } - } else { - test DFCNTRL, SCSIEN jnz ultra2_dma_loop; - } + call idle_loop; + /* + * The transfer is complete if either the last segment + * completes or the target changes phase. + */ + test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { + /* + * As a target, we control the phases, + * so ignore PHASEMIS. + */ + test SSTAT0, TARGET jnz ultra2_dma_loop; + } + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT1,PHASEMIS jz ultra2_dma_loop; + } + } else { + test DFCNTRL, SCSIEN jnz ultra2_dma_loop; + } ultra2_dmafinish: - /* - * The transfer has terminated either due to a phase - * change, and/or the completion of the last segment. - * We have two goals here. Do as much other work - * as possible while the data fifo drains on a read - * and respond as quickly as possible to the standard - * messages (save data pointers/disconnect and command - * complete) that usually follow a data phase. - */ - if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { - /* - * On chips with broken auto-flush, start - * the flushing process now. We'll poke - * the chip from time to time to keep the - * flush process going as we complete the - * data phase. - */ - or DFCNTRL, FIFOFLUSH; - } - /* - * We assume that, even though data may still be - * transferring to the host, that the SCSI side of - * the DMA engine is now in a static state. This - * allows us to update our notion of where we are - * in this transfer. - * - * If, by chance, we stopped before being able - * to fetch additional segments for this transfer, - * yet the last S/G was completely exhausted, - * call our idle loop until it is able to load - * another segment. This will allow us to immediately - * pickup on the next segment on the next data phase. - * - * If we happened to stop on the last segment, then - * our residual information is still correct from - * the idle loop and there is no need to perform - * any fixups. - */ + /* + * The transfer has terminated either due to a phase + * change, and/or the completion of the last segment. + * We have two goals here. Do as much other work + * as possible while the data fifo drains on a read + * and respond as quickly as possible to the standard + * messages (save data pointers/disconnect and command + * complete) that usually follow a data phase. + */ + if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { + /* + * On chips with broken auto-flush, start + * the flushing process now. We'll poke + * the chip from time to time to keep the + * flush process going as we complete the + * data phase. + */ + or DFCNTRL, FIFOFLUSH; + } + /* + * We assume that, even though data may still be + * transferring to the host, that the SCSI side of + * the DMA engine is now in a static state. This + * allows us to update our notion of where we are + * in this transfer. + * + * If, by chance, we stopped before being able + * to fetch additional segments for this transfer, + * yet the last S/G was completely exhausted, + * call our idle loop until it is able to load + * another segment. This will allow us to immediately + * pickup on the next segment on the next data phase. + * + * If we happened to stop on the last segment, then + * our residual information is still correct from + * the idle loop and there is no need to perform + * any fixups. + */ ultra2_ensure_sg: - test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; - /* Record if we've consumed all S/G entries */ - test SSTAT2, SHVALID jnz residuals_correct; - or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; - jmp residuals_correct; + test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; + /* Record if we've consumed all S/G entries */ + test SSTAT2, SHVALID jnz residuals_correct; + or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; + jmp residuals_correct; ultra2_shvalid: - test SSTAT2, SHVALID jnz sgptr_fixup; - call idle_loop; - jmp ultra2_ensure_sg; + test SSTAT2, SHVALID jnz sgptr_fixup; + call idle_loop; + jmp ultra2_ensure_sg; sgptr_fixup: - /* - * Fixup the residual next S/G pointer. The S/G preload - * feature of the chip allows us to load two elements - * in addition to the currently active element. We - * store the bottom byte of the next S/G pointer in - * the SG_CACEPTR register so we can restore the - * correct value when the DMA completes. If the next - * sg ptr value has advanced to the point where higher - * bytes in the address have been affected, fix them - * too. - */ - test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; - test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; - add SCB_RESIDUAL_SGPTR[1], -1; - adc SCB_RESIDUAL_SGPTR[2], -1; - adc SCB_RESIDUAL_SGPTR[3], -1; + /* + * Fixup the residual next S/G pointer. The S/G preload + * feature of the chip allows us to load two elements + * in addition to the currently active element. We + * store the bottom byte of the next S/G pointer in + * the SG_CACEPTR register so we can restore the + * correct value when the DMA completes. If the next + * sg ptr value has advanced to the point where higher + * bytes in the address have been affected, fix them + * too. + */ + test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; + test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; + add SCB_RESIDUAL_SGPTR[1], -1; + adc SCB_RESIDUAL_SGPTR[2], -1; + adc SCB_RESIDUAL_SGPTR[3], -1; sgptr_fixup_done: - and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; - clr DATA_COUNT_ODD; - test SG_CACHE_SHADOW, ODD_SEG jz . + 2; - or DATA_COUNT_ODD, 0x1; - clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ + and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; + clr DATA_COUNT_ODD; + test SG_CACHE_SHADOW, ODD_SEG jz . + 2; + or DATA_COUNT_ODD, 0x1; + clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ residuals_correct: - /* - * Go ahead and shut down the DMA engine now. - * In the future, we'll want to handle end of - * transfer messages prior to doing this, but this - * requires similar restructuring for pre-ULTRA2 - * controllers. - */ - test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; + /* + * Go ahead and shut down the DMA engine now. + * In the future, we'll want to handle end of + * transfer messages prior to doing this, but this + * requires similar restructuring for pre-ULTRA2 + * controllers. + */ + test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; ultra2_fifoflush: - if ((ahc->features & AHC_DT) == 0) { - if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { - /* - * On Rev A of the aic7890, the autoflush - * feature doesn't function correctly. - * Perform an explicit manual flush. During - * a manual flush, the FIFOEMP bit becomes - * true every time the PCI FIFO empties - * regardless of the state of the SCSI FIFO. - * It can take up to 4 clock cycles for the - * SCSI FIFO to get data into the PCI FIFO - * and for FIFOEMP to de-assert. Here we - * guard against this condition by making - * sure the FIFOEMP bit stays on for 5 full - * clock cycles. - */ - or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - } - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - } else { - /* - * We enable the auto-ack feature on DT capable - * controllers. This means that the controller may - * have already transferred some overrun bytes into - * the data FIFO and acked them on the bus. The only - * way to detect this situation is to wait for - * LAST_SEG_DONE to come true on a completed transfer - * and then test to see if the data FIFO is non-empty. - */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4; - test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; - test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; - /* Overrun */ - jmp data_phase_loop; - test DFSTATUS, FIFOEMP jz .; - } + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { + /* + * On Rev A of the aic7890, the autoflush + * feature doesn't function correctly. + * Perform an explicit manual flush. During + * a manual flush, the FIFOEMP bit becomes + * true every time the PCI FIFO empties + * regardless of the state of the SCSI FIFO. + * It can take up to 4 clock cycles for the + * SCSI FIFO to get data into the PCI FIFO + * and for FIFOEMP to de-assert. Here we + * guard against this condition by making + * sure the FIFOEMP bit stays on for 5 full + * clock cycles. + */ + or DFCNTRL, FIFOFLUSH; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } else { + /* + * We enable the auto-ack feature on DT capable + * controllers. This means that the controller may + * have already transferred some overrun bytes into + * the data FIFO and acked them on the bus. The only + * way to detect this situation is to wait for + * LAST_SEG_DONE to come true on a completed transfer + * and then test to see if the data FIFO is non-empty. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; + /* Overrun */ + jmp data_phase_loop; + test DFSTATUS, FIFOEMP jz .; + } ultra2_fifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz ultra2_fifoempty; + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz ultra2_fifoempty; ultra2_dmahalt: - and DFCNTRL, ~(SCSIEN|HDMAEN); - test DFCNTRL, SCSIEN|HDMAEN jnz .; - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - /* - * Keep HHADDR cleared for future, 32bit addressed - * only, DMA operations. - * - * Due to bayonette style S/G handling, our residual - * data must be "fixed up" once the transfer is halted. - * Here we fixup the HSHADDR stored in the high byte - * of the residual data cnt. By postponing the fixup, - * we can batch the clearing of HADDR with the fixup. - * If we halted on the last segment, the residual is - * already correct. If we are not on the last - * segment, copy the high address directly from HSHADDR. - * We don't need to worry about maintaining the - * SG_LAST_SEG flag as it will always be false in the - * case where an update is required. - */ - or DSCOMMAND1, HADDLDSEL0; - test SG_CACHE_SHADOW, LAST_SEG jnz . + 2; - mov SCB_RESIDUAL_DATACNT[3], SHADDR; - clr HADDR; - and DSCOMMAND1, ~HADDLDSEL0; - } + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, SCSIEN|HDMAEN jnz .; + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + /* + * Keep HHADDR cleared for future, 32bit addressed + * only, DMA operations. + * + * Due to bayonette style S/G handling, our residual + * data must be "fixed up" once the transfer is halted. + * Here we fixup the HSHADDR stored in the high byte + * of the residual data cnt. By postponing the fixup, + * we can batch the clearing of HADDR with the fixup. + * If we halted on the last segment, the residual is + * already correct. If we are not on the last + * segment, copy the high address directly from HSHADDR. + * We don't need to worry about maintaining the + * SG_LAST_SEG flag as it will always be false in the + * case where an update is required. + */ + or DSCOMMAND1, HADDLDSEL0; + test SG_CACHE_SHADOW, LAST_SEG jnz . + 2; + mov SCB_RESIDUAL_DATACNT[3], SHADDR; + clr HADDR; + and DSCOMMAND1, ~HADDLDSEL0; + } } else { - /* If we are the last SG block, tell the hardware. */ - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 - && ahc->pci_cachesize != 0) { - test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; - } - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; - if ((ahc->flags & AHC_TARGETROLE) != 0) { - test SSTAT0, TARGET jz dma_last_sg; - if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { - test DMAPARAMS, DIRECTION jz dma_mid_sg; - } + /* If we are the last SG block, tell the hardware. */ + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 + && ahc->pci_cachesize != 0) { + test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; + } + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; + if ((ahc->flags & AHC_TARGETROLE) != 0) { + test SSTAT0, TARGET jz dma_last_sg; + if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { + test DMAPARAMS, DIRECTION jz dma_mid_sg; + } } dma_last_sg: and DMAPARAMS, ~WIDEODD; dma_mid_sg: - /* Start DMA data transfer. */ + /* Start DMA data transfer. */ mov DFCNTRL, DMAPARAMS; dma_loop: - if ((ahc->features & AHC_CMD_CHAN) != 0) { - call idle_loop; - } - test SSTAT0,DMADONE jnz dma_dmadone; - test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + call idle_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 the target changes the phase (in light of this, - * it makes sense that the DMA circuitry doesn't ACK when - * PHASEMIS is active). If we are doing a SCSI->Host transfer, - * the data FIFO should be flushed auto-magically on STCNT=0 - * or a phase change, so just wait for FIFO empty status. - */ + /* + * We will be "done" DMAing when the transfer count goes to + * zero, or the target changes the phase (in light of this, + * it makes sense that the DMA circuitry doesn't ACK when + * PHASEMIS is active). If we are doing a SCSI->Host transfer, + * the data FIFO should be flushed auto-magically on STCNT=0 + * or a phase change, so just wait for FIFO empty status. + */ dma_checkfifo: - test DFCNTRL,DIRECTION jnz dma_fifoempty; + test DFCNTRL,DIRECTION jnz dma_fifoempty; dma_fifoflush: - test DFSTATUS,FIFOEMP jz 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 off the DMA and make sure that the DMA - * hardware has actually stopped. Touching the DMA - * counters, etc. while a DMA is active will result - * in an ILLSADDR exception. - */ + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz dma_fifoempty; + + /* + * Now shut off the DMA and make sure that the DMA + * hardware has actually stopped. Touching the DMA + * counters, etc. while a DMA is active will result + * in an ILLSADDR exception. + */ dma_dmadone: - and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); + and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); dma_halt: - /* - * Some revisions of the aic78XX 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 drain - * the prefetched but unused data from the data fifo until - * there is space for the input latch to drain. - */ - if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { - mov NONE, DFDAT; - } - test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; - - /* See if we have completed this last 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 - */ - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 - && ahc->pci_cachesize != 0) { - test MWI_RESIDUAL, 0xFF jz no_mwi_resid; - /* - * Reload HADDR from SHADDR and setup the - * count to be the size of our residual. - */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov HADDR, SHADDR, 4; - mov HCNT, MWI_RESIDUAL; - bmov HCNT[1], ALLZEROS, 2; - } else { - mvi DINDEX, HADDR; - mvi SHADDR call bcopy_4; - mov MWI_RESIDUAL call set_hcnt; - } - clr MWI_RESIDUAL; - jmp sg_load_done; + /* + * Some revisions of the aic78XX 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 drain + * the prefetched but unused data from the data fifo until + * there is space for the input latch to drain. + */ + if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { + mov NONE, DFDAT; + } + test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; + + /* See if we have completed this last 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 + */ + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 + && ahc->pci_cachesize != 0) { + test MWI_RESIDUAL, 0xFF jz no_mwi_resid; + /* + * Reload HADDR from SHADDR and setup the + * count to be the size of our residual. + */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov HADDR, SHADDR, 4; + mov HCNT, MWI_RESIDUAL; + bmov HCNT[1], ALLZEROS, 2; + } else { + mvi DINDEX, HADDR; + mvi SHADDR call bcopy_4; + mov MWI_RESIDUAL call set_hcnt; + } + clr MWI_RESIDUAL; + jmp sg_load_done; no_mwi_resid: - } - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; - or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; - jmp data_phase_finish; + } + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; + or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; + jmp data_phase_finish; sg_load: /* - * Load the next SG element's data address and length - * into the DMA engine. If we don't have hardware - * to perform a prefetch, we'll have to fetch the - * segment from host memory first. + * Load the next SG element's data address and length + * into the DMA engine. If we don't have hardware + * to perform a prefetch, we'll have to fetch the + * segment from host memory first. */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* Wait for the idle loop to complete */ - test CCSGCTL, CCSGEN jz . + 3; - call idle_loop; - test CCSGCTL, CCSGEN jnz . - 1; - bmov HADDR, CCSGRAM, 7; - /* - * Workaround for flaky external SCB RAM - * on certain aic7895 setups. It seems - * unable to handle direct transfers from - * S/G ram to certain SCB locations. - */ - mov SINDEX, CCSGRAM; - mov SCB_RESIDUAL_DATACNT[3], SINDEX; - } else { - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - mov ALLZEROS call set_hhaddr; - } - mvi DINDEX, HADDR; - mvi SCB_RESIDUAL_SGPTR call bcopy_4; - - mvi SG_SIZEOF call set_hcnt; - - or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - - call dma_finish; - - mvi DINDEX, HADDR; - call dfdat_in_7; - mov SCB_RESIDUAL_DATACNT[3], DFDAT; - } - - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; - - /* - * The lowest address byte must be loaded - * last as it triggers the computation of - * some items in the PCI block. The ULTRA2 - * chips do this on PRELOAD. - */ - mov HADDR, HADDR; - } - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 - && ahc->pci_cachesize != 0) { - call calc_mwi_residual; - } - - /* Point to the new next sg in memory */ - call sg_advance; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Wait for the idle loop to complete */ + test CCSGCTL, CCSGEN jz . + 3; + call idle_loop; + test CCSGCTL, CCSGEN jnz . - 1; + bmov HADDR, CCSGRAM, 7; + /* + * Workaround for flaky external SCB RAM + * on certain aic7895 setups. It seems + * unable to handle direct transfers from + * S/G ram to certain SCB locations. + */ + mov SINDEX, CCSGRAM; + mov SCB_RESIDUAL_DATACNT[3], SINDEX; + } else { + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + mov ALLZEROS call set_hhaddr; + } + mvi DINDEX, HADDR; + mvi SCB_RESIDUAL_SGPTR call bcopy_4; + + mvi SG_SIZEOF call set_hcnt; + + or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; + + call dma_finish; + + mvi DINDEX, HADDR; + call dfdat_in_7; + mov SCB_RESIDUAL_DATACNT[3], DFDAT; + } + + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; + + /* + * The lowest address byte must be loaded + * last as it triggers the computation of + * some items in the PCI block. The ULTRA2 + * chips do this on PRELOAD. + */ + mov HADDR, HADDR; + } + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 + && ahc->pci_cachesize != 0) { + call calc_mwi_residual; + } + + /* Point to the new next sg in memory */ + call sg_advance; sg_load_done: if ((ahc->features & AHC_CMD_CHAN) != 0) { @@ -1223,112 +1247,121 @@ sg_load_done: } else { call set_stcnt_from_hcnt; } - /* Track odd'ness */ - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; + /* Track odd'ness */ + test HCNT[0], 0x1 jz . + 2; + xor DATA_COUNT_ODD, 0x1; - if ((ahc->flags & AHC_TARGETROLE) != 0) { - test SSTAT0, TARGET jnz data_phase_loop; - } + if ((ahc->flags & AHC_TARGETROLE) != 0) { + test SSTAT0, TARGET jnz data_phase_loop; + } } data_phase_finish: - /* - * If the target has left us in data phase, loop through - * the dma code again. In the case of ULTRA2 adapters, - * we should only loop if there is a data overrun. For - * all other adapters, we'll loop after each S/G element - * is loaded as well as if there is an overrun. - */ - if ((ahc->flags & AHC_TARGETROLE) != 0) { - test SSTAT0, TARGET jnz data_phase_done; - } - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT1, REQINIT jz .; - if ((ahc->features & AHC_DT) == 0) { - test SSTAT1,PHASEMIS jz data_phase_loop; - } else { - test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; - } - } + /* + * If the target has left us in data phase, loop through + * the DMA code again. In the case of ULTRA2 adapters, + * we should only loop if there is a data overrun. For + * all other adapters, we'll loop after each S/G element + * is loaded as well as if there is an overrun. + */ + if ((ahc->flags & AHC_TARGETROLE) != 0) { + test SSTAT0, TARGET jnz data_phase_done; + } + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT1, REQINIT jz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz data_phase_loop; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; + } + } data_phase_done: - /* - * 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. - */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* Kill off any pending prefetch */ - call disable_ccsgen; - } - - if ((ahc->features & AHC_ULTRA2) == 0) { - /* - * Clear the high address byte so that all other DMA - * operations, which use 32bit addressing, can assume - * HHADDR is 0. - */ - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - mov ALLZEROS call set_hhaddr; - } - } - - /* - * Update our residual information before the information is - * lost by some other type of SCSI I/O (e.g. PIO). If we have - * transferred all data, no update is needed. - * - */ - test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done; - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 - && ahc->pci_cachesize != 0) { - if ((ahc->features & AHC_CMD_CHAN) != 0) { - test MWI_RESIDUAL, 0xFF jz bmov_resid; - } - mov A, MWI_RESIDUAL; - add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; - clr A; - adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; - adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; - clr MWI_RESIDUAL; - if ((ahc->features & AHC_CMD_CHAN) != 0) { - jmp . + 2; + /* + * 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. + */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Kill off any pending prefetch */ + call disable_ccsgen; + } + + if ((ahc->features & AHC_ULTRA2) == 0) { + /* + * Clear the high address byte so that all other DMA + * operations, which use 32bit addressing, can assume + * HHADDR is 0. + */ + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + mov ALLZEROS call set_hhaddr; + } + } + + /* + * Update our residual information before the information is + * lost by some other type of SCSI I/O (e.g. PIO). If we have + * transferred all data, no update is needed. + * + */ + test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done; + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 + && ahc->pci_cachesize != 0) { + if ((ahc->features & AHC_CMD_CHAN) != 0) { + test MWI_RESIDUAL, 0xFF jz bmov_resid; + } + mov A, MWI_RESIDUAL; + add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; + clr A; + adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; + adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; + clr MWI_RESIDUAL; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + jmp . + 2; bmov_resid: - bmov SCB_RESIDUAL_DATACNT, STCNT, 3; - } - } else if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESIDUAL_DATACNT, STCNT, 3; + bmov SCB_RESIDUAL_DATACNT, STCNT, 3; + } + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESIDUAL_DATACNT, STCNT, 3; } else { - mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; - mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; - mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; + mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; + mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; + mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; } residual_update_done: - /* - * Since we've been through a data phase, the SCB_RESID* fields - * are now initialized. Clear the full residual flag. - */ - and SCB_SGPTR[0], ~SG_FULL_RESID; + /* + * Since we've been through a data phase, the SCB_RESID* fields + * are now initialized. Clear the full residual flag. + */ + and SCB_SGPTR[0], ~SG_FULL_RESID; if ((ahc->features & AHC_ULTRA2) != 0) { - /* Clear the channel in case we return to data phase later */ - or SXFRCTL0, CLRSTCNT|CLRCHN; + /* Clear the channel in case we return to data phase later */ + or SXFRCTL0, CLRSTCNT|CLRCHN; or SXFRCTL0, CLRSTCNT|CLRCHN; } - if ((ahc->flags & AHC_TARGETROLE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 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. + * initiator before changing phase. We only need to + * send Ignore Wide Residue messages for data-in phases. */ test DFCNTRL, DIRECTION jz target_ITloop; test SSTAT1, REQINIT jnz .; + test DATA_COUNT_ODD, 0x1 jz target_ITloop; + test SCSIRATE, WIDEXFER jz target_ITloop; + /* + * Issue an Ignore Wide Residue Message. + */ + mvi P_MESGIN|BSYO call change_phase; + mvi MSG_IGN_WIDE_RESIDUE call target_outb; + mvi 1 call target_outb; jmp target_ITloop; - } else { - jmp ITloop; + } else { + jmp ITloop; } if ((ahc->flags & AHC_INITIATORROLE) != 0) { @@ -1336,95 +1369,99 @@ if ((ahc->flags & AHC_INITIATORROLE) != 0) { * Command phase. Set up the DMA registers and let 'er rip. */ p_command: - test SEQ_FLAGS,IDENTIFY_SEEN jnz p_command_okay; - mvi NO_IDENT jmp set_seqint; + test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay; + mvi PROTO_VIOLATION call set_seqint; p_command_okay: - if ((ahc->features & AHC_ULTRA2) != 0) { - bmov HCNT[0], SCB_CDB_LEN, 1; - bmov HCNT[1], ALLZEROS, 2; - mvi SG_CACHE_PRE, LAST_SEG; - } else if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov STCNT[0], SCB_CDB_LEN, 1; - bmov STCNT[1], ALLZEROS, 2; - } else { - mov STCNT[0], SCB_CDB_LEN; - clr STCNT[1]; - clr STCNT[2]; - } - add NONE, -13, SCB_CDB_LEN; - mvi SCB_CDB_STORE jnc p_command_embedded; + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov HCNT[0], SCB_CDB_LEN, 1; + bmov HCNT[1], ALLZEROS, 2; + mvi SG_CACHE_PRE, LAST_SEG; + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT[0], SCB_CDB_LEN, 1; + bmov STCNT[1], ALLZEROS, 2; + } else { + mov STCNT[0], SCB_CDB_LEN; + clr STCNT[1]; + clr STCNT[2]; + } + add NONE, -13, SCB_CDB_LEN; + mvi SCB_CDB_STORE jnc p_command_embedded; p_command_from_host: - if ((ahc->features & AHC_ULTRA2) != 0) { - bmov HADDR[0], SCB_CDB_PTR, 4; - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); - } else { - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov HADDR[0], SCB_CDB_PTR, 4; - bmov HCNT, STCNT, 3; - } else { - mvi DINDEX, HADDR; - mvi SCB_CDB_PTR call bcopy_4; - mov SCB_CDB_LEN call set_hcnt; - } - mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); - } - jmp p_command_loop; + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov HADDR[0], SCB_CDB_PTR, 4; + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); + } else { + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov HADDR[0], SCB_CDB_PTR, 4; + bmov HCNT, STCNT, 3; + } else { + mvi DINDEX, HADDR; + mvi SCB_CDB_PTR call bcopy_4; + mov SCB_CDB_LEN call set_hcnt; + } + mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); + } + jmp p_command_xfer; p_command_embedded: - /* - * The data fifo seems to require 4 byte aligned - * transfers from the sequencer. Force this to - * be the case by clearing HADDR[0] even though + /* + * The data fifo seems to require 4 byte aligned + * transfers from the sequencer. Force this to + * be the case by clearing HADDR[0] even though * we aren't going to touch host memory. - */ - clr HADDR[0]; - if ((ahc->features & AHC_ULTRA2) != 0) { - mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); - bmov DFDAT, SCB_CDB_STORE, 12; - } else if ((ahc->features & AHC_CMD_CHAN) != 0) { - if ((ahc->flags & AHC_SCB_BTT) != 0) { - /* - * On the 7895 the data FIFO will - * get corrupted if you try to dump - * data from external SCB memory into - * the FIFO while it is enabled. So, - * fill the fifo and then enable SCSI - * transfers. - */ - mvi DFCNTRL, (DIRECTION|FIFORESET); + */ + clr HADDR[0]; + if ((ahc->features & AHC_ULTRA2) != 0) { + mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); + bmov DFDAT, SCB_CDB_STORE, 12; + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + if ((ahc->flags & AHC_SCB_BTT) != 0) { + /* + * On the 7895 the data FIFO will + * get corrupted if you try to dump + * data from external SCB memory into + * the FIFO while it is enabled. So, + * fill the fifo and then enable SCSI + * transfers. + */ + mvi DFCNTRL, (DIRECTION|FIFORESET); } else { mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); } - bmov DFDAT, SCB_CDB_STORE, 12; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); - } else { - or DFCNTRL, FIFOFLUSH; + bmov DFDAT, SCB_CDB_STORE, 12; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); + } else { + or DFCNTRL, FIFOFLUSH; } } else { - mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); - call copy_to_fifo_6; - call copy_to_fifo_6; - or DFCNTRL, FIFOFLUSH; - } -p_command_loop: - if ((ahc->features & AHC_DT) == 0) { - test SSTAT0, SDONE jnz . + 2; - test SSTAT1, PHASEMIS jz p_command_loop; - /* - * Wait for our ACK to go-away on it's own - * instead of being killed by SCSIEN getting cleared. - */ - test SCSISIGI, ACKI jnz .; - } else { - test DFCNTRL, SCSIEN jnz p_command_loop; - } + mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); + call copy_to_fifo_6; + call copy_to_fifo_6; + or DFCNTRL, FIFOFLUSH; + } +p_command_xfer: + and SEQ_FLAGS, ~NO_CDB_SENT; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT0, SDONE jnz . + 2; + test SSTAT1, PHASEMIS jz . - 1; + /* + * Wait for our ACK to go-away on it's own + * instead of being killed by SCSIEN getting cleared. + */ + test SCSISIGI, ACKI jnz .; + } else { + test DFCNTRL, SCSIEN jnz .; + } + test SSTAT0, SDONE jnz p_command_successful; + /* + * Don't allow a data phase if the command + * was not fully transferred. + */ + or SEQ_FLAGS, NO_CDB_SENT; +p_command_successful: and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; - if ((ahc->features & AHC_ULTRA2) != 0) { - /* Drop any residual from the S/G Preload queue */ - or SXFRCTL0, CLRSTCNT; - } jmp ITloop; /* @@ -1432,10 +1469,10 @@ p_command_loop: * and store it into the SCB. */ p_status: - test SEQ_FLAGS,IDENTIFY_SEEN jnz p_status_okay; - mvi NO_IDENT jmp set_seqint; + test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; p_status_okay: - mov SCB_SCSI_STATUS, SCSIDATL; + mov SCB_SCSI_STATUS, SCSIDATL; + or SCB_CONTROL, STATUS_RCVD; jmp ITloop; /* @@ -1463,20 +1500,20 @@ p_status_okay: * reason. */ p_mesgout_retry: - /* Turn on ATN for the retry */ - if ((ahc->features & AHC_DT) == 0) { - or SCSISIGO, ATNO, LASTPHASE; - } else { - mvi SCSISIGO, ATNO; - } + /* Turn on ATN for the retry */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } p_mesgout: mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; p_mesgout_identify: - or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; - test SCB_CONTROL, DISCENB jnz . + 2; - and SINDEX, ~DISCENB; + or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; + test SCB_CONTROL, DISCENB jnz . + 2; + and SINDEX, ~DISCENB; /* * 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. @@ -1526,7 +1563,7 @@ p_mesgin: cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; cmp ALLZEROS,A je mesgin_complete; cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; - cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; + cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; cmp A,MSG_NOOP je mesgin_done; /* @@ -1539,30 +1576,32 @@ p_mesgin: * shouldn't hurt, but why do it twice... */ host_message_loop: - mvi HOST_MSG_LOOP call set_seqint; + mvi HOST_MSG_LOOP call set_seqint; call phase_lock; cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; jmp host_message_loop; mesgin_ign_wide_residue: if ((ahc->features & AHC_WIDE) != 0) { - test SCSIRATE, WIDEXFER jz mesgin_reject; - /* Pull the residue byte */ - mvi ARG_1 call inb_next; - cmp ARG_1, 0x01 jne mesgin_reject; - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; - test DATA_COUNT_ODD, 0x1 jz mesgin_done; - mvi IGN_WIDE_RES call set_seqint; - jmp mesgin_done; + test SCSIRATE, WIDEXFER jz mesgin_reject; + /* Pull the residue byte */ + mvi ARG_1 call inb_next; + cmp ARG_1, 0x01 jne mesgin_reject; + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; + test DATA_COUNT_ODD, 0x1 jz mesgin_done; + mvi IGN_WIDE_RES call set_seqint; + jmp mesgin_done; } +mesgin_proto_violation: + mvi PROTO_VIOLATION call set_seqint; + jmp mesgin_done; mesgin_reject: - mvi MSG_MESSAGE_REJECT call mk_mesg; + mvi MSG_MESSAGE_REJECT call mk_mesg; mesgin_done: mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ jmp ITloop; -mesgin_complete: /* * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, * and trigger a completion interrupt. Before doing so, check to see if there @@ -1575,40 +1614,62 @@ mesgin_complete: * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting * RETURN_1 to SEND_SENSE. */ +mesgin_complete: -/* - * If ATN is raised, we still want to give the target a message. - * Perhaps there was a parity error on this last message byte. - * Either way, the target should take us to message out phase - * and then attempt to complete the command again. We should use a - * critical section here to guard against a timeout triggering - * for this command and setting ATN while we are still processing - * the completion. - test SCSISIGI, ATNI jnz mesgin_done; - */ + /* + * If ATN is raised, we still want to give the target a message. + * Perhaps there was a parity error on this last message byte. + * Either way, the target should take us to message out phase + * and then attempt to complete the command again. We should use a + * critical section here to guard against a timeout triggering + * for this command and setting ATN while we are still processing + * the completion. + test SCSISIGI, ATNI jnz mesgin_done; + */ -/* - * See if we attempted to deliver a message but the target ingnored us. - */ - test SCB_CONTROL, MK_MESSAGE jz . + 2; - mvi MKMSG_FAILED call set_seqint; + /* + * If we are identified and have successfully sent the CDB, + * any status will do. Optimize this fast path. + */ + test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation; + test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; -/* - * Check for residuals - */ - test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ - test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ - test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; + /* + * If the target never sent an identify message but instead went + * to mesgin to give an invalid message, let the host abort us. + */ + test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; + + /* + * If we recevied good status but never successfully sent the + * cdb, abort the command. + */ + test SCB_SCSI_STATUS,0xff jnz complete_accepted; + test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation; + +complete_accepted: + /* + * See if we attempted to deliver a message but the target ingnored us. + */ + test SCB_CONTROL, MK_MESSAGE jz . + 2; + mvi MKMSG_FAILED call set_seqint; + + /* + * Check for residuals + */ + test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ + test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ + test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; check_status: - test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ + test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ upload_scb: - or SCB_SGPTR, SG_RESID_VALID; + or SCB_SGPTR, SG_RESID_VALID; mvi DMAPARAMS, FIFORESET; mov SCB_TAG call dma_scb; - test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ - mvi BAD_STATUS call set_seqint; /* let driver know */ + test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ + mvi BAD_STATUS call set_seqint; /* let driver know */ cmp RETURN_1, SEND_SENSE jne complete; - call add_scb_to_free_list; + call add_scb_to_free_list; jmp await_busfree; complete: mov SCB_TAG call complete_post; @@ -1639,25 +1700,25 @@ if ((ahc->flags & AHC_INITIATORROLE) != 0) { * a reselction. */ mesgin_disconnect: - /* - * If ATN is raised, we still want to give the target a message. - * Perhaps there was a parity error on this last message byte - * or we want to abort this command. Either way, the target - * should take us to message out phase and then attempt to - * disconnect again. - * XXX - Wait for more testing. - test SCSISIGI, ATNI jnz mesgin_done; - */ - - test SCSISIGI, ATNI jnz mesgin_done; + /* + * If ATN is raised, we still want to give the target a message. + * Perhaps there was a parity error on this last message byte + * or we want to abort this command. Either way, the target + * should take us to message out phase and then attempt to + * disconnect again. + * XXX - Wait for more testing. + test SCSISIGI, ATNI jnz mesgin_done; + */ + test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT + jnz mesgin_proto_violation; or SCB_CONTROL,DISCONNECTED; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - call add_scb_to_disc_list; - } - test SCB_CONTROL, TAG_ENB jnz await_busfree; - mov ARG_1, SCB_TAG; - mov SAVED_LUN, SCB_LUN; - mov SCB_SCSIID call set_busy_target; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + call add_scb_to_disc_list; + } + test SCB_CONTROL, TAG_ENB jnz await_busfree; + mov ARG_1, SCB_TAG; + mov SAVED_LUN, SCB_LUN; + mov SCB_SCSIID call set_busy_target; jmp await_busfree; /* @@ -1671,53 +1732,54 @@ mesgin_disconnect: * chips, SHADDR increments with every bus transaction, even PIO. */ mesgin_sdptrs: - if ((ahc->features & AHC_ULTRA2) != 0) { - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - test SEQ_FLAGS, DPHASE jz ITloop; - } else { - test SEQ_FLAGS, DPHASE jz mesgin_done; - } + if ((ahc->features & AHC_ULTRA2) != 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + test SEQ_FLAGS, DPHASE jz ITloop; + } else { + test SEQ_FLAGS, DPHASE jz mesgin_done; + } /* - * If we are asked to save our position at the end of the - * transfer, just mark us at the end rather than perform a - * full save. - */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full; - or SCB_SGPTR, SG_LIST_NULL; - if ((ahc->features & AHC_ULTRA2) != 0) { - jmp ITloop; - } else { - jmp mesgin_done; - } + * If we are asked to save our position at the end of the + * transfer, just mark us at the end rather than perform a + * full save. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full; + or SCB_SGPTR, SG_LIST_NULL; + if ((ahc->features & AHC_ULTRA2) != 0) { + jmp ITloop; + } else { + jmp mesgin_done; + } mesgin_sdptrs_full: - /* - * The SCB_SGPTR becomes the next one we'll download, - * and the SCB_DATAPTR becomes the current SHADDR. + /* + * 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_DATAPTR, SHADDR, 4; - if ((ahc->features & AHC_ULTRA2) == 0) { - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - } - bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; + if ((ahc->features & AHC_ULTRA2) == 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + } + bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; } else { mvi DINDEX, SCB_DATAPTR; - mvi SHADDR call bcopy_4; - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - mvi SCB_RESIDUAL_DATACNT call bcopy_8; + mvi SHADDR call bcopy_4; + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + mvi SCB_RESIDUAL_DATACNT call bcopy_8; } - jmp ITloop; + jmp ITloop; /* * Restore pointers message? Data pointers are recopied from the * SCB anytime we enter a data phase for the first time, so all * we need to do is clear the DPHASE flag and let the data phase - * code do the rest. + * code do the rest. We also reset/reallocate the FIFO to make + * sure we have a clean start for the next data or command phase. */ mesgin_rdptrs: and SEQ_FLAGS, ~DPHASE; /* @@ -1725,6 +1787,7 @@ mesgin_rdptrs: * the next time through * the dataphase. */ + or SXFRCTL0, CLRSTCNT|CLRCHN; jmp mesgin_done; /* @@ -1732,14 +1795,14 @@ mesgin_rdptrs: * upon return. SCBPTR may be modified by this action. */ set_busy_target: - shr DINDEX, 4, SINDEX; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mov SCBPTR, SAVED_LUN; - add DINDEX, SCB_64_BTT; - } else { - add DINDEX, BUSY_TARGETS; - } - mov DINDIR, ARG_1 ret; + shr DINDEX, 4, SINDEX; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mov SCBPTR, SAVED_LUN; + add DINDEX, SCB_64_BTT; + } else { + add DINDEX, BUSY_TARGETS; + } + mov DINDIR, ARG_1 ret; /* * Identify message? For a reconnecting target, this tells us the lun @@ -1747,68 +1810,68 @@ set_busy_target: * clearing the "disconnected" bit so we don't "find" it by accident later. */ mesgin_identify: - /* - * Determine whether a target is using tagged or non-tagged - * transactions by first looking at the transaction stored in - * the busy target array. If there is no untagged transaction - * for this target or the transaction is for a different lun, then - * this must be an untagged transaction. - */ - shr SINDEX, 4, SAVED_SCSIID; - and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - add SINDEX, SCB_64_BTT; - mov SCBPTR, SAVED_LUN; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - add NONE, -SCB_64_BTT, SINDEX; - jc . + 2; - mvi INTSTAT, OUT_OF_RANGE; - nop; - add NONE, -(SCB_64_BTT + 16), SINDEX; - jnc . + 2; - mvi INTSTAT, OUT_OF_RANGE; - nop; - } + /* + * Determine whether a target is using tagged or non-tagged + * transactions by first looking at the transaction stored in + * the busy target array. If there is no untagged transaction + * for this target or the transaction is for a different lun, then + * this must be a tagged transaction. + */ + shr SINDEX, 4, SAVED_SCSIID; + and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + add SINDEX, SCB_64_BTT; + mov SCBPTR, SAVED_LUN; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + add NONE, -SCB_64_BTT, SINDEX; + jc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + nop; + add NONE, -(SCB_64_BTT + 16), SINDEX; + jnc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + nop; + } } else { - add SINDEX, BUSY_TARGETS; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - add NONE, -BUSY_TARGETS, SINDEX; - jc . + 2; - mvi INTSTAT, OUT_OF_RANGE; - nop; - add NONE, -(BUSY_TARGETS + 16), SINDEX; - jnc . + 2; - mvi INTSTAT, OUT_OF_RANGE; - nop; - } - } - mov ARG_1, SINDIR; + add SINDEX, BUSY_TARGETS; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + add NONE, -BUSY_TARGETS, SINDEX; + jc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + nop; + add NONE, -(BUSY_TARGETS + 16), SINDEX; + jnc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + nop; + } + } + mov ARG_1, SINDIR; cmp ARG_1, SCB_LIST_NULL je snoop_tag; if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov ARG_1 call findSCB; - } else { - mov SCBPTR, ARG_1; - } - if ((ahc->flags & AHC_SCB_BTT) != 0) { - jmp setup_SCB_id_lun_okay; - } else { - /* - * We only allow one untagged command per-target - * at a time. So, if the lun doesn't match, look - * for a tag message. - */ - mov A, SCB_LUN; - cmp SAVED_LUN, A je setup_SCB_id_lun_okay; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - /* - * findSCB removes the SCB from the - * disconnected list, so we must replace - * it there should this SCB be for another - * lun. - */ - call cleanup_scb; - } - } + mov ARG_1 call findSCB; + } else { + mov SCBPTR, ARG_1; + } + if ((ahc->flags & AHC_SCB_BTT) != 0) { + jmp setup_SCB_id_lun_okay; + } else { + /* + * We only allow one untagged command per-target + * at a time. So, if the lun doesn't match, look + * for a tag message. + */ + mov A, SCB_LUN; + cmp SAVED_LUN, A je setup_SCB_id_lun_okay; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + /* + * findSCB removes the SCB from the + * disconnected list, so we must replace + * it there should this SCB be for another + * lun. + */ + call cleanup_scb; + } + } /* * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. @@ -1819,61 +1882,61 @@ mesgin_identify: * SCB. */ snoop_tag: - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x80; - } + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x80; + } mov NONE,SCSIDATL; /* ACK Identify MSG */ call phase_lock; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x1; - } + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x1; + } cmp LASTPHASE, P_MESGIN jne not_found; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x2; - } + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x2; + } cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; get_tag: - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mvi ARG_1 call inb_next; /* tag value */ - mov ARG_1 call findSCB; - } else { - mvi ARG_1 call inb_next; /* tag value */ - mov SCBPTR, ARG_1; - } + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mvi ARG_1 call inb_next; /* tag value */ + mov ARG_1 call findSCB; + } else { + mvi ARG_1 call inb_next; /* tag value */ + mov SCBPTR, ARG_1; + } /* * Ensure that the SCB the tag points to is for * an SCB transaction to the reconnecting target. */ setup_SCB: - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x4; - } - mov A, SCB_SCSIID; - cmp SAVED_SCSIID, A jne not_found_cleanup_scb; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x8; - } + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x4; + } + mov A, SCB_SCSIID; + cmp SAVED_SCSIID, A jne not_found_cleanup_scb; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x8; + } setup_SCB_id_okay: - mov A, SCB_LUN; - cmp SAVED_LUN, A jne not_found_cleanup_scb; + mov A, SCB_LUN; + cmp SAVED_LUN, A jne not_found_cleanup_scb; setup_SCB_id_lun_okay: - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x10; - } + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x10; + } test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; and SCB_CONTROL,~DISCONNECTED; - test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mov A, SCBPTR; - } - mvi ARG_1, SCB_LIST_NULL; - mov SAVED_SCSIID call set_busy_target; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mov SCBPTR, A; - } + test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mov A, SCBPTR; + } + mvi ARG_1, SCB_LIST_NULL; + mov SAVED_SCSIID call set_busy_target; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mov SCBPTR, A; + } setup_SCB_tagged: - mvi SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ + clr SEQ_FLAGS; /* 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; @@ -1881,19 +1944,19 @@ setup_SCB_tagged: jmp mesgin_done; not_found_cleanup_scb: - if ((ahc->flags & AHC_PAGESCBS) != 0) { - call cleanup_scb; - } + if ((ahc->flags & AHC_PAGESCBS) != 0) { + call cleanup_scb; + } not_found: - mvi NO_MATCH call set_seqint; + mvi NO_MATCH call set_seqint; jmp mesgin_done; mk_mesg: - if ((ahc->features & AHC_DT) == 0) { - or SCSISIGO, ATNO, LASTPHASE; - } else { - mvi SCSISIGO, ATNO; - } + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } mov MSG_OUT,SINDEX ret; /* @@ -1912,7 +1975,7 @@ mk_mesg: * use the same calling convention as inb. */ inb_next_wait_perr: - mvi PERR_DETECTED call set_seqint; + mvi PERR_DETECTED call set_seqint; jmp inb_next_wait; inb_next: mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ @@ -1951,7 +2014,7 @@ change_phase: /* * If the data direction has changed, from * out (initiator driving) to in (target driving), - * we must wait at least a data release delay plus + * we must wait at least a data release delay plus * the normal bus settle delay. [SCSI III SPI 10.11.0] */ cmp DINDEX, A je change_phase_wait; @@ -1984,21 +2047,21 @@ target_outb: if ((ahc->flags & AHC_PAGESCBS) != 0) { BEGIN_CRITICAL; findSCB: - mov A, SINDEX; /* Tag passed in SINDEX */ - cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; - mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ - mvi ARG_2, SCB_LIST_NULL; /* Head of list */ - jmp findSCB_loop; + mov A, SINDEX; /* Tag passed in SINDEX */ + cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; + mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ + mvi ARG_2, SCB_LIST_NULL; /* Head of list */ + jmp findSCB_loop; findSCB_next: - cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; + cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; mov ARG_2, SCBPTR; mov SCBPTR,SCB_NEXT; findSCB_loop: - cmp SCB_TAG, A jne findSCB_next; + cmp SCB_TAG, A jne findSCB_next; rem_scb_from_disc_list: cmp ARG_2, SCB_LIST_NULL je rHead; mov DINDEX, SCB_NEXT; - mov SINDEX, SCBPTR; + mov SINDEX, SCBPTR; mov SCBPTR, ARG_2; mov SCB_NEXT, DINDEX; mov SCBPTR, SINDEX ret; @@ -2006,11 +2069,11 @@ rHead: mov DISCONNECTED_SCBH,SCB_NEXT ret; END_CRITICAL; findSCB_notFound: - /* - * We didn't find it. Page in the SCB. - */ - mov ARG_1, A; /* Save tag */ - mov ALLZEROS call get_free_or_disc_scb; + /* + * We didn't find it. Page in the SCB. + */ + mov ARG_1, A; /* Save tag */ + mov ALLZEROS call get_free_or_disc_scb; mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov ARG_1 jmp dma_scb; } @@ -2023,13 +2086,13 @@ post_byte_setup: mov ARG_2, SINDEX; if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; - mvi SHARED_DATA_ADDR call set_1byte_addr; + mvi SHARED_DATA_ADDR call set_1byte_addr; mvi CCHCNT, 1; mvi CCSCBCTL, CCSCBRESET ret; } else { mvi DINDEX, HADDR; - mvi SHARED_DATA_ADDR call set_1byte_addr; - mvi 1 call set_hcnt; + mvi SHARED_DATA_ADDR call set_1byte_addr; + mvi 1 call set_hcnt; mvi DFCNTRL, FIFORESET ret; } @@ -2046,7 +2109,7 @@ post_byte: } phase_lock_perr: - mvi PERR_DETECTED call set_seqint; + mvi PERR_DETECTED call set_seqint; phase_lock: /* * If there is a parity error, wait for the kernel to @@ -2056,17 +2119,17 @@ phase_lock: test SSTAT1, REQINIT jz phase_lock; test SSTAT1, SCSIPERR jnz phase_lock_perr; phase_lock_latch_phase: - if ((ahc->features & AHC_DT) == 0) { - and SCSISIGO, PHASE_MASK, SCSISIGI; - } + if ((ahc->features & AHC_DT) == 0) { + and SCSISIGO, PHASE_MASK, SCSISIGI; + } and LASTPHASE, PHASE_MASK, SCSISIGI ret; if ((ahc->features & AHC_CMD_CHAN) == 0) { set_hcnt: - mov HCNT[0], SINDEX; + mov HCNT[0], SINDEX; clear_hcnt: - clr HCNT[1]; - clr HCNT[2] ret; + clr HCNT[1]; + clr HCNT[2] ret; set_stcnt_from_hcnt: mov STCNT[0], HCNT[0]; @@ -2074,7 +2137,7 @@ set_stcnt_from_hcnt: mov STCNT[2], HCNT[2] ret; bcopy_8: - mov DINDIR, SINDIR; + mov DINDIR, SINDIR; bcopy_7: mov DINDIR, SINDIR; mov DINDIR, SINDIR; @@ -2139,27 +2202,27 @@ dma_scb: mvi HSCB_ADDR call set_64byte_addr; mov CCSCBPTR, SCBPTR; test DMAPARAMS, DIRECTION jz dma_scb_tohost; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; - } else { - mvi CCHCNT, SCB_DOWNLOAD_SIZE; - } + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; + } else { + mvi CCHCNT, SCB_DOWNLOAD_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_UPLOAD_SIZE; - if ((ahc->features & AHC_ULTRA2) == 0) { + mvi CCHCNT, SCB_UPLOAD_SIZE; + if ((ahc->features & AHC_ULTRA2) == 0) { mvi CCSCBCTL, CCSCBRESET; - bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; + bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; - } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { - mvi CCSCBCTL, CCARREN|CCSCBRESET; - cmp CCSCBCTL, ARRDONE|CCARREN jne .; - mvi CCHCNT, SCB_UPLOAD_SIZE; - mvi CCSCBCTL, CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; + } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { + mvi CCSCBCTL, CCARREN|CCSCBRESET; + cmp CCSCBCTL, ARRDONE|CCARREN jne .; + mvi CCHCNT, SCB_UPLOAD_SIZE; + mvi CCSCBCTL, CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; } else { mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; @@ -2171,74 +2234,73 @@ dma_scb_finish: } else { mvi DINDEX, HADDR; mvi HSCB_ADDR call set_64byte_addr; - mvi SCB_DOWNLOAD_SIZE call set_hcnt; + mvi SCB_DOWNLOAD_SIZE call set_hcnt; mov DFCNTRL, DMAPARAMS; test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; /* Fill it with the SCB data */ copy_scb_tofifo: - mvi SINDEX, SCB_BASE; - add A, SCB_DOWNLOAD_SIZE, SINDEX; + mvi SINDEX, SCB_BASE; + add A, SCB_DOWNLOAD_SIZE, SINDEX; copy_scb_tofifo_loop: - call copy_to_fifo_8; + call copy_to_fifo_8; cmp SINDEX, A jne copy_scb_tofifo_loop; or DFCNTRL, HDMAEN|FIFOFLUSH; - jmp dma_finish; + jmp dma_finish; dma_scb_fromhost: - mvi DINDEX, SCB_BASE; - if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { - /* - * The PCI module will only issue a PCI - * retry if the data FIFO is empty. If the - * host disconnects in the middle of a - * transfer, we must empty the fifo of all - * available data to force the chip to - * continue the transfer. This does not - * happen for SCSI transfers as the SCSI module - * will drain the FIFO as data is made available. - * When the hang occurs, we know that a multiple - * of 8 bytes are in the FIFO because the PCI - * module has an 8 byte input latch that only - * dumps to the FIFO when HCNT == 0 or the - * latch is full. - */ - clr A; - /* Wait for at least 8 bytes of data to arrive. */ + mvi DINDEX, SCB_BASE; + if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { + /* + * The PCI module will only issue a PCI + * retry if the data FIFO is empty. If the + * host disconnects in the middle of a + * transfer, we must empty the fifo of all + * available data to force the chip to + * continue the transfer. This does not + * happen for SCSI transfers as the SCSI module + * will drain the FIFO as data are made available. + * When the hang occurs, we know that a multiple + * of 8 bytes is in the FIFO because the PCI + * module has an 8 byte input latch that only + * dumps to the FIFO when HCNT == 0 or the + * latch is full. + */ + clr A; + /* Wait for at least 8 bytes of data to arrive. */ dma_scb_hang_fifo: - test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; + test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; dma_scb_hang_wait: - test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - /* - * The PCI module no longer intends to perform - * a PCI transaction. Drain the fifo. - */ + test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + /* + * The PCI module no longer intends to perform + * a PCI transaction. Drain the fifo. + */ dma_scb_hang_dma_drain_fifo: - not A, HCNT; - add A, SCB_DOWNLOAD_SIZE+SCB_BASE+1; - and A, ~0x7; - mov DINDIR,DFDAT; - cmp DINDEX, A jne . - 1; - cmp DINDEX, SCB_DOWNLOAD_SIZE+SCB_BASE - je dma_finish_nowait; - /* Restore A as the lines left to transfer. */ - add A, -SCB_BASE, DINDEX; - shr A, 3; - jmp dma_scb_hang_fifo; + not A, HCNT; + add A, SCB_DOWNLOAD_SIZE+SCB_BASE+1; + and A, ~0x7; + mov DINDIR,DFDAT; + cmp DINDEX, A jne . - 1; + cmp DINDEX, SCB_DOWNLOAD_SIZE+SCB_BASE + je dma_finish_nowait; + /* Restore A as the lines left to transfer. */ + add A, -SCB_BASE, DINDEX; + shr A, 3; + jmp dma_scb_hang_fifo; dma_scb_hang_dma_done: - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - add SEQADDR0, A; - } else { - call dma_finish; - } - /* If we were putting the SCB, we are done */ - call dfdat_in_8; - call dfdat_in_8; - call dfdat_in_8; + and DFCNTRL, ~HDMAEN; + test DFCNTRL, HDMAEN jnz .; + add SEQADDR0, A; + } else { + call dma_finish; + } + call dfdat_in_8; + call dfdat_in_8; + call dfdat_in_8; dfdat_in_8: - mov DINDIR,DFDAT; + mov DINDIR,DFDAT; dfdat_in_7: mov DINDIR,DFDAT; mov DINDIR,DFDAT; @@ -2251,17 +2313,17 @@ dfdat_in_2: } copy_to_fifo_8: - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; copy_to_fifo_6: - mov DFDAT,SINDIR; + mov DFDAT,SINDIR; copy_to_fifo_5: - mov DFDAT,SINDIR; + mov DFDAT,SINDIR; copy_to_fifo_4: - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR ret; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR ret; /* * Wait for DMA from host memory to data FIFO to complete, then disable @@ -2282,9 +2344,9 @@ dma_finish_nowait: * If it is not in the disconnected state, it must be free. */ cleanup_scb: - if ((ahc->flags & AHC_PAGESCBS) != 0) { - test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list; - } + if ((ahc->flags & AHC_PAGESCBS) != 0) { + test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list; + } add_scb_to_free_list: if ((ahc->flags & AHC_PAGESCBS) != 0) { BEGIN_CRITICAL; @@ -2298,9 +2360,9 @@ END_CRITICAL; if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { set_hhaddr: - or DSCOMMAND1, HADDLDSEL0; - and HADDR, SG_HIGH_ADDR_BITS, SINDEX; - and DSCOMMAND1, ~HADDLDSEL0 ret; + or DSCOMMAND1, HADDLDSEL0; + and HADDR, SG_HIGH_ADDR_BITS, SINDEX; + and DSCOMMAND1, ~HADDLDSEL0 ret; } if ((ahc->flags & AHC_PAGESCBS) != 0) { @@ -2309,14 +2371,14 @@ BEGIN_CRITICAL; cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; return_error: - mvi NO_FREE_SCB call set_seqint; + mvi NO_FREE_SCB call set_seqint; mvi SINDEX, SCB_LIST_NULL ret; dequeue_disc_scb: mov SCBPTR, DISCONNECTED_SCBH; - mov DISCONNECTED_SCBH, SCB_NEXT; + mov DISCONNECTED_SCBH, SCB_NEXT; END_CRITICAL; mvi DMAPARAMS, FIFORESET; - mov SCB_TAG jmp dma_scb; + mov SCB_TAG jmp dma_scb; BEGIN_CRITICAL; dequeue_free_scb: mov SCBPTR, FREE_SCBH; @@ -2335,7 +2397,7 @@ BEGIN_CRITICAL; END_CRITICAL; } set_seqint: - mov INTSTAT, SINDEX; - nop; + mov INTSTAT, SINDEX; + nop; return: - ret; + ret; |