aic7xxx.seq revision 22451
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:
1022234Sgibbs *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
4221673SjkhVERSION AIC7XXX_SEQ_VER "$FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 22451 1997-02-09 03:23:28Z gibbs $"
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:
8716198Sgibbs	clr	SCSIRATE		/*
8816198Sgibbs					 * We don't know the target we will
8916198Sgibbs					 * connect to, so default to narrow
9016198Sgibbs					 * transfers to avoid parity problems.
9116198Sgibbs					 */
9222451Sgibbs	and	SXFRCTL0, 0xdf		/* ~FAST20*/
9321947Sgibbs	mvi	SCSISEQ,ENRSELI		/* Always allow reselection */
9420117Sgibbs	mvi	LASTPHASE, P_BUSFREE
9520117Sgibbs	and	FLAGS,0x07		/* clear target specific flags */
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
13019623Sgibbs	mov	ALLZEROS	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
14919921Sgibbs * commands.  We also don't have enough spare SCB space for us 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
15522078Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
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
17721947Sgibbs	 * never happen.
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
18621947Sgibbs	mvi	SEQCTL,0x10			/* FASTMODE */
1878104Sgibbs	jmp	poll_for_work
18819164Sgibbssimple_busy_link:
18919164Sgibbs	mov	SCBPTR, ARG_1
19019164Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
19121947Sgibbs	mvi	SEQCTL,0x10			/* FASTMODE */
19219164Sgibbs	jmp	poll_for_work
19319164Sgibbsmake_busy:
19419164Sgibbs	mov	DINDIR, CUR_SCBID
19519164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
19622078Sgibbs	mvi	SEQCTL,0x10			/* FASTMODE */
1974568Sgibbs
1985326Sgibbsstart_scb:
19919164Sgibbs	/*
20019164Sgibbs	 * Place us on the waiting list in case our selection
20119164Sgibbs	 * doesn't win during bus arbitration.
20219164Sgibbs	 */
20315328Sgibbs	mov	SCB_NEXT,WAITING_SCBH
20413177Sgibbs	mov	WAITING_SCBH, SCBPTR
20513177Sgibbsstart_scb2:
20613177Sgibbs	and	SINDEX,0xf7,SBLKCTL	/* Clear the channel select bit */
20713177Sgibbs	and	A,0x08,SCB_TCL		/* Get new channel bit */
20813177Sgibbs	or	SINDEX,A
20913177Sgibbs	mov	SBLKCTL,SINDEX		/* select channel */
21013177Sgibbs	mov	SCB_TCL	call initialize_scsiid
2118104Sgibbs
21213177Sgibbs/*
21313177Sgibbs * Enable selection phase as an initiator, and do automatic ATN
21413177Sgibbs * after the selection.  We do this now so that we can overlap the
21513177Sgibbs * rest of our work to set up this target with the arbitration and
21613177Sgibbs * selection bus phases.
21713177Sgibbs */
2188104Sgibbsstart_selection:
21913177Sgibbs	mvi	SCSISEQ,0x58		/* ENSELO|ENAUTOATNO|ENRSELI */
2204568Sgibbs
22113177Sgibbs/*
22213177Sgibbs * As soon as we get a successful selection, the target should go
22313177Sgibbs * into the message out phase since we have ATN asserted.  Prepare
22413177Sgibbs * the message to send.
22513177Sgibbs *
22613177Sgibbs * Messages are stored in scratch RAM starting with a length byte
22713177Sgibbs * followed by the message itself.
22813177Sgibbs */
2298567Sdg
23013177Sgibbsmk_identify:
23119164Sgibbs	and	MSG0,0x7,SCB_TCL	/* lun */
23213177Sgibbs	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privledge */
23313690Sgibbs	or	MSG0,A			/* or in disconnect privledge */
23418762Sgibbs	or	MSG0,MSG_IDENTIFYFLAG
23513690Sgibbs	mvi	MSG_LEN, 1
2364568Sgibbs
23713177Sgibbs/*
23815328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
23915328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
24013177Sgibbs */
2416608Sgibbsmk_tag:
24218762Sgibbs	test	SCB_CONTROL,TAG_ENB jz  mk_message
24319164Sgibbs	and	MSG1,0x23,SCB_CONTROL
24419164Sgibbs	mov	MSG2,SCB_TAG
24519164Sgibbs	add	MSG_LEN,2	/* update message length */
2466608Sgibbs
24718762Sgibbs/*
24818762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer
24918762Sgibbs * if it asks.
25018762Sgibbs */
25118762Sgibbsmk_message:
25218762Sgibbs	test	SCB_CONTROL,MK_MESSAGE  jz wait_for_selection
2536608Sgibbs
25418762Sgibbs	mvi     INTSTAT,AWAITING_MSG
2556608Sgibbs
2569917Sgibbswait_for_selection:
25713177Sgibbs	test	SSTAT0,SELDO	jnz select 
25813177Sgibbs	test	SSTAT0,SELDI	jz wait_for_selection
2594568Sgibbs
26013177Sgibbs/*
26113177Sgibbs * Reselection has been initiated by a target. Make a note that we've been
26219164Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
26313177Sgibbs */
2644568Sgibbsreselect:
26513177Sgibbs	clr	MSG_LEN		/* Don't have anything in the mesg buffer */
26621947Sgibbs	/* XXX test for and handle ONE BIT condition */
26721947Sgibbs	and	SAVED_TCL, 0xf0, SELID
26813177Sgibbs	or	FLAGS,RESELECTED
26913177Sgibbs	jmp	select2
2704568Sgibbs
27113177Sgibbs/*
27219164Sgibbs * After the selection, remove this SCB from the "waiting SCB"
27313177Sgibbs * list.  This is achieved by simply moving our "next" pointer into
27413177Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
27513177Sgibbs * SCB is used, so don't bother with it now.
27613177Sgibbs */
2778104Sgibbsselect:
27815328Sgibbs	mov	WAITING_SCBH,SCB_NEXT
2798104Sgibbsselect2:
28021947Sgibbs	/* Turn off the selection hardware */
28121947Sgibbs	mvi	SCSISEQ,ENAUTOATNP		/*
28221947Sgibbs						 * ATN on parity errors
28321947Sgibbs						 * for "in" phases
28421947Sgibbs						 */
28521947Sgibbs	mvi	CLRSINT0,0x60			/* CLRSELDI|CLRSELDO */
28621947Sgibbs	mvi	CLRSINT1,CLRBUSFREE
28721947Sgibbs	or	SIMODE1, ENBUSFREE		/*
28821947Sgibbs						 * We aren't expecting a
28921947Sgibbs						 * bus free, so interrupt
29021947Sgibbs						 * the kernel driver if it
29121947Sgibbs						 * happens.
29221947Sgibbs						 */
29313177Sgibbs/*
29422451Sgibbs * Initialize Ultra mode setting and clear the SCSI channel.
29522451Sgibbs */
29622451Sgibbs	or	SXFRCTL0, 0x1a			/* CLRSTCNT|SPIOEN|CLRCHN */
29722451Sgibbsultra:
29822451Sgibbs	mvi	SINDEX, ULTRA_ENB_B
29922451Sgibbs	test	SAVED_TCL, 0x80		jnz ultra_2	/* Target ID > 7 */
30022451Sgibbs	test	SBLKCTL, SELBUSB	jnz ultra_2	/* Second channel */
30122451Sgibbs	dec	SINDEX
30222451Sgibbsultra_2:
30322451Sgibbs	mov     FUNCTION1,SAVED_TCL
30422451Sgibbs	mov     A,FUNCTION1
30522451Sgibbs	test	SINDIR, A	jz ndx_dtr
30622451Sgibbs	or	SXFRCTL0, FAST20
30722451Sgibbs 
30822451Sgibbs/*
30913177Sgibbs * Initialize SCSIRATE with the appropriate value for this target.
31019164Sgibbs * The SCSIRATE settings for each target are stored in an array
31119164Sgibbs * based at TARG_SCRATCH.
31213177Sgibbs */
31319164Sgibbsndx_dtr:
31421947Sgibbs	shr	A,SAVED_TCL,4
31519164Sgibbs	test	SBLKCTL,SELBUSB	jz ndx_dtr_2
31619164Sgibbs	or	SAVED_TCL, SELBUSB /* Add the channel bit while we're here */
31719164Sgibbs	or	A,0x08		/* Channel B entries add 8 */
31819164Sgibbsndx_dtr_2:
31919164Sgibbs	add	SINDEX,TARG_SCRATCH,A
32013177Sgibbs	mov	SCSIRATE,SINDIR
32113177Sgibbs
32215843Sgibbs
32313177Sgibbs/*
32413177Sgibbs * Main loop for information transfer phases.  If BSY is false, then
32513177Sgibbs * we have a bus free condition, expected or not.  Otherwise, wait
32613177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O
32713177Sgibbs * for the bus phase.
32813177Sgibbs *
32913177Sgibbs */
3304568SgibbsITloop:
33122451Sgibbs	test	SSTAT1,0x9	jz ITloop	/* REQINIT|BUSFREE */
33213177Sgibbs	test	SSTAT1,BUSFREE	jnz p_busfree
3334568Sgibbs
33413177Sgibbs	and	A,PHASE_MASK,SCSISIGI
33513690Sgibbs	mov	LASTPHASE,A
33613690Sgibbs	mov	SCSISIGO,A
3374568Sgibbs
3384568Sgibbs	cmp	ALLZEROS,A	je p_dataout
33913177Sgibbs	cmp	A,P_DATAIN	je p_datain
34013177Sgibbs	cmp	A,P_COMMAND	je p_command
34113177Sgibbs	cmp	A,P_MESGOUT	je p_mesgout
34213177Sgibbs	cmp	A,P_STATUS	je p_status
34313177Sgibbs	cmp	A,P_MESGIN	je p_mesgin
3444568Sgibbs
34513177Sgibbs	mvi	INTSTAT,BAD_PHASE	/* unknown phase - signal driver */
34615843Sgibbs	jmp	ITloop			/* Try reading the bus again. */
3474568Sgibbs
3484568Sgibbsp_dataout:
34913177Sgibbs	mvi	DMAPARAMS,0x7d			/*
35013177Sgibbs						 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
35113177Sgibbs						 * DIRECTION|FIFORESET
35213177Sgibbs						 */
3539928Sgibbs	jmp	data_phase_init
3544568Sgibbs
35513177Sgibbs/*
35613177Sgibbs * If we re-enter the data phase after going through another phase, the
35713177Sgibbs * STCNT may have been cleared, so restore it from the residual field.
35813177Sgibbs */
3599928Sgibbsdata_phase_reinit:
36019231Sgibbs	mvi	DINDEX, STCNT0
36119231Sgibbs	mvi	SCB_RESID_DCNT0	call bcopy_3
3629928Sgibbs	jmp	data_phase_loop
3634568Sgibbs
3649928Sgibbsp_datain:
36513177Sgibbs	mvi	DMAPARAMS,0x79		/*
36613177Sgibbs					 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
36713177Sgibbs					 * !DIRECTION|FIFORESET
36813177Sgibbs					 */
3699928Sgibbsdata_phase_init:
37019164Sgibbs	call	assert			/*
37119164Sgibbs					 * Ensure entering a data
37219164Sgibbs					 * phase is okay - seen identify, etc.
37319164Sgibbs					 */
3745775Sgibbs
3759928Sgibbs	test	FLAGS, DPHASE	jnz data_phase_reinit
3764568Sgibbs
37719164Sgibbs	/*
37819164Sgibbs	 * Initialize the DMA address and counter from the SCB.
37919164Sgibbs	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
38019164Sgibbs	 * modify the values in the SCB itself until we see a
38119164Sgibbs	 * save data pointers message.
38219164Sgibbs	 */
38319164Sgibbs	mvi	DINDEX, HADDR0
38419164Sgibbs	mvi	SCB_DATAPTR	call bcopy_7
38519164Sgibbs
38619164Sgibbs	call	set_stcnt_from_hcnt
38719164Sgibbs
38819164Sgibbs	mov	SG_COUNT,SCB_SGCOUNT
38919164Sgibbs
39019164Sgibbs	mvi	DINDEX, SG_NEXT
39119164Sgibbs	mvi	SCB_SGPTR	call bcopy_4
39219164Sgibbs
39319164Sgibbs	/* We have seen a data phase */
39419164Sgibbs	or	FLAGS, DPHASE
39519164Sgibbs
3969928Sgibbsdata_phase_loop:
39716260Sgibbs/* Guard against overruns */
39816260Sgibbs	test	SG_COUNT, 0xff jnz data_phase_inbounds
39916260Sgibbs/*
40016260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to
40116260Sgibbs * 16meg and let the target run until it changes phase.
40216260Sgibbs * When the transfer completes, notify the host that we
40316260Sgibbs * had an overrun.
40416260Sgibbs */
40516260Sgibbs	or	SXFRCTL1,BITBUCKET
40622451Sgibbs	mvi	HCNT0, 0xff
40722451Sgibbs	mvi	HCNT1, 0xff
40822451Sgibbs	mvi	HCNT2, 0xff
40922451Sgibbs	call	set_stcnt_from_hcnt
41016260Sgibbs
41116260Sgibbsdata_phase_inbounds:
41219164Sgibbs/* If we are the last SG block, ensure wideodd is off. */
4139928Sgibbs	cmp	SG_COUNT,0x01 jne data_phase_wideodd
41413177Sgibbs	and	DMAPARAMS, 0xbf		/* Turn off WIDEODD */
4159928Sgibbsdata_phase_wideodd:
4169928Sgibbs	mov	DMAPARAMS  call dma
4174568Sgibbs
41816260Sgibbs/* Go tell the host about any overruns */
41916260Sgibbs	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun
42016260Sgibbs
42122451Sgibbs/* Exit if we had an underrun.  dma clears SINDEX in this case. */
42222451Sgibbs	test	SINDEX,0xff	jz data_phase_finish
4237532Sgibbs
42413177Sgibbs/*
42513177Sgibbs * Advance the scatter-gather pointers if needed 
42613177Sgibbs */
4279928Sgibbssg_advance:
42813177Sgibbs	dec	SG_COUNT	/* one less segment to go */
4294568Sgibbs
43013177Sgibbs	test	SG_COUNT, 0xff	jz data_phase_finish /* Are we done? */
4314568Sgibbs
43213177Sgibbs	clr	A			/* add sizeof(struct scatter) */
43313177Sgibbs	add	SG_NEXT0,SG_SIZEOF,SG_NEXT0
43413177Sgibbs	adc	SG_NEXT1,A,SG_NEXT1
4354568Sgibbs
43613177Sgibbs/*
43713177Sgibbs * Load a struct scatter and set up the data address and length.
43813177Sgibbs * If the working value of the SG count is nonzero, then
43913177Sgibbs * we need to load a new set of values.
44013177Sgibbs *
44115328Sgibbs * This, like all DMA's, assumes little-endian host data storage.
44213177Sgibbs */
4439928Sgibbssg_load:
44413177Sgibbs	clr	HCNT2
44513177Sgibbs	clr	HCNT1
44613177Sgibbs	mvi	HCNT0,SG_SIZEOF
4474568Sgibbs
44819164Sgibbs	mvi	DINDEX, HADDR0
44919164Sgibbs	mvi	SG_NEXT0	call bcopy_4
4504568Sgibbs
45113690Sgibbs	or	DFCNTRL,0xd			/* HDMAEN|DIRECTION|FIFORESET */
4529928Sgibbs
45319164Sgibbs	call	dma_finish
4549928Sgibbs
45513177Sgibbs/*
45613177Sgibbs * Copy data from FIFO into SCB data pointer and data count.  This assumes
45719164Sgibbs * that the SG segments are of the form:
45813177Sgibbs *
45913177Sgibbs * struct ahc_dma_seg {
46019164Sgibbs *	u_int32_t	addr;		four bytes, little-endian order
46119164Sgibbs *	u_int32_t	len;		four bytes, little endian order
46213177Sgibbs * };
46313177Sgibbs */
46419164Sgibbs	mvi	HADDR0	call dfdat_in_7
4659928Sgibbs
46613177Sgibbs/* Load STCNT as well.  It is a mirror of HCNT */
46719164Sgibbs	call	set_stcnt_from_hcnt
46819164Sgibbs	test	SSTAT1,PHASEMIS  jz data_phase_loop
4694568Sgibbs
4709928Sgibbsdata_phase_finish:
47113177Sgibbs/*
47213177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB
47313177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
47413177Sgibbs * were transferred on the SCSI (as opposed to the host) bus.
47513177Sgibbs */
47613690Sgibbs	mov	SCB_RESID_DCNT0,STCNT0
47713690Sgibbs	mov	SCB_RESID_DCNT1,STCNT1
47813690Sgibbs	mov	SCB_RESID_DCNT2,STCNT2
47913177Sgibbs	mov	SCB_RESID_SGCNT, SG_COUNT
4804568Sgibbs	jmp	ITloop
4814568Sgibbs
48216260Sgibbsdata_phase_overrun:
48313177Sgibbs/*
48416260Sgibbs * Turn off BITBUCKET mode and notify the host
48516260Sgibbs */
48616260Sgibbs	and	SXFRCTL1,0x7f		/* ~BITBUCKET */
48716260Sgibbs	mvi	INTSTAT,DATA_OVERRUN
48816260Sgibbs	jmp	ITloop
48916260Sgibbs
49016260Sgibbs/*
49115328Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
49213177Sgibbs */
4934568Sgibbsp_command:
4944568Sgibbs	call	assert
4954568Sgibbs
49613177Sgibbs/*
49715328Sgibbs * Load HADDR and HCNT.
49813177Sgibbs */
49919164Sgibbs	mvi	DINDEX, HADDR0
50019164Sgibbs	mvi	SCB_CMDPTR	call bcopy_5
50113690Sgibbs	clr	HCNT1
50213690Sgibbs	clr	HCNT2
5034568Sgibbs
50419164Sgibbs	call	set_stcnt_from_hcnt
5054568Sgibbs
50622078Sgibbs	mvi	0x3d		call dma	/*  SCSIEN|SDMAEN|HDMAEN
50721982Sgibbs						 * |DIRECTION|FIFORESET
50821982Sgibbs						 */
5094568Sgibbs	jmp	ITloop
5104568Sgibbs
51113177Sgibbs/*
51213177Sgibbs * Status phase.  Wait for the data byte to appear, then read it
51313177Sgibbs * and store it into the SCB.
51413177Sgibbs */
5154568Sgibbsp_status:
51619803Sgibbs	call	assert
51719803Sgibbs
51821947Sgibbs	mov	SCB_TARGET_STATUS, SCSIDATL
51921947Sgibbs	jmp	ITloop
5204568Sgibbs
52113177Sgibbs/*
52215328Sgibbs * Message out phase.  If there is not an active message, but the target
52313177Sgibbs * took us into this phase anyway, build a no-op message and send it.
52413177Sgibbs */
5254568Sgibbsp_mesgout:
52613177Sgibbs	test	MSG_LEN, 0xff	jnz  p_mesgout_start
52718762Sgibbs	mvi	MSG_NOOP	call mk_mesg	/* build NOP message */
52813177Sgibbsp_mesgout_start:
52913177Sgibbs/*
53013177Sgibbs * Set up automatic PIO transfer from MSG0.  Bit 3 in
53113177Sgibbs * SXFRCTL0 (SPIOEN) is already on.
53213177Sgibbs */
53313177Sgibbs	mvi	SINDEX,MSG0
5344568Sgibbs	mov	DINDEX,MSG_LEN
5354568Sgibbs
53613177Sgibbs/*
53713177Sgibbs * When target asks for a byte, drop ATN if it's the last one in
53813177Sgibbs * the message.  Otherwise, keep going until the message is exhausted.
53913177Sgibbs *
54013177Sgibbs * Keep an eye out for a phase change, in case the target issues
54113177Sgibbs * a MESSAGE REJECT.
54213177Sgibbs */
54313177Sgibbsp_mesgout_loop:
54421947Sgibbs	/*
54521947Sgibbs	 * If there is a parity error, wait for the kernel to
54621947Sgibbs	 * see the interrupt and "update" our message response
54721947Sgibbs	 * before continuing.
54821947Sgibbs	 */
54921947Sgibbs	test	SSTAT1, REQINIT	jz p_mesgout_loop
55021947Sgibbs	test	SSTAT1, SCSIPERR jnz p_mesgout_loop
55121947Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
55221947Sgibbs	cmp	LASTPHASE, P_MESGOUT jne p_mesgout_done
55313177Sgibbs/*
55413177Sgibbs * If the next bus phase after ATN drops is a message out, it means
55513177Sgibbs * that the target is requesting that the last message(s) be resent.
55613177Sgibbs */
55719921Sgibbsp_mesgout_testretry:
55820117Sgibbs	test	DINDEX,0xff	jnz p_mesgout_dropatn
55921947Sgibbs	or	SCSISIGO,ATNO,LASTPHASE	/* turn on ATN for the retry */
56019906Sgibbs	jmp	p_mesgout_start
56120117Sgibbsp_mesgout_dropatn:
56220117Sgibbs	cmp	DINDEX,1	jne p_mesgout_outb	/* last byte? */
56320117Sgibbs	mvi	CLRSINT1,CLRATNO			/* drop ATN */
56419906Sgibbsp_mesgout_outb:
56519906Sgibbs	dec	DINDEX
56619906Sgibbs	mvi	CLRSINT0, CLRSPIORDY
56719906Sgibbs	mov	SCSIDATL,SINDIR
56819906Sgibbs	jmp	p_mesgout_loop
5694568Sgibbs
57019906Sgibbsp_mesgout_done:
57115328Sgibbs	mvi	CLRSINT1,CLRATNO	/* Be sure to turn ATNO off */
57213177Sgibbs	clr	MSG_LEN			/* no active msg */
5734568Sgibbs	jmp	ITloop
5744568Sgibbs
57513177Sgibbs/*
57613177Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
57713177Sgibbs */
5784568Sgibbsp_mesgin:
57913177Sgibbs	mvi	A		call inb_first	/* read the 1st message byte */
58013177Sgibbs	mov	REJBYTE,A			/* save it for the driver */
5814568Sgibbs
58218762Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify
58313177Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect
58418762Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs
58513177Sgibbs	cmp	ALLZEROS,A		je mesgin_complete
58618762Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs
58713177Sgibbs	cmp	A,MSG_EXTENDED		je mesgin_extended
58818762Sgibbs	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject
58922451Sgibbs	cmp	A,MSG_NOOP		je mesgin_done
5904568Sgibbs
5919954Sgibbsrej_mesgin:
59213177Sgibbs/*
59319164Sgibbs * We have no idea what this message in is, so we issue a message reject
59419164Sgibbs * and hope for the best.  In any case, rejection should be a rare
59519164Sgibbs * occurrence - signal the driver when it happens.
59613177Sgibbs */
59713177Sgibbs	mvi	INTSTAT,SEND_REJECT		/* let driver know */
5989954Sgibbs
59918762Sgibbs	mvi	MSG_MESSAGE_REJECT	call mk_mesg
6009954Sgibbs
6019954Sgibbsmesgin_done:
60222451Sgibbs	call	inb_last
6039954Sgibbs	jmp	ITloop
6049954Sgibbs
6059954Sgibbs
6069954Sgibbsmesgin_complete:
60713177Sgibbs/*
60819164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
60919164Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
61019164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0).  In
61119164Sgibbs * either of these conditions, we upload the SCB back to the host so it can
61219164Sgibbs * process this information.  In the case of a non zero status byte, we 
61319164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
61419164Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
61519164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set
61619164Sgibbs * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
61719164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list.
61819164Sgibbs * If the kernel driver does not wish to request sense, it need only clear
61919164Sgibbs * RETURN_1, and the command is allowed to complete normally.  We don't bother
62019164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra
62119164Sgibbs * work in the kernel driver to ensure that the entry was removed before the
62219164Sgibbs * command complete code tried processing it.
62313177Sgibbs */
62419164Sgibbs
62513177Sgibbs/*
62619921Sgibbs * We expect to go to bus free after this message.
62719921Sgibbs */
62819921Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
62919921Sgibbs/*
63019164Sgibbs * First check for residuals
63113177Sgibbs */
63219164Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz upload_scb
63319164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Good Status? */
63419164Sgibbsupload_scb:
63519164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
63619164Sgibbs	mov	SCB_TAG		call dma_scb
6377532Sgibbscheck_status:
63819164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Just a residual? */
63913177Sgibbs	mvi	INTSTAT,BAD_STATUS			/* let driver know */
64013177Sgibbs	cmp	RETURN_1, SEND_SENSE	jne status_ok
64119164Sgibbs	/* This SCB becomes the next to execute as it will retrieve sense */
64219164Sgibbs	mov	SCB_LINKED_NEXT, SCB_TAG
64319164Sgibbs	jmp	dma_next_scb
6445326Sgibbs
6454568Sgibbsstatus_ok:
64613177Sgibbs/* First, mark this target as free. */
64719921Sgibbs	test	SCB_CONTROL,TAG_ENB jnz complete	/*
64813177Sgibbs							 * Tagged commands
64913177Sgibbs							 * don't busy the
65013177Sgibbs							 * target.
65113177Sgibbs							 */
65219164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
65319164Sgibbs	mov	SAVED_LINKPTR, SCB_LINKED_NEXT
65419218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
65519164Sgibbs	mov	DINDIR, SAVED_LINKPTR
65619164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
6575326Sgibbs
6585326Sgibbscomplete:
65919164Sgibbs	/* Post the SCB and issue an interrupt */
66015328Sgibbs	mov	QOUTFIFO,SCB_TAG
6617532Sgibbs	mvi	INTSTAT,CMDCMPLT
66219164Sgibbs
66319164Sgibbsdma_next_scb:
66419921Sgibbs	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je add_to_free_list
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
6779954Sgibbs	jmp	mesgin_done
67819921Sgibbsadd_to_free_list:
67919921Sgibbs	call	add_scb_to_free_list
68019921Sgibbs	jmp	mesgin_done
6814568Sgibbs
68213177Sgibbs/*
68318762Sgibbs * Is it an extended message?  Copy the message to our message buffer and
68418762Sgibbs * notify the host.  The host will tell us whether to reject this message,
68518762Sgibbs * respond to it with the message that the host placed in our message buffer,
68618762Sgibbs * or simply to do nothing.
68713177Sgibbs */
6889954Sgibbsmesgin_extended:
68918762Sgibbs	mvi	MSGIN_EXT_LEN	 call inb_next
69018762Sgibbs	mov	A, MSGIN_EXT_LEN
69118762Sgibbsmesgin_extended_loop:
69219164Sgibbs	mov	DINDEX	call	inb_next
69318762Sgibbs	dec	A
69419164Sgibbs	cmp	DINDEX, MSGIN_EXT_LASTBYTE jne mesgin_extended_loop_test
69519164Sgibbs	dec	DINDEX		/* dump by repeatedly filling the last byte */
69619164Sgibbsmesgin_extended_loop_test:
69719164Sgibbs	test	A, 0xFF		jnz mesgin_extended_loop
69818762Sgibbsmesgin_extended_intr:
69918762Sgibbs	mvi	INTSTAT,EXTENDED_MSG		/* let driver know */
70018762Sgibbs	cmp	RETURN_1,SEND_REJ je rej_mesgin
70118762Sgibbs	cmp	RETURN_1,SEND_MSG jne mesgin_done
70218762Sgibbs/* The kernel has setup a message to be sent */
70321947Sgibbs	or	SCSISIGO,ATNO,LASTPHASE		/* turn on ATNO */
7049954Sgibbs	jmp	mesgin_done
7055562Sgibbs
70613177Sgibbs/*
70713177Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
70813177Sgibbs * and await the bus going free.
70913177Sgibbs */
7109954Sgibbsmesgin_disconnect:
71119921Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
71213177Sgibbs	or	SCB_CONTROL,DISCONNECTED
71315328Sgibbs	test	FLAGS, PAGESCBS jz mesgin_done
71419164Sgibbs	call	add_scb_to_disc_list
71519164Sgibbs	jmp	mesgin_done
71619164Sgibbs
71715328Sgibbs/*
71819164Sgibbs * Save data pointers message:
71919164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
72019164Sgibbs * only if we've actually been into a data phase to change them.  This
72119164Sgibbs * protects against bogus data in scratch ram and the residual counts
72219164Sgibbs * since they are only initialized when we go into data_in or data_out.
72315328Sgibbs */
72419164Sgibbsmesgin_sdptrs:
72519164Sgibbs	test	FLAGS, DPHASE	jz mesgin_done
72619164Sgibbs	mov	SCB_SGCOUNT,SG_COUNT
7274568Sgibbs
72819164Sgibbs	/* The SCB SGPTR becomes the next one we'll download */
72919164Sgibbs	mvi	DINDEX, SCB_SGPTR
73019164Sgibbs	mvi	SG_NEXT0	call bcopy_4
73119164Sgibbs	
73219164Sgibbs	/* The SCB DATAPTR0 becomes the current SHADDR */
73319164Sgibbs	mvi	DINDEX, SCB_DATAPTR0
73419164Sgibbs	mvi	SHADDR0		call bcopy_4
73519164Sgibbs
73613177Sgibbs/*
73719164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer.
73813177Sgibbs */
73919164Sgibbs	mvi	SCB_RESID_DCNT0	call	bcopy_3
74019164Sgibbs
7419954Sgibbs	jmp	mesgin_done
7424568Sgibbs
74313177Sgibbs/*
74413177Sgibbs * Restore pointers message?  Data pointers are recopied from the
74513177Sgibbs * SCB anytime we enter a data phase for the first time, so all
74613177Sgibbs * we need to do is clear the DPHASE flag and let the data phase
74713177Sgibbs * code do the rest.
74813177Sgibbs */
7499954Sgibbsmesgin_rdptrs:
75015328Sgibbs	and	FLAGS,0xef			/*
75113177Sgibbs						 * !DPHASE we'll reload them
75213177Sgibbs						 * the next time through
75313177Sgibbs						 */
7549954Sgibbs	jmp	mesgin_done
7554568Sgibbs
75613177Sgibbs/*
75713177Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
75813177Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
75913177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
76013177Sgibbs */
7619954Sgibbsmesgin_identify:
76213177Sgibbs	test	A,0x78	jnz rej_mesgin	/*!DiscPriv|!LUNTAR|!Reserved*/
76313177Sgibbs	and	A,0x07			/* lun in lower three bits */
76419164Sgibbs	or      SAVED_TCL,A		/* SAVED_TCL should be complete now */
76513177Sgibbs	call	inb_last		/* ACK */
76613177Sgibbs
76713177Sgibbs/*
76813177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
76915328Sgibbs * If we get one, we use the tag returned to switch to find the proper
77015328Sgibbs * SCB.  With SCB paging, this requires using findSCB for both tagged
77115328Sgibbs * and non-tagged transactions since the SCB may exist in any slot.
77215328Sgibbs * If we're not using SCB paging, we can use the tag as the direct
77315328Sgibbs * index to the SCB.
77413177Sgibbs */
77515328Sgibbs	mvi	ARG_1,SCB_LIST_NULL	/* Default to no-tag */
77613177Sgibbssnoop_tag_loop:
77720117Sgibbs	test	SSTAT1,REQINIT		jz snoop_tag_loop
77821947Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
77921947Sgibbs	cmp	LASTPHASE, P_MESGIN, jne use_findSCB
78018762Sgibbs	mvi	A			call inb_first
78118762Sgibbs	cmp	A,MSG_SIMPLE_Q_TAG	jne use_findSCB
7826608Sgibbsget_tag:
78319218Sgibbs	or	FLAGS, TAGGED_SCB
78413177Sgibbs	mvi	ARG_1	call inb_next	/* tag value */
78513177Sgibbs/*
78613177Sgibbs * See if the tag is in range.  The tag is < SCBCOUNT if we add
78713177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is
78813177Sgibbs * no carry.
78913177Sgibbs */
79013177Sgibbs	mov	A,COMP_SCBCOUNT	
79113177Sgibbs	add	SINDEX,A,ARG_1
79219218Sgibbs	jc	send_abort_msg
79313177Sgibbs
79413177Sgibbs/*
79515328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction
79613177Sgibbs * to the reconnecting target.
79713177Sgibbs */
79815328Sgibbs	test	FLAGS, PAGESCBS	jz index_by_tag
79915328Sgibbsuse_findSCB:
80015328Sgibbs	mov	ALLZEROS	call findSCB	  /* Have to search */
80119218Sgibbs	cmp	SINDEX, SCB_LIST_NULL, je not_found
80215328Sgibbssetup_SCB:
80315328Sgibbs	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
80415328Sgibbs	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
80519164Sgibbs	test	SCB_CONTROL,TAG_ENB	jnz  mesgin_done /* Ack Tag */
80615328Sgibbs	jmp	ITloop
80715328Sgibbsindex_by_tag:
80813177Sgibbs	mov	SCBPTR,ARG_1
80919218Sgibbs	mov	A, SAVED_TCL
81019218Sgibbs	cmp	SCB_TCL,A		jne send_abort_msg
81119218Sgibbs	test	SCB_CONTROL,TAG_ENB	jz  send_abort_msg
81213177Sgibbs	jmp	setup_SCB
81315328Sgibbs
81419218Sgibbsnot_found:
81519218Sgibbs	mvi	INTSTAT, NO_MATCH
81619218Sgibbssend_abort_msg:
81719218Sgibbs	test	FLAGS, TAGGED_SCB jnz abort_tag_msg
81819218Sgibbs	mvi	MSG_ABORT	call mk_mesg
81919218Sgibbs	jmp	mesgin_done
82019164Sgibbsabort_tag_msg:
82115328Sgibbs	mvi	MSG_ABORT_TAG	call mk_mesg	/* ABORT TAG message */
82213177Sgibbs	jmp	mesgin_done
8236608Sgibbs
82413177Sgibbs/*
82513177Sgibbs * Message reject?  Let the kernel driver handle this.  If we have an 
82613177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 
82713177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
82813177Sgibbs * it since we have no clue what it pertains to.
82913177Sgibbs */
8309954Sgibbsmesgin_reject:
83113177Sgibbs	mvi	INTSTAT, REJECT_MSG
8329954Sgibbs	jmp	mesgin_done
8335562Sgibbs
83413177Sgibbs/*
83513177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ]
83613177Sgibbs */
8374568Sgibbs
83813177Sgibbs/*
83913177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX
84013177Sgibbs * if there is no active message already.  SINDEX is returned intact.
84113177Sgibbs */
8424568Sgibbsmk_mesg:
84313177Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
84413177Sgibbs	test	MSG_LEN,0xff	jz mk_mesg1	/* Should always succeed */
84513177Sgibbs	
84613177Sgibbs	/*
84713177Sgibbs	 * Hmmm.  For some reason the mesg buffer is in use.
84813177Sgibbs	 * Tell the driver.  It should look at SINDEX to find
84913177Sgibbs	 * out what we wanted to use the buffer for and resolve
85013177Sgibbs	 * the conflict.
85113177Sgibbs	 */
85213177Sgibbs	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
85313690Sgibbs	mvi	INTSTAT,MSG_BUFFER_BUSY
8544568Sgibbs
8554568Sgibbsmk_mesg1:
85621947Sgibbs	or	SCSISIGO,ATNO,LASTPHASE	/* turn on ATNO */
85713177Sgibbs	mvi	MSG_LEN,1		/* length = 1 */
85813177Sgibbs	mov	MSG0,SINDEX		/* 1-byte message */
85913177Sgibbs	mvi	SEQCTL,0x10	ret	/* !PAUSEDIS|FASTMODE */
8604568Sgibbs
86113177Sgibbs/*
86213177Sgibbs * Functions to read data in Automatic PIO mode.
86313177Sgibbs *
86413177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
86513177Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
86613177Sgibbs * latched (the usual way), then read the data byte directly off the bus
86713177Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
86813177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
86913177Sgibbs * spec guarantees that the target will hold the data byte on the bus until
87013177Sgibbs * we send our ACK.
87113177Sgibbs *
87213177Sgibbs * The assumption here is that these are called in a particular sequence,
87313177Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
87413177Sgibbs * use the same calling convention as inb.
87513177Sgibbs */
87613177Sgibbs
87713177Sgibbsinb_next:
87821947Sgibbs	mov	NONE,SCSIDATL			/*dummy read from latch to ACK*/
87913360Sgibbsinb_next_wait:
88021947Sgibbs	/*
88121947Sgibbs	 * If there is a parity error, wait for the kernel to
88221947Sgibbs	 * see the interrupt and prepare our message response
88321947Sgibbs	 * before continuing.
88421947Sgibbs	 */
88521947Sgibbs	test	SSTAT1, REQINIT	jz inb_next_wait
88621947Sgibbs	test	SSTAT1, SCSIPERR jnz inb_next_wait
88721947Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
88821947Sgibbs	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis
88919623Sgibbsinb_first:
8904568Sgibbs	mov	DINDEX,SINDEX
89113177Sgibbs	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
89213177Sgibbsinb_last:
89313360Sgibbs	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
8944568Sgibbs
89513177Sgibbsmesgin_phasemis:
89613177Sgibbs/*
89713177Sgibbs * We expected to receive another byte, but the target changed phase
89813177Sgibbs */
89913177Sgibbs	mvi	INTSTAT, MSGIN_PHASEMIS
90013177Sgibbs	jmp	ITloop
9014568Sgibbs
90213177Sgibbs/*
90313177Sgibbs * DMA data transfer.  HADDR and HCNT must be loaded first, and
90413177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for
90513177Sgibbs * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
90613177Sgibbs * during initialization.
90713177Sgibbs */
9084568Sgibbsdma:
9094568Sgibbs	mov	DFCNTRL,SINDEX
9104568Sgibbsdma1:
91113177Sgibbs	test	SSTAT0,DMADONE	jnz dma3
91213177Sgibbs	test	SSTAT1,PHASEMIS	jz dma1		/* ie. underrun */
91322451Sgibbs	test	SSTAT0,SDONE	jnz dma3
91422451Sgibbs	mov	SINDEX,ALLZEROS			/* Notify caller of phasemiss */
9154568Sgibbs
91613177Sgibbs/*
91713177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or
91813177Sgibbs * the target changes the phase (in light of this, it makes sense that
91913177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
92013177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
92113177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty
92213177Sgibbs * status.
92313177Sgibbs */
9244568Sgibbsdma3:
92522451Sgibbs	test	DFCNTRL,DIRECTION	jnz dma5
9264568Sgibbsdma4:
92713177Sgibbs	test	DFSTATUS,FIFOEMP	jz dma4
9284568Sgibbs
92913177Sgibbs/*
93013177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 
93113177Sgibbs * actually off first lest we get an ILLSADDR.
93213177Sgibbs */
9334568Sgibbsdma5:
93421982Sgibbs	/* Don't clobber an inprogress host data transfer */
93521982Sgibbs	test	DFSTATUS, MREQPEND	jnz dma5
93621982Sgibbs	/* disable DMA */
93722451Sgibbs	and	DFCNTRL, 0xc7		/* ~(SCSIEN|SDMAEN|HDMAEN) */
9384568Sgibbsdma6:
93922451Sgibbs	test	DFCNTRL, 0x38	jnz dma6  /* (SCSIEN|SDMAEN|HDMAEN) */
94018762Sgibbsreturn:
9414568Sgibbs	ret
9424568Sgibbs
94313177Sgibbs/*
94413177Sgibbs * Common SCSI initialization for selection and reselection.  Expects
94513177Sgibbs * the target SCSI ID to be in the upper four bits of SINDEX, and A's
94613177Sgibbs * contents are stomped on return.
94713177Sgibbs */
9488104Sgibbsinitialize_scsiid:
94913177Sgibbs	and	SINDEX,0xf0		/* Get target ID */
95019164Sgibbs	mov	SAVED_TCL, SINDEX	/* Update the target portion of this */
9515775Sgibbs	and	A,0x0f,SCSIID
9525775Sgibbs	or	SINDEX,A
9538104Sgibbs	mov	SCSIID,SINDEX ret
9545326Sgibbs
95513177Sgibbs/*
95613177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
95713177Sgibbs * message.
95813177Sgibbs */
9594568Sgibbsassert:
96013177Sgibbs	test	FLAGS,RESELECTED	jz return	/* reselected? */
96113177Sgibbs	test	FLAGS,IDENTIFY_SEEN	jnz return	/* seen IDENTIFY? */
9624568Sgibbs
96319164Sgibbs	mvi	INTSTAT,NO_IDENT 	ret	/* no - tell the kernel */
9644568Sgibbs
96513177Sgibbs/*
96619218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
96719218Sgibbs * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
96819218Sgibbs * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
96919218Sgibbs * otherwise, SCBPTR is set to the proper SCB.
97013177Sgibbs */
9714568SgibbsfindSCB:
97215328Sgibbs	mov	SCBPTR,SINDEX			/* switch to next SCB */
97313177Sgibbs	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
97419218Sgibbs	cmp	ARG_1, SCB_LIST_NULL	jne findBySCBID
97519218Sgibbs	mov	A, SAVED_TCL
97619218Sgibbs	cmp	SCB_TCL,A	je foundSCB /* target ID/channel/lun match? */
97719164SgibbsfindSCB1:
97819164Sgibbs	inc	SINDEX
97919164Sgibbs	mov	A,SCBCOUNT
98019164Sgibbs	cmp	SINDEX,A	jne findSCB
98119164Sgibbs/*
98219164Sgibbs * We didn't find it.  If we're paging, pull an SCB and DMA down the
98319164Sgibbs * one we want.  If we aren't paging or the SCB we dma down has the
98419218Sgibbs * abort flag set, return not found.
98519164Sgibbs */
98619218Sgibbs	test	FLAGS, PAGESCBS	jz find_error
98719623Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb
98819218Sgibbs	cmp	ARG_1, SCB_LIST_NULL jne find_dma_scb
98919218Sgibbs	mov	SAVED_TCL	call	index_untagged_scb
99019218Sgibbs	mov	ARG_1, SINDIR	/* SCBID of SCB to fetch */
99119164Sgibbsfind_dma_scb:
99219164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
99319218Sgibbs	mov	ARG_1	call dma_scb
99419164Sgibbs	test	SCB_CONTROL, ABORT_SCB jz return
99522078Sgibbs	call	add_scb_to_free_list
99619218Sgibbsfind_error:
99719218Sgibbs	mvi	SINDEX, SCB_LIST_NULL ret
99819218SgibbsfindBySCBID:
99915328Sgibbs	mov	A, ARG_1			/* Tag passed in ARG_1 */
100015328Sgibbs	cmp	SCB_TAG,A	jne findSCB1	/* Found it? */
100115328SgibbsfoundSCB:
100219218Sgibbs	test	SCB_CONTROL, ABORT_SCB jnz find_error
100319164Sgibbs	test	FLAGS,PAGESCBS	jz return
100419164Sgibbsrem_scb_from_disc_list:
100515328Sgibbs/* Remove this SCB from the disconnection list */
100615328Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev
100715328Sgibbs	mov	SAVED_LINKPTR, SCB_PREV
100815328Sgibbs	mov	SCBPTR, SCB_NEXT
100915328Sgibbs	mov	SCB_PREV, SAVED_LINKPTR
101015328Sgibbs	mov	SCBPTR, SINDEX
101115328Sgibbsunlink_prev:
101215328Sgibbs	cmp	SCB_PREV,SCB_LIST_NULL	je rHead/* At the head of the list */
101315328Sgibbs	mov	SAVED_LINKPTR, SCB_NEXT
101415328Sgibbs	mov	SCBPTR, SCB_PREV
101515328Sgibbs	mov	SCB_NEXT, SAVED_LINKPTR
101619164Sgibbs	mov	SCBPTR, SINDEX ret
101715328SgibbsrHead:
101819164Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret
10194568Sgibbs
102019164Sgibbsset_stcnt_from_hcnt:
102119164Sgibbs	mov	STCNT0, HCNT0
102219164Sgibbs	mov	STCNT1, HCNT1
102319164Sgibbs	mov	STCNT2, HCNT2 ret
10244568Sgibbs
102519164Sgibbsbcopy_7:
102619164Sgibbs	mov	DINDIR, SINDIR
102719164Sgibbs	mov	DINDIR, SINDIR
102819164Sgibbsbcopy_5:
102919164Sgibbs	mov	DINDIR, SINDIR
103019164Sgibbsbcopy_4:
103119164Sgibbs	mov	DINDIR, SINDIR
103219164Sgibbsbcopy_3:
103319164Sgibbs	mov	DINDIR, SINDIR
103419164Sgibbs	mov	DINDIR, SINDIR
103519164Sgibbs	mov	DINDIR, SINDIR ret
10364568Sgibbs
103719164Sgibbsdma_scb:
103819164Sgibbs	/*
103919164Sgibbs	 * SCB index is in SINDEX.  Determine the physical address in
104019164Sgibbs	 * the host where this SCB is located and load HADDR with it.
104119164Sgibbs	 */
104219164Sgibbs	shr	DINDEX, SINDEX, 3
104319164Sgibbs	shl	A, SINDEX, 5
104419164Sgibbs	add	HADDR0, A, HSCB_ADDR0
104519164Sgibbs	mov	A, DINDEX
104619164Sgibbs	adc	HADDR1, A, HSCB_ADDR1
104719164Sgibbs	clr	A
104819164Sgibbs	adc	HADDR2, A, HSCB_ADDR2
104919164Sgibbs	adc	HADDR3, A, HSCB_ADDR3
105019164Sgibbs	/* Setup Count */
105119164Sgibbs	mvi	HCNT0, 28
105219164Sgibbs	clr	HCNT1
105319164Sgibbs	clr	HCNT2
105419164Sgibbs	mov	DFCNTRL, DMAPARAMS
105519164Sgibbs	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost
105619164Sgibbs	/* Fill it with the SCB data */
105719164Sgibbs	call	copy_scb_tofifo
105819164Sgibbs	mvi	DFCNTRL, 0xa		/* HDMAEN | FIFOFLUSH */
105919164Sgibbsdma_scb_fromhost:
106019164Sgibbs	call	dma_finish
106119164Sgibbs	/* If we were putting the SCB, we are done */
106219164Sgibbs	test	DMAPARAMS, DIRECTION	jz	return
106319164Sgibbs	mvi	SCBARRAY  call dfdat_in_7
106419164Sgibbs	call	dfdat_in_7_continued
106519164Sgibbs	call	dfdat_in_7_continued
106619164Sgibbs	jmp	dfdat_in_7_continued
106719164Sgibbsdfdat_in_7:
106819164Sgibbs	mov     DINDEX,SINDEX
106919164Sgibbsdfdat_in_7_continued:
107019164Sgibbs	mov	DINDIR,DFDAT
107119164Sgibbs	mov	DINDIR,DFDAT
107219164Sgibbs	mov	DINDIR,DFDAT
107319164Sgibbs	mov	DINDIR,DFDAT
107419164Sgibbs	mov	DINDIR,DFDAT
107519164Sgibbs	mov	DINDIR,DFDAT
107619164Sgibbs	mov	DINDIR,DFDAT ret
107719164Sgibbs
107819164Sgibbscopy_scb_tofifo:
107919164Sgibbs	mvi	SCBARRAY  call dfdat_out_7
108019164Sgibbs	call	dfdat_out_7
108119164Sgibbs	call	dfdat_out_7
108219164Sgibbsdfdat_out_7:
108319164Sgibbs	mov	DFDAT,SINDIR
108419164Sgibbs	mov	DFDAT,SINDIR
108519164Sgibbs	mov	DFDAT,SINDIR
108619164Sgibbs	mov	DFDAT,SINDIR
108719164Sgibbs	mov	DFDAT,SINDIR
108819164Sgibbs	mov	DFDAT,SINDIR
108919164Sgibbs	mov	DFDAT,SINDIR ret
109019164Sgibbs
109113177Sgibbs/*
109219164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
109319164Sgibbs * DMA and wait for it to acknowledge that it's off.
109413177Sgibbs */
109519164Sgibbsdma_finish:
109619164Sgibbs	test	DFSTATUS,HDONE	jz dma_finish
109722234Sgibbs	/* Turn off DMA */
109822234Sgibbs	and	DFCNTRL, 0xf7 ret	# ~HDMAEN
10999928Sgibbs
110019164Sgibbsindex_untagged_scb:
110119218Sgibbs	mov	DINDEX, SINDEX
110219218Sgibbs	shr	DINDEX, 4
110319218Sgibbs	and	DINDEX, 0x03			/* Bottom two bits of tid */
110419218Sgibbs	add	DINDEX, SCB_ACTIVE0
110519218Sgibbs	shr	A, SINDEX, 6			/* Target ID divided by 4 */
110619421Sgibbs	test	SINDEX, SELBUSB jz index_untagged_scb2
110719421Sgibbs	add	A, 2				/* Add 2 positions */
110819164Sgibbsindex_untagged_scb2:
110919164Sgibbs	mov	SCBPTR, A			/*
111019164Sgibbs						 * Select the SCB with this 
111119164Sgibbs						 * target's information.
111219164Sgibbs						 */
111319218Sgibbs	mov	SINDEX, DINDEX	ret
11149928Sgibbs
11154568Sgibbs
111619164Sgibbsget_free_or_disc_scb:
111719623Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb
111819623Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb
111919623Sgibbsreturn_error:
112019623Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret
112119623Sgibbsdequeue_disc_scb:
112219164Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH
112313177Sgibbs/*
112419164Sgibbs * If we have a residual, then we are in the middle of some I/O
112519164Sgibbs * and we have to send this SCB back up to the kernel so that the
112619164Sgibbs * saved data pointers and residual information isn't lost.
112719164Sgibbs */
112819164Sgibbs	test	SCB_RESID_SGCNT,0xff	jz unlink_disc_scb
112919164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
113019164Sgibbs	mov	SCB_TAG		call dma_scb
113119164Sgibbsunlink_disc_scb:
113219623Sgibbs	/* jmp instead of call since we want to return anyway */
113319623Sgibbs	mov	SCBPTR	jmp rem_scb_from_disc_list
113419164Sgibbsdequeue_free_scb:
113519164Sgibbs	mov	SCBPTR, FREE_SCBH
113619164Sgibbs	mov	FREE_SCBH, SCB_NEXT ret
11374568Sgibbs
113819164Sgibbsadd_scb_to_free_list:
113919164Sgibbs	mov	SCB_NEXT, FREE_SCBH
114019164Sgibbs	mov	FREE_SCBH, SCBPTR ret
11414568Sgibbs
114219164Sgibbsadd_scb_to_disc_list:
114313177Sgibbs/*
114419164Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
114519164Sgibbs * candidates for paging out an SCB if one is needed for a new command.
114619164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
114713177Sgibbs */
114819164Sgibbs	mvi	SCB_PREV, SCB_LIST_NULL
114919164Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH
115019164Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR
115119164Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je return
115219164Sgibbs	mov	SCBPTR,SCB_NEXT
115319164Sgibbs	mov	SCB_PREV,DISCONNECTED_SCBH
115419164Sgibbs	mov	SCBPTR,DISCONNECTED_SCBH ret
11554568Sgibbs
1156