aic7xxx.seq revision 20117
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
4220117SgibbsVERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.51 1996/11/22 08:25:20 gibbs Exp $"
435647Sgibbs
4415998Sgibbs#if defined(__NetBSD__)
4515998Sgibbs#include "../../../../dev/ic/aic7xxxreg.h"
4618762Sgibbs#include "../../../../scsi/scsi_message.h"
4715998Sgibbs#elif defined(__FreeBSD__)
4813177Sgibbs#include "../../dev/aic7xxx/aic7xxx_reg.h"
4918762Sgibbs#include "../../scsi/scsi_message.h"
5015998Sgibbs#endif
514568Sgibbs
5213177Sgibbs/*
5313177Sgibbs * We can't just use ACCUM in the sequencer code because it
5413177Sgibbs * must be treated specially by the assembler, and it currently
5513690Sgibbs * looks for the symbol 'A'.  This is the only register defined in
5613177Sgibbs * the assembler's symbol space.
5713177Sgibbs */
5813177SgibbsA = ACCUM
594568Sgibbs
6019164Sgibbs/*
6119164Sgibbs * A few words on the waiting SCB list:
6219164Sgibbs * After starting the selection hardware, we check for reconnecting targets
6313690Sgibbs * as well as for our selection to complete just in case the reselection wins
6413690Sgibbs * bus arbitration.  The problem with this is that we must keep track of the
6513690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection
6613690Sgibbs * on just in case the reselection wins so that we can retry the selection at
6713690Sgibbs * a later time.  This problem cannot be resolved by holding a single entry
6813690Sgibbs * in scratch ram since a reconnecting target can request sense and this will
6913690Sgibbs * create yet another SCB waiting for selection.  The solution used here is to 
7013690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
7119164Sgibbs * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
7219164Sgibbs * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
7319164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged
7419164Sgibbs * command for which a second SCB has been queued.  The sequencer will
7519164Sgibbs * automatically consume the entries.
7613177Sgibbs */
774568Sgibbs
7813177Sgibbs/*
7914449Sgibbs * We assume that the kernel driver may reset us at any time, even in the
8014449Sgibbs * middle of a DMA, so clear DFCNTRL too.
8113177Sgibbs */
8214449Sgibbsreset:
8314449Sgibbs	clr	DFCNTRL
8414449Sgibbs	clr	SCSISIGO		/* De-assert BSY */
8519921Sgibbs
8619921Sgibbsp_busfree:
8713177Sgibbs	mvi	SCSISEQ,ENRSELI		/* Always allow reselection */
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					 */
9320117Sgibbs	mvi	LASTPHASE, P_BUSFREE
9420117Sgibbs	and	FLAGS,0x07		/* clear target specific flags */
958104Sgibbspoll_for_work:
9613177Sgibbs	/*
9713177Sgibbs	 * Are we a twin channel device?
9813177Sgibbs	 * For fairness, we check the other bus first,
9913177Sgibbs	 * since we just finished a transaction on the
10013177Sgibbs	 * current channel.
10113177Sgibbs	 */
10213177Sgibbs	test	FLAGS,TWIN_BUS	jz start2
10313177Sgibbs	xor	SBLKCTL,SELBUSB			/* Toggle to the other bus */
1048104Sgibbs	test	SSTAT0,SELDI	jnz reselect
10513177Sgibbs	xor	SBLKCTL,SELBUSB			/* Toggle to the original bus */
1065326Sgibbsstart2:
1078104Sgibbs	test	SSTAT0,SELDI	jnz reselect
10819164Sgibbs	cmp	WAITING_SCBH,SCB_LIST_NULL je test_queue
10919164Sgibbsstart_waiting:
11019164Sgibbs	/*
11119164Sgibbs	 * Pull the first entry off of the waiting SCB list
11219164Sgibbs	 * We don't have to "test_busy" because only transactions that
11319164Sgibbs	 * have passed that test can be in the WAITING_SCB list.
11419164Sgibbs	 */
11519164Sgibbs	mov	SCBPTR,WAITING_SCBH
11619164Sgibbs	jmp	start_scb2
11719164Sgibbstest_queue:
11819164Sgibbs	/* Has the driver posted any work for us? */
11914934Sgibbs	mov	A, QCNTMASK
12014934Sgibbs	test	QINCNT,A	jz poll_for_work
1214568Sgibbs
12213690Sgibbs/*
12313690Sgibbs * We have at least one queued SCB now and we don't have any 
12419164Sgibbs * SCBs in the list of SCBs awaiting selection.  If we have
12519164Sgibbs * any SCBs availible for use, pull the tag from the QINFIFO
12619164Sgibbs * and get to work on it.
12713177Sgibbs */
12819164Sgibbs	test	FLAGS, PAGESCBS	jz	dequeue_scb
12919623Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb
13019164Sgibbs	cmp	SINDEX, SCB_LIST_NULL	je poll_for_work
13119164Sgibbsdequeue_scb:
13219164Sgibbs	mov	CUR_SCBID,QINFIFO
13319164Sgibbs	test	FLAGS, PAGESCBS jnz dma_queued_scb
13419164Sgibbs	/* In the non-paging case, the SCBID == hardware SCB index */
13519164Sgibbs	mov	SCBPTR, CUR_SCBID
13619164Sgibbsdma_queued_scb:
13719164Sgibbs/*
13819164Sgibbs * DMA the SCB from host ram into the current SCB location.
13919164Sgibbs */
14019164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
14119164Sgibbs	mov	CUR_SCBID	call dma_scb
1424568Sgibbs
14313177Sgibbs/*
14413177Sgibbs * See if there is not already an active SCB for this target.  This code
14513177Sgibbs * locks out on a per target basis instead of target/lun.  Although this
14613177Sgibbs * is not ideal for devices that have multiple luns active at the same
14713177Sgibbs * time, it is faster than looping through all SCB's looking for active
14819921Sgibbs * commands.  We also don't have enough spare SCB space for us to store the
14919164Sgibbs * SCBID of the currently busy transaction for each target/lun making it
15019164Sgibbs * impossible to link up the SCBs.
15113177Sgibbs */
1525647Sgibbstest_busy:
15319164Sgibbs	test	SCB_CONTROL, TAG_ENB	jnz start_scb
15419164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
15519218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
15619164Sgibbs	mov	ARG_1, SINDIR			/*
15719164Sgibbs						 * ARG_1 should
15819164Sgibbs						 * now have the SCB ID of
15919164Sgibbs						 * any active, non-tagged,
16019164Sgibbs						 * command for this target.
16119164Sgibbs						 */
16219164Sgibbs	cmp	ARG_1, SCB_LIST_NULL je make_busy
16319164Sgibbs	test	FLAGS, PAGESCBS jz simple_busy_link
16419164Sgibbs	/*
16519164Sgibbs	 * Put this SCB back onto the free list.  It
16619164Sgibbs	 * may be necessary to satisfy the search for
16719164Sgibbs	 * the active SCB.
16819164Sgibbs	 */
16919218Sgibbs	mov	SCBPTR, SAVED_SCBPTR
17019164Sgibbs	call	add_scb_to_free_list
17119164Sgibbs	/* Find the active SCB */
17219164Sgibbs	mov	ALLZEROS	call findSCB
17319218Sgibbs	/*
17419218Sgibbs	 * If we couldn't find it, tell the kernel.  This should
17519218Sgibbs	 * only happen if the parent SCB was aborted and this
17619218Sgibbs	 * one was already here at the time of the abort.
17719218Sgibbs	 */
17819218Sgibbs	cmp	SINDEX, SCB_LIST_NULL	jne paged_busy_link
17919218Sgibbs	mvi	INTSTAT, NO_MATCH_BUSY
18019218Sgibbspaged_busy_link:
18119164Sgibbs	/* Link us in */
18219164Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
18319164Sgibbs	/* Put it back on the disconnected list */
18419164Sgibbs	call	add_scb_to_disc_list
1858104Sgibbs	jmp	poll_for_work
18619164Sgibbssimple_busy_link:
18719164Sgibbs	mov	SCBPTR, ARG_1
18819164Sgibbs	mov	SCB_LINKED_NEXT, CUR_SCBID 
18919164Sgibbs	jmp	poll_for_work
19019164Sgibbsmake_busy:
19119164Sgibbs	mov	DINDIR, CUR_SCBID
19219164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
1934568Sgibbs
1945326Sgibbsstart_scb:
19519164Sgibbs	/*
19619164Sgibbs	 * Place us on the waiting list in case our selection
19719164Sgibbs	 * doesn't win during bus arbitration.
19819164Sgibbs	 */
19915328Sgibbs	mov	SCB_NEXT,WAITING_SCBH
20013177Sgibbs	mov	WAITING_SCBH, SCBPTR
20113177Sgibbsstart_scb2:
20213177Sgibbs	and	SINDEX,0xf7,SBLKCTL	/* Clear the channel select bit */
20313177Sgibbs	and	A,0x08,SCB_TCL		/* Get new channel bit */
20413177Sgibbs	or	SINDEX,A
20513177Sgibbs	mov	SBLKCTL,SINDEX		/* select channel */
20613177Sgibbs	mov	SCB_TCL	call initialize_scsiid
2078104Sgibbs
20813177Sgibbs/*
20913177Sgibbs * Enable selection phase as an initiator, and do automatic ATN
21013177Sgibbs * after the selection.  We do this now so that we can overlap the
21113177Sgibbs * rest of our work to set up this target with the arbitration and
21213177Sgibbs * selection bus phases.
21313177Sgibbs */
2148104Sgibbsstart_selection:
21513177Sgibbs	mvi	SCSISEQ,0x58		/* ENSELO|ENAUTOATNO|ENRSELI */
2164568Sgibbs
21713177Sgibbs/*
21813177Sgibbs * As soon as we get a successful selection, the target should go
21913177Sgibbs * into the message out phase since we have ATN asserted.  Prepare
22013177Sgibbs * the message to send.
22113177Sgibbs *
22213177Sgibbs * Messages are stored in scratch RAM starting with a length byte
22313177Sgibbs * followed by the message itself.
22413177Sgibbs */
2258567Sdg
22613177Sgibbsmk_identify:
22719164Sgibbs	and	MSG0,0x7,SCB_TCL	/* lun */
22813177Sgibbs	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privledge */
22913690Sgibbs	or	MSG0,A			/* or in disconnect privledge */
23018762Sgibbs	or	MSG0,MSG_IDENTIFYFLAG
23113690Sgibbs	mvi	MSG_LEN, 1
2324568Sgibbs
23313177Sgibbs/*
23415328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block.
23515328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
23613177Sgibbs */
2376608Sgibbsmk_tag:
23818762Sgibbs	test	SCB_CONTROL,TAG_ENB jz  mk_message
23919164Sgibbs	and	MSG1,0x23,SCB_CONTROL
24019164Sgibbs	mov	MSG2,SCB_TAG
24119164Sgibbs	add	MSG_LEN,2	/* update message length */
2426608Sgibbs
24318762Sgibbs/*
24418762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer
24518762Sgibbs * if it asks.
24618762Sgibbs */
24718762Sgibbsmk_message:
24818762Sgibbs	test	SCB_CONTROL,MK_MESSAGE  jz wait_for_selection
2496608Sgibbs
25018762Sgibbs	mvi     INTSTAT,AWAITING_MSG
2516608Sgibbs
2529917Sgibbswait_for_selection:
25313177Sgibbs	test	SSTAT0,SELDO	jnz select 
25413177Sgibbs	test	SSTAT0,SELDI	jz wait_for_selection
2554568Sgibbs
25613177Sgibbs/*
25713177Sgibbs * Reselection has been initiated by a target. Make a note that we've been
25819164Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet.
25913177Sgibbs */
2604568Sgibbsreselect:
26113177Sgibbs	clr	MSG_LEN		/* Don't have anything in the mesg buffer */
2628104Sgibbs	mov	SELID		call initialize_scsiid
26313177Sgibbs	or	FLAGS,RESELECTED
26413177Sgibbs	jmp	select2
2654568Sgibbs
26613177Sgibbs/*
26719164Sgibbs * After the selection, remove this SCB from the "waiting SCB"
26813177Sgibbs * list.  This is achieved by simply moving our "next" pointer into
26913177Sgibbs * WAITING_SCBH.  Our next pointer will be set to null the next time this
27013177Sgibbs * SCB is used, so don't bother with it now.
27113177Sgibbs */
2728104Sgibbsselect:
27315328Sgibbs	mov	WAITING_SCBH,SCB_NEXT
2748104Sgibbsselect2:
27513177Sgibbs/*
27613177Sgibbs * Initialize SCSIRATE with the appropriate value for this target.
27719164Sgibbs * The SCSIRATE settings for each target are stored in an array
27819164Sgibbs * based at TARG_SCRATCH.
27913177Sgibbs */
28019164Sgibbsndx_dtr:
28119164Sgibbs	shr	A,SCSIID,4
28219164Sgibbs	test	SBLKCTL,SELBUSB	jz ndx_dtr_2
28319164Sgibbs	or	SAVED_TCL, SELBUSB /* Add the channel bit while we're here */
28419164Sgibbs	or	A,0x08		/* Channel B entries add 8 */
28519164Sgibbsndx_dtr_2:
28619164Sgibbs	add	SINDEX,TARG_SCRATCH,A
28713177Sgibbs	mov	SCSIRATE,SINDIR
28813177Sgibbs
28915843Sgibbs/*
29019164Sgibbs * Initialize Ultra mode setting and clear the SCSI channel.
29115843Sgibbs */
29219164Sgibbsultra:
29319164Sgibbs	and	DINDEX,0xdf,SXFRCTL0            /* default to Ultra disabled */
29419164Sgibbs	/*
29519164Sgibbs	 * Set CLRCHN here before the target has entered a data transfer mode -
29619164Sgibbs	 * with synchronous SCSI, if you do it later, you blow away some
29719164Sgibbs	 * data in the SCSI FIFO that the target has already sent to you.
29819164Sgibbs	 */
29919164Sgibbs	or	DINDEX, CLRCHN
30019164Sgibbs	mvi	SINDEX, ULTRA_ENB_B
30119164Sgibbs	test	SCSIID, 0x80     jnz ultra_2     /* Target ID > 7 */
30219164Sgibbs	test	SBLKCTL, SELBUSB jnz ultra_2     /* Second channel device */
30319164Sgibbs	dec	SINDEX
30419164Sgibbsultra_2:
30519164Sgibbs	mov     FUNCTION1,SCSIID 
30619164Sgibbs	mov     A,FUNCTION1
30719164Sgibbs	test	SINDIR, A	jz set_sxfrctl0
30819164Sgibbs	or	DINDEX, ULTRAEN
30919164Sgibbs 
31015843Sgibbsset_sxfrctl0:
31119164Sgibbs	mov	SXFRCTL0,DINDEX
31215843Sgibbs
31316198Sgibbs	mvi	SCSISEQ,ENAUTOATNP		/*
31416198Sgibbs						 * ATN on parity errors
31516198Sgibbs						 * for "in" phases
31613177Sgibbs						 */
31713177Sgibbs	mvi	CLRSINT1,CLRBUSFREE
31813177Sgibbs	mvi	CLRSINT0,0x60			/* CLRSELDI|CLRSELDO */
31919921Sgibbs	or	SIMODE1, ENBUSFREE		/*
32019921Sgibbs						 * We aren't expecting a
32119921Sgibbs						 * bus free, so interrupt
32219921Sgibbs						 * the kernel driver if it
32319921Sgibbs						 * happens.
32419921Sgibbs						 */
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
5084568Sgibbs	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
5094568Sgibbs						#   DIRECTION|FIFORESET
5104568Sgibbs	jmp	ITloop
5114568Sgibbs
51213177Sgibbs/*
51313177Sgibbs * Status phase.  Wait for the data byte to appear, then read it
51413177Sgibbs * and store it into the SCB.
51513177Sgibbs */
5164568Sgibbsp_status:
51719803Sgibbs	call	assert
51819803Sgibbs
51913177Sgibbs	mvi	SCB_TARGET_STATUS	call inb_first
5209954Sgibbs	jmp	mesgin_done
5214568Sgibbs
52213177Sgibbs/*
52315328Sgibbs * Message out phase.  If there is not an active message, but the target
52413177Sgibbs * took us into this phase anyway, build a no-op message and send it.
52513177Sgibbs */
5264568Sgibbsp_mesgout:
52713177Sgibbs	test	MSG_LEN, 0xff	jnz  p_mesgout_start
52818762Sgibbs	mvi	MSG_NOOP	call mk_mesg	/* build NOP message */
52913177Sgibbsp_mesgout_start:
53013177Sgibbs/*
53113177Sgibbs * Set up automatic PIO transfer from MSG0.  Bit 3 in
53213177Sgibbs * SXFRCTL0 (SPIOEN) is already on.
53313177Sgibbs */
53413177Sgibbs	mvi	SINDEX,MSG0
5354568Sgibbs	mov	DINDEX,MSG_LEN
5364568Sgibbs
53713177Sgibbs/*
53813177Sgibbs * When target asks for a byte, drop ATN if it's the last one in
53913177Sgibbs * the message.  Otherwise, keep going until the message is exhausted.
54013177Sgibbs *
54113177Sgibbs * Keep an eye out for a phase change, in case the target issues
54213177Sgibbs * a MESSAGE REJECT.
54313177Sgibbs */
54413177Sgibbsp_mesgout_loop:
54519906Sgibbs	test	SSTAT0,SPIORDY jz p_mesgout_loop
54619906Sgibbs	test	SSTAT1,PHASEMIS	jnz p_mesgout_done
54713177Sgibbs/*
54813177Sgibbs * If the next bus phase after ATN drops is a message out, it means
54913177Sgibbs * that the target is requesting that the last message(s) be resent.
55013177Sgibbs */
55119921Sgibbsp_mesgout_testretry:
55220117Sgibbs	test	DINDEX,0xff	jnz p_mesgout_dropatn
55319906Sgibbs	or	SCSISIGO,ATNO		/* turn on ATN for the retry */
55419906Sgibbs	jmp	p_mesgout_start
55520117Sgibbsp_mesgout_dropatn:
55620117Sgibbs	cmp	DINDEX,1	jne p_mesgout_outb	/* last byte? */
55720117Sgibbs	mvi	CLRSINT1,CLRATNO			/* drop ATN */
55819906Sgibbsp_mesgout_outb:
55919906Sgibbs	dec	DINDEX
56019906Sgibbs	mvi	CLRSINT0, CLRSPIORDY
56119906Sgibbs	mov	SCSIDATL,SINDIR
56219906Sgibbs	jmp	p_mesgout_loop
5634568Sgibbs
56419906Sgibbsp_mesgout_done:
56515328Sgibbs	mvi	CLRSINT1,CLRATNO	/* Be sure to turn ATNO off */
56613177Sgibbs	clr	MSG_LEN			/* no active msg */
5674568Sgibbs	jmp	ITloop
5684568Sgibbs
56913177Sgibbs/*
57013177Sgibbs * Message in phase.  Bytes are read using Automatic PIO mode.
57113177Sgibbs */
5724568Sgibbsp_mesgin:
57313177Sgibbs	mvi	A		call inb_first	/* read the 1st message byte */
57413177Sgibbs	mov	REJBYTE,A			/* save it for the driver */
5754568Sgibbs
57618762Sgibbs	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify
57713177Sgibbs	cmp	A,MSG_DISCONNECT	je mesgin_disconnect
57818762Sgibbs	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs
57913177Sgibbs	cmp	ALLZEROS,A		je mesgin_complete
58018762Sgibbs	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs
58113177Sgibbs	cmp	A,MSG_EXTENDED		je mesgin_extended
58218762Sgibbs	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject
5834568Sgibbs
5849954Sgibbsrej_mesgin:
58513177Sgibbs/*
58619164Sgibbs * We have no idea what this message in is, so we issue a message reject
58719164Sgibbs * and hope for the best.  In any case, rejection should be a rare
58819164Sgibbs * occurrence - signal the driver when it happens.
58913177Sgibbs */
59013177Sgibbs	mvi	INTSTAT,SEND_REJECT		/* let driver know */
5919954Sgibbs
59218762Sgibbs	mvi	MSG_MESSAGE_REJECT	call mk_mesg
5939954Sgibbs
5949954Sgibbsmesgin_done:
59513177Sgibbs	call	inb_last			/*ack & turn auto PIO back on*/
5969954Sgibbs	jmp	ITloop
5979954Sgibbs
5989954Sgibbs
5999954Sgibbsmesgin_complete:
60013177Sgibbs/*
60119164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
60219164Sgibbs * and trigger a completion interrupt.  Before doing so, check to see if there
60319164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0).  In
60419164Sgibbs * either of these conditions, we upload the SCB back to the host so it can
60519164Sgibbs * process this information.  In the case of a non zero status byte, we 
60619164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to
60719164Sgibbs * decide if sense should be retrieved.  If the kernel driver wishes to request
60819164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set
60919164Sgibbs * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
61019164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list.
61119164Sgibbs * If the kernel driver does not wish to request sense, it need only clear
61219164Sgibbs * RETURN_1, and the command is allowed to complete normally.  We don't bother
61319164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra
61419164Sgibbs * work in the kernel driver to ensure that the entry was removed before the
61519164Sgibbs * command complete code tried processing it.
61613177Sgibbs */
61719164Sgibbs
61813177Sgibbs/*
61919921Sgibbs * We expect to go to bus free after this message.
62019921Sgibbs */
62119921Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
62219921Sgibbs/*
62319164Sgibbs * First check for residuals
62413177Sgibbs */
62519164Sgibbs	test	SCB_RESID_SGCNT,0xff	jnz upload_scb
62619164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Good Status? */
62719164Sgibbsupload_scb:
62819164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
62919164Sgibbs	mov	SCB_TAG		call dma_scb
6307532Sgibbscheck_status:
63119164Sgibbs	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Just a residual? */
63213177Sgibbs	mvi	INTSTAT,BAD_STATUS			/* let driver know */
63313177Sgibbs	cmp	RETURN_1, SEND_SENSE	jne status_ok
63419164Sgibbs	/* This SCB becomes the next to execute as it will retrieve sense */
63519164Sgibbs	mov	SCB_LINKED_NEXT, SCB_TAG
63619164Sgibbs	jmp	dma_next_scb
6375326Sgibbs
6384568Sgibbsstatus_ok:
63913177Sgibbs/* First, mark this target as free. */
64019921Sgibbs	test	SCB_CONTROL,TAG_ENB jnz complete	/*
64113177Sgibbs							 * Tagged commands
64213177Sgibbs							 * don't busy the
64313177Sgibbs							 * target.
64413177Sgibbs							 */
64519164Sgibbs	mov	SAVED_SCBPTR, SCBPTR
64619164Sgibbs	mov	SAVED_LINKPTR, SCB_LINKED_NEXT
64719218Sgibbs	mov	SCB_TCL		call	index_untagged_scb
64819164Sgibbs	mov	DINDIR, SAVED_LINKPTR
64919164Sgibbs	mov	SCBPTR, SAVED_SCBPTR
6505326Sgibbs
6515326Sgibbscomplete:
65219623Sgibbs	test	FLAGS, PAGESCBS jz complete_post
65319623Sgibbs	mov	A, QFULLCNT
65419623Sgibbscomplete_poll:
65519623Sgibbs	cmp	QOUTQCNT, A	je complete_poll
65619803Sgibbs	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
65719623Sgibbs	inc	QOUTQCNT
65819623Sgibbscomplete_post:
65919164Sgibbs	/* Post the SCB and issue an interrupt */
66015328Sgibbs	mov	QOUTFIFO,SCB_TAG
66119803Sgibbs	mvi	SEQCTL,0x10			/* FASTMODE */
6627532Sgibbs	mvi	INTSTAT,CMDCMPLT
66319164Sgibbs
66419164Sgibbsdma_next_scb:
66519921Sgibbs	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je add_to_free_list
66619164Sgibbs	test	FLAGS, PAGESCBS jnz dma_next_scb2
66719164Sgibbs	/* Only DMA on top of ourselves if we are the SCB to download */
66819164Sgibbs	mov	A, SCB_LINKED_NEXT
66919164Sgibbs	cmp	SCB_TAG, A	je dma_next_scb2
67019164Sgibbs	mov	SCBPTR, A
67119164Sgibbs	jmp	add_to_waiting_list
67219164Sgibbsdma_next_scb2:
67319164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
67419218Sgibbs	mov	SCB_LINKED_NEXT		call dma_scb
67519164Sgibbsadd_to_waiting_list:
67619164Sgibbs	mov	SCB_NEXT,WAITING_SCBH
67719164Sgibbs	mov	WAITING_SCBH, SCBPTR
6789954Sgibbs	jmp	mesgin_done
67919921Sgibbsadd_to_free_list:
68019921Sgibbs	call	add_scb_to_free_list
68119921Sgibbs	jmp	mesgin_done
6824568Sgibbs
68313177Sgibbs/*
68418762Sgibbs * Is it an extended message?  Copy the message to our message buffer and
68518762Sgibbs * notify the host.  The host will tell us whether to reject this message,
68618762Sgibbs * respond to it with the message that the host placed in our message buffer,
68718762Sgibbs * or simply to do nothing.
68813177Sgibbs */
6899954Sgibbsmesgin_extended:
69018762Sgibbs	mvi	MSGIN_EXT_LEN	 call inb_next
69118762Sgibbs	mov	A, MSGIN_EXT_LEN
69218762Sgibbsmesgin_extended_loop:
69319164Sgibbs	mov	DINDEX	call	inb_next
69418762Sgibbs	dec	A
69519164Sgibbs	cmp	DINDEX, MSGIN_EXT_LASTBYTE jne mesgin_extended_loop_test
69619164Sgibbs	dec	DINDEX		/* dump by repeatedly filling the last byte */
69719164Sgibbsmesgin_extended_loop_test:
69819164Sgibbs	test	A, 0xFF		jnz mesgin_extended_loop
69918762Sgibbsmesgin_extended_intr:
70018762Sgibbs	mvi	INTSTAT,EXTENDED_MSG		/* let driver know */
70118762Sgibbs	cmp	RETURN_1,SEND_REJ je rej_mesgin
70218762Sgibbs	cmp	RETURN_1,SEND_MSG jne mesgin_done
70318762Sgibbs/* The kernel has setup a message to be sent */
70413690Sgibbs	or	SCSISIGO,ATNO			/* turn on ATNO */
7059954Sgibbs	jmp	mesgin_done
7065562Sgibbs
70713177Sgibbs/*
70813177Sgibbs * Is it a disconnect message?  Set a flag in the SCB to remind us
70913177Sgibbs * and await the bus going free.
71013177Sgibbs */
7119954Sgibbsmesgin_disconnect:
71219921Sgibbs	and	SIMODE1, 0xf7		/* ~ENBUSFREE */
71313177Sgibbs	or	SCB_CONTROL,DISCONNECTED
71415328Sgibbs	test	FLAGS, PAGESCBS jz mesgin_done
71519164Sgibbs	call	add_scb_to_disc_list
71619164Sgibbs	jmp	mesgin_done
71719164Sgibbs
71815328Sgibbs/*
71919164Sgibbs * Save data pointers message:
72019164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but
72119164Sgibbs * only if we've actually been into a data phase to change them.  This
72219164Sgibbs * protects against bogus data in scratch ram and the residual counts
72319164Sgibbs * since they are only initialized when we go into data_in or data_out.
72415328Sgibbs */
72519164Sgibbsmesgin_sdptrs:
72619164Sgibbs	test	FLAGS, DPHASE	jz mesgin_done
72719164Sgibbs	mov	SCB_SGCOUNT,SG_COUNT
7284568Sgibbs
72919164Sgibbs	/* The SCB SGPTR becomes the next one we'll download */
73019164Sgibbs	mvi	DINDEX, SCB_SGPTR
73119164Sgibbs	mvi	SG_NEXT0	call bcopy_4
73219164Sgibbs	
73319164Sgibbs	/* The SCB DATAPTR0 becomes the current SHADDR */
73419164Sgibbs	mvi	DINDEX, SCB_DATAPTR0
73519164Sgibbs	mvi	SHADDR0		call bcopy_4
73619164Sgibbs
73713177Sgibbs/*
73819164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer.
73913177Sgibbs */
74019164Sgibbs	mvi	SCB_RESID_DCNT0	call	bcopy_3
74119164Sgibbs
7429954Sgibbs	jmp	mesgin_done
7434568Sgibbs
74413177Sgibbs/*
74513177Sgibbs * Restore pointers message?  Data pointers are recopied from the
74613177Sgibbs * SCB anytime we enter a data phase for the first time, so all
74713177Sgibbs * we need to do is clear the DPHASE flag and let the data phase
74813177Sgibbs * code do the rest.
74913177Sgibbs */
7509954Sgibbsmesgin_rdptrs:
75115328Sgibbs	and	FLAGS,0xef			/*
75213177Sgibbs						 * !DPHASE we'll reload them
75313177Sgibbs						 * the next time through
75413177Sgibbs						 */
7559954Sgibbs	jmp	mesgin_done
7564568Sgibbs
75713177Sgibbs/*
75813177Sgibbs * Identify message?  For a reconnecting target, this tells us the lun
75913177Sgibbs * that the reconnection is for - find the correct SCB and switch to it,
76013177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later.
76113177Sgibbs */
7629954Sgibbsmesgin_identify:
76313177Sgibbs	test	A,0x78	jnz rej_mesgin	/*!DiscPriv|!LUNTAR|!Reserved*/
76413177Sgibbs	and	A,0x07			/* lun in lower three bits */
76519164Sgibbs	or      SAVED_TCL,A		/* SAVED_TCL should be complete now */
76613177Sgibbs	call	inb_last		/* ACK */
76713177Sgibbs
76813177Sgibbs/*
76913177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
77015328Sgibbs * If we get one, we use the tag returned to switch to find the proper
77115328Sgibbs * SCB.  With SCB paging, this requires using findSCB for both tagged
77215328Sgibbs * and non-tagged transactions since the SCB may exist in any slot.
77315328Sgibbs * If we're not using SCB paging, we can use the tag as the direct
77415328Sgibbs * index to the SCB.
77513177Sgibbs */
77615328Sgibbs	mvi	ARG_1,SCB_LIST_NULL	/* Default to no-tag */
77713177Sgibbssnoop_tag_loop:
77820117Sgibbs	test	SSTAT1,REQINIT		jz snoop_tag_loop
77918762Sgibbs	test	SSTAT1,PHASEMIS		jnz 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:
85619623Sgibbs	or	SCSISIGO,ATNO		/* 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:
87819803Sgibbs	call	inb_last	/* ACK */
87913360Sgibbsinb_next_wait:
88019906Sgibbs	test	SSTAT0, SPIORDY	jz inb_next_wait
88119803Sgibbs	test	SSTAT1,PHASEMIS	jnz mesgin_phasemis
88219623Sgibbsinb_first:
8834568Sgibbs	mov	DINDEX,SINDEX
88413177Sgibbs	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
88513177Sgibbsinb_last:
88619906Sgibbs	mvi	CLRSINT0, CLRSPIORDY
88713360Sgibbs	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
8884568Sgibbs
88913177Sgibbsmesgin_phasemis:
89013177Sgibbs/*
89113177Sgibbs * We expected to receive another byte, but the target changed phase
89213177Sgibbs */
89313177Sgibbs	mvi	INTSTAT, MSGIN_PHASEMIS
89413177Sgibbs	jmp	ITloop
8954568Sgibbs
89613177Sgibbs/*
89713177Sgibbs * DMA data transfer.  HADDR and HCNT must be loaded first, and
89813177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for
89913177Sgibbs * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
90013177Sgibbs * during initialization.
90113177Sgibbs */
9024568Sgibbsdma:
9034568Sgibbs	mov	DFCNTRL,SINDEX
9044568Sgibbsdma1:
90513177Sgibbs	test	SSTAT0,DMADONE	jnz dma3
90613177Sgibbs	test	SSTAT1,PHASEMIS	jz dma1		/* ie. underrun */
9074568Sgibbs
90813177Sgibbs/*
90913177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or
91013177Sgibbs * the target changes the phase (in light of this, it makes sense that
91113177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
91213177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
91313177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty
91413177Sgibbs * status.
91513177Sgibbs */
9164568Sgibbsdma3:
91713177Sgibbs	test	SINDEX,DIRECTION	jnz dma5
9184568Sgibbsdma4:
91913177Sgibbs	test	DFSTATUS,FIFOEMP	jz dma4
9204568Sgibbs
92113177Sgibbs/*
92213177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 
92313177Sgibbs * actually off first lest we get an ILLSADDR.
92413177Sgibbs */
9254568Sgibbsdma5:
92613177Sgibbs	/* disable DMA, but maintain WIDEODD */
92713690Sgibbs	and	DFCNTRL,WIDEODD
9284568Sgibbsdma6:
92913177Sgibbs	test	DFCNTRL,0x38	jnz dma6  /* SCSIENACK|SDMAENACK|HDMAENACK */
93018762Sgibbsreturn:
9314568Sgibbs	ret
9324568Sgibbs
93313177Sgibbs/*
93413177Sgibbs * Common SCSI initialization for selection and reselection.  Expects
93513177Sgibbs * the target SCSI ID to be in the upper four bits of SINDEX, and A's
93613177Sgibbs * contents are stomped on return.
93713177Sgibbs */
9388104Sgibbsinitialize_scsiid:
93913177Sgibbs	and	SINDEX,0xf0		/* Get target ID */
94019164Sgibbs	mov	SAVED_TCL, SINDEX	/* Update the target portion of this */
9415775Sgibbs	and	A,0x0f,SCSIID
9425775Sgibbs	or	SINDEX,A
9438104Sgibbs	mov	SCSIID,SINDEX ret
9445326Sgibbs
94513177Sgibbs/*
94613177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY
94713177Sgibbs * message.
94813177Sgibbs */
9494568Sgibbsassert:
95013177Sgibbs	test	FLAGS,RESELECTED	jz return	/* reselected? */
95113177Sgibbs	test	FLAGS,IDENTIFY_SEEN	jnz return	/* seen IDENTIFY? */
9524568Sgibbs
95319164Sgibbs	mvi	INTSTAT,NO_IDENT 	ret	/* no - tell the kernel */
9544568Sgibbs
95513177Sgibbs/*
95619218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
95719218Sgibbs * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
95819218Sgibbs * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
95919218Sgibbs * otherwise, SCBPTR is set to the proper SCB.
96013177Sgibbs */
9614568SgibbsfindSCB:
96215328Sgibbs	mov	SCBPTR,SINDEX			/* switch to next SCB */
96313177Sgibbs	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
96419218Sgibbs	cmp	ARG_1, SCB_LIST_NULL	jne findBySCBID
96519218Sgibbs	mov	A, SAVED_TCL
96619218Sgibbs	cmp	SCB_TCL,A	je foundSCB /* target ID/channel/lun match? */
96719164SgibbsfindSCB1:
96819164Sgibbs	inc	SINDEX
96919164Sgibbs	mov	A,SCBCOUNT
97019164Sgibbs	cmp	SINDEX,A	jne findSCB
97119164Sgibbs/*
97219164Sgibbs * We didn't find it.  If we're paging, pull an SCB and DMA down the
97319164Sgibbs * one we want.  If we aren't paging or the SCB we dma down has the
97419218Sgibbs * abort flag set, return not found.
97519164Sgibbs */
97619218Sgibbs	test	FLAGS, PAGESCBS	jz find_error
97719623Sgibbs	mov	ALLZEROS	call	get_free_or_disc_scb
97819218Sgibbs	cmp	ARG_1, SCB_LIST_NULL jne find_dma_scb
97919218Sgibbs	mov	SAVED_TCL	call	index_untagged_scb
98019218Sgibbs	mov	ARG_1, SINDIR	/* SCBID of SCB to fetch */
98119164Sgibbsfind_dma_scb:
98219164Sgibbs	mvi	DMAPARAMS, 0xd	/* HDMAEN|DIRECTION|FIFORESET */
98319218Sgibbs	mov	ARG_1	call dma_scb
98419164Sgibbs	test	SCB_CONTROL, ABORT_SCB jz return
98519218Sgibbsfind_error:
98619218Sgibbs	mvi	SINDEX, SCB_LIST_NULL ret
98719218SgibbsfindBySCBID:
98815328Sgibbs	mov	A, ARG_1			/* Tag passed in ARG_1 */
98915328Sgibbs	cmp	SCB_TAG,A	jne findSCB1	/* Found it? */
99015328SgibbsfoundSCB:
99119218Sgibbs	test	SCB_CONTROL, ABORT_SCB jnz find_error
99219164Sgibbs	test	FLAGS,PAGESCBS	jz return
99319164Sgibbsrem_scb_from_disc_list:
99415328Sgibbs/* Remove this SCB from the disconnection list */
99515328Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev
99615328Sgibbs	mov	SAVED_LINKPTR, SCB_PREV
99715328Sgibbs	mov	SCBPTR, SCB_NEXT
99815328Sgibbs	mov	SCB_PREV, SAVED_LINKPTR
99915328Sgibbs	mov	SCBPTR, SINDEX
100015328Sgibbsunlink_prev:
100115328Sgibbs	cmp	SCB_PREV,SCB_LIST_NULL	je rHead/* At the head of the list */
100215328Sgibbs	mov	SAVED_LINKPTR, SCB_NEXT
100315328Sgibbs	mov	SCBPTR, SCB_PREV
100415328Sgibbs	mov	SCB_NEXT, SAVED_LINKPTR
100519164Sgibbs	mov	SCBPTR, SINDEX ret
100615328SgibbsrHead:
100719164Sgibbs	mov	DISCONNECTED_SCBH,SCB_NEXT ret
10084568Sgibbs
100919164Sgibbsset_stcnt_from_hcnt:
101019164Sgibbs	mov	STCNT0, HCNT0
101119164Sgibbs	mov	STCNT1, HCNT1
101219164Sgibbs	mov	STCNT2, HCNT2 ret
10134568Sgibbs
101419164Sgibbsbcopy_7:
101519164Sgibbs	mov	DINDIR, SINDIR
101619164Sgibbs	mov	DINDIR, SINDIR
101719164Sgibbsbcopy_5:
101819164Sgibbs	mov	DINDIR, SINDIR
101919164Sgibbsbcopy_4:
102019164Sgibbs	mov	DINDIR, SINDIR
102119164Sgibbsbcopy_3:
102219164Sgibbs	mov	DINDIR, SINDIR
102319164Sgibbs	mov	DINDIR, SINDIR
102419164Sgibbs	mov	DINDIR, SINDIR ret
10254568Sgibbs
102619164Sgibbsdma_scb:
102719164Sgibbs	/*
102819164Sgibbs	 * SCB index is in SINDEX.  Determine the physical address in
102919164Sgibbs	 * the host where this SCB is located and load HADDR with it.
103019164Sgibbs	 */
103119164Sgibbs	shr	DINDEX, SINDEX, 3
103219164Sgibbs	shl	A, SINDEX, 5
103319164Sgibbs	add	HADDR0, A, HSCB_ADDR0
103419164Sgibbs	mov	A, DINDEX
103519164Sgibbs	adc	HADDR1, A, HSCB_ADDR1
103619164Sgibbs	clr	A
103719164Sgibbs	adc	HADDR2, A, HSCB_ADDR2
103819164Sgibbs	adc	HADDR3, A, HSCB_ADDR3
103919164Sgibbs	/* Setup Count */
104019164Sgibbs	mvi	HCNT0, 28
104119164Sgibbs	clr	HCNT1
104219164Sgibbs	clr	HCNT2
104319164Sgibbs	mov	DFCNTRL, DMAPARAMS
104419164Sgibbs	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost
104519164Sgibbs	/* Fill it with the SCB data */
104619164Sgibbs	call	copy_scb_tofifo
104719164Sgibbs	mvi	DFCNTRL, 0xa		/* HDMAEN | FIFOFLUSH */
104819164Sgibbsdma_scb_fromhost:
104919164Sgibbs	call	dma_finish
105019164Sgibbs	/* If we were putting the SCB, we are done */
105119164Sgibbs	test	DMAPARAMS, DIRECTION	jz	return
105219164Sgibbs	mvi	SCBARRAY  call dfdat_in_7
105319164Sgibbs	call	dfdat_in_7_continued
105419164Sgibbs	call	dfdat_in_7_continued
105519164Sgibbs	jmp	dfdat_in_7_continued
105619164Sgibbsdfdat_in_7:
105719164Sgibbs	mov     DINDEX,SINDEX
105819164Sgibbsdfdat_in_7_continued:
105919164Sgibbs	mov	DINDIR,DFDAT
106019164Sgibbs	mov	DINDIR,DFDAT
106119164Sgibbs	mov	DINDIR,DFDAT
106219164Sgibbs	mov	DINDIR,DFDAT
106319164Sgibbs	mov	DINDIR,DFDAT
106419164Sgibbs	mov	DINDIR,DFDAT
106519164Sgibbs	mov	DINDIR,DFDAT ret
106619164Sgibbs
106719164Sgibbscopy_scb_tofifo:
106819164Sgibbs	mvi	SCBARRAY  call dfdat_out_7
106919164Sgibbs	call	dfdat_out_7
107019164Sgibbs	call	dfdat_out_7
107119164Sgibbsdfdat_out_7:
107219164Sgibbs	mov	DFDAT,SINDIR
107319164Sgibbs	mov	DFDAT,SINDIR
107419164Sgibbs	mov	DFDAT,SINDIR
107519164Sgibbs	mov	DFDAT,SINDIR
107619164Sgibbs	mov	DFDAT,SINDIR
107719164Sgibbs	mov	DFDAT,SINDIR
107819164Sgibbs	mov	DFDAT,SINDIR ret
107919164Sgibbs
108013177Sgibbs/*
108119164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable
108219164Sgibbs * DMA and wait for it to acknowledge that it's off.
108313177Sgibbs */
108419164Sgibbsdma_finish:
108519164Sgibbs	test	DFSTATUS,HDONE	jz dma_finish
108619164Sgibbs	/* Turn off DMA preserving WIDEODD */
108719164Sgibbs	and	DFCNTRL,WIDEODD
108819164Sgibbsdma_finish2:
108919164Sgibbs	test	DFCNTRL,HDMAENACK jnz dma_finish2
109019164Sgibbs	ret
10919928Sgibbs
109219164Sgibbsindex_untagged_scb:
109319218Sgibbs	mov	DINDEX, SINDEX
109419218Sgibbs	shr	DINDEX, 4
109519218Sgibbs	and	DINDEX, 0x03			/* Bottom two bits of tid */
109619218Sgibbs	add	DINDEX, SCB_ACTIVE0
109719218Sgibbs	shr	A, SINDEX, 6			/* Target ID divided by 4 */
109819421Sgibbs	test	SINDEX, SELBUSB jz index_untagged_scb2
109919421Sgibbs	add	A, 2				/* Add 2 positions */
110019164Sgibbsindex_untagged_scb2:
110119164Sgibbs	mov	SCBPTR, A			/*
110219164Sgibbs						 * Select the SCB with this 
110319164Sgibbs						 * target's information.
110419164Sgibbs						 */
110519218Sgibbs	mov	SINDEX, DINDEX	ret
11069928Sgibbs
11074568Sgibbs
110819164Sgibbsget_free_or_disc_scb:
110919623Sgibbs	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb
111019623Sgibbs	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb
111119623Sgibbsreturn_error:
111219623Sgibbs	mvi	SINDEX, SCB_LIST_NULL	ret
111319623Sgibbsdequeue_disc_scb:
111419164Sgibbs	mov	SCBPTR, DISCONNECTED_SCBH
111513177Sgibbs/*
111619164Sgibbs * If we have a residual, then we are in the middle of some I/O
111719164Sgibbs * and we have to send this SCB back up to the kernel so that the
111819164Sgibbs * saved data pointers and residual information isn't lost.
111919164Sgibbs */
112019164Sgibbs	test	SCB_RESID_SGCNT,0xff	jz unlink_disc_scb
112119164Sgibbs	mvi	DMAPARAMS, 0x9	/* HDMAEN | FIFORESET*/
112219164Sgibbs	mov	SCB_TAG		call dma_scb
112319164Sgibbsunlink_disc_scb:
112419623Sgibbs	/* jmp instead of call since we want to return anyway */
112519623Sgibbs	mov	SCBPTR	jmp rem_scb_from_disc_list
112619164Sgibbsdequeue_free_scb:
112719164Sgibbs	mov	SCBPTR, FREE_SCBH
112819164Sgibbs	mov	FREE_SCBH, SCB_NEXT ret
11294568Sgibbs
113019164Sgibbsadd_scb_to_free_list:
113119164Sgibbs	mov	SCB_NEXT, FREE_SCBH
113219164Sgibbs	mov	FREE_SCBH, SCBPTR ret
11334568Sgibbs
113419164Sgibbsadd_scb_to_disc_list:
113513177Sgibbs/*
113619164Sgibbs * Link this SCB into the DISCONNECTED list.  This list holds the
113719164Sgibbs * candidates for paging out an SCB if one is needed for a new command.
113819164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section.
113913177Sgibbs */
114019164Sgibbs	mvi	SCB_PREV, SCB_LIST_NULL
114119164Sgibbs	mov	SCB_NEXT, DISCONNECTED_SCBH
114219164Sgibbs	mov	DISCONNECTED_SCBH, SCBPTR
114319164Sgibbs	cmp	SCB_NEXT,SCB_LIST_NULL je return
114419164Sgibbs	mov	SCBPTR,SCB_NEXT
114519164Sgibbs	mov	SCB_PREV,DISCONNECTED_SCBH
114619164Sgibbs	mov	SCBPTR,DISCONNECTED_SCBH ret
11474568Sgibbs
1148