aic7xxx.seq revision 9928
1##+M#########################################################################
2# Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
3#
4# Copyright (c) 1994 John Aycock
5#   The University of Calgary Department of Computer Science.
6#   All rights reserved.
7#
8# Modifications/enhancements:
9#   Copyright (c) 1994, 1995 Justin Gibbs. All rights reserved.
10#
11# Redistribution and use in source and binary forms, with or without
12# modification, are permitted provided that the following conditions
13# are met:
14# 1. Redistributions of source code must retain the above copyright
15#    notice, this list of conditions, and the following disclaimer.
16# 2. Redistributions in binary form must reproduce the above copyright
17#    notice, this list of conditions and the following disclaimer in the
18#    documentation and/or other materials provided with the distribution.
19# 3. All advertising materials mentioning features or use of this software
20#    must display the following acknowledgement:
21#      This product includes software developed by the University of Calgary
22#      Department of Computer Science and its contributors.
23# 4. Neither the name of the University nor the names of its contributors
24#    may be used to endorse or promote products derived from this software
25#    without specific prior written permission.
26#
27# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
28# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
31# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37# SUCH DAMAGE.
38# 
39# FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 
40# optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
41#
42##-M#########################################################################
43
44VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.18 1995/07/31 08:21:59 gibbs Exp $"
45
46SCBMASK		= 0xff
47
48SCSISEQ		= 0x00
49ENRSELI		= 0x10
50SXFRCTL0	= 0x01
51SXFRCTL1	= 0x02
52SCSISIGI	= 0x03
53SCSISIGO	= 0x03
54SCSIRATE	= 0x04
55SCSIID		= 0x05
56SCSIDATL	= 0x06
57STCNT		= 0x08
58STCNT+0		= 0x08
59STCNT+1		= 0x09
60STCNT+2		= 0x0a
61CLRSINT0	= 0x0b
62SSTAT0		= 0x0b
63SELDO		= 0x40
64SELDI		= 0x20
65CLRSINT1	= 0x0c
66SSTAT1		= 0x0c
67PHASEMIS	= 0x10
68SIMODE1		= 0x11
69SCSIBUSL	= 0x12
70SHADDR		= 0x14
71SELID		= 0x19
72SBLKCTL		= 0x1f
73SEQCTL		= 0x60
74A		= 0x64				# == ACCUM
75SINDEX		= 0x65
76DINDEX		= 0x66
77ALLZEROS	= 0x6a
78NONE		= 0x6a
79SINDIR		= 0x6c
80DINDIR		= 0x6d
81FUNCTION1	= 0x6e
82HADDR		= 0x88
83HADDR+1		= 0x89
84HADDR+2		= 0x8a
85HADDR+3		= 0x8b
86HCNT		= 0x8c
87HCNT+0		= 0x8c
88HCNT+1		= 0x8d
89HCNT+2		= 0x8e
90SCBPTR		= 0x90
91INTSTAT		= 0x91
92DFCNTRL		= 0x93
93DFSTATUS	= 0x94
94DFDAT		= 0x99
95QINFIFO		= 0x9b
96QINCNT		= 0x9c
97QOUTFIFO	= 0x9d
98
99SCSICONF_A	= 0x5a
100SCSICONF_B	= 0x5b
101
102#  The two reserved bytes at SCBARRAY+1[23] are expected to be set to
103#  zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate 
104#  whether or not to DMA an SCB from host ram. This flag prevents the
105#  "re-fetching" of transactions that are requed because the target is
106#  busy with another command. We also use bits 6 & 7 to indicate whether 
107#  or not to initiate SDTR or WDTR repectively when starting this command.
108#
109SCBARRAY+0	= 0xa0
110
111DISCONNECTED	= 0x04
112NEEDDMA		= 0x08
113NEEDSDTR	= 0x10
114TAG_ENB		= 0x20
115DISCENB		= 0x40
116NEEDWDTR	= 0x80
117
118SCBARRAY+1	= 0xa1
119SCBARRAY+2	= 0xa2
120SCBARRAY+3	= 0xa3
121SCBARRAY+4	= 0xa4
122SCBARRAY+5	= 0xa5
123SCBARRAY+6	= 0xa6
124SCBARRAY+7	= 0xa7
125SCBARRAY+8	= 0xa8
126SCBARRAY+9	= 0xa9
127SCBARRAY+10	= 0xaa
128SCBARRAY+11	= 0xab
129SCBARRAY+12	= 0xac
130SCBARRAY+13	= 0xad
131SCBARRAY+14	= 0xae
132SCBARRAY+15	= 0xaf
133SCBARRAY+16	= 0xb0
134SCBARRAY+17	= 0xb1
135SCBARRAY+18	= 0xb2
136SCBARRAY+19	= 0xb3
137SCBARRAY+20	= 0xb4
138SCBARRAY+21	= 0xb5
139SCBARRAY+22	= 0xb6
140SCBARRAY+23	= 0xb7
141SCBARRAY+24	= 0xb8
142SCBARRAY+25	= 0xb9
143SCBARRAY+26	= 0xba
144SCBARRAY+27	= 0xbb
145SCBARRAY+28	= 0xbc
146SCBARRAY+29	= 0xbd
147SCBARRAY+30	= 0xbe
148
149BAD_PHASE	= 0x01				# unknown scsi bus phase
150CMDCMPLT	= 0x02				# Command Complete
151SEND_REJECT	= 0x11				# sending a message reject
152NO_IDENT	= 0x21				# no IDENTIFY after reconnect
153NO_MATCH	= 0x31				# no cmd match for reconnect
154MSG_SDTR	= 0x41				# SDTR message recieved
155MSG_WDTR	= 0x51				# WDTR message recieved
156MSG_REJECT	= 0x61				# Reject message recieved
157BAD_STATUS	= 0x71				# Bad status from target
158RESIDUAL	= 0x81				# Residual byte count != 0
159ABORT_TAG	= 0x91				# Sent an ABORT_TAG message
160AWAITING_MSG	= 0xa1				# Kernel requested to specify
161						# a message to this target
162						# (command was null), so tell
163						# it that it can fill the
164						# message buffer.
165IMMEDDONE	= 0xb1
166
167
168#  The host adapter card (at least the BIOS) uses 20-2f for SCSI
169#  device information, 32-33 and 5a-5f as well. As it turns out, the
170#  BIOS trashes 20-2f, writing the synchronous negotiation results
171#  on top of the BIOS values, so we re-use those for our per-target
172#  scratchspace (actually a value that can be copied directly into
173#  SCSIRATE).  The kernel driver will enable synchronous negotiation
174#  for all targets that have a value other than 0 in the lower four
175#  bits of the target scratch space.  This should work regardless of
176#  whether the bios has been installed. NEEDSDTR and NEEDWDTR are the
177#  fouth and sevent bits of the SCB control byte.  The kernel driver 
178#  will set these when a WDTR or SDTR message should be sent to the 
179#  target the SCB's command references.
180#
181#  REJBYTE contains the first byte of a MESSAGE IN message, so the driver 
182#  can report an intelligible error if a message is rejected.
183#
184#  FLAGS's high bit is true if we are currently handling a reselect;
185#  its next-highest bit is true ONLY IF we've seen an IDENTIFY message
186#  from the reselecting target.  If we haven't had IDENTIFY, then we have
187#  no idea what the lun is, and we can't select the right SCB register
188#  bank, so force a kernel panic if the target attempts a data in/out or
189#  command phase instead of corrupting something.  FLAGS also contains
190#  configuration bits so that we can optimize for TWIN and WIDE controllers,
191#  the MAX_OFFSET bit which we set when we want to negotiate for maximum sync 
192#  offset irregardless of what the per target scratch space says.
193#
194#  Note that SG_NEXT occupies four bytes.
195#
196SYNCNEG		= 0x20
197
198REJBYTE		= 0x31
199DISC_DSB_A	= 0x32
200DISC_DSB_B	= 0x33
201
202MSG_LEN		= 0x34
203MSG_START+0	= 0x35
204MSG_START+1	= 0x36
205MSG_START+2	= 0x37
206MSG_START+3	= 0x38
207MSG_START+4	= 0x39
208MSG_START+5	= 0x3a
209-MSG_START+0	= 0xcb				# 2's complement of MSG_START+0
210
211ARG_1		= 0x4a				# sdtr conversion args & return
212BUS_16_BIT	= 0x01
213RETURN_1	= 0x4a
214
215SIGSTATE	= 0x4b				# value written to SCSISIGO
216
217# Linux users should use 0xc (12) for SG_SIZEOF
218SG_SIZEOF	= 0x8 				# sizeof(struct ahc_dma)
219#SG_SIZEOF	= 0xc 				# sizeof(struct scatterlist)
220SCB_SIZEOF	= 0x1a				# sizeof SCB to DMA (26 bytes)
221
222DMAPARAMS	= 0x4c				# Parameters for DMA
223SG_COUNT	= 0x4d				# working value of SG count
224SG_NEXT		= 0x4e				# working value of SG pointer
225SG_NEXT+0	= 0x4e
226SG_NEXT+1	= 0x4f
227SG_NEXT+2	= 0x50
228SG_NEXT+3	= 0x51
229
230SCBCOUNT	= 0x52				# the actual number of SCBs
231FLAGS		= 0x53				# Device configuration flags
232TWIN_BUS	= 0x01
233WIDE_BUS	= 0x02
234DPHASE		= 0x04
235MAX_OFFSET	= 0x08
236ACTIVE_MSG	= 0x20
237IDENTIFY_SEEN	= 0x40
238RESELECTED	= 0x80
239
240MAX_OFFSET_8BIT	= 0x0f
241MAX_OFFSET_WIDE	= 0x08
242
243ACTIVE_A	= 0x54
244ACTIVE_B	= 0x55
245SAVED_TCL	= 0x56				# Temporary storage for the 
246						# target/channel/lun of a
247						# reconnecting target
248# After starting the selection hardware, we return to the "poll_for_work"
249# loop so that we can check for reconnecting targets as well as for our
250# selection to complete just in case the reselection wins bus arbitration.
251# The problem with this is that we must keep track of the SCB that we've
252# already pulled from the QINFIFO and started the selection on just in case
253# the reselection wins so that we can retry the selection at a later time.
254# This problem cannot be resolved by holding a single entry in scratch
255# ram since a reconnecting target can request sense and this will create
256# yet another SCB waiting for selection.  The solution used here is to 
257# use byte 31 of the SCB as a psuedo-next pointer and to thread a list
258# of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB offsets, 
259# SCB_LIST_NULL is 0xff which is out of range.  The kernel driver must
260# add an entry to this list everytime a request sense occurs.  The sequencer
261# will automatically consume the entries.
262
263WAITING_SCBH	= 0x57				# head of list of SCBs awaiting
264						# selection
265WAITING_SCBT	= 0x58				# tail of list of SCBs awaiting
266						# selection
267SCB_LIST_NULL	= 0xff
268
269
270#  Poll QINCNT for work - the lower bits contain
271#  the number of entries in the Queue In FIFO.
272#
273poll_for_work:
274	test	FLAGS,TWIN_BUS	jz start2	# Are we a twin channel device?
275# For fairness, we check the other bus first, since we just finished a 
276# transaction on the current channel.
277	xor	SBLKCTL,0x08			# Toggle to the other bus
278	test	SSTAT0,SELDI	jnz reselect
279	xor	SBLKCTL,0x08			# Toggle to the original bus
280start2:
281	test	SSTAT0,SELDI	jnz reselect
282	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting
283	test	QINCNT,SCBMASK	jz poll_for_work
284
285# We have at least one queued SCB now and we don't have any 
286# SCBs in the list of SCBs awaiting selection.  Set the SCB
287# pointer from the FIFO so we see the right bank of SCB 
288# registers, then set SCSI options and set the initiator and
289# target SCSI IDs.
290#
291	mov	SCBPTR,QINFIFO
292
293# If the control byte of this SCB has the NEEDDMA flag set, we have
294# yet to DMA it from host memory
295
296test    SCBARRAY+0,NEEDDMA      jz test_busy    
297	clr	HCNT+2
298	clr	HCNT+1
299	mvi	HCNT+0,SCB_SIZEOF
300
301	mvi	DINDEX,HADDR      
302	mvi	SCBARRAY+26     call bcopy_4
303        
304	mvi	DFCNTRL,0xd                     # HDMAEN|DIRECTION|FIFORESET
305
306#  Wait for DMA from host memory to data FIFO to complete, then disable
307#  DMA and wait for it to acknowledge that it's off.
308#
309	call	dma_finish
310
311# Copy the SCB from the FIFO to  the SCBARRAY
312
313	mvi	DINDEX, SCBARRAY+0
314	call	bcopy_5_dfdat 
315	call	bcopy_7_dfdat
316	call	bcopy_7_dfdat
317	call	bcopy_7_dfdat   
318
319# See if there is not already an active SCB for this target.  This code
320# locks out on a per target basis instead of target/lun.  Although this
321# is not ideal for devices that have multiple luns active at the same
322# time, it is faster than looping through all SCB's looking for active
323# commands.  It may be benificial to make findscb a more general procedure
324# to see if the added cost of the search is negligible.  This code also 
325# assumes that the kernel driver will clear the active flags on board 
326# initialization, board reset, and a target's SELTO.
327
328test_busy:
329	and	FUNCTION1,0x70,SCBARRAY+1
330	mov	A,FUNCTION1
331	test	SCBARRAY+1,0x88	jz test_a	# Id < 8 && A channel
332
333	test	ACTIVE_B,A	jnz requeue
334	test	SCBARRAY+0,TAG_ENB	jnz start_scb
335	or	ACTIVE_B,A	# Mark the current target as busy
336	jmp	start_scb
337
338# Place the currently active back on the queue for later processing
339requeue:
340	mov	QINFIFO, SCBPTR
341	jmp	poll_for_work
342
343# Pull the first entry off of the waiting for selection list
344start_waiting:
345	mov	SCBPTR,WAITING_SCBH
346	jmp	start_scb
347
348test_a:
349	test	ACTIVE_A,A	jnz requeue
350	test	SCBARRAY+0,TAG_ENB	jnz start_scb
351	or	ACTIVE_A,A	# Mark the current target as busy
352
353start_scb:
354	and	SINDEX,0xf7,SBLKCTL  #Clear the channel select bit
355	and	A,0x08,SCBARRAY+1    #Get new channel bit
356	or	SINDEX,A	     
357	mov	SBLKCTL,SINDEX	# select channel
358	mov	SCBARRAY+1	call initialize_scsiid
359
360# Enable selection phase as an initiator, and do automatic ATN
361# after the selection.  We do this now so that we can overlap the
362# rest of our work to set up this target with the arbitration and
363# selection bus phases.
364#
365start_selection:
366	or	SCSISEQ,0x48			# ENSELO|ENAUTOATNO
367	mov	WAITING_SCBH, SCBPTR
368	and	FLAGS,0x3f	# !RESELECTING 
369
370#  As soon as we get a successful selection, the target should go
371#  into the message out phase since we have ATN asserted.  Prepare
372#  the message to send, locking out the device driver.  If the device
373#  driver hasn't beaten us with an ABORT or RESET message, then tack
374#  on an SDTR negotiation if required.
375#
376#  Messages are stored in scratch RAM starting with a flag byte (high bit
377#  set means active message), one length byte, and then the message itself.
378#
379
380	test	SCBARRAY+11,0xff jnz identify	# 0 Length Command?
381
382#  The kernel has sent us an SCB with no command attached.  This implies
383#  that the kernel wants to send a message of some sort to this target,
384#  so we interrupt the driver, allow it to fill the message buffer, and
385#  then go back into the arbitration loop
386	mvi     INTSTAT,AWAITING_MSG
387	jmp     wait_for_selection
388
389identify:
390	and	A,DISCENB,SCBARRAY+0		# mask off disconnect privledge
391
392	and	SINDEX,0x7,SCBARRAY+1		# lun
393	or	SINDEX,A			# or in disconnect privledge
394	or	SINDEX,0x80	call mk_mesg	# IDENTIFY message
395
396	mov	A,SINDEX
397	test	SCBARRAY+0,0xb0	jz  !message	# WDTR, SDTR or TAG??
398	cmp	MSG_START+0,A	jne !message	# did driver beat us?
399
400# Tag Message if Tag enabled in SCB control block.  Use SCBPTR as the tag
401# value
402
403mk_tag:
404	mvi	DINDEX, MSG_START+1
405	test	SCBARRAY+0,TAG_ENB jz mk_tag_done
406	and	A,0x23,SCBARRAY+0
407	mov	DINDIR,A
408	mov	DINDIR,SCBPTR
409
410	add	MSG_LEN,-MSG_START+0,DINDEX	# update message length
411
412mk_tag_done:
413
414	mov	DINDEX	call mk_dtr	# build DTR message if needed
415
416!message:
417wait_for_selection:
418	test	SSTAT0,SELDI	jnz reselect
419	test	SSTAT0,SELDO	jnz select
420	jmp	wait_for_selection
421
422#  Reselection has been initiated by a target. Make a note that we've been
423#  reselected, but haven't seen an IDENTIFY message from the target
424#  yet.
425#
426reselect:
427	mov	SELID		call initialize_scsiid
428	and	FLAGS,0x3f			# reselected, no IDENTIFY	
429	or	FLAGS,RESELECTED jmp select2
430
431# After the selection, remove this SCB from the "waiting for selection"
432# list.  This is achieved by simply moving our "next" pointer into
433# WAITING_SCBH and setting our next pointer to null so that the next
434# time this SCB is used, we don't get confused.
435#
436select:
437	or	SCBARRAY+0,NEEDDMA
438	mov	WAITING_SCBH,SCBARRAY+30
439	mvi	SCBARRAY+30,SCB_LIST_NULL
440select2:
441	call	initialize_for_target
442	mvi	SCSISEQ,ENRSELI
443	mvi	CLRSINT0,0x60			# CLRSELDI|CLRSELDO
444	mvi	CLRSINT1,0x8			# CLRBUSFREE
445
446#  Main loop for information transfer phases.  If BSY is false, then
447#  we have a bus free condition, expected or not.  Otherwise, wait
448#  for the target to assert REQ before checking MSG, C/D and I/O
449#  for the bus phase.
450#
451#  We can't simply look at the values of SCSISIGI here (if we want
452#  to do synchronous data transfer), because the target won't assert
453#  REQ if it's already sent us some data that we haven't acknowledged
454#  yet.
455#
456ITloop:
457	test	SSTAT1,0x8	jnz p_busfree	# BUSFREE
458	test	SSTAT1,0x1	jz ITloop	# REQINIT
459
460	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
461
462	cmp	ALLZEROS,A	je p_dataout
463	cmp	A,0x40		je p_datain
464	cmp	A,0x80		je p_command
465	cmp	A,0xc0		je p_status
466	cmp	A,0xa0		je p_mesgout
467	cmp	A,0xe0		je p_mesgin
468
469	mvi	INTSTAT,BAD_PHASE		# unknown - signal driver
470
471p_dataout:
472	mvi	0		call scsisig	# !CDO|!IOO|!MSGO
473	mvi	DMAPARAMS,0x7d			# WIDEODD|SCSIEN|SDMAEN|HDMAEN|
474						#   DIRECTION|FIFORESET
475	jmp	data_phase_init
476
477# If we re-enter the data phase after going through another phase, the
478# STCNT may have been cleared, so restore it from the residual field.
479data_phase_reinit:
480	mvi	DINDEX, STCNT
481	mvi	SCBARRAY+15	call bcopy_3
482	jmp	data_phase_loop
483
484# Reads should not use WIDEODD since it may make the last byte for a SG segment
485# go to the next segment.
486p_datain:
487	mvi	0x40		call scsisig	# !CDO|IOO|!MSGO
488	mvi	DMAPARAMS,0x39			# SCSIEN|SDMAEN|HDMAEN|
489						#   !DIRECTION|FIFORESET
490data_phase_init:
491	call	assert
492
493	test	FLAGS, DPHASE	jnz data_phase_reinit
494	call	sg_scb2ram
495	or	FLAGS, DPHASE			# We have seen a data phase
496
497data_phase_loop:
498# If we are the last SG block, don't set wideodd.
499	cmp	SG_COUNT,0x01 jne data_phase_wideodd
500	and	DMAPARAMS, 0xbf		        # Turn off WIDEODD 
501data_phase_wideodd:
502	mov	DMAPARAMS  call dma
503
504# Exit if we had an underrun
505	test	SSTAT0,0x04	jz data_phase_finish	# underrun STCNT != 0
506
507#  Advance the scatter-gather pointers if needed 
508#
509sg_advance:
510	dec	SG_COUNT			# one less segment to go
511
512	test	SG_COUNT, 0xff	jz data_phase_finish #Are we done?
513
514	clr	A				# add sizeof(struct scatter)
515	add	SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
516	adc	SG_NEXT+1,A,SG_NEXT+1
517	adc	SG_NEXT+2,A,SG_NEXT+2
518	adc	SG_NEXT+3,A,SG_NEXT+3
519
520#  Load a struct scatter and set up the data address and length.
521#  If the working value of the SG count is nonzero, then
522#  we need to load a new set of values.
523#
524#  This, like all DMA's, assumes a little-endian host data storage.
525#
526sg_load:
527	clr	HCNT+2
528	clr	HCNT+1
529	mvi	HCNT+0,SG_SIZEOF
530
531	mvi	DINDEX,HADDR
532	mvi	SG_NEXT		call bcopy_4
533
534	mvi	DFCNTRL,0xd			# HDMAEN|DIRECTION|FIFORESET
535
536#  Wait for DMA from host memory to data FIFO to complete, then disable
537#  DMA and wait for it to acknowledge that it's off.
538#
539	call	dma_finish
540
541#  Copy data from FIFO into SCB data pointer and data count.  This assumes
542#  that the struct scatterlist has this structure (this and sizeof(struct
543#  scatterlist) == 12 are asserted in aic7xxx.c):
544#
545#	struct scatterlist {
546#		char *address;		/* four bytes, little-endian order */
547#		...			/* four bytes, ignored */
548#		unsigned short length;	/* two bytes, little-endian order */
549#	}
550#
551
552# Not in FreeBSD.  the scatter list entry is only 8 bytes.
553# 
554# struct ahc_dma_seg {
555#       physaddr addr;                  /* four bytes, little-endian order */
556#       long    len;                    /* four bytes, little endian order */   
557# };
558#
559
560	mvi	DINDEX,HADDR
561	call	bcopy_7_dfdat
562
563# For Linux, we must throw away four bytes since there is a 32bit gap
564# in the middle of a struct scatterlist
565#	call	bcopy_4_dfdat
566#	mov	NONE,DFDAT
567#	mov	NONE,DFDAT
568#	mov	NONE,DFDAT
569#	mov	NONE,DFDAT
570#	call	bcopy_3_dfdat		#Only support 24 bit length.
571
572# Load STCNT as well.  It is a mirror of HCNT
573	mvi	DINDEX,STCNT
574	mvi	HCNT	call bcopy_3
575        test    SSTAT1,PHASEMIS  jz data_phase_loop
576
577data_phase_finish:
578#  After a DMA finishes, save the SG and STCNT residuals back into the SCB
579#  We use STCNT instead of HCNT, since it's a reflection of how many bytes 
580#  were transferred on the SCSI (as opposed to the host) bus.
581#
582	mvi	DINDEX,SCBARRAY+15
583	mvi	STCNT		call bcopy_3
584	mov	SCBARRAY+18, SG_COUNT
585	jmp	ITloop
586
587#  Command phase.  Set up the DMA registers and let 'er rip - the
588#  two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
589#  so we can copy those three bytes directly into HCNT.
590#
591p_command:
592	mvi	0x80		call scsisig	# CDO|!IOO|!MSGO
593	call	assert
594
595# Load HADDR and HCNT.  We can do this in one bcopy since they are neighbors
596	mvi	DINDEX,HADDR
597	mvi	SCBARRAY+7	call bcopy_7
598
599	mvi	DINDEX,STCNT
600	mvi	SCBARRAY+11	call bcopy_3
601
602	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
603						#   DIRECTION|FIFORESET
604	jmp	ITloop
605
606#  Status phase.  Wait for the data byte to appear, then read it
607#  and store it into the SCB.
608#
609p_status:
610	mvi	0xc0		call scsisig	# CDO|IOO|!MSGO
611
612	mvi	SCBARRAY+14	call inb_first
613	jmp	p_mesgin_done
614
615#  Message out phase.  If there is no active message, but the target
616#  took us into this phase anyway, build a no-op message and send it.
617#
618p_mesgout:
619	mvi	0xa0		call scsisig	# CDO|!IOO|MSGO
620	mvi	0x8		call mk_mesg	# build NOP message
621
622	clr     STCNT+2
623	clr     STCNT+1
624
625#  Set up automatic PIO transfer from MSG_START.  Bit 3 in
626#  SXFRCTL0 (SPIOEN) is already on.
627#
628	mvi	SINDEX,MSG_START+0
629	mov	DINDEX,MSG_LEN
630
631#  When target asks for a byte, drop ATN if it's the last one in
632#  the message.  Otherwise, keep going until the message is exhausted.
633#  (We can't use outb for this since it wants the input in SINDEX.)
634#
635#  Keep an eye out for a phase change, in case the target issues
636#  a MESSAGE REJECT.
637#
638p_mesgout2:
639	test	SSTAT0,0x2	jz p_mesgout2	# SPIORDY
640	test	SSTAT1,0x10	jnz p_mesgout6	# PHASEMIS
641
642	cmp	DINDEX,1	jne p_mesgout3	# last byte?
643	mvi	CLRSINT1,0x40			# CLRATNO - drop ATN
644
645#  Write a byte to the SCSI bus.  The AIC-7770 refuses to automatically
646#  send ACKs in automatic PIO or DMA mode unless you make sure that the
647#  "expected" bus phase in SCSISIGO matches the actual bus phase.  This
648#  behaviour is completely undocumented and caused me several days of
649#  grief.
650#
651#  After plugging in different drives to test with and using a longer
652#  SCSI cable, I found that I/O in Automatic PIO mode ceased to function,
653#  especially when transferring >1 byte.  It seems to be much more stable
654#  if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is
655#  polled for transfer completion - for both output _and_ input.  The
656#  only theory I have is that SPIORDY doesn't drop right away when SCSIDATL
657#  is accessed (like the documentation says it does), and that on a longer
658#  cable run, the sequencer code was fast enough to loop back and see
659#  an SPIORDY that hadn't dropped yet.
660#
661p_mesgout3:
662	mvi	STCNT+0, 0x01	
663	mov	SCSIDATL,SINDIR
664
665p_mesgout4:
666	test	SSTAT0,0x4	jz p_mesgout4	# SDONE
667	dec	DINDEX
668	test	DINDEX,0xff	jnz p_mesgout2
669
670#  If the next bus phase after ATN drops is a message out, it means
671#  that the target is requesting that the last message(s) be resent.
672#
673p_mesgout5:
674	test	SSTAT1,0x8	jnz p_mesgout6	# BUSFREE
675	test	SSTAT1,0x1	jz p_mesgout5	# REQINIT
676
677	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
678	cmp	A,0xa0		jne p_mesgout6
679	mvi	0x10		call scsisig	# ATNO - re-assert ATN
680
681	jmp	ITloop
682
683p_mesgout6:
684	mvi	CLRSINT1,0x40			# CLRATNO - in case of PHASEMIS
685	and	FLAGS,0xdf			# no active msg
686	jmp	ITloop
687
688#  Message in phase.  Bytes are read using Automatic PIO mode, but not
689#  using inb.  This alleviates a race condition, namely that if ATN had
690#  to be asserted under Automatic PIO mode, it had to beat the SCSI
691#  circuitry sending an ACK to the target.  This showed up under heavy
692#  loads and really confused things, since ABORT commands wouldn't be
693#  seen by the drive after an IDENTIFY message in until it had changed
694#  to a data I/O phase.
695#
696p_mesgin:
697	mvi	0xe0		call scsisig	# CDO|IOO|MSGO
698	mvi	A		call inb_first	# read the 1st message byte
699	mvi	REJBYTE,A			# save it for the driver
700
701	cmp	ALLZEROS,A	jne p_mesgin1
702
703#  We got a "command complete" message, so put the SCB pointer
704#  into the Queue Out, and trigger a completion interrupt.
705#  Check status for non zero return and interrupt driver if needed
706#  This allows the driver to interpret errors only when they occur
707#  instead of always uploading the scb.  If the status is SCSI_CHECK,
708#  the driver will download a new scb requesting sense to replace
709#  the old one, modify the "waiting for selection" SCB list and set 
710#  RETURN_1 to 0x80.  If RETURN_1 is set to 0x80 the sequencer imediately
711#  jumps to main loop where it will run down the waiting SCB list.
712#  If the kernel driver does not wish to request sense, it need
713#  only clear RETURN_1, and the command is allowed to complete.  We don't 
714#  bother to post to the QOUTFIFO in the error case since it would require 
715#  extra work in the kernel driver to ensure that the entry was removed 
716#  before the command complete code tried processing it.
717
718# First check for residuals
719	test	SCBARRAY+18,0xff	jnz resid
720
721check_status:
722	test	SCBARRAY+14,0xff	jz status_ok	# 0 Status?
723	mvi	INTSTAT,BAD_STATUS			# let driver know
724	test	RETURN_1, 0x80	jz status_ok
725	jmp	p_mesgin_done
726
727status_ok:
728#  First, mark this target as free.
729	test	SCBARRAY+0,TAG_ENB	jnz complete		# Tagged command
730	and	FUNCTION1,0x70,SCBARRAY+1
731	mov	A,FUNCTION1
732	test	SCBARRAY+1,0x88 jz clear_a
733	xor	ACTIVE_B,A
734	jmp	complete
735
736clear_a:
737	xor	ACTIVE_A,A
738
739	test    SCBARRAY+11,0xff jnz complete  # Immediate message complete
740# Pause the sequencer until the driver gets around to handling the command
741# complete.  This is so that any action that might require carefull timing
742# with the completion of this command can occur.
743	mvi	INTSTAT,IMMEDDONE
744	jmp	poll_for_work
745complete:
746	mov	QOUTFIFO,SCBPTR
747	mvi	INTSTAT,CMDCMPLT
748	jmp	p_mesgin_done
749
750# If we have a residual count, interrupt and tell the host.  Other
751# alternatives are to pause the sequencer on all command completes (yuck),
752# dma the resid directly to the host (slick, but a ton of instructions), or
753# have the sequencer pause itself when it encounters a non-zero resid 
754# (unecessary pause just to flag the command -- yuck, but takes few instructions
755# and since it shouldn't happen that often is good enough for our purposes).  
756
757resid:
758	mvi	INTSTAT,RESIDUAL
759	jmp	check_status
760
761#  Is it an extended message?  We only support the synchronous and wide data
762#  transfer request messages, which will probably be in response to
763#  WDTR or SDTR message outs from us.  If it's not SDTR or WDTR, reject it -
764#  apparently this can be done after any message in byte, according
765#  to the SCSI-2 spec.
766#
767p_mesgin1:
768	cmp	A,1		jne p_mesgin2	# extended message code?
769	
770	mvi	ARG_1		call inb_next	# extended message length
771	mvi	A		call inb_next	# extended message code
772
773	cmp	A,1		je p_mesginSDTR	# Syncronous negotiation message
774	cmp	A,3		je p_mesginWDTR # Wide negotiation message
775	jmp	p_mesginN
776
777p_mesginWDTR:
778	cmp	ARG_1,2		jne p_mesginN	# extended mesg length = 2
779	mvi	A		call inb_next	# Width of bus
780	mvi	INTSTAT,MSG_WDTR		# let driver know
781	test	RETURN_1,0x80	jz p_mesgin_done# Do we need to send WDTR?
782
783# We didn't initiate the wide negotiation, so we must respond to the request
784	and	RETURN_1,0x7f			# Clear the SEND_WDTR Flag
785	or	FLAGS,ACTIVE_MSG
786	mvi	DINDEX,MSG_START+0
787	mvi	MSG_START+0	call mk_wdtr	# build WDTR message	
788	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
789	call	scsisig
790	jmp	p_mesgin_done
791
792p_mesginSDTR:
793	cmp	ARG_1,3		jne p_mesginN	# extended mesg length = 3
794	mvi	ARG_1		call inb_next	# xfer period
795	mvi	A		call inb_next	# REQ/ACK offset
796	mvi	INTSTAT,MSG_SDTR		# call driver to convert
797
798	test	RETURN_1,0xc0	jz p_mesgin_done# Do we need to mk_sdtr or rej?
799	test	RETURN_1,0x40	jnz p_mesginN	# Requested SDTR too small - rej
800	or	FLAGS,ACTIVE_MSG
801	mvi	DINDEX, MSG_START+0
802	mvi     MSG_START+0     call mk_sdtr
803	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
804	call	scsisig
805	jmp	p_mesgin_done
806
807#  Is it a disconnect message?  Set a flag in the SCB to remind us
808#  and await the bus going free.
809#
810p_mesgin2:
811	cmp	A,4		jne p_mesgin3	# disconnect code?
812
813	or	SCBARRAY+0,DISCONNECTED
814	jmp	p_mesgin_done
815
816#  Save data pointers message?  Copy working values into the SCB,
817#  usually in preparation for a disconnect.
818#
819p_mesgin3:
820	cmp	A,2		jne p_mesgin4	# save data pointers code?
821
822	call	sg_ram2scb
823	jmp	p_mesgin_done
824
825#  Restore pointers message?  Data pointers are recopied from the
826#  SCB anytime we enter a data phase for the first time, so all
827#  we need to do is clear the DPHASE flag and let the data phase
828#  code do the rest.
829#
830p_mesgin4:
831	cmp	A,3		jne p_mesgin5	# restore pointers code?
832
833	and	FLAGS,0xfb			# !DPHASE we'll reload them
834						#   the next time through
835	jmp	p_mesgin_done
836
837#  Identify message?  For a reconnecting target, this tells us the lun
838#  that the reconnection is for - find the correct SCB and switch to it,
839#  clearing the "disconnected" bit so we don't "find" it by accident later.
840#
841p_mesgin5:
842	test	A,0x80		jz p_mesgin6	# identify message?
843
844	test	A,0x78		jnz p_mesginN	# !DiscPriv|!LUNTAR|!Reserved
845
846	and	A,0x07				# lun in lower three bits
847	or      SAVED_TCL,A,SELID          
848	and     SAVED_TCL,0xf7
849	and     A,0x08,SBLKCTL			# B Channel??
850	or      SAVED_TCL,A
851	call	inb_last			# ACK
852	mov	ALLZEROS	call findSCB    
853setup_SCB:
854	and	SCBARRAY+0,0xfb			# clear disconnect bit in SCB
855	or	FLAGS,IDENTIFY_SEEN		# make note of IDENTIFY
856
857	jmp	ITloop
858get_tag:
859	mvi	A		call inb_first
860	cmp	A,0x20  	jne return	# Simple Tag message?
861	mvi	A		call inb_next
862	call			inb_last
863	test	A,0xf0		jnz abort_tag	# Tag in range?
864	mov	SCBPTR,A
865	mov	A,SAVED_TCL
866	cmp	SCBARRAY+1,A		jne abort_tag
867	test	SCBARRAY+0,TAG_ENB	jz  abort_tag
868	ret
869abort_tag:
870	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
871	call	scsisig
872	mvi	INTSTAT,ABORT_TAG 		# let driver know
873	mvi	0xd		call mk_mesg	# ABORT TAG message
874	ret
875
876#  Message reject?  Let the kernel driver handle this.  If we have an 
877#  outstanding WDTR or SDTR negotiation, assume that it's a response from 
878#  the target selecting 8bit or asynchronous transfer, otherwise just ignore 
879#  it since we have no clue what it pertains to.
880#
881p_mesgin6:
882	cmp	A,7		jne p_mesgin7	# message reject code?
883
884	mvi	INTSTAT, MSG_REJECT
885	jmp	p_mesgin_done
886
887#  [ ADD MORE MESSAGE HANDLING HERE ]
888#
889p_mesgin7:
890
891#  We have no idea what this message in is, and there's no way
892#  to pass it up to the kernel, so we issue a message reject and
893#  hope for the best.  Since we're now using manual PIO mode to
894#  read in the message, there should no longer be a race condition
895#  present when we assert ATN.  In any case, rejection should be a
896#  rare occurrence - signal the driver when it happens.
897#
898p_mesginN:
899	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
900	call	scsisig
901	mvi	INTSTAT,SEND_REJECT		# let driver know
902
903	mvi	0x7		call mk_mesg	# MESSAGE REJECT message
904
905p_mesgin_done:
906	call	inb_last			# ack & turn auto PIO back on
907	jmp	ITloop
908
909
910#  Bus free phase.  It might be useful to interrupt the device
911#  driver if we aren't expecting this.  For now, make sure that
912#  ATN isn't being asserted and look for a new command.
913#
914p_busfree:
915	mvi	CLRSINT1,0x40			# CLRATNO
916	clr	SIGSTATE
917
918#  if this is an immediate command, perform a psuedo command complete to
919#  notify the driver.
920	test	SCBARRAY+11,0xff	jz status_ok
921	jmp	poll_for_work
922
923#  Instead of a generic bcopy routine that requires an argument, we unroll
924#  the cases that are actually used, and call them explicitly.  This
925#  not only reduces the overhead of doing a bcopy, but ends up saving space 
926#  in the program since you don't have to put the argument into the accumulator
927#  before the call.  Both functions expect DINDEX to contain the destination 
928#  address and SINDEX to contain the source address.
929bcopy_7:
930	mov	DINDIR,SINDIR
931	mov	DINDIR,SINDIR
932bcopy_5:
933	mov	DINDIR,SINDIR
934bcopy_4:
935	mov	DINDIR,SINDIR
936bcopy_3:
937	mov	DINDIR,SINDIR
938	mov	DINDIR,SINDIR
939	mov	DINDIR,SINDIR	ret
940	
941bcopy_7_dfdat:
942	mov	DINDIR,DFDAT
943	mov	DINDIR,DFDAT
944bcopy_5_dfdat:
945	mov	DINDIR,DFDAT
946bcopy_4_dfdat:
947	mov	DINDIR,DFDAT
948bcopy_3_dfdat:
949	mov	DINDIR,DFDAT
950	mov	DINDIR,DFDAT
951	mov	DINDIR,DFDAT	ret
952
953#  Locking the driver out, build a one-byte message passed in SINDEX
954#  if there is no active message already.  SINDEX is returned intact.
955#
956mk_mesg:
957	mvi	SEQCTL,0x50			# PAUSEDIS|FASTMODE
958	test	FLAGS,ACTIVE_MSG jnz mk_mesg1	# active message?
959
960	or	FLAGS,ACTIVE_MSG		# if not, there is now
961	mvi	MSG_LEN,1			# length = 1
962	mov	MSG_START+0,SINDEX		# 1-byte message
963
964mk_mesg1:
965	mvi	SEQCTL,0x10	ret		# !PAUSEDIS|FASTMODE
966
967#  Carefully read data in Automatic PIO mode.  I first tried this using
968#  Manual PIO mode, but it gave me continual underrun errors, probably
969#  indicating that I did something wrong, but I feel more secure leaving
970#  Automatic PIO on all the time.
971#
972#  According to Adaptec's documentation, an ACK is not sent on input from
973#  the target until SCSIDATL is read from.  So we wait until SCSIDATL is
974#  latched (the usual way), then read the data byte directly off the bus
975#  using SCSIBUSL.  When we have pulled the ATN line, or we just want to
976#  acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
977#  spec guarantees that the target will hold the data byte on the bus until
978#  we send our ACK.
979#
980#  The assumption here is that these are called in a particular sequence,
981#  and that REQ is already set when inb_first is called.  inb_{first,next}
982#  use the same calling convention as inb.
983#
984inb_first:
985	clr	STCNT+2
986	clr	STCNT+1
987	mov	DINDEX,SINDEX
988	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
989
990inb_next:
991	mov	DINDEX,SINDEX			# save SINDEX
992
993        mvi     STCNT+0,1			# xfer one byte
994	mov	NONE,SCSIDATL			# dummy read from latch to ACK
995inb_next1:
996	test	SSTAT0,0x4	jz inb_next1	# SDONE
997inb_next2:
998	test	SSTAT0,0x2	jz inb_next2	# SPIORDY - wait for next byte
999	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
1000
1001inb_last:
1002	mvi	STCNT+0,1			# ACK with dummy read
1003	mov	NONE,SCSIDATL
1004inb_last1:
1005	test	SSTAT0,0x4	jz inb_last1	# wait for completion
1006	ret
1007
1008#  DMA data transfer.  HADDR and HCNT must be loaded first, and
1009#  SINDEX should contain the value to load DFCNTRL with - 0x3d for
1010#  host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
1011#  during initialization.
1012#
1013dma:
1014	mov	DFCNTRL,SINDEX
1015dma1:
1016	test	SSTAT0,0x1	jnz dma3	# DMADONE
1017	test	SSTAT1,0x10	jz dma1		# PHASEMIS, ie. underrun
1018
1019#  We will be "done" DMAing when the transfer count goes to zero, or
1020#  the target changes the phase (in light of this, it makes sense that
1021#  the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
1022#  doing a SCSI->Host transfer, the data FIFO should be flushed auto-
1023#  magically on STCNT=0 or a phase change, so just wait for FIFO empty
1024#  status.
1025#
1026dma3:
1027	test	SINDEX,0x4	jnz dma5	# DIRECTION
1028dma4:
1029	test	DFSTATUS,0x1	jz dma4		# !FIFOEMP
1030
1031#  Now shut the DMA enables off and make sure that the DMA enables are 
1032#  actually off first lest we get an ILLSADDR.
1033#
1034dma5:
1035	clr	DFCNTRL				# disable DMA
1036dma6:
1037	test	DFCNTRL,0x38	jnz dma6	# SCSIENACK|SDMAENACK|HDMAENACK
1038
1039	ret
1040
1041dma_finish:
1042	test	DFSTATUS,0x8	jz dma_finish	# HDONE
1043
1044	clr	DFCNTRL				# disable DMA
1045dma_finish2:
1046	test	DFCNTRL,0x8	jnz dma_finish2	# HDMAENACK
1047	ret
1048
1049#  Common SCSI initialization for selection and reselection.  Expects
1050#  the target SCSI ID to be in the upper four bits of SINDEX, and A's
1051#  contents are stomped on return.
1052#
1053initialize_scsiid:
1054	and	SINDEX,0xf0		# Get target ID
1055	and	A,0x0f,SCSIID
1056	or	SINDEX,A
1057	mov	SCSIID,SINDEX ret
1058
1059initialize_for_target:
1060#  Turn on Automatic PIO mode now, before we expect to see a REQ
1061#  from the target.  It shouldn't hurt anything to leave it on.  Set
1062#  CLRCHN here before the target has entered a data transfer mode -
1063#  with synchronous SCSI, if you do it later, you blow away some
1064#  data in the SCSI FIFO that the target has already sent to you.
1065#
1066	clr	SIGSTATE 
1067
1068	mvi	SXFRCTL0,0x8a			# DFON|SPIOEN|CLRCHN
1069
1070#  Make sure that the system knows we have not been through a DATA
1071#  phase.
1072	and	FLAGS, 0xfb			# !DPHASE
1073
1074#  Initialize SCSIRATE with the appropriate value for this target.
1075#
1076	call	ndx_dtr
1077	mov	SCSIRATE,SINDIR	ret
1078
1079#  Assert that if we've been reselected, then we've seen an IDENTIFY
1080#  message.
1081#
1082assert:
1083	test	FLAGS,RESELECTED	jz return	# reselected?
1084	test	FLAGS,IDENTIFY_SEEN	jnz return	# seen IDENTIFY?
1085
1086	mvi	INTSTAT,NO_IDENT 	ret	# no - cause a kernel panic
1087
1088#  Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch 
1089#  the SCB to it.  Have the kernel print a warning message if it can't be 
1090#  found, and generate an ABORT message to the target.  SINDEX should be
1091#  cleared on call.
1092#
1093findSCB:
1094	mov	A,SAVED_TCL
1095	mov	SCBPTR,SINDEX			# switch to new SCB
1096	cmp	SCBARRAY+1,A	jne findSCB1	# target ID/channel/lun match?
1097	test	SCBARRAY+0,DISCONNECTED	jz findSCB1 # should be disconnected
1098	test	SCBARRAY+0,TAG_ENB jnz get_tag
1099	ret
1100
1101findSCB1:
1102	inc	SINDEX
1103	mov	A,SCBCOUNT
1104	cmp	SINDEX,A	jne findSCB
1105
1106	mvi	INTSTAT,NO_MATCH		# not found - signal kernel
1107	mvi	0x6		call mk_mesg	# ABORT message
1108
1109	or	SINDEX,0x10,SIGSTATE		# assert ATNO
1110	call	scsisig
1111	ret
1112
1113#  Make a working copy of the scatter-gather parameters from the SCB.
1114#
1115sg_scb2ram:
1116	mvi	DINDEX,HADDR
1117	mvi	SCBARRAY+19	call bcopy_7
1118
1119	mvi	DINDEX,STCNT
1120	mvi	SCBARRAY+23	call bcopy_3
1121
1122	mov	SG_COUNT,SCBARRAY+2
1123
1124	mvi	DINDEX,SG_NEXT
1125	mvi	SCBARRAY+3	call bcopy_4
1126	ret
1127
1128#  Copying RAM values back to SCB, for Save Data Pointers message, but
1129#  only if we've actually been into a data phase to change them.  This
1130#  protects against bogus data in scratch ram and the residual counts
1131#  since they are only initialized when we go into data_in or data_out.
1132#
1133sg_ram2scb:
1134	test	FLAGS, DPHASE	jz return
1135	mov	SCBARRAY+2,SG_COUNT
1136
1137	mvi	DINDEX,SCBARRAY+3
1138	mvi	SG_NEXT		call bcopy_4
1139	
1140	mvi	DINDEX,SCBARRAY+19
1141	mvi	SHADDR	call bcopy_4
1142
1143# Use the residual number since STCNT is corrupted by any message transfer
1144	mvi	SCBARRAY+15	call bcopy_3
1145	ret
1146
1147#  Add the array base SYNCNEG to the target offset (the target address
1148#  is in SCSIID), and return the result in SINDEX.  The accumulator
1149#  contains the 3->8 decoding of the target ID on return.
1150#
1151ndx_dtr:
1152	shr	A,SCSIID,4
1153	test	SBLKCTL,0x08	jz ndx_dtr_2
1154	or	A,0x08		# Channel B entries add 8
1155ndx_dtr_2:
1156	add	SINDEX,SYNCNEG,A
1157
1158	and	FUNCTION1,0x70,SCSIID		# 3-bit target address decode
1159	mov	A,FUNCTION1	ret
1160
1161#  If we need to negotiate transfer parameters, build the WDTR or SDTR message
1162#  starting at the address passed in SINDEX.  DINDEX is modified on return.
1163#  The SCSI-II spec requires that Wide negotiation occur first and you can
1164#  only negotiat one or the other at a time otherwise in the event of a message
1165#  reject, you wouldn't be able to tell which message was the culpret.
1166#
1167mk_dtr:
1168	test	SCBARRAY+0,0x90 jz return	# NEEDWDTR|NEEDSDTR
1169	test	SCBARRAY+0,NEEDWDTR jnz  mk_wdtr_16bit
1170	or	FLAGS, MAX_OFFSET	# Force an offset of 15 or 8 if WIDE
1171
1172mk_sdtr:
1173	mvi	DINDIR,1			# extended message
1174	mvi	DINDIR,3			# extended message length = 3
1175	mvi	DINDIR,1			# SDTR code
1176	call	sdtr_to_rate
1177	mov	DINDIR,RETURN_1			# REQ/ACK transfer period
1178	test	FLAGS, MAX_OFFSET jnz mk_sdtr_max_offset
1179	and	DINDIR,0x0f,SINDIR		# Sync Offset
1180
1181mk_sdtr_done:
1182	add	MSG_LEN,-MSG_START+0,DINDEX ret	# update message length
1183
1184mk_sdtr_max_offset:
1185# We're initiating sync negotiation, so request the max offset we can (15 or 8)
1186	xor	FLAGS, MAX_OFFSET
1187	test	SCSIRATE, 0x80	jnz wmax_offset	# Talking to a WIDE device?
1188	mvi	DINDIR, MAX_OFFSET_8BIT
1189	jmp	mk_sdtr_done
1190
1191wmax_offset:
1192	mvi	DINDIR, MAX_OFFSET_WIDE
1193	jmp	mk_sdtr_done
1194
1195mk_wdtr_16bit:
1196	mvi	ARG_1,BUS_16_BIT
1197mk_wdtr:
1198	mvi	DINDIR,1			# extended message
1199	mvi	DINDIR,2			# extended message length = 2
1200	mvi	DINDIR,3			# WDTR code
1201	mov	DINDIR,ARG_1			# bus width
1202
1203	add	MSG_LEN,-MSG_START+0,DINDEX ret	# update message length
1204	
1205#  Set SCSI bus control signal state.  This also saves the last-written
1206#  value into a location where the higher-level driver can read it - if
1207#  it has to send an ABORT or RESET message, then it needs to know this
1208#  so it can assert ATN without upsetting SCSISIGO.  The new value is
1209#  expected in SINDEX.  Change the actual state last to avoid contention
1210#  from the driver.
1211#
1212scsisig:
1213	mov	SIGSTATE,SINDEX
1214	mov	SCSISIGO,SINDEX	ret
1215
1216sdtr_to_rate:
1217	call	ndx_dtr				# index scratch space for target
1218	shr	A,SINDIR,0x4
1219	dec	SINDEX				#Preserve SINDEX
1220	and	A,0x7
1221	clr	RETURN_1
1222sdtr_to_rate_loop:
1223	test	A,0x0f	jz sdtr_to_rate_done
1224	add	RETURN_1,0x18
1225	dec	A	
1226	jmp	sdtr_to_rate_loop
1227sdtr_to_rate_done:
1228	shr	RETURN_1,0x2
1229	add	RETURN_1,0x18	ret
1230
1231return:
1232	ret
1233