aic7xxx.seq revision 29897
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 * 3829897Sgibbs * $Id: aic7xxx.seq,v 1.75 1997/08/13 17:02:28 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? */ 9129897Sgibbs test QINCNT,QCNTMASK jz poll_for_work; 924568Sgibbs 9313690Sgibbs/* 9413690Sgibbs * We have at least one queued SCB now and we don't have any 9519164Sgibbs * SCBs in the list of SCBs awaiting selection. If we have 9623925Sgibbs * any SCBs available for use, pull the tag from the QINFIFO 9719164Sgibbs * and get to work on it. 9813177Sgibbs */ 9923925Sgibbs.if ( SCB_PAGING ) 10023925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 10123925Sgibbs cmp SINDEX, SCB_LIST_NULL je poll_for_work; 10223925Sgibbs.endif 10319164Sgibbsdequeue_scb: 10423925Sgibbs mov CUR_SCBID,QINFIFO; 10523925Sgibbs.if !( SCB_PAGING ) 10619164Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 10723925Sgibbs mov SCBPTR, CUR_SCBID; 10823925Sgibbs.endif 10919164Sgibbsdma_queued_scb: 11019164Sgibbs/* 11119164Sgibbs * DMA the SCB from host ram into the current SCB location. 11219164Sgibbs */ 11323925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 11423925Sgibbs mov CUR_SCBID call dma_scb; 1154568Sgibbs 11613177Sgibbs/* 11713177Sgibbs * See if there is not already an active SCB for this target. This code 11813177Sgibbs * locks out on a per target basis instead of target/lun. Although this 11913177Sgibbs * is not ideal for devices that have multiple luns active at the same 12013177Sgibbs * time, it is faster than looping through all SCB's looking for active 12119921Sgibbs * commands. We also don't have enough spare SCB space for us to store the 12219164Sgibbs * SCBID of the currently busy transaction for each target/lun making it 12319164Sgibbs * impossible to link up the SCBs. 12413177Sgibbs */ 1255647Sgibbstest_busy: 12623925Sgibbs test SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb; 12723925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 12823925Sgibbs mov SAVED_SCBPTR, SCBPTR; 12923925Sgibbs mov SCB_TCL call index_untagged_scb; 13023925Sgibbs mov ARG_1, SINDIR; /* 13119164Sgibbs * ARG_1 should 13219164Sgibbs * now have the SCB ID of 13319164Sgibbs * any active, non-tagged, 13419164Sgibbs * command for this target. 13519164Sgibbs */ 13623925Sgibbs cmp ARG_1, SCB_LIST_NULL je make_busy; 13723925Sgibbs.if ( SCB_PAGING ) 13819164Sgibbs /* 13919164Sgibbs * Put this SCB back onto the free list. It 14019164Sgibbs * may be necessary to satisfy the search for 14119164Sgibbs * the active SCB. 14219164Sgibbs */ 14323925Sgibbs mov SCBPTR, SAVED_SCBPTR; 14423925Sgibbs call add_scb_to_free_list; 14519164Sgibbs /* Find the active SCB */ 14623925Sgibbs mov ALLZEROS call findSCB; 14719218Sgibbs /* 14819218Sgibbs * If we couldn't find it, tell the kernel. This should 14921947Sgibbs * never happen. 15019218Sgibbs */ 15123925Sgibbs cmp SINDEX, SCB_LIST_NULL jne paged_busy_link; 15223925Sgibbs mvi INTSTAT, NO_MATCH_BUSY; 15319218Sgibbspaged_busy_link: 15419164Sgibbs /* Link us in */ 15523925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 15619164Sgibbs /* Put it back on the disconnected list */ 15723925Sgibbs call add_scb_to_disc_list; 15823925Sgibbs mvi SEQCTL, FASTMODE; 15923925Sgibbs jmp poll_for_work; 16025005Sgibbs.else 16119164Sgibbssimple_busy_link: 16223925Sgibbs mov SCBPTR, ARG_1; 16323925Sgibbs mov SCB_LINKED_NEXT, CUR_SCBID; 16423925Sgibbs mvi SEQCTL, FASTMODE; 16523925Sgibbs jmp poll_for_work; 16625005Sgibbs.endif 16719164Sgibbsmake_busy: 16823925Sgibbs mov DINDIR, CUR_SCBID; 16923925Sgibbs mov SCBPTR, SAVED_SCBPTR; 17023925Sgibbs mvi SEQCTL, FASTMODE; 1714568Sgibbs 1725326Sgibbsstart_scb: 17319164Sgibbs /* 17419164Sgibbs * Place us on the waiting list in case our selection 17519164Sgibbs * doesn't win during bus arbitration. 17619164Sgibbs */ 17723925Sgibbs mov SCB_NEXT,WAITING_SCBH; 17823925Sgibbs mov WAITING_SCBH, SCBPTR; 17923925Sgibbsstart_waiting: 18023925Sgibbs /* 18123925Sgibbs * Pull the first entry off of the waiting SCB list 18223925Sgibbs * We don't have to "test_busy" because only transactions that 18323925Sgibbs * have passed that test can be in the WAITING_SCB list. 18423925Sgibbs */ 18523925Sgibbs mov SCBPTR, WAITING_SCBH; 18623925Sgibbs call start_selection; 18723925Sgibbs jmp poll_for_work; 1888104Sgibbs 18923925Sgibbsstart_selection: 19023991Sgibbs.if ( TWIN_CHANNEL ) 19123925Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */ 19223925Sgibbs and A,SELBUSB,SCB_TCL; /* Get new channel bit */ 19323925Sgibbs or SINDEX,A; 19423925Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 19523991Sgibbs.endif 19623925Sgibbsinitialize_scsiid: 19723925Sgibbs and A, TID, SCB_TCL; /* Get target ID */ 19823925Sgibbs and SCSIID, OID; /* Clear old target */ 19923925Sgibbs or SCSIID, A; 20023925Sgibbs mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; 20113177Sgibbs/* 20223925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 20323925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 20413177Sgibbs */ 20523925Sgibbsreselect: 20623925Sgibbs clr MSG_LEN; /* Don't have anything in the mesg buffer */ 20723925Sgibbs mvi CLRSINT0, CLRSELDI; 20823925Sgibbs /* XXX test for and handle ONE BIT condition */ 20923925Sgibbs and SAVED_TCL, SELID_MASK, SELID; 21023925Sgibbs or SEQ_FLAGS,RESELECTED; 21123925Sgibbs jmp select2; 2124568Sgibbs 21313177Sgibbs/* 21423925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 21523925Sgibbs * list. This is achieved by simply moving our "next" pointer into 21623925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 21723925Sgibbs * SCB is used, so don't bother with it now. 21823925Sgibbs */ 21923925Sgibbsselect: 22025005Sgibbs /* Turn off the selection hardware */ 22123925Sgibbs mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* 22223925Sgibbs * ATN on parity errors 22323925Sgibbs * for "in" phases 22423925Sgibbs */ 22525005Sgibbs mvi CLRSINT0, CLRSELDO; 22625005Sgibbs mov SCBPTR, WAITING_SCBH; 22724914Sgibbs mov WAITING_SCBH,SCB_NEXT; 22823925Sgibbs mov SAVED_TCL, SCB_TCL; 22923925Sgibbs/* 23013177Sgibbs * As soon as we get a successful selection, the target should go 23113177Sgibbs * into the message out phase since we have ATN asserted. Prepare 23213177Sgibbs * the message to send. 23313177Sgibbs * 23413177Sgibbs * Messages are stored in scratch RAM starting with a length byte 23513177Sgibbs * followed by the message itself. 23613177Sgibbs */ 2378567Sdg 23813177Sgibbsmk_identify: 23923925Sgibbs and MSG_OUT,0x7,SCB_TCL; /* lun */ 24023925Sgibbs and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ 24123925Sgibbs or MSG_OUT,A; /* or in disconnect privledge */ 24223925Sgibbs or MSG_OUT,MSG_IDENTIFYFLAG; 24323925Sgibbs mvi MSG_LEN, 1; 2444568Sgibbs 24513177Sgibbs/* 24615328Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 24715328Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 24813177Sgibbs */ 2496608Sgibbsmk_tag: 25023925Sgibbs test SCB_CONTROL,TAG_ENB jz mk_message; 25123925Sgibbs and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 25223925Sgibbs mov MSG_OUT[2],SCB_TAG; 25323925Sgibbs add MSG_LEN,2; /* update message length */ 2546608Sgibbs 25518762Sgibbs/* 25618762Sgibbs * Interrupt the driver, and allow it to tweak the message buffer 25718762Sgibbs * if it asks. 25818762Sgibbs */ 25918762Sgibbsmk_message: 26023925Sgibbs test SCB_CONTROL,MK_MESSAGE jz select2; 26123925Sgibbs mvi INTSTAT,AWAITING_MSG; 2626608Sgibbs 2638104Sgibbsselect2: 26425005Sgibbs mvi CLRSINT1,CLRBUSFREE; 26525005Sgibbs or SIMODE1, ENBUSFREE; /* 26625005Sgibbs * We aren't expecting a 26725005Sgibbs * bus free, so interrupt 26825005Sgibbs * the kernel driver if it 26925005Sgibbs * happens. 27025005Sgibbs */ 27113177Sgibbs/* 27222451Sgibbs * Initialize Ultra mode setting and clear the SCSI channel. 27322451Sgibbs */ 27423925Sgibbs or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN; 27523925Sgibbs.if ( ULTRA ) 27622451Sgibbsultra: 27723925Sgibbs mvi SINDEX, ULTRA_ENB+1; 27823925Sgibbs test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ 27923925Sgibbs dec SINDEX; 28022451Sgibbsultra_2: 28123925Sgibbs mov FUNCTION1,SAVED_TCL; 28223925Sgibbs mov A,FUNCTION1; 28323925Sgibbs test SINDIR, A jz ndx_dtr; 28423925Sgibbs or SXFRCTL0, FAST20; 28523925Sgibbs.endif 28622451Sgibbs 28722451Sgibbs/* 28813177Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 28919164Sgibbs * The SCSIRATE settings for each target are stored in an array 29019164Sgibbs * based at TARG_SCRATCH. 29113177Sgibbs */ 29219164Sgibbsndx_dtr: 29323925Sgibbs shr A,4,SAVED_TCL; 29423925Sgibbs test SBLKCTL,SELBUSB jz ndx_dtr_2; 29523925Sgibbs or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */ 29623925Sgibbs or A,0x08; /* Channel B entries add 8 */ 29719164Sgibbsndx_dtr_2: 29823925Sgibbs add SINDEX,TARG_SCRATCH,A; 29923925Sgibbs mov SCSIRATE,SINDIR; 30013177Sgibbs 30115843Sgibbs 30213177Sgibbs/* 30313177Sgibbs * Main loop for information transfer phases. If BSY is false, then 30413177Sgibbs * we have a bus free condition, expected or not. Otherwise, wait 30513177Sgibbs * for the target to assert REQ before checking MSG, C/D and I/O 30613177Sgibbs * for the bus phase. 30713177Sgibbs * 30813177Sgibbs */ 3094568SgibbsITloop: 31024794Sgibbs test SSTAT1,REQINIT jz ITloop; 31124794Sgibbs test SSTAT1, SCSIPERR jnz ITloop; 3124568Sgibbs 31323925Sgibbs and A,PHASE_MASK,SCSISIGI; 31423925Sgibbs mov LASTPHASE,A; 31523925Sgibbs mov SCSISIGO,A; 3164568Sgibbs 31723925Sgibbs cmp ALLZEROS,A je p_dataout; 31823925Sgibbs cmp A,P_DATAIN je p_datain; 31923925Sgibbs cmp A,P_COMMAND je p_command; 32023925Sgibbs cmp A,P_MESGOUT je p_mesgout; 32123925Sgibbs cmp A,P_STATUS je p_status; 32223925Sgibbs cmp A,P_MESGIN je p_mesgin; 3234568Sgibbs 32423925Sgibbs mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ 32523925Sgibbs jmp ITloop; /* Try reading the bus again. */ 3264568Sgibbs 32723925Sgibbsawait_busfree: 32823925Sgibbs and SIMODE1, ~ENBUSFREE; 32924794Sgibbs call clear_target_state; 33023925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 33123925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 33223925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 33323925Sgibbs mvi INTSTAT, BAD_PHASE; 33423925Sgibbs 33523925Sgibbsclear_target_state: 33623925Sgibbs clr DFCNTRL; 33723925Sgibbs clr SCSIRATE; /* 33823925Sgibbs * We don't know the target we will 33923925Sgibbs * connect to, so default to narrow 34023925Sgibbs * transfers to avoid parity problems. 34123925Sgibbs */ 34223925Sgibbs and SXFRCTL0, ~FAST20; 34323925Sgibbs mvi LASTPHASE, P_BUSFREE; 34423925Sgibbs /* clear target specific flags */ 34523925Sgibbs and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret; 34623925Sgibbs 3474568Sgibbsp_dataout: 34823925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET; 34923925Sgibbs jmp data_phase_init; 3504568Sgibbs 35113177Sgibbs/* 35213177Sgibbs * If we re-enter the data phase after going through another phase, the 35313177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 35413177Sgibbs */ 3559928Sgibbsdata_phase_reinit: 35623925Sgibbs mvi DINDEX, STCNT; 35723925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 35823925Sgibbs jmp data_phase_loop; 3594568Sgibbs 3609928Sgibbsp_datain: 36123925Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 3629928Sgibbsdata_phase_init: 36323925Sgibbs call assert; /* 36419164Sgibbs * Ensure entering a data 36519164Sgibbs * phase is okay - seen identify, etc. 36619164Sgibbs */ 3675775Sgibbs 36823925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 3694568Sgibbs 37019164Sgibbs /* 37119164Sgibbs * Initialize the DMA address and counter from the SCB. 37219164Sgibbs * Also set SG_COUNT and SG_NEXT in memory since we cannot 37319164Sgibbs * modify the values in the SCB itself until we see a 37419164Sgibbs * save data pointers message. 37519164Sgibbs */ 37623925Sgibbs mvi DINDEX, HADDR; 37723925Sgibbs mvi SCB_DATAPTR call bcopy_7; 37819164Sgibbs 37923925Sgibbs call set_stcnt_from_hcnt; 38019164Sgibbs 38123925Sgibbs mov SG_COUNT,SCB_SGCOUNT; 38219164Sgibbs 38323925Sgibbs mvi DINDEX, SG_NEXT; 38423925Sgibbs mvi SCB_SGPTR call bcopy_4; 38519164Sgibbs 3869928Sgibbsdata_phase_loop: 38716260Sgibbs/* Guard against overruns */ 38823925Sgibbs test SG_COUNT, 0xff jnz data_phase_inbounds; 38916260Sgibbs/* 39016260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to 39116260Sgibbs * 16meg and let the target run until it changes phase. 39216260Sgibbs * When the transfer completes, notify the host that we 39316260Sgibbs * had an overrun. 39416260Sgibbs */ 39523925Sgibbs or SXFRCTL1,BITBUCKET; 39623925Sgibbs mvi HCNT[0], 0xff; 39723925Sgibbs mvi HCNT[1], 0xff; 39823925Sgibbs mvi HCNT[2], 0xff; 39923925Sgibbs call set_stcnt_from_hcnt; 40016260Sgibbs 40116260Sgibbsdata_phase_inbounds: 40219164Sgibbs/* If we are the last SG block, ensure wideodd is off. */ 40323925Sgibbs cmp SG_COUNT,0x01 jne data_phase_wideodd; 40423925Sgibbs and DMAPARAMS, ~WIDEODD; 4059928Sgibbsdata_phase_wideodd: 40623925Sgibbs mov DMAPARAMS call dma; 4074568Sgibbs 40816260Sgibbs/* Go tell the host about any overruns */ 40923925Sgibbs test SXFRCTL1,BITBUCKET jnz data_phase_overrun; 41016260Sgibbs 41122451Sgibbs/* Exit if we had an underrun. dma clears SINDEX in this case. */ 41223925Sgibbs test SINDEX,0xff jz data_phase_finish; 4137532Sgibbs 41413177Sgibbs/* 41513177Sgibbs * Advance the scatter-gather pointers if needed 41613177Sgibbs */ 4179928Sgibbssg_advance: 41823925Sgibbs dec SG_COUNT; /* one less segment to go */ 4194568Sgibbs 42023925Sgibbs test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ 4214568Sgibbs 42223925Sgibbs clr A; /* add sizeof(struct scatter) */ 42323925Sgibbs add SG_NEXT[0],SG_SIZEOF; 42423925Sgibbs adc SG_NEXT[1],A; 4254568Sgibbs 42613177Sgibbs/* 42713177Sgibbs * Load a struct scatter and set up the data address and length. 42813177Sgibbs * If the working value of the SG count is nonzero, then 42913177Sgibbs * we need to load a new set of values. 43013177Sgibbs * 43115328Sgibbs * This, like all DMA's, assumes little-endian host data storage. 43213177Sgibbs */ 4339928Sgibbssg_load: 43423925Sgibbs mvi DINDEX, HADDR; 43523925Sgibbs mvi SG_NEXT call bcopy_4; 4364568Sgibbs 43723925Sgibbs mvi HCNT[0],SG_SIZEOF; 43823925Sgibbs clr HCNT[1]; 43923925Sgibbs clr HCNT[2]; 44022568Sgibbs 44123925Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 4429928Sgibbs 44323925Sgibbs call dma_finish; 4449928Sgibbs 44513177Sgibbs/* 44613177Sgibbs * Copy data from FIFO into SCB data pointer and data count. This assumes 44719164Sgibbs * that the SG segments are of the form: 44813177Sgibbs * 44913177Sgibbs * struct ahc_dma_seg { 45019164Sgibbs * u_int32_t addr; four bytes, little-endian order 45119164Sgibbs * u_int32_t len; four bytes, little endian order 45213177Sgibbs * }; 45313177Sgibbs */ 45423925Sgibbs mvi HADDR call dfdat_in_7; 4559928Sgibbs 45613177Sgibbs/* Load STCNT as well. It is a mirror of HCNT */ 45723925Sgibbs call set_stcnt_from_hcnt; 45823925Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 4594568Sgibbs 4609928Sgibbsdata_phase_finish: 46113177Sgibbs/* 46213177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB 46313177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 46413177Sgibbs * were transferred on the SCSI (as opposed to the host) bus. 46513177Sgibbs */ 46623925Sgibbs mov SCB_RESID_DCNT[0],STCNT[0]; 46723925Sgibbs mov SCB_RESID_DCNT[1],STCNT[1]; 46823925Sgibbs mov SCB_RESID_DCNT[2],STCNT[2]; 46923925Sgibbs mov SCB_RESID_SGCNT, SG_COUNT; 47022568Sgibbs 47122568Sgibbs /* We have seen a data phase */ 47223925Sgibbs or SEQ_FLAGS, DPHASE; 47322568Sgibbs 47423925Sgibbs jmp ITloop; 4754568Sgibbs 47616260Sgibbsdata_phase_overrun: 47713177Sgibbs/* 47816260Sgibbs * Turn off BITBUCKET mode and notify the host 47916260Sgibbs */ 48023925Sgibbs and SXFRCTL1, ~BITBUCKET; 48123925Sgibbs mvi INTSTAT,DATA_OVERRUN; 48223925Sgibbs jmp ITloop; 48316260Sgibbs 48416260Sgibbs/* 48515328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 48613177Sgibbs */ 4874568Sgibbsp_command: 48823925Sgibbs call assert; 4894568Sgibbs 49013177Sgibbs/* 49115328Sgibbs * Load HADDR and HCNT. 49213177Sgibbs */ 49323925Sgibbs mvi DINDEX, HADDR; 49423925Sgibbs mvi SCB_CMDPTR call bcopy_5; 49523925Sgibbs clr HCNT[1]; 49623925Sgibbs clr HCNT[2]; 4974568Sgibbs 49823925Sgibbs call set_stcnt_from_hcnt; 4994568Sgibbs 50023925Sgibbs mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; 50123925Sgibbs jmp ITloop; 5024568Sgibbs 50313177Sgibbs/* 50413177Sgibbs * Status phase. Wait for the data byte to appear, then read it 50513177Sgibbs * and store it into the SCB. 50613177Sgibbs */ 5074568Sgibbsp_status: 50823925Sgibbs call assert; 50919803Sgibbs 51023925Sgibbs mov SCB_TARGET_STATUS, SCSIDATL; 51123925Sgibbs jmp ITloop; 5124568Sgibbs 51313177Sgibbs/* 51415328Sgibbs * Message out phase. If there is not an active message, but the target 51513177Sgibbs * took us into this phase anyway, build a no-op message and send it. 51613177Sgibbs */ 5174568Sgibbsp_mesgout: 51823925Sgibbs test MSG_LEN, 0xff jnz p_mesgout_start; 51923925Sgibbs mvi MSG_NOOP call mk_mesg; /* build NOP message */ 52013177Sgibbsp_mesgout_start: 52113177Sgibbs/* 52223925Sgibbs * Set up automatic PIO transfer from MSG_OUT. Bit 3 in 52313177Sgibbs * SXFRCTL0 (SPIOEN) is already on. 52413177Sgibbs */ 52523925Sgibbs mvi SINDEX,MSG_OUT; 52623925Sgibbs mov DINDEX,MSG_LEN; 5274568Sgibbs 52813177Sgibbs/* 52913177Sgibbs * When target asks for a byte, drop ATN if it's the last one in 53013177Sgibbs * the message. Otherwise, keep going until the message is exhausted. 53123925Sgibbs * ATN must be dropped *at least* 90ns before we ack the last byte, so 53223925Sgibbs * the code is aranged to execute two instructions before the byte is 53323925Sgibbs * transferred to give a good margin of safety 53413177Sgibbs * 53513177Sgibbs * Keep an eye out for a phase change, in case the target issues 53613177Sgibbs * a MESSAGE REJECT. 53713177Sgibbs */ 53813177Sgibbsp_mesgout_loop: 53924794Sgibbs test SSTAT1, REQINIT jz p_mesgout_loop; 54024794Sgibbs test SSTAT1, SCSIPERR jnz p_mesgout_loop; 54123925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 54223925Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 54325005Sgibbsp_mesgout_testretry: 54425005Sgibbs test DINDEX,0xff jnz p_mesgout_dropatn; 54525005Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 54625005Sgibbs jmp p_mesgout_start; 54713177Sgibbs/* 54813177Sgibbs * If the next bus phase after ATN drops is a message out, it means 54913177Sgibbs * that the target is requesting that the last message(s) be resent. 55013177Sgibbs */ 55124914Sgibbsp_mesgout_dropatn: 55224914Sgibbs cmp DINDEX,1 jne p_mesgout_outb; /* last byte? */ 55324914Sgibbs mvi CLRSINT1,CLRATNO; /* drop ATN */ 55419906Sgibbsp_mesgout_outb: 55523925Sgibbs dec DINDEX; 55623925Sgibbs mov SCSIDATL,SINDIR; 55723925Sgibbs jmp p_mesgout_loop; 5584568Sgibbs 55919906Sgibbsp_mesgout_done: 56023925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 56123925Sgibbs clr MSG_LEN; /* no active msg */ 56223925Sgibbs jmp ITloop; 5634568Sgibbs 56413177Sgibbs/* 56513177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 56613177Sgibbs */ 5674568Sgibbsp_mesgin: 56823925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 5694568Sgibbs 57023925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 57123925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 57223925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 57323925Sgibbs cmp ALLZEROS,A je mesgin_complete; 57423925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 57523925Sgibbs cmp A,MSG_EXTENDED je mesgin_extended; 57623925Sgibbs cmp A,MSG_MESSAGE_REJECT je mesgin_reject; 57723925Sgibbs cmp A,MSG_NOOP je mesgin_done; 5784568Sgibbs 5799954Sgibbsrej_mesgin: 58013177Sgibbs/* 58119164Sgibbs * We have no idea what this message in is, so we issue a message reject 58219164Sgibbs * and hope for the best. In any case, rejection should be a rare 58319164Sgibbs * occurrence - signal the driver when it happens. 58413177Sgibbs */ 58523925Sgibbs mvi INTSTAT,SEND_REJECT; /* let driver know */ 5869954Sgibbs 58723925Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 5889954Sgibbs 5899954Sgibbsmesgin_done: 59023925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 59123925Sgibbs jmp ITloop; 5929954Sgibbs 5939954Sgibbs 5949954Sgibbsmesgin_complete: 59513177Sgibbs/* 59619164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, 59719164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 59819164Sgibbs * is a residual or the status byte is something other than NO_ERROR (0). In 59919164Sgibbs * either of these conditions, we upload the SCB back to the host so it can 60019164Sgibbs * process this information. In the case of a non zero status byte, we 60119164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 60219164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 60319164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set 60419164Sgibbs * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload 60519164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list. 60619164Sgibbs * If the kernel driver does not wish to request sense, it need only clear 60719164Sgibbs * RETURN_1, and the command is allowed to complete normally. We don't bother 60819164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra 60919164Sgibbs * work in the kernel driver to ensure that the entry was removed before the 61019164Sgibbs * command complete code tried processing it. 61113177Sgibbs */ 61219164Sgibbs 61313177Sgibbs/* 61419164Sgibbs * First check for residuals 61513177Sgibbs */ 61623925Sgibbs test SCB_RESID_SGCNT,0xff jnz upload_scb; 61723925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */ 61819164Sgibbsupload_scb: 61923925Sgibbs mvi DMAPARAMS, FIFORESET; 62023925Sgibbs mov SCB_TAG call dma_scb; 6217532Sgibbscheck_status: 62223925Sgibbs test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */ 62323925Sgibbs mvi INTSTAT,BAD_STATUS; /* let driver know */ 62423925Sgibbs cmp RETURN_1, SEND_SENSE jne status_ok; 62519164Sgibbs /* This SCB becomes the next to execute as it will retrieve sense */ 62623925Sgibbs mov SCB_LINKED_NEXT, SCB_TAG; 62723925Sgibbs jmp dma_next_scb; 6285326Sgibbs 6294568Sgibbsstatus_ok: 63013177Sgibbs/* First, mark this target as free. */ 63123925Sgibbs test SCB_CONTROL,TAG_ENB jnz complete; /* 63213177Sgibbs * Tagged commands 63313177Sgibbs * don't busy the 63413177Sgibbs * target. 63513177Sgibbs */ 63623925Sgibbs mov SAVED_SCBPTR, SCBPTR; 63723925Sgibbs mov SAVED_LINKPTR, SCB_LINKED_NEXT; 63823925Sgibbs mov SCB_TCL call index_untagged_scb; 63923925Sgibbs mov DINDIR, SAVED_LINKPTR; 64023925Sgibbs mov SCBPTR, SAVED_SCBPTR; 6415326Sgibbs 6425326Sgibbscomplete: 64319164Sgibbs /* Post the SCB and issue an interrupt */ 64428169Sgibbs.if ( SCB_PAGING ) 64528169Sgibbs /* 64628169Sgibbs * Spin loop until there is space 64728169Sgibbs * in the QOUTFIFO. 64828169Sgibbs */ 64929897Sgibbs cmp CMDOUTCNT, FIFODEPTH je .; 65028169Sgibbs inc CMDOUTCNT; 65128169Sgibbs.endif 65223925Sgibbs mov QOUTFIFO,SCB_TAG; 65323925Sgibbs mvi INTSTAT,CMDCMPLT; 65423925Sgibbs test SCB_CONTROL, ABORT_SCB jz dma_next_scb; 65523925Sgibbs mvi INTSTAT, ABORT_CMDCMPLT; 65619164Sgibbs 65719164Sgibbsdma_next_scb: 65823925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list; 65923925Sgibbs.if !( SCB_PAGING ) 66019164Sgibbs /* Only DMA on top of ourselves if we are the SCB to download */ 66123925Sgibbs mov A, SCB_LINKED_NEXT; 66223925Sgibbs cmp SCB_TAG, A je dma_next_scb2; 66325005Sgibbs call add_scb_to_free_list; 66423925Sgibbs mov SCBPTR, A; 66523925Sgibbs jmp add_to_waiting_list; 66623925Sgibbs.endif 66719164Sgibbsdma_next_scb2: 66823925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 66923925Sgibbs mov SCB_LINKED_NEXT call dma_scb; 67019164Sgibbsadd_to_waiting_list: 67123925Sgibbs mov SCB_NEXT,WAITING_SCBH; 67223925Sgibbs mov WAITING_SCBH, SCBPTR; 67323925Sgibbs /* 67423925Sgibbs * Prepare our selection hardware before the busfree so we have a 67523925Sgibbs * high probability of winning arbitration. 67623925Sgibbs */ 67723925Sgibbs call start_selection; 67823925Sgibbs jmp await_busfree; 67919921Sgibbsadd_to_free_list: 68023925Sgibbs call add_scb_to_free_list; 68123925Sgibbs jmp await_busfree; 6824568Sgibbs 68313177Sgibbs/* 68418762Sgibbs * Is it an extended message? Copy the message to our message buffer and 68518762Sgibbs * notify the host. The host will tell us whether to reject this message, 68618762Sgibbs * respond to it with the message that the host placed in our message buffer, 68718762Sgibbs * or simply to do nothing. 68813177Sgibbs */ 6899954Sgibbsmesgin_extended: 69023925Sgibbs mvi MSGIN_EXT_LEN call inb_next; 69123925Sgibbs mov A, MSGIN_EXT_LEN; 69218762Sgibbsmesgin_extended_loop: 69323925Sgibbs mov DINDEX call inb_next; 69423925Sgibbs dec A; 69523925Sgibbs cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test; 69623925Sgibbs dec DINDEX; /* dump by repeatedly filling the last byte */ 69719164Sgibbsmesgin_extended_loop_test: 69823925Sgibbs test A, 0xFF jnz mesgin_extended_loop; 69918762Sgibbsmesgin_extended_intr: 70023925Sgibbs mvi INTSTAT,EXTENDED_MSG; /* let driver know */ 70123925Sgibbs cmp RETURN_1,SEND_REJ je rej_mesgin; 70223925Sgibbs cmp RETURN_1,SEND_MSG jne mesgin_done; 70318762Sgibbs/* The kernel has setup a message to be sent */ 70423925Sgibbs or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */ 70523925Sgibbs jmp mesgin_done; 7065562Sgibbs 70713177Sgibbs/* 70813177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 70913177Sgibbs * and await the bus going free. 71013177Sgibbs */ 7119954Sgibbsmesgin_disconnect: 71223925Sgibbs or SCB_CONTROL,DISCONNECTED; 71323925Sgibbs.if ( SCB_PAGING ) 71423925Sgibbs call add_scb_to_disc_list; 71523925Sgibbs.endif 71623925Sgibbs jmp await_busfree; 71719164Sgibbs 71815328Sgibbs/* 71919164Sgibbs * Save data pointers message: 72019164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 72119164Sgibbs * only if we've actually been into a data phase to change them. This 72219164Sgibbs * protects against bogus data in scratch ram and the residual counts 72319164Sgibbs * since they are only initialized when we go into data_in or data_out. 72415328Sgibbs */ 72519164Sgibbsmesgin_sdptrs: 72623925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 72723925Sgibbs mov SCB_SGCOUNT,SG_COUNT; 7284568Sgibbs 72919164Sgibbs /* The SCB SGPTR becomes the next one we'll download */ 73023925Sgibbs mvi DINDEX, SCB_SGPTR; 73123925Sgibbs mvi SG_NEXT call bcopy_4; 73219164Sgibbs 73319164Sgibbs /* The SCB DATAPTR0 becomes the current SHADDR */ 73423925Sgibbs mvi DINDEX, SCB_DATAPTR; 73523925Sgibbs mvi SHADDR call bcopy_4; 73619164Sgibbs 73713177Sgibbs/* 73819164Sgibbs * Use the residual number since STCNT is corrupted by any message transfer. 73913177Sgibbs */ 74023925Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 74119164Sgibbs 74223925Sgibbs jmp mesgin_done; 7434568Sgibbs 74413177Sgibbs/* 74513177Sgibbs * Restore pointers message? Data pointers are recopied from the 74613177Sgibbs * SCB anytime we enter a data phase for the first time, so all 74713177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 74813177Sgibbs * code do the rest. 74913177Sgibbs */ 7509954Sgibbsmesgin_rdptrs: 75123925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 75223925Sgibbs * We'll reload them 75313177Sgibbs * the next time through 75423925Sgibbs * the dataphase. 75513177Sgibbs */ 75623925Sgibbs jmp mesgin_done; 7574568Sgibbs 75813177Sgibbs/* 75913177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 76013177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 76113177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 76213177Sgibbs */ 7639954Sgibbsmesgin_identify: 76423925Sgibbs test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/ 76523925Sgibbs and A,0x07; /* lun in lower three bits */ 76623925Sgibbs or SAVED_TCL,A; /* SAVED_TCL should be complete now */ 76723925Sgibbs mov SAVED_TCL call index_untagged_scb; 76823925Sgibbs mov ARG_1, SINDIR; 76924608Sgibbs.if ( SCB_PAGING ) 77023925Sgibbs cmp ARG_1,SCB_LIST_NULL jne use_findSCB; 77124608Sgibbs.else 77224608Sgibbs cmp ARG_1,SCB_LIST_NULL je snoop_tag; 77324608Sgibbs /* Directly index the SCB */ 77424608Sgibbs mov SCBPTR,ARG_1; 77524608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 77624608Sgibbs jmp setup_SCB; 77724608Sgibbs.endif 77813177Sgibbs/* 77913177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 78023168Sgibbs * If we get one, we use the tag returned to find the proper 78115328Sgibbs * SCB. With SCB paging, this requires using findSCB for both tagged 78215328Sgibbs * and non-tagged transactions since the SCB may exist in any slot. 78315328Sgibbs * If we're not using SCB paging, we can use the tag as the direct 78415328Sgibbs * index to the SCB. 78513177Sgibbs */ 78624608Sgibbssnoop_tag: 78723925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 78813177Sgibbssnoop_tag_loop: 78923925Sgibbs test SSTAT1,REQINIT jz snoop_tag_loop; 79024794Sgibbs test SSTAT1, SCSIPERR jnz snoop_tag_loop; 79123925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 79223925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 79323925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 7946608Sgibbsget_tag: 79523925Sgibbs or SEQ_FLAGS, TAGGED_SCB; 79623925Sgibbs mvi ARG_1 call inb_next; /* tag value */ 79713177Sgibbs/* 79813177Sgibbs * See if the tag is in range. The tag is < SCBCOUNT if we add 79913177Sgibbs * the complement of SCBCOUNT to the incomming tag and there is 80013177Sgibbs * no carry. 80113177Sgibbs */ 80229897Sgibbs add SINDEX,COMP_SCBCOUNT,ARG_1; 80323925Sgibbs jc not_found; 80413177Sgibbs 80523925Sgibbs.if ! ( SCB_PAGING ) 80624608Sgibbsindex_by_tag: 80724608Sgibbs mov SCBPTR,ARG_1; 80824608Sgibbs mov A, SAVED_TCL; 80924608Sgibbs cmp SCB_TCL,A jne not_found; 81024608Sgibbs test SCB_CONTROL,TAG_ENB jz not_found; 81124608Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found; 81224608Sgibbs.else 81313177Sgibbs/* 81415328Sgibbs * Ensure that the SCB the tag points to is for an SCB transaction 81513177Sgibbs * to the reconnecting target. 81613177Sgibbs */ 81715328Sgibbsuse_findSCB: 81823925Sgibbs mov ALLZEROS call findSCB; /* Have to search */ 81923925Sgibbs cmp SINDEX, SCB_LIST_NULL je not_found; 82024608Sgibbs.endif 82115328Sgibbssetup_SCB: 82223925Sgibbs and SCB_CONTROL,~DISCONNECTED; 82323925Sgibbs or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 82423925Sgibbs jmp mesgin_done; 82515328Sgibbs 82619218Sgibbsnot_found: 82723925Sgibbs mvi INTSTAT, NO_MATCH; 82825005Sgibbs mvi MSG_BUS_DEV_RESET call mk_mesg; 82923925Sgibbs jmp mesgin_done; 8306608Sgibbs 83113177Sgibbs/* 83213177Sgibbs * Message reject? Let the kernel driver handle this. If we have an 83313177Sgibbs * outstanding WDTR or SDTR negotiation, assume that it's a response from 83413177Sgibbs * the target selecting 8bit or asynchronous transfer, otherwise just ignore 83513177Sgibbs * it since we have no clue what it pertains to. 83613177Sgibbs */ 8379954Sgibbsmesgin_reject: 83823925Sgibbs mvi INTSTAT, REJECT_MSG; 83923925Sgibbs jmp mesgin_done; 8405562Sgibbs 84113177Sgibbs/* 84213177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ] 84313177Sgibbs */ 8444568Sgibbs 84513177Sgibbs/* 84613177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX 84713177Sgibbs * if there is no active message already. SINDEX is returned intact. 84813177Sgibbs */ 8494568Sgibbsmk_mesg: 85023925Sgibbs mvi SEQCTL, PAUSEDIS|FASTMODE; 85123925Sgibbs test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */ 85213177Sgibbs 85313177Sgibbs /* 85413177Sgibbs * Hmmm. For some reason the mesg buffer is in use. 85513177Sgibbs * Tell the driver. It should look at SINDEX to find 85613177Sgibbs * out what we wanted to use the buffer for and resolve 85713177Sgibbs * the conflict. 85813177Sgibbs */ 85923925Sgibbs mvi SEQCTL,FASTMODE; 86023925Sgibbs mvi INTSTAT,MSG_BUFFER_BUSY; 8614568Sgibbs 8624568Sgibbsmk_mesg1: 86323925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 86423925Sgibbs mvi MSG_LEN,1; /* length = 1 */ 86523925Sgibbs mov MSG_OUT,SINDEX; /* 1-byte message */ 86623925Sgibbs mvi SEQCTL,FASTMODE ret; 8674568Sgibbs 86813177Sgibbs/* 86913177Sgibbs * Functions to read data in Automatic PIO mode. 87013177Sgibbs * 87113177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 87213177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 87313177Sgibbs * latched (the usual way), then read the data byte directly off the bus 87413177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 87513177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 87613177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 87713177Sgibbs * we send our ACK. 87813177Sgibbs * 87913177Sgibbs * The assumption here is that these are called in a particular sequence, 88013177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 88113177Sgibbs * use the same calling convention as inb. 88213177Sgibbs */ 88313177Sgibbs 88413177Sgibbsinb_next: 88523925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 88613360Sgibbsinb_next_wait: 88721947Sgibbs /* 88821947Sgibbs * If there is a parity error, wait for the kernel to 88921947Sgibbs * see the interrupt and prepare our message response 89021947Sgibbs * before continuing. 89121947Sgibbs */ 89223925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 89323925Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait; 89423925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 89523925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 89619623Sgibbsinb_first: 89723925Sgibbs mov DINDEX,SINDEX; 89823925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 89913177Sgibbsinb_last: 90023925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 9014568Sgibbs 90213177Sgibbsmesgin_phasemis: 90313177Sgibbs/* 90413177Sgibbs * We expected to receive another byte, but the target changed phase 90513177Sgibbs */ 90623925Sgibbs mvi INTSTAT, MSGIN_PHASEMIS; 90723925Sgibbs jmp ITloop; 9084568Sgibbs 90913177Sgibbs/* 91013177Sgibbs * DMA data transfer. HADDR and HCNT must be loaded first, and 91113177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for 91213177Sgibbs * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 91313177Sgibbs * during initialization. 91413177Sgibbs */ 9154568Sgibbsdma: 91623925Sgibbs mov DFCNTRL,SINDEX; 91722568Sgibbsdma_loop: 91823925Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 91923925Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 92022568Sgibbsdma_phasemis: 92123925Sgibbs test SSTAT0,SDONE jnz dma_checkfifo; 92223925Sgibbs mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ 9234568Sgibbs 92413177Sgibbs/* 92513177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or 92613177Sgibbs * the target changes the phase (in light of this, it makes sense that 92713177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 92813177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto- 92913177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty 93013177Sgibbs * status. 93113177Sgibbs */ 93222568Sgibbsdma_checkfifo: 93323925Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 93422568Sgibbsdma_fifoflush: 93523925Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 9364568Sgibbs 93722568Sgibbsdma_fifoempty: 93822568Sgibbs /* Don't clobber an inprogress host data transfer */ 93923925Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 94013177Sgibbs/* 94113177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 94213177Sgibbs * actually off first lest we get an ILLSADDR. 94313177Sgibbs */ 94422568Sgibbsdma_dmadone: 94523925Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 94622568Sgibbsdma_halt: 94723925Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 94818762Sgibbsreturn: 94923925Sgibbs ret; 9504568Sgibbs 95113177Sgibbs/* 95213177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 95313177Sgibbs * message. 95413177Sgibbs */ 9554568Sgibbsassert: 95623925Sgibbs test SEQ_FLAGS,RESELECTED jz return; /* reselected? */ 95723925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 9584568Sgibbs 95923925Sgibbs mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ 9604568Sgibbs 96124608Sgibbs.if ( SCB_PAGING ) 96213177Sgibbs/* 96319218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) 96419218Sgibbs * or by the SCBIDn ARG_1. The search begins at the SCB index passed in 96519218Sgibbs * via SINDEX. If the SCB cannot be found, SINDEX will be SCB_LIST_NULL, 96619218Sgibbs * otherwise, SCBPTR is set to the proper SCB. 96713177Sgibbs */ 9684568SgibbsfindSCB: 96923925Sgibbs mov SCBPTR,SINDEX; /* switch to next SCB */ 97023925Sgibbs mov A, ARG_1; /* Tag passed in ARG_1 */ 97123925Sgibbs cmp SCB_TAG,A jne findSCB_loop; 97223925Sgibbs test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/ 97323168SgibbsfindSCB_loop: 97423925Sgibbs inc SINDEX; 97529897Sgibbs cmp SINDEX,SCBCOUNT jne findSCB; 97619164Sgibbs/* 97719164Sgibbs * We didn't find it. If we're paging, pull an SCB and DMA down the 97819164Sgibbs * one we want. If we aren't paging or the SCB we dma down has the 97919218Sgibbs * abort flag set, return not found. 98019164Sgibbs */ 98123925Sgibbs mov ALLZEROS call get_free_or_disc_scb; 98223925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 98323925Sgibbs mov ARG_1 call dma_scb; 98425123Sgibbs test SCB_RESID_SGCNT, 0xff jz . + 2; 98525123Sgibbs or SCB_CONTROL, MUST_DMAUP_SCB; 98623925Sgibbs test SCB_CONTROL, ABORT_SCB jz return; 98719218Sgibbsfind_error: 98823925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 98915328SgibbsfoundSCB: 99023925Sgibbs test SCB_CONTROL, ABORT_SCB jnz find_error; 99119164Sgibbsrem_scb_from_disc_list: 99215328Sgibbs/* Remove this SCB from the disconnection list */ 99323925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev; 99423925Sgibbs mov SAVED_LINKPTR, SCB_PREV; 99523925Sgibbs mov SCBPTR, SCB_NEXT; 99623925Sgibbs mov SCB_PREV, SAVED_LINKPTR; 99723925Sgibbs mov SCBPTR, SINDEX; 99815328Sgibbsunlink_prev: 99923925Sgibbs cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */ 100023925Sgibbs mov SAVED_LINKPTR, SCB_NEXT; 100123925Sgibbs mov SCBPTR, SCB_PREV; 100223925Sgibbs mov SCB_NEXT, SAVED_LINKPTR; 100323925Sgibbs mov SCBPTR, SINDEX ret; 100415328SgibbsrHead: 100523925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 100623925Sgibbs.else 100723925Sgibbs ret; 100823925Sgibbs.endif 10094568Sgibbs 101019164Sgibbsset_stcnt_from_hcnt: 101123925Sgibbs mov STCNT[0], HCNT[0]; 101223925Sgibbs mov STCNT[1], HCNT[1]; 101323925Sgibbs mov STCNT[2], HCNT[2] ret; 10144568Sgibbs 101519164Sgibbsbcopy_7: 101623925Sgibbs mov DINDIR, SINDIR; 101723925Sgibbs mov DINDIR, SINDIR; 101819164Sgibbsbcopy_5: 101923925Sgibbs mov DINDIR, SINDIR; 102019164Sgibbsbcopy_4: 102123925Sgibbs mov DINDIR, SINDIR; 102219164Sgibbsbcopy_3: 102323925Sgibbs mov DINDIR, SINDIR; 102423925Sgibbs mov DINDIR, SINDIR; 102523925Sgibbs mov DINDIR, SINDIR ret; 10264568Sgibbs 102719164Sgibbsdma_scb: 102819164Sgibbs /* 102919164Sgibbs * SCB index is in SINDEX. Determine the physical address in 103019164Sgibbs * the host where this SCB is located and load HADDR with it. 103119164Sgibbs */ 103223925Sgibbs shr DINDEX, 3, SINDEX; 103323925Sgibbs shl A, 5, SINDEX; 103423925Sgibbs add HADDR[0], A, HSCB_ADDR[0]; 103523925Sgibbs mov A, DINDEX; 103623925Sgibbs adc HADDR[1], A, HSCB_ADDR[1]; 103723925Sgibbs clr A; 103823925Sgibbs adc HADDR[2], A, HSCB_ADDR[2]; 103923925Sgibbs adc HADDR[3], A, HSCB_ADDR[3]; 104019164Sgibbs /* Setup Count */ 104123925Sgibbs mvi HCNT[0], 28; 104223925Sgibbs clr HCNT[1]; 104323925Sgibbs clr HCNT[2]; 104423925Sgibbs mov DFCNTRL, DMAPARAMS; 104523925Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 104619164Sgibbs /* Fill it with the SCB data */ 104724175Sgibbscopy_scb_tofifo: 104824175Sgibbs mvi SINDEX, SCB_CONTROL; 104924175Sgibbs add A, 28, SINDEX; 105024175Sgibbscopy_scb_tofifo_loop: 105124175Sgibbs mov DFDAT,SINDIR; 105224175Sgibbs mov DFDAT,SINDIR; 105324175Sgibbs mov DFDAT,SINDIR; 105424175Sgibbs mov DFDAT,SINDIR; 105524175Sgibbs mov DFDAT,SINDIR; 105624175Sgibbs mov DFDAT,SINDIR; 105724175Sgibbs mov DFDAT,SINDIR; 105824175Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 105923925Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 106019164Sgibbsdma_scb_fromhost: 106123925Sgibbs call dma_finish; 106219164Sgibbs /* If we were putting the SCB, we are done */ 106323925Sgibbs test DMAPARAMS, DIRECTION jz return; 106423925Sgibbs mvi SCB_CONTROL call dfdat_in_7; 106523925Sgibbs call dfdat_in_7_continued; 106623925Sgibbs call dfdat_in_7_continued; 106723925Sgibbs jmp dfdat_in_7_continued; 106819164Sgibbsdfdat_in_7: 106923925Sgibbs mov DINDEX,SINDEX; 107019164Sgibbsdfdat_in_7_continued: 107123925Sgibbs mov DINDIR,DFDAT; 107223925Sgibbs mov DINDIR,DFDAT; 107323925Sgibbs mov DINDIR,DFDAT; 107423925Sgibbs mov DINDIR,DFDAT; 107523925Sgibbs mov DINDIR,DFDAT; 107623925Sgibbs mov DINDIR,DFDAT; 107723925Sgibbs mov DINDIR,DFDAT ret; 107819164Sgibbs 107913177Sgibbs/* 108019164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 108119164Sgibbs * DMA and wait for it to acknowledge that it's off. 108213177Sgibbs */ 108319164Sgibbsdma_finish: 108423925Sgibbs test DFSTATUS,HDONE jz dma_finish; 108522234Sgibbs /* Turn off DMA */ 108623925Sgibbs and DFCNTRL, ~HDMAEN; 108723925Sgibbs test DFCNTRL, HDMAEN jnz .; 108823925Sgibbs ret; 10899928Sgibbs 109019164Sgibbsindex_untagged_scb: 109123925Sgibbs mov DINDEX, SINDEX; 109223925Sgibbs shr DINDEX, 4; 109323925Sgibbs and DINDEX, 0x03; /* Bottom two bits of tid */ 109423925Sgibbs add DINDEX, SCB_BUSYTARGETS; 109523925Sgibbs shr A, 6, SINDEX; /* Target ID divided by 4 */ 109623925Sgibbs test SINDEX, SELBUSB jz index_untagged_scb2; 109723925Sgibbs add A, 2; /* Add 2 positions */ 109819164Sgibbsindex_untagged_scb2: 109923925Sgibbs mov SCBPTR, A; /* 110019164Sgibbs * Select the SCB with this 110119164Sgibbs * target's information. 110219164Sgibbs */ 110323925Sgibbs mov SINDEX, DINDEX ret; 11049928Sgibbs 110523925Sgibbsadd_scb_to_free_list: 110623925Sgibbs mov SCB_NEXT, FREE_SCBH; 110723925Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 110823925Sgibbs mov FREE_SCBH, SCBPTR ret; 11094568Sgibbs 111023925Sgibbs.if ( SCB_PAGING ) 111119164Sgibbsget_free_or_disc_scb: 111223925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 111323925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 111419623Sgibbsreturn_error: 111523925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 111619623Sgibbsdequeue_disc_scb: 111723925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 111813177Sgibbs/* 111919164Sgibbs * If we have a residual, then we are in the middle of some I/O 112019164Sgibbs * and we have to send this SCB back up to the kernel so that the 112119164Sgibbs * saved data pointers and residual information isn't lost. 112219164Sgibbs */ 112325123Sgibbs test SCB_CONTROL, MUST_DMAUP_SCB jz . + 3; 112425123Sgibbs and SCB_CONTROL, ~MUST_DMAUP_SCB; 112525123Sgibbs jmp dma_up_scb; 112623925Sgibbs test SCB_RESID_SGCNT,0xff jnz dma_up_scb; 112723925Sgibbs cmp SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb; 112823925Sgibbsdma_up_scb: 112923925Sgibbs mvi DMAPARAMS, FIFORESET; 113023925Sgibbs mov SCB_TAG call dma_scb; 113119164Sgibbsunlink_disc_scb: 113219623Sgibbs /* jmp instead of call since we want to return anyway */ 113323925Sgibbs mov SCBPTR jmp rem_scb_from_disc_list; 113419164Sgibbsdequeue_free_scb: 113523925Sgibbs mov SCBPTR, FREE_SCBH; 113623925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 11374568Sgibbs 113819164Sgibbsadd_scb_to_disc_list: 113913177Sgibbs/* 114019164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 114119164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 114219164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 114313177Sgibbs */ 114423925Sgibbs mvi SCB_PREV, SCB_LIST_NULL; 114523925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 114623925Sgibbs mov DISCONNECTED_SCBH, SCBPTR; 114723925Sgibbs cmp SCB_NEXT,SCB_LIST_NULL je return; 114823925Sgibbs mov SCBPTR,SCB_NEXT; 114923925Sgibbs mov SCB_PREV,DISCONNECTED_SCBH; 115023925Sgibbs mov SCBPTR,DISCONNECTED_SCBH ret; 115123925Sgibbs.endif 1152