aic7xxx.seq revision 24662
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: 1023925Sgibbs *Copyright (c) 1994, 1995, 1996, 1997 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 * 4024662Sgibbs * $Id: aic7xxx.seq,v 1.68 1997/04/04 19:35:30 gibbs Exp $ 4124634Sgibbs * 4213177Sgibbs *-M************************************************************************/ 434568Sgibbs 4423925Sgibbs#include <dev/aic7xxx/aic7xxx.reg> 4523925Sgibbs#include <scsi/scsi_message.h> 465647Sgibbs 4713177Sgibbs/* 4819164Sgibbs * A few words on the waiting SCB list: 4919164Sgibbs * After starting the selection hardware, we check for reconnecting targets 5013690Sgibbs * as well as for our selection to complete just in case the reselection wins 5113690Sgibbs * bus arbitration. The problem with this is that we must keep track of the 5213690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection 5313690Sgibbs * on just in case the reselection wins so that we can retry the selection at 5413690Sgibbs * a later time. This problem cannot be resolved by holding a single entry 5513690Sgibbs * in scratch ram since a reconnecting target can request sense and this will 5613690Sgibbs * create yet another SCB waiting for selection. The solution used here is to 5713690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list 5819164Sgibbs * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, 5919164Sgibbs * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to 6019164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged 6119164Sgibbs * command for which a second SCB has been queued. The sequencer will 6219164Sgibbs * automatically consume the entries. 6313177Sgibbs */ 644568Sgibbs 6513177Sgibbs/* 6614449Sgibbs * We assume that the kernel driver may reset us at any time, even in the 6714449Sgibbs * middle of a DMA, so clear DFCNTRL too. 6813177Sgibbs */ 6914449Sgibbsreset: 7023925Sgibbs clr SCSISIGO; /* De-assert BSY */ 7123925Sgibbs /* Always allow reselection */ 7223925Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; 7323925Sgibbs call clear_target_state; 748104Sgibbspoll_for_work: 7524662Sgibbs test SSTAT0,SELDO jnz select; 7624662Sgibbs test SSTAT0,SELDI jnz reselect; 7723925Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 7823925Sgibbs.if ( TWIN_CHANNEL ) 7913177Sgibbs /* 8023925Sgibbs * Twin channel devices cannot handle things like SELTO 8123925Sgibbs * interrupts on the "background" channel. So, if we 8223925Sgibbs * are selecting, keep polling the current channel util 8323925Sgibbs * either a selection or reselection occurs. 8413177Sgibbs */ 8523925Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 8624662Sgibbs test SSTAT0,SELDO jnz select; 8724662Sgibbs test SSTAT0,SELDI jnz reselect; 8823925Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 8923925Sgibbs xor SBLKCTL,SELBUSB; /* Toggle back */ 9023925Sgibbs.endif 9123925Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 9219164Sgibbstest_queue: 9319164Sgibbs /* Has the driver posted any work for us? */ 9423925Sgibbs mov A, QCNTMASK; 9523925Sgibbs test QINCNT,A jz poll_for_work; 964568Sgibbs 9713690Sgibbs/* 9813690Sgibbs * We have at least one queued SCB now and we don't have any 9919164Sgibbs * SCBs in the list of SCBs awaiting selection. If we have 10023925Sgibbs * any SCBs available for use, pull the tag from the QINFIFO 10119164Sgibbs * and get to work on it. 10213177Sgibbs */ 10323925Sgibbs.if ( SCB_PAGING ) 10423925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 10523925Sgibbs cmp SINDEX, SCB_LIST_NULL je poll_for_work; 10623925Sgibbs.endif 10719164Sgibbsdequeue_scb: 10823925Sgibbs mov CUR_SCBID,QINFIFO; 10923925Sgibbs.if !( SCB_PAGING ) 11019164Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 11123925Sgibbs mov SCBPTR, CUR_SCBID; 11223925Sgibbs.endif 11319164Sgibbsdma_queued_scb: 11419164Sgibbs/* 11519164Sgibbs * DMA the SCB from host ram into the current SCB location. 11619164Sgibbs */ 11723925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 11823925Sgibbs mov CUR_SCBID call dma_scb; 1194568Sgibbs 12013177Sgibbs/* 12113177Sgibbs * See if there is not already an active SCB for this target. This code 12213177Sgibbs * locks out on a per target basis instead of target/lun. Although this 12313177Sgibbs * is not ideal for devices that have multiple luns active at the same 12413177Sgibbs * time, it is faster than looping through all SCB's looking for active 12519921Sgibbs * commands. We also don't have enough spare SCB space for us to store the 12619164Sgibbs * SCBID of the currently busy transaction for each target/lun making it 12719164Sgibbs * impossible to link up the SCBs. 12813177Sgibbs */ 1295647Sgibbstest_busy: 13023925Sgibbs test SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb; 13123925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 13223925Sgibbs mov SAVED_SCBPTR, SCBPTR; 13323925Sgibbs mov SCB_TCL call index_untagged_scb; 13423925Sgibbs mov ARG_1, SINDIR; /* 13519164Sgibbs * ARG_1 should 13619164Sgibbs * now have the SCB ID of 13719164Sgibbs * any active, non-tagged, 13819164Sgibbs * command for this target. 13919164Sgibbs */ 14023925Sgibbs cmp ARG_1, SCB_LIST_NULL je make_busy; 14123925Sgibbs.if ( SCB_PAGING ) 14219164Sgibbs /* 14319164Sgibbs * Put this SCB back onto the free list. It 14419164Sgibbs * may be necessary to satisfy the search for 14519164Sgibbs * the active SCB. 14619164Sgibbs */ 14723925Sgibbs mov SCBPTR, SAVED_SCBPTR; 14823925Sgibbs call add_scb_to_free_list; 14919164Sgibbs /* Find the active SCB */ 15023925Sgibbs mov ALLZEROS call findSCB; 15119218Sgibbs /* 15219218Sgibbs * If we couldn't find it, tell the kernel. This should 15321947Sgibbs * never happen. 15419218Sgibbs */ 15523925Sgibbs cmp SINDEX, SCB_LIST_NULL jne paged_busy_link; 15623925Sgibbs mvi INTSTAT, NO_MATCH_BUSY; 15719218Sgibbspaged_busy_link: 15819164Sgibbs /* Link us in */ 15923925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 16019164Sgibbs /* Put it back on the disconnected list */ 16123925Sgibbs call add_scb_to_disc_list; 16223925Sgibbs mvi SEQCTL, FASTMODE; 16323925Sgibbs jmp poll_for_work; 16423925Sgibbs.endif 16519164Sgibbssimple_busy_link: 16623925Sgibbs mov SCBPTR, ARG_1; 16723925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 16823925Sgibbs mvi SEQCTL, FASTMODE; 16923925Sgibbs jmp poll_for_work; 17019164Sgibbsmake_busy: 17123925Sgibbs mov DINDIR, CUR_SCBID; 17223925Sgibbs mov SCBPTR, SAVED_SCBPTR; 17323925Sgibbs mvi SEQCTL, FASTMODE; 1744568Sgibbs 1755326Sgibbsstart_scb: 17619164Sgibbs /* 17719164Sgibbs * Place us on the waiting list in case our selection 17819164Sgibbs * doesn't win during bus arbitration. 17919164Sgibbs */ 18023925Sgibbs mov SCB_NEXT,WAITING_SCBH; 18123925Sgibbs mov WAITING_SCBH, SCBPTR; 18223925Sgibbsstart_waiting: 18323925Sgibbs /* 18423925Sgibbs * Pull the first entry off of the waiting SCB list 18523925Sgibbs * We don't have to "test_busy" because only transactions that 18623925Sgibbs * have passed that test can be in the WAITING_SCB list. 18723925Sgibbs */ 18823925Sgibbs mov SCBPTR, WAITING_SCBH; 18923925Sgibbs call start_selection; 19023925Sgibbs jmp poll_for_work; 1918104Sgibbs 19223925Sgibbsstart_selection: 19323991Sgibbs.if ( TWIN_CHANNEL ) 19423925Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */ 19523925Sgibbs and A,SELBUSB,SCB_TCL; /* Get new channel bit */ 19623925Sgibbs or SINDEX,A; 19723925Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 19823991Sgibbs.endif 19923925Sgibbsinitialize_scsiid: 20023925Sgibbs and A, TID, SCB_TCL; /* Get target ID */ 20123925Sgibbs and SCSIID, OID; /* Clear old target */ 20223925Sgibbs or SCSIID, A; 20323925Sgibbs mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; 20413177Sgibbs/* 20523925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 20623925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 20713177Sgibbs */ 20823925Sgibbsreselect: 20923925Sgibbs clr MSG_LEN; /* Don't have anything in the mesg buffer */ 21023925Sgibbs mvi CLRSINT0, CLRSELDI; 21123925Sgibbs /* XXX test for and handle ONE BIT condition */ 21223925Sgibbs and SAVED_TCL, SELID_MASK, SELID; 21323925Sgibbs or SEQ_FLAGS,RESELECTED; 21423925Sgibbs jmp select2; 2154568Sgibbs 21613177Sgibbs/* 21723925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 21823925Sgibbs * list. This is achieved by simply moving our "next" pointer into 21923925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 22023925Sgibbs * SCB is used, so don't bother with it now. 22123925Sgibbs */ 22223925Sgibbsselect: 22323925Sgibbs /* Turn off the selection hardware */ 22423925Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* 22523925Sgibbs * ATN on parity errors 22623925Sgibbs * for "in" phases 22723925Sgibbs */ 22823925Sgibbs mvi CLRSINT0, CLRSELDO; 22923925Sgibbs mov SCBPTR, WAITING_SCBH; 23023925Sgibbs mov WAITING_SCBH,SCB_NEXT; 23123925Sgibbs mov SAVED_TCL, SCB_TCL; 23223925Sgibbs/* 23313177Sgibbs * As soon as we get a successful selection, the target should go 23413177Sgibbs * into the message out phase since we have ATN asserted. Prepare 23513177Sgibbs * the message to send. 23613177Sgibbs * 23713177Sgibbs * Messages are stored in scratch RAM starting with a length byte 23813177Sgibbs * followed by the message itself. 23913177Sgibbs */ 2408567Sdg 24113177Sgibbsmk_identify: 24223925Sgibbs and MSG_OUT,0x7,SCB_TCL; /* lun */ 24323925Sgibbs and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ 24423925Sgibbs or MSG_OUT,A; /* or in disconnect privledge */ 24523925Sgibbs or MSG_OUT,MSG_IDENTIFYFLAG; 24623925Sgibbs mvi MSG_LEN, 1; 2474568Sgibbs 24813177Sgibbs/* 24915328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 25015328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 25113177Sgibbs */ 2526608Sgibbsmk_tag: 25323925Sgibbs test SCB_CONTROL,TAG_ENB jz mk_message; 25423925Sgibbs and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 25523925Sgibbs mov MSG_OUT[2],SCB_TAG; 25623925Sgibbs add MSG_LEN,2; /* update message length */ 2576608Sgibbs 25818762Sgibbs/* 25918762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer 26018762Sgibbs * if it asks. 26118762Sgibbs */ 26218762Sgibbsmk_message: 26323925Sgibbs test SCB_CONTROL,MK_MESSAGE jz select2; 26423925Sgibbs mvi INTSTAT,AWAITING_MSG; 2656608Sgibbs 2668104Sgibbsselect2: 26723925Sgibbs mvi CLRSINT1,CLRBUSFREE; 26823925Sgibbs or SIMODE1, ENBUSFREE; /* 26921947Sgibbs * We aren't expecting a 27021947Sgibbs * bus free, so interrupt 27121947Sgibbs * the kernel driver if it 27221947Sgibbs * happens. 27321947Sgibbs */ 27413177Sgibbs/* 27522451Sgibbs * Initialize Ultra mode setting and clear the SCSI channel. 27622451Sgibbs */ 27723925Sgibbs or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN; 27823925Sgibbs.if ( ULTRA ) 27922451Sgibbsultra: 28023925Sgibbs mvi SINDEX, ULTRA_ENB+1; 28123925Sgibbs test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ 28223925Sgibbs dec SINDEX; 28322451Sgibbsultra_2: 28423925Sgibbs mov FUNCTION1,SAVED_TCL; 28523925Sgibbs mov A,FUNCTION1; 28623925Sgibbs test SINDIR, A jz ndx_dtr; 28723925Sgibbs or SXFRCTL0, FAST20; 28823925Sgibbs.endif 28922451Sgibbs 29022451Sgibbs/* 29113177Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 29219164Sgibbs * The SCSIRATE settings for each target are stored in an array 29319164Sgibbs * based at TARG_SCRATCH. 29413177Sgibbs */ 29519164Sgibbsndx_dtr: 29623925Sgibbs shr A,4,SAVED_TCL; 29723925Sgibbs test SBLKCTL,SELBUSB jz ndx_dtr_2; 29823925Sgibbs or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */ 29923925Sgibbs or A,0x08; /* Channel B entries add 8 */ 30019164Sgibbsndx_dtr_2: 30123925Sgibbs add SINDEX,TARG_SCRATCH,A; 30223925Sgibbs mov SCSIRATE,SINDIR; 30313177Sgibbs 30415843Sgibbs 30513177Sgibbs/* 30613177Sgibbs * Main loop for information transfer phases. If BSY is false, then 30713177Sgibbs * we have a bus free condition, expected or not. Otherwise, wait 30813177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O 30913177Sgibbs * for the bus phase. 31013177Sgibbs * 31113177Sgibbs */ 3124568SgibbsITloop: 31323925Sgibbs test SSTAT1,REQINIT jz ITloop; 3144568Sgibbs 31523925Sgibbs and A,PHASE_MASK,SCSISIGI; 31623925Sgibbs mov LASTPHASE,A; 31723925Sgibbs mov SCSISIGO,A; 3184568Sgibbs 31923925Sgibbs cmp ALLZEROS,A je p_dataout; 32023925Sgibbs cmp A,P_DATAIN je p_datain; 32123925Sgibbs cmp A,P_COMMAND je p_command; 32223925Sgibbs cmp A,P_MESGOUT je p_mesgout; 32323925Sgibbs cmp A,P_STATUS je p_status; 32423925Sgibbs cmp A,P_MESGIN je p_mesgin; 3254568Sgibbs 32623925Sgibbs mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ 32723925Sgibbs jmp ITloop; /* Try reading the bus again. */ 3284568Sgibbs 32923925Sgibbsawait_busfree: 33023925Sgibbs and SIMODE1, ~ENBUSFREE; 33123925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 33223925Sgibbs call clear_target_state; 33323925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 33423925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 33523925Sgibbs mvi INTSTAT, BAD_PHASE; 33623925Sgibbs 33723925Sgibbsclear_target_state: 33823925Sgibbs clr DFCNTRL; 33923925Sgibbs clr SCSIRATE; /* 34023925Sgibbs * We don't know the target we will 34123925Sgibbs * connect to, so default to narrow 34223925Sgibbs * transfers to avoid parity problems. 34323925Sgibbs */ 34423925Sgibbs and SXFRCTL0, ~FAST20; 34523925Sgibbs mvi LASTPHASE, P_BUSFREE; 34623925Sgibbs /* clear target specific flags */ 34723925Sgibbs and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret; 34823925Sgibbs 3494568Sgibbsp_dataout: 35023925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET; 35123925Sgibbs jmp data_phase_init; 3524568Sgibbs 35313177Sgibbs/* 35413177Sgibbs * If we re-enter the data phase after going through another phase, the 35513177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 35613177Sgibbs */ 3579928Sgibbsdata_phase_reinit: 35823925Sgibbs mvi DINDEX, STCNT; 35923925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 36023925Sgibbs jmp data_phase_loop; 3614568Sgibbs 3629928Sgibbsp_datain: 36323925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 3649928Sgibbsdata_phase_init: 36523925Sgibbs call assert; /* 36619164Sgibbs * Ensure entering a data 36719164Sgibbs * phase is okay - seen identify, etc. 36819164Sgibbs */ 3695775Sgibbs 37023925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 3714568Sgibbs 37219164Sgibbs /* 37319164Sgibbs * Initialize the DMA address and counter from the SCB. 37419164Sgibbs * Also set SG_COUNT and SG_NEXT in memory since we cannot 37519164Sgibbs * modify the values in the SCB itself until we see a 37619164Sgibbs * save data pointers message. 37719164Sgibbs */ 37823925Sgibbs mvi DINDEX, HADDR; 37923925Sgibbs mvi SCB_DATAPTR call bcopy_7; 38019164Sgibbs 38123925Sgibbs call set_stcnt_from_hcnt; 38219164Sgibbs 38323925Sgibbs mov SG_COUNT,SCB_SGCOUNT; 38419164Sgibbs 38523925Sgibbs mvi DINDEX, SG_NEXT; 38623925Sgibbs mvi SCB_SGPTR call bcopy_4; 38719164Sgibbs 3889928Sgibbsdata_phase_loop: 38916260Sgibbs/* Guard against overruns */ 39023925Sgibbs test SG_COUNT, 0xff jnz data_phase_inbounds; 39116260Sgibbs/* 39216260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to 39316260Sgibbs * 16meg and let the target run until it changes phase. 39416260Sgibbs * When the transfer completes, notify the host that we 39516260Sgibbs * had an overrun. 39616260Sgibbs */ 39723925Sgibbs or SXFRCTL1,BITBUCKET; 39823925Sgibbs mvi HCNT[0], 0xff; 39923925Sgibbs mvi HCNT[1], 0xff; 40023925Sgibbs mvi HCNT[2], 0xff; 40123925Sgibbs call set_stcnt_from_hcnt; 40216260Sgibbs 40316260Sgibbsdata_phase_inbounds: 40419164Sgibbs/* If we are the last SG block, ensure wideodd is off. */ 40523925Sgibbs cmp SG_COUNT,0x01 jne data_phase_wideodd; 40623925Sgibbs and DMAPARAMS, ~WIDEODD; 4079928Sgibbsdata_phase_wideodd: 40823925Sgibbs mov DMAPARAMS call dma; 4094568Sgibbs 41016260Sgibbs/* Go tell the host about any overruns */ 41123925Sgibbs test SXFRCTL1,BITBUCKET jnz data_phase_overrun; 41216260Sgibbs 41322451Sgibbs/* Exit if we had an underrun. dma clears SINDEX in this case. */ 41423925Sgibbs test SINDEX,0xff jz data_phase_finish; 4157532Sgibbs 41613177Sgibbs/* 41713177Sgibbs * Advance the scatter-gather pointers if needed 41813177Sgibbs */ 4199928Sgibbssg_advance: 42023925Sgibbs dec SG_COUNT; /* one less segment to go */ 4214568Sgibbs 42223925Sgibbs test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ 4234568Sgibbs 42423925Sgibbs clr A; /* add sizeof(struct scatter) */ 42523925Sgibbs add SG_NEXT[0],SG_SIZEOF; 42623925Sgibbs adc SG_NEXT[1],A; 4274568Sgibbs 42813177Sgibbs/* 42913177Sgibbs * Load a struct scatter and set up the data address and length. 43013177Sgibbs * If the working value of the SG count is nonzero, then 43113177Sgibbs * we need to load a new set of values. 43213177Sgibbs * 43315328Sgibbs * This, like all DMA's, assumes little-endian host data storage. 43413177Sgibbs */ 4359928Sgibbssg_load: 43623925Sgibbs mvi DINDEX, HADDR; 43723925Sgibbs mvi SG_NEXT call bcopy_4; 4384568Sgibbs 43923925Sgibbs mvi HCNT[0],SG_SIZEOF; 44023925Sgibbs clr HCNT[1]; 44123925Sgibbs clr HCNT[2]; 44222568Sgibbs 44323925Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 4449928Sgibbs 44523925Sgibbs call dma_finish; 4469928Sgibbs 44713177Sgibbs/* 44813177Sgibbs * Copy data from FIFO into SCB data pointer and data count. This assumes 44919164Sgibbs * that the SG segments are of the form: 45013177Sgibbs * 45113177Sgibbs * struct ahc_dma_seg { 45219164Sgibbs * u_int32_t addr; four bytes, little-endian order 45319164Sgibbs * u_int32_t len; four bytes, little endian order 45413177Sgibbs * }; 45513177Sgibbs */ 45623925Sgibbs mvi HADDR call dfdat_in_7; 4579928Sgibbs 45813177Sgibbs/* Load STCNT as well. It is a mirror of HCNT */ 45923925Sgibbs call set_stcnt_from_hcnt; 46023925Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 4614568Sgibbs 4629928Sgibbsdata_phase_finish: 46313177Sgibbs/* 46413177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB 46513177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 46613177Sgibbs * were transferred on the SCSI (as opposed to the host) bus. 46713177Sgibbs */ 46823925Sgibbs mov SCB_RESID_DCNT[0],STCNT[0]; 46923925Sgibbs mov SCB_RESID_DCNT[1],STCNT[1]; 47023925Sgibbs mov SCB_RESID_DCNT[2],STCNT[2]; 47123925Sgibbs mov SCB_RESID_SGCNT, SG_COUNT; 47222568Sgibbs 47322568Sgibbs /* We have seen a data phase */ 47423925Sgibbs or SEQ_FLAGS, DPHASE; 47522568Sgibbs 47623925Sgibbs jmp ITloop; 4774568Sgibbs 47816260Sgibbsdata_phase_overrun: 47913177Sgibbs/* 48016260Sgibbs * Turn off BITBUCKET mode and notify the host 48116260Sgibbs */ 48223925Sgibbs and SXFRCTL1, ~BITBUCKET; 48323925Sgibbs mvi INTSTAT,DATA_OVERRUN; 48423925Sgibbs jmp ITloop; 48516260Sgibbs 48616260Sgibbs/* 48715328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 48813177Sgibbs */ 4894568Sgibbsp_command: 49023925Sgibbs call assert; 4914568Sgibbs 49213177Sgibbs/* 49315328Sgibbs * Load HADDR and HCNT. 49413177Sgibbs */ 49523925Sgibbs mvi DINDEX, HADDR; 49623925Sgibbs mvi SCB_CMDPTR call bcopy_5; 49723925Sgibbs clr HCNT[1]; 49823925Sgibbs clr HCNT[2]; 4994568Sgibbs 50023925Sgibbs call set_stcnt_from_hcnt; 5014568Sgibbs 50223925Sgibbs mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; 50323925Sgibbs jmp ITloop; 5044568Sgibbs 50513177Sgibbs/* 50613177Sgibbs * Status phase. Wait for the data byte to appear, then read it 50713177Sgibbs * and store it into the SCB. 50813177Sgibbs */ 5094568Sgibbsp_status: 51023925Sgibbs call assert; 51119803Sgibbs 51223925Sgibbs mov SCB_TARGET_STATUS, SCSIDATL; 51323925Sgibbs jmp ITloop; 5144568Sgibbs 51513177Sgibbs/* 51615328Sgibbs * Message out phase. If there is not an active message, but the target 51713177Sgibbs * took us into this phase anyway, build a no-op message and send it. 51813177Sgibbs */ 5194568Sgibbsp_mesgout: 52023925Sgibbs test MSG_LEN, 0xff jnz p_mesgout_start; 52123925Sgibbs mvi MSG_NOOP call mk_mesg; /* build NOP message */ 52213177Sgibbsp_mesgout_start: 52313177Sgibbs/* 52423925Sgibbs * Set up automatic PIO transfer from MSG_OUT. Bit 3 in 52513177Sgibbs * SXFRCTL0 (SPIOEN) is already on. 52613177Sgibbs */ 52723925Sgibbs mvi SINDEX,MSG_OUT; 52823925Sgibbs mov DINDEX,MSG_LEN; 5294568Sgibbs 53013177Sgibbs/* 53113177Sgibbs * When target asks for a byte, drop ATN if it's the last one in 53213177Sgibbs * the message. Otherwise, keep going until the message is exhausted. 53323925Sgibbs * ATN must be dropped *at least* 90ns before we ack the last byte, so 53423925Sgibbs * the code is aranged to execute two instructions before the byte is 53523925Sgibbs * transferred to give a good margin of safety 53613177Sgibbs * 53713177Sgibbs * Keep an eye out for a phase change, in case the target issues 53813177Sgibbs * a MESSAGE REJECT. 53913177Sgibbs */ 54013177Sgibbsp_mesgout_loop: 54123925Sgibbs test SSTAT1, REQINIT jz p_mesgout_loop; 54223925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 54323925Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 54413177Sgibbs/* 54513177Sgibbs * If the next bus phase after ATN drops is a message out, it means 54613177Sgibbs * that the target is requesting that the last message(s) be resent. 54713177Sgibbs */ 54823925Sgibbsp_mesgout_dropatn: 54923925Sgibbs cmp DINDEX,1 jne p_mesgout_testretry;/* last byte? */ 55023925Sgibbs mvi CLRSINT1,CLRATNO; /* drop ATN */ 55119921Sgibbsp_mesgout_testretry: 55223925Sgibbs test DINDEX,0xff jnz p_mesgout_outb; 55323925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 55423925Sgibbs jmp p_mesgout_start; 55519906Sgibbsp_mesgout_outb: 55623925Sgibbs dec DINDEX; 55723925Sgibbs mov SCSIDATL,SINDIR; 55823925Sgibbs jmp p_mesgout_loop; 5594568Sgibbs 56019906Sgibbsp_mesgout_done: 56123925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 56223925Sgibbs clr MSG_LEN; /* no active msg */ 56323925Sgibbs jmp ITloop; 5644568Sgibbs 56513177Sgibbs/* 56613177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 56713177Sgibbs */ 5684568Sgibbsp_mesgin: 56923925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 57023925Sgibbs mov REJBYTE,A; /* save it for the driver */ 5714568Sgibbs 57223925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 57323925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 57423925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 57523925Sgibbs cmp ALLZEROS,A je mesgin_complete; 57623925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 57723925Sgibbs cmp A,MSG_EXTENDED je mesgin_extended; 57823925Sgibbs cmp A,MSG_MESSAGE_REJECT je mesgin_reject; 57923925Sgibbs cmp A,MSG_NOOP je mesgin_done; 5804568Sgibbs 5819954Sgibbsrej_mesgin: 58213177Sgibbs/* 58319164Sgibbs * We have no idea what this message in is, so we issue a message reject 58419164Sgibbs * and hope for the best. In any case, rejection should be a rare 58519164Sgibbs * occurrence - signal the driver when it happens. 58613177Sgibbs */ 58723925Sgibbs mvi INTSTAT,SEND_REJECT; /* let driver know */ 5889954Sgibbs 58923925Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 5909954Sgibbs 5919954Sgibbsmesgin_done: 59223925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 59323925Sgibbs jmp ITloop; 5949954Sgibbs 5959954Sgibbs 5969954Sgibbsmesgin_complete: 59713177Sgibbs/* 59819164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, 59919164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 60019164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0). In 60119164Sgibbs * either of these conditions, we upload the SCB back to the host so it can 60219164Sgibbs * process this information. In the case of a non zero status byte, we 60319164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 60419164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 60519164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set 60619164Sgibbs * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload 60719164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list. 60819164Sgibbs * If the kernel driver does not wish to request sense, it need only clear 60919164Sgibbs * RETURN_1, and the command is allowed to complete normally. We don't bother 61019164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra 61119164Sgibbs * work in the kernel driver to ensure that the entry was removed before the 61219164Sgibbs * command complete code tried processing it. 61313177Sgibbs */ 61419164Sgibbs 61513177Sgibbs/* 61619164Sgibbs * First check for residuals 61713177Sgibbs */ 61823925Sgibbs test SCB_RESID_SGCNT,0xff jnz upload_scb; 61923925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */ 62019164Sgibbsupload_scb: 62123925Sgibbs mvi DMAPARAMS, FIFORESET; 62223925Sgibbs mov SCB_TAG call dma_scb; 6237532Sgibbscheck_status: 62423925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */ 62523925Sgibbs mvi INTSTAT,BAD_STATUS; /* let driver know */ 62623925Sgibbs cmp RETURN_1, SEND_SENSE jne status_ok; 62719164Sgibbs /* This SCB becomes the next to execute as it will retrieve sense */ 62823925Sgibbs mov SCB_LINKED_NEXT, SCB_TAG; 62923925Sgibbs jmp dma_next_scb; 6305326Sgibbs 6314568Sgibbsstatus_ok: 63213177Sgibbs/* First, mark this target as free. */ 63323925Sgibbs test SCB_CONTROL,TAG_ENB jnz complete; /* 63413177Sgibbs * Tagged commands 63513177Sgibbs * don't busy the 63613177Sgibbs * target. 63713177Sgibbs */ 63823925Sgibbs mov SAVED_SCBPTR, SCBPTR; 63923925Sgibbs mov SAVED_LINKPTR, SCB_LINKED_NEXT; 64023925Sgibbs mov SCB_TCL call index_untagged_scb; 64123925Sgibbs mov DINDIR, SAVED_LINKPTR; 64223925Sgibbs mov SCBPTR, SAVED_SCBPTR; 6435326Sgibbs 6445326Sgibbscomplete: 64519164Sgibbs /* Post the SCB and issue an interrupt */ 64623925Sgibbs mov QOUTFIFO,SCB_TAG; 64723925Sgibbs mvi INTSTAT,CMDCMPLT; 64823925Sgibbs test SCB_CONTROL, ABORT_SCB jz dma_next_scb; 64923925Sgibbs mvi INTSTAT, ABORT_CMDCMPLT; 65019164Sgibbs 65119164Sgibbsdma_next_scb: 65223925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list; 65323925Sgibbs.if !( SCB_PAGING ) 65419164Sgibbs /* Only DMA on top of ourselves if we are the SCB to download */ 65523925Sgibbs mov A, SCB_LINKED_NEXT; 65623925Sgibbs cmp SCB_TAG, A je dma_next_scb2; 65723925Sgibbs mov SCBPTR, A; 65823925Sgibbs jmp add_to_waiting_list; 65923925Sgibbs.endif 66019164Sgibbsdma_next_scb2: 66123925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 66223925Sgibbs mov SCB_LINKED_NEXT call dma_scb; 66319164Sgibbsadd_to_waiting_list: 66423925Sgibbs mov SCB_NEXT,WAITING_SCBH; 66523925Sgibbs mov WAITING_SCBH, SCBPTR; 66623925Sgibbs /* 66723925Sgibbs * Prepare our selection hardware before the busfree so we have a 66823925Sgibbs * high probability of winning arbitration. 66923925Sgibbs */ 67023925Sgibbs call start_selection; 67123925Sgibbs jmp await_busfree; 67219921Sgibbsadd_to_free_list: 67323925Sgibbs call add_scb_to_free_list; 67423925Sgibbs jmp await_busfree; 6754568Sgibbs 67613177Sgibbs/* 67718762Sgibbs * Is it an extended message? Copy the message to our message buffer and 67818762Sgibbs * notify the host. The host will tell us whether to reject this message, 67918762Sgibbs * respond to it with the message that the host placed in our message buffer, 68018762Sgibbs * or simply to do nothing. 68113177Sgibbs */ 6829954Sgibbsmesgin_extended: 68323925Sgibbs mvi MSGIN_EXT_LEN call inb_next; 68423925Sgibbs mov A, MSGIN_EXT_LEN; 68518762Sgibbsmesgin_extended_loop: 68623925Sgibbs mov DINDEX call inb_next; 68723925Sgibbs dec A; 68823925Sgibbs cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test; 68923925Sgibbs dec DINDEX; /* dump by repeatedly filling the last byte */ 69019164Sgibbsmesgin_extended_loop_test: 69123925Sgibbs test A, 0xFF jnz mesgin_extended_loop; 69218762Sgibbsmesgin_extended_intr: 69323925Sgibbs mvi INTSTAT,EXTENDED_MSG; /* let driver know */ 69423925Sgibbs cmp RETURN_1,SEND_REJ je rej_mesgin; 69523925Sgibbs cmp RETURN_1,SEND_MSG jne mesgin_done; 69618762Sgibbs/* The kernel has setup a message to be sent */ 69723925Sgibbs or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */ 69823925Sgibbs jmp mesgin_done; 6995562Sgibbs 70013177Sgibbs/* 70113177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 70213177Sgibbs * and await the bus going free. 70313177Sgibbs */ 7049954Sgibbsmesgin_disconnect: 70523925Sgibbs or SCB_CONTROL,DISCONNECTED; 70623925Sgibbs.if ( SCB_PAGING ) 70723925Sgibbs call add_scb_to_disc_list; 70823925Sgibbs.endif 70923925Sgibbs jmp await_busfree; 71019164Sgibbs 71115328Sgibbs/* 71219164Sgibbs * Save data pointers message: 71319164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 71419164Sgibbs * only if we've actually been into a data phase to change them. This 71519164Sgibbs * protects against bogus data in scratch ram and the residual counts 71619164Sgibbs * since they are only initialized when we go into data_in or data_out. 71715328Sgibbs */ 71819164Sgibbsmesgin_sdptrs: 71923925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 72023925Sgibbs mov SCB_SGCOUNT,SG_COUNT; 7214568Sgibbs 72219164Sgibbs /* The SCB SGPTR becomes the next one we'll download */ 72323925Sgibbs mvi DINDEX, SCB_SGPTR; 72423925Sgibbs mvi SG_NEXT call bcopy_4; 72519164Sgibbs 72619164Sgibbs /* The SCB DATAPTR0 becomes the current SHADDR */ 72723925Sgibbs mvi DINDEX, SCB_DATAPTR; 72823925Sgibbs mvi SHADDR call bcopy_4; 72919164Sgibbs 73013177Sgibbs/* 73119164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer. 73213177Sgibbs */ 73323925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 73419164Sgibbs 73523925Sgibbs jmp mesgin_done; 7364568Sgibbs 73713177Sgibbs/* 73813177Sgibbs * Restore pointers message? Data pointers are recopied from the 73913177Sgibbs * SCB anytime we enter a data phase for the first time, so all 74013177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 74113177Sgibbs * code do the rest. 74213177Sgibbs */ 7439954Sgibbsmesgin_rdptrs: 74423925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 74523925Sgibbs * We'll reload them 74613177Sgibbs * the next time through 74723925Sgibbs * the dataphase. 74813177Sgibbs */ 74923925Sgibbs jmp mesgin_done; 7504568Sgibbs 75113177Sgibbs/* 75213177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 75313177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 75413177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 75513177Sgibbs */ 7569954Sgibbsmesgin_identify: 75723925Sgibbs test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/ 75823925Sgibbs and A,0x07; /* lun in lower three bits */ 75923925Sgibbs or SAVED_TCL,A; /* SAVED_TCL should be complete now */ 76023925Sgibbs mov SAVED_TCL call index_untagged_scb; 76123925Sgibbs mov ARG_1, SINDIR; 76224608Sgibbs.if ( SCB_PAGING ) 76323925Sgibbs cmp ARG_1,SCB_LIST_NULL jne use_findSCB; 76424608Sgibbs.else 76524608Sgibbs cmp ARG_1,SCB_LIST_NULL je snoop_tag; 76624608Sgibbs /* Directly index the SCB */ 76724608Sgibbs mov SCBPTR,ARG_1; 76824608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 76924608Sgibbs jmp setup_SCB; 77024608Sgibbs.endif 77113177Sgibbs/* 77213177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 77323168Sgibbs * If we get one, we use the tag returned to find the proper 77415328Sgibbs * SCB. With SCB paging, this requires using findSCB for both tagged 77515328Sgibbs * and non-tagged transactions since the SCB may exist in any slot. 77615328Sgibbs * If we're not using SCB paging, we can use the tag as the direct 77715328Sgibbs * index to the SCB. 77813177Sgibbs */ 77924608Sgibbssnoop_tag: 78023925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 78113177Sgibbssnoop_tag_loop: 78223925Sgibbs test SSTAT1,REQINIT jz snoop_tag_loop; 78323925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 78423925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 78523925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 7866608Sgibbsget_tag: 78723925Sgibbs or SEQ_FLAGS, TAGGED_SCB; 78823925Sgibbs mvi ARG_1 call inb_next; /* tag value */ 78913177Sgibbs/* 79013177Sgibbs * See if the tag is in range. The tag is < SCBCOUNT if we add 79113177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is 79213177Sgibbs * no carry. 79313177Sgibbs */ 79423925Sgibbs mov A,COMP_SCBCOUNT; 79523925Sgibbs add SINDEX,A,ARG_1; 79623925Sgibbs jc not_found; 79713177Sgibbs 79823925Sgibbs.if ! ( SCB_PAGING ) 79924608Sgibbsindex_by_tag: 80024608Sgibbs mov SCBPTR,ARG_1; 80124608Sgibbs mov A, SAVED_TCL; 80224608Sgibbs cmp SCB_TCL,A jne not_found; 80324608Sgibbs test SCB_CONTROL,TAG_ENB jz not_found; 80424608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 80524608Sgibbs.else 80613177Sgibbs/* 80715328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction 80813177Sgibbs * to the reconnecting target. 80913177Sgibbs */ 81015328Sgibbsuse_findSCB: 81123925Sgibbs mov ALLZEROS call findSCB; /* Have to search */ 81223925Sgibbs cmp SINDEX, SCB_LIST_NULL je not_found; 81324608Sgibbs.endif 81415328Sgibbssetup_SCB: 81523925Sgibbs and SCB_CONTROL,~DISCONNECTED; 81623925Sgibbs or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 81723925Sgibbs jmp mesgin_done; 81815328Sgibbs 81919218Sgibbsnot_found: 82023925Sgibbs mvi INTSTAT, NO_MATCH; 82119218Sgibbssend_abort_msg: 82223925Sgibbs test SEQ_FLAGS, TAGGED_SCB jnz send_abort_tag_msg; 82323925Sgibbs mvi MSG_ABORT call mk_mesg; 82423925Sgibbs jmp send_abort_done; 82523168Sgibbssend_abort_tag_msg: 82623925Sgibbs mvi MSG_ABORT_TAG call mk_mesg; /* ABORT TAG message */ 82723168Sgibbssend_abort_done: 82823168Sgibbs /* If we don't have the tag ID yet, we're "looking ahead" at state 82923168Sgibbs * that hasn't been processed, so don't ack. 83023168Sgibbs */ 83123925Sgibbs cmp ARG_1, SCB_LIST_NULL je ITloop; 83223925Sgibbs jmp mesgin_done; 8336608Sgibbs 83413177Sgibbs/* 83513177Sgibbs * Message reject? Let the kernel driver handle this. If we have an 83613177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 83713177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 83813177Sgibbs * it since we have no clue what it pertains to. 83913177Sgibbs */ 8409954Sgibbsmesgin_reject: 84123925Sgibbs mvi INTSTAT, REJECT_MSG; 84223925Sgibbs jmp mesgin_done; 8435562Sgibbs 84413177Sgibbs/* 84513177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ] 84613177Sgibbs */ 8474568Sgibbs 84813177Sgibbs/* 84913177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX 85013177Sgibbs * if there is no active message already. SINDEX is returned intact. 85113177Sgibbs */ 8524568Sgibbsmk_mesg: 85323925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 85423925Sgibbs test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */ 85513177Sgibbs 85613177Sgibbs /* 85713177Sgibbs * Hmmm. For some reason the mesg buffer is in use. 85813177Sgibbs * Tell the driver. It should look at SINDEX to find 85913177Sgibbs * out what we wanted to use the buffer for and resolve 86013177Sgibbs * the conflict. 86113177Sgibbs */ 86223925Sgibbs mvi SEQCTL,FASTMODE; 86323925Sgibbs mvi INTSTAT,MSG_BUFFER_BUSY; 8644568Sgibbs 8654568Sgibbsmk_mesg1: 86623925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 86723925Sgibbs mvi MSG_LEN,1; /* length = 1 */ 86823925Sgibbs mov MSG_OUT,SINDEX; /* 1-byte message */ 86923925Sgibbs mvi SEQCTL,FASTMODE ret; 8704568Sgibbs 87113177Sgibbs/* 87213177Sgibbs * Functions to read data in Automatic PIO mode. 87313177Sgibbs * 87413177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 87513177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 87613177Sgibbs * latched (the usual way), then read the data byte directly off the bus 87713177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 87813177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 87913177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 88013177Sgibbs * we send our ACK. 88113177Sgibbs * 88213177Sgibbs * The assumption here is that these are called in a particular sequence, 88313177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 88413177Sgibbs * use the same calling convention as inb. 88513177Sgibbs */ 88613177Sgibbs 88713177Sgibbsinb_next: 88823925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 88913360Sgibbsinb_next_wait: 89021947Sgibbs /* 89121947Sgibbs * If there is a parity error, wait for the kernel to 89221947Sgibbs * see the interrupt and prepare our message response 89321947Sgibbs * before continuing. 89421947Sgibbs */ 89523925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 89623925Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait; 89723925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 89823925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 89919623Sgibbsinb_first: 90023925Sgibbs mov DINDEX,SINDEX; 90123925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 90213177Sgibbsinb_last: 90323925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 9044568Sgibbs 90513177Sgibbsmesgin_phasemis: 90613177Sgibbs/* 90713177Sgibbs * We expected to receive another byte, but the target changed phase 90813177Sgibbs */ 90923925Sgibbs mvi INTSTAT, MSGIN_PHASEMIS; 91023925Sgibbs jmp ITloop; 9114568Sgibbs 91213177Sgibbs/* 91313177Sgibbs * DMA data transfer. HADDR and HCNT must be loaded first, and 91413177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for 91513177Sgibbs * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 91613177Sgibbs * during initialization. 91713177Sgibbs */ 9184568Sgibbsdma: 91923925Sgibbs mov DFCNTRL,SINDEX; 92022568Sgibbsdma_loop: 92123925Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 92223925Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 92322568Sgibbsdma_phasemis: 92423925Sgibbs test SSTAT0,SDONE jnz dma_checkfifo; 92523925Sgibbs mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ 9264568Sgibbs 92713177Sgibbs/* 92813177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or 92913177Sgibbs * the target changes the phase (in light of this, it makes sense that 93013177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 93113177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto- 93213177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty 93313177Sgibbs * status. 93413177Sgibbs */ 93522568Sgibbsdma_checkfifo: 93623925Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 93722568Sgibbsdma_fifoflush: 93823925Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 9394568Sgibbs 94022568Sgibbsdma_fifoempty: 94122568Sgibbs /* Don't clobber an inprogress host data transfer */ 94223925Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 94313177Sgibbs/* 94413177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 94513177Sgibbs * actually off first lest we get an ILLSADDR. 94613177Sgibbs */ 94722568Sgibbsdma_dmadone: 94823925Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 94922568Sgibbsdma_halt: 95023925Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 95118762Sgibbsreturn: 95223925Sgibbs ret; 9534568Sgibbs 95413177Sgibbs/* 95513177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 95613177Sgibbs * message. 95713177Sgibbs */ 9584568Sgibbsassert: 95923925Sgibbs test SEQ_FLAGS,RESELECTED jz return; /* reselected? */ 96023925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 9614568Sgibbs 96223925Sgibbs mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ 9634568Sgibbs 96424608Sgibbs.if ( SCB_PAGING ) 96513177Sgibbs/* 96619218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) 96719218Sgibbs * or by the SCBIDn ARG_1. The search begins at the SCB index passed in 96819218Sgibbs * via SINDEX. If the SCB cannot be found, SINDEX will be SCB_LIST_NULL, 96919218Sgibbs * otherwise, SCBPTR is set to the proper SCB. 97013177Sgibbs */ 9714568SgibbsfindSCB: 97223925Sgibbs mov SCBPTR,SINDEX; /* switch to next SCB */ 97323925Sgibbs mov A, ARG_1; /* Tag passed in ARG_1 */ 97423925Sgibbs cmp SCB_TAG,A jne findSCB_loop; 97523925Sgibbs test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/ 97623168SgibbsfindSCB_loop: 97723925Sgibbs inc SINDEX; 97823925Sgibbs mov A,SCBCOUNT; 97923925Sgibbs cmp SINDEX,A jne findSCB; 98019164Sgibbs/* 98119164Sgibbs * We didn't find it. If we're paging, pull an SCB and DMA down the 98219164Sgibbs * one we want. If we aren't paging or the SCB we dma down has the 98319218Sgibbs * abort flag set, return not found. 98419164Sgibbs */ 98523925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 98623925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 98723925Sgibbs mov ARG_1 call dma_scb; 98823925Sgibbs test SCB_CONTROL, ABORT_SCB jz return; 98919218Sgibbsfind_error: 99023925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 99115328SgibbsfoundSCB: 99223925Sgibbs test SCB_CONTROL, ABORT_SCB jnz find_error; 99319164Sgibbsrem_scb_from_disc_list: 99415328Sgibbs/* Remove this SCB from the disconnection list */ 99523925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev; 99623925Sgibbs mov SAVED_LINKPTR, SCB_PREV; 99723925Sgibbs mov SCBPTR, SCB_NEXT; 99823925Sgibbs mov SCB_PREV, SAVED_LINKPTR; 99923925Sgibbs mov SCBPTR, SINDEX; 100015328Sgibbsunlink_prev: 100123925Sgibbs cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */ 100223925Sgibbs mov SAVED_LINKPTR, SCB_NEXT; 100323925Sgibbs mov SCBPTR, SCB_PREV; 100423925Sgibbs mov SCB_NEXT, SAVED_LINKPTR; 100523925Sgibbs mov SCBPTR, SINDEX ret; 100615328SgibbsrHead: 100723925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 100823925Sgibbs.else 100923925Sgibbs ret; 101023925Sgibbs.endif 10114568Sgibbs 101219164Sgibbsset_stcnt_from_hcnt: 101323925Sgibbs mov STCNT[0], HCNT[0]; 101423925Sgibbs mov STCNT[1], HCNT[1]; 101523925Sgibbs mov STCNT[2], HCNT[2] ret; 10164568Sgibbs 101719164Sgibbsbcopy_7: 101823925Sgibbs mov DINDIR, SINDIR; 101923925Sgibbs mov DINDIR, SINDIR; 102019164Sgibbsbcopy_5: 102123925Sgibbs mov DINDIR, SINDIR; 102219164Sgibbsbcopy_4: 102323925Sgibbs mov DINDIR, SINDIR; 102419164Sgibbsbcopy_3: 102523925Sgibbs mov DINDIR, SINDIR; 102623925Sgibbs mov DINDIR, SINDIR; 102723925Sgibbs mov DINDIR, SINDIR ret; 10284568Sgibbs 102919164Sgibbsdma_scb: 103019164Sgibbs /* 103119164Sgibbs * SCB index is in SINDEX. Determine the physical address in 103219164Sgibbs * the host where this SCB is located and load HADDR with it. 103319164Sgibbs */ 103423925Sgibbs shr DINDEX, 3, SINDEX; 103523925Sgibbs shl A, 5, SINDEX; 103623925Sgibbs add HADDR[0], A, HSCB_ADDR[0]; 103723925Sgibbs mov A, DINDEX; 103823925Sgibbs adc HADDR[1], A, HSCB_ADDR[1]; 103923925Sgibbs clr A; 104023925Sgibbs adc HADDR[2], A, HSCB_ADDR[2]; 104123925Sgibbs adc HADDR[3], A, HSCB_ADDR[3]; 104219164Sgibbs /* Setup Count */ 104323925Sgibbs mvi HCNT[0], 28; 104423925Sgibbs clr HCNT[1]; 104523925Sgibbs clr HCNT[2]; 104623925Sgibbs mov DFCNTRL, DMAPARAMS; 104723925Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 104819164Sgibbs /* Fill it with the SCB data */ 104924175Sgibbscopy_scb_tofifo: 105024175Sgibbs mvi SINDEX, SCB_CONTROL; 105124175Sgibbs add A, 28, SINDEX; 105224175Sgibbscopy_scb_tofifo_loop: 105324175Sgibbs mov DFDAT,SINDIR; 105424175Sgibbs mov DFDAT,SINDIR; 105524175Sgibbs mov DFDAT,SINDIR; 105624175Sgibbs mov DFDAT,SINDIR; 105724175Sgibbs mov DFDAT,SINDIR; 105824175Sgibbs mov DFDAT,SINDIR; 105924175Sgibbs mov DFDAT,SINDIR; 106024175Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 106123925Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 106219164Sgibbsdma_scb_fromhost: 106323925Sgibbs call dma_finish; 106419164Sgibbs /* If we were putting the SCB, we are done */ 106523925Sgibbs test DMAPARAMS, DIRECTION jz return; 106623925Sgibbs mvi SCB_CONTROL call dfdat_in_7; 106723925Sgibbs call dfdat_in_7_continued; 106823925Sgibbs call dfdat_in_7_continued; 106923925Sgibbs jmp dfdat_in_7_continued; 107019164Sgibbsdfdat_in_7: 107123925Sgibbs mov DINDEX,SINDEX; 107219164Sgibbsdfdat_in_7_continued: 107323925Sgibbs mov DINDIR,DFDAT; 107423925Sgibbs mov DINDIR,DFDAT; 107523925Sgibbs mov DINDIR,DFDAT; 107623925Sgibbs mov DINDIR,DFDAT; 107723925Sgibbs mov DINDIR,DFDAT; 107823925Sgibbs mov DINDIR,DFDAT; 107923925Sgibbs mov DINDIR,DFDAT ret; 108019164Sgibbs 108113177Sgibbs/* 108219164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 108319164Sgibbs * DMA and wait for it to acknowledge that it's off. 108413177Sgibbs */ 108519164Sgibbsdma_finish: 108623925Sgibbs test DFSTATUS,HDONE jz dma_finish; 108722234Sgibbs /* Turn off DMA */ 108823925Sgibbs and DFCNTRL, ~HDMAEN; 108923925Sgibbs test DFCNTRL, HDMAEN jnz .; 109023925Sgibbs ret; 10919928Sgibbs 109219164Sgibbsindex_untagged_scb: 109323925Sgibbs mov DINDEX, SINDEX; 109423925Sgibbs shr DINDEX, 4; 109523925Sgibbs and DINDEX, 0x03; /* Bottom two bits of tid */ 109623925Sgibbs add DINDEX, SCB_BUSYTARGETS; 109723925Sgibbs shr A, 6, SINDEX; /* Target ID divided by 4 */ 109823925Sgibbs test SINDEX, SELBUSB jz index_untagged_scb2; 109923925Sgibbs add A, 2; /* Add 2 positions */ 110019164Sgibbsindex_untagged_scb2: 110123925Sgibbs mov SCBPTR, A; /* 110219164Sgibbs * Select the SCB with this 110319164Sgibbs * target's information. 110419164Sgibbs */ 110523925Sgibbs mov SINDEX, DINDEX ret; 11069928Sgibbs 110723925Sgibbsadd_scb_to_free_list: 110823925Sgibbs mov SCB_NEXT, FREE_SCBH; 110923925Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 111023925Sgibbs mov FREE_SCBH, SCBPTR ret; 11114568Sgibbs 111223925Sgibbs.if ( SCB_PAGING ) 111319164Sgibbsget_free_or_disc_scb: 111423925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 111523925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 111619623Sgibbsreturn_error: 111723925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 111819623Sgibbsdequeue_disc_scb: 111923925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 112013177Sgibbs/* 112119164Sgibbs * If we have a residual, then we are in the middle of some I/O 112219164Sgibbs * and we have to send this SCB back up to the kernel so that the 112319164Sgibbs * saved data pointers and residual information isn't lost. 112419164Sgibbs */ 112523925Sgibbs test SCB_RESID_SGCNT,0xff jnz dma_up_scb; 112623925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb; 112723925Sgibbsdma_up_scb: 112823925Sgibbs mvi DMAPARAMS, FIFORESET; 112923925Sgibbs mov SCB_TAG call dma_scb; 113019164Sgibbsunlink_disc_scb: 113119623Sgibbs /* jmp instead of call since we want to return anyway */ 113223925Sgibbs mov SCBPTR jmp rem_scb_from_disc_list; 113319164Sgibbsdequeue_free_scb: 113423925Sgibbs mov SCBPTR, FREE_SCBH; 113523925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 11364568Sgibbs 113719164Sgibbsadd_scb_to_disc_list: 113813177Sgibbs/* 113919164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 114019164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 114119164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 114213177Sgibbs */ 114323925Sgibbs mvi SCB_PREV, SCB_LIST_NULL; 114423925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 114523925Sgibbs mov DISCONNECTED_SCBH, SCBPTR; 114623925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je return; 114723925Sgibbs mov SCBPTR,SCB_NEXT; 114823925Sgibbs mov SCB_PREV,DISCONNECTED_SCBH; 114923925Sgibbs mov SCBPTR,DISCONNECTED_SCBH ret; 115023925Sgibbs.endif 1151