aic7xxx.seq revision 6940
15562Sgibbs# @(#)aic7xxx.seq 1.32 94/11/29 jda 24568Sgibbs# 35647Sgibbs# Adaptec 274x/284x/294x device driver for Linux and FreeBSD. 44568Sgibbs# Copyright (c) 1994 The University of Calgary Department of Computer Science. 54568Sgibbs# 64568Sgibbs# This program is free software; you can redistribute it and/or modify 74568Sgibbs# it under the terms of the GNU General Public License as published by 84568Sgibbs# the Free Software Foundation; either version 2 of the License, or 94568Sgibbs# (at your option) any later version. 104568Sgibbs# 114568Sgibbs# This program is distributed in the hope that it will be useful, 124568Sgibbs# but WITHOUT ANY WARRANTY; without even the implied warranty of 134568Sgibbs# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 144568Sgibbs# GNU General Public License for more details. 154568Sgibbs# 164568Sgibbs# You should have received a copy of the GNU General Public License 174568Sgibbs# along with this program; if not, write to the Free Software 184568Sgibbs# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 195647Sgibbs# 204568Sgibbs 216608Sgibbs# FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 226608Sgibbs# optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org) 235647Sgibbs# 246940Sgibbs# $Id: aic7xxx.seq,v 1.8 1995/02/22 01:37:52 gibbs Exp $ 254568Sgibbs 266608SgibbsVERSION AIC7XXX_SEQ_VERSION 1.8 275647Sgibbs 284866SgibbsSCBMASK = 0x1f 294568Sgibbs 304568SgibbsSCSISEQ = 0x00 314568SgibbsSXFRCTL0 = 0x01 324568SgibbsSXFRCTL1 = 0x02 334568SgibbsSCSISIGI = 0x03 344568SgibbsSCSISIGO = 0x03 354568SgibbsSCSIRATE = 0x04 364568SgibbsSCSIID = 0x05 374568SgibbsSCSIDATL = 0x06 384568SgibbsSTCNT = 0x08 394568SgibbsSTCNT+0 = 0x08 404568SgibbsSTCNT+1 = 0x09 414568SgibbsSTCNT+2 = 0x0a 424568SgibbsSSTAT0 = 0x0b 434568SgibbsCLRSINT1 = 0x0c 444568SgibbsSSTAT1 = 0x0c 454568SgibbsSIMODE1 = 0x11 464568SgibbsSCSIBUSL = 0x12 474568SgibbsSHADDR = 0x14 484568SgibbsSELID = 0x19 494568SgibbsSBLKCTL = 0x1f 504568SgibbsSEQCTL = 0x60 514568SgibbsA = 0x64 # == ACCUM 524568SgibbsSINDEX = 0x65 534568SgibbsDINDEX = 0x66 544568SgibbsALLZEROS = 0x6a 554568SgibbsNONE = 0x6a 564568SgibbsSINDIR = 0x6c 574568SgibbsDINDIR = 0x6d 584568SgibbsFUNCTION1 = 0x6e 594568SgibbsHADDR = 0x88 604568SgibbsHCNT = 0x8c 614568SgibbsHCNT+0 = 0x8c 624568SgibbsHCNT+1 = 0x8d 634568SgibbsHCNT+2 = 0x8e 644568SgibbsSCBPTR = 0x90 654568SgibbsINTSTAT = 0x91 664568SgibbsDFCNTRL = 0x93 674568SgibbsDFSTATUS = 0x94 684568SgibbsDFDAT = 0x99 694568SgibbsQINFIFO = 0x9b 704568SgibbsQINCNT = 0x9c 714568SgibbsQOUTFIFO = 0x9d 724568Sgibbs 735326SgibbsSCSICONF_A = 0x5a 745326SgibbsSCSICONF_B = 0x5b 754568Sgibbs 764568Sgibbs# The two reserved bytes at SCBARRAY+1[23] are expected to be set to 774568Sgibbs# zero, and the reserved bit in SCBARRAY+0 is used as an internal flag 784568Sgibbs# to indicate whether or not to reload scatter-gather parameters after 795647Sgibbs# a disconnect. We also use bits 6 & 7 to indicate whether or not to 805647Sgibbs# initiate SDTR or WDTR repectively when starting this command. 814568Sgibbs# 824568SgibbsSCBARRAY+0 = 0xa0 835647Sgibbs 845647SgibbsDISCONNECTED = 0x04 855647SgibbsNEEDDMA = 0x08 865647SgibbsSG_LOAD = 0x10 876608SgibbsTAG_ENB = 0x20 885647SgibbsNEEDSDTR = 0x40 895647SgibbsNEEDWDTR = 0x80 905647Sgibbs 914568SgibbsSCBARRAY+1 = 0xa1 924568SgibbsSCBARRAY+2 = 0xa2 934568SgibbsSCBARRAY+3 = 0xa3 945647SgibbsSCBARRAY+4 = 0xa4 955647SgibbsSCBARRAY+5 = 0xa5 965647SgibbsSCBARRAY+6 = 0xa6 974568SgibbsSCBARRAY+7 = 0xa7 985647SgibbsSCBARRAY+8 = 0xa8 995647SgibbsSCBARRAY+9 = 0xa9 1005647SgibbsSCBARRAY+10 = 0xaa 1014568SgibbsSCBARRAY+11 = 0xab 1025647SgibbsSCBARRAY+12 = 0xac 1035647SgibbsSCBARRAY+13 = 0xad 1044568SgibbsSCBARRAY+14 = 0xae 1054568SgibbsSCBARRAY+15 = 0xaf 1064568SgibbsSCBARRAY+16 = 0xb0 1074568SgibbsSCBARRAY+17 = 0xb1 1084568SgibbsSCBARRAY+18 = 0xb2 1094568SgibbsSCBARRAY+19 = 0xb3 1104568SgibbsSCBARRAY+20 = 0xb4 1114568SgibbsSCBARRAY+21 = 0xb5 1124568SgibbsSCBARRAY+22 = 0xb6 1134568SgibbsSCBARRAY+23 = 0xb7 1144568SgibbsSCBARRAY+24 = 0xb8 1154568SgibbsSCBARRAY+25 = 0xb9 1165647SgibbsSCBARRAY+26 = 0xba 1174568Sgibbs 1185647SgibbsBAD_PHASE = 0x01 # unknown scsi bus phase 1195647SgibbsSEND_REJECT = 0x11 # sending a message reject 1205647SgibbsNO_IDENT = 0x21 # no IDENTIFY after reconnect 1215647SgibbsNO_MATCH = 0x31 # no cmd match for reconnect 1225647SgibbsMSG_SDTR = 0x41 # SDTR message recieved 1235647SgibbsMSG_WDTR = 0x51 # WDTR message recieved 1245647SgibbsMSG_REJECT = 0x61 # Reject message recieved 1255647SgibbsBAD_STATUS = 0x71 # Bad status from target 1264568Sgibbs 1274568Sgibbs# The host adapter card (at least the BIOS) uses 20-2f for SCSI 1285326Sgibbs# device information, 32-33 and 5a-5f as well. As it turns out, the 1295326Sgibbs# BIOS trashes 20-2f, writing the synchronous negotiation results 1304568Sgibbs# on top of the BIOS values, so we re-use those for our per-target 1314568Sgibbs# scratchspace (actually a value that can be copied directly into 1325326Sgibbs# SCSIRATE). The kernel driver will enable synchronous negotiation 1335326Sgibbs# for all targets that have a value other than 0 in the lower four 1345326Sgibbs# bits of the target scratch space. This should work irregardless of 1355647Sgibbs# whether the bios has been installed. NEEDWDTR and NEEDSDTR are the top 1365647Sgibbs# two bits of the SCB control byte. The kernel driver will set these 1375647Sgibbs# when a WDTR or SDTR message should be sent to the target the SCB's 1385647Sgibbs# command references. 1394568Sgibbs# 1404568Sgibbs# The high bit of DROPATN is set if ATN should be dropped before the ACK 1414568Sgibbs# when outb is called. REJBYTE contains the first byte of a MESSAGE IN 1424568Sgibbs# message, so the driver can report an intelligible error if a message is 1434568Sgibbs# rejected. 1444568Sgibbs# 1455562Sgibbs# FLAGS's high bit is true if we are currently handling a reselect; 1464568Sgibbs# its next-highest bit is true ONLY IF we've seen an IDENTIFY message 1474568Sgibbs# from the reselecting target. If we haven't had IDENTIFY, then we have 1484568Sgibbs# no idea what the lun is, and we can't select the right SCB register 1494568Sgibbs# bank, so force a kernel panic if the target attempts a data in/out or 1504568Sgibbs# command phase instead of corrupting something. 1514568Sgibbs# 1524568Sgibbs# Note that SG_NEXT occupies four bytes. 1534568Sgibbs# 1544568SgibbsSYNCNEG = 0x20 1554568Sgibbs 1564568SgibbsDROPATN = 0x30 1574568SgibbsREJBYTE = 0x31 1585326SgibbsDISC_DSB_A = 0x32 1595326SgibbsDISC_DSB_B = 0x33 1604568Sgibbs 1616608SgibbsMSG_LEN = 0x34 1626608SgibbsMSG_START+0 = 0x35 1636608SgibbsMSG_START+1 = 0x36 1646608SgibbsMSG_START+2 = 0x37 1656608SgibbsMSG_START+3 = 0x38 1666608SgibbsMSG_START+4 = 0x39 1676608SgibbsMSG_START+5 = 0x3a 1686608Sgibbs-MSG_START+0 = 0xcb # 2's complement of MSG_START+0 1694568Sgibbs 1706608SgibbsARG_1 = 0x4a # sdtr conversion args & return 1715647SgibbsBUS_16_BIT = 0x01 1726608SgibbsRETURN_1 = 0x4a 1734568Sgibbs 1746608SgibbsSIGSTATE = 0x4b # value written to SCSISIGO 1754568Sgibbs 1765647Sgibbs# Linux users should use 0xc (12) for SG_SIZEOF 1775647SgibbsSG_SIZEOF = 0x8 # sizeof(struct ahc_dma) 1785647Sgibbs#SG_SIZEOF = 0xc # sizeof(struct scatterlist) 1795647SgibbsSCB_SIZEOF = 0x13 # sizeof SCB to DMA (19 bytes) 1805647Sgibbs 1816608SgibbsSG_NOLOAD = 0x4c # load SG pointer/length? 1826608SgibbsSG_COUNT = 0x4d # working value of SG count 1836608SgibbsSG_NEXT = 0x4e # working value of SG pointer 1846608SgibbsSG_NEXT+0 = 0x4e 1856608SgibbsSG_NEXT+1 = 0x4f 1866608SgibbsSG_NEXT+2 = 0x50 1876608SgibbsSG_NEXT+3 = 0x51 1884568Sgibbs 1896608SgibbsSCBCOUNT = 0x52 # the actual number of SCBs 1906608SgibbsFLAGS = 0x53 # Device configuration flags 1915326SgibbsTWIN_BUS = 0x01 1925326SgibbsWIDE_BUS = 0x02 1935562SgibbsSENSE = 0x10 1945562SgibbsACTIVE_MSG = 0x20 1955562SgibbsIDENTIFY_SEEN = 0x40 1965562SgibbsRESELECTED = 0x80 1974568Sgibbs 1986608SgibbsACTIVE_A = 0x54 1996608SgibbsACTIVE_B = 0x55 2006608SgibbsSAVED_TCL = 0x56 2014866Sgibbs# Poll QINCNT for work - the lower bits contain 2024568Sgibbs# the number of entries in the Queue In FIFO. 2034568Sgibbs# 2044568Sgibbsstart: 2055562Sgibbs test FLAGS,SENSE jnz start_sense 2065775Sgibbsstart_nosense: 2075326Sgibbs test FLAGS,TWIN_BUS jz start2 # Are we a twin channel device? 2085326Sgibbs# For fairness, we check the other bus first, since we just finished a 2095326Sgibbs# transaction on the current channel. 2105326Sgibbs xor SBLKCTL,0x08 # Toggle to the other bus 2114568Sgibbs test SCSISIGI,0x4 jnz reselect # BSYI 2125326Sgibbs xor SBLKCTL,0x08 # Toggle to the original bus 2135326Sgibbsstart2: 2145326Sgibbs test SCSISIGI,0x4 jnz reselect # BSYI 2155775Sgibbs test QINCNT,SCBMASK jz start_nosense 2164568Sgibbs 2175647Sgibbs# We have at least one queued SCB now. Set the SCB pointer 2185647Sgibbs# from the FIFO so we see the right bank of SCB registers, 2195647Sgibbs# then set SCSI options and set the initiator and target 2205647Sgibbs# SCSI IDs. 2214568Sgibbs# 2224568Sgibbs mov SCBPTR,QINFIFO 2234568Sgibbs 2245647Sgibbs# If the control byte of this SCB has the NEEDDMA flag set, we have 2255647Sgibbs# yet to DMA it from host memory 2265647Sgibbs 2275647Sgibbstest SCBARRAY+0,NEEDDMA jz test_busy 2285647Sgibbs clr HCNT+2 2295647Sgibbs clr HCNT+1 2305647Sgibbs mvi HCNT+0,SCB_SIZEOF 2315647Sgibbs 2325647Sgibbs mvi DINDEX,HADDR 2335775Sgibbs mvi SCBARRAY+26 call bcopy_4 2345647Sgibbs 2355647Sgibbs mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET 2365647Sgibbs 2375647Sgibbs# Wait for DMA from host memory to data FIFO to complete, then disable 2385647Sgibbs# DMA and wait for it to acknowledge that it's off. 2395647Sgibbs# 2405647Sgibbsscb_load1: 2415647Sgibbs test DFSTATUS,0x8 jz scb_load1 # HDONE 2425647Sgibbs 2435647Sgibbs clr DFCNTRL # disable DMA 2445647Sgibbsscb_load2: 2455647Sgibbs test DFCNTRL,0x8 jnz scb_load2 # HDMAENACK 2465647Sgibbs 2475647Sgibbs# Copy the SCB from the FIFO to the SCBARRAY 2485647Sgibbs 2495647Sgibbs mov SCBARRAY+0, DFDAT 2505647Sgibbs mov SCBARRAY+1, DFDAT 2515647Sgibbs mov SCBARRAY+2, DFDAT 2525647Sgibbs mov SCBARRAY+3, DFDAT 2535647Sgibbs mov SCBARRAY+4, DFDAT 2545647Sgibbs mov SCBARRAY+5, DFDAT 2555647Sgibbs mov SCBARRAY+6, DFDAT 2565647Sgibbs mov SCBARRAY+7, DFDAT 2575647Sgibbs mov SCBARRAY+8, DFDAT 2585647Sgibbs mov SCBARRAY+9, DFDAT 2595647Sgibbs mov SCBARRAY+10, DFDAT 2605647Sgibbs mov SCBARRAY+11, DFDAT 2615647Sgibbs mov SCBARRAY+12, DFDAT 2625647Sgibbs mov SCBARRAY+13, DFDAT 2635647Sgibbs mov SCBARRAY+14, DFDAT 2645647Sgibbs mov SCBARRAY+15, DFDAT 2655647Sgibbs mov SCBARRAY+16, DFDAT 2665647Sgibbs mov SCBARRAY+17, DFDAT 2675647Sgibbs mov SCBARRAY+18, DFDAT 2685647Sgibbs 2694568Sgibbs# See if there is not already an active SCB for this target. This code 2705326Sgibbs# locks out on a per target basis instead of target/lun. Although this 2715326Sgibbs# is not ideal for devices that have multiple luns active at the same 2725326Sgibbs# time, it is faster than looping through all SCB's looking for active 2735326Sgibbs# commands. It may be benificial to make findscb a more general procedure 2745326Sgibbs# to see if the added cost of the search is negligible. This code also 2755326Sgibbs# assumes that the kernel driver will clear the active flags on board 2765326Sgibbs# initialization, board reset, and a target's SELTO. 2774568Sgibbs 2785647Sgibbstest_busy: 2796608Sgibbs test SCBARRAY+0,0x20 jnz start_scb 2804568Sgibbs and FUNCTION1,0x70,SCBARRAY+1 2814568Sgibbs mov A,FUNCTION1 2825326Sgibbs test SCBARRAY+1,0x88 jz test_a # Id < 8 && A channel 2835326Sgibbs 2845326Sgibbs test ACTIVE_B,A jnz requeue 2855326Sgibbs or ACTIVE_B,A # Mark the current target as busy 2865326Sgibbs jmp start_scb 2875326Sgibbs 2885562Sgibbsstart_sense: 2895562Sgibbs# Clear the SENSE flag first, then do a normal start_scb 2905562Sgibbs and FLAGS,0xef 2915562Sgibbs jmp start_scb 2925562Sgibbs 2934568Sgibbs# Place the currently active back on the queue for later processing 2945326Sgibbsrequeue: 2954568Sgibbs mov QINFIFO, SCBPTR 2965775Sgibbs jmp start_nosense 2974568Sgibbs 2985326Sgibbstest_a: 2995326Sgibbs test ACTIVE_A,A jnz requeue 3005326Sgibbs or ACTIVE_A,A # Mark the current target as busy 3015326Sgibbs 3025326Sgibbsstart_scb: 3035647Sgibbs or SCBARRAY+0,NEEDDMA 3046940Sgibbs and SINDEX,0xf7,SBLKCTL #Clear the channel select bit 3056940Sgibbs and A,0x08,SCBARRAY+1 #Get new channel bit 3066940Sgibbs or SINDEX,A 3076940Sgibbs mov SBLKCTL,SINDEX # select channel 3084568Sgibbs mov SCBARRAY+1 call initialize 3094568Sgibbs clr SG_NOLOAD 3105562Sgibbs and FLAGS,0x3f # !RESELECTING 3114568Sgibbs 3124568Sgibbs# As soon as we get a successful selection, the target should go 3134568Sgibbs# into the message out phase since we have ATN asserted. Prepare 3144568Sgibbs# the message to send, locking out the device driver. If the device 3154568Sgibbs# driver hasn't beaten us with an ABORT or RESET message, then tack 3164866Sgibbs# on an SDTR negotiation if required. 3174568Sgibbs# 3184568Sgibbs# Messages are stored in scratch RAM starting with a flag byte (high bit 3194568Sgibbs# set means active message), one length byte, and then the message itself. 3204568Sgibbs# 3214568Sgibbs mov SCBARRAY+1 call disconnect # disconnect ok? 3224568Sgibbs 3234568Sgibbs and SINDEX,0x7,SCBARRAY+1 # lun 3244568Sgibbs or SINDEX,A # return value from disconnect 3254568Sgibbs or SINDEX,0x80 call mk_mesg # IDENTIFY message 3264568Sgibbs 3274568Sgibbs mov A,SINDEX 3286608Sgibbs test SCBARRAY+0,0xe0 jz !message # WDTR, SDTR or TAG?? 3294568Sgibbs cmp MSG_START+0,A jne !message # did driver beat us? 3304568Sgibbs 3316608Sgibbs# Tag Message if Tag enabled in SCB control block. Use SCBPTR as the tag 3326608Sgibbs# value 3336608Sgibbs 3346608Sgibbsmk_tag: 3356608Sgibbs mvi DINDEX, MSG_START+1 3366608Sgibbs test SCBARRAY+0,TAG_ENB jz mk_tag_done 3376608Sgibbs and A,0x23,SCBARRAY+0 3386608Sgibbs mov DINDIR,A 3396608Sgibbs mov DINDIR,SCBPTR 3406608Sgibbs 3416608Sgibbs add MSG_LEN,-MSG_START+0,DINDEX # update message length 3426608Sgibbs jmp !message # Can't do DTR when taged 3436608Sgibbs 3446608Sgibbsmk_tag_done: 3456608Sgibbs 3466608Sgibbs mov DINDEX call mk_dtr # build DTR message if needed 3476608Sgibbs 3484568Sgibbs!message: 3494568Sgibbs 3504568Sgibbs# Enable selection phase as an initiator, and do automatic ATN 3514568Sgibbs# after the selection. 3524568Sgibbs# 3534568Sgibbs mvi SCSISEQ,0x48 # ENSELO|ENAUTOATNO 3544568Sgibbs 3554568Sgibbs# Wait for successful arbitration. The AIC-7770 documentation says 3564568Sgibbs# that SELINGO indicates successful arbitration, and that it should 3574568Sgibbs# be used to look for SELDO. However, if the sequencer is paused at 3584568Sgibbs# just the right time - a parallel fsck(8) on two drives did it for 3594568Sgibbs# me - then SELINGO can flip back to false before we've seen it. This 3604568Sgibbs# makes the sequencer sit in the arbitration loop forever. This is 3614568Sgibbs# Not Good. 3624568Sgibbs# 3634568Sgibbs# Therefore, I've added a check in the arbitration loop for SELDO 3644568Sgibbs# too. This could arguably be made a critical section by disabling 3654568Sgibbs# pauses, but I don't want to make a potentially infinite loop a CS. 3664568Sgibbs# I suppose you could fold it into the select loop, too, but since 3674568Sgibbs# I've been hunting this bug for four days it's kinda like a trophy. 3684568Sgibbs# 3694568Sgibbsarbitrate: 3704568Sgibbs test SSTAT0,0x40 jnz *select # SELDO 3714568Sgibbs test SSTAT0,0x10 jz arbitrate # SELINGO 3724568Sgibbs 3734568Sgibbs# Wait for a successful selection. If the hardware selection 3744568Sgibbs# timer goes off, then the driver gets the interrupt, so we don't 3754568Sgibbs# need to worry about it. 3764568Sgibbs# 3774568Sgibbsselect: 3784568Sgibbs test SSTAT0,0x40 jz select # SELDO 3794568Sgibbs jmp *select 3804568Sgibbs 3814568Sgibbs# Reselection is being initiated by a target - we've seen the BSY 3824568Sgibbs# line driven active, and we didn't do it! Enable the reselection 3834568Sgibbs# hardware, and wait for it to finish. Make a note that we've been 3844568Sgibbs# reselected, but haven't seen an IDENTIFY message from the target 3854568Sgibbs# yet. 3864568Sgibbs# 3874568Sgibbsreselect: 3884568Sgibbs mvi SCSISEQ,0x10 # ENRSELI 3894568Sgibbs 3904568Sgibbsreselect1: 3914568Sgibbs test SSTAT0,0x20 jz reselect1 # SELDI 3924568Sgibbs mov SELID call initialize 3934568Sgibbs 3945562Sgibbs and FLAGS,0x3f # reselected, no IDENTIFY 3955562Sgibbs or FLAGS,RESELECTED 3964568Sgibbs 3974568Sgibbs# After the [re]selection, make sure that the [re]selection enable 3984568Sgibbs# bit is off. This chip is flaky enough without extra things 3994568Sgibbs# turned on. Also clear the BUSFREE bit in SSTAT1 since we'll be 4004568Sgibbs# using it shortly. 4014568Sgibbs# 4024568Sgibbs*select: 4034568Sgibbs clr SCSISEQ 4044568Sgibbs mvi CLRSINT1,0x8 # CLRBUSFREE 4054568Sgibbs 4064568Sgibbs# Main loop for information transfer phases. If BSY is false, then 4074568Sgibbs# we have a bus free condition, expected or not. Otherwise, wait 4084568Sgibbs# for the target to assert REQ before checking MSG, C/D and I/O 4094568Sgibbs# for the bus phase. 4104568Sgibbs# 4114568Sgibbs# We can't simply look at the values of SCSISIGI here (if we want 4124568Sgibbs# to do synchronous data transfer), because the target won't assert 4134568Sgibbs# REQ if it's already sent us some data that we haven't acknowledged 4144568Sgibbs# yet. 4154568Sgibbs# 4164568SgibbsITloop: 4174568Sgibbs test SSTAT1,0x8 jnz p_busfree # BUSFREE 4184568Sgibbs test SSTAT1,0x1 jz ITloop # REQINIT 4194568Sgibbs 4204568Sgibbs and A,0xe0,SCSISIGI # CDI|IOI|MSGI 4214568Sgibbs 4224568Sgibbs cmp ALLZEROS,A je p_dataout 4234568Sgibbs cmp A,0x40 je p_datain 4244568Sgibbs cmp A,0x80 je p_command 4254568Sgibbs cmp A,0xc0 je p_status 4264568Sgibbs cmp A,0xa0 je p_mesgout 4274568Sgibbs cmp A,0xe0 je p_mesgin 4284568Sgibbs 4295647Sgibbs mvi INTSTAT,BAD_PHASE # unknown - signal driver 4304568Sgibbs 4314568Sgibbsp_dataout: 4324568Sgibbs mvi 0 call scsisig # !CDO|!IOO|!MSGO 4334568Sgibbs call assert 4344568Sgibbs call sg_load 4354568Sgibbs 4365775Sgibbs mvi DINDEX,HADDR 4375775Sgibbs mvi SCBARRAY+19 call bcopy_4 4384568Sgibbs 4395775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 4405775Sgibbs mvi SCBARRAY+23 call bcopy_3 4415775Sgibbs 4424568Sgibbs mvi DINDEX,STCNT 4435775Sgibbs mvi SCBARRAY+23 call bcopy_3 4444568Sgibbs 4454568Sgibbs mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN| 4464568Sgibbs # DIRECTION|FIFORESET 4474568Sgibbs 4484568Sgibbs# After a DMA finishes, save the final transfer pointer and count 4494568Sgibbs# back into the SCB, in case a device disconnects in the middle of 4504568Sgibbs# a transfer. Use SHADDR and STCNT instead of HADDR and HCNT, since 4514568Sgibbs# it's a reflection of how many bytes were transferred on the SCSI 4524568Sgibbs# (as opposed to the host) bus. 4534568Sgibbs# 4544568Sgibbs mvi DINDEX,SCBARRAY+23 4555775Sgibbs mvi STCNT call bcopy_3 4564568Sgibbs 4574568Sgibbs mvi DINDEX,SCBARRAY+19 4585775Sgibbs mvi SHADDR call bcopy_4 4594568Sgibbs 4604568Sgibbs call sg_advance 4614568Sgibbs mov SCBARRAY+18,SG_COUNT # residual S/G count 4624568Sgibbs 4634568Sgibbs jmp ITloop 4644568Sgibbs 4654568Sgibbsp_datain: 4664568Sgibbs mvi 0x40 call scsisig # !CDO|IOO|!MSGO 4674568Sgibbs call assert 4684568Sgibbs call sg_load 4694568Sgibbs 4705775Sgibbs mvi DINDEX,HADDR 4715775Sgibbs mvi SCBARRAY+19 call bcopy_4 4724568Sgibbs 4735775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 4745775Sgibbs mvi SCBARRAY+23 call bcopy_3 4755775Sgibbs 4764568Sgibbs mvi DINDEX,STCNT 4775775Sgibbs mvi SCBARRAY+23 call bcopy_3 4784568Sgibbs 4794568Sgibbs mvi 0x39 call dma # SCSIEN|SDMAEN|HDMAEN| 4804568Sgibbs # !DIRECTION|FIFORESET 4814568Sgibbs mvi DINDEX,SCBARRAY+23 4825775Sgibbs mvi STCNT call bcopy_3 4834568Sgibbs 4844568Sgibbs mvi DINDEX,SCBARRAY+19 4855775Sgibbs mvi SHADDR call bcopy_4 4864568Sgibbs 4874568Sgibbs call sg_advance 4884568Sgibbs mov SCBARRAY+18,SG_COUNT # residual S/G count 4894568Sgibbs 4904568Sgibbs jmp ITloop 4914568Sgibbs 4924568Sgibbs# Command phase. Set up the DMA registers and let 'er rip - the 4934568Sgibbs# two bytes after the SCB SCSI_cmd_length are zeroed by the driver, 4944568Sgibbs# so we can copy those three bytes directly into HCNT. 4954568Sgibbs# 4964568Sgibbsp_command: 4974568Sgibbs mvi 0x80 call scsisig # CDO|!IOO|!MSGO 4984568Sgibbs call assert 4994568Sgibbs 5005775Sgibbs mvi DINDEX,HADDR 5015775Sgibbs mvi SCBARRAY+7 call bcopy_4 5024568Sgibbs 5035775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 5045775Sgibbs mvi SCBARRAY+11 call bcopy_3 5055775Sgibbs 5064568Sgibbs mvi DINDEX,STCNT 5075775Sgibbs mvi SCBARRAY+11 call bcopy_3 5084568Sgibbs 5094568Sgibbs mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN| 5104568Sgibbs # DIRECTION|FIFORESET 5114568Sgibbs jmp ITloop 5124568Sgibbs 5134568Sgibbs# Status phase. Wait for the data byte to appear, then read it 5144568Sgibbs# and store it into the SCB. 5154568Sgibbs# 5164568Sgibbsp_status: 5174568Sgibbs mvi 0xc0 call scsisig # CDO|IOO|!MSGO 5184568Sgibbs 5194568Sgibbs mvi SCBARRAY+14 call inb 5204568Sgibbs jmp ITloop 5214568Sgibbs 5224568Sgibbs# Message out phase. If there is no active message, but the target 5234568Sgibbs# took us into this phase anyway, build a no-op message and send it. 5244568Sgibbs# 5254568Sgibbsp_mesgout: 5264568Sgibbs mvi 0xa0 call scsisig # CDO|!IOO|MSGO 5274568Sgibbs mvi 0x8 call mk_mesg # build NOP message 5284568Sgibbs 5294568Sgibbs# Set up automatic PIO transfer from MSG_START. Bit 3 in 5304568Sgibbs# SXFRCTL0 (SPIOEN) is already on. 5314568Sgibbs# 5324568Sgibbs mvi SINDEX,MSG_START+0 5334568Sgibbs mov DINDEX,MSG_LEN 5344568Sgibbs clr A 5354568Sgibbs 5364568Sgibbs# When target asks for a byte, drop ATN if it's the last one in 5374568Sgibbs# the message. Otherwise, keep going until the message is exhausted. 5384568Sgibbs# (We can't use outb for this since it wants the input in SINDEX.) 5394568Sgibbs# 5404568Sgibbs# Keep an eye out for a phase change, in case the target issues 5414568Sgibbs# a MESSAGE REJECT. 5424568Sgibbs# 5434568Sgibbsp_mesgout2: 5444568Sgibbs test SSTAT0,0x2 jz p_mesgout2 # SPIORDY 5454568Sgibbs test SSTAT1,0x10 jnz p_mesgout6 # PHASEMIS 5464568Sgibbs 5474568Sgibbs cmp DINDEX,1 jne p_mesgout3 # last byte? 5484568Sgibbs mvi CLRSINT1,0x40 # CLRATNO - drop ATN 5494568Sgibbs 5504568Sgibbs# Write a byte to the SCSI bus. The AIC-7770 refuses to automatically 5514568Sgibbs# send ACKs in automatic PIO or DMA mode unless you make sure that the 5524568Sgibbs# "expected" bus phase in SCSISIGO matches the actual bus phase. This 5534568Sgibbs# behaviour is completely undocumented and caused me several days of 5544568Sgibbs# grief. 5554568Sgibbs# 5564568Sgibbs# After plugging in different drives to test with and using a longer 5574568Sgibbs# SCSI cable, I found that I/O in Automatic PIO mode ceased to function, 5584568Sgibbs# especially when transferring >1 byte. It seems to be much more stable 5594568Sgibbs# if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is 5604568Sgibbs# polled for transfer completion - for both output _and_ input. The 5614568Sgibbs# only theory I have is that SPIORDY doesn't drop right away when SCSIDATL 5624568Sgibbs# is accessed (like the documentation says it does), and that on a longer 5634568Sgibbs# cable run, the sequencer code was fast enough to loop back and see 5644568Sgibbs# an SPIORDY that hadn't dropped yet. 5654568Sgibbs# 5664568Sgibbsp_mesgout3: 5674568Sgibbs call one_stcnt 5684568Sgibbs mov SCSIDATL,SINDIR 5694568Sgibbs 5704568Sgibbsp_mesgout4: 5714568Sgibbs test SSTAT0,0x4 jz p_mesgout4 # SDONE 5724568Sgibbs dec DINDEX 5734568Sgibbs inc A 5744568Sgibbs cmp MSG_LEN,A jne p_mesgout2 5754568Sgibbs 5764568Sgibbs# If the next bus phase after ATN drops is a message out, it means 5774568Sgibbs# that the target is requesting that the last message(s) be resent. 5784568Sgibbs# 5794568Sgibbsp_mesgout5: 5804568Sgibbs test SSTAT1,0x8 jnz p_mesgout6 # BUSFREE 5814568Sgibbs test SSTAT1,0x1 jz p_mesgout5 # REQINIT 5824568Sgibbs 5834568Sgibbs and A,0xe0,SCSISIGI # CDI|IOI|MSGI 5844568Sgibbs cmp A,0xa0 jne p_mesgout6 5854568Sgibbs mvi 0x10 call scsisig # ATNO - re-assert ATN 5864568Sgibbs 5874568Sgibbs jmp ITloop 5884568Sgibbs 5894568Sgibbsp_mesgout6: 5904568Sgibbs mvi CLRSINT1,0x40 # CLRATNO - in case of PHASEMIS 5915562Sgibbs and FLAGS,0xdf # no active msg 5924568Sgibbs jmp ITloop 5934568Sgibbs 5944568Sgibbs# Message in phase. Bytes are read using Automatic PIO mode, but not 5954568Sgibbs# using inb. This alleviates a race condition, namely that if ATN had 5964568Sgibbs# to be asserted under Automatic PIO mode, it had to beat the SCSI 5974568Sgibbs# circuitry sending an ACK to the target. This showed up under heavy 5984568Sgibbs# loads and really confused things, since ABORT commands wouldn't be 5994568Sgibbs# seen by the drive after an IDENTIFY message in until it had changed 6004568Sgibbs# to a data I/O phase. 6014568Sgibbs# 6024568Sgibbsp_mesgin: 6034568Sgibbs mvi 0xe0 call scsisig # CDO|IOO|MSGO 6044568Sgibbs mvi A call inb_first # read the 1st message byte 6054568Sgibbs mvi REJBYTE,A # save it for the driver 6064568Sgibbs 6074568Sgibbs cmp ALLZEROS,A jne p_mesgin1 6084568Sgibbs 6094568Sgibbs# We got a "command complete" message, so put the SCB pointer 6104568Sgibbs# into the Queue Out, and trigger a completion interrupt. 6114568Sgibbs# Check status for non zero return and interrupt driver if needed 6125326Sgibbs# This allows the driver to interpret errors only when they occur 6135326Sgibbs# instead of always uploading the scb. If the status is SCSI_CHECK, 6145326Sgibbs# the driver will download a new scb requesting sense, to replace 6155326Sgibbs# the old one and the sequencer code will imediately jump to start 6165326Sgibbs# working on it. If the kernel driver does not wish to request sense, 6175326Sgibbs# the sequencer program counter is incremented by 1, preventing another run 6185326Sgibbs# on the current SCB and the command is allowed to complete. We don't 6195326Sgibbs# bother to post to the QOUTFIFO in the error case since it would require 6205326Sgibbs# extra work in the kernel driver to ensure that the entry was removed 6215326Sgibbs# before the command complete code tried processing it. 6224568Sgibbs 6235647Sgibbs test SCBARRAY+14,0xff jz status_ok # 0 Status? 6245647Sgibbs mvi INTSTAT,BAD_STATUS # let driver know 6255562Sgibbs test FLAGS,SENSE jz status_ok 6265562Sgibbs jmp p_mesgin_done 6275326Sgibbs 6284568Sgibbsstatus_ok: 6295326Sgibbs 6305326Sgibbs# First, mark this target as free. 6316608Sgibbs test SCBARRAY+0,0x20 jnz complete # Tagged command 6325326Sgibbs and FUNCTION1,0x70,SCBARRAY+1 6335326Sgibbs mov A,FUNCTION1 6345326Sgibbs test SCBARRAY+1,0x88 jz clear_a 6355326Sgibbs xor ACTIVE_B,A 6365326Sgibbs jmp complete 6375326Sgibbs 6385326Sgibbsclear_a: 6395326Sgibbs xor ACTIVE_A,A 6405326Sgibbs 6415326Sgibbscomplete: 6424568Sgibbs mov QOUTFIFO,SCBPTR 6435326Sgibbs mvi INTSTAT,0x02 # CMDCMPLT 6444568Sgibbs jmp p_mesgin_done 6454568Sgibbs 6465562Sgibbs# Is it an extended message? We only support the synchronous and wide data 6475562Sgibbs# transfer request messages, which will probably be in response to 6485562Sgibbs# WDTR or SDTR message outs from us. If it's not SDTR or WDTR, reject it - 6494568Sgibbs# apparently this can be done after any message in byte, according 6504568Sgibbs# to the SCSI-2 spec. 6514568Sgibbs# 6524568Sgibbsp_mesgin1: 6534568Sgibbs cmp A,1 jne p_mesgin2 # extended message code? 6544568Sgibbs 6555562Sgibbs mvi ARG_1 call inb_next # extended message length 6565562Sgibbs mvi A call inb_next # extended message code 6574568Sgibbs 6585562Sgibbs cmp A,1 je p_mesginSDTR # Syncronous negotiation message 6595562Sgibbs cmp A,3 je p_mesginWDTR # Wide negotiation message 6605562Sgibbs jmp p_mesginN 6615562Sgibbs 6625562Sgibbsp_mesginWDTR: 6635562Sgibbs cmp ARG_1,2 jne p_mesginN # extended mesg length = 2 6645562Sgibbs mvi A call inb_next # Width of bus 6655647Sgibbs mvi INTSTAT,MSG_WDTR # let driver know 6665562Sgibbs test RETURN_1,0x80 jz p_mesgin_done# Do we need to send WDTR? 6675562Sgibbs 6685562Sgibbs# We didn't initiate the wide negotiation, so we must respond to the request 6695562Sgibbs and RETURN_1,0x7f # Clear the SEND_WDTR Flag 6705562Sgibbs or FLAGS,ACTIVE_MSG 6715647Sgibbs mvi DINDEX,MSG_START+0 6725562Sgibbs mvi MSG_START+0 call mk_wdtr # build WDTR message 6735562Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 6745562Sgibbs call scsisig 6755562Sgibbs jmp p_mesgin_done 6765562Sgibbs 6775562Sgibbsp_mesginSDTR: 6785562Sgibbs cmp ARG_1,3 jne p_mesginN # extended mesg length = 3 6794568Sgibbs mvi ARG_1 call inb_next # xfer period 6805326Sgibbs mvi A call inb_next # REQ/ACK offset 6815647Sgibbs mvi INTSTAT,MSG_SDTR # call driver to convert 6824568Sgibbs 6835562Sgibbs test RETURN_1,0x80 jz p_mesgin_done# Do we need to mk_sdtr? 6845326Sgibbs 6855562Sgibbs or FLAGS,ACTIVE_MSG 6865647Sgibbs mvi DINDEX, MSG_START+0 6875562Sgibbs mvi MSG_START+0 call mk_sdtr 6885562Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 6895562Sgibbs call scsisig 6904568Sgibbs jmp p_mesgin_done 6914568Sgibbs 6924568Sgibbs# Is it a disconnect message? Set a flag in the SCB to remind us 6934568Sgibbs# and await the bus going free. 6944568Sgibbs# 6954568Sgibbsp_mesgin2: 6964568Sgibbs cmp A,4 jne p_mesgin3 # disconnect code? 6974568Sgibbs 6984568Sgibbs or SCBARRAY+0,0x4 # set "disconnected" bit 6994568Sgibbs jmp p_mesgin_done 7004568Sgibbs 7014568Sgibbs# Save data pointers message? Copy working values into the SCB, 7024568Sgibbs# usually in preparation for a disconnect. 7034568Sgibbs# 7044568Sgibbsp_mesgin3: 7054568Sgibbs cmp A,2 jne p_mesgin4 # save data pointers code? 7064568Sgibbs 7074568Sgibbs call sg_ram2scb 7084568Sgibbs jmp p_mesgin_done 7094568Sgibbs 7104568Sgibbs# Restore pointers message? Data pointers are recopied from the 7114568Sgibbs# SCB anyway at the start of any DMA operation, so the only thing 7124568Sgibbs# to copy is the scatter-gather values. 7134568Sgibbs# 7144568Sgibbsp_mesgin4: 7154568Sgibbs cmp A,3 jne p_mesgin5 # restore pointers code? 7164568Sgibbs 7174568Sgibbs call sg_scb2ram 7184568Sgibbs jmp p_mesgin_done 7194568Sgibbs 7204568Sgibbs# Identify message? For a reconnecting target, this tells us the lun 7214568Sgibbs# that the reconnection is for - find the correct SCB and switch to it, 7224568Sgibbs# clearing the "disconnected" bit so we don't "find" it by accident later. 7234568Sgibbs# 7244568Sgibbsp_mesgin5: 7254568Sgibbs test A,0x80 jz p_mesgin6 # identify message? 7264568Sgibbs 7274568Sgibbs test A,0x78 jnz p_mesginN # !DiscPriv|!LUNTAR|!Reserved 7284568Sgibbs 7296608Sgibbs and A,0x7 # lun in lower three bits 7306608Sgibbs or SAVED_TCL,A,SELID 7316608Sgibbs and SAVED_TCL,0xf7 7326608Sgibbs and A,0x08,SBLKCTL # B Channel?? 7336608Sgibbs or SAVED_TCL,A 7346608Sgibbs call inb_last # Ack 7354568Sgibbs 7366608Sgibbs# Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 7376608Sgibbs# If we get one, we use the tag returned to switch to the proper 7386608Sgibbs# SCB. Otherwise, we just use the findSCB method. 7396608Sgibbsp_mesgin5_loop: 7406608Sgibbs test SSTAT1,0x8 jnz use_findSCB # BUSFREE 7416608Sgibbs test SSTAT1,0x1 jz p_mesgin5_loop # REQINIT 7426608Sgibbs and A,0xe0,SCSISIGI # CDI|IOI|MSGI 7436608Sgibbs cmp A,0xe0 jne use_findSCB # Still p_mesgin? 7446608Sgibbs mvi A call inb_first 7456608Sgibbs cmp A,0x20 je get_tag # Simple Tag message? 7466608Sgibbsuse_findSCB: 7476608Sgibbs mov ALLZEROS call findSCB # Have to search 7486608Sgibbs 7494568Sgibbs# If a active message is present after calling findSCB, then either it 7504568Sgibbs# or the driver is trying to abort the command. Either way, something 7514568Sgibbs# untoward has happened and we should just leave it alone. 7524568Sgibbs# 7536608Sgibbssetup_SCB: 7545562Sgibbs test FLAGS,ACTIVE_MSG jnz p_mesgin_done 7554568Sgibbs 7565326Sgibbs and SCBARRAY+0,0xfb # clear disconnect bit in SCB 7575562Sgibbs or FLAGS,0xc0 # make note of IDENTIFY 7584568Sgibbs 7594568Sgibbs call sg_scb2ram # implied restore pointers 7604568Sgibbs # required on reselect 7616608Sgibbs jmp ITloop 7624568Sgibbs 7636608Sgibbsget_tag: 7646608Sgibbs mvi A call inb_next 7656608Sgibbs test A,0xf0 jnz abort_tag # Tag in range? 7666608Sgibbs mov SCBPTR,A 7676608Sgibbs mov A,SAVED_TCL 7686608Sgibbs cmp SCBARRAY+1,A jne abort_tag 7696608Sgibbs test SCBARRAY+0,TAG_ENB jz abort_tag 7706608Sgibbs call inb_last 7716608Sgibbs jmp setup_SCB 7726608Sgibbs 7735647Sgibbs# Message reject? Let the kernel driver handle this. If we have an 7745647Sgibbs# outstanding WDTR or SDTR negotiation, assume that it's a response from 7755647Sgibbs# the target selecting 8bit or asynchronous transfer, otherwise just ignore 7765647Sgibbs# it since we have no clue what it pertains to. 7774568Sgibbs# 7784568Sgibbsp_mesgin6: 7794568Sgibbs cmp A,7 jne p_mesgin7 # message reject code? 7804568Sgibbs 7815647Sgibbs mvi INTSTAT, MSG_REJECT 7825562Sgibbs jmp p_mesgin_done 7835562Sgibbs 7844568Sgibbs# [ ADD MORE MESSAGE HANDLING HERE ] 7854568Sgibbs# 7864568Sgibbsp_mesgin7: 7874568Sgibbs 7884568Sgibbs# We have no idea what this message in is, and there's no way 7894568Sgibbs# to pass it up to the kernel, so we issue a message reject and 7904568Sgibbs# hope for the best. Since we're now using manual PIO mode to 7914568Sgibbs# read in the message, there should no longer be a race condition 7924568Sgibbs# present when we assert ATN. In any case, rejection should be a 7934568Sgibbs# rare occurrence - signal the driver when it happens. 7944568Sgibbs# 7954568Sgibbsp_mesginN: 7964568Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 7974568Sgibbs call scsisig 7985647Sgibbs mvi INTSTAT,SEND_REJECT # let driver know 7994568Sgibbs 8004568Sgibbs mvi 0x7 call mk_mesg # MESSAGE REJECT message 8014568Sgibbs 8024568Sgibbsp_mesgin_done: 8034568Sgibbs call inb_last # ack & turn auto PIO back on 8044568Sgibbs jmp ITloop 8054568Sgibbs 8066608Sgibbsabort_tag: 8076608Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 8086608Sgibbs call scsisig 8096608Sgibbs# mvi INTSTAT,ABORT_TAG # let driver know 8106608Sgibbs mvi 0xd call mk_mesg # ABORT TAG message 8116608Sgibbs jmp p_mesgin_done 8126608Sgibbs 8134568Sgibbs# Bus free phase. It might be useful to interrupt the device 8144568Sgibbs# driver if we aren't expecting this. For now, make sure that 8154568Sgibbs# ATN isn't being asserted and look for a new command. 8164568Sgibbs# 8174568Sgibbsp_busfree: 8184568Sgibbs mvi CLRSINT1,0x40 # CLRATNO 8194568Sgibbs clr SIGSTATE 8204568Sgibbs jmp start 8214568Sgibbs 8225775Sgibbs# Instead of a generic bcopy routine that requires an argument, we unroll 8235775Sgibbs# the two cases that are actually used, and call them explicitly. This 8245775Sgibbs# not only reduces the overhead of doing a bcopy by 2/3rds, but ends up 8255775Sgibbs# saving space in the program since you don't have to put the argument 8265775Sgibbs# into the accumulator before the call. Both functions expect DINDEX to 8275775Sgibbs# contain the destination address and SINDEX to contain the source 8285775Sgibbs# address. 8295775Sgibbsbcopy_3: 8304568Sgibbs mov DINDIR,SINDIR 8315775Sgibbs mov DINDIR,SINDIR 8325775Sgibbs mov DINDIR,SINDIR ret 8334568Sgibbs 8345775Sgibbsbcopy_4: 8355775Sgibbs mov DINDIR,SINDIR 8365775Sgibbs mov DINDIR,SINDIR 8375775Sgibbs mov DINDIR,SINDIR 8385775Sgibbs mov DINDIR,SINDIR ret 8395775Sgibbs 8405775Sgibbs 8414568Sgibbs# Locking the driver out, build a one-byte message passed in SINDEX 8424568Sgibbs# if there is no active message already. SINDEX is returned intact. 8434568Sgibbs# 8444568Sgibbsmk_mesg: 8454866Sgibbs mvi SEQCTL,0x50 # PAUSEDIS|FASTMODE 8465562Sgibbs test FLAGS,ACTIVE_MSG jnz mk_mesg1 # active message? 8474568Sgibbs 8485562Sgibbs or FLAGS,ACTIVE_MSG # if not, there is now 8494568Sgibbs mvi MSG_LEN,1 # length = 1 8504568Sgibbs mov MSG_START+0,SINDEX # 1-byte message 8514568Sgibbs 8524568Sgibbsmk_mesg1: 8535775Sgibbs mvi SEQCTL,0x10 ret # !PAUSEDIS|FASTMODE 8544568Sgibbs 8554568Sgibbs# Input byte in Automatic PIO mode. The address to store the byte 8564568Sgibbs# in should be in SINDEX. DINDEX will be used by this routine. 8574568Sgibbs# 8584568Sgibbsinb: 8594568Sgibbs test SSTAT0,0x2 jz inb # SPIORDY 8604568Sgibbs mov DINDEX,SINDEX 8614568Sgibbs call one_stcnt # xfer one byte 8624568Sgibbs mov DINDIR,SCSIDATL 8634568Sgibbsinb1: 8644568Sgibbs test SSTAT0,0x4 jz inb1 # SDONE - wait to "finish" 8654568Sgibbs ret 8664568Sgibbs 8674568Sgibbs# Carefully read data in Automatic PIO mode. I first tried this using 8684568Sgibbs# Manual PIO mode, but it gave me continual underrun errors, probably 8694568Sgibbs# indicating that I did something wrong, but I feel more secure leaving 8704568Sgibbs# Automatic PIO on all the time. 8714568Sgibbs# 8724568Sgibbs# According to Adaptec's documentation, an ACK is not sent on input from 8734568Sgibbs# the target until SCSIDATL is read from. So we wait until SCSIDATL is 8744568Sgibbs# latched (the usual way), then read the data byte directly off the bus 8754568Sgibbs# using SCSIBUSL. When we have pulled the ATN line, or we just want to 8764568Sgibbs# acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 8774568Sgibbs# spec guarantees that the target will hold the data byte on the bus until 8784568Sgibbs# we send our ACK. 8794568Sgibbs# 8804568Sgibbs# The assumption here is that these are called in a particular sequence, 8814568Sgibbs# and that REQ is already set when inb_first is called. inb_{first,next} 8824568Sgibbs# use the same calling convention as inb. 8834568Sgibbs# 8844568Sgibbsinb_first: 8854568Sgibbs mov DINDEX,SINDEX 8864568Sgibbs mov DINDIR,SCSIBUSL ret # read byte directly from bus 8874568Sgibbs 8884568Sgibbsinb_next: 8894568Sgibbs mov DINDEX,SINDEX # save SINDEX 8904568Sgibbs 8914568Sgibbs call one_stcnt # xfer one byte 8924568Sgibbs mov NONE,SCSIDATL # dummy read from latch to ACK 8934568Sgibbsinb_next1: 8944568Sgibbs test SSTAT0,0x4 jz inb_next1 # SDONE 8954568Sgibbsinb_next2: 8964568Sgibbs test SSTAT0,0x2 jz inb_next2 # SPIORDY - wait for next byte 8974568Sgibbs mov DINDIR,SCSIBUSL ret # read byte directly from bus 8984568Sgibbs 8994568Sgibbsinb_last: 9004568Sgibbs call one_stcnt # ACK with dummy read 9014568Sgibbs mov NONE,SCSIDATL 9024568Sgibbsinb_last1: 9034568Sgibbs test SSTAT0,0x4 jz inb_last1 # wait for completion 9044568Sgibbs ret 9054568Sgibbs 9064568Sgibbs# Output byte in Automatic PIO mode. The byte to output should be 9074568Sgibbs# in SINDEX. If DROPATN's high bit is set, then ATN will be dropped 9084568Sgibbs# before the byte is output. 9094568Sgibbs# 9104568Sgibbsoutb: 9114568Sgibbs test SSTAT0,0x2 jz outb # SPIORDY 9124568Sgibbs call one_stcnt # xfer one byte 9134568Sgibbs 9144568Sgibbs test DROPATN,0x80 jz outb1 9154568Sgibbs mvi CLRSINT1,0x40 # CLRATNO 9164568Sgibbs clr DROPATN 9174568Sgibbsoutb1: 9184568Sgibbs mov SCSIDATL,SINDEX 9194568Sgibbsoutb2: 9204568Sgibbs test SSTAT0,0x4 jz outb2 # SDONE 9214568Sgibbs ret 9224568Sgibbs 9234568Sgibbs# Write the value "1" into the STCNT registers, for Automatic PIO 9244568Sgibbs# transfers. 9254568Sgibbs# 9264568Sgibbsone_stcnt: 9274568Sgibbs clr STCNT+2 9284568Sgibbs clr STCNT+1 9294568Sgibbs mvi STCNT+0,1 ret 9304568Sgibbs 9314568Sgibbs# DMA data transfer. HADDR and HCNT must be loaded first, and 9324568Sgibbs# SINDEX should contain the value to load DFCNTRL with - 0x3d for 9334568Sgibbs# host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 9344568Sgibbs# during initialization. 9354568Sgibbs# 9364568Sgibbsdma: 9374568Sgibbs mov DFCNTRL,SINDEX 9384568Sgibbsdma1: 9394568Sgibbsdma2: 9404568Sgibbs test SSTAT0,0x1 jnz dma3 # DMADONE 9414568Sgibbs test SSTAT1,0x10 jz dma1 # PHASEMIS, ie. underrun 9424568Sgibbs 9434568Sgibbs# We will be "done" DMAing when the transfer count goes to zero, or 9444568Sgibbs# the target changes the phase (in light of this, it makes sense that 9454568Sgibbs# the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 9464866Sgibbs# doing a SCSI->Host transfer, the data FIFO should be flushed auto- 9474866Sgibbs# magically on STCNT=0 or a phase change, so just wait for FIFO empty 9484866Sgibbs# status. 9494568Sgibbs# 9504568Sgibbsdma3: 9514568Sgibbs test SINDEX,0x4 jnz dma5 # DIRECTION 9524568Sgibbsdma4: 9535562Sgibbs test DFSTATUS,0x1 jz dma4 # !FIFOEMP 9544568Sgibbs 9554568Sgibbs# Now shut the DMA enables off, and copy STCNT (ie. the underrun 9564568Sgibbs# amount, if any) to the SCB registers; SG_COUNT will get copied to 9574568Sgibbs# the SCB's residual S/G count field after sg_advance is called. Make 9584568Sgibbs# sure that the DMA enables are actually off first lest we get an ILLSADDR. 9594568Sgibbs# 9604568Sgibbsdma5: 9614568Sgibbs clr DFCNTRL # disable DMA 9624568Sgibbsdma6: 9634568Sgibbs test DFCNTRL,0x38 jnz dma6 # SCSIENACK|SDMAENACK|HDMAENACK 9644568Sgibbs 9654568Sgibbs mvi DINDEX,SCBARRAY+15 9665775Sgibbs mvi STCNT call bcopy_3 9674568Sgibbs 9684568Sgibbs ret 9694568Sgibbs 9704568Sgibbs# Common SCSI initialization for selection and reselection. Expects 9714568Sgibbs# the target SCSI ID to be in the upper four bits of SINDEX, and A's 9724568Sgibbs# contents are stomped on return. 9734568Sgibbs# 9744568Sgibbsinitialize: 9755775Sgibbs and SINDEX,0xf0 # Get target ID 9765775Sgibbs and A,0x0f,SCSIID 9775775Sgibbs or SINDEX,A 9785775Sgibbs mov SCSIID,SINDEX 9795326Sgibbs 9804568Sgibbs# Esundry initialization. 9814568Sgibbs# 9824568Sgibbs clr DROPATN 9834568Sgibbs clr SIGSTATE 9844568Sgibbs 9855775Sgibbs# Turn on Automatic PIO mode now, before we expect to see a REQ 9864568Sgibbs# from the target. It shouldn't hurt anything to leave it on. Set 9874568Sgibbs# CLRCHN here before the target has entered a data transfer mode - 9884568Sgibbs# with synchronous SCSI, if you do it later, you blow away some 9894568Sgibbs# data in the SCSI FIFO that the target has already sent to you. 9904568Sgibbs# 9914866Sgibbs mvi SXFRCTL0,0x8a # DFON|SPIOEN|CLRCHN 9924568Sgibbs 9934568Sgibbs# Initialize scatter-gather pointers by setting up the working copy 9944568Sgibbs# in scratch RAM. 9954568Sgibbs# 9964568Sgibbs call sg_scb2ram 9974568Sgibbs 9984568Sgibbs# Initialize SCSIRATE with the appropriate value for this target. 9994568Sgibbs# 10005562Sgibbs call ndx_dtr 10015775Sgibbs mov SCSIRATE,SINDIR ret 10024568Sgibbs 10034568Sgibbs# Assert that if we've been reselected, then we've seen an IDENTIFY 10044568Sgibbs# message. 10054568Sgibbs# 10064568Sgibbsassert: 10075562Sgibbs test FLAGS,RESELECTED jz assert1 # reselected? 10085562Sgibbs test FLAGS,IDENTIFY_SEEN jnz assert1 # seen IDENTIFY? 10094568Sgibbs 10105647Sgibbs mvi INTSTAT,NO_IDENT # no - cause a kernel panic 10114568Sgibbs 10124568Sgibbsassert1: 10134568Sgibbs ret 10144568Sgibbs 10154568Sgibbs# Find out if disconnection is ok from the information the BIOS has left 10165326Sgibbs# us. The tcl from SCBARRAY+1 should be in SINDEX; A will 10174866Sgibbs# contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok) 10184568Sgibbs# on exit. 10194568Sgibbs# 10205326Sgibbs# To allow for wide or twin busses, we check the upper bit of the target ID 10215326Sgibbs# and the channel ID and look at the appropriate disconnect register. 10224568Sgibbs# 10234568Sgibbsdisconnect: 10244568Sgibbs and FUNCTION1,0x70,SINDEX # strip off extra just in case 10254568Sgibbs mov A,FUNCTION1 10265326Sgibbs test SINDEX, 0x88 jz disconnect_a 10275326Sgibbs 10285326Sgibbs test DISC_DSB_B,A jz disconnect1 # bit nonzero if DISabled 10295326Sgibbs clr A ret 10305326Sgibbs 10315326Sgibbsdisconnect_a: 10324568Sgibbs test DISC_DSB_A,A jz disconnect1 # bit nonzero if DISabled 10335326Sgibbs clr A ret 10344568Sgibbs 10354568Sgibbsdisconnect1: 10364568Sgibbs mvi A,0x40 ret 10374568Sgibbs 10386608Sgibbs# Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch 10396608Sgibbs# the SCB to it. Have the kernel print a warning message if it can't be 10406608Sgibbs# found, and generate an ABORT message to the target. SINDEX should be 10416608Sgibbs# cleared on call. 10424568Sgibbs# 10434568SgibbsfindSCB: 10446608Sgibbs mov A,SAVED_TCL 10454568Sgibbs mov SCBPTR,SINDEX # switch to new SCB 10466608Sgibbs cmp SCBARRAY+1,A jne findSCB1 # target ID/channel/lun match? 10476608Sgibbs test SCBARRAY+0,0x4 jz findSCB1 # should be disconnected 10484568Sgibbs ret 10494568Sgibbs 10506608SgibbsfindSCB1: 10514568Sgibbs inc SINDEX 10524568Sgibbs mov A,SCBCOUNT 10536608Sgibbs cmp SINDEX,A jne findSCB 10544568Sgibbs 10555647Sgibbs mvi INTSTAT,NO_MATCH # not found - signal kernel 10564568Sgibbs mvi 0x6 call mk_mesg # ABORT message 10574568Sgibbs 10584568Sgibbs or SINDEX,0x10,SIGSTATE # assert ATNO 10594568Sgibbs call scsisig 10604568Sgibbs ret 10614568Sgibbs 10624568Sgibbs# Make a working copy of the scatter-gather parameters in the SCB. 10634568Sgibbs# 10644568Sgibbssg_scb2ram: 10654568Sgibbs mov SG_COUNT,SCBARRAY+2 10664568Sgibbs 10674568Sgibbs mvi DINDEX,SG_NEXT 10685775Sgibbs mvi SCBARRAY+3 call bcopy_4 10694568Sgibbs 10704568Sgibbs mvi SG_NOLOAD,0x80 10714568Sgibbs test SCBARRAY+0,0x10 jnz sg_scb2ram1 # don't reload s/g? 10724568Sgibbs clr SG_NOLOAD 10734568Sgibbs 10744568Sgibbssg_scb2ram1: 10754568Sgibbs ret 10764568Sgibbs 10774568Sgibbs# Copying RAM values back to SCB, for Save Data Pointers message. 10784568Sgibbs# 10794568Sgibbssg_ram2scb: 10804568Sgibbs mov SCBARRAY+2,SG_COUNT 10814568Sgibbs 10824568Sgibbs mvi DINDEX,SCBARRAY+3 10835775Sgibbs mvi SG_NEXT call bcopy_4 10844568Sgibbs 10854568Sgibbs and SCBARRAY+0,0xef,SCBARRAY+0 10864568Sgibbs test SG_NOLOAD,0x80 jz sg_ram2scb1 # reload s/g? 10875647Sgibbs or SCBARRAY+0,SG_LOAD 10884568Sgibbs 10894568Sgibbssg_ram2scb1: 10904568Sgibbs ret 10914568Sgibbs 10924568Sgibbs# Load a struct scatter if needed and set up the data address and 10934568Sgibbs# length. If the working value of the SG count is nonzero, then 10944568Sgibbs# we need to load a new set of values. 10954568Sgibbs# 10964568Sgibbs# This, like the above DMA, assumes a little-endian host data storage. 10974568Sgibbs# 10984568Sgibbssg_load: 10994568Sgibbs test SG_COUNT,0xff jz sg_load3 # SG being used? 11004568Sgibbs test SG_NOLOAD,0x80 jnz sg_load3 # don't reload s/g? 11014568Sgibbs 11024568Sgibbs clr HCNT+2 11034568Sgibbs clr HCNT+1 11044568Sgibbs mvi HCNT+0,SG_SIZEOF 11054568Sgibbs 11064568Sgibbs mvi DINDEX,HADDR 11075775Sgibbs mvi SG_NEXT call bcopy_4 11084568Sgibbs 11094568Sgibbs mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET 11104568Sgibbs 11114568Sgibbs# Wait for DMA from host memory to data FIFO to complete, then disable 11124568Sgibbs# DMA and wait for it to acknowledge that it's off. 11134568Sgibbs# 11144568Sgibbssg_load1: 11154568Sgibbs test DFSTATUS,0x8 jz sg_load1 # HDONE 11164568Sgibbs 11174568Sgibbs clr DFCNTRL # disable DMA 11184568Sgibbssg_load2: 11194568Sgibbs test DFCNTRL,0x8 jnz sg_load2 # HDMAENACK 11204568Sgibbs 11214568Sgibbs# Copy data from FIFO into SCB data pointer and data count. This assumes 11224568Sgibbs# that the struct scatterlist has this structure (this and sizeof(struct 11234568Sgibbs# scatterlist) == 12 are asserted in aic7xxx.c): 11244568Sgibbs# 11254568Sgibbs# struct scatterlist { 11264568Sgibbs# char *address; /* four bytes, little-endian order */ 11274568Sgibbs# ... /* four bytes, ignored */ 11284568Sgibbs# unsigned short length; /* two bytes, little-endian order */ 11294568Sgibbs# } 11304568Sgibbs# 11314568Sgibbs 11324568Sgibbs# Not in FreeBSD. the scatter list is only 8 bytes. 11334568Sgibbs# 11344568Sgibbs# struct ahc_dma_seg { 11354568Sgibbs# physaddr addr; /* four bytes, little-endian order */ 11364568Sgibbs# long len; /* four bytes, little endian order */ 11374568Sgibbs# }; 11384568Sgibbs# 11394568Sgibbs 11404568Sgibbs mov SCBARRAY+19,DFDAT # new data address 11414568Sgibbs mov SCBARRAY+20,DFDAT 11424568Sgibbs mov SCBARRAY+21,DFDAT 11434568Sgibbs mov SCBARRAY+22,DFDAT 11444568Sgibbs 11455647Sgibbs# For Linux, we must throw away four bytes since there is a 32bit gap 11465647Sgibbs# in the middle of a struct scatterlist 11475647Sgibbs# mov NONE,DFDAT 11485647Sgibbs# mov NONE,DFDAT 11495647Sgibbs# mov NONE,DFDAT 11505647Sgibbs# mov NONE,DFDAT 11515647Sgibbs 11524568Sgibbs mov SCBARRAY+23,DFDAT 11534568Sgibbs mov SCBARRAY+24,DFDAT 11545647Sgibbs mov SCBARRAY+25,DFDAT #Only support 24 bit length. 11554568Sgibbs 11564568Sgibbssg_load3: 11574568Sgibbs ret 11584568Sgibbs 11594568Sgibbs# Advance the scatter-gather pointers only IF NEEDED. If SG is enabled, 11604568Sgibbs# and the SCSI transfer count is zero (note that this should be called 11614568Sgibbs# right after a DMA finishes), then move the working copies of the SG 11624568Sgibbs# pointer/length along. If the SCSI transfer count is not zero, then 11634568Sgibbs# presumably the target is disconnecting - do not reload the SG values 11644568Sgibbs# next time. 11654568Sgibbs# 11664568Sgibbssg_advance: 11674568Sgibbs test SG_COUNT,0xff jz sg_advance2 # s/g enabled? 11684568Sgibbs 11694568Sgibbs test STCNT+0,0xff jnz sg_advance1 # SCSI transfer count nonzero? 11704568Sgibbs test STCNT+1,0xff jnz sg_advance1 11714568Sgibbs test STCNT+2,0xff jnz sg_advance1 11724568Sgibbs 11734568Sgibbs clr SG_NOLOAD # reload s/g next time 11744568Sgibbs dec SG_COUNT # one less segment to go 11754568Sgibbs 11764568Sgibbs clr A # add sizeof(struct scatter) 11774568Sgibbs add SG_NEXT+0,SG_SIZEOF,SG_NEXT+0 11784568Sgibbs adc SG_NEXT+1,A,SG_NEXT+1 11794568Sgibbs adc SG_NEXT+2,A,SG_NEXT+2 11805775Sgibbs adc SG_NEXT+3,A,SG_NEXT+3 ret 11814568Sgibbs 11824568Sgibbssg_advance1: 11834568Sgibbs mvi SG_NOLOAD,0x80 # don't reload s/g next time 11844568Sgibbssg_advance2: 11854568Sgibbs ret 11864568Sgibbs 11874568Sgibbs# Add the array base SYNCNEG to the target offset (the target address 11884568Sgibbs# is in SCSIID), and return the result in SINDEX. The accumulator 11894568Sgibbs# contains the 3->8 decoding of the target ID on return. 11904568Sgibbs# 11915562Sgibbsndx_dtr: 11924568Sgibbs shr A,SCSIID,4 11935562Sgibbs test SBLKCTL,0x08 jz ndx_dtr_2 11945326Sgibbs or A,0x08 # Channel B entries add 8 11955562Sgibbsndx_dtr_2: 11964568Sgibbs add SINDEX,SYNCNEG,A 11974568Sgibbs 11984568Sgibbs and FUNCTION1,0x70,SCSIID # 3-bit target address decode 11994568Sgibbs mov A,FUNCTION1 ret 12004568Sgibbs 12015562Sgibbs# If we need to negotiate transfer parameters, build the WDTR or SDTR message 12024568Sgibbs# starting at the address passed in SINDEX. DINDEX is modified on return. 12035562Sgibbs# The SCSI-II spec requires that Wide negotiation occur first and you can 12045562Sgibbs# only negotiat one or the other at a time otherwise in the event of a message 12055562Sgibbs# reject, you wouldn't be able to tell which message was the culpret. 12064568Sgibbs# 12075562Sgibbsmk_dtr: 12084568Sgibbs mov DINDEX,SINDEX # save SINDEX 12094568Sgibbs 12105647Sgibbs test SCBARRAY+0,NEEDWDTR jnz mk_wdtr_16bit 12115647Sgibbs jmp mk_sdtr 12124568Sgibbs 12135647Sgibbsmk_wdtr_16bit: 12145647Sgibbs mvi ARG_1,BUS_16_BIT 12155562Sgibbsmk_wdtr: 12164568Sgibbs mvi DINDIR,1 # extended message 12175562Sgibbs mvi DINDIR,2 # extended message length = 2 12185562Sgibbs mvi DINDIR,3 # WDTR code 12195562Sgibbs mov DINDIR,ARG_1 # bus width 12205562Sgibbs 12215775Sgibbs add MSG_LEN,-MSG_START+0,DINDEX ret # update message length 12225562Sgibbs 12235562Sgibbsmk_sdtr: 12245562Sgibbs mvi DINDIR,1 # extended message 12254568Sgibbs mvi DINDIR,3 # extended message length = 3 12264568Sgibbs mvi DINDIR,1 # SDTR code 12275562Sgibbs call sdtr_to_rate 12285562Sgibbs mov DINDIR,RETURN_1 # REQ/ACK transfer period 12295562Sgibbs and DINDIR,0xf,SINDIR # Sync Offset 12304568Sgibbs 12315775Sgibbs add MSG_LEN,-MSG_START+0,DINDEX ret # update message length 12324568Sgibbs 12334568Sgibbs# Set SCSI bus control signal state. This also saves the last-written 12344568Sgibbs# value into a location where the higher-level driver can read it - if 12354568Sgibbs# it has to send an ABORT or RESET message, then it needs to know this 12364568Sgibbs# so it can assert ATN without upsetting SCSISIGO. The new value is 12374568Sgibbs# expected in SINDEX. Change the actual state last to avoid contention 12384568Sgibbs# from the driver. 12394568Sgibbs# 12404568Sgibbsscsisig: 12414568Sgibbs mov SIGSTATE,SINDEX 12424568Sgibbs mov SCSISIGO,SINDEX ret 12435562Sgibbs 12445562Sgibbssdtr_to_rate: 12455562Sgibbs call ndx_dtr # index scratch space for target 12465562Sgibbs shr A,SINDIR,0x4 12475562Sgibbs dec SINDEX #Preserve SINDEX 12485562Sgibbs and A,0x7 12495562Sgibbs clr RETURN_1 12505562Sgibbssdtr_to_rate_loop: 12515562Sgibbs test A,0x0f jz sdtr_to_rate_done 12525562Sgibbs add RETURN_1,0x18 12535562Sgibbs dec A 12545562Sgibbs jmp sdtr_to_rate_loop 12555562Sgibbssdtr_to_rate_done: 12565562Sgibbs shr RETURN_1,0x2 12575562Sgibbs add RETURN_1,0x18 ret 1258