aic7xxx.seq revision 9810
17857Sgibbs##+M######################################################################### 27857Sgibbs# Adaptec 274x/284x/294x device driver for Linux and FreeBSD. 34568Sgibbs# 47857Sgibbs# Copyright (c) 1994 John Aycock 57857Sgibbs# The University of Calgary Department of Computer Science. 67857Sgibbs# All rights reserved. 77857Sgibbs# 87857Sgibbs# Modifications/enhancements: 97857Sgibbs# Copyright (c) 1994, 1995 Justin Gibbs. All rights reserved. 107857Sgibbs# 117857Sgibbs# Redistribution and use in source and binary forms, with or without 127857Sgibbs# modification, are permitted provided that the following conditions 137857Sgibbs# are met: 147857Sgibbs# 1. Redistributions of source code must retain the above copyright 157857Sgibbs# notice, this list of conditions, and the following disclaimer. 167857Sgibbs# 2. Redistributions in binary form must reproduce the above copyright 177857Sgibbs# notice, this list of conditions and the following disclaimer in the 187857Sgibbs# documentation and/or other materials provided with the distribution. 197857Sgibbs# 3. All advertising materials mentioning features or use of this software 207857Sgibbs# must display the following acknowledgement: 217857Sgibbs# This product includes software developed by the University of Calgary 227857Sgibbs# Department of Computer Science and its contributors. 237857Sgibbs# 4. Neither the name of the University nor the names of its contributors 247857Sgibbs# may be used to endorse or promote products derived from this software 257857Sgibbs# without specific prior written permission. 267857Sgibbs# 277857Sgibbs# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 287857Sgibbs# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 297857Sgibbs# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 307857Sgibbs# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 317857Sgibbs# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 327857Sgibbs# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 337857Sgibbs# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 347857Sgibbs# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 357857Sgibbs# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 367857Sgibbs# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 377857Sgibbs# SUCH DAMAGE. 384568Sgibbs# 396608Sgibbs# FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 406608Sgibbs# optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org) 415647Sgibbs# 427857Sgibbs##-M######################################################################### 434568Sgibbs 449810SgibbsVERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.17 1995/07/04 20:58:57 gibbs Exp $" 455647Sgibbs 464866SgibbsSCBMASK = 0x1f 474568Sgibbs 484568SgibbsSCSISEQ = 0x00 498104SgibbsENRSELI = 0x10 504568SgibbsSXFRCTL0 = 0x01 514568SgibbsSXFRCTL1 = 0x02 524568SgibbsSCSISIGI = 0x03 534568SgibbsSCSISIGO = 0x03 544568SgibbsSCSIRATE = 0x04 554568SgibbsSCSIID = 0x05 564568SgibbsSCSIDATL = 0x06 574568SgibbsSTCNT = 0x08 584568SgibbsSTCNT+0 = 0x08 594568SgibbsSTCNT+1 = 0x09 604568SgibbsSTCNT+2 = 0x0a 618104SgibbsCLRSINT0 = 0x0b 624568SgibbsSSTAT0 = 0x0b 638104SgibbsSELDO = 0x40 648104SgibbsSELDI = 0x20 654568SgibbsCLRSINT1 = 0x0c 664568SgibbsSSTAT1 = 0x0c 674568SgibbsSIMODE1 = 0x11 684568SgibbsSCSIBUSL = 0x12 694568SgibbsSHADDR = 0x14 704568SgibbsSELID = 0x19 714568SgibbsSBLKCTL = 0x1f 724568SgibbsSEQCTL = 0x60 734568SgibbsA = 0x64 # == ACCUM 744568SgibbsSINDEX = 0x65 754568SgibbsDINDEX = 0x66 764568SgibbsALLZEROS = 0x6a 774568SgibbsNONE = 0x6a 784568SgibbsSINDIR = 0x6c 794568SgibbsDINDIR = 0x6d 804568SgibbsFUNCTION1 = 0x6e 814568SgibbsHADDR = 0x88 827532SgibbsHADDR+1 = 0x89 837532SgibbsHADDR+2 = 0x8a 847532SgibbsHADDR+3 = 0x8b 854568SgibbsHCNT = 0x8c 864568SgibbsHCNT+0 = 0x8c 874568SgibbsHCNT+1 = 0x8d 884568SgibbsHCNT+2 = 0x8e 894568SgibbsSCBPTR = 0x90 904568SgibbsINTSTAT = 0x91 914568SgibbsDFCNTRL = 0x93 924568SgibbsDFSTATUS = 0x94 934568SgibbsDFDAT = 0x99 944568SgibbsQINFIFO = 0x9b 954568SgibbsQINCNT = 0x9c 964568SgibbsQOUTFIFO = 0x9d 974568Sgibbs 985326SgibbsSCSICONF_A = 0x5a 995326SgibbsSCSICONF_B = 0x5b 1004568Sgibbs 1014568Sgibbs# The two reserved bytes at SCBARRAY+1[23] are expected to be set to 1024568Sgibbs# zero, and the reserved bit in SCBARRAY+0 is used as an internal flag 1034568Sgibbs# to indicate whether or not to reload scatter-gather parameters after 1045647Sgibbs# a disconnect. We also use bits 6 & 7 to indicate whether or not to 1055647Sgibbs# initiate SDTR or WDTR repectively when starting this command. 1064568Sgibbs# 1074568SgibbsSCBARRAY+0 = 0xa0 1085647Sgibbs 1095647SgibbsDISCONNECTED = 0x04 1105647SgibbsNEEDDMA = 0x08 1115647SgibbsSG_LOAD = 0x10 1126608SgibbsTAG_ENB = 0x20 1135647SgibbsNEEDSDTR = 0x40 1145647SgibbsNEEDWDTR = 0x80 1155647Sgibbs 1164568SgibbsSCBARRAY+1 = 0xa1 1174568SgibbsSCBARRAY+2 = 0xa2 1184568SgibbsSCBARRAY+3 = 0xa3 1195647SgibbsSCBARRAY+4 = 0xa4 1205647SgibbsSCBARRAY+5 = 0xa5 1215647SgibbsSCBARRAY+6 = 0xa6 1224568SgibbsSCBARRAY+7 = 0xa7 1235647SgibbsSCBARRAY+8 = 0xa8 1245647SgibbsSCBARRAY+9 = 0xa9 1255647SgibbsSCBARRAY+10 = 0xaa 1264568SgibbsSCBARRAY+11 = 0xab 1275647SgibbsSCBARRAY+12 = 0xac 1285647SgibbsSCBARRAY+13 = 0xad 1294568SgibbsSCBARRAY+14 = 0xae 1304568SgibbsSCBARRAY+15 = 0xaf 1314568SgibbsSCBARRAY+16 = 0xb0 1324568SgibbsSCBARRAY+17 = 0xb1 1334568SgibbsSCBARRAY+18 = 0xb2 1344568SgibbsSCBARRAY+19 = 0xb3 1354568SgibbsSCBARRAY+20 = 0xb4 1364568SgibbsSCBARRAY+21 = 0xb5 1374568SgibbsSCBARRAY+22 = 0xb6 1384568SgibbsSCBARRAY+23 = 0xb7 1394568SgibbsSCBARRAY+24 = 0xb8 1404568SgibbsSCBARRAY+25 = 0xb9 1415647SgibbsSCBARRAY+26 = 0xba 1427532SgibbsSCBARRAY+27 = 0xbb 1437532SgibbsSCBARRAY+28 = 0xbc 1447532SgibbsSCBARRAY+29 = 0xbd 1458104SgibbsSCBARRAY+30 = 0xbe 1464568Sgibbs 1475647SgibbsBAD_PHASE = 0x01 # unknown scsi bus phase 1488104SgibbsCMDCMPLT = 0x02 # Command Complete 1495647SgibbsSEND_REJECT = 0x11 # sending a message reject 1505647SgibbsNO_IDENT = 0x21 # no IDENTIFY after reconnect 1515647SgibbsNO_MATCH = 0x31 # no cmd match for reconnect 1525647SgibbsMSG_SDTR = 0x41 # SDTR message recieved 1535647SgibbsMSG_WDTR = 0x51 # WDTR message recieved 1545647SgibbsMSG_REJECT = 0x61 # Reject message recieved 1555647SgibbsBAD_STATUS = 0x71 # Bad status from target 1567532SgibbsRESIDUAL = 0x81 # Residual byte count != 0 1577562SgibbsABORT_TAG = 0x91 # Sent an ABORT_TAG message 1588567SdgAWAITING_MSG = 0xa1 # Kernel requested to specify 1598567Sdg # a message to this target 1608567Sdg # (command was null), so tell 1618567Sdg # it that it can fill the 1628567Sdg # message buffer. 1639810SgibbsIMMEDDONE = 0xb1 1644568Sgibbs 1658567Sdg 1664568Sgibbs# The host adapter card (at least the BIOS) uses 20-2f for SCSI 1675326Sgibbs# device information, 32-33 and 5a-5f as well. As it turns out, the 1685326Sgibbs# BIOS trashes 20-2f, writing the synchronous negotiation results 1694568Sgibbs# on top of the BIOS values, so we re-use those for our per-target 1704568Sgibbs# scratchspace (actually a value that can be copied directly into 1715326Sgibbs# SCSIRATE). The kernel driver will enable synchronous negotiation 1725326Sgibbs# for all targets that have a value other than 0 in the lower four 1735326Sgibbs# bits of the target scratch space. This should work irregardless of 1745647Sgibbs# whether the bios has been installed. NEEDWDTR and NEEDSDTR are the top 1755647Sgibbs# two bits of the SCB control byte. The kernel driver will set these 1765647Sgibbs# when a WDTR or SDTR message should be sent to the target the SCB's 1775647Sgibbs# command references. 1784568Sgibbs# 1798104Sgibbs# REJBYTE contains the first byte of a MESSAGE IN message, so the driver 1808104Sgibbs# can report an intelligible error if a message is rejected. 1814568Sgibbs# 1825562Sgibbs# FLAGS's high bit is true if we are currently handling a reselect; 1834568Sgibbs# its next-highest bit is true ONLY IF we've seen an IDENTIFY message 1844568Sgibbs# from the reselecting target. If we haven't had IDENTIFY, then we have 1854568Sgibbs# no idea what the lun is, and we can't select the right SCB register 1864568Sgibbs# bank, so force a kernel panic if the target attempts a data in/out or 1878104Sgibbs# command phase instead of corrupting something. FLAGS also contains 1888104Sgibbs# configuration bits so that we can optimize for TWIN and WIDE controllers 1898567Sdg# as well as the MAX_OFFSET bit which we set when we want to negotiate for 1908567Sdg# maximum sync offset irregardless of what the per target scratch space says. 1914568Sgibbs# 1924568Sgibbs# Note that SG_NEXT occupies four bytes. 1934568Sgibbs# 1944568SgibbsSYNCNEG = 0x20 1954568Sgibbs 1964568SgibbsREJBYTE = 0x31 1975326SgibbsDISC_DSB_A = 0x32 1985326SgibbsDISC_DSB_B = 0x33 1994568Sgibbs 2006608SgibbsMSG_LEN = 0x34 2016608SgibbsMSG_START+0 = 0x35 2026608SgibbsMSG_START+1 = 0x36 2036608SgibbsMSG_START+2 = 0x37 2046608SgibbsMSG_START+3 = 0x38 2056608SgibbsMSG_START+4 = 0x39 2066608SgibbsMSG_START+5 = 0x3a 2077562Sgibbs-MSG_START+0 = 0xcb # 2's complement of MSG_START+0 2084568Sgibbs 2096608SgibbsARG_1 = 0x4a # sdtr conversion args & return 2105647SgibbsBUS_16_BIT = 0x01 2116608SgibbsRETURN_1 = 0x4a 2124568Sgibbs 2136608SgibbsSIGSTATE = 0x4b # value written to SCSISIGO 2144568Sgibbs 2155647Sgibbs# Linux users should use 0xc (12) for SG_SIZEOF 2165647SgibbsSG_SIZEOF = 0x8 # sizeof(struct ahc_dma) 2175647Sgibbs#SG_SIZEOF = 0xc # sizeof(struct scatterlist) 2185647SgibbsSCB_SIZEOF = 0x13 # sizeof SCB to DMA (19 bytes) 2195647Sgibbs 2206608SgibbsSG_NOLOAD = 0x4c # load SG pointer/length? 2216608SgibbsSG_COUNT = 0x4d # working value of SG count 2226608SgibbsSG_NEXT = 0x4e # working value of SG pointer 2236608SgibbsSG_NEXT+0 = 0x4e 2246608SgibbsSG_NEXT+1 = 0x4f 2256608SgibbsSG_NEXT+2 = 0x50 2266608SgibbsSG_NEXT+3 = 0x51 2274568Sgibbs 2286608SgibbsSCBCOUNT = 0x52 # the actual number of SCBs 2296608SgibbsFLAGS = 0x53 # Device configuration flags 2305326SgibbsTWIN_BUS = 0x01 2315326SgibbsWIDE_BUS = 0x02 2328567SdgMAX_OFFSET = 0x08 2335562SgibbsACTIVE_MSG = 0x20 2345562SgibbsIDENTIFY_SEEN = 0x40 2355562SgibbsRESELECTED = 0x80 2364568Sgibbs 2378567SdgMAX_OFFSET_8BIT = 0x0f 2388567SdgMAX_OFFSET_WIDE = 0x08 2398567Sdg 2406608SgibbsACTIVE_A = 0x54 2416608SgibbsACTIVE_B = 0x55 2428104SgibbsSAVED_TCL = 0x56 # Temporary storage for the 2438104Sgibbs # target/channel/lun of a 2448104Sgibbs # reconnecting target 2458104Sgibbs 2468104Sgibbs# After starting the selection hardware, we return to the "poll_for_work" 2478104Sgibbs# loop so that we can check for reconnecting targets as well as for our 2488104Sgibbs# selection to complete just in case the reselection wins bus arbitration. 2498104Sgibbs# The problem with this is that we must keep track of the SCB that we've 2508104Sgibbs# already pulled from the QINFIFO and started the selection on just in case 2518104Sgibbs# the reselection wins so that we can retry the selection at a later time. 2528104Sgibbs# This problem cannot be resolved by holding a single entry in scratch 2538104Sgibbs# ram since a reconnecting target can request sense and this will create 2548104Sgibbs# yet another SCB waiting for selection. The solution used here is to 2558104Sgibbs# use byte 31 of the SCB as a psuedo-next pointer and to thread a list 2569395Sgibbs# of SCBs that are awaiting selection. Since 0-0xfe are valid SCB offsets, 2579395Sgibbs# SCB_LIST_NULL is 0xff which is out of range. The kernel driver must 2588104Sgibbs# add an entry to this list everytime a request sense occurs. The sequencer 2598104Sgibbs# will automatically consume the entries. 2608104Sgibbs 2618104SgibbsWAITING_SCBH = 0x57 # head of list of SCBs awaiting 2628104Sgibbs # selection 2638104SgibbsWAITING_SCBT = 0x58 # tail of list of SCBs awaiting 2648104Sgibbs # selection 2659395SgibbsSCB_LIST_NULL = 0xff 2668104Sgibbs 2678104Sgibbs 2684866Sgibbs# Poll QINCNT for work - the lower bits contain 2694568Sgibbs# the number of entries in the Queue In FIFO. 2704568Sgibbs# 2714568Sgibbsstart: 2729395Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting 2738104Sgibbspoll_for_work: 2745326Sgibbs test FLAGS,TWIN_BUS jz start2 # Are we a twin channel device? 2755326Sgibbs# For fairness, we check the other bus first, since we just finished a 2765326Sgibbs# transaction on the current channel. 2775326Sgibbs xor SBLKCTL,0x08 # Toggle to the other bus 2788104Sgibbs test SSTAT0,SELDI jnz reselect 2798104Sgibbs test SSTAT0,SELDO jnz select 2805326Sgibbs xor SBLKCTL,0x08 # Toggle to the original bus 2815326Sgibbsstart2: 2828104Sgibbs test SSTAT0,SELDI jnz reselect 2838104Sgibbs test SSTAT0,SELDO jnz select 2849395Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting 2858104Sgibbs test QINCNT,SCBMASK jz poll_for_work 2864568Sgibbs 2878104Sgibbs# We have at least one queued SCB now and we don't have any 2888104Sgibbs# SCBs in the list of SCBs awaiting selection. Set the SCB 2898104Sgibbs# pointer from the FIFO so we see the right bank of SCB 2908104Sgibbs# registers, then set SCSI options and set the initiator and 2918104Sgibbs# target SCSI IDs. 2924568Sgibbs# 2934568Sgibbs mov SCBPTR,QINFIFO 2944568Sgibbs 2955647Sgibbs# If the control byte of this SCB has the NEEDDMA flag set, we have 2965647Sgibbs# yet to DMA it from host memory 2975647Sgibbs 2988104Sgibbstest SCBARRAY+0,NEEDDMA jz test_busy 2995647Sgibbs clr HCNT+2 3005647Sgibbs clr HCNT+1 3015647Sgibbs mvi HCNT+0,SCB_SIZEOF 3025647Sgibbs 3038104Sgibbs mvi DINDEX,HADDR 3048104Sgibbs mvi SCBARRAY+26 call bcopy_4 3058104Sgibbs 3068104Sgibbs mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET 3075647Sgibbs 3085647Sgibbs# Wait for DMA from host memory to data FIFO to complete, then disable 3095647Sgibbs# DMA and wait for it to acknowledge that it's off. 3105647Sgibbs# 3117532Sgibbs call dma_finish 3125647Sgibbs 3135647Sgibbs# Copy the SCB from the FIFO to the SCBARRAY 3145647Sgibbs 3157532Sgibbs mvi DINDEX, SCBARRAY+0 3168104Sgibbs call bcopy_3_dfdat 3177532Sgibbs call bcopy_4_dfdat 3187532Sgibbs call bcopy_4_dfdat 3198104Sgibbs call bcopy_4_dfdat 3207532Sgibbs call bcopy_4_dfdat 3218104Sgibbs 3224568Sgibbs# See if there is not already an active SCB for this target. This code 3235326Sgibbs# locks out on a per target basis instead of target/lun. Although this 3245326Sgibbs# is not ideal for devices that have multiple luns active at the same 3255326Sgibbs# time, it is faster than looping through all SCB's looking for active 3265326Sgibbs# commands. It may be benificial to make findscb a more general procedure 3275326Sgibbs# to see if the added cost of the search is negligible. This code also 3285326Sgibbs# assumes that the kernel driver will clear the active flags on board 3295326Sgibbs# initialization, board reset, and a target's SELTO. 3304568Sgibbs 3315647Sgibbstest_busy: 3324568Sgibbs and FUNCTION1,0x70,SCBARRAY+1 3334568Sgibbs mov A,FUNCTION1 3345326Sgibbs test SCBARRAY+1,0x88 jz test_a # Id < 8 && A channel 3355326Sgibbs 3365326Sgibbs test ACTIVE_B,A jnz requeue 3379395Sgibbs test SCBARRAY+0,0x20 jnz start_scb 3385326Sgibbs or ACTIVE_B,A # Mark the current target as busy 3395326Sgibbs jmp start_scb 3405326Sgibbs 3414568Sgibbs# Place the currently active back on the queue for later processing 3425326Sgibbsrequeue: 3434568Sgibbs mov QINFIFO, SCBPTR 3448104Sgibbs jmp poll_for_work 3454568Sgibbs 3468104Sgibbs# Pull the first entry off of the waiting for selection list 3478104Sgibbsstart_waiting: 3488104Sgibbs mov SCBPTR,WAITING_SCBH 3498104Sgibbs jmp start_scb 3508104Sgibbs 3515326Sgibbstest_a: 3525326Sgibbs test ACTIVE_A,A jnz requeue 3539395Sgibbs test SCBARRAY+0,0x20 jnz start_scb 3545326Sgibbs or ACTIVE_A,A # Mark the current target as busy 3555326Sgibbs 3565326Sgibbsstart_scb: 3576940Sgibbs and SINDEX,0xf7,SBLKCTL #Clear the channel select bit 3586940Sgibbs and A,0x08,SCBARRAY+1 #Get new channel bit 3596940Sgibbs or SINDEX,A 3606940Sgibbs mov SBLKCTL,SINDEX # select channel 3618104Sgibbs mov SCBARRAY+1 call initialize_scsiid 3628104Sgibbs 3638104Sgibbs# Enable selection phase as an initiator, and do automatic ATN 3648104Sgibbs# after the selection. We do this now so that we can overlap the 3658104Sgibbs# rest of our work to set up this target with the arbitration and 3668104Sgibbs# selection bus phases. 3678104Sgibbs# 3688104Sgibbsstart_selection: 3698104Sgibbs or SCSISEQ,0x48 # ENSELO|ENAUTOATNO 3708104Sgibbs mov WAITING_SCBH, SCBPTR 3714568Sgibbs clr SG_NOLOAD 3725562Sgibbs and FLAGS,0x3f # !RESELECTING 3734568Sgibbs 3744568Sgibbs# As soon as we get a successful selection, the target should go 3754568Sgibbs# into the message out phase since we have ATN asserted. Prepare 3764568Sgibbs# the message to send, locking out the device driver. If the device 3774568Sgibbs# driver hasn't beaten us with an ABORT or RESET message, then tack 3784866Sgibbs# on an SDTR negotiation if required. 3794568Sgibbs# 3804568Sgibbs# Messages are stored in scratch RAM starting with a flag byte (high bit 3814568Sgibbs# set means active message), one length byte, and then the message itself. 3824568Sgibbs# 3838567Sdg 3848567Sdg test SCBARRAY+11,0xff jnz identify # 0 Length Command? 3858567Sdg 3868567Sdg# The kernel has sent us an SCB with no command attached. This implies 3878567Sdg# that the kernel wants to send a message of some sort to this target, 3888567Sdg# so we interrupt the driver, allow it to fill the message buffer, and 3898567Sdg# then go back into the arbitration loop 3908567Sdg mvi INTSTAT,AWAITING_MSG 3918567Sdg jmp poll_for_work 3928567Sdg 3938567Sdgidentify: 3944568Sgibbs mov SCBARRAY+1 call disconnect # disconnect ok? 3954568Sgibbs 3964568Sgibbs and SINDEX,0x7,SCBARRAY+1 # lun 3974568Sgibbs or SINDEX,A # return value from disconnect 3984568Sgibbs or SINDEX,0x80 call mk_mesg # IDENTIFY message 3994568Sgibbs 4004568Sgibbs mov A,SINDEX 4016608Sgibbs test SCBARRAY+0,0xe0 jz !message # WDTR, SDTR or TAG?? 4024568Sgibbs cmp MSG_START+0,A jne !message # did driver beat us? 4034568Sgibbs 4046608Sgibbs# Tag Message if Tag enabled in SCB control block. Use SCBPTR as the tag 4056608Sgibbs# value 4066608Sgibbs 4076608Sgibbsmk_tag: 4086608Sgibbs mvi DINDEX, MSG_START+1 4096608Sgibbs test SCBARRAY+0,TAG_ENB jz mk_tag_done 4106608Sgibbs and A,0x23,SCBARRAY+0 4116608Sgibbs mov DINDIR,A 4126608Sgibbs mov DINDIR,SCBPTR 4136608Sgibbs 4146608Sgibbs add MSG_LEN,-MSG_START+0,DINDEX # update message length 4156608Sgibbs 4166608Sgibbsmk_tag_done: 4176608Sgibbs 4186608Sgibbs mov DINDEX call mk_dtr # build DTR message if needed 4196608Sgibbs 4204568Sgibbs!message: 4218104Sgibbs jmp poll_for_work 4224568Sgibbs 4238104Sgibbs# Reselection has been initiated by a target. Make a note that we've been 4244568Sgibbs# reselected, but haven't seen an IDENTIFY message from the target 4254568Sgibbs# yet. 4264568Sgibbs# 4274568Sgibbsreselect: 4288104Sgibbs mov SELID call initialize_scsiid 4295562Sgibbs and FLAGS,0x3f # reselected, no IDENTIFY 4308104Sgibbs or FLAGS,RESELECTED jmp select2 4314568Sgibbs 4328104Sgibbs# After the selection, remove this SCB from the "waiting for selection" 4338104Sgibbs# list. This is achieved by simply moving our "next" pointer into 4348104Sgibbs# WAITING_SCBH and setting our next pointer to null so that the next 4358104Sgibbs# time this SCB is used, we don't get confused. 4364568Sgibbs# 4378104Sgibbsselect: 4388104Sgibbs or SCBARRAY+0,NEEDDMA 4398104Sgibbs mov WAITING_SCBH,SCBARRAY+30 4408104Sgibbs mvi SCBARRAY+30,SCB_LIST_NULL 4418104Sgibbsselect2: 4428104Sgibbs call initialize_for_target 4438104Sgibbs mvi SCSISEQ,ENRSELI 4448104Sgibbs mvi CLRSINT0,0x60 # CLRSELDI|CLRSELDO 4454568Sgibbs mvi CLRSINT1,0x8 # CLRBUSFREE 4464568Sgibbs 4474568Sgibbs# Main loop for information transfer phases. If BSY is false, then 4484568Sgibbs# we have a bus free condition, expected or not. Otherwise, wait 4494568Sgibbs# for the target to assert REQ before checking MSG, C/D and I/O 4504568Sgibbs# for the bus phase. 4514568Sgibbs# 4524568Sgibbs# We can't simply look at the values of SCSISIGI here (if we want 4534568Sgibbs# to do synchronous data transfer), because the target won't assert 4544568Sgibbs# REQ if it's already sent us some data that we haven't acknowledged 4554568Sgibbs# yet. 4564568Sgibbs# 4574568SgibbsITloop: 4584568Sgibbs test SSTAT1,0x8 jnz p_busfree # BUSFREE 4594568Sgibbs test SSTAT1,0x1 jz ITloop # REQINIT 4604568Sgibbs 4614568Sgibbs and A,0xe0,SCSISIGI # CDI|IOI|MSGI 4624568Sgibbs 4634568Sgibbs cmp ALLZEROS,A je p_dataout 4644568Sgibbs cmp A,0x40 je p_datain 4654568Sgibbs cmp A,0x80 je p_command 4664568Sgibbs cmp A,0xc0 je p_status 4674568Sgibbs cmp A,0xa0 je p_mesgout 4684568Sgibbs cmp A,0xe0 je p_mesgin 4694568Sgibbs 4705647Sgibbs mvi INTSTAT,BAD_PHASE # unknown - signal driver 4714568Sgibbs 4724568Sgibbsp_dataout: 4734568Sgibbs mvi 0 call scsisig # !CDO|!IOO|!MSGO 4744568Sgibbs call assert 4754568Sgibbs call sg_load 4764568Sgibbs 4775775Sgibbs mvi DINDEX,HADDR 4785775Sgibbs mvi SCBARRAY+19 call bcopy_4 4794568Sgibbs 4805775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 4815775Sgibbs mvi SCBARRAY+23 call bcopy_3 4825775Sgibbs 4834568Sgibbs mvi DINDEX,STCNT 4845775Sgibbs mvi SCBARRAY+23 call bcopy_3 4854568Sgibbs 4867532Sgibbs# If we are the last SG block, don't set wideodd. 4877532Sgibbs test SCBARRAY+18,0xff jnz p_dataout_wideodd 4884568Sgibbs mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN| 4894568Sgibbs # DIRECTION|FIFORESET 4907532Sgibbs jmp p_dataout_rest 4914568Sgibbs 4927532Sgibbsp_dataout_wideodd: 4937532Sgibbs mvi 0xbd call dma # WIDEODD|SCSIEN|SDMAEN|HDMAEN| 4947532Sgibbs # DIRECTION|FIFORESET 4957532Sgibbs 4967532Sgibbsp_dataout_rest: 4974568Sgibbs# After a DMA finishes, save the final transfer pointer and count 4984568Sgibbs# back into the SCB, in case a device disconnects in the middle of 4994568Sgibbs# a transfer. Use SHADDR and STCNT instead of HADDR and HCNT, since 5004568Sgibbs# it's a reflection of how many bytes were transferred on the SCSI 5014568Sgibbs# (as opposed to the host) bus. 5024568Sgibbs# 5034568Sgibbs mvi DINDEX,SCBARRAY+23 5045775Sgibbs mvi STCNT call bcopy_3 5054568Sgibbs 5064568Sgibbs mvi DINDEX,SCBARRAY+19 5075775Sgibbs mvi SHADDR call bcopy_4 5084568Sgibbs 5094568Sgibbs call sg_advance 5104568Sgibbs mov SCBARRAY+18,SG_COUNT # residual S/G count 5114568Sgibbs 5124568Sgibbs jmp ITloop 5134568Sgibbs 5144568Sgibbsp_datain: 5154568Sgibbs mvi 0x40 call scsisig # !CDO|IOO|!MSGO 5164568Sgibbs call assert 5174568Sgibbs call sg_load 5184568Sgibbs 5195775Sgibbs mvi DINDEX,HADDR 5205775Sgibbs mvi SCBARRAY+19 call bcopy_4 5214568Sgibbs 5225775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 5235775Sgibbs mvi SCBARRAY+23 call bcopy_3 5245775Sgibbs 5254568Sgibbs mvi DINDEX,STCNT 5265775Sgibbs mvi SCBARRAY+23 call bcopy_3 5274568Sgibbs 5287532Sgibbs# If we are the last SG block, don't set wideodd. 5297532Sgibbs test SCBARRAY+18,0xff jnz p_datain_wideodd 5304568Sgibbs mvi 0x39 call dma # SCSIEN|SDMAEN|HDMAEN| 5314568Sgibbs # !DIRECTION|FIFORESET 5327532Sgibbs jmp p_datain_rest 5337532Sgibbsp_datain_wideodd: 5347532Sgibbs mvi 0xb9 call dma # WIDEODD|SCSIEN|SDMAEN|HDMAEN| 5357532Sgibbs # !DIRECTION|FIFORESET 5367532Sgibbsp_datain_rest: 5374568Sgibbs mvi DINDEX,SCBARRAY+23 5385775Sgibbs mvi STCNT call bcopy_3 5394568Sgibbs 5404568Sgibbs mvi DINDEX,SCBARRAY+19 5415775Sgibbs mvi SHADDR call bcopy_4 5424568Sgibbs 5434568Sgibbs call sg_advance 5444568Sgibbs mov SCBARRAY+18,SG_COUNT # residual S/G count 5454568Sgibbs 5464568Sgibbs jmp ITloop 5474568Sgibbs 5484568Sgibbs# Command phase. Set up the DMA registers and let 'er rip - the 5494568Sgibbs# two bytes after the SCB SCSI_cmd_length are zeroed by the driver, 5504568Sgibbs# so we can copy those three bytes directly into HCNT. 5514568Sgibbs# 5524568Sgibbsp_command: 5534568Sgibbs mvi 0x80 call scsisig # CDO|!IOO|!MSGO 5544568Sgibbs call assert 5554568Sgibbs 5565775Sgibbs mvi DINDEX,HADDR 5575775Sgibbs mvi SCBARRAY+7 call bcopy_4 5584568Sgibbs 5595775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 5605775Sgibbs mvi SCBARRAY+11 call bcopy_3 5615775Sgibbs 5624568Sgibbs mvi DINDEX,STCNT 5635775Sgibbs mvi SCBARRAY+11 call bcopy_3 5644568Sgibbs 5654568Sgibbs mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN| 5664568Sgibbs # DIRECTION|FIFORESET 5674568Sgibbs jmp ITloop 5684568Sgibbs 5694568Sgibbs# Status phase. Wait for the data byte to appear, then read it 5704568Sgibbs# and store it into the SCB. 5714568Sgibbs# 5724568Sgibbsp_status: 5734568Sgibbs mvi 0xc0 call scsisig # CDO|IOO|!MSGO 5744568Sgibbs 5757700Sgibbs mvi SCBARRAY+14 call inb_first 5767700Sgibbs jmp p_mesgin_done 5774568Sgibbs 5784568Sgibbs# Message out phase. If there is no active message, but the target 5794568Sgibbs# took us into this phase anyway, build a no-op message and send it. 5804568Sgibbs# 5814568Sgibbsp_mesgout: 5824568Sgibbs mvi 0xa0 call scsisig # CDO|!IOO|MSGO 5834568Sgibbs mvi 0x8 call mk_mesg # build NOP message 5844568Sgibbs 5857700Sgibbs clr STCNT+2 5867700Sgibbs clr STCNT+1 5877700Sgibbs 5884568Sgibbs# Set up automatic PIO transfer from MSG_START. Bit 3 in 5894568Sgibbs# SXFRCTL0 (SPIOEN) is already on. 5904568Sgibbs# 5914568Sgibbs mvi SINDEX,MSG_START+0 5924568Sgibbs mov DINDEX,MSG_LEN 5934568Sgibbs 5944568Sgibbs# When target asks for a byte, drop ATN if it's the last one in 5954568Sgibbs# the message. Otherwise, keep going until the message is exhausted. 5964568Sgibbs# (We can't use outb for this since it wants the input in SINDEX.) 5974568Sgibbs# 5984568Sgibbs# Keep an eye out for a phase change, in case the target issues 5994568Sgibbs# a MESSAGE REJECT. 6004568Sgibbs# 6014568Sgibbsp_mesgout2: 6024568Sgibbs test SSTAT0,0x2 jz p_mesgout2 # SPIORDY 6034568Sgibbs test SSTAT1,0x10 jnz p_mesgout6 # PHASEMIS 6044568Sgibbs 6054568Sgibbs cmp DINDEX,1 jne p_mesgout3 # last byte? 6064568Sgibbs mvi CLRSINT1,0x40 # CLRATNO - drop ATN 6074568Sgibbs 6084568Sgibbs# Write a byte to the SCSI bus. The AIC-7770 refuses to automatically 6094568Sgibbs# send ACKs in automatic PIO or DMA mode unless you make sure that the 6104568Sgibbs# "expected" bus phase in SCSISIGO matches the actual bus phase. This 6114568Sgibbs# behaviour is completely undocumented and caused me several days of 6124568Sgibbs# grief. 6134568Sgibbs# 6144568Sgibbs# After plugging in different drives to test with and using a longer 6154568Sgibbs# SCSI cable, I found that I/O in Automatic PIO mode ceased to function, 6164568Sgibbs# especially when transferring >1 byte. It seems to be much more stable 6174568Sgibbs# if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is 6184568Sgibbs# polled for transfer completion - for both output _and_ input. The 6194568Sgibbs# only theory I have is that SPIORDY doesn't drop right away when SCSIDATL 6204568Sgibbs# is accessed (like the documentation says it does), and that on a longer 6214568Sgibbs# cable run, the sequencer code was fast enough to loop back and see 6224568Sgibbs# an SPIORDY that hadn't dropped yet. 6234568Sgibbs# 6244568Sgibbsp_mesgout3: 6257700Sgibbs mvi STCNT+0, 0x01 6264568Sgibbs mov SCSIDATL,SINDIR 6274568Sgibbs 6284568Sgibbsp_mesgout4: 6294568Sgibbs test SSTAT0,0x4 jz p_mesgout4 # SDONE 6304568Sgibbs dec DINDEX 6317700Sgibbs test DINDEX,0xff jnz p_mesgout2 6324568Sgibbs 6334568Sgibbs# If the next bus phase after ATN drops is a message out, it means 6344568Sgibbs# that the target is requesting that the last message(s) be resent. 6354568Sgibbs# 6364568Sgibbsp_mesgout5: 6374568Sgibbs test SSTAT1,0x8 jnz p_mesgout6 # BUSFREE 6384568Sgibbs test SSTAT1,0x1 jz p_mesgout5 # REQINIT 6394568Sgibbs 6404568Sgibbs and A,0xe0,SCSISIGI # CDI|IOI|MSGI 6414568Sgibbs cmp A,0xa0 jne p_mesgout6 6424568Sgibbs mvi 0x10 call scsisig # ATNO - re-assert ATN 6434568Sgibbs 6444568Sgibbs jmp ITloop 6454568Sgibbs 6464568Sgibbsp_mesgout6: 6474568Sgibbs mvi CLRSINT1,0x40 # CLRATNO - in case of PHASEMIS 6485562Sgibbs and FLAGS,0xdf # no active msg 6494568Sgibbs jmp ITloop 6504568Sgibbs 6514568Sgibbs# Message in phase. Bytes are read using Automatic PIO mode, but not 6524568Sgibbs# using inb. This alleviates a race condition, namely that if ATN had 6534568Sgibbs# to be asserted under Automatic PIO mode, it had to beat the SCSI 6544568Sgibbs# circuitry sending an ACK to the target. This showed up under heavy 6554568Sgibbs# loads and really confused things, since ABORT commands wouldn't be 6564568Sgibbs# seen by the drive after an IDENTIFY message in until it had changed 6574568Sgibbs# to a data I/O phase. 6584568Sgibbs# 6594568Sgibbsp_mesgin: 6604568Sgibbs mvi 0xe0 call scsisig # CDO|IOO|MSGO 6614568Sgibbs mvi A call inb_first # read the 1st message byte 6624568Sgibbs mvi REJBYTE,A # save it for the driver 6634568Sgibbs 6644568Sgibbs cmp ALLZEROS,A jne p_mesgin1 6654568Sgibbs 6664568Sgibbs# We got a "command complete" message, so put the SCB pointer 6674568Sgibbs# into the Queue Out, and trigger a completion interrupt. 6684568Sgibbs# Check status for non zero return and interrupt driver if needed 6695326Sgibbs# This allows the driver to interpret errors only when they occur 6705326Sgibbs# instead of always uploading the scb. If the status is SCSI_CHECK, 6718104Sgibbs# the driver will download a new scb requesting sense to replace 6728104Sgibbs# the old one, modify the "waiting for selection" SCB list and set 6738104Sgibbs# RETURN_1 to 0x80. If RETURN_1 is set to 0x80 the sequencer imediately 6748104Sgibbs# jumps to main loop where it will run down the waiting SCB list. 6758104Sgibbs# If the kernel driver does not wish to request sense, it need 6768104Sgibbs# only clear RETURN_1, and the command is allowed to complete. We don't 6775326Sgibbs# bother to post to the QOUTFIFO in the error case since it would require 6785326Sgibbs# extra work in the kernel driver to ensure that the entry was removed 6795326Sgibbs# before the command complete code tried processing it. 6804568Sgibbs 6817700Sgibbs# First check for residuals 6827532Sgibbs test SCBARRAY+15,0xff jnz resid 6837532Sgibbs test SCBARRAY+16,0xff jnz resid 6847532Sgibbs test SCBARRAY+17,0xff jnz resid 6857532Sgibbs 6867532Sgibbscheck_status: 6875647Sgibbs test SCBARRAY+14,0xff jz status_ok # 0 Status? 6885647Sgibbs mvi INTSTAT,BAD_STATUS # let driver know 6898104Sgibbs test RETURN_1, 0x80 jz status_ok 6905562Sgibbs jmp p_mesgin_done 6915326Sgibbs 6924568Sgibbsstatus_ok: 6935326Sgibbs# First, mark this target as free. 6946608Sgibbs test SCBARRAY+0,0x20 jnz complete # Tagged command 6955326Sgibbs and FUNCTION1,0x70,SCBARRAY+1 6965326Sgibbs mov A,FUNCTION1 6975326Sgibbs test SCBARRAY+1,0x88 jz clear_a 6985326Sgibbs xor ACTIVE_B,A 6995326Sgibbs jmp complete 7005326Sgibbs 7015326Sgibbsclear_a: 7025326Sgibbs xor ACTIVE_A,A 7035326Sgibbs 7049810Sgibbs test SCBARRAY+11,0xff jnz complete # Immediate message complete 7059810Sgibbs# Pause the sequencer until the driver gets around to handling the command 7069810Sgibbs# complete. This is so that any action that might require carefull timing 7079810Sgibbs# with the completion of this command can occur. 7089810Sgibbs mvi INTSTAT,IMMEDDONE 7099810Sgibbs jmp start 7105326Sgibbscomplete: 7114568Sgibbs mov QOUTFIFO,SCBPTR 7127532Sgibbs mvi INTSTAT,CMDCMPLT 7134568Sgibbs jmp p_mesgin_done 7144568Sgibbs 7157532Sgibbs# If we have a residual count, interrupt and tell the host. Other 7167532Sgibbs# alternatives are to pause the sequencer on all command completes (yuck), 7177532Sgibbs# dma the resid directly to the host (slick, but a ton of instructions), or 7187532Sgibbs# have the sequencer pause itself when it encounters a non-zero resid 7197532Sgibbs# (unecessary pause just to flag the command -- yuck, but takes few instructions 7207700Sgibbs# and since it shouldn't happen that often is good enough for our purposes). 7217532Sgibbs 7227532Sgibbsresid: 7237532Sgibbs mvi INTSTAT,RESIDUAL 7247532Sgibbs jmp check_status 7257532Sgibbs 7265562Sgibbs# Is it an extended message? We only support the synchronous and wide data 7275562Sgibbs# transfer request messages, which will probably be in response to 7285562Sgibbs# WDTR or SDTR message outs from us. If it's not SDTR or WDTR, reject it - 7294568Sgibbs# apparently this can be done after any message in byte, according 7304568Sgibbs# to the SCSI-2 spec. 7314568Sgibbs# 7324568Sgibbsp_mesgin1: 7334568Sgibbs cmp A,1 jne p_mesgin2 # extended message code? 7344568Sgibbs 7355562Sgibbs mvi ARG_1 call inb_next # extended message length 7365562Sgibbs mvi A call inb_next # extended message code 7374568Sgibbs 7385562Sgibbs cmp A,1 je p_mesginSDTR # Syncronous negotiation message 7395562Sgibbs cmp A,3 je p_mesginWDTR # Wide negotiation message 7405562Sgibbs jmp p_mesginN 7415562Sgibbs 7425562Sgibbsp_mesginWDTR: 7435562Sgibbs cmp ARG_1,2 jne p_mesginN # extended mesg length = 2 7445562Sgibbs mvi A call inb_next # Width of bus 7455647Sgibbs mvi INTSTAT,MSG_WDTR # let driver know 7465562Sgibbs test RETURN_1,0x80 jz p_mesgin_done# Do we need to send WDTR? 7475562Sgibbs 7485562Sgibbs# We didn't initiate the wide negotiation, so we must respond to the request 7495562Sgibbs and RETURN_1,0x7f # Clear the SEND_WDTR Flag 7505562Sgibbs or FLAGS,ACTIVE_MSG 7515647Sgibbs mvi DINDEX,MSG_START+0 7525562Sgibbs mvi MSG_START+0 call mk_wdtr # build WDTR message 7535562Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 7545562Sgibbs call scsisig 7555562Sgibbs jmp p_mesgin_done 7565562Sgibbs 7575562Sgibbsp_mesginSDTR: 7585562Sgibbs cmp ARG_1,3 jne p_mesginN # extended mesg length = 3 7594568Sgibbs mvi ARG_1 call inb_next # xfer period 7605326Sgibbs mvi A call inb_next # REQ/ACK offset 7615647Sgibbs mvi INTSTAT,MSG_SDTR # call driver to convert 7624568Sgibbs 7637857Sgibbs test RETURN_1,0xc0 jz p_mesgin_done# Do we need to mk_sdtr or rej? 7647857Sgibbs test RETURN_1,0x40 jnz p_mesginN # Requested SDTR too small - rej 7655562Sgibbs or FLAGS,ACTIVE_MSG 7665647Sgibbs mvi DINDEX, MSG_START+0 7675562Sgibbs mvi MSG_START+0 call mk_sdtr 7685562Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 7695562Sgibbs call scsisig 7704568Sgibbs jmp p_mesgin_done 7714568Sgibbs 7724568Sgibbs# Is it a disconnect message? Set a flag in the SCB to remind us 7734568Sgibbs# and await the bus going free. 7744568Sgibbs# 7754568Sgibbsp_mesgin2: 7764568Sgibbs cmp A,4 jne p_mesgin3 # disconnect code? 7774568Sgibbs 7784568Sgibbs or SCBARRAY+0,0x4 # set "disconnected" bit 7794568Sgibbs jmp p_mesgin_done 7804568Sgibbs 7814568Sgibbs# Save data pointers message? Copy working values into the SCB, 7824568Sgibbs# usually in preparation for a disconnect. 7834568Sgibbs# 7844568Sgibbsp_mesgin3: 7854568Sgibbs cmp A,2 jne p_mesgin4 # save data pointers code? 7864568Sgibbs 7874568Sgibbs call sg_ram2scb 7884568Sgibbs jmp p_mesgin_done 7894568Sgibbs 7904568Sgibbs# Restore pointers message? Data pointers are recopied from the 7914568Sgibbs# SCB anyway at the start of any DMA operation, so the only thing 7924568Sgibbs# to copy is the scatter-gather values. 7934568Sgibbs# 7944568Sgibbsp_mesgin4: 7954568Sgibbs cmp A,3 jne p_mesgin5 # restore pointers code? 7964568Sgibbs 7974568Sgibbs call sg_scb2ram 7984568Sgibbs jmp p_mesgin_done 7994568Sgibbs 8004568Sgibbs# Identify message? For a reconnecting target, this tells us the lun 8014568Sgibbs# that the reconnection is for - find the correct SCB and switch to it, 8024568Sgibbs# clearing the "disconnected" bit so we don't "find" it by accident later. 8034568Sgibbs# 8044568Sgibbsp_mesgin5: 8054568Sgibbs test A,0x80 jz p_mesgin6 # identify message? 8064568Sgibbs 8074568Sgibbs test A,0x78 jnz p_mesginN # !DiscPriv|!LUNTAR|!Reserved 8084568Sgibbs 8097118Sgibbs and A,0x07 # lun in lower three bits 8106608Sgibbs or SAVED_TCL,A,SELID 8116608Sgibbs and SAVED_TCL,0xf7 8126608Sgibbs and A,0x08,SBLKCTL # B Channel?? 8136608Sgibbs or SAVED_TCL,A 8147700Sgibbs call inb_last # ACK 8157700Sgibbs mov ALLZEROS call findSCB 8166608Sgibbssetup_SCB: 8175326Sgibbs and SCBARRAY+0,0xfb # clear disconnect bit in SCB 8187700Sgibbs or FLAGS,IDENTIFY_SEEN # make note of IDENTIFY 8194568Sgibbs 8204568Sgibbs call sg_scb2ram # implied restore pointers 8214568Sgibbs # required on reselect 8226608Sgibbs jmp ITloop 8236608Sgibbsget_tag: 8247700Sgibbs mvi A call inb_first 8257700Sgibbs cmp A,0x20 jne return # Simple Tag message? 8266608Sgibbs mvi A call inb_next 8277700Sgibbs call inb_last 8286608Sgibbs test A,0xf0 jnz abort_tag # Tag in range? 8296608Sgibbs mov SCBPTR,A 8306608Sgibbs mov A,SAVED_TCL 8316608Sgibbs cmp SCBARRAY+1,A jne abort_tag 8326608Sgibbs test SCBARRAY+0,TAG_ENB jz abort_tag 8337700Sgibbs ret 8347700Sgibbsabort_tag: 8357700Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 8367700Sgibbs call scsisig 8377700Sgibbs mvi INTSTAT,ABORT_TAG # let driver know 8387700Sgibbs mvi 0xd call mk_mesg # ABORT TAG message 8397700Sgibbs ret 8406608Sgibbs 8415647Sgibbs# Message reject? Let the kernel driver handle this. If we have an 8425647Sgibbs# outstanding WDTR or SDTR negotiation, assume that it's a response from 8435647Sgibbs# the target selecting 8bit or asynchronous transfer, otherwise just ignore 8445647Sgibbs# it since we have no clue what it pertains to. 8454568Sgibbs# 8464568Sgibbsp_mesgin6: 8474568Sgibbs cmp A,7 jne p_mesgin7 # message reject code? 8484568Sgibbs 8495647Sgibbs mvi INTSTAT, MSG_REJECT 8505562Sgibbs jmp p_mesgin_done 8515562Sgibbs 8524568Sgibbs# [ ADD MORE MESSAGE HANDLING HERE ] 8534568Sgibbs# 8544568Sgibbsp_mesgin7: 8554568Sgibbs 8564568Sgibbs# We have no idea what this message in is, and there's no way 8574568Sgibbs# to pass it up to the kernel, so we issue a message reject and 8584568Sgibbs# hope for the best. Since we're now using manual PIO mode to 8594568Sgibbs# read in the message, there should no longer be a race condition 8604568Sgibbs# present when we assert ATN. In any case, rejection should be a 8614568Sgibbs# rare occurrence - signal the driver when it happens. 8624568Sgibbs# 8634568Sgibbsp_mesginN: 8644568Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 8654568Sgibbs call scsisig 8665647Sgibbs mvi INTSTAT,SEND_REJECT # let driver know 8674568Sgibbs 8684568Sgibbs mvi 0x7 call mk_mesg # MESSAGE REJECT message 8694568Sgibbs 8704568Sgibbsp_mesgin_done: 8714568Sgibbs call inb_last # ack & turn auto PIO back on 8724568Sgibbs jmp ITloop 8734568Sgibbs 8746608Sgibbs 8754568Sgibbs# Bus free phase. It might be useful to interrupt the device 8764568Sgibbs# driver if we aren't expecting this. For now, make sure that 8774568Sgibbs# ATN isn't being asserted and look for a new command. 8784568Sgibbs# 8794568Sgibbsp_busfree: 8804568Sgibbs mvi CLRSINT1,0x40 # CLRATNO 8814568Sgibbs clr SIGSTATE 8828567Sdg 8838567Sdg# if this is an immediate command, perform a psuedo command complete to 8848567Sdg# notify the driver. 8858567Sdg test SCBARRAY+11,0xff jz status_ok 8864568Sgibbs jmp start 8874568Sgibbs 8885775Sgibbs# Instead of a generic bcopy routine that requires an argument, we unroll 8895775Sgibbs# the two cases that are actually used, and call them explicitly. This 8905775Sgibbs# not only reduces the overhead of doing a bcopy by 2/3rds, but ends up 8915775Sgibbs# saving space in the program since you don't have to put the argument 8925775Sgibbs# into the accumulator before the call. Both functions expect DINDEX to 8935775Sgibbs# contain the destination address and SINDEX to contain the source 8945775Sgibbs# address. 8955775Sgibbsbcopy_3: 8964568Sgibbs mov DINDIR,SINDIR 8975775Sgibbs mov DINDIR,SINDIR 8985775Sgibbs mov DINDIR,SINDIR ret 8994568Sgibbs 9005775Sgibbsbcopy_4: 9015775Sgibbs mov DINDIR,SINDIR 9025775Sgibbs mov DINDIR,SINDIR 9035775Sgibbs mov DINDIR,SINDIR 9045775Sgibbs mov DINDIR,SINDIR ret 9055775Sgibbs 9067532Sgibbsbcopy_3_dfdat: 9077532Sgibbs mov DINDIR,DFDAT 9087532Sgibbs mov DINDIR,DFDAT 9097532Sgibbs mov DINDIR,DFDAT ret 9105775Sgibbs 9117532Sgibbsbcopy_4_dfdat: 9127532Sgibbs mov DINDIR,DFDAT 9137532Sgibbs mov DINDIR,DFDAT 9147532Sgibbs mov DINDIR,DFDAT 9157532Sgibbs mov DINDIR,DFDAT ret 9167532Sgibbs 9174568Sgibbs# Locking the driver out, build a one-byte message passed in SINDEX 9184568Sgibbs# if there is no active message already. SINDEX is returned intact. 9194568Sgibbs# 9204568Sgibbsmk_mesg: 9214866Sgibbs mvi SEQCTL,0x50 # PAUSEDIS|FASTMODE 9225562Sgibbs test FLAGS,ACTIVE_MSG jnz mk_mesg1 # active message? 9234568Sgibbs 9245562Sgibbs or FLAGS,ACTIVE_MSG # if not, there is now 9254568Sgibbs mvi MSG_LEN,1 # length = 1 9264568Sgibbs mov MSG_START+0,SINDEX # 1-byte message 9274568Sgibbs 9284568Sgibbsmk_mesg1: 9295775Sgibbs mvi SEQCTL,0x10 ret # !PAUSEDIS|FASTMODE 9304568Sgibbs 9314568Sgibbs# Carefully read data in Automatic PIO mode. I first tried this using 9324568Sgibbs# Manual PIO mode, but it gave me continual underrun errors, probably 9334568Sgibbs# indicating that I did something wrong, but I feel more secure leaving 9344568Sgibbs# Automatic PIO on all the time. 9354568Sgibbs# 9364568Sgibbs# According to Adaptec's documentation, an ACK is not sent on input from 9374568Sgibbs# the target until SCSIDATL is read from. So we wait until SCSIDATL is 9384568Sgibbs# latched (the usual way), then read the data byte directly off the bus 9394568Sgibbs# using SCSIBUSL. When we have pulled the ATN line, or we just want to 9404568Sgibbs# acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 9414568Sgibbs# spec guarantees that the target will hold the data byte on the bus until 9424568Sgibbs# we send our ACK. 9434568Sgibbs# 9444568Sgibbs# The assumption here is that these are called in a particular sequence, 9454568Sgibbs# and that REQ is already set when inb_first is called. inb_{first,next} 9464568Sgibbs# use the same calling convention as inb. 9474568Sgibbs# 9484568Sgibbsinb_first: 9497700Sgibbs clr STCNT+2 9507700Sgibbs clr STCNT+1 9514568Sgibbs mov DINDEX,SINDEX 9524568Sgibbs mov DINDIR,SCSIBUSL ret # read byte directly from bus 9534568Sgibbs 9544568Sgibbsinb_next: 9554568Sgibbs mov DINDEX,SINDEX # save SINDEX 9564568Sgibbs 9577700Sgibbs mvi STCNT+0,1 # xfer one byte 9584568Sgibbs mov NONE,SCSIDATL # dummy read from latch to ACK 9594568Sgibbsinb_next1: 9604568Sgibbs test SSTAT0,0x4 jz inb_next1 # SDONE 9614568Sgibbsinb_next2: 9624568Sgibbs test SSTAT0,0x2 jz inb_next2 # SPIORDY - wait for next byte 9634568Sgibbs mov DINDIR,SCSIBUSL ret # read byte directly from bus 9644568Sgibbs 9654568Sgibbsinb_last: 9667700Sgibbs mvi STCNT+0,1 # ACK with dummy read 9674568Sgibbs mov NONE,SCSIDATL 9684568Sgibbsinb_last1: 9694568Sgibbs test SSTAT0,0x4 jz inb_last1 # wait for completion 9704568Sgibbs ret 9714568Sgibbs 9724568Sgibbs# DMA data transfer. HADDR and HCNT must be loaded first, and 9734568Sgibbs# SINDEX should contain the value to load DFCNTRL with - 0x3d for 9744568Sgibbs# host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 9754568Sgibbs# during initialization. 9764568Sgibbs# 9774568Sgibbsdma: 9784568Sgibbs mov DFCNTRL,SINDEX 9794568Sgibbsdma1: 9804568Sgibbsdma2: 9814568Sgibbs test SSTAT0,0x1 jnz dma3 # DMADONE 9824568Sgibbs test SSTAT1,0x10 jz dma1 # PHASEMIS, ie. underrun 9834568Sgibbs 9844568Sgibbs# We will be "done" DMAing when the transfer count goes to zero, or 9854568Sgibbs# the target changes the phase (in light of this, it makes sense that 9864568Sgibbs# the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 9874866Sgibbs# doing a SCSI->Host transfer, the data FIFO should be flushed auto- 9884866Sgibbs# magically on STCNT=0 or a phase change, so just wait for FIFO empty 9894866Sgibbs# status. 9904568Sgibbs# 9914568Sgibbsdma3: 9924568Sgibbs test SINDEX,0x4 jnz dma5 # DIRECTION 9934568Sgibbsdma4: 9945562Sgibbs test DFSTATUS,0x1 jz dma4 # !FIFOEMP 9954568Sgibbs 9964568Sgibbs# Now shut the DMA enables off, and copy STCNT (ie. the underrun 9974568Sgibbs# amount, if any) to the SCB registers; SG_COUNT will get copied to 9984568Sgibbs# the SCB's residual S/G count field after sg_advance is called. Make 9994568Sgibbs# sure that the DMA enables are actually off first lest we get an ILLSADDR. 10004568Sgibbs# 10014568Sgibbsdma5: 10024568Sgibbs clr DFCNTRL # disable DMA 10034568Sgibbsdma6: 10044568Sgibbs test DFCNTRL,0x38 jnz dma6 # SCSIENACK|SDMAENACK|HDMAENACK 10054568Sgibbs 10064568Sgibbs mvi DINDEX,SCBARRAY+15 10075775Sgibbs mvi STCNT call bcopy_3 10084568Sgibbs 10094568Sgibbs ret 10104568Sgibbs 10117532Sgibbsdma_finish: 10127532Sgibbs test DFSTATUS,0x8 jz dma_finish # HDONE 10137532Sgibbs 10147532Sgibbs clr DFCNTRL # disable DMA 10157532Sgibbsdma_finish2: 10167532Sgibbs test DFCNTRL,0x8 jnz dma_finish2 # HDMAENACK 10177532Sgibbs ret 10187532Sgibbs 10194568Sgibbs# Common SCSI initialization for selection and reselection. Expects 10204568Sgibbs# the target SCSI ID to be in the upper four bits of SINDEX, and A's 10214568Sgibbs# contents are stomped on return. 10224568Sgibbs# 10238104Sgibbsinitialize_scsiid: 10245775Sgibbs and SINDEX,0xf0 # Get target ID 10255775Sgibbs and A,0x0f,SCSIID 10265775Sgibbs or SINDEX,A 10278104Sgibbs mov SCSIID,SINDEX ret 10285326Sgibbs 10298104Sgibbsinitialize_for_target: 10305775Sgibbs# Turn on Automatic PIO mode now, before we expect to see a REQ 10314568Sgibbs# from the target. It shouldn't hurt anything to leave it on. Set 10324568Sgibbs# CLRCHN here before the target has entered a data transfer mode - 10334568Sgibbs# with synchronous SCSI, if you do it later, you blow away some 10344568Sgibbs# data in the SCSI FIFO that the target has already sent to you. 10354568Sgibbs# 10368104Sgibbs clr SIGSTATE 10378104Sgibbs 10384866Sgibbs mvi SXFRCTL0,0x8a # DFON|SPIOEN|CLRCHN 10394568Sgibbs 10404568Sgibbs# Initialize scatter-gather pointers by setting up the working copy 10414568Sgibbs# in scratch RAM. 10424568Sgibbs# 10434568Sgibbs call sg_scb2ram 10444568Sgibbs 10454568Sgibbs# Initialize SCSIRATE with the appropriate value for this target. 10464568Sgibbs# 10475562Sgibbs call ndx_dtr 10485775Sgibbs mov SCSIRATE,SINDIR ret 10494568Sgibbs 10504568Sgibbs# Assert that if we've been reselected, then we've seen an IDENTIFY 10514568Sgibbs# message. 10524568Sgibbs# 10534568Sgibbsassert: 10547532Sgibbs test FLAGS,RESELECTED jz return # reselected? 10557532Sgibbs test FLAGS,IDENTIFY_SEEN jnz return # seen IDENTIFY? 10564568Sgibbs 10577532Sgibbs mvi INTSTAT,NO_IDENT ret # no - cause a kernel panic 10584568Sgibbs 10594568Sgibbs# Find out if disconnection is ok from the information the BIOS has left 10605326Sgibbs# us. The tcl from SCBARRAY+1 should be in SINDEX; A will 10614866Sgibbs# contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok) 10624568Sgibbs# on exit. 10634568Sgibbs# 10645326Sgibbs# To allow for wide or twin busses, we check the upper bit of the target ID 10655326Sgibbs# and the channel ID and look at the appropriate disconnect register. 10664568Sgibbs# 10674568Sgibbsdisconnect: 10684568Sgibbs and FUNCTION1,0x70,SINDEX # strip off extra just in case 10694568Sgibbs mov A,FUNCTION1 10705326Sgibbs test SINDEX, 0x88 jz disconnect_a 10715326Sgibbs 10725326Sgibbs test DISC_DSB_B,A jz disconnect1 # bit nonzero if DISabled 10735326Sgibbs clr A ret 10745326Sgibbs 10755326Sgibbsdisconnect_a: 10764568Sgibbs test DISC_DSB_A,A jz disconnect1 # bit nonzero if DISabled 10775326Sgibbs clr A ret 10784568Sgibbs 10794568Sgibbsdisconnect1: 10804568Sgibbs mvi A,0x40 ret 10814568Sgibbs 10826608Sgibbs# Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch 10836608Sgibbs# the SCB to it. Have the kernel print a warning message if it can't be 10846608Sgibbs# found, and generate an ABORT message to the target. SINDEX should be 10856608Sgibbs# cleared on call. 10864568Sgibbs# 10874568SgibbsfindSCB: 10886608Sgibbs mov A,SAVED_TCL 10894568Sgibbs mov SCBPTR,SINDEX # switch to new SCB 10906608Sgibbs cmp SCBARRAY+1,A jne findSCB1 # target ID/channel/lun match? 10916608Sgibbs test SCBARRAY+0,0x4 jz findSCB1 # should be disconnected 10927700Sgibbs test SCBARRAY+0,TAG_ENB jnz get_tag 10934568Sgibbs ret 10944568Sgibbs 10956608SgibbsfindSCB1: 10964568Sgibbs inc SINDEX 10974568Sgibbs mov A,SCBCOUNT 10986608Sgibbs cmp SINDEX,A jne findSCB 10994568Sgibbs 11005647Sgibbs mvi INTSTAT,NO_MATCH # not found - signal kernel 11014568Sgibbs mvi 0x6 call mk_mesg # ABORT message 11024568Sgibbs 11034568Sgibbs or SINDEX,0x10,SIGSTATE # assert ATNO 11044568Sgibbs call scsisig 11054568Sgibbs ret 11064568Sgibbs 11074568Sgibbs# Make a working copy of the scatter-gather parameters in the SCB. 11084568Sgibbs# 11094568Sgibbssg_scb2ram: 11104568Sgibbs mov SG_COUNT,SCBARRAY+2 11114568Sgibbs 11124568Sgibbs mvi DINDEX,SG_NEXT 11135775Sgibbs mvi SCBARRAY+3 call bcopy_4 11144568Sgibbs 11154568Sgibbs mvi SG_NOLOAD,0x80 11167532Sgibbs test SCBARRAY+0,0x10 jnz return # don't reload s/g? 11177532Sgibbs clr SG_NOLOAD ret 11184568Sgibbs 11194568Sgibbs# Copying RAM values back to SCB, for Save Data Pointers message. 11204568Sgibbs# 11214568Sgibbssg_ram2scb: 11224568Sgibbs mov SCBARRAY+2,SG_COUNT 11234568Sgibbs 11244568Sgibbs mvi DINDEX,SCBARRAY+3 11255775Sgibbs mvi SG_NEXT call bcopy_4 11264568Sgibbs 11274568Sgibbs and SCBARRAY+0,0xef,SCBARRAY+0 11287532Sgibbs test SG_NOLOAD,0x80 jz return # reload s/g? 11297532Sgibbs or SCBARRAY+0,SG_LOAD ret 11304568Sgibbs 11314568Sgibbs# Load a struct scatter if needed and set up the data address and 11324568Sgibbs# length. If the working value of the SG count is nonzero, then 11334568Sgibbs# we need to load a new set of values. 11344568Sgibbs# 11354568Sgibbs# This, like the above DMA, assumes a little-endian host data storage. 11364568Sgibbs# 11374568Sgibbssg_load: 11387532Sgibbs test SG_COUNT,0xff jz return # SG being used? 11397532Sgibbs test SG_NOLOAD,0x80 jnz return # don't reload s/g? 11404568Sgibbs 11414568Sgibbs clr HCNT+2 11424568Sgibbs clr HCNT+1 11434568Sgibbs mvi HCNT+0,SG_SIZEOF 11444568Sgibbs 11454568Sgibbs mvi DINDEX,HADDR 11465775Sgibbs mvi SG_NEXT call bcopy_4 11474568Sgibbs 11484568Sgibbs mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET 11494568Sgibbs 11504568Sgibbs# Wait for DMA from host memory to data FIFO to complete, then disable 11514568Sgibbs# DMA and wait for it to acknowledge that it's off. 11524568Sgibbs# 11534568Sgibbs 11547532Sgibbs call dma_finish 11554568Sgibbs 11564568Sgibbs# Copy data from FIFO into SCB data pointer and data count. This assumes 11574568Sgibbs# that the struct scatterlist has this structure (this and sizeof(struct 11584568Sgibbs# scatterlist) == 12 are asserted in aic7xxx.c): 11594568Sgibbs# 11604568Sgibbs# struct scatterlist { 11614568Sgibbs# char *address; /* four bytes, little-endian order */ 11624568Sgibbs# ... /* four bytes, ignored */ 11634568Sgibbs# unsigned short length; /* two bytes, little-endian order */ 11644568Sgibbs# } 11654568Sgibbs# 11664568Sgibbs 11677532Sgibbs# Not in FreeBSD. the scatter list entry is only 8 bytes. 11684568Sgibbs# 11694568Sgibbs# struct ahc_dma_seg { 11704568Sgibbs# physaddr addr; /* four bytes, little-endian order */ 11714568Sgibbs# long len; /* four bytes, little endian order */ 11724568Sgibbs# }; 11734568Sgibbs# 11744568Sgibbs 11757532Sgibbs mvi DINDEX, SCBARRAY+19 11767532Sgibbs call bcopy_4_dfdat 11774568Sgibbs 11785647Sgibbs# For Linux, we must throw away four bytes since there is a 32bit gap 11795647Sgibbs# in the middle of a struct scatterlist 11805647Sgibbs# mov NONE,DFDAT 11815647Sgibbs# mov NONE,DFDAT 11825647Sgibbs# mov NONE,DFDAT 11835647Sgibbs# mov NONE,DFDAT 11845647Sgibbs 11857532Sgibbs call bcopy_3_dfdat #Only support 24 bit length. 11864568Sgibbs ret 11874568Sgibbs 11884568Sgibbs# Advance the scatter-gather pointers only IF NEEDED. If SG is enabled, 11894568Sgibbs# and the SCSI transfer count is zero (note that this should be called 11904568Sgibbs# right after a DMA finishes), then move the working copies of the SG 11914568Sgibbs# pointer/length along. If the SCSI transfer count is not zero, then 11924568Sgibbs# presumably the target is disconnecting - do not reload the SG values 11934568Sgibbs# next time. 11944568Sgibbs# 11954568Sgibbssg_advance: 11967532Sgibbs test SG_COUNT,0xff jz return # s/g enabled? 11974568Sgibbs 11984568Sgibbs test STCNT+0,0xff jnz sg_advance1 # SCSI transfer count nonzero? 11994568Sgibbs test STCNT+1,0xff jnz sg_advance1 12004568Sgibbs test STCNT+2,0xff jnz sg_advance1 12014568Sgibbs 12024568Sgibbs clr SG_NOLOAD # reload s/g next time 12034568Sgibbs dec SG_COUNT # one less segment to go 12044568Sgibbs 12054568Sgibbs clr A # add sizeof(struct scatter) 12064568Sgibbs add SG_NEXT+0,SG_SIZEOF,SG_NEXT+0 12074568Sgibbs adc SG_NEXT+1,A,SG_NEXT+1 12084568Sgibbs adc SG_NEXT+2,A,SG_NEXT+2 12095775Sgibbs adc SG_NEXT+3,A,SG_NEXT+3 ret 12104568Sgibbs 12114568Sgibbssg_advance1: 12127532Sgibbs mvi SG_NOLOAD,0x80 ret # don't reload s/g next time 12134568Sgibbs 12144568Sgibbs# Add the array base SYNCNEG to the target offset (the target address 12154568Sgibbs# is in SCSIID), and return the result in SINDEX. The accumulator 12164568Sgibbs# contains the 3->8 decoding of the target ID on return. 12174568Sgibbs# 12185562Sgibbsndx_dtr: 12194568Sgibbs shr A,SCSIID,4 12205562Sgibbs test SBLKCTL,0x08 jz ndx_dtr_2 12215326Sgibbs or A,0x08 # Channel B entries add 8 12225562Sgibbsndx_dtr_2: 12234568Sgibbs add SINDEX,SYNCNEG,A 12244568Sgibbs 12254568Sgibbs and FUNCTION1,0x70,SCSIID # 3-bit target address decode 12264568Sgibbs mov A,FUNCTION1 ret 12274568Sgibbs 12285562Sgibbs# If we need to negotiate transfer parameters, build the WDTR or SDTR message 12294568Sgibbs# starting at the address passed in SINDEX. DINDEX is modified on return. 12305562Sgibbs# The SCSI-II spec requires that Wide negotiation occur first and you can 12315562Sgibbs# only negotiat one or the other at a time otherwise in the event of a message 12325562Sgibbs# reject, you wouldn't be able to tell which message was the culpret. 12334568Sgibbs# 12345562Sgibbsmk_dtr: 12357532Sgibbs test SCBARRAY+0,0xc0 jz return # NEEDWDTR|NEEDSDTR 12365647Sgibbs test SCBARRAY+0,NEEDWDTR jnz mk_wdtr_16bit 12378567Sdg or FLAGS, MAX_OFFSET # Force an offset of 15 or 8 if WIDE 12384568Sgibbs 12397532Sgibbsmk_sdtr: 12407532Sgibbs mvi DINDIR,1 # extended message 12417532Sgibbs mvi DINDIR,3 # extended message length = 3 12427532Sgibbs mvi DINDIR,1 # SDTR code 12437532Sgibbs call sdtr_to_rate 12447532Sgibbs mov DINDIR,RETURN_1 # REQ/ACK transfer period 12458567Sdg test FLAGS, MAX_OFFSET jnz mk_sdtr_max_offset 12468567Sdg and DINDIR,0x0f,SINDIR # Sync Offset 12477532Sgibbs 12487532Sgibbsmk_sdtr_done: 12497532Sgibbs add MSG_LEN,-MSG_START+0,DINDEX ret # update message length 12507532Sgibbs 12518567Sdgmk_sdtr_max_offset: 12528567Sdg# We're initiating sync negotiation, so request the max offset we can (15 or 8) 12538567Sdg xor FLAGS, MAX_OFFSET 12548567Sdg test SCSIRATE, 0x80 jnz wmax_offset # Talking to a WIDE device? 12558567Sdg mvi DINDIR, MAX_OFFSET_8BIT 12567532Sgibbs jmp mk_sdtr_done 12577532Sgibbs 12588567Sdgwmax_offset: 12598567Sdg mvi DINDIR, MAX_OFFSET_WIDE 12608567Sdg jmp mk_sdtr_done 12618567Sdg 12625647Sgibbsmk_wdtr_16bit: 12635647Sgibbs mvi ARG_1,BUS_16_BIT 12645562Sgibbsmk_wdtr: 12654568Sgibbs mvi DINDIR,1 # extended message 12665562Sgibbs mvi DINDIR,2 # extended message length = 2 12675562Sgibbs mvi DINDIR,3 # WDTR code 12685562Sgibbs mov DINDIR,ARG_1 # bus width 12695562Sgibbs 12705775Sgibbs add MSG_LEN,-MSG_START+0,DINDEX ret # update message length 12715562Sgibbs 12724568Sgibbs# Set SCSI bus control signal state. This also saves the last-written 12734568Sgibbs# value into a location where the higher-level driver can read it - if 12744568Sgibbs# it has to send an ABORT or RESET message, then it needs to know this 12754568Sgibbs# so it can assert ATN without upsetting SCSISIGO. The new value is 12764568Sgibbs# expected in SINDEX. Change the actual state last to avoid contention 12774568Sgibbs# from the driver. 12784568Sgibbs# 12794568Sgibbsscsisig: 12804568Sgibbs mov SIGSTATE,SINDEX 12814568Sgibbs mov SCSISIGO,SINDEX ret 12825562Sgibbs 12835562Sgibbssdtr_to_rate: 12845562Sgibbs call ndx_dtr # index scratch space for target 12855562Sgibbs shr A,SINDIR,0x4 12865562Sgibbs dec SINDEX #Preserve SINDEX 12875562Sgibbs and A,0x7 12885562Sgibbs clr RETURN_1 12895562Sgibbssdtr_to_rate_loop: 12905562Sgibbs test A,0x0f jz sdtr_to_rate_done 12915562Sgibbs add RETURN_1,0x18 12925562Sgibbs dec A 12935562Sgibbs jmp sdtr_to_rate_loop 12945562Sgibbssdtr_to_rate_done: 12955562Sgibbs shr RETURN_1,0x2 12965562Sgibbs add RETURN_1,0x18 ret 12977532Sgibbs 12987532Sgibbsreturn: 12997532Sgibbs ret 1300