aic7xxx.seq revision 28169
126997Sgibbs/* 226997Sgibbs * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. 313177Sgibbs * 426997Sgibbs * Copyright (c) 1994-1997 Justin Gibbs. 526997Sgibbs * All rights reserved. 613177Sgibbs * 726997Sgibbs * Redistribution and use in source and binary forms, with or without 826997Sgibbs * modification, are permitted provided that the following conditions 926997Sgibbs * are met: 1026997Sgibbs * 1. Redistributions of source code must retain the above copyright 1126997Sgibbs * notice, this list of conditions, and the following disclaimer, 1226997Sgibbs * without modification, immediately at the beginning of the file. 1326997Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1426997Sgibbs * notice, this list of conditions and the following disclaimer in the 1526997Sgibbs * documentation and/or other materials provided with the distribution. 1626997Sgibbs * 3. The name of the author may not be used to endorse or promote products 1726997Sgibbs * derived from this software without specific prior written permission. 1813177Sgibbs * 1926997Sgibbs * Where this Software is combined with software released under the terms of 2026997Sgibbs * the GNU Public License ("GPL") and the terms of the GPL would require the 2126997Sgibbs * combined work to also be released under the terms of the GPL, the terms 2226997Sgibbs * and conditions of this License will apply in addition to those of the 2326997Sgibbs * GPL with the exception of any terms or conditions of this License that 2426997Sgibbs * conflict with, or are expressly prohibited by, the GPL. 2513177Sgibbs * 2626997Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2726997Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2826997Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2926997Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 3026997Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3126997Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3226997Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3326997Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3426997Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3526997Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3626997Sgibbs * SUCH DAMAGE. 3713177Sgibbs * 3828169Sgibbs * $Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $ 3926997Sgibbs */ 404568Sgibbs 4123925Sgibbs#include <dev/aic7xxx/aic7xxx.reg> 4223925Sgibbs#include <scsi/scsi_message.h> 435647Sgibbs 4413177Sgibbs/* 4519164Sgibbs * A few words on the waiting SCB list: 4619164Sgibbs * After starting the selection hardware, we check for reconnecting targets 4713690Sgibbs * as well as for our selection to complete just in case the reselection wins 4813690Sgibbs * bus arbitration. The problem with this is that we must keep track of the 4913690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection 5013690Sgibbs * on just in case the reselection wins so that we can retry the selection at 5113690Sgibbs * a later time. This problem cannot be resolved by holding a single entry 5213690Sgibbs * in scratch ram since a reconnecting target can request sense and this will 5313690Sgibbs * create yet another SCB waiting for selection. The solution used here is to 5413690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list 5519164Sgibbs * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, 5619164Sgibbs * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to 5719164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged 5819164Sgibbs * command for which a second SCB has been queued. The sequencer will 5919164Sgibbs * automatically consume the entries. 6013177Sgibbs */ 614568Sgibbs 6213177Sgibbs/* 6314449Sgibbs * We assume that the kernel driver may reset us at any time, even in the 6414449Sgibbs * middle of a DMA, so clear DFCNTRL too. 6513177Sgibbs */ 6614449Sgibbsreset: 6723925Sgibbs clr SCSISIGO; /* De-assert BSY */ 6823925Sgibbs /* Always allow reselection */ 6923925Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; 7023925Sgibbs call clear_target_state; 718104Sgibbspoll_for_work: 7224662Sgibbs test SSTAT0,SELDO jnz select; 7324662Sgibbs test SSTAT0,SELDI jnz reselect; 7423925Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 7523925Sgibbs.if ( TWIN_CHANNEL ) 7613177Sgibbs /* 7723925Sgibbs * Twin channel devices cannot handle things like SELTO 7823925Sgibbs * interrupts on the "background" channel. So, if we 7923925Sgibbs * are selecting, keep polling the current channel util 8023925Sgibbs * either a selection or reselection occurs. 8113177Sgibbs */ 8223925Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 8324662Sgibbs test SSTAT0,SELDO jnz select; 8424662Sgibbs test SSTAT0,SELDI jnz reselect; 8523925Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 8623925Sgibbs xor SBLKCTL,SELBUSB; /* Toggle back */ 8723925Sgibbs.endif 8823925Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 8919164Sgibbstest_queue: 9019164Sgibbs /* Has the driver posted any work for us? */ 9123925Sgibbs mov A, QCNTMASK; 9223925Sgibbs test QINCNT,A jz poll_for_work; 934568Sgibbs 9413690Sgibbs/* 9513690Sgibbs * We have at least one queued SCB now and we don't have any 9619164Sgibbs * SCBs in the list of SCBs awaiting selection. If we have 9723925Sgibbs * any SCBs available for use, pull the tag from the QINFIFO 9819164Sgibbs * and get to work on it. 9913177Sgibbs */ 10023925Sgibbs.if ( SCB_PAGING ) 10123925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 10223925Sgibbs cmp SINDEX, SCB_LIST_NULL je poll_for_work; 10323925Sgibbs.endif 10419164Sgibbsdequeue_scb: 10523925Sgibbs mov CUR_SCBID,QINFIFO; 10623925Sgibbs.if !( SCB_PAGING ) 10719164Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 10823925Sgibbs mov SCBPTR, CUR_SCBID; 10923925Sgibbs.endif 11019164Sgibbsdma_queued_scb: 11119164Sgibbs/* 11219164Sgibbs * DMA the SCB from host ram into the current SCB location. 11319164Sgibbs */ 11423925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 11523925Sgibbs mov CUR_SCBID call dma_scb; 1164568Sgibbs 11713177Sgibbs/* 11813177Sgibbs * See if there is not already an active SCB for this target. This code 11913177Sgibbs * locks out on a per target basis instead of target/lun. Although this 12013177Sgibbs * is not ideal for devices that have multiple luns active at the same 12113177Sgibbs * time, it is faster than looping through all SCB's looking for active 12219921Sgibbs * commands. We also don't have enough spare SCB space for us to store the 12319164Sgibbs * SCBID of the currently busy transaction for each target/lun making it 12419164Sgibbs * impossible to link up the SCBs. 12513177Sgibbs */ 1265647Sgibbstest_busy: 12723925Sgibbs test SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb; 12823925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 12923925Sgibbs mov SAVED_SCBPTR, SCBPTR; 13023925Sgibbs mov SCB_TCL call index_untagged_scb; 13123925Sgibbs mov ARG_1, SINDIR; /* 13219164Sgibbs * ARG_1 should 13319164Sgibbs * now have the SCB ID of 13419164Sgibbs * any active, non-tagged, 13519164Sgibbs * command for this target. 13619164Sgibbs */ 13723925Sgibbs cmp ARG_1, SCB_LIST_NULL je make_busy; 13823925Sgibbs.if ( SCB_PAGING ) 13919164Sgibbs /* 14019164Sgibbs * Put this SCB back onto the free list. It 14119164Sgibbs * may be necessary to satisfy the search for 14219164Sgibbs * the active SCB. 14319164Sgibbs */ 14423925Sgibbs mov SCBPTR, SAVED_SCBPTR; 14523925Sgibbs call add_scb_to_free_list; 14619164Sgibbs /* Find the active SCB */ 14723925Sgibbs mov ALLZEROS call findSCB; 14819218Sgibbs /* 14919218Sgibbs * If we couldn't find it, tell the kernel. This should 15021947Sgibbs * never happen. 15119218Sgibbs */ 15223925Sgibbs cmp SINDEX, SCB_LIST_NULL jne paged_busy_link; 15323925Sgibbs mvi INTSTAT, NO_MATCH_BUSY; 15419218Sgibbspaged_busy_link: 15519164Sgibbs /* Link us in */ 15623925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 15719164Sgibbs /* Put it back on the disconnected list */ 15823925Sgibbs call add_scb_to_disc_list; 15923925Sgibbs mvi SEQCTL, FASTMODE; 16023925Sgibbs jmp poll_for_work; 16125005Sgibbs.else 16219164Sgibbssimple_busy_link: 16323925Sgibbs mov SCBPTR, ARG_1; 16423925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 16523925Sgibbs mvi SEQCTL, FASTMODE; 16623925Sgibbs jmp poll_for_work; 16725005Sgibbs.endif 16819164Sgibbsmake_busy: 16923925Sgibbs mov DINDIR, CUR_SCBID; 17023925Sgibbs mov SCBPTR, SAVED_SCBPTR; 17123925Sgibbs mvi SEQCTL, FASTMODE; 1724568Sgibbs 1735326Sgibbsstart_scb: 17419164Sgibbs /* 17519164Sgibbs * Place us on the waiting list in case our selection 17619164Sgibbs * doesn't win during bus arbitration. 17719164Sgibbs */ 17823925Sgibbs mov SCB_NEXT,WAITING_SCBH; 17923925Sgibbs mov WAITING_SCBH, SCBPTR; 18023925Sgibbsstart_waiting: 18123925Sgibbs /* 18223925Sgibbs * Pull the first entry off of the waiting SCB list 18323925Sgibbs * We don't have to "test_busy" because only transactions that 18423925Sgibbs * have passed that test can be in the WAITING_SCB list. 18523925Sgibbs */ 18623925Sgibbs mov SCBPTR, WAITING_SCBH; 18723925Sgibbs call start_selection; 18823925Sgibbs jmp poll_for_work; 1898104Sgibbs 19023925Sgibbsstart_selection: 19123991Sgibbs.if ( TWIN_CHANNEL ) 19223925Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */ 19323925Sgibbs and A,SELBUSB,SCB_TCL; /* Get new channel bit */ 19423925Sgibbs or SINDEX,A; 19523925Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 19623991Sgibbs.endif 19723925Sgibbsinitialize_scsiid: 19823925Sgibbs and A, TID, SCB_TCL; /* Get target ID */ 19923925Sgibbs and SCSIID, OID; /* Clear old target */ 20023925Sgibbs or SCSIID, A; 20123925Sgibbs mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; 20213177Sgibbs/* 20323925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 20423925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 20513177Sgibbs */ 20623925Sgibbsreselect: 20723925Sgibbs clr MSG_LEN; /* Don't have anything in the mesg buffer */ 20823925Sgibbs mvi CLRSINT0, CLRSELDI; 20923925Sgibbs /* XXX test for and handle ONE BIT condition */ 21023925Sgibbs and SAVED_TCL, SELID_MASK, SELID; 21123925Sgibbs or SEQ_FLAGS,RESELECTED; 21223925Sgibbs jmp select2; 2134568Sgibbs 21413177Sgibbs/* 21523925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 21623925Sgibbs * list. This is achieved by simply moving our "next" pointer into 21723925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 21823925Sgibbs * SCB is used, so don't bother with it now. 21923925Sgibbs */ 22023925Sgibbsselect: 22125005Sgibbs /* Turn off the selection hardware */ 22223925Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* 22323925Sgibbs * ATN on parity errors 22423925Sgibbs * for "in" phases 22523925Sgibbs */ 22625005Sgibbs mvi CLRSINT0, CLRSELDO; 22725005Sgibbs mov SCBPTR, WAITING_SCBH; 22824914Sgibbs mov WAITING_SCBH,SCB_NEXT; 22923925Sgibbs mov SAVED_TCL, SCB_TCL; 23023925Sgibbs/* 23113177Sgibbs * As soon as we get a successful selection, the target should go 23213177Sgibbs * into the message out phase since we have ATN asserted. Prepare 23313177Sgibbs * the message to send. 23413177Sgibbs * 23513177Sgibbs * Messages are stored in scratch RAM starting with a length byte 23613177Sgibbs * followed by the message itself. 23713177Sgibbs */ 2388567Sdg 23913177Sgibbsmk_identify: 24023925Sgibbs and MSG_OUT,0x7,SCB_TCL; /* lun */ 24123925Sgibbs and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ 24223925Sgibbs or MSG_OUT,A; /* or in disconnect privledge */ 24323925Sgibbs or MSG_OUT,MSG_IDENTIFYFLAG; 24423925Sgibbs mvi MSG_LEN, 1; 2454568Sgibbs 24613177Sgibbs/* 24715328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 24815328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 24913177Sgibbs */ 2506608Sgibbsmk_tag: 25123925Sgibbs test SCB_CONTROL,TAG_ENB jz mk_message; 25223925Sgibbs and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 25323925Sgibbs mov MSG_OUT[2],SCB_TAG; 25423925Sgibbs add MSG_LEN,2; /* update message length */ 2556608Sgibbs 25618762Sgibbs/* 25718762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer 25818762Sgibbs * if it asks. 25918762Sgibbs */ 26018762Sgibbsmk_message: 26123925Sgibbs test SCB_CONTROL,MK_MESSAGE jz select2; 26223925Sgibbs mvi INTSTAT,AWAITING_MSG; 2636608Sgibbs 2648104Sgibbsselect2: 26525005Sgibbs mvi CLRSINT1,CLRBUSFREE; 26625005Sgibbs or SIMODE1, ENBUSFREE; /* 26725005Sgibbs * We aren't expecting a 26825005Sgibbs * bus free, so interrupt 26925005Sgibbs * the kernel driver if it 27025005Sgibbs * happens. 27125005Sgibbs */ 27213177Sgibbs/* 27322451Sgibbs * Initialize Ultra mode setting and clear the SCSI channel. 27422451Sgibbs */ 27523925Sgibbs or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN; 27623925Sgibbs.if ( ULTRA ) 27722451Sgibbsultra: 27823925Sgibbs mvi SINDEX, ULTRA_ENB+1; 27923925Sgibbs test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ 28023925Sgibbs dec SINDEX; 28122451Sgibbsultra_2: 28223925Sgibbs mov FUNCTION1,SAVED_TCL; 28323925Sgibbs mov A,FUNCTION1; 28423925Sgibbs test SINDIR, A jz ndx_dtr; 28523925Sgibbs or SXFRCTL0, FAST20; 28623925Sgibbs.endif 28722451Sgibbs 28822451Sgibbs/* 28913177Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 29019164Sgibbs * The SCSIRATE settings for each target are stored in an array 29119164Sgibbs * based at TARG_SCRATCH. 29213177Sgibbs */ 29319164Sgibbsndx_dtr: 29423925Sgibbs shr A,4,SAVED_TCL; 29523925Sgibbs test SBLKCTL,SELBUSB jz ndx_dtr_2; 29623925Sgibbs or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */ 29723925Sgibbs or A,0x08; /* Channel B entries add 8 */ 29819164Sgibbsndx_dtr_2: 29923925Sgibbs add SINDEX,TARG_SCRATCH,A; 30023925Sgibbs mov SCSIRATE,SINDIR; 30113177Sgibbs 30215843Sgibbs 30313177Sgibbs/* 30413177Sgibbs * Main loop for information transfer phases. If BSY is false, then 30513177Sgibbs * we have a bus free condition, expected or not. Otherwise, wait 30613177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O 30713177Sgibbs * for the bus phase. 30813177Sgibbs * 30913177Sgibbs */ 3104568SgibbsITloop: 31124794Sgibbs test SSTAT1,REQINIT jz ITloop; 31224794Sgibbs test SSTAT1, SCSIPERR jnz ITloop; 3134568Sgibbs 31423925Sgibbs and A,PHASE_MASK,SCSISIGI; 31523925Sgibbs mov LASTPHASE,A; 31623925Sgibbs mov SCSISIGO,A; 3174568Sgibbs 31823925Sgibbs cmp ALLZEROS,A je p_dataout; 31923925Sgibbs cmp A,P_DATAIN je p_datain; 32023925Sgibbs cmp A,P_COMMAND je p_command; 32123925Sgibbs cmp A,P_MESGOUT je p_mesgout; 32223925Sgibbs cmp A,P_STATUS je p_status; 32323925Sgibbs cmp A,P_MESGIN je p_mesgin; 3244568Sgibbs 32523925Sgibbs mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ 32623925Sgibbs jmp ITloop; /* Try reading the bus again. */ 3274568Sgibbs 32823925Sgibbsawait_busfree: 32923925Sgibbs and SIMODE1, ~ENBUSFREE; 33024794Sgibbs call clear_target_state; 33123925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 33223925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 33323925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 33423925Sgibbs mvi INTSTAT, BAD_PHASE; 33523925Sgibbs 33623925Sgibbsclear_target_state: 33723925Sgibbs clr DFCNTRL; 33823925Sgibbs clr SCSIRATE; /* 33923925Sgibbs * We don't know the target we will 34023925Sgibbs * connect to, so default to narrow 34123925Sgibbs * transfers to avoid parity problems. 34223925Sgibbs */ 34323925Sgibbs and SXFRCTL0, ~FAST20; 34423925Sgibbs mvi LASTPHASE, P_BUSFREE; 34523925Sgibbs /* clear target specific flags */ 34623925Sgibbs and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret; 34723925Sgibbs 3484568Sgibbsp_dataout: 34923925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET; 35023925Sgibbs jmp data_phase_init; 3514568Sgibbs 35213177Sgibbs/* 35313177Sgibbs * If we re-enter the data phase after going through another phase, the 35413177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 35513177Sgibbs */ 3569928Sgibbsdata_phase_reinit: 35723925Sgibbs mvi DINDEX, STCNT; 35823925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 35923925Sgibbs jmp data_phase_loop; 3604568Sgibbs 3619928Sgibbsp_datain: 36223925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 3639928Sgibbsdata_phase_init: 36423925Sgibbs call assert; /* 36519164Sgibbs * Ensure entering a data 36619164Sgibbs * phase is okay - seen identify, etc. 36719164Sgibbs */ 3685775Sgibbs 36923925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 3704568Sgibbs 37119164Sgibbs /* 37219164Sgibbs * Initialize the DMA address and counter from the SCB. 37319164Sgibbs * Also set SG_COUNT and SG_NEXT in memory since we cannot 37419164Sgibbs * modify the values in the SCB itself until we see a 37519164Sgibbs * save data pointers message. 37619164Sgibbs */ 37723925Sgibbs mvi DINDEX, HADDR; 37823925Sgibbs mvi SCB_DATAPTR call bcopy_7; 37919164Sgibbs 38023925Sgibbs call set_stcnt_from_hcnt; 38119164Sgibbs 38223925Sgibbs mov SG_COUNT,SCB_SGCOUNT; 38319164Sgibbs 38423925Sgibbs mvi DINDEX, SG_NEXT; 38523925Sgibbs mvi SCB_SGPTR call bcopy_4; 38619164Sgibbs 3879928Sgibbsdata_phase_loop: 38816260Sgibbs/* Guard against overruns */ 38923925Sgibbs test SG_COUNT, 0xff jnz data_phase_inbounds; 39016260Sgibbs/* 39116260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to 39216260Sgibbs * 16meg and let the target run until it changes phase. 39316260Sgibbs * When the transfer completes, notify the host that we 39416260Sgibbs * had an overrun. 39516260Sgibbs */ 39623925Sgibbs or SXFRCTL1,BITBUCKET; 39723925Sgibbs mvi HCNT[0], 0xff; 39823925Sgibbs mvi HCNT[1], 0xff; 39923925Sgibbs mvi HCNT[2], 0xff; 40023925Sgibbs call set_stcnt_from_hcnt; 40116260Sgibbs 40216260Sgibbsdata_phase_inbounds: 40319164Sgibbs/* If we are the last SG block, ensure wideodd is off. */ 40423925Sgibbs cmp SG_COUNT,0x01 jne data_phase_wideodd; 40523925Sgibbs and DMAPARAMS, ~WIDEODD; 4069928Sgibbsdata_phase_wideodd: 40723925Sgibbs mov DMAPARAMS call dma; 4084568Sgibbs 40916260Sgibbs/* Go tell the host about any overruns */ 41023925Sgibbs test SXFRCTL1,BITBUCKET jnz data_phase_overrun; 41116260Sgibbs 41222451Sgibbs/* Exit if we had an underrun. dma clears SINDEX in this case. */ 41323925Sgibbs test SINDEX,0xff jz data_phase_finish; 4147532Sgibbs 41513177Sgibbs/* 41613177Sgibbs * Advance the scatter-gather pointers if needed 41713177Sgibbs */ 4189928Sgibbssg_advance: 41923925Sgibbs dec SG_COUNT; /* one less segment to go */ 4204568Sgibbs 42123925Sgibbs test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ 4224568Sgibbs 42323925Sgibbs clr A; /* add sizeof(struct scatter) */ 42423925Sgibbs add SG_NEXT[0],SG_SIZEOF; 42523925Sgibbs adc SG_NEXT[1],A; 4264568Sgibbs 42713177Sgibbs/* 42813177Sgibbs * Load a struct scatter and set up the data address and length. 42913177Sgibbs * If the working value of the SG count is nonzero, then 43013177Sgibbs * we need to load a new set of values. 43113177Sgibbs * 43215328Sgibbs * This, like all DMA's, assumes little-endian host data storage. 43313177Sgibbs */ 4349928Sgibbssg_load: 43523925Sgibbs mvi DINDEX, HADDR; 43623925Sgibbs mvi SG_NEXT call bcopy_4; 4374568Sgibbs 43823925Sgibbs mvi HCNT[0],SG_SIZEOF; 43923925Sgibbs clr HCNT[1]; 44023925Sgibbs clr HCNT[2]; 44122568Sgibbs 44223925Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 4439928Sgibbs 44423925Sgibbs call dma_finish; 4459928Sgibbs 44613177Sgibbs/* 44713177Sgibbs * Copy data from FIFO into SCB data pointer and data count. This assumes 44819164Sgibbs * that the SG segments are of the form: 44913177Sgibbs * 45013177Sgibbs * struct ahc_dma_seg { 45119164Sgibbs * u_int32_t addr; four bytes, little-endian order 45219164Sgibbs * u_int32_t len; four bytes, little endian order 45313177Sgibbs * }; 45413177Sgibbs */ 45523925Sgibbs mvi HADDR call dfdat_in_7; 4569928Sgibbs 45713177Sgibbs/* Load STCNT as well. It is a mirror of HCNT */ 45823925Sgibbs call set_stcnt_from_hcnt; 45923925Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 4604568Sgibbs 4619928Sgibbsdata_phase_finish: 46213177Sgibbs/* 46313177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB 46413177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 46513177Sgibbs * were transferred on the SCSI (as opposed to the host) bus. 46613177Sgibbs */ 46723925Sgibbs mov SCB_RESID_DCNT[0],STCNT[0]; 46823925Sgibbs mov SCB_RESID_DCNT[1],STCNT[1]; 46923925Sgibbs mov SCB_RESID_DCNT[2],STCNT[2]; 47023925Sgibbs mov SCB_RESID_SGCNT, SG_COUNT; 47122568Sgibbs 47222568Sgibbs /* We have seen a data phase */ 47323925Sgibbs or SEQ_FLAGS, DPHASE; 47422568Sgibbs 47523925Sgibbs jmp ITloop; 4764568Sgibbs 47716260Sgibbsdata_phase_overrun: 47813177Sgibbs/* 47916260Sgibbs * Turn off BITBUCKET mode and notify the host 48016260Sgibbs */ 48123925Sgibbs and SXFRCTL1, ~BITBUCKET; 48223925Sgibbs mvi INTSTAT,DATA_OVERRUN; 48323925Sgibbs jmp ITloop; 48416260Sgibbs 48516260Sgibbs/* 48615328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 48713177Sgibbs */ 4884568Sgibbsp_command: 48923925Sgibbs call assert; 4904568Sgibbs 49113177Sgibbs/* 49215328Sgibbs * Load HADDR and HCNT. 49313177Sgibbs */ 49423925Sgibbs mvi DINDEX, HADDR; 49523925Sgibbs mvi SCB_CMDPTR call bcopy_5; 49623925Sgibbs clr HCNT[1]; 49723925Sgibbs clr HCNT[2]; 4984568Sgibbs 49923925Sgibbs call set_stcnt_from_hcnt; 5004568Sgibbs 50123925Sgibbs mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; 50223925Sgibbs jmp ITloop; 5034568Sgibbs 50413177Sgibbs/* 50513177Sgibbs * Status phase. Wait for the data byte to appear, then read it 50613177Sgibbs * and store it into the SCB. 50713177Sgibbs */ 5084568Sgibbsp_status: 50923925Sgibbs call assert; 51019803Sgibbs 51123925Sgibbs mov SCB_TARGET_STATUS, SCSIDATL; 51223925Sgibbs jmp ITloop; 5134568Sgibbs 51413177Sgibbs/* 51515328Sgibbs * Message out phase. If there is not an active message, but the target 51613177Sgibbs * took us into this phase anyway, build a no-op message and send it. 51713177Sgibbs */ 5184568Sgibbsp_mesgout: 51923925Sgibbs test MSG_LEN, 0xff jnz p_mesgout_start; 52023925Sgibbs mvi MSG_NOOP call mk_mesg; /* build NOP message */ 52113177Sgibbsp_mesgout_start: 52213177Sgibbs/* 52323925Sgibbs * Set up automatic PIO transfer from MSG_OUT. Bit 3 in 52413177Sgibbs * SXFRCTL0 (SPIOEN) is already on. 52513177Sgibbs */ 52623925Sgibbs mvi SINDEX,MSG_OUT; 52723925Sgibbs mov DINDEX,MSG_LEN; 5284568Sgibbs 52913177Sgibbs/* 53013177Sgibbs * When target asks for a byte, drop ATN if it's the last one in 53113177Sgibbs * the message. Otherwise, keep going until the message is exhausted. 53223925Sgibbs * ATN must be dropped *at least* 90ns before we ack the last byte, so 53323925Sgibbs * the code is aranged to execute two instructions before the byte is 53423925Sgibbs * transferred to give a good margin of safety 53513177Sgibbs * 53613177Sgibbs * Keep an eye out for a phase change, in case the target issues 53713177Sgibbs * a MESSAGE REJECT. 53813177Sgibbs */ 53913177Sgibbsp_mesgout_loop: 54024794Sgibbs test SSTAT1, REQINIT jz p_mesgout_loop; 54124794Sgibbs test SSTAT1, SCSIPERR jnz p_mesgout_loop; 54223925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 54323925Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 54425005Sgibbsp_mesgout_testretry: 54525005Sgibbs test DINDEX,0xff jnz p_mesgout_dropatn; 54625005Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 54725005Sgibbs jmp p_mesgout_start; 54813177Sgibbs/* 54913177Sgibbs * If the next bus phase after ATN drops is a message out, it means 55013177Sgibbs * that the target is requesting that the last message(s) be resent. 55113177Sgibbs */ 55224914Sgibbsp_mesgout_dropatn: 55324914Sgibbs cmp DINDEX,1 jne p_mesgout_outb; /* last byte? */ 55424914Sgibbs mvi CLRSINT1,CLRATNO; /* drop ATN */ 55519906Sgibbsp_mesgout_outb: 55623925Sgibbs dec DINDEX; 55723925Sgibbs mov SCSIDATL,SINDIR; 55823925Sgibbs jmp p_mesgout_loop; 5594568Sgibbs 56019906Sgibbsp_mesgout_done: 56123925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 56223925Sgibbs clr MSG_LEN; /* no active msg */ 56323925Sgibbs jmp ITloop; 5644568Sgibbs 56513177Sgibbs/* 56613177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 56713177Sgibbs */ 5684568Sgibbsp_mesgin: 56923925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 57023925Sgibbs mov REJBYTE,A; /* save it for the driver */ 5714568Sgibbs 57223925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 57323925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 57423925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 57523925Sgibbs cmp ALLZEROS,A je mesgin_complete; 57623925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 57723925Sgibbs cmp A,MSG_EXTENDED je mesgin_extended; 57823925Sgibbs cmp A,MSG_MESSAGE_REJECT je mesgin_reject; 57923925Sgibbs cmp A,MSG_NOOP je mesgin_done; 5804568Sgibbs 5819954Sgibbsrej_mesgin: 58213177Sgibbs/* 58319164Sgibbs * We have no idea what this message in is, so we issue a message reject 58419164Sgibbs * and hope for the best. In any case, rejection should be a rare 58519164Sgibbs * occurrence - signal the driver when it happens. 58613177Sgibbs */ 58723925Sgibbs mvi INTSTAT,SEND_REJECT; /* let driver know */ 5889954Sgibbs 58923925Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 5909954Sgibbs 5919954Sgibbsmesgin_done: 59223925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 59323925Sgibbs jmp ITloop; 5949954Sgibbs 5959954Sgibbs 5969954Sgibbsmesgin_complete: 59713177Sgibbs/* 59819164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, 59919164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 60019164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0). In 60119164Sgibbs * either of these conditions, we upload the SCB back to the host so it can 60219164Sgibbs * process this information. In the case of a non zero status byte, we 60319164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 60419164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 60519164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set 60619164Sgibbs * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload 60719164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list. 60819164Sgibbs * If the kernel driver does not wish to request sense, it need only clear 60919164Sgibbs * RETURN_1, and the command is allowed to complete normally. We don't bother 61019164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra 61119164Sgibbs * work in the kernel driver to ensure that the entry was removed before the 61219164Sgibbs * command complete code tried processing it. 61313177Sgibbs */ 61419164Sgibbs 61513177Sgibbs/* 61619164Sgibbs * First check for residuals 61713177Sgibbs */ 61823925Sgibbs test SCB_RESID_SGCNT,0xff jnz upload_scb; 61923925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */ 62019164Sgibbsupload_scb: 62123925Sgibbs mvi DMAPARAMS, FIFORESET; 62223925Sgibbs mov SCB_TAG call dma_scb; 6237532Sgibbscheck_status: 62423925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */ 62523925Sgibbs mvi INTSTAT,BAD_STATUS; /* let driver know */ 62623925Sgibbs cmp RETURN_1, SEND_SENSE jne status_ok; 62719164Sgibbs /* This SCB becomes the next to execute as it will retrieve sense */ 62823925Sgibbs mov SCB_LINKED_NEXT, SCB_TAG; 62923925Sgibbs jmp dma_next_scb; 6305326Sgibbs 6314568Sgibbsstatus_ok: 63213177Sgibbs/* First, mark this target as free. */ 63323925Sgibbs test SCB_CONTROL,TAG_ENB jnz complete; /* 63413177Sgibbs * Tagged commands 63513177Sgibbs * don't busy the 63613177Sgibbs * target. 63713177Sgibbs */ 63823925Sgibbs mov SAVED_SCBPTR, SCBPTR; 63923925Sgibbs mov SAVED_LINKPTR, SCB_LINKED_NEXT; 64023925Sgibbs mov SCB_TCL call index_untagged_scb; 64123925Sgibbs mov DINDIR, SAVED_LINKPTR; 64223925Sgibbs mov SCBPTR, SAVED_SCBPTR; 6435326Sgibbs 6445326Sgibbscomplete: 64519164Sgibbs /* Post the SCB and issue an interrupt */ 64628169Sgibbs.if ( SCB_PAGING ) 64728169Sgibbs /* 64828169Sgibbs * Spin loop until there is space 64928169Sgibbs * in the QOUTFIFO. 65028169Sgibbs */ 65128169Sgibbs mov A, FIFODEPTH; 65228169Sgibbs cmp CMDOUTCNT, A je .; 65328169Sgibbs inc CMDOUTCNT; 65428169Sgibbs.endif 65523925Sgibbs mov QOUTFIFO,SCB_TAG; 65623925Sgibbs mvi INTSTAT,CMDCMPLT; 65723925Sgibbs test SCB_CONTROL, ABORT_SCB jz dma_next_scb; 65823925Sgibbs mvi INTSTAT, ABORT_CMDCMPLT; 65919164Sgibbs 66019164Sgibbsdma_next_scb: 66123925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list; 66223925Sgibbs.if !( SCB_PAGING ) 66319164Sgibbs /* Only DMA on top of ourselves if we are the SCB to download */ 66423925Sgibbs mov A, SCB_LINKED_NEXT; 66523925Sgibbs cmp SCB_TAG, A je dma_next_scb2; 66625005Sgibbs call add_scb_to_free_list; 66723925Sgibbs mov SCBPTR, A; 66823925Sgibbs jmp add_to_waiting_list; 66923925Sgibbs.endif 67019164Sgibbsdma_next_scb2: 67123925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 67223925Sgibbs mov SCB_LINKED_NEXT call dma_scb; 67319164Sgibbsadd_to_waiting_list: 67423925Sgibbs mov SCB_NEXT,WAITING_SCBH; 67523925Sgibbs mov WAITING_SCBH, SCBPTR; 67623925Sgibbs /* 67723925Sgibbs * Prepare our selection hardware before the busfree so we have a 67823925Sgibbs * high probability of winning arbitration. 67923925Sgibbs */ 68023925Sgibbs call start_selection; 68123925Sgibbs jmp await_busfree; 68219921Sgibbsadd_to_free_list: 68323925Sgibbs call add_scb_to_free_list; 68423925Sgibbs jmp await_busfree; 6854568Sgibbs 68613177Sgibbs/* 68718762Sgibbs * Is it an extended message? Copy the message to our message buffer and 68818762Sgibbs * notify the host. The host will tell us whether to reject this message, 68918762Sgibbs * respond to it with the message that the host placed in our message buffer, 69018762Sgibbs * or simply to do nothing. 69113177Sgibbs */ 6929954Sgibbsmesgin_extended: 69323925Sgibbs mvi MSGIN_EXT_LEN call inb_next; 69423925Sgibbs mov A, MSGIN_EXT_LEN; 69518762Sgibbsmesgin_extended_loop: 69623925Sgibbs mov DINDEX call inb_next; 69723925Sgibbs dec A; 69823925Sgibbs cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test; 69923925Sgibbs dec DINDEX; /* dump by repeatedly filling the last byte */ 70019164Sgibbsmesgin_extended_loop_test: 70123925Sgibbs test A, 0xFF jnz mesgin_extended_loop; 70218762Sgibbsmesgin_extended_intr: 70323925Sgibbs mvi INTSTAT,EXTENDED_MSG; /* let driver know */ 70423925Sgibbs cmp RETURN_1,SEND_REJ je rej_mesgin; 70523925Sgibbs cmp RETURN_1,SEND_MSG jne mesgin_done; 70618762Sgibbs/* The kernel has setup a message to be sent */ 70723925Sgibbs or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */ 70823925Sgibbs jmp mesgin_done; 7095562Sgibbs 71013177Sgibbs/* 71113177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 71213177Sgibbs * and await the bus going free. 71313177Sgibbs */ 7149954Sgibbsmesgin_disconnect: 71523925Sgibbs or SCB_CONTROL,DISCONNECTED; 71623925Sgibbs.if ( SCB_PAGING ) 71723925Sgibbs call add_scb_to_disc_list; 71823925Sgibbs.endif 71923925Sgibbs jmp await_busfree; 72019164Sgibbs 72115328Sgibbs/* 72219164Sgibbs * Save data pointers message: 72319164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 72419164Sgibbs * only if we've actually been into a data phase to change them. This 72519164Sgibbs * protects against bogus data in scratch ram and the residual counts 72619164Sgibbs * since they are only initialized when we go into data_in or data_out. 72715328Sgibbs */ 72819164Sgibbsmesgin_sdptrs: 72923925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 73023925Sgibbs mov SCB_SGCOUNT,SG_COUNT; 7314568Sgibbs 73219164Sgibbs /* The SCB SGPTR becomes the next one we'll download */ 73323925Sgibbs mvi DINDEX, SCB_SGPTR; 73423925Sgibbs mvi SG_NEXT call bcopy_4; 73519164Sgibbs 73619164Sgibbs /* The SCB DATAPTR0 becomes the current SHADDR */ 73723925Sgibbs mvi DINDEX, SCB_DATAPTR; 73823925Sgibbs mvi SHADDR call bcopy_4; 73919164Sgibbs 74013177Sgibbs/* 74119164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer. 74213177Sgibbs */ 74323925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 74419164Sgibbs 74523925Sgibbs jmp mesgin_done; 7464568Sgibbs 74713177Sgibbs/* 74813177Sgibbs * Restore pointers message? Data pointers are recopied from the 74913177Sgibbs * SCB anytime we enter a data phase for the first time, so all 75013177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 75113177Sgibbs * code do the rest. 75213177Sgibbs */ 7539954Sgibbsmesgin_rdptrs: 75423925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 75523925Sgibbs * We'll reload them 75613177Sgibbs * the next time through 75723925Sgibbs * the dataphase. 75813177Sgibbs */ 75923925Sgibbs jmp mesgin_done; 7604568Sgibbs 76113177Sgibbs/* 76213177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 76313177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 76413177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 76513177Sgibbs */ 7669954Sgibbsmesgin_identify: 76723925Sgibbs test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/ 76823925Sgibbs and A,0x07; /* lun in lower three bits */ 76923925Sgibbs or SAVED_TCL,A; /* SAVED_TCL should be complete now */ 77023925Sgibbs mov SAVED_TCL call index_untagged_scb; 77123925Sgibbs mov ARG_1, SINDIR; 77224608Sgibbs.if ( SCB_PAGING ) 77323925Sgibbs cmp ARG_1,SCB_LIST_NULL jne use_findSCB; 77424608Sgibbs.else 77524608Sgibbs cmp ARG_1,SCB_LIST_NULL je snoop_tag; 77624608Sgibbs /* Directly index the SCB */ 77724608Sgibbs mov SCBPTR,ARG_1; 77824608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 77924608Sgibbs jmp setup_SCB; 78024608Sgibbs.endif 78113177Sgibbs/* 78213177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 78323168Sgibbs * If we get one, we use the tag returned to find the proper 78415328Sgibbs * SCB. With SCB paging, this requires using findSCB for both tagged 78515328Sgibbs * and non-tagged transactions since the SCB may exist in any slot. 78615328Sgibbs * If we're not using SCB paging, we can use the tag as the direct 78715328Sgibbs * index to the SCB. 78813177Sgibbs */ 78924608Sgibbssnoop_tag: 79023925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 79113177Sgibbssnoop_tag_loop: 79223925Sgibbs test SSTAT1,REQINIT jz snoop_tag_loop; 79324794Sgibbs test SSTAT1, SCSIPERR jnz snoop_tag_loop; 79423925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 79523925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 79623925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 7976608Sgibbsget_tag: 79823925Sgibbs or SEQ_FLAGS, TAGGED_SCB; 79923925Sgibbs mvi ARG_1 call inb_next; /* tag value */ 80013177Sgibbs/* 80113177Sgibbs * See if the tag is in range. The tag is < SCBCOUNT if we add 80213177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is 80313177Sgibbs * no carry. 80413177Sgibbs */ 80523925Sgibbs mov A,COMP_SCBCOUNT; 80623925Sgibbs add SINDEX,A,ARG_1; 80723925Sgibbs jc not_found; 80813177Sgibbs 80923925Sgibbs.if ! ( SCB_PAGING ) 81024608Sgibbsindex_by_tag: 81124608Sgibbs mov SCBPTR,ARG_1; 81224608Sgibbs mov A, SAVED_TCL; 81324608Sgibbs cmp SCB_TCL,A jne not_found; 81424608Sgibbs test SCB_CONTROL,TAG_ENB jz not_found; 81524608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 81624608Sgibbs.else 81713177Sgibbs/* 81815328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction 81913177Sgibbs * to the reconnecting target. 82013177Sgibbs */ 82115328Sgibbsuse_findSCB: 82223925Sgibbs mov ALLZEROS call findSCB; /* Have to search */ 82323925Sgibbs cmp SINDEX, SCB_LIST_NULL je not_found; 82424608Sgibbs.endif 82515328Sgibbssetup_SCB: 82623925Sgibbs and SCB_CONTROL,~DISCONNECTED; 82723925Sgibbs or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 82823925Sgibbs jmp mesgin_done; 82915328Sgibbs 83019218Sgibbsnot_found: 83123925Sgibbs mvi INTSTAT, NO_MATCH; 83225005Sgibbs mvi MSG_BUS_DEV_RESET call mk_mesg; 83323925Sgibbs jmp mesgin_done; 8346608Sgibbs 83513177Sgibbs/* 83613177Sgibbs * Message reject? Let the kernel driver handle this. If we have an 83713177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 83813177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 83913177Sgibbs * it since we have no clue what it pertains to. 84013177Sgibbs */ 8419954Sgibbsmesgin_reject: 84223925Sgibbs mvi INTSTAT, REJECT_MSG; 84323925Sgibbs jmp mesgin_done; 8445562Sgibbs 84513177Sgibbs/* 84613177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ] 84713177Sgibbs */ 8484568Sgibbs 84913177Sgibbs/* 85013177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX 85113177Sgibbs * if there is no active message already. SINDEX is returned intact. 85213177Sgibbs */ 8534568Sgibbsmk_mesg: 85423925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 85523925Sgibbs test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */ 85613177Sgibbs 85713177Sgibbs /* 85813177Sgibbs * Hmmm. For some reason the mesg buffer is in use. 85913177Sgibbs * Tell the driver. It should look at SINDEX to find 86013177Sgibbs * out what we wanted to use the buffer for and resolve 86113177Sgibbs * the conflict. 86213177Sgibbs */ 86323925Sgibbs mvi SEQCTL,FASTMODE; 86423925Sgibbs mvi INTSTAT,MSG_BUFFER_BUSY; 8654568Sgibbs 8664568Sgibbsmk_mesg1: 86723925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 86823925Sgibbs mvi MSG_LEN,1; /* length = 1 */ 86923925Sgibbs mov MSG_OUT,SINDEX; /* 1-byte message */ 87023925Sgibbs mvi SEQCTL,FASTMODE ret; 8714568Sgibbs 87213177Sgibbs/* 87313177Sgibbs * Functions to read data in Automatic PIO mode. 87413177Sgibbs * 87513177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 87613177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 87713177Sgibbs * latched (the usual way), then read the data byte directly off the bus 87813177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 87913177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 88013177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 88113177Sgibbs * we send our ACK. 88213177Sgibbs * 88313177Sgibbs * The assumption here is that these are called in a particular sequence, 88413177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 88513177Sgibbs * use the same calling convention as inb. 88613177Sgibbs */ 88713177Sgibbs 88813177Sgibbsinb_next: 88923925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 89013360Sgibbsinb_next_wait: 89121947Sgibbs /* 89221947Sgibbs * If there is a parity error, wait for the kernel to 89321947Sgibbs * see the interrupt and prepare our message response 89421947Sgibbs * before continuing. 89521947Sgibbs */ 89623925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 89723925Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait; 89823925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 89923925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 90019623Sgibbsinb_first: 90123925Sgibbs mov DINDEX,SINDEX; 90223925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 90313177Sgibbsinb_last: 90423925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 9054568Sgibbs 90613177Sgibbsmesgin_phasemis: 90713177Sgibbs/* 90813177Sgibbs * We expected to receive another byte, but the target changed phase 90913177Sgibbs */ 91023925Sgibbs mvi INTSTAT, MSGIN_PHASEMIS; 91123925Sgibbs jmp ITloop; 9124568Sgibbs 91313177Sgibbs/* 91413177Sgibbs * DMA data transfer. HADDR and HCNT must be loaded first, and 91513177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for 91613177Sgibbs * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 91713177Sgibbs * during initialization. 91813177Sgibbs */ 9194568Sgibbsdma: 92023925Sgibbs mov DFCNTRL,SINDEX; 92122568Sgibbsdma_loop: 92223925Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 92323925Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 92422568Sgibbsdma_phasemis: 92523925Sgibbs test SSTAT0,SDONE jnz dma_checkfifo; 92623925Sgibbs mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ 9274568Sgibbs 92813177Sgibbs/* 92913177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or 93013177Sgibbs * the target changes the phase (in light of this, it makes sense that 93113177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 93213177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto- 93313177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty 93413177Sgibbs * status. 93513177Sgibbs */ 93622568Sgibbsdma_checkfifo: 93723925Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 93822568Sgibbsdma_fifoflush: 93923925Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 9404568Sgibbs 94122568Sgibbsdma_fifoempty: 94222568Sgibbs /* Don't clobber an inprogress host data transfer */ 94323925Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 94413177Sgibbs/* 94513177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 94613177Sgibbs * actually off first lest we get an ILLSADDR. 94713177Sgibbs */ 94822568Sgibbsdma_dmadone: 94923925Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 95022568Sgibbsdma_halt: 95123925Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 95218762Sgibbsreturn: 95323925Sgibbs ret; 9544568Sgibbs 95513177Sgibbs/* 95613177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 95713177Sgibbs * message. 95813177Sgibbs */ 9594568Sgibbsassert: 96023925Sgibbs test SEQ_FLAGS,RESELECTED jz return; /* reselected? */ 96123925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 9624568Sgibbs 96323925Sgibbs mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ 9644568Sgibbs 96524608Sgibbs.if ( SCB_PAGING ) 96613177Sgibbs/* 96719218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) 96819218Sgibbs * or by the SCBIDn ARG_1. The search begins at the SCB index passed in 96919218Sgibbs * via SINDEX. If the SCB cannot be found, SINDEX will be SCB_LIST_NULL, 97019218Sgibbs * otherwise, SCBPTR is set to the proper SCB. 97113177Sgibbs */ 9724568SgibbsfindSCB: 97323925Sgibbs mov SCBPTR,SINDEX; /* switch to next SCB */ 97423925Sgibbs mov A, ARG_1; /* Tag passed in ARG_1 */ 97523925Sgibbs cmp SCB_TAG,A jne findSCB_loop; 97623925Sgibbs test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/ 97723168SgibbsfindSCB_loop: 97823925Sgibbs inc SINDEX; 97923925Sgibbs mov A,SCBCOUNT; 98023925Sgibbs cmp SINDEX,A jne findSCB; 98119164Sgibbs/* 98219164Sgibbs * We didn't find it. If we're paging, pull an SCB and DMA down the 98319164Sgibbs * one we want. If we aren't paging or the SCB we dma down has the 98419218Sgibbs * abort flag set, return not found. 98519164Sgibbs */ 98623925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 98723925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 98823925Sgibbs mov ARG_1 call dma_scb; 98925123Sgibbs test SCB_RESID_SGCNT, 0xff jz . + 2; 99025123Sgibbs or SCB_CONTROL, MUST_DMAUP_SCB; 99123925Sgibbs test SCB_CONTROL, ABORT_SCB jz return; 99219218Sgibbsfind_error: 99323925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 99415328SgibbsfoundSCB: 99523925Sgibbs test SCB_CONTROL, ABORT_SCB jnz find_error; 99619164Sgibbsrem_scb_from_disc_list: 99715328Sgibbs/* Remove this SCB from the disconnection list */ 99823925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev; 99923925Sgibbs mov SAVED_LINKPTR, SCB_PREV; 100023925Sgibbs mov SCBPTR, SCB_NEXT; 100123925Sgibbs mov SCB_PREV, SAVED_LINKPTR; 100223925Sgibbs mov SCBPTR, SINDEX; 100315328Sgibbsunlink_prev: 100423925Sgibbs cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */ 100523925Sgibbs mov SAVED_LINKPTR, SCB_NEXT; 100623925Sgibbs mov SCBPTR, SCB_PREV; 100723925Sgibbs mov SCB_NEXT, SAVED_LINKPTR; 100823925Sgibbs mov SCBPTR, SINDEX ret; 100915328SgibbsrHead: 101023925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 101123925Sgibbs.else 101223925Sgibbs ret; 101323925Sgibbs.endif 10144568Sgibbs 101519164Sgibbsset_stcnt_from_hcnt: 101623925Sgibbs mov STCNT[0], HCNT[0]; 101723925Sgibbs mov STCNT[1], HCNT[1]; 101823925Sgibbs mov STCNT[2], HCNT[2] ret; 10194568Sgibbs 102019164Sgibbsbcopy_7: 102123925Sgibbs mov DINDIR, SINDIR; 102223925Sgibbs mov DINDIR, SINDIR; 102319164Sgibbsbcopy_5: 102423925Sgibbs mov DINDIR, SINDIR; 102519164Sgibbsbcopy_4: 102623925Sgibbs mov DINDIR, SINDIR; 102719164Sgibbsbcopy_3: 102823925Sgibbs mov DINDIR, SINDIR; 102923925Sgibbs mov DINDIR, SINDIR; 103023925Sgibbs mov DINDIR, SINDIR ret; 10314568Sgibbs 103219164Sgibbsdma_scb: 103319164Sgibbs /* 103419164Sgibbs * SCB index is in SINDEX. Determine the physical address in 103519164Sgibbs * the host where this SCB is located and load HADDR with it. 103619164Sgibbs */ 103723925Sgibbs shr DINDEX, 3, SINDEX; 103823925Sgibbs shl A, 5, SINDEX; 103923925Sgibbs add HADDR[0], A, HSCB_ADDR[0]; 104023925Sgibbs mov A, DINDEX; 104123925Sgibbs adc HADDR[1], A, HSCB_ADDR[1]; 104223925Sgibbs clr A; 104323925Sgibbs adc HADDR[2], A, HSCB_ADDR[2]; 104423925Sgibbs adc HADDR[3], A, HSCB_ADDR[3]; 104519164Sgibbs /* Setup Count */ 104623925Sgibbs mvi HCNT[0], 28; 104723925Sgibbs clr HCNT[1]; 104823925Sgibbs clr HCNT[2]; 104923925Sgibbs mov DFCNTRL, DMAPARAMS; 105023925Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 105119164Sgibbs /* Fill it with the SCB data */ 105224175Sgibbscopy_scb_tofifo: 105324175Sgibbs mvi SINDEX, SCB_CONTROL; 105424175Sgibbs add A, 28, SINDEX; 105524175Sgibbscopy_scb_tofifo_loop: 105624175Sgibbs mov DFDAT,SINDIR; 105724175Sgibbs mov DFDAT,SINDIR; 105824175Sgibbs mov DFDAT,SINDIR; 105924175Sgibbs mov DFDAT,SINDIR; 106024175Sgibbs mov DFDAT,SINDIR; 106124175Sgibbs mov DFDAT,SINDIR; 106224175Sgibbs mov DFDAT,SINDIR; 106324175Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 106423925Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 106519164Sgibbsdma_scb_fromhost: 106623925Sgibbs call dma_finish; 106719164Sgibbs /* If we were putting the SCB, we are done */ 106823925Sgibbs test DMAPARAMS, DIRECTION jz return; 106923925Sgibbs mvi SCB_CONTROL call dfdat_in_7; 107023925Sgibbs call dfdat_in_7_continued; 107123925Sgibbs call dfdat_in_7_continued; 107223925Sgibbs jmp dfdat_in_7_continued; 107319164Sgibbsdfdat_in_7: 107423925Sgibbs mov DINDEX,SINDEX; 107519164Sgibbsdfdat_in_7_continued: 107623925Sgibbs mov DINDIR,DFDAT; 107723925Sgibbs mov DINDIR,DFDAT; 107823925Sgibbs mov DINDIR,DFDAT; 107923925Sgibbs mov DINDIR,DFDAT; 108023925Sgibbs mov DINDIR,DFDAT; 108123925Sgibbs mov DINDIR,DFDAT; 108223925Sgibbs mov DINDIR,DFDAT ret; 108319164Sgibbs 108413177Sgibbs/* 108519164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 108619164Sgibbs * DMA and wait for it to acknowledge that it's off. 108713177Sgibbs */ 108819164Sgibbsdma_finish: 108923925Sgibbs test DFSTATUS,HDONE jz dma_finish; 109022234Sgibbs /* Turn off DMA */ 109123925Sgibbs and DFCNTRL, ~HDMAEN; 109223925Sgibbs test DFCNTRL, HDMAEN jnz .; 109323925Sgibbs ret; 10949928Sgibbs 109519164Sgibbsindex_untagged_scb: 109623925Sgibbs mov DINDEX, SINDEX; 109723925Sgibbs shr DINDEX, 4; 109823925Sgibbs and DINDEX, 0x03; /* Bottom two bits of tid */ 109923925Sgibbs add DINDEX, SCB_BUSYTARGETS; 110023925Sgibbs shr A, 6, SINDEX; /* Target ID divided by 4 */ 110123925Sgibbs test SINDEX, SELBUSB jz index_untagged_scb2; 110223925Sgibbs add A, 2; /* Add 2 positions */ 110319164Sgibbsindex_untagged_scb2: 110423925Sgibbs mov SCBPTR, A; /* 110519164Sgibbs * Select the SCB with this 110619164Sgibbs * target's information. 110719164Sgibbs */ 110823925Sgibbs mov SINDEX, DINDEX ret; 11099928Sgibbs 111023925Sgibbsadd_scb_to_free_list: 111123925Sgibbs mov SCB_NEXT, FREE_SCBH; 111223925Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 111323925Sgibbs mov FREE_SCBH, SCBPTR ret; 11144568Sgibbs 111523925Sgibbs.if ( SCB_PAGING ) 111619164Sgibbsget_free_or_disc_scb: 111723925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 111823925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 111919623Sgibbsreturn_error: 112023925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 112119623Sgibbsdequeue_disc_scb: 112223925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 112313177Sgibbs/* 112419164Sgibbs * If we have a residual, then we are in the middle of some I/O 112519164Sgibbs * and we have to send this SCB back up to the kernel so that the 112619164Sgibbs * saved data pointers and residual information isn't lost. 112719164Sgibbs */ 112825123Sgibbs test SCB_CONTROL, MUST_DMAUP_SCB jz . + 3; 112925123Sgibbs and SCB_CONTROL, ~MUST_DMAUP_SCB; 113025123Sgibbs jmp dma_up_scb; 113123925Sgibbs test SCB_RESID_SGCNT,0xff jnz dma_up_scb; 113223925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb; 113323925Sgibbsdma_up_scb: 113423925Sgibbs mvi DMAPARAMS, FIFORESET; 113523925Sgibbs mov SCB_TAG call dma_scb; 113619164Sgibbsunlink_disc_scb: 113719623Sgibbs /* jmp instead of call since we want to return anyway */ 113823925Sgibbs mov SCBPTR jmp rem_scb_from_disc_list; 113919164Sgibbsdequeue_free_scb: 114023925Sgibbs mov SCBPTR, FREE_SCBH; 114123925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 11424568Sgibbs 114319164Sgibbsadd_scb_to_disc_list: 114413177Sgibbs/* 114519164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 114619164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 114719164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 114813177Sgibbs */ 114923925Sgibbs mvi SCB_PREV, SCB_LIST_NULL; 115023925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 115123925Sgibbs mov DISCONNECTED_SCBH, SCBPTR; 115223925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je return; 115323925Sgibbs mov SCBPTR,SCB_NEXT; 115423925Sgibbs mov SCB_PREV,DISCONNECTED_SCBH; 115523925Sgibbs mov SCBPTR,DISCONNECTED_SCBH ret; 115623925Sgibbs.endif 1157