aic7xxx.seq revision 19218
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
4219218SgibbsVERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.44 1996/10/25 06:34:56 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 */
8514449Sgibbs/*
8614449Sgibbs * We jump to start after every bus free.
8714449Sgibbs */
8813177Sgibbsstart:
8919164Sgibbs	and	FLAGS,0x07		/* clear target specific flags */
9013177Sgibbs	mvi	SCSISEQ,ENRSELI		/* Always allow reselection */
9116198Sgibbs	clr	SCSIRATE		/*
9216198Sgibbs					 * We don't know the target we will
9316198Sgibbs					 * connect to, so default to narrow
9416198Sgibbs					 * transfers to avoid parity problems.
9516198Sgibbs					 */
968104Sgibbspoll_for_work:
9713177Sgibbs	/*
9813177Sgibbs	 * Are we a twin channel device?
9913177Sgibbs	 * For fairness, we check the other bus first,
10013177Sgibbs	 * since we just finished a transaction on the
10113177Sgibbs	 * current channel.
10213177Sgibbs	 */
10313177Sgibbs	test	FLAGS,TWIN_BUS	jz start2
10413177Sgibbs	xor	SBLKCTL,SELBUSB			/* Toggle to the other bus */
1058104Sgibbs	test	SSTAT0,SELDI	jnz reselect
10613177Sgibbs	xor	SBLKCTL,SELBUSB			/* Toggle to the original bus */
1075326Sgibbsstart2:
1088104Sgibbs	test	SSTAT0,SELDI	jnz reselect
10919164Sgibbs	cmp	WAITING_SCBH,SCB_LIST_NULL je test_queue
11019164Sgibbsstart_waiting:
11119164Sgibbs	/*
11219164Sgibbs	 * Pull the first entry off of the waiting SCB list
11319164Sgibbs	 * We don't have to "test_busy" because only transactions that
11419164Sgibbs	 * have passed that test can be in the WAITING_SCB list.
11519164Sgibbs	 */
11619164Sgibbs	mov	SCBPTR,WAITING_SCBH
11719164Sgibbs	jmp	start_scb2
11819164Sgibbstest_queue:
11919164Sgibbs	/* Has the driver posted any work for us? */
12014934Sgibbs	mov	A, QCNTMASK
12114934Sgibbs	test	QINCNT,A	jz poll_for_work
1224568Sgibbs
12313690Sgibbs/*
12413690Sgibbs * We have at least one queued SCB now and we don't have any 
12519164Sgibbs * SCBs in the list of SCBs awaiting selection.  If we have
12619164Sgibbs * any SCBs availible for use, pull the tag from the QINFIFO
12719164Sgibbs * and get to work on it.
12813177Sgibbs */
12919164Sgibbs	test	FLAGS, PAGESCBS	jz	dequeue_scb
13019164Sgibbs	call	get_free_or_disc_scb
13119164Sgibbs	cmp	SINDEX, SCB_LIST_NULL	je poll_for_work
13219164Sgibbsdequeue_scb:
13319164Sgibbs	mov	CUR_SCBID,QINFIFO
13419164Sgibbs	test	FLAGS, PAGESCBS jnz dma_queued_scb
13519164Sgibbs	/* In the non-paging case, the SCBID == hardware SCB index */
13619164Sgibbs	mov	SCBPTR, CUR_SCBID
13719164Sgibbsdma_queued_scb:
13819164Sgibbs/*
13919164Sgibbs * DMA the SCB from host ram into the current SCB location.
14019164Sgibbs */
14119164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
14219164Sgibbs	mov	CUR_SCBID	call dma_scb
1434568Sgibbs
14413177Sgibbs/*
14513177Sgibbs * See if there is not already an active SCB for this target.  This code
14613177Sgibbs * locks out on a per target basis instead of target/lun.  Although this
14713177Sgibbs * is not ideal for devices that have multiple luns active at the same
14813177Sgibbs * time, it is faster than looping through all SCB's looking for active
14919164Sgibbs * commands.  We also don't have enough spare SCB space for to store the
15019164Sgibbs * SCBID of the currently busy transaction for each target/lun making it
15119164Sgibbs * impossible to link up the SCBs.
15213177Sgibbs */
1535647Sgibbstest_busy:
15419164Sgibbs	test	SCB_CONTROL, TAG_ENB	jnz start_scb
15519164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
15619218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
15719164Sgibbs	mov	ARG_1, SINDIR			/*
15819164Sgibbs						 * ARG_1 should
15919164Sgibbs						 * now have the SCB ID of
16019164Sgibbs						 * any active, non-tagged,
16119164Sgibbs						 * command for this target.
16219164Sgibbs						 */
16319164Sgibbs	cmp	ARG_1, SCB_LIST_NULL je make_busy
16419164Sgibbs	test	FLAGS, PAGESCBS jz simple_busy_link
16519164Sgibbs	/*
16619164Sgibbs	 * Put this SCB back onto the free list.  It
16719164Sgibbs	 * may be necessary to satisfy the search for
16819164Sgibbs	 * the active SCB.
16919164Sgibbs	 */
17019218Sgibbs	mov	SCBPTR, SAVED_SCBPTR
17119164Sgibbs	call	add_scb_to_free_list
17219164Sgibbs	/* Find the active SCB */
17319164Sgibbs	mov	ALLZEROS	call findSCB
17419218Sgibbs	/*
17519218Sgibbs	 * If we couldn't find it, tell the kernel.  This should
17619218Sgibbs	 * only happen if the parent SCB was aborted and this
17719218Sgibbs	 * one was already here at the time of the abort.
17819218Sgibbs	 */
17919218Sgibbs	cmp	SINDEX, SCB_LIST_NULL	jne paged_busy_link
18019218Sgibbs	mvi	INTSTAT, NO_MATCH_BUSY
18119218Sgibbspaged_busy_link:
18219164Sgibbs	/* Link us in */
18319164Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
18419164Sgibbs	/* Put it back on the disconnected list */
18519164Sgibbs	call	add_scb_to_disc_list
1868104Sgibbs	jmp	poll_for_work
18719164Sgibbssimple_busy_link:
18819164Sgibbs	mov	SCBPTR, ARG_1
18919164Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
19019164Sgibbs	jmp	poll_for_work
19119164Sgibbsmake_busy:
19219164Sgibbs	mov	DINDIR, CUR_SCBID
19319164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
1944568Sgibbs
1955326Sgibbsstart_scb:
19619164Sgibbs	/*
19719164Sgibbs	 * Place us on the waiting list in case our selection
19819164Sgibbs	 * doesn't win during bus arbitration.
19919164Sgibbs	 */
20015328Sgibbs	mov	SCB_NEXT,WAITING_SCBH
20113177Sgibbs	mov	WAITING_SCBH, SCBPTR
20213177Sgibbsstart_scb2:
20313177Sgibbs	and	SINDEX,0xf7,SBLKCTL	/* Clear the channel select bit */
20413177Sgibbs	and	A,0x08,SCB_TCL		/* Get new channel bit */
20513177Sgibbs	or	SINDEX,A
20613177Sgibbs	mov	SBLKCTL,SINDEX		/* select channel */
20713177Sgibbs	mov	SCB_TCL	call initialize_scsiid
2088104Sgibbs
20913177Sgibbs/*
21013177Sgibbs * Enable selection phase as an initiator, and do automatic ATN
21113177Sgibbs * after the selection.  We do this now so that we can overlap the
21213177Sgibbs * rest of our work to set up this target with the arbitration and
21313177Sgibbs * selection bus phases.
21413177Sgibbs */
2158104Sgibbsstart_selection:
21613177Sgibbs	mvi	SCSISEQ,0x58		/* ENSELO|ENAUTOATNO|ENRSELI */
2174568Sgibbs
21813177Sgibbs/*
21913177Sgibbs * As soon as we get a successful selection, the target should go
22013177Sgibbs * into the message out phase since we have ATN asserted.  Prepare
22113177Sgibbs * the message to send.
22213177Sgibbs *
22313177Sgibbs * Messages are stored in scratch RAM starting with a length byte
22413177Sgibbs * followed by the message itself.
22513177Sgibbs */
2268567Sdg
22713177Sgibbsmk_identify:
22819164Sgibbs	and	MSG0,0x7,SCB_TCL	/* lun */
22913177Sgibbs	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privledge */
23013690Sgibbs	or	MSG0,A			/* or in disconnect privledge */
23118762Sgibbs	or	MSG0,MSG_IDENTIFYFLAG
23213690Sgibbs	mvi	MSG_LEN, 1
2334568Sgibbs
23413177Sgibbs/*
23515328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
23615328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
23713177Sgibbs */
2386608Sgibbsmk_tag:
23918762Sgibbs	test	SCB_CONTROL,TAG_ENB jz  mk_message
24019164Sgibbs	and	MSG1,0x23,SCB_CONTROL
24119164Sgibbs	mov	MSG2,SCB_TAG
24219164Sgibbs	add	MSG_LEN,2	/* update message length */
2436608Sgibbs
24418762Sgibbs/*
24518762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer
24618762Sgibbs * if it asks.
24718762Sgibbs */
24818762Sgibbsmk_message:
24918762Sgibbs	test	SCB_CONTROL,MK_MESSAGE  jz wait_for_selection
2506608Sgibbs
25118762Sgibbs	mvi     INTSTAT,AWAITING_MSG
2526608Sgibbs
2539917Sgibbswait_for_selection:
25413177Sgibbs	test	SSTAT0,SELDO	jnz select 
25513177Sgibbs	test	SSTAT0,SELDI	jz wait_for_selection
2564568Sgibbs
25713177Sgibbs/*
25813177Sgibbs * Reselection has been initiated by a target. Make a note that we've been
25919164Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
26013177Sgibbs */
2614568Sgibbsreselect:
26213177Sgibbs	clr	MSG_LEN		/* Don't have anything in the mesg buffer */
2638104Sgibbs	mov	SELID		call initialize_scsiid
26413177Sgibbs	or	FLAGS,RESELECTED
26513177Sgibbs	jmp	select2
2664568Sgibbs
26713177Sgibbs/*
26819164Sgibbs * After the selection, remove this SCB from the "waiting SCB"
26913177Sgibbs * list.  This is achieved by simply moving our "next" pointer into
27013177Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
27113177Sgibbs * SCB is used, so don't bother with it now.
27213177Sgibbs */
2738104Sgibbsselect:
27415328Sgibbs	mov	WAITING_SCBH,SCB_NEXT
2758104Sgibbsselect2:
27613177Sgibbs/*
27713177Sgibbs * Initialize SCSIRATE with the appropriate value for this target.
27819164Sgibbs * The SCSIRATE settings for each target are stored in an array
27919164Sgibbs * based at TARG_SCRATCH.
28013177Sgibbs */
28119164Sgibbsndx_dtr:
28219164Sgibbs	shr	A,SCSIID,4
28319164Sgibbs	test	SBLKCTL,SELBUSB	jz ndx_dtr_2
28419164Sgibbs	or	SAVED_TCL, SELBUSB /* Add the channel bit while we're here */
28519164Sgibbs	or	A,0x08		/* Channel B entries add 8 */
28619164Sgibbsndx_dtr_2:
28719164Sgibbs	add	SINDEX,TARG_SCRATCH,A
28813177Sgibbs	mov	SCSIRATE,SINDIR
28913177Sgibbs
29015843Sgibbs/*
29119164Sgibbs * Initialize Ultra mode setting and clear the SCSI channel.
29215843Sgibbs */
29319164Sgibbsultra:
29419164Sgibbs	and	DINDEX,0xdf,SXFRCTL0            /* default to Ultra disabled */
29519164Sgibbs	/*
29619164Sgibbs	 * Set CLRCHN here before the target has entered a data transfer mode -
29719164Sgibbs	 * with synchronous SCSI, if you do it later, you blow away some
29819164Sgibbs	 * data in the SCSI FIFO that the target has already sent to you.
29919164Sgibbs	 */
30019164Sgibbs	or	DINDEX, CLRCHN
30119164Sgibbs	mvi	SINDEX, ULTRA_ENB_B
30219164Sgibbs	test	SCSIID, 0x80     jnz ultra_2     /* Target ID > 7 */
30319164Sgibbs	test	SBLKCTL, SELBUSB jnz ultra_2     /* Second channel device */
30419164Sgibbs	dec	SINDEX
30519164Sgibbsultra_2:
30619164Sgibbs	mov     FUNCTION1,SCSIID 
30719164Sgibbs	mov     A,FUNCTION1
30819164Sgibbs	test	SINDIR, A	jz set_sxfrctl0
30919164Sgibbs	or	DINDEX, ULTRAEN
31019164Sgibbs 
31115843Sgibbsset_sxfrctl0:
31219164Sgibbs	mov	SXFRCTL0,DINDEX
31315843Sgibbs
31416198Sgibbs	mvi	SCSISEQ,ENAUTOATNP		/*
31516198Sgibbs						 * ATN on parity errors
31616198Sgibbs						 * for "in" phases
31713177Sgibbs						 */
31813177Sgibbs	mvi	CLRSINT1,CLRBUSFREE
31913177Sgibbs	mvi	CLRSINT0,0x60			/* CLRSELDI|CLRSELDO */
32013177Sgibbs/*
32113177Sgibbs * Main loop for information transfer phases.  If BSY is false, then
32213177Sgibbs * we have a bus free condition, expected or not.  Otherwise, wait
32313177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O
32413177Sgibbs * for the bus phase.
32513177Sgibbs *
32613177Sgibbs */
3274568SgibbsITloop:
32813177Sgibbs	test	SSTAT1,BUSFREE	jnz p_busfree
32913177Sgibbs	test	SSTAT1,REQINIT	jz ITloop
3304568Sgibbs
33113177Sgibbs	and	A,PHASE_MASK,SCSISIGI
33213690Sgibbs	mov	LASTPHASE,A
33313690Sgibbs	mov	SCSISIGO,A
3344568Sgibbs
3354568Sgibbs	cmp	ALLZEROS,A	je p_dataout
33613177Sgibbs	cmp	A,P_DATAIN	je p_datain
33713177Sgibbs	cmp	A,P_COMMAND	je p_command
33813177Sgibbs	cmp	A,P_MESGOUT	je p_mesgout
33913177Sgibbs	cmp	A,P_STATUS	je p_status
34013177Sgibbs	cmp	A,P_MESGIN	je p_mesgin
3414568Sgibbs
34213177Sgibbs	mvi	INTSTAT,BAD_PHASE	/* unknown phase - signal driver */
34315843Sgibbs	jmp	ITloop			/* Try reading the bus again. */
3444568Sgibbs
3454568Sgibbsp_dataout:
34613177Sgibbs	mvi	DMAPARAMS,0x7d			/*
34713177Sgibbs						 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
34813177Sgibbs						 * DIRECTION|FIFORESET
34913177Sgibbs						 */
3509928Sgibbs	jmp	data_phase_init
3514568Sgibbs
35213177Sgibbs/*
35313177Sgibbs * If we re-enter the data phase after going through another phase, the
35413177Sgibbs * STCNT may have been cleared, so restore it from the residual field.
35513177Sgibbs */
3569928Sgibbsdata_phase_reinit:
35719218Sgibbs	mov	DINDEX, STCNT0
35819218Sgibbs	mov	SCB_RESID_DCNT0	call bcopy_3
3599928Sgibbs	jmp	data_phase_loop
3604568Sgibbs
3619928Sgibbsp_datain:
36213177Sgibbs	mvi	DMAPARAMS,0x79		/*
36313177Sgibbs					 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
36413177Sgibbs					 * !DIRECTION|FIFORESET
36513177Sgibbs					 */
3669928Sgibbsdata_phase_init:
36719164Sgibbs	call	assert			/*
36819164Sgibbs					 * Ensure entering a data
36919164Sgibbs					 * phase is okay - seen identify, etc.
37019164Sgibbs					 */
3715775Sgibbs
3729928Sgibbs	test	FLAGS, DPHASE	jnz data_phase_reinit
3734568Sgibbs
37419164Sgibbs	/*
37519164Sgibbs	 * Initialize the DMA address and counter from the SCB.
37619164Sgibbs	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
37719164Sgibbs	 * modify the values in the SCB itself until we see a
37819164Sgibbs	 * save data pointers message.
37919164Sgibbs	 */
38019164Sgibbs	mvi	DINDEX, HADDR0
38119164Sgibbs	mvi	SCB_DATAPTR	call bcopy_7
38219164Sgibbs
38319164Sgibbs	call	set_stcnt_from_hcnt
38419164Sgibbs
38519164Sgibbs	mov	SG_COUNT,SCB_SGCOUNT
38619164Sgibbs
38719164Sgibbs	mvi	DINDEX, SG_NEXT
38819164Sgibbs	mvi	SCB_SGPTR	call bcopy_4
38919164Sgibbs
39019164Sgibbs	/* We have seen a data phase */
39119164Sgibbs	or	FLAGS, DPHASE
39219164Sgibbs
3939928Sgibbsdata_phase_loop:
39416260Sgibbs/* Guard against overruns */
39516260Sgibbs	test	SG_COUNT, 0xff jnz data_phase_inbounds
39616260Sgibbs/*
39716260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to
39816260Sgibbs * 16meg and let the target run until it changes phase.
39916260Sgibbs * When the transfer completes, notify the host that we
40016260Sgibbs * had an overrun.
40116260Sgibbs */
40216260Sgibbs	or	SXFRCTL1,BITBUCKET
40316260Sgibbs	mvi	STCNT0,0xff
40416260Sgibbs	mvi	STCNT1,0xff
40516260Sgibbs	mvi	STCNT2,0xff
40616260Sgibbs
40716260Sgibbsdata_phase_inbounds:
40819164Sgibbs/* If we are the last SG block, ensure wideodd is off. */
4099928Sgibbs	cmp	SG_COUNT,0x01 jne data_phase_wideodd
41013177Sgibbs	and	DMAPARAMS, 0xbf		/* Turn off WIDEODD */
4119928Sgibbsdata_phase_wideodd:
4129928Sgibbs	mov	DMAPARAMS  call dma
4134568Sgibbs
41416260Sgibbs/* Go tell the host about any overruns */
41516260Sgibbs	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun
41616260Sgibbs
41713177Sgibbs/* Exit if we had an underrun */
41813177Sgibbs	test	SSTAT0,SDONE	jz data_phase_finish /* underrun STCNT != 0 */
4197532Sgibbs
42013177Sgibbs/*
42113177Sgibbs * Advance the scatter-gather pointers if needed 
42213177Sgibbs */
4239928Sgibbssg_advance:
42413177Sgibbs	dec	SG_COUNT	/* one less segment to go */
4254568Sgibbs
42613177Sgibbs	test	SG_COUNT, 0xff	jz data_phase_finish /* Are we done? */
4274568Sgibbs
42813177Sgibbs	clr	A			/* add sizeof(struct scatter) */
42913177Sgibbs	add	SG_NEXT0,SG_SIZEOF,SG_NEXT0
43013177Sgibbs	adc	SG_NEXT1,A,SG_NEXT1
4314568Sgibbs
43213177Sgibbs/*
43313177Sgibbs * Load a struct scatter and set up the data address and length.
43413177Sgibbs * If the working value of the SG count is nonzero, then
43513177Sgibbs * we need to load a new set of values.
43613177Sgibbs *
43715328Sgibbs * This, like all DMA's, assumes little-endian host data storage.
43813177Sgibbs */
4399928Sgibbssg_load:
44013177Sgibbs	clr	HCNT2
44113177Sgibbs	clr	HCNT1
44213177Sgibbs	mvi	HCNT0,SG_SIZEOF
4434568Sgibbs
44419164Sgibbs	mvi	DINDEX, HADDR0
44519164Sgibbs	mvi	SG_NEXT0	call bcopy_4
4464568Sgibbs
44713690Sgibbs	or	DFCNTRL,0xd			/* HDMAEN|DIRECTION|FIFORESET */
4489928Sgibbs
44919164Sgibbs	call	dma_finish
4509928Sgibbs
45113177Sgibbs/*
45213177Sgibbs * Copy data from FIFO into SCB data pointer and data count.  This assumes
45319164Sgibbs * that the SG segments are of the form:
45413177Sgibbs *
45513177Sgibbs * struct ahc_dma_seg {
45619164Sgibbs *	u_int32_t	addr;		four bytes, little-endian order
45719164Sgibbs *	u_int32_t	len;		four bytes, little endian order
45813177Sgibbs * };
45913177Sgibbs */
46019164Sgibbs	mvi	HADDR0	call dfdat_in_7
4619928Sgibbs
46213177Sgibbs/* Load STCNT as well.  It is a mirror of HCNT */
46319164Sgibbs	call	set_stcnt_from_hcnt
46419164Sgibbs	test	SSTAT1,PHASEMIS  jz data_phase_loop
4654568Sgibbs
4669928Sgibbsdata_phase_finish:
46713177Sgibbs/*
46813177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB
46913177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
47013177Sgibbs * were transferred on the SCSI (as opposed to the host) bus.
47113177Sgibbs */
47213690Sgibbs	mov	SCB_RESID_DCNT0,STCNT0
47313690Sgibbs	mov	SCB_RESID_DCNT1,STCNT1
47413690Sgibbs	mov	SCB_RESID_DCNT2,STCNT2
47513177Sgibbs	mov	SCB_RESID_SGCNT, SG_COUNT
4764568Sgibbs	jmp	ITloop
4774568Sgibbs
47816260Sgibbsdata_phase_overrun:
47913177Sgibbs/*
48016260Sgibbs * Turn off BITBUCKET mode and notify the host
48116260Sgibbs */
48216260Sgibbs	and	SXFRCTL1,0x7f		/* ~BITBUCKET */
48316260Sgibbs	mvi	INTSTAT,DATA_OVERRUN
48416260Sgibbs	jmp	ITloop
48516260Sgibbs
48616260Sgibbs/*
48715328Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
48813177Sgibbs */
4894568Sgibbsp_command:
4904568Sgibbs	call	assert
4914568Sgibbs
49213177Sgibbs/*
49315328Sgibbs * Load HADDR and HCNT.
49413177Sgibbs */
49519164Sgibbs	mvi	DINDEX, HADDR0
49619164Sgibbs	mvi	SCB_CMDPTR	call bcopy_5
49713690Sgibbs	clr	HCNT1
49813690Sgibbs	clr	HCNT2
4994568Sgibbs
50019164Sgibbs	call	set_stcnt_from_hcnt
5014568Sgibbs
5024568Sgibbs	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
5034568Sgibbs						#   DIRECTION|FIFORESET
5044568Sgibbs	jmp	ITloop
5054568Sgibbs
50613177Sgibbs/*
50713177Sgibbs * Status phase.  Wait for the data byte to appear, then read it
50813177Sgibbs * and store it into the SCB.
50913177Sgibbs */
5104568Sgibbsp_status:
51113177Sgibbs	mvi	SCB_TARGET_STATUS	call inb_first
5129954Sgibbs	jmp	mesgin_done
5134568Sgibbs
51413177Sgibbs/*
51515328Sgibbs * Message out phase.  If there is not an active message, but the target
51613177Sgibbs * took us into this phase anyway, build a no-op message and send it.
51713177Sgibbs */
5184568Sgibbsp_mesgout:
51913177Sgibbs	test	MSG_LEN, 0xff	jnz  p_mesgout_start
52018762Sgibbs	mvi	MSG_NOOP	call mk_mesg	/* build NOP message */
52113177Sgibbsp_mesgout_start:
52213177Sgibbs/*
52313177Sgibbs * Set up automatic PIO transfer from MSG0.  Bit 3 in
52413177Sgibbs * SXFRCTL0 (SPIOEN) is already on.
52513177Sgibbs */
52613177Sgibbs	mvi	SINDEX,MSG0
5274568Sgibbs	mov	DINDEX,MSG_LEN
5284568Sgibbs
52913177Sgibbs/*
53013177Sgibbs * When target asks for a byte, drop ATN if it's the last one in
53113177Sgibbs * the message.  Otherwise, keep going until the message is exhausted.
53213177Sgibbs *
53313177Sgibbs * Keep an eye out for a phase change, in case the target issues
53413177Sgibbs * a MESSAGE REJECT.
53513177Sgibbs */
53613177Sgibbsp_mesgout_loop:
53716198Sgibbs	test	SSTAT1,PHASEMIS	jnz p_mesgout_phasemis
53813177Sgibbs	test	SSTAT0,SPIORDY	jz p_mesgout_loop
53916198Sgibbs	test	SSTAT1,PHASEMIS	jnz p_mesgout_phasemis
54013177Sgibbs	cmp	DINDEX,1	jne p_mesgout_outb	/* last byte? */
54113177Sgibbs	mvi	CLRSINT1,CLRATNO			/* drop ATN */
54213177Sgibbsp_mesgout_outb:
54313177Sgibbs	dec	DINDEX
54413386Sgibbs	or	CLRSINT0, CLRSPIORDY
5454568Sgibbs	mov	SCSIDATL,SINDIR
54613313Sgibbs	
5474568Sgibbsp_mesgout4:
54813177Sgibbs	test	DINDEX,0xff	jnz p_mesgout_loop
5494568Sgibbs
55013177Sgibbs/*
55113177Sgibbs * If the next bus phase after ATN drops is a message out, it means
55213177Sgibbs * that the target is requesting that the last message(s) be resent.
55313177Sgibbs */
55413177Sgibbsp_mesgout_snoop:
55513177Sgibbs	test	SSTAT1,BUSFREE	jnz p_mesgout_done
55613177Sgibbs	test	SSTAT1,REQINIT	jz p_mesgout_snoop
5574568Sgibbs
55813177Sgibbs	test	SSTAT1,PHASEMIS	jnz p_mesgout_done
5594568Sgibbs
56013690Sgibbs	or	SCSISIGO,ATNO			/* turn on ATNO */
56113177Sgibbs
5624568Sgibbs	jmp	ITloop
5634568Sgibbs
56413177Sgibbsp_mesgout_phasemis:
56515328Sgibbs	mvi	CLRSINT1,CLRATNO	/* Be sure to turn ATNO off */
56613177Sgibbsp_mesgout_done:
56713177Sgibbs	clr	MSG_LEN			/* no active msg */
5684568Sgibbs	jmp	ITloop
5694568Sgibbs
57013177Sgibbs/*
57113177Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
57213177Sgibbs */
5734568Sgibbsp_mesgin:
57413177Sgibbs	mvi	A		call inb_first	/* read the 1st message byte */
57513177Sgibbs	mov	REJBYTE,A			/* save it for the driver */
5764568Sgibbs
57718762Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify
57813177Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect
57918762Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs
58013177Sgibbs	cmp	ALLZEROS,A		je mesgin_complete
58118762Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs
58213177Sgibbs	cmp	A,MSG_EXTENDED		je mesgin_extended
58318762Sgibbs	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject
5844568Sgibbs
5859954Sgibbsrej_mesgin:
58613177Sgibbs/*
58719164Sgibbs * We have no idea what this message in is, so we issue a message reject
58819164Sgibbs * and hope for the best.  In any case, rejection should be a rare
58919164Sgibbs * occurrence - signal the driver when it happens.
59013177Sgibbs */
59113690Sgibbs	or	SCSISIGO,ATNO			/* turn on ATNO */
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/*
62119164Sgibbs * First check for residuals
62213177Sgibbs */
62319164Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz upload_scb
62419164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Good Status? */
62519164Sgibbsupload_scb:
62619164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
62719164Sgibbs	mov	SCB_TAG		call dma_scb
6287532Sgibbscheck_status:
62919164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Just a residual? */
63013177Sgibbs	mvi	INTSTAT,BAD_STATUS			/* let driver know */
63113177Sgibbs	cmp	RETURN_1, SEND_SENSE	jne status_ok
63219164Sgibbs	/* This SCB becomes the next to execute as it will retrieve sense */
63319164Sgibbs	mov	SCB_LINKED_NEXT, SCB_TAG
63419164Sgibbs	jmp	dma_next_scb
6355326Sgibbs
6364568Sgibbsstatus_ok:
63713177Sgibbs/* First, mark this target as free. */
63813177Sgibbs	test	SCB_CONTROL,TAG_ENB jnz test_immediate	/*
63913177Sgibbs							 * Tagged commands
64013177Sgibbs							 * don't busy the
64113177Sgibbs							 * target.
64213177Sgibbs							 */
64319164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
64419164Sgibbs	mov	SAVED_LINKPTR, SCB_LINKED_NEXT
64519218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
64619164Sgibbs	mov	DINDIR, SAVED_LINKPTR
64719164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
6485326Sgibbs
64913177Sgibbstest_immediate:
65013177Sgibbs	test    SCB_CMDLEN,0xff jnz complete  /* Immediate message complete */
65113177Sgibbs/*
65213177Sgibbs * Pause the sequencer until the driver gets around to handling the command
65313177Sgibbs * complete.  This is so that any action that might require carefull timing
65413177Sgibbs * with the completion of this command can occur.
65513177Sgibbs */
6569810Sgibbs	mvi	INTSTAT,IMMEDDONE
65719164Sgibbs	jmp	dma_next_scb
6585326Sgibbscomplete:
65919164Sgibbs	/* Post the SCB and issue an interrupt */
66015328Sgibbs	mov	QOUTFIFO,SCB_TAG
6617532Sgibbs	mvi	INTSTAT,CMDCMPLT
66219164Sgibbs
66319164Sgibbsdma_next_scb:
66419164Sgibbs	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je mesgin_done
66519164Sgibbs	test	FLAGS, PAGESCBS jnz dma_next_scb2
66619164Sgibbs	/* Only DMA on top of ourselves if we are the SCB to download */
66719164Sgibbs	mov	A, SCB_LINKED_NEXT
66819164Sgibbs	cmp	SCB_TAG, A	je dma_next_scb2
66919164Sgibbs	mov	SCBPTR, A
67019164Sgibbs	jmp	add_to_waiting_list
67119164Sgibbsdma_next_scb2:
67219164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
67319218Sgibbs	mov	SCB_LINKED_NEXT		call dma_scb
67419164Sgibbsadd_to_waiting_list:
67519164Sgibbs	mov	SCB_NEXT,WAITING_SCBH
67619164Sgibbs	mov	WAITING_SCBH, SCBPTR
67719164Sgibbs	or	FLAGS, SCB_LISTED
6789954Sgibbs	jmp	mesgin_done
6794568Sgibbs
68013177Sgibbs/*
68118762Sgibbs * Is it an extended message?  Copy the message to our message buffer and
68218762Sgibbs * notify the host.  The host will tell us whether to reject this message,
68318762Sgibbs * respond to it with the message that the host placed in our message buffer,
68418762Sgibbs * or simply to do nothing.
68513177Sgibbs */
6869954Sgibbsmesgin_extended:
68718762Sgibbs	mvi	MSGIN_EXT_LEN	 call inb_next
68818762Sgibbs	mov	A, MSGIN_EXT_LEN
68918762Sgibbsmesgin_extended_loop:
69019164Sgibbs	mov	DINDEX	call	inb_next
69118762Sgibbs	dec	A
69219164Sgibbs	cmp	DINDEX, MSGIN_EXT_LASTBYTE jne mesgin_extended_loop_test
69319164Sgibbs	dec	DINDEX		/* dump by repeatedly filling the last byte */
69419164Sgibbsmesgin_extended_loop_test:
69519164Sgibbs	test	A, 0xFF		jnz mesgin_extended_loop
69618762Sgibbsmesgin_extended_intr:
69718762Sgibbs	mvi	INTSTAT,EXTENDED_MSG		/* let driver know */
69818762Sgibbs	cmp	RETURN_1,SEND_REJ je rej_mesgin
69918762Sgibbs	cmp	RETURN_1,SEND_MSG jne mesgin_done
70018762Sgibbs/* The kernel has setup a message to be sent */
70113690Sgibbs	or	SCSISIGO,ATNO			/* turn on ATNO */
7029954Sgibbs	jmp	mesgin_done
7035562Sgibbs
70413177Sgibbs/*
70513177Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
70613177Sgibbs * and await the bus going free.
70713177Sgibbs */
7089954Sgibbsmesgin_disconnect:
70913177Sgibbs	or	SCB_CONTROL,DISCONNECTED
71015328Sgibbs	test	FLAGS, PAGESCBS jz mesgin_done
71119164Sgibbs	call	add_scb_to_disc_list
71219164Sgibbs	or	FLAGS, SCB_LISTED
71319164Sgibbs	jmp	mesgin_done
71419164Sgibbs
71515328Sgibbs/*
71619164Sgibbs * Save data pointers message:
71719164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
71819164Sgibbs * only if we've actually been into a data phase to change them.  This
71919164Sgibbs * protects against bogus data in scratch ram and the residual counts
72019164Sgibbs * since they are only initialized when we go into data_in or data_out.
72115328Sgibbs */
72219164Sgibbsmesgin_sdptrs:
72319164Sgibbs	test	FLAGS, DPHASE	jz mesgin_done
72419164Sgibbs	mov	SCB_SGCOUNT,SG_COUNT
7254568Sgibbs
72619164Sgibbs	/* The SCB SGPTR becomes the next one we'll download */
72719164Sgibbs	mvi	DINDEX, SCB_SGPTR
72819164Sgibbs	mvi	SG_NEXT0	call bcopy_4
72919164Sgibbs	
73019164Sgibbs	/* The SCB DATAPTR0 becomes the current SHADDR */
73119164Sgibbs	mvi	DINDEX, SCB_DATAPTR0
73219164Sgibbs	mvi	SHADDR0		call bcopy_4
73319164Sgibbs
73413177Sgibbs/*
73519164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer.
73613177Sgibbs */
73719164Sgibbs	mvi	SCB_RESID_DCNT0	call	bcopy_3
73819164Sgibbs
7399954Sgibbs	jmp	mesgin_done
7404568Sgibbs
74113177Sgibbs/*
74213177Sgibbs * Restore pointers message?  Data pointers are recopied from the
74313177Sgibbs * SCB anytime we enter a data phase for the first time, so all
74413177Sgibbs * we need to do is clear the DPHASE flag and let the data phase
74513177Sgibbs * code do the rest.
74613177Sgibbs */
7479954Sgibbsmesgin_rdptrs:
74815328Sgibbs	and	FLAGS,0xef			/*
74913177Sgibbs						 * !DPHASE we'll reload them
75013177Sgibbs						 * the next time through
75113177Sgibbs						 */
7529954Sgibbs	jmp	mesgin_done
7534568Sgibbs
75413177Sgibbs/*
75513177Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
75613177Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
75713177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
75813177Sgibbs */
7599954Sgibbsmesgin_identify:
76013177Sgibbs	test	A,0x78	jnz rej_mesgin	/*!DiscPriv|!LUNTAR|!Reserved*/
76113177Sgibbs	and	A,0x07			/* lun in lower three bits */
76219164Sgibbs	or      SAVED_TCL,A		/* SAVED_TCL should be complete now */
76313177Sgibbs	call	inb_last		/* ACK */
76413177Sgibbs
76513177Sgibbs/*
76613177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
76715328Sgibbs * If we get one, we use the tag returned to switch to find the proper
76815328Sgibbs * SCB.  With SCB paging, this requires using findSCB for both tagged
76915328Sgibbs * and non-tagged transactions since the SCB may exist in any slot.
77015328Sgibbs * If we're not using SCB paging, we can use the tag as the direct
77115328Sgibbs * index to the SCB.
77213177Sgibbs */
77315328Sgibbs	mvi	ARG_1,SCB_LIST_NULL	/* Default to no-tag */
77413177Sgibbssnoop_tag_loop:
77518762Sgibbs	test	SSTAT1,BUSFREE		jnz use_findSCB
77618762Sgibbs	test	SSTAT1,REQINIT		jz snoop_tag_loop
77718762Sgibbs	test	SSTAT1,PHASEMIS		jnz use_findSCB
77818762Sgibbs	mvi	A			call inb_first
77918762Sgibbs	cmp	A,MSG_SIMPLE_Q_TAG	jne use_findSCB
7806608Sgibbsget_tag:
78119218Sgibbs	or	FLAGS, TAGGED_SCB
78213177Sgibbs	mvi	ARG_1	call inb_next	/* tag value */
78313177Sgibbs/*
78413177Sgibbs * See if the tag is in range.  The tag is < SCBCOUNT if we add
78513177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is
78613177Sgibbs * no carry.
78713177Sgibbs */
78813177Sgibbs	mov	A,COMP_SCBCOUNT	
78913177Sgibbs	add	SINDEX,A,ARG_1
79019218Sgibbs	jc	send_abort_msg
79113177Sgibbs
79213177Sgibbs/*
79315328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction
79413177Sgibbs * to the reconnecting target.
79513177Sgibbs */
79615328Sgibbs	test	FLAGS, PAGESCBS	jz index_by_tag
79715328Sgibbsuse_findSCB:
79815328Sgibbs	mov	ALLZEROS	call findSCB	  /* Have to search */
79919218Sgibbs	cmp	SINDEX, SCB_LIST_NULL, je not_found
80015328Sgibbssetup_SCB:
80115328Sgibbs	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
80215328Sgibbs	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
80319164Sgibbs	test	SCB_CONTROL,TAG_ENB	jnz  mesgin_done /* Ack Tag */
80415328Sgibbs	jmp	ITloop
80515328Sgibbsindex_by_tag:
80613177Sgibbs	mov	SCBPTR,ARG_1
80719218Sgibbs	mov	A, SAVED_TCL
80819218Sgibbs	cmp	SCB_TCL,A		jne send_abort_msg
80919218Sgibbs	test	SCB_CONTROL,TAG_ENB	jz  send_abort_msg
81013177Sgibbs	jmp	setup_SCB
81115328Sgibbs
81219218Sgibbsnot_found:
81319218Sgibbs	mvi	INTSTAT, NO_MATCH
81419218Sgibbssend_abort_msg:
81513690Sgibbs	or	SCSISIGO,ATNO			/* turn on ATNO */
81619218Sgibbs	test	FLAGS, TAGGED_SCB jnz abort_tag_msg
81719218Sgibbs	mvi	MSG_ABORT	call mk_mesg
81819218Sgibbs	jmp	mesgin_done
81919164Sgibbsabort_tag_msg:
82015328Sgibbs	mvi	MSG_ABORT_TAG	call mk_mesg	/* ABORT TAG message */
82113177Sgibbs	jmp	mesgin_done
8226608Sgibbs
82313177Sgibbs/*
82413177Sgibbs * Message reject?  Let the kernel driver handle this.  If we have an 
82513177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 
82613177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
82713177Sgibbs * it since we have no clue what it pertains to.
82813177Sgibbs */
8299954Sgibbsmesgin_reject:
83013177Sgibbs	mvi	INTSTAT, REJECT_MSG
8319954Sgibbs	jmp	mesgin_done
8325562Sgibbs
83313177Sgibbs/*
83413177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ]
83513177Sgibbs */
8364568Sgibbs
83713177Sgibbs/*
83813177Sgibbs * Bus free phase.  It might be useful to interrupt the device
83913177Sgibbs * driver if we aren't expecting this.  For now, make sure that
84013177Sgibbs * ATN isn't being asserted and look for a new command.
84113177Sgibbs */
8424568Sgibbsp_busfree:
84313177Sgibbs	mvi	CLRSINT1,CLRATNO
84414449Sgibbs	clr	LASTPHASE
8458567Sdg
84613177Sgibbs/*
84713177Sgibbs * if this is an immediate command, perform a psuedo command complete to
84813177Sgibbs * notify the driver.
84913177Sgibbs */
85013177Sgibbs	test	SCB_CMDLEN,0xff	jz status_ok
85119164Sgibbs	test	FLAGS, SCB_LISTED	jnz start
85219164Sgibbs	/*
85319164Sgibbs	 * This SCB didn't disconnect or have a command complete,
85419164Sgibbs	 * so put it on the free queue.  It was probably the
85519164Sgibbs	 * result of an abort of some sort.  This prevents us
85619164Sgibbs	 * from "leaking" SCBs.
85719164Sgibbs	 */
85819164Sgibbs	call	add_scb_to_free_list
85913177Sgibbs	jmp	start
8604568Sgibbs
86113177Sgibbs/*
86213177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX
86313177Sgibbs * if there is no active message already.  SINDEX is returned intact.
86413177Sgibbs */
8654568Sgibbsmk_mesg:
86613177Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
86713177Sgibbs	test	MSG_LEN,0xff	jz mk_mesg1	/* Should always succeed */
86813177Sgibbs	
86913177Sgibbs	/*
87013177Sgibbs	 * Hmmm.  For some reason the mesg buffer is in use.
87113177Sgibbs	 * Tell the driver.  It should look at SINDEX to find
87213177Sgibbs	 * out what we wanted to use the buffer for and resolve
87313177Sgibbs	 * the conflict.
87413177Sgibbs	 */
87513177Sgibbs	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
87613690Sgibbs	mvi	INTSTAT,MSG_BUFFER_BUSY
8774568Sgibbs
8784568Sgibbsmk_mesg1:
87913177Sgibbs	mvi	MSG_LEN,1		/* length = 1 */
88013177Sgibbs	mov	MSG0,SINDEX		/* 1-byte message */
88113177Sgibbs	mvi	SEQCTL,0x10	ret	/* !PAUSEDIS|FASTMODE */
8824568Sgibbs
88313177Sgibbs/*
88413177Sgibbs * Functions to read data in Automatic PIO mode.
88513177Sgibbs *
88613177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
88713177Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
88813177Sgibbs * latched (the usual way), then read the data byte directly off the bus
88913177Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
89013177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
89113177Sgibbs * spec guarantees that the target will hold the data byte on the bus until
89213177Sgibbs * we send our ACK.
89313177Sgibbs *
89413177Sgibbs * The assumption here is that these are called in a particular sequence,
89513177Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
89613177Sgibbs * use the same calling convention as inb.
89713177Sgibbs */
89813177Sgibbs
89913177Sgibbsinb_next:
90013386Sgibbs	or	CLRSINT0, CLRSPIORDY
90113360Sgibbs	mov	NONE,SCSIDATL			/*dummy read from latch to ACK*/
90213360Sgibbsinb_next_wait:
90316198Sgibbs	test	SSTAT1,PHASEMIS	jnz mesgin_phasemis
90415951Sgibbs	test	SSTAT0,SPIORDY	jz inb_next_wait /* wait for next byte */
90513313Sgibbsinb_first:
9064568Sgibbs	mov	DINDEX,SINDEX
90716002Sgibbs	test	SSTAT1,PHASEMIS	jnz mesgin_phasemis
90813177Sgibbs	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
90913177Sgibbsinb_last:
91013360Sgibbs	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
9114568Sgibbs
91213177Sgibbsmesgin_phasemis:
91313177Sgibbs/*
91413177Sgibbs * We expected to receive another byte, but the target changed phase
91513177Sgibbs */
91613177Sgibbs	mvi	INTSTAT, MSGIN_PHASEMIS
91713177Sgibbs	jmp	ITloop
9184568Sgibbs
91913177Sgibbs/*
92013177Sgibbs * DMA data transfer.  HADDR and HCNT must be loaded first, and
92113177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for
92213177Sgibbs * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
92313177Sgibbs * during initialization.
92413177Sgibbs */
9254568Sgibbsdma:
9264568Sgibbs	mov	DFCNTRL,SINDEX
9274568Sgibbsdma1:
92813177Sgibbs	test	SSTAT0,DMADONE	jnz dma3
92913177Sgibbs	test	SSTAT1,PHASEMIS	jz dma1		/* ie. underrun */
9304568Sgibbs
93113177Sgibbs/*
93213177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or
93313177Sgibbs * the target changes the phase (in light of this, it makes sense that
93413177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
93513177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
93613177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty
93713177Sgibbs * status.
93813177Sgibbs */
9394568Sgibbsdma3:
94013177Sgibbs	test	SINDEX,DIRECTION	jnz dma5
9414568Sgibbsdma4:
94213177Sgibbs	test	DFSTATUS,FIFOEMP	jz dma4
9434568Sgibbs
94413177Sgibbs/*
94513177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 
94613177Sgibbs * actually off first lest we get an ILLSADDR.
94713177Sgibbs */
9484568Sgibbsdma5:
94913177Sgibbs	/* disable DMA, but maintain WIDEODD */
95013690Sgibbs	and	DFCNTRL,WIDEODD
9514568Sgibbsdma6:
95213177Sgibbs	test	DFCNTRL,0x38	jnz dma6  /* SCSIENACK|SDMAENACK|HDMAENACK */
95318762Sgibbsreturn:
9544568Sgibbs	ret
9554568Sgibbs
95613177Sgibbs/*
95713177Sgibbs * Common SCSI initialization for selection and reselection.  Expects
95813177Sgibbs * the target SCSI ID to be in the upper four bits of SINDEX, and A's
95913177Sgibbs * contents are stomped on return.
96013177Sgibbs */
9618104Sgibbsinitialize_scsiid:
96213177Sgibbs	and	SINDEX,0xf0		/* Get target ID */
96319164Sgibbs	mov	SAVED_TCL, SINDEX	/* Update the target portion of this */
9645775Sgibbs	and	A,0x0f,SCSIID
9655775Sgibbs	or	SINDEX,A
9668104Sgibbs	mov	SCSIID,SINDEX ret
9675326Sgibbs
96813177Sgibbs/*
96913177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
97013177Sgibbs * message.
97113177Sgibbs */
9724568Sgibbsassert:
97313177Sgibbs	test	FLAGS,RESELECTED	jz return	/* reselected? */
97413177Sgibbs	test	FLAGS,IDENTIFY_SEEN	jnz return	/* seen IDENTIFY? */
9754568Sgibbs
97619164Sgibbs	mvi	INTSTAT,NO_IDENT 	ret	/* no - tell the kernel */
9774568Sgibbs
97813177Sgibbs/*
97919218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
98019218Sgibbs * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
98119218Sgibbs * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
98219218Sgibbs * otherwise, SCBPTR is set to the proper SCB.
98313177Sgibbs */
9844568SgibbsfindSCB:
98515328Sgibbs	mov	SCBPTR,SINDEX			/* switch to next SCB */
98613177Sgibbs	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
98719218Sgibbs	cmp	ARG_1, SCB_LIST_NULL	jne findBySCBID
98819218Sgibbs	mov	A, SAVED_TCL
98919218Sgibbs	cmp	SCB_TCL,A	je foundSCB /* target ID/channel/lun match? */
99019164SgibbsfindSCB1:
99119164Sgibbs	inc	SINDEX
99219164Sgibbs	mov	A,SCBCOUNT
99319164Sgibbs	cmp	SINDEX,A	jne findSCB
99419164Sgibbs/*
99519164Sgibbs * We didn't find it.  If we're paging, pull an SCB and DMA down the
99619164Sgibbs * one we want.  If we aren't paging or the SCB we dma down has the
99719218Sgibbs * abort flag set, return not found.
99819164Sgibbs */
99919218Sgibbs	test	FLAGS, PAGESCBS	jz find_error
100019164Sgibbs	call	get_free_or_disc_scb
100119218Sgibbs	cmp	ARG_1, SCB_LIST_NULL jne find_dma_scb
100219218Sgibbs	mov	SAVED_TCL	call	index_untagged_scb
100319218Sgibbs	mov	ARG_1, SINDIR	/* SCBID of SCB to fetch */
100419164Sgibbsfind_dma_scb:
100519164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
100619218Sgibbs	mov	ARG_1	call dma_scb
100719164Sgibbs	test	SCB_CONTROL, ABORT_SCB jz return
100819218Sgibbsfind_error:
100919218Sgibbs	mvi	SINDEX, SCB_LIST_NULL ret
101019218SgibbsfindBySCBID:
101115328Sgibbs	mov	A, ARG_1			/* Tag passed in ARG_1 */
101215328Sgibbs	cmp	SCB_TAG,A	jne findSCB1	/* Found it? */
101315328SgibbsfoundSCB:
101419218Sgibbs	test	SCB_CONTROL, ABORT_SCB jnz find_error
101519164Sgibbs	test	FLAGS,PAGESCBS	jz return
101619164Sgibbsrem_scb_from_disc_list:
101715328Sgibbs/* Remove this SCB from the disconnection list */
101815328Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev
101915328Sgibbs	mov	SAVED_LINKPTR, SCB_PREV
102015328Sgibbs	mov	SCBPTR, SCB_NEXT
102115328Sgibbs	mov	SCB_PREV, SAVED_LINKPTR
102215328Sgibbs	mov	SCBPTR, SINDEX
102315328Sgibbsunlink_prev:
102415328Sgibbs	cmp	SCB_PREV,SCB_LIST_NULL	je rHead/* At the head of the list */
102515328Sgibbs	mov	SAVED_LINKPTR, SCB_NEXT
102615328Sgibbs	mov	SCBPTR, SCB_PREV
102715328Sgibbs	mov	SCB_NEXT, SAVED_LINKPTR
102819164Sgibbs	mov	SCBPTR, SINDEX ret
102915328SgibbsrHead:
103019164Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret
10314568Sgibbs
103219164Sgibbsset_stcnt_from_hcnt:
103319164Sgibbs	mov	STCNT0, HCNT0
103419164Sgibbs	mov	STCNT1, HCNT1
103519164Sgibbs	mov	STCNT2, HCNT2 ret
10364568Sgibbs
103719164Sgibbsbcopy_7:
103819164Sgibbs	mov	DINDIR, SINDIR
103919164Sgibbs	mov	DINDIR, SINDIR
104019164Sgibbsbcopy_5:
104119164Sgibbs	mov	DINDIR, SINDIR
104219164Sgibbsbcopy_4:
104319164Sgibbs	mov	DINDIR, SINDIR
104419164Sgibbsbcopy_3:
104519164Sgibbs	mov	DINDIR, SINDIR
104619164Sgibbs	mov	DINDIR, SINDIR
104719164Sgibbs	mov	DINDIR, SINDIR ret
10484568Sgibbs
104919164Sgibbsdma_scb:
105019164Sgibbs	/*
105119164Sgibbs	 * SCB index is in SINDEX.  Determine the physical address in
105219164Sgibbs	 * the host where this SCB is located and load HADDR with it.
105319164Sgibbs	 */
105419164Sgibbs	shr	DINDEX, SINDEX, 3
105519164Sgibbs	shl	A, SINDEX, 5
105619164Sgibbs	add	HADDR0, A, HSCB_ADDR0
105719164Sgibbs	mov	A, DINDEX
105819164Sgibbs	adc	HADDR1, A, HSCB_ADDR1
105919164Sgibbs	clr	A
106019164Sgibbs	adc	HADDR2, A, HSCB_ADDR2
106119164Sgibbs	adc	HADDR3, A, HSCB_ADDR3
106219164Sgibbs	/* Setup Count */
106319164Sgibbs	mvi	HCNT0, 28
106419164Sgibbs	clr	HCNT1
106519164Sgibbs	clr	HCNT2
106619164Sgibbs	mov	DFCNTRL, DMAPARAMS
106719164Sgibbs	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost
106819164Sgibbs	/* Fill it with the SCB data */
106919164Sgibbs	call	copy_scb_tofifo
107019164Sgibbs	mvi	DFCNTRL, 0xa		/* HDMAEN | FIFOFLUSH */
107119164Sgibbsdma_scb_fromhost:
107219164Sgibbs	call	dma_finish
107319164Sgibbs	/* If we were putting the SCB, we are done */
107419164Sgibbs	test	DMAPARAMS, DIRECTION	jz	return
107519164Sgibbs	mvi	SCBARRAY  call dfdat_in_7
107619164Sgibbs	call	dfdat_in_7_continued
107719164Sgibbs	call	dfdat_in_7_continued
107819164Sgibbs	jmp	dfdat_in_7_continued
107919164Sgibbsdfdat_in_7:
108019164Sgibbs	mov     DINDEX,SINDEX
108119164Sgibbsdfdat_in_7_continued:
108219164Sgibbs	mov	DINDIR,DFDAT
108319164Sgibbs	mov	DINDIR,DFDAT
108419164Sgibbs	mov	DINDIR,DFDAT
108519164Sgibbs	mov	DINDIR,DFDAT
108619164Sgibbs	mov	DINDIR,DFDAT
108719164Sgibbs	mov	DINDIR,DFDAT
108819164Sgibbs	mov	DINDIR,DFDAT ret
108919164Sgibbs
109019164Sgibbscopy_scb_tofifo:
109119164Sgibbs	mvi	SCBARRAY  call dfdat_out_7
109219164Sgibbs	call	dfdat_out_7
109319164Sgibbs	call	dfdat_out_7
109419164Sgibbsdfdat_out_7:
109519164Sgibbs	mov	DFDAT,SINDIR
109619164Sgibbs	mov	DFDAT,SINDIR
109719164Sgibbs	mov	DFDAT,SINDIR
109819164Sgibbs	mov	DFDAT,SINDIR
109919164Sgibbs	mov	DFDAT,SINDIR
110019164Sgibbs	mov	DFDAT,SINDIR
110119164Sgibbs	mov	DFDAT,SINDIR ret
110219164Sgibbs
110313177Sgibbs/*
110419164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
110519164Sgibbs * DMA and wait for it to acknowledge that it's off.
110613177Sgibbs */
110719164Sgibbsdma_finish:
110819164Sgibbs	test	DFSTATUS,HDONE	jz dma_finish
110919164Sgibbs	/* Turn off DMA preserving WIDEODD */
111019164Sgibbs	and	DFCNTRL,WIDEODD
111119164Sgibbsdma_finish2:
111219164Sgibbs	test	DFCNTRL,HDMAENACK jnz dma_finish2
111319164Sgibbs	ret
11149928Sgibbs
111519164Sgibbsindex_untagged_scb:
111619218Sgibbs	mov	DINDEX, SINDEX
111719218Sgibbs	shr	DINDEX, 4
111819218Sgibbs	and	DINDEX, 0x03			/* Bottom two bits of tid */
111919218Sgibbs	add	DINDEX, SCB_ACTIVE0
112019218Sgibbs	shr	A, SINDEX, 6			/* Target ID divided by 4 */
112119164Sgibbs	test	SCB_TCL, SELBUSB jz index_untagged_scb2
112219164Sgibbs	or	A, 2				/* Add 2 positions */
112319164Sgibbsindex_untagged_scb2:
112419164Sgibbs	mov	SCBPTR, A			/*
112519164Sgibbs						 * Select the SCB with this 
112619164Sgibbs						 * target's information.
112719164Sgibbs						 */
112819218Sgibbs	mov	SINDEX, DINDEX	ret
11299928Sgibbs
11304568Sgibbs
113119164Sgibbsget_free_or_disc_scb:
113219164Sgibbs	mov	SINDEX, ALLZEROS
113319164Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne get_free_scb
113419164Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je return_error
113519164Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH
113613177Sgibbs/*
113719164Sgibbs * If we are starting a new transaction, we have to ensure that
113819164Sgibbs * there is at least one SCB left in case a reselection wins out.
113913177Sgibbs */
114019164Sgibbs	test	FLAGS, RESELECTED	jnz dequeue_disc_scb
114119164Sgibbs	cmp	SCB_NEXT, SCB_LIST_NULL je return_error
114219164Sgibbsdequeue_disc_scb:
114319164Sgibbs/*
114419164Sgibbs * If we have a residual, then we are in the middle of some I/O
114519164Sgibbs * and we have to send this SCB back up to the kernel so that the
114619164Sgibbs * saved data pointers and residual information isn't lost.
114719164Sgibbs */
114819164Sgibbs	test	SCB_RESID_SGCNT,0xff	jz unlink_disc_scb
114919164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
115019164Sgibbs	mov	SCB_TAG		call dma_scb
115119164Sgibbsunlink_disc_scb:
115219164Sgibbs	call	rem_scb_from_disc_list
115319164Sgibbs	ret
115419164Sgibbsget_free_scb:
115519164Sgibbs/*
115619164Sgibbs * If we are starting a new transaction, we have to ensure that
115719164Sgibbs * there is at least one SCB left in case a reselection wins out.
115819164Sgibbs */
115919164Sgibbs	test	FLAGS, RESELECTED	jnz dequeue_free_scb
116019164Sgibbs	cmp	SCB_NEXT, SCB_LIST_NULL jne dequeue_free_scb
116119164Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je return_error
116219164Sgibbsdequeue_free_scb:
116319164Sgibbs	mov	SCBPTR, FREE_SCBH
116419164Sgibbs	mov	FREE_SCBH, SCB_NEXT ret
116519164Sgibbsreturn_error:
116619164Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret
11674568Sgibbs
116819164Sgibbsadd_scb_to_free_list:
116919164Sgibbs	mov	SCB_NEXT, FREE_SCBH
117019164Sgibbs	mov	FREE_SCBH, SCBPTR ret
11714568Sgibbs
117219164Sgibbsadd_scb_to_disc_list:
117313177Sgibbs/*
117419164Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
117519164Sgibbs * candidates for paging out an SCB if one is needed for a new command.
117619164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
117713177Sgibbs */
117819164Sgibbs	mvi	SCB_PREV, SCB_LIST_NULL
117919164Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH
118019164Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR
118119164Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je return
118219164Sgibbs	mov	SCBPTR,SCB_NEXT
118319164Sgibbs	mov	SCB_PREV,DISCONNECTED_SCBH
118419164Sgibbs	mov	SCBPTR,DISCONNECTED_SCBH ret
11854568Sgibbs
1186