aic7xxx.seq revision 21982
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
4221673SjkhVERSION AIC7XXX_SEQ_VER "$FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 21982 1997-01-24 21:57:47Z 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:
8721947Sgibbs	or	SXFRCTL0, CLRCHN
8816198Sgibbs	clr	SCSIRATE		/*
8916198Sgibbs					 * We don't know the target we will
9016198Sgibbs					 * connect to, so default to narrow
9116198Sgibbs					 * transfers to avoid parity problems.
9216198Sgibbs					 */
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
15519164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
15619218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
15721947Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
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:
19421947Sgibbs	mvi	SEQCTL,0x10			/* FASTMODE */
19519164Sgibbs	mov	DINDIR, CUR_SCBID
19619164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
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/*
29413177Sgibbs * Initialize SCSIRATE with the appropriate value for this target.
29519164Sgibbs * The SCSIRATE settings for each target are stored in an array
29619164Sgibbs * based at TARG_SCRATCH.
29713177Sgibbs */
29819164Sgibbsndx_dtr:
29921947Sgibbs	shr	A,SAVED_TCL,4
30019164Sgibbs	test	SBLKCTL,SELBUSB	jz ndx_dtr_2
30119164Sgibbs	or	SAVED_TCL, SELBUSB /* Add the channel bit while we're here */
30219164Sgibbs	or	A,0x08		/* Channel B entries add 8 */
30319164Sgibbsndx_dtr_2:
30419164Sgibbs	add	SINDEX,TARG_SCRATCH,A
30513177Sgibbs	mov	SCSIRATE,SINDIR
30613177Sgibbs
30715843Sgibbs/*
30819164Sgibbs * Initialize Ultra mode setting and clear the SCSI channel.
30915843Sgibbs */
31019164Sgibbsultra:
31119164Sgibbs	and	DINDEX,0xdf,SXFRCTL0            /* default to Ultra disabled */
31219164Sgibbs	mvi	SINDEX, ULTRA_ENB_B
31321947Sgibbs	test	SAVED_TCL, 0x80     jnz ultra_2     /* Target ID > 7 */
31419164Sgibbs	test	SBLKCTL, SELBUSB jnz ultra_2     /* Second channel device */
31519164Sgibbs	dec	SINDEX
31619164Sgibbsultra_2:
31721947Sgibbs	mov     FUNCTION1,SAVED_TCL
31819164Sgibbs	mov     A,FUNCTION1
31919164Sgibbs	test	SINDIR, A	jz set_sxfrctl0
32019164Sgibbs	or	DINDEX, ULTRAEN
32119164Sgibbs 
32215843Sgibbsset_sxfrctl0:
32319164Sgibbs	mov	SXFRCTL0,DINDEX
32415843Sgibbs
32513177Sgibbs/*
32613177Sgibbs * Main loop for information transfer phases.  If BSY is false, then
32713177Sgibbs * we have a bus free condition, expected or not.  Otherwise, wait
32813177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O
32913177Sgibbs * for the bus phase.
33013177Sgibbs *
33113177Sgibbs */
3324568SgibbsITloop:
33313177Sgibbs	test	SSTAT1,BUSFREE	jnz p_busfree
33413177Sgibbs	test	SSTAT1,REQINIT	jz ITloop
3354568Sgibbs
33613177Sgibbs	and	A,PHASE_MASK,SCSISIGI
33713690Sgibbs	mov	LASTPHASE,A
33813690Sgibbs	mov	SCSISIGO,A
3394568Sgibbs
3404568Sgibbs	cmp	ALLZEROS,A	je p_dataout
34113177Sgibbs	cmp	A,P_DATAIN	je p_datain
34213177Sgibbs	cmp	A,P_COMMAND	je p_command
34313177Sgibbs	cmp	A,P_MESGOUT	je p_mesgout
34413177Sgibbs	cmp	A,P_STATUS	je p_status
34513177Sgibbs	cmp	A,P_MESGIN	je p_mesgin
3464568Sgibbs
34713177Sgibbs	mvi	INTSTAT,BAD_PHASE	/* unknown phase - signal driver */
34815843Sgibbs	jmp	ITloop			/* Try reading the bus again. */
3494568Sgibbs
3504568Sgibbsp_dataout:
35113177Sgibbs	mvi	DMAPARAMS,0x7d			/*
35213177Sgibbs						 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
35313177Sgibbs						 * DIRECTION|FIFORESET
35413177Sgibbs						 */
3559928Sgibbs	jmp	data_phase_init
3564568Sgibbs
35713177Sgibbs/*
35813177Sgibbs * If we re-enter the data phase after going through another phase, the
35913177Sgibbs * STCNT may have been cleared, so restore it from the residual field.
36013177Sgibbs */
3619928Sgibbsdata_phase_reinit:
36219231Sgibbs	mvi	DINDEX, STCNT0
36319231Sgibbs	mvi	SCB_RESID_DCNT0	call bcopy_3
3649928Sgibbs	jmp	data_phase_loop
3654568Sgibbs
3669928Sgibbsp_datain:
36713177Sgibbs	mvi	DMAPARAMS,0x79		/*
36813177Sgibbs					 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
36913177Sgibbs					 * !DIRECTION|FIFORESET
37013177Sgibbs					 */
3719928Sgibbsdata_phase_init:
37219164Sgibbs	call	assert			/*
37319164Sgibbs					 * Ensure entering a data
37419164Sgibbs					 * phase is okay - seen identify, etc.
37519164Sgibbs					 */
3765775Sgibbs
3779928Sgibbs	test	FLAGS, DPHASE	jnz data_phase_reinit
3784568Sgibbs
37919164Sgibbs	/*
38019164Sgibbs	 * Initialize the DMA address and counter from the SCB.
38119164Sgibbs	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
38219164Sgibbs	 * modify the values in the SCB itself until we see a
38319164Sgibbs	 * save data pointers message.
38419164Sgibbs	 */
38519164Sgibbs	mvi	DINDEX, HADDR0
38619164Sgibbs	mvi	SCB_DATAPTR	call bcopy_7
38719164Sgibbs
38819164Sgibbs	call	set_stcnt_from_hcnt
38919164Sgibbs
39019164Sgibbs	mov	SG_COUNT,SCB_SGCOUNT
39119164Sgibbs
39219164Sgibbs	mvi	DINDEX, SG_NEXT
39319164Sgibbs	mvi	SCB_SGPTR	call bcopy_4
39419164Sgibbs
39519164Sgibbs	/* We have seen a data phase */
39619164Sgibbs	or	FLAGS, DPHASE
39719164Sgibbs
3989928Sgibbsdata_phase_loop:
39916260Sgibbs/* Guard against overruns */
40016260Sgibbs	test	SG_COUNT, 0xff jnz data_phase_inbounds
40116260Sgibbs/*
40216260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to
40316260Sgibbs * 16meg and let the target run until it changes phase.
40416260Sgibbs * When the transfer completes, notify the host that we
40516260Sgibbs * had an overrun.
40616260Sgibbs */
40716260Sgibbs	or	SXFRCTL1,BITBUCKET
40819921Sgibbs	and	DMAPARAMS, 0xf7		/* Turn off HDMAEN */
40916260Sgibbs	mvi	STCNT0,0xff
41016260Sgibbs	mvi	STCNT1,0xff
41116260Sgibbs	mvi	STCNT2,0xff
41216260Sgibbs
41316260Sgibbsdata_phase_inbounds:
41419164Sgibbs/* If we are the last SG block, ensure wideodd is off. */
4159928Sgibbs	cmp	SG_COUNT,0x01 jne data_phase_wideodd
41613177Sgibbs	and	DMAPARAMS, 0xbf		/* Turn off WIDEODD */
4179928Sgibbsdata_phase_wideodd:
4189928Sgibbs	mov	DMAPARAMS  call dma
4194568Sgibbs
42016260Sgibbs/* Go tell the host about any overruns */
42116260Sgibbs	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun
42216260Sgibbs
42313177Sgibbs/* Exit if we had an underrun */
42413177Sgibbs	test	SSTAT0,SDONE	jz data_phase_finish /* underrun STCNT != 0 */
4257532Sgibbs
42613177Sgibbs/*
42713177Sgibbs * Advance the scatter-gather pointers if needed 
42813177Sgibbs */
4299928Sgibbssg_advance:
43013177Sgibbs	dec	SG_COUNT	/* one less segment to go */
4314568Sgibbs
43213177Sgibbs	test	SG_COUNT, 0xff	jz data_phase_finish /* Are we done? */
4334568Sgibbs
43413177Sgibbs	clr	A			/* add sizeof(struct scatter) */
43513177Sgibbs	add	SG_NEXT0,SG_SIZEOF,SG_NEXT0
43613177Sgibbs	adc	SG_NEXT1,A,SG_NEXT1
4374568Sgibbs
43813177Sgibbs/*
43913177Sgibbs * Load a struct scatter and set up the data address and length.
44013177Sgibbs * If the working value of the SG count is nonzero, then
44113177Sgibbs * we need to load a new set of values.
44213177Sgibbs *
44315328Sgibbs * This, like all DMA's, assumes little-endian host data storage.
44413177Sgibbs */
4459928Sgibbssg_load:
44613177Sgibbs	clr	HCNT2
44713177Sgibbs	clr	HCNT1
44813177Sgibbs	mvi	HCNT0,SG_SIZEOF
4494568Sgibbs
45019164Sgibbs	mvi	DINDEX, HADDR0
45119164Sgibbs	mvi	SG_NEXT0	call bcopy_4
4524568Sgibbs
45313690Sgibbs	or	DFCNTRL,0xd			/* HDMAEN|DIRECTION|FIFORESET */
4549928Sgibbs
45519164Sgibbs	call	dma_finish
4569928Sgibbs
45713177Sgibbs/*
45813177Sgibbs * Copy data from FIFO into SCB data pointer and data count.  This assumes
45919164Sgibbs * that the SG segments are of the form:
46013177Sgibbs *
46113177Sgibbs * struct ahc_dma_seg {
46219164Sgibbs *	u_int32_t	addr;		four bytes, little-endian order
46319164Sgibbs *	u_int32_t	len;		four bytes, little endian order
46413177Sgibbs * };
46513177Sgibbs */
46619164Sgibbs	mvi	HADDR0	call dfdat_in_7
4679928Sgibbs
46813177Sgibbs/* Load STCNT as well.  It is a mirror of HCNT */
46919164Sgibbs	call	set_stcnt_from_hcnt
47019164Sgibbs	test	SSTAT1,PHASEMIS  jz data_phase_loop
4714568Sgibbs
4729928Sgibbsdata_phase_finish:
47313177Sgibbs/*
47413177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB
47513177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
47613177Sgibbs * were transferred on the SCSI (as opposed to the host) bus.
47713177Sgibbs */
47813690Sgibbs	mov	SCB_RESID_DCNT0,STCNT0
47913690Sgibbs	mov	SCB_RESID_DCNT1,STCNT1
48013690Sgibbs	mov	SCB_RESID_DCNT2,STCNT2
48113177Sgibbs	mov	SCB_RESID_SGCNT, SG_COUNT
4824568Sgibbs	jmp	ITloop
4834568Sgibbs
48416260Sgibbsdata_phase_overrun:
48513177Sgibbs/*
48616260Sgibbs * Turn off BITBUCKET mode and notify the host
48716260Sgibbs */
48816260Sgibbs	and	SXFRCTL1,0x7f		/* ~BITBUCKET */
48916260Sgibbs	mvi	INTSTAT,DATA_OVERRUN
49016260Sgibbs	jmp	ITloop
49116260Sgibbs
49216260Sgibbs/*
49315328Sgibbs * Command phase.  Set up the DMA registers and let 'er rip.
49413177Sgibbs */
4954568Sgibbsp_command:
4964568Sgibbs	call	assert
4974568Sgibbs
49813177Sgibbs/*
49915328Sgibbs * Load HADDR and HCNT.
50013177Sgibbs */
50119164Sgibbs	mvi	DINDEX, HADDR0
50219164Sgibbs	mvi	SCB_CMDPTR	call bcopy_5
50313690Sgibbs	clr	HCNT1
50413690Sgibbs	clr	HCNT2
5054568Sgibbs
50619164Sgibbs	call	set_stcnt_from_hcnt
5074568Sgibbs
50821982Sgibbs	mvi	DFCNTRL, 0x3d			/*  SCSIEN|SDMAEN|HDMAEN
50921982Sgibbs						 * |DIRECTION|FIFORESET
51021982Sgibbs						 */
51121982Sgibbsp_command_dma:
51221982Sgibbs	test	SSTAT0, SDONE		jnz p_command_dma_done
51321982Sgibbs	test	SSTAT1, PHASEMIS	jz  p_command_dma
51421982Sgibbs	test	SSTAT0, SDONE		jnz p_command_dma_done
51521982Sgibbs	clr	DFCNTRL
5164568Sgibbs	jmp	ITloop
51721982Sgibbsp_command_dma_done:
51821982Sgibbs	and	DFCNTRL, 0xc7		/* ~(SCSIEN|SDMAEN|HDMAEN) */
51921982Sgibbsp_command_dma_clear:
52021982Sgibbs	test	DFCNTRL, 0x38		jnz p_command_dma_clear
52121982Sgibbs	jmp	ITloop
5224568Sgibbs
52313177Sgibbs/*
52413177Sgibbs * Status phase.  Wait for the data byte to appear, then read it
52513177Sgibbs * and store it into the SCB.
52613177Sgibbs */
5274568Sgibbsp_status:
52819803Sgibbs	call	assert
52919803Sgibbs
53021947Sgibbs	mov	SCB_TARGET_STATUS, SCSIDATL
53121947Sgibbs	jmp	ITloop
5324568Sgibbs
53313177Sgibbs/*
53415328Sgibbs * Message out phase.  If there is not an active message, but the target
53513177Sgibbs * took us into this phase anyway, build a no-op message and send it.
53613177Sgibbs */
5374568Sgibbsp_mesgout:
53813177Sgibbs	test	MSG_LEN, 0xff	jnz  p_mesgout_start
53918762Sgibbs	mvi	MSG_NOOP	call mk_mesg	/* build NOP message */
54013177Sgibbsp_mesgout_start:
54113177Sgibbs/*
54213177Sgibbs * Set up automatic PIO transfer from MSG0.  Bit 3 in
54313177Sgibbs * SXFRCTL0 (SPIOEN) is already on.
54413177Sgibbs */
54513177Sgibbs	mvi	SINDEX,MSG0
5464568Sgibbs	mov	DINDEX,MSG_LEN
5474568Sgibbs
54813177Sgibbs/*
54913177Sgibbs * When target asks for a byte, drop ATN if it's the last one in
55013177Sgibbs * the message.  Otherwise, keep going until the message is exhausted.
55113177Sgibbs *
55213177Sgibbs * Keep an eye out for a phase change, in case the target issues
55313177Sgibbs * a MESSAGE REJECT.
55413177Sgibbs */
55513177Sgibbsp_mesgout_loop:
55621947Sgibbs	/*
55721947Sgibbs	 * If there is a parity error, wait for the kernel to
55821947Sgibbs	 * see the interrupt and "update" our message response
55921947Sgibbs	 * before continuing.
56021947Sgibbs	 */
56121947Sgibbs	test	SSTAT1, REQINIT	jz p_mesgout_loop
56221947Sgibbs	test	SSTAT1, SCSIPERR jnz p_mesgout_loop
56321947Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
56421947Sgibbs	cmp	LASTPHASE, P_MESGOUT jne p_mesgout_done
56513177Sgibbs/*
56613177Sgibbs * If the next bus phase after ATN drops is a message out, it means
56713177Sgibbs * that the target is requesting that the last message(s) be resent.
56813177Sgibbs */
56919921Sgibbsp_mesgout_testretry:
57020117Sgibbs	test	DINDEX,0xff	jnz p_mesgout_dropatn
57121947Sgibbs	or	SCSISIGO,ATNO,LASTPHASE	/* turn on ATN for the retry */
57219906Sgibbs	jmp	p_mesgout_start
57320117Sgibbsp_mesgout_dropatn:
57420117Sgibbs	cmp	DINDEX,1	jne p_mesgout_outb	/* last byte? */
57520117Sgibbs	mvi	CLRSINT1,CLRATNO			/* drop ATN */
57619906Sgibbsp_mesgout_outb:
57719906Sgibbs	dec	DINDEX
57819906Sgibbs	mvi	CLRSINT0, CLRSPIORDY
57919906Sgibbs	mov	SCSIDATL,SINDIR
58019906Sgibbs	jmp	p_mesgout_loop
5814568Sgibbs
58219906Sgibbsp_mesgout_done:
58315328Sgibbs	mvi	CLRSINT1,CLRATNO	/* Be sure to turn ATNO off */
58413177Sgibbs	clr	MSG_LEN			/* no active msg */
5854568Sgibbs	jmp	ITloop
5864568Sgibbs
58713177Sgibbs/*
58813177Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
58913177Sgibbs */
5904568Sgibbsp_mesgin:
59113177Sgibbs	mvi	A		call inb_first	/* read the 1st message byte */
59213177Sgibbs	mov	REJBYTE,A			/* save it for the driver */
5934568Sgibbs
59418762Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify
59513177Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect
59618762Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs
59713177Sgibbs	cmp	ALLZEROS,A		je mesgin_complete
59818762Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs
59913177Sgibbs	cmp	A,MSG_EXTENDED		je mesgin_extended
60018762Sgibbs	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject
6014568Sgibbs
6029954Sgibbsrej_mesgin:
60313177Sgibbs/*
60419164Sgibbs * We have no idea what this message in is, so we issue a message reject
60519164Sgibbs * and hope for the best.  In any case, rejection should be a rare
60619164Sgibbs * occurrence - signal the driver when it happens.
60713177Sgibbs */
60813177Sgibbs	mvi	INTSTAT,SEND_REJECT		/* let driver know */
6099954Sgibbs
61018762Sgibbs	mvi	MSG_MESSAGE_REJECT	call mk_mesg
6119954Sgibbs
6129954Sgibbsmesgin_done:
61313177Sgibbs	call	inb_last			/*ack & turn auto PIO back on*/
6149954Sgibbs	jmp	ITloop
6159954Sgibbs
6169954Sgibbs
6179954Sgibbsmesgin_complete:
61813177Sgibbs/*
61919164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
62019164Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
62119164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0).  In
62219164Sgibbs * either of these conditions, we upload the SCB back to the host so it can
62319164Sgibbs * process this information.  In the case of a non zero status byte, we 
62419164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
62519164Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
62619164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set
62719164Sgibbs * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
62819164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list.
62919164Sgibbs * If the kernel driver does not wish to request sense, it need only clear
63019164Sgibbs * RETURN_1, and the command is allowed to complete normally.  We don't bother
63119164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra
63219164Sgibbs * work in the kernel driver to ensure that the entry was removed before the
63319164Sgibbs * command complete code tried processing it.
63413177Sgibbs */
63519164Sgibbs
63613177Sgibbs/*
63719921Sgibbs * We expect to go to bus free after this message.
63819921Sgibbs */
63919921Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
64019921Sgibbs/*
64119164Sgibbs * First check for residuals
64213177Sgibbs */
64319164Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz upload_scb
64419164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Good Status? */
64519164Sgibbsupload_scb:
64619164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
64719164Sgibbs	mov	SCB_TAG		call dma_scb
6487532Sgibbscheck_status:
64919164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Just a residual? */
65013177Sgibbs	mvi	INTSTAT,BAD_STATUS			/* let driver know */
65113177Sgibbs	cmp	RETURN_1, SEND_SENSE	jne status_ok
65219164Sgibbs	/* This SCB becomes the next to execute as it will retrieve sense */
65319164Sgibbs	mov	SCB_LINKED_NEXT, SCB_TAG
65419164Sgibbs	jmp	dma_next_scb
6555326Sgibbs
6564568Sgibbsstatus_ok:
65713177Sgibbs/* First, mark this target as free. */
65819921Sgibbs	test	SCB_CONTROL,TAG_ENB jnz complete	/*
65913177Sgibbs							 * Tagged commands
66013177Sgibbs							 * don't busy the
66113177Sgibbs							 * target.
66213177Sgibbs							 */
66319164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
66419164Sgibbs	mov	SAVED_LINKPTR, SCB_LINKED_NEXT
66519218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
66619164Sgibbs	mov	DINDIR, SAVED_LINKPTR
66719164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
6685326Sgibbs
6695326Sgibbscomplete:
67019164Sgibbs	/* Post the SCB and issue an interrupt */
67115328Sgibbs	mov	QOUTFIFO,SCB_TAG
6727532Sgibbs	mvi	INTSTAT,CMDCMPLT
67319164Sgibbs
67419164Sgibbsdma_next_scb:
67519921Sgibbs	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je add_to_free_list
67619164Sgibbs	test	FLAGS, PAGESCBS jnz dma_next_scb2
67719164Sgibbs	/* Only DMA on top of ourselves if we are the SCB to download */
67819164Sgibbs	mov	A, SCB_LINKED_NEXT
67919164Sgibbs	cmp	SCB_TAG, A	je dma_next_scb2
68019164Sgibbs	mov	SCBPTR, A
68119164Sgibbs	jmp	add_to_waiting_list
68219164Sgibbsdma_next_scb2:
68319164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
68419218Sgibbs	mov	SCB_LINKED_NEXT		call dma_scb
68519164Sgibbsadd_to_waiting_list:
68619164Sgibbs	mov	SCB_NEXT,WAITING_SCBH
68719164Sgibbs	mov	WAITING_SCBH, SCBPTR
6889954Sgibbs	jmp	mesgin_done
68919921Sgibbsadd_to_free_list:
69019921Sgibbs	call	add_scb_to_free_list
69119921Sgibbs	jmp	mesgin_done
6924568Sgibbs
69313177Sgibbs/*
69418762Sgibbs * Is it an extended message?  Copy the message to our message buffer and
69518762Sgibbs * notify the host.  The host will tell us whether to reject this message,
69618762Sgibbs * respond to it with the message that the host placed in our message buffer,
69718762Sgibbs * or simply to do nothing.
69813177Sgibbs */
6999954Sgibbsmesgin_extended:
70018762Sgibbs	mvi	MSGIN_EXT_LEN	 call inb_next
70118762Sgibbs	mov	A, MSGIN_EXT_LEN
70218762Sgibbsmesgin_extended_loop:
70319164Sgibbs	mov	DINDEX	call	inb_next
70418762Sgibbs	dec	A
70519164Sgibbs	cmp	DINDEX, MSGIN_EXT_LASTBYTE jne mesgin_extended_loop_test
70619164Sgibbs	dec	DINDEX		/* dump by repeatedly filling the last byte */
70719164Sgibbsmesgin_extended_loop_test:
70819164Sgibbs	test	A, 0xFF		jnz mesgin_extended_loop
70918762Sgibbsmesgin_extended_intr:
71018762Sgibbs	mvi	INTSTAT,EXTENDED_MSG		/* let driver know */
71118762Sgibbs	cmp	RETURN_1,SEND_REJ je rej_mesgin
71218762Sgibbs	cmp	RETURN_1,SEND_MSG jne mesgin_done
71318762Sgibbs/* The kernel has setup a message to be sent */
71421947Sgibbs	or	SCSISIGO,ATNO,LASTPHASE		/* turn on ATNO */
7159954Sgibbs	jmp	mesgin_done
7165562Sgibbs
71713177Sgibbs/*
71813177Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
71913177Sgibbs * and await the bus going free.
72013177Sgibbs */
7219954Sgibbsmesgin_disconnect:
72219921Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
72313177Sgibbs	or	SCB_CONTROL,DISCONNECTED
72415328Sgibbs	test	FLAGS, PAGESCBS jz mesgin_done
72519164Sgibbs	call	add_scb_to_disc_list
72619164Sgibbs	jmp	mesgin_done
72719164Sgibbs
72815328Sgibbs/*
72919164Sgibbs * Save data pointers message:
73019164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
73119164Sgibbs * only if we've actually been into a data phase to change them.  This
73219164Sgibbs * protects against bogus data in scratch ram and the residual counts
73319164Sgibbs * since they are only initialized when we go into data_in or data_out.
73415328Sgibbs */
73519164Sgibbsmesgin_sdptrs:
73619164Sgibbs	test	FLAGS, DPHASE	jz mesgin_done
73719164Sgibbs	mov	SCB_SGCOUNT,SG_COUNT
7384568Sgibbs
73919164Sgibbs	/* The SCB SGPTR becomes the next one we'll download */
74019164Sgibbs	mvi	DINDEX, SCB_SGPTR
74119164Sgibbs	mvi	SG_NEXT0	call bcopy_4
74219164Sgibbs	
74319164Sgibbs	/* The SCB DATAPTR0 becomes the current SHADDR */
74419164Sgibbs	mvi	DINDEX, SCB_DATAPTR0
74519164Sgibbs	mvi	SHADDR0		call bcopy_4
74619164Sgibbs
74713177Sgibbs/*
74819164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer.
74913177Sgibbs */
75019164Sgibbs	mvi	SCB_RESID_DCNT0	call	bcopy_3
75119164Sgibbs
7529954Sgibbs	jmp	mesgin_done
7534568Sgibbs
75413177Sgibbs/*
75513177Sgibbs * Restore pointers message?  Data pointers are recopied from the
75613177Sgibbs * SCB anytime we enter a data phase for the first time, so all
75713177Sgibbs * we need to do is clear the DPHASE flag and let the data phase
75813177Sgibbs * code do the rest.
75913177Sgibbs */
7609954Sgibbsmesgin_rdptrs:
76115328Sgibbs	and	FLAGS,0xef			/*
76213177Sgibbs						 * !DPHASE we'll reload them
76313177Sgibbs						 * the next time through
76413177Sgibbs						 */
7659954Sgibbs	jmp	mesgin_done
7664568Sgibbs
76713177Sgibbs/*
76813177Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
76913177Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
77013177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
77113177Sgibbs */
7729954Sgibbsmesgin_identify:
77313177Sgibbs	test	A,0x78	jnz rej_mesgin	/*!DiscPriv|!LUNTAR|!Reserved*/
77413177Sgibbs	and	A,0x07			/* lun in lower three bits */
77519164Sgibbs	or      SAVED_TCL,A		/* SAVED_TCL should be complete now */
77613177Sgibbs	call	inb_last		/* ACK */
77713177Sgibbs
77813177Sgibbs/*
77913177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
78015328Sgibbs * If we get one, we use the tag returned to switch to find the proper
78115328Sgibbs * SCB.  With SCB paging, this requires using findSCB for both tagged
78215328Sgibbs * and non-tagged transactions since the SCB may exist in any slot.
78315328Sgibbs * If we're not using SCB paging, we can use the tag as the direct
78415328Sgibbs * index to the SCB.
78513177Sgibbs */
78615328Sgibbs	mvi	ARG_1,SCB_LIST_NULL	/* Default to no-tag */
78713177Sgibbssnoop_tag_loop:
78820117Sgibbs	test	SSTAT1,REQINIT		jz snoop_tag_loop
78921947Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
79021947Sgibbs	cmp	LASTPHASE, P_MESGIN, jne use_findSCB
79118762Sgibbs	mvi	A			call inb_first
79218762Sgibbs	cmp	A,MSG_SIMPLE_Q_TAG	jne use_findSCB
7936608Sgibbsget_tag:
79419218Sgibbs	or	FLAGS, TAGGED_SCB
79513177Sgibbs	mvi	ARG_1	call inb_next	/* tag value */
79613177Sgibbs/*
79713177Sgibbs * See if the tag is in range.  The tag is < SCBCOUNT if we add
79813177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is
79913177Sgibbs * no carry.
80013177Sgibbs */
80113177Sgibbs	mov	A,COMP_SCBCOUNT	
80213177Sgibbs	add	SINDEX,A,ARG_1
80319218Sgibbs	jc	send_abort_msg
80413177Sgibbs
80513177Sgibbs/*
80615328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction
80713177Sgibbs * to the reconnecting target.
80813177Sgibbs */
80915328Sgibbs	test	FLAGS, PAGESCBS	jz index_by_tag
81015328Sgibbsuse_findSCB:
81115328Sgibbs	mov	ALLZEROS	call findSCB	  /* Have to search */
81219218Sgibbs	cmp	SINDEX, SCB_LIST_NULL, je not_found
81315328Sgibbssetup_SCB:
81415328Sgibbs	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
81515328Sgibbs	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
81619164Sgibbs	test	SCB_CONTROL,TAG_ENB	jnz  mesgin_done /* Ack Tag */
81715328Sgibbs	jmp	ITloop
81815328Sgibbsindex_by_tag:
81913177Sgibbs	mov	SCBPTR,ARG_1
82019218Sgibbs	mov	A, SAVED_TCL
82119218Sgibbs	cmp	SCB_TCL,A		jne send_abort_msg
82219218Sgibbs	test	SCB_CONTROL,TAG_ENB	jz  send_abort_msg
82313177Sgibbs	jmp	setup_SCB
82415328Sgibbs
82519218Sgibbsnot_found:
82619218Sgibbs	mvi	INTSTAT, NO_MATCH
82719218Sgibbssend_abort_msg:
82819218Sgibbs	test	FLAGS, TAGGED_SCB jnz abort_tag_msg
82919218Sgibbs	mvi	MSG_ABORT	call mk_mesg
83019218Sgibbs	jmp	mesgin_done
83119164Sgibbsabort_tag_msg:
83215328Sgibbs	mvi	MSG_ABORT_TAG	call mk_mesg	/* ABORT TAG message */
83313177Sgibbs	jmp	mesgin_done
8346608Sgibbs
83513177Sgibbs/*
83613177Sgibbs * Message reject?  Let the kernel driver handle this.  If we have an 
83713177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 
83813177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
83913177Sgibbs * it since we have no clue what it pertains to.
84013177Sgibbs */
8419954Sgibbsmesgin_reject:
84213177Sgibbs	mvi	INTSTAT, REJECT_MSG
8439954Sgibbs	jmp	mesgin_done
8445562Sgibbs
84513177Sgibbs/*
84613177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ]
84713177Sgibbs */
8484568Sgibbs
84913177Sgibbs/*
85013177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX
85113177Sgibbs * if there is no active message already.  SINDEX is returned intact.
85213177Sgibbs */
8534568Sgibbsmk_mesg:
85413177Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
85513177Sgibbs	test	MSG_LEN,0xff	jz mk_mesg1	/* Should always succeed */
85613177Sgibbs	
85713177Sgibbs	/*
85813177Sgibbs	 * Hmmm.  For some reason the mesg buffer is in use.
85913177Sgibbs	 * Tell the driver.  It should look at SINDEX to find
86013177Sgibbs	 * out what we wanted to use the buffer for and resolve
86113177Sgibbs	 * the conflict.
86213177Sgibbs	 */
86313177Sgibbs	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
86413690Sgibbs	mvi	INTSTAT,MSG_BUFFER_BUSY
8654568Sgibbs
8664568Sgibbsmk_mesg1:
86721947Sgibbs	or	SCSISIGO,ATNO,LASTPHASE	/* turn on ATNO */
86813177Sgibbs	mvi	MSG_LEN,1		/* length = 1 */
86913177Sgibbs	mov	MSG0,SINDEX		/* 1-byte message */
87013177Sgibbs	mvi	SEQCTL,0x10	ret	/* !PAUSEDIS|FASTMODE */
8714568Sgibbs
87213177Sgibbs/*
87313177Sgibbs * Functions to read data in Automatic PIO mode.
87413177Sgibbs *
87513177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from
87613177Sgibbs * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
87713177Sgibbs * latched (the usual way), then read the data byte directly off the bus
87813177Sgibbs * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
87913177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
88013177Sgibbs * spec guarantees that the target will hold the data byte on the bus until
88113177Sgibbs * we send our ACK.
88213177Sgibbs *
88313177Sgibbs * The assumption here is that these are called in a particular sequence,
88413177Sgibbs * and that REQ is already set when inb_first is called.  inb_{first,next}
88513177Sgibbs * use the same calling convention as inb.
88613177Sgibbs */
88713177Sgibbs
88813177Sgibbsinb_next:
88921947Sgibbs	mov	NONE,SCSIDATL			/*dummy read from latch to ACK*/
89013360Sgibbsinb_next_wait:
89121947Sgibbs	/*
89221947Sgibbs	 * If there is a parity error, wait for the kernel to
89321947Sgibbs	 * see the interrupt and prepare our message response
89421947Sgibbs	 * before continuing.
89521947Sgibbs	 */
89621947Sgibbs	test	SSTAT1, REQINIT	jz inb_next_wait
89721947Sgibbs	test	SSTAT1, SCSIPERR jnz inb_next_wait
89821947Sgibbs	and	LASTPHASE, PHASE_MASK, SCSISIGI
89921947Sgibbs	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis
90019623Sgibbsinb_first:
9014568Sgibbs	mov	DINDEX,SINDEX
90213177Sgibbs	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
90313177Sgibbsinb_last:
90413360Sgibbs	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
9054568Sgibbs
90613177Sgibbsmesgin_phasemis:
90713177Sgibbs/*
90813177Sgibbs * We expected to receive another byte, but the target changed phase
90913177Sgibbs */
91013177Sgibbs	mvi	INTSTAT, MSGIN_PHASEMIS
91113177Sgibbs	jmp	ITloop
9124568Sgibbs
91313177Sgibbs/*
91413177Sgibbs * DMA data transfer.  HADDR and HCNT must be loaded first, and
91513177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for
91613177Sgibbs * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
91713177Sgibbs * during initialization.
91813177Sgibbs */
9194568Sgibbsdma:
9204568Sgibbs	mov	DFCNTRL,SINDEX
9214568Sgibbsdma1:
92213177Sgibbs	test	SSTAT0,DMADONE	jnz dma3
92313177Sgibbs	test	SSTAT1,PHASEMIS	jz dma1		/* ie. underrun */
9244568Sgibbs
92513177Sgibbs/*
92613177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or
92713177Sgibbs * the target changes the phase (in light of this, it makes sense that
92813177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
92913177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
93013177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty
93113177Sgibbs * status.
93213177Sgibbs */
9334568Sgibbsdma3:
93413177Sgibbs	test	SINDEX,DIRECTION	jnz dma5
9354568Sgibbsdma4:
93613177Sgibbs	test	DFSTATUS,FIFOEMP	jz dma4
9374568Sgibbs
93813177Sgibbs/*
93913177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 
94013177Sgibbs * actually off first lest we get an ILLSADDR.
94113177Sgibbs */
9424568Sgibbsdma5:
94321982Sgibbs	/* Don't clobber an inprogress host data transfer */
94421982Sgibbs	test	DFSTATUS, MREQPEND	jnz dma5
94521982Sgibbs	/* disable DMA */
94621982Sgibbs	and	DFCNTRL, 0xc7		/* ~(SCSIEN|SDMAEN|HDMAEN|DIRECTION) */
9474568Sgibbsdma6:
94821982Sgibbs	test	DFCNTRL, HDMAENACK	jnz dma6 
94918762Sgibbsreturn:
9504568Sgibbs	ret
9514568Sgibbs
95213177Sgibbs/*
95313177Sgibbs * Common SCSI initialization for selection and reselection.  Expects
95413177Sgibbs * the target SCSI ID to be in the upper four bits of SINDEX, and A's
95513177Sgibbs * contents are stomped on return.
95613177Sgibbs */
9578104Sgibbsinitialize_scsiid:
95813177Sgibbs	and	SINDEX,0xf0		/* Get target ID */
95919164Sgibbs	mov	SAVED_TCL, SINDEX	/* Update the target portion of this */
9605775Sgibbs	and	A,0x0f,SCSIID
9615775Sgibbs	or	SINDEX,A
9628104Sgibbs	mov	SCSIID,SINDEX ret
9635326Sgibbs
96413177Sgibbs/*
96513177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
96613177Sgibbs * message.
96713177Sgibbs */
9684568Sgibbsassert:
96913177Sgibbs	test	FLAGS,RESELECTED	jz return	/* reselected? */
97013177Sgibbs	test	FLAGS,IDENTIFY_SEEN	jnz return	/* seen IDENTIFY? */
9714568Sgibbs
97219164Sgibbs	mvi	INTSTAT,NO_IDENT 	ret	/* no - tell the kernel */
9734568Sgibbs
97413177Sgibbs/*
97519218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
97619218Sgibbs * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
97719218Sgibbs * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
97819218Sgibbs * otherwise, SCBPTR is set to the proper SCB.
97913177Sgibbs */
9804568SgibbsfindSCB:
98115328Sgibbs	mov	SCBPTR,SINDEX			/* switch to next SCB */
98213177Sgibbs	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
98319218Sgibbs	cmp	ARG_1, SCB_LIST_NULL	jne findBySCBID
98419218Sgibbs	mov	A, SAVED_TCL
98519218Sgibbs	cmp	SCB_TCL,A	je foundSCB /* target ID/channel/lun match? */
98619164SgibbsfindSCB1:
98719164Sgibbs	inc	SINDEX
98819164Sgibbs	mov	A,SCBCOUNT
98919164Sgibbs	cmp	SINDEX,A	jne findSCB
99019164Sgibbs/*
99119164Sgibbs * We didn't find it.  If we're paging, pull an SCB and DMA down the
99219164Sgibbs * one we want.  If we aren't paging or the SCB we dma down has the
99319218Sgibbs * abort flag set, return not found.
99419164Sgibbs */
99519218Sgibbs	test	FLAGS, PAGESCBS	jz find_error
99619623Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb
99719218Sgibbs	cmp	ARG_1, SCB_LIST_NULL jne find_dma_scb
99819218Sgibbs	mov	SAVED_TCL	call	index_untagged_scb
99919218Sgibbs	mov	ARG_1, SINDIR	/* SCBID of SCB to fetch */
100019164Sgibbsfind_dma_scb:
100119164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
100219218Sgibbs	mov	ARG_1	call dma_scb
100319164Sgibbs	test	SCB_CONTROL, ABORT_SCB jz return
100419218Sgibbsfind_error:
100519218Sgibbs	mvi	SINDEX, SCB_LIST_NULL ret
100619218SgibbsfindBySCBID:
100715328Sgibbs	mov	A, ARG_1			/* Tag passed in ARG_1 */
100815328Sgibbs	cmp	SCB_TAG,A	jne findSCB1	/* Found it? */
100915328SgibbsfoundSCB:
101019218Sgibbs	test	SCB_CONTROL, ABORT_SCB jnz find_error
101119164Sgibbs	test	FLAGS,PAGESCBS	jz return
101219164Sgibbsrem_scb_from_disc_list:
101315328Sgibbs/* Remove this SCB from the disconnection list */
101415328Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev
101515328Sgibbs	mov	SAVED_LINKPTR, SCB_PREV
101615328Sgibbs	mov	SCBPTR, SCB_NEXT
101715328Sgibbs	mov	SCB_PREV, SAVED_LINKPTR
101815328Sgibbs	mov	SCBPTR, SINDEX
101915328Sgibbsunlink_prev:
102015328Sgibbs	cmp	SCB_PREV,SCB_LIST_NULL	je rHead/* At the head of the list */
102115328Sgibbs	mov	SAVED_LINKPTR, SCB_NEXT
102215328Sgibbs	mov	SCBPTR, SCB_PREV
102315328Sgibbs	mov	SCB_NEXT, SAVED_LINKPTR
102419164Sgibbs	mov	SCBPTR, SINDEX ret
102515328SgibbsrHead:
102619164Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret
10274568Sgibbs
102819164Sgibbsset_stcnt_from_hcnt:
102919164Sgibbs	mov	STCNT0, HCNT0
103019164Sgibbs	mov	STCNT1, HCNT1
103119164Sgibbs	mov	STCNT2, HCNT2 ret
10324568Sgibbs
103319164Sgibbsbcopy_7:
103419164Sgibbs	mov	DINDIR, SINDIR
103519164Sgibbs	mov	DINDIR, SINDIR
103619164Sgibbsbcopy_5:
103719164Sgibbs	mov	DINDIR, SINDIR
103819164Sgibbsbcopy_4:
103919164Sgibbs	mov	DINDIR, SINDIR
104019164Sgibbsbcopy_3:
104119164Sgibbs	mov	DINDIR, SINDIR
104219164Sgibbs	mov	DINDIR, SINDIR
104319164Sgibbs	mov	DINDIR, SINDIR ret
10444568Sgibbs
104519164Sgibbsdma_scb:
104619164Sgibbs	/*
104719164Sgibbs	 * SCB index is in SINDEX.  Determine the physical address in
104819164Sgibbs	 * the host where this SCB is located and load HADDR with it.
104919164Sgibbs	 */
105019164Sgibbs	shr	DINDEX, SINDEX, 3
105119164Sgibbs	shl	A, SINDEX, 5
105219164Sgibbs	add	HADDR0, A, HSCB_ADDR0
105319164Sgibbs	mov	A, DINDEX
105419164Sgibbs	adc	HADDR1, A, HSCB_ADDR1
105519164Sgibbs	clr	A
105619164Sgibbs	adc	HADDR2, A, HSCB_ADDR2
105719164Sgibbs	adc	HADDR3, A, HSCB_ADDR3
105819164Sgibbs	/* Setup Count */
105919164Sgibbs	mvi	HCNT0, 28
106019164Sgibbs	clr	HCNT1
106119164Sgibbs	clr	HCNT2
106219164Sgibbs	mov	DFCNTRL, DMAPARAMS
106319164Sgibbs	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost
106419164Sgibbs	/* Fill it with the SCB data */
106519164Sgibbs	call	copy_scb_tofifo
106619164Sgibbs	mvi	DFCNTRL, 0xa		/* HDMAEN | FIFOFLUSH */
106719164Sgibbsdma_scb_fromhost:
106819164Sgibbs	call	dma_finish
106919164Sgibbs	/* If we were putting the SCB, we are done */
107019164Sgibbs	test	DMAPARAMS, DIRECTION	jz	return
107119164Sgibbs	mvi	SCBARRAY  call dfdat_in_7
107219164Sgibbs	call	dfdat_in_7_continued
107319164Sgibbs	call	dfdat_in_7_continued
107419164Sgibbs	jmp	dfdat_in_7_continued
107519164Sgibbsdfdat_in_7:
107619164Sgibbs	mov     DINDEX,SINDEX
107719164Sgibbsdfdat_in_7_continued:
107819164Sgibbs	mov	DINDIR,DFDAT
107919164Sgibbs	mov	DINDIR,DFDAT
108019164Sgibbs	mov	DINDIR,DFDAT
108119164Sgibbs	mov	DINDIR,DFDAT
108219164Sgibbs	mov	DINDIR,DFDAT
108319164Sgibbs	mov	DINDIR,DFDAT
108419164Sgibbs	mov	DINDIR,DFDAT ret
108519164Sgibbs
108619164Sgibbscopy_scb_tofifo:
108719164Sgibbs	mvi	SCBARRAY  call dfdat_out_7
108819164Sgibbs	call	dfdat_out_7
108919164Sgibbs	call	dfdat_out_7
109019164Sgibbsdfdat_out_7:
109119164Sgibbs	mov	DFDAT,SINDIR
109219164Sgibbs	mov	DFDAT,SINDIR
109319164Sgibbs	mov	DFDAT,SINDIR
109419164Sgibbs	mov	DFDAT,SINDIR
109519164Sgibbs	mov	DFDAT,SINDIR
109619164Sgibbs	mov	DFDAT,SINDIR
109719164Sgibbs	mov	DFDAT,SINDIR ret
109819164Sgibbs
109913177Sgibbs/*
110019164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
110119164Sgibbs * DMA and wait for it to acknowledge that it's off.
110213177Sgibbs */
110319164Sgibbsdma_finish:
110419164Sgibbs	test	DFSTATUS,HDONE	jz dma_finish
110519164Sgibbs	/* Turn off DMA preserving WIDEODD */
110619164Sgibbs	and	DFCNTRL,WIDEODD
110719164Sgibbsdma_finish2:
110819164Sgibbs	test	DFCNTRL,HDMAENACK jnz dma_finish2
110919164Sgibbs	ret
11109928Sgibbs
111119164Sgibbsindex_untagged_scb:
111219218Sgibbs	mov	DINDEX, SINDEX
111319218Sgibbs	shr	DINDEX, 4
111419218Sgibbs	and	DINDEX, 0x03			/* Bottom two bits of tid */
111519218Sgibbs	add	DINDEX, SCB_ACTIVE0
111619218Sgibbs	shr	A, SINDEX, 6			/* Target ID divided by 4 */
111719421Sgibbs	test	SINDEX, SELBUSB jz index_untagged_scb2
111819421Sgibbs	add	A, 2				/* Add 2 positions */
111919164Sgibbsindex_untagged_scb2:
112019164Sgibbs	mov	SCBPTR, A			/*
112119164Sgibbs						 * Select the SCB with this 
112219164Sgibbs						 * target's information.
112319164Sgibbs						 */
112419218Sgibbs	mov	SINDEX, DINDEX	ret
11259928Sgibbs
11264568Sgibbs
112719164Sgibbsget_free_or_disc_scb:
112819623Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb
112919623Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb
113019623Sgibbsreturn_error:
113119623Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret
113219623Sgibbsdequeue_disc_scb:
113319164Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH
113413177Sgibbs/*
113519164Sgibbs * If we have a residual, then we are in the middle of some I/O
113619164Sgibbs * and we have to send this SCB back up to the kernel so that the
113719164Sgibbs * saved data pointers and residual information isn't lost.
113819164Sgibbs */
113919164Sgibbs	test	SCB_RESID_SGCNT,0xff	jz unlink_disc_scb
114019164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
114119164Sgibbs	mov	SCB_TAG		call dma_scb
114219164Sgibbsunlink_disc_scb:
114319623Sgibbs	/* jmp instead of call since we want to return anyway */
114419623Sgibbs	mov	SCBPTR	jmp rem_scb_from_disc_list
114519164Sgibbsdequeue_free_scb:
114619164Sgibbs	mov	SCBPTR, FREE_SCBH
114719164Sgibbs	mov	FREE_SCBH, SCB_NEXT ret
11484568Sgibbs
114919164Sgibbsadd_scb_to_free_list:
115019164Sgibbs	mov	SCB_NEXT, FREE_SCBH
115119164Sgibbs	mov	FREE_SCBH, SCBPTR ret
11524568Sgibbs
115319164Sgibbsadd_scb_to_disc_list:
115413177Sgibbs/*
115519164Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
115619164Sgibbs * candidates for paging out an SCB if one is needed for a new command.
115719164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
115813177Sgibbs */
115919164Sgibbs	mvi	SCB_PREV, SCB_LIST_NULL
116019164Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH
116119164Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR
116219164Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je return
116319164Sgibbs	mov	SCBPTR,SCB_NEXT
116419164Sgibbs	mov	SCB_PREV,DISCONNECTED_SCBH
116519164Sgibbs	mov	SCBPTR,DISCONNECTED_SCBH ret
11664568Sgibbs
1167