aic7xxx.seq revision 24608
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 * 4013177Sgibbs *-M************************************************************************/ 414568Sgibbs 4223925Sgibbs#include <dev/aic7xxx/aic7xxx.reg> 4323925Sgibbs#include <scsi/scsi_message.h> 445647Sgibbs 4513177Sgibbs/* 4619164Sgibbs * A few words on the waiting SCB list: 4719164Sgibbs * After starting the selection hardware, we check for reconnecting targets 4813690Sgibbs * as well as for our selection to complete just in case the reselection wins 4913690Sgibbs * bus arbitration. The problem with this is that we must keep track of the 5013690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection 5113690Sgibbs * on just in case the reselection wins so that we can retry the selection at 5213690Sgibbs * a later time. This problem cannot be resolved by holding a single entry 5313690Sgibbs * in scratch ram since a reconnecting target can request sense and this will 5413690Sgibbs * create yet another SCB waiting for selection. The solution used here is to 5513690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list 5619164Sgibbs * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, 5719164Sgibbs * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to 5819164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged 5919164Sgibbs * command for which a second SCB has been queued. The sequencer will 6019164Sgibbs * automatically consume the entries. 6113177Sgibbs */ 624568Sgibbs 6313177Sgibbs/* 6414449Sgibbs * We assume that the kernel driver may reset us at any time, even in the 6514449Sgibbs * middle of a DMA, so clear DFCNTRL too. 6613177Sgibbs */ 6714449Sgibbsreset: 6823925Sgibbs clr SCSISIGO; /* De-assert BSY */ 6923925Sgibbs /* Always allow reselection */ 7023925Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; 7123925Sgibbs call clear_target_state; 728104Sgibbspoll_for_work: 7323925Sgibbs test SSTAT0,SELDI|SELDO jnz selection; 7423925Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 7523925Sgibbs.if ( TWIN_CHANNEL ) 7613177Sgibbs /* 7723925Sgibbs * Twin channel devices cannot handle things like SELTO 7823925Sgibbs * interrupts on the "background" channel. So, if we 7923925Sgibbs * are selecting, keep polling the current channel util 8023925Sgibbs * either a selection or reselection occurs. 8113177Sgibbs */ 8223925Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 8323925Sgibbs test SSTAT0,SELDI|SELDO jnz selection; 8423925Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 8523925Sgibbs xor SBLKCTL,SELBUSB; /* Toggle back */ 8623925Sgibbs.endif 8723925Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 8819164Sgibbstest_queue: 8919164Sgibbs /* Has the driver posted any work for us? */ 9023925Sgibbs mov A, QCNTMASK; 9123925Sgibbs test QINCNT,A jz poll_for_work; 924568Sgibbs 9313690Sgibbs/* 9413690Sgibbs * We have at least one queued SCB now and we don't have any 9519164Sgibbs * SCBs in the list of SCBs awaiting selection. If we have 9623925Sgibbs * any SCBs available for use, pull the tag from the QINFIFO 9719164Sgibbs * and get to work on it. 9813177Sgibbs */ 9923925Sgibbs.if ( SCB_PAGING ) 10023925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 10123925Sgibbs cmp SINDEX, SCB_LIST_NULL je poll_for_work; 10223925Sgibbs.endif 10319164Sgibbsdequeue_scb: 10423925Sgibbs mov CUR_SCBID,QINFIFO; 10523925Sgibbs.if !( SCB_PAGING ) 10619164Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 10723925Sgibbs mov SCBPTR, CUR_SCBID; 10823925Sgibbs.endif 10919164Sgibbsdma_queued_scb: 11019164Sgibbs/* 11119164Sgibbs * DMA the SCB from host ram into the current SCB location. 11219164Sgibbs */ 11323925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 11423925Sgibbs mov CUR_SCBID call dma_scb; 1154568Sgibbs 11613177Sgibbs/* 11713177Sgibbs * See if there is not already an active SCB for this target. This code 11813177Sgibbs * locks out on a per target basis instead of target/lun. Although this 11913177Sgibbs * is not ideal for devices that have multiple luns active at the same 12013177Sgibbs * time, it is faster than looping through all SCB's looking for active 12119921Sgibbs * commands. We also don't have enough spare SCB space for us to store the 12219164Sgibbs * SCBID of the currently busy transaction for each target/lun making it 12319164Sgibbs * impossible to link up the SCBs. 12413177Sgibbs */ 1255647Sgibbstest_busy: 12623925Sgibbs test SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb; 12723925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 12823925Sgibbs mov SAVED_SCBPTR, SCBPTR; 12923925Sgibbs mov SCB_TCL call index_untagged_scb; 13023925Sgibbs mov ARG_1, SINDIR; /* 13119164Sgibbs * ARG_1 should 13219164Sgibbs * now have the SCB ID of 13319164Sgibbs * any active, non-tagged, 13419164Sgibbs * command for this target. 13519164Sgibbs */ 13623925Sgibbs cmp ARG_1, SCB_LIST_NULL je make_busy; 13723925Sgibbs.if ( SCB_PAGING ) 13819164Sgibbs /* 13919164Sgibbs * Put this SCB back onto the free list. It 14019164Sgibbs * may be necessary to satisfy the search for 14119164Sgibbs * the active SCB. 14219164Sgibbs */ 14323925Sgibbs mov SCBPTR, SAVED_SCBPTR; 14423925Sgibbs call add_scb_to_free_list; 14519164Sgibbs /* Find the active SCB */ 14623925Sgibbs mov ALLZEROS call findSCB; 14719218Sgibbs /* 14819218Sgibbs * If we couldn't find it, tell the kernel. This should 14921947Sgibbs * never happen. 15019218Sgibbs */ 15123925Sgibbs cmp SINDEX, SCB_LIST_NULL jne paged_busy_link; 15223925Sgibbs mvi INTSTAT, NO_MATCH_BUSY; 15319218Sgibbspaged_busy_link: 15419164Sgibbs /* Link us in */ 15523925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 15619164Sgibbs /* Put it back on the disconnected list */ 15723925Sgibbs call add_scb_to_disc_list; 15823925Sgibbs mvi SEQCTL, FASTMODE; 15923925Sgibbs jmp poll_for_work; 16023925Sgibbs.endif 16119164Sgibbssimple_busy_link: 16223925Sgibbs mov SCBPTR, ARG_1; 16323925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 16423925Sgibbs mvi SEQCTL, FASTMODE; 16523925Sgibbs jmp poll_for_work; 16619164Sgibbsmake_busy: 16723925Sgibbs mov DINDIR, CUR_SCBID; 16823925Sgibbs mov SCBPTR, SAVED_SCBPTR; 16923925Sgibbs mvi SEQCTL, FASTMODE; 1704568Sgibbs 1715326Sgibbsstart_scb: 17219164Sgibbs /* 17319164Sgibbs * Place us on the waiting list in case our selection 17419164Sgibbs * doesn't win during bus arbitration. 17519164Sgibbs */ 17623925Sgibbs mov SCB_NEXT,WAITING_SCBH; 17723925Sgibbs mov WAITING_SCBH, SCBPTR; 17823925Sgibbsstart_waiting: 17923925Sgibbs /* 18023925Sgibbs * Pull the first entry off of the waiting SCB list 18123925Sgibbs * We don't have to "test_busy" because only transactions that 18223925Sgibbs * have passed that test can be in the WAITING_SCB list. 18323925Sgibbs */ 18423925Sgibbs mov SCBPTR, WAITING_SCBH; 18523925Sgibbs call start_selection; 18623925Sgibbs jmp poll_for_work; 1878104Sgibbs 18823925Sgibbsstart_selection: 18923991Sgibbs.if ( TWIN_CHANNEL ) 19023925Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */ 19123925Sgibbs and A,SELBUSB,SCB_TCL; /* Get new channel bit */ 19223925Sgibbs or SINDEX,A; 19323925Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 19423991Sgibbs.endif 19523925Sgibbsinitialize_scsiid: 19623925Sgibbs and A, TID, SCB_TCL; /* Get target ID */ 19723925Sgibbs and SCSIID, OID; /* Clear old target */ 19823925Sgibbs or SCSIID, A; 19923925Sgibbs mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; 20013177Sgibbs/* 20123925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 20223925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 20313177Sgibbs */ 20423925Sgibbsselection: 20523925Sgibbs test SSTAT0, SELDI jz select; 20623925Sgibbsreselect: 20723925Sgibbs clr MSG_LEN; /* Don't have anything in the mesg buffer */ 20823925Sgibbs mvi CLRSINT0, CLRSELDI; 20923925Sgibbs /* XXX test for and handle ONE BIT condition */ 21023925Sgibbs and SAVED_TCL, SELID_MASK, SELID; 21123925Sgibbs or SEQ_FLAGS,RESELECTED; 21223925Sgibbs jmp select2; 2134568Sgibbs 21413177Sgibbs/* 21523925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 21623925Sgibbs * list. This is achieved by simply moving our "next" pointer into 21723925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 21823925Sgibbs * SCB is used, so don't bother with it now. 21923925Sgibbs */ 22023925Sgibbsselect: 22123925Sgibbs /* Turn off the selection hardware */ 22223925Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* 22323925Sgibbs * ATN on parity errors 22423925Sgibbs * for "in" phases 22523925Sgibbs */ 22623925Sgibbs mvi CLRSINT0, CLRSELDO; 22723925Sgibbs mov SCBPTR, WAITING_SCBH; 22823925Sgibbs mov WAITING_SCBH,SCB_NEXT; 22923925Sgibbs mov SAVED_TCL, SCB_TCL; 23023925Sgibbs/* 23113177Sgibbs * As soon as we get a successful selection, the target should go 23213177Sgibbs * into the message out phase since we have ATN asserted. Prepare 23313177Sgibbs * the message to send. 23413177Sgibbs * 23513177Sgibbs * Messages are stored in scratch RAM starting with a length byte 23613177Sgibbs * followed by the message itself. 23713177Sgibbs */ 2388567Sdg 23913177Sgibbsmk_identify: 24023925Sgibbs and MSG_OUT,0x7,SCB_TCL; /* lun */ 24123925Sgibbs and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ 24223925Sgibbs or MSG_OUT,A; /* or in disconnect privledge */ 24323925Sgibbs or MSG_OUT,MSG_IDENTIFYFLAG; 24423925Sgibbs mvi MSG_LEN, 1; 2454568Sgibbs 24613177Sgibbs/* 24715328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 24815328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 24913177Sgibbs */ 2506608Sgibbsmk_tag: 25123925Sgibbs test SCB_CONTROL,TAG_ENB jz mk_message; 25223925Sgibbs and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 25323925Sgibbs mov MSG_OUT[2],SCB_TAG; 25423925Sgibbs add MSG_LEN,2; /* update message length */ 2556608Sgibbs 25618762Sgibbs/* 25718762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer 25818762Sgibbs * if it asks. 25918762Sgibbs */ 26018762Sgibbsmk_message: 26123925Sgibbs test SCB_CONTROL,MK_MESSAGE jz select2; 26223925Sgibbs mvi INTSTAT,AWAITING_MSG; 2636608Sgibbs 2648104Sgibbsselect2: 26523925Sgibbs mvi CLRSINT1,CLRBUSFREE; 26623925Sgibbs or SIMODE1, ENBUSFREE; /* 26721947Sgibbs * We aren't expecting a 26821947Sgibbs * bus free, so interrupt 26921947Sgibbs * the kernel driver if it 27021947Sgibbs * happens. 27121947Sgibbs */ 27213177Sgibbs/* 27322451Sgibbs * Initialize Ultra mode setting and clear the SCSI channel. 27422451Sgibbs */ 27523925Sgibbs or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN; 27623925Sgibbs.if ( ULTRA ) 27722451Sgibbsultra: 27823925Sgibbs mvi SINDEX, ULTRA_ENB+1; 27923925Sgibbs test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ 28023925Sgibbs dec SINDEX; 28122451Sgibbsultra_2: 28223925Sgibbs mov FUNCTION1,SAVED_TCL; 28323925Sgibbs mov A,FUNCTION1; 28423925Sgibbs test SINDIR, A jz ndx_dtr; 28523925Sgibbs or SXFRCTL0, FAST20; 28623925Sgibbs.endif 28722451Sgibbs 28822451Sgibbs/* 28913177Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 29019164Sgibbs * The SCSIRATE settings for each target are stored in an array 29119164Sgibbs * based at TARG_SCRATCH. 29213177Sgibbs */ 29319164Sgibbsndx_dtr: 29423925Sgibbs shr A,4,SAVED_TCL; 29523925Sgibbs test SBLKCTL,SELBUSB jz ndx_dtr_2; 29623925Sgibbs or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */ 29723925Sgibbs or A,0x08; /* Channel B entries add 8 */ 29819164Sgibbsndx_dtr_2: 29923925Sgibbs add SINDEX,TARG_SCRATCH,A; 30023925Sgibbs mov SCSIRATE,SINDIR; 30113177Sgibbs 30215843Sgibbs 30313177Sgibbs/* 30413177Sgibbs * Main loop for information transfer phases. If BSY is false, then 30513177Sgibbs * we have a bus free condition, expected or not. Otherwise, wait 30613177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O 30713177Sgibbs * for the bus phase. 30813177Sgibbs * 30913177Sgibbs */ 3104568SgibbsITloop: 31123925Sgibbs test SSTAT1,REQINIT jz ITloop; 3124568Sgibbs 31323925Sgibbs and A,PHASE_MASK,SCSISIGI; 31423925Sgibbs mov LASTPHASE,A; 31523925Sgibbs mov SCSISIGO,A; 3164568Sgibbs 31723925Sgibbs cmp ALLZEROS,A je p_dataout; 31823925Sgibbs cmp A,P_DATAIN je p_datain; 31923925Sgibbs cmp A,P_COMMAND je p_command; 32023925Sgibbs cmp A,P_MESGOUT je p_mesgout; 32123925Sgibbs cmp A,P_STATUS je p_status; 32223925Sgibbs cmp A,P_MESGIN je p_mesgin; 3234568Sgibbs 32423925Sgibbs mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ 32523925Sgibbs jmp ITloop; /* Try reading the bus again. */ 3264568Sgibbs 32723925Sgibbsawait_busfree: 32823925Sgibbs and SIMODE1, ~ENBUSFREE; 32923925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 33023925Sgibbs call clear_target_state; 33123925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 33223925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 33323925Sgibbs mvi INTSTAT, BAD_PHASE; 33423925Sgibbs 33523925Sgibbsclear_target_state: 33623925Sgibbs clr DFCNTRL; 33723925Sgibbs clr SCSIRATE; /* 33823925Sgibbs * We don't know the target we will 33923925Sgibbs * connect to, so default to narrow 34023925Sgibbs * transfers to avoid parity problems. 34123925Sgibbs */ 34223925Sgibbs and SXFRCTL0, ~FAST20; 34323925Sgibbs mvi LASTPHASE, P_BUSFREE; 34423925Sgibbs /* clear target specific flags */ 34523925Sgibbs and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret; 34623925Sgibbs 3474568Sgibbsp_dataout: 34823925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET; 34923925Sgibbs jmp data_phase_init; 3504568Sgibbs 35113177Sgibbs/* 35213177Sgibbs * If we re-enter the data phase after going through another phase, the 35313177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 35413177Sgibbs */ 3559928Sgibbsdata_phase_reinit: 35623925Sgibbs mvi DINDEX, STCNT; 35723925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 35823925Sgibbs jmp data_phase_loop; 3594568Sgibbs 3609928Sgibbsp_datain: 36123925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 3629928Sgibbsdata_phase_init: 36323925Sgibbs call assert; /* 36419164Sgibbs * Ensure entering a data 36519164Sgibbs * phase is okay - seen identify, etc. 36619164Sgibbs */ 3675775Sgibbs 36823925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 3694568Sgibbs 37019164Sgibbs /* 37119164Sgibbs * Initialize the DMA address and counter from the SCB. 37219164Sgibbs * Also set SG_COUNT and SG_NEXT in memory since we cannot 37319164Sgibbs * modify the values in the SCB itself until we see a 37419164Sgibbs * save data pointers message. 37519164Sgibbs */ 37623925Sgibbs mvi DINDEX, HADDR; 37723925Sgibbs mvi SCB_DATAPTR call bcopy_7; 37819164Sgibbs 37923925Sgibbs call set_stcnt_from_hcnt; 38019164Sgibbs 38123925Sgibbs mov SG_COUNT,SCB_SGCOUNT; 38219164Sgibbs 38323925Sgibbs mvi DINDEX, SG_NEXT; 38423925Sgibbs mvi SCB_SGPTR call bcopy_4; 38519164Sgibbs 3869928Sgibbsdata_phase_loop: 38716260Sgibbs/* Guard against overruns */ 38823925Sgibbs test SG_COUNT, 0xff jnz data_phase_inbounds; 38916260Sgibbs/* 39016260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to 39116260Sgibbs * 16meg and let the target run until it changes phase. 39216260Sgibbs * When the transfer completes, notify the host that we 39316260Sgibbs * had an overrun. 39416260Sgibbs */ 39523925Sgibbs or SXFRCTL1,BITBUCKET; 39623925Sgibbs mvi HCNT[0], 0xff; 39723925Sgibbs mvi HCNT[1], 0xff; 39823925Sgibbs mvi HCNT[2], 0xff; 39923925Sgibbs call set_stcnt_from_hcnt; 40016260Sgibbs 40116260Sgibbsdata_phase_inbounds: 40219164Sgibbs/* If we are the last SG block, ensure wideodd is off. */ 40323925Sgibbs cmp SG_COUNT,0x01 jne data_phase_wideodd; 40423925Sgibbs and DMAPARAMS, ~WIDEODD; 4059928Sgibbsdata_phase_wideodd: 40623925Sgibbs mov DMAPARAMS call dma; 4074568Sgibbs 40816260Sgibbs/* Go tell the host about any overruns */ 40923925Sgibbs test SXFRCTL1,BITBUCKET jnz data_phase_overrun; 41016260Sgibbs 41122451Sgibbs/* Exit if we had an underrun. dma clears SINDEX in this case. */ 41223925Sgibbs test SINDEX,0xff jz data_phase_finish; 4137532Sgibbs 41413177Sgibbs/* 41513177Sgibbs * Advance the scatter-gather pointers if needed 41613177Sgibbs */ 4179928Sgibbssg_advance: 41823925Sgibbs dec SG_COUNT; /* one less segment to go */ 4194568Sgibbs 42023925Sgibbs test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ 4214568Sgibbs 42223925Sgibbs clr A; /* add sizeof(struct scatter) */ 42323925Sgibbs add SG_NEXT[0],SG_SIZEOF; 42423925Sgibbs adc SG_NEXT[1],A; 4254568Sgibbs 42613177Sgibbs/* 42713177Sgibbs * Load a struct scatter and set up the data address and length. 42813177Sgibbs * If the working value of the SG count is nonzero, then 42913177Sgibbs * we need to load a new set of values. 43013177Sgibbs * 43115328Sgibbs * This, like all DMA's, assumes little-endian host data storage. 43213177Sgibbs */ 4339928Sgibbssg_load: 43423925Sgibbs mvi DINDEX, HADDR; 43523925Sgibbs mvi SG_NEXT call bcopy_4; 4364568Sgibbs 43723925Sgibbs mvi HCNT[0],SG_SIZEOF; 43823925Sgibbs clr HCNT[1]; 43923925Sgibbs clr HCNT[2]; 44022568Sgibbs 44123925Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 4429928Sgibbs 44323925Sgibbs call dma_finish; 4449928Sgibbs 44513177Sgibbs/* 44613177Sgibbs * Copy data from FIFO into SCB data pointer and data count. This assumes 44719164Sgibbs * that the SG segments are of the form: 44813177Sgibbs * 44913177Sgibbs * struct ahc_dma_seg { 45019164Sgibbs * u_int32_t addr; four bytes, little-endian order 45119164Sgibbs * u_int32_t len; four bytes, little endian order 45213177Sgibbs * }; 45313177Sgibbs */ 45423925Sgibbs mvi HADDR call dfdat_in_7; 4559928Sgibbs 45613177Sgibbs/* Load STCNT as well. It is a mirror of HCNT */ 45723925Sgibbs call set_stcnt_from_hcnt; 45823925Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 4594568Sgibbs 4609928Sgibbsdata_phase_finish: 46113177Sgibbs/* 46213177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB 46313177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 46413177Sgibbs * were transferred on the SCSI (as opposed to the host) bus. 46513177Sgibbs */ 46623925Sgibbs mov SCB_RESID_DCNT[0],STCNT[0]; 46723925Sgibbs mov SCB_RESID_DCNT[1],STCNT[1]; 46823925Sgibbs mov SCB_RESID_DCNT[2],STCNT[2]; 46923925Sgibbs mov SCB_RESID_SGCNT, SG_COUNT; 47022568Sgibbs 47122568Sgibbs /* We have seen a data phase */ 47223925Sgibbs or SEQ_FLAGS, DPHASE; 47322568Sgibbs 47423925Sgibbs jmp ITloop; 4754568Sgibbs 47616260Sgibbsdata_phase_overrun: 47713177Sgibbs/* 47816260Sgibbs * Turn off BITBUCKET mode and notify the host 47916260Sgibbs */ 48023925Sgibbs and SXFRCTL1, ~BITBUCKET; 48123925Sgibbs mvi INTSTAT,DATA_OVERRUN; 48223925Sgibbs jmp ITloop; 48316260Sgibbs 48416260Sgibbs/* 48515328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 48613177Sgibbs */ 4874568Sgibbsp_command: 48823925Sgibbs call assert; 4894568Sgibbs 49013177Sgibbs/* 49115328Sgibbs * Load HADDR and HCNT. 49213177Sgibbs */ 49323925Sgibbs mvi DINDEX, HADDR; 49423925Sgibbs mvi SCB_CMDPTR call bcopy_5; 49523925Sgibbs clr HCNT[1]; 49623925Sgibbs clr HCNT[2]; 4974568Sgibbs 49823925Sgibbs call set_stcnt_from_hcnt; 4994568Sgibbs 50023925Sgibbs mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; 50123925Sgibbs jmp ITloop; 5024568Sgibbs 50313177Sgibbs/* 50413177Sgibbs * Status phase. Wait for the data byte to appear, then read it 50513177Sgibbs * and store it into the SCB. 50613177Sgibbs */ 5074568Sgibbsp_status: 50823925Sgibbs call assert; 50919803Sgibbs 51023925Sgibbs mov SCB_TARGET_STATUS, SCSIDATL; 51123925Sgibbs jmp ITloop; 5124568Sgibbs 51313177Sgibbs/* 51415328Sgibbs * Message out phase. If there is not an active message, but the target 51513177Sgibbs * took us into this phase anyway, build a no-op message and send it. 51613177Sgibbs */ 5174568Sgibbsp_mesgout: 51823925Sgibbs test MSG_LEN, 0xff jnz p_mesgout_start; 51923925Sgibbs mvi MSG_NOOP call mk_mesg; /* build NOP message */ 52013177Sgibbsp_mesgout_start: 52113177Sgibbs/* 52223925Sgibbs * Set up automatic PIO transfer from MSG_OUT. Bit 3 in 52313177Sgibbs * SXFRCTL0 (SPIOEN) is already on. 52413177Sgibbs */ 52523925Sgibbs mvi SINDEX,MSG_OUT; 52623925Sgibbs mov DINDEX,MSG_LEN; 5274568Sgibbs 52813177Sgibbs/* 52913177Sgibbs * When target asks for a byte, drop ATN if it's the last one in 53013177Sgibbs * the message. Otherwise, keep going until the message is exhausted. 53123925Sgibbs * ATN must be dropped *at least* 90ns before we ack the last byte, so 53223925Sgibbs * the code is aranged to execute two instructions before the byte is 53323925Sgibbs * transferred to give a good margin of safety 53413177Sgibbs * 53513177Sgibbs * Keep an eye out for a phase change, in case the target issues 53613177Sgibbs * a MESSAGE REJECT. 53713177Sgibbs */ 53813177Sgibbsp_mesgout_loop: 53923925Sgibbs test SSTAT1, REQINIT jz p_mesgout_loop; 54023925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 54123925Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 54213177Sgibbs/* 54313177Sgibbs * If the next bus phase after ATN drops is a message out, it means 54413177Sgibbs * that the target is requesting that the last message(s) be resent. 54513177Sgibbs */ 54623925Sgibbsp_mesgout_dropatn: 54723925Sgibbs cmp DINDEX,1 jne p_mesgout_testretry;/* last byte? */ 54823925Sgibbs mvi CLRSINT1,CLRATNO; /* drop ATN */ 54919921Sgibbsp_mesgout_testretry: 55023925Sgibbs test DINDEX,0xff jnz p_mesgout_outb; 55123925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 55223925Sgibbs jmp p_mesgout_start; 55319906Sgibbsp_mesgout_outb: 55423925Sgibbs dec DINDEX; 55523925Sgibbs mov SCSIDATL,SINDIR; 55623925Sgibbs jmp p_mesgout_loop; 5574568Sgibbs 55819906Sgibbsp_mesgout_done: 55923925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 56023925Sgibbs clr MSG_LEN; /* no active msg */ 56123925Sgibbs jmp ITloop; 5624568Sgibbs 56313177Sgibbs/* 56413177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 56513177Sgibbs */ 5664568Sgibbsp_mesgin: 56723925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 56823925Sgibbs mov REJBYTE,A; /* save it for the driver */ 5694568Sgibbs 57023925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 57123925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 57223925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 57323925Sgibbs cmp ALLZEROS,A je mesgin_complete; 57423925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 57523925Sgibbs cmp A,MSG_EXTENDED je mesgin_extended; 57623925Sgibbs cmp A,MSG_MESSAGE_REJECT je mesgin_reject; 57723925Sgibbs cmp A,MSG_NOOP je mesgin_done; 5784568Sgibbs 5799954Sgibbsrej_mesgin: 58013177Sgibbs/* 58119164Sgibbs * We have no idea what this message in is, so we issue a message reject 58219164Sgibbs * and hope for the best. In any case, rejection should be a rare 58319164Sgibbs * occurrence - signal the driver when it happens. 58413177Sgibbs */ 58523925Sgibbs mvi INTSTAT,SEND_REJECT; /* let driver know */ 5869954Sgibbs 58723925Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 5889954Sgibbs 5899954Sgibbsmesgin_done: 59023925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 59123925Sgibbs jmp ITloop; 5929954Sgibbs 5939954Sgibbs 5949954Sgibbsmesgin_complete: 59513177Sgibbs/* 59619164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, 59719164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 59819164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0). In 59919164Sgibbs * either of these conditions, we upload the SCB back to the host so it can 60019164Sgibbs * process this information. In the case of a non zero status byte, we 60119164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 60219164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 60319164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set 60419164Sgibbs * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload 60519164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list. 60619164Sgibbs * If the kernel driver does not wish to request sense, it need only clear 60719164Sgibbs * RETURN_1, and the command is allowed to complete normally. We don't bother 60819164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra 60919164Sgibbs * work in the kernel driver to ensure that the entry was removed before the 61019164Sgibbs * command complete code tried processing it. 61113177Sgibbs */ 61219164Sgibbs 61313177Sgibbs/* 61419164Sgibbs * First check for residuals 61513177Sgibbs */ 61623925Sgibbs test SCB_RESID_SGCNT,0xff jnz upload_scb; 61723925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */ 61819164Sgibbsupload_scb: 61923925Sgibbs mvi DMAPARAMS, FIFORESET; 62023925Sgibbs mov SCB_TAG call dma_scb; 6217532Sgibbscheck_status: 62223925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */ 62323925Sgibbs mvi INTSTAT,BAD_STATUS; /* let driver know */ 62423925Sgibbs cmp RETURN_1, SEND_SENSE jne status_ok; 62519164Sgibbs /* This SCB becomes the next to execute as it will retrieve sense */ 62623925Sgibbs mov SCB_LINKED_NEXT, SCB_TAG; 62723925Sgibbs jmp dma_next_scb; 6285326Sgibbs 6294568Sgibbsstatus_ok: 63013177Sgibbs/* First, mark this target as free. */ 63123925Sgibbs test SCB_CONTROL,TAG_ENB jnz complete; /* 63213177Sgibbs * Tagged commands 63313177Sgibbs * don't busy the 63413177Sgibbs * target. 63513177Sgibbs */ 63623925Sgibbs mov SAVED_SCBPTR, SCBPTR; 63723925Sgibbs mov SAVED_LINKPTR, SCB_LINKED_NEXT; 63823925Sgibbs mov SCB_TCL call index_untagged_scb; 63923925Sgibbs mov DINDIR, SAVED_LINKPTR; 64023925Sgibbs mov SCBPTR, SAVED_SCBPTR; 6415326Sgibbs 6425326Sgibbscomplete: 64319164Sgibbs /* Post the SCB and issue an interrupt */ 64423925Sgibbs mov QOUTFIFO,SCB_TAG; 64523925Sgibbs mvi INTSTAT,CMDCMPLT; 64623925Sgibbs test SCB_CONTROL, ABORT_SCB jz dma_next_scb; 64723925Sgibbs mvi INTSTAT, ABORT_CMDCMPLT; 64819164Sgibbs 64919164Sgibbsdma_next_scb: 65023925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list; 65123925Sgibbs.if !( SCB_PAGING ) 65219164Sgibbs /* Only DMA on top of ourselves if we are the SCB to download */ 65323925Sgibbs mov A, SCB_LINKED_NEXT; 65423925Sgibbs cmp SCB_TAG, A je dma_next_scb2; 65523925Sgibbs mov SCBPTR, A; 65623925Sgibbs jmp add_to_waiting_list; 65723925Sgibbs.endif 65819164Sgibbsdma_next_scb2: 65923925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 66023925Sgibbs mov SCB_LINKED_NEXT call dma_scb; 66119164Sgibbsadd_to_waiting_list: 66223925Sgibbs mov SCB_NEXT,WAITING_SCBH; 66323925Sgibbs mov WAITING_SCBH, SCBPTR; 66423925Sgibbs /* 66523925Sgibbs * Prepare our selection hardware before the busfree so we have a 66623925Sgibbs * high probability of winning arbitration. 66723925Sgibbs */ 66823925Sgibbs call start_selection; 66923925Sgibbs jmp await_busfree; 67019921Sgibbsadd_to_free_list: 67123925Sgibbs call add_scb_to_free_list; 67223925Sgibbs jmp await_busfree; 6734568Sgibbs 67413177Sgibbs/* 67518762Sgibbs * Is it an extended message? Copy the message to our message buffer and 67618762Sgibbs * notify the host. The host will tell us whether to reject this message, 67718762Sgibbs * respond to it with the message that the host placed in our message buffer, 67818762Sgibbs * or simply to do nothing. 67913177Sgibbs */ 6809954Sgibbsmesgin_extended: 68123925Sgibbs mvi MSGIN_EXT_LEN call inb_next; 68223925Sgibbs mov A, MSGIN_EXT_LEN; 68318762Sgibbsmesgin_extended_loop: 68423925Sgibbs mov DINDEX call inb_next; 68523925Sgibbs dec A; 68623925Sgibbs cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test; 68723925Sgibbs dec DINDEX; /* dump by repeatedly filling the last byte */ 68819164Sgibbsmesgin_extended_loop_test: 68923925Sgibbs test A, 0xFF jnz mesgin_extended_loop; 69018762Sgibbsmesgin_extended_intr: 69123925Sgibbs mvi INTSTAT,EXTENDED_MSG; /* let driver know */ 69223925Sgibbs cmp RETURN_1,SEND_REJ je rej_mesgin; 69323925Sgibbs cmp RETURN_1,SEND_MSG jne mesgin_done; 69418762Sgibbs/* The kernel has setup a message to be sent */ 69523925Sgibbs or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */ 69623925Sgibbs jmp mesgin_done; 6975562Sgibbs 69813177Sgibbs/* 69913177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 70013177Sgibbs * and await the bus going free. 70113177Sgibbs */ 7029954Sgibbsmesgin_disconnect: 70323925Sgibbs or SCB_CONTROL,DISCONNECTED; 70423925Sgibbs.if ( SCB_PAGING ) 70523925Sgibbs call add_scb_to_disc_list; 70623925Sgibbs.endif 70723925Sgibbs jmp await_busfree; 70819164Sgibbs 70915328Sgibbs/* 71019164Sgibbs * Save data pointers message: 71119164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 71219164Sgibbs * only if we've actually been into a data phase to change them. This 71319164Sgibbs * protects against bogus data in scratch ram and the residual counts 71419164Sgibbs * since they are only initialized when we go into data_in or data_out. 71515328Sgibbs */ 71619164Sgibbsmesgin_sdptrs: 71723925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 71823925Sgibbs mov SCB_SGCOUNT,SG_COUNT; 7194568Sgibbs 72019164Sgibbs /* The SCB SGPTR becomes the next one we'll download */ 72123925Sgibbs mvi DINDEX, SCB_SGPTR; 72223925Sgibbs mvi SG_NEXT call bcopy_4; 72319164Sgibbs 72419164Sgibbs /* The SCB DATAPTR0 becomes the current SHADDR */ 72523925Sgibbs mvi DINDEX, SCB_DATAPTR; 72623925Sgibbs mvi SHADDR call bcopy_4; 72719164Sgibbs 72813177Sgibbs/* 72919164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer. 73013177Sgibbs */ 73123925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 73219164Sgibbs 73323925Sgibbs jmp mesgin_done; 7344568Sgibbs 73513177Sgibbs/* 73613177Sgibbs * Restore pointers message? Data pointers are recopied from the 73713177Sgibbs * SCB anytime we enter a data phase for the first time, so all 73813177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 73913177Sgibbs * code do the rest. 74013177Sgibbs */ 7419954Sgibbsmesgin_rdptrs: 74223925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 74323925Sgibbs * We'll reload them 74413177Sgibbs * the next time through 74523925Sgibbs * the dataphase. 74613177Sgibbs */ 74723925Sgibbs jmp mesgin_done; 7484568Sgibbs 74913177Sgibbs/* 75013177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 75113177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 75213177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 75313177Sgibbs */ 7549954Sgibbsmesgin_identify: 75523925Sgibbs test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/ 75623925Sgibbs and A,0x07; /* lun in lower three bits */ 75723925Sgibbs or SAVED_TCL,A; /* SAVED_TCL should be complete now */ 75823925Sgibbs mov SAVED_TCL call index_untagged_scb; 75923925Sgibbs mov ARG_1, SINDIR; 76024608Sgibbs.if ( SCB_PAGING ) 76123925Sgibbs cmp ARG_1,SCB_LIST_NULL jne use_findSCB; 76224608Sgibbs.else 76324608Sgibbs cmp ARG_1,SCB_LIST_NULL je snoop_tag; 76424608Sgibbs /* Directly index the SCB */ 76524608Sgibbs mov SCBPTR,ARG_1; 76624608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 76724608Sgibbs jmp setup_SCB; 76824608Sgibbs.endif 76913177Sgibbs/* 77013177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 77123168Sgibbs * If we get one, we use the tag returned to find the proper 77215328Sgibbs * SCB. With SCB paging, this requires using findSCB for both tagged 77315328Sgibbs * and non-tagged transactions since the SCB may exist in any slot. 77415328Sgibbs * If we're not using SCB paging, we can use the tag as the direct 77515328Sgibbs * index to the SCB. 77613177Sgibbs */ 77724608Sgibbssnoop_tag: 77823925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 77913177Sgibbssnoop_tag_loop: 78023925Sgibbs test SSTAT1,REQINIT jz snoop_tag_loop; 78123925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 78223925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 78323925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 7846608Sgibbsget_tag: 78523925Sgibbs or SEQ_FLAGS, TAGGED_SCB; 78623925Sgibbs mvi ARG_1 call inb_next; /* tag value */ 78713177Sgibbs/* 78813177Sgibbs * See if the tag is in range. The tag is < SCBCOUNT if we add 78913177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is 79013177Sgibbs * no carry. 79113177Sgibbs */ 79223925Sgibbs mov A,COMP_SCBCOUNT; 79323925Sgibbs add SINDEX,A,ARG_1; 79423925Sgibbs jc not_found; 79513177Sgibbs 79623925Sgibbs.if ! ( SCB_PAGING ) 79724608Sgibbsindex_by_tag: 79824608Sgibbs mov SCBPTR,ARG_1; 79924608Sgibbs mov A, SAVED_TCL; 80024608Sgibbs cmp SCB_TCL,A jne not_found; 80124608Sgibbs test SCB_CONTROL,TAG_ENB jz not_found; 80224608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 80324608Sgibbs.else 80413177Sgibbs/* 80515328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction 80613177Sgibbs * to the reconnecting target. 80713177Sgibbs */ 80815328Sgibbsuse_findSCB: 80923925Sgibbs mov ALLZEROS call findSCB; /* Have to search */ 81023925Sgibbs cmp SINDEX, SCB_LIST_NULL je not_found; 81124608Sgibbs.endif 81215328Sgibbssetup_SCB: 81323925Sgibbs and SCB_CONTROL,~DISCONNECTED; 81423925Sgibbs or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 81523925Sgibbs jmp mesgin_done; 81615328Sgibbs 81719218Sgibbsnot_found: 81823925Sgibbs mvi INTSTAT, NO_MATCH; 81919218Sgibbssend_abort_msg: 82023925Sgibbs test SEQ_FLAGS, TAGGED_SCB jnz send_abort_tag_msg; 82123925Sgibbs mvi MSG_ABORT call mk_mesg; 82223925Sgibbs jmp send_abort_done; 82323168Sgibbssend_abort_tag_msg: 82423925Sgibbs mvi MSG_ABORT_TAG call mk_mesg; /* ABORT TAG message */ 82523168Sgibbssend_abort_done: 82623168Sgibbs /* If we don't have the tag ID yet, we're "looking ahead" at state 82723168Sgibbs * that hasn't been processed, so don't ack. 82823168Sgibbs */ 82923925Sgibbs cmp ARG_1, SCB_LIST_NULL je ITloop; 83023925Sgibbs jmp mesgin_done; 8316608Sgibbs 83213177Sgibbs/* 83313177Sgibbs * Message reject? Let the kernel driver handle this. If we have an 83413177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 83513177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 83613177Sgibbs * it since we have no clue what it pertains to. 83713177Sgibbs */ 8389954Sgibbsmesgin_reject: 83923925Sgibbs mvi INTSTAT, REJECT_MSG; 84023925Sgibbs jmp mesgin_done; 8415562Sgibbs 84213177Sgibbs/* 84313177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ] 84413177Sgibbs */ 8454568Sgibbs 84613177Sgibbs/* 84713177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX 84813177Sgibbs * if there is no active message already. SINDEX is returned intact. 84913177Sgibbs */ 8504568Sgibbsmk_mesg: 85123925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 85223925Sgibbs test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */ 85313177Sgibbs 85413177Sgibbs /* 85513177Sgibbs * Hmmm. For some reason the mesg buffer is in use. 85613177Sgibbs * Tell the driver. It should look at SINDEX to find 85713177Sgibbs * out what we wanted to use the buffer for and resolve 85813177Sgibbs * the conflict. 85913177Sgibbs */ 86023925Sgibbs mvi SEQCTL,FASTMODE; 86123925Sgibbs mvi INTSTAT,MSG_BUFFER_BUSY; 8624568Sgibbs 8634568Sgibbsmk_mesg1: 86423925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 86523925Sgibbs mvi MSG_LEN,1; /* length = 1 */ 86623925Sgibbs mov MSG_OUT,SINDEX; /* 1-byte message */ 86723925Sgibbs mvi SEQCTL,FASTMODE ret; 8684568Sgibbs 86913177Sgibbs/* 87013177Sgibbs * Functions to read data in Automatic PIO mode. 87113177Sgibbs * 87213177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 87313177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 87413177Sgibbs * latched (the usual way), then read the data byte directly off the bus 87513177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 87613177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 87713177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 87813177Sgibbs * we send our ACK. 87913177Sgibbs * 88013177Sgibbs * The assumption here is that these are called in a particular sequence, 88113177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 88213177Sgibbs * use the same calling convention as inb. 88313177Sgibbs */ 88413177Sgibbs 88513177Sgibbsinb_next: 88623925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 88713360Sgibbsinb_next_wait: 88821947Sgibbs /* 88921947Sgibbs * If there is a parity error, wait for the kernel to 89021947Sgibbs * see the interrupt and prepare our message response 89121947Sgibbs * before continuing. 89221947Sgibbs */ 89323925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 89423925Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait; 89523925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 89623925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 89719623Sgibbsinb_first: 89823925Sgibbs mov DINDEX,SINDEX; 89923925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 90013177Sgibbsinb_last: 90123925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 9024568Sgibbs 90313177Sgibbsmesgin_phasemis: 90413177Sgibbs/* 90513177Sgibbs * We expected to receive another byte, but the target changed phase 90613177Sgibbs */ 90723925Sgibbs mvi INTSTAT, MSGIN_PHASEMIS; 90823925Sgibbs jmp ITloop; 9094568Sgibbs 91013177Sgibbs/* 91113177Sgibbs * DMA data transfer. HADDR and HCNT must be loaded first, and 91213177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for 91313177Sgibbs * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 91413177Sgibbs * during initialization. 91513177Sgibbs */ 9164568Sgibbsdma: 91723925Sgibbs mov DFCNTRL,SINDEX; 91822568Sgibbsdma_loop: 91923925Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 92023925Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 92122568Sgibbsdma_phasemis: 92223925Sgibbs test SSTAT0,SDONE jnz dma_checkfifo; 92323925Sgibbs mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ 9244568Sgibbs 92513177Sgibbs/* 92613177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or 92713177Sgibbs * the target changes the phase (in light of this, it makes sense that 92813177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 92913177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto- 93013177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty 93113177Sgibbs * status. 93213177Sgibbs */ 93322568Sgibbsdma_checkfifo: 93423925Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 93522568Sgibbsdma_fifoflush: 93623925Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 9374568Sgibbs 93822568Sgibbsdma_fifoempty: 93922568Sgibbs /* Don't clobber an inprogress host data transfer */ 94023925Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 94113177Sgibbs/* 94213177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 94313177Sgibbs * actually off first lest we get an ILLSADDR. 94413177Sgibbs */ 94522568Sgibbsdma_dmadone: 94623925Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 94722568Sgibbsdma_halt: 94823925Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 94918762Sgibbsreturn: 95023925Sgibbs ret; 9514568Sgibbs 95213177Sgibbs/* 95313177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 95413177Sgibbs * message. 95513177Sgibbs */ 9564568Sgibbsassert: 95723925Sgibbs test SEQ_FLAGS,RESELECTED jz return; /* reselected? */ 95823925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 9594568Sgibbs 96023925Sgibbs mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ 9614568Sgibbs 96224608Sgibbs.if ( SCB_PAGING ) 96313177Sgibbs/* 96419218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) 96519218Sgibbs * or by the SCBIDn ARG_1. The search begins at the SCB index passed in 96619218Sgibbs * via SINDEX. If the SCB cannot be found, SINDEX will be SCB_LIST_NULL, 96719218Sgibbs * otherwise, SCBPTR is set to the proper SCB. 96813177Sgibbs */ 9694568SgibbsfindSCB: 97023925Sgibbs mov SCBPTR,SINDEX; /* switch to next SCB */ 97123925Sgibbs mov A, ARG_1; /* Tag passed in ARG_1 */ 97223925Sgibbs cmp SCB_TAG,A jne findSCB_loop; 97323925Sgibbs test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/ 97423168SgibbsfindSCB_loop: 97523925Sgibbs inc SINDEX; 97623925Sgibbs mov A,SCBCOUNT; 97723925Sgibbs cmp SINDEX,A jne findSCB; 97819164Sgibbs/* 97919164Sgibbs * We didn't find it. If we're paging, pull an SCB and DMA down the 98019164Sgibbs * one we want. If we aren't paging or the SCB we dma down has the 98119218Sgibbs * abort flag set, return not found. 98219164Sgibbs */ 98323925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 98423925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 98523925Sgibbs mov ARG_1 call dma_scb; 98623925Sgibbs test SCB_CONTROL, ABORT_SCB jz return; 98719218Sgibbsfind_error: 98823925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 98915328SgibbsfoundSCB: 99023925Sgibbs test SCB_CONTROL, ABORT_SCB jnz find_error; 99119164Sgibbsrem_scb_from_disc_list: 99215328Sgibbs/* Remove this SCB from the disconnection list */ 99323925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev; 99423925Sgibbs mov SAVED_LINKPTR, SCB_PREV; 99523925Sgibbs mov SCBPTR, SCB_NEXT; 99623925Sgibbs mov SCB_PREV, SAVED_LINKPTR; 99723925Sgibbs mov SCBPTR, SINDEX; 99815328Sgibbsunlink_prev: 99923925Sgibbs cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */ 100023925Sgibbs mov SAVED_LINKPTR, SCB_NEXT; 100123925Sgibbs mov SCBPTR, SCB_PREV; 100223925Sgibbs mov SCB_NEXT, SAVED_LINKPTR; 100323925Sgibbs mov SCBPTR, SINDEX ret; 100415328SgibbsrHead: 100523925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 100623925Sgibbs.else 100723925Sgibbs ret; 100823925Sgibbs.endif 10094568Sgibbs 101019164Sgibbsset_stcnt_from_hcnt: 101123925Sgibbs mov STCNT[0], HCNT[0]; 101223925Sgibbs mov STCNT[1], HCNT[1]; 101323925Sgibbs mov STCNT[2], HCNT[2] ret; 10144568Sgibbs 101519164Sgibbsbcopy_7: 101623925Sgibbs mov DINDIR, SINDIR; 101723925Sgibbs mov DINDIR, SINDIR; 101819164Sgibbsbcopy_5: 101923925Sgibbs mov DINDIR, SINDIR; 102019164Sgibbsbcopy_4: 102123925Sgibbs mov DINDIR, SINDIR; 102219164Sgibbsbcopy_3: 102323925Sgibbs mov DINDIR, SINDIR; 102423925Sgibbs mov DINDIR, SINDIR; 102523925Sgibbs mov DINDIR, SINDIR ret; 10264568Sgibbs 102719164Sgibbsdma_scb: 102819164Sgibbs /* 102919164Sgibbs * SCB index is in SINDEX. Determine the physical address in 103019164Sgibbs * the host where this SCB is located and load HADDR with it. 103119164Sgibbs */ 103223925Sgibbs shr DINDEX, 3, SINDEX; 103323925Sgibbs shl A, 5, SINDEX; 103423925Sgibbs add HADDR[0], A, HSCB_ADDR[0]; 103523925Sgibbs mov A, DINDEX; 103623925Sgibbs adc HADDR[1], A, HSCB_ADDR[1]; 103723925Sgibbs clr A; 103823925Sgibbs adc HADDR[2], A, HSCB_ADDR[2]; 103923925Sgibbs adc HADDR[3], A, HSCB_ADDR[3]; 104019164Sgibbs /* Setup Count */ 104123925Sgibbs mvi HCNT[0], 28; 104223925Sgibbs clr HCNT[1]; 104323925Sgibbs clr HCNT[2]; 104423925Sgibbs mov DFCNTRL, DMAPARAMS; 104523925Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 104619164Sgibbs /* Fill it with the SCB data */ 104724175Sgibbscopy_scb_tofifo: 104824175Sgibbs mvi SINDEX, SCB_CONTROL; 104924175Sgibbs add A, 28, SINDEX; 105024175Sgibbscopy_scb_tofifo_loop: 105124175Sgibbs mov DFDAT,SINDIR; 105224175Sgibbs mov DFDAT,SINDIR; 105324175Sgibbs mov DFDAT,SINDIR; 105424175Sgibbs mov DFDAT,SINDIR; 105524175Sgibbs mov DFDAT,SINDIR; 105624175Sgibbs mov DFDAT,SINDIR; 105724175Sgibbs mov DFDAT,SINDIR; 105824175Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 105923925Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 106019164Sgibbsdma_scb_fromhost: 106123925Sgibbs call dma_finish; 106219164Sgibbs /* If we were putting the SCB, we are done */ 106323925Sgibbs test DMAPARAMS, DIRECTION jz return; 106423925Sgibbs mvi SCB_CONTROL call dfdat_in_7; 106523925Sgibbs call dfdat_in_7_continued; 106623925Sgibbs call dfdat_in_7_continued; 106723925Sgibbs jmp dfdat_in_7_continued; 106819164Sgibbsdfdat_in_7: 106923925Sgibbs mov DINDEX,SINDEX; 107019164Sgibbsdfdat_in_7_continued: 107123925Sgibbs mov DINDIR,DFDAT; 107223925Sgibbs mov DINDIR,DFDAT; 107323925Sgibbs mov DINDIR,DFDAT; 107423925Sgibbs mov DINDIR,DFDAT; 107523925Sgibbs mov DINDIR,DFDAT; 107623925Sgibbs mov DINDIR,DFDAT; 107723925Sgibbs mov DINDIR,DFDAT ret; 107819164Sgibbs 107913177Sgibbs/* 108019164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 108119164Sgibbs * DMA and wait for it to acknowledge that it's off. 108213177Sgibbs */ 108319164Sgibbsdma_finish: 108423925Sgibbs test DFSTATUS,HDONE jz dma_finish; 108522234Sgibbs /* Turn off DMA */ 108623925Sgibbs and DFCNTRL, ~HDMAEN; 108723925Sgibbs test DFCNTRL, HDMAEN jnz .; 108823925Sgibbs ret; 10899928Sgibbs 109019164Sgibbsindex_untagged_scb: 109123925Sgibbs mov DINDEX, SINDEX; 109223925Sgibbs shr DINDEX, 4; 109323925Sgibbs and DINDEX, 0x03; /* Bottom two bits of tid */ 109423925Sgibbs add DINDEX, SCB_BUSYTARGETS; 109523925Sgibbs shr A, 6, SINDEX; /* Target ID divided by 4 */ 109623925Sgibbs test SINDEX, SELBUSB jz index_untagged_scb2; 109723925Sgibbs add A, 2; /* Add 2 positions */ 109819164Sgibbsindex_untagged_scb2: 109923925Sgibbs mov SCBPTR, A; /* 110019164Sgibbs * Select the SCB with this 110119164Sgibbs * target's information. 110219164Sgibbs */ 110323925Sgibbs mov SINDEX, DINDEX ret; 11049928Sgibbs 110523925Sgibbsadd_scb_to_free_list: 110623925Sgibbs mov SCB_NEXT, FREE_SCBH; 110723925Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 110823925Sgibbs mov FREE_SCBH, SCBPTR ret; 11094568Sgibbs 111023925Sgibbs.if ( SCB_PAGING ) 111119164Sgibbsget_free_or_disc_scb: 111223925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 111323925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 111419623Sgibbsreturn_error: 111523925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 111619623Sgibbsdequeue_disc_scb: 111723925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 111813177Sgibbs/* 111919164Sgibbs * If we have a residual, then we are in the middle of some I/O 112019164Sgibbs * and we have to send this SCB back up to the kernel so that the 112119164Sgibbs * saved data pointers and residual information isn't lost. 112219164Sgibbs */ 112323925Sgibbs test SCB_RESID_SGCNT,0xff jnz dma_up_scb; 112423925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb; 112523925Sgibbsdma_up_scb: 112623925Sgibbs mvi DMAPARAMS, FIFORESET; 112723925Sgibbs mov SCB_TAG call dma_scb; 112819164Sgibbsunlink_disc_scb: 112919623Sgibbs /* jmp instead of call since we want to return anyway */ 113023925Sgibbs mov SCBPTR jmp rem_scb_from_disc_list; 113119164Sgibbsdequeue_free_scb: 113223925Sgibbs mov SCBPTR, FREE_SCBH; 113323925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 11344568Sgibbs 113519164Sgibbsadd_scb_to_disc_list: 113613177Sgibbs/* 113719164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 113819164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 113919164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 114013177Sgibbs */ 114123925Sgibbs mvi SCB_PREV, SCB_LIST_NULL; 114223925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 114323925Sgibbs mov DISCONNECTED_SCBH, SCBPTR; 114423925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je return; 114523925Sgibbs mov SCBPTR,SCB_NEXT; 114623925Sgibbs mov SCB_PREV,DISCONNECTED_SCBH; 114723925Sgibbs mov SCBPTR,DISCONNECTED_SCBH ret; 114823925Sgibbs.endif 1149