aic7xxx.seq revision 54211
126997Sgibbs/* 226997Sgibbs * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. 313177Sgibbs * 442652Sgibbs * Copyright (c) 1994-1999 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 54211 1999-12-06 18:23:31Z 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 */ 5741646Sgibbs and SXFRCTL1, ~BITBUCKET; 5823925Sgibbs /* Always allow reselection */ 5941816Sgibbs and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE; 6039220Sgibbs 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 mvi MSG_OUT, MSG_NOOP; /* No message to send */ 41739220Sgibbs jmp ITloop; 41841646Sgibbs} 4194568Sgibbs 42013177Sgibbs/* 42123925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 42223925Sgibbs * list. This is achieved by simply moving our "next" pointer into 42323925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 42423925Sgibbs * SCB is used, so don't bother with it now. 42523925Sgibbs */ 42639220Sgibbsselect_out: 42725005Sgibbs /* Turn off the selection hardware */ 42841816Sgibbs and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE; 42925005Sgibbs mvi CLRSINT0, CLRSELDO; 43025005Sgibbs mov SCBPTR, WAITING_SCBH; 43124914Sgibbs mov WAITING_SCBH,SCB_NEXT; 43223925Sgibbs mov SAVED_TCL, SCB_TCL; 43339220Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 43439220Sgibbs test SSTAT0, TARGET jz initiator_select; 4358567Sdg 43639220Sgibbs /* 43739220Sgibbs * We've just re-selected an initiator. 43839220Sgibbs * Assert BSY and setup the phase for 43939220Sgibbs * sending our identify messages. 44039220Sgibbs */ 44141646Sgibbs mvi P_MESGIN|BSYO call change_phase; 44241646Sgibbs mvi CLRSINT1,CLRBUSFREE; 4434568Sgibbs 44439220Sgibbs /* 44539220Sgibbs * Start out with a simple identify message. 44639220Sgibbs */ 44739220Sgibbs and A, LID, SCB_TCL; 44839220Sgibbs or A, MSG_IDENTIFYFLAG call target_outb; 4496608Sgibbs 45039220Sgibbs /* 45139220Sgibbs * If we are the result of a tagged command, send 45239220Sgibbs * a simple Q tag and the tag id. 45339220Sgibbs */ 45439220Sgibbs test SCB_CONTROL, TAG_ENB jz . + 3; 45539220Sgibbs mvi MSG_SIMPLE_Q_TAG call target_outb; 45642652Sgibbs mov SCB_INITIATOR_TAG call target_outb; 45742652Sgibbs mov INITIATOR_TAG, SCB_INITIATOR_TAG; 45839220Sgibbstarget_synccmd: 45939220Sgibbs /* 46039220Sgibbs * Now determine what phases the host wants us 46139220Sgibbs * to go through. 46239220Sgibbs */ 46339220Sgibbs mov SEQ_FLAGS, SCB_TARGET_PHASES; 46442652Sgibbs 46539220Sgibbs 46639220Sgibbstarget_ITloop: 46739220Sgibbs /* 46841646Sgibbs * Start honoring ATN signals now that 46944507Sgibbs * we properly identified ourselves. 47039220Sgibbs */ 47141646Sgibbs test SCSISIGI, ATNI jnz target_mesgout; 47239220Sgibbs test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; 47339220Sgibbs test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; 47439220Sgibbs test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; 47539220Sgibbs 47639220Sgibbs /* 47739220Sgibbs * No more work to do. Either disconnect or not depending 47839220Sgibbs * on the state of NO_DISCONNECT. 47939220Sgibbs */ 48039220Sgibbs test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 48139220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 48239220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 48339220Sgibbs } 48441646Sgibbs mov RETURN_1, ALLZEROS; 48539220Sgibbs call complete_target_cmd; 48641646Sgibbs cmp RETURN_1, CONT_MSG_LOOP jne .; 48739220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 48839220Sgibbs mov SCB_TAG call dma_scb; 48939220Sgibbs jmp target_synccmd; 49039220Sgibbs 49141646Sgibbstarget_mesgout: 49241646Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 49341646Sgibbs call target_inb; 49441646Sgibbs /* Local Processing goes here... */ 49541646Sgibbstarget_mesgout_pending_msg: 49641646Sgibbs jmp host_target_message_loop; 49741646Sgibbs 49839220Sgibbstarget_disconnect: 49941646Sgibbs mvi P_MESGIN|BSYO call change_phase; 50041816Sgibbs test SEQ_FLAGS, DPHASE jz . + 2; 50141816Sgibbs mvi MSG_SAVEDATAPOINTER call target_outb; 50239220Sgibbs mvi MSG_DISCONNECT call target_outb; 50339220Sgibbs 50443880Sgibbstarget_busfree_wait: 50543880Sgibbs /* Wait for preceeding I/O session to complete. */ 50643880Sgibbs test SCSISIGI, ACKI jnz .; 50739220Sgibbstarget_busfree: 50839220Sgibbs clr SCSISIGO; 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 { 77039220Sgibbs and DMAPARAMS, ~WIDEODD; 77139220Sgibbs } 7729928Sgibbsdata_phase_wideodd: 77339220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 77439220Sgibbs mov SINDEX, ALLONES; 77539220Sgibbs mov DFCNTRL, DMAPARAMS; 77639220Sgibbs test SSTAT0, SDONE jnz .;/* Wait for preload to complete */ 77739220Sgibbsdata_phase_dma_loop: 77839220Sgibbs test SSTAT0, SDONE jnz data_phase_dma_done; 77939220Sgibbs test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ 78039220Sgibbsdata_phase_dma_phasemis: 78139220Sgibbs test SSTAT0,SDONE jnz . + 2; 78239220Sgibbs mov SINDEX,ALLZEROS; /* Remeber the phasemiss */ 78339220Sgibbs } else { 78439220Sgibbs mov DMAPARAMS call dma; 78539220Sgibbs } 7864568Sgibbs 78739220Sgibbsdata_phase_dma_done: 78816260Sgibbs/* Go tell the host about any overruns */ 78923925Sgibbs test SXFRCTL1,BITBUCKET jnz data_phase_overrun; 79016260Sgibbs 79122451Sgibbs/* Exit if we had an underrun. dma clears SINDEX in this case. */ 79223925Sgibbs test SINDEX,0xff jz data_phase_finish; 7937532Sgibbs 79413177Sgibbs/* 79513177Sgibbs * Advance the scatter-gather pointers if needed 79613177Sgibbs */ 7979928Sgibbssg_advance: 79823925Sgibbs dec SG_COUNT; /* one less segment to go */ 7994568Sgibbs 80023925Sgibbs test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ 80113177Sgibbs/* 80213177Sgibbs * Load a struct scatter and set up the data address and length. 80313177Sgibbs * If the working value of the SG count is nonzero, then 80413177Sgibbs * we need to load a new set of values. 80513177Sgibbs * 80615328Sgibbs * This, like all DMA's, assumes little-endian host data storage. 80713177Sgibbs */ 8089928Sgibbssg_load: 80939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 81039220Sgibbs /* 81139220Sgibbs * Do we have any prefetch left??? 81239220Sgibbs */ 81339220Sgibbs cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; 8144568Sgibbs 81539220Sgibbs /* 81639220Sgibbs * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. 81739220Sgibbs */ 81839220Sgibbs add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; 81939220Sgibbs mvi A, CCSGADDR_MAX; 82039220Sgibbs jc . + 2; 82139220Sgibbs shl A, 3, SG_COUNT; 82239220Sgibbs mov CCHCNT, A; 82339220Sgibbs bmov CCHADDR, SG_NEXT, 4; 82439220Sgibbs mvi CCSGCTL, CCSGEN|CCSGRESET; 82539220Sgibbs test CCSGCTL, CCSGDONE jz .; 82639220Sgibbs and CCSGCTL, ~CCSGEN; 82739220Sgibbs test CCSGCTL, CCSGEN jnz .; 82839220Sgibbs mvi CCSGCTL, CCSGRESET; 82939220Sgibbsprefetched_segs_avail: 83039220Sgibbs bmov HADDR, CCSGRAM, 8; 83139220Sgibbs } else { 83239220Sgibbs mvi DINDEX, HADDR; 83339220Sgibbs mvi SG_NEXT call bcopy_4; 83422568Sgibbs 83539220Sgibbs mvi HCNT[0],SG_SIZEOF; 83639220Sgibbs clr HCNT[1]; 83739220Sgibbs clr HCNT[2]; 8389928Sgibbs 83939220Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 8409928Sgibbs 84139220Sgibbs call dma_finish; 8429928Sgibbs 84339220Sgibbs /* 84439220Sgibbs * Copy data from FIFO into SCB data pointer and data count. 84539220Sgibbs * This assumes that the SG segments are of the form: 84639220Sgibbs * struct ahc_dma_seg { 84739220Sgibbs * u_int32_t addr; four bytes, little-endian order 84839220Sgibbs * u_int32_t len; four bytes, little endian order 84939220Sgibbs * }; 85039220Sgibbs */ 85139220Sgibbs mvi HADDR call dfdat_in_7; 85239220Sgibbs } 85339220Sgibbs 85442652Sgibbs /* Track odd'ness */ 85542652Sgibbs test HCNT[0], 0x1 jz . + 2; 85642652Sgibbs xor DATA_COUNT_ODD, 0x1; 85742652Sgibbs 85839220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 85939220Sgibbs /* Load STCNT as well. It is a mirror of HCNT */ 86039220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 86139220Sgibbs bmov STCNT, HCNT, 3; 86239220Sgibbs } else { 86339220Sgibbs call set_stcnt_from_hcnt; 86439220Sgibbs } 86539220Sgibbs } 86639220Sgibbs 86739220Sgibbs/* Advance the SG pointer */ 86839220Sgibbs clr A; /* add sizeof(struct scatter) */ 86939220Sgibbs add SG_NEXT[0],SG_SIZEOF; 87039220Sgibbs adc SG_NEXT[1],A; 87139220Sgibbs 87241646Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 87341646Sgibbs test SSTAT0, TARGET jnz data_phase_loop; 87441646Sgibbs } 87541646Sgibbs test SSTAT1, REQINIT jz .; 87623925Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 87741646Sgibbs 87839220Sgibbs /* Ensure the last seg is visable at the shaddow layer */ 87939220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 88039220Sgibbs or DFCNTRL, PRELOADEN; 88139220Sgibbs } 8824568Sgibbs 8839928Sgibbsdata_phase_finish: 88439220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 88539220Sgibbs call ultra2_dmafinish; 88639220Sgibbs } 88713177Sgibbs/* 88813177Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into the SCB 88913177Sgibbs * We use STCNT instead of HCNT, since it's a reflection of how many bytes 89013177Sgibbs * were transferred on the SCSI (as opposed to the host) bus. 89113177Sgibbs */ 89239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 89339220Sgibbs bmov SCB_RESID_DCNT, STCNT, 3; 89439220Sgibbs } else { 89539220Sgibbs mov SCB_RESID_DCNT[0],STCNT[0]; 89639220Sgibbs mov SCB_RESID_DCNT[1],STCNT[1]; 89739220Sgibbs mov SCB_RESID_DCNT[2],STCNT[2]; 89839220Sgibbs } 89923925Sgibbs mov SCB_RESID_SGCNT, SG_COUNT; 90022568Sgibbs 90139220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 90239220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 90339220Sgibbs } 90422568Sgibbs 90539220Sgibbs if ((ahc->flags & AHC_TARGETMODE) != 0) { 90641646Sgibbs test SEQ_FLAGS, DPHASE_PENDING jz ITloop; 90739220Sgibbs and SEQ_FLAGS, ~DPHASE_PENDING; 90842652Sgibbs /* 90942652Sgibbs * For data-in phases, wait for any pending acks from the 91042652Sgibbs * initiator before changing phase. 91142652Sgibbs */ 91242652Sgibbs test DFCNTRL, DIRECTION jz target_ITloop; 91342652Sgibbs test SSTAT1, REQINIT jnz .; 91439220Sgibbs jmp target_ITloop; 91539220Sgibbs } 91623925Sgibbs jmp ITloop; 9174568Sgibbs 91816260Sgibbsdata_phase_overrun: 91939220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 92039220Sgibbs call ultra2_dmafinish; 92139220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 92239220Sgibbs } 92313177Sgibbs/* 92416260Sgibbs * Turn off BITBUCKET mode and notify the host 92516260Sgibbs */ 92623925Sgibbs and SXFRCTL1, ~BITBUCKET; 92723925Sgibbs mvi INTSTAT,DATA_OVERRUN; 92823925Sgibbs jmp ITloop; 92916260Sgibbs 93039220Sgibbsultra2_dmafinish: 93139220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 93239220Sgibbs test DFCNTRL, DIRECTION jnz ultra2_dmahalt; 93339220Sgibbs and DFCNTRL, ~SCSIEN; 93439220Sgibbs test DFCNTRL, SCSIEN jnz .; 93551471Sgibbsultra2_dmafifoflush: 93639220Sgibbs or DFCNTRL, FIFOFLUSH; 93751471Sgibbs /* 93851471Sgibbs * The FIFOEMP status bit on the Ultra2 class 93951471Sgibbs * of controllers seems to be a bit flaky. 94051471Sgibbs * It appears that if the FIFO is full and the 94151471Sgibbs * transfer ends with some data in the REQ/ACK 94251471Sgibbs * FIFO, FIFOEMP will fall temporarily 94351471Sgibbs * as the data is transferred to the PCI bus. 94451471Sgibbs * This glitch lasts for fewer than 5 clock cycles, 94551471Sgibbs * so we work around the problem by ensuring the 94651471Sgibbs * status bit stays false through a full glitch 94751471Sgibbs * window. 94851471Sgibbs */ 94951471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95051471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95151471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95251471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95351471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 95451471Sgibbs 95551471Sgibbsultra2_dmafifoempty: 95651471Sgibbs /* Don't clobber an inprogress host data transfer */ 95751471Sgibbs test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; 95851471Sgibbs 95939220Sgibbsultra2_dmahalt: 96039220Sgibbs and DFCNTRL, ~(SCSIEN|HDMAEN); 96139220Sgibbs test DFCNTRL, HDMAEN jnz .; 96239220Sgibbs ret; 96339220Sgibbs } 96439220Sgibbs 96541646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) { 96616260Sgibbs/* 96715328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 96813177Sgibbs */ 9694568Sgibbsp_command: 97023925Sgibbs call assert; 9714568Sgibbs 97239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 97339220Sgibbs mov HCNT[0], SCB_CMDLEN; 97439220Sgibbs bmov HCNT[1], ALLZEROS, 2; 97539220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 97639220Sgibbs bmov STCNT, HCNT, 3; 97739220Sgibbs } 97839220Sgibbs add NONE, -17, SCB_CMDLEN; 97939220Sgibbs jc dma_cmd_data; 98039220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 98139220Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); 98239220Sgibbs } else { 98339220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 98439220Sgibbs } 98539220Sgibbs bmov DFDAT, SCB_CMDSTORE, 16; 98639220Sgibbs jmp cmd_loop; 98739220Sgibbsdma_cmd_data: 98839220Sgibbs bmov HADDR, SCB_CMDPTR, 4; 98939220Sgibbs } else { 99039220Sgibbs mvi DINDEX, HADDR; 99139220Sgibbs mvi SCB_CMDPTR call bcopy_5; 99239220Sgibbs clr HCNT[1]; 99339220Sgibbs clr HCNT[2]; 99439220Sgibbs } 9954568Sgibbs 99639220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 99739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) == 0) { 99839220Sgibbs call set_stcnt_from_hcnt; 99939220Sgibbs } 100039220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); 100139220Sgibbs } else { 100239220Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); 100339220Sgibbs } 100439220Sgibbscmd_loop: 100539220Sgibbs test SSTAT0, SDONE jnz . + 2; 100639220Sgibbs test SSTAT1, PHASEMIS jz cmd_loop; 100739220Sgibbs and DFCNTRL, ~(SCSIEN|HDMAEN|SDMAEN); 100839220Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; 100923925Sgibbs jmp ITloop; 10104568Sgibbs 101113177Sgibbs/* 101213177Sgibbs * Status phase. Wait for the data byte to appear, then read it 101313177Sgibbs * and store it into the SCB. 101413177Sgibbs */ 10154568Sgibbsp_status: 101623925Sgibbs call assert; 101719803Sgibbs 101823925Sgibbs mov SCB_TARGET_STATUS, SCSIDATL; 101923925Sgibbs jmp ITloop; 10204568Sgibbs 102113177Sgibbs/* 102241646Sgibbs * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full 102341646Sgibbs * indentify message sequence and send it to the target. The host may 102441646Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB 102541646Sgibbs * control byte. This will cause us to interrupt the host and allow 102641646Sgibbs * it to handle the message phase completely on its own. If the bit 102741646Sgibbs * associated with this target is set, we will also interrupt the host, 102841646Sgibbs * thereby allowing it to send a message on the next selection regardless 102941646Sgibbs * of the transaction being sent. 103039220Sgibbs * 103139220Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. 103241646Sgibbs * This is done to allow the host to send messages outside of an identify 103339220Sgibbs * sequence while protecting the seqencer from testing the MK_MESSAGE bit 103439220Sgibbs * on an SCB that might not be for the current nexus. (For example, a 103539220Sgibbs * BDR message in responce to a bad reselection would leave us pointed to 103639220Sgibbs * an SCB that doesn't have anything to do with the current target). 103741646Sgibbs * 103839220Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, 103939220Sgibbs * bus device reset). 104039220Sgibbs * 104139220Sgibbs * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, 104239220Sgibbs * in case the target decides to put us in this phase for some strange 104339220Sgibbs * reason. 104413177Sgibbs */ 104541646Sgibbsp_mesgout_retry: 104641646Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 10474568Sgibbsp_mesgout: 104839220Sgibbs mov SINDEX, MSG_OUT; 104939220Sgibbs cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; 105041646Sgibbs test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; 105141646Sgibbs mov FUNCTION1, SCB_TCL; 105241646Sgibbs mov A, FUNCTION1; 105347158Sgibbs if ((ahc->features & AHC_HS_MAILBOX) != 0) { 105447158Sgibbs /* 105547158Sgibbs * Work around a pausing bug in at least the aic7890. 105647158Sgibbs * If the host needs to update the TARGET_MSG_REQUEST 105747158Sgibbs * bit field, it will set the HS_MAILBOX to 1. In 105847158Sgibbs * response, we pause with a specific interrupt code 105947158Sgibbs * asking for the mask to be updated before we continue. 106047158Sgibbs * Ugh. 106147158Sgibbs */ 106247158Sgibbs test HS_MAILBOX, 0xF0 jz . + 2; 106347158Sgibbs mvi INTSTAT, UPDATE_TMSG_REQ; 106447414Sgibbs nop; 106547158Sgibbs } 106647414Sgibbs mov SINDEX, TARGET_MSG_REQUEST[0]; 106741646Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 106841646Sgibbs /* Second Channel uses high byte bits */ 106941646Sgibbs test SCB_TCL, SELBUSB jz . + 2; 107041646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 107141646Sgibbs } else if ((ahc->features & AHC_WIDE) != 0) { 107241646Sgibbs test SCB_TCL, 0x80 jz . + 2; /* target > 7 */ 107341646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 107441646Sgibbs } 107541646Sgibbs test SINDEX, A jnz host_message_loop; 107639220Sgibbsp_mesgout_identify: 107741299Sgibbs and SINDEX,LID,SCB_TCL; /* lun */ 107839220Sgibbs and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ 107939220Sgibbs or SINDEX,A; /* or in disconnect privledge */ 108039220Sgibbs or SINDEX,MSG_IDENTIFYFLAG; 108113177Sgibbs/* 108239220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 108339220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 108413177Sgibbs */ 108539220Sgibbsp_mesgout_tag: 108639220Sgibbs test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; 108739220Sgibbs mov SCSIDATL, SINDEX; /* Send the identify message */ 108839220Sgibbs call phase_lock; 108939220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 109039220Sgibbs and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 109139220Sgibbs call phase_lock; 109239220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 109339220Sgibbs mov SCB_TAG jmp p_mesgout_onebyte; 109413177Sgibbs/* 109541646Sgibbs * Interrupt the driver, and allow it to handle this message 109641646Sgibbs * phase and any required retries. 109713177Sgibbs */ 109839220Sgibbsp_mesgout_from_host: 109939220Sgibbs cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; 110041646Sgibbs jmp host_message_loop; 110139220Sgibbs 110239220Sgibbsp_mesgout_onebyte: 110339220Sgibbs mvi CLRSINT1, CLRATNO; 110439220Sgibbs mov SCSIDATL, SINDEX; 110539220Sgibbs 110613177Sgibbs/* 110741646Sgibbs * If the next bus phase after ATN drops is message out, it means 110813177Sgibbs * that the target is requesting that the last message(s) be resent. 110913177Sgibbs */ 111039220Sgibbs call phase_lock; 111141646Sgibbs cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; 11124568Sgibbs 111319906Sgibbsp_mesgout_done: 111423925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 111539220Sgibbs mov LAST_MSG, MSG_OUT; 111639220Sgibbs mvi MSG_OUT, MSG_NOOP; /* No message left */ 111723925Sgibbs jmp ITloop; 11184568Sgibbs 111913177Sgibbs/* 112013177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 112113177Sgibbs */ 11224568Sgibbsp_mesgin: 112323925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 11244568Sgibbs 112523925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 112623925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 112723925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 112823925Sgibbs cmp ALLZEROS,A je mesgin_complete; 112923925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 113023925Sgibbs cmp A,MSG_NOOP je mesgin_done; 11314568Sgibbs 113213177Sgibbs/* 113341887Sgibbs * Pushed message loop to allow the kernel to 113441887Sgibbs * RUN IT's own message state engine. To avoid an 113541887Sgibbs * extra nop instruction after signaling the kernel, 113641887Sgibbs * we perform the phase_lock before checking to see 113741887Sgibbs * if we should exit the loop and skip the phase_lock 113841887Sgibbs * in the ITloop. Performing back to back phase_locks 113941887Sgibbs * shouldn't hurt, but why do it twice... 114013177Sgibbs */ 114141887Sgibbshost_message_loop: 114241887Sgibbs mvi INTSTAT, HOST_MSG_LOOP; 114341887Sgibbs call phase_lock; 114441887Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; 114541887Sgibbs jmp host_message_loop; 11469954Sgibbs 11479954Sgibbsmesgin_done: 114823925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 114923925Sgibbs jmp ITloop; 11509954Sgibbs 11519954Sgibbs 11529954Sgibbsmesgin_complete: 115313177Sgibbs/* 115419164Sgibbs * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, 115519164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 115639220Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0). 115739220Sgibbs * In either of these conditions, we upload the SCB back to the host so it can 115819164Sgibbs * process this information. In the case of a non zero status byte, we 115919164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 116019164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 116119164Sgibbs * sense, it will fill the kernel SCB with a request sense command and set 116219164Sgibbs * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload 116319164Sgibbs * the SCB, and process it as the next command by adding it to the waiting list. 116419164Sgibbs * If the kernel driver does not wish to request sense, it need only clear 116519164Sgibbs * RETURN_1, and the command is allowed to complete normally. We don't bother 116619164Sgibbs * to post to the QOUTFIFO in the error cases since it would require extra 116719164Sgibbs * work in the kernel driver to ensure that the entry was removed before the 116819164Sgibbs * command complete code tried processing it. 116913177Sgibbs */ 117019164Sgibbs 117113177Sgibbs/* 117219164Sgibbs * First check for residuals 117313177Sgibbs */ 117423925Sgibbs test SCB_RESID_SGCNT,0xff jnz upload_scb; 117539220Sgibbs test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */ 117619164Sgibbsupload_scb: 117723925Sgibbs mvi DMAPARAMS, FIFORESET; 117823925Sgibbs mov SCB_TAG call dma_scb; 11797532Sgibbscheck_status: 118039220Sgibbs test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ 118123925Sgibbs mvi INTSTAT,BAD_STATUS; /* let driver know */ 118239220Sgibbs nop; 118339220Sgibbs cmp RETURN_1, SEND_SENSE jne complete; 118419164Sgibbs /* This SCB becomes the next to execute as it will retrieve sense */ 118523925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 118639220Sgibbs mov SCB_TAG call dma_scb; 118719164Sgibbsadd_to_waiting_list: 118823925Sgibbs mov SCB_NEXT,WAITING_SCBH; 118923925Sgibbs mov WAITING_SCBH, SCBPTR; 119023925Sgibbs /* 119123925Sgibbs * Prepare our selection hardware before the busfree so we have a 119223925Sgibbs * high probability of winning arbitration. 119323925Sgibbs */ 119423925Sgibbs call start_selection; 119523925Sgibbs jmp await_busfree; 119639220Sgibbs 119739220Sgibbscomplete: 119839220Sgibbs /* If we are untagged, clear our address up in host ram */ 119939220Sgibbs test SCB_CONTROL, TAG_ENB jnz complete_queue; 120039220Sgibbs mov A, SAVED_TCL; 120139220Sgibbs mvi UNTAGGEDSCB_OFFSET call post_byte_setup; 120239220Sgibbs mvi SCB_LIST_NULL call post_byte; 120339220Sgibbs 120439220Sgibbscomplete_queue: 120539220Sgibbs mov SCB_TAG call complete_post; 120623925Sgibbs jmp await_busfree; 120741646Sgibbs} 12084568Sgibbs 120939220Sgibbscomplete_post: 121039220Sgibbs /* Post the SCBID in SINDEX and issue an interrupt */ 121144507Sgibbs call add_scb_to_free_list; 121239220Sgibbs mov ARG_1, SINDEX; 121339220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 121439220Sgibbs mov A, SDSCB_QOFF; 121539220Sgibbs } else { 121639220Sgibbs mov A, QOUTPOS; 121739220Sgibbs } 121839220Sgibbs mvi QOUTFIFO_OFFSET call post_byte_setup; 121939220Sgibbs mov ARG_1 call post_byte; 122039220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) == 0) { 122139220Sgibbs inc QOUTPOS; 122239220Sgibbs } 122339220Sgibbs mvi INTSTAT,CMDCMPLT ret; 122439220Sgibbs 122541646Sgibbsif ((ahc->flags & AHC_INITIATORMODE) != 0) { 122613177Sgibbs/* 122713177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 122813177Sgibbs * and await the bus going free. 122913177Sgibbs */ 12309954Sgibbsmesgin_disconnect: 123123925Sgibbs or SCB_CONTROL,DISCONNECTED; 123223925Sgibbs call add_scb_to_disc_list; 123323925Sgibbs jmp await_busfree; 123419164Sgibbs 123515328Sgibbs/* 123619164Sgibbs * Save data pointers message: 123719164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 123819164Sgibbs * only if we've actually been into a data phase to change them. This 123919164Sgibbs * protects against bogus data in scratch ram and the residual counts 124019164Sgibbs * since they are only initialized when we go into data_in or data_out. 124115328Sgibbs */ 124219164Sgibbsmesgin_sdptrs: 124323925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 12444568Sgibbs 124539220Sgibbs /* 124639220Sgibbs * The SCB SGPTR becomes the next one we'll download, 124739220Sgibbs * and the SCB DATAPTR becomes the current SHADDR. 124839220Sgibbs * Use the residual number since STCNT is corrupted by 124939220Sgibbs * any message transfer. 125039220Sgibbs */ 125139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 125239220Sgibbs bmov SCB_SGCOUNT, SG_COUNT, 5; 125339220Sgibbs bmov SCB_DATAPTR, SHADDR, 4; 125439220Sgibbs bmov SCB_DATACNT, SCB_RESID_DCNT, 3; 125539220Sgibbs } else { 125639220Sgibbs mvi DINDEX, SCB_SGCOUNT; 125739220Sgibbs mvi SG_COUNT call bcopy_5; 125819164Sgibbs 125939220Sgibbs mvi DINDEX, SCB_DATAPTR; 126039220Sgibbs mvi SHADDR call bcopy_4; 126139220Sgibbs mvi SCB_RESID_DCNT call bcopy_3; 126239220Sgibbs } 126323925Sgibbs jmp mesgin_done; 12644568Sgibbs 126513177Sgibbs/* 126613177Sgibbs * Restore pointers message? Data pointers are recopied from the 126713177Sgibbs * SCB anytime we enter a data phase for the first time, so all 126813177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 126913177Sgibbs * code do the rest. 127013177Sgibbs */ 12719954Sgibbsmesgin_rdptrs: 127223925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 127323925Sgibbs * We'll reload them 127413177Sgibbs * the next time through 127523925Sgibbs * the dataphase. 127613177Sgibbs */ 127723925Sgibbs jmp mesgin_done; 12784568Sgibbs 127913177Sgibbs/* 128013177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 128113177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 128213177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 128313177Sgibbs */ 12849954Sgibbsmesgin_identify: 128539220Sgibbs 128639220Sgibbs if ((ahc->features & AHC_WIDE) != 0) { 128739220Sgibbs and A,0x0f; /* lun in lower four bits */ 128839220Sgibbs } else { 128939220Sgibbs and A,0x07; /* lun in lower three bits */ 129039220Sgibbs } 129123925Sgibbs or SAVED_TCL,A; /* SAVED_TCL should be complete now */ 129239220Sgibbs 129339220Sgibbs mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ 129439220Sgibbs call get_untagged_SCBID; 129539220Sgibbs cmp ARG_1, SCB_LIST_NULL je snoop_tag; 129639220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 129739220Sgibbs test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; 129839220Sgibbs } 129939220Sgibbs /* 130039220Sgibbs * If the SCB was found in the disconnected list (as is 130139220Sgibbs * always the case in non-paging scenarios), SCBPTR is already 130239220Sgibbs * set to the correct SCB. So, simply setup the SCB and get 130339220Sgibbs * on with things. 130439220Sgibbs */ 130539220Sgibbs call rem_scb_from_disc_list; 130624608Sgibbs jmp setup_SCB; 130713177Sgibbs/* 130813177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 130923168Sgibbs * If we get one, we use the tag returned to find the proper 131039220Sgibbs * SCB. With SCB paging, this requires using search for both tagged 131115328Sgibbs * and non-tagged transactions since the SCB may exist in any slot. 131215328Sgibbs * If we're not using SCB paging, we can use the tag as the direct 131315328Sgibbs * index to the SCB. 131413177Sgibbs */ 131524608Sgibbssnoop_tag: 131623925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 131713177Sgibbssnoop_tag_loop: 131839220Sgibbs call phase_lock; 131923925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 132023925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 13216608Sgibbsget_tag: 132223925Sgibbs mvi ARG_1 call inb_next; /* tag value */ 132313177Sgibbs 132439220Sgibbs /* 132539220Sgibbs * Ensure that the SCB the tag points to is for 132639220Sgibbs * an SCB transaction to the reconnecting target. 132739220Sgibbs */ 132839220Sgibbsuse_retrieveSCB: 132939220Sgibbs call retrieveSCB; 133039220Sgibbssetup_SCB: 133124608Sgibbs mov A, SAVED_TCL; 133239220Sgibbs cmp SCB_TCL, A jne not_found_cleanup_scb; 133339220Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; 133423925Sgibbs and SCB_CONTROL,~DISCONNECTED; 133523925Sgibbs or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 133639220Sgibbs call set_transfer_settings; 133739220Sgibbs /* See if the host wants to send a message upon reconnection */ 133839220Sgibbs test SCB_CONTROL, MK_MESSAGE jz mesgin_done; 133939220Sgibbs and SCB_CONTROL, ~MK_MESSAGE; 134039220Sgibbs mvi HOST_MSG call mk_mesg; 134123925Sgibbs jmp mesgin_done; 134215328Sgibbs 134339220Sgibbsnot_found_cleanup_scb: 134439220Sgibbs test SCB_CONTROL, DISCONNECTED jz . + 3; 134539220Sgibbs call add_scb_to_disc_list; 134639220Sgibbs jmp not_found; 134739220Sgibbs call add_scb_to_free_list; 134819218Sgibbsnot_found: 134923925Sgibbs mvi INTSTAT, NO_MATCH; 135023925Sgibbs jmp mesgin_done; 13516608Sgibbs 135213177Sgibbs/* 135313177Sgibbs * [ ADD MORE MESSAGE HANDLING HERE ] 135413177Sgibbs */ 13554568Sgibbs 135613177Sgibbs/* 135713177Sgibbs * Locking the driver out, build a one-byte message passed in SINDEX 135813177Sgibbs * if there is no active message already. SINDEX is returned intact. 135913177Sgibbs */ 13604568Sgibbsmk_mesg: 136123925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 136239220Sgibbs mov MSG_OUT,SINDEX ret; 13634568Sgibbs 136413177Sgibbs/* 136513177Sgibbs * Functions to read data in Automatic PIO mode. 136613177Sgibbs * 136713177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 136813177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 136913177Sgibbs * latched (the usual way), then read the data byte directly off the bus 137013177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 137113177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 137213177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 137313177Sgibbs * we send our ACK. 137413177Sgibbs * 137513177Sgibbs * The assumption here is that these are called in a particular sequence, 137613177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 137713177Sgibbs * use the same calling convention as inb. 137813177Sgibbs */ 137913177Sgibbs 138013177Sgibbsinb_next: 138123925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 138213360Sgibbsinb_next_wait: 138321947Sgibbs /* 138421947Sgibbs * If there is a parity error, wait for the kernel to 138521947Sgibbs * see the interrupt and prepare our message response 138621947Sgibbs * before continuing. 138721947Sgibbs */ 138823925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 138923925Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait; 139023925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 139123925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 139219623Sgibbsinb_first: 139323925Sgibbs mov DINDEX,SINDEX; 139423925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 139513177Sgibbsinb_last: 139623925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 139741646Sgibbs} 13984568Sgibbs 139939220Sgibbsif ((ahc->flags & AHC_TARGETMODE) != 0) { 140041646Sgibbs/* 140141646Sgibbs * Change to a new phase. If we are changing the state of the I/O signal, 140241646Sgibbs * from out to in, wait an additional data release delay before continuing. 140341646Sgibbs */ 140441646Sgibbschange_phase: 140543880Sgibbs /* Wait for preceeding I/O session to complete. */ 140643880Sgibbs test SCSISIGI, ACKI jnz .; 140743880Sgibbs 140843880Sgibbs /* Change the phase */ 140941646Sgibbs and DINDEX, IOI, SCSISIGI; 141041646Sgibbs mov SCSISIGO, SINDEX; 141141646Sgibbs and A, IOI, SINDEX; 141243880Sgibbs 141343880Sgibbs /* 141443880Sgibbs * If the data direction has changed, from 141543880Sgibbs * out (initiator driving) to in (target driving), 141643880Sgibbs * we must waitat least a data release delay plus 141743880Sgibbs * the normal bus settle delay. [SCSI III SPI 10.11.0] 141843880Sgibbs */ 141941646Sgibbs cmp DINDEX, A je change_phase_wait; 142041646Sgibbs test SINDEX, IOI jz change_phase_wait; 142141646Sgibbs call change_phase_wait; 142241646Sgibbschange_phase_wait: 142341646Sgibbs nop; 142441646Sgibbs nop; 142541646Sgibbs nop; 142641646Sgibbs nop ret; 142741646Sgibbs 142841646Sgibbs/* 142941646Sgibbs * Send a byte to an initiator in Automatic PIO mode. 143041646Sgibbs */ 143139220Sgibbstarget_outb: 143239220Sgibbs or SXFRCTL0, SPIOEN; 143339220Sgibbs test SSTAT0, SPIORDY jz .; 143439220Sgibbs mov SCSIDATL, SINDEX; 143539220Sgibbs test SSTAT0, SPIORDY jz .; 143641646Sgibbs and SXFRCTL0, ~SPIOEN ret; 143739220Sgibbs} 143839220Sgibbs 143913177Sgibbsmesgin_phasemis: 144013177Sgibbs/* 144113177Sgibbs * We expected to receive another byte, but the target changed phase 144213177Sgibbs */ 144323925Sgibbs mvi INTSTAT, MSGIN_PHASEMIS; 144423925Sgibbs jmp ITloop; 14454568Sgibbs 144613177Sgibbs/* 144713177Sgibbs * DMA data transfer. HADDR and HCNT must be loaded first, and 144813177Sgibbs * SINDEX should contain the value to load DFCNTRL with - 0x3d for 144913177Sgibbs * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared 145013177Sgibbs * during initialization. 145113177Sgibbs */ 14524568Sgibbsdma: 145323925Sgibbs mov DFCNTRL,SINDEX; 145422568Sgibbsdma_loop: 145523925Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 145623925Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 145722568Sgibbsdma_phasemis: 145823925Sgibbs test SSTAT0,SDONE jnz dma_checkfifo; 145923925Sgibbs mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ 14604568Sgibbs 146113177Sgibbs/* 146213177Sgibbs * We will be "done" DMAing when the transfer count goes to zero, or 146313177Sgibbs * the target changes the phase (in light of this, it makes sense that 146413177Sgibbs * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are 146513177Sgibbs * doing a SCSI->Host transfer, the data FIFO should be flushed auto- 146613177Sgibbs * magically on STCNT=0 or a phase change, so just wait for FIFO empty 146713177Sgibbs * status. 146813177Sgibbs */ 146922568Sgibbsdma_checkfifo: 147023925Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 147122568Sgibbsdma_fifoflush: 147223925Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 14734568Sgibbs 147422568Sgibbsdma_fifoempty: 147522568Sgibbs /* Don't clobber an inprogress host data transfer */ 147623925Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 147713177Sgibbs/* 147813177Sgibbs * Now shut the DMA enables off and make sure that the DMA enables are 147913177Sgibbs * actually off first lest we get an ILLSADDR. 148013177Sgibbs */ 148122568Sgibbsdma_dmadone: 148223925Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 148322568Sgibbsdma_halt: 148437223Sgibbs /* 148537223Sgibbs * Some revisions of the aic7880 have a problem where, if the 148637223Sgibbs * data fifo is full, but the PCI input latch is not empty, 148737223Sgibbs * HDMAEN cannot be cleared. The fix used here is to attempt 148837223Sgibbs * to drain the data fifo until there is space for the input 148937223Sgibbs * latch to drain and HDMAEN de-asserts. 149037223Sgibbs */ 149139220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 149239220Sgibbs mov NONE, DFDAT; 149339220Sgibbs } 149439220Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 149518762Sgibbsreturn: 149623925Sgibbs ret; 14974568Sgibbs 149813177Sgibbs/* 149913177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 150013177Sgibbs * message. 150113177Sgibbs */ 15024568Sgibbsassert: 150323925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 15044568Sgibbs 150523925Sgibbs mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ 15064568Sgibbs 150713177Sgibbs/* 150819218Sgibbs * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) 150939220Sgibbs * or by the SCBID ARG_1. The search begins at the SCB index passed in 151039220Sgibbs * via SINDEX which is an SCB that must be on the disconnected list. If 151139220Sgibbs * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR 151239220Sgibbs * is set to the proper SCB. 151313177Sgibbs */ 15144568SgibbsfindSCB: 151539220Sgibbs mov SCBPTR,SINDEX; /* Initialize SCBPTR */ 151639220Sgibbs cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; 151739220Sgibbs mov A, SAVED_TCL; 151839220Sgibbs mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */ 151939220SgibbsfindSCB_by_SCBID: 152023925Sgibbs mov A, ARG_1; /* Tag passed in ARG_1 */ 152139220Sgibbs mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ 152239220SgibbsfindSCB_next: 152339220Sgibbs mov ARG_2, SCBPTR; 152439220Sgibbs cmp SCB_NEXT, SCB_LIST_NULL je notFound; 152539220Sgibbs mov SCBPTR,SCB_NEXT; 152639220Sgibbs dec SINDEX; /* Last comparison moved us too far */ 152723168SgibbsfindSCB_loop: 152839220Sgibbs cmp SINDIR, A jne findSCB_next; 152939220Sgibbs mov SINDEX, SCBPTR ret; 153039220SgibbsnotFound: 153139220Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 153239220Sgibbs 153319164Sgibbs/* 153439220Sgibbs * Retrieve an SCB by SCBID first searching the disconnected list falling 153539220Sgibbs * back to DMA'ing the SCB down from the host. This routine assumes that 153639220Sgibbs * ARG_1 is the SCBID of interrest and that SINDEX is the position in the 153739220Sgibbs * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, 153839220Sgibbs * we go directly to the host for the SCB. 153919164Sgibbs */ 154039220SgibbsretrieveSCB: 154139220Sgibbs test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; 154239220Sgibbs mov SCBPTR call findSCB; /* Continue the search */ 154339220Sgibbs cmp SINDEX, SCB_LIST_NULL je retrieve_from_host; 154439220Sgibbs 154539220Sgibbs/* 154639220Sgibbs * This routine expects SINDEX to contain the index of the SCB to be 154739220Sgibbs * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the 154839220Sgibbs * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL 154939220Sgibbs * if it is at the head. 155039220Sgibbs */ 155119164Sgibbsrem_scb_from_disc_list: 155215328Sgibbs/* Remove this SCB from the disconnection list */ 155339220Sgibbs cmp ARG_2, SCB_LIST_NULL je rHead; 155439220Sgibbs mov DINDEX, SCB_NEXT; 155539220Sgibbs mov SCBPTR, ARG_2; 155639220Sgibbs mov SCB_NEXT, DINDEX; 155723925Sgibbs mov SCBPTR, SINDEX ret; 155815328SgibbsrHead: 155923925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 15604568Sgibbs 156139220Sgibbsretrieve_from_host: 156239220Sgibbs/* 156339220Sgibbs * We didn't find it. Pull an SCB and DMA down the one we want. 156439220Sgibbs * We should never get here in the non-paging case. 156539220Sgibbs */ 156639220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 156739220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 156839220Sgibbs /* Jump instead of call as we want to return anyway */ 156939220Sgibbs mov ARG_1 jmp dma_scb; 157039220Sgibbs 157139220Sgibbs/* 157239220Sgibbs * Determine whether a target is using tagged or non-tagged transactions 157339220Sgibbs * by first looking for a matching transaction based on the TCL and if 157439220Sgibbs * that fails, looking up this device in the host's untagged SCB array. 157539220Sgibbs * The TCL to search for is assumed to be in SAVED_TCL. The value is 157639220Sgibbs * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). 157739220Sgibbs * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information 157839220Sgibbs * in an SCB instead of having to go to the host. 157939220Sgibbs */ 158039220Sgibbsget_untagged_SCBID: 158139220Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; 158239220Sgibbs mvi ARG_1, SCB_LIST_NULL; 158339220Sgibbs mov DISCONNECTED_SCBH call findSCB; 158439220Sgibbs cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; 158539220Sgibbs or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ 158639220Sgibbs test SCB_CONTROL, TAG_ENB jnz . + 2; 158739220Sgibbs mov ARG_1, SCB_TAG ret; 158839220Sgibbs mvi ARG_1, SCB_LIST_NULL ret; 158939220Sgibbs 159039220Sgibbs/* 159139220Sgibbs * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) 159239220Sgibbs * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. 159339220Sgibbs */ 159439220Sgibbsfetch_byte: 159539220Sgibbs mov ARG_2, SINDEX; 159639220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 159739220Sgibbs mvi DINDEX, CCHADDR; 159839220Sgibbs mvi SCBID_ADDR call set_1byte_addr; 159939220Sgibbs mvi CCHCNT, 1; 160039220Sgibbs mvi CCSGCTL, CCSGEN|CCSGRESET; 160139220Sgibbs test CCSGCTL, CCSGDONE jz .; 160239220Sgibbs mvi CCSGCTL, CCSGRESET; 160339220Sgibbs bmov RETURN_2, CCSGRAM, 1 ret; 160439220Sgibbs } else { 160539220Sgibbs mvi DINDEX, HADDR; 160639220Sgibbs mvi SCBID_ADDR call set_1byte_addr; 160739220Sgibbs mvi HCNT[0], 1; 160839220Sgibbs clr HCNT[1]; 160939220Sgibbs clr HCNT[2]; 161039220Sgibbs mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 161139220Sgibbs call dma_finish; 161239220Sgibbs mov RETURN_2, DFDAT ret; 161339220Sgibbs } 161439220Sgibbs 161539220Sgibbs/* 161639220Sgibbs * Prepare the hardware to post a byte to host memory given an 161739220Sgibbs * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. 161839220Sgibbs */ 161939220Sgibbspost_byte_setup: 162039220Sgibbs mov ARG_2, SINDEX; 162139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 162239220Sgibbs mvi DINDEX, CCHADDR; 162339220Sgibbs mvi SCBID_ADDR call set_1byte_addr; 162439220Sgibbs mvi CCHCNT, 1; 162539220Sgibbs mvi CCSCBCTL, CCSCBRESET ret; 162639220Sgibbs } else { 162739220Sgibbs mvi DINDEX, HADDR; 162839220Sgibbs mvi SCBID_ADDR call set_1byte_addr; 162939220Sgibbs mvi HCNT[0], 1; 163039220Sgibbs clr HCNT[1]; 163139220Sgibbs clr HCNT[2]; 163239220Sgibbs mvi DFCNTRL, FIFORESET ret; 163339220Sgibbs } 163439220Sgibbs 163539220Sgibbspost_byte: 163639220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 163739220Sgibbs bmov CCSCBRAM, SINDEX, 1; 163839220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 163939220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 164039220Sgibbs clr CCSCBCTL ret; 164139220Sgibbs } else { 164239220Sgibbs mov DFDAT, SINDEX; 164339220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 164439220Sgibbs jmp dma_finish; 164539220Sgibbs } 164639220Sgibbs 164739220Sgibbsget_SCBID_from_host: 164839220Sgibbs mov A, SAVED_TCL; 164939220Sgibbs mvi UNTAGGEDSCB_OFFSET call fetch_byte; 165039220Sgibbs mov RETURN_1, RETURN_2 ret; 165139220Sgibbs 165239220Sgibbsphase_lock: 165339220Sgibbs test SSTAT1, REQINIT jz phase_lock; 165439220Sgibbs test SSTAT1, SCSIPERR jnz phase_lock; 165541646Sgibbs and SCSISIGO, PHASE_MASK, SCSISIGI; 165641646Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI ret; 165739220Sgibbs 165839220Sgibbsif ((ahc->features & AHC_CMD_CHAN) == 0) { 165919164Sgibbsset_stcnt_from_hcnt: 166023925Sgibbs mov STCNT[0], HCNT[0]; 166123925Sgibbs mov STCNT[1], HCNT[1]; 166223925Sgibbs mov STCNT[2], HCNT[2] ret; 16634568Sgibbs 166419164Sgibbsbcopy_7: 166523925Sgibbs mov DINDIR, SINDIR; 166623925Sgibbs mov DINDIR, SINDIR; 166719164Sgibbsbcopy_5: 166823925Sgibbs mov DINDIR, SINDIR; 166919164Sgibbsbcopy_4: 167023925Sgibbs mov DINDIR, SINDIR; 167119164Sgibbsbcopy_3: 167223925Sgibbs mov DINDIR, SINDIR; 167323925Sgibbs mov DINDIR, SINDIR; 167423925Sgibbs mov DINDIR, SINDIR ret; 167539220Sgibbs} 16764568Sgibbs 167739220Sgibbsif ((ahc->flags & AHC_TARGETMODE) != 0) { 167839220Sgibbs/* 167939220Sgibbs * Setup addr assuming that A is an index into 168039220Sgibbs * an array of 32byte objects, SINDEX contains 168139220Sgibbs * the base address of that array, and DINDEX 168239220Sgibbs * contains the base address of the location 168339220Sgibbs * to store the indexed address. 168439220Sgibbs */ 168539220Sgibbsset_32byte_addr: 168639220Sgibbs shr ARG_2, 3, A; 168739220Sgibbs shl A, 5; 168839220Sgibbs jmp set_1byte_addr; 168939220Sgibbs} 169039220Sgibbs 169139220Sgibbs/* 169239220Sgibbs * Setup addr assuming that A is an index into 169339220Sgibbs * an array of 64byte objects, SINDEX contains 169439220Sgibbs * the base address of that array, and DINDEX 169539220Sgibbs * contains the base address of the location 169639220Sgibbs * to store the indexed address. 169739220Sgibbs */ 169839220Sgibbsset_64byte_addr: 169939220Sgibbs shr ARG_2, 2, A; 170039220Sgibbs shl A, 6; 170139220Sgibbs 170239220Sgibbs/* 170339220Sgibbs * Setup addr assuming that A + (ARG_1 * 256) is an 170439220Sgibbs * index into an array of 1byte objects, SINDEX contains 170539220Sgibbs * the base address of that array, and DINDEX contains 170639220Sgibbs * the base address of the location to store the computed 170739220Sgibbs * address. 170839220Sgibbs */ 170939220Sgibbsset_1byte_addr: 171039220Sgibbs add DINDIR, A, SINDIR; 171139220Sgibbs mov A, ARG_2; 171239220Sgibbs adc DINDIR, A, SINDIR; 171339220Sgibbs clr A; 171439220Sgibbs adc DINDIR, A, SINDIR; 171539220Sgibbs adc DINDIR, A, SINDIR ret; 171639220Sgibbs 171739220Sgibbs/* 171839220Sgibbs * Either post or fetch and SCB from host memory based on the 171939220Sgibbs * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. 172039220Sgibbs */ 172119164Sgibbsdma_scb: 172239220Sgibbs mov A, SINDEX; 172339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 172439220Sgibbs mvi DINDEX, CCHADDR; 172539220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 172639220Sgibbs mov CCSCBPTR, SCBPTR; 172739220Sgibbs test DMAPARAMS, DIRECTION jz dma_scb_tohost; 172839220Sgibbs mvi CCHCNT, SCB_64BYTE_SIZE; 172939220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; 173039220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; 173139220Sgibbs jmp dma_scb_finish; 173239220Sgibbsdma_scb_tohost: 173339220Sgibbs mvi CCHCNT, SCB_32BYTE_SIZE; 173439220Sgibbs if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { 173539220Sgibbs mvi CCSCBCTL, CCSCBRESET; 173639220Sgibbs bmov CCSCBRAM, SCB_CONTROL, SCB_32BYTE_SIZE; 173739220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 173839220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 173939220Sgibbs } else { 174039220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; 174139220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; 174239220Sgibbs } 174339220Sgibbsdma_scb_finish: 174439220Sgibbs clr CCSCBCTL; 174539220Sgibbs test CCSCBCTL, CCARREN|CCSCBEN jnz .; 174639220Sgibbs ret; 174739220Sgibbs } else { 174839220Sgibbs mvi DINDEX, HADDR; 174939220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 175039220Sgibbs mvi HCNT[0], SCB_32BYTE_SIZE; 175139220Sgibbs clr HCNT[1]; 175239220Sgibbs clr HCNT[2]; 175339220Sgibbs mov DFCNTRL, DMAPARAMS; 175439220Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 175539220Sgibbs /* Fill it with the SCB data */ 175624175Sgibbscopy_scb_tofifo: 175739220Sgibbs mvi SINDEX, SCB_CONTROL; 175839220Sgibbs add A, SCB_32BYTE_SIZE, SINDEX; 175924175Sgibbscopy_scb_tofifo_loop: 176039220Sgibbs mov DFDAT,SINDIR; 176139220Sgibbs mov DFDAT,SINDIR; 176239220Sgibbs mov DFDAT,SINDIR; 176339220Sgibbs mov DFDAT,SINDIR; 176439220Sgibbs mov DFDAT,SINDIR; 176539220Sgibbs mov DFDAT,SINDIR; 176639220Sgibbs mov DFDAT,SINDIR; 176739220Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 176839220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 176919164Sgibbsdma_scb_fromhost: 177039220Sgibbs call dma_finish; 177139220Sgibbs /* If we were putting the SCB, we are done */ 177239220Sgibbs test DMAPARAMS, DIRECTION jz return; 177339220Sgibbs mvi SCB_CONTROL call dfdat_in_7; 177439220Sgibbs call dfdat_in_7_continued; 177539220Sgibbs call dfdat_in_7_continued; 177639220Sgibbs jmp dfdat_in_7_continued; 177719164Sgibbsdfdat_in_7: 177839220Sgibbs mov DINDEX,SINDEX; 177919164Sgibbsdfdat_in_7_continued: 178039220Sgibbs mov DINDIR,DFDAT; 178139220Sgibbs mov DINDIR,DFDAT; 178239220Sgibbs mov DINDIR,DFDAT; 178339220Sgibbs mov DINDIR,DFDAT; 178439220Sgibbs mov DINDIR,DFDAT; 178539220Sgibbs mov DINDIR,DFDAT; 178639220Sgibbs mov DINDIR,DFDAT ret; 178739220Sgibbs } 178819164Sgibbs 178939220Sgibbs 179013177Sgibbs/* 179119164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 179219164Sgibbs * DMA and wait for it to acknowledge that it's off. 179313177Sgibbs */ 179419164Sgibbsdma_finish: 179523925Sgibbs test DFSTATUS,HDONE jz dma_finish; 179622234Sgibbs /* Turn off DMA */ 179723925Sgibbs and DFCNTRL, ~HDMAEN; 179823925Sgibbs test DFCNTRL, HDMAEN jnz .; 179923925Sgibbs ret; 18009928Sgibbs 180123925Sgibbsadd_scb_to_free_list: 180239220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 180339220Sgibbs mov SCB_NEXT, FREE_SCBH; 180439220Sgibbs mov FREE_SCBH, SCBPTR; 180539220Sgibbs } 180639220Sgibbs mvi SCB_TAG, SCB_LIST_NULL ret; 18074568Sgibbs 180839220Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) { 180919164Sgibbsget_free_or_disc_scb: 181023925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 181123925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 181219623Sgibbsreturn_error: 181323925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 181419623Sgibbsdequeue_disc_scb: 181523925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 181623925Sgibbsdma_up_scb: 181723925Sgibbs mvi DMAPARAMS, FIFORESET; 181823925Sgibbs mov SCB_TAG call dma_scb; 181919164Sgibbsunlink_disc_scb: 182039220Sgibbs mov DISCONNECTED_SCBH, SCB_NEXT ret; 182119164Sgibbsdequeue_free_scb: 182223925Sgibbs mov SCBPTR, FREE_SCBH; 182323925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 182439220Sgibbs} 18254568Sgibbs 182619164Sgibbsadd_scb_to_disc_list: 182713177Sgibbs/* 182819164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 182919164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 183019164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 183113177Sgibbs */ 183223925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 183339220Sgibbs mov DISCONNECTED_SCBH, SCBPTR ret; 1834