aic7xxx.seq revision 68402
126997Sgibbs/* 226997Sgibbs * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. 313177Sgibbs * 455581Sgibbs * Copyright (c) 1994-2000 Justin Gibbs. 526997Sgibbs * All rights reserved. 613177Sgibbs * 726997Sgibbs * Redistribution and use in source and binary forms, with or without 826997Sgibbs * modification, are permitted provided that the following conditions 926997Sgibbs * are met: 1026997Sgibbs * 1. Redistributions of source code must retain the above copyright 1126997Sgibbs * notice, this list of conditions, and the following disclaimer, 1254211Sgibbs * without modification. 1339220Sgibbs * 2. The name of the author may not be used to endorse or promote products 1426997Sgibbs * derived from this software without specific prior written permission. 1513177Sgibbs * 1654211Sgibbs * Alternatively, this software may be distributed under the terms of the 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 * 3166647Sgibbs * $Id: //depot/src/aic7xxx/aic7xxx.seq#7 $ 3265942Sgibbs * 3350477Speter * $FreeBSD: head/sys/dev/aic7xxx/aic7xxx.seq 68402 2000-11-06 20:05:38Z 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 5744507Sgibbspoll_for_work: 5823925Sgibbs call clear_target_state; 5939220Sgibbs and SXFRCTL0, ~SPIOEN; 6068087Sgibbs clr SCSIBUSL; 6139220Sgibbspoll_for_work_loop: 6239220Sgibbs test SSTAT0, SELDO|SELDI jnz selection; 6358258Sgibbs test SCSISEQ, ENSELO jnz poll_for_work_loop; 6439220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 6539220Sgibbs /* 6639220Sgibbs * Twin channel devices cannot handle things like SELTO 6739220Sgibbs * interrupts on the "background" channel. So, if we 6839220Sgibbs * are selecting, keep polling the current channel util 6939220Sgibbs * either a selection or reselection occurs. 7039220Sgibbs */ 7139220Sgibbs xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 7239220Sgibbs test SSTAT0, SELDO|SELDI jnz selection; 7365942Sgibbs xor SBLKCTL,SELBUSB; /* Toggle back */ 7439220Sgibbs } 7523925Sgibbs cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 7619164Sgibbstest_queue: 7719164Sgibbs /* Has the driver posted any work for us? */ 7866647SgibbsBEGIN_CRITICAL 7939220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 8039220Sgibbs test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; 8139220Sgibbs } else { 8268087Sgibbs mov A, QINPOS; 8339220Sgibbs cmp KERNEL_QINPOS, A je poll_for_work_loop; 8439220Sgibbs } 8566647Sgibbs mov ARG_1, NEXT_QUEUED_SCB; 8666647SgibbsEND_CRITICAL 874568Sgibbs 8863457Sgibbs /* 8963457Sgibbs * We have at least one queued SCB now and we don't have any 9066647Sgibbs * SCBs in the list of SCBs awaiting selection. Allocate a 9166647Sgibbs * card SCB for the host's SCB and get to work on it. 9263457Sgibbs */ 9339220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 9439220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 9566647Sgibbs } else { 9639220Sgibbs /* In the non-paging case, the SCBID == hardware SCB index */ 9766647Sgibbs mov SCBPTR, ARG_1; 9839220Sgibbs } 9919164Sgibbsdma_queued_scb: 10063457Sgibbs /* 10163457Sgibbs * DMA the SCB from host ram into the current SCB location. 10263457Sgibbs */ 10323925Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 10466647Sgibbs mov ARG_1 call dma_scb; 10519164Sgibbs /* 10666647Sgibbs * Check one last time to see if this SCB was canceled 10766647Sgibbs * before we completed the DMA operation. If it was, 10866647Sgibbs * the QINFIFO next pointer will not match our saved 10966647Sgibbs * value. 11019164Sgibbs */ 11166647Sgibbs mov A, ARG_1; 11266647SgibbsBEGIN_CRITICAL 11366647Sgibbs cmp NEXT_QUEUED_SCB, A jne abort_qinscb; 11468087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 11568087Sgibbs if ((ahc->flags & AHC_PAGESCBS) == 0) { 11668087Sgibbs cmp SCBPTR, A je . + 2; 11768402Sgibbs mvi SCBPTR_MISMATCH call set_seqint; 11868087Sgibbs } 11968087Sgibbs cmp SCB_TAG, A je . + 2; 12068402Sgibbs mvi SCB_MISMATCH call set_seqint; 12168087Sgibbs } 12266647Sgibbs mov NEXT_QUEUED_SCB, SCB_NEXT; 12323925Sgibbs mov SCB_NEXT,WAITING_SCBH; 12423925Sgibbs mov WAITING_SCBH, SCBPTR; 12568402Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 12668402Sgibbs mov NONE, SNSCB_QOFF; 12768402Sgibbs } else { 12868402Sgibbs inc QINPOS; 12968402Sgibbs } 13066647SgibbsEND_CRITICAL 13123925Sgibbsstart_waiting: 13223925Sgibbs /* 13363457Sgibbs * Start the first entry on the waiting SCB list. 13423925Sgibbs */ 13523925Sgibbs mov SCBPTR, WAITING_SCBH; 13623925Sgibbs call start_selection; 13765942Sgibbs jmp poll_for_work_loop; 1388104Sgibbs 13966647Sgibbsabort_qinscb: 14068402Sgibbs mvi ABORT_QINSCB call set_seqint; 14166647Sgibbs call add_scb_to_free_list; 14266647Sgibbs jmp poll_for_work_loop; 14366647Sgibbs 14423925Sgibbsstart_selection: 14539220Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 14639220Sgibbs and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ 14763457Sgibbs test SCB_SCSIID, TWIN_CHNLB jz . + 2; 14863457Sgibbs or SINDEX, SELBUSB; 14939220Sgibbs mov SBLKCTL,SINDEX; /* select channel */ 15039220Sgibbs } 15123925Sgibbsinitialize_scsiid: 15263457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 15363457Sgibbs mov SCSIID_ULTRA2, SCB_SCSIID; 15463457Sgibbs } else if ((ahc->features & AHC_TWIN) != 0) { 15563457Sgibbs and SCSIID, TWIN_TID|OID, SCB_SCSIID; 15663457Sgibbs } else { 15763457Sgibbs mov SCSIID, SCB_SCSIID; 15863457Sgibbs } 15968087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 16063457Sgibbs mov SINDEX, SCSISEQ_TEMPLATE; 16163457Sgibbs test SCB_CONTROL, TARGET_SCB jz . + 2; 16244507Sgibbs or SINDEX, TEMODE; 16363457Sgibbs mov SCSISEQ, SINDEX ret; 16439220Sgibbs } else { 16563457Sgibbs mov SCSISEQ, SCSISEQ_TEMPLATE ret; 16639220Sgibbs } 16739220Sgibbs 16813177Sgibbs/* 16939220Sgibbs * Initialize transfer settings and clear the SCSI channel. 17039220Sgibbs * SINDEX should contain any additional bit's the client wants 17139220Sgibbs * set in SXFRCTL0. We also assume that the current SCB is 17239220Sgibbs * a valid SCB for the target we wish to talk to. 17339220Sgibbs */ 17439220Sgibbsinitialize_channel: 17568087Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 17639220Sgibbsset_transfer_settings: 17739220Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 17839220Sgibbs test SCB_CONTROL, ULTRAENB jz . + 2; 17939220Sgibbs or SXFRCTL0, FAST20; 18039220Sgibbs } 18163457Sgibbs /* 18263457Sgibbs * Initialize SCSIRATE with the appropriate value for this target. 18363457Sgibbs */ 18439220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 18539220Sgibbs bmov SCSIRATE, SCB_SCSIRATE, 2 ret; 18639220Sgibbs } else { 18739220Sgibbs mov SCSIRATE, SCB_SCSIRATE ret; 18839220Sgibbs } 18939220Sgibbs 19039220Sgibbsselection: 19163457Sgibbs /* 19263457Sgibbs * We aren't expecting a bus free, so interrupt 19363457Sgibbs * the kernel driver if it happens. 19463457Sgibbs */ 19563457Sgibbs mvi CLRSINT1,CLRBUSFREE; 19663457Sgibbs or SIMODE1, ENBUSFREE; 19763457Sgibbs 19839220Sgibbs test SSTAT0,SELDO jnz select_out; 19939220Sgibbs mvi CLRSINT0, CLRSELDI; 20039220Sgibbsselect_in: 20168087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 20268087Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 20341646Sgibbs test SSTAT0, TARGET jz initiator_reselect; 20441646Sgibbs } 20542652Sgibbs 20639220Sgibbs /* 20739220Sgibbs * We've just been selected. Assert BSY and 20839220Sgibbs * setup the phase for receiving messages 20939220Sgibbs * from the target. 21039220Sgibbs */ 21139220Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 21239220Sgibbs 21339220Sgibbs /* 21439220Sgibbs * Setup the DMA for sending the identify and 21541299Sgibbs * command information. 21639220Sgibbs */ 21739220Sgibbs or SEQ_FLAGS, CMDPHASE_PENDING; 21841299Sgibbs 21941299Sgibbs mov A, TQINPOS; 22039220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 22139220Sgibbs mvi DINDEX, CCHADDR; 22263457Sgibbs mvi SHARED_DATA_ADDR call set_32byte_addr; 22339220Sgibbs mvi CCSCBCTL, CCSCBRESET; 22439220Sgibbs } else { 22539220Sgibbs mvi DINDEX, HADDR; 22663457Sgibbs mvi SHARED_DATA_ADDR call set_32byte_addr; 22739220Sgibbs mvi DFCNTRL, FIFORESET; 22839220Sgibbs } 22939220Sgibbs 23039220Sgibbs /* Initiator that selected us */ 23163457Sgibbs and SAVED_SCSIID, SELID_MASK, SELID; 23263457Sgibbs /* The Target ID we were selected at */ 23363457Sgibbs if ((ahc->features & AHC_MULTI_TID) != 0) { 23463457Sgibbs and A, OID, TARGIDIN; 23563457Sgibbs } else if ((ahc->features & AHC_ULTRA2) != 0) { 23663457Sgibbs and A, OID, SCSIID_ULTRA2; 23739220Sgibbs } else { 23863457Sgibbs and A, OID, SCSIID; 23939220Sgibbs } 24063457Sgibbs or SAVED_SCSIID, A; 24163457Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 24263457Sgibbs test SBLKCTL, SELBUSB jz . + 2; 24363457Sgibbs or SAVED_SCSIID, TWIN_CHNLB; 24463457Sgibbs } 24544507Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 24663457Sgibbs mov CCSCBRAM, SAVED_SCSIID; 24739220Sgibbs } else { 24863457Sgibbs mov DFDAT, SAVED_SCSIID; 24939220Sgibbs } 25039220Sgibbs 25139220Sgibbs /* 25239220Sgibbs * If ATN isn't asserted, the target isn't interested 25339220Sgibbs * in talking to us. Go directly to bus free. 25463457Sgibbs * XXX SCSI-1 may require us to assume lun 0 if 25563457Sgibbs * ATN is false. 25639220Sgibbs */ 25739220Sgibbs test SCSISIGI, ATNI jz target_busfree; 25839220Sgibbs 25939220Sgibbs /* 26039220Sgibbs * Watch ATN closely now as we pull in messages from the 26139220Sgibbs * initiator. We follow the guidlines from section 6.5 26239220Sgibbs * of the SCSI-2 spec for what messages are allowed when. 26339220Sgibbs */ 26441646Sgibbs call target_inb; 26539220Sgibbs 26639220Sgibbs /* 26739220Sgibbs * Our first message must be one of IDENTIFY, ABORT, or 26839220Sgibbs * BUS_DEVICE_RESET. 26939220Sgibbs */ 27042652Sgibbs test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; 27139220Sgibbs /* Store for host */ 27239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 27339220Sgibbs mov CCSCBRAM, DINDEX; 27439220Sgibbs } else { 27539220Sgibbs mov DFDAT, DINDEX; 27639220Sgibbs } 27739220Sgibbs 27839220Sgibbs /* Remember for disconnection decision */ 27939220Sgibbs test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; 28039220Sgibbs /* XXX Honor per target settings too */ 28139220Sgibbs or SEQ_FLAGS, NO_DISCONNECT; 28239220Sgibbs 28339220Sgibbs test SCSISIGI, ATNI jz ident_messages_done; 28441646Sgibbs call target_inb; 28539220Sgibbs /* 28639220Sgibbs * If this is a tagged request, the tagged message must 28739220Sgibbs * immediately follow the identify. We test for a valid 28839220Sgibbs * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and 28939220Sgibbs * < MSG_IGN_WIDE_RESIDUE. 29039220Sgibbs */ 29139220Sgibbs add A, -MSG_SIMPLE_Q_TAG, DINDEX; 29239220Sgibbs jnc ident_messages_done; 29339220Sgibbs add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; 29439220Sgibbs jc ident_messages_done; 29539220Sgibbs /* Store for host */ 29639220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 29739220Sgibbs mov CCSCBRAM, DINDEX; 29839220Sgibbs } else { 29939220Sgibbs mov DFDAT, DINDEX; 30039220Sgibbs } 30139220Sgibbs 30239220Sgibbs /* 30339220Sgibbs * If the initiator doesn't feel like providing a tag number, 30439220Sgibbs * we've got a failed selection and must transition to bus 30539220Sgibbs * free. 30639220Sgibbs */ 30739220Sgibbs test SCSISIGI, ATNI jz target_busfree; 30842652Sgibbs 30939220Sgibbs /* 31039220Sgibbs * Store the tag for the host. 31139220Sgibbs */ 31241646Sgibbs call target_inb; 31339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 31439220Sgibbs mov CCSCBRAM, DINDEX; 31539220Sgibbs } else { 31639220Sgibbs mov DFDAT, DINDEX; 31739220Sgibbs } 31842652Sgibbs mov INITIATOR_TAG, DINDEX; 31963457Sgibbs or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; 32063457Sgibbs test SCSISIGI, ATNI jz . + 2; 32163457Sgibbs /* Initiator still wants to give us messages */ 32263457Sgibbs call target_inb; 32339220Sgibbs jmp ident_messages_done; 32439220Sgibbs 32541646Sgibbs /* 32641646Sgibbs * Pushed message loop to allow the kernel to 32742652Sgibbs * run it's own target mode message state engine. 32841646Sgibbs */ 32941646Sgibbshost_target_message_loop: 33068402Sgibbs mvi HOST_MSG_LOOP call set_seqint; 33141646Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; 33241646Sgibbs test SSTAT0, SPIORDY jz .; 33341646Sgibbs jmp host_target_message_loop; 33441646Sgibbs 33539220Sgibbsident_messages_done: 33644507Sgibbs /* If ring buffer is full, return busy or queue full */ 33758258Sgibbs if ((ahc->features & AHC_HS_MAILBOX) != 0) { 33858258Sgibbs and A, HOST_TQINPOS, HS_MAILBOX; 33958258Sgibbs } else { 34058258Sgibbs mov A, KERNEL_TQINPOS; 34158258Sgibbs } 34244507Sgibbs cmp TQINPOS, A jne tqinfifo_has_space; 34344507Sgibbs mvi P_STATUS|BSYO call change_phase; 34468087Sgibbs test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; 34544507Sgibbs mvi STATUS_QUEUE_FULL call target_outb; 34644507Sgibbs jmp target_busfree_wait; 34744507Sgibbs mvi STATUS_BUSY call target_outb; 34844507Sgibbs jmp target_busfree_wait; 34944507Sgibbstqinfifo_has_space: 35039220Sgibbs /* Terminate the ident list */ 35139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 35239220Sgibbs mvi CCSCBRAM, SCB_LIST_NULL; 35339220Sgibbs } else { 35439220Sgibbs mvi DFDAT, SCB_LIST_NULL; 35539220Sgibbs } 35642652Sgibbs or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN; 35763457Sgibbs test SCSISIGI, ATNI jnz target_mesgout_pending; 35839220Sgibbs jmp target_ITloop; 35939220Sgibbs 36039220Sgibbs/* 36139220Sgibbs * We carefully toggle SPIOEN to allow us to return the 36239220Sgibbs * message byte we receive so it can be checked prior to 36339220Sgibbs * driving REQ on the bus for the next byte. 36439220Sgibbs */ 36541646Sgibbstarget_inb: 36641646Sgibbs /* 36741646Sgibbs * Drive REQ on the bus by enabling SCSI PIO. 36841646Sgibbs */ 36939220Sgibbs or SXFRCTL0, SPIOEN; 37039220Sgibbs /* Wait for the byte */ 37139220Sgibbs test SSTAT0, SPIORDY jz .; 37239220Sgibbs /* Prevent our read from triggering another REQ */ 37339220Sgibbs and SXFRCTL0, ~SPIOEN; 37441646Sgibbs /* Save latched contents */ 37539220Sgibbs mov DINDEX, SCSIDATL ret; 37639220Sgibbs } 37739220Sgibbs 37868087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 37939220Sgibbs/* 38023925Sgibbs * Reselection has been initiated by a target. Make a note that we've been 38123925Sgibbs * reselected, but haven't seen an IDENTIFY message from the target yet. 38213177Sgibbs */ 38339220Sgibbsinitiator_reselect: 38423925Sgibbs /* XXX test for and handle ONE BIT condition */ 38563457Sgibbs and SAVED_SCSIID, SELID_MASK, SELID; 38663457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 38763457Sgibbs and A, OID, SCSIID_ULTRA2; 38863457Sgibbs } else { 38963457Sgibbs and A, OID, SCSIID; 39063457Sgibbs } 39163457Sgibbs or SAVED_SCSIID, A; 39239545Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 39339545Sgibbs test SBLKCTL, SELBUSB jz . + 2; 39463457Sgibbs or SAVED_SCSIID, TWIN_CHNLB; 39539545Sgibbs } 39641646Sgibbs or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 39739220Sgibbs jmp ITloop; 39841646Sgibbs} 3994568Sgibbs 40013177Sgibbs/* 40123925Sgibbs * After the selection, remove this SCB from the "waiting SCB" 40223925Sgibbs * list. This is achieved by simply moving our "next" pointer into 40323925Sgibbs * WAITING_SCBH. Our next pointer will be set to null the next time this 40423925Sgibbs * SCB is used, so don't bother with it now. 40523925Sgibbs */ 40639220Sgibbsselect_out: 40725005Sgibbs /* Turn off the selection hardware */ 40858258Sgibbs and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; 40925005Sgibbs mvi CLRSINT0, CLRSELDO; 41025005Sgibbs mov SCBPTR, WAITING_SCBH; 41124914Sgibbs mov WAITING_SCBH,SCB_NEXT; 41263457Sgibbs mov SAVED_SCSIID, SCB_SCSIID; 41363457Sgibbs mov SAVED_LUN, SCB_LUN; 41468087Sgibbs call initialize_channel; 41568087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 41639220Sgibbs test SSTAT0, TARGET jz initiator_select; 4178567Sdg 41839220Sgibbs /* 41939220Sgibbs * We've just re-selected an initiator. 42039220Sgibbs * Assert BSY and setup the phase for 42139220Sgibbs * sending our identify messages. 42239220Sgibbs */ 42341646Sgibbs mvi P_MESGIN|BSYO call change_phase; 4244568Sgibbs 42539220Sgibbs /* 42639220Sgibbs * Start out with a simple identify message. 42739220Sgibbs */ 42863457Sgibbs or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; 4296608Sgibbs 43039220Sgibbs /* 43139220Sgibbs * If we are the result of a tagged command, send 43239220Sgibbs * a simple Q tag and the tag id. 43339220Sgibbs */ 43439220Sgibbs test SCB_CONTROL, TAG_ENB jz . + 3; 43539220Sgibbs mvi MSG_SIMPLE_Q_TAG call target_outb; 43663457Sgibbs mov SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb; 43739220Sgibbstarget_synccmd: 43839220Sgibbs /* 43939220Sgibbs * Now determine what phases the host wants us 44039220Sgibbs * to go through. 44139220Sgibbs */ 44263457Sgibbs mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; 44342652Sgibbs 44439220Sgibbstarget_ITloop: 44539220Sgibbs /* 44641646Sgibbs * Start honoring ATN signals now that 44744507Sgibbs * we properly identified ourselves. 44839220Sgibbs */ 44941646Sgibbs test SCSISIGI, ATNI jnz target_mesgout; 45039220Sgibbs test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; 45139220Sgibbs test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; 45239220Sgibbs test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; 45339220Sgibbs 45439220Sgibbs /* 45539220Sgibbs * No more work to do. Either disconnect or not depending 45639220Sgibbs * on the state of NO_DISCONNECT. 45739220Sgibbs */ 45839220Sgibbs test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 45939220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 46039220Sgibbs mov ALLZEROS call get_free_or_disc_scb; 46139220Sgibbs } 46241646Sgibbs mov RETURN_1, ALLZEROS; 46339220Sgibbs call complete_target_cmd; 46441646Sgibbs cmp RETURN_1, CONT_MSG_LOOP jne .; 46539220Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 46639220Sgibbs mov SCB_TAG call dma_scb; 46739220Sgibbs jmp target_synccmd; 46839220Sgibbs 46941646Sgibbstarget_mesgout: 47041646Sgibbs mvi SCSISIGO, P_MESGOUT|BSYO; 47163457Sgibbstarget_mesgout_continue: 47241646Sgibbs call target_inb; 47363457Sgibbstarget_mesgout_pending: 47441646Sgibbs /* Local Processing goes here... */ 47541646Sgibbs jmp host_target_message_loop; 47641646Sgibbs 47739220Sgibbstarget_disconnect: 47841646Sgibbs mvi P_MESGIN|BSYO call change_phase; 47941816Sgibbs test SEQ_FLAGS, DPHASE jz . + 2; 48041816Sgibbs mvi MSG_SAVEDATAPOINTER call target_outb; 48139220Sgibbs mvi MSG_DISCONNECT call target_outb; 48239220Sgibbs 48343880Sgibbstarget_busfree_wait: 48443880Sgibbs /* Wait for preceeding I/O session to complete. */ 48543880Sgibbs test SCSISIGI, ACKI jnz .; 48639220Sgibbstarget_busfree: 48763457Sgibbs and SIMODE1, ~ENBUSFREE; 48868087Sgibbs clr SCSIBUSL; 48939220Sgibbs clr SCSISIGO; 49057099Sgibbs mvi LASTPHASE, P_BUSFREE; 49139220Sgibbs call complete_target_cmd; 49239220Sgibbs jmp poll_for_work; 49339220Sgibbs 49439220Sgibbstarget_cmdphase: 49541646Sgibbs mvi P_COMMAND|BSYO call change_phase; 49641646Sgibbs call target_inb; 49739220Sgibbs mov A, DINDEX; 49839220Sgibbs /* Store for host */ 49939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 50039220Sgibbs mov CCSCBRAM, A; 50139220Sgibbs } else { 50239220Sgibbs mov DFDAT, A; 50339220Sgibbs } 50439220Sgibbs 50539220Sgibbs /* 50639220Sgibbs * Determine the number of bytes to read 50741299Sgibbs * based on the command group code via table lookup. 50841299Sgibbs * We reuse the first 8 bytes of the TARG_SCSIRATE 50941299Sgibbs * BIOS array for this table. Count is one less than 51041299Sgibbs * the total for the command since we've already fetched 51141299Sgibbs * the first byte. 51239220Sgibbs */ 51339220Sgibbs shr A, CMD_GROUP_CODE_SHIFT; 51468087Sgibbs add SINDEX, CMDSIZE_TABLE, A; 51539220Sgibbs mov A, SINDIR; 51639220Sgibbs 51739220Sgibbs test A, 0xFF jz command_phase_done; 51839220Sgibbscommand_loop: 51939220Sgibbs or SXFRCTL0, SPIOEN; 52039220Sgibbs test SSTAT0, SPIORDY jz .; 52139220Sgibbs cmp A, 1 jne . + 2; 52239220Sgibbs and SXFRCTL0, ~SPIOEN; /* Last Byte */ 52339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 52439220Sgibbs mov CCSCBRAM, SCSIDATL; 52539220Sgibbs } else { 52639220Sgibbs mov DFDAT, SCSIDATL; 52739220Sgibbs } 52839220Sgibbs dec A; 52939220Sgibbs test A, 0xFF jnz command_loop; 53039220Sgibbs 53139220Sgibbscommand_phase_done: 53239220Sgibbs and SEQ_FLAGS, ~CMDPHASE_PENDING; 53339220Sgibbs jmp target_ITloop; 53439220Sgibbs 53539220Sgibbstarget_dphase: 53639220Sgibbs /* 53763457Sgibbs * Data phases on the bus are from the 53863457Sgibbs * perspective of the initiator. The dma 53963457Sgibbs * code looks at LASTPHASE to determine the 54063457Sgibbs * data direction of the DMA. Toggle it for 54163457Sgibbs * target transfers. 54239220Sgibbs */ 54363457Sgibbs xor LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR]; 54463457Sgibbs or SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO 54563457Sgibbs call change_phase; 54639220Sgibbs jmp p_data; 54739220Sgibbs 54839220Sgibbstarget_sphase: 54941646Sgibbs mvi P_STATUS|BSYO call change_phase; 55041646Sgibbs mvi LASTPHASE, P_STATUS; 55163457Sgibbs mov SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb; 55241646Sgibbs /* XXX Watch for ATN or parity errors??? */ 55339220Sgibbs mvi SCSISIGO, P_MESGIN|BSYO; 55439220Sgibbs /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ 55539220Sgibbs mov ALLZEROS call target_outb; 55643880Sgibbs jmp target_busfree_wait; 55739220Sgibbs 55839220Sgibbscomplete_target_cmd: 55939220Sgibbs test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; 56039220Sgibbs mov SCB_TAG jmp complete_post; 56139220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 56241299Sgibbs /* Set the valid byte */ 56341299Sgibbs mvi CCSCBADDR, 24; 56441299Sgibbs mov CCSCBRAM, ALLONES; 56541299Sgibbs mvi CCHCNT, 28; 56639220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 56739220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 56839220Sgibbs clr CCSCBCTL; 56939220Sgibbs } else { 57041299Sgibbs /* Set the valid byte */ 57141299Sgibbs or DFCNTRL, FIFORESET; 57241299Sgibbs mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ 57341299Sgibbs mov DFDAT, ALLONES; 57463457Sgibbs mvi 28 call set_hcnt; 57539220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 57639220Sgibbs call dma_finish; 57739220Sgibbs } 57841299Sgibbs inc TQINPOS; 57941299Sgibbs mvi INTSTAT,CMDCMPLT ret; 58039220Sgibbs } 58141646Sgibbs 58268087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 58339220Sgibbsinitiator_select: 58441646Sgibbs /* 58541646Sgibbs * As soon as we get a successful selection, the target 58641646Sgibbs * should go into the message out phase since we have ATN 58741646Sgibbs * asserted. 58841646Sgibbs */ 58939220Sgibbs mvi MSG_OUT, MSG_IDENTIFYFLAG; 59039220Sgibbs or SEQ_FLAGS, IDENTIFY_SEEN; 59113177Sgibbs 59241646Sgibbs /* 59341646Sgibbs * Main loop for information transfer phases. Wait for the 59441646Sgibbs * target to assert REQ before checking MSG, C/D and I/O for 59541646Sgibbs * the bus phase. 59641646Sgibbs */ 59763457Sgibbsmesgin_phasemis: 5984568SgibbsITloop: 59939220Sgibbs call phase_lock; 6004568Sgibbs 60139220Sgibbs mov A, LASTPHASE; 6024568Sgibbs 60339220Sgibbs test A, ~P_DATAIN jz p_data; 60423925Sgibbs cmp A,P_COMMAND je p_command; 60523925Sgibbs cmp A,P_MESGOUT je p_mesgout; 60623925Sgibbs cmp A,P_STATUS je p_status; 60723925Sgibbs cmp A,P_MESGIN je p_mesgin; 6084568Sgibbs 60968402Sgibbs mvi BAD_PHASE call set_seqint; 61023925Sgibbs jmp ITloop; /* Try reading the bus again. */ 6114568Sgibbs 61223925Sgibbsawait_busfree: 61323925Sgibbs and SIMODE1, ~ENBUSFREE; 61423925Sgibbs mov NONE, SCSIDATL; /* Ack the last byte */ 61568087Sgibbs clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ 61639220Sgibbs and SXFRCTL0, ~SPIOEN; 61723925Sgibbs test SSTAT1,REQINIT|BUSFREE jz .; 61823925Sgibbs test SSTAT1, BUSFREE jnz poll_for_work; 61968402Sgibbs mvi BAD_PHASE call set_seqint; 62041646Sgibbs} 62123925Sgibbs 62223925Sgibbsclear_target_state: 62341646Sgibbs /* 62441646Sgibbs * We assume that the kernel driver may reset us 62541646Sgibbs * at any time, even in the middle of a DMA, so 62641646Sgibbs * clear DFCNTRL too. 62741646Sgibbs */ 62841646Sgibbs clr DFCNTRL; 62968087Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 63041646Sgibbs 63141646Sgibbs /* 63241646Sgibbs * We don't know the target we will connect to, 63341646Sgibbs * so default to narrow transfers to avoid 63441646Sgibbs * parity problems. 63541646Sgibbs */ 63641646Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 63741646Sgibbs bmov SCSIRATE, ALLZEROS, 2; 63841646Sgibbs } else { 63941646Sgibbs clr SCSIRATE; 64063457Sgibbs if ((ahc->features & AHC_ULTRA) != 0) { 64163457Sgibbs and SXFRCTL0, ~(FAST20); 64263457Sgibbs } 64341646Sgibbs } 64423925Sgibbs mvi LASTPHASE, P_BUSFREE; 64523925Sgibbs /* clear target specific flags */ 64639220Sgibbs clr SEQ_FLAGS ret; 64723925Sgibbs 64863457Sgibbssg_advance: 64963457Sgibbs clr A; /* add sizeof(struct scatter) */ 65063457Sgibbs add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; 65163457Sgibbs adc SCB_RESIDUAL_SGPTR[1],A; 65263457Sgibbs adc SCB_RESIDUAL_SGPTR[2],A; 65363457Sgibbs adc SCB_RESIDUAL_SGPTR[3],A ret; 65463457Sgibbs 65563457Sgibbsidle_loop: 65663457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 65763457Sgibbs /* Did we just finish fetching segs? */ 65863457Sgibbs cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; 65963457Sgibbs 66063457Sgibbs /* Are we actively fetching segments? */ 66163457Sgibbs test CCSGCTL, CCSGEN jnz return; 66263457Sgibbs 66363457Sgibbs /* 66463457Sgibbs * Do we need any more segments? 66563457Sgibbs */ 66663457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; 66763457Sgibbs 66863457Sgibbs /* 66963457Sgibbs * Do we have any prefetch left??? 67063457Sgibbs */ 67166647Sgibbs cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; 67263457Sgibbs 67363457Sgibbs /* 67463457Sgibbs * Need to fetch segments, but we can only do that 67563457Sgibbs * if the command channel is completely idle. Make 67663457Sgibbs * sure we don't have an SCB prefetch going on. 67763457Sgibbs */ 67863457Sgibbs test CCSCBCTL, CCSCBEN jnz return; 67963457Sgibbs 68063457Sgibbs /* 68166647Sgibbs * We fetch a "cacheline aligned" and sized amount of data 68266647Sgibbs * so we don't end up referencing a non-existant page. 68366647Sgibbs * Cacheline aligned is in quotes because the kernel will 68466647Sgibbs * set the prefetch amount to a reasonable level if the 68566647Sgibbs * cacheline size is unknown. 68663457Sgibbs */ 68766647Sgibbs mvi CCHCNT, SG_PREFETCH_CNT; 68866647Sgibbs and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; 68963457Sgibbs bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; 69063457Sgibbs mvi CCSGCTL, CCSGEN|CCSGRESET ret; 69163457Sgibbsidle_sgfetch_complete: 69263944Sgibbs clr CCSGCTL; 69363944Sgibbs test CCSGCTL, CCSGEN jnz .; 69466647Sgibbs and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; 69563457Sgibbsidle_sg_avail: 69663457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 69763457Sgibbs /* Does the hardware have space for another SG entry? */ 69863457Sgibbs test DFSTATUS, PRELOAD_AVAIL jz return; 69963457Sgibbs bmov HADDR, CCSGRAM, 4; 70063457Sgibbs bmov SINDEX, CCSGRAM, 1; 70163457Sgibbs test SINDEX, 0x1 jz . + 2; 70263457Sgibbs xor DATA_COUNT_ODD, 0x1; 70363457Sgibbs bmov HCNT[0], SINDEX, 1; 70463457Sgibbs bmov HCNT[1], CCSGRAM, 2; 70563457Sgibbs bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; 70663457Sgibbs call sg_advance; 70763457Sgibbs mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 70863457Sgibbs test DATA_COUNT_ODD, 0x1 jz . + 2; 70963457Sgibbs or SINDEX, ODD_SEG; 71063457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 71163457Sgibbs or SINDEX, LAST_SEG; 71263457Sgibbs mov SG_CACHE_PRE, SINDEX; 71363457Sgibbs /* Load the segment by writing DFCNTRL again */ 71463457Sgibbs mov DFCNTRL, DMAPARAMS; 71563457Sgibbs } 71663457Sgibbs ret; 71763457Sgibbs } 71863457Sgibbs 71965942Sgibbsif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 72013177Sgibbs/* 72165942Sgibbs * Calculate the trailing portion of this S/G segment that cannot 72265942Sgibbs * be transferred using memory write and invalidate PCI transactions. 72365942Sgibbs * XXX Can we optimize this for PCI writes only??? 72465942Sgibbs */ 72565942Sgibbscalc_mwi_residual: 72665942Sgibbs /* 72765942Sgibbs * If the ending address is on a cacheline boundary, 72865942Sgibbs * there is no need for an extra segment. 72965942Sgibbs */ 73065942Sgibbs mov A, HCNT[0]; 73165942Sgibbs add A, A, HADDR[0]; 73265942Sgibbs and A, CACHESIZE_MASK; 73365942Sgibbs test A, 0xFF jz return; 73465942Sgibbs 73565942Sgibbs /* 73665942Sgibbs * If the transfer is less than a cachline, 73765942Sgibbs * there is no need for an extra segment. 73865942Sgibbs */ 73965942Sgibbs test HCNT[1], 0xFF jnz calc_mwi_residual_final; 74065942Sgibbs test HCNT[2], 0xFF jnz calc_mwi_residual_final; 74165942Sgibbs add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; 74265942Sgibbs jnc return; 74365942Sgibbs 74465942Sgibbscalc_mwi_residual_final: 74565942Sgibbs mov MWI_RESIDUAL, A; 74665942Sgibbs not A; 74765942Sgibbs inc A; 74865942Sgibbs add HCNT[0], A; 74965942Sgibbs adc HCNT[1], -1; 75065942Sgibbs adc HCNT[2], -1 ret; 75165942Sgibbs} 75265942Sgibbs 75365942Sgibbs/* 75413177Sgibbs * If we re-enter the data phase after going through another phase, the 75513177Sgibbs * STCNT may have been cleared, so restore it from the residual field. 75613177Sgibbs */ 7579928Sgibbsdata_phase_reinit: 75851471Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 75951471Sgibbs /* 76051471Sgibbs * The preload circuitry requires us to 76151471Sgibbs * reload the address too, so pull it from 76251471Sgibbs * the shaddow address. 76351471Sgibbs */ 76451471Sgibbs bmov HADDR, SHADDR, 4; 76563457Sgibbs bmov HCNT, SCB_RESIDUAL_DATACNT, 3; 76651471Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 76763457Sgibbs bmov STCNT, SCB_RESIDUAL_DATACNT, 3; 76839220Sgibbs } else { 76939220Sgibbs mvi DINDEX, STCNT; 77063457Sgibbs mvi SCB_RESIDUAL_DATACNT call bcopy_3; 77139220Sgibbs } 77263457Sgibbs and DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0]; 77323925Sgibbs jmp data_phase_loop; 7744568Sgibbs 77539220Sgibbsp_data: 77639220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 77739220Sgibbs mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; 77839220Sgibbs } else { 77939220Sgibbs mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 78039220Sgibbs } 78139220Sgibbs test LASTPHASE, IOI jnz . + 2; 78239220Sgibbs or DMAPARAMS, DIRECTION; 78323925Sgibbs call assert; /* 78419164Sgibbs * Ensure entering a data 78519164Sgibbs * phase is okay - seen identify, etc. 78619164Sgibbs */ 78739220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 78863457Sgibbs /* We don't have any valid S/G elements */ 78966647Sgibbs mvi CCSGADDR, SG_PREFETCH_CNT; 79039220Sgibbs } 79123925Sgibbs test SEQ_FLAGS, DPHASE jnz data_phase_reinit; 7924568Sgibbs 79339220Sgibbs /* We have seen a data phase */ 79439220Sgibbs or SEQ_FLAGS, DPHASE; 79539220Sgibbs 79619164Sgibbs /* 79719164Sgibbs * Initialize the DMA address and counter from the SCB. 79863457Sgibbs * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG 79963457Sgibbs * flag in the highest byte of the data count. We cannot 80063457Sgibbs * modify the saved values in the SCB until we see a save 80163457Sgibbs * data pointers message. 80219164Sgibbs */ 80339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 80439220Sgibbs bmov HADDR, SCB_DATAPTR, 7; 80563457Sgibbs bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; 80639220Sgibbs } else { 80739220Sgibbs mvi DINDEX, HADDR; 80839220Sgibbs mvi SCB_DATAPTR call bcopy_7; 80963457Sgibbs mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; 81063457Sgibbs mvi SCB_DATACNT + 3 call bcopy_5; 81139220Sgibbs } 81265942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 81365942Sgibbs call calc_mwi_residual; 81465942Sgibbs } 81563457Sgibbs and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; 81665942Sgibbs and DATA_COUNT_ODD, 0x1, HCNT[0]; 81719164Sgibbs 81839220Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 81939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 82039220Sgibbs bmov STCNT, HCNT, 3; 82139220Sgibbs } else { 82239220Sgibbs call set_stcnt_from_hcnt; 82339220Sgibbs } 82439220Sgibbs } 82519164Sgibbs 82663457Sgibbsdata_phase_loop: 82763457Sgibbs /* Guard against overruns */ 82863457Sgibbs test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; 82919164Sgibbs 83063457Sgibbs /* 83168087Sgibbs * Turn on `Bit Bucket' mode, wait until the target takes 83268087Sgibbs * us to another phase, and then notify the host. 83363457Sgibbs */ 83468087Sgibbs and DMAPARAMS, DIRECTION; 83568087Sgibbs mov DFCNTRL, DMAPARAMS; 83623925Sgibbs or SXFRCTL1,BITBUCKET; 83768087Sgibbs test SSTAT1,PHASEMIS jz .; 83868087Sgibbs and SXFRCTL1, ~BITBUCKET; 83968402Sgibbs mvi DATA_OVERRUN call set_seqint; 84068087Sgibbs jmp ITloop; 84168087Sgibbs 84216260Sgibbsdata_phase_inbounds: 84339220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 84463457Sgibbs mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 84563457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 84663457Sgibbs or SINDEX, LAST_SEG; 84763457Sgibbs test DATA_COUNT_ODD, 0x1 jz . + 2; 84863457Sgibbs or SINDEX, ODD_SEG; 84963457Sgibbs mov SG_CACHE_PRE, SINDEX; 85063457Sgibbs mov DFCNTRL, DMAPARAMS; 85163457Sgibbsultra2_dma_loop: 85263457Sgibbs call idle_loop; 85363457Sgibbs /* 85463457Sgibbs * The transfer is complete if either the last segment 85563457Sgibbs * completes or the target changes phase. 85663457Sgibbs */ 85763457Sgibbs test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; 85863457Sgibbs test SSTAT1,PHASEMIS jz ultra2_dma_loop; 85963457Sgibbs 86063457Sgibbsultra2_dmafinish: 86163457Sgibbs test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; 86263457Sgibbs and DFCNTRL, ~SCSIEN; 86363457Sgibbs test DFCNTRL, SCSIEN jnz .; 86463944Sgibbs if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 86563944Sgibbs test DFSTATUS, FIFOEMP jnz ultra2_dmafifoempty; 86663944Sgibbs } 86763457Sgibbsultra2_dmafifoflush: 86863457Sgibbs if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 86963457Sgibbs /* 87063457Sgibbs * On Rev A of the aic7890, the autoflush 87163457Sgibbs * features doesn't function correctly. 87263457Sgibbs * Perform an explicit manual flush. During 87363457Sgibbs * a manual flush, the FIFOEMP bit becomes 87463457Sgibbs * true every time the PCI FIFO empties 87563457Sgibbs * regardless of the state of the SCSI FIFO. 87663457Sgibbs * It can take up to 4 clock cycles for the 87763457Sgibbs * SCSI FIFO to get data into the PCI FIFO 87863457Sgibbs * and for FIFOEMP to de-assert. Here we 87963457Sgibbs * guard against this condition by making 88063457Sgibbs * sure the FIFOEMP bit stays on for 5 full 88163457Sgibbs * clock cycles. 88263457Sgibbs */ 88363457Sgibbs or DFCNTRL, FIFOFLUSH; 88463457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 88563457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 88663457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 88763457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 88863457Sgibbs } 88963457Sgibbs test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; 89063457Sgibbsultra2_dmafifoempty: 89163457Sgibbs /* Don't clobber an inprogress host data transfer */ 89263457Sgibbs test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; 89363457Sgibbsultra2_dmahalt: 89463457Sgibbs and DFCNTRL, ~(SCSIEN|HDMAEN); 89563457Sgibbs test DFCNTRL, HDMAEN jnz .; 89663457Sgibbs 89763457Sgibbs /* 89863944Sgibbs * If, by chance, we stopped before being able 89963944Sgibbs * to fetch additional segments for this transfer, 90063944Sgibbs * yet the last S/G was completely exhausted, 90163944Sgibbs * call our idle loop until it is able to load 90263944Sgibbs * another segment. This will allow us to immediately 90363944Sgibbs * pickup on the next segment on the next data phase. 90463944Sgibbs * 90563944Sgibbs * If we happened to stop on the last segment, then 90663944Sgibbs * our residual information is still correct from 90763944Sgibbs * the idle loop and there is no need to perform 90863944Sgibbs * any fixups. Just jump to data_phase_finish. 90963944Sgibbs */ 91063944Sgibbsultra2_ensure_sg: 91163944Sgibbs test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; 91263944Sgibbs /* Record if we've consumed all S/G entries */ 91363944Sgibbs test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; 91463944Sgibbs or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 91563944Sgibbs jmp data_phase_finish; 91663944Sgibbs 91763944Sgibbsultra2_shvalid: 91863944Sgibbs test SSTAT2, SHVALID jnz sgptr_fixup; 91963944Sgibbs call idle_loop; 92063944Sgibbs jmp ultra2_ensure_sg; 92163944Sgibbs 92263944Sgibbssgptr_fixup: 92363944Sgibbs /* 92463457Sgibbs * Fixup the residual next S/G pointer. The S/G preload 92563457Sgibbs * feature of the chip allows us to load two elements 92663457Sgibbs * in addition to the currently active element. We 92763457Sgibbs * store the bottom byte of the next S/G pointer in 92863457Sgibbs * the SG_CACEPTR register so we can restore the 92963457Sgibbs * correct value when the DMA completes. If the next 93063457Sgibbs * sg ptr value has advanced to the point where higher 93163457Sgibbs * bytes in the address have been affected, fix them 93263457Sgibbs * too. 93363457Sgibbs */ 93463457Sgibbs test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; 93563457Sgibbs test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; 93663457Sgibbs add SCB_RESIDUAL_SGPTR[1], -1; 93763457Sgibbs adc SCB_RESIDUAL_SGPTR[2], -1; 93863457Sgibbs adc SCB_RESIDUAL_SGPTR[3], -1; 93963457Sgibbssgptr_fixup_done: 94063457Sgibbs and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; 94163457Sgibbs clr DATA_COUNT_ODD; 94263457Sgibbs test SG_CACHE_SHADOW, ODD_SEG jz . + 2; 94363457Sgibbs or DATA_COUNT_ODD, 0x1; 94463944Sgibbs clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ 94539220Sgibbs } else { 94663457Sgibbs /* If we are the last SG block, tell the hardware. */ 94765942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 94865942Sgibbs && ahc->pci_cachesize != 0) { 94965942Sgibbs test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; 95065942Sgibbs } 95163457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; 95268087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 95363944Sgibbs test SSTAT0, TARGET jz dma_last_sg; 95463944Sgibbs if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { 95563944Sgibbs test DMAPARAMS, DIRECTION jz dma_mid_sg; 95663944Sgibbs } 95757099Sgibbs } 95863944Sgibbsdma_last_sg: 95939220Sgibbs and DMAPARAMS, ~WIDEODD; 96063457Sgibbsdma_mid_sg: 96163457Sgibbs /* Start DMA data transfer. */ 96239220Sgibbs mov DFCNTRL, DMAPARAMS; 96363457Sgibbsdma_loop: 96463457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 96563457Sgibbs call idle_loop; 96663457Sgibbs } 96763457Sgibbs test SSTAT0,DMADONE jnz dma_dmadone; 96863457Sgibbs test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 96963457Sgibbsdma_phasemis: 97039220Sgibbs /* 97163457Sgibbs * We will be "done" DMAing when the transfer count goes to 97263457Sgibbs * zero, or the target changes the phase (in light of this, 97363457Sgibbs * it makes sense that the DMA circuitry doesn't ACK when 97463457Sgibbs * PHASEMIS is active). If we are doing a SCSI->Host transfer, 97563457Sgibbs * the data FIFO should be flushed auto-magically on STCNT=0 97663457Sgibbs * or a phase change, so just wait for FIFO empty status. 97739220Sgibbs */ 97863457Sgibbsdma_checkfifo: 97963457Sgibbs test DFCNTRL,DIRECTION jnz dma_fifoempty; 98063457Sgibbsdma_fifoflush: 98163457Sgibbs test DFSTATUS,FIFOEMP jz dma_fifoflush; 98263457Sgibbsdma_fifoempty: 98363457Sgibbs /* Don't clobber an inprogress host data transfer */ 98463457Sgibbs test DFSTATUS, MREQPEND jnz dma_fifoempty; 9854568Sgibbs 98639220Sgibbs /* 98763457Sgibbs * Now shut off the DMA and make sure that the DMA 98863457Sgibbs * hardware has actually stopped. Touching the DMA 98963457Sgibbs * counters, etc. while a DMA is active will result 99063457Sgibbs * in an ILLSADDR exception. 99139220Sgibbs */ 99263457Sgibbsdma_dmadone: 99363457Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 99463457Sgibbsdma_halt: 99563457Sgibbs /* 99665942Sgibbs * Some revisions of the aic78XX have a problem where, if the 99763457Sgibbs * data fifo is full, but the PCI input latch is not empty, 99863457Sgibbs * HDMAEN cannot be cleared. The fix used here is to drain 99963457Sgibbs * the prefetched but unused data from the data fifo until 100063457Sgibbs * there is space for the input latch to drain. 100163457Sgibbs */ 100265942Sgibbs if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 100365942Sgibbs mov NONE, DFDAT; 100465942Sgibbs } 100563457Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 100622568Sgibbs 100763457Sgibbs /* See if we have completed this last segment */ 100863457Sgibbs test STCNT[0], 0xff jnz data_phase_finish; 100963457Sgibbs test STCNT[1], 0xff jnz data_phase_finish; 101063457Sgibbs test STCNT[2], 0xff jnz data_phase_finish; 10119928Sgibbs 101239220Sgibbs /* 101363457Sgibbs * Advance the scatter-gather pointers if needed 101439220Sgibbs */ 101565942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 101665942Sgibbs && ahc->pci_cachesize != 0) { 101765942Sgibbs test MWI_RESIDUAL, 0xFF jz no_mwi_resid; 101865942Sgibbs /* 101965942Sgibbs * Reload HADDR from SHADDR and setup the 102065942Sgibbs * count to be the size of our residual. 102165942Sgibbs */ 102265942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 102365942Sgibbs bmov HADDR, SHADDR, 4; 102465942Sgibbs mov HCNT, MWI_RESIDUAL; 102565942Sgibbs bmov HCNT[1], ALLZEROS, 2; 102665942Sgibbs } else { 102765942Sgibbs mvi DINDEX, HADDR; 102865942Sgibbs mvi SHADDR call bcopy_4; 102965942Sgibbs mov MWI_RESIDUAL call set_hcnt; 103065942Sgibbs } 103165942Sgibbs clr MWI_RESIDUAL; 103265942Sgibbs jmp sg_load_done; 103365942Sgibbsno_mwi_resid: 103465942Sgibbs } 103563457Sgibbs test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; 103663457Sgibbs or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 103763457Sgibbs jmp data_phase_finish; 103863457Sgibbssg_load: 103963457Sgibbs /* 104063457Sgibbs * Load the next SG element's data address and length 104163457Sgibbs * into the DMA engine. If we don't have hardware 104263457Sgibbs * to perform a prefetch, we'll have to fetch the 104363457Sgibbs * segment from host memory first. 104463457Sgibbs */ 104539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 104663457Sgibbs /* Wait for the idle loop to complete */ 104763457Sgibbs test CCSGCTL, CCSGEN jz . + 3; 104863457Sgibbs call idle_loop; 104963457Sgibbs test CCSGCTL, CCSGEN jnz . - 1; 105063457Sgibbs bmov HADDR, CCSGRAM, 7; 105165942Sgibbs test CCSGRAM, SG_LAST_SEG jz . + 2; 105265942Sgibbs or SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG; 105339220Sgibbs } else { 105463457Sgibbs mvi DINDEX, HADDR; 105563457Sgibbs mvi SCB_RESIDUAL_SGPTR call bcopy_4; 105663457Sgibbs 105763457Sgibbs mvi SG_SIZEOF call set_hcnt; 105863457Sgibbs 105963457Sgibbs or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 106063457Sgibbs 106163457Sgibbs call dma_finish; 106263457Sgibbs 106365942Sgibbs mvi DINDEX, HADDR; 106465942Sgibbs call dfdat_in_7; 106563457Sgibbs mov SCB_RESIDUAL_DATACNT[3], DFDAT; 106665942Sgibbs } 106765942Sgibbs 106865942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 106965942Sgibbs && ahc->pci_cachesize != 0) { 107065942Sgibbs call calc_mwi_residual; 107165942Sgibbs } 107265942Sgibbs 107365942Sgibbs /* Point to the new next sg in memory */ 107465942Sgibbs call sg_advance; 107565942Sgibbs 107665942Sgibbssg_load_done: 107765942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 107865942Sgibbs bmov STCNT, HCNT, 3; 107965942Sgibbs } else { 108039220Sgibbs call set_stcnt_from_hcnt; 108139220Sgibbs } 108263457Sgibbs /* Track odd'ness */ 108363457Sgibbs test HCNT[0], 0x1 jz . + 2; 108463457Sgibbs xor DATA_COUNT_ODD, 0x1; 108539220Sgibbs 108668087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 108763457Sgibbs test SSTAT0, TARGET jnz data_phase_loop; 108863457Sgibbs } 108963457Sgibbs } 109063457Sgibbsdata_phase_finish: 109163457Sgibbs /* 109263457Sgibbs * If the target has left us in data phase, loop through 109363457Sgibbs * the dma code again. In the case of ULTRA2 adapters, 109463457Sgibbs * we should only loop if there is a data overrun. For 109563457Sgibbs * all other adapters, we'll loop after each S/G element 109663457Sgibbs * is loaded as well as if there is an overrun. 109763457Sgibbs */ 109868087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 109963457Sgibbs test SSTAT0, TARGET jnz data_phase_done; 110041646Sgibbs } 110168087Sgibbs if ((ahc->flags & AHC_INITIATORROLE) != 0) { 110263457Sgibbs test SSTAT1, REQINIT jz .; 110363457Sgibbs test SSTAT1,PHASEMIS jz data_phase_loop; 110463457Sgibbs 110563457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 110663457Sgibbs /* Kill off any pending prefetch */ 110763457Sgibbs clr CCSGCTL; 110863457Sgibbs test CCSGCTL, CCSGEN jnz .; 110963457Sgibbs } 111039220Sgibbs } 11114568Sgibbs 111263457Sgibbsdata_phase_done: 111363457Sgibbs /* 111463457Sgibbs * After a DMA finishes, save the SG and STCNT residuals back into 111563457Sgibbs * the SCB. We use STCNT instead of HCNT, since it's a reflection 111663457Sgibbs * of how many bytes were transferred on the SCSI (as opposed to the 111763457Sgibbs * host) bus. 111863457Sgibbs */ 111939220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 112063457Sgibbs /* Kill off any pending prefetch */ 112163457Sgibbs clr CCSGCTL; 112263457Sgibbs test CCSGCTL, CCSGEN jnz .; 112365942Sgibbs } 112463457Sgibbs 112565942Sgibbs if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 112665942Sgibbs && ahc->pci_cachesize != 0) { 112765942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 112865942Sgibbs test MWI_RESIDUAL, 0xFF jz bmov_resid; 112965942Sgibbs } 113065942Sgibbs mov A, MWI_RESIDUAL; 113165942Sgibbs add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; 113265942Sgibbs clr A; 113365942Sgibbs adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; 113465942Sgibbs adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; 113565942Sgibbs clr MWI_RESIDUAL; 113665942Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 113765942Sgibbs jmp . + 2; 113865942Sgibbsbmov_resid: 113965942Sgibbs bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 114065942Sgibbs } 114165942Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 114263457Sgibbs bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 114339220Sgibbs } else { 114465942Sgibbs mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; 114565942Sgibbs mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; 114665942Sgibbs mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; 114739220Sgibbs } 114822568Sgibbs 114963457Sgibbs /* 115063457Sgibbs * Since we've been through a data phase, the SCB_RESID* fields 115163457Sgibbs * are now initialized. Clear the full residual flag. 115263457Sgibbs */ 115363457Sgibbs and SCB_SGPTR[0], ~SG_FULL_RESID; 115463457Sgibbs 115539220Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 115663457Sgibbs /* Clear the channel in case we return to data phase later */ 115739220Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 115868402Sgibbs or SXFRCTL0, CLRSTCNT|CLRCHN; 115939220Sgibbs } 116022568Sgibbs 116168087Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 116241646Sgibbs test SEQ_FLAGS, DPHASE_PENDING jz ITloop; 116339220Sgibbs and SEQ_FLAGS, ~DPHASE_PENDING; 116442652Sgibbs /* 116542652Sgibbs * For data-in phases, wait for any pending acks from the 116642652Sgibbs * initiator before changing phase. 116742652Sgibbs */ 116842652Sgibbs test DFCNTRL, DIRECTION jz target_ITloop; 116942652Sgibbs test SSTAT1, REQINIT jnz .; 117039220Sgibbs jmp target_ITloop; 117163457Sgibbs } else { 117263457Sgibbs jmp ITloop; 117339220Sgibbs } 11744568Sgibbs 117568087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 117616260Sgibbs/* 117715328Sgibbs * Command phase. Set up the DMA registers and let 'er rip. 117813177Sgibbs */ 11794568Sgibbsp_command: 118023925Sgibbs call assert; 11814568Sgibbs 118263457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 118363457Sgibbs bmov HCNT[0], SCB_CDB_LEN, 1; 118439220Sgibbs bmov HCNT[1], ALLZEROS, 2; 118563944Sgibbs mvi SG_CACHE_PRE, LAST_SEG; 118663457Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 118763457Sgibbs bmov STCNT[0], SCB_CDB_LEN, 1; 118863457Sgibbs bmov STCNT[1], ALLZEROS, 2; 118939220Sgibbs } else { 119063457Sgibbs mov STCNT[0], SCB_CDB_LEN; 119163457Sgibbs clr STCNT[1]; 119263457Sgibbs clr STCNT[2]; 119339220Sgibbs } 119463457Sgibbs add NONE, -13, SCB_CDB_LEN; 119565942Sgibbs mvi SCB_CDB_STORE jnc p_command_embedded; 119663457Sgibbsp_command_from_host: 119763457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 119863457Sgibbs bmov HADDR[0], SCB_CDB_PTR, 4; 119963457Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); 120063457Sgibbs } else { 120163457Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 120263457Sgibbs bmov HADDR[0], SCB_CDB_PTR, 4; 120365942Sgibbs bmov HCNT, STCNT, 3; 120463457Sgibbs } else { 120563457Sgibbs mvi DINDEX, HADDR; 120668087Sgibbs mvi SCB_CDB_PTR call bcopy_4; 120768087Sgibbs mov SCB_CDB_LEN call set_hcnt; 120839220Sgibbs } 120939220Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); 121063457Sgibbs } 121163457Sgibbs jmp p_command_loop; 121263457Sgibbsp_command_embedded: 121363457Sgibbs /* 121463457Sgibbs * The data fifo seems to require 4 byte alligned 121563457Sgibbs * transfers from the sequencer. Force this to 121663457Sgibbs * be the case by clearing HADDR[0] even though 121763457Sgibbs * we aren't going to touch host memeory. 121863457Sgibbs */ 121963457Sgibbs clr HADDR[0]; 122063457Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 122163457Sgibbs mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); 122263457Sgibbs bmov DFDAT, SCB_CDB_STORE, 12; 122365942Sgibbs } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 122465942Sgibbs if ((ahc->features & AHC_SCB_BTT) != 0) { 122565942Sgibbs /* 122665942Sgibbs * On the 7895 the data FIFO will 122765942Sgibbs * get corrupted if you try to dump 122865942Sgibbs * data from external SCB memory into 122965942Sgibbs * the FIFO while it is enabled. So, 123065942Sgibbs * fill the fifo and then enable SCSI 123165942Sgibbs * transfers. 123265942Sgibbs */ 123365942Sgibbs mvi DFCNTRL, (DIRECTION|FIFORESET); 123465942Sgibbs } else { 123565942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 123665942Sgibbs } 123765942Sgibbs bmov DFDAT, SCB_CDB_STORE, 12; 123865942Sgibbs if ((ahc->features & AHC_SCB_BTT) != 0) { 123965942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); 124065942Sgibbs } else { 124163821Sgibbs or DFCNTRL, FIFOFLUSH; 124263821Sgibbs } 124363457Sgibbs } else { 124465942Sgibbs mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 124563821Sgibbs call copy_to_fifo_6; 124663821Sgibbs call copy_to_fifo_6; 124763821Sgibbs or DFCNTRL, FIFOFLUSH; 124863457Sgibbs } 124963457Sgibbsp_command_loop: 125039220Sgibbs test SSTAT0, SDONE jnz . + 2; 125163457Sgibbs test SSTAT1, PHASEMIS jz p_command_loop; 125255581Sgibbs /* 125355581Sgibbs * Wait for our ACK to go-away on it's own 125455581Sgibbs * instead of being killed by SCSIEN getting cleared. 125555581Sgibbs */ 125655581Sgibbs test SCSISIGI, ACKI jnz .; 125755581Sgibbs and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 125839220Sgibbs test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; 125968087Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) { 126068087Sgibbs /* Drop any residual from the S/G Preload queue */ 126168087Sgibbs or SXFRCTL0, CLRSTCNT; 126268087Sgibbs } 126323925Sgibbs jmp ITloop; 12644568Sgibbs 126513177Sgibbs/* 126613177Sgibbs * Status phase. Wait for the data byte to appear, then read it 126713177Sgibbs * and store it into the SCB. 126813177Sgibbs */ 12694568Sgibbsp_status: 127023925Sgibbs call assert; 127119803Sgibbs 127263457Sgibbs mov SCB_SCSI_STATUS, SCSIDATL; 127323925Sgibbs jmp ITloop; 12744568Sgibbs 127513177Sgibbs/* 127641646Sgibbs * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full 127741646Sgibbs * indentify message sequence and send it to the target. The host may 127841646Sgibbs * override this behavior by setting the MK_MESSAGE bit in the SCB 127941646Sgibbs * control byte. This will cause us to interrupt the host and allow 128041646Sgibbs * it to handle the message phase completely on its own. If the bit 128141646Sgibbs * associated with this target is set, we will also interrupt the host, 128241646Sgibbs * thereby allowing it to send a message on the next selection regardless 128341646Sgibbs * of the transaction being sent. 128439220Sgibbs * 128539220Sgibbs * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. 128641646Sgibbs * This is done to allow the host to send messages outside of an identify 128739220Sgibbs * sequence while protecting the seqencer from testing the MK_MESSAGE bit 128839220Sgibbs * on an SCB that might not be for the current nexus. (For example, a 128939220Sgibbs * BDR message in responce to a bad reselection would leave us pointed to 129039220Sgibbs * an SCB that doesn't have anything to do with the current target). 129141646Sgibbs * 129239220Sgibbs * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, 129339220Sgibbs * bus device reset). 129439220Sgibbs * 129539220Sgibbs * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, 129639220Sgibbs * in case the target decides to put us in this phase for some strange 129739220Sgibbs * reason. 129813177Sgibbs */ 129941646Sgibbsp_mesgout_retry: 130041646Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ 13014568Sgibbsp_mesgout: 130239220Sgibbs mov SINDEX, MSG_OUT; 130339220Sgibbs cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; 130441646Sgibbs test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; 130563457Sgibbs mov FUNCTION1, SCB_SCSIID; 130641646Sgibbs mov A, FUNCTION1; 130747414Sgibbs mov SINDEX, TARGET_MSG_REQUEST[0]; 130841646Sgibbs if ((ahc->features & AHC_TWIN) != 0) { 130941646Sgibbs /* Second Channel uses high byte bits */ 131063457Sgibbs test SCB_SCSIID, TWIN_CHNLB jz . + 2; 131141646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 131241646Sgibbs } else if ((ahc->features & AHC_WIDE) != 0) { 131363457Sgibbs test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ 131441646Sgibbs mov SINDEX, TARGET_MSG_REQUEST[1]; 131541646Sgibbs } 131641646Sgibbs test SINDEX, A jnz host_message_loop; 131739220Sgibbsp_mesgout_identify: 131863457Sgibbs or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; 131963457Sgibbs test SCB_CONTROL, DISCENB jnz . + 2; 132063457Sgibbs and SINDEX, ~DISCENB; 132113177Sgibbs/* 132239220Sgibbs * Send a tag message if TAG_ENB is set in the SCB control block. 132339220Sgibbs * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 132413177Sgibbs */ 132539220Sgibbsp_mesgout_tag: 132639220Sgibbs test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; 132739220Sgibbs mov SCSIDATL, SINDEX; /* Send the identify message */ 132839220Sgibbs call phase_lock; 132939220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 133039220Sgibbs and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 133139220Sgibbs call phase_lock; 133239220Sgibbs cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 133339220Sgibbs mov SCB_TAG jmp p_mesgout_onebyte; 133413177Sgibbs/* 133541646Sgibbs * Interrupt the driver, and allow it to handle this message 133641646Sgibbs * phase and any required retries. 133713177Sgibbs */ 133839220Sgibbsp_mesgout_from_host: 133939220Sgibbs cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; 134041646Sgibbs jmp host_message_loop; 134139220Sgibbs 134239220Sgibbsp_mesgout_onebyte: 134339220Sgibbs mvi CLRSINT1, CLRATNO; 134439220Sgibbs mov SCSIDATL, SINDEX; 134539220Sgibbs 134613177Sgibbs/* 134741646Sgibbs * If the next bus phase after ATN drops is message out, it means 134813177Sgibbs * that the target is requesting that the last message(s) be resent. 134913177Sgibbs */ 135039220Sgibbs call phase_lock; 135141646Sgibbs cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; 13524568Sgibbs 135319906Sgibbsp_mesgout_done: 135423925Sgibbs mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 135539220Sgibbs mov LAST_MSG, MSG_OUT; 135639220Sgibbs mvi MSG_OUT, MSG_NOOP; /* No message left */ 135723925Sgibbs jmp ITloop; 13584568Sgibbs 135913177Sgibbs/* 136013177Sgibbs * Message in phase. Bytes are read using Automatic PIO mode. 136113177Sgibbs */ 13624568Sgibbsp_mesgin: 136323925Sgibbs mvi ACCUM call inb_first; /* read the 1st message byte */ 13644568Sgibbs 136523925Sgibbs test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 136623925Sgibbs cmp A,MSG_DISCONNECT je mesgin_disconnect; 136723925Sgibbs cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 136823925Sgibbs cmp ALLZEROS,A je mesgin_complete; 136923925Sgibbs cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 137063457Sgibbs cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; 137123925Sgibbs cmp A,MSG_NOOP je mesgin_done; 13724568Sgibbs 137313177Sgibbs/* 137441887Sgibbs * Pushed message loop to allow the kernel to 137557099Sgibbs * run it's own message state engine. To avoid an 137641887Sgibbs * extra nop instruction after signaling the kernel, 137741887Sgibbs * we perform the phase_lock before checking to see 137841887Sgibbs * if we should exit the loop and skip the phase_lock 137941887Sgibbs * in the ITloop. Performing back to back phase_locks 138041887Sgibbs * shouldn't hurt, but why do it twice... 138113177Sgibbs */ 138241887Sgibbshost_message_loop: 138368402Sgibbs mvi HOST_MSG_LOOP call set_seqint; 138441887Sgibbs call phase_lock; 138541887Sgibbs cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; 138641887Sgibbs jmp host_message_loop; 13879954Sgibbs 138863457Sgibbsmesgin_ign_wide_residue: 138963457Sgibbsif ((ahc->features & AHC_WIDE) != 0) { 139063457Sgibbs test SCSIRATE, WIDEXFER jz mesgin_reject; 139163457Sgibbs /* Pull the residue byte */ 139263457Sgibbs mvi ARG_1 call inb_next; 139363457Sgibbs cmp ARG_1, 0x01 jne mesgin_reject; 139463457Sgibbs test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; 139563457Sgibbs test DATA_COUNT_ODD, 0x1 jz mesgin_done; 139668402Sgibbs mvi IGN_WIDE_RES call set_seqint; 139763457Sgibbs jmp mesgin_done; 139863457Sgibbs} 139963457Sgibbs 140063457Sgibbsmesgin_reject: 140163457Sgibbs mvi MSG_MESSAGE_REJECT call mk_mesg; 14029954Sgibbsmesgin_done: 140323925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 140423925Sgibbs jmp ITloop; 14059954Sgibbs 14069954Sgibbsmesgin_complete: 140713177Sgibbs/* 140863457Sgibbs * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, 140919164Sgibbs * and trigger a completion interrupt. Before doing so, check to see if there 141039220Sgibbs * is a residual or the status byte is something other than STATUS_GOOD (0). 141139220Sgibbs * In either of these conditions, we upload the SCB back to the host so it can 141219164Sgibbs * process this information. In the case of a non zero status byte, we 141319164Sgibbs * additionally interrupt the kernel driver synchronously, allowing it to 141419164Sgibbs * decide if sense should be retrieved. If the kernel driver wishes to request 141568087Sgibbs * sense, it will fill the kernel SCB with a request sense command, requeue 141668087Sgibbs * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 141768087Sgibbs * RETURN_1 to SEND_SENSE. 141813177Sgibbs */ 141919164Sgibbs 142013177Sgibbs/* 142168402Sgibbs * See if we attempted to deliver a message but the target ingnored us. 142213177Sgibbs */ 142368402Sgibbs test SCB_CONTROL, MK_MESSAGE jz . + 2; 142468402Sgibbs mvi MKMSG_FAILED call set_seqint; 142568402Sgibbs 142668402Sgibbs/* 142768402Sgibbs * Check for residuals 142868402Sgibbs */ 142963457Sgibbs test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ 143063457Sgibbs test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ 143163457Sgibbs test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; 143263457Sgibbscheck_status: 143363457Sgibbs test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ 143419164Sgibbsupload_scb: 143563457Sgibbs or SCB_SGPTR, SG_RESID_VALID; 143623925Sgibbs mvi DMAPARAMS, FIFORESET; 143723925Sgibbs mov SCB_TAG call dma_scb; 143863457Sgibbs test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ 143968402Sgibbs mvi BAD_STATUS call set_seqint; /* let driver know */ 144039220Sgibbs cmp RETURN_1, SEND_SENSE jne complete; 144168087Sgibbs call add_scb_to_free_list; 144223925Sgibbs jmp await_busfree; 144339220Sgibbscomplete: 144439220Sgibbs mov SCB_TAG call complete_post; 144523925Sgibbs jmp await_busfree; 144641646Sgibbs} 14474568Sgibbs 144839220Sgibbscomplete_post: 144939220Sgibbs /* Post the SCBID in SINDEX and issue an interrupt */ 145044507Sgibbs call add_scb_to_free_list; 145139220Sgibbs mov ARG_1, SINDEX; 145239220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 145339220Sgibbs mov A, SDSCB_QOFF; 145439220Sgibbs } else { 145539220Sgibbs mov A, QOUTPOS; 145639220Sgibbs } 145739220Sgibbs mvi QOUTFIFO_OFFSET call post_byte_setup; 145839220Sgibbs mov ARG_1 call post_byte; 145939220Sgibbs if ((ahc->features & AHC_QUEUE_REGS) == 0) { 146039220Sgibbs inc QOUTPOS; 146139220Sgibbs } 146239220Sgibbs mvi INTSTAT,CMDCMPLT ret; 146339220Sgibbs 146468087Sgibbsif ((ahc->flags & AHC_INITIATORROLE) != 0) { 146513177Sgibbs/* 146613177Sgibbs * Is it a disconnect message? Set a flag in the SCB to remind us 146763457Sgibbs * and await the bus going free. If this is an untagged transaction 146863457Sgibbs * store the SCB id for it in our untagged target table for lookup on 146963457Sgibbs * a reselction. 147013177Sgibbs */ 14719954Sgibbsmesgin_disconnect: 147223925Sgibbs or SCB_CONTROL,DISCONNECTED; 147363457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 147463457Sgibbs call add_scb_to_disc_list; 147563457Sgibbs } 147663457Sgibbs test SCB_CONTROL, TAG_ENB jnz await_busfree; 147763457Sgibbs mov ARG_1, SCB_TAG; 147863457Sgibbs mov SAVED_LUN, SCB_LUN; 147968087Sgibbs mov SCB_SCSIID call set_busy_target; 148023925Sgibbs jmp await_busfree; 148119164Sgibbs 148215328Sgibbs/* 148319164Sgibbs * Save data pointers message: 148419164Sgibbs * Copying RAM values back to SCB, for Save Data Pointers message, but 148519164Sgibbs * only if we've actually been into a data phase to change them. This 148619164Sgibbs * protects against bogus data in scratch ram and the residual counts 148719164Sgibbs * since they are only initialized when we go into data_in or data_out. 148815328Sgibbs */ 148919164Sgibbsmesgin_sdptrs: 149023925Sgibbs test SEQ_FLAGS, DPHASE jz mesgin_done; 14914568Sgibbs 149239220Sgibbs /* 149363457Sgibbs * The SCB_SGPTR becomes the next one we'll download, 149463457Sgibbs * and the SCB_DATAPTR becomes the current SHADDR. 149539220Sgibbs * Use the residual number since STCNT is corrupted by 149639220Sgibbs * any message transfer. 149739220Sgibbs */ 149839220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 149939220Sgibbs bmov SCB_DATAPTR, SHADDR, 4; 150063457Sgibbs bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; 150139220Sgibbs } else { 150239220Sgibbs mvi DINDEX, SCB_DATAPTR; 150363457Sgibbs mvi SHADDR call bcopy_4; 150463457Sgibbs mvi SCB_RESIDUAL_DATACNT call bcopy_8; 150539220Sgibbs } 150623925Sgibbs jmp mesgin_done; 15074568Sgibbs 150813177Sgibbs/* 150913177Sgibbs * Restore pointers message? Data pointers are recopied from the 151013177Sgibbs * SCB anytime we enter a data phase for the first time, so all 151113177Sgibbs * we need to do is clear the DPHASE flag and let the data phase 151213177Sgibbs * code do the rest. 151313177Sgibbs */ 15149954Sgibbsmesgin_rdptrs: 151523925Sgibbs and SEQ_FLAGS, ~DPHASE; /* 151623925Sgibbs * We'll reload them 151713177Sgibbs * the next time through 151823925Sgibbs * the dataphase. 151913177Sgibbs */ 152023925Sgibbs jmp mesgin_done; 15214568Sgibbs 152213177Sgibbs/* 152363457Sgibbs * Index into our Busy Target table. SINDEX and DINDEX are modified 152463457Sgibbs * upon return. SCBPTR may be modified by this action. 152563457Sgibbs */ 152668087Sgibbsset_busy_target: 152768087Sgibbs shr DINDEX, 4, SINDEX; 152863457Sgibbs if ((ahc->features & AHC_SCB_BTT) != 0) { 152963457Sgibbs mov SCBPTR, SAVED_LUN; 153068087Sgibbs add DINDEX, SCB_64_BTT; 153163457Sgibbs } else { 153268087Sgibbs add DINDEX, BUSY_TARGETS; 153363457Sgibbs } 153468087Sgibbs mov DINDIR, ARG_1 ret; 153563457Sgibbs 153663457Sgibbs/* 153713177Sgibbs * Identify message? For a reconnecting target, this tells us the lun 153813177Sgibbs * that the reconnection is for - find the correct SCB and switch to it, 153913177Sgibbs * clearing the "disconnected" bit so we don't "find" it by accident later. 154013177Sgibbs */ 15419954Sgibbsmesgin_identify: 154263457Sgibbs and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; 154363457Sgibbs /* 154463457Sgibbs * Determine whether a target is using tagged or non-tagged 154563457Sgibbs * transactions by first looking at the transaction stored in 154663457Sgibbs * the busy target array. If there is no untagged transaction 154763457Sgibbs * for this target or the transaction is for a different lun, then 154863457Sgibbs * this must be an untagged transaction. 154963457Sgibbs */ 155068087Sgibbsfetch_busy_target: 155168087Sgibbs shr A, 4, SAVED_SCSIID; 155268087Sgibbs if ((ahc->features & AHC_SCB_BTT) != 0) { 155368087Sgibbs add SINDEX, SCB_64_BTT, A; 155468087Sgibbs mov SCBPTR, SAVED_LUN; 155568087Sgibbs } else { 155668087Sgibbs add SINDEX, BUSY_TARGETS, A; 155768087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 155868087Sgibbs add A, -BUSY_TARGETS, SINDEX; 155968087Sgibbs jc . + 2; 156068087Sgibbs mvi INTSTAT, OUT_OF_RANGE; 156168402Sgibbs nop; 156268087Sgibbs add A, -(BUSY_TARGETS + 16), SINDEX; 156368087Sgibbs jnc . + 2; 156468087Sgibbs mvi INTSTAT, OUT_OF_RANGE; 156568402Sgibbs nop; 156668087Sgibbs } 156768087Sgibbs } 156868087Sgibbs mov ARG_1, SINDIR; 156968087Sgibbs cmp ARG_1, SCB_LIST_NULL je snoop_tag; 157063457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 157168087Sgibbs mov RETURN_1 call findSCB; 157239220Sgibbs } else { 157368087Sgibbs mov SCBPTR, RETURN_1; 157439220Sgibbs } 157563457Sgibbs if ((ahc->features & AHC_SCB_BTT) != 0) { 157663457Sgibbs jmp setup_SCB_id_lun_okay; 157763457Sgibbs } else { 157863457Sgibbs mov A, SCB_LUN; 157963457Sgibbs cmp SAVED_LUN, A je setup_SCB_id_lun_okay; 158063457Sgibbs } 158168087Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 158268087Sgibbs call add_scb_to_disc_list; 158368087Sgibbs } 158439220Sgibbs 158513177Sgibbs/* 158613177Sgibbs * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 158723168Sgibbs * If we get one, we use the tag returned to find the proper 158863457Sgibbs * SCB. With SCB paging, we must search for non-tagged 158963457Sgibbs * transactions since the SCB may exist in any slot. If we're not 159063457Sgibbs * using SCB paging, we can use the tag as the direct index to the 159163457Sgibbs * SCB. 159213177Sgibbs */ 159324608Sgibbssnoop_tag: 159423925Sgibbs mov NONE,SCSIDATL; /* ACK Identify MSG */ 159539220Sgibbs call phase_lock; 159668087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 159768087Sgibbs or SEQ_FLAGS, 0x1; 159868087Sgibbs } 159923925Sgibbs cmp LASTPHASE, P_MESGIN jne not_found; 160068087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 160168087Sgibbs or SEQ_FLAGS, 0x2; 160268087Sgibbs } 160323925Sgibbs cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 16046608Sgibbsget_tag: 160563457Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 160663457Sgibbs mvi ARG_1 call inb_next; /* tag value */ 160763457Sgibbs mov ARG_1 call findSCB; 160863457Sgibbs } else { 160968087Sgibbs mvi ARG_1 call inb_next; /* tag value */ 161068087Sgibbs mov SCBPTR, ARG_1; 161163457Sgibbs } 161213177Sgibbs 161363457Sgibbs/* 161463457Sgibbs * Ensure that the SCB the tag points to is for 161563457Sgibbs * an SCB transaction to the reconnecting target. 161663457Sgibbs */ 161739220Sgibbssetup_SCB: 161863457Sgibbs mov A, SAVED_SCSIID; 161968087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 162068087Sgibbs or SEQ_FLAGS, 0x4; 162168087Sgibbs } 162268087Sgibbs cmp SCB_SCSIID, A jne not_found_cleanup_scb; 162363457Sgibbs mov A, SAVED_LUN; 162468087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 162568087Sgibbs or SEQ_FLAGS, 0x8; 162668087Sgibbs } 162768087Sgibbs cmp SCB_LUN, A jne not_found_cleanup_scb; 162863457Sgibbssetup_SCB_id_lun_okay: 162968087Sgibbs if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 163068087Sgibbs or SEQ_FLAGS, 0x10; 163163457Sgibbs } 163268087Sgibbs test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; 163323925Sgibbs and SCB_CONTROL,~DISCONNECTED; 163468087Sgibbs mvi SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ 163563457Sgibbs test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; 163663457Sgibbs mov A, SCBPTR; 163768087Sgibbs mvi ARG_1, SCB_LIST_NULL; 163868087Sgibbs mov SAVED_SCSIID call set_busy_target; 163963457Sgibbs mov SCBPTR, A; 164063457Sgibbssetup_SCB_tagged: 164139220Sgibbs call set_transfer_settings; 164239220Sgibbs /* See if the host wants to send a message upon reconnection */ 164339220Sgibbs test SCB_CONTROL, MK_MESSAGE jz mesgin_done; 164439220Sgibbs mvi HOST_MSG call mk_mesg; 164523925Sgibbs jmp mesgin_done; 164615328Sgibbs 164768087Sgibbsnot_found_cleanup_scb: 164868087Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 164968087Sgibbs call add_scb_to_free_list; 165068087Sgibbs } 165119218Sgibbsnot_found: 165268402Sgibbs mvi NO_MATCH call set_seqint; 165323925Sgibbs jmp mesgin_done; 16546608Sgibbs 16554568Sgibbsmk_mesg: 165623925Sgibbs or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ 165739220Sgibbs mov MSG_OUT,SINDEX ret; 16584568Sgibbs 165913177Sgibbs/* 166013177Sgibbs * Functions to read data in Automatic PIO mode. 166113177Sgibbs * 166213177Sgibbs * According to Adaptec's documentation, an ACK is not sent on input from 166313177Sgibbs * the target until SCSIDATL is read from. So we wait until SCSIDATL is 166413177Sgibbs * latched (the usual way), then read the data byte directly off the bus 166513177Sgibbs * using SCSIBUSL. When we have pulled the ATN line, or we just want to 166613177Sgibbs * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 166713177Sgibbs * spec guarantees that the target will hold the data byte on the bus until 166813177Sgibbs * we send our ACK. 166913177Sgibbs * 167013177Sgibbs * The assumption here is that these are called in a particular sequence, 167113177Sgibbs * and that REQ is already set when inb_first is called. inb_{first,next} 167213177Sgibbs * use the same calling convention as inb. 167313177Sgibbs */ 167457099Sgibbsinb_next_wait_perr: 167568402Sgibbs mvi PERR_DETECTED call set_seqint; 167657099Sgibbs jmp inb_next_wait; 167713177Sgibbsinb_next: 167823925Sgibbs mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 167913360Sgibbsinb_next_wait: 168021947Sgibbs /* 168121947Sgibbs * If there is a parity error, wait for the kernel to 168221947Sgibbs * see the interrupt and prepare our message response 168321947Sgibbs * before continuing. 168421947Sgibbs */ 168523925Sgibbs test SSTAT1, REQINIT jz inb_next_wait; 168657099Sgibbs test SSTAT1, SCSIPERR jnz inb_next_wait_perr; 168757099Sgibbsinb_next_check_phase: 168823925Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI; 168923925Sgibbs cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 169019623Sgibbsinb_first: 169123925Sgibbs mov DINDEX,SINDEX; 169223925Sgibbs mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 169313177Sgibbsinb_last: 169423925Sgibbs mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 169541646Sgibbs} 16964568Sgibbs 169768087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 169841646Sgibbs/* 169941646Sgibbs * Change to a new phase. If we are changing the state of the I/O signal, 170041646Sgibbs * from out to in, wait an additional data release delay before continuing. 170141646Sgibbs */ 170241646Sgibbschange_phase: 170343880Sgibbs /* Wait for preceeding I/O session to complete. */ 170443880Sgibbs test SCSISIGI, ACKI jnz .; 170543880Sgibbs 170643880Sgibbs /* Change the phase */ 170741646Sgibbs and DINDEX, IOI, SCSISIGI; 170841646Sgibbs mov SCSISIGO, SINDEX; 170941646Sgibbs and A, IOI, SINDEX; 171043880Sgibbs 171143880Sgibbs /* 171243880Sgibbs * If the data direction has changed, from 171343880Sgibbs * out (initiator driving) to in (target driving), 171463457Sgibbs * we must wait at least a data release delay plus 171543880Sgibbs * the normal bus settle delay. [SCSI III SPI 10.11.0] 171643880Sgibbs */ 171741646Sgibbs cmp DINDEX, A je change_phase_wait; 171841646Sgibbs test SINDEX, IOI jz change_phase_wait; 171941646Sgibbs call change_phase_wait; 172041646Sgibbschange_phase_wait: 172141646Sgibbs nop; 172241646Sgibbs nop; 172341646Sgibbs nop; 172441646Sgibbs nop ret; 172541646Sgibbs 172641646Sgibbs/* 172741646Sgibbs * Send a byte to an initiator in Automatic PIO mode. 172841646Sgibbs */ 172939220Sgibbstarget_outb: 173039220Sgibbs or SXFRCTL0, SPIOEN; 173139220Sgibbs test SSTAT0, SPIORDY jz .; 173239220Sgibbs mov SCSIDATL, SINDEX; 173339220Sgibbs test SSTAT0, SPIORDY jz .; 173441646Sgibbs and SXFRCTL0, ~SPIOEN ret; 173539220Sgibbs} 173639220Sgibbs 17374568Sgibbs 173813177Sgibbs/* 173913177Sgibbs * Assert that if we've been reselected, then we've seen an IDENTIFY 174013177Sgibbs * message. 174113177Sgibbs */ 17424568Sgibbsassert: 174323925Sgibbs test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ 17444568Sgibbs 174568402Sgibbs mvi NO_IDENT jmp set_seqint; /* no - tell the kernel */ 17464568Sgibbs 174713177Sgibbs/* 174863457Sgibbs * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will 174963457Sgibbs * be set to the position of the SCB. If the SCB cannot be found locally, 175063457Sgibbs * it will be paged in from host memory. RETURN_2 stores the address of the 175163457Sgibbs * preceding SCB in the disconnected list which can be used to speed up 175263457Sgibbs * removal of the found SCB from the disconnected list. 175313177Sgibbs */ 175465942Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) { 17554568SgibbsfindSCB: 175668087Sgibbs mov A, SINDEX; /* Tag passed in SINDEX */ 175768087Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; 175863457Sgibbs mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ 175968087Sgibbs mvi ARG_2, SCB_LIST_NULL; /* Head of list */ 176063457Sgibbs jmp findSCB_loop; 176139220SgibbsfindSCB_next: 176263457Sgibbs cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; 176368087Sgibbs mov ARG_2, SCBPTR; 176439220Sgibbs mov SCBPTR,SCB_NEXT; 176523168SgibbsfindSCB_loop: 176663457Sgibbs cmp SCB_TAG, A jne findSCB_next; 176719164Sgibbsrem_scb_from_disc_list: 176839220Sgibbs cmp ARG_2, SCB_LIST_NULL je rHead; 176939220Sgibbs mov DINDEX, SCB_NEXT; 177068087Sgibbs mov SINDEX, SCBPTR; 177139220Sgibbs mov SCBPTR, ARG_2; 177239220Sgibbs mov SCB_NEXT, DINDEX; 177323925Sgibbs mov SCBPTR, SINDEX ret; 177415328SgibbsrHead: 177523925Sgibbs mov DISCONNECTED_SCBH,SCB_NEXT ret; 177668087SgibbsfindSCB_notFound: 177768087Sgibbs /* 177868087Sgibbs * We didn't find it. Page in the SCB. 177968087Sgibbs */ 178068087Sgibbs mov ARG_1, A; /* Save tag */ 178168087Sgibbs mov ALLZEROS call get_free_or_disc_scb; 178268087Sgibbs mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 178368087Sgibbs mov ARG_1 jmp dma_scb; 178468087Sgibbs} 17854568Sgibbs 178639220Sgibbs/* 178739220Sgibbs * Prepare the hardware to post a byte to host memory given an 178863457Sgibbs * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. 178939220Sgibbs */ 179039220Sgibbspost_byte_setup: 179139220Sgibbs mov ARG_2, SINDEX; 179239220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 179339220Sgibbs mvi DINDEX, CCHADDR; 179463457Sgibbs mvi SHARED_DATA_ADDR call set_1byte_addr; 179539220Sgibbs mvi CCHCNT, 1; 179639220Sgibbs mvi CCSCBCTL, CCSCBRESET ret; 179739220Sgibbs } else { 179839220Sgibbs mvi DINDEX, HADDR; 179963457Sgibbs mvi SHARED_DATA_ADDR call set_1byte_addr; 180063457Sgibbs mvi 1 call set_hcnt; 180139220Sgibbs mvi DFCNTRL, FIFORESET ret; 180239220Sgibbs } 180339220Sgibbs 180439220Sgibbspost_byte: 180539220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 180639220Sgibbs bmov CCSCBRAM, SINDEX, 1; 180739220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 180839220Sgibbs test CCSCBCTL, CCSCBDONE jz .; 180939220Sgibbs clr CCSCBCTL ret; 181039220Sgibbs } else { 181139220Sgibbs mov DFDAT, SINDEX; 181239220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 181339220Sgibbs jmp dma_finish; 181439220Sgibbs } 181539220Sgibbs 181657099Sgibbsphase_lock_perr: 181768402Sgibbs mvi PERR_DETECTED call set_seqint; 181839220Sgibbsphase_lock: 181957099Sgibbs /* 182057099Sgibbs * If there is a parity error, wait for the kernel to 182157099Sgibbs * see the interrupt and prepare our message response 182257099Sgibbs * before continuing. 182357099Sgibbs */ 182439220Sgibbs test SSTAT1, REQINIT jz phase_lock; 182557099Sgibbs test SSTAT1, SCSIPERR jnz phase_lock_perr; 182657099Sgibbsphase_lock_latch_phase: 182741646Sgibbs and SCSISIGO, PHASE_MASK, SCSISIGI; 182841646Sgibbs and LASTPHASE, PHASE_MASK, SCSISIGI ret; 182939220Sgibbs 183039220Sgibbsif ((ahc->features & AHC_CMD_CHAN) == 0) { 183163457Sgibbsset_hcnt: 183263457Sgibbs mov HCNT[0], SINDEX; 183363457Sgibbsclear_hcnt: 183463457Sgibbs clr HCNT[1]; 183563457Sgibbs clr HCNT[2] ret; 183663457Sgibbs 183719164Sgibbsset_stcnt_from_hcnt: 183823925Sgibbs mov STCNT[0], HCNT[0]; 183923925Sgibbs mov STCNT[1], HCNT[1]; 184023925Sgibbs mov STCNT[2], HCNT[2] ret; 18414568Sgibbs 184263457Sgibbsbcopy_8: 184363457Sgibbs mov DINDIR, SINDIR; 184419164Sgibbsbcopy_7: 184523925Sgibbs mov DINDIR, SINDIR; 184623925Sgibbs mov DINDIR, SINDIR; 184719164Sgibbsbcopy_5: 184823925Sgibbs mov DINDIR, SINDIR; 184919164Sgibbsbcopy_4: 185023925Sgibbs mov DINDIR, SINDIR; 185119164Sgibbsbcopy_3: 185223925Sgibbs mov DINDIR, SINDIR; 185323925Sgibbs mov DINDIR, SINDIR; 185423925Sgibbs mov DINDIR, SINDIR ret; 185539220Sgibbs} 18564568Sgibbs 185768087Sgibbsif ((ahc->flags & AHC_TARGETROLE) != 0) { 185839220Sgibbs/* 185939220Sgibbs * Setup addr assuming that A is an index into 186039220Sgibbs * an array of 32byte objects, SINDEX contains 186139220Sgibbs * the base address of that array, and DINDEX 186239220Sgibbs * contains the base address of the location 186339220Sgibbs * to store the indexed address. 186439220Sgibbs */ 186539220Sgibbsset_32byte_addr: 186639220Sgibbs shr ARG_2, 3, A; 186739220Sgibbs shl A, 5; 186839220Sgibbs jmp set_1byte_addr; 186939220Sgibbs} 187039220Sgibbs 187139220Sgibbs/* 187239220Sgibbs * Setup addr assuming that A is an index into 187339220Sgibbs * an array of 64byte objects, SINDEX contains 187439220Sgibbs * the base address of that array, and DINDEX 187539220Sgibbs * contains the base address of the location 187639220Sgibbs * to store the indexed address. 187739220Sgibbs */ 187839220Sgibbsset_64byte_addr: 187939220Sgibbs shr ARG_2, 2, A; 188039220Sgibbs shl A, 6; 188139220Sgibbs 188239220Sgibbs/* 188363457Sgibbs * Setup addr assuming that A + (ARG_2 * 256) is an 188439220Sgibbs * index into an array of 1byte objects, SINDEX contains 188539220Sgibbs * the base address of that array, and DINDEX contains 188639220Sgibbs * the base address of the location to store the computed 188739220Sgibbs * address. 188839220Sgibbs */ 188939220Sgibbsset_1byte_addr: 189039220Sgibbs add DINDIR, A, SINDIR; 189139220Sgibbs mov A, ARG_2; 189239220Sgibbs adc DINDIR, A, SINDIR; 189339220Sgibbs clr A; 189439220Sgibbs adc DINDIR, A, SINDIR; 189539220Sgibbs adc DINDIR, A, SINDIR ret; 189639220Sgibbs 189739220Sgibbs/* 189839220Sgibbs * Either post or fetch and SCB from host memory based on the 189939220Sgibbs * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. 190039220Sgibbs */ 190119164Sgibbsdma_scb: 190239220Sgibbs mov A, SINDEX; 190339220Sgibbs if ((ahc->features & AHC_CMD_CHAN) != 0) { 190439220Sgibbs mvi DINDEX, CCHADDR; 190539220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 190639220Sgibbs mov CCSCBPTR, SCBPTR; 190739220Sgibbs test DMAPARAMS, DIRECTION jz dma_scb_tohost; 190865942Sgibbs if ((ahc->features & AHC_SCB_BTT) != 0) { 190965942Sgibbs mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; 191065942Sgibbs } else { 191165942Sgibbs mvi CCHCNT, SCB_DOWNLOAD_SIZE; 191265942Sgibbs } 191339220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; 191439220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; 191539220Sgibbs jmp dma_scb_finish; 191639220Sgibbsdma_scb_tohost: 191765942Sgibbs mvi CCHCNT, SCB_UPLOAD_SIZE; 191865942Sgibbs if ((ahc->features & AHC_ULTRA2) == 0) { 191939220Sgibbs mvi CCSCBCTL, CCSCBRESET; 192065942Sgibbs bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; 192139220Sgibbs or CCSCBCTL, CCSCBEN|CCSCBRESET; 192268402Sgibbs cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; 192365942Sgibbs } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { 192465942Sgibbs mvi CCSCBCTL, CCARREN|CCSCBRESET; 192565942Sgibbs cmp CCSCBCTL, ARRDONE|CCARREN jne .; 192665942Sgibbs mvi CCHCNT, SCB_UPLOAD_SIZE; 192765942Sgibbs mvi CCSCBCTL, CCSCBEN|CCSCBRESET; 192865942Sgibbs cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; 192939220Sgibbs } else { 193039220Sgibbs mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; 193139220Sgibbs cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; 193239220Sgibbs } 193339220Sgibbsdma_scb_finish: 193439220Sgibbs clr CCSCBCTL; 193539220Sgibbs test CCSCBCTL, CCARREN|CCSCBEN jnz .; 193639220Sgibbs ret; 193739220Sgibbs } else { 193839220Sgibbs mvi DINDEX, HADDR; 193939220Sgibbs mvi HSCB_ADDR call set_64byte_addr; 194065942Sgibbs mvi SCB_DOWNLOAD_SIZE call set_hcnt; 194139220Sgibbs mov DFCNTRL, DMAPARAMS; 194239220Sgibbs test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 194339220Sgibbs /* Fill it with the SCB data */ 194424175Sgibbscopy_scb_tofifo: 194565942Sgibbs mvi SINDEX, SCB_BASE; 194665942Sgibbs add A, SCB_DOWNLOAD_SIZE, SINDEX; 194724175Sgibbscopy_scb_tofifo_loop: 194865942Sgibbs call copy_to_fifo_8; 194939220Sgibbs cmp SINDEX, A jne copy_scb_tofifo_loop; 195039220Sgibbs or DFCNTRL, HDMAEN|FIFOFLUSH; 195165942Sgibbs jmp dma_finish; 195219164Sgibbsdma_scb_fromhost: 195365942Sgibbs mvi DINDEX, SCB_BASE; 195465942Sgibbs if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 195565942Sgibbs /* 195665942Sgibbs * The PCI module will only issue a PCI 195765942Sgibbs * retry if the data FIFO is empty. If the 195865942Sgibbs * host disconnects in the middle of a 195965942Sgibbs * transfer, we must empty the fifo of all 196065942Sgibbs * available data to force the chip to 196165942Sgibbs * continue the transfer. This does not 196265942Sgibbs * happen for SCSI transfers as the SCSI module 196365942Sgibbs * will drain the FIFO as data is made available. 196465942Sgibbs * When the hang occurs, we know that at least 196565942Sgibbs * 8 bytes are in the FIFO because the PCI 196665942Sgibbs * module has an 8 byte input latch that only 196765942Sgibbs * dumps to the FIFO when HCNT == 0 or the 196865942Sgibbs * latch is full. 196965942Sgibbs */ 197065942Sgibbs mvi A, -24; 197165942Sgibbs /* Wait for some data to arrive. */ 197265942Sgibbsdma_scb_hang_fifo: 197365942Sgibbs test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo; 197465942Sgibbsdma_scb_hang_wait: 197565942Sgibbs test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; 197665942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 197765942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 197865942Sgibbs test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 197965942Sgibbs /* 198065942Sgibbs * The PCI no longer intends to perform a PCI 198165942Sgibbs * transaction and HDONE has not come true. 198265942Sgibbs * We are hung. Drain the fifo. 198365942Sgibbs */ 198465942Sgibbsdma_scb_hang_empty_fifo: 198565942Sgibbs call dfdat_in_8; 198665942Sgibbs add A, 8; 198765942Sgibbs add SINDEX, A, HCNT; 198865942Sgibbs /* 198965942Sgibbs * The result will be <= 0 (carry set) if at 199065942Sgibbs * least 8 bytes of data have been placed 199165942Sgibbs * into the fifo. 199265942Sgibbs */ 199365942Sgibbs jc dma_scb_hang_empty_fifo; 199465942Sgibbs jmp dma_scb_hang_fifo; 199565942Sgibbsdma_scb_hang_dma_done: 199665942Sgibbs and DFCNTRL, ~HDMAEN; 199765942Sgibbs test DFCNTRL, HDMAEN jnz .; 199865942Sgibbs call dfdat_in_8; 199965942Sgibbs add A, 8; 200065942Sgibbs cmp A, 8 jne . - 2; 200165942Sgibbs } else { 200265942Sgibbs call dma_finish; 200365942Sgibbs /* If we were putting the SCB, we are done */ 200465942Sgibbs call dfdat_in_8; 200565942Sgibbs call dfdat_in_8; 200665942Sgibbs call dfdat_in_8; 200765942Sgibbs } 200865942Sgibbsdfdat_in_8: 200965942Sgibbs mov DINDIR,DFDAT; 201019164Sgibbsdfdat_in_7: 201139220Sgibbs mov DINDIR,DFDAT; 201239220Sgibbs mov DINDIR,DFDAT; 201339220Sgibbs mov DINDIR,DFDAT; 201439220Sgibbs mov DINDIR,DFDAT; 201539220Sgibbs mov DINDIR,DFDAT; 201665942Sgibbsdfdat_in_2: 201739220Sgibbs mov DINDIR,DFDAT; 201839220Sgibbs mov DINDIR,DFDAT ret; 201939220Sgibbs } 202019164Sgibbs 202165942Sgibbscopy_to_fifo_8: 202265942Sgibbs mov DFDAT,SINDIR; 202365942Sgibbs mov DFDAT,SINDIR; 202463457Sgibbscopy_to_fifo_6: 202563457Sgibbs mov DFDAT,SINDIR; 202663457Sgibbscopy_to_fifo_5: 202763457Sgibbs mov DFDAT,SINDIR; 202863457Sgibbscopy_to_fifo_4: 202963457Sgibbs mov DFDAT,SINDIR; 203063457Sgibbs mov DFDAT,SINDIR; 203163457Sgibbs mov DFDAT,SINDIR; 203263457Sgibbs mov DFDAT,SINDIR ret; 203339220Sgibbs 203413177Sgibbs/* 203519164Sgibbs * Wait for DMA from host memory to data FIFO to complete, then disable 203619164Sgibbs * DMA and wait for it to acknowledge that it's off. 203713177Sgibbs */ 203819164Sgibbsdma_finish: 203923925Sgibbs test DFSTATUS,HDONE jz dma_finish; 204022234Sgibbs /* Turn off DMA */ 204123925Sgibbs and DFCNTRL, ~HDMAEN; 204223925Sgibbs test DFCNTRL, HDMAEN jnz .; 204323925Sgibbs ret; 20449928Sgibbs 204523925Sgibbsadd_scb_to_free_list: 204639220Sgibbs if ((ahc->flags & AHC_PAGESCBS) != 0) { 204766647SgibbsBEGIN_CRITICAL 204839220Sgibbs mov SCB_NEXT, FREE_SCBH; 204957099Sgibbs mvi SCB_TAG, SCB_LIST_NULL; 205057099Sgibbs mov FREE_SCBH, SCBPTR ret; 205166647SgibbsEND_CRITICAL 205257099Sgibbs } else { 205357099Sgibbs mvi SCB_TAG, SCB_LIST_NULL ret; 205439220Sgibbs } 20554568Sgibbs 205639220Sgibbsif ((ahc->flags & AHC_PAGESCBS) != 0) { 205719164Sgibbsget_free_or_disc_scb: 205823925Sgibbs cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 205923925Sgibbs cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 206019623Sgibbsreturn_error: 206168402Sgibbs mvi NO_FREE_SCB call set_seqint; 206223925Sgibbs mvi SINDEX, SCB_LIST_NULL ret; 206319623Sgibbsdequeue_disc_scb: 206423925Sgibbs mov SCBPTR, DISCONNECTED_SCBH; 206523925Sgibbsdma_up_scb: 206623925Sgibbs mvi DMAPARAMS, FIFORESET; 206768087Sgibbs mov SCB_TAG call dma_scb; 206819164Sgibbsunlink_disc_scb: 206939220Sgibbs mov DISCONNECTED_SCBH, SCB_NEXT ret; 207019164Sgibbsdequeue_free_scb: 207123925Sgibbs mov SCBPTR, FREE_SCBH; 207223925Sgibbs mov FREE_SCBH, SCB_NEXT ret; 20734568Sgibbs 207419164Sgibbsadd_scb_to_disc_list: 207513177Sgibbs/* 207619164Sgibbs * Link this SCB into the DISCONNECTED list. This list holds the 207719164Sgibbs * candidates for paging out an SCB if one is needed for a new command. 207819164Sgibbs * Modifying the disconnected list is a critical(pause dissabled) section. 207913177Sgibbs */ 208068087SgibbsBEGIN_CRITICAL 208123925Sgibbs mov SCB_NEXT, DISCONNECTED_SCBH; 208239220Sgibbs mov DISCONNECTED_SCBH, SCBPTR ret; 208368087SgibbsEND_CRITICAL 208465942Sgibbs} 208568402Sgibbsset_seqint: 208668402Sgibbs mov INTSTAT, SINDEX; 208768402Sgibbs nop; 208863457Sgibbsreturn: 208963457Sgibbs ret; 2090