aic7xxx.seq revision 71717
126997Sgibbs/* 226997Sgibbs * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. 313177Sgibbs * 471717Sgibbs * Copyright (c) 1994-2001 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 1763457Sgibbs * 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 * 3171390Sgibbs * $Id: //depot/src/aic7xxx/aic7xxx.seq#16 $ 3265942Sgibbs * 3350477Speter * $FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 71717 2001-01-27 20:54:24Z gibbs $ 3426997Sgibbs */ 354568Sgibbs 3666268Sgibbs#include "aic7xxx.reg" 3766268Sgibbs#include "scsi_message.h" 385647Sgibbs 3913177Sgibbs/* 4019164Sgibbs * A few words on the waiting SCB list: 4119164Sgibbs * After starting the selection hardware, we check for reconnecting targets 4213690Sgibbs * as well as for our selection to complete just in case the reselection wins 4313690Sgibbs * bus arbitration. The problem with this is that we must keep track of the 4413690Sgibbs * SCB that we've already pulled from the QINFIFO and started the selection 4513690Sgibbs * on just in case the reselection wins so that we can retry the selection at 4613690Sgibbs * a later time. This problem cannot be resolved by holding a single entry 4713690Sgibbs * in scratch ram since a reconnecting target can request sense and this will 4813690Sgibbs * create yet another SCB waiting for selection. The solution used here is to 4913690Sgibbs * use byte 27 of the SCB as a psuedo-next pointer and to thread a list 5019164Sgibbs * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, 5119164Sgibbs * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to 5219164Sgibbs * this list everytime a request sense occurs or after completing a non-tagged 5319164Sgibbs * command for which a second SCB has been queued. The sequencer will 5419164Sgibbs * automatically consume the entries. 5513177Sgibbs */ 564568Sgibbs 5771390Sgibbsbus_free_sel: 5871390Sgibbs /* 5971390Sgibbs * Turn off the selection hardware. We need to reset the 6071390Sgibbs * selection request in order to perform a new selection. 6171390Sgibbs */ 6271390Sgibbs and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; 6371390Sgibbs and SIMODE1, ~ENBUSFREE; 6444507Sgibbspoll_for_work: 6523925Sgibbs call clear_target_state; 6639220Sgibbs and SXFRCTL0, ~SPIOEN; 6768623Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 6868623Sgibbs clr SCSIBUSL; 6968623Sgibbs } 7039220Sgibbspoll_for_work_loop: 7139220Sgibbs test SSTAT0, SELDO|SELDI jnz selection; 7258258Sgibbs test SCSISEQ, ENSELO jnz poll_for_work_loop; 7339220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 7439220Sgibbs /* 7539220Sgibbs * Twin channel devices cannot handle things like SELTO 7639220Sgibbs * interrupts on the "background" channel. So, if we 7739220Sgibbs * are selecting, keep polling the current channel util 7839220Sgibbs * either a selection or reselection occurs. 7939220Sgibbs */ 8039220Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 8139220Sgibbs test SSTAT0, SELDO|SELDI jnz selection; 8265942Sgibbs xor SBLKCTL,SELBUSB; /* Toggle back */ 8339220Sgibbs } 8423925Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 8519164Sgibbstest_queue: 8619164Sgibbs /* Has the driver posted any work for us? */ 8766647SgibbsBEGIN_CRITICAL 8839220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 8939220Sgibbs test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; 9039220Sgibbs } else { 9168087Sgibbs mov A, QINPOS; 9239220Sgibbs cmp KERNEL_QINPOS, A je poll_for_work_loop; 9339220Sgibbs } 9466647Sgibbs mov ARG_1, NEXT_QUEUED_SCB; 9566647SgibbsEND_CRITICAL 964568Sgibbs 9763457Sgibbs /* 9863457Sgibbs * We have at least one queued SCB now and we don't have any 9966647Sgibbs * SCBs in the list of SCBs awaiting selection. Allocate a 10066647Sgibbs * card SCB for the host's SCB and get to work on it. 10163457Sgibbs */ 10239220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 10339220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 10466647Sgibbs } else { 10539220Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 10666647Sgibbs mov SCBPTR, ARG_1; 10739220Sgibbs } 10819164Sgibbsdma_queued_scb: 10963457Sgibbs /* 11063457Sgibbs * DMA the SCB from host ram into the current SCB location. 11163457Sgibbs */ 11223925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 11366647Sgibbs mov ARG_1 call dma_scb; 11419164Sgibbs /* 11566647Sgibbs * Check one last time to see if this SCB was canceled 11666647Sgibbs * before we completed the DMA operation. If it was, 11766647Sgibbs * the QINFIFO next pointer will not match our saved 11866647Sgibbs * value. 11919164Sgibbs */ 12066647Sgibbs mov A, ARG_1; 12166647SgibbsBEGIN_CRITICAL 12266647Sgibbs cmp NEXT_QUEUED_SCB, A jne abort_qinscb; 12368087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 12468087Sgibbs cmp SCB_TAG, A je . + 2; 12568402Sgibbs mvi SCB_MISMATCH call set_seqint; 12668087Sgibbs } 12766647Sgibbs mov NEXT_QUEUED_SCB, SCB_NEXT; 12823925Sgibbs mov SCB_NEXT,WAITING_SCBH; 12923925Sgibbs mov WAITING_SCBH, SCBPTR; 13068402Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 13168402Sgibbs mov NONE, SNSCB_QOFF; 13268402Sgibbs } else { 13368402Sgibbs inc QINPOS; 13468402Sgibbs } 13566647SgibbsEND_CRITICAL 13623925Sgibbsstart_waiting: 13723925Sgibbs /* 13863457Sgibbs * Start the first entry on the waiting SCB list. 13923925Sgibbs */ 14023925Sgibbs mov SCBPTR, WAITING_SCBH; 14123925Sgibbs call start_selection; 14265942Sgibbs jmp poll_for_work_loop; 1438104Sgibbs 14466647Sgibbsabort_qinscb: 14566647Sgibbs call add_scb_to_free_list; 14666647Sgibbs jmp poll_for_work_loop; 14766647Sgibbs 14823925Sgibbsstart_selection: 14968579Sgibbs /* 15068579Sgibbs * If bus reset interrupts have been disabled (from a previous 15168579Sgibbs * reset), re-enable them now. Resets are only of interest 15268579Sgibbs * when we have outstanding transactions, so we can safely 15368579Sgibbs * defer re-enabling the interrupt until, as an initiator, 15468579Sgibbs * we start sending out transactions again. 15568579Sgibbs */ 15668579Sgibbs test SIMODE1, ENSCSIRST jnz . + 3; 15768579Sgibbs mvi CLRSINT1, CLRSCSIRSTI; 15868579Sgibbs or SIMODE1, ENSCSIRST; 15939220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 16039220Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ 16163457Sgibbs test SCB_SCSIID, TWIN_CHNLB jz . + 2; 16263457Sgibbs or SINDEX, SELBUSB; 16339220Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 16439220Sgibbs } 16523925Sgibbsinitialize_scsiid: 16663457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 16763457Sgibbs mov SCSIID_ULTRA2, SCB_SCSIID; 16863457Sgibbs } else if ((ahc->features & AHC_TWIN) != 0) { 16963457Sgibbs and SCSIID, TWIN_TID|OID, SCB_SCSIID; 17063457Sgibbs } else { 17163457Sgibbs mov SCSIID, SCB_SCSIID; 17263457Sgibbs } 17368087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 17463457Sgibbs mov SINDEX, SCSISEQ_TEMPLATE; 17563457Sgibbs test SCB_CONTROL, TARGET_SCB jz . + 2; 17644507Sgibbs or SINDEX, TEMODE; 17763457Sgibbs mov SCSISEQ, SINDEX ret; 17839220Sgibbs } else { 17963457Sgibbs mov SCSISEQ, SCSISEQ_TEMPLATE ret; 18039220Sgibbs } 18139220Sgibbs 18213177Sgibbs/* 18339220Sgibbs * Initialize transfer settings and clear the SCSI channel. 18439220Sgibbs * SINDEX should contain any additional bit's the client wants 18539220Sgibbs * set in SXFRCTL0. We also assume that the current SCB is 18639220Sgibbs * a valid SCB for the target we wish to talk to. 18739220Sgibbs */ 18839220Sgibbsinitialize_channel: 18968087Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 19039220Sgibbsset_transfer_settings: 19139220Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 19239220Sgibbs test SCB_CONTROL, ULTRAENB jz . + 2; 19339220Sgibbs or SXFRCTL0, FAST20; 19439220Sgibbs } 19563457Sgibbs /* 19663457Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 19763457Sgibbs */ 19839220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 19939220Sgibbs bmov SCSIRATE, SCB_SCSIRATE, 2 ret; 20039220Sgibbs } else { 20139220Sgibbs mov SCSIRATE, SCB_SCSIRATE ret; 20239220Sgibbs } 20339220Sgibbs 20439220Sgibbsselection: 20563457Sgibbs /* 20663457Sgibbs * We aren't expecting a bus free, so interrupt 20763457Sgibbs * the kernel driver if it happens. 20863457Sgibbs */ 20963457Sgibbs mvi CLRSINT1,CLRBUSFREE; 21063457Sgibbs or SIMODE1, ENBUSFREE; 21163457Sgibbs 21268579Sgibbs /* 21368579Sgibbs * Guard against a bus free after (re)selection 21468579Sgibbs * but prior to enabling the busfree interrupt. SELDI 21568579Sgibbs * and SELDO will be cleared in that case. 21668579Sgibbs */ 21771390Sgibbs test SSTAT0, SELDI|SELDO jz bus_free_sel; 21839220Sgibbs test SSTAT0,SELDO jnz select_out; 21939220Sgibbsselect_in: 22068087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 22168087Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 22241646Sgibbs test SSTAT0, TARGET jz initiator_reselect; 22341646Sgibbs } 22471390Sgibbs mvi CLRSINT0, CLRSELDI; 22542652Sgibbs 22639220Sgibbs /* 22739220Sgibbs * We've just been selected. Assert BSY and 22839220Sgibbs * setup the phase for receiving messages 22939220Sgibbs * from the target. 23068579Sgibbs * 23168579Sgibbs * If bus reset interrupts have been disabled (from a 23268579Sgibbs * previous reset), re-enable them now. Resets are only 23368579Sgibbs * of interest when we have outstanding transactions, so 23468579Sgibbs * we can safely defer re-enabling the interrupt until, 23568579Sgibbs * as a target, we start receiving transactions again. 23639220Sgibbs */ 23768579Sgibbs test SIMODE1, ENSCSIRST jnz . + 3; 23868579Sgibbs mvi CLRSINT1, CLRSCSIRSTI; 23968579Sgibbs or SIMODE1, ENSCSIRST; 24039220Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 24139220Sgibbs 24239220Sgibbs /* 24339220Sgibbs * Setup the DMA for sending the identify and 24441299Sgibbs * command information. 24539220Sgibbs */ 24639220Sgibbs or SEQ_FLAGS, CMDPHASE_PENDING; 24741299Sgibbs 24841299Sgibbs mov A, TQINPOS; 24939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 25039220Sgibbs mvi DINDEX, CCHADDR; 25163457Sgibbs mvi SHARED_DATA_ADDR call set_32byte_addr; 25239220Sgibbs mvi CCSCBCTL, CCSCBRESET; 25339220Sgibbs } else { 25439220Sgibbs mvi DINDEX, HADDR; 25563457Sgibbs mvi SHARED_DATA_ADDR call set_32byte_addr; 25639220Sgibbs mvi DFCNTRL, FIFORESET; 25739220Sgibbs } 25839220Sgibbs 25939220Sgibbs /* Initiator that selected us */ 26063457Sgibbs and SAVED_SCSIID, SELID_MASK, SELID; 26163457Sgibbs /* The Target ID we were selected at */ 26263457Sgibbs if ((ahc->features & AHC_MULTI_TID) != 0) { 26363457Sgibbs and A, OID, TARGIDIN; 26463457Sgibbs } else if ((ahc->features & AHC_ULTRA2) != 0) { 26563457Sgibbs and A, OID, SCSIID_ULTRA2; 26639220Sgibbs } else { 26763457Sgibbs and A, OID, SCSIID; 26839220Sgibbs } 26963457Sgibbs or SAVED_SCSIID, A; 27063457Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 27163457Sgibbs test SBLKCTL, SELBUSB jz . + 2; 27263457Sgibbs or SAVED_SCSIID, TWIN_CHNLB; 27363457Sgibbs } 27444507Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 27563457Sgibbs mov CCSCBRAM, SAVED_SCSIID; 27639220Sgibbs } else { 27763457Sgibbs mov DFDAT, SAVED_SCSIID; 27839220Sgibbs } 27939220Sgibbs 28039220Sgibbs /* 28139220Sgibbs * If ATN isn't asserted, the target isn't interested 28239220Sgibbs * in talking to us. Go directly to bus free. 28363457Sgibbs * XXX SCSI-1 may require us to assume lun 0 if 28463457Sgibbs * ATN is false. 28539220Sgibbs */ 28639220Sgibbs test SCSISIGI, ATNI jz target_busfree; 28739220Sgibbs 28839220Sgibbs /* 28939220Sgibbs * Watch ATN closely now as we pull in messages from the 29039220Sgibbs * initiator. We follow the guidlines from section 6.5 29139220Sgibbs * of the SCSI-2 spec for what messages are allowed when. 29239220Sgibbs */ 29341646Sgibbs call target_inb; 29439220Sgibbs 29539220Sgibbs /* 29639220Sgibbs * Our first message must be one of IDENTIFY, ABORT, or 29739220Sgibbs * BUS_DEVICE_RESET. 29839220Sgibbs */ 29942652Sgibbs test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; 30039220Sgibbs /* Store for host */ 30139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 30239220Sgibbs mov CCSCBRAM, DINDEX; 30339220Sgibbs } else { 30439220Sgibbs mov DFDAT, DINDEX; 30539220Sgibbs } 30639220Sgibbs 30739220Sgibbs /* Remember for disconnection decision */ 30839220Sgibbs test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; 30939220Sgibbs /* XXX Honor per target settings too */ 31039220Sgibbs or SEQ_FLAGS, NO_DISCONNECT; 31139220Sgibbs 31239220Sgibbs test SCSISIGI, ATNI jz ident_messages_done; 31341646Sgibbs call target_inb; 31439220Sgibbs /* 31539220Sgibbs * If this is a tagged request, the tagged message must 31639220Sgibbs * immediately follow the identify. We test for a valid 31739220Sgibbs * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and 31839220Sgibbs * < MSG_IGN_WIDE_RESIDUE. 31939220Sgibbs */ 32039220Sgibbs add A, -MSG_SIMPLE_Q_TAG, DINDEX; 32139220Sgibbs jnc ident_messages_done; 32239220Sgibbs add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; 32339220Sgibbs jc ident_messages_done; 32439220Sgibbs /* Store for host */ 32539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 32639220Sgibbs mov CCSCBRAM, DINDEX; 32739220Sgibbs } else { 32839220Sgibbs mov DFDAT, DINDEX; 32939220Sgibbs } 33039220Sgibbs 33139220Sgibbs /* 33239220Sgibbs * If the initiator doesn't feel like providing a tag number, 33339220Sgibbs * we've got a failed selection and must transition to bus 33439220Sgibbs * free. 33539220Sgibbs */ 33639220Sgibbs test SCSISIGI, ATNI jz target_busfree; 33742652Sgibbs 33839220Sgibbs /* 33939220Sgibbs * Store the tag for the host. 34039220Sgibbs */ 34141646Sgibbs call target_inb; 34239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 34339220Sgibbs mov CCSCBRAM, DINDEX; 34439220Sgibbs } else { 34539220Sgibbs mov DFDAT, DINDEX; 34639220Sgibbs } 34742652Sgibbs mov INITIATOR_TAG, DINDEX; 34863457Sgibbs or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; 34963457Sgibbs test SCSISIGI, ATNI jz . + 2; 35063457Sgibbs /* Initiator still wants to give us messages */ 35163457Sgibbs call target_inb; 35239220Sgibbs jmp ident_messages_done; 35339220Sgibbs 35441646Sgibbs /* 35541646Sgibbs * Pushed message loop to allow the kernel to 35642652Sgibbs * run it's own target mode message state engine. 35741646Sgibbs */ 35841646Sgibbshost_target_message_loop: 35968402Sgibbs mvi HOST_MSG_LOOP call set_seqint; 36041646Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; 36141646Sgibbs test SSTAT0, SPIORDY jz .; 36241646Sgibbs jmp host_target_message_loop; 36341646Sgibbs 36439220Sgibbsident_messages_done: 36544507Sgibbs /* If ring buffer is full, return busy or queue full */ 36658258Sgibbs if ((ahc->features & AHC_HS_MAILBOX) != 0) { 36758258Sgibbs and A, HOST_TQINPOS, HS_MAILBOX; 36858258Sgibbs } else { 36958258Sgibbs mov A, KERNEL_TQINPOS; 37058258Sgibbs } 37144507Sgibbs cmp TQINPOS, A jne tqinfifo_has_space; 37244507Sgibbs mvi P_STATUS|BSYO call change_phase; 37368087Sgibbs test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; 37444507Sgibbs mvi STATUS_QUEUE_FULL call target_outb; 37544507Sgibbs jmp target_busfree_wait; 37644507Sgibbs mvi STATUS_BUSY call target_outb; 37744507Sgibbs jmp target_busfree_wait; 37844507Sgibbstqinfifo_has_space: 37939220Sgibbs /* Terminate the ident list */ 38039220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 38139220Sgibbs mvi CCSCBRAM, SCB_LIST_NULL; 38239220Sgibbs } else { 38339220Sgibbs mvi DFDAT, SCB_LIST_NULL; 38439220Sgibbs } 38542652Sgibbs or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN; 38663457Sgibbs test SCSISIGI, ATNI jnz target_mesgout_pending; 38739220Sgibbs jmp target_ITloop; 38839220Sgibbs 38939220Sgibbs/* 39039220Sgibbs * We carefully toggle SPIOEN to allow us to return the 39139220Sgibbs * message byte we receive so it can be checked prior to 39239220Sgibbs * driving REQ on the bus for the next byte. 39339220Sgibbs */ 39441646Sgibbstarget_inb: 39541646Sgibbs /* 39641646Sgibbs * Drive REQ on the bus by enabling SCSI PIO. 39741646Sgibbs */ 39839220Sgibbs or SXFRCTL0, SPIOEN; 39939220Sgibbs /* Wait for the byte */ 40039220Sgibbs test SSTAT0, SPIORDY jz .; 40139220Sgibbs /* Prevent our read from triggering another REQ */ 40239220Sgibbs and SXFRCTL0, ~SPIOEN; 40341646Sgibbs /* Save latched contents */ 40439220Sgibbs mov DINDEX, SCSIDATL ret; 40539220Sgibbs } 40639220Sgibbs 40768087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 40839220Sgibbs/* 40923925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 41023925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 41113177Sgibbs */ 41239220Sgibbsinitiator_reselect: 41323925Sgibbs /* XXX test for and handle ONE BIT condition */ 41471390Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 41563457Sgibbs and SAVED_SCSIID, SELID_MASK, SELID; 41663457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 41763457Sgibbs and A, OID, SCSIID_ULTRA2; 41863457Sgibbs } else { 41963457Sgibbs and A, OID, SCSIID; 42063457Sgibbs } 42163457Sgibbs or SAVED_SCSIID, A; 42239545Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 42339545Sgibbs test SBLKCTL, SELBUSB jz . + 2; 42463457Sgibbs or SAVED_SCSIID, TWIN_CHNLB; 42539545Sgibbs } 42671390Sgibbs mvi CLRSINT0, CLRSELDI; 42739220Sgibbs jmp ITloop; 42841646Sgibbs} 4294568Sgibbs 43013177Sgibbs/* 43123925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 43223925Sgibbs * list. This is achieved by simply moving our "next" pointer into 43323925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 43423925Sgibbs * SCB is used, so don't bother with it now. 43523925Sgibbs */ 43639220Sgibbsselect_out: 43725005Sgibbs /* Turn off the selection hardware */ 43858258Sgibbs and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; 43925005Sgibbs mvi CLRSINT0, CLRSELDO; 44025005Sgibbs mov SCBPTR, WAITING_SCBH; 44124914Sgibbs mov WAITING_SCBH,SCB_NEXT; 44263457Sgibbs mov SAVED_SCSIID, SCB_SCSIID; 44363457Sgibbs mov SAVED_LUN, SCB_LUN; 44468087Sgibbs call initialize_channel; 44568087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 44639220Sgibbs test SSTAT0, TARGET jz initiator_select; 4478567Sdg 44839220Sgibbs /* 44939220Sgibbs * We've just re-selected an initiator. 45039220Sgibbs * Assert BSY and setup the phase for 45139220Sgibbs * sending our identify messages. 45239220Sgibbs */ 45341646Sgibbs mvi P_MESGIN|BSYO call change_phase; 4544568Sgibbs 45539220Sgibbs /* 45639220Sgibbs * Start out with a simple identify message. 45739220Sgibbs */ 45863457Sgibbs or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; 4596608Sgibbs 46039220Sgibbs /* 46139220Sgibbs * If we are the result of a tagged command, send 46239220Sgibbs * a simple Q tag and the tag id. 46339220Sgibbs */ 46439220Sgibbs test SCB_CONTROL, TAG_ENB jz . + 3; 46539220Sgibbs mvi MSG_SIMPLE_Q_TAG call target_outb; 46663457Sgibbs mov SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb; 46739220Sgibbstarget_synccmd: 46839220Sgibbs /* 46939220Sgibbs * Now determine what phases the host wants us 47039220Sgibbs * to go through. 47139220Sgibbs */ 47263457Sgibbs mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; 47342652Sgibbs 47439220Sgibbstarget_ITloop: 47539220Sgibbs /* 47641646Sgibbs * Start honoring ATN signals now that 47744507Sgibbs * we properly identified ourselves. 47839220Sgibbs */ 47941646Sgibbs test SCSISIGI, ATNI jnz target_mesgout; 48039220Sgibbs test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; 48139220Sgibbs test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; 48239220Sgibbs test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; 48339220Sgibbs 48439220Sgibbs /* 48539220Sgibbs * No more work to do. Either disconnect or not depending 48639220Sgibbs * on the state of NO_DISCONNECT. 48739220Sgibbs */ 48839220Sgibbs test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 48939220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 49039220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 49139220Sgibbs } 49241646Sgibbs mov RETURN_1, ALLZEROS; 49339220Sgibbs call complete_target_cmd; 49441646Sgibbs cmp RETURN_1, CONT_MSG_LOOP jne .; 49539220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 49639220Sgibbs mov SCB_TAG call dma_scb; 49739220Sgibbs jmp target_synccmd; 49839220Sgibbs 49941646Sgibbstarget_mesgout: 50041646Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 50163457Sgibbstarget_mesgout_continue: 50241646Sgibbs call target_inb; 50363457Sgibbstarget_mesgout_pending: 50441646Sgibbs /* Local Processing goes here... */ 50541646Sgibbs jmp host_target_message_loop; 50641646Sgibbs 50739220Sgibbstarget_disconnect: 50841646Sgibbs mvi P_MESGIN|BSYO call change_phase; 50941816Sgibbs test SEQ_FLAGS, DPHASE jz . + 2; 51041816Sgibbs mvi MSG_SAVEDATAPOINTER call target_outb; 51139220Sgibbs mvi MSG_DISCONNECT call target_outb; 51239220Sgibbs 51343880Sgibbstarget_busfree_wait: 51443880Sgibbs /* Wait for preceeding I/O session to complete. */ 51543880Sgibbs test SCSISIGI, ACKI jnz .; 51639220Sgibbstarget_busfree: 51763457Sgibbs and SIMODE1, ~ENBUSFREE; 51868623Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 51968623Sgibbs clr SCSIBUSL; 52068623Sgibbs } 52139220Sgibbs clr SCSISIGO; 52257099Sgibbs mvi LASTPHASE, P_BUSFREE; 52339220Sgibbs call complete_target_cmd; 52439220Sgibbs jmp poll_for_work; 52539220Sgibbs 52639220Sgibbstarget_cmdphase: 52741646Sgibbs mvi P_COMMAND|BSYO call change_phase; 52841646Sgibbs call target_inb; 52939220Sgibbs mov A, DINDEX; 53039220Sgibbs /* Store for host */ 53139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 53239220Sgibbs mov CCSCBRAM, A; 53339220Sgibbs } else { 53439220Sgibbs mov DFDAT, A; 53539220Sgibbs } 53639220Sgibbs 53739220Sgibbs /* 53839220Sgibbs * Determine the number of bytes to read 53941299Sgibbs * based on the command group code via table lookup. 54041299Sgibbs * We reuse the first 8 bytes of the TARG_SCSIRATE 54141299Sgibbs * BIOS array for this table. Count is one less than 54241299Sgibbs * the total for the command since we've already fetched 54341299Sgibbs * the first byte. 54439220Sgibbs */ 54539220Sgibbs shr A, CMD_GROUP_CODE_SHIFT; 54668087Sgibbs add SINDEX, CMDSIZE_TABLE, A; 54739220Sgibbs mov A, SINDIR; 54839220Sgibbs 54939220Sgibbs test A, 0xFF jz command_phase_done; 55071390Sgibbs or SXFRCTL0, SPIOEN; 55139220Sgibbscommand_loop: 55239220Sgibbs test SSTAT0, SPIORDY jz .; 55339220Sgibbs cmp A, 1 jne . + 2; 55439220Sgibbs and SXFRCTL0, ~SPIOEN; /* Last Byte */ 55539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 55639220Sgibbs mov CCSCBRAM, SCSIDATL; 55739220Sgibbs } else { 55839220Sgibbs mov DFDAT, SCSIDATL; 55939220Sgibbs } 56039220Sgibbs dec A; 56139220Sgibbs test A, 0xFF jnz command_loop; 56239220Sgibbs 56339220Sgibbscommand_phase_done: 56439220Sgibbs and SEQ_FLAGS, ~CMDPHASE_PENDING; 56539220Sgibbs jmp target_ITloop; 56639220Sgibbs 56739220Sgibbstarget_dphase: 56839220Sgibbs /* 56963457Sgibbs * Data phases on the bus are from the 57063457Sgibbs * perspective of the initiator. The dma 57163457Sgibbs * code looks at LASTPHASE to determine the 57263457Sgibbs * data direction of the DMA. Toggle it for 57363457Sgibbs * target transfers. 57439220Sgibbs */ 57563457Sgibbs xor LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR]; 57663457Sgibbs or SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO 57763457Sgibbs call change_phase; 57839220Sgibbs jmp p_data; 57939220Sgibbs 58039220Sgibbstarget_sphase: 58141646Sgibbs mvi P_STATUS|BSYO call change_phase; 58241646Sgibbs mvi LASTPHASE, P_STATUS; 58363457Sgibbs mov SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb; 58441646Sgibbs /* XXX Watch for ATN or parity errors??? */ 58539220Sgibbs mvi SCSISIGO, P_MESGIN|BSYO; 58639220Sgibbs /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ 58739220Sgibbs mov ALLZEROS call target_outb; 58843880Sgibbs jmp target_busfree_wait; 58939220Sgibbs 59039220Sgibbscomplete_target_cmd: 59139220Sgibbs test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; 59239220Sgibbs mov SCB_TAG jmp complete_post; 59339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 59441299Sgibbs /* Set the valid byte */ 59541299Sgibbs mvi CCSCBADDR, 24; 59641299Sgibbs mov CCSCBRAM, ALLONES; 59741299Sgibbs mvi CCHCNT, 28; 59839220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 59939220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 60039220Sgibbs clr CCSCBCTL; 60139220Sgibbs } else { 60241299Sgibbs /* Set the valid byte */ 60341299Sgibbs or DFCNTRL, FIFORESET; 60441299Sgibbs mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ 60541299Sgibbs mov DFDAT, ALLONES; 60663457Sgibbs mvi 28 call set_hcnt; 60739220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 60839220Sgibbs call dma_finish; 60939220Sgibbs } 61041299Sgibbs inc TQINPOS; 61141299Sgibbs mvi INTSTAT,CMDCMPLT ret; 61239220Sgibbs } 61341646Sgibbs 61468087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 61539220Sgibbsinitiator_select: 61641646Sgibbs /* 61741646Sgibbs * As soon as we get a successful selection, the target 61841646Sgibbs * should go into the message out phase since we have ATN 61941646Sgibbs * asserted. 62041646Sgibbs */ 62139220Sgibbs mvi MSG_OUT, MSG_IDENTIFYFLAG; 62239220Sgibbs or SEQ_FLAGS, IDENTIFY_SEEN; 62313177Sgibbs 62441646Sgibbs /* 62541646Sgibbs * Main loop for information transfer phases. Wait for the 62641646Sgibbs * target to assert REQ before checking MSG, C/D and I/O for 62741646Sgibbs * the bus phase. 62841646Sgibbs */ 62963457Sgibbsmesgin_phasemis: 6304568SgibbsITloop: 63139220Sgibbs call phase_lock; 6324568Sgibbs 63339220Sgibbs mov A, LASTPHASE; 6344568Sgibbs 63539220Sgibbs test A, ~P_DATAIN jz p_data; 63623925Sgibbs cmp A,P_COMMAND je p_command; 63723925Sgibbs cmp A,P_MESGOUT je p_mesgout; 63823925Sgibbs cmp A,P_STATUS je p_status; 63923925Sgibbs cmp A,P_MESGIN je p_mesgin; 6404568Sgibbs 64168402Sgibbs mvi BAD_PHASE call set_seqint; 64223925Sgibbs jmp ITloop; /* Try reading the bus again. */ 6434568Sgibbs 64423925Sgibbsawait_busfree: 64523925Sgibbs and SIMODE1, ~ENBUSFREE; 64623925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 64768623Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 64868623Sgibbs clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ 64968623Sgibbs } 65039220Sgibbs and SXFRCTL0, ~SPIOEN; 65123925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 65223925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 65368579Sgibbs mvi MISSED_BUSFREE call set_seqint; 65441646Sgibbs} 65523925Sgibbs 65623925Sgibbsclear_target_state: 65741646Sgibbs /* 65841646Sgibbs * We assume that the kernel driver may reset us 65941646Sgibbs * at any time, even in the middle of a DMA, so 66041646Sgibbs * clear DFCNTRL too. 66141646Sgibbs */ 66241646Sgibbs clr DFCNTRL; 66368087Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 66441646Sgibbs 66541646Sgibbs /* 66641646Sgibbs * We don't know the target we will connect to, 66741646Sgibbs * so default to narrow transfers to avoid 66841646Sgibbs * parity problems. 66941646Sgibbs */ 67041646Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 67141646Sgibbs bmov SCSIRATE, ALLZEROS, 2; 67241646Sgibbs } else { 67341646Sgibbs clr SCSIRATE; 67463457Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 67563457Sgibbs and SXFRCTL0, ~(FAST20); 67663457Sgibbs } 67741646Sgibbs } 67823925Sgibbs mvi LASTPHASE, P_BUSFREE; 67923925Sgibbs /* clear target specific flags */ 68039220Sgibbs clr SEQ_FLAGS ret; 68123925Sgibbs 68263457Sgibbssg_advance: 68363457Sgibbs clr A; /* add sizeof(struct scatter) */ 68463457Sgibbs add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; 68563457Sgibbs adc SCB_RESIDUAL_SGPTR[1],A; 68663457Sgibbs adc SCB_RESIDUAL_SGPTR[2],A; 68763457Sgibbs adc SCB_RESIDUAL_SGPTR[3],A ret; 68863457Sgibbs 68963457Sgibbsidle_loop: 69063457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 69163457Sgibbs /* Did we just finish fetching segs? */ 69263457Sgibbs cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; 69363457Sgibbs 69463457Sgibbs /* Are we actively fetching segments? */ 69563457Sgibbs test CCSGCTL, CCSGEN jnz return; 69663457Sgibbs 69763457Sgibbs /* 69863457Sgibbs * Do we need any more segments? 69963457Sgibbs */ 70063457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; 70163457Sgibbs 70263457Sgibbs /* 70363457Sgibbs * Do we have any prefetch left??? 70463457Sgibbs */ 70566647Sgibbs cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; 70663457Sgibbs 70763457Sgibbs /* 70863457Sgibbs * Need to fetch segments, but we can only do that 70963457Sgibbs * if the command channel is completely idle. Make 71063457Sgibbs * sure we don't have an SCB prefetch going on. 71163457Sgibbs */ 71263457Sgibbs test CCSCBCTL, CCSCBEN jnz return; 71363457Sgibbs 71463457Sgibbs /* 71566647Sgibbs * We fetch a "cacheline aligned" and sized amount of data 71666647Sgibbs * so we don't end up referencing a non-existant page. 71766647Sgibbs * Cacheline aligned is in quotes because the kernel will 71866647Sgibbs * set the prefetch amount to a reasonable level if the 71966647Sgibbs * cacheline size is unknown. 72063457Sgibbs */ 72166647Sgibbs mvi CCHCNT, SG_PREFETCH_CNT; 72266647Sgibbs and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; 72363457Sgibbs bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; 72463457Sgibbs mvi CCSGCTL, CCSGEN|CCSGRESET ret; 72563457Sgibbsidle_sgfetch_complete: 72663944Sgibbs clr CCSGCTL; 72763944Sgibbs test CCSGCTL, CCSGEN jnz .; 72866647Sgibbs and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; 72963457Sgibbsidle_sg_avail: 73063457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 73163457Sgibbs /* Does the hardware have space for another SG entry? */ 73263457Sgibbs test DFSTATUS, PRELOAD_AVAIL jz return; 73363457Sgibbs bmov HADDR, CCSGRAM, 4; 73463457Sgibbs bmov SINDEX, CCSGRAM, 1; 73563457Sgibbs test SINDEX, 0x1 jz . + 2; 73663457Sgibbs xor DATA_COUNT_ODD, 0x1; 73763457Sgibbs bmov HCNT[0], SINDEX, 1; 73863457Sgibbs bmov HCNT[1], CCSGRAM, 2; 73963457Sgibbs bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; 74063457Sgibbs call sg_advance; 74163457Sgibbs mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 74263457Sgibbs test DATA_COUNT_ODD, 0x1 jz . + 2; 74363457Sgibbs or SINDEX, ODD_SEG; 74463457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 74563457Sgibbs or SINDEX, LAST_SEG; 74663457Sgibbs mov SG_CACHE_PRE, SINDEX; 74763457Sgibbs /* Load the segment by writing DFCNTRL again */ 74863457Sgibbs mov DFCNTRL, DMAPARAMS; 74963457Sgibbs } 75063457Sgibbs ret; 75163457Sgibbs } 75263457Sgibbs 75365942Sgibbsif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 75413177Sgibbs/* 75565942Sgibbs * Calculate the trailing portion of this S/G segment that cannot 75665942Sgibbs * be transferred using memory write and invalidate PCI transactions. 75765942Sgibbs * XXX Can we optimize this for PCI writes only??? 75865942Sgibbs */ 75965942Sgibbscalc_mwi_residual: 76065942Sgibbs /* 76165942Sgibbs * If the ending address is on a cacheline boundary, 76265942Sgibbs * there is no need for an extra segment. 76365942Sgibbs */ 76465942Sgibbs mov A, HCNT[0]; 76565942Sgibbs add A, A, HADDR[0]; 76665942Sgibbs and A, CACHESIZE_MASK; 76765942Sgibbs test A, 0xFF jz return; 76865942Sgibbs 76965942Sgibbs /* 77065942Sgibbs * If the transfer is less than a cachline, 77165942Sgibbs * there is no need for an extra segment. 77265942Sgibbs */ 77365942Sgibbs test HCNT[1], 0xFF jnz calc_mwi_residual_final; 77465942Sgibbs test HCNT[2], 0xFF jnz calc_mwi_residual_final; 77565942Sgibbs add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; 77665942Sgibbs jnc return; 77765942Sgibbs 77865942Sgibbscalc_mwi_residual_final: 77965942Sgibbs mov MWI_RESIDUAL, A; 78065942Sgibbs not A; 78165942Sgibbs inc A; 78265942Sgibbs add HCNT[0], A; 78365942Sgibbs adc HCNT[1], -1; 78465942Sgibbs adc HCNT[2], -1 ret; 78565942Sgibbs} 78665942Sgibbs 78765942Sgibbs/* 78813177Sgibbs * If we re-enter the data phase after going through another phase, the 78913177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 79013177Sgibbs */ 7919928Sgibbsdata_phase_reinit: 79251471Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 79351471Sgibbs /* 79451471Sgibbs * The preload circuitry requires us to 79551471Sgibbs * reload the address too, so pull it from 79651471Sgibbs * the shaddow address. 79751471Sgibbs */ 79851471Sgibbs bmov HADDR, SHADDR, 4; 79963457Sgibbs bmov HCNT, SCB_RESIDUAL_DATACNT, 3; 80051471Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 80163457Sgibbs bmov STCNT, SCB_RESIDUAL_DATACNT, 3; 80239220Sgibbs } else { 80339220Sgibbs mvi DINDEX, STCNT; 80463457Sgibbs mvi SCB_RESIDUAL_DATACNT call bcopy_3; 80539220Sgibbs } 80663457Sgibbs and DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0]; 80723925Sgibbs jmp data_phase_loop; 8084568Sgibbs 80939220Sgibbsp_data: 81039220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 81139220Sgibbs mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; 81239220Sgibbs } else { 81339220Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 81439220Sgibbs } 81539220Sgibbs test LASTPHASE, IOI jnz . + 2; 81639220Sgibbs or DMAPARAMS, DIRECTION; 81723925Sgibbs call assert; /* 81819164Sgibbs * Ensure entering a data 81919164Sgibbs * phase is okay - seen identify, etc. 82019164Sgibbs */ 82139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 82263457Sgibbs /* We don't have any valid S/G elements */ 82366647Sgibbs mvi CCSGADDR, SG_PREFETCH_CNT; 82439220Sgibbs } 82523925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 8264568Sgibbs 82739220Sgibbs /* We have seen a data phase */ 82839220Sgibbs or SEQ_FLAGS, DPHASE; 82939220Sgibbs 83019164Sgibbs /* 83119164Sgibbs * Initialize the DMA address and counter from the SCB. 83263457Sgibbs * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG 83363457Sgibbs * flag in the highest byte of the data count. We cannot 83463457Sgibbs * modify the saved values in the SCB until we see a save 83563457Sgibbs * data pointers message. 83619164Sgibbs */ 83739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 83839220Sgibbs bmov HADDR, SCB_DATAPTR, 7; 83963457Sgibbs bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; 84039220Sgibbs } else { 84139220Sgibbs mvi DINDEX, HADDR; 84239220Sgibbs mvi SCB_DATAPTR call bcopy_7; 84363457Sgibbs mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; 84463457Sgibbs mvi SCB_DATACNT + 3 call bcopy_5; 84539220Sgibbs } 84665942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 84765942Sgibbs call calc_mwi_residual; 84865942Sgibbs } 84963457Sgibbs and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; 85065942Sgibbs and DATA_COUNT_ODD, 0x1, HCNT[0]; 85119164Sgibbs 85239220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 85339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 85439220Sgibbs bmov STCNT, HCNT, 3; 85539220Sgibbs } else { 85639220Sgibbs call set_stcnt_from_hcnt; 85739220Sgibbs } 85839220Sgibbs } 85919164Sgibbs 86063457Sgibbsdata_phase_loop: 86163457Sgibbs /* Guard against overruns */ 86263457Sgibbs test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; 86319164Sgibbs 86463457Sgibbs /* 86568087Sgibbs * Turn on `Bit Bucket' mode, wait until the target takes 86668087Sgibbs * us to another phase, and then notify the host. 86763457Sgibbs */ 86868087Sgibbs and DMAPARAMS, DIRECTION; 86968087Sgibbs mov DFCNTRL, DMAPARAMS; 87023925Sgibbs or SXFRCTL1,BITBUCKET; 87168087Sgibbs test SSTAT1,PHASEMIS jz .; 87268087Sgibbs and SXFRCTL1, ~BITBUCKET; 87368402Sgibbs mvi DATA_OVERRUN call set_seqint; 87468087Sgibbs jmp ITloop; 87568087Sgibbs 87616260Sgibbsdata_phase_inbounds: 87739220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 87863457Sgibbs mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 87963457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 88063457Sgibbs or SINDEX, LAST_SEG; 88163457Sgibbs test DATA_COUNT_ODD, 0x1 jz . + 2; 88263457Sgibbs or SINDEX, ODD_SEG; 88363457Sgibbs mov SG_CACHE_PRE, SINDEX; 88463457Sgibbs mov DFCNTRL, DMAPARAMS; 88563457Sgibbsultra2_dma_loop: 88663457Sgibbs call idle_loop; 88763457Sgibbs /* 88863457Sgibbs * The transfer is complete if either the last segment 88963457Sgibbs * completes or the target changes phase. 89063457Sgibbs */ 89163457Sgibbs test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; 89270204Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 89370204Sgibbs /* 89470204Sgibbs * As a target, we control the phases, 89570204Sgibbs * so ignore PHASEMIS. 89670204Sgibbs */ 89770204Sgibbs test SSTAT0, TARGET jnz ultra2_dma_loop; 89870204Sgibbs } 89970204Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 90070204Sgibbs test SSTAT1,PHASEMIS jz ultra2_dma_loop; 90170204Sgibbs } 90263457Sgibbs 90363457Sgibbsultra2_dmafinish: 90463457Sgibbs test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; 90563457Sgibbs and DFCNTRL, ~SCSIEN; 90663457Sgibbs test DFCNTRL, SCSIEN jnz .; 90763944Sgibbs if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 90863944Sgibbs test DFSTATUS, FIFOEMP jnz ultra2_dmafifoempty; 90963944Sgibbs } 91063457Sgibbsultra2_dmafifoflush: 91163457Sgibbs if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 91263457Sgibbs /* 91363457Sgibbs * On Rev A of the aic7890, the autoflush 91463457Sgibbs * features doesn't function correctly. 91563457Sgibbs * Perform an explicit manual flush. During 91663457Sgibbs * a manual flush, the FIFOEMP bit becomes 91763457Sgibbs * true every time the PCI FIFO empties 91863457Sgibbs * regardless of the state of the SCSI FIFO. 91963457Sgibbs * It can take up to 4 clock cycles for the 92063457Sgibbs * SCSI FIFO to get data into the PCI FIFO 92163457Sgibbs * and for FIFOEMP to de-assert. Here we 92263457Sgibbs * guard against this condition by making 92363457Sgibbs * sure the FIFOEMP bit stays on for 5 full 92463457Sgibbs * clock cycles. 92563457Sgibbs */ 92663457Sgibbs or DFCNTRL, FIFOFLUSH; 92763457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 92863457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 92963457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 93063457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 93163457Sgibbs } 93263457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 93363457Sgibbsultra2_dmafifoempty: 93463457Sgibbs /* Don't clobber an inprogress host data transfer */ 93563457Sgibbs test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; 93663457Sgibbsultra2_dmahalt: 93763457Sgibbs and DFCNTRL, ~(SCSIEN|HDMAEN); 93863457Sgibbs test DFCNTRL, HDMAEN jnz .; 93963457Sgibbs 94063457Sgibbs /* 94163944Sgibbs * If, by chance, we stopped before being able 94263944Sgibbs * to fetch additional segments for this transfer, 94363944Sgibbs * yet the last S/G was completely exhausted, 94463944Sgibbs * call our idle loop until it is able to load 94563944Sgibbs * another segment. This will allow us to immediately 94663944Sgibbs * pickup on the next segment on the next data phase. 94763944Sgibbs * 94863944Sgibbs * If we happened to stop on the last segment, then 94963944Sgibbs * our residual information is still correct from 95063944Sgibbs * the idle loop and there is no need to perform 95163944Sgibbs * any fixups. Just jump to data_phase_finish. 95263944Sgibbs */ 95363944Sgibbsultra2_ensure_sg: 95463944Sgibbs test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; 95563944Sgibbs /* Record if we've consumed all S/G entries */ 95663944Sgibbs test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; 95763944Sgibbs or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 95863944Sgibbs jmp data_phase_finish; 95963944Sgibbs 96063944Sgibbsultra2_shvalid: 96163944Sgibbs test SSTAT2, SHVALID jnz sgptr_fixup; 96263944Sgibbs call idle_loop; 96363944Sgibbs jmp ultra2_ensure_sg; 96463944Sgibbs 96563944Sgibbssgptr_fixup: 96663944Sgibbs /* 96763457Sgibbs * Fixup the residual next S/G pointer. The S/G preload 96863457Sgibbs * feature of the chip allows us to load two elements 96963457Sgibbs * in addition to the currently active element. We 97063457Sgibbs * store the bottom byte of the next S/G pointer in 97163457Sgibbs * the SG_CACEPTR register so we can restore the 97263457Sgibbs * correct value when the DMA completes. If the next 97363457Sgibbs * sg ptr value has advanced to the point where higher 97463457Sgibbs * bytes in the address have been affected, fix them 97563457Sgibbs * too. 97663457Sgibbs */ 97763457Sgibbs test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; 97863457Sgibbs test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; 97963457Sgibbs add SCB_RESIDUAL_SGPTR[1], -1; 98063457Sgibbs adc SCB_RESIDUAL_SGPTR[2], -1; 98163457Sgibbs adc SCB_RESIDUAL_SGPTR[3], -1; 98263457Sgibbssgptr_fixup_done: 98363457Sgibbs and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; 98463457Sgibbs clr DATA_COUNT_ODD; 98563457Sgibbs test SG_CACHE_SHADOW, ODD_SEG jz . + 2; 98663457Sgibbs or DATA_COUNT_ODD, 0x1; 98763944Sgibbs clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ 98839220Sgibbs } else { 98963457Sgibbs /* If we are the last SG block, tell the hardware. */ 99065942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 99165942Sgibbs && ahc->pci_cachesize != 0) { 99265942Sgibbs test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; 99365942Sgibbs } 99463457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; 99568087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 99663944Sgibbs test SSTAT0, TARGET jz dma_last_sg; 99763944Sgibbs if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { 99863944Sgibbs test DMAPARAMS, DIRECTION jz dma_mid_sg; 99963944Sgibbs } 100057099Sgibbs } 100163944Sgibbsdma_last_sg: 100239220Sgibbs and DMAPARAMS, ~WIDEODD; 100363457Sgibbsdma_mid_sg: 100463457Sgibbs /* Start DMA data transfer. */ 100539220Sgibbs mov DFCNTRL, DMAPARAMS; 100663457Sgibbsdma_loop: 100763457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 100863457Sgibbs call idle_loop; 100963457Sgibbs } 101063457Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 101163457Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 101263457Sgibbsdma_phasemis: 101339220Sgibbs /* 101463457Sgibbs * We will be "done" DMAing when the transfer count goes to 101563457Sgibbs * zero, or the target changes the phase (in light of this, 101663457Sgibbs * it makes sense that the DMA circuitry doesn't ACK when 101763457Sgibbs * PHASEMIS is active). If we are doing a SCSI->Host transfer, 101863457Sgibbs * the data FIFO should be flushed auto-magically on STCNT=0 101963457Sgibbs * or a phase change, so just wait for FIFO empty status. 102039220Sgibbs */ 102163457Sgibbsdma_checkfifo: 102263457Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 102363457Sgibbsdma_fifoflush: 102463457Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 102563457Sgibbsdma_fifoempty: 102663457Sgibbs /* Don't clobber an inprogress host data transfer */ 102763457Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 10284568Sgibbs 102939220Sgibbs /* 103063457Sgibbs * Now shut off the DMA and make sure that the DMA 103163457Sgibbs * hardware has actually stopped. Touching the DMA 103263457Sgibbs * counters, etc. while a DMA is active will result 103363457Sgibbs * in an ILLSADDR exception. 103439220Sgibbs */ 103563457Sgibbsdma_dmadone: 103663457Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 103763457Sgibbsdma_halt: 103863457Sgibbs /* 103965942Sgibbs * Some revisions of the aic78XX have a problem where, if the 104063457Sgibbs * data fifo is full, but the PCI input latch is not empty, 104163457Sgibbs * HDMAEN cannot be cleared. The fix used here is to drain 104263457Sgibbs * the prefetched but unused data from the data fifo until 104363457Sgibbs * there is space for the input latch to drain. 104463457Sgibbs */ 104565942Sgibbs if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 104665942Sgibbs mov NONE, DFDAT; 104765942Sgibbs } 104863457Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 104922568Sgibbs 105063457Sgibbs /* See if we have completed this last segment */ 105163457Sgibbs test STCNT[0], 0xff jnz data_phase_finish; 105263457Sgibbs test STCNT[1], 0xff jnz data_phase_finish; 105363457Sgibbs test STCNT[2], 0xff jnz data_phase_finish; 10549928Sgibbs 105539220Sgibbs /* 105663457Sgibbs * Advance the scatter-gather pointers if needed 105739220Sgibbs */ 105865942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 105965942Sgibbs && ahc->pci_cachesize != 0) { 106065942Sgibbs test MWI_RESIDUAL, 0xFF jz no_mwi_resid; 106165942Sgibbs /* 106265942Sgibbs * Reload HADDR from SHADDR and setup the 106365942Sgibbs * count to be the size of our residual. 106465942Sgibbs */ 106565942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 106665942Sgibbs bmov HADDR, SHADDR, 4; 106765942Sgibbs mov HCNT, MWI_RESIDUAL; 106865942Sgibbs bmov HCNT[1], ALLZEROS, 2; 106965942Sgibbs } else { 107065942Sgibbs mvi DINDEX, HADDR; 107165942Sgibbs mvi SHADDR call bcopy_4; 107265942Sgibbs mov MWI_RESIDUAL call set_hcnt; 107365942Sgibbs } 107465942Sgibbs clr MWI_RESIDUAL; 107565942Sgibbs jmp sg_load_done; 107665942Sgibbsno_mwi_resid: 107765942Sgibbs } 107863457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; 107963457Sgibbs or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 108063457Sgibbs jmp data_phase_finish; 108163457Sgibbssg_load: 108263457Sgibbs /* 108363457Sgibbs * Load the next SG element's data address and length 108463457Sgibbs * into the DMA engine. If we don't have hardware 108563457Sgibbs * to perform a prefetch, we'll have to fetch the 108663457Sgibbs * segment from host memory first. 108763457Sgibbs */ 108839220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 108963457Sgibbs /* Wait for the idle loop to complete */ 109063457Sgibbs test CCSGCTL, CCSGEN jz . + 3; 109163457Sgibbs call idle_loop; 109263457Sgibbs test CCSGCTL, CCSGEN jnz . - 1; 109363457Sgibbs bmov HADDR, CCSGRAM, 7; 109465942Sgibbs test CCSGRAM, SG_LAST_SEG jz . + 2; 109565942Sgibbs or SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG; 109639220Sgibbs } else { 109763457Sgibbs mvi DINDEX, HADDR; 109863457Sgibbs mvi SCB_RESIDUAL_SGPTR call bcopy_4; 109963457Sgibbs 110063457Sgibbs mvi SG_SIZEOF call set_hcnt; 110163457Sgibbs 110263457Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 110363457Sgibbs 110463457Sgibbs call dma_finish; 110563457Sgibbs 110665942Sgibbs mvi DINDEX, HADDR; 110765942Sgibbs call dfdat_in_7; 110863457Sgibbs mov SCB_RESIDUAL_DATACNT[3], DFDAT; 110965942Sgibbs } 111065942Sgibbs 111165942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 111265942Sgibbs && ahc->pci_cachesize != 0) { 111365942Sgibbs call calc_mwi_residual; 111465942Sgibbs } 111565942Sgibbs 111665942Sgibbs /* Point to the new next sg in memory */ 111765942Sgibbs call sg_advance; 111865942Sgibbs 111965942Sgibbssg_load_done: 112065942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 112165942Sgibbs bmov STCNT, HCNT, 3; 112265942Sgibbs } else { 112339220Sgibbs call set_stcnt_from_hcnt; 112439220Sgibbs } 112563457Sgibbs /* Track odd'ness */ 112663457Sgibbs test HCNT[0], 0x1 jz . + 2; 112763457Sgibbs xor DATA_COUNT_ODD, 0x1; 112839220Sgibbs 112968087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 113063457Sgibbs test SSTAT0, TARGET jnz data_phase_loop; 113163457Sgibbs } 113263457Sgibbs } 113363457Sgibbsdata_phase_finish: 113463457Sgibbs /* 113563457Sgibbs * If the target has left us in data phase, loop through 113663457Sgibbs * the dma code again. In the case of ULTRA2 adapters, 113763457Sgibbs * we should only loop if there is a data overrun. For 113863457Sgibbs * all other adapters, we'll loop after each S/G element 113963457Sgibbs * is loaded as well as if there is an overrun. 114063457Sgibbs */ 114168087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 114263457Sgibbs test SSTAT0, TARGET jnz data_phase_done; 114341646Sgibbs } 114468087Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 114563457Sgibbs test SSTAT1, REQINIT jz .; 114663457Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 114763457Sgibbs 114863457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 114963457Sgibbs /* Kill off any pending prefetch */ 115063457Sgibbs clr CCSGCTL; 115163457Sgibbs test CCSGCTL, CCSGEN jnz .; 115263457Sgibbs } 115339220Sgibbs } 11544568Sgibbs 115563457Sgibbsdata_phase_done: 115663457Sgibbs /* 115763457Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into 115863457Sgibbs * the SCB. We use STCNT instead of HCNT, since it's a reflection 115963457Sgibbs * of how many bytes were transferred on the SCSI (as opposed to the 116063457Sgibbs * host) bus. 116163457Sgibbs */ 116239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 116363457Sgibbs /* Kill off any pending prefetch */ 116463457Sgibbs clr CCSGCTL; 116563457Sgibbs test CCSGCTL, CCSGEN jnz .; 116665942Sgibbs } 116763457Sgibbs 116865942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 116965942Sgibbs && ahc->pci_cachesize != 0) { 117065942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 117165942Sgibbs test MWI_RESIDUAL, 0xFF jz bmov_resid; 117265942Sgibbs } 117365942Sgibbs mov A, MWI_RESIDUAL; 117465942Sgibbs add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; 117565942Sgibbs clr A; 117665942Sgibbs adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; 117765942Sgibbs adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; 117865942Sgibbs clr MWI_RESIDUAL; 117965942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 118065942Sgibbs jmp . + 2; 118165942Sgibbsbmov_resid: 118265942Sgibbs bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 118365942Sgibbs } 118465942Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 118563457Sgibbs bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 118639220Sgibbs } else { 118765942Sgibbs mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; 118865942Sgibbs mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; 118965942Sgibbs mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; 119039220Sgibbs } 119122568Sgibbs 119263457Sgibbs /* 119363457Sgibbs * Since we've been through a data phase, the SCB_RESID* fields 119463457Sgibbs * are now initialized. Clear the full residual flag. 119563457Sgibbs */ 119663457Sgibbs and SCB_SGPTR[0], ~SG_FULL_RESID; 119763457Sgibbs 119839220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 119963457Sgibbs /* Clear the channel in case we return to data phase later */ 120039220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 120168402Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 120239220Sgibbs } 120322568Sgibbs 120468087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 120541646Sgibbs test SEQ_FLAGS, DPHASE_PENDING jz ITloop; 120639220Sgibbs and SEQ_FLAGS, ~DPHASE_PENDING; 120742652Sgibbs /* 120842652Sgibbs * For data-in phases, wait for any pending acks from the 120942652Sgibbs * initiator before changing phase. 121042652Sgibbs */ 121142652Sgibbs test DFCNTRL, DIRECTION jz target_ITloop; 121242652Sgibbs test SSTAT1, REQINIT jnz .; 121339220Sgibbs jmp target_ITloop; 121463457Sgibbs } else { 121563457Sgibbs jmp ITloop; 121639220Sgibbs } 12174568Sgibbs 121868087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 121916260Sgibbs/* 122015328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 122113177Sgibbs */ 12224568Sgibbsp_command: 122323925Sgibbs call assert; 12244568Sgibbs 122563457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 122663457Sgibbs bmov HCNT[0], SCB_CDB_LEN, 1; 122739220Sgibbs bmov HCNT[1], ALLZEROS, 2; 122863944Sgibbs mvi SG_CACHE_PRE, LAST_SEG; 122963457Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 123063457Sgibbs bmov STCNT[0], SCB_CDB_LEN, 1; 123163457Sgibbs bmov STCNT[1], ALLZEROS, 2; 123239220Sgibbs } else { 123363457Sgibbs mov STCNT[0], SCB_CDB_LEN; 123463457Sgibbs clr STCNT[1]; 123563457Sgibbs clr STCNT[2]; 123639220Sgibbs } 123763457Sgibbs add NONE, -13, SCB_CDB_LEN; 123865942Sgibbs mvi SCB_CDB_STORE jnc p_command_embedded; 123963457Sgibbsp_command_from_host: 124063457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 124163457Sgibbs bmov HADDR[0], SCB_CDB_PTR, 4; 124263457Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); 124363457Sgibbs } else { 124463457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 124563457Sgibbs bmov HADDR[0], SCB_CDB_PTR, 4; 124665942Sgibbs bmov HCNT, STCNT, 3; 124763457Sgibbs } else { 124863457Sgibbs mvi DINDEX, HADDR; 124968087Sgibbs mvi SCB_CDB_PTR call bcopy_4; 125068087Sgibbs mov SCB_CDB_LEN call set_hcnt; 125139220Sgibbs } 125239220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); 125363457Sgibbs } 125463457Sgibbs jmp p_command_loop; 125563457Sgibbsp_command_embedded: 125663457Sgibbs /* 125763457Sgibbs * The data fifo seems to require 4 byte alligned 125863457Sgibbs * transfers from the sequencer. Force this to 125963457Sgibbs * be the case by clearing HADDR[0] even though 126063457Sgibbs * we aren't going to touch host memeory. 126163457Sgibbs */ 126263457Sgibbs clr HADDR[0]; 126363457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 126463457Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); 126563457Sgibbs bmov DFDAT, SCB_CDB_STORE, 12; 126665942Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 126771390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 126865942Sgibbs /* 126965942Sgibbs * On the 7895 the data FIFO will 127065942Sgibbs * get corrupted if you try to dump 127165942Sgibbs * data from external SCB memory into 127265942Sgibbs * the FIFO while it is enabled. So, 127365942Sgibbs * fill the fifo and then enable SCSI 127465942Sgibbs * transfers. 127565942Sgibbs */ 127665942Sgibbs mvi DFCNTRL, (DIRECTION|FIFORESET); 127765942Sgibbs } else { 127865942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 127965942Sgibbs } 128065942Sgibbs bmov DFDAT, SCB_CDB_STORE, 12; 128171390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 128265942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); 128365942Sgibbs } else { 128463821Sgibbs or DFCNTRL, FIFOFLUSH; 128563821Sgibbs } 128663457Sgibbs } else { 128765942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 128863821Sgibbs call copy_to_fifo_6; 128963821Sgibbs call copy_to_fifo_6; 129063821Sgibbs or DFCNTRL, FIFOFLUSH; 129163457Sgibbs } 129263457Sgibbsp_command_loop: 129339220Sgibbs test SSTAT0, SDONE jnz . + 2; 129463457Sgibbs test SSTAT1, PHASEMIS jz p_command_loop; 129555581Sgibbs /* 129655581Sgibbs * Wait for our ACK to go-away on it's own 129755581Sgibbs * instead of being killed by SCSIEN getting cleared. 129855581Sgibbs */ 129955581Sgibbs test SCSISIGI, ACKI jnz .; 130055581Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 130139220Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; 130268087Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 130368087Sgibbs /* Drop any residual from the S/G Preload queue */ 130468087Sgibbs or SXFRCTL0, CLRSTCNT; 130568087Sgibbs } 130623925Sgibbs jmp ITloop; 13074568Sgibbs 130813177Sgibbs/* 130913177Sgibbs * Status phase. Wait for the data byte to appear, then read it 131013177Sgibbs * and store it into the SCB. 131113177Sgibbs */ 13124568Sgibbsp_status: 131323925Sgibbs call assert; 131419803Sgibbs 131563457Sgibbs mov SCB_SCSI_STATUS, SCSIDATL; 131623925Sgibbs jmp ITloop; 13174568Sgibbs 131813177Sgibbs/* 131941646Sgibbs * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full 132041646Sgibbs * indentify message sequence and send it to the target. The host may 132141646Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB 132241646Sgibbs * control byte. This will cause us to interrupt the host and allow 132341646Sgibbs * it to handle the message phase completely on its own. If the bit 132441646Sgibbs * associated with this target is set, we will also interrupt the host, 132541646Sgibbs * thereby allowing it to send a message on the next selection regardless 132641646Sgibbs * of the transaction being sent. 132739220Sgibbs * 132839220Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. 132941646Sgibbs * This is done to allow the host to send messages outside of an identify 133039220Sgibbs * sequence while protecting the seqencer from testing the MK_MESSAGE bit 133139220Sgibbs * on an SCB that might not be for the current nexus. (For example, a 133239220Sgibbs * BDR message in responce to a bad reselection would leave us pointed to 133339220Sgibbs * an SCB that doesn't have anything to do with the current target). 133441646Sgibbs * 133539220Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, 133639220Sgibbs * bus device reset). 133739220Sgibbs * 133839220Sgibbs * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, 133939220Sgibbs * in case the target decides to put us in this phase for some strange 134039220Sgibbs * reason. 134113177Sgibbs */ 134241646Sgibbsp_mesgout_retry: 134341646Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 13444568Sgibbsp_mesgout: 134539220Sgibbs mov SINDEX, MSG_OUT; 134639220Sgibbs cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; 134741646Sgibbs test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; 134863457Sgibbs mov FUNCTION1, SCB_SCSIID; 134941646Sgibbs mov A, FUNCTION1; 135047414Sgibbs mov SINDEX, TARGET_MSG_REQUEST[0]; 135141646Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 135241646Sgibbs /* Second Channel uses high byte bits */ 135363457Sgibbs test SCB_SCSIID, TWIN_CHNLB jz . + 2; 135441646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 135541646Sgibbs } else if ((ahc->features & AHC_WIDE) != 0) { 135663457Sgibbs test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ 135741646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 135841646Sgibbs } 135941646Sgibbs test SINDEX, A jnz host_message_loop; 136039220Sgibbsp_mesgout_identify: 136163457Sgibbs or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; 136263457Sgibbs test SCB_CONTROL, DISCENB jnz . + 2; 136363457Sgibbs and SINDEX, ~DISCENB; 136413177Sgibbs/* 136539220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 136639220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 136713177Sgibbs */ 136839220Sgibbsp_mesgout_tag: 136939220Sgibbs test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; 137039220Sgibbs mov SCSIDATL, SINDEX; /* Send the identify message */ 137139220Sgibbs call phase_lock; 137239220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 137339220Sgibbs and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 137439220Sgibbs call phase_lock; 137539220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 137639220Sgibbs mov SCB_TAG jmp p_mesgout_onebyte; 137713177Sgibbs/* 137841646Sgibbs * Interrupt the driver, and allow it to handle this message 137941646Sgibbs * phase and any required retries. 138013177Sgibbs */ 138139220Sgibbsp_mesgout_from_host: 138239220Sgibbs cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; 138341646Sgibbs jmp host_message_loop; 138439220Sgibbs 138539220Sgibbsp_mesgout_onebyte: 138639220Sgibbs mvi CLRSINT1, CLRATNO; 138739220Sgibbs mov SCSIDATL, SINDEX; 138839220Sgibbs 138913177Sgibbs/* 139041646Sgibbs * If the next bus phase after ATN drops is message out, it means 139113177Sgibbs * that the target is requesting that the last message(s) be resent. 139213177Sgibbs */ 139339220Sgibbs call phase_lock; 139441646Sgibbs cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; 13954568Sgibbs 139619906Sgibbsp_mesgout_done: 139723925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 139839220Sgibbs mov LAST_MSG, MSG_OUT; 139939220Sgibbs mvi MSG_OUT, MSG_NOOP; /* No message left */ 140023925Sgibbs jmp ITloop; 14014568Sgibbs 140213177Sgibbs/* 140313177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 140413177Sgibbs */ 14054568Sgibbsp_mesgin: 140623925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 14074568Sgibbs 140823925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 140923925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 141023925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 141123925Sgibbs cmp ALLZEROS,A je mesgin_complete; 141223925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 141363457Sgibbs cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; 141423925Sgibbs cmp A,MSG_NOOP je mesgin_done; 14154568Sgibbs 141613177Sgibbs/* 141741887Sgibbs * Pushed message loop to allow the kernel to 141857099Sgibbs * run it's own message state engine. To avoid an 141941887Sgibbs * extra nop instruction after signaling the kernel, 142041887Sgibbs * we perform the phase_lock before checking to see 142141887Sgibbs * if we should exit the loop and skip the phase_lock 142241887Sgibbs * in the ITloop. Performing back to back phase_locks 142341887Sgibbs * shouldn't hurt, but why do it twice... 142413177Sgibbs */ 142541887Sgibbshost_message_loop: 142668402Sgibbs mvi HOST_MSG_LOOP call set_seqint; 142741887Sgibbs call phase_lock; 142841887Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; 142941887Sgibbs jmp host_message_loop; 14309954Sgibbs 143163457Sgibbsmesgin_ign_wide_residue: 143263457Sgibbsif ((ahc->features & AHC_WIDE) != 0) { 143363457Sgibbs test SCSIRATE, WIDEXFER jz mesgin_reject; 143463457Sgibbs /* Pull the residue byte */ 143563457Sgibbs mvi ARG_1 call inb_next; 143663457Sgibbs cmp ARG_1, 0x01 jne mesgin_reject; 143763457Sgibbs test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; 143863457Sgibbs test DATA_COUNT_ODD, 0x1 jz mesgin_done; 143968402Sgibbs mvi IGN_WIDE_RES call set_seqint; 144063457Sgibbs jmp mesgin_done; 144163457Sgibbs} 144263457Sgibbs 144363457Sgibbsmesgin_reject: 144463457Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 14459954Sgibbsmesgin_done: 144623925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 144723925Sgibbs jmp ITloop; 14489954Sgibbs 14499954Sgibbsmesgin_complete: 145013177Sgibbs/* 145163457Sgibbs * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, 145219164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 145339220Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0). 145439220Sgibbs * In either of these conditions, we upload the SCB back to the host so it can 145519164Sgibbs * process this information. In the case of a non zero status byte, we 145619164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 145719164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 145868087Sgibbs * sense, it will fill the kernel SCB with a request sense command, requeue 145968087Sgibbs * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 146068087Sgibbs * RETURN_1 to SEND_SENSE. 146113177Sgibbs */ 146219164Sgibbs 146313177Sgibbs/* 146468579Sgibbs * If ATN is raised, we still want to give the target a message. 146568579Sgibbs * Perhaps there was a parity error on this last message byte. 146668579Sgibbs * Either way, the target should take us to message out phase 146768579Sgibbs * and then attempt to complete the command again. 146868579Sgibbs * XXX - Need a critical section to do this corrctly. Wait until 146968579Sgibbs * we queue completions. 147068579Sgibbs test SCSISIGI, ATNI jnz mesgin_done; 147168579Sgibbs */ 147268579Sgibbs 147368579Sgibbs/* 147468402Sgibbs * See if we attempted to deliver a message but the target ingnored us. 147513177Sgibbs */ 147668402Sgibbs test SCB_CONTROL, MK_MESSAGE jz . + 2; 147768402Sgibbs mvi MKMSG_FAILED call set_seqint; 147868402Sgibbs 147968402Sgibbs/* 148068402Sgibbs * Check for residuals 148168402Sgibbs */ 148263457Sgibbs test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ 148363457Sgibbs test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ 148463457Sgibbs test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; 148563457Sgibbscheck_status: 148663457Sgibbs test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ 148719164Sgibbsupload_scb: 148863457Sgibbs or SCB_SGPTR, SG_RESID_VALID; 148923925Sgibbs mvi DMAPARAMS, FIFORESET; 149023925Sgibbs mov SCB_TAG call dma_scb; 149163457Sgibbs test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ 149268402Sgibbs mvi BAD_STATUS call set_seqint; /* let driver know */ 149339220Sgibbs cmp RETURN_1, SEND_SENSE jne complete; 149468087Sgibbs call add_scb_to_free_list; 149523925Sgibbs jmp await_busfree; 149639220Sgibbscomplete: 149739220Sgibbs mov SCB_TAG call complete_post; 149823925Sgibbs jmp await_busfree; 149941646Sgibbs} 15004568Sgibbs 150139220Sgibbscomplete_post: 150239220Sgibbs /* Post the SCBID in SINDEX and issue an interrupt */ 150344507Sgibbs call add_scb_to_free_list; 150439220Sgibbs mov ARG_1, SINDEX; 150539220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 150639220Sgibbs mov A, SDSCB_QOFF; 150739220Sgibbs } else { 150839220Sgibbs mov A, QOUTPOS; 150939220Sgibbs } 151039220Sgibbs mvi QOUTFIFO_OFFSET call post_byte_setup; 151139220Sgibbs mov ARG_1 call post_byte; 151239220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) == 0) { 151339220Sgibbs inc QOUTPOS; 151439220Sgibbs } 151539220Sgibbs mvi INTSTAT,CMDCMPLT ret; 151639220Sgibbs 151768087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 151813177Sgibbs/* 151913177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 152063457Sgibbs * and await the bus going free. If this is an untagged transaction 152163457Sgibbs * store the SCB id for it in our untagged target table for lookup on 152263457Sgibbs * a reselction. 152313177Sgibbs */ 15249954Sgibbsmesgin_disconnect: 152568579Sgibbs /* 152668579Sgibbs * If ATN is raised, we still want to give the target a message. 152768579Sgibbs * Perhaps there was a parity error on this last message byte 152868579Sgibbs * or we want to abort this command. Either way, the target 152968579Sgibbs * should take us to message out phase and then attempt to 153068579Sgibbs * disconnect again. 153168579Sgibbs * XXX - Wait for more testing. 153268579Sgibbs test SCSISIGI, ATNI jnz mesgin_done; 153368579Sgibbs */ 153468579Sgibbs 153523925Sgibbs or SCB_CONTROL,DISCONNECTED; 153663457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 153763457Sgibbs call add_scb_to_disc_list; 153863457Sgibbs } 153963457Sgibbs test SCB_CONTROL, TAG_ENB jnz await_busfree; 154063457Sgibbs mov ARG_1, SCB_TAG; 154163457Sgibbs mov SAVED_LUN, SCB_LUN; 154268087Sgibbs mov SCB_SCSIID call set_busy_target; 154323925Sgibbs jmp await_busfree; 154419164Sgibbs 154515328Sgibbs/* 154619164Sgibbs * Save data pointers message: 154719164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 154819164Sgibbs * only if we've actually been into a data phase to change them. This 154919164Sgibbs * protects against bogus data in scratch ram and the residual counts 155019164Sgibbs * since they are only initialized when we go into data_in or data_out. 155115328Sgibbs */ 155219164Sgibbsmesgin_sdptrs: 155323925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 15544568Sgibbs 155539220Sgibbs /* 155663457Sgibbs * The SCB_SGPTR becomes the next one we'll download, 155763457Sgibbs * and the SCB_DATAPTR becomes the current SHADDR. 155839220Sgibbs * Use the residual number since STCNT is corrupted by 155939220Sgibbs * any message transfer. 156039220Sgibbs */ 156139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 156239220Sgibbs bmov SCB_DATAPTR, SHADDR, 4; 156363457Sgibbs bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; 156439220Sgibbs } else { 156539220Sgibbs mvi DINDEX, SCB_DATAPTR; 156663457Sgibbs mvi SHADDR call bcopy_4; 156763457Sgibbs mvi SCB_RESIDUAL_DATACNT call bcopy_8; 156839220Sgibbs } 156923925Sgibbs jmp mesgin_done; 15704568Sgibbs 157113177Sgibbs/* 157213177Sgibbs * Restore pointers message? Data pointers are recopied from the 157313177Sgibbs * SCB anytime we enter a data phase for the first time, so all 157413177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 157513177Sgibbs * code do the rest. 157613177Sgibbs */ 15779954Sgibbsmesgin_rdptrs: 157823925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 157923925Sgibbs * We'll reload them 158013177Sgibbs * the next time through 158123925Sgibbs * the dataphase. 158213177Sgibbs */ 158323925Sgibbs jmp mesgin_done; 15844568Sgibbs 158513177Sgibbs/* 158663457Sgibbs * Index into our Busy Target table. SINDEX and DINDEX are modified 158763457Sgibbs * upon return. SCBPTR may be modified by this action. 158863457Sgibbs */ 158968087Sgibbsset_busy_target: 159068087Sgibbs shr DINDEX, 4, SINDEX; 159171390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 159263457Sgibbs mov SCBPTR, SAVED_LUN; 159368087Sgibbs add DINDEX, SCB_64_BTT; 159463457Sgibbs } else { 159568087Sgibbs add DINDEX, BUSY_TARGETS; 159663457Sgibbs } 159768087Sgibbs mov DINDIR, ARG_1 ret; 159863457Sgibbs 159963457Sgibbs/* 160013177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 160113177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 160213177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 160313177Sgibbs */ 16049954Sgibbsmesgin_identify: 160563457Sgibbs /* 160663457Sgibbs * Determine whether a target is using tagged or non-tagged 160763457Sgibbs * transactions by first looking at the transaction stored in 160863457Sgibbs * the busy target array. If there is no untagged transaction 160963457Sgibbs * for this target or the transaction is for a different lun, then 161063457Sgibbs * this must be an untagged transaction. 161163457Sgibbs */ 161271390Sgibbs shr SINDEX, 4, SELID; 161371390Sgibbs and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; 161471390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 161571390Sgibbs add SINDEX, SCB_64_BTT; 161668087Sgibbs mov SCBPTR, SAVED_LUN; 161771390Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 161871390Sgibbs add NONE, -SCB_64_BTT, SINDEX; 161971390Sgibbs jc . + 2; 162071390Sgibbs mvi INTSTAT, OUT_OF_RANGE; 162171390Sgibbs nop; 162271390Sgibbs add NONE, -(SCB_64_BTT + 16), SINDEX; 162371390Sgibbs jnc . + 2; 162471390Sgibbs mvi INTSTAT, OUT_OF_RANGE; 162571390Sgibbs nop; 162671390Sgibbs } 162768087Sgibbs } else { 162871390Sgibbs add SINDEX, BUSY_TARGETS; 162968087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 163071390Sgibbs add NONE, -BUSY_TARGETS, SINDEX; 163168087Sgibbs jc . + 2; 163268087Sgibbs mvi INTSTAT, OUT_OF_RANGE; 163368402Sgibbs nop; 163471390Sgibbs add NONE, -(BUSY_TARGETS + 16), SINDEX; 163568087Sgibbs jnc . + 2; 163668087Sgibbs mvi INTSTAT, OUT_OF_RANGE; 163768402Sgibbs nop; 163868087Sgibbs } 163968087Sgibbs } 164068087Sgibbs mov ARG_1, SINDIR; 164168087Sgibbs cmp ARG_1, SCB_LIST_NULL je snoop_tag; 164263457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 164368579Sgibbs mov ARG_1 call findSCB; 164439220Sgibbs } else { 164568087Sgibbs mov SCBPTR, RETURN_1; 164639220Sgibbs } 164771390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 164863457Sgibbs jmp setup_SCB_id_lun_okay; 164963457Sgibbs } else { 165071390Sgibbs jmp setup_SCB_id_okay; 165163457Sgibbs } 165239220Sgibbs 165313177Sgibbs/* 165413177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 165523168Sgibbs * If we get one, we use the tag returned to find the proper 165663457Sgibbs * SCB. With SCB paging, we must search for non-tagged 165763457Sgibbs * transactions since the SCB may exist in any slot. If we're not 165863457Sgibbs * using SCB paging, we can use the tag as the direct index to the 165963457Sgibbs * SCB. 166013177Sgibbs */ 166124608Sgibbssnoop_tag: 166271390Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 166371390Sgibbs or SEQ_FLAGS, 0x80; 166471390Sgibbs } 166523925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 166639220Sgibbs call phase_lock; 166768087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 166868087Sgibbs or SEQ_FLAGS, 0x1; 166968087Sgibbs } 167023925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 167168087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 167268087Sgibbs or SEQ_FLAGS, 0x2; 167368087Sgibbs } 167423925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 16756608Sgibbsget_tag: 167663457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 167763457Sgibbs mvi ARG_1 call inb_next; /* tag value */ 167863457Sgibbs mov ARG_1 call findSCB; 167963457Sgibbs } else { 168068087Sgibbs mvi ARG_1 call inb_next; /* tag value */ 168168087Sgibbs mov SCBPTR, ARG_1; 168263457Sgibbs } 168313177Sgibbs 168463457Sgibbs/* 168563457Sgibbs * Ensure that the SCB the tag points to is for 168663457Sgibbs * an SCB transaction to the reconnecting target. 168763457Sgibbs */ 168839220Sgibbssetup_SCB: 168968087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 169068087Sgibbs or SEQ_FLAGS, 0x4; 169168087Sgibbs } 169271390Sgibbs mov A, SCB_SCSIID; 169371390Sgibbs cmp SAVED_SCSIID, A jne not_found_cleanup_scb; 169468087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 169568087Sgibbs or SEQ_FLAGS, 0x8; 169668087Sgibbs } 169771390Sgibbssetup_SCB_id_okay: 169871390Sgibbs mov A, SCB_LUN; 169971390Sgibbs cmp SAVED_LUN, A jne not_found_cleanup_scb; 170063457Sgibbssetup_SCB_id_lun_okay: 170168087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 170268087Sgibbs or SEQ_FLAGS, 0x10; 170363457Sgibbs } 170468087Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; 170523925Sgibbs and SCB_CONTROL,~DISCONNECTED; 170663457Sgibbs test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; 170763457Sgibbs mov A, SCBPTR; 170868087Sgibbs mvi ARG_1, SCB_LIST_NULL; 170968087Sgibbs mov SAVED_SCSIID call set_busy_target; 171063457Sgibbs mov SCBPTR, A; 171163457Sgibbssetup_SCB_tagged: 171268579Sgibbs mvi SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 171339220Sgibbs call set_transfer_settings; 171439220Sgibbs /* See if the host wants to send a message upon reconnection */ 171539220Sgibbs test SCB_CONTROL, MK_MESSAGE jz mesgin_done; 171639220Sgibbs mvi HOST_MSG call mk_mesg; 171723925Sgibbs jmp mesgin_done; 171815328Sgibbs 171968087Sgibbsnot_found_cleanup_scb: 172068087Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 172168087Sgibbs call add_scb_to_free_list; 172268087Sgibbs } 172319218Sgibbsnot_found: 172468402Sgibbs mvi NO_MATCH call set_seqint; 172523925Sgibbs jmp mesgin_done; 17266608Sgibbs 17274568Sgibbsmk_mesg: 172823925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 172939220Sgibbs mov MSG_OUT,SINDEX ret; 17304568Sgibbs 173113177Sgibbs/* 173213177Sgibbs * Functions to read data in Automatic PIO mode. 173313177Sgibbs * 173413177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 173513177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 173613177Sgibbs * latched (the usual way), then read the data byte directly off the bus 173713177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 173813177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 173913177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 174013177Sgibbs * we send our ACK. 174113177Sgibbs * 174213177Sgibbs * The assumption here is that these are called in a particular sequence, 174313177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 174413177Sgibbs * use the same calling convention as inb. 174513177Sgibbs */ 174657099Sgibbsinb_next_wait_perr: 174768402Sgibbs mvi PERR_DETECTED call set_seqint; 174857099Sgibbs jmp inb_next_wait; 174913177Sgibbsinb_next: 175023925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 175113360Sgibbsinb_next_wait: 175221947Sgibbs /* 175321947Sgibbs * If there is a parity error, wait for the kernel to 175421947Sgibbs * see the interrupt and prepare our message response 175521947Sgibbs * before continuing. 175621947Sgibbs */ 175723925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 175857099Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait_perr; 175957099Sgibbsinb_next_check_phase: 176023925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 176123925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 176219623Sgibbsinb_first: 176323925Sgibbs mov DINDEX,SINDEX; 176423925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 176513177Sgibbsinb_last: 176623925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 176741646Sgibbs} 17684568Sgibbs 176968087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 177041646Sgibbs/* 177141646Sgibbs * Change to a new phase. If we are changing the state of the I/O signal, 177241646Sgibbs * from out to in, wait an additional data release delay before continuing. 177341646Sgibbs */ 177441646Sgibbschange_phase: 177543880Sgibbs /* Wait for preceeding I/O session to complete. */ 177643880Sgibbs test SCSISIGI, ACKI jnz .; 177743880Sgibbs 177843880Sgibbs /* Change the phase */ 177941646Sgibbs and DINDEX, IOI, SCSISIGI; 178041646Sgibbs mov SCSISIGO, SINDEX; 178141646Sgibbs and A, IOI, SINDEX; 178243880Sgibbs 178343880Sgibbs /* 178443880Sgibbs * If the data direction has changed, from 178543880Sgibbs * out (initiator driving) to in (target driving), 178663457Sgibbs * we must wait at least a data release delay plus 178743880Sgibbs * the normal bus settle delay. [SCSI III SPI 10.11.0] 178843880Sgibbs */ 178941646Sgibbs cmp DINDEX, A je change_phase_wait; 179041646Sgibbs test SINDEX, IOI jz change_phase_wait; 179141646Sgibbs call change_phase_wait; 179241646Sgibbschange_phase_wait: 179341646Sgibbs nop; 179441646Sgibbs nop; 179541646Sgibbs nop; 179641646Sgibbs nop ret; 179741646Sgibbs 179841646Sgibbs/* 179941646Sgibbs * Send a byte to an initiator in Automatic PIO mode. 180041646Sgibbs */ 180139220Sgibbstarget_outb: 180239220Sgibbs or SXFRCTL0, SPIOEN; 180339220Sgibbs test SSTAT0, SPIORDY jz .; 180439220Sgibbs mov SCSIDATL, SINDEX; 180539220Sgibbs test SSTAT0, SPIORDY jz .; 180641646Sgibbs and SXFRCTL0, ~SPIOEN ret; 180739220Sgibbs} 180839220Sgibbs 18094568Sgibbs 181013177Sgibbs/* 181113177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 181213177Sgibbs * message. 181313177Sgibbs */ 18144568Sgibbsassert: 181523925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 18164568Sgibbs 181768402Sgibbs mvi NO_IDENT jmp set_seqint; /* no - tell the kernel */ 18184568Sgibbs 181913177Sgibbs/* 182063457Sgibbs * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will 182163457Sgibbs * be set to the position of the SCB. If the SCB cannot be found locally, 182263457Sgibbs * it will be paged in from host memory. RETURN_2 stores the address of the 182363457Sgibbs * preceding SCB in the disconnected list which can be used to speed up 182463457Sgibbs * removal of the found SCB from the disconnected list. 182513177Sgibbs */ 182665942Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) { 182768579SgibbsBEGIN_CRITICAL 18284568SgibbsfindSCB: 182968087Sgibbs mov A, SINDEX; /* Tag passed in SINDEX */ 183068087Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; 183163457Sgibbs mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ 183268087Sgibbs mvi ARG_2, SCB_LIST_NULL; /* Head of list */ 183363457Sgibbs jmp findSCB_loop; 183439220SgibbsfindSCB_next: 183563457Sgibbs cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; 183668087Sgibbs mov ARG_2, SCBPTR; 183739220Sgibbs mov SCBPTR,SCB_NEXT; 183823168SgibbsfindSCB_loop: 183963457Sgibbs cmp SCB_TAG, A jne findSCB_next; 184019164Sgibbsrem_scb_from_disc_list: 184139220Sgibbs cmp ARG_2, SCB_LIST_NULL je rHead; 184239220Sgibbs mov DINDEX, SCB_NEXT; 184368087Sgibbs mov SINDEX, SCBPTR; 184439220Sgibbs mov SCBPTR, ARG_2; 184539220Sgibbs mov SCB_NEXT, DINDEX; 184623925Sgibbs mov SCBPTR, SINDEX ret; 184715328SgibbsrHead: 184823925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 184968579SgibbsEND_CRITICAL 185068087SgibbsfindSCB_notFound: 185168087Sgibbs /* 185268087Sgibbs * We didn't find it. Page in the SCB. 185368087Sgibbs */ 185468087Sgibbs mov ARG_1, A; /* Save tag */ 185568087Sgibbs mov ALLZEROS call get_free_or_disc_scb; 185668087Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 185768087Sgibbs mov ARG_1 jmp dma_scb; 185868087Sgibbs} 18594568Sgibbs 186039220Sgibbs/* 186139220Sgibbs * Prepare the hardware to post a byte to host memory given an 186263457Sgibbs * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. 186339220Sgibbs */ 186439220Sgibbspost_byte_setup: 186539220Sgibbs mov ARG_2, SINDEX; 186639220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 186739220Sgibbs mvi DINDEX, CCHADDR; 186863457Sgibbs mvi SHARED_DATA_ADDR call set_1byte_addr; 186939220Sgibbs mvi CCHCNT, 1; 187039220Sgibbs mvi CCSCBCTL, CCSCBRESET ret; 187139220Sgibbs } else { 187239220Sgibbs mvi DINDEX, HADDR; 187363457Sgibbs mvi SHARED_DATA_ADDR call set_1byte_addr; 187463457Sgibbs mvi 1 call set_hcnt; 187539220Sgibbs mvi DFCNTRL, FIFORESET ret; 187639220Sgibbs } 187739220Sgibbs 187839220Sgibbspost_byte: 187939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 188039220Sgibbs bmov CCSCBRAM, SINDEX, 1; 188139220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 188239220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 188339220Sgibbs clr CCSCBCTL ret; 188439220Sgibbs } else { 188539220Sgibbs mov DFDAT, SINDEX; 188639220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 188739220Sgibbs jmp dma_finish; 188839220Sgibbs } 188939220Sgibbs 189057099Sgibbsphase_lock_perr: 189168402Sgibbs mvi PERR_DETECTED call set_seqint; 189239220Sgibbsphase_lock: 189357099Sgibbs /* 189457099Sgibbs * If there is a parity error, wait for the kernel to 189557099Sgibbs * see the interrupt and prepare our message response 189657099Sgibbs * before continuing. 189757099Sgibbs */ 189839220Sgibbs test SSTAT1, REQINIT jz phase_lock; 189957099Sgibbs test SSTAT1, SCSIPERR jnz phase_lock_perr; 190057099Sgibbsphase_lock_latch_phase: 190141646Sgibbs and SCSISIGO, PHASE_MASK, SCSISIGI; 190241646Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI ret; 190339220Sgibbs 190439220Sgibbsif ((ahc->features & AHC_CMD_CHAN) == 0) { 190563457Sgibbsset_hcnt: 190663457Sgibbs mov HCNT[0], SINDEX; 190763457Sgibbsclear_hcnt: 190863457Sgibbs clr HCNT[1]; 190963457Sgibbs clr HCNT[2] ret; 191063457Sgibbs 191119164Sgibbsset_stcnt_from_hcnt: 191223925Sgibbs mov STCNT[0], HCNT[0]; 191323925Sgibbs mov STCNT[1], HCNT[1]; 191423925Sgibbs mov STCNT[2], HCNT[2] ret; 19154568Sgibbs 191663457Sgibbsbcopy_8: 191763457Sgibbs mov DINDIR, SINDIR; 191819164Sgibbsbcopy_7: 191923925Sgibbs mov DINDIR, SINDIR; 192023925Sgibbs mov DINDIR, SINDIR; 192119164Sgibbsbcopy_5: 192223925Sgibbs mov DINDIR, SINDIR; 192319164Sgibbsbcopy_4: 192423925Sgibbs mov DINDIR, SINDIR; 192519164Sgibbsbcopy_3: 192623925Sgibbs mov DINDIR, SINDIR; 192723925Sgibbs mov DINDIR, SINDIR; 192823925Sgibbs mov DINDIR, SINDIR ret; 192939220Sgibbs} 19304568Sgibbs 193168087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 193239220Sgibbs/* 193339220Sgibbs * Setup addr assuming that A is an index into 193439220Sgibbs * an array of 32byte objects, SINDEX contains 193539220Sgibbs * the base address of that array, and DINDEX 193639220Sgibbs * contains the base address of the location 193739220Sgibbs * to store the indexed address. 193839220Sgibbs */ 193939220Sgibbsset_32byte_addr: 194039220Sgibbs shr ARG_2, 3, A; 194139220Sgibbs shl A, 5; 194239220Sgibbs jmp set_1byte_addr; 194339220Sgibbs} 194439220Sgibbs 194539220Sgibbs/* 194639220Sgibbs * Setup addr assuming that A is an index into 194739220Sgibbs * an array of 64byte objects, SINDEX contains 194839220Sgibbs * the base address of that array, and DINDEX 194939220Sgibbs * contains the base address of the location 195039220Sgibbs * to store the indexed address. 195139220Sgibbs */ 195239220Sgibbsset_64byte_addr: 195339220Sgibbs shr ARG_2, 2, A; 195439220Sgibbs shl A, 6; 195539220Sgibbs 195639220Sgibbs/* 195763457Sgibbs * Setup addr assuming that A + (ARG_2 * 256) is an 195839220Sgibbs * index into an array of 1byte objects, SINDEX contains 195939220Sgibbs * the base address of that array, and DINDEX contains 196039220Sgibbs * the base address of the location to store the computed 196139220Sgibbs * address. 196239220Sgibbs */ 196339220Sgibbsset_1byte_addr: 196439220Sgibbs add DINDIR, A, SINDIR; 196539220Sgibbs mov A, ARG_2; 196639220Sgibbs adc DINDIR, A, SINDIR; 196739220Sgibbs clr A; 196839220Sgibbs adc DINDIR, A, SINDIR; 196939220Sgibbs adc DINDIR, A, SINDIR ret; 197039220Sgibbs 197139220Sgibbs/* 197239220Sgibbs * Either post or fetch and SCB from host memory based on the 197339220Sgibbs * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. 197439220Sgibbs */ 197519164Sgibbsdma_scb: 197639220Sgibbs mov A, SINDEX; 197739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 197839220Sgibbs mvi DINDEX, CCHADDR; 197939220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 198039220Sgibbs mov CCSCBPTR, SCBPTR; 198139220Sgibbs test DMAPARAMS, DIRECTION jz dma_scb_tohost; 198271390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 198365942Sgibbs mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; 198465942Sgibbs } else { 198565942Sgibbs mvi CCHCNT, SCB_DOWNLOAD_SIZE; 198665942Sgibbs } 198739220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; 198839220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; 198939220Sgibbs jmp dma_scb_finish; 199039220Sgibbsdma_scb_tohost: 199165942Sgibbs mvi CCHCNT, SCB_UPLOAD_SIZE; 199265942Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 199339220Sgibbs mvi CCSCBCTL, CCSCBRESET; 199465942Sgibbs bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; 199539220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 199668579Sgibbs test CCSCBCTL, CCSCBDONE jz .; 199765942Sgibbs } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { 199865942Sgibbs mvi CCSCBCTL, CCARREN|CCSCBRESET; 199965942Sgibbs cmp CCSCBCTL, ARRDONE|CCARREN jne .; 200065942Sgibbs mvi CCHCNT, SCB_UPLOAD_SIZE; 200165942Sgibbs mvi CCSCBCTL, CCSCBEN|CCSCBRESET; 200265942Sgibbs cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; 200339220Sgibbs } else { 200439220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; 200539220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; 200639220Sgibbs } 200739220Sgibbsdma_scb_finish: 200839220Sgibbs clr CCSCBCTL; 200939220Sgibbs test CCSCBCTL, CCARREN|CCSCBEN jnz .; 201039220Sgibbs ret; 201139220Sgibbs } else { 201239220Sgibbs mvi DINDEX, HADDR; 201339220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 201465942Sgibbs mvi SCB_DOWNLOAD_SIZE call set_hcnt; 201539220Sgibbs mov DFCNTRL, DMAPARAMS; 201639220Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 201739220Sgibbs /* Fill it with the SCB data */ 201824175Sgibbscopy_scb_tofifo: 201965942Sgibbs mvi SINDEX, SCB_BASE; 202065942Sgibbs add A, SCB_DOWNLOAD_SIZE, SINDEX; 202124175Sgibbscopy_scb_tofifo_loop: 202265942Sgibbs call copy_to_fifo_8; 202339220Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 202439220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 202565942Sgibbs jmp dma_finish; 202619164Sgibbsdma_scb_fromhost: 202765942Sgibbs mvi DINDEX, SCB_BASE; 202865942Sgibbs if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 202965942Sgibbs /* 203065942Sgibbs * The PCI module will only issue a PCI 203165942Sgibbs * retry if the data FIFO is empty. If the 203265942Sgibbs * host disconnects in the middle of a 203365942Sgibbs * transfer, we must empty the fifo of all 203465942Sgibbs * available data to force the chip to 203565942Sgibbs * continue the transfer. This does not 203665942Sgibbs * happen for SCSI transfers as the SCSI module 203765942Sgibbs * will drain the FIFO as data is made available. 203865942Sgibbs * When the hang occurs, we know that at least 203965942Sgibbs * 8 bytes are in the FIFO because the PCI 204065942Sgibbs * module has an 8 byte input latch that only 204165942Sgibbs * dumps to the FIFO when HCNT == 0 or the 204265942Sgibbs * latch is full. 204365942Sgibbs */ 204465942Sgibbs mvi A, -24; 204565942Sgibbs /* Wait for some data to arrive. */ 204665942Sgibbsdma_scb_hang_fifo: 204765942Sgibbs test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo; 204865942Sgibbsdma_scb_hang_wait: 204965942Sgibbs test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; 205065942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 205165942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 205265942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 205365942Sgibbs /* 205465942Sgibbs * The PCI no longer intends to perform a PCI 205565942Sgibbs * transaction and HDONE has not come true. 205665942Sgibbs * We are hung. Drain the fifo. 205765942Sgibbs */ 205865942Sgibbsdma_scb_hang_empty_fifo: 205965942Sgibbs call dfdat_in_8; 206065942Sgibbs add A, 8; 206165942Sgibbs add SINDEX, A, HCNT; 206265942Sgibbs /* 206365942Sgibbs * The result will be <= 0 (carry set) if at 206465942Sgibbs * least 8 bytes of data have been placed 206565942Sgibbs * into the fifo. 206665942Sgibbs */ 206765942Sgibbs jc dma_scb_hang_empty_fifo; 206865942Sgibbs jmp dma_scb_hang_fifo; 206965942Sgibbsdma_scb_hang_dma_done: 207065942Sgibbs and DFCNTRL, ~HDMAEN; 207165942Sgibbs test DFCNTRL, HDMAEN jnz .; 207265942Sgibbs call dfdat_in_8; 207365942Sgibbs add A, 8; 207465942Sgibbs cmp A, 8 jne . - 2; 207565942Sgibbs } else { 207665942Sgibbs call dma_finish; 207765942Sgibbs /* If we were putting the SCB, we are done */ 207865942Sgibbs call dfdat_in_8; 207965942Sgibbs call dfdat_in_8; 208065942Sgibbs call dfdat_in_8; 208165942Sgibbs } 208265942Sgibbsdfdat_in_8: 208365942Sgibbs mov DINDIR,DFDAT; 208419164Sgibbsdfdat_in_7: 208539220Sgibbs mov DINDIR,DFDAT; 208639220Sgibbs mov DINDIR,DFDAT; 208739220Sgibbs mov DINDIR,DFDAT; 208839220Sgibbs mov DINDIR,DFDAT; 208939220Sgibbs mov DINDIR,DFDAT; 209065942Sgibbsdfdat_in_2: 209139220Sgibbs mov DINDIR,DFDAT; 209239220Sgibbs mov DINDIR,DFDAT ret; 209339220Sgibbs } 209419164Sgibbs 209565942Sgibbscopy_to_fifo_8: 209665942Sgibbs mov DFDAT,SINDIR; 209765942Sgibbs mov DFDAT,SINDIR; 209863457Sgibbscopy_to_fifo_6: 209963457Sgibbs mov DFDAT,SINDIR; 210063457Sgibbscopy_to_fifo_5: 210163457Sgibbs mov DFDAT,SINDIR; 210263457Sgibbscopy_to_fifo_4: 210363457Sgibbs mov DFDAT,SINDIR; 210463457Sgibbs mov DFDAT,SINDIR; 210563457Sgibbs mov DFDAT,SINDIR; 210663457Sgibbs mov DFDAT,SINDIR ret; 210739220Sgibbs 210813177Sgibbs/* 210919164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 211019164Sgibbs * DMA and wait for it to acknowledge that it's off. 211113177Sgibbs */ 211219164Sgibbsdma_finish: 211323925Sgibbs test DFSTATUS,HDONE jz dma_finish; 211422234Sgibbs /* Turn off DMA */ 211523925Sgibbs and DFCNTRL, ~HDMAEN; 211623925Sgibbs test DFCNTRL, HDMAEN jnz .; 211723925Sgibbs ret; 21189928Sgibbs 211923925Sgibbsadd_scb_to_free_list: 212039220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 212166647SgibbsBEGIN_CRITICAL 212239220Sgibbs mov SCB_NEXT, FREE_SCBH; 212357099Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 212457099Sgibbs mov FREE_SCBH, SCBPTR ret; 212566647SgibbsEND_CRITICAL 212657099Sgibbs } else { 212757099Sgibbs mvi SCB_TAG, SCB_LIST_NULL ret; 212839220Sgibbs } 21294568Sgibbs 213039220Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) { 213119164Sgibbsget_free_or_disc_scb: 213268579SgibbsBEGIN_CRITICAL 213323925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 213423925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 213519623Sgibbsreturn_error: 213668402Sgibbs mvi NO_FREE_SCB call set_seqint; 213723925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 213819623Sgibbsdequeue_disc_scb: 213923925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 214068579Sgibbs mov DISCONNECTED_SCBH, SCB_NEXT; 214168579SgibbsEND_CRITICAL 214223925Sgibbs mvi DMAPARAMS, FIFORESET; 214368579Sgibbs mov SCB_TAG jmp dma_scb; 214468579SgibbsBEGIN_CRITICAL 214519164Sgibbsdequeue_free_scb: 214623925Sgibbs mov SCBPTR, FREE_SCBH; 214723925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 214868579SgibbsEND_CRITICAL 21494568Sgibbs 215019164Sgibbsadd_scb_to_disc_list: 215113177Sgibbs/* 215219164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 215319164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 215419164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 215513177Sgibbs */ 215668087SgibbsBEGIN_CRITICAL 215723925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 215839220Sgibbs mov DISCONNECTED_SCBH, SCBPTR ret; 215968087SgibbsEND_CRITICAL 216065942Sgibbs} 216168402Sgibbsset_seqint: 216268402Sgibbs mov INTSTAT, SINDEX; 216368402Sgibbs nop; 216463457Sgibbsreturn: 216563457Sgibbs ret; 2166