aic7xxx.seq revision 25123
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 * 4025123Sgibbs * $Id: aic7xxx.seq,v 1.72 1997/04/18 16:31:55 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; 16425005Sgibbs.else 16519164Sgibbssimple_busy_link: 16623925Sgibbs mov SCBPTR, ARG_1; 16723925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 16823925Sgibbs mvi SEQCTL, FASTMODE; 16923925Sgibbs jmp poll_for_work; 17025005Sgibbs.endif 17119164Sgibbsmake_busy: 17223925Sgibbs mov DINDIR, CUR_SCBID; 17323925Sgibbs mov SCBPTR, SAVED_SCBPTR; 17423925Sgibbs mvi SEQCTL, FASTMODE; 1754568Sgibbs 1765326Sgibbsstart_scb: 17719164Sgibbs /* 17819164Sgibbs * Place us on the waiting list in case our selection 17919164Sgibbs * doesn't win during bus arbitration. 18019164Sgibbs */ 18123925Sgibbs mov SCB_NEXT,WAITING_SCBH; 18223925Sgibbs mov WAITING_SCBH, SCBPTR; 18323925Sgibbsstart_waiting: 18423925Sgibbs /* 18523925Sgibbs * Pull the first entry off of the waiting SCB list 18623925Sgibbs * We don't have to "test_busy" because only transactions that 18723925Sgibbs * have passed that test can be in the WAITING_SCB list. 18823925Sgibbs */ 18923925Sgibbs mov SCBPTR, WAITING_SCBH; 19023925Sgibbs call start_selection; 19123925Sgibbs jmp poll_for_work; 1928104Sgibbs 19323925Sgibbsstart_selection: 19423991Sgibbs.if ( TWIN_CHANNEL ) 19523925Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */ 19623925Sgibbs and A,SELBUSB,SCB_TCL; /* Get new channel bit */ 19723925Sgibbs or SINDEX,A; 19823925Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 19923991Sgibbs.endif 20023925Sgibbsinitialize_scsiid: 20123925Sgibbs and A, TID, SCB_TCL; /* Get target ID */ 20223925Sgibbs and SCSIID, OID; /* Clear old target */ 20323925Sgibbs or SCSIID, A; 20423925Sgibbs mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; 20513177Sgibbs/* 20623925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 20723925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 20813177Sgibbs */ 20923925Sgibbsreselect: 21023925Sgibbs clr MSG_LEN; /* Don't have anything in the mesg buffer */ 21123925Sgibbs mvi CLRSINT0, CLRSELDI; 21223925Sgibbs /* XXX test for and handle ONE BIT condition */ 21323925Sgibbs and SAVED_TCL, SELID_MASK, SELID; 21423925Sgibbs or SEQ_FLAGS,RESELECTED; 21523925Sgibbs jmp select2; 2164568Sgibbs 21713177Sgibbs/* 21823925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 21923925Sgibbs * list. This is achieved by simply moving our "next" pointer into 22023925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 22123925Sgibbs * SCB is used, so don't bother with it now. 22223925Sgibbs */ 22323925Sgibbsselect: 22425005Sgibbs /* Turn off the selection hardware */ 22523925Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* 22623925Sgibbs * ATN on parity errors 22723925Sgibbs * for "in" phases 22823925Sgibbs */ 22925005Sgibbs mvi CLRSINT0, CLRSELDO; 23025005Sgibbs mov SCBPTR, WAITING_SCBH; 23124914Sgibbs mov WAITING_SCBH,SCB_NEXT; 23223925Sgibbs mov SAVED_TCL, SCB_TCL; 23323925Sgibbs/* 23413177Sgibbs * As soon as we get a successful selection, the target should go 23513177Sgibbs * into the message out phase since we have ATN asserted. Prepare 23613177Sgibbs * the message to send. 23713177Sgibbs * 23813177Sgibbs * Messages are stored in scratch RAM starting with a length byte 23913177Sgibbs * followed by the message itself. 24013177Sgibbs */ 2418567Sdg 24213177Sgibbsmk_identify: 24323925Sgibbs and MSG_OUT,0x7,SCB_TCL; /* lun */ 24423925Sgibbs and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ 24523925Sgibbs or MSG_OUT,A; /* or in disconnect privledge */ 24623925Sgibbs or MSG_OUT,MSG_IDENTIFYFLAG; 24723925Sgibbs mvi MSG_LEN, 1; 2484568Sgibbs 24913177Sgibbs/* 25015328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 25115328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 25213177Sgibbs */ 2536608Sgibbsmk_tag: 25423925Sgibbs test SCB_CONTROL,TAG_ENB jz mk_message; 25523925Sgibbs and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 25623925Sgibbs mov MSG_OUT[2],SCB_TAG; 25723925Sgibbs add MSG_LEN,2; /* update message length */ 2586608Sgibbs 25918762Sgibbs/* 26018762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer 26118762Sgibbs * if it asks. 26218762Sgibbs */ 26318762Sgibbsmk_message: 26423925Sgibbs test SCB_CONTROL,MK_MESSAGE jz select2; 26523925Sgibbs mvi INTSTAT,AWAITING_MSG; 2666608Sgibbs 2678104Sgibbsselect2: 26825005Sgibbs mvi CLRSINT1,CLRBUSFREE; 26925005Sgibbs or SIMODE1, ENBUSFREE; /* 27025005Sgibbs * We aren't expecting a 27125005Sgibbs * bus free, so interrupt 27225005Sgibbs * the kernel driver if it 27325005Sgibbs * happens. 27425005Sgibbs */ 27513177Sgibbs/* 27622451Sgibbs * Initialize Ultra mode setting and clear the SCSI channel. 27722451Sgibbs */ 27823925Sgibbs or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN; 27923925Sgibbs.if ( ULTRA ) 28022451Sgibbsultra: 28123925Sgibbs mvi SINDEX, ULTRA_ENB+1; 28223925Sgibbs test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ 28323925Sgibbs dec SINDEX; 28422451Sgibbsultra_2: 28523925Sgibbs mov FUNCTION1,SAVED_TCL; 28623925Sgibbs mov A,FUNCTION1; 28723925Sgibbs test SINDIR, A jz ndx_dtr; 28823925Sgibbs or SXFRCTL0, FAST20; 28923925Sgibbs.endif 29022451Sgibbs 29122451Sgibbs/* 29213177Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 29319164Sgibbs * The SCSIRATE settings for each target are stored in an array 29419164Sgibbs * based at TARG_SCRATCH. 29513177Sgibbs */ 29619164Sgibbsndx_dtr: 29723925Sgibbs shr A,4,SAVED_TCL; 29823925Sgibbs test SBLKCTL,SELBUSB jz ndx_dtr_2; 29923925Sgibbs or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */ 30023925Sgibbs or A,0x08; /* Channel B entries add 8 */ 30119164Sgibbsndx_dtr_2: 30223925Sgibbs add SINDEX,TARG_SCRATCH,A; 30323925Sgibbs mov SCSIRATE,SINDIR; 30413177Sgibbs 30515843Sgibbs 30613177Sgibbs/* 30713177Sgibbs * Main loop for information transfer phases. If BSY is false, then 30813177Sgibbs * we have a bus free condition, expected or not. Otherwise, wait 30913177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O 31013177Sgibbs * for the bus phase. 31113177Sgibbs * 31213177Sgibbs */ 3134568SgibbsITloop: 31424794Sgibbs test SSTAT1,REQINIT jz ITloop; 31524794Sgibbs test SSTAT1, SCSIPERR jnz ITloop; 3164568Sgibbs 31723925Sgibbs and A,PHASE_MASK,SCSISIGI; 31823925Sgibbs mov LASTPHASE,A; 31923925Sgibbs mov SCSISIGO,A; 3204568Sgibbs 32123925Sgibbs cmp ALLZEROS,A je p_dataout; 32223925Sgibbs cmp A,P_DATAIN je p_datain; 32323925Sgibbs cmp A,P_COMMAND je p_command; 32423925Sgibbs cmp A,P_MESGOUT je p_mesgout; 32523925Sgibbs cmp A,P_STATUS je p_status; 32623925Sgibbs cmp A,P_MESGIN je p_mesgin; 3274568Sgibbs 32823925Sgibbs mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ 32923925Sgibbs jmp ITloop; /* Try reading the bus again. */ 3304568Sgibbs 33123925Sgibbsawait_busfree: 33223925Sgibbs and SIMODE1, ~ENBUSFREE; 33324794Sgibbs call clear_target_state; 33423925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 33523925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 33623925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 33723925Sgibbs mvi INTSTAT, BAD_PHASE; 33823925Sgibbs 33923925Sgibbsclear_target_state: 34023925Sgibbs clr DFCNTRL; 34123925Sgibbs clr SCSIRATE; /* 34223925Sgibbs * We don't know the target we will 34323925Sgibbs * connect to, so default to narrow 34423925Sgibbs * transfers to avoid parity problems. 34523925Sgibbs */ 34623925Sgibbs and SXFRCTL0, ~FAST20; 34723925Sgibbs mvi LASTPHASE, P_BUSFREE; 34823925Sgibbs /* clear target specific flags */ 34923925Sgibbs and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret; 35023925Sgibbs 3514568Sgibbsp_dataout: 35223925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET; 35323925Sgibbs jmp data_phase_init; 3544568Sgibbs 35513177Sgibbs/* 35613177Sgibbs * If we re-enter the data phase after going through another phase, the 35713177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 35813177Sgibbs */ 3599928Sgibbsdata_phase_reinit: 36023925Sgibbs mvi DINDEX, STCNT; 36123925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 36223925Sgibbs jmp data_phase_loop; 3634568Sgibbs 3649928Sgibbsp_datain: 36523925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 3669928Sgibbsdata_phase_init: 36723925Sgibbs call assert; /* 36819164Sgibbs * Ensure entering a data 36919164Sgibbs * phase is okay - seen identify, etc. 37019164Sgibbs */ 3715775Sgibbs 37223925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 3734568Sgibbs 37419164Sgibbs /* 37519164Sgibbs * Initialize the DMA address and counter from the SCB. 37619164Sgibbs * Also set SG_COUNT and SG_NEXT in memory since we cannot 37719164Sgibbs * modify the values in the SCB itself until we see a 37819164Sgibbs * save data pointers message. 37919164Sgibbs */ 38023925Sgibbs mvi DINDEX, HADDR; 38123925Sgibbs mvi SCB_DATAPTR call bcopy_7; 38219164Sgibbs 38323925Sgibbs call set_stcnt_from_hcnt; 38419164Sgibbs 38523925Sgibbs mov SG_COUNT,SCB_SGCOUNT; 38619164Sgibbs 38723925Sgibbs mvi DINDEX, SG_NEXT; 38823925Sgibbs mvi SCB_SGPTR call bcopy_4; 38919164Sgibbs 3909928Sgibbsdata_phase_loop: 39116260Sgibbs/* Guard against overruns */ 39223925Sgibbs test SG_COUNT, 0xff jnz data_phase_inbounds; 39316260Sgibbs/* 39416260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to 39516260Sgibbs * 16meg and let the target run until it changes phase. 39616260Sgibbs * When the transfer completes, notify the host that we 39716260Sgibbs * had an overrun. 39816260Sgibbs */ 39923925Sgibbs or SXFRCTL1,BITBUCKET; 40023925Sgibbs mvi HCNT[0], 0xff; 40123925Sgibbs mvi HCNT[1], 0xff; 40223925Sgibbs mvi HCNT[2], 0xff; 40323925Sgibbs call set_stcnt_from_hcnt; 40416260Sgibbs 40516260Sgibbsdata_phase_inbounds: 40619164Sgibbs/* If we are the last SG block, ensure wideodd is off. */ 40723925Sgibbs cmp SG_COUNT,0x01 jne data_phase_wideodd; 40823925Sgibbs and DMAPARAMS, ~WIDEODD; 4099928Sgibbsdata_phase_wideodd: 41023925Sgibbs mov DMAPARAMS call dma; 4114568Sgibbs 41216260Sgibbs/* Go tell the host about any overruns */ 41323925Sgibbs test SXFRCTL1,BITBUCKET jnz data_phase_overrun; 41416260Sgibbs 41522451Sgibbs/* Exit if we had an underrun. dma clears SINDEX in this case. */ 41623925Sgibbs test SINDEX,0xff jz data_phase_finish; 4177532Sgibbs 41813177Sgibbs/* 41913177Sgibbs * Advance the scatter-gather pointers if needed 42013177Sgibbs */ 4219928Sgibbssg_advance: 42223925Sgibbs dec SG_COUNT; /* one less segment to go */ 4234568Sgibbs 42423925Sgibbs test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ 4254568Sgibbs 42623925Sgibbs clr A; /* add sizeof(struct scatter) */ 42723925Sgibbs add SG_NEXT[0],SG_SIZEOF; 42823925Sgibbs adc SG_NEXT[1],A; 4294568Sgibbs 43013177Sgibbs/* 43113177Sgibbs * Load a struct scatter and set up the data address and length. 43213177Sgibbs * If the working value of the SG count is nonzero, then 43313177Sgibbs * we need to load a new set of values. 43413177Sgibbs * 43515328Sgibbs * This, like all DMA's, assumes little-endian host data storage. 43613177Sgibbs */ 4379928Sgibbssg_load: 43823925Sgibbs mvi DINDEX, HADDR; 43923925Sgibbs mvi SG_NEXT call bcopy_4; 4404568Sgibbs 44123925Sgibbs mvi HCNT[0],SG_SIZEOF; 44223925Sgibbs clr HCNT[1]; 44323925Sgibbs clr HCNT[2]; 44422568Sgibbs 44523925Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 4469928Sgibbs 44723925Sgibbs call dma_finish; 4489928Sgibbs 44913177Sgibbs/* 45013177Sgibbs * Copy data from FIFO into SCB data pointer and data count. This assumes 45119164Sgibbs * that the SG segments are of the form: 45213177Sgibbs * 45313177Sgibbs * struct ahc_dma_seg { 45419164Sgibbs * u_int32_t addr; four bytes, little-endian order 45519164Sgibbs * u_int32_t len; four bytes, little endian order 45613177Sgibbs * }; 45713177Sgibbs */ 45823925Sgibbs mvi HADDR call dfdat_in_7; 4599928Sgibbs 46013177Sgibbs/* Load STCNT as well. It is a mirror of HCNT */ 46123925Sgibbs call set_stcnt_from_hcnt; 46223925Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 4634568Sgibbs 4649928Sgibbsdata_phase_finish: 46513177Sgibbs/* 46613177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB 46713177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 46813177Sgibbs * were transferred on the SCSI (as opposed to the host) bus. 46913177Sgibbs */ 47023925Sgibbs mov SCB_RESID_DCNT[0],STCNT[0]; 47123925Sgibbs mov SCB_RESID_DCNT[1],STCNT[1]; 47223925Sgibbs mov SCB_RESID_DCNT[2],STCNT[2]; 47323925Sgibbs mov SCB_RESID_SGCNT, SG_COUNT; 47422568Sgibbs 47522568Sgibbs /* We have seen a data phase */ 47623925Sgibbs or SEQ_FLAGS, DPHASE; 47722568Sgibbs 47823925Sgibbs jmp ITloop; 4794568Sgibbs 48016260Sgibbsdata_phase_overrun: 48113177Sgibbs/* 48216260Sgibbs * Turn off BITBUCKET mode and notify the host 48316260Sgibbs */ 48423925Sgibbs and SXFRCTL1, ~BITBUCKET; 48523925Sgibbs mvi INTSTAT,DATA_OVERRUN; 48623925Sgibbs jmp ITloop; 48716260Sgibbs 48816260Sgibbs/* 48915328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 49013177Sgibbs */ 4914568Sgibbsp_command: 49223925Sgibbs call assert; 4934568Sgibbs 49413177Sgibbs/* 49515328Sgibbs * Load HADDR and HCNT. 49613177Sgibbs */ 49723925Sgibbs mvi DINDEX, HADDR; 49823925Sgibbs mvi SCB_CMDPTR call bcopy_5; 49923925Sgibbs clr HCNT[1]; 50023925Sgibbs clr HCNT[2]; 5014568Sgibbs 50223925Sgibbs call set_stcnt_from_hcnt; 5034568Sgibbs 50423925Sgibbs mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; 50523925Sgibbs jmp ITloop; 5064568Sgibbs 50713177Sgibbs/* 50813177Sgibbs * Status phase. Wait for the data byte to appear, then read it 50913177Sgibbs * and store it into the SCB. 51013177Sgibbs */ 5114568Sgibbsp_status: 51223925Sgibbs call assert; 51319803Sgibbs 51423925Sgibbs mov SCB_TARGET_STATUS, SCSIDATL; 51523925Sgibbs jmp ITloop; 5164568Sgibbs 51713177Sgibbs/* 51815328Sgibbs * Message out phase. If there is not an active message, but the target 51913177Sgibbs * took us into this phase anyway, build a no-op message and send it. 52013177Sgibbs */ 5214568Sgibbsp_mesgout: 52223925Sgibbs test MSG_LEN, 0xff jnz p_mesgout_start; 52323925Sgibbs mvi MSG_NOOP call mk_mesg; /* build NOP message */ 52413177Sgibbsp_mesgout_start: 52513177Sgibbs/* 52623925Sgibbs * Set up automatic PIO transfer from MSG_OUT. Bit 3 in 52713177Sgibbs * SXFRCTL0 (SPIOEN) is already on. 52813177Sgibbs */ 52923925Sgibbs mvi SINDEX,MSG_OUT; 53023925Sgibbs mov DINDEX,MSG_LEN; 5314568Sgibbs 53213177Sgibbs/* 53313177Sgibbs * When target asks for a byte, drop ATN if it's the last one in 53413177Sgibbs * the message. Otherwise, keep going until the message is exhausted. 53523925Sgibbs * ATN must be dropped *at least* 90ns before we ack the last byte, so 53623925Sgibbs * the code is aranged to execute two instructions before the byte is 53723925Sgibbs * transferred to give a good margin of safety 53813177Sgibbs * 53913177Sgibbs * Keep an eye out for a phase change, in case the target issues 54013177Sgibbs * a MESSAGE REJECT. 54113177Sgibbs */ 54213177Sgibbsp_mesgout_loop: 54324794Sgibbs test SSTAT1, REQINIT jz p_mesgout_loop; 54424794Sgibbs test SSTAT1, SCSIPERR jnz p_mesgout_loop; 54523925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 54623925Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 54725005Sgibbsp_mesgout_testretry: 54825005Sgibbs test DINDEX,0xff jnz p_mesgout_dropatn; 54925005Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 55025005Sgibbs jmp p_mesgout_start; 55113177Sgibbs/* 55213177Sgibbs * If the next bus phase after ATN drops is a message out, it means 55313177Sgibbs * that the target is requesting that the last message(s) be resent. 55413177Sgibbs */ 55524914Sgibbsp_mesgout_dropatn: 55624914Sgibbs cmp DINDEX,1 jne p_mesgout_outb; /* last byte? */ 55724914Sgibbs mvi CLRSINT1,CLRATNO; /* drop ATN */ 55819906Sgibbsp_mesgout_outb: 55923925Sgibbs dec DINDEX; 56023925Sgibbs mov SCSIDATL,SINDIR; 56123925Sgibbs jmp p_mesgout_loop; 5624568Sgibbs 56319906Sgibbsp_mesgout_done: 56423925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 56523925Sgibbs clr MSG_LEN; /* no active msg */ 56623925Sgibbs jmp ITloop; 5674568Sgibbs 56813177Sgibbs/* 56913177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 57013177Sgibbs */ 5714568Sgibbsp_mesgin: 57223925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 57323925Sgibbs mov REJBYTE,A; /* save it for the driver */ 5744568Sgibbs 57523925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 57623925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 57723925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 57823925Sgibbs cmp ALLZEROS,A je mesgin_complete; 57923925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 58023925Sgibbs cmp A,MSG_EXTENDED je mesgin_extended; 58123925Sgibbs cmp A,MSG_MESSAGE_REJECT je mesgin_reject; 58223925Sgibbs cmp A,MSG_NOOP je mesgin_done; 5834568Sgibbs 5849954Sgibbsrej_mesgin: 58513177Sgibbs/* 58619164Sgibbs * We have no idea what this message in is, so we issue a message reject 58719164Sgibbs * and hope for the best. In any case, rejection should be a rare 58819164Sgibbs * occurrence - signal the driver when it happens. 58913177Sgibbs */ 59023925Sgibbs mvi INTSTAT,SEND_REJECT; /* let driver know */ 5919954Sgibbs 59223925Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 5939954Sgibbs 5949954Sgibbsmesgin_done: 59523925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 59623925Sgibbs jmp ITloop; 5979954Sgibbs 5989954Sgibbs 5999954Sgibbsmesgin_complete: 60013177Sgibbs/* 60119164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, 60219164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 60319164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0). In 60419164Sgibbs * either of these conditions, we upload the SCB back to the host so it can 60519164Sgibbs * process this information. In the case of a non zero status byte, we 60619164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 60719164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 60819164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set 60919164Sgibbs * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload 61019164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list. 61119164Sgibbs * If the kernel driver does not wish to request sense, it need only clear 61219164Sgibbs * RETURN_1, and the command is allowed to complete normally. We don't bother 61319164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra 61419164Sgibbs * work in the kernel driver to ensure that the entry was removed before the 61519164Sgibbs * command complete code tried processing it. 61613177Sgibbs */ 61719164Sgibbs 61813177Sgibbs/* 61919164Sgibbs * First check for residuals 62013177Sgibbs */ 62123925Sgibbs test SCB_RESID_SGCNT,0xff jnz upload_scb; 62223925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */ 62319164Sgibbsupload_scb: 62423925Sgibbs mvi DMAPARAMS, FIFORESET; 62523925Sgibbs mov SCB_TAG call dma_scb; 6267532Sgibbscheck_status: 62723925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */ 62823925Sgibbs mvi INTSTAT,BAD_STATUS; /* let driver know */ 62923925Sgibbs cmp RETURN_1, SEND_SENSE jne status_ok; 63019164Sgibbs /* This SCB becomes the next to execute as it will retrieve sense */ 63123925Sgibbs mov SCB_LINKED_NEXT, SCB_TAG; 63223925Sgibbs jmp dma_next_scb; 6335326Sgibbs 6344568Sgibbsstatus_ok: 63513177Sgibbs/* First, mark this target as free. */ 63623925Sgibbs test SCB_CONTROL,TAG_ENB jnz complete; /* 63713177Sgibbs * Tagged commands 63813177Sgibbs * don't busy the 63913177Sgibbs * target. 64013177Sgibbs */ 64123925Sgibbs mov SAVED_SCBPTR, SCBPTR; 64223925Sgibbs mov SAVED_LINKPTR, SCB_LINKED_NEXT; 64323925Sgibbs mov SCB_TCL call index_untagged_scb; 64423925Sgibbs mov DINDIR, SAVED_LINKPTR; 64523925Sgibbs mov SCBPTR, SAVED_SCBPTR; 6465326Sgibbs 6475326Sgibbscomplete: 64819164Sgibbs /* Post the SCB and issue an interrupt */ 64923925Sgibbs mov QOUTFIFO,SCB_TAG; 65023925Sgibbs mvi INTSTAT,CMDCMPLT; 65123925Sgibbs test SCB_CONTROL, ABORT_SCB jz dma_next_scb; 65223925Sgibbs mvi INTSTAT, ABORT_CMDCMPLT; 65319164Sgibbs 65419164Sgibbsdma_next_scb: 65523925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list; 65623925Sgibbs.if !( SCB_PAGING ) 65719164Sgibbs /* Only DMA on top of ourselves if we are the SCB to download */ 65823925Sgibbs mov A, SCB_LINKED_NEXT; 65923925Sgibbs cmp SCB_TAG, A je dma_next_scb2; 66025005Sgibbs call add_scb_to_free_list; 66123925Sgibbs mov SCBPTR, A; 66223925Sgibbs jmp add_to_waiting_list; 66323925Sgibbs.endif 66419164Sgibbsdma_next_scb2: 66523925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 66623925Sgibbs mov SCB_LINKED_NEXT call dma_scb; 66719164Sgibbsadd_to_waiting_list: 66823925Sgibbs mov SCB_NEXT,WAITING_SCBH; 66923925Sgibbs mov WAITING_SCBH, SCBPTR; 67023925Sgibbs /* 67123925Sgibbs * Prepare our selection hardware before the busfree so we have a 67223925Sgibbs * high probability of winning arbitration. 67323925Sgibbs */ 67423925Sgibbs call start_selection; 67523925Sgibbs jmp await_busfree; 67619921Sgibbsadd_to_free_list: 67723925Sgibbs call add_scb_to_free_list; 67823925Sgibbs jmp await_busfree; 6794568Sgibbs 68013177Sgibbs/* 68118762Sgibbs * Is it an extended message? Copy the message to our message buffer and 68218762Sgibbs * notify the host. The host will tell us whether to reject this message, 68318762Sgibbs * respond to it with the message that the host placed in our message buffer, 68418762Sgibbs * or simply to do nothing. 68513177Sgibbs */ 6869954Sgibbsmesgin_extended: 68723925Sgibbs mvi MSGIN_EXT_LEN call inb_next; 68823925Sgibbs mov A, MSGIN_EXT_LEN; 68918762Sgibbsmesgin_extended_loop: 69023925Sgibbs mov DINDEX call inb_next; 69123925Sgibbs dec A; 69223925Sgibbs cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test; 69323925Sgibbs dec DINDEX; /* dump by repeatedly filling the last byte */ 69419164Sgibbsmesgin_extended_loop_test: 69523925Sgibbs test A, 0xFF jnz mesgin_extended_loop; 69618762Sgibbsmesgin_extended_intr: 69723925Sgibbs mvi INTSTAT,EXTENDED_MSG; /* let driver know */ 69823925Sgibbs cmp RETURN_1,SEND_REJ je rej_mesgin; 69923925Sgibbs cmp RETURN_1,SEND_MSG jne mesgin_done; 70018762Sgibbs/* The kernel has setup a message to be sent */ 70123925Sgibbs or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */ 70223925Sgibbs jmp mesgin_done; 7035562Sgibbs 70413177Sgibbs/* 70513177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 70613177Sgibbs * and await the bus going free. 70713177Sgibbs */ 7089954Sgibbsmesgin_disconnect: 70923925Sgibbs or SCB_CONTROL,DISCONNECTED; 71023925Sgibbs.if ( SCB_PAGING ) 71123925Sgibbs call add_scb_to_disc_list; 71223925Sgibbs.endif 71323925Sgibbs jmp await_busfree; 71419164Sgibbs 71515328Sgibbs/* 71619164Sgibbs * Save data pointers message: 71719164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 71819164Sgibbs * only if we've actually been into a data phase to change them. This 71919164Sgibbs * protects against bogus data in scratch ram and the residual counts 72019164Sgibbs * since they are only initialized when we go into data_in or data_out. 72115328Sgibbs */ 72219164Sgibbsmesgin_sdptrs: 72323925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 72423925Sgibbs mov SCB_SGCOUNT,SG_COUNT; 7254568Sgibbs 72619164Sgibbs /* The SCB SGPTR becomes the next one we'll download */ 72723925Sgibbs mvi DINDEX, SCB_SGPTR; 72823925Sgibbs mvi SG_NEXT call bcopy_4; 72919164Sgibbs 73019164Sgibbs /* The SCB DATAPTR0 becomes the current SHADDR */ 73123925Sgibbs mvi DINDEX, SCB_DATAPTR; 73223925Sgibbs mvi SHADDR call bcopy_4; 73319164Sgibbs 73413177Sgibbs/* 73519164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer. 73613177Sgibbs */ 73723925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 73819164Sgibbs 73923925Sgibbs jmp mesgin_done; 7404568Sgibbs 74113177Sgibbs/* 74213177Sgibbs * Restore pointers message? Data pointers are recopied from the 74313177Sgibbs * SCB anytime we enter a data phase for the first time, so all 74413177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 74513177Sgibbs * code do the rest. 74613177Sgibbs */ 7479954Sgibbsmesgin_rdptrs: 74823925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 74923925Sgibbs * We'll reload them 75013177Sgibbs * the next time through 75123925Sgibbs * the dataphase. 75213177Sgibbs */ 75323925Sgibbs jmp mesgin_done; 7544568Sgibbs 75513177Sgibbs/* 75613177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 75713177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 75813177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 75913177Sgibbs */ 7609954Sgibbsmesgin_identify: 76123925Sgibbs test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/ 76223925Sgibbs and A,0x07; /* lun in lower three bits */ 76323925Sgibbs or SAVED_TCL,A; /* SAVED_TCL should be complete now */ 76423925Sgibbs mov SAVED_TCL call index_untagged_scb; 76523925Sgibbs mov ARG_1, SINDIR; 76624608Sgibbs.if ( SCB_PAGING ) 76723925Sgibbs cmp ARG_1,SCB_LIST_NULL jne use_findSCB; 76824608Sgibbs.else 76924608Sgibbs cmp ARG_1,SCB_LIST_NULL je snoop_tag; 77024608Sgibbs /* Directly index the SCB */ 77124608Sgibbs mov SCBPTR,ARG_1; 77224608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 77324608Sgibbs jmp setup_SCB; 77424608Sgibbs.endif 77513177Sgibbs/* 77613177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 77723168Sgibbs * If we get one, we use the tag returned to find the proper 77815328Sgibbs * SCB. With SCB paging, this requires using findSCB for both tagged 77915328Sgibbs * and non-tagged transactions since the SCB may exist in any slot. 78015328Sgibbs * If we're not using SCB paging, we can use the tag as the direct 78115328Sgibbs * index to the SCB. 78213177Sgibbs */ 78324608Sgibbssnoop_tag: 78423925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 78513177Sgibbssnoop_tag_loop: 78623925Sgibbs test SSTAT1,REQINIT jz snoop_tag_loop; 78724794Sgibbs test SSTAT1, SCSIPERR jnz snoop_tag_loop; 78823925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 78923925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 79023925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 7916608Sgibbsget_tag: 79223925Sgibbs or SEQ_FLAGS, TAGGED_SCB; 79323925Sgibbs mvi ARG_1 call inb_next; /* tag value */ 79413177Sgibbs/* 79513177Sgibbs * See if the tag is in range. The tag is < SCBCOUNT if we add 79613177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is 79713177Sgibbs * no carry. 79813177Sgibbs */ 79923925Sgibbs mov A,COMP_SCBCOUNT; 80023925Sgibbs add SINDEX,A,ARG_1; 80123925Sgibbs jc not_found; 80213177Sgibbs 80323925Sgibbs.if ! ( SCB_PAGING ) 80424608Sgibbsindex_by_tag: 80524608Sgibbs mov SCBPTR,ARG_1; 80624608Sgibbs mov A, SAVED_TCL; 80724608Sgibbs cmp SCB_TCL,A jne not_found; 80824608Sgibbs test SCB_CONTROL,TAG_ENB jz not_found; 80924608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 81024608Sgibbs.else 81113177Sgibbs/* 81215328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction 81313177Sgibbs * to the reconnecting target. 81413177Sgibbs */ 81515328Sgibbsuse_findSCB: 81623925Sgibbs mov ALLZEROS call findSCB; /* Have to search */ 81723925Sgibbs cmp SINDEX, SCB_LIST_NULL je not_found; 81824608Sgibbs.endif 81915328Sgibbssetup_SCB: 82023925Sgibbs and SCB_CONTROL,~DISCONNECTED; 82123925Sgibbs or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 82223925Sgibbs jmp mesgin_done; 82315328Sgibbs 82419218Sgibbsnot_found: 82523925Sgibbs mvi INTSTAT, NO_MATCH; 82625005Sgibbs mvi MSG_BUS_DEV_RESET call mk_mesg; 82723925Sgibbs jmp mesgin_done; 8286608Sgibbs 82913177Sgibbs/* 83013177Sgibbs * Message reject? Let the kernel driver handle this. If we have an 83113177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 83213177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 83313177Sgibbs * it since we have no clue what it pertains to. 83413177Sgibbs */ 8359954Sgibbsmesgin_reject: 83623925Sgibbs mvi INTSTAT, REJECT_MSG; 83723925Sgibbs jmp mesgin_done; 8385562Sgibbs 83913177Sgibbs/* 84013177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ] 84113177Sgibbs */ 8424568Sgibbs 84313177Sgibbs/* 84413177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX 84513177Sgibbs * if there is no active message already. SINDEX is returned intact. 84613177Sgibbs */ 8474568Sgibbsmk_mesg: 84823925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 84923925Sgibbs test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */ 85013177Sgibbs 85113177Sgibbs /* 85213177Sgibbs * Hmmm. For some reason the mesg buffer is in use. 85313177Sgibbs * Tell the driver. It should look at SINDEX to find 85413177Sgibbs * out what we wanted to use the buffer for and resolve 85513177Sgibbs * the conflict. 85613177Sgibbs */ 85723925Sgibbs mvi SEQCTL,FASTMODE; 85823925Sgibbs mvi INTSTAT,MSG_BUFFER_BUSY; 8594568Sgibbs 8604568Sgibbsmk_mesg1: 86123925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 86223925Sgibbs mvi MSG_LEN,1; /* length = 1 */ 86323925Sgibbs mov MSG_OUT,SINDEX; /* 1-byte message */ 86423925Sgibbs mvi SEQCTL,FASTMODE ret; 8654568Sgibbs 86613177Sgibbs/* 86713177Sgibbs * Functions to read data in Automatic PIO mode. 86813177Sgibbs * 86913177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 87013177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 87113177Sgibbs * latched (the usual way), then read the data byte directly off the bus 87213177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 87313177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 87413177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 87513177Sgibbs * we send our ACK. 87613177Sgibbs * 87713177Sgibbs * The assumption here is that these are called in a particular sequence, 87813177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 87913177Sgibbs * use the same calling convention as inb. 88013177Sgibbs */ 88113177Sgibbs 88213177Sgibbsinb_next: 88323925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 88413360Sgibbsinb_next_wait: 88521947Sgibbs /* 88621947Sgibbs * If there is a parity error, wait for the kernel to 88721947Sgibbs * see the interrupt and prepare our message response 88821947Sgibbs * before continuing. 88921947Sgibbs */ 89023925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 89123925Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait; 89223925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 89323925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 89419623Sgibbsinb_first: 89523925Sgibbs mov DINDEX,SINDEX; 89623925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 89713177Sgibbsinb_last: 89823925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 8994568Sgibbs 90013177Sgibbsmesgin_phasemis: 90113177Sgibbs/* 90213177Sgibbs * We expected to receive another byte, but the target changed phase 90313177Sgibbs */ 90423925Sgibbs mvi INTSTAT, MSGIN_PHASEMIS; 90523925Sgibbs jmp ITloop; 9064568Sgibbs 90713177Sgibbs/* 90813177Sgibbs * DMA data transfer. HADDR and HCNT must be loaded first, and 90913177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for 91013177Sgibbs * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 91113177Sgibbs * during initialization. 91213177Sgibbs */ 9134568Sgibbsdma: 91423925Sgibbs mov DFCNTRL,SINDEX; 91522568Sgibbsdma_loop: 91623925Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 91723925Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 91822568Sgibbsdma_phasemis: 91923925Sgibbs test SSTAT0,SDONE jnz dma_checkfifo; 92023925Sgibbs mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ 9214568Sgibbs 92213177Sgibbs/* 92313177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or 92413177Sgibbs * the target changes the phase (in light of this, it makes sense that 92513177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 92613177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto- 92713177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty 92813177Sgibbs * status. 92913177Sgibbs */ 93022568Sgibbsdma_checkfifo: 93123925Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 93222568Sgibbsdma_fifoflush: 93323925Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 9344568Sgibbs 93522568Sgibbsdma_fifoempty: 93622568Sgibbs /* Don't clobber an inprogress host data transfer */ 93723925Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 93813177Sgibbs/* 93913177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 94013177Sgibbs * actually off first lest we get an ILLSADDR. 94113177Sgibbs */ 94222568Sgibbsdma_dmadone: 94323925Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 94422568Sgibbsdma_halt: 94523925Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 94618762Sgibbsreturn: 94723925Sgibbs ret; 9484568Sgibbs 94913177Sgibbs/* 95013177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 95113177Sgibbs * message. 95213177Sgibbs */ 9534568Sgibbsassert: 95423925Sgibbs test SEQ_FLAGS,RESELECTED jz return; /* reselected? */ 95523925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 9564568Sgibbs 95723925Sgibbs mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ 9584568Sgibbs 95924608Sgibbs.if ( SCB_PAGING ) 96013177Sgibbs/* 96119218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) 96219218Sgibbs * or by the SCBIDn ARG_1. The search begins at the SCB index passed in 96319218Sgibbs * via SINDEX. If the SCB cannot be found, SINDEX will be SCB_LIST_NULL, 96419218Sgibbs * otherwise, SCBPTR is set to the proper SCB. 96513177Sgibbs */ 9664568SgibbsfindSCB: 96723925Sgibbs mov SCBPTR,SINDEX; /* switch to next SCB */ 96823925Sgibbs mov A, ARG_1; /* Tag passed in ARG_1 */ 96923925Sgibbs cmp SCB_TAG,A jne findSCB_loop; 97023925Sgibbs test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/ 97123168SgibbsfindSCB_loop: 97223925Sgibbs inc SINDEX; 97323925Sgibbs mov A,SCBCOUNT; 97423925Sgibbs cmp SINDEX,A jne findSCB; 97519164Sgibbs/* 97619164Sgibbs * We didn't find it. If we're paging, pull an SCB and DMA down the 97719164Sgibbs * one we want. If we aren't paging or the SCB we dma down has the 97819218Sgibbs * abort flag set, return not found. 97919164Sgibbs */ 98023925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 98123925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 98223925Sgibbs mov ARG_1 call dma_scb; 98325123Sgibbs test SCB_RESID_SGCNT, 0xff jz . + 2; 98425123Sgibbs or SCB_CONTROL, MUST_DMAUP_SCB; 98523925Sgibbs test SCB_CONTROL, ABORT_SCB jz return; 98619218Sgibbsfind_error: 98723925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 98815328SgibbsfoundSCB: 98923925Sgibbs test SCB_CONTROL, ABORT_SCB jnz find_error; 99019164Sgibbsrem_scb_from_disc_list: 99115328Sgibbs/* Remove this SCB from the disconnection list */ 99223925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev; 99323925Sgibbs mov SAVED_LINKPTR, SCB_PREV; 99423925Sgibbs mov SCBPTR, SCB_NEXT; 99523925Sgibbs mov SCB_PREV, SAVED_LINKPTR; 99623925Sgibbs mov SCBPTR, SINDEX; 99715328Sgibbsunlink_prev: 99823925Sgibbs cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */ 99923925Sgibbs mov SAVED_LINKPTR, SCB_NEXT; 100023925Sgibbs mov SCBPTR, SCB_PREV; 100123925Sgibbs mov SCB_NEXT, SAVED_LINKPTR; 100223925Sgibbs mov SCBPTR, SINDEX ret; 100315328SgibbsrHead: 100423925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 100523925Sgibbs.else 100623925Sgibbs ret; 100723925Sgibbs.endif 10084568Sgibbs 100919164Sgibbsset_stcnt_from_hcnt: 101023925Sgibbs mov STCNT[0], HCNT[0]; 101123925Sgibbs mov STCNT[1], HCNT[1]; 101223925Sgibbs mov STCNT[2], HCNT[2] ret; 10134568Sgibbs 101419164Sgibbsbcopy_7: 101523925Sgibbs mov DINDIR, SINDIR; 101623925Sgibbs mov DINDIR, SINDIR; 101719164Sgibbsbcopy_5: 101823925Sgibbs mov DINDIR, SINDIR; 101919164Sgibbsbcopy_4: 102023925Sgibbs mov DINDIR, SINDIR; 102119164Sgibbsbcopy_3: 102223925Sgibbs mov DINDIR, SINDIR; 102323925Sgibbs mov DINDIR, SINDIR; 102423925Sgibbs mov DINDIR, SINDIR ret; 10254568Sgibbs 102619164Sgibbsdma_scb: 102719164Sgibbs /* 102819164Sgibbs * SCB index is in SINDEX. Determine the physical address in 102919164Sgibbs * the host where this SCB is located and load HADDR with it. 103019164Sgibbs */ 103123925Sgibbs shr DINDEX, 3, SINDEX; 103223925Sgibbs shl A, 5, SINDEX; 103323925Sgibbs add HADDR[0], A, HSCB_ADDR[0]; 103423925Sgibbs mov A, DINDEX; 103523925Sgibbs adc HADDR[1], A, HSCB_ADDR[1]; 103623925Sgibbs clr A; 103723925Sgibbs adc HADDR[2], A, HSCB_ADDR[2]; 103823925Sgibbs adc HADDR[3], A, HSCB_ADDR[3]; 103919164Sgibbs /* Setup Count */ 104023925Sgibbs mvi HCNT[0], 28; 104123925Sgibbs clr HCNT[1]; 104223925Sgibbs clr HCNT[2]; 104323925Sgibbs mov DFCNTRL, DMAPARAMS; 104423925Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 104519164Sgibbs /* Fill it with the SCB data */ 104624175Sgibbscopy_scb_tofifo: 104724175Sgibbs mvi SINDEX, SCB_CONTROL; 104824175Sgibbs add A, 28, SINDEX; 104924175Sgibbscopy_scb_tofifo_loop: 105024175Sgibbs mov DFDAT,SINDIR; 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 cmp SINDEX, A jne copy_scb_tofifo_loop; 105823925Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 105919164Sgibbsdma_scb_fromhost: 106023925Sgibbs call dma_finish; 106119164Sgibbs /* If we were putting the SCB, we are done */ 106223925Sgibbs test DMAPARAMS, DIRECTION jz return; 106323925Sgibbs mvi SCB_CONTROL call dfdat_in_7; 106423925Sgibbs call dfdat_in_7_continued; 106523925Sgibbs call dfdat_in_7_continued; 106623925Sgibbs jmp dfdat_in_7_continued; 106719164Sgibbsdfdat_in_7: 106823925Sgibbs mov DINDEX,SINDEX; 106919164Sgibbsdfdat_in_7_continued: 107023925Sgibbs mov DINDIR,DFDAT; 107123925Sgibbs mov DINDIR,DFDAT; 107223925Sgibbs mov DINDIR,DFDAT; 107323925Sgibbs mov DINDIR,DFDAT; 107423925Sgibbs mov DINDIR,DFDAT; 107523925Sgibbs mov DINDIR,DFDAT; 107623925Sgibbs mov DINDIR,DFDAT ret; 107719164Sgibbs 107813177Sgibbs/* 107919164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 108019164Sgibbs * DMA and wait for it to acknowledge that it's off. 108113177Sgibbs */ 108219164Sgibbsdma_finish: 108323925Sgibbs test DFSTATUS,HDONE jz dma_finish; 108422234Sgibbs /* Turn off DMA */ 108523925Sgibbs and DFCNTRL, ~HDMAEN; 108623925Sgibbs test DFCNTRL, HDMAEN jnz .; 108723925Sgibbs ret; 10889928Sgibbs 108919164Sgibbsindex_untagged_scb: 109023925Sgibbs mov DINDEX, SINDEX; 109123925Sgibbs shr DINDEX, 4; 109223925Sgibbs and DINDEX, 0x03; /* Bottom two bits of tid */ 109323925Sgibbs add DINDEX, SCB_BUSYTARGETS; 109423925Sgibbs shr A, 6, SINDEX; /* Target ID divided by 4 */ 109523925Sgibbs test SINDEX, SELBUSB jz index_untagged_scb2; 109623925Sgibbs add A, 2; /* Add 2 positions */ 109719164Sgibbsindex_untagged_scb2: 109823925Sgibbs mov SCBPTR, A; /* 109919164Sgibbs * Select the SCB with this 110019164Sgibbs * target's information. 110119164Sgibbs */ 110223925Sgibbs mov SINDEX, DINDEX ret; 11039928Sgibbs 110423925Sgibbsadd_scb_to_free_list: 110523925Sgibbs mov SCB_NEXT, FREE_SCBH; 110623925Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 110723925Sgibbs mov FREE_SCBH, SCBPTR ret; 11084568Sgibbs 110923925Sgibbs.if ( SCB_PAGING ) 111019164Sgibbsget_free_or_disc_scb: 111123925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 111223925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 111319623Sgibbsreturn_error: 111423925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 111519623Sgibbsdequeue_disc_scb: 111623925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 111713177Sgibbs/* 111819164Sgibbs * If we have a residual, then we are in the middle of some I/O 111919164Sgibbs * and we have to send this SCB back up to the kernel so that the 112019164Sgibbs * saved data pointers and residual information isn't lost. 112119164Sgibbs */ 112225123Sgibbs test SCB_CONTROL, MUST_DMAUP_SCB jz . + 3; 112325123Sgibbs and SCB_CONTROL, ~MUST_DMAUP_SCB; 112425123Sgibbs jmp dma_up_scb; 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