aic7xxx.seq revision 68087
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 68087 2000-10-31 18:43:29Z 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		mov	NONE, SNSCB_QOFF;
8239220Sgibbs	} else {
8368087Sgibbs		mov	A, QINPOS;
8439220Sgibbs		cmp	KERNEL_QINPOS, A je poll_for_work_loop;
8539220Sgibbs		inc	QINPOS;
8639220Sgibbs	}
8766647Sgibbs	mov	ARG_1, NEXT_QUEUED_SCB;
8866647SgibbsEND_CRITICAL
894568Sgibbs
9063457Sgibbs	/*
9163457Sgibbs	 * We have at least one queued SCB now and we don't have any 
9266647Sgibbs	 * SCBs in the list of SCBs awaiting selection.  Allocate a
9366647Sgibbs	 * card SCB for the host's SCB and get to work on it.
9463457Sgibbs	 */
9539220Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
9639220Sgibbs		mov	ALLZEROS	call	get_free_or_disc_scb;
9766647Sgibbs	} else {
9839220Sgibbs		/* In the non-paging case, the SCBID == hardware SCB index */
9966647Sgibbs		mov	SCBPTR, ARG_1;
10039220Sgibbs	}
10119164Sgibbsdma_queued_scb:
10263457Sgibbs	/*
10363457Sgibbs	 * DMA the SCB from host ram into the current SCB location.
10463457Sgibbs	 */
10523925Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
10666647Sgibbs	mov	ARG_1	call dma_scb;
10719164Sgibbs	/*
10866647Sgibbs	 * Check one last time to see if this SCB was canceled
10966647Sgibbs	 * before we completed the DMA operation.  If it was,
11066647Sgibbs	 * the QINFIFO next pointer will not match our saved
11166647Sgibbs	 * value.
11219164Sgibbs	 */
11366647Sgibbs	mov	A, ARG_1;
11466647SgibbsBEGIN_CRITICAL
11566647Sgibbs	cmp	NEXT_QUEUED_SCB, A jne abort_qinscb;
11668087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
11768087Sgibbs		if ((ahc->flags & AHC_PAGESCBS) == 0) {
11868087Sgibbs			cmp	SCBPTR, A je . + 2;
11968087Sgibbs			mvi	INTSTAT, SCBPTR_MISMATCH;
12068087Sgibbs		}
12168087Sgibbs		cmp	SCB_TAG, A je . + 2;
12268087Sgibbs		mvi	INTSTAT, SCB_MISMATCH;
12368087Sgibbs	}
12466647Sgibbs	mov	NEXT_QUEUED_SCB, SCB_NEXT;
12523925Sgibbs	mov	SCB_NEXT,WAITING_SCBH;
12623925Sgibbs	mov	WAITING_SCBH, SCBPTR;
12766647SgibbsEND_CRITICAL
12823925Sgibbsstart_waiting:
12923925Sgibbs	/*
13063457Sgibbs	 * Start the first entry on the waiting SCB list.
13123925Sgibbs	 */
13223925Sgibbs	mov	SCBPTR, WAITING_SCBH;
13323925Sgibbs	call	start_selection;
13465942Sgibbs	jmp	poll_for_work_loop;
1358104Sgibbs
13666647Sgibbsabort_qinscb:
13768087Sgibbs	mvi	INTSTAT, ABORT_QINSCB;
13866647Sgibbs	call	add_scb_to_free_list;
13966647Sgibbs	jmp	poll_for_work_loop;
14066647Sgibbs
14123925Sgibbsstart_selection:
14239220Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
14339220Sgibbs		and	SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
14463457Sgibbs		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
14563457Sgibbs		or	SINDEX, SELBUSB;
14639220Sgibbs		mov	SBLKCTL,SINDEX;		/* select channel */
14739220Sgibbs	}
14823925Sgibbsinitialize_scsiid:
14963457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
15063457Sgibbs		mov	SCSIID_ULTRA2, SCB_SCSIID;
15163457Sgibbs	} else if ((ahc->features & AHC_TWIN) != 0) {
15263457Sgibbs		and	SCSIID, TWIN_TID|OID, SCB_SCSIID;
15363457Sgibbs	} else {
15463457Sgibbs		mov	SCSIID, SCB_SCSIID;
15563457Sgibbs	}
15668087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
15763457Sgibbs		mov	SINDEX, SCSISEQ_TEMPLATE;
15863457Sgibbs		test	SCB_CONTROL, TARGET_SCB jz . + 2;
15944507Sgibbs		or	SINDEX, TEMODE;
16063457Sgibbs		mov	SCSISEQ, SINDEX ret;
16139220Sgibbs	} else {
16263457Sgibbs		mov	SCSISEQ, SCSISEQ_TEMPLATE ret;
16339220Sgibbs	}
16439220Sgibbs
16513177Sgibbs/*
16639220Sgibbs * Initialize transfer settings and clear the SCSI channel.
16739220Sgibbs * SINDEX should contain any additional bit's the client wants
16839220Sgibbs * set in SXFRCTL0.  We also assume that the current SCB is
16939220Sgibbs * a valid SCB for the target we wish to talk to.
17039220Sgibbs */
17139220Sgibbsinitialize_channel:
17268087Sgibbs	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
17339220Sgibbsset_transfer_settings:
17439220Sgibbs	if ((ahc->features & AHC_ULTRA) != 0) {
17539220Sgibbs		test	SCB_CONTROL, ULTRAENB jz . + 2;
17639220Sgibbs		or	SXFRCTL0, FAST20;
17739220Sgibbs	} 
17863457Sgibbs	/*
17963457Sgibbs	 * Initialize SCSIRATE with the appropriate value for this target.
18063457Sgibbs	 */
18139220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
18239220Sgibbs		bmov	SCSIRATE, SCB_SCSIRATE, 2 ret;
18339220Sgibbs	} else {
18439220Sgibbs		mov	SCSIRATE, SCB_SCSIRATE ret;
18539220Sgibbs	}
18639220Sgibbs
18739220Sgibbsselection:
18863457Sgibbs	/*
18963457Sgibbs	 * We aren't expecting a bus free, so interrupt
19063457Sgibbs	 * the kernel driver if it happens.
19163457Sgibbs	 */
19263457Sgibbs	mvi	CLRSINT1,CLRBUSFREE;
19363457Sgibbs	or	SIMODE1, ENBUSFREE;
19463457Sgibbs
19539220Sgibbs	test	SSTAT0,SELDO	jnz select_out;
19639220Sgibbs	mvi	CLRSINT0, CLRSELDI;
19739220Sgibbsselect_in:
19868087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
19968087Sgibbs		if ((ahc->flags & AHC_INITIATORROLE) != 0) {
20041646Sgibbs			test	SSTAT0, TARGET	jz initiator_reselect;
20141646Sgibbs		}
20242652Sgibbs
20339220Sgibbs		/*
20439220Sgibbs		 * We've just been selected.  Assert BSY and
20539220Sgibbs		 * setup the phase for receiving messages
20639220Sgibbs		 * from the target.
20739220Sgibbs		 */
20839220Sgibbs		mvi	SCSISIGO, P_MESGOUT|BSYO;
20939220Sgibbs
21039220Sgibbs		/*
21139220Sgibbs		 * Setup the DMA for sending the identify and
21241299Sgibbs		 * command information.
21339220Sgibbs		 */
21439220Sgibbs		or	SEQ_FLAGS, CMDPHASE_PENDING;
21541299Sgibbs
21641299Sgibbs		mov     A, TQINPOS;
21739220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
21839220Sgibbs			mvi	DINDEX, CCHADDR;
21963457Sgibbs			mvi	SHARED_DATA_ADDR call set_32byte_addr;
22039220Sgibbs			mvi	CCSCBCTL, CCSCBRESET;
22139220Sgibbs		} else {
22239220Sgibbs			mvi	DINDEX, HADDR;
22363457Sgibbs			mvi	SHARED_DATA_ADDR call set_32byte_addr;
22439220Sgibbs			mvi	DFCNTRL, FIFORESET;
22539220Sgibbs		}
22639220Sgibbs
22739220Sgibbs		/* Initiator that selected us */
22863457Sgibbs		and	SAVED_SCSIID, SELID_MASK, SELID;
22963457Sgibbs		/* The Target ID we were selected at */
23063457Sgibbs		if ((ahc->features & AHC_MULTI_TID) != 0) {
23163457Sgibbs			and	A, OID, TARGIDIN;
23263457Sgibbs		} else if ((ahc->features & AHC_ULTRA2) != 0) {
23363457Sgibbs			and	A, OID, SCSIID_ULTRA2;
23439220Sgibbs		} else {
23563457Sgibbs			and	A, OID, SCSIID;
23639220Sgibbs		}
23763457Sgibbs		or	SAVED_SCSIID, A;
23863457Sgibbs		if ((ahc->features & AHC_TWIN) != 0) {
23963457Sgibbs			test 	SBLKCTL, SELBUSB jz . + 2;
24063457Sgibbs			or	SAVED_SCSIID, TWIN_CHNLB;
24163457Sgibbs		}
24244507Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
24363457Sgibbs			mov	CCSCBRAM, SAVED_SCSIID;
24439220Sgibbs		} else {
24563457Sgibbs			mov	DFDAT, SAVED_SCSIID;
24639220Sgibbs		}
24739220Sgibbs
24839220Sgibbs		/*
24939220Sgibbs		 * If ATN isn't asserted, the target isn't interested
25039220Sgibbs		 * in talking to us.  Go directly to bus free.
25163457Sgibbs		 * XXX SCSI-1 may require us to assume lun 0 if
25263457Sgibbs		 * ATN is false.
25339220Sgibbs		 */
25439220Sgibbs		test	SCSISIGI, ATNI	jz	target_busfree;
25539220Sgibbs
25639220Sgibbs		/*
25739220Sgibbs		 * Watch ATN closely now as we pull in messages from the
25839220Sgibbs		 * initiator.  We follow the guidlines from section 6.5
25939220Sgibbs		 * of the SCSI-2 spec for what messages are allowed when.
26039220Sgibbs		 */
26141646Sgibbs		call	target_inb;
26239220Sgibbs
26339220Sgibbs		/*
26439220Sgibbs		 * Our first message must be one of IDENTIFY, ABORT, or
26539220Sgibbs		 * BUS_DEVICE_RESET.
26639220Sgibbs		 */
26742652Sgibbs		test	DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
26839220Sgibbs		/* Store for host */
26939220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
27039220Sgibbs			mov	CCSCBRAM, DINDEX;
27139220Sgibbs		} else {
27239220Sgibbs			mov	DFDAT, DINDEX;
27339220Sgibbs		}
27439220Sgibbs
27539220Sgibbs		/* Remember for disconnection decision */
27639220Sgibbs		test	DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
27739220Sgibbs		/* XXX Honor per target settings too */
27839220Sgibbs		or	SEQ_FLAGS, NO_DISCONNECT;
27939220Sgibbs
28039220Sgibbs		test	SCSISIGI, ATNI	jz	ident_messages_done;
28141646Sgibbs		call	target_inb;
28239220Sgibbs		/*
28339220Sgibbs		 * If this is a tagged request, the tagged message must
28439220Sgibbs		 * immediately follow the identify.  We test for a valid
28539220Sgibbs		 * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and
28639220Sgibbs		 * < MSG_IGN_WIDE_RESIDUE.
28739220Sgibbs		 */
28839220Sgibbs		add	A, -MSG_SIMPLE_Q_TAG, DINDEX;
28939220Sgibbs		jnc	ident_messages_done;
29039220Sgibbs		add	A, -MSG_IGN_WIDE_RESIDUE, DINDEX;
29139220Sgibbs		jc	ident_messages_done;
29239220Sgibbs		/* Store for host */
29339220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
29439220Sgibbs			mov	CCSCBRAM, DINDEX;
29539220Sgibbs		} else {
29639220Sgibbs			mov	DFDAT, DINDEX;
29739220Sgibbs		}
29839220Sgibbs		
29939220Sgibbs		/*
30039220Sgibbs		 * If the initiator doesn't feel like providing a tag number,
30139220Sgibbs		 * we've got a failed selection and must transition to bus
30239220Sgibbs		 * free.
30339220Sgibbs		 */
30439220Sgibbs		test	SCSISIGI, ATNI	jz	target_busfree;
30542652Sgibbs
30639220Sgibbs		/*
30739220Sgibbs		 * Store the tag for the host.
30839220Sgibbs		 */
30941646Sgibbs		call	target_inb;
31039220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
31139220Sgibbs			mov	CCSCBRAM, DINDEX;
31239220Sgibbs		} else {
31339220Sgibbs			mov	DFDAT, DINDEX;
31439220Sgibbs		}
31542652Sgibbs		mov	INITIATOR_TAG, DINDEX;
31663457Sgibbs		or	SEQ_FLAGS, TARGET_CMD_IS_TAGGED;
31763457Sgibbs		test	SCSISIGI, ATNI	jz . + 2;
31863457Sgibbs		/* Initiator still wants to give us messages */
31963457Sgibbs		call	target_inb;
32039220Sgibbs		jmp	ident_messages_done;
32139220Sgibbs
32241646Sgibbs		/*
32341646Sgibbs		 * Pushed message loop to allow the kernel to
32442652Sgibbs		 * run it's own target mode message state engine.
32541646Sgibbs		 */
32641646Sgibbshost_target_message_loop:
32741646Sgibbs		mvi	INTSTAT, HOST_MSG_LOOP;
32841646Sgibbs		nop;
32941646Sgibbs		cmp	RETURN_1, EXIT_MSG_LOOP	je target_ITloop;
33041646Sgibbs		test	SSTAT0, SPIORDY jz .;
33141646Sgibbs		jmp	host_target_message_loop;
33241646Sgibbs
33339220Sgibbsident_messages_done:
33444507Sgibbs		/* If ring buffer is full, return busy or queue full */
33558258Sgibbs		if ((ahc->features & AHC_HS_MAILBOX) != 0) {
33658258Sgibbs			and	A, HOST_TQINPOS, HS_MAILBOX;
33758258Sgibbs		} else {
33858258Sgibbs			mov	A, KERNEL_TQINPOS;
33958258Sgibbs		}
34044507Sgibbs		cmp	TQINPOS, A jne tqinfifo_has_space;
34144507Sgibbs		mvi	P_STATUS|BSYO call change_phase;
34268087Sgibbs		test	SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3;
34344507Sgibbs		mvi	STATUS_QUEUE_FULL call target_outb;
34444507Sgibbs		jmp	target_busfree_wait;
34544507Sgibbs		mvi	STATUS_BUSY call target_outb;
34644507Sgibbs		jmp	target_busfree_wait;
34744507Sgibbstqinfifo_has_space:	
34839220Sgibbs		/* Terminate the ident list */
34939220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
35039220Sgibbs			mvi	CCSCBRAM, SCB_LIST_NULL;
35139220Sgibbs		} else {
35239220Sgibbs			mvi	DFDAT, SCB_LIST_NULL;
35339220Sgibbs		}
35442652Sgibbs		or	SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
35563457Sgibbs		test	SCSISIGI, ATNI	jnz target_mesgout_pending;
35639220Sgibbs		jmp	target_ITloop;
35739220Sgibbs		
35839220Sgibbs/*
35939220Sgibbs * We carefully toggle SPIOEN to allow us to return the 
36039220Sgibbs * message byte we receive so it can be checked prior to
36139220Sgibbs * driving REQ on the bus for the next byte.
36239220Sgibbs */
36341646Sgibbstarget_inb:
36441646Sgibbs		/*
36541646Sgibbs		 * Drive REQ on the bus by enabling SCSI PIO.
36641646Sgibbs		 */
36739220Sgibbs		or	SXFRCTL0, SPIOEN;
36839220Sgibbs		/* Wait for the byte */
36939220Sgibbs		test	SSTAT0, SPIORDY jz .;
37039220Sgibbs		/* Prevent our read from triggering another REQ */
37139220Sgibbs		and	SXFRCTL0, ~SPIOEN;
37241646Sgibbs		/* Save latched contents */
37339220Sgibbs		mov	DINDEX, SCSIDATL ret;
37439220Sgibbs	}
37539220Sgibbs
37668087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) {
37739220Sgibbs/*
37823925Sgibbs * Reselection has been initiated by a target. Make a note that we've been
37923925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
38013177Sgibbs */
38139220Sgibbsinitiator_reselect:
38223925Sgibbs	/* XXX test for and handle ONE BIT condition */
38363457Sgibbs	and	SAVED_SCSIID, SELID_MASK, SELID;
38463457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
38563457Sgibbs		and	A, OID, SCSIID_ULTRA2;
38663457Sgibbs	} else {
38763457Sgibbs		and	A, OID, SCSIID;
38863457Sgibbs	}
38963457Sgibbs	or	SAVED_SCSIID, A;
39039545Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
39139545Sgibbs		test	SBLKCTL, SELBUSB	jz . + 2;
39263457Sgibbs		or	SAVED_SCSIID, TWIN_CHNLB;
39339545Sgibbs	}
39441646Sgibbs	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
39539220Sgibbs	jmp	ITloop;
39641646Sgibbs}
3974568Sgibbs
39813177Sgibbs/*
39923925Sgibbs * After the selection, remove this SCB from the "waiting SCB"
40023925Sgibbs * list.  This is achieved by simply moving our "next" pointer into
40123925Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
40223925Sgibbs * SCB is used, so don't bother with it now.
40323925Sgibbs */
40439220Sgibbsselect_out:
40525005Sgibbs	/* Turn off the selection hardware */
40658258Sgibbs	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
40725005Sgibbs	mvi	CLRSINT0, CLRSELDO;
40825005Sgibbs	mov	SCBPTR, WAITING_SCBH;
40968087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
41068087Sgibbs		cmp	SCB_TAG, SCB_LIST_NULL jne . + 2;
41168087Sgibbs		mvi	INTSTAT, BOGUS_TAG;
41268087Sgibbs	}
41324914Sgibbs	mov	WAITING_SCBH,SCB_NEXT;
41463457Sgibbs	mov	SAVED_SCSIID, SCB_SCSIID;
41563457Sgibbs	mov	SAVED_LUN, SCB_LUN;
41668087Sgibbs	call	initialize_channel;
41768087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
41839220Sgibbs		test	SSTAT0, TARGET	jz initiator_select;
4198567Sdg
42039220Sgibbs		/*
42139220Sgibbs		 * We've just re-selected an initiator.
42239220Sgibbs		 * Assert BSY and setup the phase for
42339220Sgibbs		 * sending our identify messages.
42439220Sgibbs		 */
42541646Sgibbs		mvi	P_MESGIN|BSYO call change_phase;
4264568Sgibbs
42739220Sgibbs		/*
42839220Sgibbs		 * Start out with a simple identify message.
42939220Sgibbs		 */
43063457Sgibbs		or	SCB_LUN, MSG_IDENTIFYFLAG call target_outb;
4316608Sgibbs
43239220Sgibbs		/*
43339220Sgibbs		 * If we are the result of a tagged command, send
43439220Sgibbs		 * a simple Q tag and the tag id.
43539220Sgibbs		 */
43639220Sgibbs		test	SCB_CONTROL, TAG_ENB	jz . + 3;
43739220Sgibbs		mvi	MSG_SIMPLE_Q_TAG call target_outb;
43863457Sgibbs		mov	SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb;
43939220Sgibbstarget_synccmd:
44039220Sgibbs		/*
44139220Sgibbs		 * Now determine what phases the host wants us
44239220Sgibbs		 * to go through.
44339220Sgibbs		 */
44463457Sgibbs		mov	SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES];
44542652Sgibbs		
44639220Sgibbstarget_ITloop:
44739220Sgibbs		/*
44841646Sgibbs		 * Start honoring ATN signals now that
44944507Sgibbs		 * we properly identified ourselves.
45039220Sgibbs		 */
45141646Sgibbs		test	SCSISIGI, ATNI			jnz target_mesgout;
45239220Sgibbs		test	SEQ_FLAGS, CMDPHASE_PENDING	jnz target_cmdphase;
45339220Sgibbs		test	SEQ_FLAGS, DPHASE_PENDING	jnz target_dphase;
45439220Sgibbs		test	SEQ_FLAGS, SPHASE_PENDING	jnz target_sphase;
45539220Sgibbs
45639220Sgibbs		/*
45739220Sgibbs		 * No more work to do.  Either disconnect or not depending
45839220Sgibbs		 * on the state of NO_DISCONNECT.
45939220Sgibbs		 */
46039220Sgibbs		test	SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 
46139220Sgibbs		if ((ahc->flags & AHC_PAGESCBS) != 0) {
46239220Sgibbs			mov	ALLZEROS	call	get_free_or_disc_scb;
46339220Sgibbs		}
46441646Sgibbs		mov	RETURN_1, ALLZEROS;
46539220Sgibbs		call	complete_target_cmd;
46641646Sgibbs		cmp	RETURN_1, CONT_MSG_LOOP jne .;
46739220Sgibbs		mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
46839220Sgibbs		mov	SCB_TAG	 call dma_scb;
46939220Sgibbs		jmp	target_synccmd;
47039220Sgibbs
47141646Sgibbstarget_mesgout:
47241646Sgibbs		mvi	SCSISIGO, P_MESGOUT|BSYO;
47363457Sgibbstarget_mesgout_continue:
47441646Sgibbs		call	target_inb;
47563457Sgibbstarget_mesgout_pending:
47641646Sgibbs		/* Local Processing goes here... */
47741646Sgibbs		jmp	host_target_message_loop;
47841646Sgibbs		
47939220Sgibbstarget_disconnect:
48041646Sgibbs		mvi	P_MESGIN|BSYO call change_phase;
48141816Sgibbs		test	SEQ_FLAGS, DPHASE	jz . + 2;
48241816Sgibbs		mvi	MSG_SAVEDATAPOINTER call target_outb;
48339220Sgibbs		mvi	MSG_DISCONNECT call target_outb;
48439220Sgibbs
48543880Sgibbstarget_busfree_wait:
48643880Sgibbs		/* Wait for preceeding I/O session to complete. */
48743880Sgibbs		test	SCSISIGI, ACKI jnz .;
48839220Sgibbstarget_busfree:
48963457Sgibbs		and	SIMODE1, ~ENBUSFREE;
49068087Sgibbs		clr	SCSIBUSL;
49139220Sgibbs		clr	SCSISIGO;
49257099Sgibbs		mvi	LASTPHASE, P_BUSFREE;
49339220Sgibbs		call	complete_target_cmd;
49439220Sgibbs		jmp	poll_for_work;
49539220Sgibbs
49639220Sgibbstarget_cmdphase:
49741646Sgibbs		mvi	P_COMMAND|BSYO call change_phase;
49841646Sgibbs		call	target_inb;
49939220Sgibbs		mov	A, DINDEX;
50039220Sgibbs		/* Store for host */
50139220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
50239220Sgibbs			mov	CCSCBRAM, A;
50339220Sgibbs		} else {
50439220Sgibbs			mov	DFDAT, A;
50539220Sgibbs		}
50639220Sgibbs
50739220Sgibbs		/*
50839220Sgibbs		 * Determine the number of bytes to read
50941299Sgibbs		 * based on the command group code via table lookup.
51041299Sgibbs		 * We reuse the first 8 bytes of the TARG_SCSIRATE
51141299Sgibbs		 * BIOS array for this table. Count is one less than
51241299Sgibbs		 * the total for the command since we've already fetched
51341299Sgibbs		 * the first byte.
51439220Sgibbs		 */
51539220Sgibbs		shr	A, CMD_GROUP_CODE_SHIFT;
51668087Sgibbs		add	SINDEX, CMDSIZE_TABLE, A;
51739220Sgibbs		mov	A, SINDIR;
51839220Sgibbs
51939220Sgibbs		test	A, 0xFF jz command_phase_done;
52039220Sgibbscommand_loop:
52139220Sgibbs		or	SXFRCTL0, SPIOEN;
52239220Sgibbs		test	SSTAT0, SPIORDY jz .;
52339220Sgibbs		cmp	A, 1 jne . + 2;
52439220Sgibbs		and	SXFRCTL0, ~SPIOEN;	/* Last Byte */
52539220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
52639220Sgibbs			mov	CCSCBRAM, SCSIDATL;
52739220Sgibbs		} else {
52839220Sgibbs			mov	DFDAT, SCSIDATL;
52939220Sgibbs		}
53039220Sgibbs		dec	A;
53139220Sgibbs		test	A, 0xFF jnz command_loop;
53239220Sgibbs
53339220Sgibbscommand_phase_done:
53439220Sgibbs		and	SEQ_FLAGS, ~CMDPHASE_PENDING;
53539220Sgibbs		jmp	target_ITloop;
53639220Sgibbs
53739220Sgibbstarget_dphase:
53839220Sgibbs		/*
53963457Sgibbs		 * Data phases on the bus are from the
54063457Sgibbs		 * perspective of the initiator.  The dma
54163457Sgibbs		 * code looks at LASTPHASE to determine the
54263457Sgibbs		 * data direction of the DMA.  Toggle it for
54363457Sgibbs		 * target transfers.
54439220Sgibbs		 */
54563457Sgibbs		xor	LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR];
54663457Sgibbs		or	SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO
54763457Sgibbs			call change_phase;
54839220Sgibbs		jmp	p_data;
54939220Sgibbs
55039220Sgibbstarget_sphase:
55141646Sgibbs		mvi	P_STATUS|BSYO call change_phase;
55241646Sgibbs		mvi	LASTPHASE, P_STATUS;
55363457Sgibbs		mov	SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb;
55441646Sgibbs		/* XXX Watch for ATN or parity errors??? */
55539220Sgibbs		mvi	SCSISIGO, P_MESGIN|BSYO;
55639220Sgibbs		/* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
55739220Sgibbs		mov	ALLZEROS call target_outb;
55843880Sgibbs		jmp	target_busfree_wait;
55939220Sgibbs	
56039220Sgibbscomplete_target_cmd:
56139220Sgibbs		test	SEQ_FLAGS, TARG_CMD_PENDING	jnz . + 2;
56239220Sgibbs		mov	SCB_TAG jmp complete_post;
56339220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
56441299Sgibbs			/* Set the valid byte */
56541299Sgibbs			mvi	CCSCBADDR, 24;
56641299Sgibbs			mov	CCSCBRAM, ALLONES;
56741299Sgibbs			mvi	CCHCNT, 28;
56839220Sgibbs			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
56939220Sgibbs			test	CCSCBCTL, CCSCBDONE jz .;
57039220Sgibbs			clr	CCSCBCTL;
57139220Sgibbs		} else {
57241299Sgibbs			/* Set the valid byte */
57341299Sgibbs			or	DFCNTRL, FIFORESET;
57441299Sgibbs			mvi	DFWADDR, 3; /* Third 64bit word or byte 24 */
57541299Sgibbs			mov	DFDAT, ALLONES;
57663457Sgibbs			mvi	28	call set_hcnt;
57739220Sgibbs			or	DFCNTRL, HDMAEN|FIFOFLUSH;
57839220Sgibbs			call	dma_finish;
57939220Sgibbs		}
58041299Sgibbs		inc	TQINPOS;
58141299Sgibbs		mvi	INTSTAT,CMDCMPLT ret;
58239220Sgibbs	}
58341646Sgibbs
58468087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) {
58539220Sgibbsinitiator_select:
58641646Sgibbs	/*
58741646Sgibbs	 * As soon as we get a successful selection, the target
58841646Sgibbs	 * should go into the message out phase since we have ATN
58941646Sgibbs	 * asserted.
59041646Sgibbs	 */
59139220Sgibbs	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
59239220Sgibbs	or	SEQ_FLAGS, IDENTIFY_SEEN;
59313177Sgibbs
59441646Sgibbs	/*
59541646Sgibbs	 * Main loop for information transfer phases.  Wait for the
59641646Sgibbs	 * target to assert REQ before checking MSG, C/D and I/O for
59741646Sgibbs	 * the bus phase.
59841646Sgibbs	 */
59963457Sgibbsmesgin_phasemis:
6004568SgibbsITloop:
60139220Sgibbs	call	phase_lock;
6024568Sgibbs
60339220Sgibbs	mov	A, LASTPHASE;
6044568Sgibbs
60539220Sgibbs	test	A, ~P_DATAIN	jz p_data;
60623925Sgibbs	cmp	A,P_COMMAND	je p_command;
60723925Sgibbs	cmp	A,P_MESGOUT	je p_mesgout;
60823925Sgibbs	cmp	A,P_STATUS	je p_status;
60923925Sgibbs	cmp	A,P_MESGIN	je p_mesgin;
6104568Sgibbs
61141646Sgibbs	mvi	INTSTAT,BAD_PHASE;
61223925Sgibbs	jmp	ITloop;			/* Try reading the bus again. */
6134568Sgibbs
61423925Sgibbsawait_busfree:
61523925Sgibbs	and	SIMODE1, ~ENBUSFREE;
61623925Sgibbs	mov	NONE, SCSIDATL;		/* Ack the last byte */
61768087Sgibbs	clr	SCSIBUSL;		/* Prevent bit leakage durint SELTO */
61839220Sgibbs	and	SXFRCTL0, ~SPIOEN;
61923925Sgibbs	test	SSTAT1,REQINIT|BUSFREE	jz .;
62023925Sgibbs	test	SSTAT1, BUSFREE jnz poll_for_work;
62123925Sgibbs	mvi	INTSTAT, BAD_PHASE;
62241646Sgibbs}
62323925Sgibbs	
62423925Sgibbsclear_target_state:
62541646Sgibbs	/*
62641646Sgibbs	 * We assume that the kernel driver may reset us
62741646Sgibbs	 * at any time, even in the middle of a DMA, so
62841646Sgibbs	 * clear DFCNTRL too.
62941646Sgibbs	 */
63041646Sgibbs	clr	DFCNTRL;
63168087Sgibbs	or	SXFRCTL0, CLRSTCNT|CLRCHN;
63241646Sgibbs
63341646Sgibbs	/*
63441646Sgibbs	 * We don't know the target we will connect to,
63541646Sgibbs	 * so default to narrow transfers to avoid
63641646Sgibbs	 * parity problems.
63741646Sgibbs	 */
63841646Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
63941646Sgibbs		bmov	SCSIRATE, ALLZEROS, 2;
64041646Sgibbs	} else {
64141646Sgibbs		clr	SCSIRATE;
64263457Sgibbs		if ((ahc->features & AHC_ULTRA) != 0) {
64363457Sgibbs			and	SXFRCTL0, ~(FAST20);
64463457Sgibbs		}
64541646Sgibbs	}
64623925Sgibbs	mvi	LASTPHASE, P_BUSFREE;
64723925Sgibbs	/* clear target specific flags */
64839220Sgibbs	clr	SEQ_FLAGS ret;
64923925Sgibbs
65063457Sgibbssg_advance:
65163457Sgibbs	clr	A;			/* add sizeof(struct scatter) */
65263457Sgibbs	add	SCB_RESIDUAL_SGPTR[0],SG_SIZEOF;
65363457Sgibbs	adc	SCB_RESIDUAL_SGPTR[1],A;
65463457Sgibbs	adc	SCB_RESIDUAL_SGPTR[2],A;
65563457Sgibbs	adc	SCB_RESIDUAL_SGPTR[3],A ret;
65663457Sgibbs
65763457Sgibbsidle_loop:
65863457Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
65963457Sgibbs		/* Did we just finish fetching segs? */
66063457Sgibbs		cmp	CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
66163457Sgibbs
66263457Sgibbs		/* Are we actively fetching segments? */
66363457Sgibbs		test	CCSGCTL, CCSGEN jnz return;
66463457Sgibbs
66563457Sgibbs		/*
66663457Sgibbs		 * Do we need any more segments?
66763457Sgibbs		 */
66863457Sgibbs		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
66963457Sgibbs
67063457Sgibbs		/*
67163457Sgibbs		 * Do we have any prefetch left???
67263457Sgibbs		 */
67366647Sgibbs		cmp	CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail;
67463457Sgibbs
67563457Sgibbs		/*
67663457Sgibbs		 * Need to fetch segments, but we can only do that
67763457Sgibbs		 * if the command channel is completely idle.  Make
67863457Sgibbs		 * sure we don't have an SCB prefetch going on.
67963457Sgibbs		 */
68063457Sgibbs		test	CCSCBCTL, CCSCBEN jnz return;
68163457Sgibbs
68263457Sgibbs		/*
68366647Sgibbs		 * We fetch a "cacheline aligned" and sized amount of data
68466647Sgibbs		 * so we don't end up referencing a non-existant page.
68566647Sgibbs		 * Cacheline aligned is in quotes because the kernel will
68666647Sgibbs		 * set the prefetch amount to a reasonable level if the
68766647Sgibbs		 * cacheline size is unknown.
68863457Sgibbs		 */
68966647Sgibbs		mvi	CCHCNT, SG_PREFETCH_CNT;
69066647Sgibbs		and	CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
69163457Sgibbs		bmov	CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
69263457Sgibbs		mvi	CCSGCTL, CCSGEN|CCSGRESET ret;
69363457Sgibbsidle_sgfetch_complete:
69463944Sgibbs		clr	CCSGCTL;
69563944Sgibbs		test	CCSGCTL, CCSGEN jnz .;
69666647Sgibbs		and	CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;
69763457Sgibbsidle_sg_avail:
69863457Sgibbs		if ((ahc->features & AHC_ULTRA2) != 0) {
69963457Sgibbs			/* Does the hardware have space for another SG entry? */
70063457Sgibbs			test	DFSTATUS, PRELOAD_AVAIL jz return;
70163457Sgibbs			bmov 	HADDR, CCSGRAM, 4;
70263457Sgibbs			bmov	SINDEX, CCSGRAM, 1;
70363457Sgibbs			test	SINDEX, 0x1 jz . + 2;
70463457Sgibbs			xor	DATA_COUNT_ODD, 0x1;
70563457Sgibbs			bmov	HCNT[0], SINDEX, 1;
70663457Sgibbs			bmov	HCNT[1], CCSGRAM, 2;
70763457Sgibbs			bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
70863457Sgibbs			call	sg_advance;
70963457Sgibbs			mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
71063457Sgibbs			test	DATA_COUNT_ODD, 0x1 jz . + 2;
71163457Sgibbs			or	SINDEX, ODD_SEG;
71263457Sgibbs			test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
71363457Sgibbs			or	SINDEX, LAST_SEG;
71463457Sgibbs			mov	SG_CACHE_PRE, SINDEX;
71563457Sgibbs			/* Load the segment by writing DFCNTRL again */
71663457Sgibbs			mov	DFCNTRL, DMAPARAMS;
71763457Sgibbs		}
71863457Sgibbs		ret;
71963457Sgibbs	}
72063457Sgibbs
72165942Sgibbsif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
72213177Sgibbs/*
72365942Sgibbs * Calculate the trailing portion of this S/G segment that cannot
72465942Sgibbs * be transferred using memory write and invalidate PCI transactions.  
72565942Sgibbs * XXX Can we optimize this for PCI writes only???
72665942Sgibbs */
72765942Sgibbscalc_mwi_residual:
72865942Sgibbs	/*
72965942Sgibbs	 * If the ending address is on a cacheline boundary,
73065942Sgibbs	 * there is no need for an extra segment.
73165942Sgibbs	 */
73265942Sgibbs	mov	A, HCNT[0];
73365942Sgibbs	add	A, A, HADDR[0];
73465942Sgibbs	and	A, CACHESIZE_MASK;
73565942Sgibbs	test	A, 0xFF jz return;
73665942Sgibbs
73765942Sgibbs	/*
73865942Sgibbs	 * If the transfer is less than a cachline,
73965942Sgibbs	 * there is no need for an extra segment.
74065942Sgibbs	 */
74165942Sgibbs	test	HCNT[1], 0xFF	jnz calc_mwi_residual_final;
74265942Sgibbs	test	HCNT[2], 0xFF	jnz calc_mwi_residual_final;
74365942Sgibbs	add	NONE, INVERTED_CACHESIZE_MASK, HCNT[0];
74465942Sgibbs	jnc	return;
74565942Sgibbs
74665942Sgibbscalc_mwi_residual_final:
74765942Sgibbs	mov	MWI_RESIDUAL, A;
74865942Sgibbs	not	A;
74965942Sgibbs	inc	A;
75065942Sgibbs	add	HCNT[0], A;
75165942Sgibbs	adc	HCNT[1], -1;
75265942Sgibbs	adc	HCNT[2], -1 ret;
75365942Sgibbs}
75465942Sgibbs
75565942Sgibbs/*
75613177Sgibbs * If we re-enter the data phase after going through another phase, the
75713177Sgibbs * STCNT may have been cleared, so restore it from the residual field.
75813177Sgibbs */
7599928Sgibbsdata_phase_reinit:
76051471Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
76151471Sgibbs		/*
76251471Sgibbs		 * The preload circuitry requires us to
76351471Sgibbs		 * reload the address too, so pull it from
76451471Sgibbs		 * the shaddow address.
76551471Sgibbs		 */
76651471Sgibbs		bmov	HADDR, SHADDR, 4;
76763457Sgibbs		bmov	HCNT, SCB_RESIDUAL_DATACNT, 3;
76851471Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
76963457Sgibbs		bmov	STCNT, SCB_RESIDUAL_DATACNT, 3;
77039220Sgibbs	} else {
77139220Sgibbs		mvi	DINDEX, STCNT;
77263457Sgibbs		mvi	SCB_RESIDUAL_DATACNT call bcopy_3;
77339220Sgibbs	}
77463457Sgibbs	and	DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0];
77523925Sgibbs	jmp	data_phase_loop;
7764568Sgibbs
77739220Sgibbsp_data:
77839220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
77939220Sgibbs		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
78039220Sgibbs	} else {
78139220Sgibbs		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
78239220Sgibbs	}
78339220Sgibbs	test	LASTPHASE, IOI jnz . + 2;
78439220Sgibbs	or	DMAPARAMS, DIRECTION;
78523925Sgibbs	call	assert;			/*
78619164Sgibbs					 * Ensure entering a data
78719164Sgibbs					 * phase is okay - seen identify, etc.
78819164Sgibbs					 */
78939220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
79063457Sgibbs		/* We don't have any valid S/G elements */
79166647Sgibbs		mvi	CCSGADDR, SG_PREFETCH_CNT;
79239220Sgibbs	}
79323925Sgibbs	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
7944568Sgibbs
79539220Sgibbs	/* We have seen a data phase */
79639220Sgibbs	or	SEQ_FLAGS, DPHASE;
79739220Sgibbs
79819164Sgibbs	/*
79919164Sgibbs	 * Initialize the DMA address and counter from the SCB.
80063457Sgibbs	 * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG
80163457Sgibbs	 * flag in the highest byte of the data count.  We cannot
80263457Sgibbs	 * modify the saved values in the SCB until we see a save
80363457Sgibbs	 * data pointers message.
80419164Sgibbs	 */
80539220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
80639220Sgibbs		bmov	HADDR, SCB_DATAPTR, 7;
80763457Sgibbs		bmov	SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
80839220Sgibbs	} else {
80939220Sgibbs		mvi	DINDEX, HADDR;
81039220Sgibbs		mvi	SCB_DATAPTR	call bcopy_7;
81163457Sgibbs		mvi	DINDEX, SCB_RESIDUAL_DATACNT + 3;
81263457Sgibbs		mvi	SCB_DATACNT + 3 call bcopy_5;
81339220Sgibbs	}
81465942Sgibbs	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
81565942Sgibbs		call	calc_mwi_residual;
81665942Sgibbs	}
81763457Sgibbs	and	SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
81865942Sgibbs	and	DATA_COUNT_ODD, 0x1, HCNT[0];
81919164Sgibbs
82039220Sgibbs	if ((ahc->features & AHC_ULTRA2) == 0) {
82139220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
82239220Sgibbs			bmov	STCNT, HCNT, 3;
82339220Sgibbs		} else {
82439220Sgibbs			call	set_stcnt_from_hcnt;
82539220Sgibbs		}
82639220Sgibbs	}
82719164Sgibbs
82863457Sgibbsdata_phase_loop:
82963457Sgibbs	/* Guard against overruns */
83063457Sgibbs	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds;
83119164Sgibbs
83263457Sgibbs	/*
83368087Sgibbs	 * Turn on `Bit Bucket' mode, wait until the target takes
83468087Sgibbs	 * us to another phase, and then notify the host.
83563457Sgibbs	 */
83668087Sgibbs	and	DMAPARAMS, DIRECTION;
83768087Sgibbs	mov	DFCNTRL, DMAPARAMS;
83823925Sgibbs	or	SXFRCTL1,BITBUCKET;
83968087Sgibbs	test	SSTAT1,PHASEMIS	jz .;
84068087Sgibbs	and	SXFRCTL1, ~BITBUCKET;
84168087Sgibbs	mvi	INTSTAT,DATA_OVERRUN;
84268087Sgibbs	jmp	ITloop;
84368087Sgibbs
84416260Sgibbsdata_phase_inbounds:
84539220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
84663457Sgibbs		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
84763457Sgibbs		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
84863457Sgibbs		or	SINDEX, LAST_SEG;
84963457Sgibbs		test	DATA_COUNT_ODD, 0x1 jz . + 2;
85063457Sgibbs		or	SINDEX, ODD_SEG;
85163457Sgibbs		mov	SG_CACHE_PRE, SINDEX;
85263457Sgibbs		mov	DFCNTRL, DMAPARAMS;
85363457Sgibbsultra2_dma_loop:
85463457Sgibbs		call	idle_loop;
85563457Sgibbs		/*
85663457Sgibbs		 * The transfer is complete if either the last segment
85763457Sgibbs		 * completes or the target changes phase.
85863457Sgibbs		 */
85963457Sgibbs		test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
86063457Sgibbs		test	SSTAT1,PHASEMIS	jz ultra2_dma_loop;
86163457Sgibbs
86263457Sgibbsultra2_dmafinish:
86363457Sgibbs		test	DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
86463457Sgibbs		and	DFCNTRL, ~SCSIEN;
86563457Sgibbs		test	DFCNTRL, SCSIEN jnz .;
86663944Sgibbs		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
86763944Sgibbs			test	DFSTATUS, FIFOEMP jnz ultra2_dmafifoempty;
86863944Sgibbs		}
86963457Sgibbsultra2_dmafifoflush:
87063457Sgibbs		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
87163457Sgibbs			/*
87263457Sgibbs			 * On Rev A of the aic7890, the autoflush
87363457Sgibbs			 * features doesn't function correctly.
87463457Sgibbs			 * Perform an explicit manual flush.  During
87563457Sgibbs			 * a manual flush, the FIFOEMP bit becomes
87663457Sgibbs			 * true every time the PCI FIFO empties
87763457Sgibbs			 * regardless of the state of the SCSI FIFO.
87863457Sgibbs			 * It can take up to 4 clock cycles for the
87963457Sgibbs			 * SCSI FIFO to get data into the PCI FIFO
88063457Sgibbs			 * and for FIFOEMP to de-assert.  Here we
88163457Sgibbs			 * guard against this condition by making
88263457Sgibbs			 * sure the FIFOEMP bit stays on for 5 full
88363457Sgibbs			 * clock cycles.
88463457Sgibbs			 */
88563457Sgibbs			or	DFCNTRL, FIFOFLUSH;
88663457Sgibbs			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
88763457Sgibbs			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
88863457Sgibbs			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
88963457Sgibbs			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
89063457Sgibbs		}
89163457Sgibbs		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
89263457Sgibbsultra2_dmafifoempty:
89363457Sgibbs		/* Don't clobber an inprogress host data transfer */
89463457Sgibbs		test	DFSTATUS, MREQPEND	jnz ultra2_dmafifoempty;
89563457Sgibbsultra2_dmahalt:
89663457Sgibbs		and     DFCNTRL, ~(SCSIEN|HDMAEN);
89763457Sgibbs		test	DFCNTRL, HDMAEN jnz .;
89863457Sgibbs
89963457Sgibbs		/*
90063944Sgibbs		 * If, by chance, we stopped before being able
90163944Sgibbs		 * to fetch additional segments for this transfer,
90263944Sgibbs		 * yet the last S/G was completely exhausted,
90363944Sgibbs		 * call our idle loop until it is able to load
90463944Sgibbs		 * another segment.  This will allow us to immediately
90563944Sgibbs		 * pickup on the next segment on the next data phase.
90663944Sgibbs		 *
90763944Sgibbs		 * If we happened to stop on the last segment, then
90863944Sgibbs		 * our residual information is still correct from
90963944Sgibbs		 * the idle loop and there is no need to perform
91063944Sgibbs		 * any fixups.  Just jump to data_phase_finish.
91163944Sgibbs		 */
91263944Sgibbsultra2_ensure_sg:
91363944Sgibbs		test	SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid;
91463944Sgibbs		/* Record if we've consumed all S/G entries */
91563944Sgibbs		test	SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish;
91663944Sgibbs		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
91763944Sgibbs		jmp	data_phase_finish;
91863944Sgibbs
91963944Sgibbsultra2_shvalid:
92063944Sgibbs                test    SSTAT2, SHVALID	jnz sgptr_fixup;
92163944Sgibbs		call	idle_loop;
92263944Sgibbs		jmp	ultra2_ensure_sg;
92363944Sgibbs
92463944Sgibbssgptr_fixup:
92563944Sgibbs		/*
92663457Sgibbs		 * Fixup the residual next S/G pointer.  The S/G preload
92763457Sgibbs		 * feature of the chip allows us to load two elements
92863457Sgibbs		 * in addition to the currently active element.  We
92963457Sgibbs		 * store the bottom byte of the next S/G pointer in
93063457Sgibbs		 * the SG_CACEPTR register so we can restore the
93163457Sgibbs		 * correct value when the DMA completes.  If the next
93263457Sgibbs		 * sg ptr value has advanced to the point where higher
93363457Sgibbs		 * bytes in the address have been affected, fix them
93463457Sgibbs		 * too.
93563457Sgibbs		 */
93663457Sgibbs		test	SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done;
93763457Sgibbs		test	SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done;
93863457Sgibbs		add	SCB_RESIDUAL_SGPTR[1], -1;
93963457Sgibbs		adc	SCB_RESIDUAL_SGPTR[2], -1; 
94063457Sgibbs		adc	SCB_RESIDUAL_SGPTR[3], -1;
94163457Sgibbssgptr_fixup_done:
94263457Sgibbs		and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
94363457Sgibbs		clr	DATA_COUNT_ODD;
94463457Sgibbs		test	SG_CACHE_SHADOW, ODD_SEG jz . + 2;
94563457Sgibbs		or	DATA_COUNT_ODD, 0x1;
94663944Sgibbs		clr	SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
94739220Sgibbs	} else {
94863457Sgibbs		/* If we are the last SG block, tell the hardware. */
94965942Sgibbs		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
95065942Sgibbs		  && ahc->pci_cachesize != 0) {
95165942Sgibbs			test	MWI_RESIDUAL, 0xFF jnz dma_mid_sg;
95265942Sgibbs		}
95363457Sgibbs		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
95468087Sgibbs		if ((ahc->flags & AHC_TARGETROLE) != 0) {
95563944Sgibbs			test	SSTAT0, TARGET jz dma_last_sg;
95663944Sgibbs			if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) {
95763944Sgibbs				test	DMAPARAMS, DIRECTION jz dma_mid_sg;
95863944Sgibbs			}
95957099Sgibbs		}
96063944Sgibbsdma_last_sg:
96139220Sgibbs		and	DMAPARAMS, ~WIDEODD;
96263457Sgibbsdma_mid_sg:
96363457Sgibbs		/* Start DMA data transfer. */
96439220Sgibbs		mov	DFCNTRL, DMAPARAMS;
96563457Sgibbsdma_loop:
96663457Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
96763457Sgibbs			call	idle_loop;
96863457Sgibbs		}
96963457Sgibbs		test	SSTAT0,DMADONE	jnz dma_dmadone;
97063457Sgibbs		test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
97163457Sgibbsdma_phasemis:
97239220Sgibbs		/*
97363457Sgibbs		 * We will be "done" DMAing when the transfer count goes to
97463457Sgibbs		 * zero, or the target changes the phase (in light of this,
97563457Sgibbs		 * it makes sense that the DMA circuitry doesn't ACK when
97663457Sgibbs		 * PHASEMIS is active).  If we are doing a SCSI->Host transfer,
97763457Sgibbs		 * the data FIFO should be flushed auto-magically on STCNT=0
97863457Sgibbs		 * or a phase change, so just wait for FIFO empty status.
97939220Sgibbs		 */
98063457Sgibbsdma_checkfifo:
98163457Sgibbs		test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
98263457Sgibbsdma_fifoflush:
98363457Sgibbs		test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
98463457Sgibbsdma_fifoempty:
98563457Sgibbs		/* Don't clobber an inprogress host data transfer */
98663457Sgibbs		test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
9874568Sgibbs
98839220Sgibbs		/*
98963457Sgibbs		 * Now shut off the DMA and make sure that the DMA
99063457Sgibbs		 * hardware has actually stopped.  Touching the DMA
99163457Sgibbs		 * counters, etc. while a DMA is active will result
99263457Sgibbs		 * in an ILLSADDR exception.
99339220Sgibbs		 */
99463457Sgibbsdma_dmadone:
99563457Sgibbs		and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
99663457Sgibbsdma_halt:
99763457Sgibbs		/*
99865942Sgibbs		 * Some revisions of the aic78XX have a problem where, if the
99963457Sgibbs		 * data fifo is full, but the PCI input latch is not empty, 
100063457Sgibbs		 * HDMAEN cannot be cleared.  The fix used here is to drain
100163457Sgibbs		 * the prefetched but unused data from the data fifo until
100263457Sgibbs		 * there is space for the input latch to drain.
100363457Sgibbs		 */
100465942Sgibbs		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
100565942Sgibbs			mov	NONE, DFDAT;
100665942Sgibbs		}
100763457Sgibbs		test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
100822568Sgibbs
100963457Sgibbs		/* See if we have completed this last segment */
101063457Sgibbs		test	STCNT[0], 0xff	jnz data_phase_finish;
101163457Sgibbs		test	STCNT[1], 0xff	jnz data_phase_finish;
101263457Sgibbs		test	STCNT[2], 0xff	jnz data_phase_finish;
10139928Sgibbs
101439220Sgibbs		/*
101563457Sgibbs		 * Advance the scatter-gather pointers if needed 
101639220Sgibbs		 */
101765942Sgibbs		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
101865942Sgibbs		  && ahc->pci_cachesize != 0) {
101965942Sgibbs			test	MWI_RESIDUAL, 0xFF jz no_mwi_resid;
102065942Sgibbs			/*
102165942Sgibbs			 * Reload HADDR from SHADDR and setup the
102265942Sgibbs			 * count to be the size of our residual.
102365942Sgibbs			 */
102465942Sgibbs			if ((ahc->features & AHC_CMD_CHAN) != 0) {
102565942Sgibbs				bmov	HADDR, SHADDR, 4;
102665942Sgibbs				mov	HCNT, MWI_RESIDUAL;
102765942Sgibbs				bmov	HCNT[1], ALLZEROS, 2;
102865942Sgibbs			} else {
102965942Sgibbs				mvi	DINDEX, HADDR;
103065942Sgibbs				mvi	SHADDR call bcopy_4;
103165942Sgibbs				mov	MWI_RESIDUAL call set_hcnt;
103265942Sgibbs			}
103365942Sgibbs			clr	MWI_RESIDUAL;
103465942Sgibbs			jmp	sg_load_done;
103565942Sgibbsno_mwi_resid:
103665942Sgibbs		}
103763457Sgibbs		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load;
103863457Sgibbs		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
103963457Sgibbs		jmp	data_phase_finish;
104063457Sgibbssg_load:
104163457Sgibbs		/*
104263457Sgibbs		 * Load the next SG element's data address and length
104363457Sgibbs		 * into the DMA engine.  If we don't have hardware
104463457Sgibbs		 * to perform a prefetch, we'll have to fetch the
104563457Sgibbs		 * segment from host memory first.
104663457Sgibbs		 */
104739220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
104863457Sgibbs			/* Wait for the idle loop to complete */
104963457Sgibbs			test	CCSGCTL, CCSGEN jz . + 3;
105063457Sgibbs			call	idle_loop;
105163457Sgibbs			test	CCSGCTL, CCSGEN jnz . - 1;
105263457Sgibbs			bmov 	HADDR, CCSGRAM, 7;
105365942Sgibbs			test	CCSGRAM, SG_LAST_SEG jz . + 2;
105465942Sgibbs			or	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG;
105539220Sgibbs		} else {
105663457Sgibbs			mvi	DINDEX, HADDR;
105763457Sgibbs			mvi	SCB_RESIDUAL_SGPTR	call bcopy_4;
105863457Sgibbs
105963457Sgibbs			mvi	SG_SIZEOF	call set_hcnt;
106063457Sgibbs
106163457Sgibbs			or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
106263457Sgibbs
106363457Sgibbs			call	dma_finish;
106463457Sgibbs
106565942Sgibbs			mvi	DINDEX, HADDR;
106665942Sgibbs			call	dfdat_in_7;
106763457Sgibbs			mov	SCB_RESIDUAL_DATACNT[3], DFDAT;
106865942Sgibbs		}
106965942Sgibbs
107065942Sgibbs		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
107165942Sgibbs		  && ahc->pci_cachesize != 0) {
107265942Sgibbs			call calc_mwi_residual;
107365942Sgibbs		}
107465942Sgibbs
107565942Sgibbs		/* Point to the new next sg in memory */
107665942Sgibbs		call	sg_advance;
107765942Sgibbs
107865942Sgibbssg_load_done:
107965942Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
108065942Sgibbs			bmov	STCNT, HCNT, 3;
108165942Sgibbs		} else {
108239220Sgibbs			call	set_stcnt_from_hcnt;
108339220Sgibbs		}
108463457Sgibbs		/* Track odd'ness */
108563457Sgibbs		test	HCNT[0], 0x1 jz . + 2;
108663457Sgibbs		xor	DATA_COUNT_ODD, 0x1;
108739220Sgibbs
108868087Sgibbs		if ((ahc->flags & AHC_TARGETROLE) != 0) {
108963457Sgibbs			test	SSTAT0, TARGET jnz data_phase_loop;
109063457Sgibbs		}
109163457Sgibbs	}
109263457Sgibbsdata_phase_finish:
109363457Sgibbs	/*
109463457Sgibbs	 * If the target has left us in data phase, loop through
109563457Sgibbs	 * the dma code again.  In the case of ULTRA2 adapters,
109663457Sgibbs	 * we should only loop if there is a data overrun.  For
109763457Sgibbs	 * all other adapters, we'll loop after each S/G element
109863457Sgibbs	 * is loaded as well as if there is an overrun.
109963457Sgibbs	 */
110068087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
110163457Sgibbs		test	SSTAT0, TARGET jnz data_phase_done;
110241646Sgibbs	}
110368087Sgibbs	if ((ahc->flags & AHC_INITIATORROLE) != 0) {
110463457Sgibbs		test	SSTAT1, REQINIT jz .;
110563457Sgibbs		test	SSTAT1,PHASEMIS	jz data_phase_loop;
110663457Sgibbs	
110763457Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
110863457Sgibbs			/* Kill off any pending prefetch */
110963457Sgibbs			clr	CCSGCTL;
111063457Sgibbs			test	CCSGCTL, CCSGEN jnz .;
111163457Sgibbs		}
111239220Sgibbs	}
11134568Sgibbs
111463457Sgibbsdata_phase_done:
111563457Sgibbs	/*
111663457Sgibbs	 * After a DMA finishes, save the SG and STCNT residuals back into
111763457Sgibbs	 * the SCB.  We use STCNT instead of HCNT, since it's a reflection
111863457Sgibbs	 * of how many bytes were transferred on the SCSI (as opposed to the
111963457Sgibbs	 * host) bus.
112063457Sgibbs	 */
112139220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
112263457Sgibbs		/* Kill off any pending prefetch */
112363457Sgibbs		clr	CCSGCTL;
112463457Sgibbs		test	CCSGCTL, CCSGEN jnz .;
112565942Sgibbs	}
112663457Sgibbs
112765942Sgibbs	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
112865942Sgibbs	  && ahc->pci_cachesize != 0) {
112965942Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
113065942Sgibbs			test	MWI_RESIDUAL, 0xFF jz bmov_resid;
113165942Sgibbs		}
113265942Sgibbs		mov	A, MWI_RESIDUAL;
113365942Sgibbs		add	SCB_RESIDUAL_DATACNT[0], A, STCNT[0];
113465942Sgibbs		clr	A;
113565942Sgibbs		adc	SCB_RESIDUAL_DATACNT[1], A, STCNT[1];
113665942Sgibbs		adc	SCB_RESIDUAL_DATACNT[2], A, STCNT[2];
113765942Sgibbs		clr	MWI_RESIDUAL;
113865942Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
113965942Sgibbs			jmp	. + 2;
114065942Sgibbsbmov_resid:
114165942Sgibbs			bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
114265942Sgibbs		}
114365942Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
114463457Sgibbs		bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
114539220Sgibbs	} else {
114665942Sgibbs		mov	SCB_RESIDUAL_DATACNT[0], STCNT[0];
114765942Sgibbs		mov	SCB_RESIDUAL_DATACNT[1], STCNT[1];
114865942Sgibbs		mov	SCB_RESIDUAL_DATACNT[2], STCNT[2];
114939220Sgibbs	}
115022568Sgibbs
115163457Sgibbs	/*
115263457Sgibbs	 * Since we've been through a data phase, the SCB_RESID* fields
115363457Sgibbs	 * are now initialized.  Clear the full residual flag.
115463457Sgibbs	 */
115563457Sgibbs	and	SCB_SGPTR[0], ~SG_FULL_RESID;
115663457Sgibbs
115739220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
115863457Sgibbs		/* Clear the channel in case we return to data phase later */
115939220Sgibbs		or	SXFRCTL0, CLRSTCNT|CLRCHN;
116039220Sgibbs	}
116122568Sgibbs
116268087Sgibbs	if ((ahc->flags & AHC_TARGETROLE) != 0) {
116341646Sgibbs		test	SEQ_FLAGS, DPHASE_PENDING jz ITloop;
116439220Sgibbs		and	SEQ_FLAGS, ~DPHASE_PENDING;
116542652Sgibbs		/*
116642652Sgibbs		 * For data-in phases, wait for any pending acks from the
116742652Sgibbs		 * initiator before changing phase.
116842652Sgibbs		 */
116942652Sgibbs		test	DFCNTRL, DIRECTION jz target_ITloop;
117042652Sgibbs		test	SSTAT1, REQINIT	jnz .;
117139220Sgibbs		jmp	target_ITloop;
117263457Sgibbs	} else {
117363457Sgibbs		jmp	ITloop;
117439220Sgibbs	}
11754568Sgibbs
117668087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) {
117716260Sgibbs/*
117815328Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
117913177Sgibbs */
11804568Sgibbsp_command:
118123925Sgibbs	call	assert;
11824568Sgibbs
118363457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
118463457Sgibbs		bmov	HCNT[0], SCB_CDB_LEN,  1;
118539220Sgibbs		bmov	HCNT[1], ALLZEROS, 2;
118663944Sgibbs		mvi	SG_CACHE_PRE, LAST_SEG;
118763457Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
118863457Sgibbs		bmov	STCNT[0], SCB_CDB_LEN, 1;
118963457Sgibbs		bmov	STCNT[1], ALLZEROS, 2;
119039220Sgibbs	} else {
119163457Sgibbs		mov	STCNT[0], SCB_CDB_LEN;
119263457Sgibbs		clr	STCNT[1];
119363457Sgibbs		clr	STCNT[2];
119439220Sgibbs	}
119563457Sgibbs	add	NONE, -13, SCB_CDB_LEN;
119665942Sgibbs	mvi	SCB_CDB_STORE jnc p_command_embedded;
119763457Sgibbsp_command_from_host:
119863457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
119963457Sgibbs		bmov	HADDR[0], SCB_CDB_PTR, 4;
120063457Sgibbs		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
120163457Sgibbs	} else {
120263457Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
120363457Sgibbs			bmov	HADDR[0], SCB_CDB_PTR, 4;
120465942Sgibbs			bmov	HCNT, STCNT, 3;
120563457Sgibbs		} else {
120663457Sgibbs			mvi	DINDEX, HADDR;
120768087Sgibbs			mvi	SCB_CDB_PTR call bcopy_4;
120868087Sgibbs			mov	SCB_CDB_LEN call set_hcnt;
120939220Sgibbs		}
121039220Sgibbs		mvi	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
121163457Sgibbs	}
121263457Sgibbs	jmp	p_command_loop;
121363457Sgibbsp_command_embedded:
121463457Sgibbs	/*
121563457Sgibbs	 * The data fifo seems to require 4 byte alligned
121663457Sgibbs	 * transfers from the sequencer.  Force this to
121763457Sgibbs	 * be the case by clearing HADDR[0] even though
121863457Sgibbs	 * we aren't going to touch host memeory.
121963457Sgibbs	 */
122063457Sgibbs	clr	HADDR[0];
122163457Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
122263457Sgibbs		mvi	DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
122363457Sgibbs		bmov	DFDAT, SCB_CDB_STORE, 12; 
122465942Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
122565942Sgibbs		if ((ahc->features & AHC_SCB_BTT) != 0) {
122665942Sgibbs			/*
122765942Sgibbs			 * On the 7895 the data FIFO will
122865942Sgibbs			 * get corrupted if you try to dump
122965942Sgibbs			 * data from external SCB memory into
123065942Sgibbs			 * the FIFO while it is enabled.  So,
123165942Sgibbs			 * fill the fifo and then enable SCSI
123265942Sgibbs			 * transfers.
123365942Sgibbs			 */
123465942Sgibbs			mvi	DFCNTRL, (DIRECTION|FIFORESET);
123565942Sgibbs		} else {
123665942Sgibbs			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
123765942Sgibbs		}
123865942Sgibbs		bmov	DFDAT, SCB_CDB_STORE, 12; 
123965942Sgibbs		if ((ahc->features & AHC_SCB_BTT) != 0) {
124065942Sgibbs			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH);
124165942Sgibbs		} else {
124263821Sgibbs			or	DFCNTRL, FIFOFLUSH;
124363821Sgibbs		}
124463457Sgibbs	} else {
124565942Sgibbs		mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
124663821Sgibbs		call	copy_to_fifo_6;
124763821Sgibbs		call	copy_to_fifo_6;
124863821Sgibbs		or	DFCNTRL, FIFOFLUSH;
124963457Sgibbs	}
125063457Sgibbsp_command_loop:
125139220Sgibbs	test	SSTAT0, SDONE jnz . + 2;
125263457Sgibbs	test    SSTAT1, PHASEMIS jz p_command_loop;
125355581Sgibbs	/*
125455581Sgibbs	 * Wait for our ACK to go-away on it's own
125555581Sgibbs	 * instead of being killed by SCSIEN getting cleared.
125655581Sgibbs	 */
125755581Sgibbs	test	SCSISIGI, ACKI jnz .;
125855581Sgibbs	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
125939220Sgibbs	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
126068087Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
126168087Sgibbs		/* Drop any residual from the S/G Preload queue */
126268087Sgibbs		or	SXFRCTL0, CLRSTCNT;
126368087Sgibbs	}
126423925Sgibbs	jmp	ITloop;
12654568Sgibbs
126613177Sgibbs/*
126713177Sgibbs * Status phase.  Wait for the data byte to appear, then read it
126813177Sgibbs * and store it into the SCB.
126913177Sgibbs */
12704568Sgibbsp_status:
127123925Sgibbs	call	assert;
127219803Sgibbs
127363457Sgibbs	mov	SCB_SCSI_STATUS, SCSIDATL;
127423925Sgibbs	jmp	ITloop;
12754568Sgibbs
127613177Sgibbs/*
127741646Sgibbs * Message out phase.  If MSG_OUT is MSG_IDENTIFYFLAG, build a full
127841646Sgibbs * indentify message sequence and send it to the target.  The host may
127941646Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB
128041646Sgibbs * control byte.  This will cause us to interrupt the host and allow
128141646Sgibbs * it to handle the message phase completely on its own.  If the bit
128241646Sgibbs * associated with this target is set, we will also interrupt the host,
128341646Sgibbs * thereby allowing it to send a message on the next selection regardless
128441646Sgibbs * of the transaction being sent.
128539220Sgibbs * 
128639220Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
128741646Sgibbs * This is done to allow the host to send messages outside of an identify
128839220Sgibbs * sequence while protecting the seqencer from testing the MK_MESSAGE bit
128939220Sgibbs * on an SCB that might not be for the current nexus. (For example, a
129039220Sgibbs * BDR message in responce to a bad reselection would leave us pointed to
129139220Sgibbs * an SCB that doesn't have anything to do with the current target).
129241646Sgibbs *
129339220Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
129439220Sgibbs * bus device reset).
129539220Sgibbs *
129639220Sgibbs * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
129739220Sgibbs * in case the target decides to put us in this phase for some strange
129839220Sgibbs * reason.
129913177Sgibbs */
130041646Sgibbsp_mesgout_retry:
130141646Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
13024568Sgibbsp_mesgout:
130339220Sgibbs	mov	SINDEX, MSG_OUT;
130439220Sgibbs	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
130541646Sgibbs	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
130663457Sgibbs	mov	FUNCTION1, SCB_SCSIID;
130741646Sgibbs	mov	A, FUNCTION1;
130847414Sgibbs	mov	SINDEX, TARGET_MSG_REQUEST[0];
130941646Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
131041646Sgibbs		/* Second Channel uses high byte bits */
131163457Sgibbs		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
131241646Sgibbs		mov	SINDEX, TARGET_MSG_REQUEST[1];
131341646Sgibbs	} else if ((ahc->features & AHC_WIDE) != 0) {
131463457Sgibbs		test	SCB_SCSIID, 0x80	jz . + 2; /* target > 7 */
131541646Sgibbs		mov	SINDEX, TARGET_MSG_REQUEST[1];
131641646Sgibbs	}
131741646Sgibbs	test	SINDEX, A	jnz host_message_loop;
131839220Sgibbsp_mesgout_identify:
131963457Sgibbs	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN;
132063457Sgibbs	test	SCB_CONTROL, DISCENB jnz . + 2;
132163457Sgibbs	and	SINDEX, ~DISCENB;
132213177Sgibbs/*
132339220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
132439220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
132513177Sgibbs */
132639220Sgibbsp_mesgout_tag:
132739220Sgibbs	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
132839220Sgibbs	mov	SCSIDATL, SINDEX;	/* Send the identify message */
132939220Sgibbs	call	phase_lock;
133039220Sgibbs	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
133139220Sgibbs	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
133239220Sgibbs	call	phase_lock;
133339220Sgibbs	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
133439220Sgibbs	mov	SCB_TAG	jmp p_mesgout_onebyte;
133513177Sgibbs/*
133641646Sgibbs * Interrupt the driver, and allow it to handle this message
133741646Sgibbs * phase and any required retries.
133813177Sgibbs */
133939220Sgibbsp_mesgout_from_host:
134039220Sgibbs	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
134141646Sgibbs	jmp	host_message_loop;
134239220Sgibbs
134339220Sgibbsp_mesgout_onebyte:
134439220Sgibbs	mvi	CLRSINT1, CLRATNO;
134539220Sgibbs	mov	SCSIDATL, SINDEX;
134639220Sgibbs
134713177Sgibbs/*
134841646Sgibbs * If the next bus phase after ATN drops is message out, it means
134913177Sgibbs * that the target is requesting that the last message(s) be resent.
135013177Sgibbs */
135139220Sgibbs	call	phase_lock;
135241646Sgibbs	cmp	LASTPHASE, P_MESGOUT	je p_mesgout_retry;
13534568Sgibbs
135419906Sgibbsp_mesgout_done:
135523925Sgibbs	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
135639220Sgibbs	mov	LAST_MSG, MSG_OUT;
135739220Sgibbs	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
135823925Sgibbs	jmp	ITloop;
13594568Sgibbs
136013177Sgibbs/*
136113177Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
136213177Sgibbs */
13634568Sgibbsp_mesgin:
136423925Sgibbs	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
13654568Sgibbs
136623925Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
136723925Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
136823925Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
136923925Sgibbs	cmp	ALLZEROS,A		je mesgin_complete;
137023925Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
137163457Sgibbs	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_ign_wide_residue;
137223925Sgibbs	cmp	A,MSG_NOOP		je mesgin_done;
13734568Sgibbs
137413177Sgibbs/*
137541887Sgibbs * Pushed message loop to allow the kernel to
137657099Sgibbs * run it's own message state engine.  To avoid an
137741887Sgibbs * extra nop instruction after signaling the kernel,
137841887Sgibbs * we perform the phase_lock before checking to see
137941887Sgibbs * if we should exit the loop and skip the phase_lock
138041887Sgibbs * in the ITloop.  Performing back to back phase_locks
138141887Sgibbs * shouldn't hurt, but why do it twice...
138213177Sgibbs */
138341887Sgibbshost_message_loop:
138441887Sgibbs	mvi	INTSTAT, HOST_MSG_LOOP;
138541887Sgibbs	call	phase_lock;
138641887Sgibbs	cmp	RETURN_1, EXIT_MSG_LOOP	je ITloop + 1;
138741887Sgibbs	jmp	host_message_loop;
13889954Sgibbs
138963457Sgibbsmesgin_ign_wide_residue:
139063457Sgibbsif ((ahc->features & AHC_WIDE) != 0) {
139163457Sgibbs	test	SCSIRATE, WIDEXFER jz mesgin_reject;
139263457Sgibbs	/* Pull the residue byte */
139363457Sgibbs	mvi	ARG_1	call inb_next;
139463457Sgibbs	cmp	ARG_1, 0x01 jne mesgin_reject;
139563457Sgibbs	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
139663457Sgibbs	test	DATA_COUNT_ODD, 0x1	jz mesgin_done;
139763457Sgibbs	mvi	INTSTAT, IGN_WIDE_RES;
139863457Sgibbs	jmp	mesgin_done;
139963457Sgibbs}
140063457Sgibbs
140163457Sgibbsmesgin_reject:
140263457Sgibbs	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
14039954Sgibbsmesgin_done:
140423925Sgibbs	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
140523925Sgibbs	jmp	ITloop;
14069954Sgibbs
14079954Sgibbsmesgin_complete:
140813177Sgibbs/*
140963457Sgibbs * We received a "command complete" message.  Put the SCB_TAG into the QOUTFIFO,
141019164Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
141139220Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0).
141239220Sgibbs * In either of these conditions, we upload the SCB back to the host so it can
141319164Sgibbs * process this information.  In the case of a non zero status byte, we 
141419164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
141519164Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
141668087Sgibbs * sense, it will fill the kernel SCB with a request sense command, requeue
141768087Sgibbs * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 
141868087Sgibbs * RETURN_1 to SEND_SENSE.
141913177Sgibbs */
142019164Sgibbs
142113177Sgibbs/*
142219164Sgibbs * First check for residuals
142313177Sgibbs */
142463457Sgibbs	test	SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */
142563457Sgibbs	test	SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
142663457Sgibbs	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
142763457Sgibbscheck_status:
142863457Sgibbs	test	SCB_SCSI_STATUS,0xff	jz complete;	/* Good Status? */
142919164Sgibbsupload_scb:
143063457Sgibbs	or	SCB_SGPTR, SG_RESID_VALID;
143123925Sgibbs	mvi	DMAPARAMS, FIFORESET;
143223925Sgibbs	mov	SCB_TAG		call dma_scb;
143363457Sgibbs	test	SCB_SCSI_STATUS, 0xff	jz complete;	/* Just a residual? */
143463457Sgibbs	mvi	INTSTAT, BAD_STATUS;			/* let driver know */
143568087Sgibbs	nop;
143639220Sgibbs	cmp	RETURN_1, SEND_SENSE	jne complete;
143768087Sgibbs	call	add_scb_to_free_list;
143823925Sgibbs	jmp	await_busfree;
143939220Sgibbscomplete:
144039220Sgibbs	mov	SCB_TAG call complete_post;
144123925Sgibbs	jmp	await_busfree;
144241646Sgibbs}
14434568Sgibbs
144439220Sgibbscomplete_post:
144539220Sgibbs	/* Post the SCBID in SINDEX and issue an interrupt */
144644507Sgibbs	call	add_scb_to_free_list;
144739220Sgibbs	mov	ARG_1, SINDEX;
144839220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
144939220Sgibbs		mov	A, SDSCB_QOFF;
145039220Sgibbs	} else {
145139220Sgibbs		mov	A, QOUTPOS;
145239220Sgibbs	}
145339220Sgibbs	mvi	QOUTFIFO_OFFSET call post_byte_setup;
145439220Sgibbs	mov	ARG_1 call post_byte;
145539220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) == 0) {
145639220Sgibbs		inc 	QOUTPOS;
145739220Sgibbs	}
145839220Sgibbs	mvi	INTSTAT,CMDCMPLT ret;
145939220Sgibbs
146068087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) {
146113177Sgibbs/*
146213177Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
146363457Sgibbs * and await the bus going free.  If this is an untagged transaction
146463457Sgibbs * store the SCB id for it in our untagged target table for lookup on
146563457Sgibbs * a reselction.
146613177Sgibbs */
14679954Sgibbsmesgin_disconnect:
146823925Sgibbs	or	SCB_CONTROL,DISCONNECTED;
146963457Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
147063457Sgibbs		call	add_scb_to_disc_list;
147163457Sgibbs	}
147263457Sgibbs	test	SCB_CONTROL, TAG_ENB jnz await_busfree;
147363457Sgibbs	mov	ARG_1, SCB_TAG;
147463457Sgibbs	mov	SAVED_LUN, SCB_LUN;
147568087Sgibbs	mov	SCB_SCSIID	call set_busy_target;
147623925Sgibbs	jmp	await_busfree;
147719164Sgibbs
147815328Sgibbs/*
147919164Sgibbs * Save data pointers message:
148019164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
148119164Sgibbs * only if we've actually been into a data phase to change them.  This
148219164Sgibbs * protects against bogus data in scratch ram and the residual counts
148319164Sgibbs * since they are only initialized when we go into data_in or data_out.
148415328Sgibbs */
148519164Sgibbsmesgin_sdptrs:
148623925Sgibbs	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
14874568Sgibbs
148839220Sgibbs	/*
148963457Sgibbs	 * The SCB_SGPTR becomes the next one we'll download,
149063457Sgibbs	 * and the SCB_DATAPTR becomes the current SHADDR.
149139220Sgibbs	 * Use the residual number since STCNT is corrupted by
149239220Sgibbs	 * any message transfer.
149339220Sgibbs	 */
149439220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
149539220Sgibbs		bmov	SCB_DATAPTR, SHADDR, 4;
149663457Sgibbs		bmov	SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8;
149739220Sgibbs	} else {
149839220Sgibbs		mvi	DINDEX, SCB_DATAPTR;
149963457Sgibbs		mvi	SHADDR call bcopy_4;
150063457Sgibbs		mvi	SCB_RESIDUAL_DATACNT call bcopy_8;
150139220Sgibbs	}
150223925Sgibbs	jmp	mesgin_done;
15034568Sgibbs
150413177Sgibbs/*
150513177Sgibbs * Restore pointers message?  Data pointers are recopied from the
150613177Sgibbs * SCB anytime we enter a data phase for the first time, so all
150713177Sgibbs * we need to do is clear the DPHASE flag and let the data phase
150813177Sgibbs * code do the rest.
150913177Sgibbs */
15109954Sgibbsmesgin_rdptrs:
151123925Sgibbs	and	SEQ_FLAGS, ~DPHASE;		/*
151223925Sgibbs						 * We'll reload them
151313177Sgibbs						 * the next time through
151423925Sgibbs						 * the dataphase.
151513177Sgibbs						 */
151623925Sgibbs	jmp	mesgin_done;
15174568Sgibbs
151813177Sgibbs/*
151963457Sgibbs * Index into our Busy Target table.  SINDEX and DINDEX are modified
152063457Sgibbs * upon return.  SCBPTR may be modified by this action.
152163457Sgibbs */
152268087Sgibbsset_busy_target:
152368087Sgibbs	shr	DINDEX, 4, SINDEX;
152463457Sgibbs	if ((ahc->features & AHC_SCB_BTT) != 0) {
152563457Sgibbs		mov	SCBPTR, SAVED_LUN;
152668087Sgibbs		add	DINDEX, SCB_64_BTT;
152763457Sgibbs	} else {
152868087Sgibbs		add	DINDEX, BUSY_TARGETS;
152963457Sgibbs	}
153068087Sgibbs	mov	DINDIR, ARG_1 ret;
153163457Sgibbs
153263457Sgibbs/*
153313177Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
153413177Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
153513177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
153613177Sgibbs */
15379954Sgibbsmesgin_identify:
153863457Sgibbs	and	SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
153963457Sgibbs	/*
154063457Sgibbs	 * Determine whether a target is using tagged or non-tagged
154163457Sgibbs	 * transactions by first looking at the transaction stored in
154263457Sgibbs	 * the busy target array.  If there is no untagged transaction
154363457Sgibbs	 * for this target or the transaction is for a different lun, then
154463457Sgibbs	 * this must be an untagged transaction.
154563457Sgibbs	 */
154668087Sgibbsfetch_busy_target:
154768087Sgibbs	shr	A, 4, SAVED_SCSIID;
154868087Sgibbs	if ((ahc->features & AHC_SCB_BTT) != 0) {
154968087Sgibbs		add	SINDEX, SCB_64_BTT, A;
155068087Sgibbs		mov	SCBPTR, SAVED_LUN;
155168087Sgibbs	} else {
155268087Sgibbs		add	SINDEX, BUSY_TARGETS, A;
155368087Sgibbs		if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
155468087Sgibbs			add	A, -BUSY_TARGETS, SINDEX;
155568087Sgibbs			jc	. + 2;
155668087Sgibbs			mvi	INTSTAT, OUT_OF_RANGE;
155768087Sgibbs			add	A, -(BUSY_TARGETS + 16), SINDEX;
155868087Sgibbs			jnc	. + 2;
155968087Sgibbs			mvi	INTSTAT, OUT_OF_RANGE;
156068087Sgibbs		}
156168087Sgibbs	}
156268087Sgibbs	mov	ARG_1, SINDIR;
156368087Sgibbs	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
156463457Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
156568087Sgibbs		mov	RETURN_1 call findSCB;
156639220Sgibbs	} else {
156768087Sgibbs		mov	SCBPTR, RETURN_1;
156839220Sgibbs	}
156963457Sgibbs	if ((ahc->features & AHC_SCB_BTT) != 0) {
157063457Sgibbs		jmp setup_SCB_id_lun_okay;
157163457Sgibbs	} else {
157263457Sgibbs		mov	A, SCB_LUN;
157363457Sgibbs		cmp	SAVED_LUN, A		je setup_SCB_id_lun_okay;
157463457Sgibbs	}
157568087Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
157668087Sgibbs		call	add_scb_to_disc_list;
157768087Sgibbs	}
157839220Sgibbs
157913177Sgibbs/*
158013177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
158123168Sgibbs * If we get one, we use the tag returned to find the proper
158263457Sgibbs * SCB.  With SCB paging, we must search for non-tagged
158363457Sgibbs * transactions since the SCB may exist in any slot.  If we're not
158463457Sgibbs * using SCB paging, we can use the tag as the direct index to the
158563457Sgibbs * SCB.
158613177Sgibbs */
158724608Sgibbssnoop_tag:
158823925Sgibbs	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
158939220Sgibbs	call	phase_lock;
159068087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
159168087Sgibbs		or	SEQ_FLAGS, 0x1;
159268087Sgibbs	}
159323925Sgibbs	cmp	LASTPHASE, P_MESGIN	jne not_found;
159468087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
159568087Sgibbs		or	SEQ_FLAGS, 0x2;
159668087Sgibbs	}
159723925Sgibbs	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
15986608Sgibbsget_tag:
159963457Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
160063457Sgibbs		mvi	ARG_1	call inb_next;	/* tag value */
160163457Sgibbs		mov	ARG_1	call findSCB;
160263457Sgibbs	} else {
160368087Sgibbs		mvi	ARG_1	call inb_next;	/* tag value */
160468087Sgibbs		mov	SCBPTR, ARG_1;
160563457Sgibbs	}
160613177Sgibbs
160763457Sgibbs/*
160863457Sgibbs * Ensure that the SCB the tag points to is for
160963457Sgibbs * an SCB transaction to the reconnecting target.
161063457Sgibbs */
161139220Sgibbssetup_SCB:
161263457Sgibbs	mov	A, SAVED_SCSIID;
161368087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
161468087Sgibbs		or	SEQ_FLAGS, 0x4;
161568087Sgibbs	}
161668087Sgibbs	cmp	SCB_SCSIID, A	jne not_found_cleanup_scb;
161763457Sgibbs	mov	A, SAVED_LUN;
161868087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
161968087Sgibbs		or	SEQ_FLAGS, 0x8;
162068087Sgibbs	}
162168087Sgibbs	cmp	SCB_LUN, A	jne not_found_cleanup_scb;
162263457Sgibbssetup_SCB_id_lun_okay:
162368087Sgibbs	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
162468087Sgibbs		or	SEQ_FLAGS, 0x10;
162563457Sgibbs	}
162668087Sgibbs	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
162723925Sgibbs	and	SCB_CONTROL,~DISCONNECTED;
162868087Sgibbs	mvi	SEQ_FLAGS,IDENTIFY_SEEN;	/* make note of IDENTIFY */
162963457Sgibbs	test	SCB_CONTROL, TAG_ENB	jnz setup_SCB_tagged;
163063457Sgibbs	mov	A, SCBPTR;
163168087Sgibbs	mvi	ARG_1, SCB_LIST_NULL;
163268087Sgibbs	mov	SAVED_SCSIID	call	set_busy_target;
163363457Sgibbs	mov	SCBPTR, A;
163463457Sgibbssetup_SCB_tagged:
163539220Sgibbs	call	set_transfer_settings;
163639220Sgibbs	/* See if the host wants to send a message upon reconnection */
163739220Sgibbs	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
163839220Sgibbs	mvi	HOST_MSG	call mk_mesg;
163923925Sgibbs	jmp	mesgin_done;
164015328Sgibbs
164168087Sgibbsnot_found_cleanup_scb:
164268087Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
164368087Sgibbs		call	add_scb_to_free_list;
164468087Sgibbs	}
164519218Sgibbsnot_found:
164623925Sgibbs	mvi	INTSTAT, NO_MATCH;
164723925Sgibbs	jmp	mesgin_done;
16486608Sgibbs
16494568Sgibbsmk_mesg:
165023925Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
165139220Sgibbs	mov	MSG_OUT,SINDEX ret;
16524568Sgibbs
165313177Sgibbs/*
165413177Sgibbs * Functions to read data in Automatic PIO mode.
165513177Sgibbs *
165613177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
165713177Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
165813177Sgibbs * latched (the usual way), then read the data byte directly off the bus
165913177Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
166013177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
166113177Sgibbs * spec guarantees that the target will hold the data byte on the bus until
166213177Sgibbs * we send our ACK.
166313177Sgibbs *
166413177Sgibbs * The assumption here is that these are called in a particular sequence,
166513177Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
166613177Sgibbs * use the same calling convention as inb.
166713177Sgibbs */
166857099Sgibbsinb_next_wait_perr:
166957099Sgibbs	mvi	INTSTAT, PERR_DETECTED;
167057099Sgibbs	jmp	inb_next_wait;
167113177Sgibbsinb_next:
167223925Sgibbs	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
167313360Sgibbsinb_next_wait:
167421947Sgibbs	/*
167521947Sgibbs	 * If there is a parity error, wait for the kernel to
167621947Sgibbs	 * see the interrupt and prepare our message response
167721947Sgibbs	 * before continuing.
167821947Sgibbs	 */
167923925Sgibbs	test	SSTAT1, REQINIT	jz inb_next_wait;
168057099Sgibbs	test	SSTAT1, SCSIPERR jnz inb_next_wait_perr;
168157099Sgibbsinb_next_check_phase:
168223925Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI;
168323925Sgibbs	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
168419623Sgibbsinb_first:
168523925Sgibbs	mov	DINDEX,SINDEX;
168623925Sgibbs	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
168713177Sgibbsinb_last:
168823925Sgibbs	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
168941646Sgibbs}
16904568Sgibbs
169168087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) {
169241646Sgibbs/*
169341646Sgibbs * Change to a new phase.  If we are changing the state of the I/O signal,
169441646Sgibbs * from out to in, wait an additional data release delay before continuing.
169541646Sgibbs */
169641646Sgibbschange_phase:
169743880Sgibbs	/* Wait for preceeding I/O session to complete. */
169843880Sgibbs	test	SCSISIGI, ACKI jnz .;
169943880Sgibbs
170043880Sgibbs	/* Change the phase */
170141646Sgibbs	and	DINDEX, IOI, SCSISIGI;
170241646Sgibbs	mov	SCSISIGO, SINDEX;
170341646Sgibbs	and	A, IOI, SINDEX;
170443880Sgibbs
170543880Sgibbs	/*
170643880Sgibbs	 * If the data direction has changed, from
170743880Sgibbs	 * out (initiator driving) to in (target driving),
170863457Sgibbs	 * we must wait at least a data release delay plus
170943880Sgibbs	 * the normal bus settle delay. [SCSI III SPI 10.11.0]
171043880Sgibbs	 */
171141646Sgibbs	cmp 	DINDEX, A je change_phase_wait;
171241646Sgibbs	test	SINDEX, IOI jz change_phase_wait;
171341646Sgibbs	call	change_phase_wait;
171441646Sgibbschange_phase_wait:
171541646Sgibbs	nop;
171641646Sgibbs	nop;
171741646Sgibbs	nop;
171841646Sgibbs	nop ret;
171941646Sgibbs
172041646Sgibbs/*
172141646Sgibbs * Send a byte to an initiator in Automatic PIO mode.
172241646Sgibbs */
172339220Sgibbstarget_outb:
172439220Sgibbs	or	SXFRCTL0, SPIOEN;
172539220Sgibbs	test	SSTAT0, SPIORDY	jz .;
172639220Sgibbs	mov	SCSIDATL, SINDEX;
172739220Sgibbs	test	SSTAT0, SPIORDY	jz .;
172841646Sgibbs	and	SXFRCTL0, ~SPIOEN ret;
172939220Sgibbs}
173039220Sgibbs	
17314568Sgibbs
173213177Sgibbs/*
173313177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
173413177Sgibbs * message.
173513177Sgibbs */
17364568Sgibbsassert:
173723925Sgibbs	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
17384568Sgibbs
173923925Sgibbs	mvi	INTSTAT,NO_IDENT 	ret;	/* no - tell the kernel */
17404568Sgibbs
174113177Sgibbs/*
174263457Sgibbs * Locate a disconnected SCB by SCBID.  Upon return, SCBPTR and SINDEX will
174363457Sgibbs * be set to the position of the SCB.  If the SCB cannot be found locally,
174463457Sgibbs * it will be paged in from host memory.  RETURN_2 stores the address of the
174563457Sgibbs * preceding SCB in the disconnected list which can be used to speed up
174663457Sgibbs * removal of the found SCB from the disconnected list.
174713177Sgibbs */
174865942Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) {
17494568SgibbsfindSCB:
175068087Sgibbs	mov	A, SINDEX;			/* Tag passed in SINDEX */
175168087Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound;
175263457Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH;	/* Initialize SCBPTR */
175368087Sgibbs	mvi	ARG_2, SCB_LIST_NULL;		/* Head of list */
175463457Sgibbs	jmp	findSCB_loop;
175539220SgibbsfindSCB_next:
175663457Sgibbs	cmp	SCB_NEXT, SCB_LIST_NULL je findSCB_notFound;
175768087Sgibbs	mov	ARG_2, SCBPTR;
175839220Sgibbs	mov	SCBPTR,SCB_NEXT;
175923168SgibbsfindSCB_loop:
176063457Sgibbs	cmp	SCB_TAG, A	jne findSCB_next;
176119164Sgibbsrem_scb_from_disc_list:
176239220Sgibbs	cmp	ARG_2, SCB_LIST_NULL	je rHead;
176339220Sgibbs	mov	DINDEX, SCB_NEXT;
176468087Sgibbs	mov	SINDEX, SCBPTR;
176539220Sgibbs	mov	SCBPTR, ARG_2;
176639220Sgibbs	mov	SCB_NEXT, DINDEX;
176723925Sgibbs	mov	SCBPTR, SINDEX ret;
176815328SgibbsrHead:
176923925Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
177068087SgibbsfindSCB_notFound:
177168087Sgibbs	/*
177268087Sgibbs	 * We didn't find it.  Page in the SCB.
177368087Sgibbs	 */
177468087Sgibbs	mov	ARG_1, A; /* Save tag */
177568087Sgibbs	mov	ALLZEROS call get_free_or_disc_scb;
177668087Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
177768087Sgibbs	mov	ARG_1	jmp dma_scb;
177868087Sgibbs}
17794568Sgibbs
178039220Sgibbs/*
178139220Sgibbs * Prepare the hardware to post a byte to host memory given an
178263457Sgibbs * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR.
178339220Sgibbs */
178439220Sgibbspost_byte_setup:
178539220Sgibbs	mov	ARG_2, SINDEX;
178639220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
178739220Sgibbs		mvi	DINDEX, CCHADDR;
178863457Sgibbs		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
178939220Sgibbs		mvi	CCHCNT, 1;
179039220Sgibbs		mvi	CCSCBCTL, CCSCBRESET ret;
179139220Sgibbs	} else {
179239220Sgibbs		mvi	DINDEX, HADDR;
179363457Sgibbs		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
179463457Sgibbs		mvi	1	call set_hcnt;
179539220Sgibbs		mvi	DFCNTRL, FIFORESET ret;
179639220Sgibbs	}
179739220Sgibbs
179839220Sgibbspost_byte:
179939220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
180039220Sgibbs		bmov	CCSCBRAM, SINDEX, 1;
180139220Sgibbs		or	CCSCBCTL, CCSCBEN|CCSCBRESET;
180239220Sgibbs		test	CCSCBCTL, CCSCBDONE jz .;
180339220Sgibbs		clr	CCSCBCTL ret;
180439220Sgibbs	} else {
180539220Sgibbs		mov	DFDAT, SINDEX;
180639220Sgibbs		or	DFCNTRL, HDMAEN|FIFOFLUSH;
180739220Sgibbs		jmp	dma_finish;
180839220Sgibbs	}
180939220Sgibbs
181057099Sgibbsphase_lock_perr:
181157099Sgibbs	mvi	INTSTAT, PERR_DETECTED;
181239220Sgibbsphase_lock:     
181357099Sgibbs	/*
181457099Sgibbs	 * If there is a parity error, wait for the kernel to
181557099Sgibbs	 * see the interrupt and prepare our message response
181657099Sgibbs	 * before continuing.
181757099Sgibbs	 */
181839220Sgibbs	test	SSTAT1, REQINIT jz phase_lock;
181957099Sgibbs	test	SSTAT1, SCSIPERR jnz phase_lock_perr;
182057099Sgibbsphase_lock_latch_phase:
182141646Sgibbs	and	SCSISIGO, PHASE_MASK, SCSISIGI;
182241646Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
182339220Sgibbs
182439220Sgibbsif ((ahc->features & AHC_CMD_CHAN) == 0) {
182563457Sgibbsset_hcnt:
182663457Sgibbs	mov	HCNT[0], SINDEX;
182763457Sgibbsclear_hcnt:
182863457Sgibbs	clr	HCNT[1];
182963457Sgibbs	clr	HCNT[2] ret;
183063457Sgibbs
183119164Sgibbsset_stcnt_from_hcnt:
183223925Sgibbs	mov	STCNT[0], HCNT[0];
183323925Sgibbs	mov	STCNT[1], HCNT[1];
183423925Sgibbs	mov	STCNT[2], HCNT[2] ret;
18354568Sgibbs
183663457Sgibbsbcopy_8:
183763457Sgibbs	mov	DINDIR, SINDIR;
183819164Sgibbsbcopy_7:
183923925Sgibbs	mov	DINDIR, SINDIR;
184023925Sgibbs	mov	DINDIR, SINDIR;
184119164Sgibbsbcopy_5:
184223925Sgibbs	mov	DINDIR, SINDIR;
184319164Sgibbsbcopy_4:
184423925Sgibbs	mov	DINDIR, SINDIR;
184519164Sgibbsbcopy_3:
184623925Sgibbs	mov	DINDIR, SINDIR;
184723925Sgibbs	mov	DINDIR, SINDIR;
184823925Sgibbs	mov	DINDIR, SINDIR ret;
184939220Sgibbs}
18504568Sgibbs
185168087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) {
185239220Sgibbs/*
185339220Sgibbs * Setup addr assuming that A is an index into
185439220Sgibbs * an array of 32byte objects, SINDEX contains
185539220Sgibbs * the base address of that array, and DINDEX
185639220Sgibbs * contains the base address of the location
185739220Sgibbs * to store the indexed address.
185839220Sgibbs */
185939220Sgibbsset_32byte_addr:
186039220Sgibbs	shr	ARG_2, 3, A;
186139220Sgibbs	shl	A, 5;
186239220Sgibbs	jmp	set_1byte_addr;
186339220Sgibbs}
186439220Sgibbs
186539220Sgibbs/*
186639220Sgibbs * Setup addr assuming that A is an index into
186739220Sgibbs * an array of 64byte objects, SINDEX contains
186839220Sgibbs * the base address of that array, and DINDEX
186939220Sgibbs * contains the base address of the location
187039220Sgibbs * to store the indexed address.
187139220Sgibbs */
187239220Sgibbsset_64byte_addr:
187339220Sgibbs	shr	ARG_2, 2, A;
187439220Sgibbs	shl	A, 6;
187539220Sgibbs
187639220Sgibbs/*
187763457Sgibbs * Setup addr assuming that A + (ARG_2 * 256) is an
187839220Sgibbs * index into an array of 1byte objects, SINDEX contains
187939220Sgibbs * the base address of that array, and DINDEX contains
188039220Sgibbs * the base address of the location to store the computed
188139220Sgibbs * address.
188239220Sgibbs */
188339220Sgibbsset_1byte_addr:
188439220Sgibbs	add     DINDIR, A, SINDIR;
188539220Sgibbs	mov     A, ARG_2;
188639220Sgibbs	adc	DINDIR, A, SINDIR;
188739220Sgibbs	clr	A;
188839220Sgibbs	adc	DINDIR, A, SINDIR;
188939220Sgibbs	adc	DINDIR, A, SINDIR ret;
189039220Sgibbs
189139220Sgibbs/*
189239220Sgibbs * Either post or fetch and SCB from host memory based on the
189339220Sgibbs * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
189439220Sgibbs */
189519164Sgibbsdma_scb:
189639220Sgibbs	mov	A, SINDEX;
189739220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
189839220Sgibbs		mvi	DINDEX, CCHADDR;
189939220Sgibbs		mvi	HSCB_ADDR call set_64byte_addr;
190039220Sgibbs		mov	CCSCBPTR, SCBPTR;
190139220Sgibbs		test	DMAPARAMS, DIRECTION jz dma_scb_tohost;
190265942Sgibbs		if ((ahc->features & AHC_SCB_BTT) != 0) {
190365942Sgibbs			mvi	CCHCNT, SCB_DOWNLOAD_SIZE_64;
190465942Sgibbs		} else {
190565942Sgibbs			mvi	CCHCNT, SCB_DOWNLOAD_SIZE;
190665942Sgibbs		}
190739220Sgibbs		mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
190839220Sgibbs		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
190939220Sgibbs		jmp	dma_scb_finish;
191039220Sgibbsdma_scb_tohost:
191165942Sgibbs		mvi	CCHCNT, SCB_UPLOAD_SIZE;
191265942Sgibbs		if ((ahc->features & AHC_ULTRA2) == 0) {
191339220Sgibbs			mvi	CCSCBCTL, CCSCBRESET;
191465942Sgibbs			bmov	CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE;
191539220Sgibbs			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
191639220Sgibbs			test	CCSCBCTL, CCSCBDONE jz .;
191765942Sgibbs		} else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) {
191865942Sgibbs			mvi	CCSCBCTL, CCARREN|CCSCBRESET;
191965942Sgibbs			cmp	CCSCBCTL, ARRDONE|CCARREN jne .;
192065942Sgibbs			mvi	CCHCNT, SCB_UPLOAD_SIZE;
192165942Sgibbs			mvi	CCSCBCTL, CCSCBEN|CCSCBRESET;
192265942Sgibbs			cmp	CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
192339220Sgibbs		} else {
192439220Sgibbs			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
192539220Sgibbs			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
192639220Sgibbs		}
192739220Sgibbsdma_scb_finish:
192839220Sgibbs		clr	CCSCBCTL;
192939220Sgibbs		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
193039220Sgibbs		ret;
193139220Sgibbs	} else {
193239220Sgibbs		mvi	DINDEX, HADDR;
193339220Sgibbs		mvi	HSCB_ADDR call set_64byte_addr;
193465942Sgibbs		mvi	SCB_DOWNLOAD_SIZE call set_hcnt;
193539220Sgibbs		mov	DFCNTRL, DMAPARAMS;
193639220Sgibbs		test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
193739220Sgibbs		/* Fill it with the SCB data */
193824175Sgibbscopy_scb_tofifo:
193965942Sgibbs		mvi	SINDEX, SCB_BASE;
194065942Sgibbs		add	A, SCB_DOWNLOAD_SIZE, SINDEX;
194124175Sgibbscopy_scb_tofifo_loop:
194265942Sgibbs		call	copy_to_fifo_8;
194339220Sgibbs		cmp	SINDEX, A jne copy_scb_tofifo_loop;
194439220Sgibbs		or	DFCNTRL, HDMAEN|FIFOFLUSH;
194565942Sgibbs		jmp	dma_finish;
194619164Sgibbsdma_scb_fromhost:
194765942Sgibbs		mvi	DINDEX, SCB_BASE;
194865942Sgibbs		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
194965942Sgibbs			/*
195065942Sgibbs			 * The PCI module will only issue a PCI
195165942Sgibbs			 * retry if the data FIFO is empty.  If the
195265942Sgibbs			 * host disconnects in the middle of a
195365942Sgibbs			 * transfer, we must empty the fifo of all
195465942Sgibbs			 * available data to force the chip to
195565942Sgibbs			 * continue the transfer.  This does not
195665942Sgibbs			 * happen for SCSI transfers as the SCSI module
195765942Sgibbs			 * will drain the FIFO as data is made available.
195865942Sgibbs			 * When the hang occurs, we know that at least
195965942Sgibbs			 * 8 bytes are in the FIFO because the PCI
196065942Sgibbs			 * module has an 8 byte input latch that only
196165942Sgibbs			 * dumps to the FIFO when HCNT == 0 or the
196265942Sgibbs			 * latch is full.
196365942Sgibbs			 */
196465942Sgibbs			mvi	A, -24;
196565942Sgibbs			/* Wait for some data to arrive. */
196665942Sgibbsdma_scb_hang_fifo:
196765942Sgibbs			test	DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo;
196865942Sgibbsdma_scb_hang_wait:
196965942Sgibbs			test	DFSTATUS, MREQPEND jnz dma_scb_hang_wait;
197065942Sgibbs			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
197165942Sgibbs			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
197265942Sgibbs			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
197365942Sgibbs			/*
197465942Sgibbs			 * The PCI no longer intends to perform a PCI
197565942Sgibbs			 * transaction and HDONE has not come true.
197665942Sgibbs			 * We are hung.  Drain the fifo.
197765942Sgibbs			 */
197865942Sgibbsdma_scb_hang_empty_fifo:
197965942Sgibbs			call	dfdat_in_8;
198065942Sgibbs			add	A, 8;
198165942Sgibbs			add	SINDEX, A, HCNT; 
198265942Sgibbs			/*
198365942Sgibbs			 * The result will be <= 0 (carry set) if at
198465942Sgibbs			 * least 8 bytes of data have been placed
198565942Sgibbs			 * into the fifo.
198665942Sgibbs			 */
198765942Sgibbs			jc	dma_scb_hang_empty_fifo;
198865942Sgibbs			jmp	dma_scb_hang_fifo;
198965942Sgibbsdma_scb_hang_dma_done:
199065942Sgibbs			and	DFCNTRL, ~HDMAEN;
199165942Sgibbs			test	DFCNTRL, HDMAEN jnz .;
199265942Sgibbs			call	dfdat_in_8;
199365942Sgibbs			add	A, 8;
199465942Sgibbs			cmp	A, 8 jne . - 2;
199565942Sgibbs		} else {
199665942Sgibbs			call	dma_finish;
199765942Sgibbs			/* If we were putting the SCB, we are done */
199865942Sgibbs			call	dfdat_in_8;
199965942Sgibbs			call	dfdat_in_8;
200065942Sgibbs			call	dfdat_in_8;
200165942Sgibbs		}
200265942Sgibbsdfdat_in_8:
200365942Sgibbs		mov	DINDIR,DFDAT;
200419164Sgibbsdfdat_in_7:
200539220Sgibbs		mov	DINDIR,DFDAT;
200639220Sgibbs		mov	DINDIR,DFDAT;
200739220Sgibbs		mov	DINDIR,DFDAT;
200839220Sgibbs		mov	DINDIR,DFDAT;
200939220Sgibbs		mov	DINDIR,DFDAT;
201065942Sgibbsdfdat_in_2:
201139220Sgibbs		mov	DINDIR,DFDAT;
201239220Sgibbs		mov	DINDIR,DFDAT ret;
201339220Sgibbs	}
201419164Sgibbs
201565942Sgibbscopy_to_fifo_8:
201665942Sgibbs	mov	DFDAT,SINDIR;
201765942Sgibbs	mov	DFDAT,SINDIR;
201863457Sgibbscopy_to_fifo_6:
201963457Sgibbs	mov	DFDAT,SINDIR;
202063457Sgibbscopy_to_fifo_5:
202163457Sgibbs	mov	DFDAT,SINDIR;
202263457Sgibbscopy_to_fifo_4:
202363457Sgibbs	mov	DFDAT,SINDIR;
202463457Sgibbs	mov	DFDAT,SINDIR;
202563457Sgibbs	mov	DFDAT,SINDIR;
202663457Sgibbs	mov	DFDAT,SINDIR ret;
202739220Sgibbs
202813177Sgibbs/*
202919164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
203019164Sgibbs * DMA and wait for it to acknowledge that it's off.
203113177Sgibbs */
203219164Sgibbsdma_finish:
203323925Sgibbs	test	DFSTATUS,HDONE	jz dma_finish;
203422234Sgibbs	/* Turn off DMA */
203523925Sgibbs	and	DFCNTRL, ~HDMAEN;
203623925Sgibbs	test	DFCNTRL, HDMAEN jnz .;
203723925Sgibbs	ret;
20389928Sgibbs
203923925Sgibbsadd_scb_to_free_list:
204039220Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
204166647SgibbsBEGIN_CRITICAL
204239220Sgibbs		mov	SCB_NEXT, FREE_SCBH;
204357099Sgibbs		mvi	SCB_TAG, SCB_LIST_NULL;
204457099Sgibbs		mov	FREE_SCBH, SCBPTR ret;
204566647SgibbsEND_CRITICAL
204657099Sgibbs	} else {
204757099Sgibbs		mvi	SCB_TAG, SCB_LIST_NULL ret;
204839220Sgibbs	}
20494568Sgibbs
205039220Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) {
205119164Sgibbsget_free_or_disc_scb:
205223925Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
205323925Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
205419623Sgibbsreturn_error:
205568087Sgibbs	mvi	INTSTAT, NO_FREE_SCB;
205623925Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret;
205719623Sgibbsdequeue_disc_scb:
205823925Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH;
205923925Sgibbsdma_up_scb:
206023925Sgibbs	mvi	DMAPARAMS, FIFORESET;
206168087Sgibbs	mov	SCB_TAG	call dma_scb;
206219164Sgibbsunlink_disc_scb:
206339220Sgibbs	mov	DISCONNECTED_SCBH, SCB_NEXT ret;
206419164Sgibbsdequeue_free_scb:
206523925Sgibbs	mov	SCBPTR, FREE_SCBH;
206623925Sgibbs	mov	FREE_SCBH, SCB_NEXT ret;
20674568Sgibbs
206819164Sgibbsadd_scb_to_disc_list:
206913177Sgibbs/*
207019164Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
207119164Sgibbs * candidates for paging out an SCB if one is needed for a new command.
207219164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
207313177Sgibbs */
207468087SgibbsBEGIN_CRITICAL
207523925Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH;
207639220Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR ret;
207768087SgibbsEND_CRITICAL
207865942Sgibbs}
207963457Sgibbsreturn:
208063457Sgibbs	ret;
2081