aic7xxx.seq revision 68402
126997Sgibbs/*
226997Sgibbs * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
313177Sgibbs *
455581Sgibbs * Copyright (c) 1994-2000 Justin Gibbs.
526997Sgibbs * All rights reserved.
613177Sgibbs *
726997Sgibbs * Redistribution and use in source and binary forms, with or without
826997Sgibbs * modification, are permitted provided that the following conditions
926997Sgibbs * are met:
1026997Sgibbs * 1. Redistributions of source code must retain the above copyright
1126997Sgibbs *    notice, this list of conditions, and the following disclaimer,
1254211Sgibbs *    without modification.
1339220Sgibbs * 2. The name of the author may not be used to endorse or promote products
1426997Sgibbs *    derived from this software without specific prior written permission.
1513177Sgibbs *
1654211Sgibbs * Alternatively, this software may be distributed under the terms of the
1763457Sgibbs * GNU Public License ("GPL").
1813177Sgibbs *
1926997Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2026997Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2126997Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2226997Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2326997Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2426997Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2526997Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2626997Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2726997Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2826997Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2926997Sgibbs * SUCH DAMAGE.
3013177Sgibbs *
3166647Sgibbs * $Id: //depot/src/aic7xxx/aic7xxx.seq#7 $
3265942Sgibbs *
3350477Speter * $FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 68402 2000-11-06 20:05:38Z gibbs $
3426997Sgibbs */
354568Sgibbs
3666268Sgibbs#include "aic7xxx.reg"
3766268Sgibbs#include "scsi_message.h"
385647Sgibbs
3913177Sgibbs/*
4019164Sgibbs * A few words on the waiting SCB list:
4119164Sgibbs * After starting the selection hardware, we check for reconnecting targets
4213690Sgibbs * as well as for our selection to complete just in case the reselection wins
4313690Sgibbs * bus arbitration.  The problem with this is that we must keep track of the
4413690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection
4513690Sgibbs * on just in case the reselection wins so that we can retry the selection at
4613690Sgibbs * a later time.  This problem cannot be resolved by holding a single entry
4713690Sgibbs * in scratch ram since a reconnecting target can request sense and this will
4813690Sgibbs * create yet another SCB waiting for selection.  The solution used here is to 
4913690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
5019164Sgibbs * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
5119164Sgibbs * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
5219164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged
5319164Sgibbs * command for which a second SCB has been queued.  The sequencer will
5419164Sgibbs * automatically consume the entries.
5513177Sgibbs */
564568Sgibbs
5744507Sgibbspoll_for_work:
5823925Sgibbs	call	clear_target_state;
5939220Sgibbs	and	SXFRCTL0, ~SPIOEN;
6068087Sgibbs	clr	SCSIBUSL;
6139220Sgibbspoll_for_work_loop:
6239220Sgibbs	test	SSTAT0, SELDO|SELDI	jnz selection;
6358258Sgibbs	test	SCSISEQ, ENSELO	jnz poll_for_work_loop;
6439220Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
6539220Sgibbs		/*
6639220Sgibbs		 * Twin channel devices cannot handle things like SELTO
6739220Sgibbs		 * interrupts on the "background" channel.  So, if we
6839220Sgibbs		 * are selecting, keep polling the current channel util
6939220Sgibbs		 * either a selection or reselection occurs.
7039220Sgibbs		 */
7139220Sgibbs		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
7239220Sgibbs		test	SSTAT0, SELDO|SELDI	jnz selection;
7365942Sgibbs		xor	SBLKCTL,SELBUSB;	/* Toggle back */
7439220Sgibbs	}
7523925Sgibbs	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
7619164Sgibbstest_queue:
7719164Sgibbs	/* Has the driver posted any work for us? */
7866647SgibbsBEGIN_CRITICAL
7939220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
8039220Sgibbs		test	QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
8139220Sgibbs	} else {
8268087Sgibbs		mov	A, QINPOS;
8339220Sgibbs		cmp	KERNEL_QINPOS, A je poll_for_work_loop;
8439220Sgibbs	}
8566647Sgibbs	mov	ARG_1, NEXT_QUEUED_SCB;
8666647SgibbsEND_CRITICAL
874568Sgibbs
8863457Sgibbs	/*
8963457Sgibbs	 * We have at least one queued SCB now and we don't have any 
9066647Sgibbs	 * SCBs in the list of SCBs awaiting selection.  Allocate a
9166647Sgibbs	 * card SCB for the host's SCB and get to work on it.
9263457Sgibbs	 */
9339220Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
9439220Sgibbs		mov	ALLZEROS	call	get_free_or_disc_scb;
9566647Sgibbs	} else {
9639220Sgibbs		/* In the non-paging case, the SCBID == hardware SCB index */
9766647Sgibbs		mov	SCBPTR, ARG_1;
9839220Sgibbs	}
9919164Sgibbsdma_queued_scb:
10063457Sgibbs	/*
10163457Sgibbs	 * DMA the SCB from host ram into the current SCB location.
10263457Sgibbs	 */
10323925Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
10466647Sgibbs	mov	ARG_1	call dma_scb;
10519164Sgibbs	/*
10666647Sgibbs	 * Check one last time to see if this SCB was canceled
10766647Sgibbs	 * before we completed the DMA operation.  If it was,
10866647Sgibbs	 * the QINFIFO next pointer will not match our saved
10966647Sgibbs	 * value.
11019164Sgibbs	 */
11166647Sgibbs	mov	A, ARG_1;
11266647SgibbsBEGIN_CRITICAL
11366647Sgibbs	cmp	NEXT_QUEUED_SCB, A jne abort_qinscb;
11468087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
11568087Sgibbs		if ((ahc->flags & AHC_PAGESCBS) == 0) {
11668087Sgibbs			cmp	SCBPTR, A je . + 2;
11768402Sgibbs			mvi	SCBPTR_MISMATCH call set_seqint;
11868087Sgibbs		}
11968087Sgibbs		cmp	SCB_TAG, A je . + 2;
12068402Sgibbs		mvi	SCB_MISMATCH call set_seqint;
12168087Sgibbs	}
12266647Sgibbs	mov	NEXT_QUEUED_SCB, SCB_NEXT;
12323925Sgibbs	mov	SCB_NEXT,WAITING_SCBH;
12423925Sgibbs	mov	WAITING_SCBH, SCBPTR;
12568402Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
12668402Sgibbs		mov	NONE, SNSCB_QOFF;
12768402Sgibbs	} else {
12868402Sgibbs		inc	QINPOS;
12968402Sgibbs	}
13066647SgibbsEND_CRITICAL
13123925Sgibbsstart_waiting:
13223925Sgibbs	/*
13363457Sgibbs	 * Start the first entry on the waiting SCB list.
13423925Sgibbs	 */
13523925Sgibbs	mov	SCBPTR, WAITING_SCBH;
13623925Sgibbs	call	start_selection;
13765942Sgibbs	jmp	poll_for_work_loop;
1388104Sgibbs
13966647Sgibbsabort_qinscb:
14068402Sgibbs	mvi	ABORT_QINSCB call set_seqint;
14166647Sgibbs	call	add_scb_to_free_list;
14266647Sgibbs	jmp	poll_for_work_loop;
14366647Sgibbs
14423925Sgibbsstart_selection:
14539220Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
14639220Sgibbs		and	SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
14763457Sgibbs		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
14863457Sgibbs		or	SINDEX, SELBUSB;
14939220Sgibbs		mov	SBLKCTL,SINDEX;		/* select channel */
15039220Sgibbs	}
15123925Sgibbsinitialize_scsiid:
15263457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
15363457Sgibbs		mov	SCSIID_ULTRA2, SCB_SCSIID;
15463457Sgibbs	} else if ((ahc->features & AHC_TWIN) != 0) {
15563457Sgibbs		and	SCSIID, TWIN_TID|OID, SCB_SCSIID;
15663457Sgibbs	} else {
15763457Sgibbs		mov	SCSIID, SCB_SCSIID;
15863457Sgibbs	}
15968087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
16063457Sgibbs		mov	SINDEX, SCSISEQ_TEMPLATE;
16163457Sgibbs		test	SCB_CONTROL, TARGET_SCB jz . + 2;
16244507Sgibbs		or	SINDEX, TEMODE;
16363457Sgibbs		mov	SCSISEQ, SINDEX ret;
16439220Sgibbs	} else {
16563457Sgibbs		mov	SCSISEQ, SCSISEQ_TEMPLATE ret;
16639220Sgibbs	}
16739220Sgibbs
16813177Sgibbs/*
16939220Sgibbs * Initialize transfer settings and clear the SCSI channel.
17039220Sgibbs * SINDEX should contain any additional bit's the client wants
17139220Sgibbs * set in SXFRCTL0.  We also assume that the current SCB is
17239220Sgibbs * a valid SCB for the target we wish to talk to.
17339220Sgibbs */
17439220Sgibbsinitialize_channel:
17568087Sgibbs	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
17639220Sgibbsset_transfer_settings:
17739220Sgibbs	if ((ahc->features & AHC_ULTRA) != 0) {
17839220Sgibbs		test	SCB_CONTROL, ULTRAENB jz . + 2;
17939220Sgibbs		or	SXFRCTL0, FAST20;
18039220Sgibbs	} 
18163457Sgibbs	/*
18263457Sgibbs	 * Initialize SCSIRATE with the appropriate value for this target.
18363457Sgibbs	 */
18439220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
18539220Sgibbs		bmov	SCSIRATE, SCB_SCSIRATE, 2 ret;
18639220Sgibbs	} else {
18739220Sgibbs		mov	SCSIRATE, SCB_SCSIRATE ret;
18839220Sgibbs	}
18939220Sgibbs
19039220Sgibbsselection:
19163457Sgibbs	/*
19263457Sgibbs	 * We aren't expecting a bus free, so interrupt
19363457Sgibbs	 * the kernel driver if it happens.
19463457Sgibbs	 */
19563457Sgibbs	mvi	CLRSINT1,CLRBUSFREE;
19663457Sgibbs	or	SIMODE1, ENBUSFREE;
19763457Sgibbs
19839220Sgibbs	test	SSTAT0,SELDO	jnz select_out;
19939220Sgibbs	mvi	CLRSINT0, CLRSELDI;
20039220Sgibbsselect_in:
20168087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
20268087Sgibbs		if ((ahc->flags & AHC_INITIATORROLE) != 0) {
20341646Sgibbs			test	SSTAT0, TARGET	jz initiator_reselect;
20441646Sgibbs		}
20542652Sgibbs
20639220Sgibbs		/*
20739220Sgibbs		 * We've just been selected.  Assert BSY and
20839220Sgibbs		 * setup the phase for receiving messages
20939220Sgibbs		 * from the target.
21039220Sgibbs		 */
21139220Sgibbs		mvi	SCSISIGO, P_MESGOUT|BSYO;
21239220Sgibbs
21339220Sgibbs		/*
21439220Sgibbs		 * Setup the DMA for sending the identify and
21541299Sgibbs		 * command information.
21639220Sgibbs		 */
21739220Sgibbs		or	SEQ_FLAGS, CMDPHASE_PENDING;
21841299Sgibbs
21941299Sgibbs		mov     A, TQINPOS;
22039220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
22139220Sgibbs			mvi	DINDEX, CCHADDR;
22263457Sgibbs			mvi	SHARED_DATA_ADDR call set_32byte_addr;
22339220Sgibbs			mvi	CCSCBCTL, CCSCBRESET;
22439220Sgibbs		} else {
22539220Sgibbs			mvi	DINDEX, HADDR;
22663457Sgibbs			mvi	SHARED_DATA_ADDR call set_32byte_addr;
22739220Sgibbs			mvi	DFCNTRL, FIFORESET;
22839220Sgibbs		}
22939220Sgibbs
23039220Sgibbs		/* Initiator that selected us */
23163457Sgibbs		and	SAVED_SCSIID, SELID_MASK, SELID;
23263457Sgibbs		/* The Target ID we were selected at */
23363457Sgibbs		if ((ahc->features & AHC_MULTI_TID) != 0) {
23463457Sgibbs			and	A, OID, TARGIDIN;
23563457Sgibbs		} else if ((ahc->features & AHC_ULTRA2) != 0) {
23663457Sgibbs			and	A, OID, SCSIID_ULTRA2;
23739220Sgibbs		} else {
23863457Sgibbs			and	A, OID, SCSIID;
23939220Sgibbs		}
24063457Sgibbs		or	SAVED_SCSIID, A;
24163457Sgibbs		if ((ahc->features & AHC_TWIN) != 0) {
24263457Sgibbs			test 	SBLKCTL, SELBUSB jz . + 2;
24363457Sgibbs			or	SAVED_SCSIID, TWIN_CHNLB;
24463457Sgibbs		}
24544507Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
24663457Sgibbs			mov	CCSCBRAM, SAVED_SCSIID;
24739220Sgibbs		} else {
24863457Sgibbs			mov	DFDAT, SAVED_SCSIID;
24939220Sgibbs		}
25039220Sgibbs
25139220Sgibbs		/*
25239220Sgibbs		 * If ATN isn't asserted, the target isn't interested
25339220Sgibbs		 * in talking to us.  Go directly to bus free.
25463457Sgibbs		 * XXX SCSI-1 may require us to assume lun 0 if
25563457Sgibbs		 * ATN is false.
25639220Sgibbs		 */
25739220Sgibbs		test	SCSISIGI, ATNI	jz	target_busfree;
25839220Sgibbs
25939220Sgibbs		/*
26039220Sgibbs		 * Watch ATN closely now as we pull in messages from the
26139220Sgibbs		 * initiator.  We follow the guidlines from section 6.5
26239220Sgibbs		 * of the SCSI-2 spec for what messages are allowed when.
26339220Sgibbs		 */
26441646Sgibbs		call	target_inb;
26539220Sgibbs
26639220Sgibbs		/*
26739220Sgibbs		 * Our first message must be one of IDENTIFY, ABORT, or
26839220Sgibbs		 * BUS_DEVICE_RESET.
26939220Sgibbs		 */
27042652Sgibbs		test	DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
27139220Sgibbs		/* Store for host */
27239220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
27339220Sgibbs			mov	CCSCBRAM, DINDEX;
27439220Sgibbs		} else {
27539220Sgibbs			mov	DFDAT, DINDEX;
27639220Sgibbs		}
27739220Sgibbs
27839220Sgibbs		/* Remember for disconnection decision */
27939220Sgibbs		test	DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
28039220Sgibbs		/* XXX Honor per target settings too */
28139220Sgibbs		or	SEQ_FLAGS, NO_DISCONNECT;
28239220Sgibbs
28339220Sgibbs		test	SCSISIGI, ATNI	jz	ident_messages_done;
28441646Sgibbs		call	target_inb;
28539220Sgibbs		/*
28639220Sgibbs		 * If this is a tagged request, the tagged message must
28739220Sgibbs		 * immediately follow the identify.  We test for a valid
28839220Sgibbs		 * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and
28939220Sgibbs		 * < MSG_IGN_WIDE_RESIDUE.
29039220Sgibbs		 */
29139220Sgibbs		add	A, -MSG_SIMPLE_Q_TAG, DINDEX;
29239220Sgibbs		jnc	ident_messages_done;
29339220Sgibbs		add	A, -MSG_IGN_WIDE_RESIDUE, DINDEX;
29439220Sgibbs		jc	ident_messages_done;
29539220Sgibbs		/* Store for host */
29639220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
29739220Sgibbs			mov	CCSCBRAM, DINDEX;
29839220Sgibbs		} else {
29939220Sgibbs			mov	DFDAT, DINDEX;
30039220Sgibbs		}
30139220Sgibbs		
30239220Sgibbs		/*
30339220Sgibbs		 * If the initiator doesn't feel like providing a tag number,
30439220Sgibbs		 * we've got a failed selection and must transition to bus
30539220Sgibbs		 * free.
30639220Sgibbs		 */
30739220Sgibbs		test	SCSISIGI, ATNI	jz	target_busfree;
30842652Sgibbs
30939220Sgibbs		/*
31039220Sgibbs		 * Store the tag for the host.
31139220Sgibbs		 */
31241646Sgibbs		call	target_inb;
31339220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
31439220Sgibbs			mov	CCSCBRAM, DINDEX;
31539220Sgibbs		} else {
31639220Sgibbs			mov	DFDAT, DINDEX;
31739220Sgibbs		}
31842652Sgibbs		mov	INITIATOR_TAG, DINDEX;
31963457Sgibbs		or	SEQ_FLAGS, TARGET_CMD_IS_TAGGED;
32063457Sgibbs		test	SCSISIGI, ATNI	jz . + 2;
32163457Sgibbs		/* Initiator still wants to give us messages */
32263457Sgibbs		call	target_inb;
32339220Sgibbs		jmp	ident_messages_done;
32439220Sgibbs
32541646Sgibbs		/*
32641646Sgibbs		 * Pushed message loop to allow the kernel to
32742652Sgibbs		 * run it's own target mode message state engine.
32841646Sgibbs		 */
32941646Sgibbshost_target_message_loop:
33068402Sgibbs		mvi	HOST_MSG_LOOP call set_seqint;
33141646Sgibbs		cmp	RETURN_1, EXIT_MSG_LOOP	je target_ITloop;
33241646Sgibbs		test	SSTAT0, SPIORDY jz .;
33341646Sgibbs		jmp	host_target_message_loop;
33441646Sgibbs
33539220Sgibbsident_messages_done:
33644507Sgibbs		/* If ring buffer is full, return busy or queue full */
33758258Sgibbs		if ((ahc->features & AHC_HS_MAILBOX) != 0) {
33858258Sgibbs			and	A, HOST_TQINPOS, HS_MAILBOX;
33958258Sgibbs		} else {
34058258Sgibbs			mov	A, KERNEL_TQINPOS;
34158258Sgibbs		}
34244507Sgibbs		cmp	TQINPOS, A jne tqinfifo_has_space;
34344507Sgibbs		mvi	P_STATUS|BSYO call change_phase;
34468087Sgibbs		test	SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3;
34544507Sgibbs		mvi	STATUS_QUEUE_FULL call target_outb;
34644507Sgibbs		jmp	target_busfree_wait;
34744507Sgibbs		mvi	STATUS_BUSY call target_outb;
34844507Sgibbs		jmp	target_busfree_wait;
34944507Sgibbstqinfifo_has_space:	
35039220Sgibbs		/* Terminate the ident list */
35139220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
35239220Sgibbs			mvi	CCSCBRAM, SCB_LIST_NULL;
35339220Sgibbs		} else {
35439220Sgibbs			mvi	DFDAT, SCB_LIST_NULL;
35539220Sgibbs		}
35642652Sgibbs		or	SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
35763457Sgibbs		test	SCSISIGI, ATNI	jnz target_mesgout_pending;
35839220Sgibbs		jmp	target_ITloop;
35939220Sgibbs		
36039220Sgibbs/*
36139220Sgibbs * We carefully toggle SPIOEN to allow us to return the 
36239220Sgibbs * message byte we receive so it can be checked prior to
36339220Sgibbs * driving REQ on the bus for the next byte.
36439220Sgibbs */
36541646Sgibbstarget_inb:
36641646Sgibbs		/*
36741646Sgibbs		 * Drive REQ on the bus by enabling SCSI PIO.
36841646Sgibbs		 */
36939220Sgibbs		or	SXFRCTL0, SPIOEN;
37039220Sgibbs		/* Wait for the byte */
37139220Sgibbs		test	SSTAT0, SPIORDY jz .;
37239220Sgibbs		/* Prevent our read from triggering another REQ */
37339220Sgibbs		and	SXFRCTL0, ~SPIOEN;
37441646Sgibbs		/* Save latched contents */
37539220Sgibbs		mov	DINDEX, SCSIDATL ret;
37639220Sgibbs	}
37739220Sgibbs
37868087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) {
37939220Sgibbs/*
38023925Sgibbs * Reselection has been initiated by a target. Make a note that we've been
38123925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
38213177Sgibbs */
38339220Sgibbsinitiator_reselect:
38423925Sgibbs	/* XXX test for and handle ONE BIT condition */
38563457Sgibbs	and	SAVED_SCSIID, SELID_MASK, SELID;
38663457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
38763457Sgibbs		and	A, OID, SCSIID_ULTRA2;
38863457Sgibbs	} else {
38963457Sgibbs		and	A, OID, SCSIID;
39063457Sgibbs	}
39163457Sgibbs	or	SAVED_SCSIID, A;
39239545Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
39339545Sgibbs		test	SBLKCTL, SELBUSB	jz . + 2;
39463457Sgibbs		or	SAVED_SCSIID, TWIN_CHNLB;
39539545Sgibbs	}
39641646Sgibbs	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
39739220Sgibbs	jmp	ITloop;
39841646Sgibbs}
3994568Sgibbs
40013177Sgibbs/*
40123925Sgibbs * After the selection, remove this SCB from the "waiting SCB"
40223925Sgibbs * list.  This is achieved by simply moving our "next" pointer into
40323925Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
40423925Sgibbs * SCB is used, so don't bother with it now.
40523925Sgibbs */
40639220Sgibbsselect_out:
40725005Sgibbs	/* Turn off the selection hardware */
40858258Sgibbs	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
40925005Sgibbs	mvi	CLRSINT0, CLRSELDO;
41025005Sgibbs	mov	SCBPTR, WAITING_SCBH;
41124914Sgibbs	mov	WAITING_SCBH,SCB_NEXT;
41263457Sgibbs	mov	SAVED_SCSIID, SCB_SCSIID;
41363457Sgibbs	mov	SAVED_LUN, SCB_LUN;
41468087Sgibbs	call	initialize_channel;
41568087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
41639220Sgibbs		test	SSTAT0, TARGET	jz initiator_select;
4178567Sdg
41839220Sgibbs		/*
41939220Sgibbs		 * We've just re-selected an initiator.
42039220Sgibbs		 * Assert BSY and setup the phase for
42139220Sgibbs		 * sending our identify messages.
42239220Sgibbs		 */
42341646Sgibbs		mvi	P_MESGIN|BSYO call change_phase;
4244568Sgibbs
42539220Sgibbs		/*
42639220Sgibbs		 * Start out with a simple identify message.
42739220Sgibbs		 */
42863457Sgibbs		or	SCB_LUN, MSG_IDENTIFYFLAG call target_outb;
4296608Sgibbs
43039220Sgibbs		/*
43139220Sgibbs		 * If we are the result of a tagged command, send
43239220Sgibbs		 * a simple Q tag and the tag id.
43339220Sgibbs		 */
43439220Sgibbs		test	SCB_CONTROL, TAG_ENB	jz . + 3;
43539220Sgibbs		mvi	MSG_SIMPLE_Q_TAG call target_outb;
43663457Sgibbs		mov	SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb;
43739220Sgibbstarget_synccmd:
43839220Sgibbs		/*
43939220Sgibbs		 * Now determine what phases the host wants us
44039220Sgibbs		 * to go through.
44139220Sgibbs		 */
44263457Sgibbs		mov	SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES];
44342652Sgibbs		
44439220Sgibbstarget_ITloop:
44539220Sgibbs		/*
44641646Sgibbs		 * Start honoring ATN signals now that
44744507Sgibbs		 * we properly identified ourselves.
44839220Sgibbs		 */
44941646Sgibbs		test	SCSISIGI, ATNI			jnz target_mesgout;
45039220Sgibbs		test	SEQ_FLAGS, CMDPHASE_PENDING	jnz target_cmdphase;
45139220Sgibbs		test	SEQ_FLAGS, DPHASE_PENDING	jnz target_dphase;
45239220Sgibbs		test	SEQ_FLAGS, SPHASE_PENDING	jnz target_sphase;
45339220Sgibbs
45439220Sgibbs		/*
45539220Sgibbs		 * No more work to do.  Either disconnect or not depending
45639220Sgibbs		 * on the state of NO_DISCONNECT.
45739220Sgibbs		 */
45839220Sgibbs		test	SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 
45939220Sgibbs		if ((ahc->flags & AHC_PAGESCBS) != 0) {
46039220Sgibbs			mov	ALLZEROS	call	get_free_or_disc_scb;
46139220Sgibbs		}
46241646Sgibbs		mov	RETURN_1, ALLZEROS;
46339220Sgibbs		call	complete_target_cmd;
46441646Sgibbs		cmp	RETURN_1, CONT_MSG_LOOP jne .;
46539220Sgibbs		mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
46639220Sgibbs		mov	SCB_TAG	 call dma_scb;
46739220Sgibbs		jmp	target_synccmd;
46839220Sgibbs
46941646Sgibbstarget_mesgout:
47041646Sgibbs		mvi	SCSISIGO, P_MESGOUT|BSYO;
47163457Sgibbstarget_mesgout_continue:
47241646Sgibbs		call	target_inb;
47363457Sgibbstarget_mesgout_pending:
47441646Sgibbs		/* Local Processing goes here... */
47541646Sgibbs		jmp	host_target_message_loop;
47641646Sgibbs		
47739220Sgibbstarget_disconnect:
47841646Sgibbs		mvi	P_MESGIN|BSYO call change_phase;
47941816Sgibbs		test	SEQ_FLAGS, DPHASE	jz . + 2;
48041816Sgibbs		mvi	MSG_SAVEDATAPOINTER call target_outb;
48139220Sgibbs		mvi	MSG_DISCONNECT call target_outb;
48239220Sgibbs
48343880Sgibbstarget_busfree_wait:
48443880Sgibbs		/* Wait for preceeding I/O session to complete. */
48543880Sgibbs		test	SCSISIGI, ACKI jnz .;
48639220Sgibbstarget_busfree:
48763457Sgibbs		and	SIMODE1, ~ENBUSFREE;
48868087Sgibbs		clr	SCSIBUSL;
48939220Sgibbs		clr	SCSISIGO;
49057099Sgibbs		mvi	LASTPHASE, P_BUSFREE;
49139220Sgibbs		call	complete_target_cmd;
49239220Sgibbs		jmp	poll_for_work;
49339220Sgibbs
49439220Sgibbstarget_cmdphase:
49541646Sgibbs		mvi	P_COMMAND|BSYO call change_phase;
49641646Sgibbs		call	target_inb;
49739220Sgibbs		mov	A, DINDEX;
49839220Sgibbs		/* Store for host */
49939220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
50039220Sgibbs			mov	CCSCBRAM, A;
50139220Sgibbs		} else {
50239220Sgibbs			mov	DFDAT, A;
50339220Sgibbs		}
50439220Sgibbs
50539220Sgibbs		/*
50639220Sgibbs		 * Determine the number of bytes to read
50741299Sgibbs		 * based on the command group code via table lookup.
50841299Sgibbs		 * We reuse the first 8 bytes of the TARG_SCSIRATE
50941299Sgibbs		 * BIOS array for this table. Count is one less than
51041299Sgibbs		 * the total for the command since we've already fetched
51141299Sgibbs		 * the first byte.
51239220Sgibbs		 */
51339220Sgibbs		shr	A, CMD_GROUP_CODE_SHIFT;
51468087Sgibbs		add	SINDEX, CMDSIZE_TABLE, A;
51539220Sgibbs		mov	A, SINDIR;
51639220Sgibbs
51739220Sgibbs		test	A, 0xFF jz command_phase_done;
51839220Sgibbscommand_loop:
51939220Sgibbs		or	SXFRCTL0, SPIOEN;
52039220Sgibbs		test	SSTAT0, SPIORDY jz .;
52139220Sgibbs		cmp	A, 1 jne . + 2;
52239220Sgibbs		and	SXFRCTL0, ~SPIOEN;	/* Last Byte */
52339220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
52439220Sgibbs			mov	CCSCBRAM, SCSIDATL;
52539220Sgibbs		} else {
52639220Sgibbs			mov	DFDAT, SCSIDATL;
52739220Sgibbs		}
52839220Sgibbs		dec	A;
52939220Sgibbs		test	A, 0xFF jnz command_loop;
53039220Sgibbs
53139220Sgibbscommand_phase_done:
53239220Sgibbs		and	SEQ_FLAGS, ~CMDPHASE_PENDING;
53339220Sgibbs		jmp	target_ITloop;
53439220Sgibbs
53539220Sgibbstarget_dphase:
53639220Sgibbs		/*
53763457Sgibbs		 * Data phases on the bus are from the
53863457Sgibbs		 * perspective of the initiator.  The dma
53963457Sgibbs		 * code looks at LASTPHASE to determine the
54063457Sgibbs		 * data direction of the DMA.  Toggle it for
54163457Sgibbs		 * target transfers.
54239220Sgibbs		 */
54363457Sgibbs		xor	LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR];
54463457Sgibbs		or	SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO
54563457Sgibbs			call change_phase;
54639220Sgibbs		jmp	p_data;
54739220Sgibbs
54839220Sgibbstarget_sphase:
54941646Sgibbs		mvi	P_STATUS|BSYO call change_phase;
55041646Sgibbs		mvi	LASTPHASE, P_STATUS;
55163457Sgibbs		mov	SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb;
55241646Sgibbs		/* XXX Watch for ATN or parity errors??? */
55339220Sgibbs		mvi	SCSISIGO, P_MESGIN|BSYO;
55439220Sgibbs		/* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
55539220Sgibbs		mov	ALLZEROS call target_outb;
55643880Sgibbs		jmp	target_busfree_wait;
55739220Sgibbs	
55839220Sgibbscomplete_target_cmd:
55939220Sgibbs		test	SEQ_FLAGS, TARG_CMD_PENDING	jnz . + 2;
56039220Sgibbs		mov	SCB_TAG jmp complete_post;
56139220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
56241299Sgibbs			/* Set the valid byte */
56341299Sgibbs			mvi	CCSCBADDR, 24;
56441299Sgibbs			mov	CCSCBRAM, ALLONES;
56541299Sgibbs			mvi	CCHCNT, 28;
56639220Sgibbs			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
56739220Sgibbs			test	CCSCBCTL, CCSCBDONE jz .;
56839220Sgibbs			clr	CCSCBCTL;
56939220Sgibbs		} else {
57041299Sgibbs			/* Set the valid byte */
57141299Sgibbs			or	DFCNTRL, FIFORESET;
57241299Sgibbs			mvi	DFWADDR, 3; /* Third 64bit word or byte 24 */
57341299Sgibbs			mov	DFDAT, ALLONES;
57463457Sgibbs			mvi	28	call set_hcnt;
57539220Sgibbs			or	DFCNTRL, HDMAEN|FIFOFLUSH;
57639220Sgibbs			call	dma_finish;
57739220Sgibbs		}
57841299Sgibbs		inc	TQINPOS;
57941299Sgibbs		mvi	INTSTAT,CMDCMPLT ret;
58039220Sgibbs	}
58141646Sgibbs
58268087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) {
58339220Sgibbsinitiator_select:
58441646Sgibbs	/*
58541646Sgibbs	 * As soon as we get a successful selection, the target
58641646Sgibbs	 * should go into the message out phase since we have ATN
58741646Sgibbs	 * asserted.
58841646Sgibbs	 */
58939220Sgibbs	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
59039220Sgibbs	or	SEQ_FLAGS, IDENTIFY_SEEN;
59113177Sgibbs
59241646Sgibbs	/*
59341646Sgibbs	 * Main loop for information transfer phases.  Wait for the
59441646Sgibbs	 * target to assert REQ before checking MSG, C/D and I/O for
59541646Sgibbs	 * the bus phase.
59641646Sgibbs	 */
59763457Sgibbsmesgin_phasemis:
5984568SgibbsITloop:
59939220Sgibbs	call	phase_lock;
6004568Sgibbs
60139220Sgibbs	mov	A, LASTPHASE;
6024568Sgibbs
60339220Sgibbs	test	A, ~P_DATAIN	jz p_data;
60423925Sgibbs	cmp	A,P_COMMAND	je p_command;
60523925Sgibbs	cmp	A,P_MESGOUT	je p_mesgout;
60623925Sgibbs	cmp	A,P_STATUS	je p_status;
60723925Sgibbs	cmp	A,P_MESGIN	je p_mesgin;
6084568Sgibbs
60968402Sgibbs	mvi	BAD_PHASE call set_seqint;
61023925Sgibbs	jmp	ITloop;			/* Try reading the bus again. */
6114568Sgibbs
61223925Sgibbsawait_busfree:
61323925Sgibbs	and	SIMODE1, ~ENBUSFREE;
61423925Sgibbs	mov	NONE, SCSIDATL;		/* Ack the last byte */
61568087Sgibbs	clr	SCSIBUSL;		/* Prevent bit leakage durint SELTO */
61639220Sgibbs	and	SXFRCTL0, ~SPIOEN;
61723925Sgibbs	test	SSTAT1,REQINIT|BUSFREE	jz .;
61823925Sgibbs	test	SSTAT1, BUSFREE jnz poll_for_work;
61968402Sgibbs	mvi	BAD_PHASE call set_seqint;
62041646Sgibbs}
62123925Sgibbs	
62223925Sgibbsclear_target_state:
62341646Sgibbs	/*
62441646Sgibbs	 * We assume that the kernel driver may reset us
62541646Sgibbs	 * at any time, even in the middle of a DMA, so
62641646Sgibbs	 * clear DFCNTRL too.
62741646Sgibbs	 */
62841646Sgibbs	clr	DFCNTRL;
62968087Sgibbs	or	SXFRCTL0, CLRSTCNT|CLRCHN;
63041646Sgibbs
63141646Sgibbs	/*
63241646Sgibbs	 * We don't know the target we will connect to,
63341646Sgibbs	 * so default to narrow transfers to avoid
63441646Sgibbs	 * parity problems.
63541646Sgibbs	 */
63641646Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
63741646Sgibbs		bmov	SCSIRATE, ALLZEROS, 2;
63841646Sgibbs	} else {
63941646Sgibbs		clr	SCSIRATE;
64063457Sgibbs		if ((ahc->features & AHC_ULTRA) != 0) {
64163457Sgibbs			and	SXFRCTL0, ~(FAST20);
64263457Sgibbs		}
64341646Sgibbs	}
64423925Sgibbs	mvi	LASTPHASE, P_BUSFREE;
64523925Sgibbs	/* clear target specific flags */
64639220Sgibbs	clr	SEQ_FLAGS ret;
64723925Sgibbs
64863457Sgibbssg_advance:
64963457Sgibbs	clr	A;			/* add sizeof(struct scatter) */
65063457Sgibbs	add	SCB_RESIDUAL_SGPTR[0],SG_SIZEOF;
65163457Sgibbs	adc	SCB_RESIDUAL_SGPTR[1],A;
65263457Sgibbs	adc	SCB_RESIDUAL_SGPTR[2],A;
65363457Sgibbs	adc	SCB_RESIDUAL_SGPTR[3],A ret;
65463457Sgibbs
65563457Sgibbsidle_loop:
65663457Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
65763457Sgibbs		/* Did we just finish fetching segs? */
65863457Sgibbs		cmp	CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
65963457Sgibbs
66063457Sgibbs		/* Are we actively fetching segments? */
66163457Sgibbs		test	CCSGCTL, CCSGEN jnz return;
66263457Sgibbs
66363457Sgibbs		/*
66463457Sgibbs		 * Do we need any more segments?
66563457Sgibbs		 */
66663457Sgibbs		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
66763457Sgibbs
66863457Sgibbs		/*
66963457Sgibbs		 * Do we have any prefetch left???
67063457Sgibbs		 */
67166647Sgibbs		cmp	CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail;
67263457Sgibbs
67363457Sgibbs		/*
67463457Sgibbs		 * Need to fetch segments, but we can only do that
67563457Sgibbs		 * if the command channel is completely idle.  Make
67663457Sgibbs		 * sure we don't have an SCB prefetch going on.
67763457Sgibbs		 */
67863457Sgibbs		test	CCSCBCTL, CCSCBEN jnz return;
67963457Sgibbs
68063457Sgibbs		/*
68166647Sgibbs		 * We fetch a "cacheline aligned" and sized amount of data
68266647Sgibbs		 * so we don't end up referencing a non-existant page.
68366647Sgibbs		 * Cacheline aligned is in quotes because the kernel will
68466647Sgibbs		 * set the prefetch amount to a reasonable level if the
68566647Sgibbs		 * cacheline size is unknown.
68663457Sgibbs		 */
68766647Sgibbs		mvi	CCHCNT, SG_PREFETCH_CNT;
68866647Sgibbs		and	CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
68963457Sgibbs		bmov	CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
69063457Sgibbs		mvi	CCSGCTL, CCSGEN|CCSGRESET ret;
69163457Sgibbsidle_sgfetch_complete:
69263944Sgibbs		clr	CCSGCTL;
69363944Sgibbs		test	CCSGCTL, CCSGEN jnz .;
69466647Sgibbs		and	CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;
69563457Sgibbsidle_sg_avail:
69663457Sgibbs		if ((ahc->features & AHC_ULTRA2) != 0) {
69763457Sgibbs			/* Does the hardware have space for another SG entry? */
69863457Sgibbs			test	DFSTATUS, PRELOAD_AVAIL jz return;
69963457Sgibbs			bmov 	HADDR, CCSGRAM, 4;
70063457Sgibbs			bmov	SINDEX, CCSGRAM, 1;
70163457Sgibbs			test	SINDEX, 0x1 jz . + 2;
70263457Sgibbs			xor	DATA_COUNT_ODD, 0x1;
70363457Sgibbs			bmov	HCNT[0], SINDEX, 1;
70463457Sgibbs			bmov	HCNT[1], CCSGRAM, 2;
70563457Sgibbs			bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
70663457Sgibbs			call	sg_advance;
70763457Sgibbs			mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
70863457Sgibbs			test	DATA_COUNT_ODD, 0x1 jz . + 2;
70963457Sgibbs			or	SINDEX, ODD_SEG;
71063457Sgibbs			test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
71163457Sgibbs			or	SINDEX, LAST_SEG;
71263457Sgibbs			mov	SG_CACHE_PRE, SINDEX;
71363457Sgibbs			/* Load the segment by writing DFCNTRL again */
71463457Sgibbs			mov	DFCNTRL, DMAPARAMS;
71563457Sgibbs		}
71663457Sgibbs		ret;
71763457Sgibbs	}
71863457Sgibbs
71965942Sgibbsif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
72013177Sgibbs/*
72165942Sgibbs * Calculate the trailing portion of this S/G segment that cannot
72265942Sgibbs * be transferred using memory write and invalidate PCI transactions.  
72365942Sgibbs * XXX Can we optimize this for PCI writes only???
72465942Sgibbs */
72565942Sgibbscalc_mwi_residual:
72665942Sgibbs	/*
72765942Sgibbs	 * If the ending address is on a cacheline boundary,
72865942Sgibbs	 * there is no need for an extra segment.
72965942Sgibbs	 */
73065942Sgibbs	mov	A, HCNT[0];
73165942Sgibbs	add	A, A, HADDR[0];
73265942Sgibbs	and	A, CACHESIZE_MASK;
73365942Sgibbs	test	A, 0xFF jz return;
73465942Sgibbs
73565942Sgibbs	/*
73665942Sgibbs	 * If the transfer is less than a cachline,
73765942Sgibbs	 * there is no need for an extra segment.
73865942Sgibbs	 */
73965942Sgibbs	test	HCNT[1], 0xFF	jnz calc_mwi_residual_final;
74065942Sgibbs	test	HCNT[2], 0xFF	jnz calc_mwi_residual_final;
74165942Sgibbs	add	NONE, INVERTED_CACHESIZE_MASK, HCNT[0];
74265942Sgibbs	jnc	return;
74365942Sgibbs
74465942Sgibbscalc_mwi_residual_final:
74565942Sgibbs	mov	MWI_RESIDUAL, A;
74665942Sgibbs	not	A;
74765942Sgibbs	inc	A;
74865942Sgibbs	add	HCNT[0], A;
74965942Sgibbs	adc	HCNT[1], -1;
75065942Sgibbs	adc	HCNT[2], -1 ret;
75165942Sgibbs}
75265942Sgibbs
75365942Sgibbs/*
75413177Sgibbs * If we re-enter the data phase after going through another phase, the
75513177Sgibbs * STCNT may have been cleared, so restore it from the residual field.
75613177Sgibbs */
7579928Sgibbsdata_phase_reinit:
75851471Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
75951471Sgibbs		/*
76051471Sgibbs		 * The preload circuitry requires us to
76151471Sgibbs		 * reload the address too, so pull it from
76251471Sgibbs		 * the shaddow address.
76351471Sgibbs		 */
76451471Sgibbs		bmov	HADDR, SHADDR, 4;
76563457Sgibbs		bmov	HCNT, SCB_RESIDUAL_DATACNT, 3;
76651471Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
76763457Sgibbs		bmov	STCNT, SCB_RESIDUAL_DATACNT, 3;
76839220Sgibbs	} else {
76939220Sgibbs		mvi	DINDEX, STCNT;
77063457Sgibbs		mvi	SCB_RESIDUAL_DATACNT call bcopy_3;
77139220Sgibbs	}
77263457Sgibbs	and	DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0];
77323925Sgibbs	jmp	data_phase_loop;
7744568Sgibbs
77539220Sgibbsp_data:
77639220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
77739220Sgibbs		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
77839220Sgibbs	} else {
77939220Sgibbs		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
78039220Sgibbs	}
78139220Sgibbs	test	LASTPHASE, IOI jnz . + 2;
78239220Sgibbs	or	DMAPARAMS, DIRECTION;
78323925Sgibbs	call	assert;			/*
78419164Sgibbs					 * Ensure entering a data
78519164Sgibbs					 * phase is okay - seen identify, etc.
78619164Sgibbs					 */
78739220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
78863457Sgibbs		/* We don't have any valid S/G elements */
78966647Sgibbs		mvi	CCSGADDR, SG_PREFETCH_CNT;
79039220Sgibbs	}
79123925Sgibbs	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
7924568Sgibbs
79339220Sgibbs	/* We have seen a data phase */
79439220Sgibbs	or	SEQ_FLAGS, DPHASE;
79539220Sgibbs
79619164Sgibbs	/*
79719164Sgibbs	 * Initialize the DMA address and counter from the SCB.
79863457Sgibbs	 * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG
79963457Sgibbs	 * flag in the highest byte of the data count.  We cannot
80063457Sgibbs	 * modify the saved values in the SCB until we see a save
80163457Sgibbs	 * data pointers message.
80219164Sgibbs	 */
80339220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
80439220Sgibbs		bmov	HADDR, SCB_DATAPTR, 7;
80563457Sgibbs		bmov	SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
80639220Sgibbs	} else {
80739220Sgibbs		mvi	DINDEX, HADDR;
80839220Sgibbs		mvi	SCB_DATAPTR	call bcopy_7;
80963457Sgibbs		mvi	DINDEX, SCB_RESIDUAL_DATACNT + 3;
81063457Sgibbs		mvi	SCB_DATACNT + 3 call bcopy_5;
81139220Sgibbs	}
81265942Sgibbs	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
81365942Sgibbs		call	calc_mwi_residual;
81465942Sgibbs	}
81563457Sgibbs	and	SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
81665942Sgibbs	and	DATA_COUNT_ODD, 0x1, HCNT[0];
81719164Sgibbs
81839220Sgibbs	if ((ahc->features & AHC_ULTRA2) == 0) {
81939220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
82039220Sgibbs			bmov	STCNT, HCNT, 3;
82139220Sgibbs		} else {
82239220Sgibbs			call	set_stcnt_from_hcnt;
82339220Sgibbs		}
82439220Sgibbs	}
82519164Sgibbs
82663457Sgibbsdata_phase_loop:
82763457Sgibbs	/* Guard against overruns */
82863457Sgibbs	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds;
82919164Sgibbs
83063457Sgibbs	/*
83168087Sgibbs	 * Turn on `Bit Bucket' mode, wait until the target takes
83268087Sgibbs	 * us to another phase, and then notify the host.
83363457Sgibbs	 */
83468087Sgibbs	and	DMAPARAMS, DIRECTION;
83568087Sgibbs	mov	DFCNTRL, DMAPARAMS;
83623925Sgibbs	or	SXFRCTL1,BITBUCKET;
83768087Sgibbs	test	SSTAT1,PHASEMIS	jz .;
83868087Sgibbs	and	SXFRCTL1, ~BITBUCKET;
83968402Sgibbs	mvi	DATA_OVERRUN call set_seqint;
84068087Sgibbs	jmp	ITloop;
84168087Sgibbs
84216260Sgibbsdata_phase_inbounds:
84339220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
84463457Sgibbs		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
84563457Sgibbs		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
84663457Sgibbs		or	SINDEX, LAST_SEG;
84763457Sgibbs		test	DATA_COUNT_ODD, 0x1 jz . + 2;
84863457Sgibbs		or	SINDEX, ODD_SEG;
84963457Sgibbs		mov	SG_CACHE_PRE, SINDEX;
85063457Sgibbs		mov	DFCNTRL, DMAPARAMS;
85163457Sgibbsultra2_dma_loop:
85263457Sgibbs		call	idle_loop;
85363457Sgibbs		/*
85463457Sgibbs		 * The transfer is complete if either the last segment
85563457Sgibbs		 * completes or the target changes phase.
85663457Sgibbs		 */
85763457Sgibbs		test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
85863457Sgibbs		test	SSTAT1,PHASEMIS	jz ultra2_dma_loop;
85963457Sgibbs
86063457Sgibbsultra2_dmafinish:
86163457Sgibbs		test	DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
86263457Sgibbs		and	DFCNTRL, ~SCSIEN;
86363457Sgibbs		test	DFCNTRL, SCSIEN jnz .;
86463944Sgibbs		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
86563944Sgibbs			test	DFSTATUS, FIFOEMP jnz ultra2_dmafifoempty;
86663944Sgibbs		}
86763457Sgibbsultra2_dmafifoflush:
86863457Sgibbs		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
86963457Sgibbs			/*
87063457Sgibbs			 * On Rev A of the aic7890, the autoflush
87163457Sgibbs			 * features doesn't function correctly.
87263457Sgibbs			 * Perform an explicit manual flush.  During
87363457Sgibbs			 * a manual flush, the FIFOEMP bit becomes
87463457Sgibbs			 * true every time the PCI FIFO empties
87563457Sgibbs			 * regardless of the state of the SCSI FIFO.
87663457Sgibbs			 * It can take up to 4 clock cycles for the
87763457Sgibbs			 * SCSI FIFO to get data into the PCI FIFO
87863457Sgibbs			 * and for FIFOEMP to de-assert.  Here we
87963457Sgibbs			 * guard against this condition by making
88063457Sgibbs			 * sure the FIFOEMP bit stays on for 5 full
88163457Sgibbs			 * clock cycles.
88263457Sgibbs			 */
88363457Sgibbs			or	DFCNTRL, FIFOFLUSH;
88463457Sgibbs			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
88563457Sgibbs			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
88663457Sgibbs			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
88763457Sgibbs			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
88863457Sgibbs		}
88963457Sgibbs		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
89063457Sgibbsultra2_dmafifoempty:
89163457Sgibbs		/* Don't clobber an inprogress host data transfer */
89263457Sgibbs		test	DFSTATUS, MREQPEND	jnz ultra2_dmafifoempty;
89363457Sgibbsultra2_dmahalt:
89463457Sgibbs		and     DFCNTRL, ~(SCSIEN|HDMAEN);
89563457Sgibbs		test	DFCNTRL, HDMAEN jnz .;
89663457Sgibbs
89763457Sgibbs		/*
89863944Sgibbs		 * If, by chance, we stopped before being able
89963944Sgibbs		 * to fetch additional segments for this transfer,
90063944Sgibbs		 * yet the last S/G was completely exhausted,
90163944Sgibbs		 * call our idle loop until it is able to load
90263944Sgibbs		 * another segment.  This will allow us to immediately
90363944Sgibbs		 * pickup on the next segment on the next data phase.
90463944Sgibbs		 *
90563944Sgibbs		 * If we happened to stop on the last segment, then
90663944Sgibbs		 * our residual information is still correct from
90763944Sgibbs		 * the idle loop and there is no need to perform
90863944Sgibbs		 * any fixups.  Just jump to data_phase_finish.
90963944Sgibbs		 */
91063944Sgibbsultra2_ensure_sg:
91163944Sgibbs		test	SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid;
91263944Sgibbs		/* Record if we've consumed all S/G entries */
91363944Sgibbs		test	SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish;
91463944Sgibbs		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
91563944Sgibbs		jmp	data_phase_finish;
91663944Sgibbs
91763944Sgibbsultra2_shvalid:
91863944Sgibbs                test    SSTAT2, SHVALID	jnz sgptr_fixup;
91963944Sgibbs		call	idle_loop;
92063944Sgibbs		jmp	ultra2_ensure_sg;
92163944Sgibbs
92263944Sgibbssgptr_fixup:
92363944Sgibbs		/*
92463457Sgibbs		 * Fixup the residual next S/G pointer.  The S/G preload
92563457Sgibbs		 * feature of the chip allows us to load two elements
92663457Sgibbs		 * in addition to the currently active element.  We
92763457Sgibbs		 * store the bottom byte of the next S/G pointer in
92863457Sgibbs		 * the SG_CACEPTR register so we can restore the
92963457Sgibbs		 * correct value when the DMA completes.  If the next
93063457Sgibbs		 * sg ptr value has advanced to the point where higher
93163457Sgibbs		 * bytes in the address have been affected, fix them
93263457Sgibbs		 * too.
93363457Sgibbs		 */
93463457Sgibbs		test	SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done;
93563457Sgibbs		test	SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done;
93663457Sgibbs		add	SCB_RESIDUAL_SGPTR[1], -1;
93763457Sgibbs		adc	SCB_RESIDUAL_SGPTR[2], -1; 
93863457Sgibbs		adc	SCB_RESIDUAL_SGPTR[3], -1;
93963457Sgibbssgptr_fixup_done:
94063457Sgibbs		and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
94163457Sgibbs		clr	DATA_COUNT_ODD;
94263457Sgibbs		test	SG_CACHE_SHADOW, ODD_SEG jz . + 2;
94363457Sgibbs		or	DATA_COUNT_ODD, 0x1;
94463944Sgibbs		clr	SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
94539220Sgibbs	} else {
94663457Sgibbs		/* If we are the last SG block, tell the hardware. */
94765942Sgibbs		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
94865942Sgibbs		  && ahc->pci_cachesize != 0) {
94965942Sgibbs			test	MWI_RESIDUAL, 0xFF jnz dma_mid_sg;
95065942Sgibbs		}
95163457Sgibbs		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
95268087Sgibbs		if ((ahc->flags & AHC_TARGETROLE) != 0) {
95363944Sgibbs			test	SSTAT0, TARGET jz dma_last_sg;
95463944Sgibbs			if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) {
95563944Sgibbs				test	DMAPARAMS, DIRECTION jz dma_mid_sg;
95663944Sgibbs			}
95757099Sgibbs		}
95863944Sgibbsdma_last_sg:
95939220Sgibbs		and	DMAPARAMS, ~WIDEODD;
96063457Sgibbsdma_mid_sg:
96163457Sgibbs		/* Start DMA data transfer. */
96239220Sgibbs		mov	DFCNTRL, DMAPARAMS;
96363457Sgibbsdma_loop:
96463457Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
96563457Sgibbs			call	idle_loop;
96663457Sgibbs		}
96763457Sgibbs		test	SSTAT0,DMADONE	jnz dma_dmadone;
96863457Sgibbs		test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
96963457Sgibbsdma_phasemis:
97039220Sgibbs		/*
97163457Sgibbs		 * We will be "done" DMAing when the transfer count goes to
97263457Sgibbs		 * zero, or the target changes the phase (in light of this,
97363457Sgibbs		 * it makes sense that the DMA circuitry doesn't ACK when
97463457Sgibbs		 * PHASEMIS is active).  If we are doing a SCSI->Host transfer,
97563457Sgibbs		 * the data FIFO should be flushed auto-magically on STCNT=0
97663457Sgibbs		 * or a phase change, so just wait for FIFO empty status.
97739220Sgibbs		 */
97863457Sgibbsdma_checkfifo:
97963457Sgibbs		test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
98063457Sgibbsdma_fifoflush:
98163457Sgibbs		test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
98263457Sgibbsdma_fifoempty:
98363457Sgibbs		/* Don't clobber an inprogress host data transfer */
98463457Sgibbs		test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
9854568Sgibbs
98639220Sgibbs		/*
98763457Sgibbs		 * Now shut off the DMA and make sure that the DMA
98863457Sgibbs		 * hardware has actually stopped.  Touching the DMA
98963457Sgibbs		 * counters, etc. while a DMA is active will result
99063457Sgibbs		 * in an ILLSADDR exception.
99139220Sgibbs		 */
99263457Sgibbsdma_dmadone:
99363457Sgibbs		and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
99463457Sgibbsdma_halt:
99563457Sgibbs		/*
99665942Sgibbs		 * Some revisions of the aic78XX have a problem where, if the
99763457Sgibbs		 * data fifo is full, but the PCI input latch is not empty, 
99863457Sgibbs		 * HDMAEN cannot be cleared.  The fix used here is to drain
99963457Sgibbs		 * the prefetched but unused data from the data fifo until
100063457Sgibbs		 * there is space for the input latch to drain.
100163457Sgibbs		 */
100265942Sgibbs		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
100365942Sgibbs			mov	NONE, DFDAT;
100465942Sgibbs		}
100563457Sgibbs		test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
100622568Sgibbs
100763457Sgibbs		/* See if we have completed this last segment */
100863457Sgibbs		test	STCNT[0], 0xff	jnz data_phase_finish;
100963457Sgibbs		test	STCNT[1], 0xff	jnz data_phase_finish;
101063457Sgibbs		test	STCNT[2], 0xff	jnz data_phase_finish;
10119928Sgibbs
101239220Sgibbs		/*
101363457Sgibbs		 * Advance the scatter-gather pointers if needed 
101439220Sgibbs		 */
101565942Sgibbs		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
101665942Sgibbs		  && ahc->pci_cachesize != 0) {
101765942Sgibbs			test	MWI_RESIDUAL, 0xFF jz no_mwi_resid;
101865942Sgibbs			/*
101965942Sgibbs			 * Reload HADDR from SHADDR and setup the
102065942Sgibbs			 * count to be the size of our residual.
102165942Sgibbs			 */
102265942Sgibbs			if ((ahc->features & AHC_CMD_CHAN) != 0) {
102365942Sgibbs				bmov	HADDR, SHADDR, 4;
102465942Sgibbs				mov	HCNT, MWI_RESIDUAL;
102565942Sgibbs				bmov	HCNT[1], ALLZEROS, 2;
102665942Sgibbs			} else {
102765942Sgibbs				mvi	DINDEX, HADDR;
102865942Sgibbs				mvi	SHADDR call bcopy_4;
102965942Sgibbs				mov	MWI_RESIDUAL call set_hcnt;
103065942Sgibbs			}
103165942Sgibbs			clr	MWI_RESIDUAL;
103265942Sgibbs			jmp	sg_load_done;
103365942Sgibbsno_mwi_resid:
103465942Sgibbs		}
103563457Sgibbs		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load;
103663457Sgibbs		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
103763457Sgibbs		jmp	data_phase_finish;
103863457Sgibbssg_load:
103963457Sgibbs		/*
104063457Sgibbs		 * Load the next SG element's data address and length
104163457Sgibbs		 * into the DMA engine.  If we don't have hardware
104263457Sgibbs		 * to perform a prefetch, we'll have to fetch the
104363457Sgibbs		 * segment from host memory first.
104463457Sgibbs		 */
104539220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
104663457Sgibbs			/* Wait for the idle loop to complete */
104763457Sgibbs			test	CCSGCTL, CCSGEN jz . + 3;
104863457Sgibbs			call	idle_loop;
104963457Sgibbs			test	CCSGCTL, CCSGEN jnz . - 1;
105063457Sgibbs			bmov 	HADDR, CCSGRAM, 7;
105165942Sgibbs			test	CCSGRAM, SG_LAST_SEG jz . + 2;
105265942Sgibbs			or	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG;
105339220Sgibbs		} else {
105463457Sgibbs			mvi	DINDEX, HADDR;
105563457Sgibbs			mvi	SCB_RESIDUAL_SGPTR	call bcopy_4;
105663457Sgibbs
105763457Sgibbs			mvi	SG_SIZEOF	call set_hcnt;
105863457Sgibbs
105963457Sgibbs			or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
106063457Sgibbs
106163457Sgibbs			call	dma_finish;
106263457Sgibbs
106365942Sgibbs			mvi	DINDEX, HADDR;
106465942Sgibbs			call	dfdat_in_7;
106563457Sgibbs			mov	SCB_RESIDUAL_DATACNT[3], DFDAT;
106665942Sgibbs		}
106765942Sgibbs
106865942Sgibbs		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
106965942Sgibbs		  && ahc->pci_cachesize != 0) {
107065942Sgibbs			call calc_mwi_residual;
107165942Sgibbs		}
107265942Sgibbs
107365942Sgibbs		/* Point to the new next sg in memory */
107465942Sgibbs		call	sg_advance;
107565942Sgibbs
107665942Sgibbssg_load_done:
107765942Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
107865942Sgibbs			bmov	STCNT, HCNT, 3;
107965942Sgibbs		} else {
108039220Sgibbs			call	set_stcnt_from_hcnt;
108139220Sgibbs		}
108263457Sgibbs		/* Track odd'ness */
108363457Sgibbs		test	HCNT[0], 0x1 jz . + 2;
108463457Sgibbs		xor	DATA_COUNT_ODD, 0x1;
108539220Sgibbs
108668087Sgibbs		if ((ahc->flags & AHC_TARGETROLE) != 0) {
108763457Sgibbs			test	SSTAT0, TARGET jnz data_phase_loop;
108863457Sgibbs		}
108963457Sgibbs	}
109063457Sgibbsdata_phase_finish:
109163457Sgibbs	/*
109263457Sgibbs	 * If the target has left us in data phase, loop through
109363457Sgibbs	 * the dma code again.  In the case of ULTRA2 adapters,
109463457Sgibbs	 * we should only loop if there is a data overrun.  For
109563457Sgibbs	 * all other adapters, we'll loop after each S/G element
109663457Sgibbs	 * is loaded as well as if there is an overrun.
109763457Sgibbs	 */
109868087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
109963457Sgibbs		test	SSTAT0, TARGET jnz data_phase_done;
110041646Sgibbs	}
110168087Sgibbs	if ((ahc->flags & AHC_INITIATORROLE) != 0) {
110263457Sgibbs		test	SSTAT1, REQINIT jz .;
110363457Sgibbs		test	SSTAT1,PHASEMIS	jz data_phase_loop;
110463457Sgibbs	
110563457Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
110663457Sgibbs			/* Kill off any pending prefetch */
110763457Sgibbs			clr	CCSGCTL;
110863457Sgibbs			test	CCSGCTL, CCSGEN jnz .;
110963457Sgibbs		}
111039220Sgibbs	}
11114568Sgibbs
111263457Sgibbsdata_phase_done:
111363457Sgibbs	/*
111463457Sgibbs	 * After a DMA finishes, save the SG and STCNT residuals back into
111563457Sgibbs	 * the SCB.  We use STCNT instead of HCNT, since it's a reflection
111663457Sgibbs	 * of how many bytes were transferred on the SCSI (as opposed to the
111763457Sgibbs	 * host) bus.
111863457Sgibbs	 */
111939220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
112063457Sgibbs		/* Kill off any pending prefetch */
112163457Sgibbs		clr	CCSGCTL;
112263457Sgibbs		test	CCSGCTL, CCSGEN jnz .;
112365942Sgibbs	}
112463457Sgibbs
112565942Sgibbs	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
112665942Sgibbs	  && ahc->pci_cachesize != 0) {
112765942Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
112865942Sgibbs			test	MWI_RESIDUAL, 0xFF jz bmov_resid;
112965942Sgibbs		}
113065942Sgibbs		mov	A, MWI_RESIDUAL;
113165942Sgibbs		add	SCB_RESIDUAL_DATACNT[0], A, STCNT[0];
113265942Sgibbs		clr	A;
113365942Sgibbs		adc	SCB_RESIDUAL_DATACNT[1], A, STCNT[1];
113465942Sgibbs		adc	SCB_RESIDUAL_DATACNT[2], A, STCNT[2];
113565942Sgibbs		clr	MWI_RESIDUAL;
113665942Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
113765942Sgibbs			jmp	. + 2;
113865942Sgibbsbmov_resid:
113965942Sgibbs			bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
114065942Sgibbs		}
114165942Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
114263457Sgibbs		bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
114339220Sgibbs	} else {
114465942Sgibbs		mov	SCB_RESIDUAL_DATACNT[0], STCNT[0];
114565942Sgibbs		mov	SCB_RESIDUAL_DATACNT[1], STCNT[1];
114665942Sgibbs		mov	SCB_RESIDUAL_DATACNT[2], STCNT[2];
114739220Sgibbs	}
114822568Sgibbs
114963457Sgibbs	/*
115063457Sgibbs	 * Since we've been through a data phase, the SCB_RESID* fields
115163457Sgibbs	 * are now initialized.  Clear the full residual flag.
115263457Sgibbs	 */
115363457Sgibbs	and	SCB_SGPTR[0], ~SG_FULL_RESID;
115463457Sgibbs
115539220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
115663457Sgibbs		/* Clear the channel in case we return to data phase later */
115739220Sgibbs		or	SXFRCTL0, CLRSTCNT|CLRCHN;
115868402Sgibbs		or	SXFRCTL0, CLRSTCNT|CLRCHN;
115939220Sgibbs	}
116022568Sgibbs
116168087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
116241646Sgibbs		test	SEQ_FLAGS, DPHASE_PENDING jz ITloop;
116339220Sgibbs		and	SEQ_FLAGS, ~DPHASE_PENDING;
116442652Sgibbs		/*
116542652Sgibbs		 * For data-in phases, wait for any pending acks from the
116642652Sgibbs		 * initiator before changing phase.
116742652Sgibbs		 */
116842652Sgibbs		test	DFCNTRL, DIRECTION jz target_ITloop;
116942652Sgibbs		test	SSTAT1, REQINIT	jnz .;
117039220Sgibbs		jmp	target_ITloop;
117163457Sgibbs	} else {
117263457Sgibbs		jmp	ITloop;
117339220Sgibbs	}
11744568Sgibbs
117568087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) {
117616260Sgibbs/*
117715328Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
117813177Sgibbs */
11794568Sgibbsp_command:
118023925Sgibbs	call	assert;
11814568Sgibbs
118263457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
118363457Sgibbs		bmov	HCNT[0], SCB_CDB_LEN,  1;
118439220Sgibbs		bmov	HCNT[1], ALLZEROS, 2;
118563944Sgibbs		mvi	SG_CACHE_PRE, LAST_SEG;
118663457Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
118763457Sgibbs		bmov	STCNT[0], SCB_CDB_LEN, 1;
118863457Sgibbs		bmov	STCNT[1], ALLZEROS, 2;
118939220Sgibbs	} else {
119063457Sgibbs		mov	STCNT[0], SCB_CDB_LEN;
119163457Sgibbs		clr	STCNT[1];
119263457Sgibbs		clr	STCNT[2];
119339220Sgibbs	}
119463457Sgibbs	add	NONE, -13, SCB_CDB_LEN;
119565942Sgibbs	mvi	SCB_CDB_STORE jnc p_command_embedded;
119663457Sgibbsp_command_from_host:
119763457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
119863457Sgibbs		bmov	HADDR[0], SCB_CDB_PTR, 4;
119963457Sgibbs		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
120063457Sgibbs	} else {
120163457Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
120263457Sgibbs			bmov	HADDR[0], SCB_CDB_PTR, 4;
120365942Sgibbs			bmov	HCNT, STCNT, 3;
120463457Sgibbs		} else {
120563457Sgibbs			mvi	DINDEX, HADDR;
120668087Sgibbs			mvi	SCB_CDB_PTR call bcopy_4;
120768087Sgibbs			mov	SCB_CDB_LEN call set_hcnt;
120839220Sgibbs		}
120939220Sgibbs		mvi	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
121063457Sgibbs	}
121163457Sgibbs	jmp	p_command_loop;
121263457Sgibbsp_command_embedded:
121363457Sgibbs	/*
121463457Sgibbs	 * The data fifo seems to require 4 byte alligned
121563457Sgibbs	 * transfers from the sequencer.  Force this to
121663457Sgibbs	 * be the case by clearing HADDR[0] even though
121763457Sgibbs	 * we aren't going to touch host memeory.
121863457Sgibbs	 */
121963457Sgibbs	clr	HADDR[0];
122063457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
122163457Sgibbs		mvi	DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
122263457Sgibbs		bmov	DFDAT, SCB_CDB_STORE, 12; 
122365942Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
122465942Sgibbs		if ((ahc->features & AHC_SCB_BTT) != 0) {
122565942Sgibbs			/*
122665942Sgibbs			 * On the 7895 the data FIFO will
122765942Sgibbs			 * get corrupted if you try to dump
122865942Sgibbs			 * data from external SCB memory into
122965942Sgibbs			 * the FIFO while it is enabled.  So,
123065942Sgibbs			 * fill the fifo and then enable SCSI
123165942Sgibbs			 * transfers.
123265942Sgibbs			 */
123365942Sgibbs			mvi	DFCNTRL, (DIRECTION|FIFORESET);
123465942Sgibbs		} else {
123565942Sgibbs			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
123665942Sgibbs		}
123765942Sgibbs		bmov	DFDAT, SCB_CDB_STORE, 12; 
123865942Sgibbs		if ((ahc->features & AHC_SCB_BTT) != 0) {
123965942Sgibbs			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH);
124065942Sgibbs		} else {
124163821Sgibbs			or	DFCNTRL, FIFOFLUSH;
124263821Sgibbs		}
124363457Sgibbs	} else {
124465942Sgibbs		mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
124563821Sgibbs		call	copy_to_fifo_6;
124663821Sgibbs		call	copy_to_fifo_6;
124763821Sgibbs		or	DFCNTRL, FIFOFLUSH;
124863457Sgibbs	}
124963457Sgibbsp_command_loop:
125039220Sgibbs	test	SSTAT0, SDONE jnz . + 2;
125163457Sgibbs	test    SSTAT1, PHASEMIS jz p_command_loop;
125255581Sgibbs	/*
125355581Sgibbs	 * Wait for our ACK to go-away on it's own
125455581Sgibbs	 * instead of being killed by SCSIEN getting cleared.
125555581Sgibbs	 */
125655581Sgibbs	test	SCSISIGI, ACKI jnz .;
125755581Sgibbs	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
125839220Sgibbs	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
125968087Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
126068087Sgibbs		/* Drop any residual from the S/G Preload queue */
126168087Sgibbs		or	SXFRCTL0, CLRSTCNT;
126268087Sgibbs	}
126323925Sgibbs	jmp	ITloop;
12644568Sgibbs
126513177Sgibbs/*
126613177Sgibbs * Status phase.  Wait for the data byte to appear, then read it
126713177Sgibbs * and store it into the SCB.
126813177Sgibbs */
12694568Sgibbsp_status:
127023925Sgibbs	call	assert;
127119803Sgibbs
127263457Sgibbs	mov	SCB_SCSI_STATUS, SCSIDATL;
127323925Sgibbs	jmp	ITloop;
12744568Sgibbs
127513177Sgibbs/*
127641646Sgibbs * Message out phase.  If MSG_OUT is MSG_IDENTIFYFLAG, build a full
127741646Sgibbs * indentify message sequence and send it to the target.  The host may
127841646Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB
127941646Sgibbs * control byte.  This will cause us to interrupt the host and allow
128041646Sgibbs * it to handle the message phase completely on its own.  If the bit
128141646Sgibbs * associated with this target is set, we will also interrupt the host,
128241646Sgibbs * thereby allowing it to send a message on the next selection regardless
128341646Sgibbs * of the transaction being sent.
128439220Sgibbs * 
128539220Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
128641646Sgibbs * This is done to allow the host to send messages outside of an identify
128739220Sgibbs * sequence while protecting the seqencer from testing the MK_MESSAGE bit
128839220Sgibbs * on an SCB that might not be for the current nexus. (For example, a
128939220Sgibbs * BDR message in responce to a bad reselection would leave us pointed to
129039220Sgibbs * an SCB that doesn't have anything to do with the current target).
129141646Sgibbs *
129239220Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
129339220Sgibbs * bus device reset).
129439220Sgibbs *
129539220Sgibbs * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
129639220Sgibbs * in case the target decides to put us in this phase for some strange
129739220Sgibbs * reason.
129813177Sgibbs */
129941646Sgibbsp_mesgout_retry:
130041646Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
13014568Sgibbsp_mesgout:
130239220Sgibbs	mov	SINDEX, MSG_OUT;
130339220Sgibbs	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
130441646Sgibbs	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
130563457Sgibbs	mov	FUNCTION1, SCB_SCSIID;
130641646Sgibbs	mov	A, FUNCTION1;
130747414Sgibbs	mov	SINDEX, TARGET_MSG_REQUEST[0];
130841646Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
130941646Sgibbs		/* Second Channel uses high byte bits */
131063457Sgibbs		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
131141646Sgibbs		mov	SINDEX, TARGET_MSG_REQUEST[1];
131241646Sgibbs	} else if ((ahc->features & AHC_WIDE) != 0) {
131363457Sgibbs		test	SCB_SCSIID, 0x80	jz . + 2; /* target > 7 */
131441646Sgibbs		mov	SINDEX, TARGET_MSG_REQUEST[1];
131541646Sgibbs	}
131641646Sgibbs	test	SINDEX, A	jnz host_message_loop;
131739220Sgibbsp_mesgout_identify:
131863457Sgibbs	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN;
131963457Sgibbs	test	SCB_CONTROL, DISCENB jnz . + 2;
132063457Sgibbs	and	SINDEX, ~DISCENB;
132113177Sgibbs/*
132239220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
132339220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
132413177Sgibbs */
132539220Sgibbsp_mesgout_tag:
132639220Sgibbs	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
132739220Sgibbs	mov	SCSIDATL, SINDEX;	/* Send the identify message */
132839220Sgibbs	call	phase_lock;
132939220Sgibbs	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
133039220Sgibbs	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
133139220Sgibbs	call	phase_lock;
133239220Sgibbs	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
133339220Sgibbs	mov	SCB_TAG	jmp p_mesgout_onebyte;
133413177Sgibbs/*
133541646Sgibbs * Interrupt the driver, and allow it to handle this message
133641646Sgibbs * phase and any required retries.
133713177Sgibbs */
133839220Sgibbsp_mesgout_from_host:
133939220Sgibbs	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
134041646Sgibbs	jmp	host_message_loop;
134139220Sgibbs
134239220Sgibbsp_mesgout_onebyte:
134339220Sgibbs	mvi	CLRSINT1, CLRATNO;
134439220Sgibbs	mov	SCSIDATL, SINDEX;
134539220Sgibbs
134613177Sgibbs/*
134741646Sgibbs * If the next bus phase after ATN drops is message out, it means
134813177Sgibbs * that the target is requesting that the last message(s) be resent.
134913177Sgibbs */
135039220Sgibbs	call	phase_lock;
135141646Sgibbs	cmp	LASTPHASE, P_MESGOUT	je p_mesgout_retry;
13524568Sgibbs
135319906Sgibbsp_mesgout_done:
135423925Sgibbs	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
135539220Sgibbs	mov	LAST_MSG, MSG_OUT;
135639220Sgibbs	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
135723925Sgibbs	jmp	ITloop;
13584568Sgibbs
135913177Sgibbs/*
136013177Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
136113177Sgibbs */
13624568Sgibbsp_mesgin:
136323925Sgibbs	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
13644568Sgibbs
136523925Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
136623925Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
136723925Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
136823925Sgibbs	cmp	ALLZEROS,A		je mesgin_complete;
136923925Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
137063457Sgibbs	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_ign_wide_residue;
137123925Sgibbs	cmp	A,MSG_NOOP		je mesgin_done;
13724568Sgibbs
137313177Sgibbs/*
137441887Sgibbs * Pushed message loop to allow the kernel to
137557099Sgibbs * run it's own message state engine.  To avoid an
137641887Sgibbs * extra nop instruction after signaling the kernel,
137741887Sgibbs * we perform the phase_lock before checking to see
137841887Sgibbs * if we should exit the loop and skip the phase_lock
137941887Sgibbs * in the ITloop.  Performing back to back phase_locks
138041887Sgibbs * shouldn't hurt, but why do it twice...
138113177Sgibbs */
138241887Sgibbshost_message_loop:
138368402Sgibbs	mvi	HOST_MSG_LOOP call set_seqint;
138441887Sgibbs	call	phase_lock;
138541887Sgibbs	cmp	RETURN_1, EXIT_MSG_LOOP	je ITloop + 1;
138641887Sgibbs	jmp	host_message_loop;
13879954Sgibbs
138863457Sgibbsmesgin_ign_wide_residue:
138963457Sgibbsif ((ahc->features & AHC_WIDE) != 0) {
139063457Sgibbs	test	SCSIRATE, WIDEXFER jz mesgin_reject;
139163457Sgibbs	/* Pull the residue byte */
139263457Sgibbs	mvi	ARG_1	call inb_next;
139363457Sgibbs	cmp	ARG_1, 0x01 jne mesgin_reject;
139463457Sgibbs	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
139563457Sgibbs	test	DATA_COUNT_ODD, 0x1	jz mesgin_done;
139668402Sgibbs	mvi	IGN_WIDE_RES call set_seqint;
139763457Sgibbs	jmp	mesgin_done;
139863457Sgibbs}
139963457Sgibbs
140063457Sgibbsmesgin_reject:
140163457Sgibbs	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
14029954Sgibbsmesgin_done:
140323925Sgibbs	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
140423925Sgibbs	jmp	ITloop;
14059954Sgibbs
14069954Sgibbsmesgin_complete:
140713177Sgibbs/*
140863457Sgibbs * We received a "command complete" message.  Put the SCB_TAG into the QOUTFIFO,
140919164Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
141039220Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0).
141139220Sgibbs * In either of these conditions, we upload the SCB back to the host so it can
141219164Sgibbs * process this information.  In the case of a non zero status byte, we 
141319164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
141419164Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
141568087Sgibbs * sense, it will fill the kernel SCB with a request sense command, requeue
141668087Sgibbs * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 
141768087Sgibbs * RETURN_1 to SEND_SENSE.
141813177Sgibbs */
141919164Sgibbs
142013177Sgibbs/*
142168402Sgibbs * See if we attempted to deliver a message but the target ingnored us.
142213177Sgibbs */
142368402Sgibbs	test	SCB_CONTROL, MK_MESSAGE jz . + 2;
142468402Sgibbs	mvi	MKMSG_FAILED call set_seqint;
142568402Sgibbs
142668402Sgibbs/*
142768402Sgibbs * Check for residuals
142868402Sgibbs */
142963457Sgibbs	test	SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */
143063457Sgibbs	test	SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
143163457Sgibbs	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
143263457Sgibbscheck_status:
143363457Sgibbs	test	SCB_SCSI_STATUS,0xff	jz complete;	/* Good Status? */
143419164Sgibbsupload_scb:
143563457Sgibbs	or	SCB_SGPTR, SG_RESID_VALID;
143623925Sgibbs	mvi	DMAPARAMS, FIFORESET;
143723925Sgibbs	mov	SCB_TAG		call dma_scb;
143863457Sgibbs	test	SCB_SCSI_STATUS, 0xff	jz complete;	/* Just a residual? */
143968402Sgibbs	mvi	BAD_STATUS call set_seqint;		/* let driver know */
144039220Sgibbs	cmp	RETURN_1, SEND_SENSE	jne complete;
144168087Sgibbs	call	add_scb_to_free_list;
144223925Sgibbs	jmp	await_busfree;
144339220Sgibbscomplete:
144439220Sgibbs	mov	SCB_TAG call complete_post;
144523925Sgibbs	jmp	await_busfree;
144641646Sgibbs}
14474568Sgibbs
144839220Sgibbscomplete_post:
144939220Sgibbs	/* Post the SCBID in SINDEX and issue an interrupt */
145044507Sgibbs	call	add_scb_to_free_list;
145139220Sgibbs	mov	ARG_1, SINDEX;
145239220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
145339220Sgibbs		mov	A, SDSCB_QOFF;
145439220Sgibbs	} else {
145539220Sgibbs		mov	A, QOUTPOS;
145639220Sgibbs	}
145739220Sgibbs	mvi	QOUTFIFO_OFFSET call post_byte_setup;
145839220Sgibbs	mov	ARG_1 call post_byte;
145939220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) == 0) {
146039220Sgibbs		inc 	QOUTPOS;
146139220Sgibbs	}
146239220Sgibbs	mvi	INTSTAT,CMDCMPLT ret;
146339220Sgibbs
146468087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) {
146513177Sgibbs/*
146613177Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
146763457Sgibbs * and await the bus going free.  If this is an untagged transaction
146863457Sgibbs * store the SCB id for it in our untagged target table for lookup on
146963457Sgibbs * a reselction.
147013177Sgibbs */
14719954Sgibbsmesgin_disconnect:
147223925Sgibbs	or	SCB_CONTROL,DISCONNECTED;
147363457Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
147463457Sgibbs		call	add_scb_to_disc_list;
147563457Sgibbs	}
147663457Sgibbs	test	SCB_CONTROL, TAG_ENB jnz await_busfree;
147763457Sgibbs	mov	ARG_1, SCB_TAG;
147863457Sgibbs	mov	SAVED_LUN, SCB_LUN;
147968087Sgibbs	mov	SCB_SCSIID	call set_busy_target;
148023925Sgibbs	jmp	await_busfree;
148119164Sgibbs
148215328Sgibbs/*
148319164Sgibbs * Save data pointers message:
148419164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
148519164Sgibbs * only if we've actually been into a data phase to change them.  This
148619164Sgibbs * protects against bogus data in scratch ram and the residual counts
148719164Sgibbs * since they are only initialized when we go into data_in or data_out.
148815328Sgibbs */
148919164Sgibbsmesgin_sdptrs:
149023925Sgibbs	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
14914568Sgibbs
149239220Sgibbs	/*
149363457Sgibbs	 * The SCB_SGPTR becomes the next one we'll download,
149463457Sgibbs	 * and the SCB_DATAPTR becomes the current SHADDR.
149539220Sgibbs	 * Use the residual number since STCNT is corrupted by
149639220Sgibbs	 * any message transfer.
149739220Sgibbs	 */
149839220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
149939220Sgibbs		bmov	SCB_DATAPTR, SHADDR, 4;
150063457Sgibbs		bmov	SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8;
150139220Sgibbs	} else {
150239220Sgibbs		mvi	DINDEX, SCB_DATAPTR;
150363457Sgibbs		mvi	SHADDR call bcopy_4;
150463457Sgibbs		mvi	SCB_RESIDUAL_DATACNT call bcopy_8;
150539220Sgibbs	}
150623925Sgibbs	jmp	mesgin_done;
15074568Sgibbs
150813177Sgibbs/*
150913177Sgibbs * Restore pointers message?  Data pointers are recopied from the
151013177Sgibbs * SCB anytime we enter a data phase for the first time, so all
151113177Sgibbs * we need to do is clear the DPHASE flag and let the data phase
151213177Sgibbs * code do the rest.
151313177Sgibbs */
15149954Sgibbsmesgin_rdptrs:
151523925Sgibbs	and	SEQ_FLAGS, ~DPHASE;		/*
151623925Sgibbs						 * We'll reload them
151713177Sgibbs						 * the next time through
151823925Sgibbs						 * the dataphase.
151913177Sgibbs						 */
152023925Sgibbs	jmp	mesgin_done;
15214568Sgibbs
152213177Sgibbs/*
152363457Sgibbs * Index into our Busy Target table.  SINDEX and DINDEX are modified
152463457Sgibbs * upon return.  SCBPTR may be modified by this action.
152563457Sgibbs */
152668087Sgibbsset_busy_target:
152768087Sgibbs	shr	DINDEX, 4, SINDEX;
152863457Sgibbs	if ((ahc->features & AHC_SCB_BTT) != 0) {
152963457Sgibbs		mov	SCBPTR, SAVED_LUN;
153068087Sgibbs		add	DINDEX, SCB_64_BTT;
153163457Sgibbs	} else {
153268087Sgibbs		add	DINDEX, BUSY_TARGETS;
153363457Sgibbs	}
153468087Sgibbs	mov	DINDIR, ARG_1 ret;
153563457Sgibbs
153663457Sgibbs/*
153713177Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
153813177Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
153913177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
154013177Sgibbs */
15419954Sgibbsmesgin_identify:
154263457Sgibbs	and	SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
154363457Sgibbs	/*
154463457Sgibbs	 * Determine whether a target is using tagged or non-tagged
154563457Sgibbs	 * transactions by first looking at the transaction stored in
154663457Sgibbs	 * the busy target array.  If there is no untagged transaction
154763457Sgibbs	 * for this target or the transaction is for a different lun, then
154863457Sgibbs	 * this must be an untagged transaction.
154963457Sgibbs	 */
155068087Sgibbsfetch_busy_target:
155168087Sgibbs	shr	A, 4, SAVED_SCSIID;
155268087Sgibbs	if ((ahc->features & AHC_SCB_BTT) != 0) {
155368087Sgibbs		add	SINDEX, SCB_64_BTT, A;
155468087Sgibbs		mov	SCBPTR, SAVED_LUN;
155568087Sgibbs	} else {
155668087Sgibbs		add	SINDEX, BUSY_TARGETS, A;
155768087Sgibbs		if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
155868087Sgibbs			add	A, -BUSY_TARGETS, SINDEX;
155968087Sgibbs			jc	. + 2;
156068087Sgibbs			mvi	INTSTAT, OUT_OF_RANGE;
156168402Sgibbs			nop;
156268087Sgibbs			add	A, -(BUSY_TARGETS + 16), SINDEX;
156368087Sgibbs			jnc	. + 2;
156468087Sgibbs			mvi	INTSTAT, OUT_OF_RANGE;
156568402Sgibbs			nop;
156668087Sgibbs		}
156768087Sgibbs	}
156868087Sgibbs	mov	ARG_1, SINDIR;
156968087Sgibbs	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
157063457Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
157168087Sgibbs		mov	RETURN_1 call findSCB;
157239220Sgibbs	} else {
157368087Sgibbs		mov	SCBPTR, RETURN_1;
157439220Sgibbs	}
157563457Sgibbs	if ((ahc->features & AHC_SCB_BTT) != 0) {
157663457Sgibbs		jmp setup_SCB_id_lun_okay;
157763457Sgibbs	} else {
157863457Sgibbs		mov	A, SCB_LUN;
157963457Sgibbs		cmp	SAVED_LUN, A		je setup_SCB_id_lun_okay;
158063457Sgibbs	}
158168087Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
158268087Sgibbs		call	add_scb_to_disc_list;
158368087Sgibbs	}
158439220Sgibbs
158513177Sgibbs/*
158613177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
158723168Sgibbs * If we get one, we use the tag returned to find the proper
158863457Sgibbs * SCB.  With SCB paging, we must search for non-tagged
158963457Sgibbs * transactions since the SCB may exist in any slot.  If we're not
159063457Sgibbs * using SCB paging, we can use the tag as the direct index to the
159163457Sgibbs * SCB.
159213177Sgibbs */
159324608Sgibbssnoop_tag:
159423925Sgibbs	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
159539220Sgibbs	call	phase_lock;
159668087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
159768087Sgibbs		or	SEQ_FLAGS, 0x1;
159868087Sgibbs	}
159923925Sgibbs	cmp	LASTPHASE, P_MESGIN	jne not_found;
160068087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
160168087Sgibbs		or	SEQ_FLAGS, 0x2;
160268087Sgibbs	}
160323925Sgibbs	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
16046608Sgibbsget_tag:
160563457Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
160663457Sgibbs		mvi	ARG_1	call inb_next;	/* tag value */
160763457Sgibbs		mov	ARG_1	call findSCB;
160863457Sgibbs	} else {
160968087Sgibbs		mvi	ARG_1	call inb_next;	/* tag value */
161068087Sgibbs		mov	SCBPTR, ARG_1;
161163457Sgibbs	}
161213177Sgibbs
161363457Sgibbs/*
161463457Sgibbs * Ensure that the SCB the tag points to is for
161563457Sgibbs * an SCB transaction to the reconnecting target.
161663457Sgibbs */
161739220Sgibbssetup_SCB:
161863457Sgibbs	mov	A, SAVED_SCSIID;
161968087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
162068087Sgibbs		or	SEQ_FLAGS, 0x4;
162168087Sgibbs	}
162268087Sgibbs	cmp	SCB_SCSIID, A	jne not_found_cleanup_scb;
162363457Sgibbs	mov	A, SAVED_LUN;
162468087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
162568087Sgibbs		or	SEQ_FLAGS, 0x8;
162668087Sgibbs	}
162768087Sgibbs	cmp	SCB_LUN, A	jne not_found_cleanup_scb;
162863457Sgibbssetup_SCB_id_lun_okay:
162968087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
163068087Sgibbs		or	SEQ_FLAGS, 0x10;
163163457Sgibbs	}
163268087Sgibbs	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
163323925Sgibbs	and	SCB_CONTROL,~DISCONNECTED;
163468087Sgibbs	mvi	SEQ_FLAGS,IDENTIFY_SEEN;	/* make note of IDENTIFY */
163563457Sgibbs	test	SCB_CONTROL, TAG_ENB	jnz setup_SCB_tagged;
163663457Sgibbs	mov	A, SCBPTR;
163768087Sgibbs	mvi	ARG_1, SCB_LIST_NULL;
163868087Sgibbs	mov	SAVED_SCSIID	call	set_busy_target;
163963457Sgibbs	mov	SCBPTR, A;
164063457Sgibbssetup_SCB_tagged:
164139220Sgibbs	call	set_transfer_settings;
164239220Sgibbs	/* See if the host wants to send a message upon reconnection */
164339220Sgibbs	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
164439220Sgibbs	mvi	HOST_MSG	call mk_mesg;
164523925Sgibbs	jmp	mesgin_done;
164615328Sgibbs
164768087Sgibbsnot_found_cleanup_scb:
164868087Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
164968087Sgibbs		call	add_scb_to_free_list;
165068087Sgibbs	}
165119218Sgibbsnot_found:
165268402Sgibbs	mvi	NO_MATCH call set_seqint;
165323925Sgibbs	jmp	mesgin_done;
16546608Sgibbs
16554568Sgibbsmk_mesg:
165623925Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
165739220Sgibbs	mov	MSG_OUT,SINDEX ret;
16584568Sgibbs
165913177Sgibbs/*
166013177Sgibbs * Functions to read data in Automatic PIO mode.
166113177Sgibbs *
166213177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
166313177Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
166413177Sgibbs * latched (the usual way), then read the data byte directly off the bus
166513177Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
166613177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
166713177Sgibbs * spec guarantees that the target will hold the data byte on the bus until
166813177Sgibbs * we send our ACK.
166913177Sgibbs *
167013177Sgibbs * The assumption here is that these are called in a particular sequence,
167113177Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
167213177Sgibbs * use the same calling convention as inb.
167313177Sgibbs */
167457099Sgibbsinb_next_wait_perr:
167568402Sgibbs	mvi	PERR_DETECTED call set_seqint;
167657099Sgibbs	jmp	inb_next_wait;
167713177Sgibbsinb_next:
167823925Sgibbs	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
167913360Sgibbsinb_next_wait:
168021947Sgibbs	/*
168121947Sgibbs	 * If there is a parity error, wait for the kernel to
168221947Sgibbs	 * see the interrupt and prepare our message response
168321947Sgibbs	 * before continuing.
168421947Sgibbs	 */
168523925Sgibbs	test	SSTAT1, REQINIT	jz inb_next_wait;
168657099Sgibbs	test	SSTAT1, SCSIPERR jnz inb_next_wait_perr;
168757099Sgibbsinb_next_check_phase:
168823925Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI;
168923925Sgibbs	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
169019623Sgibbsinb_first:
169123925Sgibbs	mov	DINDEX,SINDEX;
169223925Sgibbs	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
169313177Sgibbsinb_last:
169423925Sgibbs	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
169541646Sgibbs}
16964568Sgibbs
169768087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) {
169841646Sgibbs/*
169941646Sgibbs * Change to a new phase.  If we are changing the state of the I/O signal,
170041646Sgibbs * from out to in, wait an additional data release delay before continuing.
170141646Sgibbs */
170241646Sgibbschange_phase:
170343880Sgibbs	/* Wait for preceeding I/O session to complete. */
170443880Sgibbs	test	SCSISIGI, ACKI jnz .;
170543880Sgibbs
170643880Sgibbs	/* Change the phase */
170741646Sgibbs	and	DINDEX, IOI, SCSISIGI;
170841646Sgibbs	mov	SCSISIGO, SINDEX;
170941646Sgibbs	and	A, IOI, SINDEX;
171043880Sgibbs
171143880Sgibbs	/*
171243880Sgibbs	 * If the data direction has changed, from
171343880Sgibbs	 * out (initiator driving) to in (target driving),
171463457Sgibbs	 * we must wait at least a data release delay plus
171543880Sgibbs	 * the normal bus settle delay. [SCSI III SPI 10.11.0]
171643880Sgibbs	 */
171741646Sgibbs	cmp 	DINDEX, A je change_phase_wait;
171841646Sgibbs	test	SINDEX, IOI jz change_phase_wait;
171941646Sgibbs	call	change_phase_wait;
172041646Sgibbschange_phase_wait:
172141646Sgibbs	nop;
172241646Sgibbs	nop;
172341646Sgibbs	nop;
172441646Sgibbs	nop ret;
172541646Sgibbs
172641646Sgibbs/*
172741646Sgibbs * Send a byte to an initiator in Automatic PIO mode.
172841646Sgibbs */
172939220Sgibbstarget_outb:
173039220Sgibbs	or	SXFRCTL0, SPIOEN;
173139220Sgibbs	test	SSTAT0, SPIORDY	jz .;
173239220Sgibbs	mov	SCSIDATL, SINDEX;
173339220Sgibbs	test	SSTAT0, SPIORDY	jz .;
173441646Sgibbs	and	SXFRCTL0, ~SPIOEN ret;
173539220Sgibbs}
173639220Sgibbs	
17374568Sgibbs
173813177Sgibbs/*
173913177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
174013177Sgibbs * message.
174113177Sgibbs */
17424568Sgibbsassert:
174323925Sgibbs	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
17444568Sgibbs
174568402Sgibbs	mvi	NO_IDENT jmp set_seqint;	/* no - tell the kernel */
17464568Sgibbs
174713177Sgibbs/*
174863457Sgibbs * Locate a disconnected SCB by SCBID.  Upon return, SCBPTR and SINDEX will
174963457Sgibbs * be set to the position of the SCB.  If the SCB cannot be found locally,
175063457Sgibbs * it will be paged in from host memory.  RETURN_2 stores the address of the
175163457Sgibbs * preceding SCB in the disconnected list which can be used to speed up
175263457Sgibbs * removal of the found SCB from the disconnected list.
175313177Sgibbs */
175465942Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) {
17554568SgibbsfindSCB:
175668087Sgibbs	mov	A, SINDEX;			/* Tag passed in SINDEX */
175768087Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound;
175863457Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH;	/* Initialize SCBPTR */
175968087Sgibbs	mvi	ARG_2, SCB_LIST_NULL;		/* Head of list */
176063457Sgibbs	jmp	findSCB_loop;
176139220SgibbsfindSCB_next:
176263457Sgibbs	cmp	SCB_NEXT, SCB_LIST_NULL je findSCB_notFound;
176368087Sgibbs	mov	ARG_2, SCBPTR;
176439220Sgibbs	mov	SCBPTR,SCB_NEXT;
176523168SgibbsfindSCB_loop:
176663457Sgibbs	cmp	SCB_TAG, A	jne findSCB_next;
176719164Sgibbsrem_scb_from_disc_list:
176839220Sgibbs	cmp	ARG_2, SCB_LIST_NULL	je rHead;
176939220Sgibbs	mov	DINDEX, SCB_NEXT;
177068087Sgibbs	mov	SINDEX, SCBPTR;
177139220Sgibbs	mov	SCBPTR, ARG_2;
177239220Sgibbs	mov	SCB_NEXT, DINDEX;
177323925Sgibbs	mov	SCBPTR, SINDEX ret;
177415328SgibbsrHead:
177523925Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
177668087SgibbsfindSCB_notFound:
177768087Sgibbs	/*
177868087Sgibbs	 * We didn't find it.  Page in the SCB.
177968087Sgibbs	 */
178068087Sgibbs	mov	ARG_1, A; /* Save tag */
178168087Sgibbs	mov	ALLZEROS call get_free_or_disc_scb;
178268087Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
178368087Sgibbs	mov	ARG_1	jmp dma_scb;
178468087Sgibbs}
17854568Sgibbs
178639220Sgibbs/*
178739220Sgibbs * Prepare the hardware to post a byte to host memory given an
178863457Sgibbs * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR.
178939220Sgibbs */
179039220Sgibbspost_byte_setup:
179139220Sgibbs	mov	ARG_2, SINDEX;
179239220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
179339220Sgibbs		mvi	DINDEX, CCHADDR;
179463457Sgibbs		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
179539220Sgibbs		mvi	CCHCNT, 1;
179639220Sgibbs		mvi	CCSCBCTL, CCSCBRESET ret;
179739220Sgibbs	} else {
179839220Sgibbs		mvi	DINDEX, HADDR;
179963457Sgibbs		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
180063457Sgibbs		mvi	1	call set_hcnt;
180139220Sgibbs		mvi	DFCNTRL, FIFORESET ret;
180239220Sgibbs	}
180339220Sgibbs
180439220Sgibbspost_byte:
180539220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
180639220Sgibbs		bmov	CCSCBRAM, SINDEX, 1;
180739220Sgibbs		or	CCSCBCTL, CCSCBEN|CCSCBRESET;
180839220Sgibbs		test	CCSCBCTL, CCSCBDONE jz .;
180939220Sgibbs		clr	CCSCBCTL ret;
181039220Sgibbs	} else {
181139220Sgibbs		mov	DFDAT, SINDEX;
181239220Sgibbs		or	DFCNTRL, HDMAEN|FIFOFLUSH;
181339220Sgibbs		jmp	dma_finish;
181439220Sgibbs	}
181539220Sgibbs
181657099Sgibbsphase_lock_perr:
181768402Sgibbs	mvi	PERR_DETECTED call set_seqint;
181839220Sgibbsphase_lock:     
181957099Sgibbs	/*
182057099Sgibbs	 * If there is a parity error, wait for the kernel to
182157099Sgibbs	 * see the interrupt and prepare our message response
182257099Sgibbs	 * before continuing.
182357099Sgibbs	 */
182439220Sgibbs	test	SSTAT1, REQINIT jz phase_lock;
182557099Sgibbs	test	SSTAT1, SCSIPERR jnz phase_lock_perr;
182657099Sgibbsphase_lock_latch_phase:
182741646Sgibbs	and	SCSISIGO, PHASE_MASK, SCSISIGI;
182841646Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
182939220Sgibbs
183039220Sgibbsif ((ahc->features & AHC_CMD_CHAN) == 0) {
183163457Sgibbsset_hcnt:
183263457Sgibbs	mov	HCNT[0], SINDEX;
183363457Sgibbsclear_hcnt:
183463457Sgibbs	clr	HCNT[1];
183563457Sgibbs	clr	HCNT[2] ret;
183663457Sgibbs
183719164Sgibbsset_stcnt_from_hcnt:
183823925Sgibbs	mov	STCNT[0], HCNT[0];
183923925Sgibbs	mov	STCNT[1], HCNT[1];
184023925Sgibbs	mov	STCNT[2], HCNT[2] ret;
18414568Sgibbs
184263457Sgibbsbcopy_8:
184363457Sgibbs	mov	DINDIR, SINDIR;
184419164Sgibbsbcopy_7:
184523925Sgibbs	mov	DINDIR, SINDIR;
184623925Sgibbs	mov	DINDIR, SINDIR;
184719164Sgibbsbcopy_5:
184823925Sgibbs	mov	DINDIR, SINDIR;
184919164Sgibbsbcopy_4:
185023925Sgibbs	mov	DINDIR, SINDIR;
185119164Sgibbsbcopy_3:
185223925Sgibbs	mov	DINDIR, SINDIR;
185323925Sgibbs	mov	DINDIR, SINDIR;
185423925Sgibbs	mov	DINDIR, SINDIR ret;
185539220Sgibbs}
18564568Sgibbs
185768087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) {
185839220Sgibbs/*
185939220Sgibbs * Setup addr assuming that A is an index into
186039220Sgibbs * an array of 32byte objects, SINDEX contains
186139220Sgibbs * the base address of that array, and DINDEX
186239220Sgibbs * contains the base address of the location
186339220Sgibbs * to store the indexed address.
186439220Sgibbs */
186539220Sgibbsset_32byte_addr:
186639220Sgibbs	shr	ARG_2, 3, A;
186739220Sgibbs	shl	A, 5;
186839220Sgibbs	jmp	set_1byte_addr;
186939220Sgibbs}
187039220Sgibbs
187139220Sgibbs/*
187239220Sgibbs * Setup addr assuming that A is an index into
187339220Sgibbs * an array of 64byte objects, SINDEX contains
187439220Sgibbs * the base address of that array, and DINDEX
187539220Sgibbs * contains the base address of the location
187639220Sgibbs * to store the indexed address.
187739220Sgibbs */
187839220Sgibbsset_64byte_addr:
187939220Sgibbs	shr	ARG_2, 2, A;
188039220Sgibbs	shl	A, 6;
188139220Sgibbs
188239220Sgibbs/*
188363457Sgibbs * Setup addr assuming that A + (ARG_2 * 256) is an
188439220Sgibbs * index into an array of 1byte objects, SINDEX contains
188539220Sgibbs * the base address of that array, and DINDEX contains
188639220Sgibbs * the base address of the location to store the computed
188739220Sgibbs * address.
188839220Sgibbs */
188939220Sgibbsset_1byte_addr:
189039220Sgibbs	add     DINDIR, A, SINDIR;
189139220Sgibbs	mov     A, ARG_2;
189239220Sgibbs	adc	DINDIR, A, SINDIR;
189339220Sgibbs	clr	A;
189439220Sgibbs	adc	DINDIR, A, SINDIR;
189539220Sgibbs	adc	DINDIR, A, SINDIR ret;
189639220Sgibbs
189739220Sgibbs/*
189839220Sgibbs * Either post or fetch and SCB from host memory based on the
189939220Sgibbs * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
190039220Sgibbs */
190119164Sgibbsdma_scb:
190239220Sgibbs	mov	A, SINDEX;
190339220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
190439220Sgibbs		mvi	DINDEX, CCHADDR;
190539220Sgibbs		mvi	HSCB_ADDR call set_64byte_addr;
190639220Sgibbs		mov	CCSCBPTR, SCBPTR;
190739220Sgibbs		test	DMAPARAMS, DIRECTION jz dma_scb_tohost;
190865942Sgibbs		if ((ahc->features & AHC_SCB_BTT) != 0) {
190965942Sgibbs			mvi	CCHCNT, SCB_DOWNLOAD_SIZE_64;
191065942Sgibbs		} else {
191165942Sgibbs			mvi	CCHCNT, SCB_DOWNLOAD_SIZE;
191265942Sgibbs		}
191339220Sgibbs		mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
191439220Sgibbs		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
191539220Sgibbs		jmp	dma_scb_finish;
191639220Sgibbsdma_scb_tohost:
191765942Sgibbs		mvi	CCHCNT, SCB_UPLOAD_SIZE;
191865942Sgibbs		if ((ahc->features & AHC_ULTRA2) == 0) {
191939220Sgibbs			mvi	CCSCBCTL, CCSCBRESET;
192065942Sgibbs			bmov	CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE;
192139220Sgibbs			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
192268402Sgibbs			cmp	CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
192365942Sgibbs		} else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) {
192465942Sgibbs			mvi	CCSCBCTL, CCARREN|CCSCBRESET;
192565942Sgibbs			cmp	CCSCBCTL, ARRDONE|CCARREN jne .;
192665942Sgibbs			mvi	CCHCNT, SCB_UPLOAD_SIZE;
192765942Sgibbs			mvi	CCSCBCTL, CCSCBEN|CCSCBRESET;
192865942Sgibbs			cmp	CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
192939220Sgibbs		} else {
193039220Sgibbs			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
193139220Sgibbs			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
193239220Sgibbs		}
193339220Sgibbsdma_scb_finish:
193439220Sgibbs		clr	CCSCBCTL;
193539220Sgibbs		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
193639220Sgibbs		ret;
193739220Sgibbs	} else {
193839220Sgibbs		mvi	DINDEX, HADDR;
193939220Sgibbs		mvi	HSCB_ADDR call set_64byte_addr;
194065942Sgibbs		mvi	SCB_DOWNLOAD_SIZE call set_hcnt;
194139220Sgibbs		mov	DFCNTRL, DMAPARAMS;
194239220Sgibbs		test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
194339220Sgibbs		/* Fill it with the SCB data */
194424175Sgibbscopy_scb_tofifo:
194565942Sgibbs		mvi	SINDEX, SCB_BASE;
194665942Sgibbs		add	A, SCB_DOWNLOAD_SIZE, SINDEX;
194724175Sgibbscopy_scb_tofifo_loop:
194865942Sgibbs		call	copy_to_fifo_8;
194939220Sgibbs		cmp	SINDEX, A jne copy_scb_tofifo_loop;
195039220Sgibbs		or	DFCNTRL, HDMAEN|FIFOFLUSH;
195165942Sgibbs		jmp	dma_finish;
195219164Sgibbsdma_scb_fromhost:
195365942Sgibbs		mvi	DINDEX, SCB_BASE;
195465942Sgibbs		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
195565942Sgibbs			/*
195665942Sgibbs			 * The PCI module will only issue a PCI
195765942Sgibbs			 * retry if the data FIFO is empty.  If the
195865942Sgibbs			 * host disconnects in the middle of a
195965942Sgibbs			 * transfer, we must empty the fifo of all
196065942Sgibbs			 * available data to force the chip to
196165942Sgibbs			 * continue the transfer.  This does not
196265942Sgibbs			 * happen for SCSI transfers as the SCSI module
196365942Sgibbs			 * will drain the FIFO as data is made available.
196465942Sgibbs			 * When the hang occurs, we know that at least
196565942Sgibbs			 * 8 bytes are in the FIFO because the PCI
196665942Sgibbs			 * module has an 8 byte input latch that only
196765942Sgibbs			 * dumps to the FIFO when HCNT == 0 or the
196865942Sgibbs			 * latch is full.
196965942Sgibbs			 */
197065942Sgibbs			mvi	A, -24;
197165942Sgibbs			/* Wait for some data to arrive. */
197265942Sgibbsdma_scb_hang_fifo:
197365942Sgibbs			test	DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo;
197465942Sgibbsdma_scb_hang_wait:
197565942Sgibbs			test	DFSTATUS, MREQPEND jnz dma_scb_hang_wait;
197665942Sgibbs			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
197765942Sgibbs			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
197865942Sgibbs			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
197965942Sgibbs			/*
198065942Sgibbs			 * The PCI no longer intends to perform a PCI
198165942Sgibbs			 * transaction and HDONE has not come true.
198265942Sgibbs			 * We are hung.  Drain the fifo.
198365942Sgibbs			 */
198465942Sgibbsdma_scb_hang_empty_fifo:
198565942Sgibbs			call	dfdat_in_8;
198665942Sgibbs			add	A, 8;
198765942Sgibbs			add	SINDEX, A, HCNT; 
198865942Sgibbs			/*
198965942Sgibbs			 * The result will be <= 0 (carry set) if at
199065942Sgibbs			 * least 8 bytes of data have been placed
199165942Sgibbs			 * into the fifo.
199265942Sgibbs			 */
199365942Sgibbs			jc	dma_scb_hang_empty_fifo;
199465942Sgibbs			jmp	dma_scb_hang_fifo;
199565942Sgibbsdma_scb_hang_dma_done:
199665942Sgibbs			and	DFCNTRL, ~HDMAEN;
199765942Sgibbs			test	DFCNTRL, HDMAEN jnz .;
199865942Sgibbs			call	dfdat_in_8;
199965942Sgibbs			add	A, 8;
200065942Sgibbs			cmp	A, 8 jne . - 2;
200165942Sgibbs		} else {
200265942Sgibbs			call	dma_finish;
200365942Sgibbs			/* If we were putting the SCB, we are done */
200465942Sgibbs			call	dfdat_in_8;
200565942Sgibbs			call	dfdat_in_8;
200665942Sgibbs			call	dfdat_in_8;
200765942Sgibbs		}
200865942Sgibbsdfdat_in_8:
200965942Sgibbs		mov	DINDIR,DFDAT;
201019164Sgibbsdfdat_in_7:
201139220Sgibbs		mov	DINDIR,DFDAT;
201239220Sgibbs		mov	DINDIR,DFDAT;
201339220Sgibbs		mov	DINDIR,DFDAT;
201439220Sgibbs		mov	DINDIR,DFDAT;
201539220Sgibbs		mov	DINDIR,DFDAT;
201665942Sgibbsdfdat_in_2:
201739220Sgibbs		mov	DINDIR,DFDAT;
201839220Sgibbs		mov	DINDIR,DFDAT ret;
201939220Sgibbs	}
202019164Sgibbs
202165942Sgibbscopy_to_fifo_8:
202265942Sgibbs	mov	DFDAT,SINDIR;
202365942Sgibbs	mov	DFDAT,SINDIR;
202463457Sgibbscopy_to_fifo_6:
202563457Sgibbs	mov	DFDAT,SINDIR;
202663457Sgibbscopy_to_fifo_5:
202763457Sgibbs	mov	DFDAT,SINDIR;
202863457Sgibbscopy_to_fifo_4:
202963457Sgibbs	mov	DFDAT,SINDIR;
203063457Sgibbs	mov	DFDAT,SINDIR;
203163457Sgibbs	mov	DFDAT,SINDIR;
203263457Sgibbs	mov	DFDAT,SINDIR ret;
203339220Sgibbs
203413177Sgibbs/*
203519164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
203619164Sgibbs * DMA and wait for it to acknowledge that it's off.
203713177Sgibbs */
203819164Sgibbsdma_finish:
203923925Sgibbs	test	DFSTATUS,HDONE	jz dma_finish;
204022234Sgibbs	/* Turn off DMA */
204123925Sgibbs	and	DFCNTRL, ~HDMAEN;
204223925Sgibbs	test	DFCNTRL, HDMAEN jnz .;
204323925Sgibbs	ret;
20449928Sgibbs
204523925Sgibbsadd_scb_to_free_list:
204639220Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
204766647SgibbsBEGIN_CRITICAL
204839220Sgibbs		mov	SCB_NEXT, FREE_SCBH;
204957099Sgibbs		mvi	SCB_TAG, SCB_LIST_NULL;
205057099Sgibbs		mov	FREE_SCBH, SCBPTR ret;
205166647SgibbsEND_CRITICAL
205257099Sgibbs	} else {
205357099Sgibbs		mvi	SCB_TAG, SCB_LIST_NULL ret;
205439220Sgibbs	}
20554568Sgibbs
205639220Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) {
205719164Sgibbsget_free_or_disc_scb:
205823925Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
205923925Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
206019623Sgibbsreturn_error:
206168402Sgibbs	mvi	NO_FREE_SCB call set_seqint;
206223925Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret;
206319623Sgibbsdequeue_disc_scb:
206423925Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH;
206523925Sgibbsdma_up_scb:
206623925Sgibbs	mvi	DMAPARAMS, FIFORESET;
206768087Sgibbs	mov	SCB_TAG	call dma_scb;
206819164Sgibbsunlink_disc_scb:
206939220Sgibbs	mov	DISCONNECTED_SCBH, SCB_NEXT ret;
207019164Sgibbsdequeue_free_scb:
207123925Sgibbs	mov	SCBPTR, FREE_SCBH;
207223925Sgibbs	mov	FREE_SCBH, SCB_NEXT ret;
20734568Sgibbs
207419164Sgibbsadd_scb_to_disc_list:
207513177Sgibbs/*
207619164Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
207719164Sgibbs * candidates for paging out an SCB if one is needed for a new command.
207819164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
207913177Sgibbs */
208068087SgibbsBEGIN_CRITICAL
208123925Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH;
208239220Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR ret;
208368087SgibbsEND_CRITICAL
208465942Sgibbs}
208568402Sgibbsset_seqint:
208668402Sgibbs	mov	INTSTAT, SINDEX;
208768402Sgibbs	nop;
208863457Sgibbsreturn:
208963457Sgibbs	ret;
2090