aic7xxx.seq revision 25005
126997Sgibbs/*+M*********************************************************************** 226997Sgibbs *Adaptec 274x/284x/294x device driver for Linux and FreeBSD. 313177Sgibbs * 439220Sgibbs *Copyright (c) 1994 John Aycock 526997Sgibbs * The University of Calgary Department of Computer Science. 613177Sgibbs * All rights reserved. 726997Sgibbs * 826997Sgibbs *FreeBSD, Twin, Wide, 2 command per target support, tagged queuing, 926997Sgibbs *SCB paging and other optimizations: 1026997Sgibbs *Copyright (c) 1994, 1995, 1996, 1997 Justin Gibbs. All rights reserved. 1126997Sgibbs * 1226997Sgibbs *Redistribution and use in source and binary forms, with or without 1339220Sgibbs *modification, are permitted provided that the following conditions 1426997Sgibbs *are met: 1513177Sgibbs *1. Redistributions of source code must retain the above copyright 1626997Sgibbs * notice, this list of conditions, and the following disclaimer. 1739220Sgibbs *2. Redistributions in binary form must reproduce the above copyright 1826997Sgibbs * notice, this list of conditions and the following disclaimer in the 1926997Sgibbs * documentation and/or other materials provided with the distribution. 2026997Sgibbs *3. All advertising materials mentioning features or use of this software 2126997Sgibbs * must display the following acknowledgement: 2213177Sgibbs * This product includes software developed by the University of Calgary 2326997Sgibbs * Department of Computer Science and its contributors. 2426997Sgibbs *4. Neither the name of the University nor the names of its contributors 2526997Sgibbs * may be used to endorse or promote products derived from this software 2626997Sgibbs * without specific prior written permission. 2726997Sgibbs * 2826997Sgibbs *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2926997Sgibbs *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3026997Sgibbs *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3126997Sgibbs *ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 3226997Sgibbs *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3326997Sgibbs *DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3413177Sgibbs *OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3541816Sgibbs *HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3626997Sgibbs *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 374568Sgibbs *OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3823925Sgibbs *SUCH DAMAGE. 3939220Sgibbs * 405647Sgibbs * $Id: aic7xxx.seq,v 1.71 1997/04/14 02:26:59 gibbs Exp $ 4113177Sgibbs * 4219164Sgibbs *-M************************************************************************/ 4319164Sgibbs 4413690Sgibbs#include <dev/aic7xxx/aic7xxx.reg> 4513690Sgibbs#include <scsi/scsi_message.h> 4613690Sgibbs 4713690Sgibbs/* 4813690Sgibbs * A few words on the waiting SCB list: 4913690Sgibbs * 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 5219164Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection 5319164Sgibbs * on just in case the reselection wins so that we can retry the selection at 5419164Sgibbs * a later time. This problem cannot be resolved by holding a single entry 5519164Sgibbs * in scratch ram since a reconnecting target can request sense and this will 5619164Sgibbs * create yet another SCB waiting for selection. The solution used here is to 5713177Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list 584568Sgibbs * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, 5914449Sgibbs * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to 6023925Sgibbs * this list everytime a request sense occurs or after completing a non-tagged 6141646Sgibbs * command for which a second SCB has been queued. The sequencer will 6223925Sgibbs * automatically consume the entries. 6341816Sgibbs */ 6439220Sgibbs 6539220Sgibbs/* 6639220Sgibbs * We assume that the kernel driver may reset us at any time, even in the 6739220Sgibbs * middle of a DMA, so clear DFCNTRL too. 6839220Sgibbs */ 6939220Sgibbsreset: 7039220Sgibbs clr SCSISIGO; /* De-assert BSY */ 7123925Sgibbs /* Always allow reselection */ 728104Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; 7339220Sgibbs call clear_target_state; 7439220Sgibbspoll_for_work: 7539220Sgibbs test SSTAT0,SELDO jnz select; 7639220Sgibbs test SSTAT0,SELDI jnz reselect; 7739220Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 7839220Sgibbs.if ( TWIN_CHANNEL ) 7939220Sgibbs /* 8039220Sgibbs * Twin channel devices cannot handle things like SELTO 8139220Sgibbs * interrupts on the "background" channel. So, if we 8223925Sgibbs * are selecting, keep polling the current channel util 8339220Sgibbs * either a selection or reselection occurs. 8439220Sgibbs */ 8539220Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 8639220Sgibbs test SSTAT0,SELDO jnz select; 8739220Sgibbs test SSTAT0,SELDI jnz reselect; 8839220Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 8939220Sgibbs xor SBLKCTL,SELBUSB; /* Toggle back */ 9039220Sgibbs.endif 9139220Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 9239220Sgibbstest_queue: 9339220Sgibbs /* Has the driver posted any work for us? */ 9439220Sgibbs mov A, QCNTMASK; 9523925Sgibbs test QINCNT,A jz poll_for_work; 9619164Sgibbs 9719164Sgibbs/* 9839220Sgibbs * We have at least one queued SCB now and we don't have any 9939220Sgibbs * SCBs in the list of SCBs awaiting selection. If we have 10039220Sgibbs * any SCBs available for use, pull the tag from the QINFIFO 10139220Sgibbs * and get to work on it. 10239220Sgibbs */ 10339220Sgibbs.if ( SCB_PAGING ) 10439220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 10539220Sgibbs cmp SINDEX, SCB_LIST_NULL je poll_for_work; 10639220Sgibbs.endif 10739220Sgibbsdequeue_scb: 1084568Sgibbs mov CUR_SCBID,QINFIFO; 10913690Sgibbs.if !( SCB_PAGING ) 11013690Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 11119164Sgibbs mov SCBPTR, CUR_SCBID; 11223925Sgibbs.endif 11319164Sgibbsdma_queued_scb: 11413177Sgibbs/* 11539220Sgibbs * DMA the SCB from host ram into the current SCB location. 11639220Sgibbs */ 11739220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 11839220Sgibbs mov CUR_SCBID call dma_scb; 11919164Sgibbs 12039220Sgibbs/* 12139220Sgibbs * See if there is not already an active SCB for this target. This code 12239220Sgibbs * locks out on a per target basis instead of target/lun. Although this 12339220Sgibbs * is not ideal for devices that have multiple luns active at the same 12439220Sgibbs * time, it is faster than looping through all SCB's looking for active 12539220Sgibbs * commands. We also don't have enough spare SCB space for us to store the 12639220Sgibbs * SCBID of the currently busy transaction for each target/lun making it 12719164Sgibbs * impossible to link up the SCBs. 12819164Sgibbs */ 12919164Sgibbstest_busy: 13019164Sgibbs test SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb; 13123925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 13239220Sgibbs mov SAVED_SCBPTR, SCBPTR; 1334568Sgibbs mov SCB_TCL call index_untagged_scb; 13413177Sgibbs mov ARG_1, SINDIR; /* 13539220Sgibbs * ARG_1 should 13639220Sgibbs * now have the SCB ID of 13739220Sgibbs * any active, non-tagged, 13839220Sgibbs * command for this target. 13913177Sgibbs */ 14039220Sgibbs cmp ARG_1, SCB_LIST_NULL je make_busy; 14139220Sgibbs.if ( SCB_PAGING ) 14239220Sgibbs /* 14339220Sgibbs * Put this SCB back onto the free list. It 14439220Sgibbs * may be necessary to satisfy the search for 14539220Sgibbs * the active SCB. 14639220Sgibbs */ 14739220Sgibbs mov SCBPTR, SAVED_SCBPTR; 1484568Sgibbs call add_scb_to_free_list; 1495326Sgibbs /* Find the active SCB */ 15019164Sgibbs mov ALLZEROS call findSCB; 15119164Sgibbs /* 15219164Sgibbs * If we couldn't find it, tell the kernel. This should 15319164Sgibbs * never happen. 15423925Sgibbs */ 15523925Sgibbs cmp SINDEX, SCB_LIST_NULL jne paged_busy_link; 15623925Sgibbs mvi INTSTAT, NO_MATCH_BUSY; 15723925Sgibbspaged_busy_link: 15839220Sgibbs /* Link us in */ 15923925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 16023925Sgibbs /* Put it back on the disconnected list */ 16123925Sgibbs call add_scb_to_disc_list; 16223925Sgibbs mvi SEQCTL, FASTMODE; 1638104Sgibbs jmp poll_for_work; 16423925Sgibbs.else 16539220Sgibbssimple_busy_link: 16639220Sgibbs mov SCBPTR, ARG_1; 16739220Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 16839220Sgibbs mvi SEQCTL, FASTMODE; 16939220Sgibbs jmp poll_for_work; 17039220Sgibbs.endif 17123925Sgibbsmake_busy: 17239220Sgibbs mov DINDIR, CUR_SCBID; 17339220Sgibbs mov SCBPTR, SAVED_SCBPTR; 17439220Sgibbs mvi SEQCTL, FASTMODE; 17539220Sgibbs 17639220Sgibbsstart_scb: 17739220Sgibbs /* 17839220Sgibbs * Place us on the waiting list in case our selection 17939220Sgibbs * doesn't win during bus arbitration. 18039220Sgibbs */ 18141816Sgibbs mov SCB_NEXT,WAITING_SCBH; 18239220Sgibbs mov WAITING_SCBH, SCBPTR; 18341816Sgibbsstart_waiting: 18441816Sgibbs /* 18539220Sgibbs * Pull the first entry off of the waiting SCB list 18641816Sgibbs * We don't have to "test_busy" because only transactions that 18739220Sgibbs * have passed that test can be in the WAITING_SCB list. 18813177Sgibbs */ 18939220Sgibbs mov SCBPTR, WAITING_SCBH; 19039220Sgibbs call start_selection; 19139220Sgibbs jmp poll_for_work; 19239220Sgibbs 19339220Sgibbsstart_selection: 19439220Sgibbs.if ( TWIN_CHANNEL ) 19539220Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */ 19639220Sgibbs and A,SELBUSB,SCB_TCL; /* Get new channel bit */ 19739220Sgibbs or SINDEX,A; 19839220Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 19939220Sgibbs.endif 20039220Sgibbsinitialize_scsiid: 20139220Sgibbs and A, TID, SCB_TCL; /* Get target ID */ 20239220Sgibbs and SCSIID, OID; /* Clear old target */ 20339220Sgibbs or SCSIID, A; 20439220Sgibbs mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; 20539220Sgibbs/* 20639220Sgibbs * Reselection has been initiated by a target. Make a note that we've been 20739220Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 20839220Sgibbs */ 20939220Sgibbsreselect: 21039220Sgibbs clr MSG_LEN; /* Don't have anything in the mesg buffer */ 21139220Sgibbs mvi CLRSINT0, CLRSELDI; 21239220Sgibbs /* XXX test for and handle ONE BIT condition */ 21339220Sgibbs and SAVED_TCL, SELID_MASK, SELID; 21439220Sgibbs or SEQ_FLAGS,RESELECTED; 21541646Sgibbs jmp select2; 21641646Sgibbs 21741646Sgibbs/* 21839220Sgibbs * After the selection, remove this SCB from the "waiting SCB" 21939220Sgibbs * list. This is achieved by simply moving our "next" pointer into 22039220Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 22139220Sgibbs * SCB is used, so don't bother with it now. 22239220Sgibbs */ 22341646Sgibbsselect: 22439220Sgibbs /* Turn off the selection hardware */ 22541646Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* 22639220Sgibbs * ATN on parity errors 22739220Sgibbs * for "in" phases 22839220Sgibbs */ 22939220Sgibbs mvi CLRSINT0, CLRSELDO; 23039220Sgibbs mov SCBPTR, WAITING_SCBH; 23139220Sgibbs mov WAITING_SCBH,SCB_NEXT; 23239220Sgibbs mov SAVED_TCL, SCB_TCL; 23339220Sgibbs/* 23439220Sgibbs * As soon as we get a successful selection, the target should go 23539220Sgibbs * into the message out phase since we have ATN asserted. Prepare 23639220Sgibbs * the message to send. 23741299Sgibbs * 23839220Sgibbs * Messages are stored in scratch RAM starting with a length byte 23939220Sgibbs * followed by the message itself. 24041299Sgibbs */ 24141299Sgibbs 24241299Sgibbsmk_identify: 24339220Sgibbs and MSG_OUT,0x7,SCB_TCL; /* lun */ 24439220Sgibbs and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ 24539220Sgibbs or MSG_OUT,A; /* or in disconnect privledge */ 24639220Sgibbs or MSG_OUT,MSG_IDENTIFYFLAG; 24739220Sgibbs mvi MSG_LEN, 1; 24839220Sgibbs 24939220Sgibbs/* 25039220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 25139220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 25239220Sgibbs */ 25339220Sgibbsmk_tag: 25439220Sgibbs test SCB_CONTROL,TAG_ENB jz mk_message; 25539220Sgibbs and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 25639220Sgibbs mov MSG_OUT[2],SCB_TAG; 25739220Sgibbs add MSG_LEN,2; /* update message length */ 25839220Sgibbs 25939220Sgibbs/* 26039220Sgibbs * Interrupt the driver, and allow it to tweak the message buffer 26139220Sgibbs * if it asks. 26239220Sgibbs */ 26339220Sgibbsmk_message: 26439220Sgibbs test SCB_CONTROL,MK_MESSAGE jz select2; 26539220Sgibbs mvi INTSTAT,AWAITING_MSG; 26639220Sgibbs 26739220Sgibbsselect2: 26839220Sgibbs mvi CLRSINT1,CLRBUSFREE; 26939220Sgibbs or SIMODE1, ENBUSFREE; /* 27039220Sgibbs * We aren't expecting a 27139220Sgibbs * bus free, so interrupt 27239220Sgibbs * the kernel driver if it 27339220Sgibbs * happens. 27439220Sgibbs */ 27539220Sgibbs/* 27639220Sgibbs * Initialize Ultra mode setting and clear the SCSI channel. 27739220Sgibbs */ 27839220Sgibbs or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN; 27939220Sgibbs.if ( ULTRA ) 28039220Sgibbsultra: 28139220Sgibbs mvi SINDEX, ULTRA_ENB+1; 28239220Sgibbs test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ 28339220Sgibbs dec SINDEX; 28439220Sgibbsultra_2: 28539220Sgibbs mov FUNCTION1,SAVED_TCL; 28639220Sgibbs mov A,FUNCTION1; 28741646Sgibbs test SINDIR, A jz ndx_dtr; 28839220Sgibbs or SXFRCTL0, FAST20; 28939220Sgibbs.endif 29039220Sgibbs 29139220Sgibbs/* 29239220Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 29341299Sgibbs * The SCSIRATE settings for each target are stored in an array 29439220Sgibbs * based at TARG_SCRATCH. 29539220Sgibbs */ 29639220Sgibbsndx_dtr: 29739220Sgibbs shr A,4,SAVED_TCL; 29839220Sgibbs test SBLKCTL,SELBUSB jz ndx_dtr_2; 29939220Sgibbs or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */ 30039220Sgibbs or A,0x08; /* Channel B entries add 8 */ 30139220Sgibbsndx_dtr_2: 30239220Sgibbs add SINDEX,TARG_SCRATCH,A; 30339220Sgibbs mov SCSIRATE,SINDIR; 30439220Sgibbs 30539220Sgibbs 30639220Sgibbs/* 30739220Sgibbs * Main loop for information transfer phases. If BSY is false, then 30841646Sgibbs * we have a bus free condition, expected or not. Otherwise, wait 30939220Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O 31039220Sgibbs * for the bus phase. 31139220Sgibbs * 31239220Sgibbs */ 31339220SgibbsITloop: 31439220Sgibbs test SSTAT1,REQINIT jz ITloop; 31539220Sgibbs test SSTAT1, SCSIPERR jnz ITloop; 31639220Sgibbs 31739220Sgibbs and A,PHASE_MASK,SCSISIGI; 31839220Sgibbs mov LASTPHASE,A; 31939220Sgibbs mov SCSISIGO,A; 32039220Sgibbs 32139220Sgibbs cmp ALLZEROS,A je p_dataout; 32239220Sgibbs cmp A,P_DATAIN je p_datain; 32339220Sgibbs cmp A,P_COMMAND je p_command; 32439220Sgibbs cmp A,P_MESGOUT je p_mesgout; 32539220Sgibbs cmp A,P_STATUS je p_status; 32639220Sgibbs cmp A,P_MESGIN je p_mesgin; 32739220Sgibbs 32839220Sgibbs mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ 32939220Sgibbs jmp ITloop; /* Try reading the bus again. */ 33039220Sgibbs 33139220Sgibbsawait_busfree: 33239220Sgibbs and SIMODE1, ~ENBUSFREE; 33339220Sgibbs call clear_target_state; 33439220Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 33541646Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 33639220Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 33739220Sgibbs mvi INTSTAT, BAD_PHASE; 33839220Sgibbs 33939220Sgibbsclear_target_state: 34039220Sgibbs clr DFCNTRL; 34139220Sgibbs clr SCSIRATE; /* 34239220Sgibbs * We don't know the target we will 34341646Sgibbs * connect to, so default to narrow 34441646Sgibbs * transfers to avoid parity problems. 34541646Sgibbs */ 34641646Sgibbs and SXFRCTL0, ~FAST20; 34741646Sgibbs mvi LASTPHASE, P_BUSFREE; 34841646Sgibbs /* clear target specific flags */ 34941646Sgibbs and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret; 35041646Sgibbs 35141646Sgibbsp_dataout: 35241646Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET; 35341646Sgibbs jmp data_phase_init; 35441646Sgibbs 35541646Sgibbs/* 35641646Sgibbs * If we re-enter the data phase after going through another phase, the 35741646Sgibbs * STCNT may have been cleared, so restore it from the residual field. 35841646Sgibbs */ 35939220Sgibbsdata_phase_reinit: 36039220Sgibbs mvi DINDEX, STCNT; 36139220Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 36239220Sgibbs jmp data_phase_loop; 36339220Sgibbs 36439220Sgibbsp_datain: 36539220Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 36639220Sgibbsdata_phase_init: 36739220Sgibbs call assert; /* 36839220Sgibbs * Ensure entering a data 36939220Sgibbs * phase is okay - seen identify, etc. 37039220Sgibbs */ 37139220Sgibbs 37239220Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 37339220Sgibbs 37439220Sgibbs /* 37539220Sgibbs * Initialize the DMA address and counter from the SCB. 37639220Sgibbs * Also set SG_COUNT and SG_NEXT in memory since we cannot 37739220Sgibbs * modify the values in the SCB itself until we see a 37839220Sgibbs * save data pointers message. 37939220Sgibbs */ 38041646Sgibbs mvi DINDEX, HADDR; 38139220Sgibbs mvi SCB_DATAPTR call bcopy_7; 38239220Sgibbs 38339220Sgibbs call set_stcnt_from_hcnt; 38439220Sgibbs 38539220Sgibbs mov SG_COUNT,SCB_SGCOUNT; 38639220Sgibbs 38739220Sgibbs mvi DINDEX, SG_NEXT; 38841646Sgibbs mvi SCB_SGPTR call bcopy_4; 38941646Sgibbs 39041646Sgibbsdata_phase_loop: 39141646Sgibbs/* Guard against overruns */ 39239220Sgibbs test SG_COUNT, 0xff jnz data_phase_inbounds; 39339220Sgibbs/* 39439220Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to 39539220Sgibbs * 16meg and let the target run until it changes phase. 39639220Sgibbs * When the transfer completes, notify the host that we 39741646Sgibbs * had an overrun. 39839220Sgibbs */ 39939220Sgibbs or SXFRCTL1,BITBUCKET; 40039220Sgibbs mvi HCNT[0], 0xff; 40141646Sgibbs mvi HCNT[1], 0xff; 40239220Sgibbs mvi HCNT[2], 0xff; 40323925Sgibbs call set_stcnt_from_hcnt; 40423925Sgibbs 40513177Sgibbsdata_phase_inbounds: 40639220Sgibbs/* If we are the last SG block, ensure wideodd is off. */ 40723925Sgibbs cmp SG_COUNT,0x01 jne data_phase_wideodd; 40823925Sgibbs and DMAPARAMS, ~WIDEODD; 40939545Sgibbsdata_phase_wideodd: 41039545Sgibbs mov DMAPARAMS call dma; 41139545Sgibbs 41239545Sgibbs/* Go tell the host about any overruns */ 41341646Sgibbs test SXFRCTL1,BITBUCKET jnz data_phase_overrun; 41439220Sgibbs 41539220Sgibbs/* Exit if we had an underrun. dma clears SINDEX in this case. */ 41639220Sgibbs test SINDEX,0xff jz data_phase_finish; 41739220Sgibbs 41839220Sgibbs/* 41939220Sgibbs * Advance the scatter-gather pointers if needed 42039220Sgibbs */ 42139220Sgibbssg_advance: 42239220Sgibbs dec SG_COUNT; /* one less segment to go */ 42341646Sgibbs 4244568Sgibbs test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ 42513177Sgibbs 42623925Sgibbs clr A; /* add sizeof(struct scatter) */ 42723925Sgibbs add SG_NEXT[0],SG_SIZEOF; 42823925Sgibbs adc SG_NEXT[1],A; 42923925Sgibbs 43023925Sgibbs/* 43139220Sgibbs * Load a struct scatter and set up the data address and length. 43225005Sgibbs * If the working value of the SG count is nonzero, then 43341816Sgibbs * we need to load a new set of values. 43425005Sgibbs * 43525005Sgibbs * This, like all DMA's, assumes little-endian host data storage. 43624914Sgibbs */ 43723925Sgibbssg_load: 43839220Sgibbs mvi DINDEX, HADDR; 43939220Sgibbs mvi SG_NEXT call bcopy_4; 4408567Sdg 44139220Sgibbs mvi HCNT[0],SG_SIZEOF; 44239220Sgibbs clr HCNT[1]; 44339220Sgibbs clr HCNT[2]; 44439220Sgibbs 44539220Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 44641646Sgibbs 44741646Sgibbs call dma_finish; 4484568Sgibbs 44939220Sgibbs/* 45039220Sgibbs * Copy data from FIFO into SCB data pointer and data count. This assumes 45139220Sgibbs * that the SG segments are of the form: 45239220Sgibbs * 45339220Sgibbs * struct ahc_dma_seg { 4546608Sgibbs * u_int32_t addr; four bytes, little-endian order 45539220Sgibbs * u_int32_t len; four bytes, little endian order 45639220Sgibbs * }; 45739220Sgibbs */ 45839220Sgibbs mvi HADDR call dfdat_in_7; 45939220Sgibbs 46039220Sgibbs/* Load STCNT as well. It is a mirror of HCNT */ 46139220Sgibbs call set_stcnt_from_hcnt; 46239220Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 46339220Sgibbs 46439220Sgibbsdata_phase_finish: 46539220Sgibbs/* 46639220Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB 46739220Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 46839220Sgibbs * were transferred on the SCSI (as opposed to the host) bus. 46939220Sgibbs */ 47039220Sgibbs mov SCB_RESID_DCNT[0],STCNT[0]; 47141646Sgibbs mov SCB_RESID_DCNT[1],STCNT[1]; 47241646Sgibbs mov SCB_RESID_DCNT[2],STCNT[2]; 47339220Sgibbs mov SCB_RESID_SGCNT, SG_COUNT; 47441646Sgibbs 47539220Sgibbs /* We have seen a data phase */ 47639220Sgibbs or SEQ_FLAGS, DPHASE; 47739220Sgibbs 47839220Sgibbs jmp ITloop; 47939220Sgibbs 48039220Sgibbsdata_phase_overrun: 48139220Sgibbs/* 48239220Sgibbs * Turn off BITBUCKET mode and notify the host 48339220Sgibbs */ 48439220Sgibbs and SXFRCTL1, ~BITBUCKET; 48539220Sgibbs mvi INTSTAT,DATA_OVERRUN; 48639220Sgibbs jmp ITloop; 48741646Sgibbs 48839220Sgibbs/* 48941646Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 49039220Sgibbs */ 49139220Sgibbsp_command: 49239220Sgibbs call assert; 49339220Sgibbs 49441646Sgibbs/* 49541646Sgibbs * Load HADDR and HCNT. 49641646Sgibbs */ 49741646Sgibbs mvi DINDEX, HADDR; 49841646Sgibbs mvi SCB_CMDPTR call bcopy_5; 49941646Sgibbs clr HCNT[1]; 50041646Sgibbs clr HCNT[2]; 50139220Sgibbs 50241646Sgibbs call set_stcnt_from_hcnt; 50341816Sgibbs 50441816Sgibbs mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; 50539220Sgibbs jmp ITloop; 50639220Sgibbs 50739220Sgibbs/* 50839220Sgibbs * Status phase. Wait for the data byte to appear, then read it 50939220Sgibbs * and store it into the SCB. 51039220Sgibbs */ 51139220Sgibbsp_status: 51239220Sgibbs call assert; 51339220Sgibbs 51439220Sgibbs mov SCB_TARGET_STATUS, SCSIDATL; 51539220Sgibbs jmp ITloop; 51641646Sgibbs 51741646Sgibbs/* 51839220Sgibbs * Message out phase. If there is not an active message, but the target 51939220Sgibbs * took us into this phase anyway, build a no-op message and send it. 52039220Sgibbs */ 52139220Sgibbsp_mesgout: 52239220Sgibbs test MSG_LEN, 0xff jnz p_mesgout_start; 52339220Sgibbs mvi MSG_NOOP call mk_mesg; /* build NOP message */ 52439220Sgibbsp_mesgout_start: 52539220Sgibbs/* 52639220Sgibbs * Set up automatic PIO transfer from MSG_OUT. Bit 3 in 52739220Sgibbs * SXFRCTL0 (SPIOEN) is already on. 52841299Sgibbs */ 52941299Sgibbs mvi SINDEX,MSG_OUT; 53041299Sgibbs mov DINDEX,MSG_LEN; 53141299Sgibbs 53241299Sgibbs/* 53339220Sgibbs * When target asks for a byte, drop ATN if it's the last one in 53439220Sgibbs * the message. Otherwise, keep going until the message is exhausted. 53539220Sgibbs * ATN must be dropped *at least* 90ns before we ack the last byte, so 53639220Sgibbs * the code is aranged to execute two instructions before the byte is 53739220Sgibbs * transferred to give a good margin of safety 53839220Sgibbs * 53939220Sgibbs * Keep an eye out for a phase change, in case the target issues 54039220Sgibbs * a MESSAGE REJECT. 54139220Sgibbs */ 54239220Sgibbsp_mesgout_loop: 54339220Sgibbs test SSTAT1, REQINIT jz p_mesgout_loop; 54439220Sgibbs test SSTAT1, SCSIPERR jnz p_mesgout_loop; 54539220Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 54639220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 54739220Sgibbsp_mesgout_testretry: 54839220Sgibbs test DINDEX,0xff jnz p_mesgout_dropatn; 54939220Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 55039220Sgibbs jmp p_mesgout_start; 55139220Sgibbs/* 55239220Sgibbs * If the next bus phase after ATN drops is a message out, it means 55339220Sgibbs * that the target is requesting that the last message(s) be resent. 55439220Sgibbs */ 55539220Sgibbsp_mesgout_dropatn: 55639220Sgibbs cmp DINDEX,1 jne p_mesgout_outb; /* last byte? */ 55739220Sgibbs mvi CLRSINT1,CLRATNO; /* drop ATN */ 55839220Sgibbsp_mesgout_outb: 55939220Sgibbs dec DINDEX; 56039220Sgibbs mov SCSIDATL,SINDIR; 56141646Sgibbs jmp p_mesgout_loop; 56239220Sgibbs 56339220Sgibbsp_mesgout_done: 56441646Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 56539220Sgibbs clr MSG_LEN; /* no active msg */ 56639220Sgibbs jmp ITloop; 56741646Sgibbs 56839220Sgibbs/* 56939220Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 57039220Sgibbs */ 57141646Sgibbsp_mesgin: 57241646Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 57339220Sgibbs mov REJBYTE,A; /* save it for the driver */ 57441646Sgibbs 57539220Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 57639220Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 57739220Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 57839220Sgibbs cmp ALLZEROS,A je mesgin_complete; 57939220Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 58039220Sgibbs cmp A,MSG_EXTENDED je mesgin_extended; 58139220Sgibbs cmp A,MSG_MESSAGE_REJECT je mesgin_reject; 58239220Sgibbs cmp A,MSG_NOOP je mesgin_done; 58339220Sgibbs 58441299Sgibbsrej_mesgin: 58541299Sgibbs/* 58641299Sgibbs * We have no idea what this message in is, so we issue a message reject 58741299Sgibbs * and hope for the best. In any case, rejection should be a rare 58839220Sgibbs * occurrence - signal the driver when it happens. 58939220Sgibbs */ 59039220Sgibbs mvi INTSTAT,SEND_REJECT; /* let driver know */ 59139220Sgibbs 59241299Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 59341299Sgibbs 59441299Sgibbsmesgin_done: 59541299Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 59641299Sgibbs jmp ITloop; 59741299Sgibbs 59841299Sgibbs 59939220Sgibbsmesgin_complete: 60039220Sgibbs/* 60139220Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, 60241299Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 60341299Sgibbs * is a residual or the status byte is something other than NO_ERROR (0). In 60439220Sgibbs * either of these conditions, we upload the SCB back to the host so it can 60541646Sgibbs * process this information. In the case of a non zero status byte, we 60641646Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 60739220Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 60839220Sgibbs * sense, it will fill the kernel SCB with a request sense command and set 60941646Sgibbs * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload 61041646Sgibbs * the SCB, and process it as the next command by adding it to the waiting list. 61141646Sgibbs * If the kernel driver does not wish to request sense, it need only clear 61241646Sgibbs * RETURN_1, and the command is allowed to complete normally. We don't bother 61341646Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra 61425005Sgibbs * work in the kernel driver to ensure that the entry was removed before the 61539220Sgibbs * command complete code tried processing it. 61641646Sgibbs */ 61741646Sgibbs 61841646Sgibbs/* 61941646Sgibbs * First check for residuals 62041646Sgibbs */ 62141646Sgibbs test SCB_RESID_SGCNT,0xff jnz upload_scb; 62239220Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */ 62339220Sgibbsupload_scb: 62413177Sgibbs mvi DMAPARAMS, FIFORESET; 62541646Sgibbs mov SCB_TAG call dma_scb; 62641646Sgibbscheck_status: 62741646Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */ 62841646Sgibbs mvi INTSTAT,BAD_STATUS; /* let driver know */ 62941646Sgibbs cmp RETURN_1, SEND_SENSE jne status_ok; 6304568Sgibbs /* This SCB becomes the next to execute as it will retrieve sense */ 63139220Sgibbs mov SCB_LINKED_NEXT, SCB_TAG; 6324568Sgibbs jmp dma_next_scb; 63339220Sgibbs 6344568Sgibbsstatus_ok: 63539220Sgibbs/* First, mark this target as free. */ 63623925Sgibbs test SCB_CONTROL,TAG_ENB jnz complete; /* 63723925Sgibbs * Tagged commands 63823925Sgibbs * don't busy the 63923925Sgibbs * target. 6404568Sgibbs */ 64141646Sgibbs mov SAVED_SCBPTR, SCBPTR; 64223925Sgibbs mov SAVED_LINKPTR, SCB_LINKED_NEXT; 6434568Sgibbs mov SCB_TCL call index_untagged_scb; 64423925Sgibbs mov DINDIR, SAVED_LINKPTR; 64523925Sgibbs mov SCBPTR, SAVED_SCBPTR; 64624794Sgibbs 64723925Sgibbscomplete: 64839220Sgibbs /* 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; 65241646Sgibbs mvi INTSTAT, ABORT_CMDCMPLT; 65323925Sgibbs 65423925Sgibbsdma_next_scb: 65541646Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list; 65641646Sgibbs.if !( SCB_PAGING ) 65741646Sgibbs /* Only DMA on top of ourselves if we are the SCB to download */ 65841646Sgibbs mov A, SCB_LINKED_NEXT; 65941646Sgibbs cmp SCB_TAG, A je dma_next_scb2; 66041646Sgibbs call add_scb_to_free_list; 66141646Sgibbs mov SCBPTR, A; 66241646Sgibbs jmp add_to_waiting_list; 66341646Sgibbs.endif 66441646Sgibbsdma_next_scb2: 66541646Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 66641646Sgibbs mov SCB_LINKED_NEXT call dma_scb; 66741646Sgibbsadd_to_waiting_list: 66841646Sgibbs mov SCB_NEXT,WAITING_SCBH; 66941646Sgibbs mov WAITING_SCBH, SCBPTR; 67041646Sgibbs /* 67141646Sgibbs * Prepare our selection hardware before the busfree so we have a 67241646Sgibbs * high probability of winning arbitration. 67323925Sgibbs */ 67423925Sgibbs call start_selection; 67539220Sgibbs jmp await_busfree; 67623925Sgibbsadd_to_free_list: 67713177Sgibbs call add_scb_to_free_list; 67813177Sgibbs jmp await_busfree; 67913177Sgibbs 68013177Sgibbs/* 6819928Sgibbs * Is it an extended message? Copy the message to our message buffer and 68239220Sgibbs * notify the host. The host will tell us whether to reject this message, 68339220Sgibbs * respond to it with the message that the host placed in our message buffer, 68439220Sgibbs * or simply to do nothing. 68539220Sgibbs */ 68639220Sgibbsmesgin_extended: 68739220Sgibbs mvi MSGIN_EXT_LEN call inb_next; 68823925Sgibbs mov A, MSGIN_EXT_LEN; 6894568Sgibbsmesgin_extended_loop: 69039220Sgibbs mov DINDEX call inb_next; 69139220Sgibbs dec A; 69239220Sgibbs cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test; 69339220Sgibbs dec DINDEX; /* dump by repeatedly filling the last byte */ 69439220Sgibbsmesgin_extended_loop_test: 69539220Sgibbs test A, 0xFF jnz mesgin_extended_loop; 69639220Sgibbsmesgin_extended_intr: 69739220Sgibbs mvi INTSTAT,EXTENDED_MSG; /* let driver know */ 69823925Sgibbs cmp RETURN_1,SEND_REJ je rej_mesgin; 69919164Sgibbs cmp RETURN_1,SEND_MSG jne mesgin_done; 70019164Sgibbs/* The kernel has setup a message to be sent */ 70119164Sgibbs or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */ 70239220Sgibbs jmp mesgin_done; 70339220Sgibbs 70439220Sgibbs/* 70523925Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 7064568Sgibbs * and await the bus going free. 70739220Sgibbs */ 70839220Sgibbsmesgin_disconnect: 70939220Sgibbs or SCB_CONTROL,DISCONNECTED; 71019164Sgibbs.if ( SCB_PAGING ) 71119164Sgibbs call add_scb_to_disc_list; 71219164Sgibbs.endif 71319164Sgibbs jmp await_busfree; 71419164Sgibbs 71519164Sgibbs/* 71639220Sgibbs * Save data pointers message: 71739220Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 71839220Sgibbs * only if we've actually been into a data phase to change them. This 71939220Sgibbs * protects against bogus data in scratch ram and the residual counts 72039220Sgibbs * since they are only initialized when we go into data_in or data_out. 72139220Sgibbs */ 72219164Sgibbsmesgin_sdptrs: 72339220Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 72439220Sgibbs mov SCB_SGCOUNT,SG_COUNT; 72539220Sgibbs 72639220Sgibbs /* The SCB SGPTR becomes the next one we'll download */ 72739220Sgibbs mvi DINDEX, SCB_SGPTR; 72839220Sgibbs mvi SG_NEXT call bcopy_4; 72939220Sgibbs 73019164Sgibbs /* The SCB DATAPTR0 becomes the current SHADDR */ 73139220Sgibbs mvi DINDEX, SCB_DATAPTR; 73239220Sgibbs mvi SHADDR call bcopy_4; 73339220Sgibbs 73439220Sgibbs/* 73539220Sgibbs * Use the residual number since STCNT is corrupted by any message transfer. 73639220Sgibbs */ 73719164Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 7389928Sgibbs 73916260Sgibbs jmp mesgin_done; 74023925Sgibbs 74116260Sgibbs/* 74216260Sgibbs * Restore pointers message? Data pointers are recopied from the 74316260Sgibbs * SCB anytime we enter a data phase for the first time, so all 74416260Sgibbs * we need to do is clear the DPHASE flag and let the data phase 74516260Sgibbs * code do the rest. 74616260Sgibbs */ 74723925Sgibbsmesgin_rdptrs: 74839220Sgibbs and SEQ_FLAGS, ~DPHASE; /* 74939220Sgibbs * We'll reload them 75039220Sgibbs * the next time through 75139220Sgibbs * the dataphase. 75239220Sgibbs */ 75339220Sgibbs jmp mesgin_done; 75439220Sgibbs 75539220Sgibbs/* 75639220Sgibbs * Identify message? For a reconnecting target, this tells us the lun 75739220Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 75816260Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 75939220Sgibbs */ 76023925Sgibbsmesgin_identify: 76139220Sgibbs test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/ 76239220Sgibbs and A,0x07; /* lun in lower three bits */ 76339220Sgibbs or SAVED_TCL,A; /* SAVED_TCL should be complete now */ 76439220Sgibbs mov SAVED_TCL call index_untagged_scb; 76539220Sgibbs mov ARG_1, SINDIR; 7669928Sgibbs.if ( SCB_PAGING ) 76739220Sgibbs cmp ARG_1,SCB_LIST_NULL jne use_findSCB; 76839220Sgibbs.else 76939220Sgibbs cmp ARG_1,SCB_LIST_NULL je snoop_tag; 77039220Sgibbs /* Directly index the SCB */ 77139220Sgibbs mov SCBPTR,ARG_1; 77239220Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 77339220Sgibbs jmp setup_SCB; 77439220Sgibbs.endif 77539220Sgibbs/* 77639220Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 77739220Sgibbs * If we get one, we use the tag returned to find the proper 77839220Sgibbs * SCB. With SCB paging, this requires using findSCB for both tagged 77939220Sgibbs * and non-tagged transactions since the SCB may exist in any slot. 7804568Sgibbs * If we're not using SCB paging, we can use the tag as the direct 78139220Sgibbs * index to the SCB. 78216260Sgibbs */ 78323925Sgibbssnoop_tag: 78416260Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 78522451Sgibbssnoop_tag_loop: 78623925Sgibbs test SSTAT1,REQINIT jz snoop_tag_loop; 7877532Sgibbs test SSTAT1, SCSIPERR jnz snoop_tag_loop; 78813177Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 78913177Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 79013177Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 7919928Sgibbsget_tag: 79223925Sgibbs or SEQ_FLAGS, TAGGED_SCB; 7934568Sgibbs mvi ARG_1 call inb_next; /* tag value */ 79423925Sgibbs/* 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 */ 79913177Sgibbs mov A,COMP_SCBCOUNT; 80015328Sgibbs add SINDEX,A,ARG_1; 80113177Sgibbs jc not_found; 8029928Sgibbs 80339220Sgibbs.if ! ( SCB_PAGING ) 80439220Sgibbsindex_by_tag: 80539220Sgibbs mov SCBPTR,ARG_1; 80639220Sgibbs mov A, SAVED_TCL; 80739220Sgibbs cmp SCB_TCL,A jne not_found; 8084568Sgibbs test SCB_CONTROL,TAG_ENB jz not_found; 80939220Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 81039220Sgibbs.else 81139220Sgibbs/* 81239220Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction 81339220Sgibbs * to the reconnecting target. 81439220Sgibbs */ 81539220Sgibbsuse_findSCB: 81639220Sgibbs mov ALLZEROS call findSCB; /* Have to search */ 81739220Sgibbs cmp SINDEX, SCB_LIST_NULL je not_found; 81839220Sgibbs.endif 81939220Sgibbssetup_SCB: 82039220Sgibbs and SCB_CONTROL,~DISCONNECTED; 82139220Sgibbs or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 82239220Sgibbs jmp mesgin_done; 82339220Sgibbs 82439220Sgibbsnot_found: 82539220Sgibbs mvi INTSTAT, NO_MATCH; 82639220Sgibbs mvi MSG_BUS_DEV_RESET call mk_mesg; 82739220Sgibbs jmp mesgin_done; 82822568Sgibbs 82939220Sgibbs/* 83039220Sgibbs * Message reject? Let the kernel driver handle this. If we have an 83139220Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 8329928Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 83339220Sgibbs * it since we have no clue what it pertains to. 8349928Sgibbs */ 83539220Sgibbsmesgin_reject: 8369928Sgibbs mvi INTSTAT, REJECT_MSG; 83739220Sgibbs jmp mesgin_done; 83839220Sgibbs 83939220Sgibbs/* 84039220Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ] 84139220Sgibbs */ 84239220Sgibbs 84339220Sgibbs/* 84439220Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX 84539220Sgibbs * if there is no active message already. SINDEX is returned intact. 84639220Sgibbs */ 84739220Sgibbsmk_mesg: 84839220Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 84939220Sgibbs test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */ 85039220Sgibbs 85139220Sgibbs /* 85239220Sgibbs * Hmmm. For some reason the mesg buffer is in use. 85339220Sgibbs * Tell the driver. It should look at SINDEX to find 85439220Sgibbs * out what we wanted to use the buffer for and resolve 85539220Sgibbs * the conflict. 85639220Sgibbs */ 85739220Sgibbs mvi SEQCTL,FASTMODE; 85839220Sgibbs mvi INTSTAT,MSG_BUFFER_BUSY; 85939220Sgibbs 86039220Sgibbsmk_mesg1: 86139220Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 86241646Sgibbs mvi MSG_LEN,1; /* length = 1 */ 86341646Sgibbs mov MSG_OUT,SINDEX; /* 1-byte message */ 86441646Sgibbs mvi SEQCTL,FASTMODE ret; 86541646Sgibbs 86623925Sgibbs/* 86741646Sgibbs * Functions to read data in Automatic PIO mode. 86839220Sgibbs * 86939220Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 87039220Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 87139220Sgibbs * latched (the usual way), then read the data byte directly off the bus 8724568Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 8739928Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 87439220Sgibbs * spec guarantees that the target will hold the data byte on the bus until 87539220Sgibbs * we send our ACK. 87639220Sgibbs * 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 88239220Sgibbsinb_next: 88339220Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 88439220Sgibbsinb_next_wait: 88539220Sgibbs /* 88639220Sgibbs * If there is a parity error, wait for the kernel to 88739220Sgibbs * see the interrupt and prepare our message response 88839220Sgibbs * before continuing. 88923925Sgibbs */ 89022568Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 89139220Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait; 89239220Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 89339220Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 89422568Sgibbsinb_first: 89539220Sgibbs mov DINDEX,SINDEX; 89641646Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 89739220Sgibbsinb_last: 89839220Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 89939220Sgibbs 90023925Sgibbsmesgin_phasemis: 9014568Sgibbs/* 90216260Sgibbs * We expected to receive another byte, but the target changed phase 90339220Sgibbs */ 90439220Sgibbs mvi INTSTAT, MSGIN_PHASEMIS; 90539220Sgibbs jmp ITloop; 90639220Sgibbs 90713177Sgibbs/* 90816260Sgibbs * DMA data transfer. HADDR and HCNT must be loaded first, and 90916260Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for 91023925Sgibbs * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 91123925Sgibbs * during initialization. 91223925Sgibbs */ 91316260Sgibbsdma: 91439220Sgibbs mov DFCNTRL,SINDEX; 91539220Sgibbsdma_loop: 91639220Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 91739220Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 91839220Sgibbsdma_phasemis: 91939220Sgibbs test SSTAT0,SDONE jnz dma_checkfifo; 92039220Sgibbs mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ 92139220Sgibbs 92239220Sgibbs/* 92339220Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or 92439220Sgibbs * the target changes the phase (in light of this, it makes sense that 92539220Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 92639220Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto- 92741646Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty 92816260Sgibbs * status. 92915328Sgibbs */ 93013177Sgibbsdma_checkfifo: 9314568Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 93223925Sgibbsdma_fifoflush: 9334568Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 93439220Sgibbs 93539220Sgibbsdma_fifoempty: 93639220Sgibbs /* Don't clobber an inprogress host data transfer */ 93739220Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 93839220Sgibbs/* 93939220Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 94039220Sgibbs * actually off first lest we get an ILLSADDR. 94139220Sgibbs */ 94239220Sgibbsdma_dmadone: 94339220Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 94439220Sgibbsdma_halt: 94539220Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 94639220Sgibbsreturn: 94739220Sgibbs ret; 94839220Sgibbs 94939220Sgibbs/* 95039220Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 95139220Sgibbs * message. 95239220Sgibbs */ 95339220Sgibbsassert: 95439220Sgibbs test SEQ_FLAGS,RESELECTED jz return; /* reselected? */ 95539220Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 95639220Sgibbs 9574568Sgibbs mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ 95839220Sgibbs 95939220Sgibbs.if ( SCB_PAGING ) 96039220Sgibbs/* 96139220Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) 96239220Sgibbs * or by the SCBIDn ARG_1. The search begins at the SCB index passed in 96339220Sgibbs * via SINDEX. If the SCB cannot be found, SINDEX will be SCB_LIST_NULL, 96439220Sgibbs * otherwise, SCBPTR is set to the proper SCB. 96539220Sgibbs */ 96639220SgibbsfindSCB: 96739220Sgibbs mov SCBPTR,SINDEX; /* switch to next SCB */ 96839220Sgibbs mov A, ARG_1; /* Tag passed in ARG_1 */ 96939220Sgibbs cmp SCB_TAG,A jne findSCB_loop; 97039220Sgibbs test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/ 97123925SgibbsfindSCB_loop: 9724568Sgibbs inc SINDEX; 97313177Sgibbs mov A,SCBCOUNT; 97413177Sgibbs cmp SINDEX,A jne findSCB; 97513177Sgibbs/* 97613177Sgibbs * We didn't find it. If we're paging, pull an SCB and DMA down the 9774568Sgibbs * one we want. If we aren't paging or the SCB we dma down has the 97823925Sgibbs * abort flag set, return not found. 97919803Sgibbs */ 98023925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 98123925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 9824568Sgibbs mov ARG_1 call dma_scb; 98313177Sgibbs test SCB_CONTROL, ABORT_SCB jz return; 98441646Sgibbsfind_error: 98541646Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 98641646SgibbsfoundSCB: 98741646Sgibbs test SCB_CONTROL, ABORT_SCB jnz find_error; 98841646Sgibbsrem_scb_from_disc_list: 98941646Sgibbs/* Remove this SCB from the disconnection list */ 99041646Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev; 99141646Sgibbs mov SAVED_LINKPTR, SCB_PREV; 99239220Sgibbs mov SCBPTR, SCB_NEXT; 99339220Sgibbs mov SCB_PREV, SAVED_LINKPTR; 99441646Sgibbs mov SCBPTR, SINDEX; 99539220Sgibbsunlink_prev: 99639220Sgibbs cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */ 99739220Sgibbs mov SAVED_LINKPTR, SCB_NEXT; 99839220Sgibbs mov SCBPTR, SCB_PREV; 99941646Sgibbs mov SCB_NEXT, SAVED_LINKPTR; 100039220Sgibbs mov SCBPTR, SINDEX ret; 100139220SgibbsrHead: 100239220Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 100339220Sgibbs.else 100439220Sgibbs ret; 100539220Sgibbs.endif 100613177Sgibbs 100741646Sgibbsset_stcnt_from_hcnt: 100841646Sgibbs mov STCNT[0], HCNT[0]; 10094568Sgibbs mov STCNT[1], HCNT[1]; 101039220Sgibbs mov STCNT[2], HCNT[2] ret; 101139220Sgibbs 101241646Sgibbsbcopy_7: 101341646Sgibbs mov DINDIR, SINDIR; 101441646Sgibbs mov DINDIR, SINDIR; 101541646Sgibbsbcopy_5: 101641646Sgibbs mov DINDIR, SINDIR; 101741646Sgibbsbcopy_4: 101841646Sgibbs mov DINDIR, SINDIR; 101941646Sgibbsbcopy_3: 102041646Sgibbs mov DINDIR, SINDIR; 102141646Sgibbs mov DINDIR, SINDIR; 102241646Sgibbs mov DINDIR, SINDIR ret; 102341646Sgibbs 102441646Sgibbsdma_scb: 102539220Sgibbs /* 102641299Sgibbs * SCB index is in SINDEX. Determine the physical address in 102739220Sgibbs * the host where this SCB is located and load HADDR with it. 102839220Sgibbs */ 102939220Sgibbs shr DINDEX, 3, SINDEX; 103013177Sgibbs shl A, 5, SINDEX; 103139220Sgibbs add HADDR[0], A, HSCB_ADDR[0]; 103239220Sgibbs mov A, DINDEX; 103313177Sgibbs adc HADDR[1], A, HSCB_ADDR[1]; 103439220Sgibbs clr A; 103539220Sgibbs adc HADDR[2], A, HSCB_ADDR[2]; 103639220Sgibbs adc HADDR[3], A, HSCB_ADDR[3]; 103739220Sgibbs /* Setup Count */ 103839220Sgibbs mvi HCNT[0], 28; 103939220Sgibbs clr HCNT[1]; 104039220Sgibbs clr HCNT[2]; 104139220Sgibbs mov DFCNTRL, DMAPARAMS; 104239220Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 104313177Sgibbs /* Fill it with the SCB data */ 104441646Sgibbscopy_scb_tofifo: 104541646Sgibbs mvi SINDEX, SCB_CONTROL; 104613177Sgibbs add A, 28, SINDEX; 104739220Sgibbscopy_scb_tofifo_loop: 104839220Sgibbs mov DFDAT,SINDIR; 104941646Sgibbs mov DFDAT,SINDIR; 105039220Sgibbs mov DFDAT,SINDIR; 105139220Sgibbs mov DFDAT,SINDIR; 105239220Sgibbs mov DFDAT,SINDIR; 105339220Sgibbs mov DFDAT,SINDIR; 105439220Sgibbs mov DFDAT,SINDIR; 105513177Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 105641646Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 105713177Sgibbsdma_scb_fromhost: 105813177Sgibbs call dma_finish; 105939220Sgibbs /* If we were putting the SCB, we are done */ 106041646Sgibbs test DMAPARAMS, DIRECTION jz return; 10614568Sgibbs mvi SCB_CONTROL call dfdat_in_7; 106219906Sgibbs call dfdat_in_7_continued; 106323925Sgibbs call dfdat_in_7_continued; 106439220Sgibbs jmp dfdat_in_7_continued; 106539220Sgibbsdfdat_in_7: 106623925Sgibbs mov DINDEX,SINDEX; 10674568Sgibbsdfdat_in_7_continued: 106813177Sgibbs mov DINDIR,DFDAT; 106941646Sgibbs mov DINDIR,DFDAT; 107041646Sgibbs mov DINDIR,DFDAT; 107141646Sgibbs mov DINDIR,DFDAT; 107241646Sgibbs mov DINDIR,DFDAT; 107341646Sgibbs mov DINDIR,DFDAT; 107441646Sgibbs mov DINDIR,DFDAT ret; 107541646Sgibbs 107641646Sgibbs/* 107741646Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 107841646Sgibbs * DMA and wait for it to acknowledge that it's off. 107941646Sgibbs */ 108041646Sgibbsdma_finish: 108141646Sgibbs test DFSTATUS,HDONE jz dma_finish; 108241646Sgibbs /* Turn off DMA */ 108341646Sgibbs and DFCNTRL, ~HDMAEN; 108413177Sgibbs test DFCNTRL, HDMAEN jnz .; 108513177Sgibbs ret; 10864568Sgibbs 108723925Sgibbsindex_untagged_scb: 10884568Sgibbs mov DINDEX, SINDEX; 108923925Sgibbs shr DINDEX, 4; 109023925Sgibbs and DINDEX, 0x03; /* Bottom two bits of tid */ 109123925Sgibbs add DINDEX, SCB_BUSYTARGETS; 109223925Sgibbs shr A, 6, SINDEX; /* Target ID divided by 4 */ 109323925Sgibbs test SINDEX, SELBUSB jz index_untagged_scb2; 109441646Sgibbs add A, 2; /* Add 2 positions */ 109523925Sgibbsindex_untagged_scb2: 109623925Sgibbs mov SCBPTR, A; /* 10974568Sgibbs * Select the SCB with this 10989954Sgibbs * target's information. 109913177Sgibbs */ 110019164Sgibbs mov SINDEX, DINDEX ret; 110119164Sgibbs 110219164Sgibbsadd_scb_to_free_list: 110313177Sgibbs mov SCB_NEXT, FREE_SCBH; 110423925Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 11059954Sgibbs mov FREE_SCBH, SCBPTR ret; 110623925Sgibbs 11079954Sgibbs.if ( SCB_PAGING ) 11089954Sgibbsget_free_or_disc_scb: 110923925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 111023925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 11119954Sgibbsreturn_error: 11129954Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 11139954Sgibbsdequeue_disc_scb: 111413177Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 111519164Sgibbs/* 111619164Sgibbs * If we have a residual, then we are in the middle of some I/O 111739220Sgibbs * and we have to send this SCB back up to the kernel so that the 111839220Sgibbs * saved data pointers and residual information isn't lost. 111919164Sgibbs */ 112019164Sgibbs test SCB_RESID_SGCNT,0xff jnz dma_up_scb; 112119164Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb; 112219164Sgibbsdma_up_scb: 112319164Sgibbs mvi DMAPARAMS, FIFORESET; 112419164Sgibbs mov SCB_TAG call dma_scb; 112519164Sgibbsunlink_disc_scb: 112619164Sgibbs /* jmp instead of call since we want to return anyway */ 112719164Sgibbs mov SCBPTR jmp rem_scb_from_disc_list; 112819164Sgibbsdequeue_free_scb: 112919164Sgibbs mov SCBPTR, FREE_SCBH; 113013177Sgibbs mov FREE_SCBH, SCB_NEXT ret; 113119164Sgibbs 113213177Sgibbsadd_scb_to_disc_list: 113319164Sgibbs/* 113413177Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 113523925Sgibbs * candidates for paging out an SCB if one is needed for a new command. 113639220Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 113719164Sgibbs */ 113823925Sgibbs mvi SCB_PREV, SCB_LIST_NULL; 113923925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 11407532Sgibbs mov DISCONNECTED_SCBH, SCBPTR; 114139220Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je return; 114223925Sgibbs mov SCBPTR,SCB_NEXT; 114339220Sgibbs mov SCB_PREV,DISCONNECTED_SCBH; 114439220Sgibbs mov SCBPTR,DISCONNECTED_SCBH ret; 114519164Sgibbs.endif 114623925Sgibbs