aic7xxx.seq revision 19921
113177Sgibbs/*+M***********************************************************************
213177Sgibbs *Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
313177Sgibbs *
413177Sgibbs *Copyright (c) 1994 John Aycock
513177Sgibbs *  The University of Calgary Department of Computer Science.
613177Sgibbs *  All rights reserved.
713177Sgibbs *
815328Sgibbs *FreeBSD, Twin, Wide, 2 command per target support, tagged queuing,
915328Sgibbs *SCB paging and other optimizations:
1015328Sgibbs *Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
1113177Sgibbs *
1213177Sgibbs *Redistribution and use in source and binary forms, with or without
1313177Sgibbs *modification, are permitted provided that the following conditions
1413177Sgibbs *are met:
1513177Sgibbs *1. Redistributions of source code must retain the above copyright
1613177Sgibbs *   notice, this list of conditions, and the following disclaimer.
1713177Sgibbs *2. Redistributions in binary form must reproduce the above copyright
1813177Sgibbs *   notice, this list of conditions and the following disclaimer in the
1913177Sgibbs *   documentation and/or other materials provided with the distribution.
2013177Sgibbs *3. All advertising materials mentioning features or use of this software
2113177Sgibbs *   must display the following acknowledgement:
2213177Sgibbs *     This product includes software developed by the University of Calgary
2313177Sgibbs *     Department of Computer Science and its contributors.
2413177Sgibbs *4. Neither the name of the University nor the names of its contributors
2513177Sgibbs *   may be used to endorse or promote products derived from this software
2613177Sgibbs *   without specific prior written permission.
2713177Sgibbs *
2813177Sgibbs *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2913177Sgibbs *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3013177Sgibbs *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3113177Sgibbs *ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
3213177Sgibbs *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3313177Sgibbs *DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3413177Sgibbs *OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3513177Sgibbs *HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3613177Sgibbs *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3713177Sgibbs *OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3813177Sgibbs *SUCH DAMAGE.
3913177Sgibbs *
4013177Sgibbs *-M************************************************************************/
414568Sgibbs
4219921SgibbsVERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.50 1996/11/21 06:18:33 gibbs Exp $"
435647Sgibbs
4415998Sgibbs#if defined(__NetBSD__)
4515998Sgibbs#include "../../../../dev/ic/aic7xxxreg.h"
4618762Sgibbs#include "../../../../scsi/scsi_message.h"
4715998Sgibbs#elif defined(__FreeBSD__)
4813177Sgibbs#include "../../dev/aic7xxx/aic7xxx_reg.h"
4918762Sgibbs#include "../../scsi/scsi_message.h"
5015998Sgibbs#endif
514568Sgibbs
5213177Sgibbs/*
5313177Sgibbs * We can't just use ACCUM in the sequencer code because it
5413177Sgibbs * must be treated specially by the assembler, and it currently
5513690Sgibbs * looks for the symbol 'A'.  This is the only register defined in
5613177Sgibbs * the assembler's symbol space.
5713177Sgibbs */
5813177SgibbsA = ACCUM
594568Sgibbs
6019164Sgibbs/*
6119164Sgibbs * A few words on the waiting SCB list:
6219164Sgibbs * After starting the selection hardware, we check for reconnecting targets
6313690Sgibbs * as well as for our selection to complete just in case the reselection wins
6413690Sgibbs * bus arbitration.  The problem with this is that we must keep track of the
6513690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection
6613690Sgibbs * on just in case the reselection wins so that we can retry the selection at
6713690Sgibbs * a later time.  This problem cannot be resolved by holding a single entry
6813690Sgibbs * in scratch ram since a reconnecting target can request sense and this will
6913690Sgibbs * create yet another SCB waiting for selection.  The solution used here is to 
7013690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
7119164Sgibbs * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
7219164Sgibbs * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
7319164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged
7419164Sgibbs * command for which a second SCB has been queued.  The sequencer will
7519164Sgibbs * automatically consume the entries.
7613177Sgibbs */
774568Sgibbs
7813177Sgibbs/*
7914449Sgibbs * We assume that the kernel driver may reset us at any time, even in the
8014449Sgibbs * middle of a DMA, so clear DFCNTRL too.
8113177Sgibbs */
8214449Sgibbsreset:
8314449Sgibbs	clr	DFCNTRL
8414449Sgibbs	clr	SCSISIGO		/* De-assert BSY */
8519921Sgibbs
8619921Sgibbsp_busfree:
8719921Sgibbs	mvi	LASTPHASE, P_BUSFREE
8819921Sgibbs
8913177Sgibbsstart:
9019164Sgibbs	and	FLAGS,0x07		/* clear target specific flags */
9113177Sgibbs	mvi	SCSISEQ,ENRSELI		/* Always allow reselection */
9216198Sgibbs	clr	SCSIRATE		/*
9316198Sgibbs					 * We don't know the target we will
9416198Sgibbs					 * connect to, so default to narrow
9516198Sgibbs					 * transfers to avoid parity problems.
9616198Sgibbs					 */
978104Sgibbspoll_for_work:
9813177Sgibbs	/*
9913177Sgibbs	 * Are we a twin channel device?
10013177Sgibbs	 * For fairness, we check the other bus first,
10113177Sgibbs	 * since we just finished a transaction on the
10213177Sgibbs	 * current channel.
10313177Sgibbs	 */
10413177Sgibbs	test	FLAGS,TWIN_BUS	jz start2
10513177Sgibbs	xor	SBLKCTL,SELBUSB			/* Toggle to the other bus */
1068104Sgibbs	test	SSTAT0,SELDI	jnz reselect
10713177Sgibbs	xor	SBLKCTL,SELBUSB			/* Toggle to the original bus */
1085326Sgibbsstart2:
1098104Sgibbs	test	SSTAT0,SELDI	jnz reselect
11019164Sgibbs	cmp	WAITING_SCBH,SCB_LIST_NULL je test_queue
11119164Sgibbsstart_waiting:
11219164Sgibbs	/*
11319164Sgibbs	 * Pull the first entry off of the waiting SCB list
11419164Sgibbs	 * We don't have to "test_busy" because only transactions that
11519164Sgibbs	 * have passed that test can be in the WAITING_SCB list.
11619164Sgibbs	 */
11719164Sgibbs	mov	SCBPTR,WAITING_SCBH
11819164Sgibbs	jmp	start_scb2
11919164Sgibbstest_queue:
12019164Sgibbs	/* Has the driver posted any work for us? */
12114934Sgibbs	mov	A, QCNTMASK
12214934Sgibbs	test	QINCNT,A	jz poll_for_work
1234568Sgibbs
12413690Sgibbs/*
12513690Sgibbs * We have at least one queued SCB now and we don't have any 
12619164Sgibbs * SCBs in the list of SCBs awaiting selection.  If we have
12719164Sgibbs * any SCBs availible for use, pull the tag from the QINFIFO
12819164Sgibbs * and get to work on it.
12913177Sgibbs */
13019164Sgibbs	test	FLAGS, PAGESCBS	jz	dequeue_scb
13119623Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb
13219164Sgibbs	cmp	SINDEX, SCB_LIST_NULL	je poll_for_work
13319164Sgibbsdequeue_scb:
13419164Sgibbs	mov	CUR_SCBID,QINFIFO
13519164Sgibbs	test	FLAGS, PAGESCBS jnz dma_queued_scb
13619164Sgibbs	/* In the non-paging case, the SCBID == hardware SCB index */
13719164Sgibbs	mov	SCBPTR, CUR_SCBID
13819164Sgibbsdma_queued_scb:
13919164Sgibbs/*
14019164Sgibbs * DMA the SCB from host ram into the current SCB location.
14119164Sgibbs */
14219164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
14319164Sgibbs	mov	CUR_SCBID	call dma_scb
1444568Sgibbs
14513177Sgibbs/*
14613177Sgibbs * See if there is not already an active SCB for this target.  This code
14713177Sgibbs * locks out on a per target basis instead of target/lun.  Although this
14813177Sgibbs * is not ideal for devices that have multiple luns active at the same
14913177Sgibbs * time, it is faster than looping through all SCB's looking for active
15019921Sgibbs * commands.  We also don't have enough spare SCB space for us to store the
15119164Sgibbs * SCBID of the currently busy transaction for each target/lun making it
15219164Sgibbs * impossible to link up the SCBs.
15313177Sgibbs */
1545647Sgibbstest_busy:
15519164Sgibbs	test	SCB_CONTROL, TAG_ENB	jnz start_scb
15619164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
15719218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
15819164Sgibbs	mov	ARG_1, SINDIR			/*
15919164Sgibbs						 * ARG_1 should
16019164Sgibbs						 * now have the SCB ID of
16119164Sgibbs						 * any active, non-tagged,
16219164Sgibbs						 * command for this target.
16319164Sgibbs						 */
16419164Sgibbs	cmp	ARG_1, SCB_LIST_NULL je make_busy
16519164Sgibbs	test	FLAGS, PAGESCBS jz simple_busy_link
16619164Sgibbs	/*
16719164Sgibbs	 * Put this SCB back onto the free list.  It
16819164Sgibbs	 * may be necessary to satisfy the search for
16919164Sgibbs	 * the active SCB.
17019164Sgibbs	 */
17119218Sgibbs	mov	SCBPTR, SAVED_SCBPTR
17219164Sgibbs	call	add_scb_to_free_list
17319164Sgibbs	/* Find the active SCB */
17419164Sgibbs	mov	ALLZEROS	call findSCB
17519218Sgibbs	/*
17619218Sgibbs	 * If we couldn't find it, tell the kernel.  This should
17719218Sgibbs	 * only happen if the parent SCB was aborted and this
17819218Sgibbs	 * one was already here at the time of the abort.
17919218Sgibbs	 */
18019218Sgibbs	cmp	SINDEX, SCB_LIST_NULL	jne paged_busy_link
18119218Sgibbs	mvi	INTSTAT, NO_MATCH_BUSY
18219218Sgibbspaged_busy_link:
18319164Sgibbs	/* Link us in */
18419164Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
18519164Sgibbs	/* Put it back on the disconnected list */
18619164Sgibbs	call	add_scb_to_disc_list
1878104Sgibbs	jmp	poll_for_work
18819164Sgibbssimple_busy_link:
18919164Sgibbs	mov	SCBPTR, ARG_1
19019164Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
19119164Sgibbs	jmp	poll_for_work
19219164Sgibbsmake_busy:
19319164Sgibbs	mov	DINDIR, CUR_SCBID
19419164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
1954568Sgibbs
1965326Sgibbsstart_scb:
19719164Sgibbs	/*
19819164Sgibbs	 * Place us on the waiting list in case our selection
19919164Sgibbs	 * doesn't win during bus arbitration.
20019164Sgibbs	 */
20115328Sgibbs	mov	SCB_NEXT,WAITING_SCBH
20213177Sgibbs	mov	WAITING_SCBH, SCBPTR
20313177Sgibbsstart_scb2:
20413177Sgibbs	and	SINDEX,0xf7,SBLKCTL	/* Clear the channel select bit */
20513177Sgibbs	and	A,0x08,SCB_TCL		/* Get new channel bit */
20613177Sgibbs	or	SINDEX,A
20713177Sgibbs	mov	SBLKCTL,SINDEX		/* select channel */
20813177Sgibbs	mov	SCB_TCL	call initialize_scsiid
2098104Sgibbs
21013177Sgibbs/*
21113177Sgibbs * Enable selection phase as an initiator, and do automatic ATN
21213177Sgibbs * after the selection.  We do this now so that we can overlap the
21313177Sgibbs * rest of our work to set up this target with the arbitration and
21413177Sgibbs * selection bus phases.
21513177Sgibbs */
2168104Sgibbsstart_selection:
21713177Sgibbs	mvi	SCSISEQ,0x58		/* ENSELO|ENAUTOATNO|ENRSELI */
2184568Sgibbs
21913177Sgibbs/*
22013177Sgibbs * As soon as we get a successful selection, the target should go
22113177Sgibbs * into the message out phase since we have ATN asserted.  Prepare
22213177Sgibbs * the message to send.
22313177Sgibbs *
22413177Sgibbs * Messages are stored in scratch RAM starting with a length byte
22513177Sgibbs * followed by the message itself.
22613177Sgibbs */
2278567Sdg
22813177Sgibbsmk_identify:
22919164Sgibbs	and	MSG0,0x7,SCB_TCL	/* lun */
23013177Sgibbs	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privledge */
23113690Sgibbs	or	MSG0,A			/* or in disconnect privledge */
23218762Sgibbs	or	MSG0,MSG_IDENTIFYFLAG
23313690Sgibbs	mvi	MSG_LEN, 1
2344568Sgibbs
23513177Sgibbs/*
23615328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
23715328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
23813177Sgibbs */
2396608Sgibbsmk_tag:
24018762Sgibbs	test	SCB_CONTROL,TAG_ENB jz  mk_message
24119164Sgibbs	and	MSG1,0x23,SCB_CONTROL
24219164Sgibbs	mov	MSG2,SCB_TAG
24319164Sgibbs	add	MSG_LEN,2	/* update message length */
2446608Sgibbs
24518762Sgibbs/*
24618762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer
24718762Sgibbs * if it asks.
24818762Sgibbs */
24918762Sgibbsmk_message:
25018762Sgibbs	test	SCB_CONTROL,MK_MESSAGE  jz wait_for_selection
2516608Sgibbs
25218762Sgibbs	mvi     INTSTAT,AWAITING_MSG
2536608Sgibbs
2549917Sgibbswait_for_selection:
25513177Sgibbs	test	SSTAT0,SELDO	jnz select 
25613177Sgibbs	test	SSTAT0,SELDI	jz wait_for_selection
2574568Sgibbs
25813177Sgibbs/*
25913177Sgibbs * Reselection has been initiated by a target. Make a note that we've been
26019164Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
26113177Sgibbs */
2624568Sgibbsreselect:
26313177Sgibbs	clr	MSG_LEN		/* Don't have anything in the mesg buffer */
2648104Sgibbs	mov	SELID		call initialize_scsiid
26513177Sgibbs	or	FLAGS,RESELECTED
26613177Sgibbs	jmp	select2
2674568Sgibbs
26813177Sgibbs/*
26919164Sgibbs * After the selection, remove this SCB from the "waiting SCB"
27013177Sgibbs * list.  This is achieved by simply moving our "next" pointer into
27113177Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
27213177Sgibbs * SCB is used, so don't bother with it now.
27313177Sgibbs */
2748104Sgibbsselect:
27515328Sgibbs	mov	WAITING_SCBH,SCB_NEXT
2768104Sgibbsselect2:
27713177Sgibbs/*
27813177Sgibbs * Initialize SCSIRATE with the appropriate value for this target.
27919164Sgibbs * The SCSIRATE settings for each target are stored in an array
28019164Sgibbs * based at TARG_SCRATCH.
28113177Sgibbs */
28219164Sgibbsndx_dtr:
28319164Sgibbs	shr	A,SCSIID,4
28419164Sgibbs	test	SBLKCTL,SELBUSB	jz ndx_dtr_2
28519164Sgibbs	or	SAVED_TCL, SELBUSB /* Add the channel bit while we're here */
28619164Sgibbs	or	A,0x08		/* Channel B entries add 8 */
28719164Sgibbsndx_dtr_2:
28819164Sgibbs	add	SINDEX,TARG_SCRATCH,A
28913177Sgibbs	mov	SCSIRATE,SINDIR
29013177Sgibbs
29115843Sgibbs/*
29219164Sgibbs * Initialize Ultra mode setting and clear the SCSI channel.
29315843Sgibbs */
29419164Sgibbsultra:
29519164Sgibbs	and	DINDEX,0xdf,SXFRCTL0            /* default to Ultra disabled */
29619164Sgibbs	/*
29719164Sgibbs	 * Set CLRCHN here before the target has entered a data transfer mode -
29819164Sgibbs	 * with synchronous SCSI, if you do it later, you blow away some
29919164Sgibbs	 * data in the SCSI FIFO that the target has already sent to you.
30019164Sgibbs	 */
30119164Sgibbs	or	DINDEX, CLRCHN
30219164Sgibbs	mvi	SINDEX, ULTRA_ENB_B
30319164Sgibbs	test	SCSIID, 0x80     jnz ultra_2     /* Target ID > 7 */
30419164Sgibbs	test	SBLKCTL, SELBUSB jnz ultra_2     /* Second channel device */
30519164Sgibbs	dec	SINDEX
30619164Sgibbsultra_2:
30719164Sgibbs	mov     FUNCTION1,SCSIID 
30819164Sgibbs	mov     A,FUNCTION1
30919164Sgibbs	test	SINDIR, A	jz set_sxfrctl0
31019164Sgibbs	or	DINDEX, ULTRAEN
31119164Sgibbs 
31215843Sgibbsset_sxfrctl0:
31319164Sgibbs	mov	SXFRCTL0,DINDEX
31415843Sgibbs
31516198Sgibbs	mvi	SCSISEQ,ENAUTOATNP		/*
31616198Sgibbs						 * ATN on parity errors
31716198Sgibbs						 * for "in" phases
31813177Sgibbs						 */
31913177Sgibbs	mvi	CLRSINT1,CLRBUSFREE
32013177Sgibbs	mvi	CLRSINT0,0x60			/* CLRSELDI|CLRSELDO */
32119921Sgibbs	or	SIMODE1, ENBUSFREE		/*
32219921Sgibbs						 * We aren't expecting a
32319921Sgibbs						 * bus free, so interrupt
32419921Sgibbs						 * the kernel driver if it
32519921Sgibbs						 * happens.
32619921Sgibbs						 */
32713177Sgibbs/*
32813177Sgibbs * Main loop for information transfer phases.  If BSY is false, then
32913177Sgibbs * we have a bus free condition, expected or not.  Otherwise, wait
33013177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O
33113177Sgibbs * for the bus phase.
33213177Sgibbs *
33313177Sgibbs */
3344568SgibbsITloop:
33513177Sgibbs	test	SSTAT1,BUSFREE	jnz p_busfree
33613177Sgibbs	test	SSTAT1,REQINIT	jz ITloop
3374568Sgibbs
33813177Sgibbs	and	A,PHASE_MASK,SCSISIGI
33913690Sgibbs	mov	LASTPHASE,A
34013690Sgibbs	mov	SCSISIGO,A
3414568Sgibbs
3424568Sgibbs	cmp	ALLZEROS,A	je p_dataout
34313177Sgibbs	cmp	A,P_DATAIN	je p_datain
34413177Sgibbs	cmp	A,P_COMMAND	je p_command
34513177Sgibbs	cmp	A,P_MESGOUT	je p_mesgout
34613177Sgibbs	cmp	A,P_STATUS	je p_status
34713177Sgibbs	cmp	A,P_MESGIN	je p_mesgin
3484568Sgibbs
34913177Sgibbs	mvi	INTSTAT,BAD_PHASE	/* unknown phase - signal driver */
35015843Sgibbs	jmp	ITloop			/* Try reading the bus again. */
3514568Sgibbs
3524568Sgibbsp_dataout:
35313177Sgibbs	mvi	DMAPARAMS,0x7d			/*
35413177Sgibbs						 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
35513177Sgibbs						 * DIRECTION|FIFORESET
35613177Sgibbs						 */
3579928Sgibbs	jmp	data_phase_init
3584568Sgibbs
35913177Sgibbs/*
36013177Sgibbs * If we re-enter the data phase after going through another phase, the
36113177Sgibbs * STCNT may have been cleared, so restore it from the residual field.
36213177Sgibbs */
3639928Sgibbsdata_phase_reinit:
36419231Sgibbs	mvi	DINDEX, STCNT0
36519231Sgibbs	mvi	SCB_RESID_DCNT0	call bcopy_3
3669928Sgibbs	jmp	data_phase_loop
3674568Sgibbs
3689928Sgibbsp_datain:
36913177Sgibbs	mvi	DMAPARAMS,0x79		/*
37013177Sgibbs					 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
37113177Sgibbs					 * !DIRECTION|FIFORESET
37213177Sgibbs					 */
3739928Sgibbsdata_phase_init:
37419164Sgibbs	call	assert			/*
37519164Sgibbs					 * Ensure entering a data
37619164Sgibbs					 * phase is okay - seen identify, etc.
37719164Sgibbs					 */
3785775Sgibbs
3799928Sgibbs	test	FLAGS, DPHASE	jnz data_phase_reinit
3804568Sgibbs
38119164Sgibbs	/*
38219164Sgibbs	 * Initialize the DMA address and counter from the SCB.
38319164Sgibbs	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
38419164Sgibbs	 * modify the values in the SCB itself until we see a
38519164Sgibbs	 * save data pointers message.
38619164Sgibbs	 */
38719164Sgibbs	mvi	DINDEX, HADDR0
38819164Sgibbs	mvi	SCB_DATAPTR	call bcopy_7
38919164Sgibbs
39019164Sgibbs	call	set_stcnt_from_hcnt
39119164Sgibbs
39219164Sgibbs	mov	SG_COUNT,SCB_SGCOUNT
39319164Sgibbs
39419164Sgibbs	mvi	DINDEX, SG_NEXT
39519164Sgibbs	mvi	SCB_SGPTR	call bcopy_4
39619164Sgibbs
39719164Sgibbs	/* We have seen a data phase */
39819164Sgibbs	or	FLAGS, DPHASE
39919164Sgibbs
4009928Sgibbsdata_phase_loop:
40116260Sgibbs/* Guard against overruns */
40216260Sgibbs	test	SG_COUNT, 0xff jnz data_phase_inbounds
40316260Sgibbs/*
40416260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to
40516260Sgibbs * 16meg and let the target run until it changes phase.
40616260Sgibbs * When the transfer completes, notify the host that we
40716260Sgibbs * had an overrun.
40816260Sgibbs */
40916260Sgibbs	or	SXFRCTL1,BITBUCKET
41019921Sgibbs	and	DMAPARAMS, 0xf7		/* Turn off HDMAEN */
41116260Sgibbs	mvi	STCNT0,0xff
41216260Sgibbs	mvi	STCNT1,0xff
41316260Sgibbs	mvi	STCNT2,0xff
41416260Sgibbs
41516260Sgibbsdata_phase_inbounds:
41619164Sgibbs/* If we are the last SG block, ensure wideodd is off. */
4179928Sgibbs	cmp	SG_COUNT,0x01 jne data_phase_wideodd
41813177Sgibbs	and	DMAPARAMS, 0xbf		/* Turn off WIDEODD */
4199928Sgibbsdata_phase_wideodd:
4209928Sgibbs	mov	DMAPARAMS  call dma
4214568Sgibbs
42216260Sgibbs/* Go tell the host about any overruns */
42316260Sgibbs	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun
42416260Sgibbs
42513177Sgibbs/* Exit if we had an underrun */
42613177Sgibbs	test	SSTAT0,SDONE	jz data_phase_finish /* underrun STCNT != 0 */
4277532Sgibbs
42813177Sgibbs/*
42913177Sgibbs * Advance the scatter-gather pointers if needed 
43013177Sgibbs */
4319928Sgibbssg_advance:
43213177Sgibbs	dec	SG_COUNT	/* one less segment to go */
4334568Sgibbs
43413177Sgibbs	test	SG_COUNT, 0xff	jz data_phase_finish /* Are we done? */
4354568Sgibbs
43613177Sgibbs	clr	A			/* add sizeof(struct scatter) */
43713177Sgibbs	add	SG_NEXT0,SG_SIZEOF,SG_NEXT0
43813177Sgibbs	adc	SG_NEXT1,A,SG_NEXT1
4394568Sgibbs
44013177Sgibbs/*
44113177Sgibbs * Load a struct scatter and set up the data address and length.
44213177Sgibbs * If the working value of the SG count is nonzero, then
44313177Sgibbs * we need to load a new set of values.
44413177Sgibbs *
44515328Sgibbs * This, like all DMA's, assumes little-endian host data storage.
44613177Sgibbs */
4479928Sgibbssg_load:
44813177Sgibbs	clr	HCNT2
44913177Sgibbs	clr	HCNT1
45013177Sgibbs	mvi	HCNT0,SG_SIZEOF
4514568Sgibbs
45219164Sgibbs	mvi	DINDEX, HADDR0
45319164Sgibbs	mvi	SG_NEXT0	call bcopy_4
4544568Sgibbs
45513690Sgibbs	or	DFCNTRL,0xd			/* HDMAEN|DIRECTION|FIFORESET */
4569928Sgibbs
45719164Sgibbs	call	dma_finish
4589928Sgibbs
45913177Sgibbs/*
46013177Sgibbs * Copy data from FIFO into SCB data pointer and data count.  This assumes
46119164Sgibbs * that the SG segments are of the form:
46213177Sgibbs *
46313177Sgibbs * struct ahc_dma_seg {
46419164Sgibbs *	u_int32_t	addr;		four bytes, little-endian order
46519164Sgibbs *	u_int32_t	len;		four bytes, little endian order
46613177Sgibbs * };
46713177Sgibbs */
46819164Sgibbs	mvi	HADDR0	call dfdat_in_7
4699928Sgibbs
47013177Sgibbs/* Load STCNT as well.  It is a mirror of HCNT */
47119164Sgibbs	call	set_stcnt_from_hcnt
47219164Sgibbs	test	SSTAT1,PHASEMIS  jz data_phase_loop
4734568Sgibbs
4749928Sgibbsdata_phase_finish:
47513177Sgibbs/*
47613177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB
47713177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
47813177Sgibbs * were transferred on the SCSI (as opposed to the host) bus.
47913177Sgibbs */
48013690Sgibbs	mov	SCB_RESID_DCNT0,STCNT0
48113690Sgibbs	mov	SCB_RESID_DCNT1,STCNT1
48213690Sgibbs	mov	SCB_RESID_DCNT2,STCNT2
48313177Sgibbs	mov	SCB_RESID_SGCNT, SG_COUNT
4844568Sgibbs	jmp	ITloop
4854568Sgibbs
48616260Sgibbsdata_phase_overrun:
48713177Sgibbs/*
48816260Sgibbs * Turn off BITBUCKET mode and notify the host
48916260Sgibbs */
49016260Sgibbs	and	SXFRCTL1,0x7f		/* ~BITBUCKET */
49116260Sgibbs	mvi	INTSTAT,DATA_OVERRUN
49216260Sgibbs	jmp	ITloop
49316260Sgibbs
49416260Sgibbs/*
49515328Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
49613177Sgibbs */
4974568Sgibbsp_command:
4984568Sgibbs	call	assert
4994568Sgibbs
50013177Sgibbs/*
50115328Sgibbs * Load HADDR and HCNT.
50213177Sgibbs */
50319164Sgibbs	mvi	DINDEX, HADDR0
50419164Sgibbs	mvi	SCB_CMDPTR	call bcopy_5
50513690Sgibbs	clr	HCNT1
50613690Sgibbs	clr	HCNT2
5074568Sgibbs
50819164Sgibbs	call	set_stcnt_from_hcnt
5094568Sgibbs
5104568Sgibbs	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
5114568Sgibbs						#   DIRECTION|FIFORESET
5124568Sgibbs	jmp	ITloop
5134568Sgibbs
51413177Sgibbs/*
51513177Sgibbs * Status phase.  Wait for the data byte to appear, then read it
51613177Sgibbs * and store it into the SCB.
51713177Sgibbs */
5184568Sgibbsp_status:
51919803Sgibbs	call	assert
52019803Sgibbs
52113177Sgibbs	mvi	SCB_TARGET_STATUS	call inb_first
5229954Sgibbs	jmp	mesgin_done
5234568Sgibbs
52413177Sgibbs/*
52515328Sgibbs * Message out phase.  If there is not an active message, but the target
52613177Sgibbs * took us into this phase anyway, build a no-op message and send it.
52713177Sgibbs */
5284568Sgibbsp_mesgout:
52913177Sgibbs	test	MSG_LEN, 0xff	jnz  p_mesgout_start
53018762Sgibbs	mvi	MSG_NOOP	call mk_mesg	/* build NOP message */
53113177Sgibbsp_mesgout_start:
53213177Sgibbs/*
53313177Sgibbs * Set up automatic PIO transfer from MSG0.  Bit 3 in
53413177Sgibbs * SXFRCTL0 (SPIOEN) is already on.
53513177Sgibbs */
53613177Sgibbs	mvi	SINDEX,MSG0
5374568Sgibbs	mov	DINDEX,MSG_LEN
5384568Sgibbs
53913177Sgibbs/*
54013177Sgibbs * When target asks for a byte, drop ATN if it's the last one in
54113177Sgibbs * the message.  Otherwise, keep going until the message is exhausted.
54213177Sgibbs *
54313177Sgibbs * Keep an eye out for a phase change, in case the target issues
54413177Sgibbs * a MESSAGE REJECT.
54513177Sgibbs */
54613177Sgibbsp_mesgout_loop:
54719906Sgibbs	test	SSTAT0,SPIORDY jz p_mesgout_loop
54819906Sgibbs	test	SSTAT1,PHASEMIS	jnz p_mesgout_done
54913177Sgibbs/*
55013177Sgibbs * If the next bus phase after ATN drops is a message out, it means
55113177Sgibbs * that the target is requesting that the last message(s) be resent.
55213177Sgibbs */
55319921Sgibbsp_mesgout_dropatn:
55419921Sgibbs	cmp	DINDEX,1	jne p_mesgout_testretry	/* last byte? */
55519921Sgibbs	mvi	CLRSINT1,CLRATNO			/* drop ATN */
55619921Sgibbsp_mesgout_testretry:
55719906Sgibbs	test	DINDEX,0xff	jnz p_mesgout_outb
55819906Sgibbs	or	SCSISIGO,ATNO		/* turn on ATN for the retry */
55919906Sgibbs	jmp	p_mesgout_start
56019906Sgibbsp_mesgout_outb:
56119906Sgibbs	dec	DINDEX
56219906Sgibbs	mvi	CLRSINT0, CLRSPIORDY
56319906Sgibbs	mov	SCSIDATL,SINDIR
56419906Sgibbs	jmp	p_mesgout_loop
5654568Sgibbs
56619906Sgibbsp_mesgout_done:
56715328Sgibbs	mvi	CLRSINT1,CLRATNO	/* Be sure to turn ATNO off */
56813177Sgibbs	clr	MSG_LEN			/* no active msg */
5694568Sgibbs	jmp	ITloop
5704568Sgibbs
57113177Sgibbs/*
57213177Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
57313177Sgibbs */
5744568Sgibbsp_mesgin:
57513177Sgibbs	mvi	A		call inb_first	/* read the 1st message byte */
57613177Sgibbs	mov	REJBYTE,A			/* save it for the driver */
5774568Sgibbs
57818762Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify
57913177Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect
58018762Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs
58113177Sgibbs	cmp	ALLZEROS,A		je mesgin_complete
58218762Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs
58313177Sgibbs	cmp	A,MSG_EXTENDED		je mesgin_extended
58418762Sgibbs	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject
5854568Sgibbs
5869954Sgibbsrej_mesgin:
58713177Sgibbs/*
58819164Sgibbs * We have no idea what this message in is, so we issue a message reject
58919164Sgibbs * and hope for the best.  In any case, rejection should be a rare
59019164Sgibbs * occurrence - signal the driver when it happens.
59113177Sgibbs */
59213177Sgibbs	mvi	INTSTAT,SEND_REJECT		/* let driver know */
5939954Sgibbs
59418762Sgibbs	mvi	MSG_MESSAGE_REJECT	call mk_mesg
5959954Sgibbs
5969954Sgibbsmesgin_done:
59713177Sgibbs	call	inb_last			/*ack & turn auto PIO back on*/
5989954Sgibbs	jmp	ITloop
5999954Sgibbs
6009954Sgibbs
6019954Sgibbsmesgin_complete:
60213177Sgibbs/*
60319164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
60419164Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
60519164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0).  In
60619164Sgibbs * either of these conditions, we upload the SCB back to the host so it can
60719164Sgibbs * process this information.  In the case of a non zero status byte, we 
60819164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
60919164Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
61019164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set
61119164Sgibbs * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
61219164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list.
61319164Sgibbs * If the kernel driver does not wish to request sense, it need only clear
61419164Sgibbs * RETURN_1, and the command is allowed to complete normally.  We don't bother
61519164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra
61619164Sgibbs * work in the kernel driver to ensure that the entry was removed before the
61719164Sgibbs * command complete code tried processing it.
61813177Sgibbs */
61919164Sgibbs
62013177Sgibbs/*
62119921Sgibbs * We expect to go to bus free after this message.
62219921Sgibbs */
62319921Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
62419921Sgibbs/*
62519164Sgibbs * First check for residuals
62613177Sgibbs */
62719164Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz upload_scb
62819164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Good Status? */
62919164Sgibbsupload_scb:
63019164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
63119164Sgibbs	mov	SCB_TAG		call dma_scb
6327532Sgibbscheck_status:
63319164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Just a residual? */
63413177Sgibbs	mvi	INTSTAT,BAD_STATUS			/* let driver know */
63513177Sgibbs	cmp	RETURN_1, SEND_SENSE	jne status_ok
63619164Sgibbs	/* This SCB becomes the next to execute as it will retrieve sense */
63719164Sgibbs	mov	SCB_LINKED_NEXT, SCB_TAG
63819164Sgibbs	jmp	dma_next_scb
6395326Sgibbs
6404568Sgibbsstatus_ok:
64113177Sgibbs/* First, mark this target as free. */
64219921Sgibbs	test	SCB_CONTROL,TAG_ENB jnz complete	/*
64313177Sgibbs							 * Tagged commands
64413177Sgibbs							 * don't busy the
64513177Sgibbs							 * target.
64613177Sgibbs							 */
64719164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
64819164Sgibbs	mov	SAVED_LINKPTR, SCB_LINKED_NEXT
64919218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
65019164Sgibbs	mov	DINDIR, SAVED_LINKPTR
65119164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
6525326Sgibbs
6535326Sgibbscomplete:
65419623Sgibbs	test	FLAGS, PAGESCBS jz complete_post
65519623Sgibbs	mov	A, QFULLCNT
65619623Sgibbscomplete_poll:
65719623Sgibbs	cmp	QOUTQCNT, A	je complete_poll
65819803Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
65919623Sgibbs	inc	QOUTQCNT
66019623Sgibbscomplete_post:
66119164Sgibbs	/* Post the SCB and issue an interrupt */
66215328Sgibbs	mov	QOUTFIFO,SCB_TAG
66319803Sgibbs	mvi	SEQCTL,0x10			/* FASTMODE */
6647532Sgibbs	mvi	INTSTAT,CMDCMPLT
66519164Sgibbs
66619164Sgibbsdma_next_scb:
66719921Sgibbs	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je add_to_free_list
66819164Sgibbs	test	FLAGS, PAGESCBS jnz dma_next_scb2
66919164Sgibbs	/* Only DMA on top of ourselves if we are the SCB to download */
67019164Sgibbs	mov	A, SCB_LINKED_NEXT
67119164Sgibbs	cmp	SCB_TAG, A	je dma_next_scb2
67219164Sgibbs	mov	SCBPTR, A
67319164Sgibbs	jmp	add_to_waiting_list
67419164Sgibbsdma_next_scb2:
67519164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
67619218Sgibbs	mov	SCB_LINKED_NEXT		call dma_scb
67719164Sgibbsadd_to_waiting_list:
67819164Sgibbs	mov	SCB_NEXT,WAITING_SCBH
67919164Sgibbs	mov	WAITING_SCBH, SCBPTR
6809954Sgibbs	jmp	mesgin_done
68119921Sgibbsadd_to_free_list:
68219921Sgibbs	call	add_scb_to_free_list
68319921Sgibbs	jmp	mesgin_done
6844568Sgibbs
68513177Sgibbs/*
68618762Sgibbs * Is it an extended message?  Copy the message to our message buffer and
68718762Sgibbs * notify the host.  The host will tell us whether to reject this message,
68818762Sgibbs * respond to it with the message that the host placed in our message buffer,
68918762Sgibbs * or simply to do nothing.
69013177Sgibbs */
6919954Sgibbsmesgin_extended:
69218762Sgibbs	mvi	MSGIN_EXT_LEN	 call inb_next
69318762Sgibbs	mov	A, MSGIN_EXT_LEN
69418762Sgibbsmesgin_extended_loop:
69519164Sgibbs	mov	DINDEX	call	inb_next
69618762Sgibbs	dec	A
69719164Sgibbs	cmp	DINDEX, MSGIN_EXT_LASTBYTE jne mesgin_extended_loop_test
69819164Sgibbs	dec	DINDEX		/* dump by repeatedly filling the last byte */
69919164Sgibbsmesgin_extended_loop_test:
70019164Sgibbs	test	A, 0xFF		jnz mesgin_extended_loop
70118762Sgibbsmesgin_extended_intr:
70218762Sgibbs	mvi	INTSTAT,EXTENDED_MSG		/* let driver know */
70318762Sgibbs	cmp	RETURN_1,SEND_REJ je rej_mesgin
70418762Sgibbs	cmp	RETURN_1,SEND_MSG jne mesgin_done
70518762Sgibbs/* The kernel has setup a message to be sent */
70613690Sgibbs	or	SCSISIGO,ATNO			/* turn on ATNO */
7079954Sgibbs	jmp	mesgin_done
7085562Sgibbs
70913177Sgibbs/*
71013177Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
71113177Sgibbs * and await the bus going free.
71213177Sgibbs */
7139954Sgibbsmesgin_disconnect:
71419921Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
71513177Sgibbs	or	SCB_CONTROL,DISCONNECTED
71615328Sgibbs	test	FLAGS, PAGESCBS jz mesgin_done
71719164Sgibbs	call	add_scb_to_disc_list
71819164Sgibbs	jmp	mesgin_done
71919164Sgibbs
72015328Sgibbs/*
72119164Sgibbs * Save data pointers message:
72219164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
72319164Sgibbs * only if we've actually been into a data phase to change them.  This
72419164Sgibbs * protects against bogus data in scratch ram and the residual counts
72519164Sgibbs * since they are only initialized when we go into data_in or data_out.
72615328Sgibbs */
72719164Sgibbsmesgin_sdptrs:
72819164Sgibbs	test	FLAGS, DPHASE	jz mesgin_done
72919164Sgibbs	mov	SCB_SGCOUNT,SG_COUNT
7304568Sgibbs
73119164Sgibbs	/* The SCB SGPTR becomes the next one we'll download */
73219164Sgibbs	mvi	DINDEX, SCB_SGPTR
73319164Sgibbs	mvi	SG_NEXT0	call bcopy_4
73419164Sgibbs	
73519164Sgibbs	/* The SCB DATAPTR0 becomes the current SHADDR */
73619164Sgibbs	mvi	DINDEX, SCB_DATAPTR0
73719164Sgibbs	mvi	SHADDR0		call bcopy_4
73819164Sgibbs
73913177Sgibbs/*
74019164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer.
74113177Sgibbs */
74219164Sgibbs	mvi	SCB_RESID_DCNT0	call	bcopy_3
74319164Sgibbs
7449954Sgibbs	jmp	mesgin_done
7454568Sgibbs
74613177Sgibbs/*
74713177Sgibbs * Restore pointers message?  Data pointers are recopied from the
74813177Sgibbs * SCB anytime we enter a data phase for the first time, so all
74913177Sgibbs * we need to do is clear the DPHASE flag and let the data phase
75013177Sgibbs * code do the rest.
75113177Sgibbs */
7529954Sgibbsmesgin_rdptrs:
75315328Sgibbs	and	FLAGS,0xef			/*
75413177Sgibbs						 * !DPHASE we'll reload them
75513177Sgibbs						 * the next time through
75613177Sgibbs						 */
7579954Sgibbs	jmp	mesgin_done
7584568Sgibbs
75913177Sgibbs/*
76013177Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
76113177Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
76213177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
76313177Sgibbs */
7649954Sgibbsmesgin_identify:
76513177Sgibbs	test	A,0x78	jnz rej_mesgin	/*!DiscPriv|!LUNTAR|!Reserved*/
76613177Sgibbs	and	A,0x07			/* lun in lower three bits */
76719164Sgibbs	or      SAVED_TCL,A		/* SAVED_TCL should be complete now */
76813177Sgibbs	call	inb_last		/* ACK */
76913177Sgibbs
77013177Sgibbs/*
77113177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
77215328Sgibbs * If we get one, we use the tag returned to switch to find the proper
77315328Sgibbs * SCB.  With SCB paging, this requires using findSCB for both tagged
77415328Sgibbs * and non-tagged transactions since the SCB may exist in any slot.
77515328Sgibbs * If we're not using SCB paging, we can use the tag as the direct
77615328Sgibbs * index to the SCB.
77713177Sgibbs */
77815328Sgibbs	mvi	ARG_1,SCB_LIST_NULL	/* Default to no-tag */
77913177Sgibbssnoop_tag_loop:
78019921Sgibbs	test	SSTAT0,SPIORDY		jz snoop_tag_loop
78118762Sgibbs	test	SSTAT1,PHASEMIS		jnz use_findSCB
78218762Sgibbs	mvi	A			call inb_first
78318762Sgibbs	cmp	A,MSG_SIMPLE_Q_TAG	jne use_findSCB
7846608Sgibbsget_tag:
78519218Sgibbs	or	FLAGS, TAGGED_SCB
78613177Sgibbs	mvi	ARG_1	call inb_next	/* tag value */
78713177Sgibbs/*
78813177Sgibbs * See if the tag is in range.  The tag is < SCBCOUNT if we add
78913177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is
79013177Sgibbs * no carry.
79113177Sgibbs */
79213177Sgibbs	mov	A,COMP_SCBCOUNT	
79313177Sgibbs	add	SINDEX,A,ARG_1
79419218Sgibbs	jc	send_abort_msg
79513177Sgibbs
79613177Sgibbs/*
79715328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction
79813177Sgibbs * to the reconnecting target.
79913177Sgibbs */
80015328Sgibbs	test	FLAGS, PAGESCBS	jz index_by_tag
80115328Sgibbsuse_findSCB:
80215328Sgibbs	mov	ALLZEROS	call findSCB	  /* Have to search */
80319218Sgibbs	cmp	SINDEX, SCB_LIST_NULL, je not_found
80415328Sgibbssetup_SCB:
80515328Sgibbs	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
80615328Sgibbs	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
80719164Sgibbs	test	SCB_CONTROL,TAG_ENB	jnz  mesgin_done /* Ack Tag */
80815328Sgibbs	jmp	ITloop
80915328Sgibbsindex_by_tag:
81013177Sgibbs	mov	SCBPTR,ARG_1
81119218Sgibbs	mov	A, SAVED_TCL
81219218Sgibbs	cmp	SCB_TCL,A		jne send_abort_msg
81319218Sgibbs	test	SCB_CONTROL,TAG_ENB	jz  send_abort_msg
81413177Sgibbs	jmp	setup_SCB
81515328Sgibbs
81619218Sgibbsnot_found:
81719218Sgibbs	mvi	INTSTAT, NO_MATCH
81819218Sgibbssend_abort_msg:
81919218Sgibbs	test	FLAGS, TAGGED_SCB jnz abort_tag_msg
82019218Sgibbs	mvi	MSG_ABORT	call mk_mesg
82119218Sgibbs	jmp	mesgin_done
82219164Sgibbsabort_tag_msg:
82315328Sgibbs	mvi	MSG_ABORT_TAG	call mk_mesg	/* ABORT TAG message */
82413177Sgibbs	jmp	mesgin_done
8256608Sgibbs
82613177Sgibbs/*
82713177Sgibbs * Message reject?  Let the kernel driver handle this.  If we have an 
82813177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 
82913177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
83013177Sgibbs * it since we have no clue what it pertains to.
83113177Sgibbs */
8329954Sgibbsmesgin_reject:
83313177Sgibbs	mvi	INTSTAT, REJECT_MSG
8349954Sgibbs	jmp	mesgin_done
8355562Sgibbs
83613177Sgibbs/*
83713177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ]
83813177Sgibbs */
8394568Sgibbs
84013177Sgibbs/*
84113177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX
84213177Sgibbs * if there is no active message already.  SINDEX is returned intact.
84313177Sgibbs */
8444568Sgibbsmk_mesg:
84513177Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
84613177Sgibbs	test	MSG_LEN,0xff	jz mk_mesg1	/* Should always succeed */
84713177Sgibbs	
84813177Sgibbs	/*
84913177Sgibbs	 * Hmmm.  For some reason the mesg buffer is in use.
85013177Sgibbs	 * Tell the driver.  It should look at SINDEX to find
85113177Sgibbs	 * out what we wanted to use the buffer for and resolve
85213177Sgibbs	 * the conflict.
85313177Sgibbs	 */
85413177Sgibbs	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
85513690Sgibbs	mvi	INTSTAT,MSG_BUFFER_BUSY
8564568Sgibbs
8574568Sgibbsmk_mesg1:
85819623Sgibbs	or	SCSISIGO,ATNO		/* turn on ATNO */
85913177Sgibbs	mvi	MSG_LEN,1		/* length = 1 */
86013177Sgibbs	mov	MSG0,SINDEX		/* 1-byte message */
86113177Sgibbs	mvi	SEQCTL,0x10	ret	/* !PAUSEDIS|FASTMODE */
8624568Sgibbs
86313177Sgibbs/*
86413177Sgibbs * Functions to read data in Automatic PIO mode.
86513177Sgibbs *
86613177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
86713177Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
86813177Sgibbs * latched (the usual way), then read the data byte directly off the bus
86913177Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
87013177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
87113177Sgibbs * spec guarantees that the target will hold the data byte on the bus until
87213177Sgibbs * we send our ACK.
87313177Sgibbs *
87413177Sgibbs * The assumption here is that these are called in a particular sequence,
87513177Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
87613177Sgibbs * use the same calling convention as inb.
87713177Sgibbs */
87813177Sgibbs
87913177Sgibbsinb_next:
88019803Sgibbs	call	inb_last	/* ACK */
88113360Sgibbsinb_next_wait:
88219906Sgibbs	test	SSTAT0, SPIORDY	jz inb_next_wait
88319803Sgibbs	test	SSTAT1,PHASEMIS	jnz mesgin_phasemis
88419623Sgibbsinb_first:
8854568Sgibbs	mov	DINDEX,SINDEX
88613177Sgibbs	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
88713177Sgibbsinb_last:
88819906Sgibbs	mvi	CLRSINT0, CLRSPIORDY
88913360Sgibbs	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
8904568Sgibbs
89113177Sgibbsmesgin_phasemis:
89213177Sgibbs/*
89313177Sgibbs * We expected to receive another byte, but the target changed phase
89413177Sgibbs */
89513177Sgibbs	mvi	INTSTAT, MSGIN_PHASEMIS
89613177Sgibbs	jmp	ITloop
8974568Sgibbs
89813177Sgibbs/*
89913177Sgibbs * DMA data transfer.  HADDR and HCNT must be loaded first, and
90013177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for
90113177Sgibbs * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
90213177Sgibbs * during initialization.
90313177Sgibbs */
9044568Sgibbsdma:
9054568Sgibbs	mov	DFCNTRL,SINDEX
9064568Sgibbsdma1:
90713177Sgibbs	test	SSTAT0,DMADONE	jnz dma3
90813177Sgibbs	test	SSTAT1,PHASEMIS	jz dma1		/* ie. underrun */
9094568Sgibbs
91013177Sgibbs/*
91113177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or
91213177Sgibbs * the target changes the phase (in light of this, it makes sense that
91313177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
91413177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
91513177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty
91613177Sgibbs * status.
91713177Sgibbs */
9184568Sgibbsdma3:
91913177Sgibbs	test	SINDEX,DIRECTION	jnz dma5
9204568Sgibbsdma4:
92113177Sgibbs	test	DFSTATUS,FIFOEMP	jz dma4
9224568Sgibbs
92313177Sgibbs/*
92413177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 
92513177Sgibbs * actually off first lest we get an ILLSADDR.
92613177Sgibbs */
9274568Sgibbsdma5:
92813177Sgibbs	/* disable DMA, but maintain WIDEODD */
92913690Sgibbs	and	DFCNTRL,WIDEODD
9304568Sgibbsdma6:
93113177Sgibbs	test	DFCNTRL,0x38	jnz dma6  /* SCSIENACK|SDMAENACK|HDMAENACK */
93218762Sgibbsreturn:
9334568Sgibbs	ret
9344568Sgibbs
93513177Sgibbs/*
93613177Sgibbs * Common SCSI initialization for selection and reselection.  Expects
93713177Sgibbs * the target SCSI ID to be in the upper four bits of SINDEX, and A's
93813177Sgibbs * contents are stomped on return.
93913177Sgibbs */
9408104Sgibbsinitialize_scsiid:
94113177Sgibbs	and	SINDEX,0xf0		/* Get target ID */
94219164Sgibbs	mov	SAVED_TCL, SINDEX	/* Update the target portion of this */
9435775Sgibbs	and	A,0x0f,SCSIID
9445775Sgibbs	or	SINDEX,A
9458104Sgibbs	mov	SCSIID,SINDEX ret
9465326Sgibbs
94713177Sgibbs/*
94813177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
94913177Sgibbs * message.
95013177Sgibbs */
9514568Sgibbsassert:
95213177Sgibbs	test	FLAGS,RESELECTED	jz return	/* reselected? */
95313177Sgibbs	test	FLAGS,IDENTIFY_SEEN	jnz return	/* seen IDENTIFY? */
9544568Sgibbs
95519164Sgibbs	mvi	INTSTAT,NO_IDENT 	ret	/* no - tell the kernel */
9564568Sgibbs
95713177Sgibbs/*
95819218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
95919218Sgibbs * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
96019218Sgibbs * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
96119218Sgibbs * otherwise, SCBPTR is set to the proper SCB.
96213177Sgibbs */
9634568SgibbsfindSCB:
96415328Sgibbs	mov	SCBPTR,SINDEX			/* switch to next SCB */
96513177Sgibbs	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
96619218Sgibbs	cmp	ARG_1, SCB_LIST_NULL	jne findBySCBID
96719218Sgibbs	mov	A, SAVED_TCL
96819218Sgibbs	cmp	SCB_TCL,A	je foundSCB /* target ID/channel/lun match? */
96919164SgibbsfindSCB1:
97019164Sgibbs	inc	SINDEX
97119164Sgibbs	mov	A,SCBCOUNT
97219164Sgibbs	cmp	SINDEX,A	jne findSCB
97319164Sgibbs/*
97419164Sgibbs * We didn't find it.  If we're paging, pull an SCB and DMA down the
97519164Sgibbs * one we want.  If we aren't paging or the SCB we dma down has the
97619218Sgibbs * abort flag set, return not found.
97719164Sgibbs */
97819218Sgibbs	test	FLAGS, PAGESCBS	jz find_error
97919623Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb
98019218Sgibbs	cmp	ARG_1, SCB_LIST_NULL jne find_dma_scb
98119218Sgibbs	mov	SAVED_TCL	call	index_untagged_scb
98219218Sgibbs	mov	ARG_1, SINDIR	/* SCBID of SCB to fetch */
98319164Sgibbsfind_dma_scb:
98419164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
98519218Sgibbs	mov	ARG_1	call dma_scb
98619164Sgibbs	test	SCB_CONTROL, ABORT_SCB jz return
98719218Sgibbsfind_error:
98819218Sgibbs	mvi	SINDEX, SCB_LIST_NULL ret
98919218SgibbsfindBySCBID:
99015328Sgibbs	mov	A, ARG_1			/* Tag passed in ARG_1 */
99115328Sgibbs	cmp	SCB_TAG,A	jne findSCB1	/* Found it? */
99215328SgibbsfoundSCB:
99319218Sgibbs	test	SCB_CONTROL, ABORT_SCB jnz find_error
99419164Sgibbs	test	FLAGS,PAGESCBS	jz return
99519164Sgibbsrem_scb_from_disc_list:
99615328Sgibbs/* Remove this SCB from the disconnection list */
99715328Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev
99815328Sgibbs	mov	SAVED_LINKPTR, SCB_PREV
99915328Sgibbs	mov	SCBPTR, SCB_NEXT
100015328Sgibbs	mov	SCB_PREV, SAVED_LINKPTR
100115328Sgibbs	mov	SCBPTR, SINDEX
100215328Sgibbsunlink_prev:
100315328Sgibbs	cmp	SCB_PREV,SCB_LIST_NULL	je rHead/* At the head of the list */
100415328Sgibbs	mov	SAVED_LINKPTR, SCB_NEXT
100515328Sgibbs	mov	SCBPTR, SCB_PREV
100615328Sgibbs	mov	SCB_NEXT, SAVED_LINKPTR
100719164Sgibbs	mov	SCBPTR, SINDEX ret
100815328SgibbsrHead:
100919164Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret
10104568Sgibbs
101119164Sgibbsset_stcnt_from_hcnt:
101219164Sgibbs	mov	STCNT0, HCNT0
101319164Sgibbs	mov	STCNT1, HCNT1
101419164Sgibbs	mov	STCNT2, HCNT2 ret
10154568Sgibbs
101619164Sgibbsbcopy_7:
101719164Sgibbs	mov	DINDIR, SINDIR
101819164Sgibbs	mov	DINDIR, SINDIR
101919164Sgibbsbcopy_5:
102019164Sgibbs	mov	DINDIR, SINDIR
102119164Sgibbsbcopy_4:
102219164Sgibbs	mov	DINDIR, SINDIR
102319164Sgibbsbcopy_3:
102419164Sgibbs	mov	DINDIR, SINDIR
102519164Sgibbs	mov	DINDIR, SINDIR
102619164Sgibbs	mov	DINDIR, SINDIR ret
10274568Sgibbs
102819164Sgibbsdma_scb:
102919164Sgibbs	/*
103019164Sgibbs	 * SCB index is in SINDEX.  Determine the physical address in
103119164Sgibbs	 * the host where this SCB is located and load HADDR with it.
103219164Sgibbs	 */
103319164Sgibbs	shr	DINDEX, SINDEX, 3
103419164Sgibbs	shl	A, SINDEX, 5
103519164Sgibbs	add	HADDR0, A, HSCB_ADDR0
103619164Sgibbs	mov	A, DINDEX
103719164Sgibbs	adc	HADDR1, A, HSCB_ADDR1
103819164Sgibbs	clr	A
103919164Sgibbs	adc	HADDR2, A, HSCB_ADDR2
104019164Sgibbs	adc	HADDR3, A, HSCB_ADDR3
104119164Sgibbs	/* Setup Count */
104219164Sgibbs	mvi	HCNT0, 28
104319164Sgibbs	clr	HCNT1
104419164Sgibbs	clr	HCNT2
104519164Sgibbs	mov	DFCNTRL, DMAPARAMS
104619164Sgibbs	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost
104719164Sgibbs	/* Fill it with the SCB data */
104819164Sgibbs	call	copy_scb_tofifo
104919164Sgibbs	mvi	DFCNTRL, 0xa		/* HDMAEN | FIFOFLUSH */
105019164Sgibbsdma_scb_fromhost:
105119164Sgibbs	call	dma_finish
105219164Sgibbs	/* If we were putting the SCB, we are done */
105319164Sgibbs	test	DMAPARAMS, DIRECTION	jz	return
105419164Sgibbs	mvi	SCBARRAY  call dfdat_in_7
105519164Sgibbs	call	dfdat_in_7_continued
105619164Sgibbs	call	dfdat_in_7_continued
105719164Sgibbs	jmp	dfdat_in_7_continued
105819164Sgibbsdfdat_in_7:
105919164Sgibbs	mov     DINDEX,SINDEX
106019164Sgibbsdfdat_in_7_continued:
106119164Sgibbs	mov	DINDIR,DFDAT
106219164Sgibbs	mov	DINDIR,DFDAT
106319164Sgibbs	mov	DINDIR,DFDAT
106419164Sgibbs	mov	DINDIR,DFDAT
106519164Sgibbs	mov	DINDIR,DFDAT
106619164Sgibbs	mov	DINDIR,DFDAT
106719164Sgibbs	mov	DINDIR,DFDAT ret
106819164Sgibbs
106919164Sgibbscopy_scb_tofifo:
107019164Sgibbs	mvi	SCBARRAY  call dfdat_out_7
107119164Sgibbs	call	dfdat_out_7
107219164Sgibbs	call	dfdat_out_7
107319164Sgibbsdfdat_out_7:
107419164Sgibbs	mov	DFDAT,SINDIR
107519164Sgibbs	mov	DFDAT,SINDIR
107619164Sgibbs	mov	DFDAT,SINDIR
107719164Sgibbs	mov	DFDAT,SINDIR
107819164Sgibbs	mov	DFDAT,SINDIR
107919164Sgibbs	mov	DFDAT,SINDIR
108019164Sgibbs	mov	DFDAT,SINDIR ret
108119164Sgibbs
108213177Sgibbs/*
108319164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
108419164Sgibbs * DMA and wait for it to acknowledge that it's off.
108513177Sgibbs */
108619164Sgibbsdma_finish:
108719164Sgibbs	test	DFSTATUS,HDONE	jz dma_finish
108819164Sgibbs	/* Turn off DMA preserving WIDEODD */
108919164Sgibbs	and	DFCNTRL,WIDEODD
109019164Sgibbsdma_finish2:
109119164Sgibbs	test	DFCNTRL,HDMAENACK jnz dma_finish2
109219164Sgibbs	ret
10939928Sgibbs
109419164Sgibbsindex_untagged_scb:
109519218Sgibbs	mov	DINDEX, SINDEX
109619218Sgibbs	shr	DINDEX, 4
109719218Sgibbs	and	DINDEX, 0x03			/* Bottom two bits of tid */
109819218Sgibbs	add	DINDEX, SCB_ACTIVE0
109919218Sgibbs	shr	A, SINDEX, 6			/* Target ID divided by 4 */
110019421Sgibbs	test	SINDEX, SELBUSB jz index_untagged_scb2
110119421Sgibbs	add	A, 2				/* Add 2 positions */
110219164Sgibbsindex_untagged_scb2:
110319164Sgibbs	mov	SCBPTR, A			/*
110419164Sgibbs						 * Select the SCB with this 
110519164Sgibbs						 * target's information.
110619164Sgibbs						 */
110719218Sgibbs	mov	SINDEX, DINDEX	ret
11089928Sgibbs
11094568Sgibbs
111019164Sgibbsget_free_or_disc_scb:
111119623Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb
111219623Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb
111319623Sgibbsreturn_error:
111419623Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret
111519623Sgibbsdequeue_disc_scb:
111619164Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH
111713177Sgibbs/*
111819164Sgibbs * If we have a residual, then we are in the middle of some I/O
111919164Sgibbs * and we have to send this SCB back up to the kernel so that the
112019164Sgibbs * saved data pointers and residual information isn't lost.
112119164Sgibbs */
112219164Sgibbs	test	SCB_RESID_SGCNT,0xff	jz unlink_disc_scb
112319164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
112419164Sgibbs	mov	SCB_TAG		call dma_scb
112519164Sgibbsunlink_disc_scb:
112619623Sgibbs	/* jmp instead of call since we want to return anyway */
112719623Sgibbs	mov	SCBPTR	jmp rem_scb_from_disc_list
112819164Sgibbsdequeue_free_scb:
112919164Sgibbs	mov	SCBPTR, FREE_SCBH
113019164Sgibbs	mov	FREE_SCBH, SCB_NEXT ret
11314568Sgibbs
113219164Sgibbsadd_scb_to_free_list:
113319164Sgibbs	mov	SCB_NEXT, FREE_SCBH
113419164Sgibbs	mov	FREE_SCBH, SCBPTR ret
11354568Sgibbs
113619164Sgibbsadd_scb_to_disc_list:
113713177Sgibbs/*
113819164Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
113919164Sgibbs * candidates for paging out an SCB if one is needed for a new command.
114019164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
114113177Sgibbs */
114219164Sgibbs	mvi	SCB_PREV, SCB_LIST_NULL
114319164Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH
114419164Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR
114519164Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je return
114619164Sgibbs	mov	SCBPTR,SCB_NEXT
114719164Sgibbs	mov	SCB_PREV,DISCONNECTED_SCBH
114819164Sgibbs	mov	SCBPTR,DISCONNECTED_SCBH ret
11494568Sgibbs
1150