aic7xxx.seq revision 25005
126997Sgibbs/*+M***********************************************************************
226997Sgibbs *Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
313177Sgibbs *
439220Sgibbs *Copyright (c) 1994 John Aycock
526997Sgibbs *  The University of Calgary Department of Computer Science.
613177Sgibbs *  All rights reserved.
726997Sgibbs *
826997Sgibbs *FreeBSD, Twin, Wide, 2 command per target support, tagged queuing,
926997Sgibbs *SCB paging and other optimizations:
1026997Sgibbs *Copyright (c) 1994, 1995, 1996, 1997 Justin Gibbs. All rights reserved.
1126997Sgibbs *
1226997Sgibbs *Redistribution and use in source and binary forms, with or without
1339220Sgibbs *modification, are permitted provided that the following conditions
1426997Sgibbs *are met:
1513177Sgibbs *1. Redistributions of source code must retain the above copyright
1626997Sgibbs *   notice, this list of conditions, and the following disclaimer.
1739220Sgibbs *2. Redistributions in binary form must reproduce the above copyright
1826997Sgibbs *   notice, this list of conditions and the following disclaimer in the
1926997Sgibbs *   documentation and/or other materials provided with the distribution.
2026997Sgibbs *3. All advertising materials mentioning features or use of this software
2126997Sgibbs *   must display the following acknowledgement:
2213177Sgibbs *     This product includes software developed by the University of Calgary
2326997Sgibbs *     Department of Computer Science and its contributors.
2426997Sgibbs *4. Neither the name of the University nor the names of its contributors
2526997Sgibbs *   may be used to endorse or promote products derived from this software
2626997Sgibbs *   without specific prior written permission.
2726997Sgibbs *
2826997Sgibbs *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2926997Sgibbs *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3026997Sgibbs *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3126997Sgibbs *ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
3226997Sgibbs *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3326997Sgibbs *DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3413177Sgibbs *OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3541816Sgibbs *HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3626997Sgibbs *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
374568Sgibbs *OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3823925Sgibbs *SUCH DAMAGE.
3939220Sgibbs *
405647Sgibbs *	$Id: aic7xxx.seq,v 1.71 1997/04/14 02:26:59 gibbs Exp $
4113177Sgibbs *
4219164Sgibbs *-M************************************************************************/
4319164Sgibbs
4413690Sgibbs#include <dev/aic7xxx/aic7xxx.reg>
4513690Sgibbs#include <scsi/scsi_message.h>
4613690Sgibbs
4713690Sgibbs/*
4813690Sgibbs * A few words on the waiting SCB list:
4913690Sgibbs * After starting the selection hardware, we check for reconnecting targets
5013690Sgibbs * as well as for our selection to complete just in case the reselection wins
5113690Sgibbs * bus arbitration.  The problem with this is that we must keep track of the
5219164Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection
5319164Sgibbs * on just in case the reselection wins so that we can retry the selection at
5419164Sgibbs * a later time.  This problem cannot be resolved by holding a single entry
5519164Sgibbs * in scratch ram since a reconnecting target can request sense and this will
5619164Sgibbs * create yet another SCB waiting for selection.  The solution used here is to 
5713177Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
584568Sgibbs * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
5914449Sgibbs * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
6023925Sgibbs * this list everytime a request sense occurs or after completing a non-tagged
6141646Sgibbs * command for which a second SCB has been queued.  The sequencer will
6223925Sgibbs * automatically consume the entries.
6341816Sgibbs */
6439220Sgibbs
6539220Sgibbs/*
6639220Sgibbs * We assume that the kernel driver may reset us at any time, even in the
6739220Sgibbs * middle of a DMA, so clear DFCNTRL too.
6839220Sgibbs */
6939220Sgibbsreset:
7039220Sgibbs	clr	SCSISIGO;		/* De-assert BSY */
7123925Sgibbs	/* Always allow reselection */
728104Sgibbs	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;
7339220Sgibbs	call	clear_target_state;
7439220Sgibbspoll_for_work:
7539220Sgibbs	test	SSTAT0,SELDO	jnz select;
7639220Sgibbs	test	SSTAT0,SELDI	jnz reselect;
7739220Sgibbs	test	SCSISEQ, ENSELO	jnz poll_for_work;
7839220Sgibbs.if ( TWIN_CHANNEL )
7939220Sgibbs	/*
8039220Sgibbs	 * Twin channel devices cannot handle things like SELTO
8139220Sgibbs	 * interrupts on the "background" channel.  So, if we
8223925Sgibbs	 * are selecting, keep polling the current channel util
8339220Sgibbs	 * either a selection or reselection occurs.
8439220Sgibbs	 */
8539220Sgibbs	xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
8639220Sgibbs	test	SSTAT0,SELDO	jnz select;
8739220Sgibbs	test	SSTAT0,SELDI	jnz reselect;
8839220Sgibbs	test	SCSISEQ, ENSELO	jnz poll_for_work;
8939220Sgibbs	xor	SBLKCTL,SELBUSB;	/* Toggle back */
9039220Sgibbs.endif
9139220Sgibbs	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
9239220Sgibbstest_queue:
9339220Sgibbs	/* Has the driver posted any work for us? */
9439220Sgibbs	mov	A, QCNTMASK;
9523925Sgibbs	test	QINCNT,A	jz poll_for_work;
9619164Sgibbs
9719164Sgibbs/*
9839220Sgibbs * We have at least one queued SCB now and we don't have any 
9939220Sgibbs * SCBs in the list of SCBs awaiting selection.  If we have
10039220Sgibbs * any SCBs available for use, pull the tag from the QINFIFO
10139220Sgibbs * and get to work on it.
10239220Sgibbs */
10339220Sgibbs.if ( SCB_PAGING )
10439220Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb;
10539220Sgibbs	cmp	SINDEX, SCB_LIST_NULL	je poll_for_work;
10639220Sgibbs.endif
10739220Sgibbsdequeue_scb:
1084568Sgibbs	mov	CUR_SCBID,QINFIFO;
10913690Sgibbs.if !( SCB_PAGING )
11013690Sgibbs	/* In the non-paging case, the SCBID == hardware SCB index */
11119164Sgibbs	mov	SCBPTR, CUR_SCBID;
11223925Sgibbs.endif
11319164Sgibbsdma_queued_scb:
11413177Sgibbs/*
11539220Sgibbs * DMA the SCB from host ram into the current SCB location.
11639220Sgibbs */
11739220Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
11839220Sgibbs	mov	CUR_SCBID	call dma_scb;
11919164Sgibbs
12039220Sgibbs/*
12139220Sgibbs * See if there is not already an active SCB for this target.  This code
12239220Sgibbs * locks out on a per target basis instead of target/lun.  Although this
12339220Sgibbs * is not ideal for devices that have multiple luns active at the same
12439220Sgibbs * time, it is faster than looping through all SCB's looking for active
12539220Sgibbs * commands.  We also don't have enough spare SCB space for us to store the
12639220Sgibbs * SCBID of the currently busy transaction for each target/lun making it
12719164Sgibbs * impossible to link up the SCBs.
12819164Sgibbs */
12919164Sgibbstest_busy:
13019164Sgibbs	test	SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
13123925Sgibbs	mvi	SEQCTL, PAUSEDIS|FASTMODE;
13239220Sgibbs	mov	SAVED_SCBPTR, SCBPTR;
1334568Sgibbs	mov	SCB_TCL		call	index_untagged_scb;
13413177Sgibbs	mov	ARG_1, SINDIR;			/*
13539220Sgibbs						 * ARG_1 should
13639220Sgibbs						 * now have the SCB ID of
13739220Sgibbs						 * any active, non-tagged,
13839220Sgibbs						 * command for this target.
13913177Sgibbs						 */
14039220Sgibbs	cmp	ARG_1, SCB_LIST_NULL je make_busy;
14139220Sgibbs.if ( SCB_PAGING )
14239220Sgibbs	/*
14339220Sgibbs	 * Put this SCB back onto the free list.  It
14439220Sgibbs	 * may be necessary to satisfy the search for
14539220Sgibbs	 * the active SCB.
14639220Sgibbs	 */
14739220Sgibbs	mov	SCBPTR, SAVED_SCBPTR;
1484568Sgibbs	call	add_scb_to_free_list;
1495326Sgibbs	/* Find the active SCB */
15019164Sgibbs	mov	ALLZEROS	call findSCB;
15119164Sgibbs	/*
15219164Sgibbs	 * If we couldn't find it, tell the kernel.  This should
15319164Sgibbs	 * never happen.
15423925Sgibbs	 */
15523925Sgibbs	cmp	SINDEX, SCB_LIST_NULL	jne paged_busy_link;
15623925Sgibbs	mvi	INTSTAT, NO_MATCH_BUSY;
15723925Sgibbspaged_busy_link:
15839220Sgibbs	/* Link us in */
15923925Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID;
16023925Sgibbs	/* Put it back on the disconnected list */
16123925Sgibbs	call	add_scb_to_disc_list;
16223925Sgibbs	mvi	SEQCTL, FASTMODE;
1638104Sgibbs	jmp	poll_for_work;
16423925Sgibbs.else
16539220Sgibbssimple_busy_link:
16639220Sgibbs	mov	SCBPTR, ARG_1;
16739220Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID;
16839220Sgibbs	mvi	SEQCTL, FASTMODE;
16939220Sgibbs	jmp	poll_for_work;
17039220Sgibbs.endif
17123925Sgibbsmake_busy:
17239220Sgibbs	mov	DINDIR, CUR_SCBID;
17339220Sgibbs	mov	SCBPTR, SAVED_SCBPTR;
17439220Sgibbs	mvi	SEQCTL, FASTMODE;
17539220Sgibbs
17639220Sgibbsstart_scb:
17739220Sgibbs	/*
17839220Sgibbs	 * Place us on the waiting list in case our selection
17939220Sgibbs	 * doesn't win during bus arbitration.
18039220Sgibbs	 */
18141816Sgibbs	mov	SCB_NEXT,WAITING_SCBH;
18239220Sgibbs	mov	WAITING_SCBH, SCBPTR;
18341816Sgibbsstart_waiting:
18441816Sgibbs	/*
18539220Sgibbs	 * Pull the first entry off of the waiting SCB list
18641816Sgibbs	 * We don't have to "test_busy" because only transactions that
18739220Sgibbs	 * have passed that test can be in the WAITING_SCB list.
18813177Sgibbs	 */
18939220Sgibbs	mov	SCBPTR, WAITING_SCBH;
19039220Sgibbs	call	start_selection;
19139220Sgibbs	jmp	poll_for_work;
19239220Sgibbs
19339220Sgibbsstart_selection:
19439220Sgibbs.if ( TWIN_CHANNEL )
19539220Sgibbs	and	SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */
19639220Sgibbs	and	A,SELBUSB,SCB_TCL;	/* Get new channel bit */
19739220Sgibbs	or	SINDEX,A;
19839220Sgibbs	mov	SBLKCTL,SINDEX;		/* select channel */
19939220Sgibbs.endif
20039220Sgibbsinitialize_scsiid:
20139220Sgibbs	and	A, TID, SCB_TCL;	/* Get target ID */
20239220Sgibbs	and	SCSIID, OID;		/* Clear old target */
20339220Sgibbs	or	SCSIID, A;
20439220Sgibbs	mvi	SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
20539220Sgibbs/*
20639220Sgibbs * Reselection has been initiated by a target. Make a note that we've been
20739220Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
20839220Sgibbs */
20939220Sgibbsreselect:
21039220Sgibbs	clr	MSG_LEN;	/* Don't have anything in the mesg buffer */
21139220Sgibbs	mvi	CLRSINT0, CLRSELDI;
21239220Sgibbs	/* XXX test for and handle ONE BIT condition */
21339220Sgibbs	and	SAVED_TCL, SELID_MASK, SELID;
21439220Sgibbs	or	SEQ_FLAGS,RESELECTED;
21541646Sgibbs	jmp	select2;
21641646Sgibbs
21741646Sgibbs/*
21839220Sgibbs * After the selection, remove this SCB from the "waiting SCB"
21939220Sgibbs * list.  This is achieved by simply moving our "next" pointer into
22039220Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
22139220Sgibbs * SCB is used, so don't bother with it now.
22239220Sgibbs */
22341646Sgibbsselect:
22439220Sgibbs	/* Turn off the selection hardware */
22541646Sgibbs	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;	/*
22639220Sgibbs						 * ATN on parity errors
22739220Sgibbs						 * for "in" phases
22839220Sgibbs						 */
22939220Sgibbs	mvi	CLRSINT0, CLRSELDO;
23039220Sgibbs	mov	SCBPTR, WAITING_SCBH;
23139220Sgibbs	mov	WAITING_SCBH,SCB_NEXT;
23239220Sgibbs	mov	SAVED_TCL, SCB_TCL;
23339220Sgibbs/*
23439220Sgibbs * As soon as we get a successful selection, the target should go
23539220Sgibbs * into the message out phase since we have ATN asserted.  Prepare
23639220Sgibbs * the message to send.
23741299Sgibbs *
23839220Sgibbs * Messages are stored in scratch RAM starting with a length byte
23939220Sgibbs * followed by the message itself.
24041299Sgibbs */
24141299Sgibbs
24241299Sgibbsmk_identify:
24339220Sgibbs	and	MSG_OUT,0x7,SCB_TCL;	/* lun */
24439220Sgibbs	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
24539220Sgibbs	or	MSG_OUT,A;		/* or in disconnect privledge */
24639220Sgibbs	or	MSG_OUT,MSG_IDENTIFYFLAG;
24739220Sgibbs	mvi	MSG_LEN, 1;
24839220Sgibbs
24939220Sgibbs/*
25039220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
25139220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
25239220Sgibbs */
25339220Sgibbsmk_tag:
25439220Sgibbs	test	SCB_CONTROL,TAG_ENB jz  mk_message;
25539220Sgibbs	and	MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
25639220Sgibbs	mov	MSG_OUT[2],SCB_TAG;
25739220Sgibbs	add	MSG_LEN,2;	/* update message length */
25839220Sgibbs
25939220Sgibbs/*
26039220Sgibbs * Interrupt the driver, and allow it to tweak the message buffer
26139220Sgibbs * if it asks.
26239220Sgibbs */
26339220Sgibbsmk_message:
26439220Sgibbs	test	SCB_CONTROL,MK_MESSAGE  jz select2;
26539220Sgibbs	mvi     INTSTAT,AWAITING_MSG;
26639220Sgibbs
26739220Sgibbsselect2:
26839220Sgibbs	mvi	CLRSINT1,CLRBUSFREE;
26939220Sgibbs	or	SIMODE1, ENBUSFREE;		/*
27039220Sgibbs						 * We aren't expecting a
27139220Sgibbs						 * bus free, so interrupt
27239220Sgibbs						 * the kernel driver if it
27339220Sgibbs						 * happens.
27439220Sgibbs						 */
27539220Sgibbs/*
27639220Sgibbs * Initialize Ultra mode setting and clear the SCSI channel.
27739220Sgibbs */
27839220Sgibbs	or	SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
27939220Sgibbs.if ( ULTRA )
28039220Sgibbsultra:
28139220Sgibbs	mvi	SINDEX, ULTRA_ENB+1;
28239220Sgibbs	test	SAVED_TCL, 0x80		jnz ultra_2;	/* Target ID > 7 */
28339220Sgibbs	dec	SINDEX;
28439220Sgibbsultra_2:
28539220Sgibbs	mov     FUNCTION1,SAVED_TCL;
28639220Sgibbs	mov     A,FUNCTION1;
28741646Sgibbs	test	SINDIR, A	jz ndx_dtr;
28839220Sgibbs	or	SXFRCTL0, FAST20;
28939220Sgibbs.endif
29039220Sgibbs 
29139220Sgibbs/*
29239220Sgibbs * Initialize SCSIRATE with the appropriate value for this target.
29341299Sgibbs * The SCSIRATE settings for each target are stored in an array
29439220Sgibbs * based at TARG_SCRATCH.
29539220Sgibbs */
29639220Sgibbsndx_dtr:
29739220Sgibbs	shr	A,4,SAVED_TCL;
29839220Sgibbs	test	SBLKCTL,SELBUSB	jz ndx_dtr_2;
29939220Sgibbs	or	SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
30039220Sgibbs	or	A,0x08;			/* Channel B entries add 8 */
30139220Sgibbsndx_dtr_2:
30239220Sgibbs	add	SINDEX,TARG_SCRATCH,A;
30339220Sgibbs	mov	SCSIRATE,SINDIR;
30439220Sgibbs
30539220Sgibbs
30639220Sgibbs/*
30739220Sgibbs * Main loop for information transfer phases.  If BSY is false, then
30841646Sgibbs * we have a bus free condition, expected or not.  Otherwise, wait
30939220Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O
31039220Sgibbs * for the bus phase.
31139220Sgibbs *
31239220Sgibbs */
31339220SgibbsITloop:
31439220Sgibbs	test	SSTAT1,REQINIT		jz ITloop;
31539220Sgibbs	test	SSTAT1, SCSIPERR	jnz ITloop;
31639220Sgibbs
31739220Sgibbs	and	A,PHASE_MASK,SCSISIGI;
31839220Sgibbs	mov	LASTPHASE,A;
31939220Sgibbs	mov	SCSISIGO,A;
32039220Sgibbs
32139220Sgibbs	cmp	ALLZEROS,A	je p_dataout;
32239220Sgibbs	cmp	A,P_DATAIN	je p_datain;
32339220Sgibbs	cmp	A,P_COMMAND	je p_command;
32439220Sgibbs	cmp	A,P_MESGOUT	je p_mesgout;
32539220Sgibbs	cmp	A,P_STATUS	je p_status;
32639220Sgibbs	cmp	A,P_MESGIN	je p_mesgin;
32739220Sgibbs
32839220Sgibbs	mvi	INTSTAT,BAD_PHASE;	/* unknown phase - signal driver */
32939220Sgibbs	jmp	ITloop;			/* Try reading the bus again. */
33039220Sgibbs
33139220Sgibbsawait_busfree:
33239220Sgibbs	and	SIMODE1, ~ENBUSFREE;
33339220Sgibbs	call	clear_target_state;
33439220Sgibbs	mov	NONE, SCSIDATL;		/* Ack the last byte */
33541646Sgibbs	test	SSTAT1,REQINIT|BUSFREE	jz .;
33639220Sgibbs	test	SSTAT1, BUSFREE jnz poll_for_work;
33739220Sgibbs	mvi	INTSTAT, BAD_PHASE;
33839220Sgibbs	
33939220Sgibbsclear_target_state:
34039220Sgibbs	clr	DFCNTRL;
34139220Sgibbs	clr	SCSIRATE;		/*
34239220Sgibbs					 * We don't know the target we will
34341646Sgibbs					 * connect to, so default to narrow
34441646Sgibbs					 * transfers to avoid parity problems.
34541646Sgibbs					 */
34641646Sgibbs	and	SXFRCTL0, ~FAST20;	
34741646Sgibbs	mvi	LASTPHASE, P_BUSFREE;
34841646Sgibbs	/* clear target specific flags */
34941646Sgibbs	and	SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
35041646Sgibbs
35141646Sgibbsp_dataout:
35241646Sgibbs	mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
35341646Sgibbs	jmp	data_phase_init;
35441646Sgibbs
35541646Sgibbs/*
35641646Sgibbs * If we re-enter the data phase after going through another phase, the
35741646Sgibbs * STCNT may have been cleared, so restore it from the residual field.
35841646Sgibbs */
35939220Sgibbsdata_phase_reinit:
36039220Sgibbs	mvi	DINDEX, STCNT;
36139220Sgibbs	mvi	SCB_RESID_DCNT	call bcopy_3;
36239220Sgibbs	jmp	data_phase_loop;
36339220Sgibbs
36439220Sgibbsp_datain:
36539220Sgibbs	mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
36639220Sgibbsdata_phase_init:
36739220Sgibbs	call	assert;			/*
36839220Sgibbs					 * Ensure entering a data
36939220Sgibbs					 * phase is okay - seen identify, etc.
37039220Sgibbs					 */
37139220Sgibbs
37239220Sgibbs	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
37339220Sgibbs
37439220Sgibbs	/*
37539220Sgibbs	 * Initialize the DMA address and counter from the SCB.
37639220Sgibbs	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
37739220Sgibbs	 * modify the values in the SCB itself until we see a
37839220Sgibbs	 * save data pointers message.
37939220Sgibbs	 */
38041646Sgibbs	mvi	DINDEX, HADDR;
38139220Sgibbs	mvi	SCB_DATAPTR	call bcopy_7;
38239220Sgibbs
38339220Sgibbs	call	set_stcnt_from_hcnt;
38439220Sgibbs
38539220Sgibbs	mov	SG_COUNT,SCB_SGCOUNT;
38639220Sgibbs
38739220Sgibbs	mvi	DINDEX, SG_NEXT;
38841646Sgibbs	mvi	SCB_SGPTR	call bcopy_4;
38941646Sgibbs
39041646Sgibbsdata_phase_loop:
39141646Sgibbs/* Guard against overruns */
39239220Sgibbs	test	SG_COUNT, 0xff jnz data_phase_inbounds;
39339220Sgibbs/*
39439220Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to
39539220Sgibbs * 16meg and let the target run until it changes phase.
39639220Sgibbs * When the transfer completes, notify the host that we
39741646Sgibbs * had an overrun.
39839220Sgibbs */
39939220Sgibbs	or	SXFRCTL1,BITBUCKET;
40039220Sgibbs	mvi	HCNT[0], 0xff;
40141646Sgibbs	mvi	HCNT[1], 0xff;
40239220Sgibbs	mvi	HCNT[2], 0xff;
40323925Sgibbs	call	set_stcnt_from_hcnt;
40423925Sgibbs
40513177Sgibbsdata_phase_inbounds:
40639220Sgibbs/* If we are the last SG block, ensure wideodd is off. */
40723925Sgibbs	cmp	SG_COUNT,0x01 jne data_phase_wideodd;
40823925Sgibbs	and	DMAPARAMS, ~WIDEODD;
40939545Sgibbsdata_phase_wideodd:
41039545Sgibbs	mov	DMAPARAMS  call dma;
41139545Sgibbs
41239545Sgibbs/* Go tell the host about any overruns */
41341646Sgibbs	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
41439220Sgibbs
41539220Sgibbs/* Exit if we had an underrun.  dma clears SINDEX in this case. */
41639220Sgibbs	test	SINDEX,0xff	jz data_phase_finish;
41739220Sgibbs
41839220Sgibbs/*
41939220Sgibbs * Advance the scatter-gather pointers if needed 
42039220Sgibbs */
42139220Sgibbssg_advance:
42239220Sgibbs	dec	SG_COUNT;	/* one less segment to go */
42341646Sgibbs
4244568Sgibbs	test	SG_COUNT, 0xff	jz data_phase_finish; /* Are we done? */
42513177Sgibbs
42623925Sgibbs	clr	A;			/* add sizeof(struct scatter) */
42723925Sgibbs	add	SG_NEXT[0],SG_SIZEOF;
42823925Sgibbs	adc	SG_NEXT[1],A;
42923925Sgibbs
43023925Sgibbs/*
43139220Sgibbs * Load a struct scatter and set up the data address and length.
43225005Sgibbs * If the working value of the SG count is nonzero, then
43341816Sgibbs * we need to load a new set of values.
43425005Sgibbs *
43525005Sgibbs * This, like all DMA's, assumes little-endian host data storage.
43624914Sgibbs */
43723925Sgibbssg_load:
43839220Sgibbs	mvi	DINDEX, HADDR;
43939220Sgibbs	mvi	SG_NEXT	call bcopy_4;
4408567Sdg
44139220Sgibbs	mvi	HCNT[0],SG_SIZEOF;
44239220Sgibbs	clr	HCNT[1];
44339220Sgibbs	clr	HCNT[2];
44439220Sgibbs
44539220Sgibbs	or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
44641646Sgibbs
44741646Sgibbs	call	dma_finish;
4484568Sgibbs
44939220Sgibbs/*
45039220Sgibbs * Copy data from FIFO into SCB data pointer and data count.  This assumes
45139220Sgibbs * that the SG segments are of the form:
45239220Sgibbs *
45339220Sgibbs * struct ahc_dma_seg {
4546608Sgibbs *	u_int32_t	addr;		four bytes, little-endian order
45539220Sgibbs *	u_int32_t	len;		four bytes, little endian order
45639220Sgibbs * };
45739220Sgibbs */
45839220Sgibbs	mvi	HADDR	call dfdat_in_7;
45939220Sgibbs
46039220Sgibbs/* Load STCNT as well.  It is a mirror of HCNT */
46139220Sgibbs	call	set_stcnt_from_hcnt;
46239220Sgibbs	test	SSTAT1,PHASEMIS	jz data_phase_loop;
46339220Sgibbs
46439220Sgibbsdata_phase_finish:
46539220Sgibbs/*
46639220Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB
46739220Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
46839220Sgibbs * were transferred on the SCSI (as opposed to the host) bus.
46939220Sgibbs */
47039220Sgibbs	mov	SCB_RESID_DCNT[0],STCNT[0];
47141646Sgibbs	mov	SCB_RESID_DCNT[1],STCNT[1];
47241646Sgibbs	mov	SCB_RESID_DCNT[2],STCNT[2];
47339220Sgibbs	mov	SCB_RESID_SGCNT, SG_COUNT;
47441646Sgibbs
47539220Sgibbs	/* We have seen a data phase */
47639220Sgibbs	or	SEQ_FLAGS, DPHASE;
47739220Sgibbs
47839220Sgibbs	jmp	ITloop;
47939220Sgibbs
48039220Sgibbsdata_phase_overrun:
48139220Sgibbs/*
48239220Sgibbs * Turn off BITBUCKET mode and notify the host
48339220Sgibbs */
48439220Sgibbs	and	SXFRCTL1, ~BITBUCKET;
48539220Sgibbs	mvi	INTSTAT,DATA_OVERRUN;
48639220Sgibbs	jmp	ITloop;
48741646Sgibbs
48839220Sgibbs/*
48941646Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
49039220Sgibbs */
49139220Sgibbsp_command:
49239220Sgibbs	call	assert;
49339220Sgibbs
49441646Sgibbs/*
49541646Sgibbs * Load HADDR and HCNT.
49641646Sgibbs */
49741646Sgibbs	mvi	DINDEX, HADDR;
49841646Sgibbs	mvi	SCB_CMDPTR	call bcopy_5;
49941646Sgibbs	clr	HCNT[1];
50041646Sgibbs	clr	HCNT[2];
50139220Sgibbs
50241646Sgibbs	call	set_stcnt_from_hcnt;
50341816Sgibbs
50441816Sgibbs	mvi	(SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
50539220Sgibbs	jmp	ITloop;
50639220Sgibbs
50739220Sgibbs/*
50839220Sgibbs * Status phase.  Wait for the data byte to appear, then read it
50939220Sgibbs * and store it into the SCB.
51039220Sgibbs */
51139220Sgibbsp_status:
51239220Sgibbs	call	assert;
51339220Sgibbs
51439220Sgibbs	mov	SCB_TARGET_STATUS, SCSIDATL;
51539220Sgibbs	jmp	ITloop;
51641646Sgibbs
51741646Sgibbs/*
51839220Sgibbs * Message out phase.  If there is not an active message, but the target
51939220Sgibbs * took us into this phase anyway, build a no-op message and send it.
52039220Sgibbs */
52139220Sgibbsp_mesgout:
52239220Sgibbs	test	MSG_LEN, 0xff	jnz  p_mesgout_start;
52339220Sgibbs	mvi	MSG_NOOP	call mk_mesg;	/* build NOP message */
52439220Sgibbsp_mesgout_start:
52539220Sgibbs/*
52639220Sgibbs * Set up automatic PIO transfer from MSG_OUT.  Bit 3 in
52739220Sgibbs * SXFRCTL0 (SPIOEN) is already on.
52841299Sgibbs */
52941299Sgibbs	mvi	SINDEX,MSG_OUT;
53041299Sgibbs	mov	DINDEX,MSG_LEN;
53141299Sgibbs
53241299Sgibbs/*
53339220Sgibbs * When target asks for a byte, drop ATN if it's the last one in
53439220Sgibbs * the message.  Otherwise, keep going until the message is exhausted.
53539220Sgibbs * ATN must be dropped *at least* 90ns before we ack the last byte, so
53639220Sgibbs * the code is aranged to execute two instructions before the byte is
53739220Sgibbs * transferred to give a good margin of safety
53839220Sgibbs *
53939220Sgibbs * Keep an eye out for a phase change, in case the target issues
54039220Sgibbs * a MESSAGE REJECT.
54139220Sgibbs */
54239220Sgibbsp_mesgout_loop:
54339220Sgibbs	test	SSTAT1, REQINIT		jz p_mesgout_loop;
54439220Sgibbs	test	SSTAT1, SCSIPERR	jnz p_mesgout_loop;
54539220Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI;
54639220Sgibbs	cmp	LASTPHASE, P_MESGOUT jne p_mesgout_done;
54739220Sgibbsp_mesgout_testretry:
54839220Sgibbs	test	DINDEX,0xff	jnz p_mesgout_dropatn;
54939220Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
55039220Sgibbs	jmp	p_mesgout_start;
55139220Sgibbs/*
55239220Sgibbs * If the next bus phase after ATN drops is a message out, it means
55339220Sgibbs * that the target is requesting that the last message(s) be resent.
55439220Sgibbs */
55539220Sgibbsp_mesgout_dropatn:
55639220Sgibbs	cmp	DINDEX,1	jne p_mesgout_outb;	/* last byte? */
55739220Sgibbs	mvi	CLRSINT1,CLRATNO;			/* drop ATN */
55839220Sgibbsp_mesgout_outb:
55939220Sgibbs	dec	DINDEX;
56039220Sgibbs	mov	SCSIDATL,SINDIR;
56141646Sgibbs	jmp	p_mesgout_loop;
56239220Sgibbs
56339220Sgibbsp_mesgout_done:
56441646Sgibbs	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
56539220Sgibbs	clr	MSG_LEN;		/* no active msg */
56639220Sgibbs	jmp	ITloop;
56741646Sgibbs
56839220Sgibbs/*
56939220Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
57039220Sgibbs */
57141646Sgibbsp_mesgin:
57241646Sgibbs	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
57339220Sgibbs	mov	REJBYTE,A;			/* save it for the driver */
57441646Sgibbs
57539220Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
57639220Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
57739220Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
57839220Sgibbs	cmp	ALLZEROS,A		je mesgin_complete;
57939220Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
58039220Sgibbs	cmp	A,MSG_EXTENDED		je mesgin_extended;
58139220Sgibbs	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject;
58239220Sgibbs	cmp	A,MSG_NOOP		je mesgin_done;
58339220Sgibbs
58441299Sgibbsrej_mesgin:
58541299Sgibbs/*
58641299Sgibbs * We have no idea what this message in is, so we issue a message reject
58741299Sgibbs * and hope for the best.  In any case, rejection should be a rare
58839220Sgibbs * occurrence - signal the driver when it happens.
58939220Sgibbs */
59039220Sgibbs	mvi	INTSTAT,SEND_REJECT;		/* let driver know */
59139220Sgibbs
59241299Sgibbs	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
59341299Sgibbs
59441299Sgibbsmesgin_done:
59541299Sgibbs	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
59641299Sgibbs	jmp	ITloop;
59741299Sgibbs
59841299Sgibbs
59939220Sgibbsmesgin_complete:
60039220Sgibbs/*
60139220Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
60241299Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
60341299Sgibbs * is a residual or the status byte is something other than NO_ERROR (0).  In
60439220Sgibbs * either of these conditions, we upload the SCB back to the host so it can
60541646Sgibbs * process this information.  In the case of a non zero status byte, we 
60641646Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
60739220Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
60839220Sgibbs * sense, it will fill the kernel SCB with a request sense command and set
60941646Sgibbs * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
61041646Sgibbs * the SCB, and process it as the next command by adding it to the waiting list.
61141646Sgibbs * If the kernel driver does not wish to request sense, it need only clear
61241646Sgibbs * RETURN_1, and the command is allowed to complete normally.  We don't bother
61341646Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra
61425005Sgibbs * work in the kernel driver to ensure that the entry was removed before the
61539220Sgibbs * command complete code tried processing it.
61641646Sgibbs */
61741646Sgibbs
61841646Sgibbs/*
61941646Sgibbs * First check for residuals
62041646Sgibbs */
62141646Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz upload_scb;
62239220Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok;	/* Good Status? */
62339220Sgibbsupload_scb:
62413177Sgibbs	mvi	DMAPARAMS, FIFORESET;
62541646Sgibbs	mov	SCB_TAG		call dma_scb;
62641646Sgibbscheck_status:
62741646Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok;	/* Just a residual? */
62841646Sgibbs	mvi	INTSTAT,BAD_STATUS;			/* let driver know */
62941646Sgibbs	cmp	RETURN_1, SEND_SENSE	jne status_ok;
6304568Sgibbs	/* This SCB becomes the next to execute as it will retrieve sense */
63139220Sgibbs	mov	SCB_LINKED_NEXT, SCB_TAG;
6324568Sgibbs	jmp	dma_next_scb;
63339220Sgibbs
6344568Sgibbsstatus_ok:
63539220Sgibbs/* First, mark this target as free. */
63623925Sgibbs	test	SCB_CONTROL,TAG_ENB jnz complete;	/*
63723925Sgibbs							 * Tagged commands
63823925Sgibbs							 * don't busy the
63923925Sgibbs							 * target.
6404568Sgibbs							 */
64141646Sgibbs	mov	SAVED_SCBPTR, SCBPTR;
64223925Sgibbs	mov	SAVED_LINKPTR, SCB_LINKED_NEXT;
6434568Sgibbs	mov	SCB_TCL	call index_untagged_scb;
64423925Sgibbs	mov	DINDIR, SAVED_LINKPTR;
64523925Sgibbs	mov	SCBPTR, SAVED_SCBPTR;
64624794Sgibbs
64723925Sgibbscomplete:
64839220Sgibbs	/* Post the SCB and issue an interrupt */
64923925Sgibbs	mov	QOUTFIFO,SCB_TAG;
65023925Sgibbs	mvi	INTSTAT,CMDCMPLT;
65123925Sgibbs	test	SCB_CONTROL, ABORT_SCB jz dma_next_scb;
65241646Sgibbs	mvi	INTSTAT, ABORT_CMDCMPLT;
65323925Sgibbs
65423925Sgibbsdma_next_scb:
65541646Sgibbs	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je add_to_free_list;
65641646Sgibbs.if !( SCB_PAGING )
65741646Sgibbs	/* Only DMA on top of ourselves if we are the SCB to download */
65841646Sgibbs	mov	A, SCB_LINKED_NEXT;
65941646Sgibbs	cmp	SCB_TAG, A	je dma_next_scb2;
66041646Sgibbs	call	add_scb_to_free_list;
66141646Sgibbs	mov	SCBPTR, A;
66241646Sgibbs	jmp	add_to_waiting_list;
66341646Sgibbs.endif
66441646Sgibbsdma_next_scb2:
66541646Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
66641646Sgibbs	mov	SCB_LINKED_NEXT		call dma_scb;
66741646Sgibbsadd_to_waiting_list:
66841646Sgibbs	mov	SCB_NEXT,WAITING_SCBH;
66941646Sgibbs	mov	WAITING_SCBH, SCBPTR;
67041646Sgibbs	/*
67141646Sgibbs	 * Prepare our selection hardware before the busfree so we have a
67241646Sgibbs	 * high probability of winning arbitration.
67323925Sgibbs	 */
67423925Sgibbs	call	start_selection;
67539220Sgibbs	jmp	await_busfree;
67623925Sgibbsadd_to_free_list:
67713177Sgibbs	call	add_scb_to_free_list;
67813177Sgibbs	jmp	await_busfree;
67913177Sgibbs
68013177Sgibbs/*
6819928Sgibbs * Is it an extended message?  Copy the message to our message buffer and
68239220Sgibbs * notify the host.  The host will tell us whether to reject this message,
68339220Sgibbs * respond to it with the message that the host placed in our message buffer,
68439220Sgibbs * or simply to do nothing.
68539220Sgibbs */
68639220Sgibbsmesgin_extended:
68739220Sgibbs	mvi	MSGIN_EXT_LEN	 call inb_next;
68823925Sgibbs	mov	A, MSGIN_EXT_LEN;
6894568Sgibbsmesgin_extended_loop:
69039220Sgibbs	mov	DINDEX	call	inb_next;
69139220Sgibbs	dec	A;
69239220Sgibbs	cmp	DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
69339220Sgibbs	dec	DINDEX;		/* dump by repeatedly filling the last byte */
69439220Sgibbsmesgin_extended_loop_test:
69539220Sgibbs	test	A, 0xFF		jnz mesgin_extended_loop;
69639220Sgibbsmesgin_extended_intr:
69739220Sgibbs	mvi	INTSTAT,EXTENDED_MSG;		/* let driver know */
69823925Sgibbs	cmp	RETURN_1,SEND_REJ je rej_mesgin;
69919164Sgibbs	cmp	RETURN_1,SEND_MSG jne mesgin_done;
70019164Sgibbs/* The kernel has setup a message to be sent */
70119164Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;	/* turn on ATNO */
70239220Sgibbs	jmp	mesgin_done;
70339220Sgibbs
70439220Sgibbs/*
70523925Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
7064568Sgibbs * and await the bus going free.
70739220Sgibbs */
70839220Sgibbsmesgin_disconnect:
70939220Sgibbs	or	SCB_CONTROL,DISCONNECTED;
71019164Sgibbs.if ( SCB_PAGING )
71119164Sgibbs	call	add_scb_to_disc_list;
71219164Sgibbs.endif
71319164Sgibbs	jmp	await_busfree;
71419164Sgibbs
71519164Sgibbs/*
71639220Sgibbs * Save data pointers message:
71739220Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
71839220Sgibbs * only if we've actually been into a data phase to change them.  This
71939220Sgibbs * protects against bogus data in scratch ram and the residual counts
72039220Sgibbs * since they are only initialized when we go into data_in or data_out.
72139220Sgibbs */
72219164Sgibbsmesgin_sdptrs:
72339220Sgibbs	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
72439220Sgibbs	mov	SCB_SGCOUNT,SG_COUNT;
72539220Sgibbs
72639220Sgibbs	/* The SCB SGPTR becomes the next one we'll download */
72739220Sgibbs	mvi	DINDEX, SCB_SGPTR;
72839220Sgibbs	mvi	SG_NEXT	call bcopy_4;
72939220Sgibbs	
73019164Sgibbs	/* The SCB DATAPTR0 becomes the current SHADDR */
73139220Sgibbs	mvi	DINDEX, SCB_DATAPTR;
73239220Sgibbs	mvi	SHADDR		call bcopy_4;
73339220Sgibbs
73439220Sgibbs/*
73539220Sgibbs * Use the residual number since STCNT is corrupted by any message transfer.
73639220Sgibbs */
73719164Sgibbs	mvi	SCB_RESID_DCNT	call	bcopy_3;
7389928Sgibbs
73916260Sgibbs	jmp	mesgin_done;
74023925Sgibbs
74116260Sgibbs/*
74216260Sgibbs * Restore pointers message?  Data pointers are recopied from the
74316260Sgibbs * SCB anytime we enter a data phase for the first time, so all
74416260Sgibbs * we need to do is clear the DPHASE flag and let the data phase
74516260Sgibbs * code do the rest.
74616260Sgibbs */
74723925Sgibbsmesgin_rdptrs:
74839220Sgibbs	and	SEQ_FLAGS, ~DPHASE;		/*
74939220Sgibbs						 * We'll reload them
75039220Sgibbs						 * the next time through
75139220Sgibbs						 * the dataphase.
75239220Sgibbs						 */
75339220Sgibbs	jmp	mesgin_done;
75439220Sgibbs
75539220Sgibbs/*
75639220Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
75739220Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
75816260Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
75939220Sgibbs */
76023925Sgibbsmesgin_identify:
76139220Sgibbs	test	A,0x78	jnz rej_mesgin;	/*!DiscPriv|!LUNTAR|!Reserved*/
76239220Sgibbs	and	A,0x07;			/* lun in lower three bits */
76339220Sgibbs	or      SAVED_TCL,A;		/* SAVED_TCL should be complete now */
76439220Sgibbs	mov	SAVED_TCL call index_untagged_scb;
76539220Sgibbs	mov	ARG_1, SINDIR;
7669928Sgibbs.if ( SCB_PAGING )
76739220Sgibbs	cmp	ARG_1,SCB_LIST_NULL	jne use_findSCB;
76839220Sgibbs.else
76939220Sgibbs	cmp	ARG_1,SCB_LIST_NULL	je snoop_tag;
77039220Sgibbs	/* Directly index the SCB */
77139220Sgibbs	mov	SCBPTR,ARG_1;
77239220Sgibbs	test	SCB_CONTROL,DISCONNECTED jz not_found;
77339220Sgibbs	jmp	setup_SCB;
77439220Sgibbs.endif
77539220Sgibbs/*
77639220Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
77739220Sgibbs * If we get one, we use the tag returned to find the proper
77839220Sgibbs * SCB.  With SCB paging, this requires using findSCB for both tagged
77939220Sgibbs * and non-tagged transactions since the SCB may exist in any slot.
7804568Sgibbs * If we're not using SCB paging, we can use the tag as the direct
78139220Sgibbs * index to the SCB.
78216260Sgibbs */
78323925Sgibbssnoop_tag:
78416260Sgibbs	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
78522451Sgibbssnoop_tag_loop:
78623925Sgibbs	test	SSTAT1,REQINIT		jz snoop_tag_loop;
7877532Sgibbs	test	SSTAT1, SCSIPERR	jnz snoop_tag_loop;
78813177Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI;
78913177Sgibbs	cmp	LASTPHASE, P_MESGIN	jne not_found;
79013177Sgibbs	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
7919928Sgibbsget_tag:
79223925Sgibbs	or	SEQ_FLAGS, TAGGED_SCB;
7934568Sgibbs	mvi	ARG_1	call inb_next;	/* tag value */
79423925Sgibbs/*
79513177Sgibbs * See if the tag is in range.  The tag is < SCBCOUNT if we add
79613177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is
79713177Sgibbs * no carry.
79813177Sgibbs */
79913177Sgibbs	mov	A,COMP_SCBCOUNT;
80015328Sgibbs	add	SINDEX,A,ARG_1;
80113177Sgibbs	jc	not_found;
8029928Sgibbs
80339220Sgibbs.if ! ( SCB_PAGING )
80439220Sgibbsindex_by_tag:
80539220Sgibbs	mov	SCBPTR,ARG_1;
80639220Sgibbs	mov	A, SAVED_TCL;
80739220Sgibbs	cmp	SCB_TCL,A		jne not_found;
8084568Sgibbs	test	SCB_CONTROL,TAG_ENB	jz  not_found;
80939220Sgibbs	test	SCB_CONTROL,DISCONNECTED jz not_found;
81039220Sgibbs.else
81139220Sgibbs/*
81239220Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction
81339220Sgibbs * to the reconnecting target.
81439220Sgibbs */
81539220Sgibbsuse_findSCB:
81639220Sgibbs	mov	ALLZEROS	call findSCB;	  /* Have to search */
81739220Sgibbs	cmp	SINDEX, SCB_LIST_NULL	je not_found;
81839220Sgibbs.endif
81939220Sgibbssetup_SCB:
82039220Sgibbs	and	SCB_CONTROL,~DISCONNECTED;
82139220Sgibbs	or	SEQ_FLAGS,IDENTIFY_SEEN;	  /* make note of IDENTIFY */
82239220Sgibbs	jmp	mesgin_done;
82339220Sgibbs
82439220Sgibbsnot_found:
82539220Sgibbs	mvi	INTSTAT, NO_MATCH;
82639220Sgibbs	mvi	MSG_BUS_DEV_RESET	call mk_mesg;
82739220Sgibbs	jmp	mesgin_done;
82822568Sgibbs
82939220Sgibbs/*
83039220Sgibbs * Message reject?  Let the kernel driver handle this.  If we have an 
83139220Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 
8329928Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
83339220Sgibbs * it since we have no clue what it pertains to.
8349928Sgibbs */
83539220Sgibbsmesgin_reject:
8369928Sgibbs	mvi	INTSTAT, REJECT_MSG;
83739220Sgibbs	jmp	mesgin_done;
83839220Sgibbs
83939220Sgibbs/*
84039220Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ]
84139220Sgibbs */
84239220Sgibbs
84339220Sgibbs/*
84439220Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX
84539220Sgibbs * if there is no active message already.  SINDEX is returned intact.
84639220Sgibbs */
84739220Sgibbsmk_mesg:
84839220Sgibbs	mvi	SEQCTL, PAUSEDIS|FASTMODE;
84939220Sgibbs	test	MSG_LEN,0xff	jz mk_mesg1;	/* Should always succeed */
85039220Sgibbs	
85139220Sgibbs	/*
85239220Sgibbs	 * Hmmm.  For some reason the mesg buffer is in use.
85339220Sgibbs	 * Tell the driver.  It should look at SINDEX to find
85439220Sgibbs	 * out what we wanted to use the buffer for and resolve
85539220Sgibbs	 * the conflict.
85639220Sgibbs	 */
85739220Sgibbs	mvi	SEQCTL,FASTMODE;
85839220Sgibbs	mvi	INTSTAT,MSG_BUFFER_BUSY;
85939220Sgibbs
86039220Sgibbsmk_mesg1:
86139220Sgibbs	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
86241646Sgibbs	mvi	MSG_LEN,1;		/* length = 1 */
86341646Sgibbs	mov	MSG_OUT,SINDEX;		/* 1-byte message */
86441646Sgibbs	mvi	SEQCTL,FASTMODE	ret;
86541646Sgibbs
86623925Sgibbs/*
86741646Sgibbs * Functions to read data in Automatic PIO mode.
86839220Sgibbs *
86939220Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
87039220Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
87139220Sgibbs * latched (the usual way), then read the data byte directly off the bus
8724568Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
8739928Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
87439220Sgibbs * spec guarantees that the target will hold the data byte on the bus until
87539220Sgibbs * we send our ACK.
87639220Sgibbs *
87713177Sgibbs * The assumption here is that these are called in a particular sequence,
87813177Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
87913177Sgibbs * use the same calling convention as inb.
88013177Sgibbs */
88113177Sgibbs
88239220Sgibbsinb_next:
88339220Sgibbs	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
88439220Sgibbsinb_next_wait:
88539220Sgibbs	/*
88639220Sgibbs	 * If there is a parity error, wait for the kernel to
88739220Sgibbs	 * see the interrupt and prepare our message response
88839220Sgibbs	 * before continuing.
88923925Sgibbs	 */
89022568Sgibbs	test	SSTAT1, REQINIT	jz inb_next_wait;
89139220Sgibbs	test	SSTAT1, SCSIPERR jnz inb_next_wait;
89239220Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI;
89339220Sgibbs	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
89422568Sgibbsinb_first:
89539220Sgibbs	mov	DINDEX,SINDEX;
89641646Sgibbs	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
89739220Sgibbsinb_last:
89839220Sgibbs	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
89939220Sgibbs
90023925Sgibbsmesgin_phasemis:
9014568Sgibbs/*
90216260Sgibbs * We expected to receive another byte, but the target changed phase
90339220Sgibbs */
90439220Sgibbs	mvi	INTSTAT, MSGIN_PHASEMIS;
90539220Sgibbs	jmp	ITloop;
90639220Sgibbs
90713177Sgibbs/*
90816260Sgibbs * DMA data transfer.  HADDR and HCNT must be loaded first, and
90916260Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for
91023925Sgibbs * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
91123925Sgibbs * during initialization.
91223925Sgibbs */
91316260Sgibbsdma:
91439220Sgibbs	mov	DFCNTRL,SINDEX;
91539220Sgibbsdma_loop:
91639220Sgibbs	test	SSTAT0,DMADONE	jnz dma_dmadone;
91739220Sgibbs	test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
91839220Sgibbsdma_phasemis:
91939220Sgibbs	test	SSTAT0,SDONE	jnz dma_checkfifo;
92039220Sgibbs	mov	SINDEX,ALLZEROS;		/* Notify caller of phasemiss */
92139220Sgibbs
92239220Sgibbs/*
92339220Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or
92439220Sgibbs * the target changes the phase (in light of this, it makes sense that
92539220Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
92639220Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
92741646Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty
92816260Sgibbs * status.
92915328Sgibbs */
93013177Sgibbsdma_checkfifo:
9314568Sgibbs	test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
93223925Sgibbsdma_fifoflush:
9334568Sgibbs	test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
93439220Sgibbs
93539220Sgibbsdma_fifoempty:
93639220Sgibbs	/* Don't clobber an inprogress host data transfer */
93739220Sgibbs	test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
93839220Sgibbs/*
93939220Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 
94039220Sgibbs * actually off first lest we get an ILLSADDR.
94139220Sgibbs */
94239220Sgibbsdma_dmadone:
94339220Sgibbs	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
94439220Sgibbsdma_halt:
94539220Sgibbs	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN)	jnz dma_halt; 
94639220Sgibbsreturn:
94739220Sgibbs	ret;
94839220Sgibbs
94939220Sgibbs/*
95039220Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
95139220Sgibbs * message.
95239220Sgibbs */
95339220Sgibbsassert:
95439220Sgibbs	test	SEQ_FLAGS,RESELECTED	jz return;	/* reselected? */
95539220Sgibbs	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
95639220Sgibbs
9574568Sgibbs	mvi	INTSTAT,NO_IDENT 	ret;	/* no - tell the kernel */
95839220Sgibbs
95939220Sgibbs.if ( SCB_PAGING )
96039220Sgibbs/*
96139220Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
96239220Sgibbs * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
96339220Sgibbs * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
96439220Sgibbs * otherwise, SCBPTR is set to the proper SCB.
96539220Sgibbs */
96639220SgibbsfindSCB:
96739220Sgibbs	mov	SCBPTR,SINDEX;			/* switch to next SCB */
96839220Sgibbs	mov	A, ARG_1;			/* Tag passed in ARG_1 */
96939220Sgibbs	cmp	SCB_TAG,A	jne findSCB_loop;
97039220Sgibbs	test	SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
97123925SgibbsfindSCB_loop:
9724568Sgibbs	inc	SINDEX;
97313177Sgibbs	mov	A,SCBCOUNT;
97413177Sgibbs	cmp	SINDEX,A	jne findSCB;
97513177Sgibbs/*
97613177Sgibbs * We didn't find it.  If we're paging, pull an SCB and DMA down the
9774568Sgibbs * one we want.  If we aren't paging or the SCB we dma down has the
97823925Sgibbs * abort flag set, return not found.
97919803Sgibbs */
98023925Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb;
98123925Sgibbs	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
9824568Sgibbs	mov	ARG_1	call dma_scb;
98313177Sgibbs	test	SCB_CONTROL, ABORT_SCB jz return;
98441646Sgibbsfind_error:
98541646Sgibbs	mvi	SINDEX, SCB_LIST_NULL ret;
98641646SgibbsfoundSCB:
98741646Sgibbs	test	SCB_CONTROL, ABORT_SCB jnz find_error;
98841646Sgibbsrem_scb_from_disc_list:
98941646Sgibbs/* Remove this SCB from the disconnection list */
99041646Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev;
99141646Sgibbs	mov	SAVED_LINKPTR, SCB_PREV;
99239220Sgibbs	mov	SCBPTR, SCB_NEXT;
99339220Sgibbs	mov	SCB_PREV, SAVED_LINKPTR;
99441646Sgibbs	mov	SCBPTR, SINDEX;
99539220Sgibbsunlink_prev:
99639220Sgibbs	cmp	SCB_PREV,SCB_LIST_NULL	je rHead;/* At the head of the list */
99739220Sgibbs	mov	SAVED_LINKPTR, SCB_NEXT;
99839220Sgibbs	mov	SCBPTR, SCB_PREV;
99941646Sgibbs	mov	SCB_NEXT, SAVED_LINKPTR;
100039220Sgibbs	mov	SCBPTR, SINDEX ret;
100139220SgibbsrHead:
100239220Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
100339220Sgibbs.else
100439220Sgibbs	ret;
100539220Sgibbs.endif
100613177Sgibbs
100741646Sgibbsset_stcnt_from_hcnt:
100841646Sgibbs	mov	STCNT[0], HCNT[0];
10094568Sgibbs	mov	STCNT[1], HCNT[1];
101039220Sgibbs	mov	STCNT[2], HCNT[2] ret;
101139220Sgibbs
101241646Sgibbsbcopy_7:
101341646Sgibbs	mov	DINDIR, SINDIR;
101441646Sgibbs	mov	DINDIR, SINDIR;
101541646Sgibbsbcopy_5:
101641646Sgibbs	mov	DINDIR, SINDIR;
101741646Sgibbsbcopy_4:
101841646Sgibbs	mov	DINDIR, SINDIR;
101941646Sgibbsbcopy_3:
102041646Sgibbs	mov	DINDIR, SINDIR;
102141646Sgibbs	mov	DINDIR, SINDIR;
102241646Sgibbs	mov	DINDIR, SINDIR ret;
102341646Sgibbs
102441646Sgibbsdma_scb:
102539220Sgibbs	/*
102641299Sgibbs	 * SCB index is in SINDEX.  Determine the physical address in
102739220Sgibbs	 * the host where this SCB is located and load HADDR with it.
102839220Sgibbs	 */
102939220Sgibbs	shr	DINDEX, 3, SINDEX;
103013177Sgibbs	shl	A, 5, SINDEX;
103139220Sgibbs	add	HADDR[0], A, HSCB_ADDR[0];
103239220Sgibbs	mov	A, DINDEX;
103313177Sgibbs	adc	HADDR[1], A, HSCB_ADDR[1];
103439220Sgibbs	clr	A;
103539220Sgibbs	adc	HADDR[2], A, HSCB_ADDR[2];
103639220Sgibbs	adc	HADDR[3], A, HSCB_ADDR[3];
103739220Sgibbs	/* Setup Count */
103839220Sgibbs	mvi	HCNT[0], 28;
103939220Sgibbs	clr	HCNT[1];
104039220Sgibbs	clr	HCNT[2];
104139220Sgibbs	mov	DFCNTRL, DMAPARAMS;
104239220Sgibbs	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
104313177Sgibbs	/* Fill it with the SCB data */
104441646Sgibbscopy_scb_tofifo:
104541646Sgibbs	mvi	SINDEX, SCB_CONTROL;
104613177Sgibbs	add	A, 28, SINDEX;
104739220Sgibbscopy_scb_tofifo_loop:
104839220Sgibbs	mov	DFDAT,SINDIR;
104941646Sgibbs	mov	DFDAT,SINDIR;
105039220Sgibbs	mov	DFDAT,SINDIR;
105139220Sgibbs	mov	DFDAT,SINDIR;
105239220Sgibbs	mov	DFDAT,SINDIR;
105339220Sgibbs	mov	DFDAT,SINDIR;
105439220Sgibbs	mov	DFDAT,SINDIR;
105513177Sgibbs	cmp	SINDEX, A jne copy_scb_tofifo_loop;
105641646Sgibbs	or	DFCNTRL, HDMAEN|FIFOFLUSH;
105713177Sgibbsdma_scb_fromhost:
105813177Sgibbs	call	dma_finish;
105939220Sgibbs	/* If we were putting the SCB, we are done */
106041646Sgibbs	test	DMAPARAMS, DIRECTION	jz	return;
10614568Sgibbs	mvi	SCB_CONTROL  call dfdat_in_7;
106219906Sgibbs	call	dfdat_in_7_continued;
106323925Sgibbs	call	dfdat_in_7_continued;
106439220Sgibbs	jmp	dfdat_in_7_continued;
106539220Sgibbsdfdat_in_7:
106623925Sgibbs	mov     DINDEX,SINDEX;
10674568Sgibbsdfdat_in_7_continued:
106813177Sgibbs	mov	DINDIR,DFDAT;
106941646Sgibbs	mov	DINDIR,DFDAT;
107041646Sgibbs	mov	DINDIR,DFDAT;
107141646Sgibbs	mov	DINDIR,DFDAT;
107241646Sgibbs	mov	DINDIR,DFDAT;
107341646Sgibbs	mov	DINDIR,DFDAT;
107441646Sgibbs	mov	DINDIR,DFDAT ret;
107541646Sgibbs
107641646Sgibbs/*
107741646Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
107841646Sgibbs * DMA and wait for it to acknowledge that it's off.
107941646Sgibbs */
108041646Sgibbsdma_finish:
108141646Sgibbs	test	DFSTATUS,HDONE	jz dma_finish;
108241646Sgibbs	/* Turn off DMA */
108341646Sgibbs	and	DFCNTRL, ~HDMAEN;
108413177Sgibbs	test	DFCNTRL, HDMAEN jnz .;
108513177Sgibbs	ret;
10864568Sgibbs
108723925Sgibbsindex_untagged_scb:
10884568Sgibbs	mov	DINDEX, SINDEX;
108923925Sgibbs	shr	DINDEX, 4;
109023925Sgibbs	and	DINDEX, 0x03;			/* Bottom two bits of tid */
109123925Sgibbs	add	DINDEX, SCB_BUSYTARGETS;
109223925Sgibbs	shr	A, 6, SINDEX;			/* Target ID divided by 4 */
109323925Sgibbs	test	SINDEX, SELBUSB jz index_untagged_scb2;
109441646Sgibbs	add	A, 2;				/* Add 2 positions */
109523925Sgibbsindex_untagged_scb2:
109623925Sgibbs	mov	SCBPTR, A;			/*
10974568Sgibbs						 * Select the SCB with this 
10989954Sgibbs						 * target's information.
109913177Sgibbs						 */
110019164Sgibbs	mov	SINDEX, DINDEX	ret;
110119164Sgibbs
110219164Sgibbsadd_scb_to_free_list:
110313177Sgibbs	mov	SCB_NEXT, FREE_SCBH;
110423925Sgibbs	mvi	SCB_TAG, SCB_LIST_NULL;
11059954Sgibbs	mov	FREE_SCBH, SCBPTR ret;
110623925Sgibbs
11079954Sgibbs.if ( SCB_PAGING )
11089954Sgibbsget_free_or_disc_scb:
110923925Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
111023925Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
11119954Sgibbsreturn_error:
11129954Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret;
11139954Sgibbsdequeue_disc_scb:
111413177Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH;
111519164Sgibbs/*
111619164Sgibbs * If we have a residual, then we are in the middle of some I/O
111739220Sgibbs * and we have to send this SCB back up to the kernel so that the
111839220Sgibbs * saved data pointers and residual information isn't lost.
111919164Sgibbs */
112019164Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz dma_up_scb;
112119164Sgibbs	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
112219164Sgibbsdma_up_scb:
112319164Sgibbs	mvi	DMAPARAMS, FIFORESET;
112419164Sgibbs	mov	SCB_TAG		call dma_scb;
112519164Sgibbsunlink_disc_scb:
112619164Sgibbs	/* jmp instead of call since we want to return anyway */
112719164Sgibbs	mov	SCBPTR	jmp rem_scb_from_disc_list;
112819164Sgibbsdequeue_free_scb:
112919164Sgibbs	mov	SCBPTR, FREE_SCBH;
113013177Sgibbs	mov	FREE_SCBH, SCB_NEXT ret;
113119164Sgibbs
113213177Sgibbsadd_scb_to_disc_list:
113319164Sgibbs/*
113413177Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
113523925Sgibbs * candidates for paging out an SCB if one is needed for a new command.
113639220Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
113719164Sgibbs */
113823925Sgibbs	mvi	SCB_PREV, SCB_LIST_NULL;
113923925Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH;
11407532Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR;
114139220Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je return;
114223925Sgibbs	mov	SCBPTR,SCB_NEXT;
114339220Sgibbs	mov	SCB_PREV,DISCONNECTED_SCBH;
114439220Sgibbs	mov	SCBPTR,DISCONNECTED_SCBH ret;
114519164Sgibbs.endif
114623925Sgibbs