xref: /OK3568_Linux_fs/kernel/drivers/scsi/aic7xxx/aic7xxx.seq (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/*
2*4882a593Smuzhiyun * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (c) 1994-2001 Justin T. Gibbs.
5*4882a593Smuzhiyun * Copyright (c) 2000-2001 Adaptec Inc.
6*4882a593Smuzhiyun * All rights reserved.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or without
9*4882a593Smuzhiyun * modification, are permitted provided that the following conditions
10*4882a593Smuzhiyun * are met:
11*4882a593Smuzhiyun * 1. Redistributions of source code must retain the above copyright
12*4882a593Smuzhiyun *    notice, this list of conditions, and the following disclaimer,
13*4882a593Smuzhiyun *    without modification.
14*4882a593Smuzhiyun * 2. Redistributions in binary form must reproduce at minimum a disclaimer
15*4882a593Smuzhiyun *    substantially similar to the "NO WARRANTY" disclaimer below
16*4882a593Smuzhiyun *    ("Disclaimer") and any redistribution must be conditioned upon
17*4882a593Smuzhiyun *    including a substantially similar Disclaimer requirement for further
18*4882a593Smuzhiyun *    binary redistribution.
19*4882a593Smuzhiyun * 3. Neither the names of the above-listed copyright holders nor the names
20*4882a593Smuzhiyun *    of any contributors may be used to endorse or promote products derived
21*4882a593Smuzhiyun *    from this software without specific prior written permission.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * Alternatively, this software may be distributed under the terms of the
24*4882a593Smuzhiyun * GNU General Public License ("GPL") version 2 as published by the Free
25*4882a593Smuzhiyun * Software Foundation.
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun * NO WARRANTY
28*4882a593Smuzhiyun * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29*4882a593Smuzhiyun * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30*4882a593Smuzhiyun * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
31*4882a593Smuzhiyun * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32*4882a593Smuzhiyun * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33*4882a593Smuzhiyun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34*4882a593Smuzhiyun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35*4882a593Smuzhiyun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36*4882a593Smuzhiyun * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
37*4882a593Smuzhiyun * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38*4882a593Smuzhiyun * POSSIBILITY OF SUCH DAMAGES.
39*4882a593Smuzhiyun *
40*4882a593Smuzhiyun * $FreeBSD$
41*4882a593Smuzhiyun */
42*4882a593Smuzhiyun
43*4882a593SmuzhiyunVERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $"
44*4882a593SmuzhiyunPATCH_ARG_LIST = "struct ahc_softc *ahc"
45*4882a593SmuzhiyunPREFIX = "ahc_"
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun#include "aic7xxx.reg"
48*4882a593Smuzhiyun#include "scsi_message.h"
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun/*
51*4882a593Smuzhiyun * A few words on the waiting SCB list:
52*4882a593Smuzhiyun * After starting the selection hardware, we check for reconnecting targets
53*4882a593Smuzhiyun * as well as for our selection to complete just in case the reselection wins
54*4882a593Smuzhiyun * bus arbitration.  The problem with this is that we must keep track of the
55*4882a593Smuzhiyun * SCB that we've already pulled from the QINFIFO and started the selection
56*4882a593Smuzhiyun * on just in case the reselection wins so that we can retry the selection at
57*4882a593Smuzhiyun * a later time.  This problem cannot be resolved by holding a single entry
58*4882a593Smuzhiyun * in scratch ram since a reconnecting target can request sense and this will
59*4882a593Smuzhiyun * create yet another SCB waiting for selection.  The solution used here is to
60*4882a593Smuzhiyun * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
61*4882a593Smuzhiyun * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes,
62*4882a593Smuzhiyun * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
63*4882a593Smuzhiyun * this list every time a request sense occurs or after completing a non-tagged
64*4882a593Smuzhiyun * command for which a second SCB has been queued.  The sequencer will
65*4882a593Smuzhiyun * automatically consume the entries.
66*4882a593Smuzhiyun */
67*4882a593Smuzhiyun
68*4882a593Smuzhiyunbus_free_sel:
69*4882a593Smuzhiyun	/*
70*4882a593Smuzhiyun	 * Turn off the selection hardware.  We need to reset the
71*4882a593Smuzhiyun	 * selection request in order to perform a new selection.
72*4882a593Smuzhiyun	 */
73*4882a593Smuzhiyun	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP;
74*4882a593Smuzhiyun	and	SIMODE1, ~ENBUSFREE;
75*4882a593Smuzhiyunpoll_for_work:
76*4882a593Smuzhiyun	call	clear_target_state;
77*4882a593Smuzhiyun	and	SXFRCTL0, ~SPIOEN;
78*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
79*4882a593Smuzhiyun		clr	SCSIBUSL;
80*4882a593Smuzhiyun	}
81*4882a593Smuzhiyun	test	SCSISEQ, ENSELO	jnz poll_for_selection;
82*4882a593Smuzhiyun	if ((ahc->features & AHC_TWIN) != 0) {
83*4882a593Smuzhiyun		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
84*4882a593Smuzhiyun		test	SCSISEQ, ENSELO		jnz poll_for_selection;
85*4882a593Smuzhiyun	}
86*4882a593Smuzhiyun	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
87*4882a593Smuzhiyunpoll_for_work_loop:
88*4882a593Smuzhiyun	if ((ahc->features & AHC_TWIN) != 0) {
89*4882a593Smuzhiyun		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
90*4882a593Smuzhiyun	}
91*4882a593Smuzhiyun	test	SSTAT0, SELDO|SELDI	jnz selection;
92*4882a593Smuzhiyuntest_queue:
93*4882a593Smuzhiyun	/* Has the driver posted any work for us? */
94*4882a593SmuzhiyunBEGIN_CRITICAL;
95*4882a593Smuzhiyun	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
96*4882a593Smuzhiyun		test	QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
97*4882a593Smuzhiyun	} else {
98*4882a593Smuzhiyun		mov	A, QINPOS;
99*4882a593Smuzhiyun		cmp	KERNEL_QINPOS, A je poll_for_work_loop;
100*4882a593Smuzhiyun	}
101*4882a593Smuzhiyun	mov	ARG_1, NEXT_QUEUED_SCB;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun	/*
104*4882a593Smuzhiyun	 * We have at least one queued SCB now and we don't have any
105*4882a593Smuzhiyun	 * SCBs in the list of SCBs awaiting selection.  Allocate a
106*4882a593Smuzhiyun	 * card SCB for the host's SCB and get to work on it.
107*4882a593Smuzhiyun	 */
108*4882a593Smuzhiyun	if ((ahc->flags & AHC_PAGESCBS) != 0) {
109*4882a593Smuzhiyun		mov	ALLZEROS	call	get_free_or_disc_scb;
110*4882a593Smuzhiyun	} else {
111*4882a593Smuzhiyun		/* In the non-paging case, the SCBID == hardware SCB index */
112*4882a593Smuzhiyun		mov	SCBPTR, ARG_1;
113*4882a593Smuzhiyun	}
114*4882a593Smuzhiyun	or	SEQ_FLAGS2, SCB_DMA;
115*4882a593SmuzhiyunEND_CRITICAL;
116*4882a593Smuzhiyundma_queued_scb:
117*4882a593Smuzhiyun	/*
118*4882a593Smuzhiyun	 * DMA the SCB from host ram into the current SCB location.
119*4882a593Smuzhiyun	 */
120*4882a593Smuzhiyun	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
121*4882a593Smuzhiyun	mov	ARG_1	call dma_scb;
122*4882a593Smuzhiyun	/*
123*4882a593Smuzhiyun	 * Check one last time to see if this SCB was canceled
124*4882a593Smuzhiyun	 * before we completed the DMA operation.  If it was,
125*4882a593Smuzhiyun	 * the QINFIFO next pointer will not match our saved
126*4882a593Smuzhiyun	 * value.
127*4882a593Smuzhiyun	 */
128*4882a593Smuzhiyun	mov	A, ARG_1;
129*4882a593SmuzhiyunBEGIN_CRITICAL;
130*4882a593Smuzhiyun	cmp	NEXT_QUEUED_SCB, A jne abort_qinscb;
131*4882a593Smuzhiyun	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
132*4882a593Smuzhiyun		cmp	SCB_TAG, A je . + 2;
133*4882a593Smuzhiyun		mvi	SCB_MISMATCH call set_seqint;
134*4882a593Smuzhiyun	}
135*4882a593Smuzhiyun	mov	NEXT_QUEUED_SCB, SCB_NEXT;
136*4882a593Smuzhiyun	mov	SCB_NEXT,WAITING_SCBH;
137*4882a593Smuzhiyun	mov	WAITING_SCBH, SCBPTR;
138*4882a593Smuzhiyun	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
139*4882a593Smuzhiyun		mov	NONE, SNSCB_QOFF;
140*4882a593Smuzhiyun	} else {
141*4882a593Smuzhiyun		inc	QINPOS;
142*4882a593Smuzhiyun	}
143*4882a593Smuzhiyun	and	SEQ_FLAGS2, ~SCB_DMA;
144*4882a593SmuzhiyunEND_CRITICAL;
145*4882a593Smuzhiyunstart_waiting:
146*4882a593Smuzhiyun	/*
147*4882a593Smuzhiyun	 * Start the first entry on the waiting SCB list.
148*4882a593Smuzhiyun	 */
149*4882a593Smuzhiyun	mov	SCBPTR, WAITING_SCBH;
150*4882a593Smuzhiyun	call	start_selection;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyunpoll_for_selection:
153*4882a593Smuzhiyun	/*
154*4882a593Smuzhiyun	 * Twin channel devices cannot handle things like SELTO
155*4882a593Smuzhiyun	 * interrupts on the "background" channel.  So, while
156*4882a593Smuzhiyun	 * selecting, keep polling the current channel until
157*4882a593Smuzhiyun	 * either a selection or reselection occurs.
158*4882a593Smuzhiyun	 */
159*4882a593Smuzhiyun	test	SSTAT0, SELDO|SELDI	jz poll_for_selection;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyunselection:
162*4882a593Smuzhiyun	/*
163*4882a593Smuzhiyun	 * We aren't expecting a bus free, so interrupt
164*4882a593Smuzhiyun	 * the kernel driver if it happens.
165*4882a593Smuzhiyun	 */
166*4882a593Smuzhiyun	mvi	CLRSINT1,CLRBUSFREE;
167*4882a593Smuzhiyun	if ((ahc->features & AHC_DT) == 0) {
168*4882a593Smuzhiyun		or	SIMODE1, ENBUSFREE;
169*4882a593Smuzhiyun	}
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun	/*
172*4882a593Smuzhiyun	 * Guard against a bus free after (re)selection
173*4882a593Smuzhiyun	 * but prior to enabling the busfree interrupt.  SELDI
174*4882a593Smuzhiyun	 * and SELDO will be cleared in that case.
175*4882a593Smuzhiyun	 */
176*4882a593Smuzhiyun	test	SSTAT0, SELDI|SELDO	jz bus_free_sel;
177*4882a593Smuzhiyun	test	SSTAT0,SELDO	jnz select_out;
178*4882a593Smuzhiyunselect_in:
179*4882a593Smuzhiyun	if ((ahc->flags & AHC_TARGETROLE) != 0) {
180*4882a593Smuzhiyun		if ((ahc->flags & AHC_INITIATORROLE) != 0) {
181*4882a593Smuzhiyun			test	SSTAT0, TARGET	jz initiator_reselect;
182*4882a593Smuzhiyun		}
183*4882a593Smuzhiyun		mvi	CLRSINT0, CLRSELDI;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun		/*
186*4882a593Smuzhiyun		 * We've just been selected.  Assert BSY and
187*4882a593Smuzhiyun		 * setup the phase for receiving messages
188*4882a593Smuzhiyun		 * from the target.
189*4882a593Smuzhiyun		 */
190*4882a593Smuzhiyun		mvi	SCSISIGO, P_MESGOUT|BSYO;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun		/*
193*4882a593Smuzhiyun		 * Setup the DMA for sending the identify and
194*4882a593Smuzhiyun		 * command information.
195*4882a593Smuzhiyun		 */
196*4882a593Smuzhiyun		mvi	SEQ_FLAGS, CMDPHASE_PENDING;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun		mov     A, TQINPOS;
199*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
200*4882a593Smuzhiyun			mvi	DINDEX, CCHADDR;
201*4882a593Smuzhiyun			mvi	SHARED_DATA_ADDR call set_32byte_addr;
202*4882a593Smuzhiyun			mvi	CCSCBCTL, CCSCBRESET;
203*4882a593Smuzhiyun		} else {
204*4882a593Smuzhiyun			mvi	DINDEX, HADDR;
205*4882a593Smuzhiyun			mvi	SHARED_DATA_ADDR call set_32byte_addr;
206*4882a593Smuzhiyun			mvi	DFCNTRL, FIFORESET;
207*4882a593Smuzhiyun		}
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun		/* Initiator that selected us */
210*4882a593Smuzhiyun		and	SAVED_SCSIID, SELID_MASK, SELID;
211*4882a593Smuzhiyun		/* The Target ID we were selected at */
212*4882a593Smuzhiyun		if ((ahc->features & AHC_MULTI_TID) != 0) {
213*4882a593Smuzhiyun			and	A, OID, TARGIDIN;
214*4882a593Smuzhiyun		} else if ((ahc->features & AHC_ULTRA2) != 0) {
215*4882a593Smuzhiyun			and	A, OID, SCSIID_ULTRA2;
216*4882a593Smuzhiyun		} else {
217*4882a593Smuzhiyun			and	A, OID, SCSIID;
218*4882a593Smuzhiyun		}
219*4882a593Smuzhiyun		or	SAVED_SCSIID, A;
220*4882a593Smuzhiyun		if ((ahc->features & AHC_TWIN) != 0) {
221*4882a593Smuzhiyun			test 	SBLKCTL, SELBUSB jz . + 2;
222*4882a593Smuzhiyun			or	SAVED_SCSIID, TWIN_CHNLB;
223*4882a593Smuzhiyun		}
224*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
225*4882a593Smuzhiyun			mov	CCSCBRAM, SAVED_SCSIID;
226*4882a593Smuzhiyun		} else {
227*4882a593Smuzhiyun			mov	DFDAT, SAVED_SCSIID;
228*4882a593Smuzhiyun		}
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun		/*
231*4882a593Smuzhiyun		 * If ATN isn't asserted, the target isn't interested
232*4882a593Smuzhiyun		 * in talking to us.  Go directly to bus free.
233*4882a593Smuzhiyun		 * XXX SCSI-1 may require us to assume lun 0 if
234*4882a593Smuzhiyun		 * ATN is false.
235*4882a593Smuzhiyun		 */
236*4882a593Smuzhiyun		test	SCSISIGI, ATNI	jz	target_busfree;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun		/*
239*4882a593Smuzhiyun		 * Watch ATN closely now as we pull in messages from the
240*4882a593Smuzhiyun		 * initiator.  We follow the guidlines from section 6.5
241*4882a593Smuzhiyun		 * of the SCSI-2 spec for what messages are allowed when.
242*4882a593Smuzhiyun		 */
243*4882a593Smuzhiyun		call	target_inb;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun		/*
246*4882a593Smuzhiyun		 * Our first message must be one of IDENTIFY, ABORT, or
247*4882a593Smuzhiyun		 * BUS_DEVICE_RESET.
248*4882a593Smuzhiyun		 */
249*4882a593Smuzhiyun		test	DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
250*4882a593Smuzhiyun		/* Store for host */
251*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
252*4882a593Smuzhiyun			mov	CCSCBRAM, DINDEX;
253*4882a593Smuzhiyun		} else {
254*4882a593Smuzhiyun			mov	DFDAT, DINDEX;
255*4882a593Smuzhiyun		}
256*4882a593Smuzhiyun		and	SAVED_LUN, MSG_IDENTIFY_LUNMASK, DINDEX;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun		/* Remember for disconnection decision */
259*4882a593Smuzhiyun		test	DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
260*4882a593Smuzhiyun		/* XXX Honor per target settings too */
261*4882a593Smuzhiyun		or	SEQ_FLAGS, NO_DISCONNECT;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun		test	SCSISIGI, ATNI	jz	ident_messages_done;
264*4882a593Smuzhiyun		call	target_inb;
265*4882a593Smuzhiyun		/*
266*4882a593Smuzhiyun		 * If this is a tagged request, the tagged message must
267*4882a593Smuzhiyun		 * immediately follow the identify.  We test for a valid
268*4882a593Smuzhiyun		 * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and
269*4882a593Smuzhiyun		 * < MSG_IGN_WIDE_RESIDUE.
270*4882a593Smuzhiyun		 */
271*4882a593Smuzhiyun		add	A, -MSG_SIMPLE_Q_TAG, DINDEX;
272*4882a593Smuzhiyun		jnc	ident_messages_done_msg_pending;
273*4882a593Smuzhiyun		add	A, -MSG_IGN_WIDE_RESIDUE, DINDEX;
274*4882a593Smuzhiyun		jc	ident_messages_done_msg_pending;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun		/* Store for host */
277*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
278*4882a593Smuzhiyun			mov	CCSCBRAM, DINDEX;
279*4882a593Smuzhiyun		} else {
280*4882a593Smuzhiyun			mov	DFDAT, DINDEX;
281*4882a593Smuzhiyun		}
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun		/*
284*4882a593Smuzhiyun		 * If the initiator doesn't feel like providing a tag number,
285*4882a593Smuzhiyun		 * we've got a failed selection and must transition to bus
286*4882a593Smuzhiyun		 * free.
287*4882a593Smuzhiyun		 */
288*4882a593Smuzhiyun		test	SCSISIGI, ATNI	jz	target_busfree;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun		/*
291*4882a593Smuzhiyun		 * Store the tag for the host.
292*4882a593Smuzhiyun		 */
293*4882a593Smuzhiyun		call	target_inb;
294*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
295*4882a593Smuzhiyun			mov	CCSCBRAM, DINDEX;
296*4882a593Smuzhiyun		} else {
297*4882a593Smuzhiyun			mov	DFDAT, DINDEX;
298*4882a593Smuzhiyun		}
299*4882a593Smuzhiyun		mov	INITIATOR_TAG, DINDEX;
300*4882a593Smuzhiyun		or	SEQ_FLAGS, TARGET_CMD_IS_TAGGED;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyunident_messages_done:
303*4882a593Smuzhiyun		/* Terminate the ident list */
304*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
305*4882a593Smuzhiyun			mvi	CCSCBRAM, SCB_LIST_NULL;
306*4882a593Smuzhiyun		} else {
307*4882a593Smuzhiyun			mvi	DFDAT, SCB_LIST_NULL;
308*4882a593Smuzhiyun		}
309*4882a593Smuzhiyun		or	SEQ_FLAGS, TARG_CMD_PENDING;
310*4882a593Smuzhiyun		test	SEQ_FLAGS2, TARGET_MSG_PENDING
311*4882a593Smuzhiyun			jnz target_mesgout_pending;
312*4882a593Smuzhiyun		test	SCSISIGI, ATNI jnz target_mesgout_continue;
313*4882a593Smuzhiyun		jmp	target_ITloop;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun
316*4882a593Smuzhiyunident_messages_done_msg_pending:
317*4882a593Smuzhiyun		or	SEQ_FLAGS2, TARGET_MSG_PENDING;
318*4882a593Smuzhiyun		jmp	ident_messages_done;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun		/*
321*4882a593Smuzhiyun		 * Pushed message loop to allow the kernel to
322*4882a593Smuzhiyun		 * run it's own target mode message state engine.
323*4882a593Smuzhiyun		 */
324*4882a593Smuzhiyunhost_target_message_loop:
325*4882a593Smuzhiyun		mvi	HOST_MSG_LOOP call set_seqint;
326*4882a593Smuzhiyun		cmp	RETURN_1, EXIT_MSG_LOOP	je target_ITloop;
327*4882a593Smuzhiyun		test	SSTAT0, SPIORDY jz .;
328*4882a593Smuzhiyun		jmp	host_target_message_loop;
329*4882a593Smuzhiyun	}
330*4882a593Smuzhiyun
331*4882a593Smuzhiyunif ((ahc->flags & AHC_INITIATORROLE) != 0) {
332*4882a593Smuzhiyun/*
333*4882a593Smuzhiyun * Reselection has been initiated by a target. Make a note that we've been
334*4882a593Smuzhiyun * reselected, but haven't seen an IDENTIFY message from the target yet.
335*4882a593Smuzhiyun */
336*4882a593Smuzhiyuninitiator_reselect:
337*4882a593Smuzhiyun	/* XXX test for and handle ONE BIT condition */
338*4882a593Smuzhiyun	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
339*4882a593Smuzhiyun	and	SAVED_SCSIID, SELID_MASK, SELID;
340*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
341*4882a593Smuzhiyun		and	A, OID, SCSIID_ULTRA2;
342*4882a593Smuzhiyun	} else {
343*4882a593Smuzhiyun		and	A, OID, SCSIID;
344*4882a593Smuzhiyun	}
345*4882a593Smuzhiyun	or	SAVED_SCSIID, A;
346*4882a593Smuzhiyun	if ((ahc->features & AHC_TWIN) != 0) {
347*4882a593Smuzhiyun		test	SBLKCTL, SELBUSB	jz . + 2;
348*4882a593Smuzhiyun		or	SAVED_SCSIID, TWIN_CHNLB;
349*4882a593Smuzhiyun	}
350*4882a593Smuzhiyun	mvi	CLRSINT0, CLRSELDI;
351*4882a593Smuzhiyun	jmp	ITloop;
352*4882a593Smuzhiyun}
353*4882a593Smuzhiyun
354*4882a593Smuzhiyunabort_qinscb:
355*4882a593Smuzhiyun	call	add_scb_to_free_list;
356*4882a593Smuzhiyun	jmp	poll_for_work_loop;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyunstart_selection:
359*4882a593Smuzhiyun	/*
360*4882a593Smuzhiyun	 * If bus reset interrupts have been disabled (from a previous
361*4882a593Smuzhiyun	 * reset), re-enable them now.  Resets are only of interest
362*4882a593Smuzhiyun	 * when we have outstanding transactions, so we can safely
363*4882a593Smuzhiyun	 * defer re-enabling the interrupt until, as an initiator,
364*4882a593Smuzhiyun	 * we start sending out transactions again.
365*4882a593Smuzhiyun	 */
366*4882a593Smuzhiyun	test	SIMODE1, ENSCSIRST	jnz . + 3;
367*4882a593Smuzhiyun	mvi	CLRSINT1, CLRSCSIRSTI;
368*4882a593Smuzhiyun	or	SIMODE1, ENSCSIRST;
369*4882a593Smuzhiyun	if ((ahc->features & AHC_TWIN) != 0) {
370*4882a593Smuzhiyun		and	SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
371*4882a593Smuzhiyun		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
372*4882a593Smuzhiyun		or	SINDEX, SELBUSB;
373*4882a593Smuzhiyun		mov	SBLKCTL,SINDEX;		/* select channel */
374*4882a593Smuzhiyun	}
375*4882a593Smuzhiyuninitialize_scsiid:
376*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
377*4882a593Smuzhiyun		mov	SCSIID_ULTRA2, SCB_SCSIID;
378*4882a593Smuzhiyun	} else if ((ahc->features & AHC_TWIN) != 0) {
379*4882a593Smuzhiyun		and	SCSIID, TWIN_TID|OID, SCB_SCSIID;
380*4882a593Smuzhiyun	} else {
381*4882a593Smuzhiyun		mov	SCSIID, SCB_SCSIID;
382*4882a593Smuzhiyun	}
383*4882a593Smuzhiyun	if ((ahc->flags & AHC_TARGETROLE) != 0) {
384*4882a593Smuzhiyun		mov	SINDEX, SCSISEQ_TEMPLATE;
385*4882a593Smuzhiyun		test	SCB_CONTROL, TARGET_SCB jz . + 2;
386*4882a593Smuzhiyun		or	SINDEX, TEMODE;
387*4882a593Smuzhiyun		mov	SCSISEQ, SINDEX ret;
388*4882a593Smuzhiyun	} else {
389*4882a593Smuzhiyun		mov	SCSISEQ, SCSISEQ_TEMPLATE ret;
390*4882a593Smuzhiyun	}
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun/*
393*4882a593Smuzhiyun * Initialize transfer settings with SCB provided settings.
394*4882a593Smuzhiyun */
395*4882a593Smuzhiyunset_transfer_settings:
396*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA) != 0) {
397*4882a593Smuzhiyun		test	SCB_CONTROL, ULTRAENB jz . + 2;
398*4882a593Smuzhiyun		or	SXFRCTL0, FAST20;
399*4882a593Smuzhiyun	}
400*4882a593Smuzhiyun	/*
401*4882a593Smuzhiyun	 * Initialize SCSIRATE with the appropriate value for this target.
402*4882a593Smuzhiyun	 */
403*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
404*4882a593Smuzhiyun		bmov	SCSIRATE, SCB_SCSIRATE, 2 ret;
405*4882a593Smuzhiyun	} else {
406*4882a593Smuzhiyun		mov	SCSIRATE, SCB_SCSIRATE ret;
407*4882a593Smuzhiyun	}
408*4882a593Smuzhiyun
409*4882a593Smuzhiyunif ((ahc->flags & AHC_TARGETROLE) != 0) {
410*4882a593Smuzhiyun/*
411*4882a593Smuzhiyun * We carefully toggle SPIOEN to allow us to return the
412*4882a593Smuzhiyun * message byte we receive so it can be checked prior to
413*4882a593Smuzhiyun * driving REQ on the bus for the next byte.
414*4882a593Smuzhiyun */
415*4882a593Smuzhiyuntarget_inb:
416*4882a593Smuzhiyun	/*
417*4882a593Smuzhiyun	 * Drive REQ on the bus by enabling SCSI PIO.
418*4882a593Smuzhiyun	 */
419*4882a593Smuzhiyun	or	SXFRCTL0, SPIOEN;
420*4882a593Smuzhiyun	/* Wait for the byte */
421*4882a593Smuzhiyun	test	SSTAT0, SPIORDY jz .;
422*4882a593Smuzhiyun	/* Prevent our read from triggering another REQ */
423*4882a593Smuzhiyun	and	SXFRCTL0, ~SPIOEN;
424*4882a593Smuzhiyun	/* Save latched contents */
425*4882a593Smuzhiyun	mov	DINDEX, SCSIDATL ret;
426*4882a593Smuzhiyun}
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun/*
429*4882a593Smuzhiyun * After the selection, remove this SCB from the "waiting SCB"
430*4882a593Smuzhiyun * list.  This is achieved by simply moving our "next" pointer into
431*4882a593Smuzhiyun * WAITING_SCBH.  Our next pointer will be set to null the next time this
432*4882a593Smuzhiyun * SCB is used, so don't bother with it now.
433*4882a593Smuzhiyun */
434*4882a593Smuzhiyunselect_out:
435*4882a593Smuzhiyun	/* Turn off the selection hardware */
436*4882a593Smuzhiyun	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
437*4882a593Smuzhiyun	mov	SCBPTR, WAITING_SCBH;
438*4882a593Smuzhiyun	mov	WAITING_SCBH,SCB_NEXT;
439*4882a593Smuzhiyun	mov	SAVED_SCSIID, SCB_SCSIID;
440*4882a593Smuzhiyun	and	SAVED_LUN, LID, SCB_LUN;
441*4882a593Smuzhiyun	call	set_transfer_settings;
442*4882a593Smuzhiyun	if ((ahc->flags & AHC_TARGETROLE) != 0) {
443*4882a593Smuzhiyun		test	SSTAT0, TARGET	jz initiator_select;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun		or	SXFRCTL0, CLRSTCNT|CLRCHN;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun		/*
448*4882a593Smuzhiyun		 * Put tag in connonical location since not
449*4882a593Smuzhiyun		 * all connections have an SCB.
450*4882a593Smuzhiyun		 */
451*4882a593Smuzhiyun		mov	INITIATOR_TAG, SCB_TARGET_ITAG;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun		/*
454*4882a593Smuzhiyun		 * We've just re-selected an initiator.
455*4882a593Smuzhiyun		 * Assert BSY and setup the phase for
456*4882a593Smuzhiyun		 * sending our identify messages.
457*4882a593Smuzhiyun		 */
458*4882a593Smuzhiyun		mvi	P_MESGIN|BSYO call change_phase;
459*4882a593Smuzhiyun		mvi	CLRSINT0, CLRSELDO;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun		/*
462*4882a593Smuzhiyun		 * Start out with a simple identify message.
463*4882a593Smuzhiyun		 */
464*4882a593Smuzhiyun		or	SAVED_LUN, MSG_IDENTIFYFLAG call target_outb;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun		/*
467*4882a593Smuzhiyun		 * If we are the result of a tagged command, send
468*4882a593Smuzhiyun		 * a simple Q tag and the tag id.
469*4882a593Smuzhiyun		 */
470*4882a593Smuzhiyun		test	SCB_CONTROL, TAG_ENB	jz . + 3;
471*4882a593Smuzhiyun		mvi	MSG_SIMPLE_Q_TAG call target_outb;
472*4882a593Smuzhiyun		mov	SCB_TARGET_ITAG call target_outb;
473*4882a593Smuzhiyuntarget_synccmd:
474*4882a593Smuzhiyun		/*
475*4882a593Smuzhiyun		 * Now determine what phases the host wants us
476*4882a593Smuzhiyun		 * to go through.
477*4882a593Smuzhiyun		 */
478*4882a593Smuzhiyun		mov	SEQ_FLAGS, SCB_TARGET_PHASES;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun		test	SCB_CONTROL, MK_MESSAGE	jz target_ITloop;
481*4882a593Smuzhiyun		mvi	P_MESGIN|BSYO call change_phase;
482*4882a593Smuzhiyun		jmp	host_target_message_loop;
483*4882a593Smuzhiyuntarget_ITloop:
484*4882a593Smuzhiyun		/*
485*4882a593Smuzhiyun		 * Start honoring ATN signals now that
486*4882a593Smuzhiyun		 * we properly identified ourselves.
487*4882a593Smuzhiyun		 */
488*4882a593Smuzhiyun		test	SCSISIGI, ATNI			jnz target_mesgout;
489*4882a593Smuzhiyun		test	SEQ_FLAGS, CMDPHASE_PENDING	jnz target_cmdphase;
490*4882a593Smuzhiyun		test	SEQ_FLAGS, DPHASE_PENDING	jnz target_dphase;
491*4882a593Smuzhiyun		test	SEQ_FLAGS, SPHASE_PENDING	jnz target_sphase;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun		/*
494*4882a593Smuzhiyun		 * No more work to do.  Either disconnect or not depending
495*4882a593Smuzhiyun		 * on the state of NO_DISCONNECT.
496*4882a593Smuzhiyun		 */
497*4882a593Smuzhiyun		test	SEQ_FLAGS, NO_DISCONNECT jz target_disconnect;
498*4882a593Smuzhiyun		mvi	TARG_IMMEDIATE_SCB, SCB_LIST_NULL;
499*4882a593Smuzhiyun		call	complete_target_cmd;
500*4882a593Smuzhiyun		if ((ahc->flags & AHC_PAGESCBS) != 0) {
501*4882a593Smuzhiyun			mov	ALLZEROS	call	get_free_or_disc_scb;
502*4882a593Smuzhiyun		}
503*4882a593Smuzhiyun		cmp	TARG_IMMEDIATE_SCB, SCB_LIST_NULL je .;
504*4882a593Smuzhiyun		mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
505*4882a593Smuzhiyun		mov	TARG_IMMEDIATE_SCB call dma_scb;
506*4882a593Smuzhiyun		call	set_transfer_settings;
507*4882a593Smuzhiyun		or	SXFRCTL0, CLRSTCNT|CLRCHN;
508*4882a593Smuzhiyun		jmp	target_synccmd;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyuntarget_mesgout:
511*4882a593Smuzhiyun		mvi	SCSISIGO, P_MESGOUT|BSYO;
512*4882a593Smuzhiyuntarget_mesgout_continue:
513*4882a593Smuzhiyun		call	target_inb;
514*4882a593Smuzhiyuntarget_mesgout_pending:
515*4882a593Smuzhiyun		and	SEQ_FLAGS2, ~TARGET_MSG_PENDING;
516*4882a593Smuzhiyun		/* Local Processing goes here... */
517*4882a593Smuzhiyun		jmp	host_target_message_loop;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyuntarget_disconnect:
520*4882a593Smuzhiyun		mvi	P_MESGIN|BSYO call change_phase;
521*4882a593Smuzhiyun		test	SEQ_FLAGS, DPHASE	jz . + 2;
522*4882a593Smuzhiyun		mvi	MSG_SAVEDATAPOINTER call target_outb;
523*4882a593Smuzhiyun		mvi	MSG_DISCONNECT call target_outb;
524*4882a593Smuzhiyun
525*4882a593Smuzhiyuntarget_busfree_wait:
526*4882a593Smuzhiyun		/* Wait for preceding I/O session to complete. */
527*4882a593Smuzhiyun		test	SCSISIGI, ACKI jnz .;
528*4882a593Smuzhiyuntarget_busfree:
529*4882a593Smuzhiyun		and	SIMODE1, ~ENBUSFREE;
530*4882a593Smuzhiyun		if ((ahc->features & AHC_ULTRA2) != 0) {
531*4882a593Smuzhiyun			clr	SCSIBUSL;
532*4882a593Smuzhiyun		}
533*4882a593Smuzhiyun		clr	SCSISIGO;
534*4882a593Smuzhiyun		mvi	LASTPHASE, P_BUSFREE;
535*4882a593Smuzhiyun		call	complete_target_cmd;
536*4882a593Smuzhiyun		jmp	poll_for_work;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyuntarget_cmdphase:
539*4882a593Smuzhiyun		/*
540*4882a593Smuzhiyun		 * The target has dropped ATN (doesn't want to abort or BDR)
541*4882a593Smuzhiyun		 * and we believe this selection to be valid.  If the ring
542*4882a593Smuzhiyun		 * buffer for new commands is full, return busy or queue full.
543*4882a593Smuzhiyun		 */
544*4882a593Smuzhiyun		if ((ahc->features & AHC_HS_MAILBOX) != 0) {
545*4882a593Smuzhiyun			and	A, HOST_TQINPOS, HS_MAILBOX;
546*4882a593Smuzhiyun		} else {
547*4882a593Smuzhiyun			mov	A, KERNEL_TQINPOS;
548*4882a593Smuzhiyun		}
549*4882a593Smuzhiyun		cmp	TQINPOS, A jne tqinfifo_has_space;
550*4882a593Smuzhiyun		mvi	P_STATUS|BSYO call change_phase;
551*4882a593Smuzhiyun		test	SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3;
552*4882a593Smuzhiyun		mvi	STATUS_QUEUE_FULL call target_outb;
553*4882a593Smuzhiyun		jmp	target_busfree_wait;
554*4882a593Smuzhiyun		mvi	STATUS_BUSY call target_outb;
555*4882a593Smuzhiyun		jmp	target_busfree_wait;
556*4882a593Smuzhiyuntqinfifo_has_space:
557*4882a593Smuzhiyun		mvi	P_COMMAND|BSYO call change_phase;
558*4882a593Smuzhiyun		call	target_inb;
559*4882a593Smuzhiyun		mov	A, DINDEX;
560*4882a593Smuzhiyun		/* Store for host */
561*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
562*4882a593Smuzhiyun			mov	CCSCBRAM, A;
563*4882a593Smuzhiyun		} else {
564*4882a593Smuzhiyun			mov	DFDAT, A;
565*4882a593Smuzhiyun		}
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun		/*
568*4882a593Smuzhiyun		 * Determine the number of bytes to read
569*4882a593Smuzhiyun		 * based on the command group code via table lookup.
570*4882a593Smuzhiyun		 * We reuse the first 8 bytes of the TARG_SCSIRATE
571*4882a593Smuzhiyun		 * BIOS array for this table. Count is one less than
572*4882a593Smuzhiyun		 * the total for the command since we've already fetched
573*4882a593Smuzhiyun		 * the first byte.
574*4882a593Smuzhiyun		 */
575*4882a593Smuzhiyun		shr	A, CMD_GROUP_CODE_SHIFT;
576*4882a593Smuzhiyun		add	SINDEX, CMDSIZE_TABLE, A;
577*4882a593Smuzhiyun		mov	A, SINDIR;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun		test	A, 0xFF jz command_phase_done;
580*4882a593Smuzhiyun		or	SXFRCTL0, SPIOEN;
581*4882a593Smuzhiyuncommand_loop:
582*4882a593Smuzhiyun		test	SSTAT0, SPIORDY jz .;
583*4882a593Smuzhiyun		cmp	A, 1 jne . + 2;
584*4882a593Smuzhiyun		and	SXFRCTL0, ~SPIOEN;	/* Last Byte */
585*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
586*4882a593Smuzhiyun			mov	CCSCBRAM, SCSIDATL;
587*4882a593Smuzhiyun		} else {
588*4882a593Smuzhiyun			mov	DFDAT, SCSIDATL;
589*4882a593Smuzhiyun		}
590*4882a593Smuzhiyun		dec	A;
591*4882a593Smuzhiyun		test	A, 0xFF jnz command_loop;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyuncommand_phase_done:
594*4882a593Smuzhiyun		and	SEQ_FLAGS, ~CMDPHASE_PENDING;
595*4882a593Smuzhiyun		jmp	target_ITloop;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyuntarget_dphase:
598*4882a593Smuzhiyun		/*
599*4882a593Smuzhiyun		 * Data phases on the bus are from the
600*4882a593Smuzhiyun		 * perspective of the initiator.  The dma
601*4882a593Smuzhiyun		 * code looks at LASTPHASE to determine the
602*4882a593Smuzhiyun		 * data direction of the DMA.  Toggle it for
603*4882a593Smuzhiyun		 * target transfers.
604*4882a593Smuzhiyun		 */
605*4882a593Smuzhiyun		xor	LASTPHASE, IOI, SCB_TARGET_DATA_DIR;
606*4882a593Smuzhiyun		or	SCB_TARGET_DATA_DIR, BSYO call change_phase;
607*4882a593Smuzhiyun		jmp	p_data;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyuntarget_sphase:
610*4882a593Smuzhiyun		mvi	P_STATUS|BSYO call change_phase;
611*4882a593Smuzhiyun		mvi	LASTPHASE, P_STATUS;
612*4882a593Smuzhiyun		mov	SCB_SCSI_STATUS call target_outb;
613*4882a593Smuzhiyun		/* XXX Watch for ATN or parity errors??? */
614*4882a593Smuzhiyun		mvi	SCSISIGO, P_MESGIN|BSYO;
615*4882a593Smuzhiyun		/* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
616*4882a593Smuzhiyun		mov	ALLZEROS call target_outb;
617*4882a593Smuzhiyun		jmp	target_busfree_wait;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyuncomplete_target_cmd:
620*4882a593Smuzhiyun		test	SEQ_FLAGS, TARG_CMD_PENDING	jnz . + 2;
621*4882a593Smuzhiyun		mov	SCB_TAG jmp complete_post;
622*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
623*4882a593Smuzhiyun			/* Set the valid byte */
624*4882a593Smuzhiyun			mvi	CCSCBADDR, 24;
625*4882a593Smuzhiyun			mov	CCSCBRAM, ALLONES;
626*4882a593Smuzhiyun			mvi	CCHCNT, 28;
627*4882a593Smuzhiyun			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
628*4882a593Smuzhiyun			test	CCSCBCTL, CCSCBDONE jz .;
629*4882a593Smuzhiyun			clr	CCSCBCTL;
630*4882a593Smuzhiyun		} else {
631*4882a593Smuzhiyun			/* Set the valid byte */
632*4882a593Smuzhiyun			or	DFCNTRL, FIFORESET;
633*4882a593Smuzhiyun			mvi	DFWADDR, 3; /* Third 64bit word or byte 24 */
634*4882a593Smuzhiyun			mov	DFDAT, ALLONES;
635*4882a593Smuzhiyun			mvi	28	call set_hcnt;
636*4882a593Smuzhiyun			or	DFCNTRL, HDMAEN|FIFOFLUSH;
637*4882a593Smuzhiyun			call	dma_finish;
638*4882a593Smuzhiyun		}
639*4882a593Smuzhiyun		inc	TQINPOS;
640*4882a593Smuzhiyun		mvi	INTSTAT,CMDCMPLT ret;
641*4882a593Smuzhiyun	}
642*4882a593Smuzhiyun
643*4882a593Smuzhiyunif ((ahc->flags & AHC_INITIATORROLE) != 0) {
644*4882a593Smuzhiyuninitiator_select:
645*4882a593Smuzhiyun	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
646*4882a593Smuzhiyun	/*
647*4882a593Smuzhiyun	 * As soon as we get a successful selection, the target
648*4882a593Smuzhiyun	 * should go into the message out phase since we have ATN
649*4882a593Smuzhiyun	 * asserted.
650*4882a593Smuzhiyun	 */
651*4882a593Smuzhiyun	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
652*4882a593Smuzhiyun	mvi	SEQ_FLAGS, NO_CDB_SENT;
653*4882a593Smuzhiyun	mvi	CLRSINT0, CLRSELDO;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun	/*
656*4882a593Smuzhiyun	 * Main loop for information transfer phases.  Wait for the
657*4882a593Smuzhiyun	 * target to assert REQ before checking MSG, C/D and I/O for
658*4882a593Smuzhiyun	 * the bus phase.
659*4882a593Smuzhiyun	 */
660*4882a593Smuzhiyunmesgin_phasemis:
661*4882a593SmuzhiyunITloop:
662*4882a593Smuzhiyun	call	phase_lock;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun	mov	A, LASTPHASE;
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun	test	A, ~P_DATAIN	jz p_data;
667*4882a593Smuzhiyun	cmp	A,P_COMMAND	je p_command;
668*4882a593Smuzhiyun	cmp	A,P_MESGOUT	je p_mesgout;
669*4882a593Smuzhiyun	cmp	A,P_STATUS	je p_status;
670*4882a593Smuzhiyun	cmp	A,P_MESGIN	je p_mesgin;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun	mvi	BAD_PHASE call set_seqint;
673*4882a593Smuzhiyun	jmp	ITloop;			/* Try reading the bus again. */
674*4882a593Smuzhiyun
675*4882a593Smuzhiyunawait_busfree:
676*4882a593Smuzhiyun	and	SIMODE1, ~ENBUSFREE;
677*4882a593Smuzhiyun	mov	NONE, SCSIDATL;		/* Ack the last byte */
678*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
679*4882a593Smuzhiyun		clr	SCSIBUSL;	/* Prevent bit leakage durint SELTO */
680*4882a593Smuzhiyun	}
681*4882a593Smuzhiyun	and	SXFRCTL0, ~SPIOEN;
682*4882a593Smuzhiyun	mvi	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT;
683*4882a593Smuzhiyun	test	SSTAT1,REQINIT|BUSFREE	jz .;
684*4882a593Smuzhiyun	test	SSTAT1, BUSFREE jnz poll_for_work;
685*4882a593Smuzhiyun	mvi	MISSED_BUSFREE call set_seqint;
686*4882a593Smuzhiyun}
687*4882a593Smuzhiyun
688*4882a593Smuzhiyunclear_target_state:
689*4882a593Smuzhiyun	/*
690*4882a593Smuzhiyun	 * We assume that the kernel driver may reset us
691*4882a593Smuzhiyun	 * at any time, even in the middle of a DMA, so
692*4882a593Smuzhiyun	 * clear DFCNTRL too.
693*4882a593Smuzhiyun	 */
694*4882a593Smuzhiyun	clr	DFCNTRL;
695*4882a593Smuzhiyun	or	SXFRCTL0, CLRSTCNT|CLRCHN;
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun	/*
698*4882a593Smuzhiyun	 * We don't know the target we will connect to,
699*4882a593Smuzhiyun	 * so default to narrow transfers to avoid
700*4882a593Smuzhiyun	 * parity problems.
701*4882a593Smuzhiyun	 */
702*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
703*4882a593Smuzhiyun		bmov	SCSIRATE, ALLZEROS, 2;
704*4882a593Smuzhiyun	} else {
705*4882a593Smuzhiyun		clr	SCSIRATE;
706*4882a593Smuzhiyun		if ((ahc->features & AHC_ULTRA) != 0) {
707*4882a593Smuzhiyun			and	SXFRCTL0, ~(FAST20);
708*4882a593Smuzhiyun		}
709*4882a593Smuzhiyun	}
710*4882a593Smuzhiyun	mvi	LASTPHASE, P_BUSFREE;
711*4882a593Smuzhiyun	/* clear target specific flags */
712*4882a593Smuzhiyun	mvi	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;
713*4882a593Smuzhiyun
714*4882a593Smuzhiyunsg_advance:
715*4882a593Smuzhiyun	clr	A;			/* add sizeof(struct scatter) */
716*4882a593Smuzhiyun	add	SCB_RESIDUAL_SGPTR[0],SG_SIZEOF;
717*4882a593Smuzhiyun	adc	SCB_RESIDUAL_SGPTR[1],A;
718*4882a593Smuzhiyun	adc	SCB_RESIDUAL_SGPTR[2],A;
719*4882a593Smuzhiyun	adc	SCB_RESIDUAL_SGPTR[3],A ret;
720*4882a593Smuzhiyun
721*4882a593Smuzhiyunif ((ahc->features & AHC_CMD_CHAN) != 0) {
722*4882a593Smuzhiyundisable_ccsgen:
723*4882a593Smuzhiyun	test	CCSGCTL, CCSGEN jz return;
724*4882a593Smuzhiyun	test	CCSGCTL, CCSGDONE jz .;
725*4882a593Smuzhiyundisable_ccsgen_fetch_done:
726*4882a593Smuzhiyun	clr	CCSGCTL;
727*4882a593Smuzhiyun	test	CCSGCTL, CCSGEN jnz .;
728*4882a593Smuzhiyun	ret;
729*4882a593Smuzhiyunidle_loop:
730*4882a593Smuzhiyun	/*
731*4882a593Smuzhiyun	 * Do we need any more segments for this transfer?
732*4882a593Smuzhiyun	 */
733*4882a593Smuzhiyun	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun	/* Did we just finish fetching segs? */
736*4882a593Smuzhiyun	cmp	CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun	/* Are we actively fetching segments? */
739*4882a593Smuzhiyun	test	CCSGCTL, CCSGEN jnz return;
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun	/*
742*4882a593Smuzhiyun	 * Do we have any prefetch left???
743*4882a593Smuzhiyun	 */
744*4882a593Smuzhiyun	cmp	CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun	/*
747*4882a593Smuzhiyun	 * Need to fetch segments, but we can only do that
748*4882a593Smuzhiyun	 * if the command channel is completely idle.  Make
749*4882a593Smuzhiyun	 * sure we don't have an SCB prefetch going on.
750*4882a593Smuzhiyun	 */
751*4882a593Smuzhiyun	test	CCSCBCTL, CCSCBEN jnz return;
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun	/*
754*4882a593Smuzhiyun	 * We fetch a "cacheline aligned" and sized amount of data
755*4882a593Smuzhiyun	 * so we don't end up referencing a non-existent page.
756*4882a593Smuzhiyun	 * Cacheline aligned is in quotes because the kernel will
757*4882a593Smuzhiyun	 * set the prefetch amount to a reasonable level if the
758*4882a593Smuzhiyun	 * cacheline size is unknown.
759*4882a593Smuzhiyun	 */
760*4882a593Smuzhiyun	mvi	CCHCNT, SG_PREFETCH_CNT;
761*4882a593Smuzhiyun	and	CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
762*4882a593Smuzhiyun	bmov	CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
763*4882a593Smuzhiyun	mvi	CCSGCTL, CCSGEN|CCSGRESET ret;
764*4882a593Smuzhiyunidle_sgfetch_complete:
765*4882a593Smuzhiyun	call	disable_ccsgen_fetch_done;
766*4882a593Smuzhiyun	and	CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;
767*4882a593Smuzhiyunidle_sg_avail:
768*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
769*4882a593Smuzhiyun		/* Does the hardware have space for another SG entry? */
770*4882a593Smuzhiyun		test	DFSTATUS, PRELOAD_AVAIL jz return;
771*4882a593Smuzhiyun		bmov 	HADDR, CCSGRAM, 7;
772*4882a593Smuzhiyun		bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
773*4882a593Smuzhiyun		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
774*4882a593Smuzhiyun			mov	SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
775*4882a593Smuzhiyun		}
776*4882a593Smuzhiyun		call	sg_advance;
777*4882a593Smuzhiyun		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
778*4882a593Smuzhiyun		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
779*4882a593Smuzhiyun		or	SINDEX, LAST_SEG;
780*4882a593Smuzhiyun		mov	SG_CACHE_PRE, SINDEX;
781*4882a593Smuzhiyun		/* Load the segment */
782*4882a593Smuzhiyun		or	DFCNTRL, PRELOADEN;
783*4882a593Smuzhiyun	}
784*4882a593Smuzhiyun	ret;
785*4882a593Smuzhiyun}
786*4882a593Smuzhiyun
787*4882a593Smuzhiyunif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
788*4882a593Smuzhiyun/*
789*4882a593Smuzhiyun * Calculate the trailing portion of this S/G segment that cannot
790*4882a593Smuzhiyun * be transferred using memory write and invalidate PCI transactions.
791*4882a593Smuzhiyun * XXX Can we optimize this for PCI writes only???
792*4882a593Smuzhiyun */
793*4882a593Smuzhiyuncalc_mwi_residual:
794*4882a593Smuzhiyun	/*
795*4882a593Smuzhiyun	 * If the ending address is on a cacheline boundary,
796*4882a593Smuzhiyun	 * there is no need for an extra segment.
797*4882a593Smuzhiyun	 */
798*4882a593Smuzhiyun	mov	A, HCNT[0];
799*4882a593Smuzhiyun	add	A, A, HADDR[0];
800*4882a593Smuzhiyun	and	A, CACHESIZE_MASK;
801*4882a593Smuzhiyun	test	A, 0xFF jz return;
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun	/*
804*4882a593Smuzhiyun	 * If the transfer is less than a cachline,
805*4882a593Smuzhiyun	 * there is no need for an extra segment.
806*4882a593Smuzhiyun	 */
807*4882a593Smuzhiyun	test	HCNT[1], 0xFF	jnz calc_mwi_residual_final;
808*4882a593Smuzhiyun	test	HCNT[2], 0xFF	jnz calc_mwi_residual_final;
809*4882a593Smuzhiyun	add	NONE, INVERTED_CACHESIZE_MASK, HCNT[0];
810*4882a593Smuzhiyun	jnc	return;
811*4882a593Smuzhiyun
812*4882a593Smuzhiyuncalc_mwi_residual_final:
813*4882a593Smuzhiyun	mov	MWI_RESIDUAL, A;
814*4882a593Smuzhiyun	not	A;
815*4882a593Smuzhiyun	inc	A;
816*4882a593Smuzhiyun	add	HCNT[0], A;
817*4882a593Smuzhiyun	adc	HCNT[1], -1;
818*4882a593Smuzhiyun	adc	HCNT[2], -1 ret;
819*4882a593Smuzhiyun}
820*4882a593Smuzhiyun
821*4882a593Smuzhiyunp_data:
822*4882a593Smuzhiyun	test	SEQ_FLAGS,NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed;
823*4882a593Smuzhiyun	mvi	PROTO_VIOLATION call set_seqint;
824*4882a593Smuzhiyunp_data_allowed:
825*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
826*4882a593Smuzhiyun		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
827*4882a593Smuzhiyun	} else {
828*4882a593Smuzhiyun		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
829*4882a593Smuzhiyun	}
830*4882a593Smuzhiyun	test	LASTPHASE, IOI jnz . + 2;
831*4882a593Smuzhiyun	or	DMAPARAMS, DIRECTION;
832*4882a593Smuzhiyun	if ((ahc->features & AHC_CMD_CHAN) != 0) {
833*4882a593Smuzhiyun		/* We don't have any valid S/G elements */
834*4882a593Smuzhiyun		mvi	CCSGADDR, SG_PREFETCH_CNT;
835*4882a593Smuzhiyun	}
836*4882a593Smuzhiyun	test	SEQ_FLAGS, DPHASE	jz data_phase_initialize;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun	/*
839*4882a593Smuzhiyun	 * If we re-enter the data phase after going through another
840*4882a593Smuzhiyun	 * phase, our transfer location has almost certainly been
841*4882a593Smuzhiyun	 * corrupted by the interveining, non-data, transfers.  Ask
842*4882a593Smuzhiyun	 * the host driver to fix us up based on the transfer residual.
843*4882a593Smuzhiyun	 */
844*4882a593Smuzhiyun	mvi	PDATA_REINIT	call set_seqint;
845*4882a593Smuzhiyun	jmp	data_phase_loop;
846*4882a593Smuzhiyun
847*4882a593Smuzhiyundata_phase_initialize:
848*4882a593Smuzhiyun	/* We have seen a data phase for the first time */
849*4882a593Smuzhiyun	or	SEQ_FLAGS, DPHASE;
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun	/*
852*4882a593Smuzhiyun	 * Initialize the DMA address and counter from the SCB.
853*4882a593Smuzhiyun	 * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG
854*4882a593Smuzhiyun	 * flag in the highest byte of the data count.  We cannot
855*4882a593Smuzhiyun	 * modify the saved values in the SCB until we see a save
856*4882a593Smuzhiyun	 * data pointers message.
857*4882a593Smuzhiyun	 */
858*4882a593Smuzhiyun	if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
859*4882a593Smuzhiyun		/* The lowest address byte must be loaded last. */
860*4882a593Smuzhiyun		mov	SCB_DATACNT[3] call set_hhaddr;
861*4882a593Smuzhiyun	}
862*4882a593Smuzhiyun	if ((ahc->features & AHC_CMD_CHAN) != 0) {
863*4882a593Smuzhiyun		bmov	HADDR, SCB_DATAPTR, 7;
864*4882a593Smuzhiyun		bmov	SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
865*4882a593Smuzhiyun	} else {
866*4882a593Smuzhiyun		mvi	DINDEX, HADDR;
867*4882a593Smuzhiyun		mvi	SCB_DATAPTR	call bcopy_7;
868*4882a593Smuzhiyun		mvi	DINDEX, SCB_RESIDUAL_DATACNT + 3;
869*4882a593Smuzhiyun		mvi	SCB_DATACNT + 3 call bcopy_5;
870*4882a593Smuzhiyun	}
871*4882a593Smuzhiyun	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
872*4882a593Smuzhiyun		call	calc_mwi_residual;
873*4882a593Smuzhiyun	}
874*4882a593Smuzhiyun	and	SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) == 0) {
877*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
878*4882a593Smuzhiyun			bmov	STCNT, HCNT, 3;
879*4882a593Smuzhiyun		} else {
880*4882a593Smuzhiyun			call	set_stcnt_from_hcnt;
881*4882a593Smuzhiyun		}
882*4882a593Smuzhiyun	}
883*4882a593Smuzhiyun
884*4882a593Smuzhiyundata_phase_loop:
885*4882a593Smuzhiyun	/* Guard against overruns */
886*4882a593Smuzhiyun	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun	/*
889*4882a593Smuzhiyun	 * Turn on `Bit Bucket' mode, wait until the target takes
890*4882a593Smuzhiyun	 * us to another phase, and then notify the host.
891*4882a593Smuzhiyun	 */
892*4882a593Smuzhiyun	and	DMAPARAMS, DIRECTION;
893*4882a593Smuzhiyun	mov	DFCNTRL, DMAPARAMS;
894*4882a593Smuzhiyun	or	SXFRCTL1,BITBUCKET;
895*4882a593Smuzhiyun	if ((ahc->features & AHC_DT) == 0) {
896*4882a593Smuzhiyun		test	SSTAT1,PHASEMIS	jz .;
897*4882a593Smuzhiyun	} else {
898*4882a593Smuzhiyun		test	SCSIPHASE, DATA_PHASE_MASK jnz .;
899*4882a593Smuzhiyun	}
900*4882a593Smuzhiyun	and	SXFRCTL1, ~BITBUCKET;
901*4882a593Smuzhiyun	mvi	DATA_OVERRUN call set_seqint;
902*4882a593Smuzhiyun	jmp	ITloop;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyundata_phase_inbounds:
905*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
906*4882a593Smuzhiyun		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
907*4882a593Smuzhiyun		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
908*4882a593Smuzhiyun		or	SINDEX, LAST_SEG;
909*4882a593Smuzhiyun		mov	SG_CACHE_PRE, SINDEX;
910*4882a593Smuzhiyun		mov	DFCNTRL, DMAPARAMS;
911*4882a593Smuzhiyunultra2_dma_loop:
912*4882a593Smuzhiyun		call	idle_loop;
913*4882a593Smuzhiyun		/*
914*4882a593Smuzhiyun		 * The transfer is complete if either the last segment
915*4882a593Smuzhiyun		 * completes or the target changes phase.
916*4882a593Smuzhiyun		 */
917*4882a593Smuzhiyun		test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
918*4882a593Smuzhiyun		if ((ahc->features & AHC_DT) == 0) {
919*4882a593Smuzhiyun			if ((ahc->flags & AHC_TARGETROLE) != 0) {
920*4882a593Smuzhiyun				 /*
921*4882a593Smuzhiyun				  * As a target, we control the phases,
922*4882a593Smuzhiyun				  * so ignore PHASEMIS.
923*4882a593Smuzhiyun				  */
924*4882a593Smuzhiyun				test	SSTAT0, TARGET jnz ultra2_dma_loop;
925*4882a593Smuzhiyun			}
926*4882a593Smuzhiyun			if ((ahc->flags & AHC_INITIATORROLE) != 0) {
927*4882a593Smuzhiyun				test	SSTAT1,PHASEMIS	jz ultra2_dma_loop;
928*4882a593Smuzhiyun			}
929*4882a593Smuzhiyun		} else {
930*4882a593Smuzhiyun			test	DFCNTRL, SCSIEN jnz ultra2_dma_loop;
931*4882a593Smuzhiyun		}
932*4882a593Smuzhiyun
933*4882a593Smuzhiyunultra2_dmafinish:
934*4882a593Smuzhiyun		/*
935*4882a593Smuzhiyun		 * The transfer has terminated either due to a phase
936*4882a593Smuzhiyun		 * change, and/or the completion of the last segment.
937*4882a593Smuzhiyun		 * We have two goals here.  Do as much other work
938*4882a593Smuzhiyun		 * as possible while the data fifo drains on a read
939*4882a593Smuzhiyun		 * and respond as quickly as possible to the standard
940*4882a593Smuzhiyun		 * messages (save data pointers/disconnect and command
941*4882a593Smuzhiyun		 * complete) that usually follow a data phase.
942*4882a593Smuzhiyun		 */
943*4882a593Smuzhiyun		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
944*4882a593Smuzhiyun			/*
945*4882a593Smuzhiyun			 * On chips with broken auto-flush, start
946*4882a593Smuzhiyun			 * the flushing process now.  We'll poke
947*4882a593Smuzhiyun			 * the chip from time to time to keep the
948*4882a593Smuzhiyun			 * flush process going as we complete the
949*4882a593Smuzhiyun			 * data phase.
950*4882a593Smuzhiyun			 */
951*4882a593Smuzhiyun			or	DFCNTRL, FIFOFLUSH;
952*4882a593Smuzhiyun		}
953*4882a593Smuzhiyun		/*
954*4882a593Smuzhiyun		 * We assume that, even though data may still be
955*4882a593Smuzhiyun		 * transferring to the host, that the SCSI side of
956*4882a593Smuzhiyun		 * the DMA engine is now in a static state.  This
957*4882a593Smuzhiyun		 * allows us to update our notion of where we are
958*4882a593Smuzhiyun		 * in this transfer.
959*4882a593Smuzhiyun		 *
960*4882a593Smuzhiyun		 * If, by chance, we stopped before being able
961*4882a593Smuzhiyun		 * to fetch additional segments for this transfer,
962*4882a593Smuzhiyun		 * yet the last S/G was completely exhausted,
963*4882a593Smuzhiyun		 * call our idle loop until it is able to load
964*4882a593Smuzhiyun		 * another segment.  This will allow us to immediately
965*4882a593Smuzhiyun		 * pickup on the next segment on the next data phase.
966*4882a593Smuzhiyun		 *
967*4882a593Smuzhiyun		 * If we happened to stop on the last segment, then
968*4882a593Smuzhiyun		 * our residual information is still correct from
969*4882a593Smuzhiyun		 * the idle loop and there is no need to perform
970*4882a593Smuzhiyun		 * any fixups.
971*4882a593Smuzhiyun		 */
972*4882a593Smuzhiyunultra2_ensure_sg:
973*4882a593Smuzhiyun		test	SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid;
974*4882a593Smuzhiyun		/* Record if we've consumed all S/G entries */
975*4882a593Smuzhiyun		test	SSTAT2, SHVALID	jnz residuals_correct;
976*4882a593Smuzhiyun		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
977*4882a593Smuzhiyun		jmp	residuals_correct;
978*4882a593Smuzhiyun
979*4882a593Smuzhiyunultra2_shvalid:
980*4882a593Smuzhiyun		test	SSTAT2, SHVALID	jnz sgptr_fixup;
981*4882a593Smuzhiyun		call	idle_loop;
982*4882a593Smuzhiyun		jmp	ultra2_ensure_sg;
983*4882a593Smuzhiyun
984*4882a593Smuzhiyunsgptr_fixup:
985*4882a593Smuzhiyun		/*
986*4882a593Smuzhiyun		 * Fixup the residual next S/G pointer.  The S/G preload
987*4882a593Smuzhiyun		 * feature of the chip allows us to load two elements
988*4882a593Smuzhiyun		 * in addition to the currently active element.  We
989*4882a593Smuzhiyun		 * store the bottom byte of the next S/G pointer in
990*4882a593Smuzhiyun		 * the SG_CACEPTR register so we can restore the
991*4882a593Smuzhiyun		 * correct value when the DMA completes.  If the next
992*4882a593Smuzhiyun		 * sg ptr value has advanced to the point where higher
993*4882a593Smuzhiyun		 * bytes in the address have been affected, fix them
994*4882a593Smuzhiyun		 * too.
995*4882a593Smuzhiyun		 */
996*4882a593Smuzhiyun		test	SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done;
997*4882a593Smuzhiyun		test	SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done;
998*4882a593Smuzhiyun		add	SCB_RESIDUAL_SGPTR[1], -1;
999*4882a593Smuzhiyun		adc	SCB_RESIDUAL_SGPTR[2], -1;
1000*4882a593Smuzhiyun		adc	SCB_RESIDUAL_SGPTR[3], -1;
1001*4882a593Smuzhiyunsgptr_fixup_done:
1002*4882a593Smuzhiyun		and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
1003*4882a593Smuzhiyun		/* We are not the last seg */
1004*4882a593Smuzhiyun		and	SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG;
1005*4882a593Smuzhiyunresiduals_correct:
1006*4882a593Smuzhiyun		/*
1007*4882a593Smuzhiyun		 * Go ahead and shut down the DMA engine now.
1008*4882a593Smuzhiyun		 * In the future, we'll want to handle end of
1009*4882a593Smuzhiyun		 * transfer messages prior to doing this, but this
1010*4882a593Smuzhiyun		 * requires similar restructuring for pre-ULTRA2
1011*4882a593Smuzhiyun		 * controllers.
1012*4882a593Smuzhiyun		 */
1013*4882a593Smuzhiyun		test	DMAPARAMS, DIRECTION jnz ultra2_fifoempty;
1014*4882a593Smuzhiyunultra2_fifoflush:
1015*4882a593Smuzhiyun		if ((ahc->features & AHC_DT) == 0) {
1016*4882a593Smuzhiyun			if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
1017*4882a593Smuzhiyun				/*
1018*4882a593Smuzhiyun				 * On Rev A of the aic7890, the autoflush
1019*4882a593Smuzhiyun				 * feature doesn't function correctly.
1020*4882a593Smuzhiyun				 * Perform an explicit manual flush.  During
1021*4882a593Smuzhiyun				 * a manual flush, the FIFOEMP bit becomes
1022*4882a593Smuzhiyun				 * true every time the PCI FIFO empties
1023*4882a593Smuzhiyun				 * regardless of the state of the SCSI FIFO.
1024*4882a593Smuzhiyun				 * It can take up to 4 clock cycles for the
1025*4882a593Smuzhiyun				 * SCSI FIFO to get data into the PCI FIFO
1026*4882a593Smuzhiyun				 * and for FIFOEMP to de-assert.  Here we
1027*4882a593Smuzhiyun				 * guard against this condition by making
1028*4882a593Smuzhiyun				 * sure the FIFOEMP bit stays on for 5 full
1029*4882a593Smuzhiyun				 * clock cycles.
1030*4882a593Smuzhiyun				 */
1031*4882a593Smuzhiyun				or	DFCNTRL, FIFOFLUSH;
1032*4882a593Smuzhiyun				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
1033*4882a593Smuzhiyun				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
1034*4882a593Smuzhiyun				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
1035*4882a593Smuzhiyun				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
1036*4882a593Smuzhiyun			}
1037*4882a593Smuzhiyun			test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
1038*4882a593Smuzhiyun		} else {
1039*4882a593Smuzhiyun			/*
1040*4882a593Smuzhiyun			 * We enable the auto-ack feature on DT capable
1041*4882a593Smuzhiyun			 * controllers.  This means that the controller may
1042*4882a593Smuzhiyun			 * have already transferred some overrun bytes into
1043*4882a593Smuzhiyun			 * the data FIFO and acked them on the bus.  The only
1044*4882a593Smuzhiyun			 * way to detect this situation is to wait for
1045*4882a593Smuzhiyun			 * LAST_SEG_DONE to come true on a completed transfer
1046*4882a593Smuzhiyun			 * and then test to see if the data FIFO is non-empty.
1047*4882a593Smuzhiyun			 */
1048*4882a593Smuzhiyun			test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL
1049*4882a593Smuzhiyun				jz ultra2_wait_fifoemp;
1050*4882a593Smuzhiyun			test	SG_CACHE_SHADOW, LAST_SEG_DONE jz .;
1051*4882a593Smuzhiyun			/*
1052*4882a593Smuzhiyun			 * FIFOEMP can lag LAST_SEG_DONE.  Wait a few
1053*4882a593Smuzhiyun			 * clocks before calling this an overrun.
1054*4882a593Smuzhiyun			 */
1055*4882a593Smuzhiyun			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
1056*4882a593Smuzhiyun			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
1057*4882a593Smuzhiyun			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
1058*4882a593Smuzhiyun			/* Overrun */
1059*4882a593Smuzhiyun			jmp	data_phase_loop;
1060*4882a593Smuzhiyunultra2_wait_fifoemp:
1061*4882a593Smuzhiyun			test	DFSTATUS, FIFOEMP jz .;
1062*4882a593Smuzhiyun		}
1063*4882a593Smuzhiyunultra2_fifoempty:
1064*4882a593Smuzhiyun		/* Don't clobber an inprogress host data transfer */
1065*4882a593Smuzhiyun		test	DFSTATUS, MREQPEND	jnz ultra2_fifoempty;
1066*4882a593Smuzhiyunultra2_dmahalt:
1067*4882a593Smuzhiyun		and     DFCNTRL, ~(SCSIEN|HDMAEN);
1068*4882a593Smuzhiyun		test	DFCNTRL, SCSIEN|HDMAEN jnz .;
1069*4882a593Smuzhiyun		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
1070*4882a593Smuzhiyun			/*
1071*4882a593Smuzhiyun			 * Keep HHADDR cleared for future, 32bit addressed
1072*4882a593Smuzhiyun			 * only, DMA operations.
1073*4882a593Smuzhiyun			 *
1074*4882a593Smuzhiyun			 * Due to bayonette style S/G handling, our residual
1075*4882a593Smuzhiyun			 * data must be "fixed up" once the transfer is halted.
1076*4882a593Smuzhiyun			 * Here we fixup the HSHADDR stored in the high byte
1077*4882a593Smuzhiyun			 * of the residual data cnt.  By postponing the fixup,
1078*4882a593Smuzhiyun			 * we can batch the clearing of HADDR with the fixup.
1079*4882a593Smuzhiyun			 * If we halted on the last segment, the residual is
1080*4882a593Smuzhiyun			 * already correct.   If we are not on the last
1081*4882a593Smuzhiyun			 * segment, copy the high address directly from HSHADDR.
1082*4882a593Smuzhiyun			 * We don't need to worry about maintaining the
1083*4882a593Smuzhiyun			 * SG_LAST_SEG flag as it will always be false in the
1084*4882a593Smuzhiyun			 * case where an update is required.
1085*4882a593Smuzhiyun			 */
1086*4882a593Smuzhiyun			or	DSCOMMAND1, HADDLDSEL0;
1087*4882a593Smuzhiyun			test	SG_CACHE_SHADOW, LAST_SEG jnz . + 2;
1088*4882a593Smuzhiyun			mov	SCB_RESIDUAL_DATACNT[3], SHADDR;
1089*4882a593Smuzhiyun			clr	HADDR;
1090*4882a593Smuzhiyun			and	DSCOMMAND1, ~HADDLDSEL0;
1091*4882a593Smuzhiyun		}
1092*4882a593Smuzhiyun	} else {
1093*4882a593Smuzhiyun		/* If we are the last SG block, tell the hardware. */
1094*4882a593Smuzhiyun		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
1095*4882a593Smuzhiyun		  && ahc->pci_cachesize != 0) {
1096*4882a593Smuzhiyun			test	MWI_RESIDUAL, 0xFF jnz dma_mid_sg;
1097*4882a593Smuzhiyun		}
1098*4882a593Smuzhiyun		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
1099*4882a593Smuzhiyun		if ((ahc->flags & AHC_TARGETROLE) != 0) {
1100*4882a593Smuzhiyun			test	SSTAT0, TARGET jz dma_last_sg;
1101*4882a593Smuzhiyun			if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) {
1102*4882a593Smuzhiyun				test	DMAPARAMS, DIRECTION jz dma_mid_sg;
1103*4882a593Smuzhiyun			}
1104*4882a593Smuzhiyun		}
1105*4882a593Smuzhiyundma_last_sg:
1106*4882a593Smuzhiyun		and	DMAPARAMS, ~WIDEODD;
1107*4882a593Smuzhiyundma_mid_sg:
1108*4882a593Smuzhiyun		/* Start DMA data transfer. */
1109*4882a593Smuzhiyun		mov	DFCNTRL, DMAPARAMS;
1110*4882a593Smuzhiyundma_loop:
1111*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
1112*4882a593Smuzhiyun			call	idle_loop;
1113*4882a593Smuzhiyun		}
1114*4882a593Smuzhiyun		test	SSTAT0,DMADONE	jnz dma_dmadone;
1115*4882a593Smuzhiyun		test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
1116*4882a593Smuzhiyundma_phasemis:
1117*4882a593Smuzhiyun		/*
1118*4882a593Smuzhiyun		 * We will be "done" DMAing when the transfer count goes to
1119*4882a593Smuzhiyun		 * zero, or the target changes the phase (in light of this,
1120*4882a593Smuzhiyun		 * it makes sense that the DMA circuitry doesn't ACK when
1121*4882a593Smuzhiyun		 * PHASEMIS is active).  If we are doing a SCSI->Host transfer,
1122*4882a593Smuzhiyun		 * the data FIFO should be flushed auto-magically on STCNT=0
1123*4882a593Smuzhiyun		 * or a phase change, so just wait for FIFO empty status.
1124*4882a593Smuzhiyun		 */
1125*4882a593Smuzhiyundma_checkfifo:
1126*4882a593Smuzhiyun		test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
1127*4882a593Smuzhiyundma_fifoflush:
1128*4882a593Smuzhiyun		test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
1129*4882a593Smuzhiyundma_fifoempty:
1130*4882a593Smuzhiyun		/* Don't clobber an inprogress host data transfer */
1131*4882a593Smuzhiyun		test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun		/*
1134*4882a593Smuzhiyun		 * Now shut off the DMA and make sure that the DMA
1135*4882a593Smuzhiyun		 * hardware has actually stopped.  Touching the DMA
1136*4882a593Smuzhiyun		 * counters, etc. while a DMA is active will result
1137*4882a593Smuzhiyun		 * in an ILLSADDR exception.
1138*4882a593Smuzhiyun		 */
1139*4882a593Smuzhiyundma_dmadone:
1140*4882a593Smuzhiyun		and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
1141*4882a593Smuzhiyundma_halt:
1142*4882a593Smuzhiyun		/*
1143*4882a593Smuzhiyun		 * Some revisions of the aic78XX have a problem where, if the
1144*4882a593Smuzhiyun		 * data fifo is full, but the PCI input latch is not empty,
1145*4882a593Smuzhiyun		 * HDMAEN cannot be cleared.  The fix used here is to drain
1146*4882a593Smuzhiyun		 * the prefetched but unused data from the data fifo until
1147*4882a593Smuzhiyun		 * there is space for the input latch to drain.
1148*4882a593Smuzhiyun		 */
1149*4882a593Smuzhiyun		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
1150*4882a593Smuzhiyun			mov	NONE, DFDAT;
1151*4882a593Smuzhiyun		}
1152*4882a593Smuzhiyun		test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun		/* See if we have completed this last segment */
1155*4882a593Smuzhiyun		test	STCNT[0], 0xff	jnz data_phase_finish;
1156*4882a593Smuzhiyun		test	STCNT[1], 0xff	jnz data_phase_finish;
1157*4882a593Smuzhiyun		test	STCNT[2], 0xff	jnz data_phase_finish;
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun		/*
1160*4882a593Smuzhiyun		 * Advance the scatter-gather pointers if needed
1161*4882a593Smuzhiyun		 */
1162*4882a593Smuzhiyun		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
1163*4882a593Smuzhiyun		  && ahc->pci_cachesize != 0) {
1164*4882a593Smuzhiyun			test	MWI_RESIDUAL, 0xFF jz no_mwi_resid;
1165*4882a593Smuzhiyun			/*
1166*4882a593Smuzhiyun			 * Reload HADDR from SHADDR and setup the
1167*4882a593Smuzhiyun			 * count to be the size of our residual.
1168*4882a593Smuzhiyun			 */
1169*4882a593Smuzhiyun			if ((ahc->features & AHC_CMD_CHAN) != 0) {
1170*4882a593Smuzhiyun				bmov	HADDR, SHADDR, 4;
1171*4882a593Smuzhiyun				mov	HCNT, MWI_RESIDUAL;
1172*4882a593Smuzhiyun				bmov	HCNT[1], ALLZEROS, 2;
1173*4882a593Smuzhiyun			} else {
1174*4882a593Smuzhiyun				mvi	DINDEX, HADDR;
1175*4882a593Smuzhiyun				mvi	SHADDR call bcopy_4;
1176*4882a593Smuzhiyun				mov	MWI_RESIDUAL call set_hcnt;
1177*4882a593Smuzhiyun			}
1178*4882a593Smuzhiyun			clr	MWI_RESIDUAL;
1179*4882a593Smuzhiyun			jmp	sg_load_done;
1180*4882a593Smuzhiyunno_mwi_resid:
1181*4882a593Smuzhiyun		}
1182*4882a593Smuzhiyun		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load;
1183*4882a593Smuzhiyun		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
1184*4882a593Smuzhiyun		jmp	data_phase_finish;
1185*4882a593Smuzhiyunsg_load:
1186*4882a593Smuzhiyun		/*
1187*4882a593Smuzhiyun		 * Load the next SG element's data address and length
1188*4882a593Smuzhiyun		 * into the DMA engine.  If we don't have hardware
1189*4882a593Smuzhiyun		 * to perform a prefetch, we'll have to fetch the
1190*4882a593Smuzhiyun		 * segment from host memory first.
1191*4882a593Smuzhiyun		 */
1192*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
1193*4882a593Smuzhiyun			/* Wait for the idle loop to complete */
1194*4882a593Smuzhiyun			test	CCSGCTL, CCSGEN jz . + 3;
1195*4882a593Smuzhiyun			call	idle_loop;
1196*4882a593Smuzhiyun			test	CCSGCTL, CCSGEN jnz . - 1;
1197*4882a593Smuzhiyun			bmov 	HADDR, CCSGRAM, 7;
1198*4882a593Smuzhiyun			/*
1199*4882a593Smuzhiyun			 * Workaround for flaky external SCB RAM
1200*4882a593Smuzhiyun			 * on certain aic7895 setups.  It seems
1201*4882a593Smuzhiyun			 * unable to handle direct transfers from
1202*4882a593Smuzhiyun			 * S/G ram to certain SCB locations.
1203*4882a593Smuzhiyun			 */
1204*4882a593Smuzhiyun			mov	SINDEX, CCSGRAM;
1205*4882a593Smuzhiyun			mov	SCB_RESIDUAL_DATACNT[3], SINDEX;
1206*4882a593Smuzhiyun		} else {
1207*4882a593Smuzhiyun			if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
1208*4882a593Smuzhiyun				mov	ALLZEROS call set_hhaddr;
1209*4882a593Smuzhiyun			}
1210*4882a593Smuzhiyun			mvi	DINDEX, HADDR;
1211*4882a593Smuzhiyun			mvi	SCB_RESIDUAL_SGPTR	call bcopy_4;
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun			mvi	SG_SIZEOF	call set_hcnt;
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun			or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun			call	dma_finish;
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun			mvi	DINDEX, HADDR;
1220*4882a593Smuzhiyun			call	dfdat_in_7;
1221*4882a593Smuzhiyun			mov	SCB_RESIDUAL_DATACNT[3], DFDAT;
1222*4882a593Smuzhiyun		}
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
1225*4882a593Smuzhiyun			mov	SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun			/*
1228*4882a593Smuzhiyun			 * The lowest address byte must be loaded
1229*4882a593Smuzhiyun			 * last as it triggers the computation of
1230*4882a593Smuzhiyun			 * some items in the PCI block.  The ULTRA2
1231*4882a593Smuzhiyun			 * chips do this on PRELOAD.
1232*4882a593Smuzhiyun			 */
1233*4882a593Smuzhiyun			mov	HADDR, HADDR;
1234*4882a593Smuzhiyun		}
1235*4882a593Smuzhiyun		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
1236*4882a593Smuzhiyun		  && ahc->pci_cachesize != 0) {
1237*4882a593Smuzhiyun			call calc_mwi_residual;
1238*4882a593Smuzhiyun		}
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun		/* Point to the new next sg in memory */
1241*4882a593Smuzhiyun		call	sg_advance;
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyunsg_load_done:
1244*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
1245*4882a593Smuzhiyun			bmov	STCNT, HCNT, 3;
1246*4882a593Smuzhiyun		} else {
1247*4882a593Smuzhiyun			call	set_stcnt_from_hcnt;
1248*4882a593Smuzhiyun		}
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun		if ((ahc->flags & AHC_TARGETROLE) != 0) {
1251*4882a593Smuzhiyun			test	SSTAT0, TARGET jnz data_phase_loop;
1252*4882a593Smuzhiyun		}
1253*4882a593Smuzhiyun	}
1254*4882a593Smuzhiyundata_phase_finish:
1255*4882a593Smuzhiyun	/*
1256*4882a593Smuzhiyun	 * If the target has left us in data phase, loop through
1257*4882a593Smuzhiyun	 * the dma code again.  In the case of ULTRA2 adapters,
1258*4882a593Smuzhiyun	 * we should only loop if there is a data overrun.  For
1259*4882a593Smuzhiyun	 * all other adapters, we'll loop after each S/G element
1260*4882a593Smuzhiyun	 * is loaded as well as if there is an overrun.
1261*4882a593Smuzhiyun	 */
1262*4882a593Smuzhiyun	if ((ahc->flags & AHC_TARGETROLE) != 0) {
1263*4882a593Smuzhiyun		test	SSTAT0, TARGET jnz data_phase_done;
1264*4882a593Smuzhiyun	}
1265*4882a593Smuzhiyun	if ((ahc->flags & AHC_INITIATORROLE) != 0) {
1266*4882a593Smuzhiyun		test	SSTAT1, REQINIT jz .;
1267*4882a593Smuzhiyun		if ((ahc->features & AHC_DT) == 0) {
1268*4882a593Smuzhiyun			test	SSTAT1,PHASEMIS	jz data_phase_loop;
1269*4882a593Smuzhiyun		} else {
1270*4882a593Smuzhiyun			test	SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop;
1271*4882a593Smuzhiyun		}
1272*4882a593Smuzhiyun	}
1273*4882a593Smuzhiyun
1274*4882a593Smuzhiyundata_phase_done:
1275*4882a593Smuzhiyun	/*
1276*4882a593Smuzhiyun	 * After a DMA finishes, save the SG and STCNT residuals back into
1277*4882a593Smuzhiyun	 * the SCB.  We use STCNT instead of HCNT, since it's a reflection
1278*4882a593Smuzhiyun	 * of how many bytes were transferred on the SCSI (as opposed to the
1279*4882a593Smuzhiyun	 * host) bus.
1280*4882a593Smuzhiyun	 */
1281*4882a593Smuzhiyun	if ((ahc->features & AHC_CMD_CHAN) != 0) {
1282*4882a593Smuzhiyun		/* Kill off any pending prefetch */
1283*4882a593Smuzhiyun		call	disable_ccsgen;
1284*4882a593Smuzhiyun	}
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) == 0) {
1287*4882a593Smuzhiyun		/*
1288*4882a593Smuzhiyun		 * Clear the high address byte so that all other DMA
1289*4882a593Smuzhiyun		 * operations, which use 32bit addressing, can assume
1290*4882a593Smuzhiyun		 * HHADDR is 0.
1291*4882a593Smuzhiyun		 */
1292*4882a593Smuzhiyun		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
1293*4882a593Smuzhiyun			mov	ALLZEROS call set_hhaddr;
1294*4882a593Smuzhiyun		}
1295*4882a593Smuzhiyun	}
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun	/*
1298*4882a593Smuzhiyun	 * Update our residual information before the information is
1299*4882a593Smuzhiyun	 * lost by some other type of SCSI I/O (e.g. PIO).  If we have
1300*4882a593Smuzhiyun	 * transferred all data, no update is needed.
1301*4882a593Smuzhiyun	 *
1302*4882a593Smuzhiyun	 */
1303*4882a593Smuzhiyun	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done;
1304*4882a593Smuzhiyun	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
1305*4882a593Smuzhiyun	  && ahc->pci_cachesize != 0) {
1306*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
1307*4882a593Smuzhiyun			test	MWI_RESIDUAL, 0xFF jz bmov_resid;
1308*4882a593Smuzhiyun		}
1309*4882a593Smuzhiyun		mov	A, MWI_RESIDUAL;
1310*4882a593Smuzhiyun		add	SCB_RESIDUAL_DATACNT[0], A, STCNT[0];
1311*4882a593Smuzhiyun		clr	A;
1312*4882a593Smuzhiyun		adc	SCB_RESIDUAL_DATACNT[1], A, STCNT[1];
1313*4882a593Smuzhiyun		adc	SCB_RESIDUAL_DATACNT[2], A, STCNT[2];
1314*4882a593Smuzhiyun		clr	MWI_RESIDUAL;
1315*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
1316*4882a593Smuzhiyun			jmp	. + 2;
1317*4882a593Smuzhiyunbmov_resid:
1318*4882a593Smuzhiyun			bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
1319*4882a593Smuzhiyun		}
1320*4882a593Smuzhiyun	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
1321*4882a593Smuzhiyun		bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
1322*4882a593Smuzhiyun	} else {
1323*4882a593Smuzhiyun		mov	SCB_RESIDUAL_DATACNT[0], STCNT[0];
1324*4882a593Smuzhiyun		mov	SCB_RESIDUAL_DATACNT[1], STCNT[1];
1325*4882a593Smuzhiyun		mov	SCB_RESIDUAL_DATACNT[2], STCNT[2];
1326*4882a593Smuzhiyun	}
1327*4882a593Smuzhiyunresidual_update_done:
1328*4882a593Smuzhiyun	/*
1329*4882a593Smuzhiyun	 * Since we've been through a data phase, the SCB_RESID* fields
1330*4882a593Smuzhiyun	 * are now initialized.  Clear the full residual flag.
1331*4882a593Smuzhiyun	 */
1332*4882a593Smuzhiyun	and	SCB_SGPTR[0], ~SG_FULL_RESID;
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
1335*4882a593Smuzhiyun		/* Clear the channel in case we return to data phase later */
1336*4882a593Smuzhiyun		or	SXFRCTL0, CLRSTCNT|CLRCHN;
1337*4882a593Smuzhiyun		or	SXFRCTL0, CLRSTCNT|CLRCHN;
1338*4882a593Smuzhiyun	}
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun	if ((ahc->flags & AHC_TARGETROLE) != 0) {
1341*4882a593Smuzhiyun		test	SEQ_FLAGS, DPHASE_PENDING jz ITloop;
1342*4882a593Smuzhiyun		and	SEQ_FLAGS, ~DPHASE_PENDING;
1343*4882a593Smuzhiyun		/*
1344*4882a593Smuzhiyun		 * For data-in phases, wait for any pending acks from the
1345*4882a593Smuzhiyun		 * initiator before changing phase.  We only need to
1346*4882a593Smuzhiyun		 * send Ignore Wide Residue messages for data-in phases.
1347*4882a593Smuzhiyun		 */
1348*4882a593Smuzhiyun		test	DFCNTRL, DIRECTION jz target_ITloop;
1349*4882a593Smuzhiyun		test	SSTAT1, REQINIT	jnz .;
1350*4882a593Smuzhiyun		test	SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop;
1351*4882a593Smuzhiyun		test	SCSIRATE, WIDEXFER jz target_ITloop;
1352*4882a593Smuzhiyun		/*
1353*4882a593Smuzhiyun		 * Issue an Ignore Wide Residue Message.
1354*4882a593Smuzhiyun		 */
1355*4882a593Smuzhiyun		mvi	P_MESGIN|BSYO call change_phase;
1356*4882a593Smuzhiyun		mvi	MSG_IGN_WIDE_RESIDUE call target_outb;
1357*4882a593Smuzhiyun		mvi	1 call target_outb;
1358*4882a593Smuzhiyun		jmp	target_ITloop;
1359*4882a593Smuzhiyun	} else {
1360*4882a593Smuzhiyun		jmp	ITloop;
1361*4882a593Smuzhiyun	}
1362*4882a593Smuzhiyun
1363*4882a593Smuzhiyunif ((ahc->flags & AHC_INITIATORROLE) != 0) {
1364*4882a593Smuzhiyun/*
1365*4882a593Smuzhiyun * Command phase.  Set up the DMA registers and let 'er rip.
1366*4882a593Smuzhiyun */
1367*4882a593Smuzhiyunp_command:
1368*4882a593Smuzhiyun	test	SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay;
1369*4882a593Smuzhiyun	mvi	PROTO_VIOLATION call set_seqint;
1370*4882a593Smuzhiyunp_command_okay:
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
1373*4882a593Smuzhiyun		bmov	HCNT[0], SCB_CDB_LEN,  1;
1374*4882a593Smuzhiyun		bmov	HCNT[1], ALLZEROS, 2;
1375*4882a593Smuzhiyun		mvi	SG_CACHE_PRE, LAST_SEG;
1376*4882a593Smuzhiyun	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
1377*4882a593Smuzhiyun		bmov	STCNT[0], SCB_CDB_LEN, 1;
1378*4882a593Smuzhiyun		bmov	STCNT[1], ALLZEROS, 2;
1379*4882a593Smuzhiyun	} else {
1380*4882a593Smuzhiyun		mov	STCNT[0], SCB_CDB_LEN;
1381*4882a593Smuzhiyun		clr	STCNT[1];
1382*4882a593Smuzhiyun		clr	STCNT[2];
1383*4882a593Smuzhiyun	}
1384*4882a593Smuzhiyun	add	NONE, -13, SCB_CDB_LEN;
1385*4882a593Smuzhiyun	mvi	SCB_CDB_STORE jnc p_command_embedded;
1386*4882a593Smuzhiyunp_command_from_host:
1387*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
1388*4882a593Smuzhiyun		bmov	HADDR[0], SCB_CDB_PTR, 4;
1389*4882a593Smuzhiyun		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
1390*4882a593Smuzhiyun	} else {
1391*4882a593Smuzhiyun		if ((ahc->features & AHC_CMD_CHAN) != 0) {
1392*4882a593Smuzhiyun			bmov	HADDR[0], SCB_CDB_PTR, 4;
1393*4882a593Smuzhiyun			bmov	HCNT, STCNT, 3;
1394*4882a593Smuzhiyun		} else {
1395*4882a593Smuzhiyun			mvi	DINDEX, HADDR;
1396*4882a593Smuzhiyun			mvi	SCB_CDB_PTR call bcopy_4;
1397*4882a593Smuzhiyun			mov	SCB_CDB_LEN call set_hcnt;
1398*4882a593Smuzhiyun		}
1399*4882a593Smuzhiyun		mvi	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
1400*4882a593Smuzhiyun	}
1401*4882a593Smuzhiyun	jmp	p_command_xfer;
1402*4882a593Smuzhiyunp_command_embedded:
1403*4882a593Smuzhiyun	/*
1404*4882a593Smuzhiyun	 * The data fifo seems to require 4 byte aligned
1405*4882a593Smuzhiyun	 * transfers from the sequencer.  Force this to
1406*4882a593Smuzhiyun	 * be the case by clearing HADDR[0] even though
1407*4882a593Smuzhiyun	 * we aren't going to touch host memory.
1408*4882a593Smuzhiyun	 */
1409*4882a593Smuzhiyun	clr	HADDR[0];
1410*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
1411*4882a593Smuzhiyun		mvi	DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
1412*4882a593Smuzhiyun		bmov	DFDAT, SCB_CDB_STORE, 12;
1413*4882a593Smuzhiyun	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
1414*4882a593Smuzhiyun		if ((ahc->flags & AHC_SCB_BTT) != 0) {
1415*4882a593Smuzhiyun			/*
1416*4882a593Smuzhiyun			 * On the 7895 the data FIFO will
1417*4882a593Smuzhiyun			 * get corrupted if you try to dump
1418*4882a593Smuzhiyun			 * data from external SCB memory into
1419*4882a593Smuzhiyun			 * the FIFO while it is enabled.  So,
1420*4882a593Smuzhiyun			 * fill the fifo and then enable SCSI
1421*4882a593Smuzhiyun			 * transfers.
1422*4882a593Smuzhiyun			 */
1423*4882a593Smuzhiyun			mvi	DFCNTRL, (DIRECTION|FIFORESET);
1424*4882a593Smuzhiyun		} else {
1425*4882a593Smuzhiyun			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
1426*4882a593Smuzhiyun		}
1427*4882a593Smuzhiyun		bmov	DFDAT, SCB_CDB_STORE, 12;
1428*4882a593Smuzhiyun		if ((ahc->flags & AHC_SCB_BTT) != 0) {
1429*4882a593Smuzhiyun			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH);
1430*4882a593Smuzhiyun		} else {
1431*4882a593Smuzhiyun			or	DFCNTRL, FIFOFLUSH;
1432*4882a593Smuzhiyun		}
1433*4882a593Smuzhiyun	} else {
1434*4882a593Smuzhiyun		mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
1435*4882a593Smuzhiyun		call	copy_to_fifo_6;
1436*4882a593Smuzhiyun		call	copy_to_fifo_6;
1437*4882a593Smuzhiyun		or	DFCNTRL, FIFOFLUSH;
1438*4882a593Smuzhiyun	}
1439*4882a593Smuzhiyunp_command_xfer:
1440*4882a593Smuzhiyun	and	SEQ_FLAGS, ~NO_CDB_SENT;
1441*4882a593Smuzhiyun	if ((ahc->features & AHC_DT) == 0) {
1442*4882a593Smuzhiyun		test	SSTAT0, SDONE jnz . + 2;
1443*4882a593Smuzhiyun		test    SSTAT1, PHASEMIS jz . - 1;
1444*4882a593Smuzhiyun		/*
1445*4882a593Smuzhiyun		 * Wait for our ACK to go-away on it's own
1446*4882a593Smuzhiyun		 * instead of being killed by SCSIEN getting cleared.
1447*4882a593Smuzhiyun		 */
1448*4882a593Smuzhiyun		test	SCSISIGI, ACKI jnz .;
1449*4882a593Smuzhiyun	} else {
1450*4882a593Smuzhiyun		test	DFCNTRL, SCSIEN jnz .;
1451*4882a593Smuzhiyun	}
1452*4882a593Smuzhiyun	test	SSTAT0, SDONE jnz p_command_successful;
1453*4882a593Smuzhiyun	/*
1454*4882a593Smuzhiyun	 * Don't allow a data phase if the command
1455*4882a593Smuzhiyun	 * was not fully transferred.
1456*4882a593Smuzhiyun	 */
1457*4882a593Smuzhiyun	or	SEQ_FLAGS, NO_CDB_SENT;
1458*4882a593Smuzhiyunp_command_successful:
1459*4882a593Smuzhiyun	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
1460*4882a593Smuzhiyun	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
1461*4882a593Smuzhiyun	jmp	ITloop;
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun/*
1464*4882a593Smuzhiyun * Status phase.  Wait for the data byte to appear, then read it
1465*4882a593Smuzhiyun * and store it into the SCB.
1466*4882a593Smuzhiyun */
1467*4882a593Smuzhiyunp_status:
1468*4882a593Smuzhiyun	test	SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation;
1469*4882a593Smuzhiyunp_status_okay:
1470*4882a593Smuzhiyun	mov	SCB_SCSI_STATUS, SCSIDATL;
1471*4882a593Smuzhiyun	or	SCB_CONTROL, STATUS_RCVD;
1472*4882a593Smuzhiyun	jmp	ITloop;
1473*4882a593Smuzhiyun
1474*4882a593Smuzhiyun/*
1475*4882a593Smuzhiyun * Message out phase.  If MSG_OUT is MSG_IDENTIFYFLAG, build a full
1476*4882a593Smuzhiyun * indentify message sequence and send it to the target.  The host may
1477*4882a593Smuzhiyun * override this behavior by setting the MK_MESSAGE bit in the SCB
1478*4882a593Smuzhiyun * control byte.  This will cause us to interrupt the host and allow
1479*4882a593Smuzhiyun * it to handle the message phase completely on its own.  If the bit
1480*4882a593Smuzhiyun * associated with this target is set, we will also interrupt the host,
1481*4882a593Smuzhiyun * thereby allowing it to send a message on the next selection regardless
1482*4882a593Smuzhiyun * of the transaction being sent.
1483*4882a593Smuzhiyun *
1484*4882a593Smuzhiyun * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
1485*4882a593Smuzhiyun * This is done to allow the host to send messages outside of an identify
1486*4882a593Smuzhiyun * sequence while protecting the seqencer from testing the MK_MESSAGE bit
1487*4882a593Smuzhiyun * on an SCB that might not be for the current nexus. (For example, a
1488*4882a593Smuzhiyun * BDR message in response to a bad reselection would leave us pointed to
1489*4882a593Smuzhiyun * an SCB that doesn't have anything to do with the current target).
1490*4882a593Smuzhiyun *
1491*4882a593Smuzhiyun * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
1492*4882a593Smuzhiyun * bus device reset).
1493*4882a593Smuzhiyun *
1494*4882a593Smuzhiyun * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
1495*4882a593Smuzhiyun * in case the target decides to put us in this phase for some strange
1496*4882a593Smuzhiyun * reason.
1497*4882a593Smuzhiyun */
1498*4882a593Smuzhiyunp_mesgout_retry:
1499*4882a593Smuzhiyun	/* Turn on ATN for the retry */
1500*4882a593Smuzhiyun	if ((ahc->features & AHC_DT) == 0) {
1501*4882a593Smuzhiyun		or	SCSISIGO, ATNO, LASTPHASE;
1502*4882a593Smuzhiyun	} else {
1503*4882a593Smuzhiyun		mvi	SCSISIGO, ATNO;
1504*4882a593Smuzhiyun	}
1505*4882a593Smuzhiyunp_mesgout:
1506*4882a593Smuzhiyun	mov	SINDEX, MSG_OUT;
1507*4882a593Smuzhiyun	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
1508*4882a593Smuzhiyun	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
1509*4882a593Smuzhiyunp_mesgout_identify:
1510*4882a593Smuzhiyun	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN;
1511*4882a593Smuzhiyun	test	SCB_CONTROL, DISCENB jnz . + 2;
1512*4882a593Smuzhiyun	and	SINDEX, ~DISCENB;
1513*4882a593Smuzhiyun/*
1514*4882a593Smuzhiyun * Send a tag message if TAG_ENB is set in the SCB control block.
1515*4882a593Smuzhiyun * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
1516*4882a593Smuzhiyun */
1517*4882a593Smuzhiyunp_mesgout_tag:
1518*4882a593Smuzhiyun	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
1519*4882a593Smuzhiyun	mov	SCSIDATL, SINDEX;	/* Send the identify message */
1520*4882a593Smuzhiyun	call	phase_lock;
1521*4882a593Smuzhiyun	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
1522*4882a593Smuzhiyun	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
1523*4882a593Smuzhiyun	call	phase_lock;
1524*4882a593Smuzhiyun	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
1525*4882a593Smuzhiyun	mov	SCB_TAG	jmp p_mesgout_onebyte;
1526*4882a593Smuzhiyun/*
1527*4882a593Smuzhiyun * Interrupt the driver, and allow it to handle this message
1528*4882a593Smuzhiyun * phase and any required retries.
1529*4882a593Smuzhiyun */
1530*4882a593Smuzhiyunp_mesgout_from_host:
1531*4882a593Smuzhiyun	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
1532*4882a593Smuzhiyun	jmp	host_message_loop;
1533*4882a593Smuzhiyun
1534*4882a593Smuzhiyunp_mesgout_onebyte:
1535*4882a593Smuzhiyun	mvi	CLRSINT1, CLRATNO;
1536*4882a593Smuzhiyun	mov	SCSIDATL, SINDEX;
1537*4882a593Smuzhiyun
1538*4882a593Smuzhiyun/*
1539*4882a593Smuzhiyun * If the next bus phase after ATN drops is message out, it means
1540*4882a593Smuzhiyun * that the target is requesting that the last message(s) be resent.
1541*4882a593Smuzhiyun */
1542*4882a593Smuzhiyun	call	phase_lock;
1543*4882a593Smuzhiyun	cmp	LASTPHASE, P_MESGOUT	je p_mesgout_retry;
1544*4882a593Smuzhiyun
1545*4882a593Smuzhiyunp_mesgout_done:
1546*4882a593Smuzhiyun	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
1547*4882a593Smuzhiyun	mov	LAST_MSG, MSG_OUT;
1548*4882a593Smuzhiyun	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
1549*4882a593Smuzhiyun	jmp	ITloop;
1550*4882a593Smuzhiyun
1551*4882a593Smuzhiyun/*
1552*4882a593Smuzhiyun * Message in phase.  Bytes are read using Automatic PIO mode.
1553*4882a593Smuzhiyun */
1554*4882a593Smuzhiyunp_mesgin:
1555*4882a593Smuzhiyun	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
1556*4882a593Smuzhiyun
1557*4882a593Smuzhiyun	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
1558*4882a593Smuzhiyun	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
1559*4882a593Smuzhiyun	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
1560*4882a593Smuzhiyun	cmp	ALLZEROS,A		je mesgin_complete;
1561*4882a593Smuzhiyun	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
1562*4882a593Smuzhiyun	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_ign_wide_residue;
1563*4882a593Smuzhiyun	cmp	A,MSG_NOOP		je mesgin_done;
1564*4882a593Smuzhiyun
1565*4882a593Smuzhiyun/*
1566*4882a593Smuzhiyun * Pushed message loop to allow the kernel to
1567*4882a593Smuzhiyun * run it's own message state engine.  To avoid an
1568*4882a593Smuzhiyun * extra nop instruction after signaling the kernel,
1569*4882a593Smuzhiyun * we perform the phase_lock before checking to see
1570*4882a593Smuzhiyun * if we should exit the loop and skip the phase_lock
1571*4882a593Smuzhiyun * in the ITloop.  Performing back to back phase_locks
1572*4882a593Smuzhiyun * shouldn't hurt, but why do it twice...
1573*4882a593Smuzhiyun */
1574*4882a593Smuzhiyunhost_message_loop:
1575*4882a593Smuzhiyun	mvi	HOST_MSG_LOOP call set_seqint;
1576*4882a593Smuzhiyun	call	phase_lock;
1577*4882a593Smuzhiyun	cmp	RETURN_1, EXIT_MSG_LOOP	je ITloop + 1;
1578*4882a593Smuzhiyun	jmp	host_message_loop;
1579*4882a593Smuzhiyun
1580*4882a593Smuzhiyunmesgin_ign_wide_residue:
1581*4882a593Smuzhiyunif ((ahc->features & AHC_WIDE) != 0) {
1582*4882a593Smuzhiyun	test	SCSIRATE, WIDEXFER jz mesgin_reject;
1583*4882a593Smuzhiyun	/* Pull the residue byte */
1584*4882a593Smuzhiyun	mvi	ARG_1	call inb_next;
1585*4882a593Smuzhiyun	cmp	ARG_1, 0x01 jne mesgin_reject;
1586*4882a593Smuzhiyun	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
1587*4882a593Smuzhiyun	test	SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done;
1588*4882a593Smuzhiyun	mvi	IGN_WIDE_RES call set_seqint;
1589*4882a593Smuzhiyun	jmp	mesgin_done;
1590*4882a593Smuzhiyun}
1591*4882a593Smuzhiyun
1592*4882a593Smuzhiyunmesgin_proto_violation:
1593*4882a593Smuzhiyun	mvi	PROTO_VIOLATION call set_seqint;
1594*4882a593Smuzhiyun	jmp	mesgin_done;
1595*4882a593Smuzhiyunmesgin_reject:
1596*4882a593Smuzhiyun	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
1597*4882a593Smuzhiyunmesgin_done:
1598*4882a593Smuzhiyun	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
1599*4882a593Smuzhiyun	jmp	ITloop;
1600*4882a593Smuzhiyun
1601*4882a593Smuzhiyun/*
1602*4882a593Smuzhiyun * We received a "command complete" message.  Put the SCB_TAG into the QOUTFIFO,
1603*4882a593Smuzhiyun * and trigger a completion interrupt.  Before doing so, check to see if there
1604*4882a593Smuzhiyun * is a residual or the status byte is something other than STATUS_GOOD (0).
1605*4882a593Smuzhiyun * In either of these conditions, we upload the SCB back to the host so it can
1606*4882a593Smuzhiyun * process this information.  In the case of a non zero status byte, we
1607*4882a593Smuzhiyun * additionally interrupt the kernel driver synchronously, allowing it to
1608*4882a593Smuzhiyun * decide if sense should be retrieved.  If the kernel driver wishes to request
1609*4882a593Smuzhiyun * sense, it will fill the kernel SCB with a request sense command, requeue
1610*4882a593Smuzhiyun * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting
1611*4882a593Smuzhiyun * RETURN_1 to SEND_SENSE.
1612*4882a593Smuzhiyun */
1613*4882a593Smuzhiyunmesgin_complete:
1614*4882a593Smuzhiyun
1615*4882a593Smuzhiyun	/*
1616*4882a593Smuzhiyun	 * If ATN is raised, we still want to give the target a message.
1617*4882a593Smuzhiyun	 * Perhaps there was a parity error on this last message byte.
1618*4882a593Smuzhiyun	 * Either way, the target should take us to message out phase
1619*4882a593Smuzhiyun	 * and then attempt to complete the command again.  We should use a
1620*4882a593Smuzhiyun	 * critical section here to guard against a timeout triggering
1621*4882a593Smuzhiyun	 * for this command and setting ATN while we are still processing
1622*4882a593Smuzhiyun	 * the completion.
1623*4882a593Smuzhiyun	test	SCSISIGI, ATNI jnz mesgin_done;
1624*4882a593Smuzhiyun	 */
1625*4882a593Smuzhiyun
1626*4882a593Smuzhiyun	/*
1627*4882a593Smuzhiyun	 * If we are identified and have successfully sent the CDB,
1628*4882a593Smuzhiyun	 * any status will do.  Optimize this fast path.
1629*4882a593Smuzhiyun	 */
1630*4882a593Smuzhiyun	test	SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation;
1631*4882a593Smuzhiyun	test	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted;
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun	/*
1634*4882a593Smuzhiyun	 * If the target never sent an identify message but instead went
1635*4882a593Smuzhiyun	 * to mesgin to give an invalid message, let the host abort us.
1636*4882a593Smuzhiyun	 */
1637*4882a593Smuzhiyun	test	SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation;
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun	/*
1640*4882a593Smuzhiyun	 * If we recevied good status but never successfully sent the
1641*4882a593Smuzhiyun	 * cdb, abort the command.
1642*4882a593Smuzhiyun	 */
1643*4882a593Smuzhiyun	test	SCB_SCSI_STATUS,0xff	jnz complete_accepted;
1644*4882a593Smuzhiyun	test	SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation;
1645*4882a593Smuzhiyun
1646*4882a593Smuzhiyuncomplete_accepted:
1647*4882a593Smuzhiyun	/*
1648*4882a593Smuzhiyun	 * See if we attempted to deliver a message but the target ingnored us.
1649*4882a593Smuzhiyun	 */
1650*4882a593Smuzhiyun	test	SCB_CONTROL, MK_MESSAGE jz . + 2;
1651*4882a593Smuzhiyun	mvi	MKMSG_FAILED call set_seqint;
1652*4882a593Smuzhiyun
1653*4882a593Smuzhiyun	/*
1654*4882a593Smuzhiyun	 * Check for residuals
1655*4882a593Smuzhiyun	 */
1656*4882a593Smuzhiyun	test	SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */
1657*4882a593Smuzhiyun	test	SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
1658*4882a593Smuzhiyun	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
1659*4882a593Smuzhiyuncheck_status:
1660*4882a593Smuzhiyun	test	SCB_SCSI_STATUS,0xff	jz complete;	/* Good Status? */
1661*4882a593Smuzhiyunupload_scb:
1662*4882a593Smuzhiyun	or	SCB_SGPTR, SG_RESID_VALID;
1663*4882a593Smuzhiyun	mvi	DMAPARAMS, FIFORESET;
1664*4882a593Smuzhiyun	mov	SCB_TAG		call dma_scb;
1665*4882a593Smuzhiyun	test	SCB_SCSI_STATUS, 0xff	jz complete;	/* Just a residual? */
1666*4882a593Smuzhiyun	mvi	BAD_STATUS call set_seqint;		/* let driver know */
1667*4882a593Smuzhiyun	cmp	RETURN_1, SEND_SENSE	jne complete;
1668*4882a593Smuzhiyun	call	add_scb_to_free_list;
1669*4882a593Smuzhiyun	jmp	await_busfree;
1670*4882a593Smuzhiyuncomplete:
1671*4882a593Smuzhiyun	mov	SCB_TAG call complete_post;
1672*4882a593Smuzhiyun	jmp	await_busfree;
1673*4882a593Smuzhiyun}
1674*4882a593Smuzhiyun
1675*4882a593Smuzhiyuncomplete_post:
1676*4882a593Smuzhiyun	/* Post the SCBID in SINDEX and issue an interrupt */
1677*4882a593Smuzhiyun	call	add_scb_to_free_list;
1678*4882a593Smuzhiyun	mov	ARG_1, SINDEX;
1679*4882a593Smuzhiyun	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
1680*4882a593Smuzhiyun		mov	A, SDSCB_QOFF;
1681*4882a593Smuzhiyun	} else {
1682*4882a593Smuzhiyun		mov	A, QOUTPOS;
1683*4882a593Smuzhiyun	}
1684*4882a593Smuzhiyun	mvi	QOUTFIFO_OFFSET call post_byte_setup;
1685*4882a593Smuzhiyun	mov	ARG_1 call post_byte;
1686*4882a593Smuzhiyun	if ((ahc->features & AHC_QUEUE_REGS) == 0) {
1687*4882a593Smuzhiyun		inc 	QOUTPOS;
1688*4882a593Smuzhiyun	}
1689*4882a593Smuzhiyun	mvi	INTSTAT,CMDCMPLT ret;
1690*4882a593Smuzhiyun
1691*4882a593Smuzhiyunif ((ahc->flags & AHC_INITIATORROLE) != 0) {
1692*4882a593Smuzhiyun/*
1693*4882a593Smuzhiyun * Is it a disconnect message?  Set a flag in the SCB to remind us
1694*4882a593Smuzhiyun * and await the bus going free.  If this is an untagged transaction
1695*4882a593Smuzhiyun * store the SCB id for it in our untagged target table for lookup on
1696*4882a593Smuzhiyun * a reselection.
1697*4882a593Smuzhiyun */
1698*4882a593Smuzhiyunmesgin_disconnect:
1699*4882a593Smuzhiyun	/*
1700*4882a593Smuzhiyun	 * If ATN is raised, we still want to give the target a message.
1701*4882a593Smuzhiyun	 * Perhaps there was a parity error on this last message byte
1702*4882a593Smuzhiyun	 * or we want to abort this command.  Either way, the target
1703*4882a593Smuzhiyun	 * should take us to message out phase and then attempt to
1704*4882a593Smuzhiyun	 * disconnect again.
1705*4882a593Smuzhiyun	 * XXX - Wait for more testing.
1706*4882a593Smuzhiyun	test	SCSISIGI, ATNI jnz mesgin_done;
1707*4882a593Smuzhiyun	 */
1708*4882a593Smuzhiyun	test	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT
1709*4882a593Smuzhiyun		jnz mesgin_proto_violation;
1710*4882a593Smuzhiyun	or	SCB_CONTROL,DISCONNECTED;
1711*4882a593Smuzhiyun	if ((ahc->flags & AHC_PAGESCBS) != 0) {
1712*4882a593Smuzhiyun		call	add_scb_to_disc_list;
1713*4882a593Smuzhiyun	}
1714*4882a593Smuzhiyun	test	SCB_CONTROL, TAG_ENB jnz await_busfree;
1715*4882a593Smuzhiyun	mov	ARG_1, SCB_TAG;
1716*4882a593Smuzhiyun	and	SAVED_LUN, LID, SCB_LUN;
1717*4882a593Smuzhiyun	mov	SCB_SCSIID	call set_busy_target;
1718*4882a593Smuzhiyun	jmp	await_busfree;
1719*4882a593Smuzhiyun
1720*4882a593Smuzhiyun/*
1721*4882a593Smuzhiyun * Save data pointers message:
1722*4882a593Smuzhiyun * Copying RAM values back to SCB, for Save Data Pointers message, but
1723*4882a593Smuzhiyun * only if we've actually been into a data phase to change them.  This
1724*4882a593Smuzhiyun * protects against bogus data in scratch ram and the residual counts
1725*4882a593Smuzhiyun * since they are only initialized when we go into data_in or data_out.
1726*4882a593Smuzhiyun * Ack the message as soon as possible.  For chips without S/G pipelining,
1727*4882a593Smuzhiyun * we can only ack the message after SHADDR has been saved.  On these
1728*4882a593Smuzhiyun * chips, SHADDR increments with every bus transaction, even PIO.
1729*4882a593Smuzhiyun */
1730*4882a593Smuzhiyunmesgin_sdptrs:
1731*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
1732*4882a593Smuzhiyun		mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
1733*4882a593Smuzhiyun		test	SEQ_FLAGS, DPHASE	jz ITloop;
1734*4882a593Smuzhiyun	} else {
1735*4882a593Smuzhiyun		test	SEQ_FLAGS, DPHASE	jz mesgin_done;
1736*4882a593Smuzhiyun	}
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun	/*
1739*4882a593Smuzhiyun	 * If we are asked to save our position at the end of the
1740*4882a593Smuzhiyun	 * transfer, just mark us at the end rather than perform a
1741*4882a593Smuzhiyun	 * full save.
1742*4882a593Smuzhiyun	 */
1743*4882a593Smuzhiyun	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full;
1744*4882a593Smuzhiyun	or	SCB_SGPTR, SG_LIST_NULL;
1745*4882a593Smuzhiyun	if ((ahc->features & AHC_ULTRA2) != 0) {
1746*4882a593Smuzhiyun		jmp	ITloop;
1747*4882a593Smuzhiyun	} else {
1748*4882a593Smuzhiyun		jmp	mesgin_done;
1749*4882a593Smuzhiyun	}
1750*4882a593Smuzhiyun
1751*4882a593Smuzhiyunmesgin_sdptrs_full:
1752*4882a593Smuzhiyun
1753*4882a593Smuzhiyun	/*
1754*4882a593Smuzhiyun	 * The SCB_SGPTR becomes the next one we'll download,
1755*4882a593Smuzhiyun	 * and the SCB_DATAPTR becomes the current SHADDR.
1756*4882a593Smuzhiyun	 * Use the residual number since STCNT is corrupted by
1757*4882a593Smuzhiyun	 * any message transfer.
1758*4882a593Smuzhiyun	 */
1759*4882a593Smuzhiyun	if ((ahc->features & AHC_CMD_CHAN) != 0) {
1760*4882a593Smuzhiyun		bmov	SCB_DATAPTR, SHADDR, 4;
1761*4882a593Smuzhiyun		if ((ahc->features & AHC_ULTRA2) == 0) {
1762*4882a593Smuzhiyun			mov	NONE,SCSIDATL;	/*dummy read from latch to ACK*/
1763*4882a593Smuzhiyun		}
1764*4882a593Smuzhiyun		bmov	SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8;
1765*4882a593Smuzhiyun	} else {
1766*4882a593Smuzhiyun		mvi	DINDEX, SCB_DATAPTR;
1767*4882a593Smuzhiyun		mvi	SHADDR call bcopy_4;
1768*4882a593Smuzhiyun		mov	NONE,SCSIDATL;	/*dummy read from latch to ACK*/
1769*4882a593Smuzhiyun		mvi	SCB_RESIDUAL_DATACNT call bcopy_8;
1770*4882a593Smuzhiyun	}
1771*4882a593Smuzhiyun	jmp	ITloop;
1772*4882a593Smuzhiyun
1773*4882a593Smuzhiyun/*
1774*4882a593Smuzhiyun * Restore pointers message?  Data pointers are recopied from the
1775*4882a593Smuzhiyun * SCB anytime we enter a data phase for the first time, so all
1776*4882a593Smuzhiyun * we need to do is clear the DPHASE flag and let the data phase
1777*4882a593Smuzhiyun * code do the rest.  We also reset/reallocate the FIFO to make
1778*4882a593Smuzhiyun * sure we have a clean start for the next data or command phase.
1779*4882a593Smuzhiyun */
1780*4882a593Smuzhiyunmesgin_rdptrs:
1781*4882a593Smuzhiyun	and	SEQ_FLAGS, ~DPHASE;		/*
1782*4882a593Smuzhiyun						 * We'll reload them
1783*4882a593Smuzhiyun						 * the next time through
1784*4882a593Smuzhiyun						 * the dataphase.
1785*4882a593Smuzhiyun						 */
1786*4882a593Smuzhiyun	or	SXFRCTL0, CLRSTCNT|CLRCHN;
1787*4882a593Smuzhiyun	jmp	mesgin_done;
1788*4882a593Smuzhiyun
1789*4882a593Smuzhiyun/*
1790*4882a593Smuzhiyun * Index into our Busy Target table.  SINDEX and DINDEX are modified
1791*4882a593Smuzhiyun * upon return.  SCBPTR may be modified by this action.
1792*4882a593Smuzhiyun */
1793*4882a593Smuzhiyunset_busy_target:
1794*4882a593Smuzhiyun	shr	DINDEX, 4, SINDEX;
1795*4882a593Smuzhiyun	if ((ahc->flags & AHC_SCB_BTT) != 0) {
1796*4882a593Smuzhiyun		mov	SCBPTR, SAVED_LUN;
1797*4882a593Smuzhiyun		add	DINDEX, SCB_64_BTT;
1798*4882a593Smuzhiyun	} else {
1799*4882a593Smuzhiyun		add	DINDEX, BUSY_TARGETS;
1800*4882a593Smuzhiyun	}
1801*4882a593Smuzhiyun	mov	DINDIR, ARG_1 ret;
1802*4882a593Smuzhiyun
1803*4882a593Smuzhiyun/*
1804*4882a593Smuzhiyun * Identify message?  For a reconnecting target, this tells us the lun
1805*4882a593Smuzhiyun * that the reconnection is for - find the correct SCB and switch to it,
1806*4882a593Smuzhiyun * clearing the "disconnected" bit so we don't "find" it by accident later.
1807*4882a593Smuzhiyun */
1808*4882a593Smuzhiyunmesgin_identify:
1809*4882a593Smuzhiyun	/*
1810*4882a593Smuzhiyun	 * Determine whether a target is using tagged or non-tagged
1811*4882a593Smuzhiyun	 * transactions by first looking at the transaction stored in
1812*4882a593Smuzhiyun	 * the busy target array.  If there is no untagged transaction
1813*4882a593Smuzhiyun	 * for this target or the transaction is for a different lun, then
1814*4882a593Smuzhiyun	 * this must be a tagged transaction.
1815*4882a593Smuzhiyun	 */
1816*4882a593Smuzhiyun	shr	SINDEX, 4, SAVED_SCSIID;
1817*4882a593Smuzhiyun	and	SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
1818*4882a593Smuzhiyun	if ((ahc->flags & AHC_SCB_BTT) != 0) {
1819*4882a593Smuzhiyun		add	SINDEX, SCB_64_BTT;
1820*4882a593Smuzhiyun		mov	SCBPTR, SAVED_LUN;
1821*4882a593Smuzhiyun		if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
1822*4882a593Smuzhiyun			add	NONE, -SCB_64_BTT, SINDEX;
1823*4882a593Smuzhiyun			jc	. + 2;
1824*4882a593Smuzhiyun			mvi	INTSTAT, OUT_OF_RANGE;
1825*4882a593Smuzhiyun			nop;
1826*4882a593Smuzhiyun			add	NONE, -(SCB_64_BTT + 16), SINDEX;
1827*4882a593Smuzhiyun			jnc	. + 2;
1828*4882a593Smuzhiyun			mvi	INTSTAT, OUT_OF_RANGE;
1829*4882a593Smuzhiyun			nop;
1830*4882a593Smuzhiyun		}
1831*4882a593Smuzhiyun	} else {
1832*4882a593Smuzhiyun		add	SINDEX, BUSY_TARGETS;
1833*4882a593Smuzhiyun		if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
1834*4882a593Smuzhiyun			add	NONE, -BUSY_TARGETS, SINDEX;
1835*4882a593Smuzhiyun			jc	. + 2;
1836*4882a593Smuzhiyun			mvi	INTSTAT, OUT_OF_RANGE;
1837*4882a593Smuzhiyun			nop;
1838*4882a593Smuzhiyun			add	NONE, -(BUSY_TARGETS + 16), SINDEX;
1839*4882a593Smuzhiyun			jnc	. + 2;
1840*4882a593Smuzhiyun			mvi	INTSTAT, OUT_OF_RANGE;
1841*4882a593Smuzhiyun			nop;
1842*4882a593Smuzhiyun		}
1843*4882a593Smuzhiyun	}
1844*4882a593Smuzhiyun	mov	ARG_1, SINDIR;
1845*4882a593Smuzhiyun	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
1846*4882a593Smuzhiyun	if ((ahc->flags & AHC_PAGESCBS) != 0) {
1847*4882a593Smuzhiyun		mov	ARG_1 call findSCB;
1848*4882a593Smuzhiyun	} else {
1849*4882a593Smuzhiyun		mov	SCBPTR, ARG_1;
1850*4882a593Smuzhiyun	}
1851*4882a593Smuzhiyun	if ((ahc->flags & AHC_SCB_BTT) != 0) {
1852*4882a593Smuzhiyun		jmp setup_SCB_id_lun_okay;
1853*4882a593Smuzhiyun	} else {
1854*4882a593Smuzhiyun		/*
1855*4882a593Smuzhiyun		 * We only allow one untagged command per-target
1856*4882a593Smuzhiyun		 * at a time.  So, if the lun doesn't match, look
1857*4882a593Smuzhiyun		 * for a tag message.
1858*4882a593Smuzhiyun		 */
1859*4882a593Smuzhiyun		and	A, LID, SCB_LUN;
1860*4882a593Smuzhiyun		cmp	SAVED_LUN, A	je setup_SCB_id_lun_okay;
1861*4882a593Smuzhiyun		if ((ahc->flags & AHC_PAGESCBS) != 0) {
1862*4882a593Smuzhiyun			/*
1863*4882a593Smuzhiyun			 * findSCB removes the SCB from the
1864*4882a593Smuzhiyun			 * disconnected list, so we must replace
1865*4882a593Smuzhiyun			 * it there should this SCB be for another
1866*4882a593Smuzhiyun			 * lun.
1867*4882a593Smuzhiyun			 */
1868*4882a593Smuzhiyun			call	cleanup_scb;
1869*4882a593Smuzhiyun		}
1870*4882a593Smuzhiyun	}
1871*4882a593Smuzhiyun
1872*4882a593Smuzhiyun/*
1873*4882a593Smuzhiyun * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
1874*4882a593Smuzhiyun * If we get one, we use the tag returned to find the proper
1875*4882a593Smuzhiyun * SCB.  With SCB paging, we must search for non-tagged
1876*4882a593Smuzhiyun * transactions since the SCB may exist in any slot.  If we're not
1877*4882a593Smuzhiyun * using SCB paging, we can use the tag as the direct index to the
1878*4882a593Smuzhiyun * SCB.
1879*4882a593Smuzhiyun */
1880*4882a593Smuzhiyunsnoop_tag:
1881*4882a593Smuzhiyun	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
1882*4882a593Smuzhiyun		or	SEQ_FLAGS, 0x80;
1883*4882a593Smuzhiyun	}
1884*4882a593Smuzhiyun	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
1885*4882a593Smuzhiyun	call	phase_lock;
1886*4882a593Smuzhiyun	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
1887*4882a593Smuzhiyun		or	SEQ_FLAGS, 0x1;
1888*4882a593Smuzhiyun	}
1889*4882a593Smuzhiyun	cmp	LASTPHASE, P_MESGIN	jne not_found;
1890*4882a593Smuzhiyun	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
1891*4882a593Smuzhiyun		or	SEQ_FLAGS, 0x2;
1892*4882a593Smuzhiyun	}
1893*4882a593Smuzhiyun	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
1894*4882a593Smuzhiyunget_tag:
1895*4882a593Smuzhiyun	if ((ahc->flags & AHC_PAGESCBS) != 0) {
1896*4882a593Smuzhiyun		mvi	ARG_1	call inb_next;	/* tag value */
1897*4882a593Smuzhiyun		mov	ARG_1	call findSCB;
1898*4882a593Smuzhiyun	} else {
1899*4882a593Smuzhiyun		mvi	ARG_1	call inb_next;	/* tag value */
1900*4882a593Smuzhiyun		mov	SCBPTR, ARG_1;
1901*4882a593Smuzhiyun	}
1902*4882a593Smuzhiyun
1903*4882a593Smuzhiyun/*
1904*4882a593Smuzhiyun * Ensure that the SCB the tag points to is for
1905*4882a593Smuzhiyun * an SCB transaction to the reconnecting target.
1906*4882a593Smuzhiyun */
1907*4882a593Smuzhiyunsetup_SCB:
1908*4882a593Smuzhiyun	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
1909*4882a593Smuzhiyun		or	SEQ_FLAGS, 0x4;
1910*4882a593Smuzhiyun	}
1911*4882a593Smuzhiyun	mov	A, SCB_SCSIID;
1912*4882a593Smuzhiyun	cmp	SAVED_SCSIID, A	jne not_found_cleanup_scb;
1913*4882a593Smuzhiyun	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
1914*4882a593Smuzhiyun		or	SEQ_FLAGS, 0x8;
1915*4882a593Smuzhiyun	}
1916*4882a593Smuzhiyunsetup_SCB_id_okay:
1917*4882a593Smuzhiyun	and	A, LID, SCB_LUN;
1918*4882a593Smuzhiyun	cmp	SAVED_LUN, A	jne not_found_cleanup_scb;
1919*4882a593Smuzhiyunsetup_SCB_id_lun_okay:
1920*4882a593Smuzhiyun	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
1921*4882a593Smuzhiyun		or	SEQ_FLAGS, 0x10;
1922*4882a593Smuzhiyun	}
1923*4882a593Smuzhiyun	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
1924*4882a593Smuzhiyun	and	SCB_CONTROL,~DISCONNECTED;
1925*4882a593Smuzhiyun	test	SCB_CONTROL, TAG_ENB	jnz setup_SCB_tagged;
1926*4882a593Smuzhiyun	if ((ahc->flags & AHC_SCB_BTT) != 0) {
1927*4882a593Smuzhiyun		mov	A, SCBPTR;
1928*4882a593Smuzhiyun	}
1929*4882a593Smuzhiyun	mvi	ARG_1, SCB_LIST_NULL;
1930*4882a593Smuzhiyun	mov	SAVED_SCSIID	call	set_busy_target;
1931*4882a593Smuzhiyun	if ((ahc->flags & AHC_SCB_BTT) != 0) {
1932*4882a593Smuzhiyun		mov	SCBPTR, A;
1933*4882a593Smuzhiyun	}
1934*4882a593Smuzhiyunsetup_SCB_tagged:
1935*4882a593Smuzhiyun	clr	SEQ_FLAGS;	/* make note of IDENTIFY */
1936*4882a593Smuzhiyun	call	set_transfer_settings;
1937*4882a593Smuzhiyun	/* See if the host wants to send a message upon reconnection */
1938*4882a593Smuzhiyun	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
1939*4882a593Smuzhiyun	mvi	HOST_MSG	call mk_mesg;
1940*4882a593Smuzhiyun	jmp	mesgin_done;
1941*4882a593Smuzhiyun
1942*4882a593Smuzhiyunnot_found_cleanup_scb:
1943*4882a593Smuzhiyun	if ((ahc->flags & AHC_PAGESCBS) != 0) {
1944*4882a593Smuzhiyun		call	cleanup_scb;
1945*4882a593Smuzhiyun	}
1946*4882a593Smuzhiyunnot_found:
1947*4882a593Smuzhiyun	mvi	NO_MATCH call set_seqint;
1948*4882a593Smuzhiyun	jmp	mesgin_done;
1949*4882a593Smuzhiyun
1950*4882a593Smuzhiyunmk_mesg:
1951*4882a593Smuzhiyun	if ((ahc->features & AHC_DT) == 0) {
1952*4882a593Smuzhiyun		or	SCSISIGO, ATNO, LASTPHASE;
1953*4882a593Smuzhiyun	} else {
1954*4882a593Smuzhiyun		mvi	SCSISIGO, ATNO;
1955*4882a593Smuzhiyun	}
1956*4882a593Smuzhiyun	mov	MSG_OUT,SINDEX ret;
1957*4882a593Smuzhiyun
1958*4882a593Smuzhiyun/*
1959*4882a593Smuzhiyun * Functions to read data in Automatic PIO mode.
1960*4882a593Smuzhiyun *
1961*4882a593Smuzhiyun * According to Adaptec's documentation, an ACK is not sent on input from
1962*4882a593Smuzhiyun * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
1963*4882a593Smuzhiyun * latched (the usual way), then read the data byte directly off the bus
1964*4882a593Smuzhiyun * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
1965*4882a593Smuzhiyun * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
1966*4882a593Smuzhiyun * spec guarantees that the target will hold the data byte on the bus until
1967*4882a593Smuzhiyun * we send our ACK.
1968*4882a593Smuzhiyun *
1969*4882a593Smuzhiyun * The assumption here is that these are called in a particular sequence,
1970*4882a593Smuzhiyun * and that REQ is already set when inb_first is called.  inb_{first,next}
1971*4882a593Smuzhiyun * use the same calling convention as inb.
1972*4882a593Smuzhiyun */
1973*4882a593Smuzhiyuninb_next_wait_perr:
1974*4882a593Smuzhiyun	mvi	PERR_DETECTED call set_seqint;
1975*4882a593Smuzhiyun	jmp	inb_next_wait;
1976*4882a593Smuzhiyuninb_next:
1977*4882a593Smuzhiyun	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
1978*4882a593Smuzhiyuninb_next_wait:
1979*4882a593Smuzhiyun	/*
1980*4882a593Smuzhiyun	 * If there is a parity error, wait for the kernel to
1981*4882a593Smuzhiyun	 * see the interrupt and prepare our message response
1982*4882a593Smuzhiyun	 * before continuing.
1983*4882a593Smuzhiyun	 */
1984*4882a593Smuzhiyun	test	SSTAT1, REQINIT	jz inb_next_wait;
1985*4882a593Smuzhiyun	test	SSTAT1, SCSIPERR jnz inb_next_wait_perr;
1986*4882a593Smuzhiyuninb_next_check_phase:
1987*4882a593Smuzhiyun	and	LASTPHASE, PHASE_MASK, SCSISIGI;
1988*4882a593Smuzhiyun	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
1989*4882a593Smuzhiyuninb_first:
1990*4882a593Smuzhiyun	mov	DINDEX,SINDEX;
1991*4882a593Smuzhiyun	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
1992*4882a593Smuzhiyuninb_last:
1993*4882a593Smuzhiyun	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
1994*4882a593Smuzhiyun}
1995*4882a593Smuzhiyun
1996*4882a593Smuzhiyunif ((ahc->flags & AHC_TARGETROLE) != 0) {
1997*4882a593Smuzhiyun/*
1998*4882a593Smuzhiyun * Change to a new phase.  If we are changing the state of the I/O signal,
1999*4882a593Smuzhiyun * from out to in, wait an additional data release delay before continuing.
2000*4882a593Smuzhiyun */
2001*4882a593Smuzhiyunchange_phase:
2002*4882a593Smuzhiyun	/* Wait for preceding I/O session to complete. */
2003*4882a593Smuzhiyun	test	SCSISIGI, ACKI jnz .;
2004*4882a593Smuzhiyun
2005*4882a593Smuzhiyun	/* Change the phase */
2006*4882a593Smuzhiyun	and	DINDEX, IOI, SCSISIGI;
2007*4882a593Smuzhiyun	mov	SCSISIGO, SINDEX;
2008*4882a593Smuzhiyun	and	A, IOI, SINDEX;
2009*4882a593Smuzhiyun
2010*4882a593Smuzhiyun	/*
2011*4882a593Smuzhiyun	 * If the data direction has changed, from
2012*4882a593Smuzhiyun	 * out (initiator driving) to in (target driving),
2013*4882a593Smuzhiyun	 * we must wait at least a data release delay plus
2014*4882a593Smuzhiyun	 * the normal bus settle delay. [SCSI III SPI 10.11.0]
2015*4882a593Smuzhiyun	 */
2016*4882a593Smuzhiyun	cmp 	DINDEX, A je change_phase_wait;
2017*4882a593Smuzhiyun	test	SINDEX, IOI jz change_phase_wait;
2018*4882a593Smuzhiyun	call	change_phase_wait;
2019*4882a593Smuzhiyunchange_phase_wait:
2020*4882a593Smuzhiyun	nop;
2021*4882a593Smuzhiyun	nop;
2022*4882a593Smuzhiyun	nop;
2023*4882a593Smuzhiyun	nop ret;
2024*4882a593Smuzhiyun
2025*4882a593Smuzhiyun/*
2026*4882a593Smuzhiyun * Send a byte to an initiator in Automatic PIO mode.
2027*4882a593Smuzhiyun */
2028*4882a593Smuzhiyuntarget_outb:
2029*4882a593Smuzhiyun	or	SXFRCTL0, SPIOEN;
2030*4882a593Smuzhiyun	test	SSTAT0, SPIORDY	jz .;
2031*4882a593Smuzhiyun	mov	SCSIDATL, SINDEX;
2032*4882a593Smuzhiyun	test	SSTAT0, SPIORDY	jz .;
2033*4882a593Smuzhiyun	and	SXFRCTL0, ~SPIOEN ret;
2034*4882a593Smuzhiyun}
2035*4882a593Smuzhiyun
2036*4882a593Smuzhiyun/*
2037*4882a593Smuzhiyun * Locate a disconnected SCB by SCBID.  Upon return, SCBPTR and SINDEX will
2038*4882a593Smuzhiyun * be set to the position of the SCB.  If the SCB cannot be found locally,
2039*4882a593Smuzhiyun * it will be paged in from host memory.  RETURN_2 stores the address of the
2040*4882a593Smuzhiyun * preceding SCB in the disconnected list which can be used to speed up
2041*4882a593Smuzhiyun * removal of the found SCB from the disconnected list.
2042*4882a593Smuzhiyun */
2043*4882a593Smuzhiyunif ((ahc->flags & AHC_PAGESCBS) != 0) {
2044*4882a593SmuzhiyunBEGIN_CRITICAL;
2045*4882a593SmuzhiyunfindSCB:
2046*4882a593Smuzhiyun	mov	A, SINDEX;			/* Tag passed in SINDEX */
2047*4882a593Smuzhiyun	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound;
2048*4882a593Smuzhiyun	mov	SCBPTR, DISCONNECTED_SCBH;	/* Initialize SCBPTR */
2049*4882a593Smuzhiyun	mvi	ARG_2, SCB_LIST_NULL;		/* Head of list */
2050*4882a593Smuzhiyun	jmp	findSCB_loop;
2051*4882a593SmuzhiyunfindSCB_next:
2052*4882a593Smuzhiyun	cmp	SCB_NEXT, SCB_LIST_NULL je findSCB_notFound;
2053*4882a593Smuzhiyun	mov	ARG_2, SCBPTR;
2054*4882a593Smuzhiyun	mov	SCBPTR,SCB_NEXT;
2055*4882a593SmuzhiyunfindSCB_loop:
2056*4882a593Smuzhiyun	cmp	SCB_TAG, A	jne findSCB_next;
2057*4882a593Smuzhiyunrem_scb_from_disc_list:
2058*4882a593Smuzhiyun	cmp	ARG_2, SCB_LIST_NULL	je rHead;
2059*4882a593Smuzhiyun	mov	DINDEX, SCB_NEXT;
2060*4882a593Smuzhiyun	mov	SINDEX, SCBPTR;
2061*4882a593Smuzhiyun	mov	SCBPTR, ARG_2;
2062*4882a593Smuzhiyun	mov	SCB_NEXT, DINDEX;
2063*4882a593Smuzhiyun	mov	SCBPTR, SINDEX ret;
2064*4882a593SmuzhiyunrHead:
2065*4882a593Smuzhiyun	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
2066*4882a593SmuzhiyunEND_CRITICAL;
2067*4882a593SmuzhiyunfindSCB_notFound:
2068*4882a593Smuzhiyun	/*
2069*4882a593Smuzhiyun	 * We didn't find it.  Page in the SCB.
2070*4882a593Smuzhiyun	 */
2071*4882a593Smuzhiyun	mov	ARG_1, A; /* Save tag */
2072*4882a593Smuzhiyun	mov	ALLZEROS call get_free_or_disc_scb;
2073*4882a593Smuzhiyun	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
2074*4882a593Smuzhiyun	mov	ARG_1	jmp dma_scb;
2075*4882a593Smuzhiyun}
2076*4882a593Smuzhiyun
2077*4882a593Smuzhiyun/*
2078*4882a593Smuzhiyun * Prepare the hardware to post a byte to host memory given an
2079*4882a593Smuzhiyun * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR.
2080*4882a593Smuzhiyun */
2081*4882a593Smuzhiyunpost_byte_setup:
2082*4882a593Smuzhiyun	mov	ARG_2, SINDEX;
2083*4882a593Smuzhiyun	if ((ahc->features & AHC_CMD_CHAN) != 0) {
2084*4882a593Smuzhiyun		mvi	DINDEX, CCHADDR;
2085*4882a593Smuzhiyun		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
2086*4882a593Smuzhiyun		mvi	CCHCNT, 1;
2087*4882a593Smuzhiyun		mvi	CCSCBCTL, CCSCBRESET ret;
2088*4882a593Smuzhiyun	} else {
2089*4882a593Smuzhiyun		mvi	DINDEX, HADDR;
2090*4882a593Smuzhiyun		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
2091*4882a593Smuzhiyun		mvi	1	call set_hcnt;
2092*4882a593Smuzhiyun		mvi	DFCNTRL, FIFORESET ret;
2093*4882a593Smuzhiyun	}
2094*4882a593Smuzhiyun
2095*4882a593Smuzhiyunpost_byte:
2096*4882a593Smuzhiyun	if ((ahc->features & AHC_CMD_CHAN) != 0) {
2097*4882a593Smuzhiyun		bmov	CCSCBRAM, SINDEX, 1;
2098*4882a593Smuzhiyun		or	CCSCBCTL, CCSCBEN|CCSCBRESET;
2099*4882a593Smuzhiyun		test	CCSCBCTL, CCSCBDONE jz .;
2100*4882a593Smuzhiyun		clr	CCSCBCTL ret;
2101*4882a593Smuzhiyun	} else {
2102*4882a593Smuzhiyun		mov	DFDAT, SINDEX;
2103*4882a593Smuzhiyun		or	DFCNTRL, HDMAEN|FIFOFLUSH;
2104*4882a593Smuzhiyun		jmp	dma_finish;
2105*4882a593Smuzhiyun	}
2106*4882a593Smuzhiyun
2107*4882a593Smuzhiyunphase_lock_perr:
2108*4882a593Smuzhiyun	mvi	PERR_DETECTED call set_seqint;
2109*4882a593Smuzhiyunphase_lock:
2110*4882a593Smuzhiyun	/*
2111*4882a593Smuzhiyun	 * If there is a parity error, wait for the kernel to
2112*4882a593Smuzhiyun	 * see the interrupt and prepare our message response
2113*4882a593Smuzhiyun	 * before continuing.
2114*4882a593Smuzhiyun	 */
2115*4882a593Smuzhiyun	test	SSTAT1, REQINIT jz phase_lock;
2116*4882a593Smuzhiyun	test	SSTAT1, SCSIPERR jnz phase_lock_perr;
2117*4882a593Smuzhiyunphase_lock_latch_phase:
2118*4882a593Smuzhiyun	if ((ahc->features & AHC_DT) == 0) {
2119*4882a593Smuzhiyun		and	SCSISIGO, PHASE_MASK, SCSISIGI;
2120*4882a593Smuzhiyun	}
2121*4882a593Smuzhiyun	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
2122*4882a593Smuzhiyun
2123*4882a593Smuzhiyunif ((ahc->features & AHC_CMD_CHAN) == 0) {
2124*4882a593Smuzhiyunset_hcnt:
2125*4882a593Smuzhiyun	mov	HCNT[0], SINDEX;
2126*4882a593Smuzhiyunclear_hcnt:
2127*4882a593Smuzhiyun	clr	HCNT[1];
2128*4882a593Smuzhiyun	clr	HCNT[2] ret;
2129*4882a593Smuzhiyun
2130*4882a593Smuzhiyunset_stcnt_from_hcnt:
2131*4882a593Smuzhiyun	mov	STCNT[0], HCNT[0];
2132*4882a593Smuzhiyun	mov	STCNT[1], HCNT[1];
2133*4882a593Smuzhiyun	mov	STCNT[2], HCNT[2] ret;
2134*4882a593Smuzhiyun
2135*4882a593Smuzhiyunbcopy_8:
2136*4882a593Smuzhiyun	mov	DINDIR, SINDIR;
2137*4882a593Smuzhiyunbcopy_7:
2138*4882a593Smuzhiyun	mov	DINDIR, SINDIR;
2139*4882a593Smuzhiyun	mov	DINDIR, SINDIR;
2140*4882a593Smuzhiyunbcopy_5:
2141*4882a593Smuzhiyun	mov	DINDIR, SINDIR;
2142*4882a593Smuzhiyunbcopy_4:
2143*4882a593Smuzhiyun	mov	DINDIR, SINDIR;
2144*4882a593Smuzhiyunbcopy_3:
2145*4882a593Smuzhiyun	mov	DINDIR, SINDIR;
2146*4882a593Smuzhiyun	mov	DINDIR, SINDIR;
2147*4882a593Smuzhiyun	mov	DINDIR, SINDIR ret;
2148*4882a593Smuzhiyun}
2149*4882a593Smuzhiyun
2150*4882a593Smuzhiyunif ((ahc->flags & AHC_TARGETROLE) != 0) {
2151*4882a593Smuzhiyun/*
2152*4882a593Smuzhiyun * Setup addr assuming that A is an index into
2153*4882a593Smuzhiyun * an array of 32byte objects, SINDEX contains
2154*4882a593Smuzhiyun * the base address of that array, and DINDEX
2155*4882a593Smuzhiyun * contains the base address of the location
2156*4882a593Smuzhiyun * to store the indexed address.
2157*4882a593Smuzhiyun */
2158*4882a593Smuzhiyunset_32byte_addr:
2159*4882a593Smuzhiyun	shr	ARG_2, 3, A;
2160*4882a593Smuzhiyun	shl	A, 5;
2161*4882a593Smuzhiyun	jmp	set_1byte_addr;
2162*4882a593Smuzhiyun}
2163*4882a593Smuzhiyun
2164*4882a593Smuzhiyun/*
2165*4882a593Smuzhiyun * Setup addr assuming that A is an index into
2166*4882a593Smuzhiyun * an array of 64byte objects, SINDEX contains
2167*4882a593Smuzhiyun * the base address of that array, and DINDEX
2168*4882a593Smuzhiyun * contains the base address of the location
2169*4882a593Smuzhiyun * to store the indexed address.
2170*4882a593Smuzhiyun */
2171*4882a593Smuzhiyunset_64byte_addr:
2172*4882a593Smuzhiyun	shr	ARG_2, 2, A;
2173*4882a593Smuzhiyun	shl	A, 6;
2174*4882a593Smuzhiyun
2175*4882a593Smuzhiyun/*
2176*4882a593Smuzhiyun * Setup addr assuming that A + (ARG_2 * 256) is an
2177*4882a593Smuzhiyun * index into an array of 1byte objects, SINDEX contains
2178*4882a593Smuzhiyun * the base address of that array, and DINDEX contains
2179*4882a593Smuzhiyun * the base address of the location to store the computed
2180*4882a593Smuzhiyun * address.
2181*4882a593Smuzhiyun */
2182*4882a593Smuzhiyunset_1byte_addr:
2183*4882a593Smuzhiyun	add     DINDIR, A, SINDIR;
2184*4882a593Smuzhiyun	mov     A, ARG_2;
2185*4882a593Smuzhiyun	adc	DINDIR, A, SINDIR;
2186*4882a593Smuzhiyun	clr	A;
2187*4882a593Smuzhiyun	adc	DINDIR, A, SINDIR;
2188*4882a593Smuzhiyun	adc	DINDIR, A, SINDIR ret;
2189*4882a593Smuzhiyun
2190*4882a593Smuzhiyun/*
2191*4882a593Smuzhiyun * Either post or fetch an SCB from host memory based on the
2192*4882a593Smuzhiyun * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
2193*4882a593Smuzhiyun */
2194*4882a593Smuzhiyundma_scb:
2195*4882a593Smuzhiyun	mov	A, SINDEX;
2196*4882a593Smuzhiyun	if ((ahc->features & AHC_CMD_CHAN) != 0) {
2197*4882a593Smuzhiyun		mvi	DINDEX, CCHADDR;
2198*4882a593Smuzhiyun		mvi	HSCB_ADDR call set_64byte_addr;
2199*4882a593Smuzhiyun		mov	CCSCBPTR, SCBPTR;
2200*4882a593Smuzhiyun		test	DMAPARAMS, DIRECTION jz dma_scb_tohost;
2201*4882a593Smuzhiyun		if ((ahc->flags & AHC_SCB_BTT) != 0) {
2202*4882a593Smuzhiyun			mvi	CCHCNT, SCB_DOWNLOAD_SIZE_64;
2203*4882a593Smuzhiyun		} else {
2204*4882a593Smuzhiyun			mvi	CCHCNT, SCB_DOWNLOAD_SIZE;
2205*4882a593Smuzhiyun		}
2206*4882a593Smuzhiyun		mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
2207*4882a593Smuzhiyun		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
2208*4882a593Smuzhiyun		jmp	dma_scb_finish;
2209*4882a593Smuzhiyundma_scb_tohost:
2210*4882a593Smuzhiyun		mvi	CCHCNT, SCB_UPLOAD_SIZE;
2211*4882a593Smuzhiyun		if ((ahc->features & AHC_ULTRA2) == 0) {
2212*4882a593Smuzhiyun			mvi	CCSCBCTL, CCSCBRESET;
2213*4882a593Smuzhiyun			bmov	CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE;
2214*4882a593Smuzhiyun			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
2215*4882a593Smuzhiyun			test	CCSCBCTL, CCSCBDONE jz .;
2216*4882a593Smuzhiyun		} else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) {
2217*4882a593Smuzhiyun			mvi	CCSCBCTL, CCARREN|CCSCBRESET;
2218*4882a593Smuzhiyun			cmp	CCSCBCTL, ARRDONE|CCARREN jne .;
2219*4882a593Smuzhiyun			mvi	CCHCNT, SCB_UPLOAD_SIZE;
2220*4882a593Smuzhiyun			mvi	CCSCBCTL, CCSCBEN|CCSCBRESET;
2221*4882a593Smuzhiyun			cmp	CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
2222*4882a593Smuzhiyun		} else {
2223*4882a593Smuzhiyun			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
2224*4882a593Smuzhiyun			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
2225*4882a593Smuzhiyun		}
2226*4882a593Smuzhiyundma_scb_finish:
2227*4882a593Smuzhiyun		clr	CCSCBCTL;
2228*4882a593Smuzhiyun		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
2229*4882a593Smuzhiyun		ret;
2230*4882a593Smuzhiyun	} else {
2231*4882a593Smuzhiyun		mvi	DINDEX, HADDR;
2232*4882a593Smuzhiyun		mvi	HSCB_ADDR call set_64byte_addr;
2233*4882a593Smuzhiyun		mvi	SCB_DOWNLOAD_SIZE call set_hcnt;
2234*4882a593Smuzhiyun		mov	DFCNTRL, DMAPARAMS;
2235*4882a593Smuzhiyun		test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
2236*4882a593Smuzhiyun		/* Fill it with the SCB data */
2237*4882a593Smuzhiyuncopy_scb_tofifo:
2238*4882a593Smuzhiyun		mvi	SINDEX, SCB_BASE;
2239*4882a593Smuzhiyun		add	A, SCB_DOWNLOAD_SIZE, SINDEX;
2240*4882a593Smuzhiyuncopy_scb_tofifo_loop:
2241*4882a593Smuzhiyun		call	copy_to_fifo_8;
2242*4882a593Smuzhiyun		cmp	SINDEX, A jne copy_scb_tofifo_loop;
2243*4882a593Smuzhiyun		or	DFCNTRL, HDMAEN|FIFOFLUSH;
2244*4882a593Smuzhiyun		jmp	dma_finish;
2245*4882a593Smuzhiyundma_scb_fromhost:
2246*4882a593Smuzhiyun		mvi	DINDEX, SCB_BASE;
2247*4882a593Smuzhiyun		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
2248*4882a593Smuzhiyun			/*
2249*4882a593Smuzhiyun			 * The PCI module will only issue a PCI
2250*4882a593Smuzhiyun			 * retry if the data FIFO is empty.  If the
2251*4882a593Smuzhiyun			 * host disconnects in the middle of a
2252*4882a593Smuzhiyun			 * transfer, we must empty the fifo of all
2253*4882a593Smuzhiyun			 * available data to force the chip to
2254*4882a593Smuzhiyun			 * continue the transfer.  This does not
2255*4882a593Smuzhiyun			 * happen for SCSI transfers as the SCSI module
2256*4882a593Smuzhiyun			 * will drain the FIFO as data are made available.
2257*4882a593Smuzhiyun			 * When the hang occurs, we know that a multiple
2258*4882a593Smuzhiyun			 * of 8 bytes is in the FIFO because the PCI
2259*4882a593Smuzhiyun			 * module has an 8 byte input latch that only
2260*4882a593Smuzhiyun			 * dumps to the FIFO when HCNT == 0 or the
2261*4882a593Smuzhiyun			 * latch is full.
2262*4882a593Smuzhiyun			 */
2263*4882a593Smuzhiyun			clr	A;
2264*4882a593Smuzhiyun			/* Wait for at least 8 bytes of data to arrive. */
2265*4882a593Smuzhiyundma_scb_hang_fifo:
2266*4882a593Smuzhiyun			test	DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo;
2267*4882a593Smuzhiyundma_scb_hang_wait:
2268*4882a593Smuzhiyun			test	DFSTATUS, MREQPEND jnz dma_scb_hang_wait;
2269*4882a593Smuzhiyun			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
2270*4882a593Smuzhiyun			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
2271*4882a593Smuzhiyun			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
2272*4882a593Smuzhiyun			/*
2273*4882a593Smuzhiyun			 * The PCI module no longer intends to perform
2274*4882a593Smuzhiyun			 * a PCI transaction.  Drain the fifo.
2275*4882a593Smuzhiyun			 */
2276*4882a593Smuzhiyundma_scb_hang_dma_drain_fifo:
2277*4882a593Smuzhiyun			not	A, HCNT;
2278*4882a593Smuzhiyun			add	A, SCB_DOWNLOAD_SIZE+SCB_BASE+1;
2279*4882a593Smuzhiyun			and	A, ~0x7;
2280*4882a593Smuzhiyun			mov	DINDIR,DFDAT;
2281*4882a593Smuzhiyun			cmp	DINDEX, A jne . - 1;
2282*4882a593Smuzhiyun			cmp	DINDEX, SCB_DOWNLOAD_SIZE+SCB_BASE
2283*4882a593Smuzhiyun				je	dma_finish_nowait;
2284*4882a593Smuzhiyun			/* Restore A as the lines left to transfer. */
2285*4882a593Smuzhiyun			add	A, -SCB_BASE, DINDEX;
2286*4882a593Smuzhiyun			shr	A, 3;
2287*4882a593Smuzhiyun			jmp	dma_scb_hang_fifo;
2288*4882a593Smuzhiyundma_scb_hang_dma_done:
2289*4882a593Smuzhiyun			and	DFCNTRL, ~HDMAEN;
2290*4882a593Smuzhiyun			test	DFCNTRL, HDMAEN jnz .;
2291*4882a593Smuzhiyun			add	SEQADDR0, A;
2292*4882a593Smuzhiyun		} else {
2293*4882a593Smuzhiyun			call	dma_finish;
2294*4882a593Smuzhiyun		}
2295*4882a593Smuzhiyun		call	dfdat_in_8;
2296*4882a593Smuzhiyun		call	dfdat_in_8;
2297*4882a593Smuzhiyun		call	dfdat_in_8;
2298*4882a593Smuzhiyundfdat_in_8:
2299*4882a593Smuzhiyun		mov	DINDIR,DFDAT;
2300*4882a593Smuzhiyundfdat_in_7:
2301*4882a593Smuzhiyun		mov	DINDIR,DFDAT;
2302*4882a593Smuzhiyun		mov	DINDIR,DFDAT;
2303*4882a593Smuzhiyun		mov	DINDIR,DFDAT;
2304*4882a593Smuzhiyun		mov	DINDIR,DFDAT;
2305*4882a593Smuzhiyun		mov	DINDIR,DFDAT;
2306*4882a593Smuzhiyundfdat_in_2:
2307*4882a593Smuzhiyun		mov	DINDIR,DFDAT;
2308*4882a593Smuzhiyun		mov	DINDIR,DFDAT ret;
2309*4882a593Smuzhiyun	}
2310*4882a593Smuzhiyun
2311*4882a593Smuzhiyuncopy_to_fifo_8:
2312*4882a593Smuzhiyun	mov	DFDAT,SINDIR;
2313*4882a593Smuzhiyun	mov	DFDAT,SINDIR;
2314*4882a593Smuzhiyuncopy_to_fifo_6:
2315*4882a593Smuzhiyun	mov	DFDAT,SINDIR;
2316*4882a593Smuzhiyuncopy_to_fifo_5:
2317*4882a593Smuzhiyun	mov	DFDAT,SINDIR;
2318*4882a593Smuzhiyuncopy_to_fifo_4:
2319*4882a593Smuzhiyun	mov	DFDAT,SINDIR;
2320*4882a593Smuzhiyun	mov	DFDAT,SINDIR;
2321*4882a593Smuzhiyun	mov	DFDAT,SINDIR;
2322*4882a593Smuzhiyun	mov	DFDAT,SINDIR ret;
2323*4882a593Smuzhiyun
2324*4882a593Smuzhiyun/*
2325*4882a593Smuzhiyun * Wait for DMA from host memory to data FIFO to complete, then disable
2326*4882a593Smuzhiyun * DMA and wait for it to acknowledge that it's off.
2327*4882a593Smuzhiyun */
2328*4882a593Smuzhiyundma_finish:
2329*4882a593Smuzhiyun	test	DFSTATUS,HDONE	jz dma_finish;
2330*4882a593Smuzhiyundma_finish_nowait:
2331*4882a593Smuzhiyun	/* Turn off DMA */
2332*4882a593Smuzhiyun	and	DFCNTRL, ~HDMAEN;
2333*4882a593Smuzhiyun	test	DFCNTRL, HDMAEN jnz .;
2334*4882a593Smuzhiyun	ret;
2335*4882a593Smuzhiyun
2336*4882a593Smuzhiyun/*
2337*4882a593Smuzhiyun * Restore an SCB that failed to match an incoming reselection
2338*4882a593Smuzhiyun * to the correct/safe state.  If the SCB is for a disconnected
2339*4882a593Smuzhiyun * transaction, it must be returned to the disconnected list.
2340*4882a593Smuzhiyun * If it is not in the disconnected state, it must be free.
2341*4882a593Smuzhiyun */
2342*4882a593Smuzhiyuncleanup_scb:
2343*4882a593Smuzhiyun	if ((ahc->flags & AHC_PAGESCBS) != 0) {
2344*4882a593Smuzhiyun		test	SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list;
2345*4882a593Smuzhiyun	}
2346*4882a593Smuzhiyunadd_scb_to_free_list:
2347*4882a593Smuzhiyun	if ((ahc->flags & AHC_PAGESCBS) != 0) {
2348*4882a593SmuzhiyunBEGIN_CRITICAL;
2349*4882a593Smuzhiyun		mov	SCB_NEXT, FREE_SCBH;
2350*4882a593Smuzhiyun		mvi	SCB_TAG, SCB_LIST_NULL;
2351*4882a593Smuzhiyun		mov	FREE_SCBH, SCBPTR ret;
2352*4882a593SmuzhiyunEND_CRITICAL;
2353*4882a593Smuzhiyun	} else {
2354*4882a593Smuzhiyun		mvi	SCB_TAG, SCB_LIST_NULL ret;
2355*4882a593Smuzhiyun	}
2356*4882a593Smuzhiyun
2357*4882a593Smuzhiyunif ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
2358*4882a593Smuzhiyunset_hhaddr:
2359*4882a593Smuzhiyun	or	DSCOMMAND1, HADDLDSEL0;
2360*4882a593Smuzhiyun	and	HADDR, SG_HIGH_ADDR_BITS, SINDEX;
2361*4882a593Smuzhiyun	and	DSCOMMAND1, ~HADDLDSEL0 ret;
2362*4882a593Smuzhiyun}
2363*4882a593Smuzhiyun
2364*4882a593Smuzhiyunif ((ahc->flags & AHC_PAGESCBS) != 0) {
2365*4882a593Smuzhiyunget_free_or_disc_scb:
2366*4882a593SmuzhiyunBEGIN_CRITICAL;
2367*4882a593Smuzhiyun	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
2368*4882a593Smuzhiyun	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
2369*4882a593Smuzhiyunreturn_error:
2370*4882a593Smuzhiyun	mvi	NO_FREE_SCB call set_seqint;
2371*4882a593Smuzhiyun	mvi	SINDEX, SCB_LIST_NULL	ret;
2372*4882a593Smuzhiyundequeue_disc_scb:
2373*4882a593Smuzhiyun	mov	SCBPTR, DISCONNECTED_SCBH;
2374*4882a593Smuzhiyun	mov	DISCONNECTED_SCBH, SCB_NEXT;
2375*4882a593SmuzhiyunEND_CRITICAL;
2376*4882a593Smuzhiyun	mvi	DMAPARAMS, FIFORESET;
2377*4882a593Smuzhiyun	mov	SCB_TAG	jmp dma_scb;
2378*4882a593SmuzhiyunBEGIN_CRITICAL;
2379*4882a593Smuzhiyundequeue_free_scb:
2380*4882a593Smuzhiyun	mov	SCBPTR, FREE_SCBH;
2381*4882a593Smuzhiyun	mov	FREE_SCBH, SCB_NEXT ret;
2382*4882a593SmuzhiyunEND_CRITICAL;
2383*4882a593Smuzhiyun
2384*4882a593Smuzhiyunadd_scb_to_disc_list:
2385*4882a593Smuzhiyun/*
2386*4882a593Smuzhiyun * Link this SCB into the DISCONNECTED list.  This list holds the
2387*4882a593Smuzhiyun * candidates for paging out an SCB if one is needed for a new command.
2388*4882a593Smuzhiyun * Modifying the disconnected list is a critical(pause dissabled) section.
2389*4882a593Smuzhiyun */
2390*4882a593SmuzhiyunBEGIN_CRITICAL;
2391*4882a593Smuzhiyun	mov	SCB_NEXT, DISCONNECTED_SCBH;
2392*4882a593Smuzhiyun	mov	DISCONNECTED_SCBH, SCBPTR ret;
2393*4882a593SmuzhiyunEND_CRITICAL;
2394*4882a593Smuzhiyun}
2395*4882a593Smuzhiyunset_seqint:
2396*4882a593Smuzhiyun	mov	INTSTAT, SINDEX;
2397*4882a593Smuzhiyun	nop;
2398*4882a593Smuzhiyunreturn:
2399*4882a593Smuzhiyun	ret;
2400