aic7xxx.seq revision 74507
126997Sgibbs/* 226997Sgibbs * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. 313177Sgibbs * 442652Sgibbs * 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 1754211Sgibbs * GNU Public License ("GPL"). 1813177Sgibbs * 1926997Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2026997Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2126997Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2226997Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2326997Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2426997Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2526997Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2626997Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2726997Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2826997Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2926997Sgibbs * SUCH DAMAGE. 3013177Sgibbs * 3150477Speter * $Id: //depot/src/aic7xxx/aic7xxx.seq#24 $ 3226997Sgibbs * 334568Sgibbs * $FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 74507 2001-03-20 04:37:19Z gibbs $ 3423925Sgibbs */ 3539220Sgibbs 365647Sgibbs#include "aic7xxx.reg" 3713177Sgibbs#include "scsi_message.h" 3819164Sgibbs 3919164Sgibbs/* 4013690Sgibbs * A few words on the waiting SCB list: 4113690Sgibbs * 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 4819164Sgibbs * create yet another SCB waiting for selection. The solution used here is to 4919164Sgibbs * 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 5313177Sgibbs * command for which a second SCB has been queued. The sequencer will 544568Sgibbs * automatically consume the entries. 5514449Sgibbs */ 5623925Sgibbs 5741646Sgibbsbus_free_sel: 5823925Sgibbs /* 5941816Sgibbs * Turn off the selection hardware. We need to reset the 6039220Sgibbs * selection request in order to perform a new selection. 6139220Sgibbs */ 6239220Sgibbs and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; 6339220Sgibbs and SIMODE1, ~ENBUSFREE; 6439220Sgibbspoll_for_work: 6539220Sgibbs call clear_target_state; 6639220Sgibbs and SXFRCTL0, ~SPIOEN; 6744507Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 6823925Sgibbs clr SCSIBUSL; 6939220Sgibbs } 7039220Sgibbs test SCSISEQ, ENSELO jnz poll_for_selection; 7139220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 7239220Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 7339220Sgibbs test SCSISEQ, ENSELO jnz poll_for_selection; 7439220Sgibbs } 7539220Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 7639220Sgibbspoll_for_work_loop: 7739220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 7823925Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 7939220Sgibbs } 8039220Sgibbs test SSTAT0, SELDO|SELDI jnz selection; 8139220Sgibbstest_queue: 8239220Sgibbs /* Has the driver posted any work for us? */ 8339220SgibbsBEGIN_CRITICAL 8439220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 8539220Sgibbs test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; 8639220Sgibbs } else { 8739220Sgibbs mov A, QINPOS; 8839220Sgibbs cmp KERNEL_QINPOS, A je poll_for_work_loop; 8939220Sgibbs } 9039220Sgibbs mov ARG_1, NEXT_QUEUED_SCB; 9123925Sgibbs 9219164Sgibbs /* 9319164Sgibbs * We have at least one queued SCB now and we don't have any 9439220Sgibbs * SCBs in the list of SCBs awaiting selection. Allocate a 9539220Sgibbs * card SCB for the host's SCB and get to work on it. 9639220Sgibbs */ 9739220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 9839220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 9939220Sgibbs } else { 10039220Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 10139220Sgibbs mov SCBPTR, ARG_1; 10239220Sgibbs } 10339220Sgibbs or SEQ_FLAGS2, SCB_DMA; 1044568SgibbsEND_CRITICAL 10513690Sgibbsdma_queued_scb: 10613690Sgibbs /* 10719164Sgibbs * DMA the SCB from host ram into the current SCB location. 10823925Sgibbs */ 10919164Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 11013177Sgibbs mov ARG_1 call dma_scb; 11139220Sgibbs /* 11239220Sgibbs * Check one last time to see if this SCB was canceled 11339220Sgibbs * before we completed the DMA operation. If it was, 11439220Sgibbs * the QINFIFO next pointer will not match our saved 11519164Sgibbs * value. 11639220Sgibbs */ 11739220Sgibbs mov A, ARG_1; 11839220SgibbsBEGIN_CRITICAL 11939220Sgibbs cmp NEXT_QUEUED_SCB, A jne abort_qinscb; 12039220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 12139220Sgibbs cmp SCB_TAG, A je . + 2; 12239220Sgibbs mvi SCB_MISMATCH call set_seqint; 12319164Sgibbs } 12419164Sgibbs mov NEXT_QUEUED_SCB, SCB_NEXT; 12519164Sgibbs mov SCB_NEXT,WAITING_SCBH; 12619164Sgibbs mov WAITING_SCBH, SCBPTR; 12723925Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 12839220Sgibbs mov NONE, SNSCB_QOFF; 1294568Sgibbs } else { 13013177Sgibbs inc QINPOS; 13139220Sgibbs } 13239220Sgibbs and SEQ_FLAGS2, ~SCB_DMA; 13339220SgibbsEND_CRITICAL 13439220Sgibbsstart_waiting: 13513177Sgibbs /* 13639220Sgibbs * Start the first entry on the waiting SCB list. 13739220Sgibbs */ 13839220Sgibbs mov SCBPTR, WAITING_SCBH; 13939220Sgibbs call start_selection; 14039220Sgibbs 14139220Sgibbspoll_for_selection: 14239220Sgibbs /* 14339220Sgibbs * Twin channel devices cannot handle things like SELTO 1444568Sgibbs * interrupts on the "background" channel. So, while 1455326Sgibbs * selecting, keep polling the current channel until 14619164Sgibbs * either a selection or reselection occurs. 14719164Sgibbs */ 14819164Sgibbs test SSTAT0, SELDO|SELDI jz poll_for_selection; 14919164Sgibbs 15023925Sgibbsselection: 15123925Sgibbs /* 15223925Sgibbs * We aren't expecting a bus free, so interrupt 15323925Sgibbs * the kernel driver if it happens. 15439220Sgibbs */ 15523925Sgibbs mvi CLRSINT1,CLRBUSFREE; 15623925Sgibbs or SIMODE1, ENBUSFREE; 15723925Sgibbs 15823925Sgibbs /* 1598104Sgibbs * Guard against a bus free after (re)selection 16023925Sgibbs * but prior to enabling the busfree interrupt. SELDI 16139220Sgibbs * and SELDO will be cleared in that case. 16239220Sgibbs */ 16339220Sgibbs test SSTAT0, SELDI|SELDO jz bus_free_sel; 16439220Sgibbs test SSTAT0,SELDO jnz select_out; 16539220Sgibbsselect_in: 16639220Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 16723925Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 16844507Sgibbs test SSTAT0, TARGET jz initiator_reselect; 16944507Sgibbs } 17044507Sgibbs mvi CLRSINT0, CLRSELDI; 17144507Sgibbs 17244507Sgibbs /* 17344507Sgibbs * We've just been selected. Assert BSY and 17444507Sgibbs * setup the phase for receiving messages 17544507Sgibbs * from the target. 17644507Sgibbs * 17744507Sgibbs * If bus reset interrupts have been disabled (from a 17844507Sgibbs * previous reset), re-enable them now. Resets are only 17939220Sgibbs * of interest when we have outstanding transactions, so 18039220Sgibbs * we can safely defer re-enabling the interrupt until, 18139220Sgibbs * as a target, we start receiving transactions again. 18239220Sgibbs */ 18339220Sgibbs test SIMODE1, ENSCSIRST jnz . + 3; 18439220Sgibbs mvi CLRSINT1, CLRSCSIRSTI; 18539220Sgibbs or SIMODE1, ENSCSIRST; 18639220Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 18739220Sgibbs 18844507Sgibbs /* 18941816Sgibbs * Setup the DMA for sending the identify and 19039220Sgibbs * command information. 19113177Sgibbs */ 19239220Sgibbs or SEQ_FLAGS, CMDPHASE_PENDING; 19339220Sgibbs 19439220Sgibbs mov A, TQINPOS; 19539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 19639220Sgibbs mvi DINDEX, CCHADDR; 19739220Sgibbs mvi SHARED_DATA_ADDR call set_32byte_addr; 19839220Sgibbs mvi CCSCBCTL, CCSCBRESET; 19939220Sgibbs } else { 20039220Sgibbs mvi DINDEX, HADDR; 20139220Sgibbs mvi SHARED_DATA_ADDR call set_32byte_addr; 20239220Sgibbs mvi DFCNTRL, FIFORESET; 20339220Sgibbs } 20439220Sgibbs 20539220Sgibbs /* Initiator that selected us */ 20639220Sgibbs and SAVED_SCSIID, SELID_MASK, SELID; 20739220Sgibbs /* The Target ID we were selected at */ 20839220Sgibbs if ((ahc->features & AHC_MULTI_TID) != 0) { 20939220Sgibbs and A, OID, TARGIDIN; 21039220Sgibbs } else if ((ahc->features & AHC_ULTRA2) != 0) { 21139220Sgibbs and A, OID, SCSIID_ULTRA2; 21239220Sgibbs } else { 21339220Sgibbs and A, OID, SCSIID; 21439220Sgibbs } 21539220Sgibbs or SAVED_SCSIID, A; 21639220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 21739220Sgibbs test SBLKCTL, SELBUSB jz . + 2; 21841646Sgibbs or SAVED_SCSIID, TWIN_CHNLB; 21941646Sgibbs } 22041646Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 22142652Sgibbs mov CCSCBRAM, SAVED_SCSIID; 22239220Sgibbs } else { 22339220Sgibbs mov DFDAT, SAVED_SCSIID; 22439220Sgibbs } 22539220Sgibbs 22639220Sgibbs /* 22739220Sgibbs * If ATN isn't asserted, the target isn't interested 22841646Sgibbs * in talking to us. Go directly to bus free. 22939220Sgibbs * XXX SCSI-1 may require us to assume lun 0 if 23039220Sgibbs * ATN is false. 23139220Sgibbs */ 23241299Sgibbs test SCSISIGI, ATNI jz target_busfree; 23339220Sgibbs 23439220Sgibbs /* 23541299Sgibbs * Watch ATN closely now as we pull in messages from the 23641299Sgibbs * initiator. We follow the guidlines from section 6.5 23739220Sgibbs * of the SCSI-2 spec for what messages are allowed when. 23839220Sgibbs */ 23939220Sgibbs call target_inb; 24039220Sgibbs 24139220Sgibbs /* 24239220Sgibbs * Our first message must be one of IDENTIFY, ABORT, or 24339220Sgibbs * BUS_DEVICE_RESET. 24439220Sgibbs */ 24539220Sgibbs 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 */ 25644507Sgibbs or SEQ_FLAGS, NO_DISCONNECT; 25744507Sgibbs 25844507Sgibbs test SCSISIGI, ATNI jz ident_messages_done; 25944507Sgibbs call target_inb; 26044507Sgibbs /* 26139220Sgibbs * If this is a tagged request, the tagged message must 26244507Sgibbs * 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. 26544507Sgibbs */ 26644507Sgibbs add A, -MSG_SIMPLE_Q_TAG, DINDEX; 26744507Sgibbs jnc ident_messages_done; 26844507Sgibbs 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 { 27442652Sgibbs mov DFDAT, DINDEX; 27542652Sgibbs } 27642652Sgibbs 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; 28339220Sgibbs 28439220Sgibbs /* 28539220Sgibbs * Store the tag for the host. 28639220Sgibbs */ 28739220Sgibbs call target_inb; 28841646Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 28939220Sgibbs mov CCSCBRAM, DINDEX; 29039220Sgibbs } else { 29139220Sgibbs mov DFDAT, DINDEX; 29239220Sgibbs } 29339220Sgibbs mov INITIATOR_TAG, DINDEX; 29441299Sgibbs or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; 29542652Sgibbs test SCSISIGI, ATNI jz . + 2; 29639220Sgibbs /* Initiator still wants to give us messages */ 29739220Sgibbs call target_inb; 29839220Sgibbs jmp ident_messages_done; 29939220Sgibbs 30039220Sgibbs /* 30139220Sgibbs * Pushed message loop to allow the kernel to 30239220Sgibbs * run it's own target mode message state engine. 30339220Sgibbs */ 30439220Sgibbshost_target_message_loop: 30539220Sgibbs mvi HOST_MSG_LOOP call set_seqint; 30639220Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; 30739220Sgibbs test SSTAT0, SPIORDY jz .; 30839220Sgibbs jmp host_target_message_loop; 30941646Sgibbs 31039220Sgibbsident_messages_done: 31139220Sgibbs /* If ring buffer is full, return busy or queue full */ 31239220Sgibbs if ((ahc->features & AHC_HS_MAILBOX) != 0) { 31339220Sgibbs and A, HOST_TQINPOS, HS_MAILBOX; 31439220Sgibbs } else { 31539220Sgibbs mov A, KERNEL_TQINPOS; 31639220Sgibbs } 31739220Sgibbs cmp TQINPOS, A jne tqinfifo_has_space; 31839220Sgibbs mvi P_STATUS|BSYO call change_phase; 31939220Sgibbs test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; 32039220Sgibbs mvi STATUS_QUEUE_FULL call target_outb; 32139220Sgibbs jmp target_busfree_wait; 32239220Sgibbs mvi STATUS_BUSY call target_outb; 32339220Sgibbs jmp target_busfree_wait; 32439220Sgibbstqinfifo_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 } 33139220Sgibbs or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN; 33239220Sgibbs test SCSISIGI, ATNI jnz target_mesgout_pending; 33342652Sgibbs jmp target_ITloop; 33439220Sgibbs } 33539220Sgibbs 33639220Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 33741646Sgibbs/* 33839220Sgibbs * Reselection has been initiated by a target. Make a note that we've been 33939220Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 34039220Sgibbs */ 34139220Sgibbsinitiator_reselect: 34239220Sgibbs /* XXX test for and handle ONE BIT condition */ 34342652Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 34439220Sgibbs and SAVED_SCSIID, SELID_MASK, SELID; 34539220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 34641646Sgibbs and A, OID, SCSIID_ULTRA2; 34741646Sgibbs } else { 34842652Sgibbs and A, OID, SCSIID; 34941646Sgibbs } 35041646Sgibbs or SAVED_SCSIID, A; 35141646Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 35241646Sgibbs test SBLKCTL, SELBUSB jz . + 2; 35341646Sgibbs or SAVED_SCSIID, TWIN_CHNLB; 35441646Sgibbs } 35541646Sgibbs mvi CLRSINT0, CLRSELDI; 35641646Sgibbs jmp ITloop; 35739220Sgibbs} 35844507Sgibbs 35944507Sgibbsabort_qinscb: 36044507Sgibbs call add_scb_to_free_list; 36144507Sgibbs jmp poll_for_work_loop; 36244507Sgibbs 36344507Sgibbsstart_selection: 36444507Sgibbs /* 36544507Sgibbs * If bus reset interrupts have been disabled (from a previous 36644507Sgibbs * reset), re-enable them now. Resets are only of interest 36744507Sgibbs * when we have outstanding transactions, so we can safely 36839220Sgibbs * defer re-enabling the interrupt until, as an initiator, 36939220Sgibbs * we start sending out transactions again. 37039220Sgibbs */ 37139220Sgibbs test SIMODE1, ENSCSIRST jnz . + 3; 37239220Sgibbs mvi CLRSINT1, CLRSCSIRSTI; 37339220Sgibbs or SIMODE1, ENSCSIRST; 37442652Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 37541646Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ 37639220Sgibbs test SCB_SCSIID, TWIN_CHNLB jz . + 2; 37739220Sgibbs or SINDEX, SELBUSB; 37839220Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 37939220Sgibbs } 38039220Sgibbsinitialize_scsiid: 38139220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 38239220Sgibbs mov SCSIID_ULTRA2, SCB_SCSIID; 38341646Sgibbs } else if ((ahc->features & AHC_TWIN) != 0) { 38441646Sgibbs and SCSIID, TWIN_TID|OID, SCB_SCSIID; 38541646Sgibbs } else { 38641646Sgibbs mov SCSIID, SCB_SCSIID; 38739220Sgibbs } 38839220Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 38939220Sgibbs mov SINDEX, SCSISEQ_TEMPLATE; 39039220Sgibbs test SCB_CONTROL, TARGET_SCB jz . + 2; 39139220Sgibbs or SINDEX, TEMODE; 39241646Sgibbs mov SCSISEQ, SINDEX ret; 39339220Sgibbs } else { 39439220Sgibbs mov SCSISEQ, SCSISEQ_TEMPLATE ret; 39539220Sgibbs } 39641646Sgibbs 39739220Sgibbs/* 39823925Sgibbs * Initialize transfer settings and clear the SCSI channel. 39923925Sgibbs * SINDEX should contain any additional bit's the client wants 40013177Sgibbs * set in SXFRCTL0. We also assume that the current SCB is 40139220Sgibbs * a valid SCB for the target we wish to talk to. 40223925Sgibbs */ 40323925Sgibbsinitialize_channel: 40439545Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 40539545Sgibbsset_transfer_settings: 40639545Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 40739545Sgibbs test SCB_CONTROL, ULTRAENB jz . + 2; 40841646Sgibbs or SXFRCTL0, FAST20; 40939220Sgibbs } 41039220Sgibbs /* 41139220Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 41239220Sgibbs */ 41339220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 41439220Sgibbs bmov SCSIRATE, SCB_SCSIRATE, 2 ret; 41539220Sgibbs } else { 41639220Sgibbs mov SCSIRATE, SCB_SCSIRATE ret; 41739220Sgibbs } 41841646Sgibbs 4194568Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 42013177Sgibbs/* 42123925Sgibbs * We carefully toggle SPIOEN to allow us to return the 42223925Sgibbs * message byte we receive so it can be checked prior to 42323925Sgibbs * driving REQ on the bus for the next byte. 42423925Sgibbs */ 42523925Sgibbstarget_inb: 42639220Sgibbs /* 42725005Sgibbs * Drive REQ on the bus by enabling SCSI PIO. 42841816Sgibbs */ 42925005Sgibbs or SXFRCTL0, SPIOEN; 43025005Sgibbs /* Wait for the byte */ 43124914Sgibbs test SSTAT0, SPIORDY jz .; 43223925Sgibbs /* Prevent our read from triggering another REQ */ 43339220Sgibbs and SXFRCTL0, ~SPIOEN; 43439220Sgibbs /* Save latched contents */ 4358567Sdg mov DINDEX, SCSIDATL ret; 43639220Sgibbs} 43739220Sgibbs 43839220Sgibbs/* 43939220Sgibbs * After the selection, remove this SCB from the "waiting SCB" 44039220Sgibbs * list. This is achieved by simply moving our "next" pointer into 44141646Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 44241646Sgibbs * SCB is used, so don't bother with it now. 4434568Sgibbs */ 44439220Sgibbsselect_out: 44539220Sgibbs /* Turn off the selection hardware */ 44639220Sgibbs and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; 44739220Sgibbs mvi CLRSINT0, CLRSELDO; 44839220Sgibbs mov SCBPTR, WAITING_SCBH; 4496608Sgibbs mov WAITING_SCBH,SCB_NEXT; 45039220Sgibbs mov SAVED_SCSIID, SCB_SCSIID; 45139220Sgibbs mov SAVED_LUN, SCB_LUN; 45239220Sgibbs call initialize_channel; 45339220Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 45439220Sgibbs test SSTAT0, TARGET jz initiator_select; 45539220Sgibbs 45642652Sgibbs /* 45742652Sgibbs * We've just re-selected an initiator. 45839220Sgibbs * Assert BSY and setup the phase for 45939220Sgibbs * sending our identify messages. 46039220Sgibbs */ 46139220Sgibbs mvi P_MESGIN|BSYO call change_phase; 46239220Sgibbs 46339220Sgibbs /* 46442652Sgibbs * Start out with a simple identify message. 46539220Sgibbs */ 46639220Sgibbs or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; 46739220Sgibbs 46841646Sgibbs /* 46944507Sgibbs * If we are the result of a tagged command, send 47039220Sgibbs * a simple Q tag and the tag id. 47141646Sgibbs */ 47239220Sgibbs test SCB_CONTROL, TAG_ENB jz . + 3; 47339220Sgibbs mvi MSG_SIMPLE_Q_TAG call target_outb; 47439220Sgibbs 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 */ 48039220Sgibbs mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; 48139220Sgibbs 48239220Sgibbstarget_ITloop: 48339220Sgibbs /* 48441646Sgibbs * Start honoring ATN signals now that 48539220Sgibbs * we properly identified ourselves. 48641646Sgibbs */ 48739220Sgibbs 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; 49141646Sgibbs 49241646Sgibbs /* 49341646Sgibbs * No more work to do. Either disconnect or not depending 49441646Sgibbs * on the state of NO_DISCONNECT. 49541646Sgibbs */ 49641646Sgibbs test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 49741646Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 49839220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 49941646Sgibbs } 50041816Sgibbs mov RETURN_1, ALLZEROS; 50141816Sgibbs call complete_target_cmd; 50239220Sgibbs cmp RETURN_1, CONT_MSG_LOOP jne .; 50339220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 50443880Sgibbs mov SCB_TAG call dma_scb; 50543880Sgibbs jmp target_synccmd; 50643880Sgibbs 50739220Sgibbstarget_mesgout: 50839220Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 50939220Sgibbstarget_mesgout_continue: 51039220Sgibbs call target_inb; 51139220Sgibbstarget_mesgout_pending: 51239220Sgibbs /* Local Processing goes here... */ 51341646Sgibbs jmp host_target_message_loop; 51441646Sgibbs 51539220Sgibbstarget_disconnect: 51639220Sgibbs mvi P_MESGIN|BSYO call change_phase; 51739220Sgibbs test SEQ_FLAGS, DPHASE jz . + 2; 51839220Sgibbs mvi MSG_SAVEDATAPOINTER call target_outb; 51939220Sgibbs mvi MSG_DISCONNECT call target_outb; 52039220Sgibbs 52139220Sgibbstarget_busfree_wait: 52239220Sgibbs /* Wait for preceding I/O session to complete. */ 52339220Sgibbs test SCSISIGI, ACKI jnz .; 52439220Sgibbstarget_busfree: 52541299Sgibbs and SIMODE1, ~ENBUSFREE; 52641299Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 52741299Sgibbs clr SCSIBUSL; 52841299Sgibbs } 52941299Sgibbs clr SCSISIGO; 53039220Sgibbs mvi LASTPHASE, P_BUSFREE; 53139220Sgibbs call complete_target_cmd; 53239220Sgibbs jmp poll_for_work; 53339220Sgibbs 53439220Sgibbstarget_cmdphase: 53539220Sgibbs mvi P_COMMAND|BSYO call change_phase; 53639220Sgibbs 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 54739220Sgibbs * based on the command group code via table lookup. 54839220Sgibbs * We reuse the first 8 bytes of the TARG_SCSIRATE 54939220Sgibbs * BIOS array for this table. Count is one less than 55039220Sgibbs * the total for the command since we've already fetched 55139220Sgibbs * the first byte. 55239220Sgibbs */ 55339220Sgibbs shr A, CMD_GROUP_CODE_SHIFT; 55439220Sgibbs add SINDEX, CMDSIZE_TABLE, A; 55539220Sgibbs mov A, SINDIR; 55639220Sgibbs 55739220Sgibbs test A, 0xFF jz command_phase_done; 55839220Sgibbs or SXFRCTL0, SPIOEN; 55939220Sgibbscommand_loop: 56041646Sgibbs test SSTAT0, SPIORDY jz .; 56142652Sgibbs cmp A, 1 jne . + 2; 56239220Sgibbs and SXFRCTL0, ~SPIOEN; /* Last Byte */ 56341646Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 56442652Sgibbs mov CCSCBRAM, SCSIDATL; 56539220Sgibbs } else { 56639220Sgibbs mov DFDAT, SCSIDATL; 56739220Sgibbs } 56841646Sgibbs dec A; 56941646Sgibbs test A, 0xFF jnz command_loop; 57039220Sgibbs 57141646Sgibbscommand_phase_done: 57239220Sgibbs and SEQ_FLAGS, ~CMDPHASE_PENDING; 57339220Sgibbs jmp target_ITloop; 57439220Sgibbs 57543880Sgibbstarget_dphase: 57639220Sgibbs /* 57739220Sgibbs * Data phases on the bus are from the 57839220Sgibbs * perspective of the initiator. The dma 57939220Sgibbs * code looks at LASTPHASE to determine the 58039220Sgibbs * data direction of the DMA. Toggle it for 58141299Sgibbs * target transfers. 58241299Sgibbs */ 58341299Sgibbs xor LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR]; 58441299Sgibbs or SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO 58539220Sgibbs call change_phase; 58639220Sgibbs jmp p_data; 58739220Sgibbs 58839220Sgibbstarget_sphase: 58941299Sgibbs mvi P_STATUS|BSYO call change_phase; 59041299Sgibbs mvi LASTPHASE, P_STATUS; 59141299Sgibbs mov SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb; 59241299Sgibbs /* XXX Watch for ATN or parity errors??? */ 59341299Sgibbs mvi SCSISIGO, P_MESGIN|BSYO; 59441299Sgibbs /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ 59541299Sgibbs mov ALLZEROS call target_outb; 59639220Sgibbs jmp target_busfree_wait; 59739220Sgibbs 59839220Sgibbscomplete_target_cmd: 59941299Sgibbs test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; 60041299Sgibbs mov SCB_TAG jmp complete_post; 60139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 60241646Sgibbs /* Set the valid byte */ 60341646Sgibbs mvi CCSCBADDR, 24; 60439220Sgibbs mov CCSCBRAM, ALLONES; 60539220Sgibbs mvi CCHCNT, 28; 60641646Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 60741646Sgibbs test CCSCBCTL, CCSCBDONE jz .; 60841646Sgibbs clr CCSCBCTL; 60941646Sgibbs } else { 61041646Sgibbs /* Set the valid byte */ 61125005Sgibbs or DFCNTRL, FIFORESET; 61239220Sgibbs mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ 61341646Sgibbs mov DFDAT, ALLONES; 61441646Sgibbs mvi 28 call set_hcnt; 61541646Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 61641646Sgibbs call dma_finish; 61741646Sgibbs } 61841646Sgibbs inc TQINPOS; 61939220Sgibbs mvi INTSTAT,CMDCMPLT ret; 62039220Sgibbs } 62113177Sgibbs 62241646Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 62341646Sgibbsinitiator_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 6274568Sgibbs * asserted. 62839220Sgibbs */ 6294568Sgibbs mvi MSG_OUT, MSG_IDENTIFYFLAG; 63039220Sgibbs or SEQ_FLAGS, IDENTIFY_SEEN; 6314568Sgibbs 63239220Sgibbs /* 63323925Sgibbs * Main loop for information transfer phases. Wait for the 63423925Sgibbs * target to assert REQ before checking MSG, C/D and I/O for 63523925Sgibbs * the bus phase. 63623925Sgibbs */ 6374568Sgibbsmesgin_phasemis: 63841646SgibbsITloop: 63923925Sgibbs call phase_lock; 6404568Sgibbs 64123925Sgibbs mov A, LASTPHASE; 64223925Sgibbs 64323925Sgibbs test A, ~P_DATAIN jz p_data; 64439220Sgibbs 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; 64841646Sgibbs 64923925Sgibbs mvi BAD_PHASE call set_seqint; 65023925Sgibbs jmp ITloop; /* Try reading the bus again. */ 65141646Sgibbs 65241646Sgibbsawait_busfree: 65341646Sgibbs and SIMODE1, ~ENBUSFREE; 65441646Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 65541646Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 65641646Sgibbs clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ 65741646Sgibbs } 65841646Sgibbs and SXFRCTL0, ~SPIOEN; 65941646Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 66041646Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 66141646Sgibbs mvi MISSED_BUSFREE call set_seqint; 66241646Sgibbs} 66341646Sgibbs 66441646Sgibbsclear_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. 66923925Sgibbs */ 67023925Sgibbs clr DFCNTRL; 67139220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 67223925Sgibbs 67313177Sgibbs /* 67413177Sgibbs * We don't know the target we will connect to, 67513177Sgibbs * so default to narrow transfers to avoid 67613177Sgibbs * parity problems. 6779928Sgibbs */ 67851471Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 67951471Sgibbs bmov SCSIRATE, ALLZEROS, 2; 68051471Sgibbs } else { 68151471Sgibbs clr SCSIRATE; 68251471Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 68351471Sgibbs and SXFRCTL0, ~(FAST20); 68451471Sgibbs } 68551471Sgibbs } 68651471Sgibbs mvi LASTPHASE, P_BUSFREE; 68739220Sgibbs /* clear target specific flags */ 68839220Sgibbs clr SEQ_FLAGS ret; 68939220Sgibbs 69039220Sgibbssg_advance: 69139220Sgibbs clr A; /* add sizeof(struct scatter) */ 69242652Sgibbs add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; 69323925Sgibbs adc SCB_RESIDUAL_SGPTR[1],A; 6944568Sgibbs adc SCB_RESIDUAL_SGPTR[2],A; 69539220Sgibbs adc SCB_RESIDUAL_SGPTR[3],A ret; 69639220Sgibbs 69739220Sgibbsif ((ahc->features & AHC_CMD_CHAN) != 0) { 69839220Sgibbsdisable_ccsgen: 69939220Sgibbs test CCSGCTL, CCSGEN jz return; 70039220Sgibbs test CCSGCTL, CCSGDONE jz .; 70139220Sgibbsdisable_ccsgen_fetch_done: 70239220Sgibbs clr CCSGCTL; 70323925Sgibbs test CCSGCTL, CCSGEN jnz .; 70419164Sgibbs ret; 70519164Sgibbsidle_loop: 70619164Sgibbs /* Did we just finish fetching segs? */ 70739220Sgibbs cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; 70839220Sgibbs 70939220Sgibbs /* Are we actively fetching segments? */ 71023925Sgibbs test CCSGCTL, CCSGEN jnz return; 7114568Sgibbs 71239220Sgibbs /* 71339220Sgibbs * Do we need any more segments? 71439220Sgibbs */ 71519164Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; 71619164Sgibbs 71719164Sgibbs /* 71819164Sgibbs * Do we have any prefetch left??? 71919164Sgibbs */ 72019164Sgibbs cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; 72139220Sgibbs 72239220Sgibbs /* 72339220Sgibbs * Need to fetch segments, but we can only do that 72439220Sgibbs * if the command channel is completely idle. Make 72539220Sgibbs * sure we don't have an SCB prefetch going on. 72639220Sgibbs */ 72742652Sgibbs test CCSCBCTL, CCSCBEN jnz return; 72819164Sgibbs 72939220Sgibbs /* 73039220Sgibbs * We fetch a "cacheline aligned" and sized amount of data 73139220Sgibbs * so we don't end up referencing a non-existant page. 73239220Sgibbs * Cacheline aligned is in quotes because the kernel will 73339220Sgibbs * set the prefetch amount to a reasonable level if the 73439220Sgibbs * cacheline size is unknown. 73539220Sgibbs */ 73619164Sgibbs mvi CCHCNT, SG_PREFETCH_CNT; 73739220Sgibbs and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; 73839220Sgibbs bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; 73939220Sgibbs mvi CCSGCTL, CCSGEN|CCSGRESET ret; 74039220Sgibbsidle_sgfetch_complete: 74139220Sgibbs call disable_ccsgen_fetch_done; 74239220Sgibbs and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; 74319164Sgibbsidle_sg_avail: 7449928Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 74516260Sgibbs /* Does the hardware have space for another SG entry? */ 74623925Sgibbs test DFSTATUS, PRELOAD_AVAIL jz return; 74716260Sgibbs bmov HADDR, CCSGRAM, 4; 74816260Sgibbs bmov SINDEX, CCSGRAM, 1; 74916260Sgibbs test SINDEX, 0x1 jz . + 2; 75016260Sgibbs xor DATA_COUNT_ODD, 0x1; 75116260Sgibbs bmov HCNT[0], SINDEX, 1; 75216260Sgibbs bmov HCNT[1], CCSGRAM, 2; 75323925Sgibbs bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; 75439220Sgibbs call sg_advance; 75539220Sgibbs mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 75639220Sgibbs test DATA_COUNT_ODD, 0x1 jz . + 2; 75739220Sgibbs or SINDEX, ODD_SEG; 75839220Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 75939220Sgibbs or SINDEX, LAST_SEG; 76039220Sgibbs mov SG_CACHE_PRE, SINDEX; 76139220Sgibbs /* Load the segment */ 76239220Sgibbs or DFCNTRL, PRELOADEN; 76339220Sgibbs } 76416260Sgibbs ret; 76539220Sgibbs} 76623925Sgibbs 76739220Sgibbsif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 76839220Sgibbs/* 76939220Sgibbs * Calculate the trailing portion of this S/G segment that cannot 77039220Sgibbs * be transferred using memory write and invalidate PCI transactions. 77139220Sgibbs * XXX Can we optimize this for PCI writes only??? 7729928Sgibbs */ 77339220Sgibbscalc_mwi_residual: 77439220Sgibbs /* 77539220Sgibbs * If the ending address is on a cacheline boundary, 77639220Sgibbs * there is no need for an extra segment. 77739220Sgibbs */ 77839220Sgibbs mov A, HCNT[0]; 77939220Sgibbs add A, A, HADDR[0]; 78039220Sgibbs and A, CACHESIZE_MASK; 78139220Sgibbs test A, 0xFF jz return; 78239220Sgibbs 78339220Sgibbs /* 78439220Sgibbs * If the transfer is less than a cachline, 78539220Sgibbs * there is no need for an extra segment. 7864568Sgibbs */ 78739220Sgibbs test HCNT[1], 0xFF jnz calc_mwi_residual_final; 78816260Sgibbs test HCNT[2], 0xFF jnz calc_mwi_residual_final; 78923925Sgibbs add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; 79016260Sgibbs jnc return; 79122451Sgibbs 79223925Sgibbscalc_mwi_residual_final: 7937532Sgibbs mov MWI_RESIDUAL, A; 79413177Sgibbs not A; 79513177Sgibbs inc A; 79613177Sgibbs add HCNT[0], A; 7979928Sgibbs adc HCNT[1], -1; 79823925Sgibbs adc HCNT[2], -1 ret; 7994568Sgibbs} 80023925Sgibbs 80113177Sgibbs/* 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 */ 80513177Sgibbsdata_phase_reinit: 80615328Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 80713177Sgibbs /* 8089928Sgibbs * The preload circuitry requires us to 80939220Sgibbs * reload the address too, so pull it from 81039220Sgibbs * the shaddow address. 81139220Sgibbs */ 81239220Sgibbs bmov HADDR, SHADDR, 4; 81339220Sgibbs bmov HCNT, SCB_RESIDUAL_DATACNT, 3; 8144568Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 81539220Sgibbs bmov STCNT, SCB_RESIDUAL_DATACNT, 3; 81639220Sgibbs } else { 81739220Sgibbs mvi DINDEX, STCNT; 81839220Sgibbs mvi SCB_RESIDUAL_DATACNT call bcopy_3; 81939220Sgibbs } 82039220Sgibbs and DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0]; 82139220Sgibbs jmp data_phase_loop; 82239220Sgibbs 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; 83139220Sgibbs call assert; /* 83239220Sgibbs * Ensure entering a data 83339220Sgibbs * phase is okay - seen identify, etc. 83422568Sgibbs */ 83539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 83639220Sgibbs /* We don't have any valid S/G elements */ 83739220Sgibbs mvi CCSGADDR, SG_PREFETCH_CNT; 8389928Sgibbs } 83939220Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 8409928Sgibbs 84139220Sgibbs /* We have seen a data phase */ 8429928Sgibbs or SEQ_FLAGS, DPHASE; 84339220Sgibbs 84439220Sgibbs /* 84539220Sgibbs * Initialize the DMA address and counter from the SCB. 84639220Sgibbs * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG 84739220Sgibbs * flag in the highest byte of the data count. We cannot 84839220Sgibbs * modify the saved values in the SCB until we see a save 84939220Sgibbs * data pointers message. 85039220Sgibbs */ 85139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 85239220Sgibbs bmov HADDR, SCB_DATAPTR, 7; 85339220Sgibbs bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; 85442652Sgibbs } else { 85542652Sgibbs mvi DINDEX, HADDR; 85642652Sgibbs mvi SCB_DATAPTR call bcopy_7; 85742652Sgibbs mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; 85839220Sgibbs mvi SCB_DATACNT + 3 call bcopy_5; 85939220Sgibbs } 86039220Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 86139220Sgibbs call calc_mwi_residual; 86239220Sgibbs } 86339220Sgibbs and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; 86439220Sgibbs and DATA_COUNT_ODD, 0x1, HCNT[0]; 86539220Sgibbs 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 } 87241646Sgibbs } 87341646Sgibbs 87441646Sgibbsdata_phase_loop: 87541646Sgibbs /* Guard against overruns */ 87623925Sgibbs test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; 87741646Sgibbs 87839220Sgibbs /* 87939220Sgibbs * Turn on `Bit Bucket' mode, wait until the target takes 88039220Sgibbs * us to another phase, and then notify the host. 88139220Sgibbs */ 8824568Sgibbs and DMAPARAMS, DIRECTION; 8839928Sgibbs mov DFCNTRL, DMAPARAMS; 88439220Sgibbs or SXFRCTL1,BITBUCKET; 88539220Sgibbs test SSTAT1,PHASEMIS jz .; 88639220Sgibbs and SXFRCTL1, ~BITBUCKET; 88713177Sgibbs mvi DATA_OVERRUN call set_seqint; 88813177Sgibbs jmp ITloop; 88913177Sgibbs 89013177Sgibbsdata_phase_inbounds: 89113177Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 89239220Sgibbs mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 89339220Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 89439220Sgibbs or SINDEX, LAST_SEG; 89539220Sgibbs test DATA_COUNT_ODD, 0x1 jz . + 2; 89639220Sgibbs or SINDEX, ODD_SEG; 89739220Sgibbs mov SG_CACHE_PRE, SINDEX; 89839220Sgibbs mov DFCNTRL, DMAPARAMS; 89923925Sgibbsultra2_dma_loop: 90022568Sgibbs call idle_loop; 90139220Sgibbs /* 90239220Sgibbs * The transfer is complete if either the last segment 90339220Sgibbs * completes or the target changes phase. 90422568Sgibbs */ 90539220Sgibbs test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; 90641646Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 90739220Sgibbs /* 90842652Sgibbs * As a target, we control the phases, 90942652Sgibbs * so ignore PHASEMIS. 91042652Sgibbs */ 91142652Sgibbs test SSTAT0, TARGET jnz ultra2_dma_loop; 91242652Sgibbs } 91342652Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 91439220Sgibbs test SSTAT1,PHASEMIS jz ultra2_dma_loop; 91539220Sgibbs } 91623925Sgibbs 9174568Sgibbsultra2_dmafinish: 91816260Sgibbs test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; 91939220Sgibbs if ((ahc->features & AHC_DT) == 0) { 92039220Sgibbs and DFCNTRL, ~SCSIEN; 92139220Sgibbs test DFCNTRL, SCSIEN jnz .; 92239220Sgibbs } 92313177Sgibbsultra2_dmafifoflush: 92416260Sgibbs if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 92516260Sgibbs /* 92623925Sgibbs * On Rev A of the aic7890, the autoflush 92723925Sgibbs * features doesn't function correctly. 92823925Sgibbs * Perform an explicit manual flush. During 92916260Sgibbs * a manual flush, the FIFOEMP bit becomes 93039220Sgibbs * true every time the PCI FIFO empties 93139220Sgibbs * regardless of the state of the SCSI FIFO. 93239220Sgibbs * It can take up to 4 clock cycles for the 93339220Sgibbs * SCSI FIFO to get data into the PCI FIFO 93439220Sgibbs * and for FIFOEMP to de-assert. Here we 93551471Sgibbs * guard against this condition by making 93639220Sgibbs * sure the FIFOEMP bit stays on for 5 full 93751471Sgibbs * clock cycles. 93851471Sgibbs */ 93951471Sgibbs or DFCNTRL, FIFOFLUSH; 94051471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94151471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94251471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94351471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94451471Sgibbs } 94551471Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 94651471Sgibbsultra2_dmafifoempty: 94751471Sgibbs /* Don't clobber an inprogress host data transfer */ 94851471Sgibbs test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; 94951471Sgibbsultra2_dmahalt: 95051471Sgibbs and DFCNTRL, ~(SCSIEN|HDMAEN); 95151471Sgibbs test DFCNTRL, SCSIEN|HDMAEN jnz .; 95251471Sgibbs 95351471Sgibbs /* 95451471Sgibbs * If, by chance, we stopped before being able 95551471Sgibbs * to fetch additional segments for this transfer, 95651471Sgibbs * yet the last S/G was completely exhausted, 95751471Sgibbs * call our idle loop until it is able to load 95851471Sgibbs * another segment. This will allow us to immediately 95939220Sgibbs * pickup on the next segment on the next data phase. 96039220Sgibbs * 96139220Sgibbs * If we happened to stop on the last segment, then 96239220Sgibbs * our residual information is still correct from 96339220Sgibbs * the idle loop and there is no need to perform 96439220Sgibbs * any fixups. Just jump to data_phase_finish. 96541646Sgibbs */ 96616260Sgibbsultra2_ensure_sg: 96715328Sgibbs test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; 96813177Sgibbs /* Record if we've consumed all S/G entries */ 9694568Sgibbs test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; 97023925Sgibbs or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 9714568Sgibbs jmp data_phase_finish; 97239220Sgibbs 97339220Sgibbsultra2_shvalid: 97439220Sgibbs test SSTAT2, SHVALID jnz sgptr_fixup; 97539220Sgibbs call idle_loop; 97639220Sgibbs jmp ultra2_ensure_sg; 97739220Sgibbs 97839220Sgibbssgptr_fixup: 97939220Sgibbs /* 98039220Sgibbs * Fixup the residual next S/G pointer. The S/G preload 98139220Sgibbs * feature of the chip allows us to load two elements 98239220Sgibbs * in addition to the currently active element. We 98339220Sgibbs * store the bottom byte of the next S/G pointer in 98439220Sgibbs * the SG_CACEPTR register so we can restore the 98539220Sgibbs * correct value when the DMA completes. If the next 98639220Sgibbs * sg ptr value has advanced to the point where higher 98739220Sgibbs * bytes in the address have been affected, fix them 98839220Sgibbs * too. 98939220Sgibbs */ 99039220Sgibbs test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; 99139220Sgibbs test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; 99239220Sgibbs add SCB_RESIDUAL_SGPTR[1], -1; 99339220Sgibbs adc SCB_RESIDUAL_SGPTR[2], -1; 99439220Sgibbs adc SCB_RESIDUAL_SGPTR[3], -1; 9954568Sgibbssgptr_fixup_done: 99639220Sgibbs and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; 99739220Sgibbs clr DATA_COUNT_ODD; 99839220Sgibbs test SG_CACHE_SHADOW, ODD_SEG jz . + 2; 99939220Sgibbs or DATA_COUNT_ODD, 0x1; 100039220Sgibbs clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ 100139220Sgibbs } else { 100239220Sgibbs /* If we are the last SG block, tell the hardware. */ 100339220Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 100439220Sgibbs && ahc->pci_cachesize != 0) { 100539220Sgibbs test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; 100639220Sgibbs } 100739220Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; 100839220Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 100923925Sgibbs test SSTAT0, TARGET jz dma_last_sg; 10104568Sgibbs if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { 101113177Sgibbs test DMAPARAMS, DIRECTION jz dma_mid_sg; 101213177Sgibbs } 101313177Sgibbs } 101413177Sgibbsdma_last_sg: 10154568Sgibbs and DMAPARAMS, ~WIDEODD; 101623925Sgibbsdma_mid_sg: 101719803Sgibbs /* Start DMA data transfer. */ 101823925Sgibbs mov DFCNTRL, DMAPARAMS; 101923925Sgibbsdma_loop: 10204568Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 102113177Sgibbs call idle_loop; 102241646Sgibbs } 102341646Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 102441646Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 102541646Sgibbsdma_phasemis: 102641646Sgibbs /* 102741646Sgibbs * We will be "done" DMAing when the transfer count goes to 102841646Sgibbs * zero, or the target changes the phase (in light of this, 102941646Sgibbs * it makes sense that the DMA circuitry doesn't ACK when 103039220Sgibbs * PHASEMIS is active). If we are doing a SCSI->Host transfer, 103139220Sgibbs * the data FIFO should be flushed auto-magically on STCNT=0 103241646Sgibbs * or a phase change, so just wait for FIFO empty status. 103339220Sgibbs */ 103439220Sgibbsdma_checkfifo: 103539220Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 103639220Sgibbsdma_fifoflush: 103741646Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 103839220Sgibbsdma_fifoempty: 103939220Sgibbs /* Don't clobber an inprogress host data transfer */ 104039220Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 104139220Sgibbs 104239220Sgibbs /* 104339220Sgibbs * Now shut off the DMA and make sure that the DMA 104413177Sgibbs * hardware has actually stopped. Touching the DMA 104541646Sgibbs * counters, etc. while a DMA is active will result 104641646Sgibbs * in an ILLSADDR exception. 10474568Sgibbs */ 104839220Sgibbsdma_dmadone: 104939220Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 105041646Sgibbsdma_halt: 105141646Sgibbs /* 105241646Sgibbs * Some revisions of the aic78XX have a problem where, if the 105347158Sgibbs * data fifo is full, but the PCI input latch is not empty, 105447158Sgibbs * HDMAEN cannot be cleared. The fix used here is to drain 105547158Sgibbs * the prefetched but unused data from the data fifo until 105647158Sgibbs * there is space for the input latch to drain. 105747158Sgibbs */ 105847158Sgibbs if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 105947158Sgibbs mov NONE, DFDAT; 106047158Sgibbs } 106147158Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 106247158Sgibbs 106347158Sgibbs /* See if we have completed this last segment */ 106447414Sgibbs test STCNT[0], 0xff jnz data_phase_finish; 106547158Sgibbs test STCNT[1], 0xff jnz data_phase_finish; 106647414Sgibbs test STCNT[2], 0xff jnz data_phase_finish; 106741646Sgibbs 106841646Sgibbs /* 106941646Sgibbs * Advance the scatter-gather pointers if needed 107041646Sgibbs */ 107141646Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 107241646Sgibbs && ahc->pci_cachesize != 0) { 107341646Sgibbs test MWI_RESIDUAL, 0xFF jz no_mwi_resid; 107441646Sgibbs /* 107541646Sgibbs * Reload HADDR from SHADDR and setup the 107639220Sgibbs * count to be the size of our residual. 107741299Sgibbs */ 107839220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 107939220Sgibbs bmov HADDR, SHADDR, 4; 108039220Sgibbs mov HCNT, MWI_RESIDUAL; 108113177Sgibbs bmov HCNT[1], ALLZEROS, 2; 108239220Sgibbs } else { 108339220Sgibbs mvi DINDEX, HADDR; 108413177Sgibbs mvi SHADDR call bcopy_4; 108539220Sgibbs mov MWI_RESIDUAL call set_hcnt; 108639220Sgibbs } 108739220Sgibbs clr MWI_RESIDUAL; 108839220Sgibbs jmp sg_load_done; 108939220Sgibbsno_mwi_resid: 109039220Sgibbs } 109139220Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; 109239220Sgibbs or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 109339220Sgibbs jmp data_phase_finish; 109413177Sgibbssg_load: 109541646Sgibbs /* 109641646Sgibbs * Load the next SG element's data address and length 109713177Sgibbs * into the DMA engine. If we don't have hardware 109839220Sgibbs * to perform a prefetch, we'll have to fetch the 109939220Sgibbs * segment from host memory first. 110041646Sgibbs */ 110139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 110239220Sgibbs /* Wait for the idle loop to complete */ 110339220Sgibbs test CCSGCTL, CCSGEN jz . + 3; 110439220Sgibbs call idle_loop; 110539220Sgibbs test CCSGCTL, CCSGEN jnz . - 1; 110613177Sgibbs bmov HADDR, CCSGRAM, 7; 110741646Sgibbs test CCSGRAM, SG_LAST_SEG jz . + 2; 110813177Sgibbs or SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG; 110913177Sgibbs } else { 111039220Sgibbs mvi DINDEX, HADDR; 111141646Sgibbs mvi SCB_RESIDUAL_SGPTR call bcopy_4; 11124568Sgibbs 111319906Sgibbs mvi SG_SIZEOF call set_hcnt; 111423925Sgibbs 111539220Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 111639220Sgibbs 111723925Sgibbs call dma_finish; 11184568Sgibbs 111913177Sgibbs mvi DINDEX, HADDR; 112013177Sgibbs call dfdat_in_7; 112113177Sgibbs mov SCB_RESIDUAL_DATACNT[3], DFDAT; 11224568Sgibbs } 112323925Sgibbs 11244568Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 112523925Sgibbs && ahc->pci_cachesize != 0) { 112623925Sgibbs call calc_mwi_residual; 112723925Sgibbs } 112823925Sgibbs 112923925Sgibbs /* Point to the new next sg in memory */ 113023925Sgibbs call sg_advance; 11314568Sgibbs 113213177Sgibbssg_load_done: 113341887Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 113441887Sgibbs bmov STCNT, HCNT, 3; 113541887Sgibbs } else { 113641887Sgibbs call set_stcnt_from_hcnt; 113741887Sgibbs } 113841887Sgibbs /* Track odd'ness */ 113941887Sgibbs test HCNT[0], 0x1 jz . + 2; 114013177Sgibbs xor DATA_COUNT_ODD, 0x1; 114141887Sgibbs 114241887Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 114341887Sgibbs test SSTAT0, TARGET jnz data_phase_loop; 114441887Sgibbs } 114541887Sgibbs } 11469954Sgibbsdata_phase_finish: 11479954Sgibbs /* 114823925Sgibbs * If the target has left us in data phase, loop through 114923925Sgibbs * the dma code again. In the case of ULTRA2 adapters, 11509954Sgibbs * we should only loop if there is a data overrun. For 11519954Sgibbs * all other adapters, we'll loop after each S/G element 11529954Sgibbs * is loaded as well as if there is an overrun. 115313177Sgibbs */ 115419164Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 115519164Sgibbs test SSTAT0, TARGET jnz data_phase_done; 115639220Sgibbs } 115739220Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 115819164Sgibbs test SSTAT1, REQINIT jz .; 115919164Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 116019164Sgibbs } 116119164Sgibbs 116219164Sgibbsdata_phase_done: 116319164Sgibbs /* 116419164Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into 116519164Sgibbs * the SCB. We use STCNT instead of HCNT, since it's a reflection 116619164Sgibbs * of how many bytes were transferred on the SCSI (as opposed to the 116719164Sgibbs * host) bus. 116819164Sgibbs */ 116913177Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 117019164Sgibbs /* Kill off any pending prefetch */ 117113177Sgibbs call disable_ccsgen; 117219164Sgibbs } 117313177Sgibbs 117423925Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 117539220Sgibbs && ahc->pci_cachesize != 0) { 117619164Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 117723925Sgibbs test MWI_RESIDUAL, 0xFF jz bmov_resid; 117823925Sgibbs } 11797532Sgibbs mov A, MWI_RESIDUAL; 118039220Sgibbs add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; 118123925Sgibbs clr A; 118239220Sgibbs adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; 118339220Sgibbs adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; 118419164Sgibbs clr MWI_RESIDUAL; 118523925Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 118639220Sgibbs jmp . + 2; 118719164Sgibbsbmov_resid: 118823925Sgibbs bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 118923925Sgibbs } 119023925Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 119123925Sgibbs bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 119223925Sgibbs } else { 119323925Sgibbs mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; 119423925Sgibbs mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; 119523925Sgibbs mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; 119639220Sgibbs } 119739220Sgibbs 119839220Sgibbs /* 119939220Sgibbs * Since we've been through a data phase, the SCB_RESID* fields 120039220Sgibbs * are now initialized. Clear the full residual flag. 120139220Sgibbs */ 120239220Sgibbs and SCB_SGPTR[0], ~SG_FULL_RESID; 120339220Sgibbs 120439220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 120539220Sgibbs /* Clear the channel in case we return to data phase later */ 120623925Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 120741646Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 12084568Sgibbs } 120939220Sgibbs 121039220Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 121144507Sgibbs test SEQ_FLAGS, DPHASE_PENDING jz ITloop; 121239220Sgibbs and SEQ_FLAGS, ~DPHASE_PENDING; 121339220Sgibbs /* 121439220Sgibbs * For data-in phases, wait for any pending acks from the 121539220Sgibbs * initiator before changing phase. 121639220Sgibbs */ 121739220Sgibbs test DFCNTRL, DIRECTION jz target_ITloop; 121839220Sgibbs test SSTAT1, REQINIT jnz .; 121939220Sgibbs jmp target_ITloop; 122039220Sgibbs } else { 122139220Sgibbs jmp ITloop; 122239220Sgibbs } 122339220Sgibbs 122439220Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 122541646Sgibbs/* 122613177Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 122713177Sgibbs */ 122813177Sgibbsp_command: 122913177Sgibbs call assert; 12309954Sgibbs 123123925Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 123223925Sgibbs bmov HCNT[0], SCB_CDB_LEN, 1; 123323925Sgibbs bmov HCNT[1], ALLZEROS, 2; 123419164Sgibbs mvi SG_CACHE_PRE, LAST_SEG; 123515328Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 123619164Sgibbs bmov STCNT[0], SCB_CDB_LEN, 1; 123719164Sgibbs bmov STCNT[1], ALLZEROS, 2; 123819164Sgibbs } else { 123919164Sgibbs mov STCNT[0], SCB_CDB_LEN; 124019164Sgibbs clr STCNT[1]; 124115328Sgibbs clr STCNT[2]; 124219164Sgibbs } 124323925Sgibbs add NONE, -13, SCB_CDB_LEN; 12444568Sgibbs mvi SCB_CDB_STORE jnc p_command_embedded; 124539220Sgibbsp_command_from_host: 124639220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 124739220Sgibbs bmov HADDR[0], SCB_CDB_PTR, 4; 124839220Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); 124939220Sgibbs } else { 125039220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 125139220Sgibbs bmov HADDR[0], SCB_CDB_PTR, 4; 125239220Sgibbs bmov HCNT, STCNT, 3; 125339220Sgibbs } else { 125439220Sgibbs mvi DINDEX, HADDR; 125539220Sgibbs mvi SCB_CDB_PTR call bcopy_4; 125639220Sgibbs mov SCB_CDB_LEN call set_hcnt; 125739220Sgibbs } 125819164Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); 125939220Sgibbs } 126039220Sgibbs jmp p_command_loop; 126139220Sgibbsp_command_embedded: 126239220Sgibbs /* 126323925Sgibbs * The data fifo seems to require 4 byte alligned 12644568Sgibbs * transfers from the sequencer. Force this to 126513177Sgibbs * be the case by clearing HADDR[0] even though 126613177Sgibbs * we aren't going to touch host memeory. 126713177Sgibbs */ 126813177Sgibbs clr HADDR[0]; 126913177Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 127013177Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); 12719954Sgibbs bmov DFDAT, SCB_CDB_STORE, 12; 127223925Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 127323925Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 127413177Sgibbs /* 127523925Sgibbs * On the 7895 the data FIFO will 127613177Sgibbs * get corrupted if you try to dump 127723925Sgibbs * data from external SCB memory into 12784568Sgibbs * the FIFO while it is enabled. So, 127913177Sgibbs * fill the fifo and then enable SCSI 128013177Sgibbs * transfers. 128113177Sgibbs */ 128213177Sgibbs mvi DFCNTRL, (DIRECTION|FIFORESET); 128313177Sgibbs } else { 12849954Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 128539220Sgibbs } 128639220Sgibbs bmov DFDAT, SCB_CDB_STORE, 12; 128739220Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 128839220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); 128939220Sgibbs } else { 129039220Sgibbs or DFCNTRL, FIFOFLUSH; 129123925Sgibbs } 129239220Sgibbs } else { 129339220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 129439220Sgibbs call copy_to_fifo_6; 129539220Sgibbs call copy_to_fifo_6; 129639220Sgibbs or DFCNTRL, FIFOFLUSH; 129739220Sgibbs } 129839220Sgibbsp_command_loop: 129939220Sgibbs test SSTAT0, SDONE jnz . + 2; 130039220Sgibbs test SSTAT1, PHASEMIS jz p_command_loop; 130139220Sgibbs /* 130239220Sgibbs * Wait for our ACK to go-away on it's own 130339220Sgibbs * instead of being killed by SCSIEN getting cleared. 130439220Sgibbs */ 130539220Sgibbs test SCSISIGI, ACKI jnz .; 130624608Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 130713177Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; 130813177Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 130923168Sgibbs /* Drop any residual from the S/G Preload queue */ 131039220Sgibbs or SXFRCTL0, CLRSTCNT; 131115328Sgibbs } 131215328Sgibbs jmp ITloop; 131315328Sgibbs 131413177Sgibbs/* 131524608Sgibbs * Status phase. Wait for the data byte to appear, then read it 131623925Sgibbs * and store it into the SCB. 131713177Sgibbs */ 131839220Sgibbsp_status: 131923925Sgibbs call assert; 132023925Sgibbs 13216608Sgibbs mov SCB_SCSI_STATUS, SCSIDATL; 132223925Sgibbs jmp ITloop; 132313177Sgibbs 132439220Sgibbs/* 132539220Sgibbs * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full 132639220Sgibbs * indentify message sequence and send it to the target. The host may 132739220Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB 132839220Sgibbs * control byte. This will cause us to interrupt the host and allow 132939220Sgibbs * it to handle the message phase completely on its own. If the bit 133039220Sgibbs * associated with this target is set, we will also interrupt the host, 133124608Sgibbs * thereby allowing it to send a message on the next selection regardless 133239220Sgibbs * of the transaction being sent. 133339220Sgibbs * 133423925Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. 133523925Sgibbs * 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). 134039220Sgibbs * 134123925Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, 134215328Sgibbs * 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. 134739220Sgibbs */ 134819218Sgibbsp_mesgout_retry: 134923925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 135023925Sgibbsp_mesgout: 13516608Sgibbs mov SINDEX, MSG_OUT; 135213177Sgibbs cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; 135313177Sgibbs test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; 135413177Sgibbs mov FUNCTION1, SCB_SCSIID; 13554568Sgibbs mov A, FUNCTION1; 135613177Sgibbs mov SINDEX, TARGET_MSG_REQUEST[0]; 135713177Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 135813177Sgibbs /* Second Channel uses high byte bits */ 135913177Sgibbs test SCB_SCSIID, TWIN_CHNLB jz . + 2; 13604568Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 136123925Sgibbs } else if ((ahc->features & AHC_WIDE) != 0) { 136239220Sgibbs test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ 13634568Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 136413177Sgibbs } 136513177Sgibbs test SINDEX, A jnz host_message_loop; 136613177Sgibbsp_mesgout_identify: 136713177Sgibbs or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; 136813177Sgibbs test SCB_CONTROL, DISCENB jnz . + 2; 136913177Sgibbs and SINDEX, ~DISCENB; 137013177Sgibbs/* 137113177Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 137213177Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 137313177Sgibbs */ 137413177Sgibbsp_mesgout_tag: 137513177Sgibbs test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; 137613177Sgibbs mov SCSIDATL, SINDEX; /* Send the identify message */ 137713177Sgibbs call phase_lock; 137813177Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 137913177Sgibbs and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 138013177Sgibbs call phase_lock; 138123925Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 138213360Sgibbs mov SCB_TAG jmp p_mesgout_onebyte; 138321947Sgibbs/* 138421947Sgibbs * Interrupt the driver, and allow it to handle this message 138521947Sgibbs * phase and any required retries. 138621947Sgibbs */ 138721947Sgibbsp_mesgout_from_host: 138823925Sgibbs cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; 138923925Sgibbs jmp host_message_loop; 139023925Sgibbs 139123925Sgibbsp_mesgout_onebyte: 139219623Sgibbs mvi CLRSINT1, CLRATNO; 139323925Sgibbs mov SCSIDATL, SINDEX; 139423925Sgibbs 139513177Sgibbs/* 139623925Sgibbs * If the next bus phase after ATN drops is message out, it means 139741646Sgibbs * that the target is requesting that the last message(s) be resent. 13984568Sgibbs */ 139939220Sgibbs call phase_lock; 140041646Sgibbs cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; 140141646Sgibbs 140241646Sgibbsp_mesgout_done: 140341646Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 140441646Sgibbs mov LAST_MSG, MSG_OUT; 140543880Sgibbs mvi MSG_OUT, MSG_NOOP; /* No message left */ 140643880Sgibbs jmp ITloop; 140743880Sgibbs 140843880Sgibbs/* 140941646Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 141041646Sgibbs */ 141141646Sgibbsp_mesgin: 141243880Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 141343880Sgibbs 141443880Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 141543880Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 141643880Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 141743880Sgibbs cmp ALLZEROS,A je mesgin_complete; 141843880Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 141941646Sgibbs cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; 142041646Sgibbs cmp A,MSG_NOOP je mesgin_done; 142141646Sgibbs 142241646Sgibbs/* 142341646Sgibbs * Pushed message loop to allow the kernel to 142441646Sgibbs * run it's own message state engine. To avoid an 142541646Sgibbs * extra nop instruction after signaling the kernel, 142641646Sgibbs * we perform the phase_lock before checking to see 142741646Sgibbs * if we should exit the loop and skip the phase_lock 142841646Sgibbs * in the ITloop. Performing back to back phase_locks 142941646Sgibbs * shouldn't hurt, but why do it twice... 143041646Sgibbs */ 143139220Sgibbshost_message_loop: 143239220Sgibbs mvi HOST_MSG_LOOP call set_seqint; 143339220Sgibbs call phase_lock; 143439220Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; 143539220Sgibbs jmp host_message_loop; 143641646Sgibbs 143739220Sgibbsmesgin_ign_wide_residue: 143839220Sgibbsif ((ahc->features & AHC_WIDE) != 0) { 143913177Sgibbs test SCSIRATE, WIDEXFER jz mesgin_reject; 144013177Sgibbs /* Pull the residue byte */ 144113177Sgibbs mvi ARG_1 call inb_next; 144213177Sgibbs cmp ARG_1, 0x01 jne mesgin_reject; 144323925Sgibbs test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; 144423925Sgibbs test DATA_COUNT_ODD, 0x1 jz mesgin_done; 14454568Sgibbs mvi IGN_WIDE_RES call set_seqint; 144613177Sgibbs jmp mesgin_done; 144713177Sgibbs} 144813177Sgibbs 144913177Sgibbsmesgin_reject: 145013177Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 145113177Sgibbsmesgin_done: 14524568Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 145323925Sgibbs jmp ITloop; 145422568Sgibbs 145523925Sgibbsmesgin_complete: 145623925Sgibbs/* 145722568Sgibbs * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, 145823925Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 145923925Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0). 14604568Sgibbs * In either of these conditions, we upload the SCB back to the host so it can 146113177Sgibbs * process this information. In the case of a non zero status byte, we 146213177Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 146313177Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 146413177Sgibbs * sense, it will fill the kernel SCB with a request sense command, requeue 146513177Sgibbs * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 146613177Sgibbs * RETURN_1 to SEND_SENSE. 146713177Sgibbs */ 146813177Sgibbs 146922568Sgibbs/* 147023925Sgibbs * If ATN is raised, we still want to give the target a message. 147122568Sgibbs * Perhaps there was a parity error on this last message byte. 147223925Sgibbs * Either way, the target should take us to message out phase 14734568Sgibbs * and then attempt to complete the command again. We should use a 147422568Sgibbs * critical section here to guard against a timeout triggering 147522568Sgibbs * for this command and setting ATN while we are still processing 147623925Sgibbs * the completion. 147713177Sgibbs test SCSISIGI, ATNI jnz mesgin_done; 147813177Sgibbs */ 147913177Sgibbs 148013177Sgibbs/* 148122568Sgibbs * See if we attempted to deliver a message but the target ingnored us. 148223925Sgibbs */ 148322568Sgibbs test SCB_CONTROL, MK_MESSAGE jz . + 2; 148437223Sgibbs mvi MKMSG_FAILED call set_seqint; 148537223Sgibbs 148637223Sgibbs/* 148737223Sgibbs * Check for residuals 148837223Sgibbs */ 148937223Sgibbs test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ 149037223Sgibbs test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ 149139220Sgibbs test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; 149239220Sgibbscheck_status: 149339220Sgibbs test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ 149439220Sgibbsupload_scb: 149518762Sgibbs or SCB_SGPTR, SG_RESID_VALID; 149623925Sgibbs mvi DMAPARAMS, FIFORESET; 14974568Sgibbs mov SCB_TAG call dma_scb; 149813177Sgibbs test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ 149913177Sgibbs mvi BAD_STATUS call set_seqint; /* let driver know */ 150013177Sgibbs cmp RETURN_1, SEND_SENSE jne complete; 150113177Sgibbs call add_scb_to_free_list; 15024568Sgibbs jmp await_busfree; 150323925Sgibbscomplete: 15044568Sgibbs mov SCB_TAG call complete_post; 150523925Sgibbs jmp await_busfree; 15064568Sgibbs} 150713177Sgibbs 150819218Sgibbscomplete_post: 150939220Sgibbs /* Post the SCBID in SINDEX and issue an interrupt */ 151039220Sgibbs call add_scb_to_free_list; 151139220Sgibbs mov ARG_1, SINDEX; 151239220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 151313177Sgibbs mov A, SDSCB_QOFF; 15144568Sgibbs } 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) { 152023925Sgibbs inc QOUTPOS; 152139220Sgibbs } 152239220Sgibbs mvi INTSTAT,CMDCMPLT ret; 152339220Sgibbs 152439220Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 152539220Sgibbs/* 152639220Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 152723168Sgibbs * and await the bus going free. If this is an untagged transaction 152839220Sgibbs * store the SCB id for it in our untagged target table for lookup on 152939220Sgibbs * a reselction. 153039220Sgibbs */ 153139220Sgibbsmesgin_disconnect: 153239220Sgibbs /* 153319164Sgibbs * If ATN is raised, we still want to give the target a message. 153439220Sgibbs * Perhaps there was a parity error on this last message byte 153539220Sgibbs * or we want to abort this command. Either way, the target 153639220Sgibbs * should take us to message out phase and then attempt to 153739220Sgibbs * disconnect again. 153839220Sgibbs * XXX - Wait for more testing. 153919164Sgibbs test SCSISIGI, ATNI jnz mesgin_done; 154039220Sgibbs */ 154139220Sgibbs 154239220Sgibbs or SCB_CONTROL,DISCONNECTED; 154339220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 154439220Sgibbs call add_scb_to_disc_list; 154539220Sgibbs } 154639220Sgibbs test SCB_CONTROL, TAG_ENB jnz await_busfree; 154739220Sgibbs mov ARG_1, SCB_TAG; 154839220Sgibbs mov SAVED_LUN, SCB_LUN; 154939220Sgibbs mov SCB_SCSIID call set_busy_target; 155039220Sgibbs jmp await_busfree; 155119164Sgibbs 155215328Sgibbs/* 155339220Sgibbs * Save data pointers message: 155439220Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 155539220Sgibbs * only if we've actually been into a data phase to change them. This 155639220Sgibbs * protects against bogus data in scratch ram and the residual counts 155723925Sgibbs * since they are only initialized when we go into data_in or data_out. 155815328Sgibbs */ 155923925Sgibbsmesgin_sdptrs: 15604568Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 156139220Sgibbs 156239220Sgibbs /* 156339220Sgibbs * The SCB_SGPTR becomes the next one we'll download, 156439220Sgibbs * 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; 157039220Sgibbs bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; 157139220Sgibbs } else { 157239220Sgibbs mvi DINDEX, SCB_DATAPTR; 157339220Sgibbs mvi SHADDR call bcopy_4; 157439220Sgibbs mvi SCB_RESIDUAL_DATACNT call bcopy_8; 157539220Sgibbs } 157639220Sgibbs jmp mesgin_done; 157739220Sgibbs 157839220Sgibbs/* 157939220Sgibbs * Restore pointers message? Data pointers are recopied from the 158039220Sgibbs * SCB anytime we enter a data phase for the first time, so all 158139220Sgibbs * we need to do is clear the DPHASE flag and let the data phase 158239220Sgibbs * code do the rest. 158339220Sgibbs */ 158439220Sgibbsmesgin_rdptrs: 158539220Sgibbs and SEQ_FLAGS, ~DPHASE; /* 158639220Sgibbs * We'll reload them 158739220Sgibbs * the next time through 158839220Sgibbs * the dataphase. 158939220Sgibbs */ 159039220Sgibbs jmp mesgin_done; 159139220Sgibbs 159239220Sgibbs/* 159339220Sgibbs * Index into our Busy Target table. SINDEX and DINDEX are modified 159439220Sgibbs * upon return. SCBPTR may be modified by this action. 159539220Sgibbs */ 159639220Sgibbsset_busy_target: 159739220Sgibbs shr DINDEX, 4, SINDEX; 159839220Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 159939220Sgibbs mov SCBPTR, SAVED_LUN; 160039220Sgibbs add DINDEX, SCB_64_BTT; 160139220Sgibbs } else { 160239220Sgibbs add DINDEX, BUSY_TARGETS; 160339220Sgibbs } 160439220Sgibbs mov DINDIR, ARG_1 ret; 160539220Sgibbs 160639220Sgibbs/* 160739220Sgibbs * Identify message? For a reconnecting target, this tells us the lun 160839220Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 160939220Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 161039220Sgibbs */ 161139220Sgibbsmesgin_identify: 161239220Sgibbs /* 161339220Sgibbs * Determine whether a target is using tagged or non-tagged 161439220Sgibbs * transactions by first looking at the transaction stored in 161539220Sgibbs * the busy target array. If there is no untagged transaction 161639220Sgibbs * for this target or the transaction is for a different lun, then 161739220Sgibbs * this must be an untagged transaction. 161839220Sgibbs */ 161939220Sgibbs shr SINDEX, 4, SAVED_SCSIID; 162039220Sgibbs and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; 162139220Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 162239220Sgibbs add SINDEX, SCB_64_BTT; 162339220Sgibbs mov SCBPTR, SAVED_LUN; 162439220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 162539220Sgibbs add NONE, -SCB_64_BTT, SINDEX; 162639220Sgibbs jc . + 2; 162739220Sgibbs mvi INTSTAT, OUT_OF_RANGE; 162839220Sgibbs nop; 162939220Sgibbs add NONE, -(SCB_64_BTT + 16), SINDEX; 163039220Sgibbs jnc . + 2; 163139220Sgibbs mvi INTSTAT, OUT_OF_RANGE; 163239220Sgibbs nop; 163339220Sgibbs } 163439220Sgibbs } else { 163539220Sgibbs add SINDEX, BUSY_TARGETS; 163639220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 163739220Sgibbs add NONE, -BUSY_TARGETS, SINDEX; 163839220Sgibbs jc . + 2; 163939220Sgibbs mvi INTSTAT, OUT_OF_RANGE; 164039220Sgibbs nop; 164139220Sgibbs add NONE, -(BUSY_TARGETS + 16), SINDEX; 164239220Sgibbs jnc . + 2; 164339220Sgibbs mvi INTSTAT, OUT_OF_RANGE; 164439220Sgibbs nop; 164539220Sgibbs } 164639220Sgibbs } 164739220Sgibbs mov ARG_1, SINDIR; 164839220Sgibbs cmp ARG_1, SCB_LIST_NULL je snoop_tag; 164939220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 165039220Sgibbs mov ARG_1 call findSCB; 165139220Sgibbs } else { 165239220Sgibbs mov SCBPTR, ARG_1; 165339220Sgibbs } 165439220Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 165541646Sgibbs jmp setup_SCB_id_lun_okay; 165641646Sgibbs } else { 165739220Sgibbs /* 165839220Sgibbs * We only allow one untagged command per-target 165919164Sgibbs * at a time. So, if the lun doesn't match, look 166023925Sgibbs * for a tag message. 166123925Sgibbs */ 166223925Sgibbs mov A, SCB_LUN; 16634568Sgibbs cmp SAVED_LUN, A je setup_SCB_id_lun_okay; 166419164Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 166523925Sgibbs /* 166623925Sgibbs * findSCB removes the SCB from the 166719164Sgibbs * disconnected list, so we must replace 166823925Sgibbs * it there should this SCB be for another 166919164Sgibbs * lun. 167023925Sgibbs */ 167119164Sgibbs call cleanup_scb; 167223925Sgibbs } 167323925Sgibbs } 167423925Sgibbs 167539220Sgibbs/* 16764568Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 167739220Sgibbs * If we get one, we use the tag returned to find the proper 167839220Sgibbs * SCB. With SCB paging, we must search for non-tagged 167939220Sgibbs * transactions since the SCB may exist in any slot. If we're not 168039220Sgibbs * using SCB paging, we can use the tag as the direct index to the 168139220Sgibbs * SCB. 168239220Sgibbs */ 168339220Sgibbssnoop_tag: 168439220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 168539220Sgibbs or SEQ_FLAGS, 0x80; 168639220Sgibbs } 168739220Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 168839220Sgibbs call phase_lock; 168939220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 169039220Sgibbs or SEQ_FLAGS, 0x1; 169139220Sgibbs } 169239220Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 169339220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 169439220Sgibbs or SEQ_FLAGS, 0x2; 169539220Sgibbs } 169639220Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 169739220Sgibbsget_tag: 169839220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 169939220Sgibbs mvi ARG_1 call inb_next; /* tag value */ 170039220Sgibbs mov ARG_1 call findSCB; 170139220Sgibbs } else { 170239220Sgibbs mvi ARG_1 call inb_next; /* tag value */ 170339220Sgibbs mov SCBPTR, ARG_1; 170439220Sgibbs } 170539220Sgibbs 170639220Sgibbs/* 170739220Sgibbs * Ensure that the SCB the tag points to is for 170839220Sgibbs * an SCB transaction to the reconnecting target. 170939220Sgibbs */ 171039220Sgibbssetup_SCB: 171139220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 171239220Sgibbs or SEQ_FLAGS, 0x4; 171339220Sgibbs } 171439220Sgibbs mov A, SCB_SCSIID; 171539220Sgibbs cmp SAVED_SCSIID, A jne not_found_cleanup_scb; 171639220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 171739220Sgibbs or SEQ_FLAGS, 0x8; 171839220Sgibbs } 171939220Sgibbssetup_SCB_id_okay: 172039220Sgibbs mov A, SCB_LUN; 172119164Sgibbs cmp SAVED_LUN, A jne not_found_cleanup_scb; 172239220Sgibbssetup_SCB_id_lun_okay: 172339220Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 172439220Sgibbs or SEQ_FLAGS, 0x10; 172539220Sgibbs } 172639220Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; 172739220Sgibbs and SCB_CONTROL,~DISCONNECTED; 172839220Sgibbs test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; 172939220Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 173039220Sgibbs mov A, SCBPTR; 173139220Sgibbs } 173239220Sgibbs mvi ARG_1, SCB_LIST_NULL; 173339220Sgibbs mov SAVED_SCSIID call set_busy_target; 173439220Sgibbs if ((ahc->flags & AHC_SCB_BTT) != 0) { 173539220Sgibbs mov SCBPTR, A; 173639220Sgibbs } 173739220Sgibbssetup_SCB_tagged: 173839220Sgibbs 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; 174339220Sgibbs jmp mesgin_done; 174439220Sgibbs 174539220Sgibbsnot_found_cleanup_scb: 174639220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 174739220Sgibbs call cleanup_scb; 174839220Sgibbs } 174939220Sgibbsnot_found: 175039220Sgibbs mvi NO_MATCH call set_seqint; 175139220Sgibbs jmp mesgin_done; 175239220Sgibbs 175339220Sgibbsmk_mesg: 175439220Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 175539220Sgibbs mov MSG_OUT,SINDEX ret; 175624175Sgibbs 175739220Sgibbs/* 175839220Sgibbs * Functions to read data in Automatic PIO mode. 175924175Sgibbs * 176039220Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 176139220Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 176239220Sgibbs * latched (the usual way), then read the data byte directly off the bus 176339220Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 176439220Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 176539220Sgibbs * spec guarantees that the target will hold the data byte on the bus until 176639220Sgibbs * we send our ACK. 176739220Sgibbs * 176839220Sgibbs * The assumption here is that these are called in a particular sequence, 176919164Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 177039220Sgibbs * use the same calling convention as inb. 177139220Sgibbs */ 177239220Sgibbsinb_next_wait_perr: 177339220Sgibbs mvi PERR_DETECTED call set_seqint; 177439220Sgibbs jmp inb_next_wait; 177539220Sgibbsinb_next: 177639220Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 177719164Sgibbsinb_next_wait: 177839220Sgibbs /* 177919164Sgibbs * If there is a parity error, wait for the kernel to 178039220Sgibbs * see the interrupt and prepare our message response 178139220Sgibbs * before continuing. 178239220Sgibbs */ 178339220Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 178439220Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait_perr; 178539220Sgibbsinb_next_check_phase: 178639220Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 178739220Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 178819164Sgibbsinb_first: 178939220Sgibbs mov DINDEX,SINDEX; 179013177Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 179119164Sgibbsinb_last: 179219164Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 179313177Sgibbs} 179419164Sgibbs 179523925Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 179622234Sgibbs/* 179723925Sgibbs * Change to a new phase. If we are changing the state of the I/O signal, 179823925Sgibbs * from out to in, wait an additional data release delay before continuing. 179923925Sgibbs */ 18009928Sgibbschange_phase: 180123925Sgibbs /* Wait for preceding I/O session to complete. */ 180239220Sgibbs test SCSISIGI, ACKI jnz .; 180339220Sgibbs 180439220Sgibbs /* Change the phase */ 180539220Sgibbs and DINDEX, IOI, SCSISIGI; 180639220Sgibbs mov SCSISIGO, SINDEX; 18074568Sgibbs and A, IOI, SINDEX; 180839220Sgibbs 180919164Sgibbs /* 181023925Sgibbs * If the data direction has changed, from 181123925Sgibbs * out (initiator driving) to in (target driving), 181219623Sgibbs * we must wait at least a data release delay plus 181323925Sgibbs * the normal bus settle delay. [SCSI III SPI 10.11.0] 181419623Sgibbs */ 181523925Sgibbs cmp DINDEX, A je change_phase_wait; 181623925Sgibbs test SINDEX, IOI jz change_phase_wait; 181723925Sgibbs call change_phase_wait; 181823925Sgibbschange_phase_wait: 181919164Sgibbs nop; 182039220Sgibbs nop; 182119164Sgibbs nop; 182223925Sgibbs nop ret; 182323925Sgibbs 182439220Sgibbs/* 18254568Sgibbs * Send a byte to an initiator in Automatic PIO mode. 182619164Sgibbs */ 182713177Sgibbstarget_outb: 182819164Sgibbs or SXFRCTL0, SPIOEN; 182919164Sgibbs test SSTAT0, SPIORDY jz .; 183019164Sgibbs mov SCSIDATL, SINDEX; 183113177Sgibbs test SSTAT0, SPIORDY jz .; 183223925Sgibbs and SXFRCTL0, ~SPIOEN ret; 183339220Sgibbs} 1834 1835 1836/* 1837 * Assert that if we've been reselected, then we've seen an IDENTIFY 1838 * message. 1839 */ 1840assert: 1841 test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 1842 1843 mvi NO_IDENT jmp set_seqint; /* no - tell the kernel */ 1844 1845/* 1846 * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will 1847 * be set to the position of the SCB. If the SCB cannot be found locally, 1848 * it will be paged in from host memory. RETURN_2 stores the address of the 1849 * preceding SCB in the disconnected list which can be used to speed up 1850 * removal of the found SCB from the disconnected list. 1851 */ 1852if ((ahc->flags & AHC_PAGESCBS) != 0) { 1853BEGIN_CRITICAL 1854findSCB: 1855 mov A, SINDEX; /* Tag passed in SINDEX */ 1856 cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; 1857 mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ 1858 mvi ARG_2, SCB_LIST_NULL; /* Head of list */ 1859 jmp findSCB_loop; 1860findSCB_next: 1861 cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; 1862 mov ARG_2, SCBPTR; 1863 mov SCBPTR,SCB_NEXT; 1864findSCB_loop: 1865 cmp SCB_TAG, A jne findSCB_next; 1866rem_scb_from_disc_list: 1867 cmp ARG_2, SCB_LIST_NULL je rHead; 1868 mov DINDEX, SCB_NEXT; 1869 mov SINDEX, SCBPTR; 1870 mov SCBPTR, ARG_2; 1871 mov SCB_NEXT, DINDEX; 1872 mov SCBPTR, SINDEX ret; 1873rHead: 1874 mov DISCONNECTED_SCBH,SCB_NEXT ret; 1875END_CRITICAL 1876findSCB_notFound: 1877 /* 1878 * We didn't find it. Page in the SCB. 1879 */ 1880 mov ARG_1, A; /* Save tag */ 1881 mov ALLZEROS call get_free_or_disc_scb; 1882 mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 1883 mov ARG_1 jmp dma_scb; 1884} 1885 1886/* 1887 * Prepare the hardware to post a byte to host memory given an 1888 * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. 1889 */ 1890post_byte_setup: 1891 mov ARG_2, SINDEX; 1892 if ((ahc->features & AHC_CMD_CHAN) != 0) { 1893 mvi DINDEX, CCHADDR; 1894 mvi SHARED_DATA_ADDR call set_1byte_addr; 1895 mvi CCHCNT, 1; 1896 mvi CCSCBCTL, CCSCBRESET ret; 1897 } else { 1898 mvi DINDEX, HADDR; 1899 mvi SHARED_DATA_ADDR call set_1byte_addr; 1900 mvi 1 call set_hcnt; 1901 mvi DFCNTRL, FIFORESET ret; 1902 } 1903 1904post_byte: 1905 if ((ahc->features & AHC_CMD_CHAN) != 0) { 1906 bmov CCSCBRAM, SINDEX, 1; 1907 or CCSCBCTL, CCSCBEN|CCSCBRESET; 1908 test CCSCBCTL, CCSCBDONE jz .; 1909 clr CCSCBCTL ret; 1910 } else { 1911 mov DFDAT, SINDEX; 1912 or DFCNTRL, HDMAEN|FIFOFLUSH; 1913 jmp dma_finish; 1914 } 1915 1916phase_lock_perr: 1917 mvi PERR_DETECTED call set_seqint; 1918phase_lock: 1919 /* 1920 * If there is a parity error, wait for the kernel to 1921 * see the interrupt and prepare our message response 1922 * before continuing. 1923 */ 1924 test SSTAT1, REQINIT jz phase_lock; 1925 test SSTAT1, SCSIPERR jnz phase_lock_perr; 1926phase_lock_latch_phase: 1927 and SCSISIGO, PHASE_MASK, SCSISIGI; 1928 and LASTPHASE, PHASE_MASK, SCSISIGI ret; 1929 1930if ((ahc->features & AHC_CMD_CHAN) == 0) { 1931set_hcnt: 1932 mov HCNT[0], SINDEX; 1933clear_hcnt: 1934 clr HCNT[1]; 1935 clr HCNT[2] ret; 1936 1937set_stcnt_from_hcnt: 1938 mov STCNT[0], HCNT[0]; 1939 mov STCNT[1], HCNT[1]; 1940 mov STCNT[2], HCNT[2] ret; 1941 1942bcopy_8: 1943 mov DINDIR, SINDIR; 1944bcopy_7: 1945 mov DINDIR, SINDIR; 1946 mov DINDIR, SINDIR; 1947bcopy_5: 1948 mov DINDIR, SINDIR; 1949bcopy_4: 1950 mov DINDIR, SINDIR; 1951bcopy_3: 1952 mov DINDIR, SINDIR; 1953 mov DINDIR, SINDIR; 1954 mov DINDIR, SINDIR ret; 1955} 1956 1957if ((ahc->flags & AHC_TARGETROLE) != 0) { 1958/* 1959 * Setup addr assuming that A is an index into 1960 * an array of 32byte objects, SINDEX contains 1961 * the base address of that array, and DINDEX 1962 * contains the base address of the location 1963 * to store the indexed address. 1964 */ 1965set_32byte_addr: 1966 shr ARG_2, 3, A; 1967 shl A, 5; 1968 jmp set_1byte_addr; 1969} 1970 1971/* 1972 * Setup addr assuming that A is an index into 1973 * an array of 64byte objects, SINDEX contains 1974 * the base address of that array, and DINDEX 1975 * contains the base address of the location 1976 * to store the indexed address. 1977 */ 1978set_64byte_addr: 1979 shr ARG_2, 2, A; 1980 shl A, 6; 1981 1982/* 1983 * Setup addr assuming that A + (ARG_2 * 256) is an 1984 * index into an array of 1byte objects, SINDEX contains 1985 * the base address of that array, and DINDEX contains 1986 * the base address of the location to store the computed 1987 * address. 1988 */ 1989set_1byte_addr: 1990 add DINDIR, A, SINDIR; 1991 mov A, ARG_2; 1992 adc DINDIR, A, SINDIR; 1993 clr A; 1994 adc DINDIR, A, SINDIR; 1995 adc DINDIR, A, SINDIR ret; 1996 1997/* 1998 * Either post or fetch and SCB from host memory based on the 1999 * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. 2000 */ 2001dma_scb: 2002 mov A, SINDEX; 2003 if ((ahc->features & AHC_CMD_CHAN) != 0) { 2004 mvi DINDEX, CCHADDR; 2005 mvi HSCB_ADDR call set_64byte_addr; 2006 mov CCSCBPTR, SCBPTR; 2007 test DMAPARAMS, DIRECTION jz dma_scb_tohost; 2008 if ((ahc->flags & AHC_SCB_BTT) != 0) { 2009 mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; 2010 } else { 2011 mvi CCHCNT, SCB_DOWNLOAD_SIZE; 2012 } 2013 mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; 2014 cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; 2015 jmp dma_scb_finish; 2016dma_scb_tohost: 2017 mvi CCHCNT, SCB_UPLOAD_SIZE; 2018 if ((ahc->features & AHC_ULTRA2) == 0) { 2019 mvi CCSCBCTL, CCSCBRESET; 2020 bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; 2021 or CCSCBCTL, CCSCBEN|CCSCBRESET; 2022 test CCSCBCTL, CCSCBDONE jz .; 2023 } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { 2024 mvi CCSCBCTL, CCARREN|CCSCBRESET; 2025 cmp CCSCBCTL, ARRDONE|CCARREN jne .; 2026 mvi CCHCNT, SCB_UPLOAD_SIZE; 2027 mvi CCSCBCTL, CCSCBEN|CCSCBRESET; 2028 cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; 2029 } else { 2030 mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; 2031 cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; 2032 } 2033dma_scb_finish: 2034 clr CCSCBCTL; 2035 test CCSCBCTL, CCARREN|CCSCBEN jnz .; 2036 ret; 2037 } else { 2038 mvi DINDEX, HADDR; 2039 mvi HSCB_ADDR call set_64byte_addr; 2040 mvi SCB_DOWNLOAD_SIZE call set_hcnt; 2041 mov DFCNTRL, DMAPARAMS; 2042 test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 2043 /* Fill it with the SCB data */ 2044copy_scb_tofifo: 2045 mvi SINDEX, SCB_BASE; 2046 add A, SCB_DOWNLOAD_SIZE, SINDEX; 2047copy_scb_tofifo_loop: 2048 call copy_to_fifo_8; 2049 cmp SINDEX, A jne copy_scb_tofifo_loop; 2050 or DFCNTRL, HDMAEN|FIFOFLUSH; 2051 jmp dma_finish; 2052dma_scb_fromhost: 2053 mvi DINDEX, SCB_BASE; 2054 if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 2055 /* 2056 * The PCI module will only issue a PCI 2057 * retry if the data FIFO is empty. If the 2058 * host disconnects in the middle of a 2059 * transfer, we must empty the fifo of all 2060 * available data to force the chip to 2061 * continue the transfer. This does not 2062 * happen for SCSI transfers as the SCSI module 2063 * will drain the FIFO as data is made available. 2064 * When the hang occurs, we know that a multiple 2065 * of 8 bytes are in the FIFO because the PCI 2066 * module has an 8 byte input latch that only 2067 * dumps to the FIFO when HCNT == 0 or the 2068 * latch is full. 2069 */ 2070 clr A; 2071 /* Wait for at least 8 bytes of data to arrive. */ 2072dma_scb_hang_fifo: 2073 test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; 2074dma_scb_hang_wait: 2075 test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; 2076 test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 2077 test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 2078 test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 2079 /* 2080 * The PCI module no longer intends to perform 2081 * a PCI transaction. Drain the fifo. 2082 */ 2083dma_scb_hang_empty_fifo: 2084 /* 2085 * Skip lines not yet transfered into the FIFO. 2086 */ 2087 add SINDEX, 7, HCNT; 2088 shr SINDEX, 3; 2089 2090 /* 2091 * Skip lines already copied out of the FIFO. 2092 */ 2093 add A, A, SINDEX; 2094 2095 call dma_scb_hang_dma_drain_fifo; 2096 2097 /* 2098 * Set the lines transferred to all but 2099 * those yet to reach the FIFO. 2100 */ 2101 not SINDEX; 2102 add A, 5, SINDEX; 2103 cmp A, 4 je dma_finish_nowait; 2104 jmp dma_scb_hang_fifo; 2105dma_scb_hang_dma_done: 2106 and DFCNTRL, ~HDMAEN; 2107 test DFCNTRL, HDMAEN jnz .; 2108dma_scb_hang_dma_drain_fifo: 2109 add SEQADDR0, A; 2110 } else { 2111 call dma_finish; 2112 } 2113 /* If we were putting the SCB, we are done */ 2114 call dfdat_in_8; 2115 call dfdat_in_8; 2116 call dfdat_in_8; 2117dfdat_in_8: 2118 mov DINDIR,DFDAT; 2119dfdat_in_7: 2120 mov DINDIR,DFDAT; 2121 mov DINDIR,DFDAT; 2122 mov DINDIR,DFDAT; 2123 mov DINDIR,DFDAT; 2124 mov DINDIR,DFDAT; 2125dfdat_in_2: 2126 mov DINDIR,DFDAT; 2127 mov DINDIR,DFDAT ret; 2128 } 2129 2130copy_to_fifo_8: 2131 mov DFDAT,SINDIR; 2132 mov DFDAT,SINDIR; 2133copy_to_fifo_6: 2134 mov DFDAT,SINDIR; 2135copy_to_fifo_5: 2136 mov DFDAT,SINDIR; 2137copy_to_fifo_4: 2138 mov DFDAT,SINDIR; 2139 mov DFDAT,SINDIR; 2140 mov DFDAT,SINDIR; 2141 mov DFDAT,SINDIR ret; 2142 2143/* 2144 * Wait for DMA from host memory to data FIFO to complete, then disable 2145 * DMA and wait for it to acknowledge that it's off. 2146 */ 2147dma_finish: 2148 test DFSTATUS,HDONE jz dma_finish; 2149dma_finish_nowait: 2150 /* Turn off DMA */ 2151 and DFCNTRL, ~HDMAEN; 2152 test DFCNTRL, HDMAEN jnz .; 2153 ret; 2154 2155/* 2156 * Restore an SCB that failed to match an incoming reselection 2157 * to the correct/safe state. If the SCB is for a disconnected 2158 * transaction, it must be returned to the disconnected list. 2159 * If it is not in the disconnected state, it must be free. 2160 */ 2161cleanup_scb: 2162 if ((ahc->flags & AHC_PAGESCBS) != 0) { 2163 test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list; 2164 } 2165add_scb_to_free_list: 2166 if ((ahc->flags & AHC_PAGESCBS) != 0) { 2167BEGIN_CRITICAL 2168 mov SCB_NEXT, FREE_SCBH; 2169 mvi SCB_TAG, SCB_LIST_NULL; 2170 mov FREE_SCBH, SCBPTR ret; 2171END_CRITICAL 2172 } else { 2173 mvi SCB_TAG, SCB_LIST_NULL ret; 2174 } 2175 2176if ((ahc->flags & AHC_PAGESCBS) != 0) { 2177get_free_or_disc_scb: 2178BEGIN_CRITICAL 2179 cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 2180 cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 2181return_error: 2182 mvi NO_FREE_SCB call set_seqint; 2183 mvi SINDEX, SCB_LIST_NULL ret; 2184dequeue_disc_scb: 2185 mov SCBPTR, DISCONNECTED_SCBH; 2186 mov DISCONNECTED_SCBH, SCB_NEXT; 2187END_CRITICAL 2188 mvi DMAPARAMS, FIFORESET; 2189 mov SCB_TAG jmp dma_scb; 2190BEGIN_CRITICAL 2191dequeue_free_scb: 2192 mov SCBPTR, FREE_SCBH; 2193 mov FREE_SCBH, SCB_NEXT ret; 2194END_CRITICAL 2195 2196add_scb_to_disc_list: 2197/* 2198 * Link this SCB into the DISCONNECTED list. This list holds the 2199 * candidates for paging out an SCB if one is needed for a new command. 2200 * Modifying the disconnected list is a critical(pause dissabled) section. 2201 */ 2202BEGIN_CRITICAL 2203 mov SCB_NEXT, DISCONNECTED_SCBH; 2204 mov DISCONNECTED_SCBH, SCBPTR ret; 2205END_CRITICAL 2206} 2207set_seqint: 2208 mov INTSTAT, SINDEX; 2209 nop; 2210return: 2211 ret; 2212