aic7xxx.seq revision 57099
126997Sgibbs/* 226997Sgibbs * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. 313177Sgibbs * 455581Sgibbs * Copyright (c) 1994-2000 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, 1254211Sgibbs * without modification. 1339220Sgibbs * 2. The name of the author may not be used to endorse or promote products 1426997Sgibbs * derived from this software without specific prior written permission. 1513177Sgibbs * 1654211Sgibbs * Alternatively, this software may be distributed under the terms of the 1754211Sgibbs * the GNU Public License ("GPL"). 1813177Sgibbs * 1926997Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2026997Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2126997Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2226997Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2326997Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2426997Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2526997Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2626997Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2726997Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2826997Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2926997Sgibbs * SUCH DAMAGE. 3013177Sgibbs * 3150477Speter * $FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 57099 2000-02-09 21:25:00Z gibbs $ 3226997Sgibbs */ 334568Sgibbs 3423925Sgibbs#include <dev/aic7xxx/aic7xxx.reg> 3539220Sgibbs#include <cam/scsi/scsi_message.h> 365647Sgibbs 3713177Sgibbs/* 3819164Sgibbs * A few words on the waiting SCB list: 3919164Sgibbs * After starting the selection hardware, we check for reconnecting targets 4013690Sgibbs * as well as for our selection to complete just in case the reselection wins 4113690Sgibbs * bus arbitration. The problem with this is that we must keep track of the 4213690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection 4313690Sgibbs * on just in case the reselection wins so that we can retry the selection at 4413690Sgibbs * a later time. This problem cannot be resolved by holding a single entry 4513690Sgibbs * in scratch ram since a reconnecting target can request sense and this will 4613690Sgibbs * create yet another SCB waiting for selection. The solution used here is to 4713690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list 4819164Sgibbs * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, 4919164Sgibbs * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to 5019164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged 5119164Sgibbs * command for which a second SCB has been queued. The sequencer will 5219164Sgibbs * automatically consume the entries. 5313177Sgibbs */ 544568Sgibbs 5514449Sgibbsreset: 5623925Sgibbs clr SCSISIGO; /* De-assert BSY */ 5757099Sgibbs mvi MSG_OUT, MSG_NOOP; /* No message to send */ 5841646Sgibbs and SXFRCTL1, ~BITBUCKET; 5923925Sgibbs /* Always allow reselection */ 6041816Sgibbs and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE; 6139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 6239220Sgibbs /* Ensure that no DMA operations are in progress */ 6339220Sgibbs clr CCSGCTL; 6439220Sgibbs clr CCSCBCTL; 6539220Sgibbs } 6639220Sgibbs 6744507Sgibbspoll_for_work: 6823925Sgibbs call clear_target_state; 6939220Sgibbs and SXFRCTL0, ~SPIOEN; 7039220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) == 0) { 7139220Sgibbs mov A, QINPOS; 7239220Sgibbs } 7339220Sgibbspoll_for_work_loop: 7439220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) == 0) { 7539220Sgibbs and SEQCTL, ~PAUSEDIS; 7639220Sgibbs } 7739220Sgibbs test SSTAT0, SELDO|SELDI jnz selection; 7823925Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 7939220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 8039220Sgibbs /* 8139220Sgibbs * Twin channel devices cannot handle things like SELTO 8239220Sgibbs * interrupts on the "background" channel. So, if we 8339220Sgibbs * are selecting, keep polling the current channel util 8439220Sgibbs * either a selection or reselection occurs. 8539220Sgibbs */ 8639220Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 8739220Sgibbs test SSTAT0, SELDO|SELDI jnz selection; 8839220Sgibbs test SCSISEQ, ENSELO jnz poll_for_work; 8939220Sgibbs xor SBLKCTL,SELBUSB; /* Toggle back */ 9039220Sgibbs } 9123925Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 9219164Sgibbstest_queue: 9319164Sgibbs /* Has the driver posted any work for us? */ 9439220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 9539220Sgibbs test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; 9639220Sgibbs mov NONE, SNSCB_QOFF; 9739220Sgibbs inc QINPOS; 9839220Sgibbs } else { 9939220Sgibbs or SEQCTL, PAUSEDIS; 10039220Sgibbs cmp KERNEL_QINPOS, A je poll_for_work_loop; 10139220Sgibbs inc QINPOS; 10239220Sgibbs and SEQCTL, ~PAUSEDIS; 10339220Sgibbs } 1044568Sgibbs 10513690Sgibbs/* 10613690Sgibbs * We have at least one queued SCB now and we don't have any 10719164Sgibbs * SCBs in the list of SCBs awaiting selection. If we have 10823925Sgibbs * any SCBs available for use, pull the tag from the QINFIFO 10919164Sgibbs * and get to work on it. 11013177Sgibbs */ 11139220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 11239220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 11339220Sgibbs } 11439220Sgibbs 11519164Sgibbsdequeue_scb: 11639220Sgibbs add A, -1, QINPOS; 11739220Sgibbs mvi QINFIFO_OFFSET call fetch_byte; 11839220Sgibbs 11939220Sgibbs if ((ahc->flags & AHC_PAGESCBS) == 0) { 12039220Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 12139220Sgibbs mov SCBPTR, RETURN_2; 12239220Sgibbs } 12319164Sgibbsdma_queued_scb: 12419164Sgibbs/* 12519164Sgibbs * DMA the SCB from host ram into the current SCB location. 12619164Sgibbs */ 12723925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 12839220Sgibbs mov RETURN_2 call dma_scb; 1294568Sgibbs 13013177Sgibbs/* 13139220Sgibbs * Preset the residual fields in case we never go through a data phase. 13239220Sgibbs * This isn't done by the host so we can avoid a DMA to clear these 13339220Sgibbs * fields for the normal case of I/O that completes without underrun 13439220Sgibbs * or overrun conditions. 13513177Sgibbs */ 13639220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 13739220Sgibbs bmov SCB_RESID_DCNT, SCB_DATACNT, 3; 13839220Sgibbs } else { 13939220Sgibbs mov SCB_RESID_DCNT[0],SCB_DATACNT[0]; 14039220Sgibbs mov SCB_RESID_DCNT[1],SCB_DATACNT[1]; 14139220Sgibbs mov SCB_RESID_DCNT[2],SCB_DATACNT[2]; 14239220Sgibbs } 14339220Sgibbs mov SCB_RESID_SGCNT, SCB_SGCOUNT; 1444568Sgibbs 1455326Sgibbsstart_scb: 14619164Sgibbs /* 14719164Sgibbs * Place us on the waiting list in case our selection 14819164Sgibbs * doesn't win during bus arbitration. 14919164Sgibbs */ 15023925Sgibbs mov SCB_NEXT,WAITING_SCBH; 15123925Sgibbs mov WAITING_SCBH, SCBPTR; 15223925Sgibbsstart_waiting: 15323925Sgibbs /* 15439220Sgibbs * Pull the first entry off of the waiting SCB list. 15523925Sgibbs */ 15623925Sgibbs mov SCBPTR, WAITING_SCBH; 15723925Sgibbs call start_selection; 15823925Sgibbs jmp poll_for_work; 1598104Sgibbs 16023925Sgibbsstart_selection: 16139220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 16239220Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ 16339220Sgibbs and A,SELBUSB,SCB_TCL; /* Get new channel bit */ 16439220Sgibbs or SINDEX,A; 16539220Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 16639220Sgibbs } 16723925Sgibbsinitialize_scsiid: 16844507Sgibbs mov SINDEX, SCSISEQ_TEMPLATE; 16944507Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 17044507Sgibbs test SCB_CONTROL, TARGET_SCB jz . + 4; 17144507Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 17244507Sgibbs mov SCSIID_ULTRA2, SCB_CMDPTR[2]; 17344507Sgibbs } else { 17444507Sgibbs mov SCSIID, SCB_CMDPTR[2]; 17544507Sgibbs } 17644507Sgibbs or SINDEX, TEMODE; 17744507Sgibbs jmp initialize_scsiid_fini; 17844507Sgibbs } 17939220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 18039220Sgibbs and A, TID, SCB_TCL; /* Get target ID */ 18139220Sgibbs and SCSIID_ULTRA2, OID; /* Clear old target */ 18239220Sgibbs or SCSIID_ULTRA2, A; 18339220Sgibbs } else { 18439220Sgibbs and A, TID, SCB_TCL; /* Get target ID */ 18539220Sgibbs and SCSIID, OID; /* Clear old target */ 18639220Sgibbs or SCSIID, A; 18739220Sgibbs } 18844507Sgibbsinitialize_scsiid_fini: 18941816Sgibbs mov SCSISEQ, SINDEX ret; 19039220Sgibbs 19113177Sgibbs/* 19239220Sgibbs * Initialize transfer settings and clear the SCSI channel. 19339220Sgibbs * SINDEX should contain any additional bit's the client wants 19439220Sgibbs * set in SXFRCTL0. We also assume that the current SCB is 19539220Sgibbs * a valid SCB for the target we wish to talk to. 19639220Sgibbs */ 19739220Sgibbsinitialize_channel: 19839220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; 19939220Sgibbsset_transfer_settings: 20039220Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 20139220Sgibbs test SCB_CONTROL, ULTRAENB jz . + 2; 20239220Sgibbs or SXFRCTL0, FAST20; 20339220Sgibbs } 20439220Sgibbs/* 20539220Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 20639220Sgibbs */ 20739220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 20839220Sgibbs bmov SCSIRATE, SCB_SCSIRATE, 2 ret; 20939220Sgibbs } else { 21039220Sgibbs mov SCSIRATE, SCB_SCSIRATE ret; 21139220Sgibbs } 21239220Sgibbs 21339220Sgibbsselection: 21439220Sgibbs test SSTAT0,SELDO jnz select_out; 21539220Sgibbs mvi CLRSINT0, CLRSELDI; 21639220Sgibbsselect_in: 21739220Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 21841646Sgibbs if ((ahc->flags & AHC_INITIATORMODE) != 0) { 21941646Sgibbs test SSTAT0, TARGET jz initiator_reselect; 22041646Sgibbs } 22142652Sgibbs 22239220Sgibbs /* 22339220Sgibbs * We've just been selected. Assert BSY and 22439220Sgibbs * setup the phase for receiving messages 22539220Sgibbs * from the target. 22639220Sgibbs */ 22739220Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 22841646Sgibbs mvi CLRSINT1, CLRBUSFREE; 22939220Sgibbs 23039220Sgibbs /* 23139220Sgibbs * Setup the DMA for sending the identify and 23241299Sgibbs * command information. 23339220Sgibbs */ 23439220Sgibbs or SEQ_FLAGS, CMDPHASE_PENDING; 23541299Sgibbs 23641299Sgibbs mov A, TQINPOS; 23739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 23839220Sgibbs mvi DINDEX, CCHADDR; 23939220Sgibbs mvi TMODE_CMDADDR call set_32byte_addr; 24039220Sgibbs mvi CCSCBCTL, CCSCBRESET; 24139220Sgibbs } else { 24239220Sgibbs mvi DINDEX, HADDR; 24339220Sgibbs mvi TMODE_CMDADDR call set_32byte_addr; 24439220Sgibbs mvi DFCNTRL, FIFORESET; 24539220Sgibbs } 24639220Sgibbs 24739220Sgibbs /* Initiator that selected us */ 24839220Sgibbs and SAVED_TCL, SELID_MASK, SELID; 24939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 25039220Sgibbs mov CCSCBRAM, SAVED_TCL; 25139220Sgibbs } else { 25239220Sgibbs mov DFDAT, SAVED_TCL; 25339220Sgibbs } 25439220Sgibbs 25539220Sgibbs /* The Target ID we were selected at */ 25644507Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 25744507Sgibbs if ((ahc->features & AHC_MULTI_TID) != 0) { 25844507Sgibbs and CCSCBRAM, OID, TARGIDIN; 25944507Sgibbs } else if ((ahc->features & AHC_ULTRA2) != 0) { 26044507Sgibbs and CCSCBRAM, OID, SCSIID_ULTRA2; 26139220Sgibbs } else { 26244507Sgibbs and CCSCBRAM, OID, SCSIID; 26339220Sgibbs } 26439220Sgibbs } else { 26544507Sgibbs if ((ahc->features & AHC_MULTI_TID) != 0) { 26644507Sgibbs and DFDAT, OID, TARGIDIN; 26744507Sgibbs } else if ((ahc->features & AHC_ULTRA2) != 0) { 26844507Sgibbs and DFDAT, OID, SCSIID_ULTRA2; 26939220Sgibbs } else { 27039220Sgibbs and DFDAT, OID, SCSIID; 27139220Sgibbs } 27239220Sgibbs } 27339220Sgibbs 27442652Sgibbs /* No tag yet */ 27542652Sgibbs mvi INITIATOR_TAG, SCB_LIST_NULL; 27642652Sgibbs 27739220Sgibbs /* 27839220Sgibbs * If ATN isn't asserted, the target isn't interested 27939220Sgibbs * in talking to us. Go directly to bus free. 28039220Sgibbs */ 28139220Sgibbs test SCSISIGI, ATNI jz target_busfree; 28239220Sgibbs 28339220Sgibbs /* 28439220Sgibbs * Watch ATN closely now as we pull in messages from the 28539220Sgibbs * initiator. We follow the guidlines from section 6.5 28639220Sgibbs * of the SCSI-2 spec for what messages are allowed when. 28739220Sgibbs */ 28841646Sgibbs call target_inb; 28939220Sgibbs 29039220Sgibbs /* 29139220Sgibbs * Our first message must be one of IDENTIFY, ABORT, or 29239220Sgibbs * BUS_DEVICE_RESET. 29339220Sgibbs */ 29441299Sgibbs /* XXX May need to be more lax here for older initiators... */ 29542652Sgibbs test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; 29639220Sgibbs /* Store for host */ 29739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 29839220Sgibbs mov CCSCBRAM, DINDEX; 29939220Sgibbs } else { 30039220Sgibbs mov DFDAT, DINDEX; 30139220Sgibbs } 30239220Sgibbs 30339220Sgibbs /* Remember for disconnection decision */ 30439220Sgibbs test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; 30539220Sgibbs /* XXX Honor per target settings too */ 30639220Sgibbs or SEQ_FLAGS, NO_DISCONNECT; 30739220Sgibbs 30839220Sgibbs test SCSISIGI, ATNI jz ident_messages_done; 30941646Sgibbs call target_inb; 31039220Sgibbs /* 31139220Sgibbs * If this is a tagged request, the tagged message must 31239220Sgibbs * immediately follow the identify. We test for a valid 31339220Sgibbs * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and 31439220Sgibbs * < MSG_IGN_WIDE_RESIDUE. 31539220Sgibbs */ 31639220Sgibbs add A, -MSG_SIMPLE_Q_TAG, DINDEX; 31739220Sgibbs jnc ident_messages_done; 31839220Sgibbs add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; 31939220Sgibbs jc ident_messages_done; 32039220Sgibbs /* Store for host */ 32139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 32239220Sgibbs mov CCSCBRAM, DINDEX; 32339220Sgibbs } else { 32439220Sgibbs mov DFDAT, DINDEX; 32539220Sgibbs } 32639220Sgibbs 32739220Sgibbs /* 32839220Sgibbs * If the initiator doesn't feel like providing a tag number, 32939220Sgibbs * we've got a failed selection and must transition to bus 33039220Sgibbs * free. 33139220Sgibbs */ 33239220Sgibbs test SCSISIGI, ATNI jz target_busfree; 33342652Sgibbs 33439220Sgibbs /* 33539220Sgibbs * Store the tag for the host. 33639220Sgibbs */ 33741646Sgibbs call target_inb; 33839220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 33939220Sgibbs mov CCSCBRAM, DINDEX; 34039220Sgibbs } else { 34139220Sgibbs mov DFDAT, DINDEX; 34239220Sgibbs } 34342652Sgibbs mov INITIATOR_TAG, DINDEX; 34439220Sgibbs jmp ident_messages_done; 34539220Sgibbs 34641646Sgibbs /* 34741646Sgibbs * Pushed message loop to allow the kernel to 34842652Sgibbs * run it's own target mode message state engine. 34941646Sgibbs */ 35041646Sgibbshost_target_message_loop: 35141646Sgibbs mvi INTSTAT, HOST_MSG_LOOP; 35241646Sgibbs nop; 35341646Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; 35441646Sgibbs test SSTAT0, SPIORDY jz .; 35541646Sgibbs jmp host_target_message_loop; 35641646Sgibbs 35739220Sgibbsident_messages_done: 35844507Sgibbs /* If ring buffer is full, return busy or queue full */ 35944507Sgibbs mov A, KERNEL_TQINPOS; 36044507Sgibbs cmp TQINPOS, A jne tqinfifo_has_space; 36144507Sgibbs mvi P_STATUS|BSYO call change_phase; 36244507Sgibbs cmp INITIATOR_TAG, SCB_LIST_NULL je . + 3; 36344507Sgibbs mvi STATUS_QUEUE_FULL call target_outb; 36444507Sgibbs jmp target_busfree_wait; 36544507Sgibbs mvi STATUS_BUSY call target_outb; 36644507Sgibbs jmp target_busfree_wait; 36744507Sgibbstqinfifo_has_space: 36839220Sgibbs /* Terminate the ident list */ 36939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 37039220Sgibbs mvi CCSCBRAM, SCB_LIST_NULL; 37139220Sgibbs } else { 37239220Sgibbs mvi DFDAT, SCB_LIST_NULL; 37339220Sgibbs } 37442652Sgibbs or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN; 37541646Sgibbs test SCSISIGI, ATNI jnz target_mesgout_pending_msg; 37639220Sgibbs jmp target_ITloop; 37739220Sgibbs 37839220Sgibbs/* 37939220Sgibbs * We carefully toggle SPIOEN to allow us to return the 38039220Sgibbs * message byte we receive so it can be checked prior to 38139220Sgibbs * driving REQ on the bus for the next byte. 38239220Sgibbs */ 38341646Sgibbstarget_inb: 38441646Sgibbs /* 38541646Sgibbs * Drive REQ on the bus by enabling SCSI PIO. 38641646Sgibbs */ 38739220Sgibbs or SXFRCTL0, SPIOEN; 38839220Sgibbs /* Wait for the byte */ 38939220Sgibbs test SSTAT0, SPIORDY jz .; 39039220Sgibbs /* Prevent our read from triggering another REQ */ 39139220Sgibbs and SXFRCTL0, ~SPIOEN; 39241646Sgibbs /* Save latched contents */ 39339220Sgibbs mov DINDEX, SCSIDATL ret; 39439220Sgibbs } 39539220Sgibbs 39641646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) { 39739220Sgibbs/* 39823925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 39923925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 40013177Sgibbs */ 40139220Sgibbsinitiator_reselect: 40223925Sgibbs /* XXX test for and handle ONE BIT condition */ 40323925Sgibbs and SAVED_TCL, SELID_MASK, SELID; 40439545Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 40539545Sgibbs test SBLKCTL, SELBUSB jz . + 2; 40639545Sgibbs or SAVED_TCL, SELBUSB; 40739545Sgibbs } 40841646Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 40939220Sgibbs mvi CLRSINT1,CLRBUSFREE; 41039220Sgibbs or SIMODE1, ENBUSFREE; /* 41139220Sgibbs * We aren't expecting a 41239220Sgibbs * bus free, so interrupt 41339220Sgibbs * the kernel driver if it 41439220Sgibbs * happens. 41539220Sgibbs */ 41639220Sgibbs jmp ITloop; 41741646Sgibbs} 4184568Sgibbs 41913177Sgibbs/* 42023925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 42123925Sgibbs * list. This is achieved by simply moving our "next" pointer into 42223925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 42323925Sgibbs * SCB is used, so don't bother with it now. 42423925Sgibbs */ 42539220Sgibbsselect_out: 42625005Sgibbs /* Turn off the selection hardware */ 42741816Sgibbs and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE; 42825005Sgibbs mvi CLRSINT0, CLRSELDO; 42925005Sgibbs mov SCBPTR, WAITING_SCBH; 43024914Sgibbs mov WAITING_SCBH,SCB_NEXT; 43123925Sgibbs mov SAVED_TCL, SCB_TCL; 43239220Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 43339220Sgibbs test SSTAT0, TARGET jz initiator_select; 4348567Sdg 43539220Sgibbs /* 43639220Sgibbs * We've just re-selected an initiator. 43739220Sgibbs * Assert BSY and setup the phase for 43839220Sgibbs * sending our identify messages. 43939220Sgibbs */ 44041646Sgibbs mvi P_MESGIN|BSYO call change_phase; 44141646Sgibbs mvi CLRSINT1,CLRBUSFREE; 4424568Sgibbs 44339220Sgibbs /* 44439220Sgibbs * Start out with a simple identify message. 44539220Sgibbs */ 44639220Sgibbs and A, LID, SCB_TCL; 44739220Sgibbs or A, MSG_IDENTIFYFLAG call target_outb; 4486608Sgibbs 44939220Sgibbs /* 45039220Sgibbs * If we are the result of a tagged command, send 45139220Sgibbs * a simple Q tag and the tag id. 45239220Sgibbs */ 45339220Sgibbs test SCB_CONTROL, TAG_ENB jz . + 3; 45439220Sgibbs mvi MSG_SIMPLE_Q_TAG call target_outb; 45542652Sgibbs mov SCB_INITIATOR_TAG call target_outb; 45642652Sgibbs mov INITIATOR_TAG, SCB_INITIATOR_TAG; 45739220Sgibbstarget_synccmd: 45839220Sgibbs /* 45939220Sgibbs * Now determine what phases the host wants us 46039220Sgibbs * to go through. 46139220Sgibbs */ 46239220Sgibbs mov SEQ_FLAGS, SCB_TARGET_PHASES; 46342652Sgibbs 46439220Sgibbs 46539220Sgibbstarget_ITloop: 46639220Sgibbs /* 46741646Sgibbs * Start honoring ATN signals now that 46844507Sgibbs * we properly identified ourselves. 46939220Sgibbs */ 47041646Sgibbs test SCSISIGI, ATNI jnz target_mesgout; 47139220Sgibbs test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; 47239220Sgibbs test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; 47339220Sgibbs test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; 47439220Sgibbs 47539220Sgibbs /* 47639220Sgibbs * No more work to do. Either disconnect or not depending 47739220Sgibbs * on the state of NO_DISCONNECT. 47839220Sgibbs */ 47939220Sgibbs test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 48039220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 48139220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 48239220Sgibbs } 48341646Sgibbs mov RETURN_1, ALLZEROS; 48439220Sgibbs call complete_target_cmd; 48541646Sgibbs cmp RETURN_1, CONT_MSG_LOOP jne .; 48639220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 48739220Sgibbs mov SCB_TAG call dma_scb; 48839220Sgibbs jmp target_synccmd; 48939220Sgibbs 49041646Sgibbstarget_mesgout: 49141646Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 49241646Sgibbs call target_inb; 49341646Sgibbs /* Local Processing goes here... */ 49441646Sgibbstarget_mesgout_pending_msg: 49541646Sgibbs jmp host_target_message_loop; 49641646Sgibbs 49739220Sgibbstarget_disconnect: 49841646Sgibbs mvi P_MESGIN|BSYO call change_phase; 49941816Sgibbs test SEQ_FLAGS, DPHASE jz . + 2; 50041816Sgibbs mvi MSG_SAVEDATAPOINTER call target_outb; 50139220Sgibbs mvi MSG_DISCONNECT call target_outb; 50239220Sgibbs 50343880Sgibbstarget_busfree_wait: 50443880Sgibbs /* Wait for preceeding I/O session to complete. */ 50543880Sgibbs test SCSISIGI, ACKI jnz .; 50639220Sgibbstarget_busfree: 50739220Sgibbs clr SCSISIGO; 50857099Sgibbs mvi LASTPHASE, P_BUSFREE; 50939220Sgibbs call complete_target_cmd; 51039220Sgibbs jmp poll_for_work; 51139220Sgibbs 51239220Sgibbstarget_cmdphase: 51341646Sgibbs mvi P_COMMAND|BSYO call change_phase; 51441646Sgibbs call target_inb; 51539220Sgibbs mov A, DINDEX; 51639220Sgibbs /* Store for host */ 51739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 51839220Sgibbs mov CCSCBRAM, A; 51939220Sgibbs } else { 52039220Sgibbs mov DFDAT, A; 52139220Sgibbs } 52239220Sgibbs 52339220Sgibbs /* 52439220Sgibbs * Determine the number of bytes to read 52541299Sgibbs * based on the command group code via table lookup. 52641299Sgibbs * We reuse the first 8 bytes of the TARG_SCSIRATE 52741299Sgibbs * BIOS array for this table. Count is one less than 52841299Sgibbs * the total for the command since we've already fetched 52941299Sgibbs * the first byte. 53039220Sgibbs */ 53139220Sgibbs shr A, CMD_GROUP_CODE_SHIFT; 53239220Sgibbs add SINDEX, TARG_SCSIRATE, A; 53339220Sgibbs mov A, SINDIR; 53439220Sgibbs 53539220Sgibbs test A, 0xFF jz command_phase_done; 53639220Sgibbscommand_loop: 53739220Sgibbs or SXFRCTL0, SPIOEN; 53839220Sgibbs test SSTAT0, SPIORDY jz .; 53939220Sgibbs cmp A, 1 jne . + 2; 54039220Sgibbs and SXFRCTL0, ~SPIOEN; /* Last Byte */ 54139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 54239220Sgibbs mov CCSCBRAM, SCSIDATL; 54339220Sgibbs } else { 54439220Sgibbs mov DFDAT, SCSIDATL; 54539220Sgibbs } 54639220Sgibbs dec A; 54739220Sgibbs test A, 0xFF jnz command_loop; 54839220Sgibbs 54939220Sgibbscommand_phase_done: 55039220Sgibbs and SEQ_FLAGS, ~CMDPHASE_PENDING; 55139220Sgibbs jmp target_ITloop; 55239220Sgibbs 55339220Sgibbstarget_dphase: 55439220Sgibbs /* 55539220Sgibbs * Data direction flags are from the 55639220Sgibbs * perspective of the initiator. 55739220Sgibbs */ 55839220Sgibbs test SCB_TARGET_PHASES[1], TARGET_DATA_IN jz . + 4; 55939220Sgibbs mvi LASTPHASE, P_DATAOUT; 56041646Sgibbs mvi P_DATAIN|BSYO call change_phase; 56142652Sgibbs jmp . + 3; 56239220Sgibbs mvi LASTPHASE, P_DATAIN; 56341646Sgibbs mvi P_DATAOUT|BSYO call change_phase; 56442652Sgibbs mov ALLZEROS call initialize_channel; 56539220Sgibbs jmp p_data; 56639220Sgibbs 56739220Sgibbstarget_sphase: 56841646Sgibbs mvi P_STATUS|BSYO call change_phase; 56941646Sgibbs mvi LASTPHASE, P_STATUS; 57039220Sgibbs mov SCB_TARGET_STATUS call target_outb; 57141646Sgibbs /* XXX Watch for ATN or parity errors??? */ 57239220Sgibbs mvi SCSISIGO, P_MESGIN|BSYO; 57339220Sgibbs /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ 57439220Sgibbs mov ALLZEROS call target_outb; 57543880Sgibbs jmp target_busfree_wait; 57639220Sgibbs 57739220Sgibbscomplete_target_cmd: 57839220Sgibbs test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; 57939220Sgibbs mov SCB_TAG jmp complete_post; 58039220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 58141299Sgibbs /* Set the valid byte */ 58241299Sgibbs mvi CCSCBADDR, 24; 58341299Sgibbs mov CCSCBRAM, ALLONES; 58441299Sgibbs mvi CCHCNT, 28; 58539220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 58639220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 58739220Sgibbs clr CCSCBCTL; 58839220Sgibbs } else { 58941299Sgibbs /* Set the valid byte */ 59041299Sgibbs or DFCNTRL, FIFORESET; 59141299Sgibbs mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ 59241299Sgibbs mov DFDAT, ALLONES; 59341299Sgibbs mvi HCNT[0], 28; 59441299Sgibbs clr HCNT[1]; 59541299Sgibbs clr HCNT[2]; 59639220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 59739220Sgibbs call dma_finish; 59839220Sgibbs } 59941299Sgibbs inc TQINPOS; 60041299Sgibbs mvi INTSTAT,CMDCMPLT ret; 60139220Sgibbs } 60241646Sgibbs 60341646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) { 60439220Sgibbsinitiator_select: 60539220Sgibbs mvi SPIOEN call initialize_channel; 60641646Sgibbs 60741646Sgibbs /* 60841646Sgibbs * We aren't expecting a bus free, so interrupt 60941646Sgibbs * the kernel driver if it happens. 61041646Sgibbs */ 61125005Sgibbs mvi CLRSINT1,CLRBUSFREE; 61239220Sgibbs or SIMODE1, ENBUSFREE; 61341646Sgibbs 61441646Sgibbs /* 61541646Sgibbs * As soon as we get a successful selection, the target 61641646Sgibbs * should go into the message out phase since we have ATN 61741646Sgibbs * asserted. 61841646Sgibbs */ 61939220Sgibbs mvi MSG_OUT, MSG_IDENTIFYFLAG; 62039220Sgibbs or SEQ_FLAGS, IDENTIFY_SEEN; 62113177Sgibbs 62241646Sgibbs /* 62341646Sgibbs * Main loop for information transfer phases. Wait for the 62441646Sgibbs * target to assert REQ before checking MSG, C/D and I/O for 62541646Sgibbs * the bus phase. 62641646Sgibbs */ 6274568SgibbsITloop: 62839220Sgibbs call phase_lock; 6294568Sgibbs 63039220Sgibbs mov A, LASTPHASE; 6314568Sgibbs 63239220Sgibbs test A, ~P_DATAIN jz p_data; 63323925Sgibbs cmp A,P_COMMAND je p_command; 63423925Sgibbs cmp A,P_MESGOUT je p_mesgout; 63523925Sgibbs cmp A,P_STATUS je p_status; 63623925Sgibbs cmp A,P_MESGIN je p_mesgin; 6374568Sgibbs 63841646Sgibbs mvi INTSTAT,BAD_PHASE; 63923925Sgibbs jmp ITloop; /* Try reading the bus again. */ 6404568Sgibbs 64123925Sgibbsawait_busfree: 64223925Sgibbs and SIMODE1, ~ENBUSFREE; 64323925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 64439220Sgibbs and SXFRCTL0, ~SPIOEN; 64523925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 64623925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 64723925Sgibbs mvi INTSTAT, BAD_PHASE; 64841646Sgibbs} 64923925Sgibbs 65023925Sgibbsclear_target_state: 65141646Sgibbs /* 65241646Sgibbs * We assume that the kernel driver may reset us 65341646Sgibbs * at any time, even in the middle of a DMA, so 65441646Sgibbs * clear DFCNTRL too. 65541646Sgibbs */ 65641646Sgibbs clr DFCNTRL; 65741646Sgibbs 65841646Sgibbs /* 65941646Sgibbs * We don't know the target we will connect to, 66041646Sgibbs * so default to narrow transfers to avoid 66141646Sgibbs * parity problems. 66241646Sgibbs */ 66341646Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 66441646Sgibbs bmov SCSIRATE, ALLZEROS, 2; 66541646Sgibbs } else { 66641646Sgibbs clr SCSIRATE; 66741646Sgibbs and SXFRCTL0, ~(FAST20); 66841646Sgibbs } 66923925Sgibbs mvi LASTPHASE, P_BUSFREE; 67023925Sgibbs /* clear target specific flags */ 67139220Sgibbs clr SEQ_FLAGS ret; 67223925Sgibbs 67313177Sgibbs/* 67413177Sgibbs * If we re-enter the data phase after going through another phase, the 67513177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 67613177Sgibbs */ 6779928Sgibbsdata_phase_reinit: 67851471Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 67951471Sgibbs /* 68051471Sgibbs * The preload circuitry requires us to 68151471Sgibbs * reload the address too, so pull it from 68251471Sgibbs * the shaddow address. 68351471Sgibbs */ 68451471Sgibbs bmov HADDR, SHADDR, 4; 68551471Sgibbs bmov HCNT, SCB_RESID_DCNT, 3; 68651471Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 68739220Sgibbs bmov STCNT, SCB_RESID_DCNT, 3; 68839220Sgibbs } else { 68939220Sgibbs mvi DINDEX, STCNT; 69039220Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 69139220Sgibbs } 69242652Sgibbs and DATA_COUNT_ODD, 0x1, SCB_RESID_DCNT[0]; 69323925Sgibbs jmp data_phase_loop; 6944568Sgibbs 69539220Sgibbsp_data: 69639220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 69739220Sgibbs mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; 69839220Sgibbs } else { 69939220Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 70039220Sgibbs } 70139220Sgibbs test LASTPHASE, IOI jnz . + 2; 70239220Sgibbs or DMAPARAMS, DIRECTION; 70323925Sgibbs call assert; /* 70419164Sgibbs * Ensure entering a data 70519164Sgibbs * phase is okay - seen identify, etc. 70619164Sgibbs */ 70739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 70839220Sgibbs mvi CCSGADDR, CCSGADDR_MAX; 70939220Sgibbs } 71023925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 7114568Sgibbs 71239220Sgibbs /* We have seen a data phase */ 71339220Sgibbs or SEQ_FLAGS, DPHASE; 71439220Sgibbs 71519164Sgibbs /* 71619164Sgibbs * Initialize the DMA address and counter from the SCB. 71719164Sgibbs * Also set SG_COUNT and SG_NEXT in memory since we cannot 71819164Sgibbs * modify the values in the SCB itself until we see a 71919164Sgibbs * save data pointers message. 72019164Sgibbs */ 72139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 72239220Sgibbs bmov HADDR, SCB_DATAPTR, 7; 72339220Sgibbs } else { 72439220Sgibbs mvi DINDEX, HADDR; 72539220Sgibbs mvi SCB_DATAPTR call bcopy_7; 72639220Sgibbs } 72742652Sgibbs and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0]; 72819164Sgibbs 72939220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 73039220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 73139220Sgibbs bmov STCNT, HCNT, 3; 73239220Sgibbs } else { 73339220Sgibbs call set_stcnt_from_hcnt; 73439220Sgibbs } 73539220Sgibbs } 73619164Sgibbs 73739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 73839220Sgibbs bmov SG_COUNT, SCB_SGCOUNT, 5; 73939220Sgibbs } else { 74039220Sgibbs mvi DINDEX, SG_COUNT; 74139220Sgibbs mvi SCB_SGCOUNT call bcopy_5; 74239220Sgibbs } 74319164Sgibbs 7449928Sgibbsdata_phase_loop: 74516260Sgibbs/* Guard against overruns */ 74623925Sgibbs test SG_COUNT, 0xff jnz data_phase_inbounds; 74716260Sgibbs/* 74816260Sgibbs * Turn on 'Bit Bucket' mode, set the transfer count to 74916260Sgibbs * 16meg and let the target run until it changes phase. 75016260Sgibbs * When the transfer completes, notify the host that we 75116260Sgibbs * had an overrun. 75216260Sgibbs */ 75323925Sgibbs or SXFRCTL1,BITBUCKET; 75439220Sgibbs and DMAPARAMS, ~(HDMAEN|SDMAEN); 75539220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 75639220Sgibbs bmov HCNT, ALLONES, 3; 75739220Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 75839220Sgibbs bmov STCNT, ALLONES, 3; 75939220Sgibbs } else { 76039220Sgibbs mvi STCNT[0], 0xFF; 76139220Sgibbs mvi STCNT[1], 0xFF; 76239220Sgibbs mvi STCNT[2], 0xFF; 76339220Sgibbs } 76416260Sgibbsdata_phase_inbounds: 76539220Sgibbs/* If we are the last SG block, tell the hardware. */ 76623925Sgibbs cmp SG_COUNT,0x01 jne data_phase_wideodd; 76739220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 76839220Sgibbs or SG_CACHEPTR, LAST_SEG; 76939220Sgibbs } else { 77057099Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 77157099Sgibbs test SSTAT0, TARGET jz . + 2; 77257099Sgibbs test DMAPARAMS, DIRECTION jz data_phase_wideodd; 77357099Sgibbs } 77439220Sgibbs and DMAPARAMS, ~WIDEODD; 77539220Sgibbs } 7769928Sgibbsdata_phase_wideodd: 77739220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 77839220Sgibbs mov SINDEX, ALLONES; 77939220Sgibbs mov DFCNTRL, DMAPARAMS; 78039220Sgibbs test SSTAT0, SDONE jnz .;/* Wait for preload to complete */ 78139220Sgibbsdata_phase_dma_loop: 78239220Sgibbs test SSTAT0, SDONE jnz data_phase_dma_done; 78339220Sgibbs test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ 78439220Sgibbs } else { 78539220Sgibbs mov DMAPARAMS call dma; 78639220Sgibbs } 7874568Sgibbs 78839220Sgibbsdata_phase_dma_done: 78916260Sgibbs/* Go tell the host about any overruns */ 79023925Sgibbs test SXFRCTL1,BITBUCKET jnz data_phase_overrun; 79116260Sgibbs 79255581Sgibbs/* See if we completed this segment */ 79355581Sgibbs test STCNT[0], 0xff jnz data_phase_finish; 79455581Sgibbs test STCNT[1], 0xff jnz data_phase_finish; 79555581Sgibbs test STCNT[2], 0xff jnz data_phase_finish; 7967532Sgibbs 79713177Sgibbs/* 79813177Sgibbs * Advance the scatter-gather pointers if needed 79913177Sgibbs */ 8009928Sgibbssg_advance: 80123925Sgibbs dec SG_COUNT; /* one less segment to go */ 8024568Sgibbs 80323925Sgibbs test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ 80413177Sgibbs/* 80513177Sgibbs * Load a struct scatter and set up the data address and length. 80613177Sgibbs * If the working value of the SG count is nonzero, then 80713177Sgibbs * we need to load a new set of values. 80813177Sgibbs * 80915328Sgibbs * This, like all DMA's, assumes little-endian host data storage. 81013177Sgibbs */ 8119928Sgibbssg_load: 81239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 81339220Sgibbs /* 81439220Sgibbs * Do we have any prefetch left??? 81539220Sgibbs */ 81639220Sgibbs cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; 8174568Sgibbs 81839220Sgibbs /* 81939220Sgibbs * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. 82039220Sgibbs */ 82139220Sgibbs add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; 82239220Sgibbs mvi A, CCSGADDR_MAX; 82339220Sgibbs jc . + 2; 82439220Sgibbs shl A, 3, SG_COUNT; 82539220Sgibbs mov CCHCNT, A; 82639220Sgibbs bmov CCHADDR, SG_NEXT, 4; 82739220Sgibbs mvi CCSGCTL, CCSGEN|CCSGRESET; 82839220Sgibbs test CCSGCTL, CCSGDONE jz .; 82939220Sgibbs and CCSGCTL, ~CCSGEN; 83039220Sgibbs test CCSGCTL, CCSGEN jnz .; 83139220Sgibbs mvi CCSGCTL, CCSGRESET; 83239220Sgibbsprefetched_segs_avail: 83339220Sgibbs bmov HADDR, CCSGRAM, 8; 83439220Sgibbs } else { 83539220Sgibbs mvi DINDEX, HADDR; 83639220Sgibbs mvi SG_NEXT call bcopy_4; 83722568Sgibbs 83839220Sgibbs mvi HCNT[0],SG_SIZEOF; 83939220Sgibbs clr HCNT[1]; 84039220Sgibbs clr HCNT[2]; 8419928Sgibbs 84239220Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 8439928Sgibbs 84439220Sgibbs call dma_finish; 8459928Sgibbs 84639220Sgibbs /* 84739220Sgibbs * Copy data from FIFO into SCB data pointer and data count. 84839220Sgibbs * This assumes that the SG segments are of the form: 84939220Sgibbs * struct ahc_dma_seg { 85039220Sgibbs * u_int32_t addr; four bytes, little-endian order 85139220Sgibbs * u_int32_t len; four bytes, little endian order 85239220Sgibbs * }; 85339220Sgibbs */ 85439220Sgibbs mvi HADDR call dfdat_in_7; 85539220Sgibbs } 85639220Sgibbs 85742652Sgibbs /* Track odd'ness */ 85842652Sgibbs test HCNT[0], 0x1 jz . + 2; 85942652Sgibbs xor DATA_COUNT_ODD, 0x1; 86042652Sgibbs 86139220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 86239220Sgibbs /* Load STCNT as well. It is a mirror of HCNT */ 86339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 86439220Sgibbs bmov STCNT, HCNT, 3; 86539220Sgibbs } else { 86639220Sgibbs call set_stcnt_from_hcnt; 86739220Sgibbs } 86839220Sgibbs } 86939220Sgibbs 87039220Sgibbs/* Advance the SG pointer */ 87139220Sgibbs clr A; /* add sizeof(struct scatter) */ 87239220Sgibbs add SG_NEXT[0],SG_SIZEOF; 87339220Sgibbs adc SG_NEXT[1],A; 87439220Sgibbs 87541646Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 87641646Sgibbs test SSTAT0, TARGET jnz data_phase_loop; 87741646Sgibbs } 87841646Sgibbs test SSTAT1, REQINIT jz .; 87923925Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 88041646Sgibbs 88139220Sgibbs /* Ensure the last seg is visable at the shaddow layer */ 88239220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 88355581Sgibbs mov DFCNTRL, DMAPARAMS; 88455581Sgibbs test SSTAT0, SDONE jnz .;/* Wait for preload to complete */ 88539220Sgibbs } 8864568Sgibbs 8879928Sgibbsdata_phase_finish: 88839220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 88939220Sgibbs call ultra2_dmafinish; 89039220Sgibbs } 89113177Sgibbs/* 89213177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB 89313177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 89413177Sgibbs * were transferred on the SCSI (as opposed to the host) bus. 89513177Sgibbs */ 89639220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 89739220Sgibbs bmov SCB_RESID_DCNT, STCNT, 3; 89839220Sgibbs } else { 89939220Sgibbs mov SCB_RESID_DCNT[0],STCNT[0]; 90039220Sgibbs mov SCB_RESID_DCNT[1],STCNT[1]; 90139220Sgibbs mov SCB_RESID_DCNT[2],STCNT[2]; 90239220Sgibbs } 90323925Sgibbs mov SCB_RESID_SGCNT, SG_COUNT; 90422568Sgibbs 90539220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 90639220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 90739220Sgibbs } 90822568Sgibbs 90939220Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 91041646Sgibbs test SEQ_FLAGS, DPHASE_PENDING jz ITloop; 91139220Sgibbs and SEQ_FLAGS, ~DPHASE_PENDING; 91242652Sgibbs /* 91342652Sgibbs * For data-in phases, wait for any pending acks from the 91442652Sgibbs * initiator before changing phase. 91542652Sgibbs */ 91642652Sgibbs test DFCNTRL, DIRECTION jz target_ITloop; 91742652Sgibbs test SSTAT1, REQINIT jnz .; 91839220Sgibbs jmp target_ITloop; 91939220Sgibbs } 92023925Sgibbs jmp ITloop; 9214568Sgibbs 92216260Sgibbsdata_phase_overrun: 92339220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 92439220Sgibbs call ultra2_dmafinish; 92539220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 92639220Sgibbs } 92713177Sgibbs/* 92816260Sgibbs * Turn off BITBUCKET mode and notify the host 92916260Sgibbs */ 93023925Sgibbs and SXFRCTL1, ~BITBUCKET; 93123925Sgibbs mvi INTSTAT,DATA_OVERRUN; 93223925Sgibbs jmp ITloop; 93316260Sgibbs 93439220Sgibbsultra2_dmafinish: 93539220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 93655581Sgibbs test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; 93739220Sgibbs and DFCNTRL, ~SCSIEN; 93839220Sgibbs test DFCNTRL, SCSIEN jnz .; 93951471Sgibbsultra2_dmafifoflush: 94039220Sgibbs or DFCNTRL, FIFOFLUSH; 94151471Sgibbs /* 94251471Sgibbs * The FIFOEMP status bit on the Ultra2 class 94351471Sgibbs * of controllers seems to be a bit flaky. 94451471Sgibbs * It appears that if the FIFO is full and the 94551471Sgibbs * transfer ends with some data in the REQ/ACK 94651471Sgibbs * FIFO, FIFOEMP will fall temporarily 94751471Sgibbs * as the data is transferred to the PCI bus. 94851471Sgibbs * This glitch lasts for fewer than 5 clock cycles, 94951471Sgibbs * so we work around the problem by ensuring the 95051471Sgibbs * status bit stays false through a full glitch 95151471Sgibbs * window. 95251471Sgibbs */ 95351471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95451471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95551471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95651471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95751471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95851471Sgibbs 95951471Sgibbsultra2_dmafifoempty: 96051471Sgibbs /* Don't clobber an inprogress host data transfer */ 96151471Sgibbs test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; 96251471Sgibbs 96339220Sgibbsultra2_dmahalt: 96439220Sgibbs and DFCNTRL, ~(SCSIEN|HDMAEN); 96539220Sgibbs test DFCNTRL, HDMAEN jnz .; 96639220Sgibbs ret; 96739220Sgibbs } 96839220Sgibbs 96941646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) { 97016260Sgibbs/* 97115328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 97213177Sgibbs */ 9734568Sgibbsp_command: 97423925Sgibbs call assert; 9754568Sgibbs 97639220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 97739220Sgibbs mov HCNT[0], SCB_CMDLEN; 97839220Sgibbs bmov HCNT[1], ALLZEROS, 2; 97939220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 98039220Sgibbs bmov STCNT, HCNT, 3; 98139220Sgibbs } 98239220Sgibbs add NONE, -17, SCB_CMDLEN; 98339220Sgibbs jc dma_cmd_data; 98457099Sgibbs /* 98557099Sgibbs * The data fifo seems to require 4 byte alligned 98657099Sgibbs * transfers from the sequencer. Force this to 98757099Sgibbs * be the case by clearing HADDR[0] even though 98857099Sgibbs * we aren't going to touch host memeory. 98957099Sgibbs */ 99057099Sgibbs bmov HADDR[0], ALLZEROS, 1; 99139220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 99239220Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); 99339220Sgibbs } else { 99439220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 99539220Sgibbs } 99639220Sgibbs bmov DFDAT, SCB_CMDSTORE, 16; 99739220Sgibbs jmp cmd_loop; 99839220Sgibbsdma_cmd_data: 99939220Sgibbs bmov HADDR, SCB_CMDPTR, 4; 100039220Sgibbs } else { 100139220Sgibbs mvi DINDEX, HADDR; 100239220Sgibbs mvi SCB_CMDPTR call bcopy_5; 100339220Sgibbs clr HCNT[1]; 100439220Sgibbs clr HCNT[2]; 100539220Sgibbs } 10064568Sgibbs 100739220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 100839220Sgibbs if ((ahc->features & AHC_CMD_CHAN) == 0) { 100939220Sgibbs call set_stcnt_from_hcnt; 101039220Sgibbs } 101139220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); 101239220Sgibbs } else { 101339220Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); 101439220Sgibbs } 101539220Sgibbscmd_loop: 101639220Sgibbs test SSTAT0, SDONE jnz . + 2; 101739220Sgibbs test SSTAT1, PHASEMIS jz cmd_loop; 101855581Sgibbs /* 101955581Sgibbs * Wait for our ACK to go-away on it's own 102055581Sgibbs * instead of being killed by SCSIEN getting cleared. 102155581Sgibbs */ 102255581Sgibbs test SCSISIGI, ACKI jnz .; 102355581Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 102439220Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; 102523925Sgibbs jmp ITloop; 10264568Sgibbs 102713177Sgibbs/* 102813177Sgibbs * Status phase. Wait for the data byte to appear, then read it 102913177Sgibbs * and store it into the SCB. 103013177Sgibbs */ 10314568Sgibbsp_status: 103223925Sgibbs call assert; 103319803Sgibbs 103423925Sgibbs mov SCB_TARGET_STATUS, SCSIDATL; 103523925Sgibbs jmp ITloop; 10364568Sgibbs 103713177Sgibbs/* 103841646Sgibbs * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full 103941646Sgibbs * indentify message sequence and send it to the target. The host may 104041646Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB 104141646Sgibbs * control byte. This will cause us to interrupt the host and allow 104241646Sgibbs * it to handle the message phase completely on its own. If the bit 104341646Sgibbs * associated with this target is set, we will also interrupt the host, 104441646Sgibbs * thereby allowing it to send a message on the next selection regardless 104541646Sgibbs * of the transaction being sent. 104639220Sgibbs * 104739220Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. 104841646Sgibbs * This is done to allow the host to send messages outside of an identify 104939220Sgibbs * sequence while protecting the seqencer from testing the MK_MESSAGE bit 105039220Sgibbs * on an SCB that might not be for the current nexus. (For example, a 105139220Sgibbs * BDR message in responce to a bad reselection would leave us pointed to 105239220Sgibbs * an SCB that doesn't have anything to do with the current target). 105341646Sgibbs * 105439220Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, 105539220Sgibbs * bus device reset). 105639220Sgibbs * 105739220Sgibbs * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, 105839220Sgibbs * in case the target decides to put us in this phase for some strange 105939220Sgibbs * reason. 106013177Sgibbs */ 106141646Sgibbsp_mesgout_retry: 106241646Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 10634568Sgibbsp_mesgout: 106439220Sgibbs mov SINDEX, MSG_OUT; 106539220Sgibbs cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; 106641646Sgibbs test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; 106741646Sgibbs mov FUNCTION1, SCB_TCL; 106841646Sgibbs mov A, FUNCTION1; 106947158Sgibbs if ((ahc->features & AHC_HS_MAILBOX) != 0) { 107047158Sgibbs /* 107147158Sgibbs * Work around a pausing bug in at least the aic7890. 107247158Sgibbs * If the host needs to update the TARGET_MSG_REQUEST 107347158Sgibbs * bit field, it will set the HS_MAILBOX to 1. In 107447158Sgibbs * response, we pause with a specific interrupt code 107547158Sgibbs * asking for the mask to be updated before we continue. 107647158Sgibbs * Ugh. 107747158Sgibbs */ 107847158Sgibbs test HS_MAILBOX, 0xF0 jz . + 2; 107947158Sgibbs mvi INTSTAT, UPDATE_TMSG_REQ; 108047414Sgibbs nop; 108147158Sgibbs } 108247414Sgibbs mov SINDEX, TARGET_MSG_REQUEST[0]; 108341646Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 108441646Sgibbs /* Second Channel uses high byte bits */ 108541646Sgibbs test SCB_TCL, SELBUSB jz . + 2; 108641646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 108741646Sgibbs } else if ((ahc->features & AHC_WIDE) != 0) { 108841646Sgibbs test SCB_TCL, 0x80 jz . + 2; /* target > 7 */ 108941646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 109041646Sgibbs } 109141646Sgibbs test SINDEX, A jnz host_message_loop; 109239220Sgibbsp_mesgout_identify: 109341299Sgibbs and SINDEX,LID,SCB_TCL; /* lun */ 109439220Sgibbs and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ 109539220Sgibbs or SINDEX,A; /* or in disconnect privledge */ 109639220Sgibbs or SINDEX,MSG_IDENTIFYFLAG; 109713177Sgibbs/* 109839220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 109939220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 110013177Sgibbs */ 110139220Sgibbsp_mesgout_tag: 110239220Sgibbs test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; 110339220Sgibbs mov SCSIDATL, SINDEX; /* Send the identify message */ 110439220Sgibbs call phase_lock; 110539220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 110639220Sgibbs and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 110739220Sgibbs call phase_lock; 110839220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 110939220Sgibbs mov SCB_TAG jmp p_mesgout_onebyte; 111013177Sgibbs/* 111141646Sgibbs * Interrupt the driver, and allow it to handle this message 111241646Sgibbs * phase and any required retries. 111313177Sgibbs */ 111439220Sgibbsp_mesgout_from_host: 111539220Sgibbs cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; 111641646Sgibbs jmp host_message_loop; 111739220Sgibbs 111839220Sgibbsp_mesgout_onebyte: 111939220Sgibbs mvi CLRSINT1, CLRATNO; 112039220Sgibbs mov SCSIDATL, SINDEX; 112139220Sgibbs 112213177Sgibbs/* 112341646Sgibbs * If the next bus phase after ATN drops is message out, it means 112413177Sgibbs * that the target is requesting that the last message(s) be resent. 112513177Sgibbs */ 112639220Sgibbs call phase_lock; 112741646Sgibbs cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; 11284568Sgibbs 112919906Sgibbsp_mesgout_done: 113023925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 113139220Sgibbs mov LAST_MSG, MSG_OUT; 113239220Sgibbs mvi MSG_OUT, MSG_NOOP; /* No message left */ 113323925Sgibbs jmp ITloop; 11344568Sgibbs 113513177Sgibbs/* 113613177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 113713177Sgibbs */ 11384568Sgibbsp_mesgin: 113923925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 11404568Sgibbs 114123925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 114223925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 114323925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 114423925Sgibbs cmp ALLZEROS,A je mesgin_complete; 114523925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 114623925Sgibbs cmp A,MSG_NOOP je mesgin_done; 11474568Sgibbs 114813177Sgibbs/* 114941887Sgibbs * Pushed message loop to allow the kernel to 115057099Sgibbs * run it's own message state engine. To avoid an 115141887Sgibbs * extra nop instruction after signaling the kernel, 115241887Sgibbs * we perform the phase_lock before checking to see 115341887Sgibbs * if we should exit the loop and skip the phase_lock 115441887Sgibbs * in the ITloop. Performing back to back phase_locks 115541887Sgibbs * shouldn't hurt, but why do it twice... 115613177Sgibbs */ 115741887Sgibbshost_message_loop: 115841887Sgibbs mvi INTSTAT, HOST_MSG_LOOP; 115941887Sgibbs call phase_lock; 116041887Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; 116141887Sgibbs jmp host_message_loop; 11629954Sgibbs 11639954Sgibbsmesgin_done: 116423925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 116523925Sgibbs jmp ITloop; 11669954Sgibbs 11679954Sgibbs 11689954Sgibbsmesgin_complete: 116913177Sgibbs/* 117019164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, 117119164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 117239220Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0). 117339220Sgibbs * In either of these conditions, we upload the SCB back to the host so it can 117419164Sgibbs * process this information. In the case of a non zero status byte, we 117519164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 117619164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 117719164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set 117819164Sgibbs * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload 117919164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list. 118019164Sgibbs * If the kernel driver does not wish to request sense, it need only clear 118119164Sgibbs * RETURN_1, and the command is allowed to complete normally. We don't bother 118219164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra 118319164Sgibbs * work in the kernel driver to ensure that the entry was removed before the 118419164Sgibbs * command complete code tried processing it. 118513177Sgibbs */ 118619164Sgibbs 118713177Sgibbs/* 118819164Sgibbs * First check for residuals 118913177Sgibbs */ 119023925Sgibbs test SCB_RESID_SGCNT,0xff jnz upload_scb; 119139220Sgibbs test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */ 119219164Sgibbsupload_scb: 119323925Sgibbs mvi DMAPARAMS, FIFORESET; 119423925Sgibbs mov SCB_TAG call dma_scb; 11957532Sgibbscheck_status: 119639220Sgibbs test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ 119723925Sgibbs mvi INTSTAT,BAD_STATUS; /* let driver know */ 119839220Sgibbs nop; 119939220Sgibbs cmp RETURN_1, SEND_SENSE jne complete; 120019164Sgibbs /* This SCB becomes the next to execute as it will retrieve sense */ 120123925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 120239220Sgibbs mov SCB_TAG call dma_scb; 120319164Sgibbsadd_to_waiting_list: 120423925Sgibbs mov SCB_NEXT,WAITING_SCBH; 120523925Sgibbs mov WAITING_SCBH, SCBPTR; 120623925Sgibbs /* 120723925Sgibbs * Prepare our selection hardware before the busfree so we have a 120823925Sgibbs * high probability of winning arbitration. 120923925Sgibbs */ 121023925Sgibbs call start_selection; 121123925Sgibbs jmp await_busfree; 121239220Sgibbs 121339220Sgibbscomplete: 121439220Sgibbs /* If we are untagged, clear our address up in host ram */ 121539220Sgibbs test SCB_CONTROL, TAG_ENB jnz complete_queue; 121639220Sgibbs mov A, SAVED_TCL; 121739220Sgibbs mvi UNTAGGEDSCB_OFFSET call post_byte_setup; 121839220Sgibbs mvi SCB_LIST_NULL call post_byte; 121939220Sgibbs 122039220Sgibbscomplete_queue: 122139220Sgibbs mov SCB_TAG call complete_post; 122223925Sgibbs jmp await_busfree; 122341646Sgibbs} 12244568Sgibbs 122539220Sgibbscomplete_post: 122639220Sgibbs /* Post the SCBID in SINDEX and issue an interrupt */ 122744507Sgibbs call add_scb_to_free_list; 122839220Sgibbs mov ARG_1, SINDEX; 122939220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 123039220Sgibbs mov A, SDSCB_QOFF; 123139220Sgibbs } else { 123239220Sgibbs mov A, QOUTPOS; 123339220Sgibbs } 123439220Sgibbs mvi QOUTFIFO_OFFSET call post_byte_setup; 123539220Sgibbs mov ARG_1 call post_byte; 123639220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) == 0) { 123739220Sgibbs inc QOUTPOS; 123839220Sgibbs } 123939220Sgibbs mvi INTSTAT,CMDCMPLT ret; 124039220Sgibbs 124141646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) { 124213177Sgibbs/* 124313177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 124413177Sgibbs * and await the bus going free. 124513177Sgibbs */ 12469954Sgibbsmesgin_disconnect: 124723925Sgibbs or SCB_CONTROL,DISCONNECTED; 124823925Sgibbs call add_scb_to_disc_list; 124923925Sgibbs jmp await_busfree; 125019164Sgibbs 125115328Sgibbs/* 125219164Sgibbs * Save data pointers message: 125319164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 125419164Sgibbs * only if we've actually been into a data phase to change them. This 125519164Sgibbs * protects against bogus data in scratch ram and the residual counts 125619164Sgibbs * since they are only initialized when we go into data_in or data_out. 125715328Sgibbs */ 125819164Sgibbsmesgin_sdptrs: 125923925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 12604568Sgibbs 126139220Sgibbs /* 126239220Sgibbs * The SCB SGPTR becomes the next one we'll download, 126339220Sgibbs * and the SCB DATAPTR becomes the current SHADDR. 126439220Sgibbs * Use the residual number since STCNT is corrupted by 126539220Sgibbs * any message transfer. 126639220Sgibbs */ 126739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 126839220Sgibbs bmov SCB_SGCOUNT, SG_COUNT, 5; 126939220Sgibbs bmov SCB_DATAPTR, SHADDR, 4; 127039220Sgibbs bmov SCB_DATACNT, SCB_RESID_DCNT, 3; 127139220Sgibbs } else { 127239220Sgibbs mvi DINDEX, SCB_SGCOUNT; 127339220Sgibbs mvi SG_COUNT call bcopy_5; 127419164Sgibbs 127539220Sgibbs mvi DINDEX, SCB_DATAPTR; 127639220Sgibbs mvi SHADDR call bcopy_4; 127739220Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 127839220Sgibbs } 127923925Sgibbs jmp mesgin_done; 12804568Sgibbs 128113177Sgibbs/* 128213177Sgibbs * Restore pointers message? Data pointers are recopied from the 128313177Sgibbs * SCB anytime we enter a data phase for the first time, so all 128413177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 128513177Sgibbs * code do the rest. 128613177Sgibbs */ 12879954Sgibbsmesgin_rdptrs: 128823925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 128923925Sgibbs * We'll reload them 129013177Sgibbs * the next time through 129123925Sgibbs * the dataphase. 129213177Sgibbs */ 129323925Sgibbs jmp mesgin_done; 12944568Sgibbs 129513177Sgibbs/* 129613177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 129713177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 129813177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 129913177Sgibbs */ 13009954Sgibbsmesgin_identify: 130139220Sgibbs if ((ahc->features & AHC_WIDE) != 0) { 130239220Sgibbs and A,0x0f; /* lun in lower four bits */ 130339220Sgibbs } else { 130439220Sgibbs and A,0x07; /* lun in lower three bits */ 130539220Sgibbs } 130623925Sgibbs or SAVED_TCL,A; /* SAVED_TCL should be complete now */ 130739220Sgibbs 130839220Sgibbs mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ 130939220Sgibbs call get_untagged_SCBID; 131039220Sgibbs cmp ARG_1, SCB_LIST_NULL je snoop_tag; 131139220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 131239220Sgibbs test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; 131339220Sgibbs } 131439220Sgibbs /* 131539220Sgibbs * If the SCB was found in the disconnected list (as is 131639220Sgibbs * always the case in non-paging scenarios), SCBPTR is already 131739220Sgibbs * set to the correct SCB. So, simply setup the SCB and get 131839220Sgibbs * on with things. 131939220Sgibbs */ 132039220Sgibbs call rem_scb_from_disc_list; 132124608Sgibbs jmp setup_SCB; 132213177Sgibbs/* 132313177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 132423168Sgibbs * If we get one, we use the tag returned to find the proper 132539220Sgibbs * SCB. With SCB paging, this requires using search for both tagged 132615328Sgibbs * and non-tagged transactions since the SCB may exist in any slot. 132715328Sgibbs * If we're not using SCB paging, we can use the tag as the direct 132815328Sgibbs * index to the SCB. 132913177Sgibbs */ 133024608Sgibbssnoop_tag: 133123925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 133213177Sgibbssnoop_tag_loop: 133339220Sgibbs call phase_lock; 133423925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 133523925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 13366608Sgibbsget_tag: 133723925Sgibbs mvi ARG_1 call inb_next; /* tag value */ 133813177Sgibbs 133939220Sgibbs /* 134039220Sgibbs * Ensure that the SCB the tag points to is for 134139220Sgibbs * an SCB transaction to the reconnecting target. 134239220Sgibbs */ 134339220Sgibbsuse_retrieveSCB: 134439220Sgibbs call retrieveSCB; 134539220Sgibbssetup_SCB: 134624608Sgibbs mov A, SAVED_TCL; 134739220Sgibbs cmp SCB_TCL, A jne not_found_cleanup_scb; 134839220Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; 134923925Sgibbs and SCB_CONTROL,~DISCONNECTED; 135055581Sgibbs or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 135139220Sgibbs call set_transfer_settings; 135239220Sgibbs /* See if the host wants to send a message upon reconnection */ 135339220Sgibbs test SCB_CONTROL, MK_MESSAGE jz mesgin_done; 135439220Sgibbs and SCB_CONTROL, ~MK_MESSAGE; 135539220Sgibbs mvi HOST_MSG call mk_mesg; 135623925Sgibbs jmp mesgin_done; 135715328Sgibbs 135839220Sgibbsnot_found_cleanup_scb: 135939220Sgibbs test SCB_CONTROL, DISCONNECTED jz . + 3; 136039220Sgibbs call add_scb_to_disc_list; 136139220Sgibbs jmp not_found; 136239220Sgibbs call add_scb_to_free_list; 136319218Sgibbsnot_found: 136423925Sgibbs mvi INTSTAT, NO_MATCH; 136523925Sgibbs jmp mesgin_done; 13666608Sgibbs 136713177Sgibbs/* 136813177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ] 136913177Sgibbs */ 13704568Sgibbs 137113177Sgibbs/* 137213177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX 137313177Sgibbs * if there is no active message already. SINDEX is returned intact. 137413177Sgibbs */ 13754568Sgibbsmk_mesg: 137623925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 137739220Sgibbs mov MSG_OUT,SINDEX ret; 13784568Sgibbs 137913177Sgibbs/* 138013177Sgibbs * Functions to read data in Automatic PIO mode. 138113177Sgibbs * 138213177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 138313177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 138413177Sgibbs * latched (the usual way), then read the data byte directly off the bus 138513177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 138613177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 138713177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 138813177Sgibbs * we send our ACK. 138913177Sgibbs * 139013177Sgibbs * The assumption here is that these are called in a particular sequence, 139113177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 139213177Sgibbs * use the same calling convention as inb. 139313177Sgibbs */ 139457099Sgibbsinb_next_wait_perr: 139557099Sgibbs mvi INTSTAT, PERR_DETECTED; 139657099Sgibbs jmp inb_next_wait; 139713177Sgibbsinb_next: 139823925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 139913360Sgibbsinb_next_wait: 140021947Sgibbs /* 140121947Sgibbs * If there is a parity error, wait for the kernel to 140221947Sgibbs * see the interrupt and prepare our message response 140321947Sgibbs * before continuing. 140421947Sgibbs */ 140523925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 140657099Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait_perr; 140757099Sgibbsinb_next_check_phase: 140823925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 140923925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 141019623Sgibbsinb_first: 141123925Sgibbs mov DINDEX,SINDEX; 141223925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 141313177Sgibbsinb_last: 141423925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 141541646Sgibbs} 14164568Sgibbs 141739220Sgibbsif ((ahc->flags & AHC_TARGETMODE) != 0) { 141841646Sgibbs/* 141941646Sgibbs * Change to a new phase. If we are changing the state of the I/O signal, 142041646Sgibbs * from out to in, wait an additional data release delay before continuing. 142141646Sgibbs */ 142241646Sgibbschange_phase: 142343880Sgibbs /* Wait for preceeding I/O session to complete. */ 142443880Sgibbs test SCSISIGI, ACKI jnz .; 142543880Sgibbs 142643880Sgibbs /* Change the phase */ 142741646Sgibbs and DINDEX, IOI, SCSISIGI; 142841646Sgibbs mov SCSISIGO, SINDEX; 142941646Sgibbs and A, IOI, SINDEX; 143043880Sgibbs 143143880Sgibbs /* 143243880Sgibbs * If the data direction has changed, from 143343880Sgibbs * out (initiator driving) to in (target driving), 143443880Sgibbs * we must waitat least a data release delay plus 143543880Sgibbs * the normal bus settle delay. [SCSI III SPI 10.11.0] 143643880Sgibbs */ 143741646Sgibbs cmp DINDEX, A je change_phase_wait; 143841646Sgibbs test SINDEX, IOI jz change_phase_wait; 143941646Sgibbs call change_phase_wait; 144041646Sgibbschange_phase_wait: 144141646Sgibbs nop; 144241646Sgibbs nop; 144341646Sgibbs nop; 144441646Sgibbs nop ret; 144541646Sgibbs 144641646Sgibbs/* 144741646Sgibbs * Send a byte to an initiator in Automatic PIO mode. 144841646Sgibbs */ 144939220Sgibbstarget_outb: 145039220Sgibbs or SXFRCTL0, SPIOEN; 145139220Sgibbs test SSTAT0, SPIORDY jz .; 145239220Sgibbs mov SCSIDATL, SINDEX; 145339220Sgibbs test SSTAT0, SPIORDY jz .; 145441646Sgibbs and SXFRCTL0, ~SPIOEN ret; 145539220Sgibbs} 145639220Sgibbs 145713177Sgibbsmesgin_phasemis: 145813177Sgibbs/* 145913177Sgibbs * We expected to receive another byte, but the target changed phase 146013177Sgibbs */ 146123925Sgibbs mvi INTSTAT, MSGIN_PHASEMIS; 146223925Sgibbs jmp ITloop; 14634568Sgibbs 146413177Sgibbs/* 146513177Sgibbs * DMA data transfer. HADDR and HCNT must be loaded first, and 146613177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for 146713177Sgibbs * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 146813177Sgibbs * during initialization. 146913177Sgibbs */ 14704568Sgibbsdma: 147123925Sgibbs mov DFCNTRL,SINDEX; 147222568Sgibbsdma_loop: 147323925Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 147423925Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 147522568Sgibbsdma_phasemis: 14764568Sgibbs 147713177Sgibbs/* 147813177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or 147913177Sgibbs * the target changes the phase (in light of this, it makes sense that 148013177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 148113177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto- 148213177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty 148313177Sgibbs * status. 148413177Sgibbs */ 148522568Sgibbsdma_checkfifo: 148623925Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 148722568Sgibbsdma_fifoflush: 148823925Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 14894568Sgibbs 149022568Sgibbsdma_fifoempty: 149122568Sgibbs /* Don't clobber an inprogress host data transfer */ 149223925Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 149313177Sgibbs/* 149413177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 149513177Sgibbs * actually off first lest we get an ILLSADDR. 149613177Sgibbs */ 149722568Sgibbsdma_dmadone: 149823925Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 149922568Sgibbsdma_halt: 150037223Sgibbs /* 150137223Sgibbs * Some revisions of the aic7880 have a problem where, if the 150237223Sgibbs * data fifo is full, but the PCI input latch is not empty, 150337223Sgibbs * HDMAEN cannot be cleared. The fix used here is to attempt 150437223Sgibbs * to drain the data fifo until there is space for the input 150537223Sgibbs * latch to drain and HDMAEN de-asserts. 150637223Sgibbs */ 150739220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 150839220Sgibbs mov NONE, DFDAT; 150939220Sgibbs } 151039220Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 151118762Sgibbsreturn: 151223925Sgibbs ret; 15134568Sgibbs 151413177Sgibbs/* 151513177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 151613177Sgibbs * message. 151713177Sgibbs */ 15184568Sgibbsassert: 151923925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 15204568Sgibbs 152123925Sgibbs mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ 15224568Sgibbs 152313177Sgibbs/* 152419218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) 152539220Sgibbs * or by the SCBID ARG_1. The search begins at the SCB index passed in 152639220Sgibbs * via SINDEX which is an SCB that must be on the disconnected list. If 152739220Sgibbs * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR 152839220Sgibbs * is set to the proper SCB. 152913177Sgibbs */ 15304568SgibbsfindSCB: 153139220Sgibbs mov SCBPTR,SINDEX; /* Initialize SCBPTR */ 153239220Sgibbs cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; 153339220Sgibbs mov A, SAVED_TCL; 153439220Sgibbs mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */ 153539220SgibbsfindSCB_by_SCBID: 153623925Sgibbs mov A, ARG_1; /* Tag passed in ARG_1 */ 153739220Sgibbs mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ 153839220SgibbsfindSCB_next: 153939220Sgibbs mov ARG_2, SCBPTR; 154039220Sgibbs cmp SCB_NEXT, SCB_LIST_NULL je notFound; 154139220Sgibbs mov SCBPTR,SCB_NEXT; 154239220Sgibbs dec SINDEX; /* Last comparison moved us too far */ 154323168SgibbsfindSCB_loop: 154439220Sgibbs cmp SINDIR, A jne findSCB_next; 154539220Sgibbs mov SINDEX, SCBPTR ret; 154639220SgibbsnotFound: 154739220Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 154839220Sgibbs 154919164Sgibbs/* 155039220Sgibbs * Retrieve an SCB by SCBID first searching the disconnected list falling 155139220Sgibbs * back to DMA'ing the SCB down from the host. This routine assumes that 155239220Sgibbs * ARG_1 is the SCBID of interrest and that SINDEX is the position in the 155339220Sgibbs * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, 155439220Sgibbs * we go directly to the host for the SCB. 155519164Sgibbs */ 155639220SgibbsretrieveSCB: 155739220Sgibbs test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; 155839220Sgibbs mov SCBPTR call findSCB; /* Continue the search */ 155939220Sgibbs cmp SINDEX, SCB_LIST_NULL je retrieve_from_host; 156039220Sgibbs 156139220Sgibbs/* 156239220Sgibbs * This routine expects SINDEX to contain the index of the SCB to be 156339220Sgibbs * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the 156439220Sgibbs * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL 156539220Sgibbs * if it is at the head. 156639220Sgibbs */ 156719164Sgibbsrem_scb_from_disc_list: 156815328Sgibbs/* Remove this SCB from the disconnection list */ 156939220Sgibbs cmp ARG_2, SCB_LIST_NULL je rHead; 157039220Sgibbs mov DINDEX, SCB_NEXT; 157139220Sgibbs mov SCBPTR, ARG_2; 157239220Sgibbs mov SCB_NEXT, DINDEX; 157323925Sgibbs mov SCBPTR, SINDEX ret; 157415328SgibbsrHead: 157523925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 15764568Sgibbs 157739220Sgibbsretrieve_from_host: 157839220Sgibbs/* 157939220Sgibbs * We didn't find it. Pull an SCB and DMA down the one we want. 158039220Sgibbs * We should never get here in the non-paging case. 158139220Sgibbs */ 158239220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 158339220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 158439220Sgibbs /* Jump instead of call as we want to return anyway */ 158539220Sgibbs mov ARG_1 jmp dma_scb; 158639220Sgibbs 158739220Sgibbs/* 158839220Sgibbs * Determine whether a target is using tagged or non-tagged transactions 158939220Sgibbs * by first looking for a matching transaction based on the TCL and if 159039220Sgibbs * that fails, looking up this device in the host's untagged SCB array. 159139220Sgibbs * The TCL to search for is assumed to be in SAVED_TCL. The value is 159239220Sgibbs * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). 159339220Sgibbs * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information 159439220Sgibbs * in an SCB instead of having to go to the host. 159539220Sgibbs */ 159639220Sgibbsget_untagged_SCBID: 159739220Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; 159839220Sgibbs mvi ARG_1, SCB_LIST_NULL; 159939220Sgibbs mov DISCONNECTED_SCBH call findSCB; 160039220Sgibbs cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; 160139220Sgibbs or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ 160239220Sgibbs test SCB_CONTROL, TAG_ENB jnz . + 2; 160339220Sgibbs mov ARG_1, SCB_TAG ret; 160439220Sgibbs mvi ARG_1, SCB_LIST_NULL ret; 160539220Sgibbs 160639220Sgibbs/* 160739220Sgibbs * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) 160839220Sgibbs * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. 160939220Sgibbs */ 161039220Sgibbsfetch_byte: 161139220Sgibbs mov ARG_2, SINDEX; 161239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 161339220Sgibbs mvi DINDEX, CCHADDR; 161439220Sgibbs mvi SCBID_ADDR call set_1byte_addr; 161539220Sgibbs mvi CCHCNT, 1; 161639220Sgibbs mvi CCSGCTL, CCSGEN|CCSGRESET; 161739220Sgibbs test CCSGCTL, CCSGDONE jz .; 161839220Sgibbs mvi CCSGCTL, CCSGRESET; 161939220Sgibbs bmov RETURN_2, CCSGRAM, 1 ret; 162039220Sgibbs } else { 162139220Sgibbs mvi DINDEX, HADDR; 162239220Sgibbs mvi SCBID_ADDR call set_1byte_addr; 162339220Sgibbs mvi HCNT[0], 1; 162439220Sgibbs clr HCNT[1]; 162539220Sgibbs clr HCNT[2]; 162639220Sgibbs mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 162739220Sgibbs call dma_finish; 162839220Sgibbs mov RETURN_2, DFDAT ret; 162939220Sgibbs } 163039220Sgibbs 163139220Sgibbs/* 163239220Sgibbs * Prepare the hardware to post a byte to host memory given an 163339220Sgibbs * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. 163439220Sgibbs */ 163539220Sgibbspost_byte_setup: 163639220Sgibbs mov ARG_2, SINDEX; 163739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 163839220Sgibbs mvi DINDEX, CCHADDR; 163939220Sgibbs mvi SCBID_ADDR call set_1byte_addr; 164039220Sgibbs mvi CCHCNT, 1; 164139220Sgibbs mvi CCSCBCTL, CCSCBRESET ret; 164239220Sgibbs } else { 164339220Sgibbs mvi DINDEX, HADDR; 164439220Sgibbs mvi SCBID_ADDR call set_1byte_addr; 164539220Sgibbs mvi HCNT[0], 1; 164639220Sgibbs clr HCNT[1]; 164739220Sgibbs clr HCNT[2]; 164839220Sgibbs mvi DFCNTRL, FIFORESET ret; 164939220Sgibbs } 165039220Sgibbs 165139220Sgibbspost_byte: 165239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 165339220Sgibbs bmov CCSCBRAM, SINDEX, 1; 165439220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 165539220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 165639220Sgibbs clr CCSCBCTL ret; 165739220Sgibbs } else { 165839220Sgibbs mov DFDAT, SINDEX; 165939220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 166039220Sgibbs jmp dma_finish; 166139220Sgibbs } 166239220Sgibbs 166339220Sgibbsget_SCBID_from_host: 166439220Sgibbs mov A, SAVED_TCL; 166539220Sgibbs mvi UNTAGGEDSCB_OFFSET call fetch_byte; 166639220Sgibbs mov RETURN_1, RETURN_2 ret; 166739220Sgibbs 166857099Sgibbsphase_lock_perr: 166957099Sgibbs mvi INTSTAT, PERR_DETECTED; 167039220Sgibbsphase_lock: 167157099Sgibbs /* 167257099Sgibbs * If there is a parity error, wait for the kernel to 167357099Sgibbs * see the interrupt and prepare our message response 167457099Sgibbs * before continuing. 167557099Sgibbs */ 167639220Sgibbs test SSTAT1, REQINIT jz phase_lock; 167757099Sgibbs test SSTAT1, SCSIPERR jnz phase_lock_perr; 167857099Sgibbsphase_lock_latch_phase: 167941646Sgibbs and SCSISIGO, PHASE_MASK, SCSISIGI; 168041646Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI ret; 168139220Sgibbs 168239220Sgibbsif ((ahc->features & AHC_CMD_CHAN) == 0) { 168319164Sgibbsset_stcnt_from_hcnt: 168423925Sgibbs mov STCNT[0], HCNT[0]; 168523925Sgibbs mov STCNT[1], HCNT[1]; 168623925Sgibbs mov STCNT[2], HCNT[2] ret; 16874568Sgibbs 168819164Sgibbsbcopy_7: 168923925Sgibbs mov DINDIR, SINDIR; 169023925Sgibbs mov DINDIR, SINDIR; 169119164Sgibbsbcopy_5: 169223925Sgibbs mov DINDIR, SINDIR; 169319164Sgibbsbcopy_4: 169423925Sgibbs mov DINDIR, SINDIR; 169519164Sgibbsbcopy_3: 169623925Sgibbs mov DINDIR, SINDIR; 169723925Sgibbs mov DINDIR, SINDIR; 169823925Sgibbs mov DINDIR, SINDIR ret; 169939220Sgibbs} 17004568Sgibbs 170139220Sgibbsif ((ahc->flags & AHC_TARGETMODE) != 0) { 170239220Sgibbs/* 170339220Sgibbs * Setup addr assuming that A is an index into 170439220Sgibbs * an array of 32byte objects, SINDEX contains 170539220Sgibbs * the base address of that array, and DINDEX 170639220Sgibbs * contains the base address of the location 170739220Sgibbs * to store the indexed address. 170839220Sgibbs */ 170939220Sgibbsset_32byte_addr: 171039220Sgibbs shr ARG_2, 3, A; 171139220Sgibbs shl A, 5; 171239220Sgibbs jmp set_1byte_addr; 171339220Sgibbs} 171439220Sgibbs 171539220Sgibbs/* 171639220Sgibbs * Setup addr assuming that A is an index into 171739220Sgibbs * an array of 64byte objects, SINDEX contains 171839220Sgibbs * the base address of that array, and DINDEX 171939220Sgibbs * contains the base address of the location 172039220Sgibbs * to store the indexed address. 172139220Sgibbs */ 172239220Sgibbsset_64byte_addr: 172339220Sgibbs shr ARG_2, 2, A; 172439220Sgibbs shl A, 6; 172539220Sgibbs 172639220Sgibbs/* 172739220Sgibbs * Setup addr assuming that A + (ARG_1 * 256) is an 172839220Sgibbs * index into an array of 1byte objects, SINDEX contains 172939220Sgibbs * the base address of that array, and DINDEX contains 173039220Sgibbs * the base address of the location to store the computed 173139220Sgibbs * address. 173239220Sgibbs */ 173339220Sgibbsset_1byte_addr: 173439220Sgibbs add DINDIR, A, SINDIR; 173539220Sgibbs mov A, ARG_2; 173639220Sgibbs adc DINDIR, A, SINDIR; 173739220Sgibbs clr A; 173839220Sgibbs adc DINDIR, A, SINDIR; 173939220Sgibbs adc DINDIR, A, SINDIR ret; 174039220Sgibbs 174139220Sgibbs/* 174239220Sgibbs * Either post or fetch and SCB from host memory based on the 174339220Sgibbs * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. 174439220Sgibbs */ 174519164Sgibbsdma_scb: 174639220Sgibbs mov A, SINDEX; 174739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 174839220Sgibbs mvi DINDEX, CCHADDR; 174939220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 175039220Sgibbs mov CCSCBPTR, SCBPTR; 175139220Sgibbs test DMAPARAMS, DIRECTION jz dma_scb_tohost; 175239220Sgibbs mvi CCHCNT, SCB_64BYTE_SIZE; 175339220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; 175439220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; 175539220Sgibbs jmp dma_scb_finish; 175639220Sgibbsdma_scb_tohost: 175739220Sgibbs mvi CCHCNT, SCB_32BYTE_SIZE; 175839220Sgibbs if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { 175939220Sgibbs mvi CCSCBCTL, CCSCBRESET; 176039220Sgibbs bmov CCSCBRAM, SCB_CONTROL, SCB_32BYTE_SIZE; 176139220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 176239220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 176339220Sgibbs } else { 176439220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; 176539220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; 176639220Sgibbs } 176739220Sgibbsdma_scb_finish: 176839220Sgibbs clr CCSCBCTL; 176939220Sgibbs test CCSCBCTL, CCARREN|CCSCBEN jnz .; 177039220Sgibbs ret; 177139220Sgibbs } else { 177239220Sgibbs mvi DINDEX, HADDR; 177339220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 177439220Sgibbs mvi HCNT[0], SCB_32BYTE_SIZE; 177539220Sgibbs clr HCNT[1]; 177639220Sgibbs clr HCNT[2]; 177739220Sgibbs mov DFCNTRL, DMAPARAMS; 177839220Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 177939220Sgibbs /* Fill it with the SCB data */ 178024175Sgibbscopy_scb_tofifo: 178139220Sgibbs mvi SINDEX, SCB_CONTROL; 178239220Sgibbs add A, SCB_32BYTE_SIZE, SINDEX; 178324175Sgibbscopy_scb_tofifo_loop: 178439220Sgibbs mov DFDAT,SINDIR; 178539220Sgibbs mov DFDAT,SINDIR; 178639220Sgibbs mov DFDAT,SINDIR; 178739220Sgibbs mov DFDAT,SINDIR; 178839220Sgibbs mov DFDAT,SINDIR; 178939220Sgibbs mov DFDAT,SINDIR; 179039220Sgibbs mov DFDAT,SINDIR; 179139220Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 179239220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 179319164Sgibbsdma_scb_fromhost: 179439220Sgibbs call dma_finish; 179539220Sgibbs /* If we were putting the SCB, we are done */ 179639220Sgibbs test DMAPARAMS, DIRECTION jz return; 179739220Sgibbs mvi SCB_CONTROL call dfdat_in_7; 179839220Sgibbs call dfdat_in_7_continued; 179939220Sgibbs call dfdat_in_7_continued; 180039220Sgibbs jmp dfdat_in_7_continued; 180119164Sgibbsdfdat_in_7: 180239220Sgibbs mov DINDEX,SINDEX; 180319164Sgibbsdfdat_in_7_continued: 180439220Sgibbs mov DINDIR,DFDAT; 180539220Sgibbs mov DINDIR,DFDAT; 180639220Sgibbs mov DINDIR,DFDAT; 180739220Sgibbs mov DINDIR,DFDAT; 180839220Sgibbs mov DINDIR,DFDAT; 180939220Sgibbs mov DINDIR,DFDAT; 181039220Sgibbs mov DINDIR,DFDAT ret; 181139220Sgibbs } 181219164Sgibbs 181339220Sgibbs 181413177Sgibbs/* 181519164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 181619164Sgibbs * DMA and wait for it to acknowledge that it's off. 181713177Sgibbs */ 181819164Sgibbsdma_finish: 181923925Sgibbs test DFSTATUS,HDONE jz dma_finish; 182022234Sgibbs /* Turn off DMA */ 182123925Sgibbs and DFCNTRL, ~HDMAEN; 182223925Sgibbs test DFCNTRL, HDMAEN jnz .; 182323925Sgibbs ret; 18249928Sgibbs 182523925Sgibbsadd_scb_to_free_list: 182639220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 182739220Sgibbs mov SCB_NEXT, FREE_SCBH; 182857099Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 182957099Sgibbs mov FREE_SCBH, SCBPTR ret; 183057099Sgibbs } else { 183157099Sgibbs mvi SCB_TAG, SCB_LIST_NULL ret; 183239220Sgibbs } 18334568Sgibbs 183439220Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) { 183519164Sgibbsget_free_or_disc_scb: 183623925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 183723925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 183819623Sgibbsreturn_error: 183923925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 184019623Sgibbsdequeue_disc_scb: 184123925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 184223925Sgibbsdma_up_scb: 184323925Sgibbs mvi DMAPARAMS, FIFORESET; 184423925Sgibbs mov SCB_TAG call dma_scb; 184519164Sgibbsunlink_disc_scb: 184639220Sgibbs mov DISCONNECTED_SCBH, SCB_NEXT ret; 184719164Sgibbsdequeue_free_scb: 184823925Sgibbs mov SCBPTR, FREE_SCBH; 184923925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 185039220Sgibbs} 18514568Sgibbs 185219164Sgibbsadd_scb_to_disc_list: 185313177Sgibbs/* 185419164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 185519164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 185619164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 185713177Sgibbs */ 185823925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 185939220Sgibbs mov DISCONNECTED_SCBH, SCBPTR ret; 1860