aic7xxx.seq revision 7700
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#
244568Sgibbs
257700SgibbsVERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.12 1995/04/01 19:51:40 gibbs Exp $"
265647Sgibbs
274866SgibbsSCBMASK		= 0x1f
284568Sgibbs
294568SgibbsSCSISEQ		= 0x00
304568SgibbsSXFRCTL0	= 0x01
314568SgibbsSXFRCTL1	= 0x02
324568SgibbsSCSISIGI	= 0x03
334568SgibbsSCSISIGO	= 0x03
344568SgibbsSCSIRATE	= 0x04
354568SgibbsSCSIID		= 0x05
364568SgibbsSCSIDATL	= 0x06
374568SgibbsSTCNT		= 0x08
384568SgibbsSTCNT+0		= 0x08
394568SgibbsSTCNT+1		= 0x09
404568SgibbsSTCNT+2		= 0x0a
414568SgibbsSSTAT0		= 0x0b
424568SgibbsCLRSINT1	= 0x0c
434568SgibbsSSTAT1		= 0x0c
444568SgibbsSIMODE1		= 0x11
454568SgibbsSCSIBUSL	= 0x12
464568SgibbsSHADDR		= 0x14
474568SgibbsSELID		= 0x19
484568SgibbsSBLKCTL		= 0x1f
494568SgibbsSEQCTL		= 0x60
504568SgibbsA		= 0x64				# == ACCUM
514568SgibbsSINDEX		= 0x65
524568SgibbsDINDEX		= 0x66
534568SgibbsALLZEROS	= 0x6a
544568SgibbsNONE		= 0x6a
554568SgibbsSINDIR		= 0x6c
564568SgibbsDINDIR		= 0x6d
574568SgibbsFUNCTION1	= 0x6e
584568SgibbsHADDR		= 0x88
597532SgibbsHADDR+1		= 0x89
607532SgibbsHADDR+2		= 0x8a
617532SgibbsHADDR+3		= 0x8b
624568SgibbsHCNT		= 0x8c
634568SgibbsHCNT+0		= 0x8c
644568SgibbsHCNT+1		= 0x8d
654568SgibbsHCNT+2		= 0x8e
664568SgibbsSCBPTR		= 0x90
674568SgibbsINTSTAT		= 0x91
684568SgibbsDFCNTRL		= 0x93
694568SgibbsDFSTATUS	= 0x94
704568SgibbsDFDAT		= 0x99
714568SgibbsQINFIFO		= 0x9b
724568SgibbsQINCNT		= 0x9c
734568SgibbsQOUTFIFO	= 0x9d
744568Sgibbs
755326SgibbsSCSICONF_A	= 0x5a
765326SgibbsSCSICONF_B	= 0x5b
774568Sgibbs
784568Sgibbs#  The two reserved bytes at SCBARRAY+1[23] are expected to be set to
794568Sgibbs#  zero, and the reserved bit in SCBARRAY+0 is used as an internal flag
804568Sgibbs#  to indicate whether or not to reload scatter-gather parameters after
815647Sgibbs#  a disconnect.  We also use bits 6 & 7 to indicate whether or not to
825647Sgibbs#  initiate SDTR or WDTR repectively when starting this command.
834568Sgibbs#
844568SgibbsSCBARRAY+0	= 0xa0
855647Sgibbs
865647SgibbsDISCONNECTED	= 0x04
875647SgibbsNEEDDMA		= 0x08
885647SgibbsSG_LOAD		= 0x10
896608SgibbsTAG_ENB		= 0x20
905647SgibbsNEEDSDTR	= 0x40
915647SgibbsNEEDWDTR	= 0x80
925647Sgibbs
934568SgibbsSCBARRAY+1	= 0xa1
944568SgibbsSCBARRAY+2	= 0xa2
954568SgibbsSCBARRAY+3	= 0xa3
965647SgibbsSCBARRAY+4	= 0xa4
975647SgibbsSCBARRAY+5	= 0xa5
985647SgibbsSCBARRAY+6	= 0xa6
994568SgibbsSCBARRAY+7	= 0xa7
1005647SgibbsSCBARRAY+8	= 0xa8
1015647SgibbsSCBARRAY+9	= 0xa9
1025647SgibbsSCBARRAY+10	= 0xaa
1034568SgibbsSCBARRAY+11	= 0xab
1045647SgibbsSCBARRAY+12	= 0xac
1055647SgibbsSCBARRAY+13	= 0xad
1064568SgibbsSCBARRAY+14	= 0xae
1074568SgibbsSCBARRAY+15	= 0xaf
1084568SgibbsSCBARRAY+16	= 0xb0
1094568SgibbsSCBARRAY+17	= 0xb1
1104568SgibbsSCBARRAY+18	= 0xb2
1114568SgibbsSCBARRAY+19	= 0xb3
1124568SgibbsSCBARRAY+20	= 0xb4
1134568SgibbsSCBARRAY+21	= 0xb5
1144568SgibbsSCBARRAY+22	= 0xb6
1154568SgibbsSCBARRAY+23	= 0xb7
1164568SgibbsSCBARRAY+24	= 0xb8
1174568SgibbsSCBARRAY+25	= 0xb9
1185647SgibbsSCBARRAY+26	= 0xba
1197532SgibbsSCBARRAY+27	= 0xbb
1207532SgibbsSCBARRAY+28	= 0xbc
1217532SgibbsSCBARRAY+29	= 0xbd
1224568Sgibbs
1235647SgibbsBAD_PHASE	= 0x01				# unknown scsi bus phase
1247532SgibbsCMDCMPLT	= 0x02
1255647SgibbsSEND_REJECT	= 0x11				# sending a message reject
1265647SgibbsNO_IDENT	= 0x21				# no IDENTIFY after reconnect
1275647SgibbsNO_MATCH	= 0x31				# no cmd match for reconnect
1285647SgibbsMSG_SDTR	= 0x41				# SDTR message recieved
1295647SgibbsMSG_WDTR	= 0x51				# WDTR message recieved
1305647SgibbsMSG_REJECT	= 0x61				# Reject message recieved
1315647SgibbsBAD_STATUS	= 0x71				# Bad status from target
1327532SgibbsRESIDUAL	= 0x81				# Residual byte count != 0
1337562SgibbsABORT_TAG	= 0x91				# Sent an ABORT_TAG message
1344568Sgibbs
1354568Sgibbs#  The host adapter card (at least the BIOS) uses 20-2f for SCSI
1365326Sgibbs#  device information, 32-33 and 5a-5f as well. As it turns out, the
1375326Sgibbs#  BIOS trashes 20-2f, writing the synchronous negotiation results
1384568Sgibbs#  on top of the BIOS values, so we re-use those for our per-target
1394568Sgibbs#  scratchspace (actually a value that can be copied directly into
1405326Sgibbs#  SCSIRATE).  The kernel driver will enable synchronous negotiation
1415326Sgibbs#  for all targets that have a value other than 0 in the lower four
1425326Sgibbs#  bits of the target scratch space.  This should work irregardless of
1435647Sgibbs#  whether the bios has been installed. NEEDWDTR and NEEDSDTR are the top
1445647Sgibbs#  two bits of the SCB control byte.  The kernel driver will set these
1455647Sgibbs#  when a WDTR or SDTR message should be sent to the target the SCB's 
1465647Sgibbs#  command references.
1474568Sgibbs#
1484568Sgibbs#  The high bit of DROPATN is set if ATN should be dropped before the ACK
1494568Sgibbs#  when outb is called.  REJBYTE contains the first byte of a MESSAGE IN
1504568Sgibbs#  message, so the driver can report an intelligible error if a message is
1514568Sgibbs#  rejected.
1524568Sgibbs#
1535562Sgibbs#  FLAGS's high bit is true if we are currently handling a reselect;
1544568Sgibbs#  its next-highest bit is true ONLY IF we've seen an IDENTIFY message
1554568Sgibbs#  from the reselecting target.  If we haven't had IDENTIFY, then we have
1564568Sgibbs#  no idea what the lun is, and we can't select the right SCB register
1574568Sgibbs#  bank, so force a kernel panic if the target attempts a data in/out or
1584568Sgibbs#  command phase instead of corrupting something.
1594568Sgibbs#
1604568Sgibbs#  Note that SG_NEXT occupies four bytes.
1614568Sgibbs#
1624568SgibbsSYNCNEG		= 0x20
1634568Sgibbs
1644568SgibbsDROPATN		= 0x30
1654568SgibbsREJBYTE		= 0x31
1665326SgibbsDISC_DSB_A	= 0x32
1675326SgibbsDISC_DSB_B	= 0x33
1684568Sgibbs
1696608SgibbsMSG_LEN		= 0x34
1706608SgibbsMSG_START+0	= 0x35
1716608SgibbsMSG_START+1	= 0x36
1726608SgibbsMSG_START+2	= 0x37
1736608SgibbsMSG_START+3	= 0x38
1746608SgibbsMSG_START+4	= 0x39
1756608SgibbsMSG_START+5	= 0x3a
1767562Sgibbs-MSG_START+0	= 0xcb				# 2's complement of MSG_START+0
1774568Sgibbs
1786608SgibbsARG_1		= 0x4a				# sdtr conversion args & return
1795647SgibbsBUS_16_BIT	= 0x01
1806608SgibbsRETURN_1	= 0x4a
1814568Sgibbs
1826608SgibbsSIGSTATE	= 0x4b				# value written to SCSISIGO
1834568Sgibbs
1845647Sgibbs# Linux users should use 0xc (12) for SG_SIZEOF
1855647SgibbsSG_SIZEOF	= 0x8 				# sizeof(struct ahc_dma)
1865647Sgibbs#SG_SIZEOF	= 0xc 				# sizeof(struct scatterlist)
1875647SgibbsSCB_SIZEOF	= 0x13				# sizeof SCB to DMA (19 bytes)
1885647Sgibbs
1896608SgibbsSG_NOLOAD	= 0x4c				# load SG pointer/length?
1906608SgibbsSG_COUNT	= 0x4d				# working value of SG count
1916608SgibbsSG_NEXT		= 0x4e				# working value of SG pointer
1926608SgibbsSG_NEXT+0	= 0x4e
1936608SgibbsSG_NEXT+1	= 0x4f
1946608SgibbsSG_NEXT+2	= 0x50
1956608SgibbsSG_NEXT+3	= 0x51
1964568Sgibbs
1976608SgibbsSCBCOUNT	= 0x52				# the actual number of SCBs
1986608SgibbsFLAGS		= 0x53				# Device configuration flags
1995326SgibbsTWIN_BUS	= 0x01
2005326SgibbsWIDE_BUS	= 0x02
2017532SgibbsMAX_SYNC	= 0x08
2025562SgibbsSENSE		= 0x10
2035562SgibbsACTIVE_MSG	= 0x20
2045562SgibbsIDENTIFY_SEEN	= 0x40
2055562SgibbsRESELECTED	= 0x80
2064568Sgibbs
2076608SgibbsACTIVE_A	= 0x54
2086608SgibbsACTIVE_B	= 0x55
2096608SgibbsSAVED_TCL	= 0x56
2104866Sgibbs#  Poll QINCNT for work - the lower bits contain
2114568Sgibbs#  the number of entries in the Queue In FIFO.
2124568Sgibbs#
2134568Sgibbsstart:
2145562Sgibbs	test	FLAGS,SENSE	jnz start_sense
2155775Sgibbsstart_nosense:
2165326Sgibbs	test	FLAGS,TWIN_BUS	jz start2	# Are we a twin channel device?
2175326Sgibbs# For fairness, we check the other bus first, since we just finished a 
2185326Sgibbs# transaction on the current channel.
2195326Sgibbs	xor	SBLKCTL,0x08			# Toggle to the other bus
2204568Sgibbs	test	SCSISIGI,0x4	jnz reselect	# BSYI
2215326Sgibbs	xor	SBLKCTL,0x08			# Toggle to the original bus
2225326Sgibbsstart2:
2235326Sgibbs	test	SCSISIGI,0x4	jnz reselect	# BSYI
2245775Sgibbs	test	QINCNT,SCBMASK	jz start_nosense
2254568Sgibbs
2265647Sgibbs# We have at least one queued SCB now.  Set the SCB pointer
2275647Sgibbs# from the FIFO so we see the right bank of SCB registers,
2285647Sgibbs# then set SCSI options and set the initiator and target
2295647Sgibbs# SCSI IDs.
2304568Sgibbs#
2314568Sgibbs	mov	SCBPTR,QINFIFO
2324568Sgibbs
2335647Sgibbs# If the control byte of this SCB has the NEEDDMA flag set, we have
2345647Sgibbs# yet to DMA it from host memory
2355647Sgibbs
2365647Sgibbstest	SCBARRAY+0,NEEDDMA	jz test_busy
2375647Sgibbs	clr	HCNT+2
2385647Sgibbs	clr	HCNT+1
2395647Sgibbs	mvi	HCNT+0,SCB_SIZEOF
2405647Sgibbs
2415647Sgibbs	mvi	DINDEX,HADDR
2425775Sgibbs	mvi	SCBARRAY+26	call bcopy_4
2435647Sgibbs
2445647Sgibbs	mvi	DFCNTRL,0xd			# HDMAEN|DIRECTION|FIFORESET
2455647Sgibbs
2465647Sgibbs#  Wait for DMA from host memory to data FIFO to complete, then disable
2475647Sgibbs#  DMA and wait for it to acknowledge that it's off.
2485647Sgibbs#
2497532Sgibbs	call	dma_finish
2505647Sgibbs
2515647Sgibbs# Copy the SCB from the FIFO to  the SCBARRAY
2525647Sgibbs
2537532Sgibbs	mvi	DINDEX, SCBARRAY+0
2547532Sgibbs	call	bcopy_3_dfdat
2557532Sgibbs	call	bcopy_4_dfdat
2567532Sgibbs	call	bcopy_4_dfdat
2577532Sgibbs	call	bcopy_4_dfdat
2587532Sgibbs	call	bcopy_4_dfdat
2595647Sgibbs   
2604568Sgibbs# See if there is not already an active SCB for this target.  This code
2615326Sgibbs# locks out on a per target basis instead of target/lun.  Although this
2625326Sgibbs# is not ideal for devices that have multiple luns active at the same
2635326Sgibbs# time, it is faster than looping through all SCB's looking for active
2645326Sgibbs# commands.  It may be benificial to make findscb a more general procedure
2655326Sgibbs# to see if the added cost of the search is negligible.  This code also 
2665326Sgibbs# assumes that the kernel driver will clear the active flags on board 
2675326Sgibbs# initialization, board reset, and a target's SELTO.
2684568Sgibbs
2695647Sgibbstest_busy:
2706608Sgibbs	test	SCBARRAY+0,0x20	jnz start_scb
2714568Sgibbs	and	FUNCTION1,0x70,SCBARRAY+1
2724568Sgibbs	mov	A,FUNCTION1
2735326Sgibbs	test	SCBARRAY+1,0x88	jz test_a	# Id < 8 && A channel
2745326Sgibbs
2755326Sgibbs	test	ACTIVE_B,A	jnz requeue
2765326Sgibbs	or	ACTIVE_B,A	# Mark the current target as busy
2775326Sgibbs	jmp	start_scb
2785326Sgibbs
2795562Sgibbsstart_sense:
2805562Sgibbs# Clear the SENSE flag first, then do a normal start_scb
2815562Sgibbs	and	FLAGS,0xef
2825562Sgibbs	jmp	start_scb
2835562Sgibbs
2844568Sgibbs# Place the currently active back on the queue for later processing
2855326Sgibbsrequeue:
2864568Sgibbs	mov	QINFIFO, SCBPTR
2875775Sgibbs	jmp	start_nosense
2884568Sgibbs
2895326Sgibbstest_a:
2905326Sgibbs	test	ACTIVE_A,A	jnz requeue
2915326Sgibbs	or	ACTIVE_A,A	# Mark the current target as busy
2925326Sgibbs
2935326Sgibbsstart_scb:
2945647Sgibbs	or	SCBARRAY+0,NEEDDMA
2956940Sgibbs	and	SINDEX,0xf7,SBLKCTL  #Clear the channel select bit
2966940Sgibbs	and	A,0x08,SCBARRAY+1    #Get new channel bit
2976940Sgibbs	or	SINDEX,A	     
2986940Sgibbs	mov	SBLKCTL,SINDEX	# select channel
2994568Sgibbs	mov	SCBARRAY+1	call initialize
3004568Sgibbs	clr	SG_NOLOAD
3015562Sgibbs	and	FLAGS,0x3f	# !RESELECTING
3024568Sgibbs
3034568Sgibbs#  As soon as we get a successful selection, the target should go
3044568Sgibbs#  into the message out phase since we have ATN asserted.  Prepare
3054568Sgibbs#  the message to send, locking out the device driver.  If the device
3064568Sgibbs#  driver hasn't beaten us with an ABORT or RESET message, then tack
3074866Sgibbs#  on an SDTR negotiation if required.
3084568Sgibbs#
3094568Sgibbs#  Messages are stored in scratch RAM starting with a flag byte (high bit
3104568Sgibbs#  set means active message), one length byte, and then the message itself.
3114568Sgibbs#
3124568Sgibbs	mov	SCBARRAY+1	call disconnect	# disconnect ok?
3134568Sgibbs
3144568Sgibbs	and	SINDEX,0x7,SCBARRAY+1		# lun
3154568Sgibbs	or	SINDEX,A			# return value from disconnect
3164568Sgibbs	or	SINDEX,0x80	call mk_mesg	# IDENTIFY message
3174568Sgibbs
3184568Sgibbs	mov	A,SINDEX
3196608Sgibbs	test	SCBARRAY+0,0xe0	jz  !message	# WDTR, SDTR or TAG??
3204568Sgibbs	cmp	MSG_START+0,A	jne !message	# did driver beat us?
3214568Sgibbs
3226608Sgibbs# Tag Message if Tag enabled in SCB control block.  Use SCBPTR as the tag
3236608Sgibbs# value
3246608Sgibbs
3256608Sgibbsmk_tag:
3266608Sgibbs	mvi	DINDEX, MSG_START+1
3276608Sgibbs	test	SCBARRAY+0,TAG_ENB jz mk_tag_done
3286608Sgibbs	and	A,0x23,SCBARRAY+0
3296608Sgibbs	mov	DINDIR,A
3306608Sgibbs	mov	DINDIR,SCBPTR
3316608Sgibbs
3326608Sgibbs	add	MSG_LEN,-MSG_START+0,DINDEX	# update message length
3336608Sgibbs
3346608Sgibbsmk_tag_done:
3356608Sgibbs
3366608Sgibbs	mov	DINDEX	call mk_dtr	# build DTR message if needed
3376608Sgibbs
3384568Sgibbs!message:
3394568Sgibbs
3404568Sgibbs#  Enable selection phase as an initiator, and do automatic ATN
3414568Sgibbs#  after the selection.
3424568Sgibbs#
3434568Sgibbs	mvi	SCSISEQ,0x48			# ENSELO|ENAUTOATNO
3444568Sgibbs
3454568Sgibbs#  Wait for successful arbitration.  The AIC-7770 documentation says
3464568Sgibbs#  that SELINGO indicates successful arbitration, and that it should
3474568Sgibbs#  be used to look for SELDO.  However, if the sequencer is paused at
3484568Sgibbs#  just the right time - a parallel fsck(8) on two drives did it for
3494568Sgibbs#  me - then SELINGO can flip back to false before we've seen it.  This
3504568Sgibbs#  makes the sequencer sit in the arbitration loop forever.  This is
3514568Sgibbs#  Not Good.
3524568Sgibbs#
3534568Sgibbs#  Therefore, I've added a check in the arbitration loop for SELDO
3544568Sgibbs#  too.  This could arguably be made a critical section by disabling
3554568Sgibbs#  pauses, but I don't want to make a potentially infinite loop a CS.
3564568Sgibbs#  I suppose you could fold it into the select loop, too, but since
3574568Sgibbs#  I've been hunting this bug for four days it's kinda like a trophy.
3584568Sgibbs#
3594568Sgibbsarbitrate:
3604568Sgibbs	test	SSTAT0,0x40	jnz *select	# SELDO
3614568Sgibbs	test	SSTAT0,0x10	jz arbitrate	# SELINGO
3624568Sgibbs
3634568Sgibbs#  Wait for a successful selection.  If the hardware selection
3644568Sgibbs#  timer goes off, then the driver gets the interrupt, so we don't
3654568Sgibbs#  need to worry about it.
3664568Sgibbs#
3674568Sgibbsselect:
3684568Sgibbs	test	SSTAT0,0x40	jz select	# SELDO
3694568Sgibbs	jmp	*select
3704568Sgibbs
3714568Sgibbs#  Reselection is being initiated by a target - we've seen the BSY
3724568Sgibbs#  line driven active, and we didn't do it!  Enable the reselection
3734568Sgibbs#  hardware, and wait for it to finish.  Make a note that we've been
3744568Sgibbs#  reselected, but haven't seen an IDENTIFY message from the target
3754568Sgibbs#  yet.
3764568Sgibbs#
3774568Sgibbsreselect:
3784568Sgibbs	mvi	SCSISEQ,0x10			# ENRSELI
3794568Sgibbs
3804568Sgibbsreselect1:
3814568Sgibbs	test	SSTAT0,0x20	jz reselect1	# SELDI
3824568Sgibbs	mov	SELID		call initialize
3834568Sgibbs
3845562Sgibbs	and	FLAGS,0x3f			# reselected, no IDENTIFY	
3855562Sgibbs	or	FLAGS,RESELECTED		
3864568Sgibbs
3874568Sgibbs#  After the [re]selection, make sure that the [re]selection enable
3884568Sgibbs#  bit is off.  This chip is flaky enough without extra things
3894568Sgibbs#  turned on.  Also clear the BUSFREE bit in SSTAT1 since we'll be
3904568Sgibbs#  using it shortly.
3914568Sgibbs#
3924568Sgibbs*select:
3934568Sgibbs	clr	SCSISEQ
3944568Sgibbs	mvi	CLRSINT1,0x8			# CLRBUSFREE
3954568Sgibbs
3964568Sgibbs#  Main loop for information transfer phases.  If BSY is false, then
3974568Sgibbs#  we have a bus free condition, expected or not.  Otherwise, wait
3984568Sgibbs#  for the target to assert REQ before checking MSG, C/D and I/O
3994568Sgibbs#  for the bus phase.
4004568Sgibbs#
4014568Sgibbs#  We can't simply look at the values of SCSISIGI here (if we want
4024568Sgibbs#  to do synchronous data transfer), because the target won't assert
4034568Sgibbs#  REQ if it's already sent us some data that we haven't acknowledged
4044568Sgibbs#  yet.
4054568Sgibbs#
4064568SgibbsITloop:
4074568Sgibbs	test	SSTAT1,0x8	jnz p_busfree	# BUSFREE
4084568Sgibbs	test	SSTAT1,0x1	jz ITloop	# REQINIT
4094568Sgibbs
4104568Sgibbs	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
4114568Sgibbs
4124568Sgibbs	cmp	ALLZEROS,A	je p_dataout
4134568Sgibbs	cmp	A,0x40		je p_datain
4144568Sgibbs	cmp	A,0x80		je p_command
4154568Sgibbs	cmp	A,0xc0		je p_status
4164568Sgibbs	cmp	A,0xa0		je p_mesgout
4174568Sgibbs	cmp	A,0xe0		je p_mesgin
4184568Sgibbs
4195647Sgibbs	mvi	INTSTAT,BAD_PHASE		# unknown - signal driver
4204568Sgibbs
4214568Sgibbsp_dataout:
4224568Sgibbs	mvi	0		call scsisig	# !CDO|!IOO|!MSGO
4234568Sgibbs	call	assert
4244568Sgibbs	call	sg_load
4254568Sgibbs
4265775Sgibbs	mvi	DINDEX,HADDR
4275775Sgibbs	mvi	SCBARRAY+19	call bcopy_4
4284568Sgibbs
4295775Sgibbs#	mvi	DINDEX,HCNT	# implicit since HCNT is next to HADDR
4305775Sgibbs	mvi	SCBARRAY+23	call bcopy_3
4315775Sgibbs
4324568Sgibbs	mvi	DINDEX,STCNT
4335775Sgibbs	mvi	SCBARRAY+23	call bcopy_3
4344568Sgibbs
4357532Sgibbs# If we are the last SG block, don't set wideodd.
4367532Sgibbs	test    SCBARRAY+18,0xff jnz p_dataout_wideodd
4374568Sgibbs	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
4384568Sgibbs						#   DIRECTION|FIFORESET
4397532Sgibbs	jmp	p_dataout_rest
4404568Sgibbs
4417532Sgibbsp_dataout_wideodd:
4427532Sgibbs	mvi	0xbd		call dma	# WIDEODD|SCSIEN|SDMAEN|HDMAEN|
4437532Sgibbs						#   DIRECTION|FIFORESET
4447532Sgibbs
4457532Sgibbsp_dataout_rest:
4464568Sgibbs#  After a DMA finishes, save the final transfer pointer and count
4474568Sgibbs#  back into the SCB, in case a device disconnects in the middle of
4484568Sgibbs#  a transfer.  Use SHADDR and STCNT instead of HADDR and HCNT, since
4494568Sgibbs#  it's a reflection of how many bytes were transferred on the SCSI
4504568Sgibbs#  (as opposed to the host) bus.
4514568Sgibbs#
4524568Sgibbs	mvi	DINDEX,SCBARRAY+23
4535775Sgibbs	mvi	STCNT		call bcopy_3
4544568Sgibbs
4554568Sgibbs	mvi	DINDEX,SCBARRAY+19
4565775Sgibbs	mvi	SHADDR		call bcopy_4
4574568Sgibbs
4584568Sgibbs	call	sg_advance
4594568Sgibbs	mov	SCBARRAY+18,SG_COUNT		# residual S/G count
4604568Sgibbs
4614568Sgibbs	jmp	ITloop
4624568Sgibbs
4634568Sgibbsp_datain:
4644568Sgibbs	mvi	0x40		call scsisig	# !CDO|IOO|!MSGO
4654568Sgibbs	call	assert
4664568Sgibbs	call	sg_load
4674568Sgibbs
4685775Sgibbs	mvi	DINDEX,HADDR
4695775Sgibbs	mvi	SCBARRAY+19	call bcopy_4
4704568Sgibbs
4715775Sgibbs#	mvi	DINDEX,HCNT	# implicit since HCNT is next to HADDR
4725775Sgibbs	mvi	SCBARRAY+23	call bcopy_3
4735775Sgibbs
4744568Sgibbs	mvi	DINDEX,STCNT
4755775Sgibbs	mvi	SCBARRAY+23	call bcopy_3
4764568Sgibbs
4777532Sgibbs# If we are the last SG block, don't set wideodd.
4787532Sgibbs	test	SCBARRAY+18,0xff jnz p_datain_wideodd
4794568Sgibbs	mvi	0x39		call dma	# SCSIEN|SDMAEN|HDMAEN|
4804568Sgibbs						#   !DIRECTION|FIFORESET
4817532Sgibbs	jmp	p_datain_rest
4827532Sgibbsp_datain_wideodd:
4837532Sgibbs	mvi	0xb9		call dma	# WIDEODD|SCSIEN|SDMAEN|HDMAEN|
4847532Sgibbs						#   !DIRECTION|FIFORESET
4857532Sgibbsp_datain_rest:
4864568Sgibbs	mvi	DINDEX,SCBARRAY+23
4875775Sgibbs	mvi	STCNT		call bcopy_3
4884568Sgibbs
4894568Sgibbs	mvi	DINDEX,SCBARRAY+19
4905775Sgibbs	mvi	SHADDR		call bcopy_4
4914568Sgibbs
4924568Sgibbs	call	sg_advance
4934568Sgibbs	mov	SCBARRAY+18,SG_COUNT		# residual S/G count
4944568Sgibbs
4954568Sgibbs	jmp	ITloop
4964568Sgibbs
4974568Sgibbs#  Command phase.  Set up the DMA registers and let 'er rip - the
4984568Sgibbs#  two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
4994568Sgibbs#  so we can copy those three bytes directly into HCNT.
5004568Sgibbs#
5014568Sgibbsp_command:
5024568Sgibbs	mvi	0x80		call scsisig	# CDO|!IOO|!MSGO
5034568Sgibbs	call	assert
5044568Sgibbs
5055775Sgibbs	mvi	DINDEX,HADDR
5065775Sgibbs	mvi	SCBARRAY+7	call bcopy_4
5074568Sgibbs
5085775Sgibbs#	mvi	DINDEX,HCNT	# implicit since HCNT is next to HADDR
5095775Sgibbs	mvi	SCBARRAY+11	call bcopy_3
5105775Sgibbs
5114568Sgibbs	mvi	DINDEX,STCNT
5125775Sgibbs	mvi	SCBARRAY+11	call bcopy_3
5134568Sgibbs
5144568Sgibbs	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
5154568Sgibbs						#   DIRECTION|FIFORESET
5164568Sgibbs	jmp	ITloop
5174568Sgibbs
5184568Sgibbs#  Status phase.  Wait for the data byte to appear, then read it
5194568Sgibbs#  and store it into the SCB.
5204568Sgibbs#
5214568Sgibbsp_status:
5224568Sgibbs	mvi	0xc0		call scsisig	# CDO|IOO|!MSGO
5234568Sgibbs
5247700Sgibbs	mvi	SCBARRAY+14	call inb_first
5257700Sgibbs	jmp	p_mesgin_done
5264568Sgibbs
5274568Sgibbs#  Message out phase.  If there is no active message, but the target
5284568Sgibbs#  took us into this phase anyway, build a no-op message and send it.
5294568Sgibbs#
5304568Sgibbsp_mesgout:
5314568Sgibbs	mvi	0xa0		call scsisig	# CDO|!IOO|MSGO
5324568Sgibbs	mvi	0x8		call mk_mesg	# build NOP message
5334568Sgibbs
5347700Sgibbs	clr     STCNT+2
5357700Sgibbs	clr     STCNT+1
5367700Sgibbs
5374568Sgibbs#  Set up automatic PIO transfer from MSG_START.  Bit 3 in
5384568Sgibbs#  SXFRCTL0 (SPIOEN) is already on.
5394568Sgibbs#
5404568Sgibbs	mvi	SINDEX,MSG_START+0
5414568Sgibbs	mov	DINDEX,MSG_LEN
5424568Sgibbs
5434568Sgibbs#  When target asks for a byte, drop ATN if it's the last one in
5444568Sgibbs#  the message.  Otherwise, keep going until the message is exhausted.
5454568Sgibbs#  (We can't use outb for this since it wants the input in SINDEX.)
5464568Sgibbs#
5474568Sgibbs#  Keep an eye out for a phase change, in case the target issues
5484568Sgibbs#  a MESSAGE REJECT.
5494568Sgibbs#
5504568Sgibbsp_mesgout2:
5514568Sgibbs	test	SSTAT0,0x2	jz p_mesgout2	# SPIORDY
5524568Sgibbs	test	SSTAT1,0x10	jnz p_mesgout6	# PHASEMIS
5534568Sgibbs
5544568Sgibbs	cmp	DINDEX,1	jne p_mesgout3	# last byte?
5554568Sgibbs	mvi	CLRSINT1,0x40			# CLRATNO - drop ATN
5564568Sgibbs
5574568Sgibbs#  Write a byte to the SCSI bus.  The AIC-7770 refuses to automatically
5584568Sgibbs#  send ACKs in automatic PIO or DMA mode unless you make sure that the
5594568Sgibbs#  "expected" bus phase in SCSISIGO matches the actual bus phase.  This
5604568Sgibbs#  behaviour is completely undocumented and caused me several days of
5614568Sgibbs#  grief.
5624568Sgibbs#
5634568Sgibbs#  After plugging in different drives to test with and using a longer
5644568Sgibbs#  SCSI cable, I found that I/O in Automatic PIO mode ceased to function,
5654568Sgibbs#  especially when transferring >1 byte.  It seems to be much more stable
5664568Sgibbs#  if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is
5674568Sgibbs#  polled for transfer completion - for both output _and_ input.  The
5684568Sgibbs#  only theory I have is that SPIORDY doesn't drop right away when SCSIDATL
5694568Sgibbs#  is accessed (like the documentation says it does), and that on a longer
5704568Sgibbs#  cable run, the sequencer code was fast enough to loop back and see
5714568Sgibbs#  an SPIORDY that hadn't dropped yet.
5724568Sgibbs#
5734568Sgibbsp_mesgout3:
5747700Sgibbs	mvi	STCNT+0, 0x01	
5754568Sgibbs	mov	SCSIDATL,SINDIR
5764568Sgibbs
5774568Sgibbsp_mesgout4:
5784568Sgibbs	test	SSTAT0,0x4	jz p_mesgout4	# SDONE
5794568Sgibbs	dec	DINDEX
5807700Sgibbs	test	DINDEX,0xff	jnz p_mesgout2
5814568Sgibbs
5824568Sgibbs#  If the next bus phase after ATN drops is a message out, it means
5834568Sgibbs#  that the target is requesting that the last message(s) be resent.
5844568Sgibbs#
5854568Sgibbsp_mesgout5:
5864568Sgibbs	test	SSTAT1,0x8	jnz p_mesgout6	# BUSFREE
5874568Sgibbs	test	SSTAT1,0x1	jz p_mesgout5	# REQINIT
5884568Sgibbs
5894568Sgibbs	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
5904568Sgibbs	cmp	A,0xa0		jne p_mesgout6
5914568Sgibbs	mvi	0x10		call scsisig	# ATNO - re-assert ATN
5924568Sgibbs
5934568Sgibbs	jmp	ITloop
5944568Sgibbs
5954568Sgibbsp_mesgout6:
5964568Sgibbs	mvi	CLRSINT1,0x40			# CLRATNO - in case of PHASEMIS
5975562Sgibbs	and	FLAGS,0xdf			# no active msg
5984568Sgibbs	jmp	ITloop
5994568Sgibbs
6004568Sgibbs#  Message in phase.  Bytes are read using Automatic PIO mode, but not
6014568Sgibbs#  using inb.  This alleviates a race condition, namely that if ATN had
6024568Sgibbs#  to be asserted under Automatic PIO mode, it had to beat the SCSI
6034568Sgibbs#  circuitry sending an ACK to the target.  This showed up under heavy
6044568Sgibbs#  loads and really confused things, since ABORT commands wouldn't be
6054568Sgibbs#  seen by the drive after an IDENTIFY message in until it had changed
6064568Sgibbs#  to a data I/O phase.
6074568Sgibbs#
6084568Sgibbsp_mesgin:
6094568Sgibbs	mvi	0xe0		call scsisig	# CDO|IOO|MSGO
6104568Sgibbs	mvi	A		call inb_first	# read the 1st message byte
6114568Sgibbs	mvi	REJBYTE,A			# save it for the driver
6124568Sgibbs
6134568Sgibbs	cmp	ALLZEROS,A	jne p_mesgin1
6144568Sgibbs
6154568Sgibbs#  We got a "command complete" message, so put the SCB pointer
6164568Sgibbs#  into the Queue Out, and trigger a completion interrupt.
6174568Sgibbs#  Check status for non zero return and interrupt driver if needed
6185326Sgibbs#  This allows the driver to interpret errors only when they occur
6195326Sgibbs#  instead of always uploading the scb.  If the status is SCSI_CHECK,
6205326Sgibbs#  the driver will download a new scb requesting sense, to replace 
6217532Sgibbs#  the old one and set the SENSE sequencer flag.  If the sense flag is
6227532Sgibbs#  set, the sequencer imediately jumps to start working on the sense
6237532Sgibbs#  command.  If the kernel driver does not wish to request sense, it need
6247532Sgibbs#  do nothing, and the command is allowed to complete.  We don't 
6255326Sgibbs#  bother to post to the QOUTFIFO in the error case since it would require 
6265326Sgibbs#  extra work in the kernel driver to ensure that the entry was removed 
6275326Sgibbs#  before the command complete code tried processing it.
6284568Sgibbs
6297700Sgibbs# First check for residuals
6307532Sgibbs	test	SCBARRAY+15,0xff	jnz resid
6317532Sgibbs	test	SCBARRAY+16,0xff	jnz resid
6327532Sgibbs	test	SCBARRAY+17,0xff	jnz resid
6337532Sgibbs
6347532Sgibbscheck_status:
6355647Sgibbs	test	SCBARRAY+14,0xff	jz status_ok	# 0 Status?
6365647Sgibbs	mvi	INTSTAT,BAD_STATUS			# let driver know
6375562Sgibbs	test	FLAGS,SENSE	jz status_ok
6385562Sgibbs	jmp	p_mesgin_done
6395326Sgibbs
6404568Sgibbsstatus_ok:
6415326Sgibbs#  First, mark this target as free.
6426608Sgibbs	test	SCBARRAY+0,0x20	jnz complete		# Tagged command
6435326Sgibbs	and	FUNCTION1,0x70,SCBARRAY+1
6445326Sgibbs	mov	A,FUNCTION1
6455326Sgibbs	test	SCBARRAY+1,0x88 jz clear_a
6465326Sgibbs	xor	ACTIVE_B,A
6475326Sgibbs	jmp	complete
6485326Sgibbs
6495326Sgibbsclear_a:
6505326Sgibbs	xor	ACTIVE_A,A
6515326Sgibbs
6525326Sgibbscomplete:
6534568Sgibbs	mov	QOUTFIFO,SCBPTR
6547532Sgibbs	mvi	INTSTAT,CMDCMPLT
6554568Sgibbs	jmp	p_mesgin_done
6564568Sgibbs
6577532Sgibbs# If we have a residual count, interrupt and tell the host.  Other
6587532Sgibbs# alternatives are to pause the sequencer on all command completes (yuck),
6597532Sgibbs# dma the resid directly to the host (slick, but a ton of instructions), or
6607532Sgibbs# have the sequencer pause itself when it encounters a non-zero resid 
6617532Sgibbs# (unecessary pause just to flag the command -- yuck, but takes few instructions
6627700Sgibbs# and since it shouldn't happen that often is good enough for our purposes).  
6637532Sgibbs
6647532Sgibbsresid:
6657532Sgibbs	mvi	INTSTAT,RESIDUAL
6667532Sgibbs	jmp	check_status
6677532Sgibbs
6685562Sgibbs#  Is it an extended message?  We only support the synchronous and wide data
6695562Sgibbs#  transfer request messages, which will probably be in response to
6705562Sgibbs#  WDTR or SDTR message outs from us.  If it's not SDTR or WDTR, reject it -
6714568Sgibbs#  apparently this can be done after any message in byte, according
6724568Sgibbs#  to the SCSI-2 spec.
6734568Sgibbs#
6744568Sgibbsp_mesgin1:
6754568Sgibbs	cmp	A,1		jne p_mesgin2	# extended message code?
6764568Sgibbs	
6775562Sgibbs	mvi	ARG_1		call inb_next	# extended message length
6785562Sgibbs	mvi	A		call inb_next	# extended message code
6794568Sgibbs
6805562Sgibbs	cmp	A,1		je p_mesginSDTR	# Syncronous negotiation message
6815562Sgibbs	cmp	A,3		je p_mesginWDTR # Wide negotiation message
6825562Sgibbs	jmp	p_mesginN
6835562Sgibbs
6845562Sgibbsp_mesginWDTR:
6855562Sgibbs	cmp	ARG_1,2		jne p_mesginN	# extended mesg length = 2
6865562Sgibbs	mvi	A		call inb_next	# Width of bus
6875647Sgibbs	mvi	INTSTAT,MSG_WDTR		# let driver know
6885562Sgibbs	test	RETURN_1,0x80	jz p_mesgin_done# Do we need to send WDTR?
6895562Sgibbs
6905562Sgibbs# We didn't initiate the wide negotiation, so we must respond to the request
6915562Sgibbs	and	RETURN_1,0x7f			# Clear the SEND_WDTR Flag
6925562Sgibbs	or	FLAGS,ACTIVE_MSG
6935647Sgibbs	mvi	DINDEX,MSG_START+0
6945562Sgibbs	mvi	MSG_START+0	call mk_wdtr	# build WDTR message	
6955562Sgibbs	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
6965562Sgibbs	call	scsisig
6975562Sgibbs	jmp	p_mesgin_done
6985562Sgibbs
6995562Sgibbsp_mesginSDTR:
7005562Sgibbs	cmp	ARG_1,3		jne p_mesginN	# extended mesg length = 3
7014568Sgibbs	mvi	ARG_1		call inb_next	# xfer period
7025326Sgibbs	mvi	A		call inb_next	# REQ/ACK offset
7035647Sgibbs	mvi	INTSTAT,MSG_SDTR		# call driver to convert
7044568Sgibbs
7055562Sgibbs	test	RETURN_1,0x80	jz p_mesgin_done# Do we need to mk_sdtr?
7065326Sgibbs
7075562Sgibbs	or	FLAGS,ACTIVE_MSG
7085647Sgibbs	mvi	DINDEX, MSG_START+0
7095562Sgibbs	mvi     MSG_START+0     call mk_sdtr
7105562Sgibbs	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
7115562Sgibbs	call	scsisig
7124568Sgibbs	jmp	p_mesgin_done
7134568Sgibbs
7144568Sgibbs#  Is it a disconnect message?  Set a flag in the SCB to remind us
7154568Sgibbs#  and await the bus going free.
7164568Sgibbs#
7174568Sgibbsp_mesgin2:
7184568Sgibbs	cmp	A,4		jne p_mesgin3	# disconnect code?
7194568Sgibbs
7204568Sgibbs	or	SCBARRAY+0,0x4			# set "disconnected" bit
7214568Sgibbs	jmp	p_mesgin_done
7224568Sgibbs
7234568Sgibbs#  Save data pointers message?  Copy working values into the SCB,
7244568Sgibbs#  usually in preparation for a disconnect.
7254568Sgibbs#
7264568Sgibbsp_mesgin3:
7274568Sgibbs	cmp	A,2		jne p_mesgin4	# save data pointers code?
7284568Sgibbs
7294568Sgibbs	call	sg_ram2scb
7304568Sgibbs	jmp	p_mesgin_done
7314568Sgibbs
7324568Sgibbs#  Restore pointers message?  Data pointers are recopied from the
7334568Sgibbs#  SCB anyway at the start of any DMA operation, so the only thing
7344568Sgibbs#  to copy is the scatter-gather values.
7354568Sgibbs#
7364568Sgibbsp_mesgin4:
7374568Sgibbs	cmp	A,3		jne p_mesgin5	# restore pointers code?
7384568Sgibbs
7394568Sgibbs	call	sg_scb2ram
7404568Sgibbs	jmp	p_mesgin_done
7414568Sgibbs
7424568Sgibbs#  Identify message?  For a reconnecting target, this tells us the lun
7434568Sgibbs#  that the reconnection is for - find the correct SCB and switch to it,
7444568Sgibbs#  clearing the "disconnected" bit so we don't "find" it by accident later.
7454568Sgibbs#
7464568Sgibbsp_mesgin5:
7474568Sgibbs	test	A,0x80		jz p_mesgin6	# identify message?
7484568Sgibbs
7494568Sgibbs	test	A,0x78		jnz p_mesginN	# !DiscPriv|!LUNTAR|!Reserved
7504568Sgibbs
7517118Sgibbs	and	A,0x07				# lun in lower three bits
7526608Sgibbs	or      SAVED_TCL,A,SELID          
7536608Sgibbs	and     SAVED_TCL,0xf7
7546608Sgibbs	and     A,0x08,SBLKCTL			# B Channel??
7556608Sgibbs	or      SAVED_TCL,A
7567700Sgibbs	call	inb_last			# ACK
7577700Sgibbs	mov	ALLZEROS	call findSCB    
7586608Sgibbssetup_SCB:
7595326Sgibbs	and	SCBARRAY+0,0xfb			# clear disconnect bit in SCB
7607700Sgibbs	or	FLAGS,IDENTIFY_SEEN		# make note of IDENTIFY
7614568Sgibbs
7624568Sgibbs	call	sg_scb2ram			# implied restore pointers
7634568Sgibbs						#   required on reselect
7646608Sgibbs	jmp	ITloop
7656608Sgibbsget_tag:
7667700Sgibbs	mvi	A		call inb_first
7677700Sgibbs	cmp	A,0x20  	jne return	# Simple Tag message?
7686608Sgibbs	mvi	A		call inb_next
7697700Sgibbs	call			inb_last
7706608Sgibbs	test	A,0xf0		jnz abort_tag	# Tag in range?
7716608Sgibbs	mov	SCBPTR,A
7726608Sgibbs	mov	A,SAVED_TCL
7736608Sgibbs	cmp	SCBARRAY+1,A		jne abort_tag
7746608Sgibbs	test	SCBARRAY+0,TAG_ENB	jz  abort_tag
7757700Sgibbs	ret
7767700Sgibbsabort_tag:
7777700Sgibbs	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
7787700Sgibbs	call	scsisig
7797700Sgibbs	mvi	INTSTAT,ABORT_TAG 		# let driver know
7807700Sgibbs	mvi	0xd		call mk_mesg	# ABORT TAG message
7817700Sgibbs	ret
7826608Sgibbs
7835647Sgibbs#  Message reject?  Let the kernel driver handle this.  If we have an 
7845647Sgibbs#  outstanding WDTR or SDTR negotiation, assume that it's a response from 
7855647Sgibbs#  the target selecting 8bit or asynchronous transfer, otherwise just ignore 
7865647Sgibbs#  it since we have no clue what it pertains to.
7874568Sgibbs#
7884568Sgibbsp_mesgin6:
7894568Sgibbs	cmp	A,7		jne p_mesgin7	# message reject code?
7904568Sgibbs
7915647Sgibbs	mvi	INTSTAT, MSG_REJECT
7925562Sgibbs	jmp	p_mesgin_done
7935562Sgibbs
7944568Sgibbs#  [ ADD MORE MESSAGE HANDLING HERE ]
7954568Sgibbs#
7964568Sgibbsp_mesgin7:
7974568Sgibbs
7984568Sgibbs#  We have no idea what this message in is, and there's no way
7994568Sgibbs#  to pass it up to the kernel, so we issue a message reject and
8004568Sgibbs#  hope for the best.  Since we're now using manual PIO mode to
8014568Sgibbs#  read in the message, there should no longer be a race condition
8024568Sgibbs#  present when we assert ATN.  In any case, rejection should be a
8034568Sgibbs#  rare occurrence - signal the driver when it happens.
8044568Sgibbs#
8054568Sgibbsp_mesginN:
8064568Sgibbs	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
8074568Sgibbs	call	scsisig
8085647Sgibbs	mvi	INTSTAT,SEND_REJECT		# let driver know
8094568Sgibbs
8104568Sgibbs	mvi	0x7		call mk_mesg	# MESSAGE REJECT message
8114568Sgibbs
8124568Sgibbsp_mesgin_done:
8134568Sgibbs	call	inb_last			# ack & turn auto PIO back on
8144568Sgibbs	jmp	ITloop
8154568Sgibbs
8166608Sgibbs
8174568Sgibbs#  Bus free phase.  It might be useful to interrupt the device
8184568Sgibbs#  driver if we aren't expecting this.  For now, make sure that
8194568Sgibbs#  ATN isn't being asserted and look for a new command.
8204568Sgibbs#
8214568Sgibbsp_busfree:
8224568Sgibbs	mvi	CLRSINT1,0x40			# CLRATNO
8234568Sgibbs	clr	SIGSTATE
8244568Sgibbs	jmp	start
8254568Sgibbs
8265775Sgibbs#  Instead of a generic bcopy routine that requires an argument, we unroll
8275775Sgibbs#  the two cases that are actually used, and call them explicitly.  This
8285775Sgibbs#  not only reduces the overhead of doing a bcopy by 2/3rds, but ends up
8295775Sgibbs#  saving space in the program since you don't have to put the argument 
8305775Sgibbs#  into the accumulator before the call.  Both functions expect DINDEX to
8315775Sgibbs#  contain the destination address and SINDEX to contain the source 
8325775Sgibbs#  address.
8335775Sgibbsbcopy_3:
8344568Sgibbs	mov	DINDIR,SINDIR
8355775Sgibbs	mov	DINDIR,SINDIR
8365775Sgibbs	mov	DINDIR,SINDIR	ret
8374568Sgibbs
8385775Sgibbsbcopy_4:
8395775Sgibbs	mov	DINDIR,SINDIR
8405775Sgibbs	mov	DINDIR,SINDIR
8415775Sgibbs	mov	DINDIR,SINDIR
8425775Sgibbs	mov	DINDIR,SINDIR	ret
8435775Sgibbs	
8447532Sgibbsbcopy_3_dfdat:
8457532Sgibbs	mov	DINDIR,DFDAT
8467532Sgibbs	mov	DINDIR,DFDAT
8477532Sgibbs	mov	DINDIR,DFDAT	ret
8485775Sgibbs
8497532Sgibbsbcopy_4_dfdat:
8507532Sgibbs	mov	DINDIR,DFDAT
8517532Sgibbs	mov	DINDIR,DFDAT
8527532Sgibbs	mov	DINDIR,DFDAT
8537532Sgibbs	mov	DINDIR,DFDAT	ret
8547532Sgibbs
8554568Sgibbs#  Locking the driver out, build a one-byte message passed in SINDEX
8564568Sgibbs#  if there is no active message already.  SINDEX is returned intact.
8574568Sgibbs#
8584568Sgibbsmk_mesg:
8594866Sgibbs	mvi	SEQCTL,0x50			# PAUSEDIS|FASTMODE
8605562Sgibbs	test	FLAGS,ACTIVE_MSG jnz mk_mesg1	# active message?
8614568Sgibbs
8625562Sgibbs	or	FLAGS,ACTIVE_MSG		# if not, there is now
8634568Sgibbs	mvi	MSG_LEN,1			# length = 1
8644568Sgibbs	mov	MSG_START+0,SINDEX		# 1-byte message
8654568Sgibbs
8664568Sgibbsmk_mesg1:
8675775Sgibbs	mvi	SEQCTL,0x10	ret		# !PAUSEDIS|FASTMODE
8684568Sgibbs
8694568Sgibbs#  Carefully read data in Automatic PIO mode.  I first tried this using
8704568Sgibbs#  Manual PIO mode, but it gave me continual underrun errors, probably
8714568Sgibbs#  indicating that I did something wrong, but I feel more secure leaving
8724568Sgibbs#  Automatic PIO on all the time.
8734568Sgibbs#
8744568Sgibbs#  According to Adaptec's documentation, an ACK is not sent on input from
8754568Sgibbs#  the target until SCSIDATL is read from.  So we wait until SCSIDATL is
8764568Sgibbs#  latched (the usual way), then read the data byte directly off the bus
8774568Sgibbs#  using SCSIBUSL.  When we have pulled the ATN line, or we just want to
8784568Sgibbs#  acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
8794568Sgibbs#  spec guarantees that the target will hold the data byte on the bus until
8804568Sgibbs#  we send our ACK.
8814568Sgibbs#
8824568Sgibbs#  The assumption here is that these are called in a particular sequence,
8834568Sgibbs#  and that REQ is already set when inb_first is called.  inb_{first,next}
8844568Sgibbs#  use the same calling convention as inb.
8854568Sgibbs#
8864568Sgibbsinb_first:
8877700Sgibbs	clr	STCNT+2
8887700Sgibbs	clr	STCNT+1
8894568Sgibbs	mov	DINDEX,SINDEX
8904568Sgibbs	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
8914568Sgibbs
8924568Sgibbsinb_next:
8934568Sgibbs	mov	DINDEX,SINDEX			# save SINDEX
8944568Sgibbs
8957700Sgibbs        mvi     STCNT+0,1			# xfer one byte
8964568Sgibbs	mov	NONE,SCSIDATL			# dummy read from latch to ACK
8974568Sgibbsinb_next1:
8984568Sgibbs	test	SSTAT0,0x4	jz inb_next1	# SDONE
8994568Sgibbsinb_next2:
9004568Sgibbs	test	SSTAT0,0x2	jz inb_next2	# SPIORDY - wait for next byte
9014568Sgibbs	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
9024568Sgibbs
9034568Sgibbsinb_last:
9047700Sgibbs	mvi	STCNT+0,1			# ACK with dummy read
9054568Sgibbs	mov	NONE,SCSIDATL
9064568Sgibbsinb_last1:
9074568Sgibbs	test	SSTAT0,0x4	jz inb_last1	# wait for completion
9084568Sgibbs	ret
9094568Sgibbs
9104568Sgibbs#  DMA data transfer.  HADDR and HCNT must be loaded first, and
9114568Sgibbs#  SINDEX should contain the value to load DFCNTRL with - 0x3d for
9124568Sgibbs#  host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
9134568Sgibbs#  during initialization.
9144568Sgibbs#
9154568Sgibbsdma:
9164568Sgibbs	mov	DFCNTRL,SINDEX
9174568Sgibbsdma1:
9184568Sgibbsdma2:
9194568Sgibbs	test	SSTAT0,0x1	jnz dma3	# DMADONE
9204568Sgibbs	test	SSTAT1,0x10	jz dma1		# PHASEMIS, ie. underrun
9214568Sgibbs
9224568Sgibbs#  We will be "done" DMAing when the transfer count goes to zero, or
9234568Sgibbs#  the target changes the phase (in light of this, it makes sense that
9244568Sgibbs#  the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
9254866Sgibbs#  doing a SCSI->Host transfer, the data FIFO should be flushed auto-
9264866Sgibbs#  magically on STCNT=0 or a phase change, so just wait for FIFO empty
9274866Sgibbs#  status.
9284568Sgibbs#
9294568Sgibbsdma3:
9304568Sgibbs	test	SINDEX,0x4	jnz dma5	# DIRECTION
9314568Sgibbsdma4:
9325562Sgibbs	test	DFSTATUS,0x1	jz dma4		# !FIFOEMP
9334568Sgibbs
9344568Sgibbs#  Now shut the DMA enables off, and copy STCNT (ie. the underrun
9354568Sgibbs#  amount, if any) to the SCB registers; SG_COUNT will get copied to
9364568Sgibbs#  the SCB's residual S/G count field after sg_advance is called.  Make
9374568Sgibbs#  sure that the DMA enables are actually off first lest we get an ILLSADDR.
9384568Sgibbs#
9394568Sgibbsdma5:
9404568Sgibbs	clr	DFCNTRL				# disable DMA
9414568Sgibbsdma6:
9424568Sgibbs	test	DFCNTRL,0x38	jnz dma6	# SCSIENACK|SDMAENACK|HDMAENACK
9434568Sgibbs
9444568Sgibbs	mvi	DINDEX,SCBARRAY+15
9455775Sgibbs	mvi	STCNT		call bcopy_3
9464568Sgibbs
9474568Sgibbs	ret
9484568Sgibbs
9497532Sgibbsdma_finish:
9507532Sgibbs	test	DFSTATUS,0x8	jz dma_finish	# HDONE
9517532Sgibbs
9527532Sgibbs	clr	DFCNTRL				# disable DMA
9537532Sgibbsdma_finish2:
9547532Sgibbs	test	DFCNTRL,0x8	jnz dma_finish2	# HDMAENACK
9557532Sgibbs	ret
9567532Sgibbs
9574568Sgibbs#  Common SCSI initialization for selection and reselection.  Expects
9584568Sgibbs#  the target SCSI ID to be in the upper four bits of SINDEX, and A's
9594568Sgibbs#  contents are stomped on return.
9604568Sgibbs#
9614568Sgibbsinitialize:
9625775Sgibbs	and	SINDEX,0xf0		# Get target ID
9635775Sgibbs	and	A,0x0f,SCSIID
9645775Sgibbs	or	SINDEX,A
9655775Sgibbs	mov	SCSIID,SINDEX
9665326Sgibbs
9674568Sgibbs#  Esundry initialization.
9684568Sgibbs#
9694568Sgibbs	clr	DROPATN
9704568Sgibbs	clr	SIGSTATE
9714568Sgibbs
9725775Sgibbs#  Turn on Automatic PIO mode now, before we expect to see a REQ
9734568Sgibbs#  from the target.  It shouldn't hurt anything to leave it on.  Set
9744568Sgibbs#  CLRCHN here before the target has entered a data transfer mode -
9754568Sgibbs#  with synchronous SCSI, if you do it later, you blow away some
9764568Sgibbs#  data in the SCSI FIFO that the target has already sent to you.
9774568Sgibbs#
9784866Sgibbs	mvi	SXFRCTL0,0x8a			# DFON|SPIOEN|CLRCHN
9794568Sgibbs
9804568Sgibbs#  Initialize scatter-gather pointers by setting up the working copy
9814568Sgibbs#  in scratch RAM.
9824568Sgibbs#
9834568Sgibbs	call	sg_scb2ram
9844568Sgibbs
9854568Sgibbs#  Initialize SCSIRATE with the appropriate value for this target.
9864568Sgibbs#
9875562Sgibbs	call	ndx_dtr
9885775Sgibbs	mov	SCSIRATE,SINDIR	ret
9894568Sgibbs
9904568Sgibbs#  Assert that if we've been reselected, then we've seen an IDENTIFY
9914568Sgibbs#  message.
9924568Sgibbs#
9934568Sgibbsassert:
9947532Sgibbs	test	FLAGS,RESELECTED	jz return	# reselected?
9957532Sgibbs	test	FLAGS,IDENTIFY_SEEN	jnz return	# seen IDENTIFY?
9964568Sgibbs
9977532Sgibbs	mvi	INTSTAT,NO_IDENT 	ret	# no - cause a kernel panic
9984568Sgibbs
9994568Sgibbs#  Find out if disconnection is ok from the information the BIOS has left
10005326Sgibbs#  us.  The tcl from SCBARRAY+1 should be in SINDEX; A will
10014866Sgibbs#  contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok)
10024568Sgibbs#  on exit.
10034568Sgibbs#
10045326Sgibbs#  To allow for wide or twin busses, we check the upper bit of the target ID
10055326Sgibbs#  and the channel ID and look at the appropriate disconnect register. 
10064568Sgibbs#
10074568Sgibbsdisconnect:
10084568Sgibbs	and	FUNCTION1,0x70,SINDEX		# strip off extra just in case
10094568Sgibbs	mov	A,FUNCTION1
10105326Sgibbs	test	SINDEX, 0x88	jz disconnect_a
10115326Sgibbs
10125326Sgibbs	test	DISC_DSB_B,A	jz disconnect1	# bit nonzero if DISabled
10135326Sgibbs	clr	A		ret
10145326Sgibbs
10155326Sgibbsdisconnect_a:
10164568Sgibbs	test	DISC_DSB_A,A	jz disconnect1	# bit nonzero if DISabled
10175326Sgibbs	clr	A		ret
10184568Sgibbs
10194568Sgibbsdisconnect1:
10204568Sgibbs	mvi	A,0x40		ret
10214568Sgibbs
10226608Sgibbs#  Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch 
10236608Sgibbs#  the SCB to it.  Have the kernel print a warning message if it can't be 
10246608Sgibbs#  found, and generate an ABORT message to the target.  SINDEX should be
10256608Sgibbs#  cleared on call.
10264568Sgibbs#
10274568SgibbsfindSCB:
10286608Sgibbs	mov	A,SAVED_TCL
10294568Sgibbs	mov	SCBPTR,SINDEX			# switch to new SCB
10306608Sgibbs	cmp	SCBARRAY+1,A	jne findSCB1	# target ID/channel/lun match?
10316608Sgibbs	test	SCBARRAY+0,0x4	jz findSCB1	# should be disconnected
10327700Sgibbs	test	SCBARRAY+0,TAG_ENB jnz get_tag
10334568Sgibbs	ret
10344568Sgibbs
10356608SgibbsfindSCB1:
10364568Sgibbs	inc	SINDEX
10374568Sgibbs	mov	A,SCBCOUNT
10386608Sgibbs	cmp	SINDEX,A	jne findSCB
10394568Sgibbs
10405647Sgibbs	mvi	INTSTAT,NO_MATCH		# not found - signal kernel
10414568Sgibbs	mvi	0x6		call mk_mesg	# ABORT message
10424568Sgibbs
10434568Sgibbs	or	SINDEX,0x10,SIGSTATE		# assert ATNO
10444568Sgibbs	call	scsisig
10454568Sgibbs	ret
10464568Sgibbs
10474568Sgibbs#  Make a working copy of the scatter-gather parameters in the SCB.
10484568Sgibbs#
10494568Sgibbssg_scb2ram:
10504568Sgibbs	mov	SG_COUNT,SCBARRAY+2
10514568Sgibbs
10524568Sgibbs	mvi	DINDEX,SG_NEXT
10535775Sgibbs	mvi	SCBARRAY+3	call bcopy_4
10544568Sgibbs
10554568Sgibbs	mvi	SG_NOLOAD,0x80
10567532Sgibbs	test	SCBARRAY+0,0x10	jnz return	# don't reload s/g?
10577532Sgibbs	clr	SG_NOLOAD	 ret
10584568Sgibbs
10594568Sgibbs#  Copying RAM values back to SCB, for Save Data Pointers message.
10604568Sgibbs#
10614568Sgibbssg_ram2scb:
10624568Sgibbs	mov	SCBARRAY+2,SG_COUNT
10634568Sgibbs
10644568Sgibbs	mvi	DINDEX,SCBARRAY+3
10655775Sgibbs	mvi	SG_NEXT		call bcopy_4
10664568Sgibbs
10674568Sgibbs	and	SCBARRAY+0,0xef,SCBARRAY+0
10687532Sgibbs	test	SG_NOLOAD,0x80	jz return	# reload s/g?
10697532Sgibbs	or	SCBARRAY+0,SG_LOAD	 ret
10704568Sgibbs
10714568Sgibbs#  Load a struct scatter if needed and set up the data address and
10724568Sgibbs#  length.  If the working value of the SG count is nonzero, then
10734568Sgibbs#  we need to load a new set of values.
10744568Sgibbs#
10754568Sgibbs#  This, like the above DMA, assumes a little-endian host data storage.
10764568Sgibbs#
10774568Sgibbssg_load:
10787532Sgibbs	test	SG_COUNT,0xff	jz return	# SG being used?
10797532Sgibbs	test	SG_NOLOAD,0x80	jnz return	# don't reload s/g?
10804568Sgibbs
10814568Sgibbs	clr	HCNT+2
10824568Sgibbs	clr	HCNT+1
10834568Sgibbs	mvi	HCNT+0,SG_SIZEOF
10844568Sgibbs
10854568Sgibbs	mvi	DINDEX,HADDR
10865775Sgibbs	mvi	SG_NEXT		call bcopy_4
10874568Sgibbs
10884568Sgibbs	mvi	DFCNTRL,0xd			# HDMAEN|DIRECTION|FIFORESET
10894568Sgibbs
10904568Sgibbs#  Wait for DMA from host memory to data FIFO to complete, then disable
10914568Sgibbs#  DMA and wait for it to acknowledge that it's off.
10924568Sgibbs#
10934568Sgibbs
10947532Sgibbs	call	dma_finish
10954568Sgibbs
10964568Sgibbs#  Copy data from FIFO into SCB data pointer and data count.  This assumes
10974568Sgibbs#  that the struct scatterlist has this structure (this and sizeof(struct
10984568Sgibbs#  scatterlist) == 12 are asserted in aic7xxx.c):
10994568Sgibbs#
11004568Sgibbs#	struct scatterlist {
11014568Sgibbs#		char *address;		/* four bytes, little-endian order */
11024568Sgibbs#		...			/* four bytes, ignored */
11034568Sgibbs#		unsigned short length;	/* two bytes, little-endian order */
11044568Sgibbs#	}
11054568Sgibbs#
11064568Sgibbs
11077532Sgibbs# Not in FreeBSD.  the scatter list entry is only 8 bytes.
11084568Sgibbs# 
11094568Sgibbs# struct ahc_dma_seg {
11104568Sgibbs#       physaddr addr;                  /* four bytes, little-endian order */
11114568Sgibbs#       long    len;                    /* four bytes, little endian order */   
11124568Sgibbs# };
11134568Sgibbs#
11144568Sgibbs
11157532Sgibbs	mvi	DINDEX, SCBARRAY+19
11167532Sgibbs	call	bcopy_4_dfdat
11174568Sgibbs
11185647Sgibbs# For Linux, we must throw away four bytes since there is a 32bit gap
11195647Sgibbs# in the middle of a struct scatterlist
11205647Sgibbs#	mov	NONE,DFDAT
11215647Sgibbs#	mov	NONE,DFDAT
11225647Sgibbs#	mov	NONE,DFDAT
11235647Sgibbs#	mov	NONE,DFDAT
11245647Sgibbs
11257532Sgibbs	call	bcopy_3_dfdat		#Only support 24 bit length.
11264568Sgibbs	ret
11274568Sgibbs
11284568Sgibbs#  Advance the scatter-gather pointers only IF NEEDED.  If SG is enabled,
11294568Sgibbs#  and the SCSI transfer count is zero (note that this should be called
11304568Sgibbs#  right after a DMA finishes), then move the working copies of the SG
11314568Sgibbs#  pointer/length along.  If the SCSI transfer count is not zero, then
11324568Sgibbs#  presumably the target is disconnecting - do not reload the SG values
11334568Sgibbs#  next time.
11344568Sgibbs#
11354568Sgibbssg_advance:
11367532Sgibbs	test	SG_COUNT,0xff	jz return	# s/g enabled?
11374568Sgibbs
11384568Sgibbs	test	STCNT+0,0xff	jnz sg_advance1	# SCSI transfer count nonzero?
11394568Sgibbs	test	STCNT+1,0xff	jnz sg_advance1
11404568Sgibbs	test	STCNT+2,0xff	jnz sg_advance1
11414568Sgibbs
11424568Sgibbs	clr	SG_NOLOAD			# reload s/g next time
11434568Sgibbs	dec	SG_COUNT			# one less segment to go
11444568Sgibbs
11454568Sgibbs	clr	A				# add sizeof(struct scatter)
11464568Sgibbs	add	SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
11474568Sgibbs	adc	SG_NEXT+1,A,SG_NEXT+1
11484568Sgibbs	adc	SG_NEXT+2,A,SG_NEXT+2
11495775Sgibbs	adc	SG_NEXT+3,A,SG_NEXT+3	ret
11504568Sgibbs
11514568Sgibbssg_advance1:
11527532Sgibbs	mvi	SG_NOLOAD,0x80	ret		# don't reload s/g next time
11534568Sgibbs
11544568Sgibbs#  Add the array base SYNCNEG to the target offset (the target address
11554568Sgibbs#  is in SCSIID), and return the result in SINDEX.  The accumulator
11564568Sgibbs#  contains the 3->8 decoding of the target ID on return.
11574568Sgibbs#
11585562Sgibbsndx_dtr:
11594568Sgibbs	shr	A,SCSIID,4
11605562Sgibbs	test	SBLKCTL,0x08	jz ndx_dtr_2
11615326Sgibbs	or	A,0x08		# Channel B entries add 8
11625562Sgibbsndx_dtr_2:
11634568Sgibbs	add	SINDEX,SYNCNEG,A
11644568Sgibbs
11654568Sgibbs	and	FUNCTION1,0x70,SCSIID		# 3-bit target address decode
11664568Sgibbs	mov	A,FUNCTION1	ret
11674568Sgibbs
11685562Sgibbs#  If we need to negotiate transfer parameters, build the WDTR or SDTR message
11694568Sgibbs#  starting at the address passed in SINDEX.  DINDEX is modified on return.
11705562Sgibbs#  The SCSI-II spec requires that Wide negotiation occur first and you can
11715562Sgibbs#  only negotiat one or the other at a time otherwise in the event of a message
11725562Sgibbs#  reject, you wouldn't be able to tell which message was the culpret.
11734568Sgibbs#
11745562Sgibbsmk_dtr:
11757532Sgibbs	test	SCBARRAY+0,0xc0 jz return	# NEEDWDTR|NEEDSDTR
11765647Sgibbs	test	SCBARRAY+0,NEEDWDTR jnz  mk_wdtr_16bit
11777532Sgibbs	or	FLAGS, MAX_SYNC		 # Force an offset of 15
11784568Sgibbs
11797532Sgibbsmk_sdtr:
11807532Sgibbs	mvi	DINDIR,1			# extended message
11817532Sgibbs	mvi	DINDIR,3			# extended message length = 3
11827532Sgibbs	mvi	DINDIR,1			# SDTR code
11837532Sgibbs	call	sdtr_to_rate
11847532Sgibbs	mov	DINDIR,RETURN_1			# REQ/ACK transfer period
11857532Sgibbs	test	FLAGS, MAX_SYNC	jnz mk_sdtr_max_sync
11867532Sgibbs	and	DINDIR,0xf,SINDIR		# Sync Offset
11877532Sgibbs
11887532Sgibbsmk_sdtr_done:
11897532Sgibbs	add	MSG_LEN,-MSG_START+0,DINDEX ret	# update message length
11907532Sgibbs
11917532Sgibbsmk_sdtr_max_sync:
11927532Sgibbs# We're initiating sync negotiation, so request the max offset we can (15)
11937532Sgibbs	mvi	DINDIR, 0x0f
11947532Sgibbs	xor	FLAGS, MAX_SYNC
11957532Sgibbs	jmp	mk_sdtr_done
11967532Sgibbs
11975647Sgibbsmk_wdtr_16bit:
11985647Sgibbs	mvi	ARG_1,BUS_16_BIT
11995562Sgibbsmk_wdtr:
12004568Sgibbs	mvi	DINDIR,1			# extended message
12015562Sgibbs	mvi	DINDIR,2			# extended message length = 2
12025562Sgibbs	mvi	DINDIR,3			# WDTR code
12035562Sgibbs	mov	DINDIR,ARG_1			# bus width
12045562Sgibbs
12055775Sgibbs	add	MSG_LEN,-MSG_START+0,DINDEX ret	# update message length
12065562Sgibbs	
12074568Sgibbs#  Set SCSI bus control signal state.  This also saves the last-written
12084568Sgibbs#  value into a location where the higher-level driver can read it - if
12094568Sgibbs#  it has to send an ABORT or RESET message, then it needs to know this
12104568Sgibbs#  so it can assert ATN without upsetting SCSISIGO.  The new value is
12114568Sgibbs#  expected in SINDEX.  Change the actual state last to avoid contention
12124568Sgibbs#  from the driver.
12134568Sgibbs#
12144568Sgibbsscsisig:
12154568Sgibbs	mov	SIGSTATE,SINDEX
12164568Sgibbs	mov	SCSISIGO,SINDEX	ret
12175562Sgibbs
12185562Sgibbssdtr_to_rate:
12195562Sgibbs	call	ndx_dtr				# index scratch space for target
12205562Sgibbs	shr	A,SINDIR,0x4
12215562Sgibbs	dec	SINDEX				#Preserve SINDEX
12225562Sgibbs	and	A,0x7
12235562Sgibbs	clr	RETURN_1
12245562Sgibbssdtr_to_rate_loop:
12255562Sgibbs	test	A,0x0f	jz sdtr_to_rate_done
12265562Sgibbs	add	RETURN_1,0x18
12275562Sgibbs	dec	A	
12285562Sgibbs	jmp	sdtr_to_rate_loop
12295562Sgibbssdtr_to_rate_done:
12305562Sgibbs	shr	RETURN_1,0x2
12315562Sgibbs	add	RETURN_1,0x18	ret
12327532Sgibbs
12337532Sgibbsreturn:
12347532Sgibbs	ret
1235