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