aic7xxx.seq revision 22451
197883Sgibbs/*+M***********************************************************************
297883Sgibbs *Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
397883Sgibbs *
497883Sgibbs *Copyright (c) 1994 John Aycock
5102681Sgibbs *  The University of Calgary Department of Computer Science.
697883Sgibbs *  All rights reserved.
797883Sgibbs *
897883Sgibbs *FreeBSD, Twin, Wide, 2 command per target support, tagged queuing,
997883Sgibbs *SCB paging and other optimizations:
1097883Sgibbs *Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
1197883Sgibbs *
1297883Sgibbs *Redistribution and use in source and binary forms, with or without
1397883Sgibbs *modification, are permitted provided that the following conditions
1497883Sgibbs *are met:
1597883Sgibbs *1. Redistributions of source code must retain the above copyright
1697883Sgibbs *   notice, this list of conditions, and the following disclaimer.
1797883Sgibbs *2. Redistributions in binary form must reproduce the above copyright
1897883Sgibbs *   notice, this list of conditions and the following disclaimer in the
1997883Sgibbs *   documentation and/or other materials provided with the distribution.
2097883Sgibbs *3. All advertising materials mentioning features or use of this software
2197883Sgibbs *   must display the following acknowledgement:
2297883Sgibbs *     This product includes software developed by the University of Calgary
2397883Sgibbs *     Department of Computer Science and its contributors.
2497883Sgibbs *4. Neither the name of the University nor the names of its contributors
2597883Sgibbs *   may be used to endorse or promote products derived from this software
2697883Sgibbs *   without specific prior written permission.
2797883Sgibbs *
2897883Sgibbs *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2997883Sgibbs *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3097883Sgibbs *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3197883Sgibbs *ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
3297883Sgibbs *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3397883Sgibbs *DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3497883Sgibbs *OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3597883Sgibbs *HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3697883Sgibbs *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3797883Sgibbs *OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3897883Sgibbs *SUCH DAMAGE.
3997883Sgibbs *
4097883Sgibbs *-M************************************************************************/
4197883Sgibbs
42115407SscottlVERSION AIC7XXX_SEQ_VER "$FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 22451 1997-02-09 03:23:28Z gibbs $"
4397883Sgibbs
4497883Sgibbs#if defined(__NetBSD__)
4597883Sgibbs#include "../../../../dev/ic/aic7xxxreg.h"
4697883Sgibbs#include "../../../../scsi/scsi_message.h"
4797883Sgibbs#elif defined(__FreeBSD__)
4897883Sgibbs#include "../../dev/aic7xxx/aic7xxx_reg.h"
4997883Sgibbs#include "../../scsi/scsi_message.h"
5097883Sgibbs#endif
5197883Sgibbs
5297883Sgibbs/*
5397883Sgibbs * We can't just use ACCUM in the sequencer code because it
5497883Sgibbs * must be treated specially by the assembler, and it currently
5597883Sgibbs * looks for the symbol 'A'.  This is the only register defined in
5697883Sgibbs * the assembler's symbol space.
5797883Sgibbs */
5897883SgibbsA = ACCUM
59104023Sgibbs
60104023Sgibbs/*
61104023Sgibbs * A few words on the waiting SCB list:
62104023Sgibbs * After starting the selection hardware, we check for reconnecting targets
63104023Sgibbs * as well as for our selection to complete just in case the reselection wins
64104023Sgibbs * bus arbitration.  The problem with this is that we must keep track of the
65104023Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection
66104023Sgibbs * on just in case the reselection wins so that we can retry the selection at
6797883Sgibbs * a later time.  This problem cannot be resolved by holding a single entry
68104023Sgibbs * in scratch ram since a reconnecting target can request sense and this will
69104023Sgibbs * create yet another SCB waiting for selection.  The solution used here is to 
70104023Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
71104023Sgibbs * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
72104023Sgibbs * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
73104023Sgibbs * this list everytime a request sense occurs or after completing a non-tagged
74104023Sgibbs * command for which a second SCB has been queued.  The sequencer will
75107441Sscottl * automatically consume the entries.
76107441Sscottl */
77107441Sscottl
78107441Sscottl/*
79107441Sscottl * We assume that the kernel driver may reset us at any time, even in the
80107441Sscottl * middle of a DMA, so clear DFCNTRL too.
81104023Sgibbs */
82107441Sscottlreset:
83107441Sscottl	clr	DFCNTRL
84107441Sscottl	clr	SCSISIGO		/* De-assert BSY */
85107441Sscottl
86107441Sscottlp_busfree:
87107441Sscottl	clr	SCSIRATE		/*
88107441Sscottl					 * We don't know the target we will
8997883Sgibbs					 * connect to, so default to narrow
9097883Sgibbs					 * transfers to avoid parity problems.
9197883Sgibbs					 */
9297883Sgibbs	and	SXFRCTL0, 0xdf		/* ~FAST20*/
9397883Sgibbs	mvi	SCSISEQ,ENRSELI		/* Always allow reselection */
9497883Sgibbs	mvi	LASTPHASE, P_BUSFREE
9597883Sgibbs	and	FLAGS,0x07		/* clear target specific flags */
9697883Sgibbspoll_for_work:
9797883Sgibbs	/*
98102681Sgibbs	 * Are we a twin channel device?
99102681Sgibbs	 * For fairness, we check the other bus first,
10097883Sgibbs	 * since we just finished a transaction on the
10197883Sgibbs	 * current channel.
10297883Sgibbs	 */
10397883Sgibbs	test	FLAGS,TWIN_BUS	jz start2
10497883Sgibbs	xor	SBLKCTL,SELBUSB			/* Toggle to the other bus */
10597883Sgibbs	test	SSTAT0,SELDI	jnz reselect
10697883Sgibbs	xor	SBLKCTL,SELBUSB			/* Toggle to the original bus */
10797883Sgibbsstart2:
10897883Sgibbs	test	SSTAT0,SELDI	jnz reselect
10997883Sgibbs	cmp	WAITING_SCBH,SCB_LIST_NULL je test_queue
11097883Sgibbsstart_waiting:
11197883Sgibbs	/*
112102681Sgibbs	 * Pull the first entry off of the waiting SCB list
113102681Sgibbs	 * We don't have to "test_busy" because only transactions that
114102681Sgibbs	 * have passed that test can be in the WAITING_SCB list.
115102681Sgibbs	 */
116102681Sgibbs	mov	SCBPTR,WAITING_SCBH
117102681Sgibbs	jmp	start_scb2
118102681Sgibbstest_queue:
119102681Sgibbs	/* Has the driver posted any work for us? */
12097883Sgibbs	mov	A, QCNTMASK
12197883Sgibbs	test	QINCNT,A	jz poll_for_work
12297883Sgibbs
12397883Sgibbs/*
12497883Sgibbs * We have at least one queued SCB now and we don't have any 
12597883Sgibbs * SCBs in the list of SCBs awaiting selection.  If we have
12697883Sgibbs * any SCBs availible for use, pull the tag from the QINFIFO
12797883Sgibbs * and get to work on it.
12897883Sgibbs */
129102681Sgibbs	test	FLAGS, PAGESCBS	jz	dequeue_scb
130107441Sscottl	mov	ALLZEROS	call	get_free_or_disc_scb
131107441Sscottl	cmp	SINDEX, SCB_LIST_NULL	je poll_for_work
132102681Sgibbsdequeue_scb:
133102681Sgibbs	mov	CUR_SCBID,QINFIFO
134102681Sgibbs	test	FLAGS, PAGESCBS jnz dma_queued_scb
135102681Sgibbs	/* In the non-paging case, the SCBID == hardware SCB index */
136102681Sgibbs	mov	SCBPTR, CUR_SCBID
13797883Sgibbsdma_queued_scb:
13897883Sgibbs/*
13997883Sgibbs * DMA the SCB from host ram into the current SCB location.
14097883Sgibbs */
14197883Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
14297883Sgibbs	mov	CUR_SCBID	call dma_scb
143102681Sgibbs
14497883Sgibbs/*
14597883Sgibbs * See if there is not already an active SCB for this target.  This code
14697883Sgibbs * locks out on a per target basis instead of target/lun.  Although this
14797883Sgibbs * is not ideal for devices that have multiple luns active at the same
14897883Sgibbs * time, it is faster than looping through all SCB's looking for active
14997883Sgibbs * commands.  We also don't have enough spare SCB space for us to store the
15097883Sgibbs * SCBID of the currently busy transaction for each target/lun making it
15197883Sgibbs * impossible to link up the SCBs.
152102681Sgibbs */
153102681Sgibbstest_busy:
15497883Sgibbs	test	SCB_CONTROL, TAG_ENB	jnz start_scb
15597883Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
15697883Sgibbs	mov	SAVED_SCBPTR, SCBPTR
15797883Sgibbs	mov	SCB_TCL		call	index_untagged_scb
158102681Sgibbs	mov	ARG_1, SINDIR			/*
15997883Sgibbs						 * ARG_1 should
16097883Sgibbs						 * now have the SCB ID of
16197883Sgibbs						 * any active, non-tagged,
16297883Sgibbs						 * command for this target.
163102681Sgibbs						 */
16497883Sgibbs	cmp	ARG_1, SCB_LIST_NULL je make_busy
16597883Sgibbs	test	FLAGS, PAGESCBS jz simple_busy_link
16697883Sgibbs	/*
16797883Sgibbs	 * Put this SCB back onto the free list.  It
16897883Sgibbs	 * may be necessary to satisfy the search for
169102681Sgibbs	 * the active SCB.
170102681Sgibbs	 */
171102681Sgibbs	mov	SCBPTR, SAVED_SCBPTR
172102681Sgibbs	call	add_scb_to_free_list
173102681Sgibbs	/* Find the active SCB */
174102681Sgibbs	mov	ALLZEROS	call findSCB
175107441Sscottl	/*
176109588Sgibbs	 * If we couldn't find it, tell the kernel.  This should
177109588Sgibbs	 * never happen.
178109588Sgibbs	 */
179109588Sgibbs	cmp	SINDEX, SCB_LIST_NULL	jne paged_busy_link
180109588Sgibbs	mvi	INTSTAT, NO_MATCH_BUSY
181109588Sgibbspaged_busy_link:
182109588Sgibbs	/* Link us in */
183109588Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
184109588Sgibbs	/* Put it back on the disconnected list */
185109588Sgibbs	call	add_scb_to_disc_list
186109588Sgibbs	mvi	SEQCTL,0x10			/* FASTMODE */
187109588Sgibbs	jmp	poll_for_work
188109588Sgibbssimple_busy_link:
189109588Sgibbs	mov	SCBPTR, ARG_1
190109588Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
191109588Sgibbs	mvi	SEQCTL,0x10			/* FASTMODE */
192109588Sgibbs	jmp	poll_for_work
193107441Sscottlmake_busy:
194107441Sscottl	mov	DINDIR, CUR_SCBID
195107441Sscottl	mov	SCBPTR, SAVED_SCBPTR
196107441Sscottl	mvi	SEQCTL,0x10			/* FASTMODE */
197114623Sgibbs
198114623Sgibbsstart_scb:
199102681Sgibbs	/*
20097883Sgibbs	 * Place us on the waiting list in case our selection
20197883Sgibbs	 * doesn't win during bus arbitration.
20297883Sgibbs	 */
20397883Sgibbs	mov	SCB_NEXT,WAITING_SCBH
20497883Sgibbs	mov	WAITING_SCBH, SCBPTR
20597883Sgibbsstart_scb2:
20697883Sgibbs	and	SINDEX,0xf7,SBLKCTL	/* Clear the channel select bit */
20797883Sgibbs	and	A,0x08,SCB_TCL		/* Get new channel bit */
208102681Sgibbs	or	SINDEX,A
209102681Sgibbs	mov	SBLKCTL,SINDEX		/* select channel */
210102681Sgibbs	mov	SCB_TCL	call initialize_scsiid
211107623Sscottl
212102681Sgibbs/*
213102681Sgibbs * Enable selection phase as an initiator, and do automatic ATN
214102681Sgibbs * after the selection.  We do this now so that we can overlap the
215102681Sgibbs * rest of our work to set up this target with the arbitration and
21697883Sgibbs * selection bus phases.
21797883Sgibbs */
21897883Sgibbsstart_selection:
21997883Sgibbs	mvi	SCSISEQ,0x58		/* ENSELO|ENAUTOATNO|ENRSELI */
22097883Sgibbs
22197883Sgibbs/*
22297883Sgibbs * As soon as we get a successful selection, the target should go
22397883Sgibbs * into the message out phase since we have ATN asserted.  Prepare
224102681Sgibbs * the message to send.
225102681Sgibbs *
226102681Sgibbs * Messages are stored in scratch RAM starting with a length byte
227102681Sgibbs * followed by the message itself.
228102681Sgibbs */
229102681Sgibbs
230102681Sgibbsmk_identify:
23197883Sgibbs	and	MSG0,0x7,SCB_TCL	/* lun */
23297883Sgibbs	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privledge */
23397883Sgibbs	or	MSG0,A			/* or in disconnect privledge */
23497883Sgibbs	or	MSG0,MSG_IDENTIFYFLAG
23597883Sgibbs	mvi	MSG_LEN, 1
23697883Sgibbs
23797883Sgibbs/*
23897883Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
239102681Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
240102681Sgibbs */
241102681Sgibbsmk_tag:
242102681Sgibbs	test	SCB_CONTROL,TAG_ENB jz  mk_message
243102681Sgibbs	and	MSG1,0x23,SCB_CONTROL
244102681Sgibbs	mov	MSG2,SCB_TAG
245102681Sgibbs	add	MSG_LEN,2	/* update message length */
24697883Sgibbs
24797883Sgibbs/*
24897883Sgibbs * Interrupt the driver, and allow it to tweak the message buffer
24997883Sgibbs * if it asks.
25097883Sgibbs */
25197883Sgibbsmk_message:
25297883Sgibbs	test	SCB_CONTROL,MK_MESSAGE  jz wait_for_selection
25397883Sgibbs
25497883Sgibbs	mvi     INTSTAT,AWAITING_MSG
255102681Sgibbs
256102681Sgibbswait_for_selection:
257102681Sgibbs	test	SSTAT0,SELDO	jnz select 
258102681Sgibbs	test	SSTAT0,SELDI	jz wait_for_selection
259102681Sgibbs
260102681Sgibbs/*
261102681Sgibbs * Reselection has been initiated by a target. Make a note that we've been
262102681Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
26397883Sgibbs */
26497883Sgibbsreselect:
26597883Sgibbs	clr	MSG_LEN		/* Don't have anything in the mesg buffer */
26697883Sgibbs	/* XXX test for and handle ONE BIT condition */
26797883Sgibbs	and	SAVED_TCL, 0xf0, SELID
26897883Sgibbs	or	FLAGS,RESELECTED
26997883Sgibbs	jmp	select2
27097883Sgibbs
27197883Sgibbs/*
27297883Sgibbs * After the selection, remove this SCB from the "waiting SCB"
27397883Sgibbs * list.  This is achieved by simply moving our "next" pointer into
27497883Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
27597883Sgibbs * SCB is used, so don't bother with it now.
27697883Sgibbs */
27797883Sgibbsselect:
27897883Sgibbs	mov	WAITING_SCBH,SCB_NEXT
27997883Sgibbsselect2:
28097883Sgibbs	/* Turn off the selection hardware */
28197883Sgibbs	mvi	SCSISEQ,ENAUTOATNP		/*
28297883Sgibbs						 * ATN on parity errors
28397883Sgibbs						 * for "in" phases
28497883Sgibbs						 */
28597883Sgibbs	mvi	CLRSINT0,0x60			/* CLRSELDI|CLRSELDO */
286109588Sgibbs	mvi	CLRSINT1,CLRBUSFREE
28797883Sgibbs	or	SIMODE1, ENBUSFREE		/*
28897883Sgibbs						 * We aren't expecting a
289115329Sgibbs						 * bus free, so interrupt
29097883Sgibbs						 * the kernel driver if it
29197883Sgibbs						 * happens.
29297883Sgibbs						 */
29397883Sgibbs/*
29497883Sgibbs * Initialize Ultra mode setting and clear the SCSI channel.
29597883Sgibbs */
296109588Sgibbs	or	SXFRCTL0, 0x1a			/* CLRSTCNT|SPIOEN|CLRCHN */
29797883Sgibbsultra:
298102681Sgibbs	mvi	SINDEX, ULTRA_ENB_B
299102681Sgibbs	test	SAVED_TCL, 0x80		jnz ultra_2	/* Target ID > 7 */
300102681Sgibbs	test	SBLKCTL, SELBUSB	jnz ultra_2	/* Second channel */
301102681Sgibbs	dec	SINDEX
302102681Sgibbsultra_2:
30397883Sgibbs	mov     FUNCTION1,SAVED_TCL
30497883Sgibbs	mov     A,FUNCTION1
30597883Sgibbs	test	SINDIR, A	jz ndx_dtr
30697883Sgibbs	or	SXFRCTL0, FAST20
30797883Sgibbs 
30897883Sgibbs/*
309109588Sgibbs * Initialize SCSIRATE with the appropriate value for this target.
31097883Sgibbs * The SCSIRATE settings for each target are stored in an array
311102681Sgibbs * based at TARG_SCRATCH.
312102681Sgibbs */
313102681Sgibbsndx_dtr:
314102681Sgibbs	shr	A,SAVED_TCL,4
315102681Sgibbs	test	SBLKCTL,SELBUSB	jz ndx_dtr_2
31697883Sgibbs	or	SAVED_TCL, SELBUSB /* Add the channel bit while we're here */
31797883Sgibbs	or	A,0x08		/* Channel B entries add 8 */
31897883Sgibbsndx_dtr_2:
31997883Sgibbs	add	SINDEX,TARG_SCRATCH,A
32097883Sgibbs	mov	SCSIRATE,SINDIR
32197883Sgibbs
322109588Sgibbs
32397883Sgibbs/*
32497883Sgibbs * Main loop for information transfer phases.  If BSY is false, then
32597883Sgibbs * we have a bus free condition, expected or not.  Otherwise, wait
32697883Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O
32797883Sgibbs * for the bus phase.
32897883Sgibbs *
32997883Sgibbs */
33097883SgibbsITloop:
33197883Sgibbs	test	SSTAT1,0x9	jz ITloop	/* REQINIT|BUSFREE */
33297883Sgibbs	test	SSTAT1,BUSFREE	jnz p_busfree
33397883Sgibbs
33497883Sgibbs	and	A,PHASE_MASK,SCSISIGI
33597883Sgibbs	mov	LASTPHASE,A
33697883Sgibbs	mov	SCSISIGO,A
33797883Sgibbs
33897883Sgibbs	cmp	ALLZEROS,A	je p_dataout
33997883Sgibbs	cmp	A,P_DATAIN	je p_datain
34097883Sgibbs	cmp	A,P_COMMAND	je p_command
34197883Sgibbs	cmp	A,P_MESGOUT	je p_mesgout
34297883Sgibbs	cmp	A,P_STATUS	je p_status
34397883Sgibbs	cmp	A,P_MESGIN	je p_mesgin
34497883Sgibbs
34597883Sgibbs	mvi	INTSTAT,BAD_PHASE	/* unknown phase - signal driver */
34697883Sgibbs	jmp	ITloop			/* Try reading the bus again. */
34797883Sgibbs
34897883Sgibbsp_dataout:
34997883Sgibbs	mvi	DMAPARAMS,0x7d			/*
35097883Sgibbs						 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
35197883Sgibbs						 * DIRECTION|FIFORESET
35297883Sgibbs						 */
35397883Sgibbs	jmp	data_phase_init
35497883Sgibbs
35597883Sgibbs/*
35697883Sgibbs * If we re-enter the data phase after going through another phase, the
35797883Sgibbs * STCNT may have been cleared, so restore it from the residual field.
35897883Sgibbs */
35997883Sgibbsdata_phase_reinit:
36097883Sgibbs	mvi	DINDEX, STCNT0
36197883Sgibbs	mvi	SCB_RESID_DCNT0	call bcopy_3
36297883Sgibbs	jmp	data_phase_loop
363102681Sgibbs
364102681Sgibbsp_datain:
365102681Sgibbs	mvi	DMAPARAMS,0x79		/*
366102681Sgibbs					 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
367102681Sgibbs					 * !DIRECTION|FIFORESET
368102681Sgibbs					 */
369102681Sgibbsdata_phase_init:
370102681Sgibbs	call	assert			/*
371102681Sgibbs					 * Ensure entering a data
372102681Sgibbs					 * phase is okay - seen identify, etc.
373102681Sgibbs					 */
374102681Sgibbs
375102681Sgibbs	test	FLAGS, DPHASE	jnz data_phase_reinit
376102681Sgibbs
377102681Sgibbs	/*
378102681Sgibbs	 * Initialize the DMA address and counter from the SCB.
379102681Sgibbs	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
380102681Sgibbs	 * modify the values in the SCB itself until we see a
381102681Sgibbs	 * save data pointers message.
38297883Sgibbs	 */
38397883Sgibbs	mvi	DINDEX, HADDR0
38497883Sgibbs	mvi	SCB_DATAPTR	call bcopy_7
38597883Sgibbs
38697883Sgibbs	call	set_stcnt_from_hcnt
38797883Sgibbs
38897883Sgibbs	mov	SG_COUNT,SCB_SGCOUNT
38997883Sgibbs
390102681Sgibbs	mvi	DINDEX, SG_NEXT
391102681Sgibbs	mvi	SCB_SGPTR	call bcopy_4
392102681Sgibbs
393102681Sgibbs	/* We have seen a data phase */
394102681Sgibbs	or	FLAGS, DPHASE
395102681Sgibbs
396102681Sgibbsdata_phase_loop:
397102681Sgibbs/* Guard against overruns */
39897883Sgibbs	test	SG_COUNT, 0xff jnz data_phase_inbounds
39997883Sgibbs/*
40097883Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to
40197883Sgibbs * 16meg and let the target run until it changes phase.
40297883Sgibbs * When the transfer completes, notify the host that we
40397883Sgibbs * had an overrun.
40497883Sgibbs */
40597883Sgibbs	or	SXFRCTL1,BITBUCKET
40697883Sgibbs	mvi	HCNT0, 0xff
407102681Sgibbs	mvi	HCNT1, 0xff
408107441Sscottl	mvi	HCNT2, 0xff
409102681Sgibbs	call	set_stcnt_from_hcnt
410102681Sgibbs
411102681Sgibbsdata_phase_inbounds:
412102681Sgibbs/* If we are the last SG block, ensure wideodd is off. */
413102681Sgibbs	cmp	SG_COUNT,0x01 jne data_phase_wideodd
414102681Sgibbs	and	DMAPARAMS, 0xbf		/* Turn off WIDEODD */
415102681Sgibbsdata_phase_wideodd:
416102681Sgibbs	mov	DMAPARAMS  call dma
417102681Sgibbs
41897883Sgibbs/* Go tell the host about any overruns */
41997883Sgibbs	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun
42097883Sgibbs
42197883Sgibbs/* Exit if we had an underrun.  dma clears SINDEX in this case. */
42297883Sgibbs	test	SINDEX,0xff	jz data_phase_finish
42397883Sgibbs
42497883Sgibbs/*
42597883Sgibbs * Advance the scatter-gather pointers if needed 
42697883Sgibbs */
427102681Sgibbssg_advance:
428102681Sgibbs	dec	SG_COUNT	/* one less segment to go */
429102681Sgibbs
430102681Sgibbs	test	SG_COUNT, 0xff	jz data_phase_finish /* Are we done? */
431102681Sgibbs
432102681Sgibbs	clr	A			/* add sizeof(struct scatter) */
43397883Sgibbs	add	SG_NEXT0,SG_SIZEOF,SG_NEXT0
43497883Sgibbs	adc	SG_NEXT1,A,SG_NEXT1
43597883Sgibbs
43697883Sgibbs/*
43797883Sgibbs * Load a struct scatter and set up the data address and length.
43897883Sgibbs * If the working value of the SG count is nonzero, then
43997883Sgibbs * we need to load a new set of values.
44097883Sgibbs *
44197883Sgibbs * This, like all DMA's, assumes little-endian host data storage.
442102681Sgibbs */
443102681Sgibbssg_load:
444102681Sgibbs	clr	HCNT2
445102681Sgibbs	clr	HCNT1
446102681Sgibbs	mvi	HCNT0,SG_SIZEOF
447102681Sgibbs
448102681Sgibbs	mvi	DINDEX, HADDR0
44997883Sgibbs	mvi	SG_NEXT0	call bcopy_4
45097883Sgibbs
45197883Sgibbs	or	DFCNTRL,0xd			/* HDMAEN|DIRECTION|FIFORESET */
45297883Sgibbs
45397883Sgibbs	call	dma_finish
45497883Sgibbs
45597883Sgibbs/*
45697883Sgibbs * Copy data from FIFO into SCB data pointer and data count.  This assumes
45797883Sgibbs * that the SG segments are of the form:
458102681Sgibbs *
459102681Sgibbs * struct ahc_dma_seg {
460102681Sgibbs *	u_int32_t	addr;		four bytes, little-endian order
46197883Sgibbs *	u_int32_t	len;		four bytes, little endian order
46297883Sgibbs * };
46397883Sgibbs */
46497883Sgibbs	mvi	HADDR0	call dfdat_in_7
46597883Sgibbs
46697883Sgibbs/* Load STCNT as well.  It is a mirror of HCNT */
467102681Sgibbs	call	set_stcnt_from_hcnt
468102681Sgibbs	test	SSTAT1,PHASEMIS  jz data_phase_loop
469102681Sgibbs
470102681Sgibbsdata_phase_finish:
47197883Sgibbs/*
47297883Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB
47397883Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
47497883Sgibbs * were transferred on the SCSI (as opposed to the host) bus.
47597883Sgibbs */
47697883Sgibbs	mov	SCB_RESID_DCNT0,STCNT0
47797883Sgibbs	mov	SCB_RESID_DCNT1,STCNT1
47897883Sgibbs	mov	SCB_RESID_DCNT2,STCNT2
47997883Sgibbs	mov	SCB_RESID_SGCNT, SG_COUNT
480102681Sgibbs	jmp	ITloop
481102681Sgibbs
482102681Sgibbsdata_phase_overrun:
48397883Sgibbs/*
48497883Sgibbs * Turn off BITBUCKET mode and notify the host
48597883Sgibbs */
48697883Sgibbs	and	SXFRCTL1,0x7f		/* ~BITBUCKET */
48797883Sgibbs	mvi	INTSTAT,DATA_OVERRUN
48897883Sgibbs	jmp	ITloop
48997883Sgibbs
49097883Sgibbs/*
49197883Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
49297883Sgibbs */
49397883Sgibbsp_command:
49497883Sgibbs	call	assert
49597883Sgibbs
49697883Sgibbs/*
49797883Sgibbs * Load HADDR and HCNT.
49897883Sgibbs */
49997883Sgibbs	mvi	DINDEX, HADDR0
50097883Sgibbs	mvi	SCB_CMDPTR	call bcopy_5
50197883Sgibbs	clr	HCNT1
50297883Sgibbs	clr	HCNT2
50397883Sgibbs
50497883Sgibbs	call	set_stcnt_from_hcnt
50597883Sgibbs
506107441Sscottl	mvi	0x3d		call dma	/*  SCSIEN|SDMAEN|HDMAEN
507107441Sscottl						 * |DIRECTION|FIFORESET
508107441Sscottl						 */
509107441Sscottl	jmp	ITloop
510107441Sscottl
511107441Sscottl/*
512107441Sscottl * Status phase.  Wait for the data byte to appear, then read it
513107441Sscottl * and store it into the SCB.
514107441Sscottl */
515107441Sscottlp_status:
516107441Sscottl	call	assert
51797883Sgibbs
51897883Sgibbs	mov	SCB_TARGET_STATUS, SCSIDATL
51997883Sgibbs	jmp	ITloop
52097883Sgibbs
52197883Sgibbs/*
52297883Sgibbs * Message out phase.  If there is not an active message, but the target
52397883Sgibbs * took us into this phase anyway, build a no-op message and send it.
52497883Sgibbs */
52597883Sgibbsp_mesgout:
52697883Sgibbs	test	MSG_LEN, 0xff	jnz  p_mesgout_start
52797883Sgibbs	mvi	MSG_NOOP	call mk_mesg	/* build NOP message */
52897883Sgibbsp_mesgout_start:
52997883Sgibbs/*
53097883Sgibbs * Set up automatic PIO transfer from MSG0.  Bit 3 in
53197883Sgibbs * SXFRCTL0 (SPIOEN) is already on.
53297883Sgibbs */
53397883Sgibbs	mvi	SINDEX,MSG0
53497883Sgibbs	mov	DINDEX,MSG_LEN
53597883Sgibbs
53697883Sgibbs/*
53797883Sgibbs * When target asks for a byte, drop ATN if it's the last one in
53897883Sgibbs * the message.  Otherwise, keep going until the message is exhausted.
53997883Sgibbs *
54097883Sgibbs * Keep an eye out for a phase change, in case the target issues
54197883Sgibbs * a MESSAGE REJECT.
54297883Sgibbs */
54397883Sgibbsp_mesgout_loop:
54497883Sgibbs	/*
54597883Sgibbs	 * If there is a parity error, wait for the kernel to
54697883Sgibbs	 * see the interrupt and "update" our message response
54797883Sgibbs	 * before continuing.
54897883Sgibbs	 */
54997883Sgibbs	test	SSTAT1, REQINIT	jz p_mesgout_loop
55097883Sgibbs	test	SSTAT1, SCSIPERR jnz p_mesgout_loop
55197883Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
55297883Sgibbs	cmp	LASTPHASE, P_MESGOUT jne p_mesgout_done
55397883Sgibbs/*
55497883Sgibbs * If the next bus phase after ATN drops is a message out, it means
55597883Sgibbs * that the target is requesting that the last message(s) be resent.
55697883Sgibbs */
55797883Sgibbsp_mesgout_testretry:
55897883Sgibbs	test	DINDEX,0xff	jnz p_mesgout_dropatn
55997883Sgibbs	or	SCSISIGO,ATNO,LASTPHASE	/* turn on ATN for the retry */
56097883Sgibbs	jmp	p_mesgout_start
56197883Sgibbsp_mesgout_dropatn:
56297883Sgibbs	cmp	DINDEX,1	jne p_mesgout_outb	/* last byte? */
56397883Sgibbs	mvi	CLRSINT1,CLRATNO			/* drop ATN */
56497883Sgibbsp_mesgout_outb:
56597883Sgibbs	dec	DINDEX
56697883Sgibbs	mvi	CLRSINT0, CLRSPIORDY
56797883Sgibbs	mov	SCSIDATL,SINDIR
56897883Sgibbs	jmp	p_mesgout_loop
56997883Sgibbs
57097883Sgibbsp_mesgout_done:
57197883Sgibbs	mvi	CLRSINT1,CLRATNO	/* Be sure to turn ATNO off */
57297883Sgibbs	clr	MSG_LEN			/* no active msg */
57397883Sgibbs	jmp	ITloop
57497883Sgibbs
57597883Sgibbs/*
57697883Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
57797883Sgibbs */
57897883Sgibbsp_mesgin:
57997883Sgibbs	mvi	A		call inb_first	/* read the 1st message byte */
58097883Sgibbs	mov	REJBYTE,A			/* save it for the driver */
58197883Sgibbs
58297883Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify
58397883Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect
58497883Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs
58597883Sgibbs	cmp	ALLZEROS,A		je mesgin_complete
58697883Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs
58797883Sgibbs	cmp	A,MSG_EXTENDED		je mesgin_extended
58897883Sgibbs	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject
58997883Sgibbs	cmp	A,MSG_NOOP		je mesgin_done
590102681Sgibbs
591102681Sgibbsrej_mesgin:
592102681Sgibbs/*
593102681Sgibbs * We have no idea what this message in is, so we issue a message reject
594102681Sgibbs * and hope for the best.  In any case, rejection should be a rare
595102681Sgibbs * occurrence - signal the driver when it happens.
596102681Sgibbs */
597102681Sgibbs	mvi	INTSTAT,SEND_REJECT		/* let driver know */
598102681Sgibbs
599102681Sgibbs	mvi	MSG_MESSAGE_REJECT	call mk_mesg
600102681Sgibbs
601102681Sgibbsmesgin_done:
602102681Sgibbs	call	inb_last
603102681Sgibbs	jmp	ITloop
604102681Sgibbs
605102681Sgibbs
606102681Sgibbsmesgin_complete:
607102681Sgibbs/*
608102681Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
609102681Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
61097883Sgibbs * is a residual or the status byte is something other than NO_ERROR (0).  In
61197883Sgibbs * either of these conditions, we upload the SCB back to the host so it can
61297883Sgibbs * process this information.  In the case of a non zero status byte, we 
61397883Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
61497883Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
61597883Sgibbs * sense, it will fill the kernel SCB with a request sense command and set
61697883Sgibbs * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
61797883Sgibbs * the SCB, and process it as the next command by adding it to the waiting list.
61897883Sgibbs * If the kernel driver does not wish to request sense, it need only clear
61997883Sgibbs * RETURN_1, and the command is allowed to complete normally.  We don't bother
62097883Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra
62197883Sgibbs * work in the kernel driver to ensure that the entry was removed before the
62297883Sgibbs * command complete code tried processing it.
62397883Sgibbs */
62497883Sgibbs
62597883Sgibbs/*
62697883Sgibbs * We expect to go to bus free after this message.
627102681Sgibbs */
628102681Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
629102681Sgibbs/*
630102681Sgibbs * First check for residuals
63197883Sgibbs */
63297883Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz upload_scb
63397883Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Good Status? */
63497883Sgibbsupload_scb:
63597883Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
63697883Sgibbs	mov	SCB_TAG		call dma_scb
63797883Sgibbscheck_status:
63897883Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Just a residual? */
63997883Sgibbs	mvi	INTSTAT,BAD_STATUS			/* let driver know */
64097883Sgibbs	cmp	RETURN_1, SEND_SENSE	jne status_ok
64197883Sgibbs	/* This SCB becomes the next to execute as it will retrieve sense */
64297883Sgibbs	mov	SCB_LINKED_NEXT, SCB_TAG
64397883Sgibbs	jmp	dma_next_scb
64497883Sgibbs
64597883Sgibbsstatus_ok:
64697883Sgibbs/* First, mark this target as free. */
64797883Sgibbs	test	SCB_CONTROL,TAG_ENB jnz complete	/*
648102681Sgibbs							 * Tagged commands
649102681Sgibbs							 * don't busy the
65097883Sgibbs							 * target.
65197883Sgibbs							 */
65297883Sgibbs	mov	SAVED_SCBPTR, SCBPTR
65397883Sgibbs	mov	SAVED_LINKPTR, SCB_LINKED_NEXT
65497883Sgibbs	mov	SCB_TCL		call	index_untagged_scb
65597883Sgibbs	mov	DINDIR, SAVED_LINKPTR
65697883Sgibbs	mov	SCBPTR, SAVED_SCBPTR
65797883Sgibbs
65897883Sgibbscomplete:
659102681Sgibbs	/* Post the SCB and issue an interrupt */
660102681Sgibbs	mov	QOUTFIFO,SCB_TAG
66197883Sgibbs	mvi	INTSTAT,CMDCMPLT
66297883Sgibbs
66397883Sgibbsdma_next_scb:
66497883Sgibbs	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je add_to_free_list
66597883Sgibbs	test	FLAGS, PAGESCBS jnz dma_next_scb2
66697883Sgibbs	/* Only DMA on top of ourselves if we are the SCB to download */
66797883Sgibbs	mov	A, SCB_LINKED_NEXT
66897883Sgibbs	cmp	SCB_TAG, A	je dma_next_scb2
66997883Sgibbs	mov	SCBPTR, A
670102681Sgibbs	jmp	add_to_waiting_list
671102681Sgibbsdma_next_scb2:
67297883Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
67397883Sgibbs	mov	SCB_LINKED_NEXT		call dma_scb
67497883Sgibbsadd_to_waiting_list:
67597883Sgibbs	mov	SCB_NEXT,WAITING_SCBH
67697883Sgibbs	mov	WAITING_SCBH, SCBPTR
67797883Sgibbs	jmp	mesgin_done
67897883Sgibbsadd_to_free_list:
67997883Sgibbs	call	add_scb_to_free_list
68097883Sgibbs	jmp	mesgin_done
681102681Sgibbs
682102681Sgibbs/*
683102681Sgibbs * Is it an extended message?  Copy the message to our message buffer and
684102681Sgibbs * notify the host.  The host will tell us whether to reject this message,
685102681Sgibbs * respond to it with the message that the host placed in our message buffer,
686102681Sgibbs * or simply to do nothing.
68797883Sgibbs */
68897883Sgibbsmesgin_extended:
68997883Sgibbs	mvi	MSGIN_EXT_LEN	 call inb_next
69097883Sgibbs	mov	A, MSGIN_EXT_LEN
69197883Sgibbsmesgin_extended_loop:
69297883Sgibbs	mov	DINDEX	call	inb_next
69397883Sgibbs	dec	A
69497883Sgibbs	cmp	DINDEX, MSGIN_EXT_LASTBYTE jne mesgin_extended_loop_test
69597883Sgibbs	dec	DINDEX		/* dump by repeatedly filling the last byte */
696102681Sgibbsmesgin_extended_loop_test:
69797883Sgibbs	test	A, 0xFF		jnz mesgin_extended_loop
69897883Sgibbsmesgin_extended_intr:
69997883Sgibbs	mvi	INTSTAT,EXTENDED_MSG		/* let driver know */
70097883Sgibbs	cmp	RETURN_1,SEND_REJ je rej_mesgin
70197883Sgibbs	cmp	RETURN_1,SEND_MSG jne mesgin_done
70297883Sgibbs/* The kernel has setup a message to be sent */
70397883Sgibbs	or	SCSISIGO,ATNO,LASTPHASE		/* turn on ATNO */
70497883Sgibbs	jmp	mesgin_done
70597883Sgibbs
706102681Sgibbs/*
70797883Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
70897883Sgibbs * and await the bus going free.
70997883Sgibbs */
71097883Sgibbsmesgin_disconnect:
71197883Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
71297883Sgibbs	or	SCB_CONTROL,DISCONNECTED
71397883Sgibbs	test	FLAGS, PAGESCBS jz mesgin_done
71497883Sgibbs	call	add_scb_to_disc_list
71597883Sgibbs	jmp	mesgin_done
716102681Sgibbs
71797883Sgibbs/*
71897883Sgibbs * Save data pointers message:
71997883Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
72097883Sgibbs * only if we've actually been into a data phase to change them.  This
72197883Sgibbs * protects against bogus data in scratch ram and the residual counts
72297883Sgibbs * since they are only initialized when we go into data_in or data_out.
72397883Sgibbs */
72497883Sgibbsmesgin_sdptrs:
72597883Sgibbs	test	FLAGS, DPHASE	jz mesgin_done
726102681Sgibbs	mov	SCB_SGCOUNT,SG_COUNT
727102681Sgibbs
728102681Sgibbs	/* The SCB SGPTR becomes the next one we'll download */
729102681Sgibbs	mvi	DINDEX, SCB_SGPTR
730102681Sgibbs	mvi	SG_NEXT0	call bcopy_4
731102681Sgibbs	
73297883Sgibbs	/* The SCB DATAPTR0 becomes the current SHADDR */
73397883Sgibbs	mvi	DINDEX, SCB_DATAPTR0
73497883Sgibbs	mvi	SHADDR0		call bcopy_4
73597883Sgibbs
73697883Sgibbs/*
73797883Sgibbs * Use the residual number since STCNT is corrupted by any message transfer.
73897883Sgibbs */
73997883Sgibbs	mvi	SCB_RESID_DCNT0	call	bcopy_3
74097883Sgibbs
741102681Sgibbs	jmp	mesgin_done
74297883Sgibbs
74397883Sgibbs/*
74497883Sgibbs * Restore pointers message?  Data pointers are recopied from the
74597883Sgibbs * SCB anytime we enter a data phase for the first time, so all
74697883Sgibbs * we need to do is clear the DPHASE flag and let the data phase
74797883Sgibbs * code do the rest.
74897883Sgibbs */
74997883Sgibbsmesgin_rdptrs:
75097883Sgibbs	and	FLAGS,0xef			/*
751102681Sgibbs						 * !DPHASE we'll reload them
75297883Sgibbs						 * the next time through
75397883Sgibbs						 */
75497883Sgibbs	jmp	mesgin_done
75597883Sgibbs
75697883Sgibbs/*
75797883Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
75897883Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
75997883Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
76097883Sgibbs */
761102681Sgibbsmesgin_identify:
76297883Sgibbs	test	A,0x78	jnz rej_mesgin	/*!DiscPriv|!LUNTAR|!Reserved*/
76397883Sgibbs	and	A,0x07			/* lun in lower three bits */
76497883Sgibbs	or      SAVED_TCL,A		/* SAVED_TCL should be complete now */
76597883Sgibbs	call	inb_last		/* ACK */
76697883Sgibbs
76797883Sgibbs/*
76897883Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
76997883Sgibbs * If we get one, we use the tag returned to switch to find the proper
77097883Sgibbs * SCB.  With SCB paging, this requires using findSCB for both tagged
77197883Sgibbs * and non-tagged transactions since the SCB may exist in any slot.
77297883Sgibbs * If we're not using SCB paging, we can use the tag as the direct
77397883Sgibbs * index to the SCB.
77497883Sgibbs */
77597883Sgibbs	mvi	ARG_1,SCB_LIST_NULL	/* Default to no-tag */
77697883Sgibbssnoop_tag_loop:
77797883Sgibbs	test	SSTAT1,REQINIT		jz snoop_tag_loop
77897883Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
77997883Sgibbs	cmp	LASTPHASE, P_MESGIN, jne use_findSCB
780102681Sgibbs	mvi	A			call inb_first
78197883Sgibbs	cmp	A,MSG_SIMPLE_Q_TAG	jne use_findSCB
78297883Sgibbsget_tag:
78397883Sgibbs	or	FLAGS, TAGGED_SCB
78497883Sgibbs	mvi	ARG_1	call inb_next	/* tag value */
78597883Sgibbs/*
78697883Sgibbs * See if the tag is in range.  The tag is < SCBCOUNT if we add
78797883Sgibbs * the complement of SCBCOUNT to the incomming tag and there is
78897883Sgibbs * no carry.
78997883Sgibbs */
790102681Sgibbs	mov	A,COMP_SCBCOUNT	
79197883Sgibbs	add	SINDEX,A,ARG_1
79297883Sgibbs	jc	send_abort_msg
79397883Sgibbs
79497883Sgibbs/*
79597883Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction
79697883Sgibbs * to the reconnecting target.
79797883Sgibbs */
79897883Sgibbs	test	FLAGS, PAGESCBS	jz index_by_tag
79997883Sgibbsuse_findSCB:
800102681Sgibbs	mov	ALLZEROS	call findSCB	  /* Have to search */
80197883Sgibbs	cmp	SINDEX, SCB_LIST_NULL, je not_found
80297883Sgibbssetup_SCB:
80397883Sgibbs	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
80497883Sgibbs	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
80597883Sgibbs	test	SCB_CONTROL,TAG_ENB	jnz  mesgin_done /* Ack Tag */
80697883Sgibbs	jmp	ITloop
80797883Sgibbsindex_by_tag:
80897883Sgibbs	mov	SCBPTR,ARG_1
80997883Sgibbs	mov	A, SAVED_TCL
810102681Sgibbs	cmp	SCB_TCL,A		jne send_abort_msg
811102681Sgibbs	test	SCB_CONTROL,TAG_ENB	jz  send_abort_msg
812102681Sgibbs	jmp	setup_SCB
813102681Sgibbs
814102681Sgibbsnot_found:
815102681Sgibbs	mvi	INTSTAT, NO_MATCH
816102681Sgibbssend_abort_msg:
81797883Sgibbs	test	FLAGS, TAGGED_SCB jnz abort_tag_msg
81897883Sgibbs	mvi	MSG_ABORT	call mk_mesg
81997883Sgibbs	jmp	mesgin_done
82097883Sgibbsabort_tag_msg:
82197883Sgibbs	mvi	MSG_ABORT_TAG	call mk_mesg	/* ABORT TAG message */
82297883Sgibbs	jmp	mesgin_done
82397883Sgibbs
82497883Sgibbs/*
82597883Sgibbs * Message reject?  Let the kernel driver handle this.  If we have an 
82697883Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 
82797883Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
82897883Sgibbs * it since we have no clue what it pertains to.
82997883Sgibbs */
83097883Sgibbsmesgin_reject:
83197883Sgibbs	mvi	INTSTAT, REJECT_MSG
83297883Sgibbs	jmp	mesgin_done
83397883Sgibbs
83497883Sgibbs/*
83597883Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ]
83697883Sgibbs */
83797883Sgibbs
83897883Sgibbs/*
83997883Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX
84097883Sgibbs * if there is no active message already.  SINDEX is returned intact.
84197883Sgibbs */
84297883Sgibbsmk_mesg:
84397883Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
84497883Sgibbs	test	MSG_LEN,0xff	jz mk_mesg1	/* Should always succeed */
84597883Sgibbs	
84697883Sgibbs	/*
84797883Sgibbs	 * Hmmm.  For some reason the mesg buffer is in use.
84897883Sgibbs	 * Tell the driver.  It should look at SINDEX to find
84997883Sgibbs	 * out what we wanted to use the buffer for and resolve
85097883Sgibbs	 * the conflict.
85197883Sgibbs	 */
85297883Sgibbs	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
85397883Sgibbs	mvi	INTSTAT,MSG_BUFFER_BUSY
854102681Sgibbs
855102681Sgibbsmk_mesg1:
856102681Sgibbs	or	SCSISIGO,ATNO,LASTPHASE	/* turn on ATNO */
857102681Sgibbs	mvi	MSG_LEN,1		/* length = 1 */
858102681Sgibbs	mov	MSG0,SINDEX		/* 1-byte message */
859102681Sgibbs	mvi	SEQCTL,0x10	ret	/* !PAUSEDIS|FASTMODE */
860102681Sgibbs
861102681Sgibbs/*
86297883Sgibbs * Functions to read data in Automatic PIO mode.
86397883Sgibbs *
86497883Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
86597883Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
86697883Sgibbs * latched (the usual way), then read the data byte directly off the bus
86797883Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
86897883Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
86997883Sgibbs * spec guarantees that the target will hold the data byte on the bus until
87097883Sgibbs * we send our ACK.
871102681Sgibbs *
872102681Sgibbs * The assumption here is that these are called in a particular sequence,
873102681Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
874102681Sgibbs * use the same calling convention as inb.
875102681Sgibbs */
876102681Sgibbs
877102681Sgibbsinb_next:
878102681Sgibbs	mov	NONE,SCSIDATL			/*dummy read from latch to ACK*/
87997883Sgibbsinb_next_wait:
88097883Sgibbs	/*
88197883Sgibbs	 * If there is a parity error, wait for the kernel to
88297883Sgibbs	 * see the interrupt and prepare our message response
88397883Sgibbs	 * before continuing.
88497883Sgibbs	 */
88597883Sgibbs	test	SSTAT1, REQINIT	jz inb_next_wait
88697883Sgibbs	test	SSTAT1, SCSIPERR jnz inb_next_wait
88797883Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
888102681Sgibbs	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis
889102681Sgibbsinb_first:
890102681Sgibbs	mov	DINDEX,SINDEX
891102681Sgibbs	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
892102681Sgibbsinb_last:
893102681Sgibbs	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
894102681Sgibbs
895102681Sgibbsmesgin_phasemis:
89697883Sgibbs/*
89797883Sgibbs * We expected to receive another byte, but the target changed phase
89897883Sgibbs */
89997883Sgibbs	mvi	INTSTAT, MSGIN_PHASEMIS
90097883Sgibbs	jmp	ITloop
90197883Sgibbs
90297883Sgibbs/*
90397883Sgibbs * DMA data transfer.  HADDR and HCNT must be loaded first, and
90497883Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for
905102681Sgibbs * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
90697883Sgibbs * during initialization.
90797883Sgibbs */
90897883Sgibbsdma:
90997883Sgibbs	mov	DFCNTRL,SINDEX
91097883Sgibbsdma1:
91197883Sgibbs	test	SSTAT0,DMADONE	jnz dma3
91297883Sgibbs	test	SSTAT1,PHASEMIS	jz dma1		/* ie. underrun */
91397883Sgibbs	test	SSTAT0,SDONE	jnz dma3
91497883Sgibbs	mov	SINDEX,ALLZEROS			/* Notify caller of phasemiss */
915102681Sgibbs
91697883Sgibbs/*
91797883Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or
91897883Sgibbs * the target changes the phase (in light of this, it makes sense that
91997883Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
92097883Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
92197883Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty
92297883Sgibbs * status.
92397883Sgibbs */
92497883Sgibbsdma3:
925102681Sgibbs	test	DFCNTRL,DIRECTION	jnz dma5
92697883Sgibbsdma4:
92797883Sgibbs	test	DFSTATUS,FIFOEMP	jz dma4
92897883Sgibbs
92997883Sgibbs/*
93097883Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 
93197883Sgibbs * actually off first lest we get an ILLSADDR.
93297883Sgibbs */
93397883Sgibbsdma5:
93497883Sgibbs	/* Don't clobber an inprogress host data transfer */
935102681Sgibbs	test	DFSTATUS, MREQPEND	jnz dma5
936102681Sgibbs	/* disable DMA */
93797883Sgibbs	and	DFCNTRL, 0xc7		/* ~(SCSIEN|SDMAEN|HDMAEN) */
93897883Sgibbsdma6:
93997883Sgibbs	test	DFCNTRL, 0x38	jnz dma6  /* (SCSIEN|SDMAEN|HDMAEN) */
94097883Sgibbsreturn:
94197883Sgibbs	ret
94297883Sgibbs
94397883Sgibbs/*
94497883Sgibbs * Common SCSI initialization for selection and reselection.  Expects
94597883Sgibbs * the target SCSI ID to be in the upper four bits of SINDEX, and A's
946102681Sgibbs * contents are stomped on return.
94797883Sgibbs */
94897883Sgibbsinitialize_scsiid:
94997883Sgibbs	and	SINDEX,0xf0		/* Get target ID */
95097883Sgibbs	mov	SAVED_TCL, SINDEX	/* Update the target portion of this */
95197883Sgibbs	and	A,0x0f,SCSIID
95297883Sgibbs	or	SINDEX,A
95397883Sgibbs	mov	SCSIID,SINDEX ret
95497883Sgibbs
95597883Sgibbs/*
956102681Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
95797883Sgibbs * message.
95897883Sgibbs */
95997883Sgibbsassert:
96097883Sgibbs	test	FLAGS,RESELECTED	jz return	/* reselected? */
96197883Sgibbs	test	FLAGS,IDENTIFY_SEEN	jnz return	/* seen IDENTIFY? */
96297883Sgibbs
96397883Sgibbs	mvi	INTSTAT,NO_IDENT 	ret	/* no - tell the kernel */
96497883Sgibbs
96597883Sgibbs/*
966102681Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
96797883Sgibbs * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
96897883Sgibbs * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
96997883Sgibbs * otherwise, SCBPTR is set to the proper SCB.
97097883Sgibbs */
97197883SgibbsfindSCB:
97297883Sgibbs	mov	SCBPTR,SINDEX			/* switch to next SCB */
97397883Sgibbs	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
97497883Sgibbs	cmp	ARG_1, SCB_LIST_NULL	jne findBySCBID
97597883Sgibbs	mov	A, SAVED_TCL
976102681Sgibbs	cmp	SCB_TCL,A	je foundSCB /* target ID/channel/lun match? */
97797883SgibbsfindSCB1:
97897883Sgibbs	inc	SINDEX
97997883Sgibbs	mov	A,SCBCOUNT
98097883Sgibbs	cmp	SINDEX,A	jne findSCB
98197883Sgibbs/*
98297883Sgibbs * We didn't find it.  If we're paging, pull an SCB and DMA down the
98397883Sgibbs * one we want.  If we aren't paging or the SCB we dma down has the
98497883Sgibbs * abort flag set, return not found.
98597883Sgibbs */
986102681Sgibbs	test	FLAGS, PAGESCBS	jz find_error
987102681Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb
98897883Sgibbs	cmp	ARG_1, SCB_LIST_NULL jne find_dma_scb
98997883Sgibbs	mov	SAVED_TCL	call	index_untagged_scb
99097883Sgibbs	mov	ARG_1, SINDIR	/* SCBID of SCB to fetch */
99197883Sgibbsfind_dma_scb:
99297883Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
99397883Sgibbs	mov	ARG_1	call dma_scb
99497883Sgibbs	test	SCB_CONTROL, ABORT_SCB jz return
99597883Sgibbs	call	add_scb_to_free_list
99697883Sgibbsfind_error:
997102681Sgibbs	mvi	SINDEX, SCB_LIST_NULL ret
99897883SgibbsfindBySCBID:
99997883Sgibbs	mov	A, ARG_1			/* Tag passed in ARG_1 */
100097883Sgibbs	cmp	SCB_TAG,A	jne findSCB1	/* Found it? */
100197883SgibbsfoundSCB:
100297883Sgibbs	test	SCB_CONTROL, ABORT_SCB jnz find_error
100397883Sgibbs	test	FLAGS,PAGESCBS	jz return
100497883Sgibbsrem_scb_from_disc_list:
100597883Sgibbs/* Remove this SCB from the disconnection list */
100697883Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev
1007102681Sgibbs	mov	SAVED_LINKPTR, SCB_PREV
1008102681Sgibbs	mov	SCBPTR, SCB_NEXT
100997883Sgibbs	mov	SCB_PREV, SAVED_LINKPTR
101097883Sgibbs	mov	SCBPTR, SINDEX
101197883Sgibbsunlink_prev:
101297883Sgibbs	cmp	SCB_PREV,SCB_LIST_NULL	je rHead/* At the head of the list */
101397883Sgibbs	mov	SAVED_LINKPTR, SCB_NEXT
101497883Sgibbs	mov	SCBPTR, SCB_PREV
101597883Sgibbs	mov	SCB_NEXT, SAVED_LINKPTR
101697883Sgibbs	mov	SCBPTR, SINDEX ret
101797883SgibbsrHead:
101897883Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret
101997883Sgibbs
102097883Sgibbsset_stcnt_from_hcnt:
102197883Sgibbs	mov	STCNT0, HCNT0
102297883Sgibbs	mov	STCNT1, HCNT1
102397883Sgibbs	mov	STCNT2, HCNT2 ret
102497883Sgibbs
102597883Sgibbsbcopy_7:
102697883Sgibbs	mov	DINDIR, SINDIR
1027102681Sgibbs	mov	DINDIR, SINDIR
102897883Sgibbsbcopy_5:
102997883Sgibbs	mov	DINDIR, SINDIR
103097883Sgibbsbcopy_4:
103197883Sgibbs	mov	DINDIR, SINDIR
103297883Sgibbsbcopy_3:
103397883Sgibbs	mov	DINDIR, SINDIR
103497883Sgibbs	mov	DINDIR, SINDIR
103597883Sgibbs	mov	DINDIR, SINDIR ret
103697883Sgibbs
1037102681Sgibbsdma_scb:
1038102681Sgibbs	/*
103997883Sgibbs	 * SCB index is in SINDEX.  Determine the physical address in
104097883Sgibbs	 * the host where this SCB is located and load HADDR with it.
104197883Sgibbs	 */
104297883Sgibbs	shr	DINDEX, SINDEX, 3
104397883Sgibbs	shl	A, SINDEX, 5
104497883Sgibbs	add	HADDR0, A, HSCB_ADDR0
104597883Sgibbs	mov	A, DINDEX
104697883Sgibbs	adc	HADDR1, A, HSCB_ADDR1
104797883Sgibbs	clr	A
104897883Sgibbs	adc	HADDR2, A, HSCB_ADDR2
1049102681Sgibbs	adc	HADDR3, A, HSCB_ADDR3
105097883Sgibbs	/* Setup Count */
105197883Sgibbs	mvi	HCNT0, 28
105297883Sgibbs	clr	HCNT1
105397883Sgibbs	clr	HCNT2
105497883Sgibbs	mov	DFCNTRL, DMAPARAMS
105597883Sgibbs	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost
105697883Sgibbs	/* Fill it with the SCB data */
105797883Sgibbs	call	copy_scb_tofifo
1058102681Sgibbs	mvi	DFCNTRL, 0xa		/* HDMAEN | FIFOFLUSH */
1059102681Sgibbsdma_scb_fromhost:
1060102681Sgibbs	call	dma_finish
1061102681Sgibbs	/* If we were putting the SCB, we are done */
1062102681Sgibbs	test	DMAPARAMS, DIRECTION	jz	return
1063102681Sgibbs	mvi	SCBARRAY  call dfdat_in_7
1064102681Sgibbs	call	dfdat_in_7_continued
1065102681Sgibbs	call	dfdat_in_7_continued
106697883Sgibbs	jmp	dfdat_in_7_continued
106797883Sgibbsdfdat_in_7:
106897883Sgibbs	mov     DINDEX,SINDEX
106997883Sgibbsdfdat_in_7_continued:
107097883Sgibbs	mov	DINDIR,DFDAT
107197883Sgibbs	mov	DINDIR,DFDAT
107297883Sgibbs	mov	DINDIR,DFDAT
107397883Sgibbs	mov	DINDIR,DFDAT
107497883Sgibbs	mov	DINDIR,DFDAT
1075102681Sgibbs	mov	DINDIR,DFDAT
107697883Sgibbs	mov	DINDIR,DFDAT ret
107797883Sgibbs
107897883Sgibbscopy_scb_tofifo:
107997883Sgibbs	mvi	SCBARRAY  call dfdat_out_7
108097883Sgibbs	call	dfdat_out_7
108197883Sgibbs	call	dfdat_out_7
108297883Sgibbsdfdat_out_7:
108397883Sgibbs	mov	DFDAT,SINDIR
108497883Sgibbs	mov	DFDAT,SINDIR
1085102681Sgibbs	mov	DFDAT,SINDIR
1086102681Sgibbs	mov	DFDAT,SINDIR
108797883Sgibbs	mov	DFDAT,SINDIR
108897883Sgibbs	mov	DFDAT,SINDIR
108997883Sgibbs	mov	DFDAT,SINDIR ret
109097883Sgibbs
109197883Sgibbs/*
109297883Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
109397883Sgibbs * DMA and wait for it to acknowledge that it's off.
109497883Sgibbs */
109597883Sgibbsdma_finish:
1096102681Sgibbs	test	DFSTATUS,HDONE	jz dma_finish
1097102681Sgibbs	/* Turn off DMA */
1098102681Sgibbs	and	DFCNTRL, 0xf7 ret	# ~HDMAEN
1099102681Sgibbs
1100102681Sgibbsindex_untagged_scb:
1101102681Sgibbs	mov	DINDEX, SINDEX
1102102681Sgibbs	shr	DINDEX, 4
1103102681Sgibbs	and	DINDEX, 0x03			/* Bottom two bits of tid */
110497883Sgibbs	add	DINDEX, SCB_ACTIVE0
110597883Sgibbs	shr	A, SINDEX, 6			/* Target ID divided by 4 */
110697883Sgibbs	test	SINDEX, SELBUSB jz index_untagged_scb2
110797883Sgibbs	add	A, 2				/* Add 2 positions */
110897883Sgibbsindex_untagged_scb2:
110997883Sgibbs	mov	SCBPTR, A			/*
111097883Sgibbs						 * Select the SCB with this 
111197883Sgibbs						 * target's information.
111297883Sgibbs						 */
1113102681Sgibbs	mov	SINDEX, DINDEX	ret
1114102681Sgibbs
1115102681Sgibbs
1116102681Sgibbsget_free_or_disc_scb:
1117102681Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb
1118102681Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb
1119102681Sgibbsreturn_error:
1120102681Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret
112197883Sgibbsdequeue_disc_scb:
112297883Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH
112397883Sgibbs/*
112497883Sgibbs * If we have a residual, then we are in the middle of some I/O
112597883Sgibbs * and we have to send this SCB back up to the kernel so that the
112697883Sgibbs * saved data pointers and residual information isn't lost.
112797883Sgibbs */
112897883Sgibbs	test	SCB_RESID_SGCNT,0xff	jz unlink_disc_scb
112997883Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
1130102681Sgibbs	mov	SCB_TAG		call dma_scb
1131102681Sgibbsunlink_disc_scb:
1132102681Sgibbs	/* jmp instead of call since we want to return anyway */
1133102681Sgibbs	mov	SCBPTR	jmp rem_scb_from_disc_list
1134102681Sgibbsdequeue_free_scb:
1135102681Sgibbs	mov	SCBPTR, FREE_SCBH
1136102681Sgibbs	mov	FREE_SCBH, SCB_NEXT ret
113797883Sgibbs
113897883Sgibbsadd_scb_to_free_list:
113997883Sgibbs	mov	SCB_NEXT, FREE_SCBH
114097883Sgibbs	mov	FREE_SCBH, SCBPTR ret
114197883Sgibbs
114297883Sgibbsadd_scb_to_disc_list:
114397883Sgibbs/*
114497883Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
114597883Sgibbs * candidates for paging out an SCB if one is needed for a new command.
1146102681Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
1147102681Sgibbs */
1148102681Sgibbs	mvi	SCB_PREV, SCB_LIST_NULL
1149102681Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH
1150102681Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR
1151102681Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je return
1152102681Sgibbs	mov	SCBPTR,SCB_NEXT
1153102681Sgibbs	mov	SCB_PREV,DISCONNECTED_SCBH
115497883Sgibbs	mov	SCBPTR,DISCONNECTED_SCBH ret
115597883Sgibbs
115697883Sgibbs