aic7xxx.seq revision 47158
126997Sgibbs/*
226997Sgibbs * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
313177Sgibbs *
442652Sgibbs * Copyright (c) 1994-1999 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,
1226997Sgibbs *    without modification, immediately at the beginning of the file.
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 *
1626997Sgibbs * Where this Software is combined with software released under the terms of 
1739220Sgibbs * the GNU Public License (GPL) and the terms of the GPL would require the 
1826997Sgibbs * combined work to also be released under the terms of the GPL, the terms
1926997Sgibbs * and conditions of this License will apply in addition to those of the
2026997Sgibbs * GPL with the exception of any terms or conditions of this License that
2126997Sgibbs * conflict with, or are expressly prohibited by, the GPL.
2213177Sgibbs *
2326997Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2426997Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2526997Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2626997Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2726997Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2826997Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2926997Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3026997Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3126997Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3226997Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3326997Sgibbs * SUCH DAMAGE.
3413177Sgibbs *
3547158Sgibbs *	$Id: aic7xxx.seq,v 1.87 1999/03/23 07:24:28 gibbs Exp $
3626997Sgibbs */
374568Sgibbs
3823925Sgibbs#include <dev/aic7xxx/aic7xxx.reg>
3939220Sgibbs#include <cam/scsi/scsi_message.h>
405647Sgibbs
4113177Sgibbs/*
4219164Sgibbs * A few words on the waiting SCB list:
4319164Sgibbs * After starting the selection hardware, we check for reconnecting targets
4413690Sgibbs * as well as for our selection to complete just in case the reselection wins
4513690Sgibbs * bus arbitration.  The problem with this is that we must keep track of the
4613690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection
4713690Sgibbs * on just in case the reselection wins so that we can retry the selection at
4813690Sgibbs * a later time.  This problem cannot be resolved by holding a single entry
4913690Sgibbs * in scratch ram since a reconnecting target can request sense and this will
5013690Sgibbs * create yet another SCB waiting for selection.  The solution used here is to 
5113690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
5219164Sgibbs * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
5319164Sgibbs * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
5419164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged
5519164Sgibbs * command for which a second SCB has been queued.  The sequencer will
5619164Sgibbs * automatically consume the entries.
5713177Sgibbs */
584568Sgibbs
5914449Sgibbsreset:
6023925Sgibbs	clr	SCSISIGO;		/* De-assert BSY */
6141646Sgibbs	and	SXFRCTL1, ~BITBUCKET;
6223925Sgibbs	/* Always allow reselection */
6341816Sgibbs	and	SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;
6439220Sgibbs
6539220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
6639220Sgibbs		/* Ensure that no DMA operations are in progress */
6739220Sgibbs		clr	CCSGCTL;
6839220Sgibbs		clr	CCSCBCTL;
6939220Sgibbs	}
7039220Sgibbs
7144507Sgibbspoll_for_work:
7223925Sgibbs	call	clear_target_state;
7339220Sgibbs	and	SXFRCTL0, ~SPIOEN;
7439220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) == 0) {
7539220Sgibbs		mov	A, QINPOS;
7639220Sgibbs	}
7739220Sgibbspoll_for_work_loop:
7839220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) == 0) {
7939220Sgibbs		and	SEQCTL, ~PAUSEDIS;
8039220Sgibbs	}
8139220Sgibbs	test	SSTAT0, SELDO|SELDI	jnz selection;
8223925Sgibbs	test	SCSISEQ, ENSELO	jnz poll_for_work;
8339220Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
8439220Sgibbs		/*
8539220Sgibbs		 * Twin channel devices cannot handle things like SELTO
8639220Sgibbs		 * interrupts on the "background" channel.  So, if we
8739220Sgibbs		 * are selecting, keep polling the current channel util
8839220Sgibbs		 * either a selection or reselection occurs.
8939220Sgibbs		 */
9039220Sgibbs		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
9139220Sgibbs		test	SSTAT0, SELDO|SELDI	jnz selection;
9239220Sgibbs		test	SCSISEQ, ENSELO	jnz poll_for_work;
9339220Sgibbs		xor	SBLKCTL,SELBUSB;	/* Toggle back */
9439220Sgibbs	}
9523925Sgibbs	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
9619164Sgibbstest_queue:
9719164Sgibbs	/* Has the driver posted any work for us? */
9839220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
9939220Sgibbs		test	QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
10039220Sgibbs		mov	NONE, SNSCB_QOFF;
10139220Sgibbs		inc	QINPOS;
10239220Sgibbs	} else {
10339220Sgibbs		or	SEQCTL, PAUSEDIS;
10439220Sgibbs		cmp	KERNEL_QINPOS, A je poll_for_work_loop;
10539220Sgibbs		inc	QINPOS;
10639220Sgibbs		and	SEQCTL, ~PAUSEDIS;
10739220Sgibbs	}
1084568Sgibbs
10913690Sgibbs/*
11013690Sgibbs * We have at least one queued SCB now and we don't have any 
11119164Sgibbs * SCBs in the list of SCBs awaiting selection.  If we have
11223925Sgibbs * any SCBs available for use, pull the tag from the QINFIFO
11319164Sgibbs * and get to work on it.
11413177Sgibbs */
11539220Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
11639220Sgibbs		mov	ALLZEROS	call	get_free_or_disc_scb;
11739220Sgibbs	}
11839220Sgibbs
11919164Sgibbsdequeue_scb:
12039220Sgibbs	add	A, -1, QINPOS;
12139220Sgibbs	mvi	QINFIFO_OFFSET call fetch_byte;
12239220Sgibbs
12339220Sgibbs	if ((ahc->flags & AHC_PAGESCBS) == 0) {
12439220Sgibbs		/* In the non-paging case, the SCBID == hardware SCB index */
12539220Sgibbs		mov	SCBPTR, RETURN_2;
12639220Sgibbs	}
12719164Sgibbsdma_queued_scb:
12819164Sgibbs/*
12919164Sgibbs * DMA the SCB from host ram into the current SCB location.
13019164Sgibbs */
13123925Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
13239220Sgibbs	mov	RETURN_2	 call dma_scb;
1334568Sgibbs
13413177Sgibbs/*
13539220Sgibbs * Preset the residual fields in case we never go through a data phase.
13639220Sgibbs * This isn't done by the host so we can avoid a DMA to clear these
13739220Sgibbs * fields for the normal case of I/O that completes without underrun
13839220Sgibbs * or overrun conditions.
13913177Sgibbs */
14039220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
14139220Sgibbs		bmov	SCB_RESID_DCNT, SCB_DATACNT, 3;
14239220Sgibbs	} else {
14339220Sgibbs		mov	SCB_RESID_DCNT[0],SCB_DATACNT[0];
14439220Sgibbs		mov	SCB_RESID_DCNT[1],SCB_DATACNT[1];
14539220Sgibbs		mov	SCB_RESID_DCNT[2],SCB_DATACNT[2];
14639220Sgibbs	}
14739220Sgibbs	mov	SCB_RESID_SGCNT, SCB_SGCOUNT;
1484568Sgibbs
1495326Sgibbsstart_scb:
15019164Sgibbs	/*
15119164Sgibbs	 * Place us on the waiting list in case our selection
15219164Sgibbs	 * doesn't win during bus arbitration.
15319164Sgibbs	 */
15423925Sgibbs	mov	SCB_NEXT,WAITING_SCBH;
15523925Sgibbs	mov	WAITING_SCBH, SCBPTR;
15623925Sgibbsstart_waiting:
15723925Sgibbs	/*
15839220Sgibbs	 * Pull the first entry off of the waiting SCB list.
15923925Sgibbs	 */
16023925Sgibbs	mov	SCBPTR, WAITING_SCBH;
16123925Sgibbs	call	start_selection;
16223925Sgibbs	jmp	poll_for_work;
1638104Sgibbs
16423925Sgibbsstart_selection:
16539220Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
16639220Sgibbs		and	SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
16739220Sgibbs		and	A,SELBUSB,SCB_TCL;	/* Get new channel bit */
16839220Sgibbs		or	SINDEX,A;
16939220Sgibbs		mov	SBLKCTL,SINDEX;		/* select channel */
17039220Sgibbs	}
17123925Sgibbsinitialize_scsiid:
17244507Sgibbs	mov	SINDEX, SCSISEQ_TEMPLATE;
17344507Sgibbs	if ((ahc->flags & AHC_TARGETMODE) != 0) {
17444507Sgibbs		test	SCB_CONTROL, TARGET_SCB jz . + 4;
17544507Sgibbs		if ((ahc->features & AHC_ULTRA2) != 0) {
17644507Sgibbs			mov	SCSIID_ULTRA2, SCB_CMDPTR[2];
17744507Sgibbs		} else {
17844507Sgibbs			mov	SCSIID, SCB_CMDPTR[2];
17944507Sgibbs		}
18044507Sgibbs		or	SINDEX, TEMODE;
18144507Sgibbs		jmp	initialize_scsiid_fini;
18244507Sgibbs	}
18339220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
18439220Sgibbs		and	A, TID, SCB_TCL;	/* Get target ID */
18539220Sgibbs		and	SCSIID_ULTRA2, OID;	/* Clear old target */
18639220Sgibbs		or	SCSIID_ULTRA2, A;
18739220Sgibbs	} else {
18839220Sgibbs		and	A, TID, SCB_TCL;	/* Get target ID */
18939220Sgibbs		and	SCSIID, OID;		/* Clear old target */
19039220Sgibbs		or	SCSIID, A;
19139220Sgibbs	}
19244507Sgibbsinitialize_scsiid_fini:
19341816Sgibbs	mov	SCSISEQ, SINDEX ret;
19439220Sgibbs
19513177Sgibbs/*
19639220Sgibbs * Initialize transfer settings and clear the SCSI channel.
19739220Sgibbs * SINDEX should contain any additional bit's the client wants
19839220Sgibbs * set in SXFRCTL0.  We also assume that the current SCB is
19939220Sgibbs * a valid SCB for the target we wish to talk to.
20039220Sgibbs */
20139220Sgibbsinitialize_channel:
20239220Sgibbs	or	SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;
20339220Sgibbsset_transfer_settings:
20439220Sgibbs	if ((ahc->features & AHC_ULTRA) != 0) {
20539220Sgibbs		test	SCB_CONTROL, ULTRAENB jz . + 2;
20639220Sgibbs		or	SXFRCTL0, FAST20;
20739220Sgibbs	} 
20839220Sgibbs/*
20939220Sgibbs * Initialize SCSIRATE with the appropriate value for this target.
21039220Sgibbs */
21139220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
21239220Sgibbs		bmov	SCSIRATE, SCB_SCSIRATE, 2 ret;
21339220Sgibbs	} else {
21439220Sgibbs		mov	SCSIRATE, SCB_SCSIRATE ret;
21539220Sgibbs	}
21639220Sgibbs
21739220Sgibbsselection:
21839220Sgibbs	test	SSTAT0,SELDO	jnz select_out;
21939220Sgibbs	mvi	CLRSINT0, CLRSELDI;
22039220Sgibbsselect_in:
22139220Sgibbs	if ((ahc->flags & AHC_TARGETMODE) != 0) {
22241646Sgibbs		if ((ahc->flags & AHC_INITIATORMODE) != 0) {
22341646Sgibbs			test	SSTAT0, TARGET	jz initiator_reselect;
22441646Sgibbs		}
22542652Sgibbs
22639220Sgibbs		/*
22739220Sgibbs		 * We've just been selected.  Assert BSY and
22839220Sgibbs		 * setup the phase for receiving messages
22939220Sgibbs		 * from the target.
23039220Sgibbs		 */
23139220Sgibbs		mvi	SCSISIGO, P_MESGOUT|BSYO;
23241646Sgibbs		mvi	CLRSINT1, CLRBUSFREE;
23339220Sgibbs
23439220Sgibbs		/*
23539220Sgibbs		 * Setup the DMA for sending the identify and
23641299Sgibbs		 * command information.
23739220Sgibbs		 */
23839220Sgibbs		or	SEQ_FLAGS, CMDPHASE_PENDING;
23941299Sgibbs
24041299Sgibbs		mov     A, TQINPOS;
24139220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
24239220Sgibbs			mvi	DINDEX, CCHADDR;
24339220Sgibbs			mvi	TMODE_CMDADDR call set_32byte_addr;
24439220Sgibbs			mvi	CCSCBCTL, CCSCBRESET;
24539220Sgibbs		} else {
24639220Sgibbs			mvi	DINDEX, HADDR;
24739220Sgibbs			mvi	TMODE_CMDADDR call set_32byte_addr;
24839220Sgibbs			mvi	DFCNTRL, FIFORESET;
24939220Sgibbs		}
25039220Sgibbs
25139220Sgibbs		/* Initiator that selected us */
25239220Sgibbs		and	SAVED_TCL, SELID_MASK, SELID;
25339220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
25439220Sgibbs			mov	CCSCBRAM, SAVED_TCL;
25539220Sgibbs		} else {
25639220Sgibbs			mov	DFDAT, SAVED_TCL;
25739220Sgibbs		}
25839220Sgibbs
25939220Sgibbs		/* The Target ID we were selected at */
26044507Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
26144507Sgibbs			if ((ahc->features & AHC_MULTI_TID) != 0) {
26244507Sgibbs				and	CCSCBRAM, OID, TARGIDIN;
26344507Sgibbs			} else if ((ahc->features & AHC_ULTRA2) != 0) {
26444507Sgibbs				and	CCSCBRAM, OID, SCSIID_ULTRA2;
26539220Sgibbs			} else {
26644507Sgibbs				and	CCSCBRAM, OID, SCSIID;
26739220Sgibbs			}
26839220Sgibbs		} else {
26944507Sgibbs			if ((ahc->features & AHC_MULTI_TID) != 0) {
27044507Sgibbs				and	DFDAT, OID, TARGIDIN;
27144507Sgibbs			} else if ((ahc->features & AHC_ULTRA2) != 0) {
27244507Sgibbs				and	DFDAT, OID, SCSIID_ULTRA2;
27339220Sgibbs			} else {
27439220Sgibbs				and	DFDAT, OID, SCSIID;
27539220Sgibbs			}
27639220Sgibbs		}
27739220Sgibbs
27842652Sgibbs		/* No tag yet */
27942652Sgibbs		mvi	INITIATOR_TAG, SCB_LIST_NULL;
28042652Sgibbs
28139220Sgibbs		/*
28239220Sgibbs		 * If ATN isn't asserted, the target isn't interested
28339220Sgibbs		 * in talking to us.  Go directly to bus free.
28439220Sgibbs		 */
28539220Sgibbs		test	SCSISIGI, ATNI	jz	target_busfree;
28639220Sgibbs
28739220Sgibbs		/*
28839220Sgibbs		 * Watch ATN closely now as we pull in messages from the
28939220Sgibbs		 * initiator.  We follow the guidlines from section 6.5
29039220Sgibbs		 * of the SCSI-2 spec for what messages are allowed when.
29139220Sgibbs		 */
29241646Sgibbs		call	target_inb;
29339220Sgibbs
29439220Sgibbs		/*
29539220Sgibbs		 * Our first message must be one of IDENTIFY, ABORT, or
29639220Sgibbs		 * BUS_DEVICE_RESET.
29739220Sgibbs		 */
29841299Sgibbs		/* XXX May need to be more lax here for older initiators... */
29942652Sgibbs		test	DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
30039220Sgibbs		/* Store for host */
30139220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
30239220Sgibbs			mov	CCSCBRAM, DINDEX;
30339220Sgibbs		} else {
30439220Sgibbs			mov	DFDAT, DINDEX;
30539220Sgibbs		}
30639220Sgibbs
30739220Sgibbs		/* Remember for disconnection decision */
30839220Sgibbs		test	DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
30939220Sgibbs		/* XXX Honor per target settings too */
31039220Sgibbs		or	SEQ_FLAGS, NO_DISCONNECT;
31139220Sgibbs
31239220Sgibbs		test	SCSISIGI, ATNI	jz	ident_messages_done;
31341646Sgibbs		call	target_inb;
31439220Sgibbs		/*
31539220Sgibbs		 * If this is a tagged request, the tagged message must
31639220Sgibbs		 * immediately follow the identify.  We test for a valid
31739220Sgibbs		 * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and
31839220Sgibbs		 * < MSG_IGN_WIDE_RESIDUE.
31939220Sgibbs		 */
32039220Sgibbs		add	A, -MSG_SIMPLE_Q_TAG, DINDEX;
32139220Sgibbs		jnc	ident_messages_done;
32239220Sgibbs		add	A, -MSG_IGN_WIDE_RESIDUE, DINDEX;
32339220Sgibbs		jc	ident_messages_done;
32439220Sgibbs		/* Store for host */
32539220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
32639220Sgibbs			mov	CCSCBRAM, DINDEX;
32739220Sgibbs		} else {
32839220Sgibbs			mov	DFDAT, DINDEX;
32939220Sgibbs		}
33039220Sgibbs		
33139220Sgibbs		/*
33239220Sgibbs		 * If the initiator doesn't feel like providing a tag number,
33339220Sgibbs		 * we've got a failed selection and must transition to bus
33439220Sgibbs		 * free.
33539220Sgibbs		 */
33639220Sgibbs		test	SCSISIGI, ATNI	jz	target_busfree;
33742652Sgibbs
33839220Sgibbs		/*
33939220Sgibbs		 * Store the tag for the host.
34039220Sgibbs		 */
34141646Sgibbs		call	target_inb;
34239220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
34339220Sgibbs			mov	CCSCBRAM, DINDEX;
34439220Sgibbs		} else {
34539220Sgibbs			mov	DFDAT, DINDEX;
34639220Sgibbs		}
34742652Sgibbs		mov	INITIATOR_TAG, DINDEX;
34839220Sgibbs		jmp	ident_messages_done;
34939220Sgibbs
35041646Sgibbs		/*
35141646Sgibbs		 * Pushed message loop to allow the kernel to
35242652Sgibbs		 * run it's own target mode message state engine.
35341646Sgibbs		 */
35441646Sgibbshost_target_message_loop:
35541646Sgibbs		mvi	INTSTAT, HOST_MSG_LOOP;
35641646Sgibbs		nop;
35741646Sgibbs		cmp	RETURN_1, EXIT_MSG_LOOP	je target_ITloop;
35841646Sgibbs		test	SSTAT0, SPIORDY jz .;
35941646Sgibbs		jmp	host_target_message_loop;
36041646Sgibbs
36139220Sgibbsident_messages_done:
36244507Sgibbs		/* If ring buffer is full, return busy or queue full */
36344507Sgibbs		mov	A, KERNEL_TQINPOS;
36444507Sgibbs		cmp	TQINPOS, A jne tqinfifo_has_space;
36544507Sgibbs		mvi	P_STATUS|BSYO call change_phase;
36644507Sgibbs		cmp	INITIATOR_TAG, SCB_LIST_NULL je . + 3;
36744507Sgibbs		mvi	STATUS_QUEUE_FULL call target_outb;
36844507Sgibbs		jmp	target_busfree_wait;
36944507Sgibbs		mvi	STATUS_BUSY call target_outb;
37044507Sgibbs		jmp	target_busfree_wait;
37144507Sgibbstqinfifo_has_space:	
37239220Sgibbs		/* Terminate the ident list */
37339220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
37439220Sgibbs			mvi	CCSCBRAM, SCB_LIST_NULL;
37539220Sgibbs		} else {
37639220Sgibbs			mvi	DFDAT, SCB_LIST_NULL;
37739220Sgibbs		}
37842652Sgibbs		or	SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
37941646Sgibbs		test	SCSISIGI, ATNI	jnz target_mesgout_pending_msg;
38039220Sgibbs		jmp	target_ITloop;
38139220Sgibbs		
38239220Sgibbs/*
38339220Sgibbs * We carefully toggle SPIOEN to allow us to return the 
38439220Sgibbs * message byte we receive so it can be checked prior to
38539220Sgibbs * driving REQ on the bus for the next byte.
38639220Sgibbs */
38741646Sgibbstarget_inb:
38841646Sgibbs		/*
38941646Sgibbs		 * Drive REQ on the bus by enabling SCSI PIO.
39041646Sgibbs		 */
39139220Sgibbs		or	SXFRCTL0, SPIOEN;
39239220Sgibbs		/* Wait for the byte */
39339220Sgibbs		test	SSTAT0, SPIORDY jz .;
39439220Sgibbs		/* Prevent our read from triggering another REQ */
39539220Sgibbs		and	SXFRCTL0, ~SPIOEN;
39641646Sgibbs		/* Save latched contents */
39739220Sgibbs		mov	DINDEX, SCSIDATL ret;
39839220Sgibbs	}
39939220Sgibbs
40041646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) {
40139220Sgibbs/*
40223925Sgibbs * Reselection has been initiated by a target. Make a note that we've been
40323925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
40413177Sgibbs */
40539220Sgibbsinitiator_reselect:
40623925Sgibbs	/* XXX test for and handle ONE BIT condition */
40723925Sgibbs	and	SAVED_TCL, SELID_MASK, SELID;
40839545Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
40939545Sgibbs		test	SBLKCTL, SELBUSB	jz . + 2;
41039545Sgibbs		or	SAVED_TCL, SELBUSB;
41139545Sgibbs	}
41241646Sgibbs	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
41339220Sgibbs	mvi	CLRSINT1,CLRBUSFREE;
41439220Sgibbs	or	SIMODE1, ENBUSFREE;		/*
41539220Sgibbs						 * We aren't expecting a
41639220Sgibbs						 * bus free, so interrupt
41739220Sgibbs						 * the kernel driver if it
41839220Sgibbs						 * happens.
41939220Sgibbs						 */
42039220Sgibbs	mvi	MSG_OUT, MSG_NOOP;		/* No message to send */
42139220Sgibbs	jmp	ITloop;
42241646Sgibbs}
4234568Sgibbs
42413177Sgibbs/*
42523925Sgibbs * After the selection, remove this SCB from the "waiting SCB"
42623925Sgibbs * list.  This is achieved by simply moving our "next" pointer into
42723925Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
42823925Sgibbs * SCB is used, so don't bother with it now.
42923925Sgibbs */
43039220Sgibbsselect_out:
43125005Sgibbs	/* Turn off the selection hardware */
43241816Sgibbs	and	SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;
43325005Sgibbs	mvi	CLRSINT0, CLRSELDO;
43425005Sgibbs	mov	SCBPTR, WAITING_SCBH;
43524914Sgibbs	mov	WAITING_SCBH,SCB_NEXT;
43623925Sgibbs	mov	SAVED_TCL, SCB_TCL;
43739220Sgibbs	if ((ahc->flags & AHC_TARGETMODE) != 0) {
43839220Sgibbs		test	SSTAT0, TARGET	jz initiator_select;
4398567Sdg
44039220Sgibbs		/*
44139220Sgibbs		 * We've just re-selected an initiator.
44239220Sgibbs		 * Assert BSY and setup the phase for
44339220Sgibbs		 * sending our identify messages.
44439220Sgibbs		 */
44541646Sgibbs		mvi	P_MESGIN|BSYO call change_phase;
44641646Sgibbs		mvi	CLRSINT1,CLRBUSFREE;
4474568Sgibbs
44839220Sgibbs		/*
44939220Sgibbs		 * Start out with a simple identify message.
45039220Sgibbs		 */
45139220Sgibbs		and	A, LID, SCB_TCL;
45239220Sgibbs		or	A, MSG_IDENTIFYFLAG call target_outb;
4536608Sgibbs
45439220Sgibbs		/*
45539220Sgibbs		 * If we are the result of a tagged command, send
45639220Sgibbs		 * a simple Q tag and the tag id.
45739220Sgibbs		 */
45839220Sgibbs		test	SCB_CONTROL, TAG_ENB	jz . + 3;
45939220Sgibbs		mvi	MSG_SIMPLE_Q_TAG call target_outb;
46042652Sgibbs		mov	SCB_INITIATOR_TAG call target_outb;
46142652Sgibbs		mov	INITIATOR_TAG, SCB_INITIATOR_TAG;
46239220Sgibbstarget_synccmd:
46339220Sgibbs		/*
46439220Sgibbs		 * Now determine what phases the host wants us
46539220Sgibbs		 * to go through.
46639220Sgibbs		 */
46739220Sgibbs		mov	SEQ_FLAGS, SCB_TARGET_PHASES;
46842652Sgibbs		
46939220Sgibbs
47039220Sgibbstarget_ITloop:
47139220Sgibbs		/*
47241646Sgibbs		 * Start honoring ATN signals now that
47344507Sgibbs		 * we properly identified ourselves.
47439220Sgibbs		 */
47541646Sgibbs		test	SCSISIGI, ATNI			jnz target_mesgout;
47639220Sgibbs		test	SEQ_FLAGS, CMDPHASE_PENDING	jnz target_cmdphase;
47739220Sgibbs		test	SEQ_FLAGS, DPHASE_PENDING	jnz target_dphase;
47839220Sgibbs		test	SEQ_FLAGS, SPHASE_PENDING	jnz target_sphase;
47939220Sgibbs
48039220Sgibbs		/*
48139220Sgibbs		 * No more work to do.  Either disconnect or not depending
48239220Sgibbs		 * on the state of NO_DISCONNECT.
48339220Sgibbs		 */
48439220Sgibbs		test	SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 
48539220Sgibbs		if ((ahc->flags & AHC_PAGESCBS) != 0) {
48639220Sgibbs			mov	ALLZEROS	call	get_free_or_disc_scb;
48739220Sgibbs		}
48841646Sgibbs		mov	RETURN_1, ALLZEROS;
48939220Sgibbs		call	complete_target_cmd;
49041646Sgibbs		cmp	RETURN_1, CONT_MSG_LOOP jne .;
49139220Sgibbs		mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
49239220Sgibbs		mov	SCB_TAG	 call dma_scb;
49339220Sgibbs		jmp	target_synccmd;
49439220Sgibbs
49541646Sgibbstarget_mesgout:
49641646Sgibbs		mvi	SCSISIGO, P_MESGOUT|BSYO;
49741646Sgibbs		call	target_inb;
49841646Sgibbs		/* Local Processing goes here... */
49941646Sgibbstarget_mesgout_pending_msg:
50041646Sgibbs		jmp	host_target_message_loop;
50141646Sgibbs		
50239220Sgibbstarget_disconnect:
50341646Sgibbs		mvi	P_MESGIN|BSYO call change_phase;
50441816Sgibbs		test	SEQ_FLAGS, DPHASE	jz . + 2;
50541816Sgibbs		mvi	MSG_SAVEDATAPOINTER call target_outb;
50639220Sgibbs		mvi	MSG_DISCONNECT call target_outb;
50739220Sgibbs
50843880Sgibbstarget_busfree_wait:
50943880Sgibbs		/* Wait for preceeding I/O session to complete. */
51043880Sgibbs		test	SCSISIGI, ACKI jnz .;
51139220Sgibbstarget_busfree:
51239220Sgibbs		clr	SCSISIGO;
51339220Sgibbs		call	complete_target_cmd;
51439220Sgibbs		jmp	poll_for_work;
51539220Sgibbs
51639220Sgibbstarget_cmdphase:
51741646Sgibbs		mvi	P_COMMAND|BSYO call change_phase;
51841646Sgibbs		call	target_inb;
51939220Sgibbs		mov	A, DINDEX;
52039220Sgibbs		/* Store for host */
52139220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
52239220Sgibbs			mov	CCSCBRAM, A;
52339220Sgibbs		} else {
52439220Sgibbs			mov	DFDAT, A;
52539220Sgibbs		}
52639220Sgibbs
52739220Sgibbs		/*
52839220Sgibbs		 * Determine the number of bytes to read
52941299Sgibbs		 * based on the command group code via table lookup.
53041299Sgibbs		 * We reuse the first 8 bytes of the TARG_SCSIRATE
53141299Sgibbs		 * BIOS array for this table. Count is one less than
53241299Sgibbs		 * the total for the command since we've already fetched
53341299Sgibbs		 * the first byte.
53439220Sgibbs		 */
53539220Sgibbs		shr	A, CMD_GROUP_CODE_SHIFT;
53639220Sgibbs		add	SINDEX, TARG_SCSIRATE, A;
53739220Sgibbs		mov	A, SINDIR;
53839220Sgibbs
53939220Sgibbs		test	A, 0xFF jz command_phase_done;
54039220Sgibbscommand_loop:
54139220Sgibbs		or	SXFRCTL0, SPIOEN;
54239220Sgibbs		test	SSTAT0, SPIORDY jz .;
54339220Sgibbs		cmp	A, 1 jne . + 2;
54439220Sgibbs		and	SXFRCTL0, ~SPIOEN;	/* Last Byte */
54539220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
54639220Sgibbs			mov	CCSCBRAM, SCSIDATL;
54739220Sgibbs		} else {
54839220Sgibbs			mov	DFDAT, SCSIDATL;
54939220Sgibbs		}
55039220Sgibbs		dec	A;
55139220Sgibbs		test	A, 0xFF jnz command_loop;
55239220Sgibbs
55339220Sgibbscommand_phase_done:
55439220Sgibbs		and	SEQ_FLAGS, ~CMDPHASE_PENDING;
55539220Sgibbs		jmp	target_ITloop;
55639220Sgibbs
55739220Sgibbstarget_dphase:
55839220Sgibbs		/*
55939220Sgibbs		 * Data direction flags are from the
56039220Sgibbs		 * perspective of the initiator.
56139220Sgibbs		 */
56239220Sgibbs		test	SCB_TARGET_PHASES[1], TARGET_DATA_IN jz . + 4;
56339220Sgibbs		mvi	LASTPHASE, P_DATAOUT;
56441646Sgibbs		mvi	P_DATAIN|BSYO call change_phase;
56542652Sgibbs		jmp	. + 3;
56639220Sgibbs		mvi	LASTPHASE, P_DATAIN;
56741646Sgibbs		mvi	P_DATAOUT|BSYO call change_phase;
56842652Sgibbs		mov	ALLZEROS call initialize_channel;
56939220Sgibbs		jmp	p_data;
57039220Sgibbs
57139220Sgibbstarget_sphase:
57241646Sgibbs		mvi	P_STATUS|BSYO call change_phase;
57341646Sgibbs		mvi	LASTPHASE, P_STATUS;
57439220Sgibbs		mov	SCB_TARGET_STATUS call target_outb;
57541646Sgibbs		/* XXX Watch for ATN or parity errors??? */
57639220Sgibbs		mvi	SCSISIGO, P_MESGIN|BSYO;
57739220Sgibbs		/* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
57839220Sgibbs		mov	ALLZEROS call target_outb;
57943880Sgibbs		jmp	target_busfree_wait;
58039220Sgibbs	
58139220Sgibbscomplete_target_cmd:
58239220Sgibbs		test	SEQ_FLAGS, TARG_CMD_PENDING	jnz . + 2;
58339220Sgibbs		mov	SCB_TAG jmp complete_post;
58439220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
58541299Sgibbs			/* Set the valid byte */
58641299Sgibbs			mvi	CCSCBADDR, 24;
58741299Sgibbs			mov	CCSCBRAM, ALLONES;
58841299Sgibbs			mvi	CCHCNT, 28;
58939220Sgibbs			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
59039220Sgibbs			test	CCSCBCTL, CCSCBDONE jz .;
59139220Sgibbs			clr	CCSCBCTL;
59239220Sgibbs		} else {
59341299Sgibbs			/* Set the valid byte */
59441299Sgibbs			or	DFCNTRL, FIFORESET;
59541299Sgibbs			mvi	DFWADDR, 3; /* Third 64bit word or byte 24 */
59641299Sgibbs			mov	DFDAT, ALLONES;
59741299Sgibbs			mvi	HCNT[0], 28;
59841299Sgibbs			clr	HCNT[1];
59941299Sgibbs			clr	HCNT[2];
60039220Sgibbs			or	DFCNTRL, HDMAEN|FIFOFLUSH;
60139220Sgibbs			call	dma_finish;
60239220Sgibbs		}
60341299Sgibbs		inc	TQINPOS;
60441299Sgibbs		mvi	INTSTAT,CMDCMPLT ret;
60539220Sgibbs	}
60641646Sgibbs
60741646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) {
60839220Sgibbsinitiator_select:
60939220Sgibbs	mvi	SPIOEN call	initialize_channel;
61041646Sgibbs
61141646Sgibbs	/*
61241646Sgibbs	 * We aren't expecting a bus free, so interrupt
61341646Sgibbs	 * the kernel driver if it happens.
61441646Sgibbs	 */
61525005Sgibbs	mvi	CLRSINT1,CLRBUSFREE;
61639220Sgibbs	or	SIMODE1, ENBUSFREE;
61741646Sgibbs
61841646Sgibbs	/*
61941646Sgibbs	 * As soon as we get a successful selection, the target
62041646Sgibbs	 * should go into the message out phase since we have ATN
62141646Sgibbs	 * asserted.
62241646Sgibbs	 */
62339220Sgibbs	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
62439220Sgibbs	or	SEQ_FLAGS, IDENTIFY_SEEN;
62513177Sgibbs
62641646Sgibbs	/*
62741646Sgibbs	 * Main loop for information transfer phases.  Wait for the
62841646Sgibbs	 * target to assert REQ before checking MSG, C/D and I/O for
62941646Sgibbs	 * the bus phase.
63041646Sgibbs	 */
6314568SgibbsITloop:
63239220Sgibbs	call	phase_lock;
6334568Sgibbs
63439220Sgibbs	mov	A, LASTPHASE;
6354568Sgibbs
63639220Sgibbs	test	A, ~P_DATAIN	jz p_data;
63723925Sgibbs	cmp	A,P_COMMAND	je p_command;
63823925Sgibbs	cmp	A,P_MESGOUT	je p_mesgout;
63923925Sgibbs	cmp	A,P_STATUS	je p_status;
64023925Sgibbs	cmp	A,P_MESGIN	je p_mesgin;
6414568Sgibbs
64241646Sgibbs	mvi	INTSTAT,BAD_PHASE;
64323925Sgibbs	jmp	ITloop;			/* Try reading the bus again. */
6444568Sgibbs
64523925Sgibbsawait_busfree:
64623925Sgibbs	and	SIMODE1, ~ENBUSFREE;
64723925Sgibbs	mov	NONE, SCSIDATL;		/* Ack the last byte */
64839220Sgibbs	and	SXFRCTL0, ~SPIOEN;
64923925Sgibbs	test	SSTAT1,REQINIT|BUSFREE	jz .;
65023925Sgibbs	test	SSTAT1, BUSFREE jnz poll_for_work;
65123925Sgibbs	mvi	INTSTAT, BAD_PHASE;
65241646Sgibbs}
65323925Sgibbs	
65423925Sgibbsclear_target_state:
65541646Sgibbs	/*
65641646Sgibbs	 * We assume that the kernel driver may reset us
65741646Sgibbs	 * at any time, even in the middle of a DMA, so
65841646Sgibbs	 * clear DFCNTRL too.
65941646Sgibbs	 */
66041646Sgibbs	clr	DFCNTRL;
66141646Sgibbs
66241646Sgibbs	/*
66341646Sgibbs	 * We don't know the target we will connect to,
66441646Sgibbs	 * so default to narrow transfers to avoid
66541646Sgibbs	 * parity problems.
66641646Sgibbs	 */
66741646Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
66841646Sgibbs		bmov	SCSIRATE, ALLZEROS, 2;
66941646Sgibbs	} else {
67041646Sgibbs		clr	SCSIRATE;
67141646Sgibbs		and	SXFRCTL0, ~(FAST20);
67241646Sgibbs	}
67323925Sgibbs	mvi	LASTPHASE, P_BUSFREE;
67423925Sgibbs	/* clear target specific flags */
67539220Sgibbs	clr	SEQ_FLAGS ret;
67623925Sgibbs
67713177Sgibbs/*
67813177Sgibbs * If we re-enter the data phase after going through another phase, the
67913177Sgibbs * STCNT may have been cleared, so restore it from the residual field.
68013177Sgibbs */
6819928Sgibbsdata_phase_reinit:
68239220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
68339220Sgibbs		bmov	STCNT, SCB_RESID_DCNT, 3;
68439220Sgibbs	} else {
68539220Sgibbs		mvi	DINDEX, STCNT;
68639220Sgibbs		mvi	SCB_RESID_DCNT	call bcopy_3;
68739220Sgibbs	}
68842652Sgibbs	and	DATA_COUNT_ODD, 0x1, SCB_RESID_DCNT[0];
68923925Sgibbs	jmp	data_phase_loop;
6904568Sgibbs
69139220Sgibbsp_data:
69239220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
69339220Sgibbs		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
69439220Sgibbs	} else {
69539220Sgibbs		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
69639220Sgibbs	}
69739220Sgibbs	test	LASTPHASE, IOI jnz . + 2;
69839220Sgibbs	or	DMAPARAMS, DIRECTION;
69923925Sgibbs	call	assert;			/*
70019164Sgibbs					 * Ensure entering a data
70119164Sgibbs					 * phase is okay - seen identify, etc.
70219164Sgibbs					 */
70339220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
70439220Sgibbs		mvi	CCSGADDR, CCSGADDR_MAX;
70539220Sgibbs	}
70623925Sgibbs	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
7074568Sgibbs
70839220Sgibbs	/* We have seen a data phase */
70939220Sgibbs	or	SEQ_FLAGS, DPHASE;
71039220Sgibbs
71119164Sgibbs	/*
71219164Sgibbs	 * Initialize the DMA address and counter from the SCB.
71319164Sgibbs	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
71419164Sgibbs	 * modify the values in the SCB itself until we see a
71519164Sgibbs	 * save data pointers message.
71619164Sgibbs	 */
71739220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
71839220Sgibbs		bmov	HADDR, SCB_DATAPTR, 7;
71939220Sgibbs	} else {
72039220Sgibbs		mvi	DINDEX, HADDR;
72139220Sgibbs		mvi	SCB_DATAPTR	call bcopy_7;
72239220Sgibbs	}
72342652Sgibbs	and	DATA_COUNT_ODD, 0x1, SCB_DATACNT[0];
72419164Sgibbs
72539220Sgibbs	if ((ahc->features & AHC_ULTRA2) == 0) {
72639220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
72739220Sgibbs			bmov	STCNT, HCNT, 3;
72839220Sgibbs		} else {
72939220Sgibbs			call	set_stcnt_from_hcnt;
73039220Sgibbs		}
73139220Sgibbs	}
73219164Sgibbs
73339220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
73439220Sgibbs		bmov	SG_COUNT, SCB_SGCOUNT, 5;
73539220Sgibbs	} else {
73639220Sgibbs		mvi	DINDEX, SG_COUNT;
73739220Sgibbs		mvi	SCB_SGCOUNT	call bcopy_5;
73839220Sgibbs	}
73919164Sgibbs
7409928Sgibbsdata_phase_loop:
74116260Sgibbs/* Guard against overruns */
74223925Sgibbs	test	SG_COUNT, 0xff jnz data_phase_inbounds;
74316260Sgibbs/*
74416260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to
74516260Sgibbs * 16meg and let the target run until it changes phase.
74616260Sgibbs * When the transfer completes, notify the host that we
74716260Sgibbs * had an overrun.
74816260Sgibbs */
74923925Sgibbs	or	SXFRCTL1,BITBUCKET;
75039220Sgibbs	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
75139220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
75239220Sgibbs		bmov	HCNT, ALLONES, 3;
75339220Sgibbs	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
75439220Sgibbs		bmov	STCNT, ALLONES, 3;
75539220Sgibbs	} else {
75639220Sgibbs		mvi	STCNT[0], 0xFF;
75739220Sgibbs		mvi	STCNT[1], 0xFF;
75839220Sgibbs		mvi	STCNT[2], 0xFF;
75939220Sgibbs	}
76016260Sgibbsdata_phase_inbounds:
76139220Sgibbs/* If we are the last SG block, tell the hardware. */
76223925Sgibbs	cmp	SG_COUNT,0x01 jne data_phase_wideodd;
76339220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
76439220Sgibbs		or	SG_CACHEPTR, LAST_SEG;
76539220Sgibbs	} else {
76639220Sgibbs		and	DMAPARAMS, ~WIDEODD;
76739220Sgibbs	}
7689928Sgibbsdata_phase_wideodd:
76939220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
77039220Sgibbs		mov	SINDEX, ALLONES;
77139220Sgibbs		mov	DFCNTRL, DMAPARAMS;
77239220Sgibbs		test	SSTAT0, SDONE jnz .;/* Wait for preload to complete */
77339220Sgibbsdata_phase_dma_loop:
77439220Sgibbs		test	SSTAT0,	SDONE jnz data_phase_dma_done;
77539220Sgibbs		test	SSTAT1,PHASEMIS	jz data_phase_dma_loop;	/* ie. underrun */
77639220Sgibbsdata_phase_dma_phasemis:
77739220Sgibbs		test	SSTAT0,SDONE	jnz . + 2;
77839220Sgibbs		mov	SINDEX,ALLZEROS;	/* Remeber the phasemiss */
77939220Sgibbs	} else {
78039220Sgibbs		mov	DMAPARAMS  call dma;
78139220Sgibbs	}
7824568Sgibbs
78339220Sgibbsdata_phase_dma_done:
78416260Sgibbs/* Go tell the host about any overruns */
78523925Sgibbs	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
78616260Sgibbs
78722451Sgibbs/* Exit if we had an underrun.  dma clears SINDEX in this case. */
78823925Sgibbs	test	SINDEX,0xff	jz data_phase_finish;
7897532Sgibbs
79013177Sgibbs/*
79113177Sgibbs * Advance the scatter-gather pointers if needed 
79213177Sgibbs */
7939928Sgibbssg_advance:
79423925Sgibbs	dec	SG_COUNT;	/* one less segment to go */
7954568Sgibbs
79623925Sgibbs	test	SG_COUNT, 0xff	jz data_phase_finish; /* Are we done? */
79713177Sgibbs/*
79813177Sgibbs * Load a struct scatter and set up the data address and length.
79913177Sgibbs * If the working value of the SG count is nonzero, then
80013177Sgibbs * we need to load a new set of values.
80113177Sgibbs *
80215328Sgibbs * This, like all DMA's, assumes little-endian host data storage.
80313177Sgibbs */
8049928Sgibbssg_load:
80539220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
80639220Sgibbs		/*
80739220Sgibbs		 * Do we have any prefetch left???
80839220Sgibbs		 */
80939220Sgibbs		cmp	CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
8104568Sgibbs
81139220Sgibbs		/*
81239220Sgibbs		 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
81339220Sgibbs		 */
81439220Sgibbs		add	A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
81539220Sgibbs		mvi	A, CCSGADDR_MAX;
81639220Sgibbs		jc	. + 2;
81739220Sgibbs		shl	A, 3, SG_COUNT;
81839220Sgibbs		mov	CCHCNT, A;
81939220Sgibbs		bmov	CCHADDR, SG_NEXT, 4;
82039220Sgibbs		mvi	CCSGCTL, CCSGEN|CCSGRESET;
82139220Sgibbs		test	CCSGCTL, CCSGDONE jz .;
82239220Sgibbs		and	CCSGCTL, ~CCSGEN;
82339220Sgibbs		test	CCSGCTL, CCSGEN jnz .;
82439220Sgibbs		mvi	CCSGCTL, CCSGRESET;
82539220Sgibbsprefetched_segs_avail:
82639220Sgibbs		bmov 	HADDR, CCSGRAM, 8;
82739220Sgibbs	} else {
82839220Sgibbs		mvi	DINDEX, HADDR;
82939220Sgibbs		mvi	SG_NEXT	call bcopy_4;
83022568Sgibbs
83139220Sgibbs		mvi	HCNT[0],SG_SIZEOF;
83239220Sgibbs		clr	HCNT[1];
83339220Sgibbs		clr	HCNT[2];
8349928Sgibbs
83539220Sgibbs		or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
8369928Sgibbs
83739220Sgibbs		call	dma_finish;
8389928Sgibbs
83939220Sgibbs		/*
84039220Sgibbs		 * Copy data from FIFO into SCB data pointer and data count.
84139220Sgibbs		 * This assumes that the SG segments are of the form:
84239220Sgibbs		 * struct ahc_dma_seg {
84339220Sgibbs		 *	u_int32_t	addr;	four bytes, little-endian order
84439220Sgibbs		 *	u_int32_t	len;	four bytes, little endian order
84539220Sgibbs		 * };
84639220Sgibbs		 */
84739220Sgibbs		mvi	HADDR	call dfdat_in_7;
84839220Sgibbs	}
84939220Sgibbs
85042652Sgibbs	/* Track odd'ness */
85142652Sgibbs	test	HCNT[0], 0x1 jz . + 2;
85242652Sgibbs	xor	DATA_COUNT_ODD, 0x1;
85342652Sgibbs
85439220Sgibbs	if ((ahc->features & AHC_ULTRA2) == 0) {
85539220Sgibbs		/* Load STCNT as well.  It is a mirror of HCNT */
85639220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) != 0) {
85739220Sgibbs			bmov	STCNT, HCNT, 3;
85839220Sgibbs		} else {
85939220Sgibbs			call	set_stcnt_from_hcnt;
86039220Sgibbs		}
86139220Sgibbs	}
86239220Sgibbs
86339220Sgibbs/* Advance the SG pointer */
86439220Sgibbs	clr	A;			/* add sizeof(struct scatter) */
86539220Sgibbs	add	SG_NEXT[0],SG_SIZEOF;
86639220Sgibbs	adc	SG_NEXT[1],A;
86739220Sgibbs
86841646Sgibbs	if ((ahc->flags & AHC_TARGETMODE) != 0) {
86941646Sgibbs		test	SSTAT0, TARGET jnz data_phase_loop;
87041646Sgibbs	}
87141646Sgibbs	test	SSTAT1, REQINIT jz .;
87223925Sgibbs	test	SSTAT1,PHASEMIS	jz data_phase_loop;
87341646Sgibbs
87439220Sgibbs	/* Ensure the last seg is visable at the shaddow layer */
87539220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
87639220Sgibbs		or	DFCNTRL, PRELOADEN;
87739220Sgibbs	}
8784568Sgibbs
8799928Sgibbsdata_phase_finish:
88039220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
88139220Sgibbs		call	ultra2_dmafinish;
88239220Sgibbs	}
88313177Sgibbs/*
88413177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB
88513177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
88613177Sgibbs * were transferred on the SCSI (as opposed to the host) bus.
88713177Sgibbs */
88839220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
88939220Sgibbs		bmov	SCB_RESID_DCNT, STCNT, 3;
89039220Sgibbs	} else {
89139220Sgibbs		mov	SCB_RESID_DCNT[0],STCNT[0];
89239220Sgibbs		mov	SCB_RESID_DCNT[1],STCNT[1];
89339220Sgibbs		mov	SCB_RESID_DCNT[2],STCNT[2];
89439220Sgibbs	}
89523925Sgibbs	mov	SCB_RESID_SGCNT, SG_COUNT;
89622568Sgibbs
89739220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
89839220Sgibbs		or	SXFRCTL0, CLRSTCNT|CLRCHN;
89939220Sgibbs	}
90022568Sgibbs
90139220Sgibbs	if ((ahc->flags & AHC_TARGETMODE) != 0) {
90241646Sgibbs		test	SEQ_FLAGS, DPHASE_PENDING jz ITloop;
90339220Sgibbs		and	SEQ_FLAGS, ~DPHASE_PENDING;
90442652Sgibbs		/*
90542652Sgibbs		 * For data-in phases, wait for any pending acks from the
90642652Sgibbs		 * initiator before changing phase.
90742652Sgibbs		 */
90842652Sgibbs		test	DFCNTRL, DIRECTION jz target_ITloop;
90942652Sgibbs		test	SSTAT1, REQINIT	jnz .;
91039220Sgibbs		jmp	target_ITloop;
91139220Sgibbs	}
91223925Sgibbs	jmp	ITloop;
9134568Sgibbs
91416260Sgibbsdata_phase_overrun:
91539220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
91639220Sgibbs		call	ultra2_dmafinish;
91739220Sgibbs		or	SXFRCTL0, CLRSTCNT|CLRCHN;
91839220Sgibbs	}
91913177Sgibbs/*
92016260Sgibbs * Turn off BITBUCKET mode and notify the host
92116260Sgibbs */
92223925Sgibbs	and	SXFRCTL1, ~BITBUCKET;
92323925Sgibbs	mvi	INTSTAT,DATA_OVERRUN;
92423925Sgibbs	jmp	ITloop;
92516260Sgibbs
92639220Sgibbsultra2_dmafinish:
92739220Sgibbs	if ((ahc->features & AHC_ULTRA2) != 0) {
92839220Sgibbs		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
92939220Sgibbs		and	DFCNTRL, ~SCSIEN;
93039220Sgibbs		test	DFCNTRL, SCSIEN jnz .;
93139220Sgibbs		or	DFCNTRL, FIFOFLUSH;
93239220Sgibbs		test	DFSTATUS, FIFOEMP jz . - 1;
93339220Sgibbsultra2_dmahalt:
93439220Sgibbs		and     DFCNTRL, ~(SCSIEN|HDMAEN);
93539220Sgibbs		test	DFCNTRL, HDMAEN jnz .;
93639220Sgibbs		ret;
93739220Sgibbs	}
93839220Sgibbs
93941646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) {
94016260Sgibbs/*
94115328Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
94213177Sgibbs */
9434568Sgibbsp_command:
94423925Sgibbs	call	assert;
9454568Sgibbs
94639220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
94739220Sgibbs		mov	HCNT[0], SCB_CMDLEN;
94839220Sgibbs		bmov	HCNT[1], ALLZEROS, 2;
94939220Sgibbs		if ((ahc->features & AHC_ULTRA2) == 0) {
95039220Sgibbs			bmov	STCNT, HCNT, 3;
95139220Sgibbs		}
95239220Sgibbs		add	NONE, -17, SCB_CMDLEN;
95339220Sgibbs		jc	dma_cmd_data;
95439220Sgibbs		if ((ahc->features & AHC_ULTRA2) != 0) {
95539220Sgibbs			mvi	DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
95639220Sgibbs		} else {
95739220Sgibbs			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
95839220Sgibbs		}
95939220Sgibbs		bmov   DFDAT, SCB_CMDSTORE, 16; 
96039220Sgibbs		jmp	cmd_loop;
96139220Sgibbsdma_cmd_data:
96239220Sgibbs		bmov	HADDR, SCB_CMDPTR, 4;
96339220Sgibbs	} else {
96439220Sgibbs		mvi	DINDEX, HADDR;
96539220Sgibbs		mvi	SCB_CMDPTR	call bcopy_5;
96639220Sgibbs		clr	HCNT[1];
96739220Sgibbs		clr	HCNT[2];
96839220Sgibbs	}
9694568Sgibbs
97039220Sgibbs	if ((ahc->features & AHC_ULTRA2) == 0) {
97139220Sgibbs		if ((ahc->features & AHC_CMD_CHAN) == 0) {
97239220Sgibbs			call	set_stcnt_from_hcnt;
97339220Sgibbs		}
97439220Sgibbs		mvi	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
97539220Sgibbs	} else {
97639220Sgibbs		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
97739220Sgibbs	}
97839220Sgibbscmd_loop:
97939220Sgibbs	test	SSTAT0, SDONE jnz . + 2;
98039220Sgibbs	test    SSTAT1, PHASEMIS jz cmd_loop;
98139220Sgibbs	and	DFCNTRL, ~(SCSIEN|HDMAEN|SDMAEN);
98239220Sgibbs	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
98323925Sgibbs	jmp	ITloop;
9844568Sgibbs
98513177Sgibbs/*
98613177Sgibbs * Status phase.  Wait for the data byte to appear, then read it
98713177Sgibbs * and store it into the SCB.
98813177Sgibbs */
9894568Sgibbsp_status:
99023925Sgibbs	call	assert;
99119803Sgibbs
99223925Sgibbs	mov	SCB_TARGET_STATUS, SCSIDATL;
99323925Sgibbs	jmp	ITloop;
9944568Sgibbs
99513177Sgibbs/*
99641646Sgibbs * Message out phase.  If MSG_OUT is MSG_IDENTIFYFLAG, build a full
99741646Sgibbs * indentify message sequence and send it to the target.  The host may
99841646Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB
99941646Sgibbs * control byte.  This will cause us to interrupt the host and allow
100041646Sgibbs * it to handle the message phase completely on its own.  If the bit
100141646Sgibbs * associated with this target is set, we will also interrupt the host,
100241646Sgibbs * thereby allowing it to send a message on the next selection regardless
100341646Sgibbs * of the transaction being sent.
100439220Sgibbs * 
100539220Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
100641646Sgibbs * This is done to allow the host to send messages outside of an identify
100739220Sgibbs * sequence while protecting the seqencer from testing the MK_MESSAGE bit
100839220Sgibbs * on an SCB that might not be for the current nexus. (For example, a
100939220Sgibbs * BDR message in responce to a bad reselection would leave us pointed to
101039220Sgibbs * an SCB that doesn't have anything to do with the current target).
101141646Sgibbs *
101239220Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
101339220Sgibbs * bus device reset).
101439220Sgibbs *
101539220Sgibbs * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
101639220Sgibbs * in case the target decides to put us in this phase for some strange
101739220Sgibbs * reason.
101813177Sgibbs */
101941646Sgibbsp_mesgout_retry:
102041646Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
10214568Sgibbsp_mesgout:
102239220Sgibbs	mov	SINDEX, MSG_OUT;
102339220Sgibbs	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
102441646Sgibbs	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
102541646Sgibbs	mov	FUNCTION1, SCB_TCL;
102641646Sgibbs	mov	A, FUNCTION1;
102741646Sgibbs	mov	SINDEX, TARGET_MSG_REQUEST[0];
102847158Sgibbs	if ((ahc->features & AHC_HS_MAILBOX) != 0) {
102947158Sgibbs		/*
103047158Sgibbs		 * Work around a pausing bug in at least the aic7890.
103147158Sgibbs		 * If the host needs to update the TARGET_MSG_REQUEST
103247158Sgibbs		 * bit field, it will set the HS_MAILBOX to 1.  In
103347158Sgibbs		 * response, we pause with a specific interrupt code
103447158Sgibbs		 * asking for the mask to be updated before we continue.
103547158Sgibbs		 * Ugh.
103647158Sgibbs		 */
103747158Sgibbs		test	HS_MAILBOX, 0xF0	jz . + 2;
103847158Sgibbs		mvi	INTSTAT, UPDATE_TMSG_REQ;
103947158Sgibbs	}
104041646Sgibbs	if ((ahc->features & AHC_TWIN) != 0) {
104141646Sgibbs		/* Second Channel uses high byte bits */
104241646Sgibbs		test	SCB_TCL, SELBUSB	jz . + 2;
104341646Sgibbs		mov	SINDEX, TARGET_MSG_REQUEST[1];
104441646Sgibbs	} else if ((ahc->features & AHC_WIDE) != 0) {
104541646Sgibbs		test	SCB_TCL, 0x80		jz . + 2; /* target > 7 */
104641646Sgibbs		mov	SINDEX, TARGET_MSG_REQUEST[1];
104741646Sgibbs	}
104841646Sgibbs	test	SINDEX, A	jnz host_message_loop;
104939220Sgibbsp_mesgout_identify:
105041299Sgibbs	and	SINDEX,LID,SCB_TCL;	/* lun */
105139220Sgibbs	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
105239220Sgibbs	or	SINDEX,A;		/* or in disconnect privledge */
105339220Sgibbs	or	SINDEX,MSG_IDENTIFYFLAG;
105413177Sgibbs/*
105539220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
105639220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
105713177Sgibbs */
105839220Sgibbsp_mesgout_tag:
105939220Sgibbs	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
106039220Sgibbs	mov	SCSIDATL, SINDEX;	/* Send the identify message */
106139220Sgibbs	call	phase_lock;
106239220Sgibbs	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
106339220Sgibbs	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
106439220Sgibbs	call	phase_lock;
106539220Sgibbs	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
106639220Sgibbs	mov	SCB_TAG	jmp p_mesgout_onebyte;
106713177Sgibbs/*
106841646Sgibbs * Interrupt the driver, and allow it to handle this message
106941646Sgibbs * phase and any required retries.
107013177Sgibbs */
107139220Sgibbsp_mesgout_from_host:
107239220Sgibbs	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
107341646Sgibbs	jmp	host_message_loop;
107439220Sgibbs
107539220Sgibbsp_mesgout_onebyte:
107639220Sgibbs	mvi	CLRSINT1, CLRATNO;
107739220Sgibbs	mov	SCSIDATL, SINDEX;
107839220Sgibbs
107913177Sgibbs/*
108041646Sgibbs * If the next bus phase after ATN drops is message out, it means
108113177Sgibbs * that the target is requesting that the last message(s) be resent.
108213177Sgibbs */
108339220Sgibbs	call	phase_lock;
108441646Sgibbs	cmp	LASTPHASE, P_MESGOUT	je p_mesgout_retry;
10854568Sgibbs
108619906Sgibbsp_mesgout_done:
108723925Sgibbs	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
108839220Sgibbs	mov	LAST_MSG, MSG_OUT;
108939220Sgibbs	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
109023925Sgibbs	jmp	ITloop;
10914568Sgibbs
109213177Sgibbs/*
109313177Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
109413177Sgibbs */
10954568Sgibbsp_mesgin:
109623925Sgibbs	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
10974568Sgibbs
109823925Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
109923925Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
110023925Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
110123925Sgibbs	cmp	ALLZEROS,A		je mesgin_complete;
110223925Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
110323925Sgibbs	cmp	A,MSG_NOOP		je mesgin_done;
11044568Sgibbs
110513177Sgibbs/*
110641887Sgibbs * Pushed message loop to allow the kernel to
110741887Sgibbs * RUN IT's own message state engine.  To avoid an
110841887Sgibbs * extra nop instruction after signaling the kernel,
110941887Sgibbs * we perform the phase_lock before checking to see
111041887Sgibbs * if we should exit the loop and skip the phase_lock
111141887Sgibbs * in the ITloop.  Performing back to back phase_locks
111241887Sgibbs * shouldn't hurt, but why do it twice...
111313177Sgibbs */
111441887Sgibbshost_message_loop:
111541887Sgibbs	mvi	INTSTAT, HOST_MSG_LOOP;
111641887Sgibbs	call	phase_lock;
111741887Sgibbs	cmp	RETURN_1, EXIT_MSG_LOOP	je ITloop + 1;
111841887Sgibbs	jmp	host_message_loop;
11199954Sgibbs
11209954Sgibbsmesgin_done:
112123925Sgibbs	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
112223925Sgibbs	jmp	ITloop;
11239954Sgibbs
11249954Sgibbs
11259954Sgibbsmesgin_complete:
112613177Sgibbs/*
112719164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
112819164Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
112939220Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0).
113039220Sgibbs * In either of these conditions, we upload the SCB back to the host so it can
113119164Sgibbs * process this information.  In the case of a non zero status byte, we 
113219164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
113319164Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
113419164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set
113519164Sgibbs * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
113619164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list.
113719164Sgibbs * If the kernel driver does not wish to request sense, it need only clear
113819164Sgibbs * RETURN_1, and the command is allowed to complete normally.  We don't bother
113919164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra
114019164Sgibbs * work in the kernel driver to ensure that the entry was removed before the
114119164Sgibbs * command complete code tried processing it.
114213177Sgibbs */
114319164Sgibbs
114413177Sgibbs/*
114519164Sgibbs * First check for residuals
114613177Sgibbs */
114723925Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz upload_scb;
114839220Sgibbs	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Good Status? */
114919164Sgibbsupload_scb:
115023925Sgibbs	mvi	DMAPARAMS, FIFORESET;
115123925Sgibbs	mov	SCB_TAG		call dma_scb;
11527532Sgibbscheck_status:
115339220Sgibbs	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Just a residual? */
115423925Sgibbs	mvi	INTSTAT,BAD_STATUS;			/* let driver know */
115539220Sgibbs	nop;
115639220Sgibbs	cmp	RETURN_1, SEND_SENSE	jne complete;
115719164Sgibbs	/* This SCB becomes the next to execute as it will retrieve sense */
115823925Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
115939220Sgibbs	mov	SCB_TAG		call dma_scb;
116019164Sgibbsadd_to_waiting_list:
116123925Sgibbs	mov	SCB_NEXT,WAITING_SCBH;
116223925Sgibbs	mov	WAITING_SCBH, SCBPTR;
116323925Sgibbs	/*
116423925Sgibbs	 * Prepare our selection hardware before the busfree so we have a
116523925Sgibbs	 * high probability of winning arbitration.
116623925Sgibbs	 */
116723925Sgibbs	call	start_selection;
116823925Sgibbs	jmp	await_busfree;
116939220Sgibbs
117039220Sgibbscomplete:
117139220Sgibbs	/* If we are untagged, clear our address up in host ram */
117239220Sgibbs	test	SCB_CONTROL, TAG_ENB jnz complete_queue;
117339220Sgibbs	mov	A, SAVED_TCL;
117439220Sgibbs	mvi	UNTAGGEDSCB_OFFSET call post_byte_setup;
117539220Sgibbs	mvi	SCB_LIST_NULL call post_byte;
117639220Sgibbs
117739220Sgibbscomplete_queue:
117839220Sgibbs	mov	SCB_TAG call complete_post;
117923925Sgibbs	jmp	await_busfree;
118041646Sgibbs}
11814568Sgibbs
118239220Sgibbscomplete_post:
118339220Sgibbs	/* Post the SCBID in SINDEX and issue an interrupt */
118444507Sgibbs	call	add_scb_to_free_list;
118539220Sgibbs	mov	ARG_1, SINDEX;
118639220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
118739220Sgibbs		mov	A, SDSCB_QOFF;
118839220Sgibbs	} else {
118939220Sgibbs		mov	A, QOUTPOS;
119039220Sgibbs	}
119139220Sgibbs	mvi	QOUTFIFO_OFFSET call post_byte_setup;
119239220Sgibbs	mov	ARG_1 call post_byte;
119339220Sgibbs	if ((ahc->features & AHC_QUEUE_REGS) == 0) {
119439220Sgibbs		inc 	QOUTPOS;
119539220Sgibbs	}
119639220Sgibbs	mvi	INTSTAT,CMDCMPLT ret;
119739220Sgibbs
119841646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) {
119913177Sgibbs/*
120013177Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
120113177Sgibbs * and await the bus going free.
120213177Sgibbs */
12039954Sgibbsmesgin_disconnect:
120423925Sgibbs	or	SCB_CONTROL,DISCONNECTED;
120523925Sgibbs	call	add_scb_to_disc_list;
120623925Sgibbs	jmp	await_busfree;
120719164Sgibbs
120815328Sgibbs/*
120919164Sgibbs * Save data pointers message:
121019164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
121119164Sgibbs * only if we've actually been into a data phase to change them.  This
121219164Sgibbs * protects against bogus data in scratch ram and the residual counts
121319164Sgibbs * since they are only initialized when we go into data_in or data_out.
121415328Sgibbs */
121519164Sgibbsmesgin_sdptrs:
121623925Sgibbs	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
12174568Sgibbs
121839220Sgibbs	/*
121939220Sgibbs	 * The SCB SGPTR becomes the next one we'll download,
122039220Sgibbs	 * and the SCB DATAPTR becomes the current SHADDR.
122139220Sgibbs	 * Use the residual number since STCNT is corrupted by
122239220Sgibbs	 * any message transfer.
122339220Sgibbs	 */
122439220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
122539220Sgibbs		bmov	SCB_SGCOUNT, SG_COUNT, 5;
122639220Sgibbs		bmov	SCB_DATAPTR, SHADDR, 4;
122739220Sgibbs		bmov	SCB_DATACNT, SCB_RESID_DCNT, 3;
122839220Sgibbs	} else {
122939220Sgibbs		mvi	DINDEX, SCB_SGCOUNT;
123039220Sgibbs		mvi	SG_COUNT call bcopy_5;
123119164Sgibbs	
123239220Sgibbs		mvi	DINDEX, SCB_DATAPTR;
123339220Sgibbs		mvi	SHADDR		call bcopy_4;
123439220Sgibbs		mvi	SCB_RESID_DCNT	call bcopy_3;
123539220Sgibbs	}
123623925Sgibbs	jmp	mesgin_done;
12374568Sgibbs
123813177Sgibbs/*
123913177Sgibbs * Restore pointers message?  Data pointers are recopied from the
124013177Sgibbs * SCB anytime we enter a data phase for the first time, so all
124113177Sgibbs * we need to do is clear the DPHASE flag and let the data phase
124213177Sgibbs * code do the rest.
124313177Sgibbs */
12449954Sgibbsmesgin_rdptrs:
124523925Sgibbs	and	SEQ_FLAGS, ~DPHASE;		/*
124623925Sgibbs						 * We'll reload them
124713177Sgibbs						 * the next time through
124823925Sgibbs						 * the dataphase.
124913177Sgibbs						 */
125023925Sgibbs	jmp	mesgin_done;
12514568Sgibbs
125213177Sgibbs/*
125313177Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
125413177Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
125513177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
125613177Sgibbs */
12579954Sgibbsmesgin_identify:
125839220Sgibbs	
125939220Sgibbs	if ((ahc->features & AHC_WIDE) != 0) {
126039220Sgibbs		and	A,0x0f;		/* lun in lower four bits */
126139220Sgibbs	} else {
126239220Sgibbs		and	A,0x07;		/* lun in lower three bits */
126339220Sgibbs	}
126423925Sgibbs	or      SAVED_TCL,A;		/* SAVED_TCL should be complete now */
126539220Sgibbs
126639220Sgibbs	mvi	ARG_2, SCB_LIST_NULL;	/* SCBID of prev SCB in disc List */
126739220Sgibbs	call	get_untagged_SCBID;
126839220Sgibbs	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
126939220Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
127039220Sgibbs		test	SEQ_FLAGS, SCBPTR_VALID	jz use_retrieveSCB;
127139220Sgibbs	}
127239220Sgibbs	/*
127339220Sgibbs	 * If the SCB was found in the disconnected list (as is
127439220Sgibbs	 * always the case in non-paging scenarios), SCBPTR is already
127539220Sgibbs	 * set to the correct SCB.  So, simply setup the SCB and get
127639220Sgibbs	 * on with things.
127739220Sgibbs	 */
127839220Sgibbs	call	rem_scb_from_disc_list;
127924608Sgibbs	jmp	setup_SCB;
128013177Sgibbs/*
128113177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
128223168Sgibbs * If we get one, we use the tag returned to find the proper
128339220Sgibbs * SCB.  With SCB paging, this requires using search for both tagged
128415328Sgibbs * and non-tagged transactions since the SCB may exist in any slot.
128515328Sgibbs * If we're not using SCB paging, we can use the tag as the direct
128615328Sgibbs * index to the SCB.
128713177Sgibbs */
128824608Sgibbssnoop_tag:
128923925Sgibbs	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
129013177Sgibbssnoop_tag_loop:
129139220Sgibbs	call	phase_lock;
129223925Sgibbs	cmp	LASTPHASE, P_MESGIN	jne not_found;
129323925Sgibbs	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
12946608Sgibbsget_tag:
129523925Sgibbs	mvi	ARG_1	call inb_next;	/* tag value */
129613177Sgibbs
129739220Sgibbs	/*
129839220Sgibbs	 * Ensure that the SCB the tag points to is for
129939220Sgibbs	 * an SCB transaction to the reconnecting target.
130039220Sgibbs	 */
130139220Sgibbsuse_retrieveSCB:
130239220Sgibbs	call	retrieveSCB;
130339220Sgibbssetup_SCB:
130424608Sgibbs	mov	A, SAVED_TCL;
130539220Sgibbs	cmp	SCB_TCL, A	jne not_found_cleanup_scb;
130639220Sgibbs	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
130723925Sgibbs	and	SCB_CONTROL,~DISCONNECTED;
130823925Sgibbs	or	SEQ_FLAGS,IDENTIFY_SEEN;	  /* make note of IDENTIFY */
130939220Sgibbs	call	set_transfer_settings;
131039220Sgibbs	/* See if the host wants to send a message upon reconnection */
131139220Sgibbs	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
131239220Sgibbs	and	SCB_CONTROL, ~MK_MESSAGE;
131339220Sgibbs	mvi	HOST_MSG	call mk_mesg;
131423925Sgibbs	jmp	mesgin_done;
131515328Sgibbs
131639220Sgibbsnot_found_cleanup_scb:
131739220Sgibbs	test	SCB_CONTROL, DISCONNECTED jz . + 3;
131839220Sgibbs	call	add_scb_to_disc_list;
131939220Sgibbs	jmp	not_found;
132039220Sgibbs	call	add_scb_to_free_list;
132119218Sgibbsnot_found:
132223925Sgibbs	mvi	INTSTAT, NO_MATCH;
132323925Sgibbs	jmp	mesgin_done;
13246608Sgibbs
132513177Sgibbs/*
132613177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ]
132713177Sgibbs */
13284568Sgibbs
132913177Sgibbs/*
133013177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX
133113177Sgibbs * if there is no active message already.  SINDEX is returned intact.
133213177Sgibbs */
13334568Sgibbsmk_mesg:
133423925Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
133539220Sgibbs	mov	MSG_OUT,SINDEX ret;
13364568Sgibbs
133713177Sgibbs/*
133813177Sgibbs * Functions to read data in Automatic PIO mode.
133913177Sgibbs *
134013177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
134113177Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
134213177Sgibbs * latched (the usual way), then read the data byte directly off the bus
134313177Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
134413177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
134513177Sgibbs * spec guarantees that the target will hold the data byte on the bus until
134613177Sgibbs * we send our ACK.
134713177Sgibbs *
134813177Sgibbs * The assumption here is that these are called in a particular sequence,
134913177Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
135013177Sgibbs * use the same calling convention as inb.
135113177Sgibbs */
135213177Sgibbs
135313177Sgibbsinb_next:
135423925Sgibbs	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
135513360Sgibbsinb_next_wait:
135621947Sgibbs	/*
135721947Sgibbs	 * If there is a parity error, wait for the kernel to
135821947Sgibbs	 * see the interrupt and prepare our message response
135921947Sgibbs	 * before continuing.
136021947Sgibbs	 */
136123925Sgibbs	test	SSTAT1, REQINIT	jz inb_next_wait;
136223925Sgibbs	test	SSTAT1, SCSIPERR jnz inb_next_wait;
136323925Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI;
136423925Sgibbs	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
136519623Sgibbsinb_first:
136623925Sgibbs	mov	DINDEX,SINDEX;
136723925Sgibbs	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
136813177Sgibbsinb_last:
136923925Sgibbs	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
137041646Sgibbs}
13714568Sgibbs
137239220Sgibbsif ((ahc->flags & AHC_TARGETMODE) != 0) {
137341646Sgibbs/*
137441646Sgibbs * Change to a new phase.  If we are changing the state of the I/O signal,
137541646Sgibbs * from out to in, wait an additional data release delay before continuing.
137641646Sgibbs */
137741646Sgibbschange_phase:
137843880Sgibbs	/* Wait for preceeding I/O session to complete. */
137943880Sgibbs	test	SCSISIGI, ACKI jnz .;
138043880Sgibbs
138143880Sgibbs	/* Change the phase */
138241646Sgibbs	and	DINDEX, IOI, SCSISIGI;
138341646Sgibbs	mov	SCSISIGO, SINDEX;
138441646Sgibbs	and	A, IOI, SINDEX;
138543880Sgibbs
138643880Sgibbs	/*
138743880Sgibbs	 * If the data direction has changed, from
138843880Sgibbs	 * out (initiator driving) to in (target driving),
138943880Sgibbs	 * we must waitat least a data release delay plus
139043880Sgibbs	 * the normal bus settle delay. [SCSI III SPI 10.11.0]
139143880Sgibbs	 */
139241646Sgibbs	cmp 	DINDEX, A je change_phase_wait;
139341646Sgibbs	test	SINDEX, IOI jz change_phase_wait;
139441646Sgibbs	call	change_phase_wait;
139541646Sgibbschange_phase_wait:
139641646Sgibbs	nop;
139741646Sgibbs	nop;
139841646Sgibbs	nop;
139941646Sgibbs	nop ret;
140041646Sgibbs
140141646Sgibbs/*
140241646Sgibbs * Send a byte to an initiator in Automatic PIO mode.
140341646Sgibbs */
140439220Sgibbstarget_outb:
140539220Sgibbs	or	SXFRCTL0, SPIOEN;
140639220Sgibbs	test	SSTAT0, SPIORDY	jz .;
140739220Sgibbs	mov	SCSIDATL, SINDEX;
140839220Sgibbs	test	SSTAT0, SPIORDY	jz .;
140941646Sgibbs	and	SXFRCTL0, ~SPIOEN ret;
141039220Sgibbs}
141139220Sgibbs	
141213177Sgibbsmesgin_phasemis:
141313177Sgibbs/*
141413177Sgibbs * We expected to receive another byte, but the target changed phase
141513177Sgibbs */
141623925Sgibbs	mvi	INTSTAT, MSGIN_PHASEMIS;
141723925Sgibbs	jmp	ITloop;
14184568Sgibbs
141913177Sgibbs/*
142013177Sgibbs * DMA data transfer.  HADDR and HCNT must be loaded first, and
142113177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for
142213177Sgibbs * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
142313177Sgibbs * during initialization.
142413177Sgibbs */
14254568Sgibbsdma:
142623925Sgibbs	mov	DFCNTRL,SINDEX;
142722568Sgibbsdma_loop:
142823925Sgibbs	test	SSTAT0,DMADONE	jnz dma_dmadone;
142923925Sgibbs	test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
143022568Sgibbsdma_phasemis:
143123925Sgibbs	test	SSTAT0,SDONE	jnz dma_checkfifo;
143223925Sgibbs	mov	SINDEX,ALLZEROS;		/* Notify caller of phasemiss */
14334568Sgibbs
143413177Sgibbs/*
143513177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or
143613177Sgibbs * the target changes the phase (in light of this, it makes sense that
143713177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
143813177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
143913177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty
144013177Sgibbs * status.
144113177Sgibbs */
144222568Sgibbsdma_checkfifo:
144323925Sgibbs	test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
144422568Sgibbsdma_fifoflush:
144523925Sgibbs	test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
14464568Sgibbs
144722568Sgibbsdma_fifoempty:
144822568Sgibbs	/* Don't clobber an inprogress host data transfer */
144923925Sgibbs	test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
145013177Sgibbs/*
145113177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 
145213177Sgibbs * actually off first lest we get an ILLSADDR.
145313177Sgibbs */
145422568Sgibbsdma_dmadone:
145523925Sgibbs	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
145622568Sgibbsdma_halt:
145737223Sgibbs	/*
145837223Sgibbs	 * Some revisions of the aic7880 have a problem where, if the
145937223Sgibbs	 * data fifo is full, but the PCI input latch is not empty, 
146037223Sgibbs	 * HDMAEN cannot be cleared.  The fix used here is to attempt
146137223Sgibbs	 * to drain the data fifo until there is space for the input
146237223Sgibbs	 * latch to drain and HDMAEN de-asserts.
146337223Sgibbs	 */
146439220Sgibbs	if ((ahc->features & AHC_ULTRA2) == 0) {
146539220Sgibbs		mov	NONE, DFDAT;
146639220Sgibbs	}
146739220Sgibbs	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
146818762Sgibbsreturn:
146923925Sgibbs	ret;
14704568Sgibbs
147113177Sgibbs/*
147213177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
147313177Sgibbs * message.
147413177Sgibbs */
14754568Sgibbsassert:
147623925Sgibbs	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
14774568Sgibbs
147823925Sgibbs	mvi	INTSTAT,NO_IDENT 	ret;	/* no - tell the kernel */
14794568Sgibbs
148013177Sgibbs/*
148119218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
148239220Sgibbs * or by the SCBID ARG_1.  The search begins at the SCB index passed in
148339220Sgibbs * via SINDEX which is an SCB that must be on the disconnected list.  If
148439220Sgibbs * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
148539220Sgibbs * is set to the proper SCB.
148613177Sgibbs */
14874568SgibbsfindSCB:
148839220Sgibbs	mov	SCBPTR,SINDEX;			/* Initialize SCBPTR */
148939220Sgibbs	cmp	ARG_1, SCB_LIST_NULL	jne findSCB_by_SCBID;
149039220Sgibbs	mov	A, SAVED_TCL;
149139220Sgibbs	mvi	SCB_TCL	jmp findSCB_loop;	/* &SCB_TCL -> SINDEX */
149239220SgibbsfindSCB_by_SCBID:
149323925Sgibbs	mov	A, ARG_1;			/* Tag passed in ARG_1 */
149439220Sgibbs	mvi	SCB_TAG	jmp findSCB_loop;	/* &SCB_TAG -> SINDEX */
149539220SgibbsfindSCB_next:
149639220Sgibbs	mov	ARG_2, SCBPTR;
149739220Sgibbs	cmp	SCB_NEXT, SCB_LIST_NULL je notFound;
149839220Sgibbs	mov	SCBPTR,SCB_NEXT;
149939220Sgibbs	dec	SINDEX;		/* Last comparison moved us too far */
150023168SgibbsfindSCB_loop:
150139220Sgibbs	cmp	SINDIR, A	jne findSCB_next;
150239220Sgibbs	mov	SINDEX, SCBPTR 	ret;
150339220SgibbsnotFound:
150439220Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret;
150539220Sgibbs
150619164Sgibbs/*
150739220Sgibbs * Retrieve an SCB by SCBID first searching the disconnected list falling
150839220Sgibbs * back to DMA'ing the SCB down from the host.  This routine assumes that
150939220Sgibbs * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
151039220Sgibbs * disconnected list to start the search from.  If SINDEX is SCB_LIST_NULL,
151139220Sgibbs * we go directly to the host for the SCB.
151219164Sgibbs */
151339220SgibbsretrieveSCB:
151439220Sgibbs	test	SEQ_FLAGS, SCBPTR_VALID	jz retrieve_from_host;
151539220Sgibbs	mov	SCBPTR	call findSCB;	/* Continue the search */
151639220Sgibbs	cmp	SINDEX, SCB_LIST_NULL	je retrieve_from_host;
151739220Sgibbs
151839220Sgibbs/*
151939220Sgibbs * This routine expects SINDEX to contain the index of the SCB to be
152039220Sgibbs * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the
152139220Sgibbs * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL
152239220Sgibbs * if it is at the head.
152339220Sgibbs */
152419164Sgibbsrem_scb_from_disc_list:
152515328Sgibbs/* Remove this SCB from the disconnection list */
152639220Sgibbs	cmp	ARG_2, SCB_LIST_NULL	je rHead;
152739220Sgibbs	mov	DINDEX, SCB_NEXT;
152839220Sgibbs	mov	SCBPTR, ARG_2;
152939220Sgibbs	mov	SCB_NEXT, DINDEX;
153023925Sgibbs	mov	SCBPTR, SINDEX ret;
153115328SgibbsrHead:
153223925Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
15334568Sgibbs
153439220Sgibbsretrieve_from_host:
153539220Sgibbs/*
153639220Sgibbs * We didn't find it.  Pull an SCB and DMA down the one we want.
153739220Sgibbs * We should never get here in the non-paging case.
153839220Sgibbs */
153939220Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb;
154039220Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
154139220Sgibbs	/* Jump instead of call as we want to return anyway */
154239220Sgibbs	mov	ARG_1	jmp dma_scb;
154339220Sgibbs
154439220Sgibbs/*
154539220Sgibbs * Determine whether a target is using tagged or non-tagged transactions
154639220Sgibbs * by first looking for a matching transaction based on the TCL and if
154739220Sgibbs * that fails, looking up this device in the host's untagged SCB array.
154839220Sgibbs * The TCL to search for is assumed to be in SAVED_TCL.  The value is
154939220Sgibbs * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
155039220Sgibbs * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
155139220Sgibbs * in an SCB instead of having to go to the host.
155239220Sgibbs */
155339220Sgibbsget_untagged_SCBID:
155439220Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
155539220Sgibbs	mvi	ARG_1, SCB_LIST_NULL;
155639220Sgibbs	mov	DISCONNECTED_SCBH call findSCB;
155739220Sgibbs	cmp	SINDEX, SCB_LIST_NULL	je get_SCBID_from_host;
155839220Sgibbs	or	SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
155939220Sgibbs	test	SCB_CONTROL, TAG_ENB	jnz . + 2;
156039220Sgibbs	mov	ARG_1, SCB_TAG	ret;
156139220Sgibbs	mvi	ARG_1, SCB_LIST_NULL ret;
156239220Sgibbs
156339220Sgibbs/*
156439220Sgibbs * Fetch a byte from host memory given an index of (A + (256 * SINDEX))
156539220Sgibbs * and a base address of SCBID_ADDR.  The byte is returned in RETURN_2.
156639220Sgibbs */
156739220Sgibbsfetch_byte:
156839220Sgibbs	mov	ARG_2, SINDEX;
156939220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
157039220Sgibbs		mvi	DINDEX, CCHADDR;
157139220Sgibbs		mvi	SCBID_ADDR call set_1byte_addr;
157239220Sgibbs		mvi	CCHCNT, 1;
157339220Sgibbs		mvi	CCSGCTL, CCSGEN|CCSGRESET;
157439220Sgibbs		test	CCSGCTL, CCSGDONE jz .;
157539220Sgibbs		mvi	CCSGCTL, CCSGRESET;
157639220Sgibbs		bmov	RETURN_2, CCSGRAM, 1 ret;
157739220Sgibbs	} else {
157839220Sgibbs		mvi	DINDEX, HADDR;
157939220Sgibbs		mvi	SCBID_ADDR call set_1byte_addr;
158039220Sgibbs		mvi	HCNT[0], 1;
158139220Sgibbs		clr	HCNT[1];
158239220Sgibbs		clr	HCNT[2];
158339220Sgibbs		mvi	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
158439220Sgibbs		call	dma_finish;
158539220Sgibbs		mov	RETURN_2, DFDAT ret;
158639220Sgibbs	}
158739220Sgibbs
158839220Sgibbs/*
158939220Sgibbs * Prepare the hardware to post a byte to host memory given an
159039220Sgibbs * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR.
159139220Sgibbs */
159239220Sgibbspost_byte_setup:
159339220Sgibbs	mov	ARG_2, SINDEX;
159439220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
159539220Sgibbs		mvi	DINDEX, CCHADDR;
159639220Sgibbs		mvi	SCBID_ADDR call	set_1byte_addr;
159739220Sgibbs		mvi	CCHCNT, 1;
159839220Sgibbs		mvi	CCSCBCTL, CCSCBRESET ret;
159939220Sgibbs	} else {
160039220Sgibbs		mvi	DINDEX, HADDR;
160139220Sgibbs		mvi	SCBID_ADDR call	set_1byte_addr;
160239220Sgibbs		mvi	HCNT[0], 1;
160339220Sgibbs		clr	HCNT[1];
160439220Sgibbs		clr	HCNT[2];
160539220Sgibbs		mvi	DFCNTRL, FIFORESET ret;
160639220Sgibbs	}
160739220Sgibbs
160839220Sgibbspost_byte:
160939220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
161039220Sgibbs		bmov	CCSCBRAM, SINDEX, 1;
161139220Sgibbs		or	CCSCBCTL, CCSCBEN|CCSCBRESET;
161239220Sgibbs		test	CCSCBCTL, CCSCBDONE jz .;
161339220Sgibbs		clr	CCSCBCTL ret;
161439220Sgibbs	} else {
161539220Sgibbs		mov	DFDAT, SINDEX;
161639220Sgibbs		or	DFCNTRL, HDMAEN|FIFOFLUSH;
161739220Sgibbs		jmp	dma_finish;
161839220Sgibbs	}
161939220Sgibbs
162039220Sgibbsget_SCBID_from_host:
162139220Sgibbs	mov	A, SAVED_TCL;
162239220Sgibbs	mvi	UNTAGGEDSCB_OFFSET call fetch_byte;
162339220Sgibbs	mov	RETURN_1,  RETURN_2 ret;
162439220Sgibbs
162539220Sgibbsphase_lock:     
162639220Sgibbs	test	SSTAT1, REQINIT jz phase_lock;
162739220Sgibbs	test	SSTAT1, SCSIPERR jnz phase_lock;
162841646Sgibbs	and	SCSISIGO, PHASE_MASK, SCSISIGI;
162941646Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
163039220Sgibbs
163139220Sgibbsif ((ahc->features & AHC_CMD_CHAN) == 0) {
163219164Sgibbsset_stcnt_from_hcnt:
163323925Sgibbs	mov	STCNT[0], HCNT[0];
163423925Sgibbs	mov	STCNT[1], HCNT[1];
163523925Sgibbs	mov	STCNT[2], HCNT[2] ret;
16364568Sgibbs
163719164Sgibbsbcopy_7:
163823925Sgibbs	mov	DINDIR, SINDIR;
163923925Sgibbs	mov	DINDIR, SINDIR;
164019164Sgibbsbcopy_5:
164123925Sgibbs	mov	DINDIR, SINDIR;
164219164Sgibbsbcopy_4:
164323925Sgibbs	mov	DINDIR, SINDIR;
164419164Sgibbsbcopy_3:
164523925Sgibbs	mov	DINDIR, SINDIR;
164623925Sgibbs	mov	DINDIR, SINDIR;
164723925Sgibbs	mov	DINDIR, SINDIR ret;
164839220Sgibbs}
16494568Sgibbs
165039220Sgibbsif ((ahc->flags & AHC_TARGETMODE) != 0) {
165139220Sgibbs/*
165239220Sgibbs * Setup addr assuming that A is an index into
165339220Sgibbs * an array of 32byte objects, SINDEX contains
165439220Sgibbs * the base address of that array, and DINDEX
165539220Sgibbs * contains the base address of the location
165639220Sgibbs * to store the indexed address.
165739220Sgibbs */
165839220Sgibbsset_32byte_addr:
165939220Sgibbs	shr	ARG_2, 3, A;
166039220Sgibbs	shl	A, 5;
166139220Sgibbs	jmp	set_1byte_addr;
166239220Sgibbs}
166339220Sgibbs
166439220Sgibbs/*
166539220Sgibbs * Setup addr assuming that A is an index into
166639220Sgibbs * an array of 64byte objects, SINDEX contains
166739220Sgibbs * the base address of that array, and DINDEX
166839220Sgibbs * contains the base address of the location
166939220Sgibbs * to store the indexed address.
167039220Sgibbs */
167139220Sgibbsset_64byte_addr:
167239220Sgibbs	shr	ARG_2, 2, A;
167339220Sgibbs	shl	A, 6;
167439220Sgibbs
167539220Sgibbs/*
167639220Sgibbs * Setup addr assuming that A + (ARG_1 * 256) is an
167739220Sgibbs * index into an array of 1byte objects, SINDEX contains
167839220Sgibbs * the base address of that array, and DINDEX contains
167939220Sgibbs * the base address of the location to store the computed
168039220Sgibbs * address.
168139220Sgibbs */
168239220Sgibbsset_1byte_addr:
168339220Sgibbs	add     DINDIR, A, SINDIR;
168439220Sgibbs	mov     A, ARG_2;
168539220Sgibbs	adc	DINDIR, A, SINDIR;
168639220Sgibbs	clr	A;
168739220Sgibbs	adc	DINDIR, A, SINDIR;
168839220Sgibbs	adc	DINDIR, A, SINDIR ret;
168939220Sgibbs
169039220Sgibbs/*
169139220Sgibbs * Either post or fetch and SCB from host memory based on the
169239220Sgibbs * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
169339220Sgibbs */
169419164Sgibbsdma_scb:
169539220Sgibbs	mov	A, SINDEX;
169639220Sgibbs	if ((ahc->features & AHC_CMD_CHAN) != 0) {
169739220Sgibbs		mvi	DINDEX, CCHADDR;
169839220Sgibbs		mvi	HSCB_ADDR call set_64byte_addr;
169939220Sgibbs		mov	CCSCBPTR, SCBPTR;
170039220Sgibbs		test	DMAPARAMS, DIRECTION jz dma_scb_tohost;
170139220Sgibbs		mvi	CCHCNT, SCB_64BYTE_SIZE;
170239220Sgibbs		mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
170339220Sgibbs		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
170439220Sgibbs		jmp	dma_scb_finish;
170539220Sgibbsdma_scb_tohost:
170639220Sgibbs		mvi	CCHCNT, SCB_32BYTE_SIZE;
170739220Sgibbs		if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
170839220Sgibbs			mvi	CCSCBCTL, CCSCBRESET;
170939220Sgibbs			bmov	CCSCBRAM, SCB_CONTROL, SCB_32BYTE_SIZE;
171039220Sgibbs			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
171139220Sgibbs			test	CCSCBCTL, CCSCBDONE jz .;
171239220Sgibbs		} else {
171339220Sgibbs			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
171439220Sgibbs			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
171539220Sgibbs		}
171639220Sgibbsdma_scb_finish:
171739220Sgibbs		clr	CCSCBCTL;
171839220Sgibbs		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
171939220Sgibbs		ret;
172039220Sgibbs	} else {
172139220Sgibbs		mvi	DINDEX, HADDR;
172239220Sgibbs		mvi	HSCB_ADDR call set_64byte_addr;
172339220Sgibbs		mvi	HCNT[0], SCB_32BYTE_SIZE;
172439220Sgibbs		clr	HCNT[1];
172539220Sgibbs		clr	HCNT[2];
172639220Sgibbs		mov	DFCNTRL, DMAPARAMS;
172739220Sgibbs		test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
172839220Sgibbs		/* Fill it with the SCB data */
172924175Sgibbscopy_scb_tofifo:
173039220Sgibbs		mvi	SINDEX, SCB_CONTROL;
173139220Sgibbs		add	A, SCB_32BYTE_SIZE, SINDEX;
173224175Sgibbscopy_scb_tofifo_loop:
173339220Sgibbs		mov	DFDAT,SINDIR;
173439220Sgibbs		mov	DFDAT,SINDIR;
173539220Sgibbs		mov	DFDAT,SINDIR;
173639220Sgibbs		mov	DFDAT,SINDIR;
173739220Sgibbs		mov	DFDAT,SINDIR;
173839220Sgibbs		mov	DFDAT,SINDIR;
173939220Sgibbs		mov	DFDAT,SINDIR;
174039220Sgibbs		cmp	SINDEX, A jne copy_scb_tofifo_loop;
174139220Sgibbs		or	DFCNTRL, HDMAEN|FIFOFLUSH;
174219164Sgibbsdma_scb_fromhost:
174339220Sgibbs		call	dma_finish;
174439220Sgibbs		/* If we were putting the SCB, we are done */
174539220Sgibbs		test	DMAPARAMS, DIRECTION	jz	return;
174639220Sgibbs		mvi	SCB_CONTROL  call dfdat_in_7;
174739220Sgibbs		call	dfdat_in_7_continued;
174839220Sgibbs		call	dfdat_in_7_continued;
174939220Sgibbs		jmp	dfdat_in_7_continued;
175019164Sgibbsdfdat_in_7:
175139220Sgibbs		mov     DINDEX,SINDEX;
175219164Sgibbsdfdat_in_7_continued:
175339220Sgibbs		mov	DINDIR,DFDAT;
175439220Sgibbs		mov	DINDIR,DFDAT;
175539220Sgibbs		mov	DINDIR,DFDAT;
175639220Sgibbs		mov	DINDIR,DFDAT;
175739220Sgibbs		mov	DINDIR,DFDAT;
175839220Sgibbs		mov	DINDIR,DFDAT;
175939220Sgibbs		mov	DINDIR,DFDAT ret;
176039220Sgibbs	}
176119164Sgibbs
176239220Sgibbs
176313177Sgibbs/*
176419164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
176519164Sgibbs * DMA and wait for it to acknowledge that it's off.
176613177Sgibbs */
176719164Sgibbsdma_finish:
176823925Sgibbs	test	DFSTATUS,HDONE	jz dma_finish;
176922234Sgibbs	/* Turn off DMA */
177023925Sgibbs	and	DFCNTRL, ~HDMAEN;
177123925Sgibbs	test	DFCNTRL, HDMAEN jnz .;
177223925Sgibbs	ret;
17739928Sgibbs
177423925Sgibbsadd_scb_to_free_list:
177539220Sgibbs	if ((ahc->flags & AHC_PAGESCBS) != 0) {
177639220Sgibbs		mov	SCB_NEXT, FREE_SCBH;
177739220Sgibbs		mov	FREE_SCBH, SCBPTR;
177839220Sgibbs	}
177939220Sgibbs	mvi	SCB_TAG, SCB_LIST_NULL ret;
17804568Sgibbs
178139220Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) {
178219164Sgibbsget_free_or_disc_scb:
178323925Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
178423925Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
178519623Sgibbsreturn_error:
178623925Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret;
178719623Sgibbsdequeue_disc_scb:
178823925Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH;
178923925Sgibbsdma_up_scb:
179023925Sgibbs	mvi	DMAPARAMS, FIFORESET;
179123925Sgibbs	mov	SCB_TAG		call dma_scb;
179219164Sgibbsunlink_disc_scb:
179339220Sgibbs	mov	DISCONNECTED_SCBH, SCB_NEXT ret;
179419164Sgibbsdequeue_free_scb:
179523925Sgibbs	mov	SCBPTR, FREE_SCBH;
179623925Sgibbs	mov	FREE_SCBH, SCB_NEXT ret;
179739220Sgibbs}
17984568Sgibbs
179919164Sgibbsadd_scb_to_disc_list:
180013177Sgibbs/*
180119164Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
180219164Sgibbs * candidates for paging out an SCB if one is needed for a new command.
180319164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
180413177Sgibbs */
180523925Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH;
180639220Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR ret;
1807