aic7xxx.seq revision 74094
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 * 3174094Sgibbs * $Id: //depot/src/aic7xxx/aic7xxx.seq#23 $ 3265942Sgibbs * 3350477Speter * $FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 74094 2001-03-11 06:34:17Z 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 } 7072811Sgibbs test SCSISEQ, ENSELO jnz poll_for_selection; 7172811Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 7272811Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 7372811Sgibbs test SCSISEQ, ENSELO jnz poll_for_selection; 7472811Sgibbs } 7572811Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 7639220Sgibbspoll_for_work_loop: 7739220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 7839220Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 7939220Sgibbs } 8072811Sgibbs test SSTAT0, SELDO|SELDI jnz selection; 8119164Sgibbstest_queue: 8219164Sgibbs /* Has the driver posted any work for us? */ 8366647SgibbsBEGIN_CRITICAL 8439220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 8539220Sgibbs test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; 8639220Sgibbs } else { 8768087Sgibbs mov A, QINPOS; 8839220Sgibbs cmp KERNEL_QINPOS, A je poll_for_work_loop; 8939220Sgibbs } 9066647Sgibbs mov ARG_1, NEXT_QUEUED_SCB; 914568Sgibbs 9263457Sgibbs /* 9363457Sgibbs * We have at least one queued SCB now and we don't have any 9466647Sgibbs * SCBs in the list of SCBs awaiting selection. Allocate a 9566647Sgibbs * card SCB for the host's SCB and get to work on it. 9663457Sgibbs */ 9739220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 9839220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 9966647Sgibbs } else { 10039220Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 10166647Sgibbs mov SCBPTR, ARG_1; 10239220Sgibbs } 10374094Sgibbs or SEQ_FLAGS2, SCB_DMA; 10474094SgibbsEND_CRITICAL 10519164Sgibbsdma_queued_scb: 10663457Sgibbs /* 10763457Sgibbs * DMA the SCB from host ram into the current SCB location. 10863457Sgibbs */ 10923925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 11066647Sgibbs mov ARG_1 call dma_scb; 11119164Sgibbs /* 11266647Sgibbs * Check one last time to see if this SCB was canceled 11366647Sgibbs * before we completed the DMA operation. If it was, 11466647Sgibbs * the QINFIFO next pointer will not match our saved 11566647Sgibbs * value. 11619164Sgibbs */ 11766647Sgibbs mov A, ARG_1; 11866647SgibbsBEGIN_CRITICAL 11966647Sgibbs cmp NEXT_QUEUED_SCB, A jne abort_qinscb; 12068087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 12168087Sgibbs cmp SCB_TAG, A je . + 2; 12268402Sgibbs mvi SCB_MISMATCH call set_seqint; 12368087Sgibbs } 12466647Sgibbs mov NEXT_QUEUED_SCB, SCB_NEXT; 12523925Sgibbs mov SCB_NEXT,WAITING_SCBH; 12623925Sgibbs mov WAITING_SCBH, SCBPTR; 12768402Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 12868402Sgibbs mov NONE, SNSCB_QOFF; 12968402Sgibbs } else { 13068402Sgibbs inc QINPOS; 13168402Sgibbs } 13274094Sgibbs and SEQ_FLAGS2, ~SCB_DMA; 13366647SgibbsEND_CRITICAL 13423925Sgibbsstart_waiting: 13523925Sgibbs /* 13663457Sgibbs * Start the first entry on the waiting SCB list. 13723925Sgibbs */ 13823925Sgibbs mov SCBPTR, WAITING_SCBH; 13923925Sgibbs call start_selection; 1408104Sgibbs 14172811Sgibbspoll_for_selection: 14268579Sgibbs /* 14372811Sgibbs * Twin channel devices cannot handle things like SELTO 14472811Sgibbs * interrupts on the "background" channel. So, while 14572811Sgibbs * selecting, keep polling the current channel until 14672811Sgibbs * either a selection or reselection occurs. 14768579Sgibbs */ 14872811Sgibbs test SSTAT0, SELDO|SELDI jz poll_for_selection; 14939220Sgibbs 15039220Sgibbsselection: 15163457Sgibbs /* 15263457Sgibbs * We aren't expecting a bus free, so interrupt 15363457Sgibbs * the kernel driver if it happens. 15463457Sgibbs */ 15563457Sgibbs mvi CLRSINT1,CLRBUSFREE; 15663457Sgibbs or SIMODE1, ENBUSFREE; 15763457Sgibbs 15868579Sgibbs /* 15968579Sgibbs * Guard against a bus free after (re)selection 16068579Sgibbs * but prior to enabling the busfree interrupt. SELDI 16168579Sgibbs * and SELDO will be cleared in that case. 16268579Sgibbs */ 16371390Sgibbs test SSTAT0, SELDI|SELDO jz bus_free_sel; 16439220Sgibbs test SSTAT0,SELDO jnz select_out; 16539220Sgibbsselect_in: 16668087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 16768087Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 16841646Sgibbs test SSTAT0, TARGET jz initiator_reselect; 16941646Sgibbs } 17071390Sgibbs mvi CLRSINT0, CLRSELDI; 17142652Sgibbs 17239220Sgibbs /* 17339220Sgibbs * We've just been selected. Assert BSY and 17439220Sgibbs * setup the phase for receiving messages 17539220Sgibbs * from the target. 17668579Sgibbs * 17768579Sgibbs * If bus reset interrupts have been disabled (from a 17868579Sgibbs * previous reset), re-enable them now. Resets are only 17968579Sgibbs * of interest when we have outstanding transactions, so 18068579Sgibbs * we can safely defer re-enabling the interrupt until, 18168579Sgibbs * as a target, we start receiving transactions again. 18239220Sgibbs */ 18368579Sgibbs test SIMODE1, ENSCSIRST jnz . + 3; 18468579Sgibbs mvi CLRSINT1, CLRSCSIRSTI; 18568579Sgibbs or SIMODE1, ENSCSIRST; 18639220Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 18739220Sgibbs 18839220Sgibbs /* 18939220Sgibbs * Setup the DMA for sending the identify and 19041299Sgibbs * command information. 19139220Sgibbs */ 19239220Sgibbs or SEQ_FLAGS, CMDPHASE_PENDING; 19341299Sgibbs 19441299Sgibbs mov A, TQINPOS; 19539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 19639220Sgibbs mvi DINDEX, CCHADDR; 19763457Sgibbs mvi SHARED_DATA_ADDR call set_32byte_addr; 19839220Sgibbs mvi CCSCBCTL, CCSCBRESET; 19939220Sgibbs } else { 20039220Sgibbs mvi DINDEX, HADDR; 20163457Sgibbs mvi SHARED_DATA_ADDR call set_32byte_addr; 20239220Sgibbs mvi DFCNTRL, FIFORESET; 20339220Sgibbs } 20439220Sgibbs 20539220Sgibbs /* Initiator that selected us */ 20663457Sgibbs and SAVED_SCSIID, SELID_MASK, SELID; 20763457Sgibbs /* The Target ID we were selected at */ 20863457Sgibbs if ((ahc->features & AHC_MULTI_TID) != 0) { 20963457Sgibbs and A, OID, TARGIDIN; 21063457Sgibbs } else if ((ahc->features & AHC_ULTRA2) != 0) { 21163457Sgibbs and A, OID, SCSIID_ULTRA2; 21239220Sgibbs } else { 21363457Sgibbs and A, OID, SCSIID; 21439220Sgibbs } 21563457Sgibbs or SAVED_SCSIID, A; 21663457Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 21763457Sgibbs test SBLKCTL, SELBUSB jz . + 2; 21863457Sgibbs or SAVED_SCSIID, TWIN_CHNLB; 21963457Sgibbs } 22044507Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 22163457Sgibbs mov CCSCBRAM, SAVED_SCSIID; 22239220Sgibbs } else { 22363457Sgibbs mov DFDAT, SAVED_SCSIID; 22439220Sgibbs } 22539220Sgibbs 22639220Sgibbs /* 22739220Sgibbs * If ATN isn't asserted, the target isn't interested 22839220Sgibbs * in talking to us. Go directly to bus free. 22963457Sgibbs * XXX SCSI-1 may require us to assume lun 0 if 23063457Sgibbs * ATN is false. 23139220Sgibbs */ 23239220Sgibbs test SCSISIGI, ATNI jz target_busfree; 23339220Sgibbs 23439220Sgibbs /* 23539220Sgibbs * Watch ATN closely now as we pull in messages from the 23639220Sgibbs * initiator. We follow the guidlines from section 6.5 23739220Sgibbs * of the SCSI-2 spec for what messages are allowed when. 23839220Sgibbs */ 23941646Sgibbs call target_inb; 24039220Sgibbs 24139220Sgibbs /* 24239220Sgibbs * Our first message must be one of IDENTIFY, ABORT, or 24339220Sgibbs * BUS_DEVICE_RESET. 24439220Sgibbs */ 24542652Sgibbs test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; 24639220Sgibbs /* Store for host */ 24739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 24839220Sgibbs mov CCSCBRAM, DINDEX; 24939220Sgibbs } else { 25039220Sgibbs mov DFDAT, DINDEX; 25139220Sgibbs } 25239220Sgibbs 25339220Sgibbs /* Remember for disconnection decision */ 25439220Sgibbs test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; 25539220Sgibbs /* XXX Honor per target settings too */ 25639220Sgibbs or SEQ_FLAGS, NO_DISCONNECT; 25739220Sgibbs 25839220Sgibbs test SCSISIGI, ATNI jz ident_messages_done; 25941646Sgibbs call target_inb; 26039220Sgibbs /* 26139220Sgibbs * If this is a tagged request, the tagged message must 26239220Sgibbs * immediately follow the identify. We test for a valid 26339220Sgibbs * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and 26439220Sgibbs * < MSG_IGN_WIDE_RESIDUE. 26539220Sgibbs */ 26639220Sgibbs add A, -MSG_SIMPLE_Q_TAG, DINDEX; 26739220Sgibbs jnc ident_messages_done; 26839220Sgibbs add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; 26939220Sgibbs jc ident_messages_done; 27039220Sgibbs /* Store for host */ 27139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 27239220Sgibbs mov CCSCBRAM, DINDEX; 27339220Sgibbs } else { 27439220Sgibbs mov DFDAT, DINDEX; 27539220Sgibbs } 27639220Sgibbs 27739220Sgibbs /* 27839220Sgibbs * If the initiator doesn't feel like providing a tag number, 27939220Sgibbs * we've got a failed selection and must transition to bus 28039220Sgibbs * free. 28139220Sgibbs */ 28239220Sgibbs test SCSISIGI, ATNI jz target_busfree; 28342652Sgibbs 28439220Sgibbs /* 28539220Sgibbs * Store the tag for the host. 28639220Sgibbs */ 28741646Sgibbs call target_inb; 28839220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 28939220Sgibbs mov CCSCBRAM, DINDEX; 29039220Sgibbs } else { 29139220Sgibbs mov DFDAT, DINDEX; 29239220Sgibbs } 29342652Sgibbs mov INITIATOR_TAG, DINDEX; 29463457Sgibbs or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; 29563457Sgibbs test SCSISIGI, ATNI jz . + 2; 29663457Sgibbs /* Initiator still wants to give us messages */ 29763457Sgibbs call target_inb; 29839220Sgibbs jmp ident_messages_done; 29939220Sgibbs 30041646Sgibbs /* 30141646Sgibbs * Pushed message loop to allow the kernel to 30242652Sgibbs * run it's own target mode message state engine. 30341646Sgibbs */ 30441646Sgibbshost_target_message_loop: 30568402Sgibbs mvi HOST_MSG_LOOP call set_seqint; 30641646Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; 30741646Sgibbs test SSTAT0, SPIORDY jz .; 30841646Sgibbs jmp host_target_message_loop; 30941646Sgibbs 31039220Sgibbsident_messages_done: 31144507Sgibbs /* If ring buffer is full, return busy or queue full */ 31258258Sgibbs if ((ahc->features & AHC_HS_MAILBOX) != 0) { 31358258Sgibbs and A, HOST_TQINPOS, HS_MAILBOX; 31458258Sgibbs } else { 31558258Sgibbs mov A, KERNEL_TQINPOS; 31658258Sgibbs } 31744507Sgibbs cmp TQINPOS, A jne tqinfifo_has_space; 31844507Sgibbs mvi P_STATUS|BSYO call change_phase; 31968087Sgibbs test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; 32044507Sgibbs mvi STATUS_QUEUE_FULL call target_outb; 32144507Sgibbs jmp target_busfree_wait; 32244507Sgibbs mvi STATUS_BUSY call target_outb; 32344507Sgibbs jmp target_busfree_wait; 32444507Sgibbstqinfifo_has_space: 32539220Sgibbs /* Terminate the ident list */ 32639220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 32739220Sgibbs mvi CCSCBRAM, SCB_LIST_NULL; 32839220Sgibbs } else { 32939220Sgibbs mvi DFDAT, SCB_LIST_NULL; 33039220Sgibbs } 33142652Sgibbs or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN; 33263457Sgibbs test SCSISIGI, ATNI jnz target_mesgout_pending; 33339220Sgibbs jmp target_ITloop; 33439220Sgibbs } 33539220Sgibbs 33668087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 33739220Sgibbs/* 33823925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 33923925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 34013177Sgibbs */ 34139220Sgibbsinitiator_reselect: 34223925Sgibbs /* XXX test for and handle ONE BIT condition */ 34371390Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 34463457Sgibbs and SAVED_SCSIID, SELID_MASK, SELID; 34563457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 34663457Sgibbs and A, OID, SCSIID_ULTRA2; 34763457Sgibbs } else { 34863457Sgibbs and A, OID, SCSIID; 34963457Sgibbs } 35063457Sgibbs or SAVED_SCSIID, A; 35139545Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 35239545Sgibbs test SBLKCTL, SELBUSB jz . + 2; 35363457Sgibbs or SAVED_SCSIID, TWIN_CHNLB; 35439545Sgibbs } 35571390Sgibbs mvi CLRSINT0, CLRSELDI; 35639220Sgibbs jmp ITloop; 35741646Sgibbs} 3584568Sgibbs 35972811Sgibbsabort_qinscb: 36072811Sgibbs call add_scb_to_free_list; 36172811Sgibbs jmp poll_for_work_loop; 36272811Sgibbs 36372811Sgibbsstart_selection: 36472811Sgibbs /* 36572811Sgibbs * If bus reset interrupts have been disabled (from a previous 36672811Sgibbs * reset), re-enable them now. Resets are only of interest 36772811Sgibbs * when we have outstanding transactions, so we can safely 36872811Sgibbs * defer re-enabling the interrupt until, as an initiator, 36972811Sgibbs * we start sending out transactions again. 37072811Sgibbs */ 37172811Sgibbs test SIMODE1, ENSCSIRST jnz . + 3; 37272811Sgibbs mvi CLRSINT1, CLRSCSIRSTI; 37372811Sgibbs or SIMODE1, ENSCSIRST; 37472811Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 37572811Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ 37672811Sgibbs test SCB_SCSIID, TWIN_CHNLB jz . + 2; 37772811Sgibbs or SINDEX, SELBUSB; 37872811Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 37972811Sgibbs } 38072811Sgibbsinitialize_scsiid: 38172811Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 38272811Sgibbs mov SCSIID_ULTRA2, SCB_SCSIID; 38372811Sgibbs } else if ((ahc->features & AHC_TWIN) != 0) { 38472811Sgibbs and SCSIID, TWIN_TID|OID, SCB_SCSIID; 38572811Sgibbs } else { 38672811Sgibbs mov SCSIID, SCB_SCSIID; 38772811Sgibbs } 38872811Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 38972811Sgibbs mov SINDEX, SCSISEQ_TEMPLATE; 39072811Sgibbs test SCB_CONTROL, TARGET_SCB jz . + 2; 39172811Sgibbs or SINDEX, TEMODE; 39272811Sgibbs mov SCSISEQ, SINDEX ret; 39372811Sgibbs } else { 39472811Sgibbs mov SCSISEQ, SCSISEQ_TEMPLATE ret; 39572811Sgibbs } 39672811Sgibbs 39713177Sgibbs/* 39872811Sgibbs * Initialize transfer settings and clear the SCSI channel. 39972811Sgibbs * SINDEX should contain any additional bit's the client wants 40072811Sgibbs * set in SXFRCTL0. We also assume that the current SCB is 40172811Sgibbs * a valid SCB for the target we wish to talk to. 40272811Sgibbs */ 40372811Sgibbsinitialize_channel: 40472811Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 40572811Sgibbsset_transfer_settings: 40672811Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 40772811Sgibbs test SCB_CONTROL, ULTRAENB jz . + 2; 40872811Sgibbs or SXFRCTL0, FAST20; 40972811Sgibbs } 41072811Sgibbs /* 41172811Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 41272811Sgibbs */ 41372811Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 41472811Sgibbs bmov SCSIRATE, SCB_SCSIRATE, 2 ret; 41572811Sgibbs } else { 41672811Sgibbs mov SCSIRATE, SCB_SCSIRATE ret; 41772811Sgibbs } 41872811Sgibbs 41972811Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 42072811Sgibbs/* 42172811Sgibbs * We carefully toggle SPIOEN to allow us to return the 42272811Sgibbs * message byte we receive so it can be checked prior to 42372811Sgibbs * driving REQ on the bus for the next byte. 42472811Sgibbs */ 42572811Sgibbstarget_inb: 42672811Sgibbs /* 42772811Sgibbs * Drive REQ on the bus by enabling SCSI PIO. 42872811Sgibbs */ 42972811Sgibbs or SXFRCTL0, SPIOEN; 43072811Sgibbs /* Wait for the byte */ 43172811Sgibbs test SSTAT0, SPIORDY jz .; 43272811Sgibbs /* Prevent our read from triggering another REQ */ 43372811Sgibbs and SXFRCTL0, ~SPIOEN; 43472811Sgibbs /* Save latched contents */ 43572811Sgibbs mov DINDEX, SCSIDATL ret; 43672811Sgibbs} 43772811Sgibbs 43872811Sgibbs/* 43923925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 44023925Sgibbs * list. This is achieved by simply moving our "next" pointer into 44123925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 44223925Sgibbs * SCB is used, so don't bother with it now. 44323925Sgibbs */ 44439220Sgibbsselect_out: 44525005Sgibbs /* Turn off the selection hardware */ 44658258Sgibbs and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; 44725005Sgibbs mvi CLRSINT0, CLRSELDO; 44825005Sgibbs mov SCBPTR, WAITING_SCBH; 44924914Sgibbs mov WAITING_SCBH,SCB_NEXT; 45063457Sgibbs mov SAVED_SCSIID, SCB_SCSIID; 45163457Sgibbs mov SAVED_LUN, SCB_LUN; 45268087Sgibbs call initialize_channel; 45368087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 45439220Sgibbs test SSTAT0, TARGET jz initiator_select; 4558567Sdg 45639220Sgibbs /* 45739220Sgibbs * We've just re-selected an initiator. 45839220Sgibbs * Assert BSY and setup the phase for 45939220Sgibbs * sending our identify messages. 46039220Sgibbs */ 46141646Sgibbs mvi P_MESGIN|BSYO call change_phase; 4624568Sgibbs 46339220Sgibbs /* 46439220Sgibbs * Start out with a simple identify message. 46539220Sgibbs */ 46663457Sgibbs or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; 4676608Sgibbs 46839220Sgibbs /* 46939220Sgibbs * If we are the result of a tagged command, send 47039220Sgibbs * a simple Q tag and the tag id. 47139220Sgibbs */ 47239220Sgibbs test SCB_CONTROL, TAG_ENB jz . + 3; 47339220Sgibbs mvi MSG_SIMPLE_Q_TAG call target_outb; 47463457Sgibbs mov SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb; 47539220Sgibbstarget_synccmd: 47639220Sgibbs /* 47739220Sgibbs * Now determine what phases the host wants us 47839220Sgibbs * to go through. 47939220Sgibbs */ 48063457Sgibbs mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; 48142652Sgibbs 48239220Sgibbstarget_ITloop: 48339220Sgibbs /* 48441646Sgibbs * Start honoring ATN signals now that 48544507Sgibbs * we properly identified ourselves. 48639220Sgibbs */ 48741646Sgibbs test SCSISIGI, ATNI jnz target_mesgout; 48839220Sgibbs test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; 48939220Sgibbs test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; 49039220Sgibbs test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; 49139220Sgibbs 49239220Sgibbs /* 49339220Sgibbs * No more work to do. Either disconnect or not depending 49439220Sgibbs * on the state of NO_DISCONNECT. 49539220Sgibbs */ 49639220Sgibbs test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 49739220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 49839220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 49939220Sgibbs } 50041646Sgibbs mov RETURN_1, ALLZEROS; 50139220Sgibbs call complete_target_cmd; 50241646Sgibbs cmp RETURN_1, CONT_MSG_LOOP jne .; 50339220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 50439220Sgibbs mov SCB_TAG call dma_scb; 50539220Sgibbs jmp target_synccmd; 50639220Sgibbs 50741646Sgibbstarget_mesgout: 50841646Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 50963457Sgibbstarget_mesgout_continue: 51041646Sgibbs call target_inb; 51163457Sgibbstarget_mesgout_pending: 51241646Sgibbs /* Local Processing goes here... */ 51341646Sgibbs jmp host_target_message_loop; 51441646Sgibbs 51539220Sgibbstarget_disconnect: 51641646Sgibbs mvi P_MESGIN|BSYO call change_phase; 51741816Sgibbs test SEQ_FLAGS, DPHASE jz . + 2; 51841816Sgibbs mvi MSG_SAVEDATAPOINTER call target_outb; 51939220Sgibbs mvi MSG_DISCONNECT call target_outb; 52039220Sgibbs 52143880Sgibbstarget_busfree_wait: 52272640Sasmodai /* Wait for preceding I/O session to complete. */ 52343880Sgibbs test SCSISIGI, ACKI jnz .; 52439220Sgibbstarget_busfree: 52563457Sgibbs and SIMODE1, ~ENBUSFREE; 52668623Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 52768623Sgibbs clr SCSIBUSL; 52868623Sgibbs } 52939220Sgibbs clr SCSISIGO; 53057099Sgibbs mvi LASTPHASE, P_BUSFREE; 53139220Sgibbs call complete_target_cmd; 53239220Sgibbs jmp poll_for_work; 53339220Sgibbs 53439220Sgibbstarget_cmdphase: 53541646Sgibbs mvi P_COMMAND|BSYO call change_phase; 53641646Sgibbs call target_inb; 53739220Sgibbs mov A, DINDEX; 53839220Sgibbs /* Store for host */ 53939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 54039220Sgibbs mov CCSCBRAM, A; 54139220Sgibbs } else { 54239220Sgibbs mov DFDAT, A; 54339220Sgibbs } 54439220Sgibbs 54539220Sgibbs /* 54639220Sgibbs * Determine the number of bytes to read 54741299Sgibbs * based on the command group code via table lookup. 54841299Sgibbs * We reuse the first 8 bytes of the TARG_SCSIRATE 54941299Sgibbs * BIOS array for this table. Count is one less than 55041299Sgibbs * the total for the command since we've already fetched 55141299Sgibbs * the first byte. 55239220Sgibbs */ 55339220Sgibbs shr A, CMD_GROUP_CODE_SHIFT; 55468087Sgibbs add SINDEX, CMDSIZE_TABLE, A; 55539220Sgibbs mov A, SINDIR; 55639220Sgibbs 55739220Sgibbs test A, 0xFF jz command_phase_done; 55871390Sgibbs or SXFRCTL0, SPIOEN; 55939220Sgibbscommand_loop: 56039220Sgibbs test SSTAT0, SPIORDY jz .; 56139220Sgibbs cmp A, 1 jne . + 2; 56239220Sgibbs and SXFRCTL0, ~SPIOEN; /* Last Byte */ 56339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 56439220Sgibbs mov CCSCBRAM, SCSIDATL; 56539220Sgibbs } else { 56639220Sgibbs mov DFDAT, SCSIDATL; 56739220Sgibbs } 56839220Sgibbs dec A; 56939220Sgibbs test A, 0xFF jnz command_loop; 57039220Sgibbs 57139220Sgibbscommand_phase_done: 57239220Sgibbs and SEQ_FLAGS, ~CMDPHASE_PENDING; 57339220Sgibbs jmp target_ITloop; 57439220Sgibbs 57539220Sgibbstarget_dphase: 57639220Sgibbs /* 57763457Sgibbs * Data phases on the bus are from the 57863457Sgibbs * perspective of the initiator. The dma 57963457Sgibbs * code looks at LASTPHASE to determine the 58063457Sgibbs * data direction of the DMA. Toggle it for 58163457Sgibbs * target transfers. 58239220Sgibbs */ 58363457Sgibbs xor LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR]; 58463457Sgibbs or SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO 58563457Sgibbs call change_phase; 58639220Sgibbs jmp p_data; 58739220Sgibbs 58839220Sgibbstarget_sphase: 58941646Sgibbs mvi P_STATUS|BSYO call change_phase; 59041646Sgibbs mvi LASTPHASE, P_STATUS; 59163457Sgibbs mov SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb; 59241646Sgibbs /* XXX Watch for ATN or parity errors??? */ 59339220Sgibbs mvi SCSISIGO, P_MESGIN|BSYO; 59439220Sgibbs /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ 59539220Sgibbs mov ALLZEROS call target_outb; 59643880Sgibbs jmp target_busfree_wait; 59739220Sgibbs 59839220Sgibbscomplete_target_cmd: 59939220Sgibbs test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; 60039220Sgibbs mov SCB_TAG jmp complete_post; 60139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 60241299Sgibbs /* Set the valid byte */ 60341299Sgibbs mvi CCSCBADDR, 24; 60441299Sgibbs mov CCSCBRAM, ALLONES; 60541299Sgibbs mvi CCHCNT, 28; 60639220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 60739220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 60839220Sgibbs clr CCSCBCTL; 60939220Sgibbs } else { 61041299Sgibbs /* Set the valid byte */ 61141299Sgibbs or DFCNTRL, FIFORESET; 61241299Sgibbs mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ 61341299Sgibbs mov DFDAT, ALLONES; 61463457Sgibbs mvi 28 call set_hcnt; 61539220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 61639220Sgibbs call dma_finish; 61739220Sgibbs } 61841299Sgibbs inc TQINPOS; 61941299Sgibbs mvi INTSTAT,CMDCMPLT ret; 62039220Sgibbs } 62141646Sgibbs 62268087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 62339220Sgibbsinitiator_select: 62441646Sgibbs /* 62541646Sgibbs * As soon as we get a successful selection, the target 62641646Sgibbs * should go into the message out phase since we have ATN 62741646Sgibbs * asserted. 62841646Sgibbs */ 62939220Sgibbs mvi MSG_OUT, MSG_IDENTIFYFLAG; 63039220Sgibbs or SEQ_FLAGS, IDENTIFY_SEEN; 63113177Sgibbs 63241646Sgibbs /* 63341646Sgibbs * Main loop for information transfer phases. Wait for the 63441646Sgibbs * target to assert REQ before checking MSG, C/D and I/O for 63541646Sgibbs * the bus phase. 63641646Sgibbs */ 63763457Sgibbsmesgin_phasemis: 6384568SgibbsITloop: 63939220Sgibbs call phase_lock; 6404568Sgibbs 64139220Sgibbs mov A, LASTPHASE; 6424568Sgibbs 64339220Sgibbs test A, ~P_DATAIN jz p_data; 64423925Sgibbs cmp A,P_COMMAND je p_command; 64523925Sgibbs cmp A,P_MESGOUT je p_mesgout; 64623925Sgibbs cmp A,P_STATUS je p_status; 64723925Sgibbs cmp A,P_MESGIN je p_mesgin; 6484568Sgibbs 64968402Sgibbs mvi BAD_PHASE call set_seqint; 65023925Sgibbs jmp ITloop; /* Try reading the bus again. */ 6514568Sgibbs 65223925Sgibbsawait_busfree: 65323925Sgibbs and SIMODE1, ~ENBUSFREE; 65423925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 65568623Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 65668623Sgibbs clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ 65768623Sgibbs } 65839220Sgibbs and SXFRCTL0, ~SPIOEN; 65923925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 66023925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 66168579Sgibbs mvi MISSED_BUSFREE call set_seqint; 66241646Sgibbs} 66323925Sgibbs 66423925Sgibbsclear_target_state: 66541646Sgibbs /* 66641646Sgibbs * We assume that the kernel driver may reset us 66741646Sgibbs * at any time, even in the middle of a DMA, so 66841646Sgibbs * clear DFCNTRL too. 66941646Sgibbs */ 67041646Sgibbs clr DFCNTRL; 67168087Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 67241646Sgibbs 67341646Sgibbs /* 67441646Sgibbs * We don't know the target we will connect to, 67541646Sgibbs * so default to narrow transfers to avoid 67641646Sgibbs * parity problems. 67741646Sgibbs */ 67841646Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 67941646Sgibbs bmov SCSIRATE, ALLZEROS, 2; 68041646Sgibbs } else { 68141646Sgibbs clr SCSIRATE; 68263457Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 68363457Sgibbs and SXFRCTL0, ~(FAST20); 68463457Sgibbs } 68541646Sgibbs } 68623925Sgibbs mvi LASTPHASE, P_BUSFREE; 68723925Sgibbs /* clear target specific flags */ 68839220Sgibbs clr SEQ_FLAGS ret; 68923925Sgibbs 69063457Sgibbssg_advance: 69163457Sgibbs clr A; /* add sizeof(struct scatter) */ 69263457Sgibbs add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; 69363457Sgibbs adc SCB_RESIDUAL_SGPTR[1],A; 69463457Sgibbs adc SCB_RESIDUAL_SGPTR[2],A; 69563457Sgibbs adc SCB_RESIDUAL_SGPTR[3],A ret; 69663457Sgibbs 69774094Sgibbsif ((ahc->features & AHC_CMD_CHAN) != 0) { 69874094Sgibbsdisable_ccsgen: 69974094Sgibbs test CCSGCTL, CCSGEN jz return; 70074094Sgibbs test CCSGCTL, CCSGDONE jz .; 70174094Sgibbsdisable_ccsgen_fetch_done: 70274094Sgibbs clr CCSGCTL; 70374094Sgibbs test CCSGCTL, CCSGEN jnz .; 70474094Sgibbs ret; 70563457Sgibbsidle_loop: 70674094Sgibbs /* Did we just finish fetching segs? */ 70774094Sgibbs cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; 70863457Sgibbs 70974094Sgibbs /* Are we actively fetching segments? */ 71074094Sgibbs test CCSGCTL, CCSGEN jnz return; 71163457Sgibbs 71274094Sgibbs /* 71374094Sgibbs * Do we need any more segments? 71474094Sgibbs */ 71574094Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; 71663457Sgibbs 71774094Sgibbs /* 71874094Sgibbs * Do we have any prefetch left??? 71974094Sgibbs */ 72074094Sgibbs cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; 72163457Sgibbs 72274094Sgibbs /* 72374094Sgibbs * Need to fetch segments, but we can only do that 72474094Sgibbs * if the command channel is completely idle. Make 72574094Sgibbs * sure we don't have an SCB prefetch going on. 72674094Sgibbs */ 72774094Sgibbs test CCSCBCTL, CCSCBEN jnz return; 72863457Sgibbs 72974094Sgibbs /* 73074094Sgibbs * We fetch a "cacheline aligned" and sized amount of data 73174094Sgibbs * so we don't end up referencing a non-existant page. 73274094Sgibbs * Cacheline aligned is in quotes because the kernel will 73374094Sgibbs * set the prefetch amount to a reasonable level if the 73474094Sgibbs * cacheline size is unknown. 73574094Sgibbs */ 73674094Sgibbs mvi CCHCNT, SG_PREFETCH_CNT; 73774094Sgibbs and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; 73874094Sgibbs bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; 73974094Sgibbs mvi CCSGCTL, CCSGEN|CCSGRESET ret; 74063457Sgibbsidle_sgfetch_complete: 74174094Sgibbs call disable_ccsgen_fetch_done; 74274094Sgibbs and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; 74363457Sgibbsidle_sg_avail: 74474094Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 74574094Sgibbs /* Does the hardware have space for another SG entry? */ 74674094Sgibbs test DFSTATUS, PRELOAD_AVAIL jz return; 74774094Sgibbs bmov HADDR, CCSGRAM, 4; 74874094Sgibbs bmov SINDEX, CCSGRAM, 1; 74974094Sgibbs test SINDEX, 0x1 jz . + 2; 75074094Sgibbs xor DATA_COUNT_ODD, 0x1; 75174094Sgibbs bmov HCNT[0], SINDEX, 1; 75274094Sgibbs bmov HCNT[1], CCSGRAM, 2; 75374094Sgibbs bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; 75474094Sgibbs call sg_advance; 75574094Sgibbs mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 75674094Sgibbs test DATA_COUNT_ODD, 0x1 jz . + 2; 75774094Sgibbs or SINDEX, ODD_SEG; 75874094Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 75974094Sgibbs or SINDEX, LAST_SEG; 76074094Sgibbs mov SG_CACHE_PRE, SINDEX; 76174094Sgibbs /* Load the segment by writing DFCNTRL again */ 76274094Sgibbs mov DFCNTRL, DMAPARAMS; 76363457Sgibbs } 76474094Sgibbs ret; 76574094Sgibbs} 76663457Sgibbs 76765942Sgibbsif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 76813177Sgibbs/* 76965942Sgibbs * Calculate the trailing portion of this S/G segment that cannot 77065942Sgibbs * be transferred using memory write and invalidate PCI transactions. 77165942Sgibbs * XXX Can we optimize this for PCI writes only??? 77265942Sgibbs */ 77365942Sgibbscalc_mwi_residual: 77465942Sgibbs /* 77565942Sgibbs * If the ending address is on a cacheline boundary, 77665942Sgibbs * there is no need for an extra segment. 77765942Sgibbs */ 77865942Sgibbs mov A, HCNT[0]; 77965942Sgibbs add A, A, HADDR[0]; 78065942Sgibbs and A, CACHESIZE_MASK; 78165942Sgibbs test A, 0xFF jz return; 78265942Sgibbs 78365942Sgibbs /* 78465942Sgibbs * If the transfer is less than a cachline, 78565942Sgibbs * there is no need for an extra segment. 78665942Sgibbs */ 78765942Sgibbs test HCNT[1], 0xFF jnz calc_mwi_residual_final; 78865942Sgibbs test HCNT[2], 0xFF jnz calc_mwi_residual_final; 78965942Sgibbs add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; 79065942Sgibbs jnc return; 79165942Sgibbs 79265942Sgibbscalc_mwi_residual_final: 79365942Sgibbs mov MWI_RESIDUAL, A; 79465942Sgibbs not A; 79565942Sgibbs inc A; 79665942Sgibbs add HCNT[0], A; 79765942Sgibbs adc HCNT[1], -1; 79865942Sgibbs adc HCNT[2], -1 ret; 79965942Sgibbs} 80065942Sgibbs 80165942Sgibbs/* 80213177Sgibbs * If we re-enter the data phase after going through another phase, the 80313177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 80413177Sgibbs */ 8059928Sgibbsdata_phase_reinit: 80651471Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 80751471Sgibbs /* 80851471Sgibbs * The preload circuitry requires us to 80951471Sgibbs * reload the address too, so pull it from 81051471Sgibbs * the shaddow address. 81151471Sgibbs */ 81251471Sgibbs bmov HADDR, SHADDR, 4; 81363457Sgibbs bmov HCNT, SCB_RESIDUAL_DATACNT, 3; 81451471Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 81563457Sgibbs bmov STCNT, SCB_RESIDUAL_DATACNT, 3; 81639220Sgibbs } else { 81739220Sgibbs mvi DINDEX, STCNT; 81863457Sgibbs mvi SCB_RESIDUAL_DATACNT call bcopy_3; 81939220Sgibbs } 82063457Sgibbs and DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0]; 82123925Sgibbs jmp data_phase_loop; 8224568Sgibbs 82339220Sgibbsp_data: 82439220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 82539220Sgibbs mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; 82639220Sgibbs } else { 82739220Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 82839220Sgibbs } 82939220Sgibbs test LASTPHASE, IOI jnz . + 2; 83039220Sgibbs or DMAPARAMS, DIRECTION; 83123925Sgibbs call assert; /* 83219164Sgibbs * Ensure entering a data 83319164Sgibbs * phase is okay - seen identify, etc. 83419164Sgibbs */ 83539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 83663457Sgibbs /* We don't have any valid S/G elements */ 83766647Sgibbs mvi CCSGADDR, SG_PREFETCH_CNT; 83839220Sgibbs } 83923925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 8404568Sgibbs 84139220Sgibbs /* We have seen a data phase */ 84239220Sgibbs or SEQ_FLAGS, DPHASE; 84339220Sgibbs 84419164Sgibbs /* 84519164Sgibbs * Initialize the DMA address and counter from the SCB. 84663457Sgibbs * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG 84763457Sgibbs * flag in the highest byte of the data count. We cannot 84863457Sgibbs * modify the saved values in the SCB until we see a save 84963457Sgibbs * data pointers message. 85019164Sgibbs */ 85139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 85239220Sgibbs bmov HADDR, SCB_DATAPTR, 7; 85363457Sgibbs bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; 85439220Sgibbs } else { 85539220Sgibbs mvi DINDEX, HADDR; 85639220Sgibbs mvi SCB_DATAPTR call bcopy_7; 85763457Sgibbs mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; 85863457Sgibbs mvi SCB_DATACNT + 3 call bcopy_5; 85939220Sgibbs } 86065942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 86165942Sgibbs call calc_mwi_residual; 86265942Sgibbs } 86363457Sgibbs and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; 86465942Sgibbs and DATA_COUNT_ODD, 0x1, HCNT[0]; 86519164Sgibbs 86639220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 86739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 86839220Sgibbs bmov STCNT, HCNT, 3; 86939220Sgibbs } else { 87039220Sgibbs call set_stcnt_from_hcnt; 87139220Sgibbs } 87239220Sgibbs } 87319164Sgibbs 87463457Sgibbsdata_phase_loop: 87563457Sgibbs /* Guard against overruns */ 87663457Sgibbs test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; 87719164Sgibbs 87863457Sgibbs /* 87968087Sgibbs * Turn on `Bit Bucket' mode, wait until the target takes 88068087Sgibbs * us to another phase, and then notify the host. 88163457Sgibbs */ 88268087Sgibbs and DMAPARAMS, DIRECTION; 88368087Sgibbs mov DFCNTRL, DMAPARAMS; 88423925Sgibbs or SXFRCTL1,BITBUCKET; 88568087Sgibbs test SSTAT1,PHASEMIS jz .; 88668087Sgibbs and SXFRCTL1, ~BITBUCKET; 88768402Sgibbs mvi DATA_OVERRUN call set_seqint; 88868087Sgibbs jmp ITloop; 88968087Sgibbs 89016260Sgibbsdata_phase_inbounds: 89139220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 89263457Sgibbs mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 89363457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 89463457Sgibbs or SINDEX, LAST_SEG; 89563457Sgibbs test DATA_COUNT_ODD, 0x1 jz . + 2; 89663457Sgibbs or SINDEX, ODD_SEG; 89763457Sgibbs mov SG_CACHE_PRE, SINDEX; 89863457Sgibbs mov DFCNTRL, DMAPARAMS; 89963457Sgibbsultra2_dma_loop: 90063457Sgibbs call idle_loop; 90163457Sgibbs /* 90263457Sgibbs * The transfer is complete if either the last segment 90363457Sgibbs * completes or the target changes phase. 90463457Sgibbs */ 90563457Sgibbs test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; 90670204Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 90770204Sgibbs /* 90870204Sgibbs * As a target, we control the phases, 90970204Sgibbs * so ignore PHASEMIS. 91070204Sgibbs */ 91170204Sgibbs test SSTAT0, TARGET jnz ultra2_dma_loop; 91270204Sgibbs } 91370204Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 91470204Sgibbs test SSTAT1,PHASEMIS jz ultra2_dma_loop; 91570204Sgibbs } 91663457Sgibbs 91763457Sgibbsultra2_dmafinish: 91863457Sgibbs test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; 91972325Sgibbs if ((ahc->features & AHC_DT) == 0) { 92072325Sgibbs and DFCNTRL, ~SCSIEN; 92172325Sgibbs test DFCNTRL, SCSIEN jnz .; 92263944Sgibbs } 92363457Sgibbsultra2_dmafifoflush: 92463457Sgibbs if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 92563457Sgibbs /* 92663457Sgibbs * On Rev A of the aic7890, the autoflush 92763457Sgibbs * features doesn't function correctly. 92863457Sgibbs * Perform an explicit manual flush. During 92963457Sgibbs * a manual flush, the FIFOEMP bit becomes 93063457Sgibbs * true every time the PCI FIFO empties 93163457Sgibbs * regardless of the state of the SCSI FIFO. 93263457Sgibbs * It can take up to 4 clock cycles for the 93363457Sgibbs * SCSI FIFO to get data into the PCI FIFO 93463457Sgibbs * and for FIFOEMP to de-assert. Here we 93563457Sgibbs * guard against this condition by making 93663457Sgibbs * sure the FIFOEMP bit stays on for 5 full 93763457Sgibbs * clock cycles. 93863457Sgibbs */ 93963457Sgibbs or DFCNTRL, FIFOFLUSH; 94063457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94163457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94263457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94363457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94463457Sgibbs } 94563457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94663457Sgibbsultra2_dmafifoempty: 94763457Sgibbs /* Don't clobber an inprogress host data transfer */ 94863457Sgibbs test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; 94963457Sgibbsultra2_dmahalt: 95063457Sgibbs and DFCNTRL, ~(SCSIEN|HDMAEN); 95163457Sgibbs test DFCNTRL, HDMAEN jnz .; 95263457Sgibbs 95363457Sgibbs /* 95463944Sgibbs * If, by chance, we stopped before being able 95563944Sgibbs * to fetch additional segments for this transfer, 95663944Sgibbs * yet the last S/G was completely exhausted, 95763944Sgibbs * call our idle loop until it is able to load 95863944Sgibbs * another segment. This will allow us to immediately 95963944Sgibbs * pickup on the next segment on the next data phase. 96063944Sgibbs * 96163944Sgibbs * If we happened to stop on the last segment, then 96263944Sgibbs * our residual information is still correct from 96363944Sgibbs * the idle loop and there is no need to perform 96463944Sgibbs * any fixups. Just jump to data_phase_finish. 96563944Sgibbs */ 96663944Sgibbsultra2_ensure_sg: 96763944Sgibbs test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; 96863944Sgibbs /* Record if we've consumed all S/G entries */ 96963944Sgibbs test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; 97063944Sgibbs or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 97163944Sgibbs jmp data_phase_finish; 97263944Sgibbs 97363944Sgibbsultra2_shvalid: 97463944Sgibbs test SSTAT2, SHVALID jnz sgptr_fixup; 97563944Sgibbs call idle_loop; 97663944Sgibbs jmp ultra2_ensure_sg; 97763944Sgibbs 97863944Sgibbssgptr_fixup: 97963944Sgibbs /* 98063457Sgibbs * Fixup the residual next S/G pointer. The S/G preload 98163457Sgibbs * feature of the chip allows us to load two elements 98263457Sgibbs * in addition to the currently active element. We 98363457Sgibbs * store the bottom byte of the next S/G pointer in 98463457Sgibbs * the SG_CACEPTR register so we can restore the 98563457Sgibbs * correct value when the DMA completes. If the next 98663457Sgibbs * sg ptr value has advanced to the point where higher 98763457Sgibbs * bytes in the address have been affected, fix them 98863457Sgibbs * too. 98963457Sgibbs */ 99063457Sgibbs test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; 99163457Sgibbs test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; 99263457Sgibbs add SCB_RESIDUAL_SGPTR[1], -1; 99363457Sgibbs adc SCB_RESIDUAL_SGPTR[2], -1; 99463457Sgibbs adc SCB_RESIDUAL_SGPTR[3], -1; 99563457Sgibbssgptr_fixup_done: 99663457Sgibbs and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; 99763457Sgibbs clr DATA_COUNT_ODD; 99863457Sgibbs test SG_CACHE_SHADOW, ODD_SEG jz . + 2; 99963457Sgibbs or DATA_COUNT_ODD, 0x1; 100063944Sgibbs clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ 100139220Sgibbs } else { 100263457Sgibbs /* If we are the last SG block, tell the hardware. */ 100365942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 100465942Sgibbs && ahc->pci_cachesize != 0) { 100565942Sgibbs test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; 100665942Sgibbs } 100763457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; 100868087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 100963944Sgibbs test SSTAT0, TARGET jz dma_last_sg; 101063944Sgibbs if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { 101163944Sgibbs test DMAPARAMS, DIRECTION jz dma_mid_sg; 101263944Sgibbs } 101357099Sgibbs } 101463944Sgibbsdma_last_sg: 101539220Sgibbs and DMAPARAMS, ~WIDEODD; 101663457Sgibbsdma_mid_sg: 101763457Sgibbs /* Start DMA data transfer. */ 101839220Sgibbs mov DFCNTRL, DMAPARAMS; 101963457Sgibbsdma_loop: 102063457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 102163457Sgibbs call idle_loop; 102263457Sgibbs } 102363457Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 102463457Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 102563457Sgibbsdma_phasemis: 102639220Sgibbs /* 102763457Sgibbs * We will be "done" DMAing when the transfer count goes to 102863457Sgibbs * zero, or the target changes the phase (in light of this, 102963457Sgibbs * it makes sense that the DMA circuitry doesn't ACK when 103063457Sgibbs * PHASEMIS is active). If we are doing a SCSI->Host transfer, 103163457Sgibbs * the data FIFO should be flushed auto-magically on STCNT=0 103263457Sgibbs * or a phase change, so just wait for FIFO empty status. 103339220Sgibbs */ 103463457Sgibbsdma_checkfifo: 103563457Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 103663457Sgibbsdma_fifoflush: 103763457Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 103863457Sgibbsdma_fifoempty: 103963457Sgibbs /* Don't clobber an inprogress host data transfer */ 104063457Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 10414568Sgibbs 104239220Sgibbs /* 104363457Sgibbs * Now shut off the DMA and make sure that the DMA 104463457Sgibbs * hardware has actually stopped. Touching the DMA 104563457Sgibbs * counters, etc. while a DMA is active will result 104663457Sgibbs * in an ILLSADDR exception. 104739220Sgibbs */ 104863457Sgibbsdma_dmadone: 104963457Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 105063457Sgibbsdma_halt: 105163457Sgibbs /* 105265942Sgibbs * Some revisions of the aic78XX have a problem where, if the 105363457Sgibbs * data fifo is full, but the PCI input latch is not empty, 105463457Sgibbs * HDMAEN cannot be cleared. The fix used here is to drain 105563457Sgibbs * the prefetched but unused data from the data fifo until 105663457Sgibbs * there is space for the input latch to drain. 105763457Sgibbs */ 105865942Sgibbs if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 105965942Sgibbs mov NONE, DFDAT; 106065942Sgibbs } 106163457Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 106222568Sgibbs 106363457Sgibbs /* See if we have completed this last segment */ 106463457Sgibbs test STCNT[0], 0xff jnz data_phase_finish; 106563457Sgibbs test STCNT[1], 0xff jnz data_phase_finish; 106663457Sgibbs test STCNT[2], 0xff jnz data_phase_finish; 10679928Sgibbs 106839220Sgibbs /* 106963457Sgibbs * Advance the scatter-gather pointers if needed 107039220Sgibbs */ 107165942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 107265942Sgibbs && ahc->pci_cachesize != 0) { 107365942Sgibbs test MWI_RESIDUAL, 0xFF jz no_mwi_resid; 107465942Sgibbs /* 107565942Sgibbs * Reload HADDR from SHADDR and setup the 107665942Sgibbs * count to be the size of our residual. 107765942Sgibbs */ 107865942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 107965942Sgibbs bmov HADDR, SHADDR, 4; 108065942Sgibbs mov HCNT, MWI_RESIDUAL; 108165942Sgibbs bmov HCNT[1], ALLZEROS, 2; 108265942Sgibbs } else { 108365942Sgibbs mvi DINDEX, HADDR; 108465942Sgibbs mvi SHADDR call bcopy_4; 108565942Sgibbs mov MWI_RESIDUAL call set_hcnt; 108665942Sgibbs } 108765942Sgibbs clr MWI_RESIDUAL; 108865942Sgibbs jmp sg_load_done; 108965942Sgibbsno_mwi_resid: 109065942Sgibbs } 109163457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; 109263457Sgibbs or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 109363457Sgibbs jmp data_phase_finish; 109463457Sgibbssg_load: 109563457Sgibbs /* 109663457Sgibbs * Load the next SG element's data address and length 109763457Sgibbs * into the DMA engine. If we don't have hardware 109863457Sgibbs * to perform a prefetch, we'll have to fetch the 109963457Sgibbs * segment from host memory first. 110063457Sgibbs */ 110139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 110263457Sgibbs /* Wait for the idle loop to complete */ 110363457Sgibbs test CCSGCTL, CCSGEN jz . + 3; 110463457Sgibbs call idle_loop; 110563457Sgibbs test CCSGCTL, CCSGEN jnz . - 1; 110663457Sgibbs bmov HADDR, CCSGRAM, 7; 110765942Sgibbs test CCSGRAM, SG_LAST_SEG jz . + 2; 110865942Sgibbs or SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG; 110939220Sgibbs } else { 111063457Sgibbs mvi DINDEX, HADDR; 111163457Sgibbs mvi SCB_RESIDUAL_SGPTR call bcopy_4; 111263457Sgibbs 111363457Sgibbs mvi SG_SIZEOF call set_hcnt; 111463457Sgibbs 111563457Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 111663457Sgibbs 111763457Sgibbs call dma_finish; 111863457Sgibbs 111965942Sgibbs mvi DINDEX, HADDR; 112065942Sgibbs call dfdat_in_7; 112163457Sgibbs mov SCB_RESIDUAL_DATACNT[3], DFDAT; 112265942Sgibbs } 112365942Sgibbs 112465942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 112565942Sgibbs && ahc->pci_cachesize != 0) { 112665942Sgibbs call calc_mwi_residual; 112765942Sgibbs } 112865942Sgibbs 112965942Sgibbs /* Point to the new next sg in memory */ 113065942Sgibbs call sg_advance; 113165942Sgibbs 113265942Sgibbssg_load_done: 113365942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 113465942Sgibbs bmov STCNT, HCNT, 3; 113565942Sgibbs } else { 113639220Sgibbs call set_stcnt_from_hcnt; 113739220Sgibbs } 113863457Sgibbs /* Track odd'ness */ 113963457Sgibbs test HCNT[0], 0x1 jz . + 2; 114063457Sgibbs xor DATA_COUNT_ODD, 0x1; 114139220Sgibbs 114268087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 114363457Sgibbs test SSTAT0, TARGET jnz data_phase_loop; 114463457Sgibbs } 114563457Sgibbs } 114663457Sgibbsdata_phase_finish: 114763457Sgibbs /* 114863457Sgibbs * If the target has left us in data phase, loop through 114963457Sgibbs * the dma code again. In the case of ULTRA2 adapters, 115063457Sgibbs * we should only loop if there is a data overrun. For 115163457Sgibbs * all other adapters, we'll loop after each S/G element 115263457Sgibbs * is loaded as well as if there is an overrun. 115363457Sgibbs */ 115468087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 115563457Sgibbs test SSTAT0, TARGET jnz data_phase_done; 115641646Sgibbs } 115768087Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 115863457Sgibbs test SSTAT1, REQINIT jz .; 115963457Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 116039220Sgibbs } 11614568Sgibbs 116263457Sgibbsdata_phase_done: 116363457Sgibbs /* 116463457Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into 116563457Sgibbs * the SCB. We use STCNT instead of HCNT, since it's a reflection 116663457Sgibbs * of how many bytes were transferred on the SCSI (as opposed to the 116763457Sgibbs * host) bus. 116863457Sgibbs */ 116939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 117063457Sgibbs /* Kill off any pending prefetch */ 117174094Sgibbs call disable_ccsgen; 117265942Sgibbs } 117363457Sgibbs 117465942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 117565942Sgibbs && ahc->pci_cachesize != 0) { 117665942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 117765942Sgibbs test MWI_RESIDUAL, 0xFF jz bmov_resid; 117865942Sgibbs } 117965942Sgibbs mov A, MWI_RESIDUAL; 118065942Sgibbs add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; 118165942Sgibbs clr A; 118265942Sgibbs adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; 118365942Sgibbs adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; 118465942Sgibbs clr MWI_RESIDUAL; 118565942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 118665942Sgibbs jmp . + 2; 118765942Sgibbsbmov_resid: 118865942Sgibbs bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 118965942Sgibbs } 119065942Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 119163457Sgibbs bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 119239220Sgibbs } else { 119365942Sgibbs mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; 119465942Sgibbs mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; 119565942Sgibbs mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; 119639220Sgibbs } 119722568Sgibbs 119863457Sgibbs /* 119963457Sgibbs * Since we've been through a data phase, the SCB_RESID* fields 120063457Sgibbs * are now initialized. Clear the full residual flag. 120163457Sgibbs */ 120263457Sgibbs and SCB_SGPTR[0], ~SG_FULL_RESID; 120363457Sgibbs 120439220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 120563457Sgibbs /* Clear the channel in case we return to data phase later */ 120639220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 120768402Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 120839220Sgibbs } 120922568Sgibbs 121068087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 121141646Sgibbs test SEQ_FLAGS, DPHASE_PENDING jz ITloop; 121239220Sgibbs and SEQ_FLAGS, ~DPHASE_PENDING; 121342652Sgibbs /* 121442652Sgibbs * For data-in phases, wait for any pending acks from the 121542652Sgibbs * initiator before changing phase. 121642652Sgibbs */ 121742652Sgibbs test DFCNTRL, DIRECTION jz target_ITloop; 121842652Sgibbs test SSTAT1, REQINIT jnz .; 121939220Sgibbs jmp target_ITloop; 122063457Sgibbs } else { 122163457Sgibbs jmp ITloop; 122239220Sgibbs } 12234568Sgibbs 122468087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 122516260Sgibbs/* 122615328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 122713177Sgibbs */ 12284568Sgibbsp_command: 122923925Sgibbs call assert; 12304568Sgibbs 123163457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 123263457Sgibbs bmov HCNT[0], SCB_CDB_LEN, 1; 123339220Sgibbs bmov HCNT[1], ALLZEROS, 2; 123463944Sgibbs mvi SG_CACHE_PRE, LAST_SEG; 123563457Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 123663457Sgibbs bmov STCNT[0], SCB_CDB_LEN, 1; 123763457Sgibbs bmov STCNT[1], ALLZEROS, 2; 123839220Sgibbs } else { 123963457Sgibbs mov STCNT[0], SCB_CDB_LEN; 124063457Sgibbs clr STCNT[1]; 124163457Sgibbs clr STCNT[2]; 124239220Sgibbs } 124363457Sgibbs add NONE, -13, SCB_CDB_LEN; 124465942Sgibbs mvi SCB_CDB_STORE jnc p_command_embedded; 124563457Sgibbsp_command_from_host: 124663457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 124763457Sgibbs bmov HADDR[0], SCB_CDB_PTR, 4; 124863457Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); 124963457Sgibbs } else { 125063457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 125163457Sgibbs bmov HADDR[0], SCB_CDB_PTR, 4; 125265942Sgibbs bmov HCNT, STCNT, 3; 125363457Sgibbs } else { 125463457Sgibbs mvi DINDEX, HADDR; 125568087Sgibbs mvi SCB_CDB_PTR call bcopy_4; 125668087Sgibbs mov SCB_CDB_LEN call set_hcnt; 125739220Sgibbs } 125839220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); 125963457Sgibbs } 126063457Sgibbs jmp p_command_loop; 126163457Sgibbsp_command_embedded: 126263457Sgibbs /* 126363457Sgibbs * The data fifo seems to require 4 byte alligned 126463457Sgibbs * transfers from the sequencer. Force this to 126563457Sgibbs * be the case by clearing HADDR[0] even though 126663457Sgibbs * we aren't going to touch host memeory. 126763457Sgibbs */ 126863457Sgibbs clr HADDR[0]; 126963457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 127063457Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); 127163457Sgibbs bmov DFDAT, SCB_CDB_STORE, 12; 127265942Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 127371390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 127465942Sgibbs /* 127565942Sgibbs * On the 7895 the data FIFO will 127665942Sgibbs * get corrupted if you try to dump 127765942Sgibbs * data from external SCB memory into 127865942Sgibbs * the FIFO while it is enabled. So, 127965942Sgibbs * fill the fifo and then enable SCSI 128065942Sgibbs * transfers. 128165942Sgibbs */ 128265942Sgibbs mvi DFCNTRL, (DIRECTION|FIFORESET); 128365942Sgibbs } else { 128465942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 128565942Sgibbs } 128665942Sgibbs bmov DFDAT, SCB_CDB_STORE, 12; 128771390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 128865942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); 128965942Sgibbs } else { 129063821Sgibbs or DFCNTRL, FIFOFLUSH; 129163821Sgibbs } 129263457Sgibbs } else { 129365942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 129463821Sgibbs call copy_to_fifo_6; 129563821Sgibbs call copy_to_fifo_6; 129663821Sgibbs or DFCNTRL, FIFOFLUSH; 129763457Sgibbs } 129863457Sgibbsp_command_loop: 129939220Sgibbs test SSTAT0, SDONE jnz . + 2; 130063457Sgibbs test SSTAT1, PHASEMIS jz p_command_loop; 130155581Sgibbs /* 130255581Sgibbs * Wait for our ACK to go-away on it's own 130355581Sgibbs * instead of being killed by SCSIEN getting cleared. 130455581Sgibbs */ 130555581Sgibbs test SCSISIGI, ACKI jnz .; 130655581Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 130739220Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; 130868087Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 130968087Sgibbs /* Drop any residual from the S/G Preload queue */ 131068087Sgibbs or SXFRCTL0, CLRSTCNT; 131168087Sgibbs } 131223925Sgibbs jmp ITloop; 13134568Sgibbs 131413177Sgibbs/* 131513177Sgibbs * Status phase. Wait for the data byte to appear, then read it 131613177Sgibbs * and store it into the SCB. 131713177Sgibbs */ 13184568Sgibbsp_status: 131923925Sgibbs call assert; 132019803Sgibbs 132163457Sgibbs mov SCB_SCSI_STATUS, SCSIDATL; 132223925Sgibbs jmp ITloop; 13234568Sgibbs 132413177Sgibbs/* 132541646Sgibbs * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full 132641646Sgibbs * indentify message sequence and send it to the target. The host may 132741646Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB 132841646Sgibbs * control byte. This will cause us to interrupt the host and allow 132941646Sgibbs * it to handle the message phase completely on its own. If the bit 133041646Sgibbs * associated with this target is set, we will also interrupt the host, 133141646Sgibbs * thereby allowing it to send a message on the next selection regardless 133241646Sgibbs * of the transaction being sent. 133339220Sgibbs * 133439220Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. 133541646Sgibbs * This is done to allow the host to send messages outside of an identify 133639220Sgibbs * sequence while protecting the seqencer from testing the MK_MESSAGE bit 133739220Sgibbs * on an SCB that might not be for the current nexus. (For example, a 133839220Sgibbs * BDR message in responce to a bad reselection would leave us pointed to 133939220Sgibbs * an SCB that doesn't have anything to do with the current target). 134041646Sgibbs * 134139220Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, 134239220Sgibbs * bus device reset). 134339220Sgibbs * 134439220Sgibbs * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, 134539220Sgibbs * in case the target decides to put us in this phase for some strange 134639220Sgibbs * reason. 134713177Sgibbs */ 134841646Sgibbsp_mesgout_retry: 134941646Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 13504568Sgibbsp_mesgout: 135139220Sgibbs mov SINDEX, MSG_OUT; 135239220Sgibbs cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; 135341646Sgibbs test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; 135463457Sgibbs mov FUNCTION1, SCB_SCSIID; 135541646Sgibbs mov A, FUNCTION1; 135647414Sgibbs mov SINDEX, TARGET_MSG_REQUEST[0]; 135741646Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 135841646Sgibbs /* Second Channel uses high byte bits */ 135963457Sgibbs test SCB_SCSIID, TWIN_CHNLB jz . + 2; 136041646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 136141646Sgibbs } else if ((ahc->features & AHC_WIDE) != 0) { 136263457Sgibbs test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ 136341646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 136441646Sgibbs } 136541646Sgibbs test SINDEX, A jnz host_message_loop; 136639220Sgibbsp_mesgout_identify: 136763457Sgibbs or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; 136863457Sgibbs test SCB_CONTROL, DISCENB jnz . + 2; 136963457Sgibbs and SINDEX, ~DISCENB; 137013177Sgibbs/* 137139220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 137239220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 137313177Sgibbs */ 137439220Sgibbsp_mesgout_tag: 137539220Sgibbs test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; 137639220Sgibbs mov SCSIDATL, SINDEX; /* Send the identify message */ 137739220Sgibbs call phase_lock; 137839220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 137939220Sgibbs and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 138039220Sgibbs call phase_lock; 138139220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 138239220Sgibbs mov SCB_TAG jmp p_mesgout_onebyte; 138313177Sgibbs/* 138441646Sgibbs * Interrupt the driver, and allow it to handle this message 138541646Sgibbs * phase and any required retries. 138613177Sgibbs */ 138739220Sgibbsp_mesgout_from_host: 138839220Sgibbs cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; 138941646Sgibbs jmp host_message_loop; 139039220Sgibbs 139139220Sgibbsp_mesgout_onebyte: 139239220Sgibbs mvi CLRSINT1, CLRATNO; 139339220Sgibbs mov SCSIDATL, SINDEX; 139439220Sgibbs 139513177Sgibbs/* 139641646Sgibbs * If the next bus phase after ATN drops is message out, it means 139713177Sgibbs * that the target is requesting that the last message(s) be resent. 139813177Sgibbs */ 139939220Sgibbs call phase_lock; 140041646Sgibbs cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; 14014568Sgibbs 140219906Sgibbsp_mesgout_done: 140323925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 140439220Sgibbs mov LAST_MSG, MSG_OUT; 140539220Sgibbs mvi MSG_OUT, MSG_NOOP; /* No message left */ 140623925Sgibbs jmp ITloop; 14074568Sgibbs 140813177Sgibbs/* 140913177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 141013177Sgibbs */ 14114568Sgibbsp_mesgin: 141223925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 14134568Sgibbs 141423925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 141523925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 141623925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 141723925Sgibbs cmp ALLZEROS,A je mesgin_complete; 141823925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 141963457Sgibbs cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; 142023925Sgibbs cmp A,MSG_NOOP je mesgin_done; 14214568Sgibbs 142213177Sgibbs/* 142341887Sgibbs * Pushed message loop to allow the kernel to 142457099Sgibbs * run it's own message state engine. To avoid an 142541887Sgibbs * extra nop instruction after signaling the kernel, 142641887Sgibbs * we perform the phase_lock before checking to see 142741887Sgibbs * if we should exit the loop and skip the phase_lock 142841887Sgibbs * in the ITloop. Performing back to back phase_locks 142941887Sgibbs * shouldn't hurt, but why do it twice... 143013177Sgibbs */ 143141887Sgibbshost_message_loop: 143268402Sgibbs mvi HOST_MSG_LOOP call set_seqint; 143341887Sgibbs call phase_lock; 143441887Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; 143541887Sgibbs jmp host_message_loop; 14369954Sgibbs 143763457Sgibbsmesgin_ign_wide_residue: 143863457Sgibbsif ((ahc->features & AHC_WIDE) != 0) { 143963457Sgibbs test SCSIRATE, WIDEXFER jz mesgin_reject; 144063457Sgibbs /* Pull the residue byte */ 144163457Sgibbs mvi ARG_1 call inb_next; 144263457Sgibbs cmp ARG_1, 0x01 jne mesgin_reject; 144363457Sgibbs test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; 144463457Sgibbs test DATA_COUNT_ODD, 0x1 jz mesgin_done; 144568402Sgibbs mvi IGN_WIDE_RES call set_seqint; 144663457Sgibbs jmp mesgin_done; 144763457Sgibbs} 144863457Sgibbs 144963457Sgibbsmesgin_reject: 145063457Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 14519954Sgibbsmesgin_done: 145223925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 145323925Sgibbs jmp ITloop; 14549954Sgibbs 14559954Sgibbsmesgin_complete: 145613177Sgibbs/* 145763457Sgibbs * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, 145819164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 145939220Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0). 146039220Sgibbs * In either of these conditions, we upload the SCB back to the host so it can 146119164Sgibbs * process this information. In the case of a non zero status byte, we 146219164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 146319164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 146468087Sgibbs * sense, it will fill the kernel SCB with a request sense command, requeue 146568087Sgibbs * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 146668087Sgibbs * RETURN_1 to SEND_SENSE. 146713177Sgibbs */ 146819164Sgibbs 146913177Sgibbs/* 147068579Sgibbs * If ATN is raised, we still want to give the target a message. 147168579Sgibbs * Perhaps there was a parity error on this last message byte. 147268579Sgibbs * Either way, the target should take us to message out phase 147372325Sgibbs * and then attempt to complete the command again. We should use a 147472325Sgibbs * critical section here to guard against a timeout triggering 147572325Sgibbs * for this command and setting ATN while we are still processing 147672325Sgibbs * the completion. 147768579Sgibbs test SCSISIGI, ATNI jnz mesgin_done; 147868579Sgibbs */ 147968579Sgibbs 148068579Sgibbs/* 148168402Sgibbs * See if we attempted to deliver a message but the target ingnored us. 148213177Sgibbs */ 148368402Sgibbs test SCB_CONTROL, MK_MESSAGE jz . + 2; 148468402Sgibbs mvi MKMSG_FAILED call set_seqint; 148568402Sgibbs 148668402Sgibbs/* 148768402Sgibbs * Check for residuals 148868402Sgibbs */ 148963457Sgibbs test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ 149063457Sgibbs test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ 149163457Sgibbs test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; 149263457Sgibbscheck_status: 149363457Sgibbs test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ 149419164Sgibbsupload_scb: 149563457Sgibbs or SCB_SGPTR, SG_RESID_VALID; 149623925Sgibbs mvi DMAPARAMS, FIFORESET; 149723925Sgibbs mov SCB_TAG call dma_scb; 149863457Sgibbs test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ 149968402Sgibbs mvi BAD_STATUS call set_seqint; /* let driver know */ 150039220Sgibbs cmp RETURN_1, SEND_SENSE jne complete; 150168087Sgibbs call add_scb_to_free_list; 150223925Sgibbs jmp await_busfree; 150339220Sgibbscomplete: 150439220Sgibbs mov SCB_TAG call complete_post; 150523925Sgibbs jmp await_busfree; 150641646Sgibbs} 15074568Sgibbs 150839220Sgibbscomplete_post: 150939220Sgibbs /* Post the SCBID in SINDEX and issue an interrupt */ 151044507Sgibbs call add_scb_to_free_list; 151139220Sgibbs mov ARG_1, SINDEX; 151239220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 151339220Sgibbs mov A, SDSCB_QOFF; 151439220Sgibbs } else { 151539220Sgibbs mov A, QOUTPOS; 151639220Sgibbs } 151739220Sgibbs mvi QOUTFIFO_OFFSET call post_byte_setup; 151839220Sgibbs mov ARG_1 call post_byte; 151939220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) == 0) { 152039220Sgibbs inc QOUTPOS; 152139220Sgibbs } 152239220Sgibbs mvi INTSTAT,CMDCMPLT ret; 152339220Sgibbs 152468087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 152513177Sgibbs/* 152613177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 152763457Sgibbs * and await the bus going free. If this is an untagged transaction 152863457Sgibbs * store the SCB id for it in our untagged target table for lookup on 152963457Sgibbs * a reselction. 153013177Sgibbs */ 15319954Sgibbsmesgin_disconnect: 153268579Sgibbs /* 153368579Sgibbs * If ATN is raised, we still want to give the target a message. 153468579Sgibbs * Perhaps there was a parity error on this last message byte 153568579Sgibbs * or we want to abort this command. Either way, the target 153668579Sgibbs * should take us to message out phase and then attempt to 153768579Sgibbs * disconnect again. 153868579Sgibbs * XXX - Wait for more testing. 153968579Sgibbs test SCSISIGI, ATNI jnz mesgin_done; 154068579Sgibbs */ 154168579Sgibbs 154223925Sgibbs or SCB_CONTROL,DISCONNECTED; 154363457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 154463457Sgibbs call add_scb_to_disc_list; 154563457Sgibbs } 154663457Sgibbs test SCB_CONTROL, TAG_ENB jnz await_busfree; 154763457Sgibbs mov ARG_1, SCB_TAG; 154863457Sgibbs mov SAVED_LUN, SCB_LUN; 154968087Sgibbs mov SCB_SCSIID call set_busy_target; 155023925Sgibbs jmp await_busfree; 155119164Sgibbs 155215328Sgibbs/* 155319164Sgibbs * Save data pointers message: 155419164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 155519164Sgibbs * only if we've actually been into a data phase to change them. This 155619164Sgibbs * protects against bogus data in scratch ram and the residual counts 155719164Sgibbs * since they are only initialized when we go into data_in or data_out. 155815328Sgibbs */ 155919164Sgibbsmesgin_sdptrs: 156023925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 15614568Sgibbs 156239220Sgibbs /* 156363457Sgibbs * The SCB_SGPTR becomes the next one we'll download, 156463457Sgibbs * and the SCB_DATAPTR becomes the current SHADDR. 156539220Sgibbs * Use the residual number since STCNT is corrupted by 156639220Sgibbs * any message transfer. 156739220Sgibbs */ 156839220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 156939220Sgibbs bmov SCB_DATAPTR, SHADDR, 4; 157063457Sgibbs bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; 157139220Sgibbs } else { 157239220Sgibbs mvi DINDEX, SCB_DATAPTR; 157363457Sgibbs mvi SHADDR call bcopy_4; 157463457Sgibbs mvi SCB_RESIDUAL_DATACNT call bcopy_8; 157539220Sgibbs } 157623925Sgibbs jmp mesgin_done; 15774568Sgibbs 157813177Sgibbs/* 157913177Sgibbs * Restore pointers message? Data pointers are recopied from the 158013177Sgibbs * SCB anytime we enter a data phase for the first time, so all 158113177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 158213177Sgibbs * code do the rest. 158313177Sgibbs */ 15849954Sgibbsmesgin_rdptrs: 158523925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 158623925Sgibbs * We'll reload them 158713177Sgibbs * the next time through 158823925Sgibbs * the dataphase. 158913177Sgibbs */ 159023925Sgibbs jmp mesgin_done; 15914568Sgibbs 159213177Sgibbs/* 159363457Sgibbs * Index into our Busy Target table. SINDEX and DINDEX are modified 159463457Sgibbs * upon return. SCBPTR may be modified by this action. 159563457Sgibbs */ 159668087Sgibbsset_busy_target: 159768087Sgibbs shr DINDEX, 4, SINDEX; 159871390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 159963457Sgibbs mov SCBPTR, SAVED_LUN; 160068087Sgibbs add DINDEX, SCB_64_BTT; 160163457Sgibbs } else { 160268087Sgibbs add DINDEX, BUSY_TARGETS; 160363457Sgibbs } 160468087Sgibbs mov DINDIR, ARG_1 ret; 160563457Sgibbs 160663457Sgibbs/* 160713177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 160813177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 160913177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 161013177Sgibbs */ 16119954Sgibbsmesgin_identify: 161263457Sgibbs /* 161363457Sgibbs * Determine whether a target is using tagged or non-tagged 161463457Sgibbs * transactions by first looking at the transaction stored in 161563457Sgibbs * the busy target array. If there is no untagged transaction 161663457Sgibbs * for this target or the transaction is for a different lun, then 161763457Sgibbs * this must be an untagged transaction. 161863457Sgibbs */ 161972325Sgibbs shr SINDEX, 4, SAVED_SCSIID; 162071390Sgibbs and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; 162171390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 162271390Sgibbs add SINDEX, SCB_64_BTT; 162368087Sgibbs mov SCBPTR, SAVED_LUN; 162471390Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 162571390Sgibbs add NONE, -SCB_64_BTT, SINDEX; 162671390Sgibbs jc . + 2; 162771390Sgibbs mvi INTSTAT, OUT_OF_RANGE; 162871390Sgibbs nop; 162971390Sgibbs add NONE, -(SCB_64_BTT + 16), SINDEX; 163071390Sgibbs jnc . + 2; 163171390Sgibbs mvi INTSTAT, OUT_OF_RANGE; 163271390Sgibbs nop; 163371390Sgibbs } 163468087Sgibbs } else { 163571390Sgibbs add SINDEX, BUSY_TARGETS; 163668087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 163771390Sgibbs add NONE, -BUSY_TARGETS, SINDEX; 163868087Sgibbs jc . + 2; 163968087Sgibbs mvi INTSTAT, OUT_OF_RANGE; 164068402Sgibbs nop; 164171390Sgibbs add NONE, -(BUSY_TARGETS + 16), SINDEX; 164268087Sgibbs jnc . + 2; 164368087Sgibbs mvi INTSTAT, OUT_OF_RANGE; 164468402Sgibbs nop; 164568087Sgibbs } 164668087Sgibbs } 164768087Sgibbs mov ARG_1, SINDIR; 164868087Sgibbs cmp ARG_1, SCB_LIST_NULL je snoop_tag; 164963457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 165068579Sgibbs mov ARG_1 call findSCB; 165139220Sgibbs } else { 165274094Sgibbs mov SCBPTR, ARG_1; 165339220Sgibbs } 165471390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 165563457Sgibbs jmp setup_SCB_id_lun_okay; 165663457Sgibbs } else { 165774094Sgibbs /* 165874094Sgibbs * We only allow one untagged command per-target 165974094Sgibbs * at a time. So, if the lun doesn't match, look 166074094Sgibbs * for a tag message. 166174094Sgibbs */ 166274094Sgibbs mov A, SCB_LUN; 166374094Sgibbs cmp SAVED_LUN, A je setup_SCB_id_lun_okay; 166474094Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 166574094Sgibbs /* 166674094Sgibbs * findSCB removes the SCB from the 166774094Sgibbs * disconnected list, so we must replace 166874094Sgibbs * it there should this SCB be for another 166974094Sgibbs * lun. 167074094Sgibbs */ 167174094Sgibbs call cleanup_scb; 167274094Sgibbs } 167363457Sgibbs } 167439220Sgibbs 167513177Sgibbs/* 167613177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 167723168Sgibbs * If we get one, we use the tag returned to find the proper 167863457Sgibbs * SCB. With SCB paging, we must search for non-tagged 167963457Sgibbs * transactions since the SCB may exist in any slot. If we're not 168063457Sgibbs * using SCB paging, we can use the tag as the direct index to the 168163457Sgibbs * SCB. 168213177Sgibbs */ 168324608Sgibbssnoop_tag: 168471390Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 168571390Sgibbs or SEQ_FLAGS, 0x80; 168671390Sgibbs } 168723925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 168839220Sgibbs call phase_lock; 168968087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 169068087Sgibbs or SEQ_FLAGS, 0x1; 169168087Sgibbs } 169223925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 169368087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 169468087Sgibbs or SEQ_FLAGS, 0x2; 169568087Sgibbs } 169623925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 16976608Sgibbsget_tag: 169863457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 169963457Sgibbs mvi ARG_1 call inb_next; /* tag value */ 170063457Sgibbs mov ARG_1 call findSCB; 170163457Sgibbs } else { 170268087Sgibbs mvi ARG_1 call inb_next; /* tag value */ 170368087Sgibbs mov SCBPTR, ARG_1; 170463457Sgibbs } 170513177Sgibbs 170663457Sgibbs/* 170763457Sgibbs * Ensure that the SCB the tag points to is for 170863457Sgibbs * an SCB transaction to the reconnecting target. 170963457Sgibbs */ 171039220Sgibbssetup_SCB: 171168087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 171268087Sgibbs or SEQ_FLAGS, 0x4; 171368087Sgibbs } 171471390Sgibbs mov A, SCB_SCSIID; 171571390Sgibbs cmp SAVED_SCSIID, A jne not_found_cleanup_scb; 171668087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 171768087Sgibbs or SEQ_FLAGS, 0x8; 171868087Sgibbs } 171971390Sgibbssetup_SCB_id_okay: 172071390Sgibbs mov A, SCB_LUN; 172171390Sgibbs cmp SAVED_LUN, A jne not_found_cleanup_scb; 172263457Sgibbssetup_SCB_id_lun_okay: 172368087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 172468087Sgibbs or SEQ_FLAGS, 0x10; 172563457Sgibbs } 172668087Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; 172723925Sgibbs and SCB_CONTROL,~DISCONNECTED; 172863457Sgibbs test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; 172974094Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 173074094Sgibbs mov A, SCBPTR; 173174094Sgibbs } 173268087Sgibbs mvi ARG_1, SCB_LIST_NULL; 173368087Sgibbs mov SAVED_SCSIID call set_busy_target; 173474094Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 173574094Sgibbs mov SCBPTR, A; 173674094Sgibbs } 173763457Sgibbssetup_SCB_tagged: 173868579Sgibbs mvi SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 173939220Sgibbs call set_transfer_settings; 174039220Sgibbs /* See if the host wants to send a message upon reconnection */ 174139220Sgibbs test SCB_CONTROL, MK_MESSAGE jz mesgin_done; 174239220Sgibbs mvi HOST_MSG call mk_mesg; 174323925Sgibbs jmp mesgin_done; 174415328Sgibbs 174568087Sgibbsnot_found_cleanup_scb: 174668087Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 174774094Sgibbs call cleanup_scb; 174868087Sgibbs } 174919218Sgibbsnot_found: 175068402Sgibbs mvi NO_MATCH call set_seqint; 175123925Sgibbs jmp mesgin_done; 17526608Sgibbs 17534568Sgibbsmk_mesg: 175423925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 175539220Sgibbs mov MSG_OUT,SINDEX ret; 17564568Sgibbs 175713177Sgibbs/* 175813177Sgibbs * Functions to read data in Automatic PIO mode. 175913177Sgibbs * 176013177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 176113177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 176213177Sgibbs * latched (the usual way), then read the data byte directly off the bus 176313177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 176413177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 176513177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 176613177Sgibbs * we send our ACK. 176713177Sgibbs * 176813177Sgibbs * The assumption here is that these are called in a particular sequence, 176913177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 177013177Sgibbs * use the same calling convention as inb. 177113177Sgibbs */ 177257099Sgibbsinb_next_wait_perr: 177368402Sgibbs mvi PERR_DETECTED call set_seqint; 177457099Sgibbs jmp inb_next_wait; 177513177Sgibbsinb_next: 177623925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 177713360Sgibbsinb_next_wait: 177821947Sgibbs /* 177921947Sgibbs * If there is a parity error, wait for the kernel to 178021947Sgibbs * see the interrupt and prepare our message response 178121947Sgibbs * before continuing. 178221947Sgibbs */ 178323925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 178457099Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait_perr; 178557099Sgibbsinb_next_check_phase: 178623925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 178723925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 178819623Sgibbsinb_first: 178923925Sgibbs mov DINDEX,SINDEX; 179023925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 179113177Sgibbsinb_last: 179223925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 179341646Sgibbs} 17944568Sgibbs 179568087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 179641646Sgibbs/* 179741646Sgibbs * Change to a new phase. If we are changing the state of the I/O signal, 179841646Sgibbs * from out to in, wait an additional data release delay before continuing. 179941646Sgibbs */ 180041646Sgibbschange_phase: 180172640Sasmodai /* Wait for preceding I/O session to complete. */ 180243880Sgibbs test SCSISIGI, ACKI jnz .; 180343880Sgibbs 180443880Sgibbs /* Change the phase */ 180541646Sgibbs and DINDEX, IOI, SCSISIGI; 180641646Sgibbs mov SCSISIGO, SINDEX; 180741646Sgibbs and A, IOI, SINDEX; 180843880Sgibbs 180943880Sgibbs /* 181043880Sgibbs * If the data direction has changed, from 181143880Sgibbs * out (initiator driving) to in (target driving), 181263457Sgibbs * we must wait at least a data release delay plus 181343880Sgibbs * the normal bus settle delay. [SCSI III SPI 10.11.0] 181443880Sgibbs */ 181541646Sgibbs cmp DINDEX, A je change_phase_wait; 181641646Sgibbs test SINDEX, IOI jz change_phase_wait; 181741646Sgibbs call change_phase_wait; 181841646Sgibbschange_phase_wait: 181941646Sgibbs nop; 182041646Sgibbs nop; 182141646Sgibbs nop; 182241646Sgibbs nop ret; 182341646Sgibbs 182441646Sgibbs/* 182541646Sgibbs * Send a byte to an initiator in Automatic PIO mode. 182641646Sgibbs */ 182739220Sgibbstarget_outb: 182839220Sgibbs or SXFRCTL0, SPIOEN; 182939220Sgibbs test SSTAT0, SPIORDY jz .; 183039220Sgibbs mov SCSIDATL, SINDEX; 183139220Sgibbs test SSTAT0, SPIORDY jz .; 183241646Sgibbs and SXFRCTL0, ~SPIOEN ret; 183339220Sgibbs} 183439220Sgibbs 18354568Sgibbs 183613177Sgibbs/* 183713177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 183813177Sgibbs * message. 183913177Sgibbs */ 18404568Sgibbsassert: 184123925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 18424568Sgibbs 184368402Sgibbs mvi NO_IDENT jmp set_seqint; /* no - tell the kernel */ 18444568Sgibbs 184513177Sgibbs/* 184663457Sgibbs * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will 184763457Sgibbs * be set to the position of the SCB. If the SCB cannot be found locally, 184863457Sgibbs * it will be paged in from host memory. RETURN_2 stores the address of the 184963457Sgibbs * preceding SCB in the disconnected list which can be used to speed up 185063457Sgibbs * removal of the found SCB from the disconnected list. 185113177Sgibbs */ 185265942Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) { 185368579SgibbsBEGIN_CRITICAL 18544568SgibbsfindSCB: 185568087Sgibbs mov A, SINDEX; /* Tag passed in SINDEX */ 185668087Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; 185763457Sgibbs mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ 185868087Sgibbs mvi ARG_2, SCB_LIST_NULL; /* Head of list */ 185963457Sgibbs jmp findSCB_loop; 186039220SgibbsfindSCB_next: 186163457Sgibbs cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; 186268087Sgibbs mov ARG_2, SCBPTR; 186339220Sgibbs mov SCBPTR,SCB_NEXT; 186423168SgibbsfindSCB_loop: 186563457Sgibbs cmp SCB_TAG, A jne findSCB_next; 186619164Sgibbsrem_scb_from_disc_list: 186739220Sgibbs cmp ARG_2, SCB_LIST_NULL je rHead; 186839220Sgibbs mov DINDEX, SCB_NEXT; 186968087Sgibbs mov SINDEX, SCBPTR; 187039220Sgibbs mov SCBPTR, ARG_2; 187139220Sgibbs mov SCB_NEXT, DINDEX; 187223925Sgibbs mov SCBPTR, SINDEX ret; 187315328SgibbsrHead: 187423925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 187568579SgibbsEND_CRITICAL 187668087SgibbsfindSCB_notFound: 187768087Sgibbs /* 187868087Sgibbs * We didn't find it. Page in the SCB. 187968087Sgibbs */ 188068087Sgibbs mov ARG_1, A; /* Save tag */ 188168087Sgibbs mov ALLZEROS call get_free_or_disc_scb; 188268087Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 188368087Sgibbs mov ARG_1 jmp dma_scb; 188468087Sgibbs} 18854568Sgibbs 188639220Sgibbs/* 188739220Sgibbs * Prepare the hardware to post a byte to host memory given an 188863457Sgibbs * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. 188939220Sgibbs */ 189039220Sgibbspost_byte_setup: 189139220Sgibbs mov ARG_2, SINDEX; 189239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 189339220Sgibbs mvi DINDEX, CCHADDR; 189463457Sgibbs mvi SHARED_DATA_ADDR call set_1byte_addr; 189539220Sgibbs mvi CCHCNT, 1; 189639220Sgibbs mvi CCSCBCTL, CCSCBRESET ret; 189739220Sgibbs } else { 189839220Sgibbs mvi DINDEX, HADDR; 189963457Sgibbs mvi SHARED_DATA_ADDR call set_1byte_addr; 190063457Sgibbs mvi 1 call set_hcnt; 190139220Sgibbs mvi DFCNTRL, FIFORESET ret; 190239220Sgibbs } 190339220Sgibbs 190439220Sgibbspost_byte: 190539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 190639220Sgibbs bmov CCSCBRAM, SINDEX, 1; 190739220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 190839220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 190939220Sgibbs clr CCSCBCTL ret; 191039220Sgibbs } else { 191139220Sgibbs mov DFDAT, SINDEX; 191239220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 191339220Sgibbs jmp dma_finish; 191439220Sgibbs } 191539220Sgibbs 191657099Sgibbsphase_lock_perr: 191768402Sgibbs mvi PERR_DETECTED call set_seqint; 191839220Sgibbsphase_lock: 191957099Sgibbs /* 192057099Sgibbs * If there is a parity error, wait for the kernel to 192157099Sgibbs * see the interrupt and prepare our message response 192257099Sgibbs * before continuing. 192357099Sgibbs */ 192439220Sgibbs test SSTAT1, REQINIT jz phase_lock; 192557099Sgibbs test SSTAT1, SCSIPERR jnz phase_lock_perr; 192657099Sgibbsphase_lock_latch_phase: 192741646Sgibbs and SCSISIGO, PHASE_MASK, SCSISIGI; 192841646Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI ret; 192939220Sgibbs 193039220Sgibbsif ((ahc->features & AHC_CMD_CHAN) == 0) { 193163457Sgibbsset_hcnt: 193263457Sgibbs mov HCNT[0], SINDEX; 193363457Sgibbsclear_hcnt: 193463457Sgibbs clr HCNT[1]; 193563457Sgibbs clr HCNT[2] ret; 193663457Sgibbs 193719164Sgibbsset_stcnt_from_hcnt: 193823925Sgibbs mov STCNT[0], HCNT[0]; 193923925Sgibbs mov STCNT[1], HCNT[1]; 194023925Sgibbs mov STCNT[2], HCNT[2] ret; 19414568Sgibbs 194263457Sgibbsbcopy_8: 194363457Sgibbs mov DINDIR, SINDIR; 194419164Sgibbsbcopy_7: 194523925Sgibbs mov DINDIR, SINDIR; 194623925Sgibbs mov DINDIR, SINDIR; 194719164Sgibbsbcopy_5: 194823925Sgibbs mov DINDIR, SINDIR; 194919164Sgibbsbcopy_4: 195023925Sgibbs mov DINDIR, SINDIR; 195119164Sgibbsbcopy_3: 195223925Sgibbs mov DINDIR, SINDIR; 195323925Sgibbs mov DINDIR, SINDIR; 195423925Sgibbs mov DINDIR, SINDIR ret; 195539220Sgibbs} 19564568Sgibbs 195768087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 195839220Sgibbs/* 195939220Sgibbs * Setup addr assuming that A is an index into 196039220Sgibbs * an array of 32byte objects, SINDEX contains 196139220Sgibbs * the base address of that array, and DINDEX 196239220Sgibbs * contains the base address of the location 196339220Sgibbs * to store the indexed address. 196439220Sgibbs */ 196539220Sgibbsset_32byte_addr: 196639220Sgibbs shr ARG_2, 3, A; 196739220Sgibbs shl A, 5; 196839220Sgibbs jmp set_1byte_addr; 196939220Sgibbs} 197039220Sgibbs 197139220Sgibbs/* 197239220Sgibbs * Setup addr assuming that A is an index into 197339220Sgibbs * an array of 64byte objects, SINDEX contains 197439220Sgibbs * the base address of that array, and DINDEX 197539220Sgibbs * contains the base address of the location 197639220Sgibbs * to store the indexed address. 197739220Sgibbs */ 197839220Sgibbsset_64byte_addr: 197939220Sgibbs shr ARG_2, 2, A; 198039220Sgibbs shl A, 6; 198139220Sgibbs 198239220Sgibbs/* 198363457Sgibbs * Setup addr assuming that A + (ARG_2 * 256) is an 198439220Sgibbs * index into an array of 1byte objects, SINDEX contains 198539220Sgibbs * the base address of that array, and DINDEX contains 198639220Sgibbs * the base address of the location to store the computed 198739220Sgibbs * address. 198839220Sgibbs */ 198939220Sgibbsset_1byte_addr: 199039220Sgibbs add DINDIR, A, SINDIR; 199139220Sgibbs mov A, ARG_2; 199239220Sgibbs adc DINDIR, A, SINDIR; 199339220Sgibbs clr A; 199439220Sgibbs adc DINDIR, A, SINDIR; 199539220Sgibbs adc DINDIR, A, SINDIR ret; 199639220Sgibbs 199739220Sgibbs/* 199839220Sgibbs * Either post or fetch and SCB from host memory based on the 199939220Sgibbs * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. 200039220Sgibbs */ 200119164Sgibbsdma_scb: 200239220Sgibbs mov A, SINDEX; 200339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 200439220Sgibbs mvi DINDEX, CCHADDR; 200539220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 200639220Sgibbs mov CCSCBPTR, SCBPTR; 200739220Sgibbs test DMAPARAMS, DIRECTION jz dma_scb_tohost; 200871390Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 200965942Sgibbs mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; 201065942Sgibbs } else { 201165942Sgibbs mvi CCHCNT, SCB_DOWNLOAD_SIZE; 201265942Sgibbs } 201339220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; 201439220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; 201539220Sgibbs jmp dma_scb_finish; 201639220Sgibbsdma_scb_tohost: 201765942Sgibbs mvi CCHCNT, SCB_UPLOAD_SIZE; 201865942Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 201939220Sgibbs mvi CCSCBCTL, CCSCBRESET; 202065942Sgibbs bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; 202139220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 202268579Sgibbs test CCSCBCTL, CCSCBDONE jz .; 202365942Sgibbs } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { 202465942Sgibbs mvi CCSCBCTL, CCARREN|CCSCBRESET; 202565942Sgibbs cmp CCSCBCTL, ARRDONE|CCARREN jne .; 202665942Sgibbs mvi CCHCNT, SCB_UPLOAD_SIZE; 202765942Sgibbs mvi CCSCBCTL, CCSCBEN|CCSCBRESET; 202865942Sgibbs cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; 202939220Sgibbs } else { 203039220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; 203139220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; 203239220Sgibbs } 203339220Sgibbsdma_scb_finish: 203439220Sgibbs clr CCSCBCTL; 203539220Sgibbs test CCSCBCTL, CCARREN|CCSCBEN jnz .; 203639220Sgibbs ret; 203739220Sgibbs } else { 203839220Sgibbs mvi DINDEX, HADDR; 203939220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 204065942Sgibbs mvi SCB_DOWNLOAD_SIZE call set_hcnt; 204139220Sgibbs mov DFCNTRL, DMAPARAMS; 204239220Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 204339220Sgibbs /* Fill it with the SCB data */ 204424175Sgibbscopy_scb_tofifo: 204565942Sgibbs mvi SINDEX, SCB_BASE; 204665942Sgibbs add A, SCB_DOWNLOAD_SIZE, SINDEX; 204724175Sgibbscopy_scb_tofifo_loop: 204865942Sgibbs call copy_to_fifo_8; 204939220Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 205039220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 205165942Sgibbs jmp dma_finish; 205219164Sgibbsdma_scb_fromhost: 205365942Sgibbs mvi DINDEX, SCB_BASE; 205465942Sgibbs if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 205565942Sgibbs /* 205665942Sgibbs * The PCI module will only issue a PCI 205765942Sgibbs * retry if the data FIFO is empty. If the 205865942Sgibbs * host disconnects in the middle of a 205965942Sgibbs * transfer, we must empty the fifo of all 206065942Sgibbs * available data to force the chip to 206165942Sgibbs * continue the transfer. This does not 206265942Sgibbs * happen for SCSI transfers as the SCSI module 206365942Sgibbs * will drain the FIFO as data is made available. 206472325Sgibbs * When the hang occurs, we know that a multiple 206572325Sgibbs * of 8 bytes are in the FIFO because the PCI 206665942Sgibbs * module has an 8 byte input latch that only 206765942Sgibbs * dumps to the FIFO when HCNT == 0 or the 206865942Sgibbs * latch is full. 206965942Sgibbs */ 207072325Sgibbs clr A; 207165942Sgibbs /* Wait for some data to arrive. */ 207265942Sgibbsdma_scb_hang_fifo: 207365942Sgibbs test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo; 207465942Sgibbsdma_scb_hang_wait: 207565942Sgibbs test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; 207665942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 207765942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 207865942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 207974094Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 208065942Sgibbs /* 208172325Sgibbs * The PCI module no longer intends to perform 208272325Sgibbs * a PCI transaction and HDONE has not come true. 208365942Sgibbs * We are hung. Drain the fifo. 208465942Sgibbs */ 208565942Sgibbsdma_scb_hang_empty_fifo: 208665942Sgibbs /* 208772325Sgibbs * Skip lines not yet transfered into the FIFO. 208865942Sgibbs */ 208972325Sgibbs add SINDEX, 7, HCNT; 209072325Sgibbs shr SINDEX, 3; 209172325Sgibbs 209272325Sgibbs /* 209372325Sgibbs * Skip lines already copied out of the FIFO. 209472325Sgibbs */ 209572325Sgibbs add A, A, SINDEX; 209672325Sgibbs 209772325Sgibbs call dma_scb_hang_dma_drain_fifo; 209872325Sgibbs 209972325Sgibbs /* 210072325Sgibbs * Set the lines transferred to all but 210172325Sgibbs * those yet to reach the FIFO. 210272325Sgibbs */ 210372325Sgibbs not SINDEX; 210472325Sgibbs add A, 5, SINDEX; 210565942Sgibbs jmp dma_scb_hang_fifo; 210665942Sgibbsdma_scb_hang_dma_done: 210765942Sgibbs and DFCNTRL, ~HDMAEN; 210865942Sgibbs test DFCNTRL, HDMAEN jnz .; 210972325Sgibbsdma_scb_hang_dma_drain_fifo: 211072325Sgibbs add SEQADDR0, A; 211165942Sgibbs } else { 211265942Sgibbs call dma_finish; 211365942Sgibbs } 211472325Sgibbs /* If we were putting the SCB, we are done */ 211572325Sgibbs call dfdat_in_8; 211672325Sgibbs call dfdat_in_8; 211772325Sgibbs call dfdat_in_8; 211865942Sgibbsdfdat_in_8: 211965942Sgibbs mov DINDIR,DFDAT; 212019164Sgibbsdfdat_in_7: 212139220Sgibbs mov DINDIR,DFDAT; 212239220Sgibbs mov DINDIR,DFDAT; 212339220Sgibbs mov DINDIR,DFDAT; 212439220Sgibbs mov DINDIR,DFDAT; 212539220Sgibbs mov DINDIR,DFDAT; 212665942Sgibbsdfdat_in_2: 212739220Sgibbs mov DINDIR,DFDAT; 212839220Sgibbs mov DINDIR,DFDAT ret; 212939220Sgibbs } 213019164Sgibbs 213165942Sgibbscopy_to_fifo_8: 213265942Sgibbs mov DFDAT,SINDIR; 213365942Sgibbs mov DFDAT,SINDIR; 213463457Sgibbscopy_to_fifo_6: 213563457Sgibbs mov DFDAT,SINDIR; 213663457Sgibbscopy_to_fifo_5: 213763457Sgibbs mov DFDAT,SINDIR; 213863457Sgibbscopy_to_fifo_4: 213963457Sgibbs mov DFDAT,SINDIR; 214063457Sgibbs mov DFDAT,SINDIR; 214163457Sgibbs mov DFDAT,SINDIR; 214263457Sgibbs mov DFDAT,SINDIR ret; 214339220Sgibbs 214413177Sgibbs/* 214519164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 214619164Sgibbs * DMA and wait for it to acknowledge that it's off. 214713177Sgibbs */ 214819164Sgibbsdma_finish: 214923925Sgibbs test DFSTATUS,HDONE jz dma_finish; 215022234Sgibbs /* Turn off DMA */ 215123925Sgibbs and DFCNTRL, ~HDMAEN; 215223925Sgibbs test DFCNTRL, HDMAEN jnz .; 215323925Sgibbs ret; 21549928Sgibbs 215574094Sgibbs/* 215674094Sgibbs * Restore an SCB that failed to match an incoming reselection 215774094Sgibbs * to the correct/safe state. If the SCB is for a disconnected 215874094Sgibbs * transaction, it must be returned to the disconnected list. 215974094Sgibbs * If it is not in the disconnected state, it must be free. 216074094Sgibbs */ 216174094Sgibbscleanup_scb: 216274094Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 216374094Sgibbs test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list; 216474094Sgibbs } 216523925Sgibbsadd_scb_to_free_list: 216639220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 216766647SgibbsBEGIN_CRITICAL 216839220Sgibbs mov SCB_NEXT, FREE_SCBH; 216957099Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 217057099Sgibbs mov FREE_SCBH, SCBPTR ret; 217166647SgibbsEND_CRITICAL 217257099Sgibbs } else { 217357099Sgibbs mvi SCB_TAG, SCB_LIST_NULL ret; 217439220Sgibbs } 21754568Sgibbs 217639220Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) { 217719164Sgibbsget_free_or_disc_scb: 217868579SgibbsBEGIN_CRITICAL 217923925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 218023925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 218119623Sgibbsreturn_error: 218268402Sgibbs mvi NO_FREE_SCB call set_seqint; 218323925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 218419623Sgibbsdequeue_disc_scb: 218523925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 218668579Sgibbs mov DISCONNECTED_SCBH, SCB_NEXT; 218768579SgibbsEND_CRITICAL 218823925Sgibbs mvi DMAPARAMS, FIFORESET; 218968579Sgibbs mov SCB_TAG jmp dma_scb; 219068579SgibbsBEGIN_CRITICAL 219119164Sgibbsdequeue_free_scb: 219223925Sgibbs mov SCBPTR, FREE_SCBH; 219323925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 219468579SgibbsEND_CRITICAL 21954568Sgibbs 219619164Sgibbsadd_scb_to_disc_list: 219713177Sgibbs/* 219819164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 219919164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 220019164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 220113177Sgibbs */ 220268087SgibbsBEGIN_CRITICAL 220323925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 220439220Sgibbs mov DISCONNECTED_SCBH, SCBPTR ret; 220568087SgibbsEND_CRITICAL 220665942Sgibbs} 220768402Sgibbsset_seqint: 220868402Sgibbs mov INTSTAT, SINDEX; 220968402Sgibbs nop; 221063457Sgibbsreturn: 221163457Sgibbs ret; 2212