aic7xxx.seq revision 5775
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 215647Sgibbs# FreeBSD, Twin, Wide, 2 command per target support, and other optimizations 225647Sgibbs# provided by Justin T. Gibbs (gibbs@FreeBSD.org) 235647Sgibbs# 245775Sgibbs# $Id: aic7xxx.seq,v 1.5 1995/01/16 16:31:21 gibbs Exp $ 254568Sgibbs 265647SgibbsVERSION AIC7XXX_SEQ_VERSION 1.5 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 875647SgibbsNEEDSDTR = 0x40 885647SgibbsNEEDWDTR = 0x80 895647Sgibbs 904568SgibbsSCBARRAY+1 = 0xa1 914568SgibbsSCBARRAY+2 = 0xa2 924568SgibbsSCBARRAY+3 = 0xa3 935647SgibbsSCBARRAY+4 = 0xa4 945647SgibbsSCBARRAY+5 = 0xa5 955647SgibbsSCBARRAY+6 = 0xa6 964568SgibbsSCBARRAY+7 = 0xa7 975647SgibbsSCBARRAY+8 = 0xa8 985647SgibbsSCBARRAY+9 = 0xa9 995647SgibbsSCBARRAY+10 = 0xaa 1004568SgibbsSCBARRAY+11 = 0xab 1015647SgibbsSCBARRAY+12 = 0xac 1025647SgibbsSCBARRAY+13 = 0xad 1034568SgibbsSCBARRAY+14 = 0xae 1044568SgibbsSCBARRAY+15 = 0xaf 1054568SgibbsSCBARRAY+16 = 0xb0 1064568SgibbsSCBARRAY+17 = 0xb1 1074568SgibbsSCBARRAY+18 = 0xb2 1084568SgibbsSCBARRAY+19 = 0xb3 1094568SgibbsSCBARRAY+20 = 0xb4 1104568SgibbsSCBARRAY+21 = 0xb5 1114568SgibbsSCBARRAY+22 = 0xb6 1124568SgibbsSCBARRAY+23 = 0xb7 1134568SgibbsSCBARRAY+24 = 0xb8 1144568SgibbsSCBARRAY+25 = 0xb9 1155647SgibbsSCBARRAY+26 = 0xba 1164568Sgibbs 1175647SgibbsBAD_PHASE = 0x01 # unknown scsi bus phase 1185647SgibbsSEND_REJECT = 0x11 # sending a message reject 1195647SgibbsNO_IDENT = 0x21 # no IDENTIFY after reconnect 1205647SgibbsNO_MATCH = 0x31 # no cmd match for reconnect 1215647SgibbsMSG_SDTR = 0x41 # SDTR message recieved 1225647SgibbsMSG_WDTR = 0x51 # WDTR message recieved 1235647SgibbsMSG_REJECT = 0x61 # Reject message recieved 1245647SgibbsBAD_STATUS = 0x71 # Bad status from target 1254568Sgibbs 1264568Sgibbs# The host adapter card (at least the BIOS) uses 20-2f for SCSI 1275326Sgibbs# device information, 32-33 and 5a-5f as well. As it turns out, the 1285326Sgibbs# BIOS trashes 20-2f, writing the synchronous negotiation results 1294568Sgibbs# on top of the BIOS values, so we re-use those for our per-target 1304568Sgibbs# scratchspace (actually a value that can be copied directly into 1315326Sgibbs# SCSIRATE). The kernel driver will enable synchronous negotiation 1325326Sgibbs# for all targets that have a value other than 0 in the lower four 1335326Sgibbs# bits of the target scratch space. This should work irregardless of 1345647Sgibbs# whether the bios has been installed. NEEDWDTR and NEEDSDTR are the top 1355647Sgibbs# two bits of the SCB control byte. The kernel driver will set these 1365647Sgibbs# when a WDTR or SDTR message should be sent to the target the SCB's 1375647Sgibbs# command references. 1384568Sgibbs# 1394568Sgibbs# The high bit of DROPATN is set if ATN should be dropped before the ACK 1404568Sgibbs# when outb is called. REJBYTE contains the first byte of a MESSAGE IN 1414568Sgibbs# message, so the driver can report an intelligible error if a message is 1424568Sgibbs# rejected. 1434568Sgibbs# 1445562Sgibbs# FLAGS's high bit is true if we are currently handling a reselect; 1454568Sgibbs# its next-highest bit is true ONLY IF we've seen an IDENTIFY message 1464568Sgibbs# from the reselecting target. If we haven't had IDENTIFY, then we have 1474568Sgibbs# no idea what the lun is, and we can't select the right SCB register 1484568Sgibbs# bank, so force a kernel panic if the target attempts a data in/out or 1494568Sgibbs# command phase instead of corrupting something. 1504568Sgibbs# 1514568Sgibbs# Note that SG_NEXT occupies four bytes. 1524568Sgibbs# 1534568SgibbsSYNCNEG = 0x20 1544568Sgibbs 1554568SgibbsDROPATN = 0x30 1564568SgibbsREJBYTE = 0x31 1575326SgibbsDISC_DSB_A = 0x32 1585326SgibbsDISC_DSB_B = 0x33 1594568Sgibbs 1604568SgibbsMSG_LEN = 0x36 1614568SgibbsMSG_START+0 = 0x37 1624568SgibbsMSG_START+1 = 0x38 1634568SgibbsMSG_START+2 = 0x39 1644568SgibbsMSG_START+3 = 0x3a 1654568SgibbsMSG_START+4 = 0x3b 1664568SgibbsMSG_START+5 = 0x3c 1674568Sgibbs-MSG_START+0 = 0xc9 # 2's complement of MSG_START+0 1684568Sgibbs 1694568SgibbsARG_1 = 0x4c # sdtr conversion args & return 1705647SgibbsBUS_16_BIT = 0x01 1714568SgibbsRETURN_1 = 0x4c 1724568Sgibbs 1735326SgibbsSIGSTATE = 0x4d # value written to SCSISIGO 1744568Sgibbs 1755647Sgibbs# Linux users should use 0xc (12) for SG_SIZEOF 1765647SgibbsSG_SIZEOF = 0x8 # sizeof(struct ahc_dma) 1775647Sgibbs#SG_SIZEOF = 0xc # sizeof(struct scatterlist) 1785647SgibbsSCB_SIZEOF = 0x13 # sizeof SCB to DMA (19 bytes) 1795647Sgibbs 1804568SgibbsSG_NOLOAD = 0x50 # load SG pointer/length? 1814568SgibbsSG_COUNT = 0x51 # working value of SG count 1824568SgibbsSG_NEXT = 0x52 # working value of SG pointer 1834568SgibbsSG_NEXT+0 = 0x52 1844568SgibbsSG_NEXT+1 = 0x53 1854568SgibbsSG_NEXT+2 = 0x54 1864568SgibbsSG_NEXT+3 = 0x55 1874568Sgibbs 1884568SgibbsSCBCOUNT = 0x56 # the actual number of SCBs 1895326SgibbsFLAGS = 0x57 # Device configuration flags 1905326SgibbsTWIN_BUS = 0x01 1915326SgibbsWIDE_BUS = 0x02 1925562SgibbsSENSE = 0x10 1935562SgibbsACTIVE_MSG = 0x20 1945562SgibbsIDENTIFY_SEEN = 0x40 1955562SgibbsRESELECTED = 0x80 1964568Sgibbs 1975326SgibbsACTIVE_A = 0x58 1985326SgibbsACTIVE_B = 0x59 1995326Sgibbs 2004866Sgibbs# Poll QINCNT for work - the lower bits contain 2014568Sgibbs# the number of entries in the Queue In FIFO. 2024568Sgibbs# 2034568Sgibbsstart: 2045562Sgibbs test FLAGS,SENSE jnz start_sense 2055775Sgibbsstart_nosense: 2065326Sgibbs test FLAGS,TWIN_BUS jz start2 # Are we a twin channel device? 2075326Sgibbs# For fairness, we check the other bus first, since we just finished a 2085326Sgibbs# transaction on the current channel. 2095326Sgibbs xor SBLKCTL,0x08 # Toggle to the other bus 2104568Sgibbs test SCSISIGI,0x4 jnz reselect # BSYI 2115326Sgibbs xor SBLKCTL,0x08 # Toggle to the original bus 2125326Sgibbsstart2: 2135326Sgibbs test SCSISIGI,0x4 jnz reselect # BSYI 2145775Sgibbs test QINCNT,SCBMASK jz start_nosense 2154568Sgibbs 2165647Sgibbs# We have at least one queued SCB now. Set the SCB pointer 2175647Sgibbs# from the FIFO so we see the right bank of SCB registers, 2185647Sgibbs# then set SCSI options and set the initiator and target 2195647Sgibbs# SCSI IDs. 2204568Sgibbs# 2214568Sgibbs mov SCBPTR,QINFIFO 2224568Sgibbs 2235647Sgibbs# If the control byte of this SCB has the NEEDDMA flag set, we have 2245647Sgibbs# yet to DMA it from host memory 2255647Sgibbs 2265647Sgibbstest SCBARRAY+0,NEEDDMA jz test_busy 2275647Sgibbs clr HCNT+2 2285647Sgibbs clr HCNT+1 2295647Sgibbs mvi HCNT+0,SCB_SIZEOF 2305647Sgibbs 2315647Sgibbs mvi DINDEX,HADDR 2325775Sgibbs mvi SCBARRAY+26 call bcopy_4 2335647Sgibbs 2345647Sgibbs mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET 2355647Sgibbs 2365647Sgibbs# Wait for DMA from host memory to data FIFO to complete, then disable 2375647Sgibbs# DMA and wait for it to acknowledge that it's off. 2385647Sgibbs# 2395647Sgibbsscb_load1: 2405647Sgibbs test DFSTATUS,0x8 jz scb_load1 # HDONE 2415647Sgibbs 2425647Sgibbs clr DFCNTRL # disable DMA 2435647Sgibbsscb_load2: 2445647Sgibbs test DFCNTRL,0x8 jnz scb_load2 # HDMAENACK 2455647Sgibbs 2465647Sgibbs# Copy the SCB from the FIFO to the SCBARRAY 2475647Sgibbs 2485647Sgibbs mov SCBARRAY+0, DFDAT 2495647Sgibbs mov SCBARRAY+1, DFDAT 2505647Sgibbs mov SCBARRAY+2, DFDAT 2515647Sgibbs mov SCBARRAY+3, DFDAT 2525647Sgibbs mov SCBARRAY+4, DFDAT 2535647Sgibbs mov SCBARRAY+5, DFDAT 2545647Sgibbs mov SCBARRAY+6, DFDAT 2555647Sgibbs mov SCBARRAY+7, DFDAT 2565647Sgibbs mov SCBARRAY+8, DFDAT 2575647Sgibbs mov SCBARRAY+9, DFDAT 2585647Sgibbs mov SCBARRAY+10, DFDAT 2595647Sgibbs mov SCBARRAY+11, DFDAT 2605647Sgibbs mov SCBARRAY+12, DFDAT 2615647Sgibbs mov SCBARRAY+13, DFDAT 2625647Sgibbs mov SCBARRAY+14, DFDAT 2635647Sgibbs mov SCBARRAY+15, DFDAT 2645647Sgibbs mov SCBARRAY+16, DFDAT 2655647Sgibbs mov SCBARRAY+17, DFDAT 2665647Sgibbs mov SCBARRAY+18, DFDAT 2675647Sgibbs 2684568Sgibbs# See if there is not already an active SCB for this target. This code 2695326Sgibbs# locks out on a per target basis instead of target/lun. Although this 2705326Sgibbs# is not ideal for devices that have multiple luns active at the same 2715326Sgibbs# time, it is faster than looping through all SCB's looking for active 2725326Sgibbs# commands. It may be benificial to make findscb a more general procedure 2735326Sgibbs# to see if the added cost of the search is negligible. This code also 2745326Sgibbs# assumes that the kernel driver will clear the active flags on board 2755326Sgibbs# initialization, board reset, and a target's SELTO. 2764568Sgibbs 2775647Sgibbstest_busy: 2784568Sgibbs and FUNCTION1,0x70,SCBARRAY+1 2794568Sgibbs mov A,FUNCTION1 2805326Sgibbs test SCBARRAY+1,0x88 jz test_a # Id < 8 && A channel 2815326Sgibbs 2825326Sgibbs test ACTIVE_B,A jnz requeue 2835326Sgibbs or ACTIVE_B,A # Mark the current target as busy 2845326Sgibbs jmp start_scb 2855326Sgibbs 2865562Sgibbsstart_sense: 2875562Sgibbs# Clear the SENSE flag first, then do a normal start_scb 2885562Sgibbs and FLAGS,0xef 2895562Sgibbs jmp start_scb 2905562Sgibbs 2914568Sgibbs# Place the currently active back on the queue for later processing 2925326Sgibbsrequeue: 2934568Sgibbs mov QINFIFO, SCBPTR 2945775Sgibbs jmp start_nosense 2954568Sgibbs 2965326Sgibbstest_a: 2975326Sgibbs test ACTIVE_A,A jnz requeue 2985326Sgibbs or ACTIVE_A,A # Mark the current target as busy 2995326Sgibbs 3005326Sgibbsstart_scb: 3015647Sgibbs or SCBARRAY+0,NEEDDMA 3025562Sgibbs and SINDEX,0x08,SCBARRAY+1 3035562Sgibbs and A,WIDE_BUS,FLAGS # Wide bus? 3045562Sgibbs or SINDEX,A 3055562Sgibbs mov SBLKCTL,SINDEX # select channel, bus width 3064568Sgibbs mov SCBARRAY+1 call initialize 3074568Sgibbs clr SG_NOLOAD 3085562Sgibbs and FLAGS,0x3f # !RESELECTING 3094568Sgibbs 3104568Sgibbs# As soon as we get a successful selection, the target should go 3114568Sgibbs# into the message out phase since we have ATN asserted. Prepare 3124568Sgibbs# the message to send, locking out the device driver. If the device 3134568Sgibbs# driver hasn't beaten us with an ABORT or RESET message, then tack 3144866Sgibbs# on an SDTR negotiation if required. 3154568Sgibbs# 3164568Sgibbs# Messages are stored in scratch RAM starting with a flag byte (high bit 3174568Sgibbs# set means active message), one length byte, and then the message itself. 3184568Sgibbs# 3194568Sgibbs mov SCBARRAY+1 call disconnect # disconnect ok? 3204568Sgibbs 3214568Sgibbs and SINDEX,0x7,SCBARRAY+1 # lun 3224568Sgibbs or SINDEX,A # return value from disconnect 3234568Sgibbs or SINDEX,0x80 call mk_mesg # IDENTIFY message 3244568Sgibbs 3254568Sgibbs mov A,SINDEX 3265647Sgibbs test SCBARRAY+0,0xc0 jz !message # WDTR or SDTR?? 3274568Sgibbs cmp MSG_START+0,A jne !message # did driver beat us? 3285562Sgibbs mvi MSG_START+1 call mk_dtr # build DTR message if needed 3294568Sgibbs 3304568Sgibbs!message: 3314568Sgibbs 3324568Sgibbs# Enable selection phase as an initiator, and do automatic ATN 3334568Sgibbs# after the selection. 3344568Sgibbs# 3354568Sgibbs mvi SCSISEQ,0x48 # ENSELO|ENAUTOATNO 3364568Sgibbs 3374568Sgibbs# Wait for successful arbitration. The AIC-7770 documentation says 3384568Sgibbs# that SELINGO indicates successful arbitration, and that it should 3394568Sgibbs# be used to look for SELDO. However, if the sequencer is paused at 3404568Sgibbs# just the right time - a parallel fsck(8) on two drives did it for 3414568Sgibbs# me - then SELINGO can flip back to false before we've seen it. This 3424568Sgibbs# makes the sequencer sit in the arbitration loop forever. This is 3434568Sgibbs# Not Good. 3444568Sgibbs# 3454568Sgibbs# Therefore, I've added a check in the arbitration loop for SELDO 3464568Sgibbs# too. This could arguably be made a critical section by disabling 3474568Sgibbs# pauses, but I don't want to make a potentially infinite loop a CS. 3484568Sgibbs# I suppose you could fold it into the select loop, too, but since 3494568Sgibbs# I've been hunting this bug for four days it's kinda like a trophy. 3504568Sgibbs# 3514568Sgibbsarbitrate: 3524568Sgibbs test SSTAT0,0x40 jnz *select # SELDO 3534568Sgibbs test SSTAT0,0x10 jz arbitrate # SELINGO 3544568Sgibbs 3554568Sgibbs# Wait for a successful selection. If the hardware selection 3564568Sgibbs# timer goes off, then the driver gets the interrupt, so we don't 3574568Sgibbs# need to worry about it. 3584568Sgibbs# 3594568Sgibbsselect: 3604568Sgibbs test SSTAT0,0x40 jz select # SELDO 3614568Sgibbs jmp *select 3624568Sgibbs 3634568Sgibbs# Reselection is being initiated by a target - we've seen the BSY 3644568Sgibbs# line driven active, and we didn't do it! Enable the reselection 3654568Sgibbs# hardware, and wait for it to finish. Make a note that we've been 3664568Sgibbs# reselected, but haven't seen an IDENTIFY message from the target 3674568Sgibbs# yet. 3684568Sgibbs# 3694568Sgibbsreselect: 3704568Sgibbs mvi SCSISEQ,0x10 # ENRSELI 3714568Sgibbs 3724568Sgibbsreselect1: 3734568Sgibbs test SSTAT0,0x20 jz reselect1 # SELDI 3744568Sgibbs mov SELID call initialize 3754568Sgibbs 3765562Sgibbs and FLAGS,0x3f # reselected, no IDENTIFY 3775562Sgibbs or FLAGS,RESELECTED 3784568Sgibbs 3794568Sgibbs# After the [re]selection, make sure that the [re]selection enable 3804568Sgibbs# bit is off. This chip is flaky enough without extra things 3814568Sgibbs# turned on. Also clear the BUSFREE bit in SSTAT1 since we'll be 3824568Sgibbs# using it shortly. 3834568Sgibbs# 3844568Sgibbs*select: 3854568Sgibbs clr SCSISEQ 3864568Sgibbs mvi CLRSINT1,0x8 # CLRBUSFREE 3874568Sgibbs 3884568Sgibbs# Main loop for information transfer phases. If BSY is false, then 3894568Sgibbs# we have a bus free condition, expected or not. Otherwise, wait 3904568Sgibbs# for the target to assert REQ before checking MSG, C/D and I/O 3914568Sgibbs# for the bus phase. 3924568Sgibbs# 3934568Sgibbs# We can't simply look at the values of SCSISIGI here (if we want 3944568Sgibbs# to do synchronous data transfer), because the target won't assert 3954568Sgibbs# REQ if it's already sent us some data that we haven't acknowledged 3964568Sgibbs# yet. 3974568Sgibbs# 3984568SgibbsITloop: 3994568Sgibbs test SSTAT1,0x8 jnz p_busfree # BUSFREE 4004568Sgibbs test SSTAT1,0x1 jz ITloop # REQINIT 4014568Sgibbs 4024568Sgibbs and A,0xe0,SCSISIGI # CDI|IOI|MSGI 4034568Sgibbs 4044568Sgibbs cmp ALLZEROS,A je p_dataout 4054568Sgibbs cmp A,0x40 je p_datain 4064568Sgibbs cmp A,0x80 je p_command 4074568Sgibbs cmp A,0xc0 je p_status 4084568Sgibbs cmp A,0xa0 je p_mesgout 4094568Sgibbs cmp A,0xe0 je p_mesgin 4104568Sgibbs 4115647Sgibbs mvi INTSTAT,BAD_PHASE # unknown - signal driver 4124568Sgibbs 4134568Sgibbsp_dataout: 4144568Sgibbs mvi 0 call scsisig # !CDO|!IOO|!MSGO 4154568Sgibbs call assert 4164568Sgibbs call sg_load 4174568Sgibbs 4185775Sgibbs mvi DINDEX,HADDR 4195775Sgibbs mvi SCBARRAY+19 call bcopy_4 4204568Sgibbs 4215775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 4225775Sgibbs mvi SCBARRAY+23 call bcopy_3 4235775Sgibbs 4244568Sgibbs mvi DINDEX,STCNT 4255775Sgibbs mvi SCBARRAY+23 call bcopy_3 4264568Sgibbs 4274568Sgibbs mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN| 4284568Sgibbs # DIRECTION|FIFORESET 4294568Sgibbs 4304568Sgibbs# After a DMA finishes, save the final transfer pointer and count 4314568Sgibbs# back into the SCB, in case a device disconnects in the middle of 4324568Sgibbs# a transfer. Use SHADDR and STCNT instead of HADDR and HCNT, since 4334568Sgibbs# it's a reflection of how many bytes were transferred on the SCSI 4344568Sgibbs# (as opposed to the host) bus. 4354568Sgibbs# 4364568Sgibbs mvi DINDEX,SCBARRAY+23 4375775Sgibbs mvi STCNT call bcopy_3 4384568Sgibbs 4394568Sgibbs mvi DINDEX,SCBARRAY+19 4405775Sgibbs mvi SHADDR call bcopy_4 4414568Sgibbs 4424568Sgibbs call sg_advance 4434568Sgibbs mov SCBARRAY+18,SG_COUNT # residual S/G count 4444568Sgibbs 4454568Sgibbs jmp ITloop 4464568Sgibbs 4474568Sgibbsp_datain: 4484568Sgibbs mvi 0x40 call scsisig # !CDO|IOO|!MSGO 4494568Sgibbs call assert 4504568Sgibbs call sg_load 4514568Sgibbs 4525775Sgibbs mvi DINDEX,HADDR 4535775Sgibbs mvi SCBARRAY+19 call bcopy_4 4544568Sgibbs 4555775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 4565775Sgibbs mvi SCBARRAY+23 call bcopy_3 4575775Sgibbs 4584568Sgibbs mvi DINDEX,STCNT 4595775Sgibbs mvi SCBARRAY+23 call bcopy_3 4604568Sgibbs 4614568Sgibbs mvi 0x39 call dma # SCSIEN|SDMAEN|HDMAEN| 4624568Sgibbs # !DIRECTION|FIFORESET 4634568Sgibbs mvi DINDEX,SCBARRAY+23 4645775Sgibbs mvi STCNT call bcopy_3 4654568Sgibbs 4664568Sgibbs mvi DINDEX,SCBARRAY+19 4675775Sgibbs mvi SHADDR call bcopy_4 4684568Sgibbs 4694568Sgibbs call sg_advance 4704568Sgibbs mov SCBARRAY+18,SG_COUNT # residual S/G count 4714568Sgibbs 4724568Sgibbs jmp ITloop 4734568Sgibbs 4744568Sgibbs# Command phase. Set up the DMA registers and let 'er rip - the 4754568Sgibbs# two bytes after the SCB SCSI_cmd_length are zeroed by the driver, 4764568Sgibbs# so we can copy those three bytes directly into HCNT. 4774568Sgibbs# 4784568Sgibbsp_command: 4794568Sgibbs mvi 0x80 call scsisig # CDO|!IOO|!MSGO 4804568Sgibbs call assert 4814568Sgibbs 4825775Sgibbs mvi DINDEX,HADDR 4835775Sgibbs mvi SCBARRAY+7 call bcopy_4 4844568Sgibbs 4855775Sgibbs# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR 4865775Sgibbs mvi SCBARRAY+11 call bcopy_3 4875775Sgibbs 4884568Sgibbs mvi DINDEX,STCNT 4895775Sgibbs mvi SCBARRAY+11 call bcopy_3 4904568Sgibbs 4914568Sgibbs mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN| 4924568Sgibbs # DIRECTION|FIFORESET 4934568Sgibbs jmp ITloop 4944568Sgibbs 4954568Sgibbs# Status phase. Wait for the data byte to appear, then read it 4964568Sgibbs# and store it into the SCB. 4974568Sgibbs# 4984568Sgibbsp_status: 4994568Sgibbs mvi 0xc0 call scsisig # CDO|IOO|!MSGO 5004568Sgibbs 5014568Sgibbs mvi SCBARRAY+14 call inb 5024568Sgibbs jmp ITloop 5034568Sgibbs 5044568Sgibbs# Message out phase. If there is no active message, but the target 5054568Sgibbs# took us into this phase anyway, build a no-op message and send it. 5064568Sgibbs# 5074568Sgibbsp_mesgout: 5084568Sgibbs mvi 0xa0 call scsisig # CDO|!IOO|MSGO 5094568Sgibbs mvi 0x8 call mk_mesg # build NOP message 5104568Sgibbs 5114568Sgibbs# Set up automatic PIO transfer from MSG_START. Bit 3 in 5124568Sgibbs# SXFRCTL0 (SPIOEN) is already on. 5134568Sgibbs# 5144568Sgibbs mvi SINDEX,MSG_START+0 5154568Sgibbs mov DINDEX,MSG_LEN 5164568Sgibbs clr A 5174568Sgibbs 5184568Sgibbs# When target asks for a byte, drop ATN if it's the last one in 5194568Sgibbs# the message. Otherwise, keep going until the message is exhausted. 5204568Sgibbs# (We can't use outb for this since it wants the input in SINDEX.) 5214568Sgibbs# 5224568Sgibbs# Keep an eye out for a phase change, in case the target issues 5234568Sgibbs# a MESSAGE REJECT. 5244568Sgibbs# 5254568Sgibbsp_mesgout2: 5264568Sgibbs test SSTAT0,0x2 jz p_mesgout2 # SPIORDY 5274568Sgibbs test SSTAT1,0x10 jnz p_mesgout6 # PHASEMIS 5284568Sgibbs 5294568Sgibbs cmp DINDEX,1 jne p_mesgout3 # last byte? 5304568Sgibbs mvi CLRSINT1,0x40 # CLRATNO - drop ATN 5314568Sgibbs 5324568Sgibbs# Write a byte to the SCSI bus. The AIC-7770 refuses to automatically 5334568Sgibbs# send ACKs in automatic PIO or DMA mode unless you make sure that the 5344568Sgibbs# "expected" bus phase in SCSISIGO matches the actual bus phase. This 5354568Sgibbs# behaviour is completely undocumented and caused me several days of 5364568Sgibbs# grief. 5374568Sgibbs# 5384568Sgibbs# After plugging in different drives to test with and using a longer 5394568Sgibbs# SCSI cable, I found that I/O in Automatic PIO mode ceased to function, 5404568Sgibbs# especially when transferring >1 byte. It seems to be much more stable 5414568Sgibbs# if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is 5424568Sgibbs# polled for transfer completion - for both output _and_ input. The 5434568Sgibbs# only theory I have is that SPIORDY doesn't drop right away when SCSIDATL 5444568Sgibbs# is accessed (like the documentation says it does), and that on a longer 5454568Sgibbs# cable run, the sequencer code was fast enough to loop back and see 5464568Sgibbs# an SPIORDY that hadn't dropped yet. 5474568Sgibbs# 5484568Sgibbsp_mesgout3: 5494568Sgibbs call one_stcnt 5504568Sgibbs mov SCSIDATL,SINDIR 5514568Sgibbs 5524568Sgibbsp_mesgout4: 5534568Sgibbs test SSTAT0,0x4 jz p_mesgout4 # SDONE 5544568Sgibbs dec DINDEX 5554568Sgibbs inc A 5564568Sgibbs cmp MSG_LEN,A jne p_mesgout2 5574568Sgibbs 5584568Sgibbs# If the next bus phase after ATN drops is a message out, it means 5594568Sgibbs# that the target is requesting that the last message(s) be resent. 5604568Sgibbs# 5614568Sgibbsp_mesgout5: 5624568Sgibbs test SSTAT1,0x8 jnz p_mesgout6 # BUSFREE 5634568Sgibbs test SSTAT1,0x1 jz p_mesgout5 # REQINIT 5644568Sgibbs 5654568Sgibbs and A,0xe0,SCSISIGI # CDI|IOI|MSGI 5664568Sgibbs cmp A,0xa0 jne p_mesgout6 5674568Sgibbs mvi 0x10 call scsisig # ATNO - re-assert ATN 5684568Sgibbs 5694568Sgibbs jmp ITloop 5704568Sgibbs 5714568Sgibbsp_mesgout6: 5724568Sgibbs mvi CLRSINT1,0x40 # CLRATNO - in case of PHASEMIS 5735562Sgibbs and FLAGS,0xdf # no active msg 5744568Sgibbs jmp ITloop 5754568Sgibbs 5764568Sgibbs# Message in phase. Bytes are read using Automatic PIO mode, but not 5774568Sgibbs# using inb. This alleviates a race condition, namely that if ATN had 5784568Sgibbs# to be asserted under Automatic PIO mode, it had to beat the SCSI 5794568Sgibbs# circuitry sending an ACK to the target. This showed up under heavy 5804568Sgibbs# loads and really confused things, since ABORT commands wouldn't be 5814568Sgibbs# seen by the drive after an IDENTIFY message in until it had changed 5824568Sgibbs# to a data I/O phase. 5834568Sgibbs# 5844568Sgibbsp_mesgin: 5854568Sgibbs mvi 0xe0 call scsisig # CDO|IOO|MSGO 5864568Sgibbs mvi A call inb_first # read the 1st message byte 5874568Sgibbs mvi REJBYTE,A # save it for the driver 5884568Sgibbs 5894568Sgibbs cmp ALLZEROS,A jne p_mesgin1 5904568Sgibbs 5914568Sgibbs# We got a "command complete" message, so put the SCB pointer 5924568Sgibbs# into the Queue Out, and trigger a completion interrupt. 5934568Sgibbs# Check status for non zero return and interrupt driver if needed 5945326Sgibbs# This allows the driver to interpret errors only when they occur 5955326Sgibbs# instead of always uploading the scb. If the status is SCSI_CHECK, 5965326Sgibbs# the driver will download a new scb requesting sense, to replace 5975326Sgibbs# the old one and the sequencer code will imediately jump to start 5985326Sgibbs# working on it. If the kernel driver does not wish to request sense, 5995326Sgibbs# the sequencer program counter is incremented by 1, preventing another run 6005326Sgibbs# on the current SCB and the command is allowed to complete. We don't 6015326Sgibbs# bother to post to the QOUTFIFO in the error case since it would require 6025326Sgibbs# extra work in the kernel driver to ensure that the entry was removed 6035326Sgibbs# before the command complete code tried processing it. 6044568Sgibbs 6055647Sgibbs test SCBARRAY+14,0xff jz status_ok # 0 Status? 6065647Sgibbs mvi INTSTAT,BAD_STATUS # let driver know 6075562Sgibbs test FLAGS,SENSE jz status_ok 6085562Sgibbs jmp p_mesgin_done 6095326Sgibbs 6104568Sgibbsstatus_ok: 6115326Sgibbs 6125326Sgibbs# First, mark this target as free. 6135326Sgibbs and FUNCTION1,0x70,SCBARRAY+1 6145326Sgibbs mov A,FUNCTION1 6155326Sgibbs test SCBARRAY+1,0x88 jz clear_a 6165326Sgibbs xor ACTIVE_B,A 6175326Sgibbs jmp complete 6185326Sgibbs 6195326Sgibbsclear_a: 6205326Sgibbs xor ACTIVE_A,A 6215326Sgibbs 6225326Sgibbscomplete: 6234568Sgibbs mov QOUTFIFO,SCBPTR 6245326Sgibbs mvi INTSTAT,0x02 # CMDCMPLT 6254568Sgibbs jmp p_mesgin_done 6264568Sgibbs 6275562Sgibbs# Is it an extended message? We only support the synchronous and wide data 6285562Sgibbs# transfer request messages, which will probably be in response to 6295562Sgibbs# WDTR or SDTR message outs from us. If it's not SDTR or WDTR, reject it - 6304568Sgibbs# apparently this can be done after any message in byte, according 6314568Sgibbs# to the SCSI-2 spec. 6324568Sgibbs# 6334568Sgibbsp_mesgin1: 6344568Sgibbs cmp A,1 jne p_mesgin2 # extended message code? 6354568Sgibbs 6365562Sgibbs mvi ARG_1 call inb_next # extended message length 6375562Sgibbs mvi A call inb_next # extended message code 6384568Sgibbs 6395562Sgibbs cmp A,1 je p_mesginSDTR # Syncronous negotiation message 6405562Sgibbs cmp A,3 je p_mesginWDTR # Wide negotiation message 6415562Sgibbs jmp p_mesginN 6425562Sgibbs 6435562Sgibbsp_mesginWDTR: 6445562Sgibbs cmp ARG_1,2 jne p_mesginN # extended mesg length = 2 6455562Sgibbs mvi A call inb_next # Width of bus 6465647Sgibbs mvi INTSTAT,MSG_WDTR # let driver know 6475562Sgibbs test RETURN_1,0x80 jz p_mesgin_done# Do we need to send WDTR? 6485562Sgibbs 6495562Sgibbs# We didn't initiate the wide negotiation, so we must respond to the request 6505562Sgibbs and RETURN_1,0x7f # Clear the SEND_WDTR Flag 6515562Sgibbs or FLAGS,ACTIVE_MSG 6525647Sgibbs mvi DINDEX,MSG_START+0 6535562Sgibbs mvi MSG_START+0 call mk_wdtr # build WDTR message 6545562Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 6555562Sgibbs call scsisig 6565562Sgibbs jmp p_mesgin_done 6575562Sgibbs 6585562Sgibbsp_mesginSDTR: 6595562Sgibbs cmp ARG_1,3 jne p_mesginN # extended mesg length = 3 6604568Sgibbs mvi ARG_1 call inb_next # xfer period 6615326Sgibbs mvi A call inb_next # REQ/ACK offset 6625647Sgibbs mvi INTSTAT,MSG_SDTR # call driver to convert 6634568Sgibbs 6645562Sgibbs test RETURN_1,0x80 jz p_mesgin_done# Do we need to mk_sdtr? 6655326Sgibbs 6665562Sgibbs or FLAGS,ACTIVE_MSG 6675647Sgibbs mvi DINDEX, MSG_START+0 6685562Sgibbs mvi MSG_START+0 call mk_sdtr 6695562Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 6705562Sgibbs call scsisig 6714568Sgibbs jmp p_mesgin_done 6724568Sgibbs 6734568Sgibbs# Is it a disconnect message? Set a flag in the SCB to remind us 6744568Sgibbs# and await the bus going free. 6754568Sgibbs# 6764568Sgibbsp_mesgin2: 6774568Sgibbs cmp A,4 jne p_mesgin3 # disconnect code? 6784568Sgibbs 6794568Sgibbs or SCBARRAY+0,0x4 # set "disconnected" bit 6804568Sgibbs jmp p_mesgin_done 6814568Sgibbs 6824568Sgibbs# Save data pointers message? Copy working values into the SCB, 6834568Sgibbs# usually in preparation for a disconnect. 6844568Sgibbs# 6854568Sgibbsp_mesgin3: 6864568Sgibbs cmp A,2 jne p_mesgin4 # save data pointers code? 6874568Sgibbs 6884568Sgibbs call sg_ram2scb 6894568Sgibbs jmp p_mesgin_done 6904568Sgibbs 6914568Sgibbs# Restore pointers message? Data pointers are recopied from the 6924568Sgibbs# SCB anyway at the start of any DMA operation, so the only thing 6934568Sgibbs# to copy is the scatter-gather values. 6944568Sgibbs# 6954568Sgibbsp_mesgin4: 6964568Sgibbs cmp A,3 jne p_mesgin5 # restore pointers code? 6974568Sgibbs 6984568Sgibbs call sg_scb2ram 6994568Sgibbs jmp p_mesgin_done 7004568Sgibbs 7014568Sgibbs# Identify message? For a reconnecting target, this tells us the lun 7024568Sgibbs# that the reconnection is for - find the correct SCB and switch to it, 7034568Sgibbs# clearing the "disconnected" bit so we don't "find" it by accident later. 7044568Sgibbs# 7054568Sgibbsp_mesgin5: 7064568Sgibbs test A,0x80 jz p_mesgin6 # identify message? 7074568Sgibbs 7084568Sgibbs test A,0x78 jnz p_mesginN # !DiscPriv|!LUNTAR|!Reserved 7094568Sgibbs 7104568Sgibbs mov A call findSCB # switch to correct SCB 7114568Sgibbs 7124568Sgibbs# If a active message is present after calling findSCB, then either it 7134568Sgibbs# or the driver is trying to abort the command. Either way, something 7144568Sgibbs# untoward has happened and we should just leave it alone. 7154568Sgibbs# 7165562Sgibbs test FLAGS,ACTIVE_MSG jnz p_mesgin_done 7174568Sgibbs 7185326Sgibbs and SCBARRAY+0,0xfb # clear disconnect bit in SCB 7195562Sgibbs or FLAGS,0xc0 # make note of IDENTIFY 7204568Sgibbs 7214568Sgibbs call sg_scb2ram # implied restore pointers 7224568Sgibbs # required on reselect 7234568Sgibbs jmp p_mesgin_done 7244568Sgibbs 7255647Sgibbs# Message reject? Let the kernel driver handle this. If we have an 7265647Sgibbs# outstanding WDTR or SDTR negotiation, assume that it's a response from 7275647Sgibbs# the target selecting 8bit or asynchronous transfer, otherwise just ignore 7285647Sgibbs# it since we have no clue what it pertains to. 7294568Sgibbs# 7304568Sgibbsp_mesgin6: 7314568Sgibbs cmp A,7 jne p_mesgin7 # message reject code? 7324568Sgibbs 7335647Sgibbs mvi INTSTAT, MSG_REJECT 7345562Sgibbs jmp p_mesgin_done 7355562Sgibbs 7364568Sgibbs# [ ADD MORE MESSAGE HANDLING HERE ] 7374568Sgibbs# 7384568Sgibbsp_mesgin7: 7394568Sgibbs 7404568Sgibbs# We have no idea what this message in is, and there's no way 7414568Sgibbs# to pass it up to the kernel, so we issue a message reject and 7424568Sgibbs# hope for the best. Since we're now using manual PIO mode to 7434568Sgibbs# read in the message, there should no longer be a race condition 7444568Sgibbs# present when we assert ATN. In any case, rejection should be a 7454568Sgibbs# rare occurrence - signal the driver when it happens. 7464568Sgibbs# 7474568Sgibbsp_mesginN: 7484568Sgibbs or SINDEX,0x10,SIGSTATE # turn on ATNO 7494568Sgibbs call scsisig 7505647Sgibbs mvi INTSTAT,SEND_REJECT # let driver know 7514568Sgibbs 7524568Sgibbs mvi 0x7 call mk_mesg # MESSAGE REJECT message 7534568Sgibbs 7544568Sgibbsp_mesgin_done: 7554568Sgibbs call inb_last # ack & turn auto PIO back on 7564568Sgibbs jmp ITloop 7574568Sgibbs 7584568Sgibbs# Bus free phase. It might be useful to interrupt the device 7594568Sgibbs# driver if we aren't expecting this. For now, make sure that 7604568Sgibbs# ATN isn't being asserted and look for a new command. 7614568Sgibbs# 7624568Sgibbsp_busfree: 7634568Sgibbs mvi CLRSINT1,0x40 # CLRATNO 7644568Sgibbs clr SIGSTATE 7654568Sgibbs jmp start 7664568Sgibbs 7675775Sgibbs# Instead of a generic bcopy routine that requires an argument, we unroll 7685775Sgibbs# the two cases that are actually used, and call them explicitly. This 7695775Sgibbs# not only reduces the overhead of doing a bcopy by 2/3rds, but ends up 7705775Sgibbs# saving space in the program since you don't have to put the argument 7715775Sgibbs# into the accumulator before the call. Both functions expect DINDEX to 7725775Sgibbs# contain the destination address and SINDEX to contain the source 7735775Sgibbs# address. 7745775Sgibbsbcopy_3: 7754568Sgibbs mov DINDIR,SINDIR 7765775Sgibbs mov DINDIR,SINDIR 7775775Sgibbs mov DINDIR,SINDIR ret 7784568Sgibbs 7795775Sgibbsbcopy_4: 7805775Sgibbs mov DINDIR,SINDIR 7815775Sgibbs mov DINDIR,SINDIR 7825775Sgibbs mov DINDIR,SINDIR 7835775Sgibbs mov DINDIR,SINDIR ret 7845775Sgibbs 7855775Sgibbs 7864568Sgibbs# Locking the driver out, build a one-byte message passed in SINDEX 7874568Sgibbs# if there is no active message already. SINDEX is returned intact. 7884568Sgibbs# 7894568Sgibbsmk_mesg: 7904866Sgibbs mvi SEQCTL,0x50 # PAUSEDIS|FASTMODE 7915562Sgibbs test FLAGS,ACTIVE_MSG jnz mk_mesg1 # active message? 7924568Sgibbs 7935562Sgibbs or FLAGS,ACTIVE_MSG # if not, there is now 7944568Sgibbs mvi MSG_LEN,1 # length = 1 7954568Sgibbs mov MSG_START+0,SINDEX # 1-byte message 7964568Sgibbs 7974568Sgibbsmk_mesg1: 7985775Sgibbs mvi SEQCTL,0x10 ret # !PAUSEDIS|FASTMODE 7994568Sgibbs 8004568Sgibbs# Input byte in Automatic PIO mode. The address to store the byte 8014568Sgibbs# in should be in SINDEX. DINDEX will be used by this routine. 8024568Sgibbs# 8034568Sgibbsinb: 8044568Sgibbs test SSTAT0,0x2 jz inb # SPIORDY 8054568Sgibbs mov DINDEX,SINDEX 8064568Sgibbs call one_stcnt # xfer one byte 8074568Sgibbs mov DINDIR,SCSIDATL 8084568Sgibbsinb1: 8094568Sgibbs test SSTAT0,0x4 jz inb1 # SDONE - wait to "finish" 8104568Sgibbs ret 8114568Sgibbs 8124568Sgibbs# Carefully read data in Automatic PIO mode. I first tried this using 8134568Sgibbs# Manual PIO mode, but it gave me continual underrun errors, probably 8144568Sgibbs# indicating that I did something wrong, but I feel more secure leaving 8154568Sgibbs# Automatic PIO on all the time. 8164568Sgibbs# 8174568Sgibbs# According to Adaptec's documentation, an ACK is not sent on input from 8184568Sgibbs# the target until SCSIDATL is read from. So we wait until SCSIDATL is 8194568Sgibbs# latched (the usual way), then read the data byte directly off the bus 8204568Sgibbs# using SCSIBUSL. When we have pulled the ATN line, or we just want to 8214568Sgibbs# acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 8224568Sgibbs# spec guarantees that the target will hold the data byte on the bus until 8234568Sgibbs# we send our ACK. 8244568Sgibbs# 8254568Sgibbs# The assumption here is that these are called in a particular sequence, 8264568Sgibbs# and that REQ is already set when inb_first is called. inb_{first,next} 8274568Sgibbs# use the same calling convention as inb. 8284568Sgibbs# 8294568Sgibbsinb_first: 8304568Sgibbs mov DINDEX,SINDEX 8314568Sgibbs mov DINDIR,SCSIBUSL ret # read byte directly from bus 8324568Sgibbs 8334568Sgibbsinb_next: 8344568Sgibbs mov DINDEX,SINDEX # save SINDEX 8354568Sgibbs 8364568Sgibbs call one_stcnt # xfer one byte 8374568Sgibbs mov NONE,SCSIDATL # dummy read from latch to ACK 8384568Sgibbsinb_next1: 8394568Sgibbs test SSTAT0,0x4 jz inb_next1 # SDONE 8404568Sgibbsinb_next2: 8414568Sgibbs test SSTAT0,0x2 jz inb_next2 # SPIORDY - wait for next byte 8424568Sgibbs mov DINDIR,SCSIBUSL ret # read byte directly from bus 8434568Sgibbs 8444568Sgibbsinb_last: 8454568Sgibbs call one_stcnt # ACK with dummy read 8464568Sgibbs mov NONE,SCSIDATL 8474568Sgibbsinb_last1: 8484568Sgibbs test SSTAT0,0x4 jz inb_last1 # wait for completion 8494568Sgibbs ret 8504568Sgibbs 8514568Sgibbs# Output byte in Automatic PIO mode. The byte to output should be 8524568Sgibbs# in SINDEX. If DROPATN's high bit is set, then ATN will be dropped 8534568Sgibbs# before the byte is output. 8544568Sgibbs# 8554568Sgibbsoutb: 8564568Sgibbs test SSTAT0,0x2 jz outb # SPIORDY 8574568Sgibbs call one_stcnt # xfer one byte 8584568Sgibbs 8594568Sgibbs test DROPATN,0x80 jz outb1 8604568Sgibbs mvi CLRSINT1,0x40 # CLRATNO 8614568Sgibbs clr DROPATN 8624568Sgibbsoutb1: 8634568Sgibbs mov SCSIDATL,SINDEX 8644568Sgibbsoutb2: 8654568Sgibbs test SSTAT0,0x4 jz outb2 # SDONE 8664568Sgibbs ret 8674568Sgibbs 8684568Sgibbs# Write the value "1" into the STCNT registers, for Automatic PIO 8694568Sgibbs# transfers. 8704568Sgibbs# 8714568Sgibbsone_stcnt: 8724568Sgibbs clr STCNT+2 8734568Sgibbs clr STCNT+1 8744568Sgibbs mvi STCNT+0,1 ret 8754568Sgibbs 8764568Sgibbs# DMA data transfer. HADDR and HCNT must be loaded first, and 8774568Sgibbs# SINDEX should contain the value to load DFCNTRL with - 0x3d for 8784568Sgibbs# host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 8794568Sgibbs# during initialization. 8804568Sgibbs# 8814568Sgibbsdma: 8824568Sgibbs mov DFCNTRL,SINDEX 8834568Sgibbsdma1: 8844568Sgibbsdma2: 8854568Sgibbs test SSTAT0,0x1 jnz dma3 # DMADONE 8864568Sgibbs test SSTAT1,0x10 jz dma1 # PHASEMIS, ie. underrun 8874568Sgibbs 8884568Sgibbs# We will be "done" DMAing when the transfer count goes to zero, or 8894568Sgibbs# the target changes the phase (in light of this, it makes sense that 8904568Sgibbs# the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 8914866Sgibbs# doing a SCSI->Host transfer, the data FIFO should be flushed auto- 8924866Sgibbs# magically on STCNT=0 or a phase change, so just wait for FIFO empty 8934866Sgibbs# status. 8944568Sgibbs# 8954568Sgibbsdma3: 8964568Sgibbs test SINDEX,0x4 jnz dma5 # DIRECTION 8974568Sgibbsdma4: 8985562Sgibbs test DFSTATUS,0x1 jz dma4 # !FIFOEMP 8994568Sgibbs 9004568Sgibbs# Now shut the DMA enables off, and copy STCNT (ie. the underrun 9014568Sgibbs# amount, if any) to the SCB registers; SG_COUNT will get copied to 9024568Sgibbs# the SCB's residual S/G count field after sg_advance is called. Make 9034568Sgibbs# sure that the DMA enables are actually off first lest we get an ILLSADDR. 9044568Sgibbs# 9054568Sgibbsdma5: 9064568Sgibbs clr DFCNTRL # disable DMA 9074568Sgibbsdma6: 9084568Sgibbs test DFCNTRL,0x38 jnz dma6 # SCSIENACK|SDMAENACK|HDMAENACK 9094568Sgibbs 9104568Sgibbs mvi DINDEX,SCBARRAY+15 9115775Sgibbs mvi STCNT call bcopy_3 9124568Sgibbs 9134568Sgibbs ret 9144568Sgibbs 9154568Sgibbs# Common SCSI initialization for selection and reselection. Expects 9164568Sgibbs# the target SCSI ID to be in the upper four bits of SINDEX, and A's 9174568Sgibbs# contents are stomped on return. 9184568Sgibbs# 9194568Sgibbsinitialize: 9205775Sgibbs and SINDEX,0xf0 # Get target ID 9215775Sgibbs and A,0x0f,SCSIID 9225775Sgibbs or SINDEX,A 9235775Sgibbs mov SCSIID,SINDEX 9245326Sgibbs 9254568Sgibbs# Esundry initialization. 9264568Sgibbs# 9274568Sgibbs clr DROPATN 9284568Sgibbs clr SIGSTATE 9294568Sgibbs 9305775Sgibbs# Turn on Automatic PIO mode now, before we expect to see a REQ 9314568Sgibbs# from the target. It shouldn't hurt anything to leave it on. Set 9324568Sgibbs# CLRCHN here before the target has entered a data transfer mode - 9334568Sgibbs# with synchronous SCSI, if you do it later, you blow away some 9344568Sgibbs# data in the SCSI FIFO that the target has already sent to you. 9354568Sgibbs# 9364866Sgibbs mvi SXFRCTL0,0x8a # DFON|SPIOEN|CLRCHN 9374568Sgibbs 9384568Sgibbs# Initialize scatter-gather pointers by setting up the working copy 9394568Sgibbs# in scratch RAM. 9404568Sgibbs# 9414568Sgibbs call sg_scb2ram 9424568Sgibbs 9434568Sgibbs# Initialize SCSIRATE with the appropriate value for this target. 9444568Sgibbs# 9455562Sgibbs call ndx_dtr 9465775Sgibbs mov SCSIRATE,SINDIR ret 9474568Sgibbs 9484568Sgibbs# Assert that if we've been reselected, then we've seen an IDENTIFY 9494568Sgibbs# message. 9504568Sgibbs# 9514568Sgibbsassert: 9525562Sgibbs test FLAGS,RESELECTED jz assert1 # reselected? 9535562Sgibbs test FLAGS,IDENTIFY_SEEN jnz assert1 # seen IDENTIFY? 9544568Sgibbs 9555647Sgibbs mvi INTSTAT,NO_IDENT # no - cause a kernel panic 9564568Sgibbs 9574568Sgibbsassert1: 9584568Sgibbs ret 9594568Sgibbs 9604568Sgibbs# Find out if disconnection is ok from the information the BIOS has left 9615326Sgibbs# us. The tcl from SCBARRAY+1 should be in SINDEX; A will 9624866Sgibbs# contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok) 9634568Sgibbs# on exit. 9644568Sgibbs# 9655326Sgibbs# To allow for wide or twin busses, we check the upper bit of the target ID 9665326Sgibbs# and the channel ID and look at the appropriate disconnect register. 9674568Sgibbs# 9684568Sgibbsdisconnect: 9694568Sgibbs and FUNCTION1,0x70,SINDEX # strip off extra just in case 9704568Sgibbs mov A,FUNCTION1 9715326Sgibbs test SINDEX, 0x88 jz disconnect_a 9725326Sgibbs 9735326Sgibbs test DISC_DSB_B,A jz disconnect1 # bit nonzero if DISabled 9745326Sgibbs clr A ret 9755326Sgibbs 9765326Sgibbsdisconnect_a: 9774568Sgibbs test DISC_DSB_A,A jz disconnect1 # bit nonzero if DISabled 9785326Sgibbs clr A ret 9794568Sgibbs 9804568Sgibbsdisconnect1: 9814568Sgibbs mvi A,0x40 ret 9824568Sgibbs 9834568Sgibbs# Locate the SCB matching the target ID in SELID and the lun in the lower 9844568Sgibbs# three bits of SINDEX, and switch the SCB to it. Have the kernel print 9854568Sgibbs# a warning message if it can't be found, and generate an ABORT message 9864866Sgibbs# to the target. We keep the value of the t/c/l that we are trying to find 9874568Sgibbs# in DINDEX so it is not overwritten during our check to see if we are 9884568Sgibbs# at the last SCB. 9894568Sgibbs# 9904568SgibbsfindSCB: 9914568Sgibbs and A,0x7,SINDEX # lun in lower three bits 9925326Sgibbs or DINDEX,A,SELID 9935326Sgibbs and DINDEX,0xf7 9945326Sgibbs and A,0x08,SBLKCTL # B Channel?? 9955326Sgibbs or DINDEX,A 9964568Sgibbs clr SINDEX 9974568Sgibbs 9984568SgibbsfindSCB1: 9994866Sgibbs mov A,DINDEX 10004568Sgibbs mov SCBPTR,SINDEX # switch to new SCB 10014568Sgibbs cmp SCBARRAY+1,A jne findSCB2 # target ID/channel/lun match? 10024568Sgibbs test SCBARRAY+0,0x4 jz findSCB2 # should be disconnected 10034568Sgibbs ret 10044568Sgibbs 10054568SgibbsfindSCB2: 10064568Sgibbs inc SINDEX 10074568Sgibbs mov A,SCBCOUNT 10084568Sgibbs cmp SINDEX,A jne findSCB1 10094568Sgibbs 10105647Sgibbs mvi INTSTAT,NO_MATCH # not found - signal kernel 10114568Sgibbs mvi 0x6 call mk_mesg # ABORT message 10124568Sgibbs 10134568Sgibbs or SINDEX,0x10,SIGSTATE # assert ATNO 10144568Sgibbs call scsisig 10154568Sgibbs ret 10164568Sgibbs 10174568Sgibbs# Make a working copy of the scatter-gather parameters in the SCB. 10184568Sgibbs# 10194568Sgibbssg_scb2ram: 10204568Sgibbs mov SG_COUNT,SCBARRAY+2 10214568Sgibbs 10224568Sgibbs mvi DINDEX,SG_NEXT 10235775Sgibbs mvi SCBARRAY+3 call bcopy_4 10244568Sgibbs 10254568Sgibbs mvi SG_NOLOAD,0x80 10264568Sgibbs test SCBARRAY+0,0x10 jnz sg_scb2ram1 # don't reload s/g? 10274568Sgibbs clr SG_NOLOAD 10284568Sgibbs 10294568Sgibbssg_scb2ram1: 10304568Sgibbs ret 10314568Sgibbs 10324568Sgibbs# Copying RAM values back to SCB, for Save Data Pointers message. 10334568Sgibbs# 10344568Sgibbssg_ram2scb: 10354568Sgibbs mov SCBARRAY+2,SG_COUNT 10364568Sgibbs 10374568Sgibbs mvi DINDEX,SCBARRAY+3 10385775Sgibbs mvi SG_NEXT call bcopy_4 10394568Sgibbs 10404568Sgibbs and SCBARRAY+0,0xef,SCBARRAY+0 10414568Sgibbs test SG_NOLOAD,0x80 jz sg_ram2scb1 # reload s/g? 10425647Sgibbs or SCBARRAY+0,SG_LOAD 10434568Sgibbs 10444568Sgibbssg_ram2scb1: 10454568Sgibbs ret 10464568Sgibbs 10474568Sgibbs# Load a struct scatter if needed and set up the data address and 10484568Sgibbs# length. If the working value of the SG count is nonzero, then 10494568Sgibbs# we need to load a new set of values. 10504568Sgibbs# 10514568Sgibbs# This, like the above DMA, assumes a little-endian host data storage. 10524568Sgibbs# 10534568Sgibbssg_load: 10544568Sgibbs test SG_COUNT,0xff jz sg_load3 # SG being used? 10554568Sgibbs test SG_NOLOAD,0x80 jnz sg_load3 # don't reload s/g? 10564568Sgibbs 10574568Sgibbs clr HCNT+2 10584568Sgibbs clr HCNT+1 10594568Sgibbs mvi HCNT+0,SG_SIZEOF 10604568Sgibbs 10614568Sgibbs mvi DINDEX,HADDR 10625775Sgibbs mvi SG_NEXT call bcopy_4 10634568Sgibbs 10644568Sgibbs mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET 10654568Sgibbs 10664568Sgibbs# Wait for DMA from host memory to data FIFO to complete, then disable 10674568Sgibbs# DMA and wait for it to acknowledge that it's off. 10684568Sgibbs# 10694568Sgibbssg_load1: 10704568Sgibbs test DFSTATUS,0x8 jz sg_load1 # HDONE 10714568Sgibbs 10724568Sgibbs clr DFCNTRL # disable DMA 10734568Sgibbssg_load2: 10744568Sgibbs test DFCNTRL,0x8 jnz sg_load2 # HDMAENACK 10754568Sgibbs 10764568Sgibbs# Copy data from FIFO into SCB data pointer and data count. This assumes 10774568Sgibbs# that the struct scatterlist has this structure (this and sizeof(struct 10784568Sgibbs# scatterlist) == 12 are asserted in aic7xxx.c): 10794568Sgibbs# 10804568Sgibbs# struct scatterlist { 10814568Sgibbs# char *address; /* four bytes, little-endian order */ 10824568Sgibbs# ... /* four bytes, ignored */ 10834568Sgibbs# unsigned short length; /* two bytes, little-endian order */ 10844568Sgibbs# } 10854568Sgibbs# 10864568Sgibbs 10874568Sgibbs# Not in FreeBSD. the scatter list is only 8 bytes. 10884568Sgibbs# 10894568Sgibbs# struct ahc_dma_seg { 10904568Sgibbs# physaddr addr; /* four bytes, little-endian order */ 10914568Sgibbs# long len; /* four bytes, little endian order */ 10924568Sgibbs# }; 10934568Sgibbs# 10944568Sgibbs 10954568Sgibbs mov SCBARRAY+19,DFDAT # new data address 10964568Sgibbs mov SCBARRAY+20,DFDAT 10974568Sgibbs mov SCBARRAY+21,DFDAT 10984568Sgibbs mov SCBARRAY+22,DFDAT 10994568Sgibbs 11005647Sgibbs# For Linux, we must throw away four bytes since there is a 32bit gap 11015647Sgibbs# in the middle of a struct scatterlist 11025647Sgibbs# mov NONE,DFDAT 11035647Sgibbs# mov NONE,DFDAT 11045647Sgibbs# mov NONE,DFDAT 11055647Sgibbs# mov NONE,DFDAT 11065647Sgibbs 11074568Sgibbs mov SCBARRAY+23,DFDAT 11084568Sgibbs mov SCBARRAY+24,DFDAT 11095647Sgibbs mov SCBARRAY+25,DFDAT #Only support 24 bit length. 11104568Sgibbs 11114568Sgibbssg_load3: 11124568Sgibbs ret 11134568Sgibbs 11144568Sgibbs# Advance the scatter-gather pointers only IF NEEDED. If SG is enabled, 11154568Sgibbs# and the SCSI transfer count is zero (note that this should be called 11164568Sgibbs# right after a DMA finishes), then move the working copies of the SG 11174568Sgibbs# pointer/length along. If the SCSI transfer count is not zero, then 11184568Sgibbs# presumably the target is disconnecting - do not reload the SG values 11194568Sgibbs# next time. 11204568Sgibbs# 11214568Sgibbssg_advance: 11224568Sgibbs test SG_COUNT,0xff jz sg_advance2 # s/g enabled? 11234568Sgibbs 11244568Sgibbs test STCNT+0,0xff jnz sg_advance1 # SCSI transfer count nonzero? 11254568Sgibbs test STCNT+1,0xff jnz sg_advance1 11264568Sgibbs test STCNT+2,0xff jnz sg_advance1 11274568Sgibbs 11284568Sgibbs clr SG_NOLOAD # reload s/g next time 11294568Sgibbs dec SG_COUNT # one less segment to go 11304568Sgibbs 11314568Sgibbs clr A # add sizeof(struct scatter) 11324568Sgibbs add SG_NEXT+0,SG_SIZEOF,SG_NEXT+0 11334568Sgibbs adc SG_NEXT+1,A,SG_NEXT+1 11344568Sgibbs adc SG_NEXT+2,A,SG_NEXT+2 11355775Sgibbs adc SG_NEXT+3,A,SG_NEXT+3 ret 11364568Sgibbs 11374568Sgibbssg_advance1: 11384568Sgibbs mvi SG_NOLOAD,0x80 # don't reload s/g next time 11394568Sgibbssg_advance2: 11404568Sgibbs ret 11414568Sgibbs 11424568Sgibbs# Add the array base SYNCNEG to the target offset (the target address 11434568Sgibbs# is in SCSIID), and return the result in SINDEX. The accumulator 11444568Sgibbs# contains the 3->8 decoding of the target ID on return. 11454568Sgibbs# 11465562Sgibbsndx_dtr: 11474568Sgibbs shr A,SCSIID,4 11485562Sgibbs test SBLKCTL,0x08 jz ndx_dtr_2 11495326Sgibbs or A,0x08 # Channel B entries add 8 11505562Sgibbsndx_dtr_2: 11514568Sgibbs add SINDEX,SYNCNEG,A 11524568Sgibbs 11534568Sgibbs and FUNCTION1,0x70,SCSIID # 3-bit target address decode 11544568Sgibbs mov A,FUNCTION1 ret 11554568Sgibbs 11565562Sgibbs# If we need to negotiate transfer parameters, build the WDTR or SDTR message 11574568Sgibbs# starting at the address passed in SINDEX. DINDEX is modified on return. 11585562Sgibbs# The SCSI-II spec requires that Wide negotiation occur first and you can 11595562Sgibbs# only negotiat one or the other at a time otherwise in the event of a message 11605562Sgibbs# reject, you wouldn't be able to tell which message was the culpret. 11614568Sgibbs# 11625562Sgibbsmk_dtr: 11634568Sgibbs mov DINDEX,SINDEX # save SINDEX 11644568Sgibbs 11655647Sgibbs test SCBARRAY+0,NEEDWDTR jnz mk_wdtr_16bit 11665647Sgibbs jmp mk_sdtr 11674568Sgibbs 11685647Sgibbsmk_wdtr_16bit: 11695647Sgibbs mvi ARG_1,BUS_16_BIT 11705562Sgibbsmk_wdtr: 11714568Sgibbs mvi DINDIR,1 # extended message 11725562Sgibbs mvi DINDIR,2 # extended message length = 2 11735562Sgibbs mvi DINDIR,3 # WDTR code 11745562Sgibbs mov DINDIR,ARG_1 # bus width 11755562Sgibbs 11765775Sgibbs add MSG_LEN,-MSG_START+0,DINDEX ret # update message length 11775562Sgibbs 11785562Sgibbsmk_sdtr: 11795562Sgibbs mvi DINDIR,1 # extended message 11804568Sgibbs mvi DINDIR,3 # extended message length = 3 11814568Sgibbs mvi DINDIR,1 # SDTR code 11825562Sgibbs call sdtr_to_rate 11835562Sgibbs mov DINDIR,RETURN_1 # REQ/ACK transfer period 11845562Sgibbs and DINDIR,0xf,SINDIR # Sync Offset 11854568Sgibbs 11865775Sgibbs add MSG_LEN,-MSG_START+0,DINDEX ret # update message length 11874568Sgibbs 11885562Sgibbs# Tag Message if Tag enabled in SCB control block. Use SCBPTR as the tag 11895562Sgibbs# value 11905562Sgibbs 11915562Sgibbs#mk_tag: 11925562Sgibbs# test SCBARRAY+0,0x10 jz mk_tag_done # Tag Enabled? 11935562Sgibbs# and A,0x03,SCBARRYA+0 11945562Sgibbs# or A,0x20 11955562Sgibbs# mov DINDIR,A 11965562Sgibbs# mov DINDIR,SCBPTR 11975562Sgibbs# 11985562Sgibbs# add MSG_LEN,-MSG_START+0,DINDEX # update message length 11995562Sgibbs 12005562Sgibbs#mk_tag_done: 12015562Sgibbs# ret 12025562Sgibbs 12035562Sgibbs 12044568Sgibbs# Set SCSI bus control signal state. This also saves the last-written 12054568Sgibbs# value into a location where the higher-level driver can read it - if 12064568Sgibbs# it has to send an ABORT or RESET message, then it needs to know this 12074568Sgibbs# so it can assert ATN without upsetting SCSISIGO. The new value is 12084568Sgibbs# expected in SINDEX. Change the actual state last to avoid contention 12094568Sgibbs# from the driver. 12104568Sgibbs# 12114568Sgibbsscsisig: 12124568Sgibbs mov SIGSTATE,SINDEX 12134568Sgibbs mov SCSISIGO,SINDEX ret 12145562Sgibbs 12155562Sgibbssdtr_to_rate: 12165562Sgibbs call ndx_dtr # index scratch space for target 12175562Sgibbs shr A,SINDIR,0x4 12185562Sgibbs dec SINDEX #Preserve SINDEX 12195562Sgibbs and A,0x7 12205562Sgibbs clr RETURN_1 12215562Sgibbssdtr_to_rate_loop: 12225562Sgibbs test A,0x0f jz sdtr_to_rate_done 12235562Sgibbs add RETURN_1,0x18 12245562Sgibbs dec A 12255562Sgibbs jmp sdtr_to_rate_loop 12265562Sgibbssdtr_to_rate_done: 12275562Sgibbs shr RETURN_1,0x2 12285562Sgibbs add RETURN_1,0x18 ret 1229