1*4882a593Smuzhiyun/* 2*4882a593Smuzhiyun * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. 3*4882a593Smuzhiyun * 4*4882a593Smuzhiyun * Copyright (c) 1994-2001 Justin T. Gibbs. 5*4882a593Smuzhiyun * Copyright (c) 2000-2001 Adaptec Inc. 6*4882a593Smuzhiyun * All rights reserved. 7*4882a593Smuzhiyun * 8*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or without 9*4882a593Smuzhiyun * modification, are permitted provided that the following conditions 10*4882a593Smuzhiyun * are met: 11*4882a593Smuzhiyun * 1. Redistributions of source code must retain the above copyright 12*4882a593Smuzhiyun * notice, this list of conditions, and the following disclaimer, 13*4882a593Smuzhiyun * without modification. 14*4882a593Smuzhiyun * 2. Redistributions in binary form must reproduce at minimum a disclaimer 15*4882a593Smuzhiyun * substantially similar to the "NO WARRANTY" disclaimer below 16*4882a593Smuzhiyun * ("Disclaimer") and any redistribution must be conditioned upon 17*4882a593Smuzhiyun * including a substantially similar Disclaimer requirement for further 18*4882a593Smuzhiyun * binary redistribution. 19*4882a593Smuzhiyun * 3. Neither the names of the above-listed copyright holders nor the names 20*4882a593Smuzhiyun * of any contributors may be used to endorse or promote products derived 21*4882a593Smuzhiyun * from this software without specific prior written permission. 22*4882a593Smuzhiyun * 23*4882a593Smuzhiyun * Alternatively, this software may be distributed under the terms of the 24*4882a593Smuzhiyun * GNU General Public License ("GPL") version 2 as published by the Free 25*4882a593Smuzhiyun * Software Foundation. 26*4882a593Smuzhiyun * 27*4882a593Smuzhiyun * NO WARRANTY 28*4882a593Smuzhiyun * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29*4882a593Smuzhiyun * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30*4882a593Smuzhiyun * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 31*4882a593Smuzhiyun * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32*4882a593Smuzhiyun * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33*4882a593Smuzhiyun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34*4882a593Smuzhiyun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35*4882a593Smuzhiyun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36*4882a593Smuzhiyun * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 37*4882a593Smuzhiyun * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38*4882a593Smuzhiyun * POSSIBILITY OF SUCH DAMAGES. 39*4882a593Smuzhiyun * 40*4882a593Smuzhiyun * $FreeBSD$ 41*4882a593Smuzhiyun */ 42*4882a593Smuzhiyun 43*4882a593SmuzhiyunVERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $" 44*4882a593SmuzhiyunPATCH_ARG_LIST = "struct ahc_softc *ahc" 45*4882a593SmuzhiyunPREFIX = "ahc_" 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun#include "aic7xxx.reg" 48*4882a593Smuzhiyun#include "scsi_message.h" 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun/* 51*4882a593Smuzhiyun * A few words on the waiting SCB list: 52*4882a593Smuzhiyun * After starting the selection hardware, we check for reconnecting targets 53*4882a593Smuzhiyun * as well as for our selection to complete just in case the reselection wins 54*4882a593Smuzhiyun * bus arbitration. The problem with this is that we must keep track of the 55*4882a593Smuzhiyun * SCB that we've already pulled from the QINFIFO and started the selection 56*4882a593Smuzhiyun * on just in case the reselection wins so that we can retry the selection at 57*4882a593Smuzhiyun * a later time. This problem cannot be resolved by holding a single entry 58*4882a593Smuzhiyun * in scratch ram since a reconnecting target can request sense and this will 59*4882a593Smuzhiyun * create yet another SCB waiting for selection. The solution used here is to 60*4882a593Smuzhiyun * use byte 27 of the SCB as a pseudo-next pointer and to thread a list 61*4882a593Smuzhiyun * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, 62*4882a593Smuzhiyun * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to 63*4882a593Smuzhiyun * this list every time a request sense occurs or after completing a non-tagged 64*4882a593Smuzhiyun * command for which a second SCB has been queued. The sequencer will 65*4882a593Smuzhiyun * automatically consume the entries. 66*4882a593Smuzhiyun */ 67*4882a593Smuzhiyun 68*4882a593Smuzhiyunbus_free_sel: 69*4882a593Smuzhiyun /* 70*4882a593Smuzhiyun * Turn off the selection hardware. We need to reset the 71*4882a593Smuzhiyun * selection request in order to perform a new selection. 72*4882a593Smuzhiyun */ 73*4882a593Smuzhiyun and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP; 74*4882a593Smuzhiyun and SIMODE1, ~ENBUSFREE; 75*4882a593Smuzhiyunpoll_for_work: 76*4882a593Smuzhiyun call clear_target_state; 77*4882a593Smuzhiyun and SXFRCTL0, ~SPIOEN; 78*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 79*4882a593Smuzhiyun clr SCSIBUSL; 80*4882a593Smuzhiyun } 81*4882a593Smuzhiyun test SCSISEQ, ENSELO jnz poll_for_selection; 82*4882a593Smuzhiyun if ((ahc->features & AHC_TWIN) != 0) { 83*4882a593Smuzhiyun xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 84*4882a593Smuzhiyun test SCSISEQ, ENSELO jnz poll_for_selection; 85*4882a593Smuzhiyun } 86*4882a593Smuzhiyun cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 87*4882a593Smuzhiyunpoll_for_work_loop: 88*4882a593Smuzhiyun if ((ahc->features & AHC_TWIN) != 0) { 89*4882a593Smuzhiyun xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 90*4882a593Smuzhiyun } 91*4882a593Smuzhiyun test SSTAT0, SELDO|SELDI jnz selection; 92*4882a593Smuzhiyuntest_queue: 93*4882a593Smuzhiyun /* Has the driver posted any work for us? */ 94*4882a593SmuzhiyunBEGIN_CRITICAL; 95*4882a593Smuzhiyun if ((ahc->features & AHC_QUEUE_REGS) != 0) { 96*4882a593Smuzhiyun test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; 97*4882a593Smuzhiyun } else { 98*4882a593Smuzhiyun mov A, QINPOS; 99*4882a593Smuzhiyun cmp KERNEL_QINPOS, A je poll_for_work_loop; 100*4882a593Smuzhiyun } 101*4882a593Smuzhiyun mov ARG_1, NEXT_QUEUED_SCB; 102*4882a593Smuzhiyun 103*4882a593Smuzhiyun /* 104*4882a593Smuzhiyun * We have at least one queued SCB now and we don't have any 105*4882a593Smuzhiyun * SCBs in the list of SCBs awaiting selection. Allocate a 106*4882a593Smuzhiyun * card SCB for the host's SCB and get to work on it. 107*4882a593Smuzhiyun */ 108*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 109*4882a593Smuzhiyun mov ALLZEROS call get_free_or_disc_scb; 110*4882a593Smuzhiyun } else { 111*4882a593Smuzhiyun /* In the non-paging case, the SCBID == hardware SCB index */ 112*4882a593Smuzhiyun mov SCBPTR, ARG_1; 113*4882a593Smuzhiyun } 114*4882a593Smuzhiyun or SEQ_FLAGS2, SCB_DMA; 115*4882a593SmuzhiyunEND_CRITICAL; 116*4882a593Smuzhiyundma_queued_scb: 117*4882a593Smuzhiyun /* 118*4882a593Smuzhiyun * DMA the SCB from host ram into the current SCB location. 119*4882a593Smuzhiyun */ 120*4882a593Smuzhiyun mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 121*4882a593Smuzhiyun mov ARG_1 call dma_scb; 122*4882a593Smuzhiyun /* 123*4882a593Smuzhiyun * Check one last time to see if this SCB was canceled 124*4882a593Smuzhiyun * before we completed the DMA operation. If it was, 125*4882a593Smuzhiyun * the QINFIFO next pointer will not match our saved 126*4882a593Smuzhiyun * value. 127*4882a593Smuzhiyun */ 128*4882a593Smuzhiyun mov A, ARG_1; 129*4882a593SmuzhiyunBEGIN_CRITICAL; 130*4882a593Smuzhiyun cmp NEXT_QUEUED_SCB, A jne abort_qinscb; 131*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 132*4882a593Smuzhiyun cmp SCB_TAG, A je . + 2; 133*4882a593Smuzhiyun mvi SCB_MISMATCH call set_seqint; 134*4882a593Smuzhiyun } 135*4882a593Smuzhiyun mov NEXT_QUEUED_SCB, SCB_NEXT; 136*4882a593Smuzhiyun mov SCB_NEXT,WAITING_SCBH; 137*4882a593Smuzhiyun mov WAITING_SCBH, SCBPTR; 138*4882a593Smuzhiyun if ((ahc->features & AHC_QUEUE_REGS) != 0) { 139*4882a593Smuzhiyun mov NONE, SNSCB_QOFF; 140*4882a593Smuzhiyun } else { 141*4882a593Smuzhiyun inc QINPOS; 142*4882a593Smuzhiyun } 143*4882a593Smuzhiyun and SEQ_FLAGS2, ~SCB_DMA; 144*4882a593SmuzhiyunEND_CRITICAL; 145*4882a593Smuzhiyunstart_waiting: 146*4882a593Smuzhiyun /* 147*4882a593Smuzhiyun * Start the first entry on the waiting SCB list. 148*4882a593Smuzhiyun */ 149*4882a593Smuzhiyun mov SCBPTR, WAITING_SCBH; 150*4882a593Smuzhiyun call start_selection; 151*4882a593Smuzhiyun 152*4882a593Smuzhiyunpoll_for_selection: 153*4882a593Smuzhiyun /* 154*4882a593Smuzhiyun * Twin channel devices cannot handle things like SELTO 155*4882a593Smuzhiyun * interrupts on the "background" channel. So, while 156*4882a593Smuzhiyun * selecting, keep polling the current channel until 157*4882a593Smuzhiyun * either a selection or reselection occurs. 158*4882a593Smuzhiyun */ 159*4882a593Smuzhiyun test SSTAT0, SELDO|SELDI jz poll_for_selection; 160*4882a593Smuzhiyun 161*4882a593Smuzhiyunselection: 162*4882a593Smuzhiyun /* 163*4882a593Smuzhiyun * We aren't expecting a bus free, so interrupt 164*4882a593Smuzhiyun * the kernel driver if it happens. 165*4882a593Smuzhiyun */ 166*4882a593Smuzhiyun mvi CLRSINT1,CLRBUSFREE; 167*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 168*4882a593Smuzhiyun or SIMODE1, ENBUSFREE; 169*4882a593Smuzhiyun } 170*4882a593Smuzhiyun 171*4882a593Smuzhiyun /* 172*4882a593Smuzhiyun * Guard against a bus free after (re)selection 173*4882a593Smuzhiyun * but prior to enabling the busfree interrupt. SELDI 174*4882a593Smuzhiyun * and SELDO will be cleared in that case. 175*4882a593Smuzhiyun */ 176*4882a593Smuzhiyun test SSTAT0, SELDI|SELDO jz bus_free_sel; 177*4882a593Smuzhiyun test SSTAT0,SELDO jnz select_out; 178*4882a593Smuzhiyunselect_in: 179*4882a593Smuzhiyun if ((ahc->flags & AHC_TARGETROLE) != 0) { 180*4882a593Smuzhiyun if ((ahc->flags & AHC_INITIATORROLE) != 0) { 181*4882a593Smuzhiyun test SSTAT0, TARGET jz initiator_reselect; 182*4882a593Smuzhiyun } 183*4882a593Smuzhiyun mvi CLRSINT0, CLRSELDI; 184*4882a593Smuzhiyun 185*4882a593Smuzhiyun /* 186*4882a593Smuzhiyun * We've just been selected. Assert BSY and 187*4882a593Smuzhiyun * setup the phase for receiving messages 188*4882a593Smuzhiyun * from the target. 189*4882a593Smuzhiyun */ 190*4882a593Smuzhiyun mvi SCSISIGO, P_MESGOUT|BSYO; 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun /* 193*4882a593Smuzhiyun * Setup the DMA for sending the identify and 194*4882a593Smuzhiyun * command information. 195*4882a593Smuzhiyun */ 196*4882a593Smuzhiyun mvi SEQ_FLAGS, CMDPHASE_PENDING; 197*4882a593Smuzhiyun 198*4882a593Smuzhiyun mov A, TQINPOS; 199*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 200*4882a593Smuzhiyun mvi DINDEX, CCHADDR; 201*4882a593Smuzhiyun mvi SHARED_DATA_ADDR call set_32byte_addr; 202*4882a593Smuzhiyun mvi CCSCBCTL, CCSCBRESET; 203*4882a593Smuzhiyun } else { 204*4882a593Smuzhiyun mvi DINDEX, HADDR; 205*4882a593Smuzhiyun mvi SHARED_DATA_ADDR call set_32byte_addr; 206*4882a593Smuzhiyun mvi DFCNTRL, FIFORESET; 207*4882a593Smuzhiyun } 208*4882a593Smuzhiyun 209*4882a593Smuzhiyun /* Initiator that selected us */ 210*4882a593Smuzhiyun and SAVED_SCSIID, SELID_MASK, SELID; 211*4882a593Smuzhiyun /* The Target ID we were selected at */ 212*4882a593Smuzhiyun if ((ahc->features & AHC_MULTI_TID) != 0) { 213*4882a593Smuzhiyun and A, OID, TARGIDIN; 214*4882a593Smuzhiyun } else if ((ahc->features & AHC_ULTRA2) != 0) { 215*4882a593Smuzhiyun and A, OID, SCSIID_ULTRA2; 216*4882a593Smuzhiyun } else { 217*4882a593Smuzhiyun and A, OID, SCSIID; 218*4882a593Smuzhiyun } 219*4882a593Smuzhiyun or SAVED_SCSIID, A; 220*4882a593Smuzhiyun if ((ahc->features & AHC_TWIN) != 0) { 221*4882a593Smuzhiyun test SBLKCTL, SELBUSB jz . + 2; 222*4882a593Smuzhiyun or SAVED_SCSIID, TWIN_CHNLB; 223*4882a593Smuzhiyun } 224*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 225*4882a593Smuzhiyun mov CCSCBRAM, SAVED_SCSIID; 226*4882a593Smuzhiyun } else { 227*4882a593Smuzhiyun mov DFDAT, SAVED_SCSIID; 228*4882a593Smuzhiyun } 229*4882a593Smuzhiyun 230*4882a593Smuzhiyun /* 231*4882a593Smuzhiyun * If ATN isn't asserted, the target isn't interested 232*4882a593Smuzhiyun * in talking to us. Go directly to bus free. 233*4882a593Smuzhiyun * XXX SCSI-1 may require us to assume lun 0 if 234*4882a593Smuzhiyun * ATN is false. 235*4882a593Smuzhiyun */ 236*4882a593Smuzhiyun test SCSISIGI, ATNI jz target_busfree; 237*4882a593Smuzhiyun 238*4882a593Smuzhiyun /* 239*4882a593Smuzhiyun * Watch ATN closely now as we pull in messages from the 240*4882a593Smuzhiyun * initiator. We follow the guidlines from section 6.5 241*4882a593Smuzhiyun * of the SCSI-2 spec for what messages are allowed when. 242*4882a593Smuzhiyun */ 243*4882a593Smuzhiyun call target_inb; 244*4882a593Smuzhiyun 245*4882a593Smuzhiyun /* 246*4882a593Smuzhiyun * Our first message must be one of IDENTIFY, ABORT, or 247*4882a593Smuzhiyun * BUS_DEVICE_RESET. 248*4882a593Smuzhiyun */ 249*4882a593Smuzhiyun test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; 250*4882a593Smuzhiyun /* Store for host */ 251*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 252*4882a593Smuzhiyun mov CCSCBRAM, DINDEX; 253*4882a593Smuzhiyun } else { 254*4882a593Smuzhiyun mov DFDAT, DINDEX; 255*4882a593Smuzhiyun } 256*4882a593Smuzhiyun and SAVED_LUN, MSG_IDENTIFY_LUNMASK, DINDEX; 257*4882a593Smuzhiyun 258*4882a593Smuzhiyun /* Remember for disconnection decision */ 259*4882a593Smuzhiyun test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; 260*4882a593Smuzhiyun /* XXX Honor per target settings too */ 261*4882a593Smuzhiyun or SEQ_FLAGS, NO_DISCONNECT; 262*4882a593Smuzhiyun 263*4882a593Smuzhiyun test SCSISIGI, ATNI jz ident_messages_done; 264*4882a593Smuzhiyun call target_inb; 265*4882a593Smuzhiyun /* 266*4882a593Smuzhiyun * If this is a tagged request, the tagged message must 267*4882a593Smuzhiyun * immediately follow the identify. We test for a valid 268*4882a593Smuzhiyun * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and 269*4882a593Smuzhiyun * < MSG_IGN_WIDE_RESIDUE. 270*4882a593Smuzhiyun */ 271*4882a593Smuzhiyun add A, -MSG_SIMPLE_Q_TAG, DINDEX; 272*4882a593Smuzhiyun jnc ident_messages_done_msg_pending; 273*4882a593Smuzhiyun add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; 274*4882a593Smuzhiyun jc ident_messages_done_msg_pending; 275*4882a593Smuzhiyun 276*4882a593Smuzhiyun /* Store for host */ 277*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 278*4882a593Smuzhiyun mov CCSCBRAM, DINDEX; 279*4882a593Smuzhiyun } else { 280*4882a593Smuzhiyun mov DFDAT, DINDEX; 281*4882a593Smuzhiyun } 282*4882a593Smuzhiyun 283*4882a593Smuzhiyun /* 284*4882a593Smuzhiyun * If the initiator doesn't feel like providing a tag number, 285*4882a593Smuzhiyun * we've got a failed selection and must transition to bus 286*4882a593Smuzhiyun * free. 287*4882a593Smuzhiyun */ 288*4882a593Smuzhiyun test SCSISIGI, ATNI jz target_busfree; 289*4882a593Smuzhiyun 290*4882a593Smuzhiyun /* 291*4882a593Smuzhiyun * Store the tag for the host. 292*4882a593Smuzhiyun */ 293*4882a593Smuzhiyun call target_inb; 294*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 295*4882a593Smuzhiyun mov CCSCBRAM, DINDEX; 296*4882a593Smuzhiyun } else { 297*4882a593Smuzhiyun mov DFDAT, DINDEX; 298*4882a593Smuzhiyun } 299*4882a593Smuzhiyun mov INITIATOR_TAG, DINDEX; 300*4882a593Smuzhiyun or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; 301*4882a593Smuzhiyun 302*4882a593Smuzhiyunident_messages_done: 303*4882a593Smuzhiyun /* Terminate the ident list */ 304*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 305*4882a593Smuzhiyun mvi CCSCBRAM, SCB_LIST_NULL; 306*4882a593Smuzhiyun } else { 307*4882a593Smuzhiyun mvi DFDAT, SCB_LIST_NULL; 308*4882a593Smuzhiyun } 309*4882a593Smuzhiyun or SEQ_FLAGS, TARG_CMD_PENDING; 310*4882a593Smuzhiyun test SEQ_FLAGS2, TARGET_MSG_PENDING 311*4882a593Smuzhiyun jnz target_mesgout_pending; 312*4882a593Smuzhiyun test SCSISIGI, ATNI jnz target_mesgout_continue; 313*4882a593Smuzhiyun jmp target_ITloop; 314*4882a593Smuzhiyun 315*4882a593Smuzhiyun 316*4882a593Smuzhiyunident_messages_done_msg_pending: 317*4882a593Smuzhiyun or SEQ_FLAGS2, TARGET_MSG_PENDING; 318*4882a593Smuzhiyun jmp ident_messages_done; 319*4882a593Smuzhiyun 320*4882a593Smuzhiyun /* 321*4882a593Smuzhiyun * Pushed message loop to allow the kernel to 322*4882a593Smuzhiyun * run it's own target mode message state engine. 323*4882a593Smuzhiyun */ 324*4882a593Smuzhiyunhost_target_message_loop: 325*4882a593Smuzhiyun mvi HOST_MSG_LOOP call set_seqint; 326*4882a593Smuzhiyun cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; 327*4882a593Smuzhiyun test SSTAT0, SPIORDY jz .; 328*4882a593Smuzhiyun jmp host_target_message_loop; 329*4882a593Smuzhiyun } 330*4882a593Smuzhiyun 331*4882a593Smuzhiyunif ((ahc->flags & AHC_INITIATORROLE) != 0) { 332*4882a593Smuzhiyun/* 333*4882a593Smuzhiyun * Reselection has been initiated by a target. Make a note that we've been 334*4882a593Smuzhiyun * reselected, but haven't seen an IDENTIFY message from the target yet. 335*4882a593Smuzhiyun */ 336*4882a593Smuzhiyuninitiator_reselect: 337*4882a593Smuzhiyun /* XXX test for and handle ONE BIT condition */ 338*4882a593Smuzhiyun or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 339*4882a593Smuzhiyun and SAVED_SCSIID, SELID_MASK, SELID; 340*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 341*4882a593Smuzhiyun and A, OID, SCSIID_ULTRA2; 342*4882a593Smuzhiyun } else { 343*4882a593Smuzhiyun and A, OID, SCSIID; 344*4882a593Smuzhiyun } 345*4882a593Smuzhiyun or SAVED_SCSIID, A; 346*4882a593Smuzhiyun if ((ahc->features & AHC_TWIN) != 0) { 347*4882a593Smuzhiyun test SBLKCTL, SELBUSB jz . + 2; 348*4882a593Smuzhiyun or SAVED_SCSIID, TWIN_CHNLB; 349*4882a593Smuzhiyun } 350*4882a593Smuzhiyun mvi CLRSINT0, CLRSELDI; 351*4882a593Smuzhiyun jmp ITloop; 352*4882a593Smuzhiyun} 353*4882a593Smuzhiyun 354*4882a593Smuzhiyunabort_qinscb: 355*4882a593Smuzhiyun call add_scb_to_free_list; 356*4882a593Smuzhiyun jmp poll_for_work_loop; 357*4882a593Smuzhiyun 358*4882a593Smuzhiyunstart_selection: 359*4882a593Smuzhiyun /* 360*4882a593Smuzhiyun * If bus reset interrupts have been disabled (from a previous 361*4882a593Smuzhiyun * reset), re-enable them now. Resets are only of interest 362*4882a593Smuzhiyun * when we have outstanding transactions, so we can safely 363*4882a593Smuzhiyun * defer re-enabling the interrupt until, as an initiator, 364*4882a593Smuzhiyun * we start sending out transactions again. 365*4882a593Smuzhiyun */ 366*4882a593Smuzhiyun test SIMODE1, ENSCSIRST jnz . + 3; 367*4882a593Smuzhiyun mvi CLRSINT1, CLRSCSIRSTI; 368*4882a593Smuzhiyun or SIMODE1, ENSCSIRST; 369*4882a593Smuzhiyun if ((ahc->features & AHC_TWIN) != 0) { 370*4882a593Smuzhiyun and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ 371*4882a593Smuzhiyun test SCB_SCSIID, TWIN_CHNLB jz . + 2; 372*4882a593Smuzhiyun or SINDEX, SELBUSB; 373*4882a593Smuzhiyun mov SBLKCTL,SINDEX; /* select channel */ 374*4882a593Smuzhiyun } 375*4882a593Smuzhiyuninitialize_scsiid: 376*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 377*4882a593Smuzhiyun mov SCSIID_ULTRA2, SCB_SCSIID; 378*4882a593Smuzhiyun } else if ((ahc->features & AHC_TWIN) != 0) { 379*4882a593Smuzhiyun and SCSIID, TWIN_TID|OID, SCB_SCSIID; 380*4882a593Smuzhiyun } else { 381*4882a593Smuzhiyun mov SCSIID, SCB_SCSIID; 382*4882a593Smuzhiyun } 383*4882a593Smuzhiyun if ((ahc->flags & AHC_TARGETROLE) != 0) { 384*4882a593Smuzhiyun mov SINDEX, SCSISEQ_TEMPLATE; 385*4882a593Smuzhiyun test SCB_CONTROL, TARGET_SCB jz . + 2; 386*4882a593Smuzhiyun or SINDEX, TEMODE; 387*4882a593Smuzhiyun mov SCSISEQ, SINDEX ret; 388*4882a593Smuzhiyun } else { 389*4882a593Smuzhiyun mov SCSISEQ, SCSISEQ_TEMPLATE ret; 390*4882a593Smuzhiyun } 391*4882a593Smuzhiyun 392*4882a593Smuzhiyun/* 393*4882a593Smuzhiyun * Initialize transfer settings with SCB provided settings. 394*4882a593Smuzhiyun */ 395*4882a593Smuzhiyunset_transfer_settings: 396*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA) != 0) { 397*4882a593Smuzhiyun test SCB_CONTROL, ULTRAENB jz . + 2; 398*4882a593Smuzhiyun or SXFRCTL0, FAST20; 399*4882a593Smuzhiyun } 400*4882a593Smuzhiyun /* 401*4882a593Smuzhiyun * Initialize SCSIRATE with the appropriate value for this target. 402*4882a593Smuzhiyun */ 403*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 404*4882a593Smuzhiyun bmov SCSIRATE, SCB_SCSIRATE, 2 ret; 405*4882a593Smuzhiyun } else { 406*4882a593Smuzhiyun mov SCSIRATE, SCB_SCSIRATE ret; 407*4882a593Smuzhiyun } 408*4882a593Smuzhiyun 409*4882a593Smuzhiyunif ((ahc->flags & AHC_TARGETROLE) != 0) { 410*4882a593Smuzhiyun/* 411*4882a593Smuzhiyun * We carefully toggle SPIOEN to allow us to return the 412*4882a593Smuzhiyun * message byte we receive so it can be checked prior to 413*4882a593Smuzhiyun * driving REQ on the bus for the next byte. 414*4882a593Smuzhiyun */ 415*4882a593Smuzhiyuntarget_inb: 416*4882a593Smuzhiyun /* 417*4882a593Smuzhiyun * Drive REQ on the bus by enabling SCSI PIO. 418*4882a593Smuzhiyun */ 419*4882a593Smuzhiyun or SXFRCTL0, SPIOEN; 420*4882a593Smuzhiyun /* Wait for the byte */ 421*4882a593Smuzhiyun test SSTAT0, SPIORDY jz .; 422*4882a593Smuzhiyun /* Prevent our read from triggering another REQ */ 423*4882a593Smuzhiyun and SXFRCTL0, ~SPIOEN; 424*4882a593Smuzhiyun /* Save latched contents */ 425*4882a593Smuzhiyun mov DINDEX, SCSIDATL ret; 426*4882a593Smuzhiyun} 427*4882a593Smuzhiyun 428*4882a593Smuzhiyun/* 429*4882a593Smuzhiyun * After the selection, remove this SCB from the "waiting SCB" 430*4882a593Smuzhiyun * list. This is achieved by simply moving our "next" pointer into 431*4882a593Smuzhiyun * WAITING_SCBH. Our next pointer will be set to null the next time this 432*4882a593Smuzhiyun * SCB is used, so don't bother with it now. 433*4882a593Smuzhiyun */ 434*4882a593Smuzhiyunselect_out: 435*4882a593Smuzhiyun /* Turn off the selection hardware */ 436*4882a593Smuzhiyun and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; 437*4882a593Smuzhiyun mov SCBPTR, WAITING_SCBH; 438*4882a593Smuzhiyun mov WAITING_SCBH,SCB_NEXT; 439*4882a593Smuzhiyun mov SAVED_SCSIID, SCB_SCSIID; 440*4882a593Smuzhiyun and SAVED_LUN, LID, SCB_LUN; 441*4882a593Smuzhiyun call set_transfer_settings; 442*4882a593Smuzhiyun if ((ahc->flags & AHC_TARGETROLE) != 0) { 443*4882a593Smuzhiyun test SSTAT0, TARGET jz initiator_select; 444*4882a593Smuzhiyun 445*4882a593Smuzhiyun or SXFRCTL0, CLRSTCNT|CLRCHN; 446*4882a593Smuzhiyun 447*4882a593Smuzhiyun /* 448*4882a593Smuzhiyun * Put tag in connonical location since not 449*4882a593Smuzhiyun * all connections have an SCB. 450*4882a593Smuzhiyun */ 451*4882a593Smuzhiyun mov INITIATOR_TAG, SCB_TARGET_ITAG; 452*4882a593Smuzhiyun 453*4882a593Smuzhiyun /* 454*4882a593Smuzhiyun * We've just re-selected an initiator. 455*4882a593Smuzhiyun * Assert BSY and setup the phase for 456*4882a593Smuzhiyun * sending our identify messages. 457*4882a593Smuzhiyun */ 458*4882a593Smuzhiyun mvi P_MESGIN|BSYO call change_phase; 459*4882a593Smuzhiyun mvi CLRSINT0, CLRSELDO; 460*4882a593Smuzhiyun 461*4882a593Smuzhiyun /* 462*4882a593Smuzhiyun * Start out with a simple identify message. 463*4882a593Smuzhiyun */ 464*4882a593Smuzhiyun or SAVED_LUN, MSG_IDENTIFYFLAG call target_outb; 465*4882a593Smuzhiyun 466*4882a593Smuzhiyun /* 467*4882a593Smuzhiyun * If we are the result of a tagged command, send 468*4882a593Smuzhiyun * a simple Q tag and the tag id. 469*4882a593Smuzhiyun */ 470*4882a593Smuzhiyun test SCB_CONTROL, TAG_ENB jz . + 3; 471*4882a593Smuzhiyun mvi MSG_SIMPLE_Q_TAG call target_outb; 472*4882a593Smuzhiyun mov SCB_TARGET_ITAG call target_outb; 473*4882a593Smuzhiyuntarget_synccmd: 474*4882a593Smuzhiyun /* 475*4882a593Smuzhiyun * Now determine what phases the host wants us 476*4882a593Smuzhiyun * to go through. 477*4882a593Smuzhiyun */ 478*4882a593Smuzhiyun mov SEQ_FLAGS, SCB_TARGET_PHASES; 479*4882a593Smuzhiyun 480*4882a593Smuzhiyun test SCB_CONTROL, MK_MESSAGE jz target_ITloop; 481*4882a593Smuzhiyun mvi P_MESGIN|BSYO call change_phase; 482*4882a593Smuzhiyun jmp host_target_message_loop; 483*4882a593Smuzhiyuntarget_ITloop: 484*4882a593Smuzhiyun /* 485*4882a593Smuzhiyun * Start honoring ATN signals now that 486*4882a593Smuzhiyun * we properly identified ourselves. 487*4882a593Smuzhiyun */ 488*4882a593Smuzhiyun test SCSISIGI, ATNI jnz target_mesgout; 489*4882a593Smuzhiyun test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; 490*4882a593Smuzhiyun test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; 491*4882a593Smuzhiyun test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; 492*4882a593Smuzhiyun 493*4882a593Smuzhiyun /* 494*4882a593Smuzhiyun * No more work to do. Either disconnect or not depending 495*4882a593Smuzhiyun * on the state of NO_DISCONNECT. 496*4882a593Smuzhiyun */ 497*4882a593Smuzhiyun test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 498*4882a593Smuzhiyun mvi TARG_IMMEDIATE_SCB, SCB_LIST_NULL; 499*4882a593Smuzhiyun call complete_target_cmd; 500*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 501*4882a593Smuzhiyun mov ALLZEROS call get_free_or_disc_scb; 502*4882a593Smuzhiyun } 503*4882a593Smuzhiyun cmp TARG_IMMEDIATE_SCB, SCB_LIST_NULL je .; 504*4882a593Smuzhiyun mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 505*4882a593Smuzhiyun mov TARG_IMMEDIATE_SCB call dma_scb; 506*4882a593Smuzhiyun call set_transfer_settings; 507*4882a593Smuzhiyun or SXFRCTL0, CLRSTCNT|CLRCHN; 508*4882a593Smuzhiyun jmp target_synccmd; 509*4882a593Smuzhiyun 510*4882a593Smuzhiyuntarget_mesgout: 511*4882a593Smuzhiyun mvi SCSISIGO, P_MESGOUT|BSYO; 512*4882a593Smuzhiyuntarget_mesgout_continue: 513*4882a593Smuzhiyun call target_inb; 514*4882a593Smuzhiyuntarget_mesgout_pending: 515*4882a593Smuzhiyun and SEQ_FLAGS2, ~TARGET_MSG_PENDING; 516*4882a593Smuzhiyun /* Local Processing goes here... */ 517*4882a593Smuzhiyun jmp host_target_message_loop; 518*4882a593Smuzhiyun 519*4882a593Smuzhiyuntarget_disconnect: 520*4882a593Smuzhiyun mvi P_MESGIN|BSYO call change_phase; 521*4882a593Smuzhiyun test SEQ_FLAGS, DPHASE jz . + 2; 522*4882a593Smuzhiyun mvi MSG_SAVEDATAPOINTER call target_outb; 523*4882a593Smuzhiyun mvi MSG_DISCONNECT call target_outb; 524*4882a593Smuzhiyun 525*4882a593Smuzhiyuntarget_busfree_wait: 526*4882a593Smuzhiyun /* Wait for preceding I/O session to complete. */ 527*4882a593Smuzhiyun test SCSISIGI, ACKI jnz .; 528*4882a593Smuzhiyuntarget_busfree: 529*4882a593Smuzhiyun and SIMODE1, ~ENBUSFREE; 530*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 531*4882a593Smuzhiyun clr SCSIBUSL; 532*4882a593Smuzhiyun } 533*4882a593Smuzhiyun clr SCSISIGO; 534*4882a593Smuzhiyun mvi LASTPHASE, P_BUSFREE; 535*4882a593Smuzhiyun call complete_target_cmd; 536*4882a593Smuzhiyun jmp poll_for_work; 537*4882a593Smuzhiyun 538*4882a593Smuzhiyuntarget_cmdphase: 539*4882a593Smuzhiyun /* 540*4882a593Smuzhiyun * The target has dropped ATN (doesn't want to abort or BDR) 541*4882a593Smuzhiyun * and we believe this selection to be valid. If the ring 542*4882a593Smuzhiyun * buffer for new commands is full, return busy or queue full. 543*4882a593Smuzhiyun */ 544*4882a593Smuzhiyun if ((ahc->features & AHC_HS_MAILBOX) != 0) { 545*4882a593Smuzhiyun and A, HOST_TQINPOS, HS_MAILBOX; 546*4882a593Smuzhiyun } else { 547*4882a593Smuzhiyun mov A, KERNEL_TQINPOS; 548*4882a593Smuzhiyun } 549*4882a593Smuzhiyun cmp TQINPOS, A jne tqinfifo_has_space; 550*4882a593Smuzhiyun mvi P_STATUS|BSYO call change_phase; 551*4882a593Smuzhiyun test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; 552*4882a593Smuzhiyun mvi STATUS_QUEUE_FULL call target_outb; 553*4882a593Smuzhiyun jmp target_busfree_wait; 554*4882a593Smuzhiyun mvi STATUS_BUSY call target_outb; 555*4882a593Smuzhiyun jmp target_busfree_wait; 556*4882a593Smuzhiyuntqinfifo_has_space: 557*4882a593Smuzhiyun mvi P_COMMAND|BSYO call change_phase; 558*4882a593Smuzhiyun call target_inb; 559*4882a593Smuzhiyun mov A, DINDEX; 560*4882a593Smuzhiyun /* Store for host */ 561*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 562*4882a593Smuzhiyun mov CCSCBRAM, A; 563*4882a593Smuzhiyun } else { 564*4882a593Smuzhiyun mov DFDAT, A; 565*4882a593Smuzhiyun } 566*4882a593Smuzhiyun 567*4882a593Smuzhiyun /* 568*4882a593Smuzhiyun * Determine the number of bytes to read 569*4882a593Smuzhiyun * based on the command group code via table lookup. 570*4882a593Smuzhiyun * We reuse the first 8 bytes of the TARG_SCSIRATE 571*4882a593Smuzhiyun * BIOS array for this table. Count is one less than 572*4882a593Smuzhiyun * the total for the command since we've already fetched 573*4882a593Smuzhiyun * the first byte. 574*4882a593Smuzhiyun */ 575*4882a593Smuzhiyun shr A, CMD_GROUP_CODE_SHIFT; 576*4882a593Smuzhiyun add SINDEX, CMDSIZE_TABLE, A; 577*4882a593Smuzhiyun mov A, SINDIR; 578*4882a593Smuzhiyun 579*4882a593Smuzhiyun test A, 0xFF jz command_phase_done; 580*4882a593Smuzhiyun or SXFRCTL0, SPIOEN; 581*4882a593Smuzhiyuncommand_loop: 582*4882a593Smuzhiyun test SSTAT0, SPIORDY jz .; 583*4882a593Smuzhiyun cmp A, 1 jne . + 2; 584*4882a593Smuzhiyun and SXFRCTL0, ~SPIOEN; /* Last Byte */ 585*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 586*4882a593Smuzhiyun mov CCSCBRAM, SCSIDATL; 587*4882a593Smuzhiyun } else { 588*4882a593Smuzhiyun mov DFDAT, SCSIDATL; 589*4882a593Smuzhiyun } 590*4882a593Smuzhiyun dec A; 591*4882a593Smuzhiyun test A, 0xFF jnz command_loop; 592*4882a593Smuzhiyun 593*4882a593Smuzhiyuncommand_phase_done: 594*4882a593Smuzhiyun and SEQ_FLAGS, ~CMDPHASE_PENDING; 595*4882a593Smuzhiyun jmp target_ITloop; 596*4882a593Smuzhiyun 597*4882a593Smuzhiyuntarget_dphase: 598*4882a593Smuzhiyun /* 599*4882a593Smuzhiyun * Data phases on the bus are from the 600*4882a593Smuzhiyun * perspective of the initiator. The dma 601*4882a593Smuzhiyun * code looks at LASTPHASE to determine the 602*4882a593Smuzhiyun * data direction of the DMA. Toggle it for 603*4882a593Smuzhiyun * target transfers. 604*4882a593Smuzhiyun */ 605*4882a593Smuzhiyun xor LASTPHASE, IOI, SCB_TARGET_DATA_DIR; 606*4882a593Smuzhiyun or SCB_TARGET_DATA_DIR, BSYO call change_phase; 607*4882a593Smuzhiyun jmp p_data; 608*4882a593Smuzhiyun 609*4882a593Smuzhiyuntarget_sphase: 610*4882a593Smuzhiyun mvi P_STATUS|BSYO call change_phase; 611*4882a593Smuzhiyun mvi LASTPHASE, P_STATUS; 612*4882a593Smuzhiyun mov SCB_SCSI_STATUS call target_outb; 613*4882a593Smuzhiyun /* XXX Watch for ATN or parity errors??? */ 614*4882a593Smuzhiyun mvi SCSISIGO, P_MESGIN|BSYO; 615*4882a593Smuzhiyun /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ 616*4882a593Smuzhiyun mov ALLZEROS call target_outb; 617*4882a593Smuzhiyun jmp target_busfree_wait; 618*4882a593Smuzhiyun 619*4882a593Smuzhiyuncomplete_target_cmd: 620*4882a593Smuzhiyun test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; 621*4882a593Smuzhiyun mov SCB_TAG jmp complete_post; 622*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 623*4882a593Smuzhiyun /* Set the valid byte */ 624*4882a593Smuzhiyun mvi CCSCBADDR, 24; 625*4882a593Smuzhiyun mov CCSCBRAM, ALLONES; 626*4882a593Smuzhiyun mvi CCHCNT, 28; 627*4882a593Smuzhiyun or CCSCBCTL, CCSCBEN|CCSCBRESET; 628*4882a593Smuzhiyun test CCSCBCTL, CCSCBDONE jz .; 629*4882a593Smuzhiyun clr CCSCBCTL; 630*4882a593Smuzhiyun } else { 631*4882a593Smuzhiyun /* Set the valid byte */ 632*4882a593Smuzhiyun or DFCNTRL, FIFORESET; 633*4882a593Smuzhiyun mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ 634*4882a593Smuzhiyun mov DFDAT, ALLONES; 635*4882a593Smuzhiyun mvi 28 call set_hcnt; 636*4882a593Smuzhiyun or DFCNTRL, HDMAEN|FIFOFLUSH; 637*4882a593Smuzhiyun call dma_finish; 638*4882a593Smuzhiyun } 639*4882a593Smuzhiyun inc TQINPOS; 640*4882a593Smuzhiyun mvi INTSTAT,CMDCMPLT ret; 641*4882a593Smuzhiyun } 642*4882a593Smuzhiyun 643*4882a593Smuzhiyunif ((ahc->flags & AHC_INITIATORROLE) != 0) { 644*4882a593Smuzhiyuninitiator_select: 645*4882a593Smuzhiyun or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 646*4882a593Smuzhiyun /* 647*4882a593Smuzhiyun * As soon as we get a successful selection, the target 648*4882a593Smuzhiyun * should go into the message out phase since we have ATN 649*4882a593Smuzhiyun * asserted. 650*4882a593Smuzhiyun */ 651*4882a593Smuzhiyun mvi MSG_OUT, MSG_IDENTIFYFLAG; 652*4882a593Smuzhiyun mvi SEQ_FLAGS, NO_CDB_SENT; 653*4882a593Smuzhiyun mvi CLRSINT0, CLRSELDO; 654*4882a593Smuzhiyun 655*4882a593Smuzhiyun /* 656*4882a593Smuzhiyun * Main loop for information transfer phases. Wait for the 657*4882a593Smuzhiyun * target to assert REQ before checking MSG, C/D and I/O for 658*4882a593Smuzhiyun * the bus phase. 659*4882a593Smuzhiyun */ 660*4882a593Smuzhiyunmesgin_phasemis: 661*4882a593SmuzhiyunITloop: 662*4882a593Smuzhiyun call phase_lock; 663*4882a593Smuzhiyun 664*4882a593Smuzhiyun mov A, LASTPHASE; 665*4882a593Smuzhiyun 666*4882a593Smuzhiyun test A, ~P_DATAIN jz p_data; 667*4882a593Smuzhiyun cmp A,P_COMMAND je p_command; 668*4882a593Smuzhiyun cmp A,P_MESGOUT je p_mesgout; 669*4882a593Smuzhiyun cmp A,P_STATUS je p_status; 670*4882a593Smuzhiyun cmp A,P_MESGIN je p_mesgin; 671*4882a593Smuzhiyun 672*4882a593Smuzhiyun mvi BAD_PHASE call set_seqint; 673*4882a593Smuzhiyun jmp ITloop; /* Try reading the bus again. */ 674*4882a593Smuzhiyun 675*4882a593Smuzhiyunawait_busfree: 676*4882a593Smuzhiyun and SIMODE1, ~ENBUSFREE; 677*4882a593Smuzhiyun mov NONE, SCSIDATL; /* Ack the last byte */ 678*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 679*4882a593Smuzhiyun clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ 680*4882a593Smuzhiyun } 681*4882a593Smuzhiyun and SXFRCTL0, ~SPIOEN; 682*4882a593Smuzhiyun mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT; 683*4882a593Smuzhiyun test SSTAT1,REQINIT|BUSFREE jz .; 684*4882a593Smuzhiyun test SSTAT1, BUSFREE jnz poll_for_work; 685*4882a593Smuzhiyun mvi MISSED_BUSFREE call set_seqint; 686*4882a593Smuzhiyun} 687*4882a593Smuzhiyun 688*4882a593Smuzhiyunclear_target_state: 689*4882a593Smuzhiyun /* 690*4882a593Smuzhiyun * We assume that the kernel driver may reset us 691*4882a593Smuzhiyun * at any time, even in the middle of a DMA, so 692*4882a593Smuzhiyun * clear DFCNTRL too. 693*4882a593Smuzhiyun */ 694*4882a593Smuzhiyun clr DFCNTRL; 695*4882a593Smuzhiyun or SXFRCTL0, CLRSTCNT|CLRCHN; 696*4882a593Smuzhiyun 697*4882a593Smuzhiyun /* 698*4882a593Smuzhiyun * We don't know the target we will connect to, 699*4882a593Smuzhiyun * so default to narrow transfers to avoid 700*4882a593Smuzhiyun * parity problems. 701*4882a593Smuzhiyun */ 702*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 703*4882a593Smuzhiyun bmov SCSIRATE, ALLZEROS, 2; 704*4882a593Smuzhiyun } else { 705*4882a593Smuzhiyun clr SCSIRATE; 706*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA) != 0) { 707*4882a593Smuzhiyun and SXFRCTL0, ~(FAST20); 708*4882a593Smuzhiyun } 709*4882a593Smuzhiyun } 710*4882a593Smuzhiyun mvi LASTPHASE, P_BUSFREE; 711*4882a593Smuzhiyun /* clear target specific flags */ 712*4882a593Smuzhiyun mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret; 713*4882a593Smuzhiyun 714*4882a593Smuzhiyunsg_advance: 715*4882a593Smuzhiyun clr A; /* add sizeof(struct scatter) */ 716*4882a593Smuzhiyun add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; 717*4882a593Smuzhiyun adc SCB_RESIDUAL_SGPTR[1],A; 718*4882a593Smuzhiyun adc SCB_RESIDUAL_SGPTR[2],A; 719*4882a593Smuzhiyun adc SCB_RESIDUAL_SGPTR[3],A ret; 720*4882a593Smuzhiyun 721*4882a593Smuzhiyunif ((ahc->features & AHC_CMD_CHAN) != 0) { 722*4882a593Smuzhiyundisable_ccsgen: 723*4882a593Smuzhiyun test CCSGCTL, CCSGEN jz return; 724*4882a593Smuzhiyun test CCSGCTL, CCSGDONE jz .; 725*4882a593Smuzhiyundisable_ccsgen_fetch_done: 726*4882a593Smuzhiyun clr CCSGCTL; 727*4882a593Smuzhiyun test CCSGCTL, CCSGEN jnz .; 728*4882a593Smuzhiyun ret; 729*4882a593Smuzhiyunidle_loop: 730*4882a593Smuzhiyun /* 731*4882a593Smuzhiyun * Do we need any more segments for this transfer? 732*4882a593Smuzhiyun */ 733*4882a593Smuzhiyun test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; 734*4882a593Smuzhiyun 735*4882a593Smuzhiyun /* Did we just finish fetching segs? */ 736*4882a593Smuzhiyun cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; 737*4882a593Smuzhiyun 738*4882a593Smuzhiyun /* Are we actively fetching segments? */ 739*4882a593Smuzhiyun test CCSGCTL, CCSGEN jnz return; 740*4882a593Smuzhiyun 741*4882a593Smuzhiyun /* 742*4882a593Smuzhiyun * Do we have any prefetch left??? 743*4882a593Smuzhiyun */ 744*4882a593Smuzhiyun cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; 745*4882a593Smuzhiyun 746*4882a593Smuzhiyun /* 747*4882a593Smuzhiyun * Need to fetch segments, but we can only do that 748*4882a593Smuzhiyun * if the command channel is completely idle. Make 749*4882a593Smuzhiyun * sure we don't have an SCB prefetch going on. 750*4882a593Smuzhiyun */ 751*4882a593Smuzhiyun test CCSCBCTL, CCSCBEN jnz return; 752*4882a593Smuzhiyun 753*4882a593Smuzhiyun /* 754*4882a593Smuzhiyun * We fetch a "cacheline aligned" and sized amount of data 755*4882a593Smuzhiyun * so we don't end up referencing a non-existent page. 756*4882a593Smuzhiyun * Cacheline aligned is in quotes because the kernel will 757*4882a593Smuzhiyun * set the prefetch amount to a reasonable level if the 758*4882a593Smuzhiyun * cacheline size is unknown. 759*4882a593Smuzhiyun */ 760*4882a593Smuzhiyun mvi CCHCNT, SG_PREFETCH_CNT; 761*4882a593Smuzhiyun and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; 762*4882a593Smuzhiyun bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; 763*4882a593Smuzhiyun mvi CCSGCTL, CCSGEN|CCSGRESET ret; 764*4882a593Smuzhiyunidle_sgfetch_complete: 765*4882a593Smuzhiyun call disable_ccsgen_fetch_done; 766*4882a593Smuzhiyun and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; 767*4882a593Smuzhiyunidle_sg_avail: 768*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 769*4882a593Smuzhiyun /* Does the hardware have space for another SG entry? */ 770*4882a593Smuzhiyun test DFSTATUS, PRELOAD_AVAIL jz return; 771*4882a593Smuzhiyun bmov HADDR, CCSGRAM, 7; 772*4882a593Smuzhiyun bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; 773*4882a593Smuzhiyun if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 774*4882a593Smuzhiyun mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; 775*4882a593Smuzhiyun } 776*4882a593Smuzhiyun call sg_advance; 777*4882a593Smuzhiyun mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 778*4882a593Smuzhiyun test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 779*4882a593Smuzhiyun or SINDEX, LAST_SEG; 780*4882a593Smuzhiyun mov SG_CACHE_PRE, SINDEX; 781*4882a593Smuzhiyun /* Load the segment */ 782*4882a593Smuzhiyun or DFCNTRL, PRELOADEN; 783*4882a593Smuzhiyun } 784*4882a593Smuzhiyun ret; 785*4882a593Smuzhiyun} 786*4882a593Smuzhiyun 787*4882a593Smuzhiyunif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 788*4882a593Smuzhiyun/* 789*4882a593Smuzhiyun * Calculate the trailing portion of this S/G segment that cannot 790*4882a593Smuzhiyun * be transferred using memory write and invalidate PCI transactions. 791*4882a593Smuzhiyun * XXX Can we optimize this for PCI writes only??? 792*4882a593Smuzhiyun */ 793*4882a593Smuzhiyuncalc_mwi_residual: 794*4882a593Smuzhiyun /* 795*4882a593Smuzhiyun * If the ending address is on a cacheline boundary, 796*4882a593Smuzhiyun * there is no need for an extra segment. 797*4882a593Smuzhiyun */ 798*4882a593Smuzhiyun mov A, HCNT[0]; 799*4882a593Smuzhiyun add A, A, HADDR[0]; 800*4882a593Smuzhiyun and A, CACHESIZE_MASK; 801*4882a593Smuzhiyun test A, 0xFF jz return; 802*4882a593Smuzhiyun 803*4882a593Smuzhiyun /* 804*4882a593Smuzhiyun * If the transfer is less than a cachline, 805*4882a593Smuzhiyun * there is no need for an extra segment. 806*4882a593Smuzhiyun */ 807*4882a593Smuzhiyun test HCNT[1], 0xFF jnz calc_mwi_residual_final; 808*4882a593Smuzhiyun test HCNT[2], 0xFF jnz calc_mwi_residual_final; 809*4882a593Smuzhiyun add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; 810*4882a593Smuzhiyun jnc return; 811*4882a593Smuzhiyun 812*4882a593Smuzhiyuncalc_mwi_residual_final: 813*4882a593Smuzhiyun mov MWI_RESIDUAL, A; 814*4882a593Smuzhiyun not A; 815*4882a593Smuzhiyun inc A; 816*4882a593Smuzhiyun add HCNT[0], A; 817*4882a593Smuzhiyun adc HCNT[1], -1; 818*4882a593Smuzhiyun adc HCNT[2], -1 ret; 819*4882a593Smuzhiyun} 820*4882a593Smuzhiyun 821*4882a593Smuzhiyunp_data: 822*4882a593Smuzhiyun test SEQ_FLAGS,NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed; 823*4882a593Smuzhiyun mvi PROTO_VIOLATION call set_seqint; 824*4882a593Smuzhiyunp_data_allowed: 825*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 826*4882a593Smuzhiyun mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; 827*4882a593Smuzhiyun } else { 828*4882a593Smuzhiyun mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 829*4882a593Smuzhiyun } 830*4882a593Smuzhiyun test LASTPHASE, IOI jnz . + 2; 831*4882a593Smuzhiyun or DMAPARAMS, DIRECTION; 832*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 833*4882a593Smuzhiyun /* We don't have any valid S/G elements */ 834*4882a593Smuzhiyun mvi CCSGADDR, SG_PREFETCH_CNT; 835*4882a593Smuzhiyun } 836*4882a593Smuzhiyun test SEQ_FLAGS, DPHASE jz data_phase_initialize; 837*4882a593Smuzhiyun 838*4882a593Smuzhiyun /* 839*4882a593Smuzhiyun * If we re-enter the data phase after going through another 840*4882a593Smuzhiyun * phase, our transfer location has almost certainly been 841*4882a593Smuzhiyun * corrupted by the interveining, non-data, transfers. Ask 842*4882a593Smuzhiyun * the host driver to fix us up based on the transfer residual. 843*4882a593Smuzhiyun */ 844*4882a593Smuzhiyun mvi PDATA_REINIT call set_seqint; 845*4882a593Smuzhiyun jmp data_phase_loop; 846*4882a593Smuzhiyun 847*4882a593Smuzhiyundata_phase_initialize: 848*4882a593Smuzhiyun /* We have seen a data phase for the first time */ 849*4882a593Smuzhiyun or SEQ_FLAGS, DPHASE; 850*4882a593Smuzhiyun 851*4882a593Smuzhiyun /* 852*4882a593Smuzhiyun * Initialize the DMA address and counter from the SCB. 853*4882a593Smuzhiyun * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG 854*4882a593Smuzhiyun * flag in the highest byte of the data count. We cannot 855*4882a593Smuzhiyun * modify the saved values in the SCB until we see a save 856*4882a593Smuzhiyun * data pointers message. 857*4882a593Smuzhiyun */ 858*4882a593Smuzhiyun if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 859*4882a593Smuzhiyun /* The lowest address byte must be loaded last. */ 860*4882a593Smuzhiyun mov SCB_DATACNT[3] call set_hhaddr; 861*4882a593Smuzhiyun } 862*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 863*4882a593Smuzhiyun bmov HADDR, SCB_DATAPTR, 7; 864*4882a593Smuzhiyun bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; 865*4882a593Smuzhiyun } else { 866*4882a593Smuzhiyun mvi DINDEX, HADDR; 867*4882a593Smuzhiyun mvi SCB_DATAPTR call bcopy_7; 868*4882a593Smuzhiyun mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; 869*4882a593Smuzhiyun mvi SCB_DATACNT + 3 call bcopy_5; 870*4882a593Smuzhiyun } 871*4882a593Smuzhiyun if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 872*4882a593Smuzhiyun call calc_mwi_residual; 873*4882a593Smuzhiyun } 874*4882a593Smuzhiyun and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; 875*4882a593Smuzhiyun 876*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) == 0) { 877*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 878*4882a593Smuzhiyun bmov STCNT, HCNT, 3; 879*4882a593Smuzhiyun } else { 880*4882a593Smuzhiyun call set_stcnt_from_hcnt; 881*4882a593Smuzhiyun } 882*4882a593Smuzhiyun } 883*4882a593Smuzhiyun 884*4882a593Smuzhiyundata_phase_loop: 885*4882a593Smuzhiyun /* Guard against overruns */ 886*4882a593Smuzhiyun test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; 887*4882a593Smuzhiyun 888*4882a593Smuzhiyun /* 889*4882a593Smuzhiyun * Turn on `Bit Bucket' mode, wait until the target takes 890*4882a593Smuzhiyun * us to another phase, and then notify the host. 891*4882a593Smuzhiyun */ 892*4882a593Smuzhiyun and DMAPARAMS, DIRECTION; 893*4882a593Smuzhiyun mov DFCNTRL, DMAPARAMS; 894*4882a593Smuzhiyun or SXFRCTL1,BITBUCKET; 895*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 896*4882a593Smuzhiyun test SSTAT1,PHASEMIS jz .; 897*4882a593Smuzhiyun } else { 898*4882a593Smuzhiyun test SCSIPHASE, DATA_PHASE_MASK jnz .; 899*4882a593Smuzhiyun } 900*4882a593Smuzhiyun and SXFRCTL1, ~BITBUCKET; 901*4882a593Smuzhiyun mvi DATA_OVERRUN call set_seqint; 902*4882a593Smuzhiyun jmp ITloop; 903*4882a593Smuzhiyun 904*4882a593Smuzhiyundata_phase_inbounds: 905*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 906*4882a593Smuzhiyun mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 907*4882a593Smuzhiyun test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 908*4882a593Smuzhiyun or SINDEX, LAST_SEG; 909*4882a593Smuzhiyun mov SG_CACHE_PRE, SINDEX; 910*4882a593Smuzhiyun mov DFCNTRL, DMAPARAMS; 911*4882a593Smuzhiyunultra2_dma_loop: 912*4882a593Smuzhiyun call idle_loop; 913*4882a593Smuzhiyun /* 914*4882a593Smuzhiyun * The transfer is complete if either the last segment 915*4882a593Smuzhiyun * completes or the target changes phase. 916*4882a593Smuzhiyun */ 917*4882a593Smuzhiyun test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; 918*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 919*4882a593Smuzhiyun if ((ahc->flags & AHC_TARGETROLE) != 0) { 920*4882a593Smuzhiyun /* 921*4882a593Smuzhiyun * As a target, we control the phases, 922*4882a593Smuzhiyun * so ignore PHASEMIS. 923*4882a593Smuzhiyun */ 924*4882a593Smuzhiyun test SSTAT0, TARGET jnz ultra2_dma_loop; 925*4882a593Smuzhiyun } 926*4882a593Smuzhiyun if ((ahc->flags & AHC_INITIATORROLE) != 0) { 927*4882a593Smuzhiyun test SSTAT1,PHASEMIS jz ultra2_dma_loop; 928*4882a593Smuzhiyun } 929*4882a593Smuzhiyun } else { 930*4882a593Smuzhiyun test DFCNTRL, SCSIEN jnz ultra2_dma_loop; 931*4882a593Smuzhiyun } 932*4882a593Smuzhiyun 933*4882a593Smuzhiyunultra2_dmafinish: 934*4882a593Smuzhiyun /* 935*4882a593Smuzhiyun * The transfer has terminated either due to a phase 936*4882a593Smuzhiyun * change, and/or the completion of the last segment. 937*4882a593Smuzhiyun * We have two goals here. Do as much other work 938*4882a593Smuzhiyun * as possible while the data fifo drains on a read 939*4882a593Smuzhiyun * and respond as quickly as possible to the standard 940*4882a593Smuzhiyun * messages (save data pointers/disconnect and command 941*4882a593Smuzhiyun * complete) that usually follow a data phase. 942*4882a593Smuzhiyun */ 943*4882a593Smuzhiyun if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 944*4882a593Smuzhiyun /* 945*4882a593Smuzhiyun * On chips with broken auto-flush, start 946*4882a593Smuzhiyun * the flushing process now. We'll poke 947*4882a593Smuzhiyun * the chip from time to time to keep the 948*4882a593Smuzhiyun * flush process going as we complete the 949*4882a593Smuzhiyun * data phase. 950*4882a593Smuzhiyun */ 951*4882a593Smuzhiyun or DFCNTRL, FIFOFLUSH; 952*4882a593Smuzhiyun } 953*4882a593Smuzhiyun /* 954*4882a593Smuzhiyun * We assume that, even though data may still be 955*4882a593Smuzhiyun * transferring to the host, that the SCSI side of 956*4882a593Smuzhiyun * the DMA engine is now in a static state. This 957*4882a593Smuzhiyun * allows us to update our notion of where we are 958*4882a593Smuzhiyun * in this transfer. 959*4882a593Smuzhiyun * 960*4882a593Smuzhiyun * If, by chance, we stopped before being able 961*4882a593Smuzhiyun * to fetch additional segments for this transfer, 962*4882a593Smuzhiyun * yet the last S/G was completely exhausted, 963*4882a593Smuzhiyun * call our idle loop until it is able to load 964*4882a593Smuzhiyun * another segment. This will allow us to immediately 965*4882a593Smuzhiyun * pickup on the next segment on the next data phase. 966*4882a593Smuzhiyun * 967*4882a593Smuzhiyun * If we happened to stop on the last segment, then 968*4882a593Smuzhiyun * our residual information is still correct from 969*4882a593Smuzhiyun * the idle loop and there is no need to perform 970*4882a593Smuzhiyun * any fixups. 971*4882a593Smuzhiyun */ 972*4882a593Smuzhiyunultra2_ensure_sg: 973*4882a593Smuzhiyun test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; 974*4882a593Smuzhiyun /* Record if we've consumed all S/G entries */ 975*4882a593Smuzhiyun test SSTAT2, SHVALID jnz residuals_correct; 976*4882a593Smuzhiyun or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 977*4882a593Smuzhiyun jmp residuals_correct; 978*4882a593Smuzhiyun 979*4882a593Smuzhiyunultra2_shvalid: 980*4882a593Smuzhiyun test SSTAT2, SHVALID jnz sgptr_fixup; 981*4882a593Smuzhiyun call idle_loop; 982*4882a593Smuzhiyun jmp ultra2_ensure_sg; 983*4882a593Smuzhiyun 984*4882a593Smuzhiyunsgptr_fixup: 985*4882a593Smuzhiyun /* 986*4882a593Smuzhiyun * Fixup the residual next S/G pointer. The S/G preload 987*4882a593Smuzhiyun * feature of the chip allows us to load two elements 988*4882a593Smuzhiyun * in addition to the currently active element. We 989*4882a593Smuzhiyun * store the bottom byte of the next S/G pointer in 990*4882a593Smuzhiyun * the SG_CACEPTR register so we can restore the 991*4882a593Smuzhiyun * correct value when the DMA completes. If the next 992*4882a593Smuzhiyun * sg ptr value has advanced to the point where higher 993*4882a593Smuzhiyun * bytes in the address have been affected, fix them 994*4882a593Smuzhiyun * too. 995*4882a593Smuzhiyun */ 996*4882a593Smuzhiyun test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; 997*4882a593Smuzhiyun test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; 998*4882a593Smuzhiyun add SCB_RESIDUAL_SGPTR[1], -1; 999*4882a593Smuzhiyun adc SCB_RESIDUAL_SGPTR[2], -1; 1000*4882a593Smuzhiyun adc SCB_RESIDUAL_SGPTR[3], -1; 1001*4882a593Smuzhiyunsgptr_fixup_done: 1002*4882a593Smuzhiyun and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; 1003*4882a593Smuzhiyun /* We are not the last seg */ 1004*4882a593Smuzhiyun and SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG; 1005*4882a593Smuzhiyunresiduals_correct: 1006*4882a593Smuzhiyun /* 1007*4882a593Smuzhiyun * Go ahead and shut down the DMA engine now. 1008*4882a593Smuzhiyun * In the future, we'll want to handle end of 1009*4882a593Smuzhiyun * transfer messages prior to doing this, but this 1010*4882a593Smuzhiyun * requires similar restructuring for pre-ULTRA2 1011*4882a593Smuzhiyun * controllers. 1012*4882a593Smuzhiyun */ 1013*4882a593Smuzhiyun test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; 1014*4882a593Smuzhiyunultra2_fifoflush: 1015*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 1016*4882a593Smuzhiyun if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 1017*4882a593Smuzhiyun /* 1018*4882a593Smuzhiyun * On Rev A of the aic7890, the autoflush 1019*4882a593Smuzhiyun * feature doesn't function correctly. 1020*4882a593Smuzhiyun * Perform an explicit manual flush. During 1021*4882a593Smuzhiyun * a manual flush, the FIFOEMP bit becomes 1022*4882a593Smuzhiyun * true every time the PCI FIFO empties 1023*4882a593Smuzhiyun * regardless of the state of the SCSI FIFO. 1024*4882a593Smuzhiyun * It can take up to 4 clock cycles for the 1025*4882a593Smuzhiyun * SCSI FIFO to get data into the PCI FIFO 1026*4882a593Smuzhiyun * and for FIFOEMP to de-assert. Here we 1027*4882a593Smuzhiyun * guard against this condition by making 1028*4882a593Smuzhiyun * sure the FIFOEMP bit stays on for 5 full 1029*4882a593Smuzhiyun * clock cycles. 1030*4882a593Smuzhiyun */ 1031*4882a593Smuzhiyun or DFCNTRL, FIFOFLUSH; 1032*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 1033*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 1034*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 1035*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 1036*4882a593Smuzhiyun } 1037*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 1038*4882a593Smuzhiyun } else { 1039*4882a593Smuzhiyun /* 1040*4882a593Smuzhiyun * We enable the auto-ack feature on DT capable 1041*4882a593Smuzhiyun * controllers. This means that the controller may 1042*4882a593Smuzhiyun * have already transferred some overrun bytes into 1043*4882a593Smuzhiyun * the data FIFO and acked them on the bus. The only 1044*4882a593Smuzhiyun * way to detect this situation is to wait for 1045*4882a593Smuzhiyun * LAST_SEG_DONE to come true on a completed transfer 1046*4882a593Smuzhiyun * and then test to see if the data FIFO is non-empty. 1047*4882a593Smuzhiyun */ 1048*4882a593Smuzhiyun test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL 1049*4882a593Smuzhiyun jz ultra2_wait_fifoemp; 1050*4882a593Smuzhiyun test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; 1051*4882a593Smuzhiyun /* 1052*4882a593Smuzhiyun * FIFOEMP can lag LAST_SEG_DONE. Wait a few 1053*4882a593Smuzhiyun * clocks before calling this an overrun. 1054*4882a593Smuzhiyun */ 1055*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; 1056*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; 1057*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; 1058*4882a593Smuzhiyun /* Overrun */ 1059*4882a593Smuzhiyun jmp data_phase_loop; 1060*4882a593Smuzhiyunultra2_wait_fifoemp: 1061*4882a593Smuzhiyun test DFSTATUS, FIFOEMP jz .; 1062*4882a593Smuzhiyun } 1063*4882a593Smuzhiyunultra2_fifoempty: 1064*4882a593Smuzhiyun /* Don't clobber an inprogress host data transfer */ 1065*4882a593Smuzhiyun test DFSTATUS, MREQPEND jnz ultra2_fifoempty; 1066*4882a593Smuzhiyunultra2_dmahalt: 1067*4882a593Smuzhiyun and DFCNTRL, ~(SCSIEN|HDMAEN); 1068*4882a593Smuzhiyun test DFCNTRL, SCSIEN|HDMAEN jnz .; 1069*4882a593Smuzhiyun if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 1070*4882a593Smuzhiyun /* 1071*4882a593Smuzhiyun * Keep HHADDR cleared for future, 32bit addressed 1072*4882a593Smuzhiyun * only, DMA operations. 1073*4882a593Smuzhiyun * 1074*4882a593Smuzhiyun * Due to bayonette style S/G handling, our residual 1075*4882a593Smuzhiyun * data must be "fixed up" once the transfer is halted. 1076*4882a593Smuzhiyun * Here we fixup the HSHADDR stored in the high byte 1077*4882a593Smuzhiyun * of the residual data cnt. By postponing the fixup, 1078*4882a593Smuzhiyun * we can batch the clearing of HADDR with the fixup. 1079*4882a593Smuzhiyun * If we halted on the last segment, the residual is 1080*4882a593Smuzhiyun * already correct. If we are not on the last 1081*4882a593Smuzhiyun * segment, copy the high address directly from HSHADDR. 1082*4882a593Smuzhiyun * We don't need to worry about maintaining the 1083*4882a593Smuzhiyun * SG_LAST_SEG flag as it will always be false in the 1084*4882a593Smuzhiyun * case where an update is required. 1085*4882a593Smuzhiyun */ 1086*4882a593Smuzhiyun or DSCOMMAND1, HADDLDSEL0; 1087*4882a593Smuzhiyun test SG_CACHE_SHADOW, LAST_SEG jnz . + 2; 1088*4882a593Smuzhiyun mov SCB_RESIDUAL_DATACNT[3], SHADDR; 1089*4882a593Smuzhiyun clr HADDR; 1090*4882a593Smuzhiyun and DSCOMMAND1, ~HADDLDSEL0; 1091*4882a593Smuzhiyun } 1092*4882a593Smuzhiyun } else { 1093*4882a593Smuzhiyun /* If we are the last SG block, tell the hardware. */ 1094*4882a593Smuzhiyun if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 1095*4882a593Smuzhiyun && ahc->pci_cachesize != 0) { 1096*4882a593Smuzhiyun test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; 1097*4882a593Smuzhiyun } 1098*4882a593Smuzhiyun test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; 1099*4882a593Smuzhiyun if ((ahc->flags & AHC_TARGETROLE) != 0) { 1100*4882a593Smuzhiyun test SSTAT0, TARGET jz dma_last_sg; 1101*4882a593Smuzhiyun if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) { 1102*4882a593Smuzhiyun test DMAPARAMS, DIRECTION jz dma_mid_sg; 1103*4882a593Smuzhiyun } 1104*4882a593Smuzhiyun } 1105*4882a593Smuzhiyundma_last_sg: 1106*4882a593Smuzhiyun and DMAPARAMS, ~WIDEODD; 1107*4882a593Smuzhiyundma_mid_sg: 1108*4882a593Smuzhiyun /* Start DMA data transfer. */ 1109*4882a593Smuzhiyun mov DFCNTRL, DMAPARAMS; 1110*4882a593Smuzhiyundma_loop: 1111*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1112*4882a593Smuzhiyun call idle_loop; 1113*4882a593Smuzhiyun } 1114*4882a593Smuzhiyun test SSTAT0,DMADONE jnz dma_dmadone; 1115*4882a593Smuzhiyun test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 1116*4882a593Smuzhiyundma_phasemis: 1117*4882a593Smuzhiyun /* 1118*4882a593Smuzhiyun * We will be "done" DMAing when the transfer count goes to 1119*4882a593Smuzhiyun * zero, or the target changes the phase (in light of this, 1120*4882a593Smuzhiyun * it makes sense that the DMA circuitry doesn't ACK when 1121*4882a593Smuzhiyun * PHASEMIS is active). If we are doing a SCSI->Host transfer, 1122*4882a593Smuzhiyun * the data FIFO should be flushed auto-magically on STCNT=0 1123*4882a593Smuzhiyun * or a phase change, so just wait for FIFO empty status. 1124*4882a593Smuzhiyun */ 1125*4882a593Smuzhiyundma_checkfifo: 1126*4882a593Smuzhiyun test DFCNTRL,DIRECTION jnz dma_fifoempty; 1127*4882a593Smuzhiyundma_fifoflush: 1128*4882a593Smuzhiyun test DFSTATUS,FIFOEMP jz dma_fifoflush; 1129*4882a593Smuzhiyundma_fifoempty: 1130*4882a593Smuzhiyun /* Don't clobber an inprogress host data transfer */ 1131*4882a593Smuzhiyun test DFSTATUS, MREQPEND jnz dma_fifoempty; 1132*4882a593Smuzhiyun 1133*4882a593Smuzhiyun /* 1134*4882a593Smuzhiyun * Now shut off the DMA and make sure that the DMA 1135*4882a593Smuzhiyun * hardware has actually stopped. Touching the DMA 1136*4882a593Smuzhiyun * counters, etc. while a DMA is active will result 1137*4882a593Smuzhiyun * in an ILLSADDR exception. 1138*4882a593Smuzhiyun */ 1139*4882a593Smuzhiyundma_dmadone: 1140*4882a593Smuzhiyun and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 1141*4882a593Smuzhiyundma_halt: 1142*4882a593Smuzhiyun /* 1143*4882a593Smuzhiyun * Some revisions of the aic78XX have a problem where, if the 1144*4882a593Smuzhiyun * data fifo is full, but the PCI input latch is not empty, 1145*4882a593Smuzhiyun * HDMAEN cannot be cleared. The fix used here is to drain 1146*4882a593Smuzhiyun * the prefetched but unused data from the data fifo until 1147*4882a593Smuzhiyun * there is space for the input latch to drain. 1148*4882a593Smuzhiyun */ 1149*4882a593Smuzhiyun if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 1150*4882a593Smuzhiyun mov NONE, DFDAT; 1151*4882a593Smuzhiyun } 1152*4882a593Smuzhiyun test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 1153*4882a593Smuzhiyun 1154*4882a593Smuzhiyun /* See if we have completed this last segment */ 1155*4882a593Smuzhiyun test STCNT[0], 0xff jnz data_phase_finish; 1156*4882a593Smuzhiyun test STCNT[1], 0xff jnz data_phase_finish; 1157*4882a593Smuzhiyun test STCNT[2], 0xff jnz data_phase_finish; 1158*4882a593Smuzhiyun 1159*4882a593Smuzhiyun /* 1160*4882a593Smuzhiyun * Advance the scatter-gather pointers if needed 1161*4882a593Smuzhiyun */ 1162*4882a593Smuzhiyun if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 1163*4882a593Smuzhiyun && ahc->pci_cachesize != 0) { 1164*4882a593Smuzhiyun test MWI_RESIDUAL, 0xFF jz no_mwi_resid; 1165*4882a593Smuzhiyun /* 1166*4882a593Smuzhiyun * Reload HADDR from SHADDR and setup the 1167*4882a593Smuzhiyun * count to be the size of our residual. 1168*4882a593Smuzhiyun */ 1169*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1170*4882a593Smuzhiyun bmov HADDR, SHADDR, 4; 1171*4882a593Smuzhiyun mov HCNT, MWI_RESIDUAL; 1172*4882a593Smuzhiyun bmov HCNT[1], ALLZEROS, 2; 1173*4882a593Smuzhiyun } else { 1174*4882a593Smuzhiyun mvi DINDEX, HADDR; 1175*4882a593Smuzhiyun mvi SHADDR call bcopy_4; 1176*4882a593Smuzhiyun mov MWI_RESIDUAL call set_hcnt; 1177*4882a593Smuzhiyun } 1178*4882a593Smuzhiyun clr MWI_RESIDUAL; 1179*4882a593Smuzhiyun jmp sg_load_done; 1180*4882a593Smuzhiyunno_mwi_resid: 1181*4882a593Smuzhiyun } 1182*4882a593Smuzhiyun test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; 1183*4882a593Smuzhiyun or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 1184*4882a593Smuzhiyun jmp data_phase_finish; 1185*4882a593Smuzhiyunsg_load: 1186*4882a593Smuzhiyun /* 1187*4882a593Smuzhiyun * Load the next SG element's data address and length 1188*4882a593Smuzhiyun * into the DMA engine. If we don't have hardware 1189*4882a593Smuzhiyun * to perform a prefetch, we'll have to fetch the 1190*4882a593Smuzhiyun * segment from host memory first. 1191*4882a593Smuzhiyun */ 1192*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1193*4882a593Smuzhiyun /* Wait for the idle loop to complete */ 1194*4882a593Smuzhiyun test CCSGCTL, CCSGEN jz . + 3; 1195*4882a593Smuzhiyun call idle_loop; 1196*4882a593Smuzhiyun test CCSGCTL, CCSGEN jnz . - 1; 1197*4882a593Smuzhiyun bmov HADDR, CCSGRAM, 7; 1198*4882a593Smuzhiyun /* 1199*4882a593Smuzhiyun * Workaround for flaky external SCB RAM 1200*4882a593Smuzhiyun * on certain aic7895 setups. It seems 1201*4882a593Smuzhiyun * unable to handle direct transfers from 1202*4882a593Smuzhiyun * S/G ram to certain SCB locations. 1203*4882a593Smuzhiyun */ 1204*4882a593Smuzhiyun mov SINDEX, CCSGRAM; 1205*4882a593Smuzhiyun mov SCB_RESIDUAL_DATACNT[3], SINDEX; 1206*4882a593Smuzhiyun } else { 1207*4882a593Smuzhiyun if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 1208*4882a593Smuzhiyun mov ALLZEROS call set_hhaddr; 1209*4882a593Smuzhiyun } 1210*4882a593Smuzhiyun mvi DINDEX, HADDR; 1211*4882a593Smuzhiyun mvi SCB_RESIDUAL_SGPTR call bcopy_4; 1212*4882a593Smuzhiyun 1213*4882a593Smuzhiyun mvi SG_SIZEOF call set_hcnt; 1214*4882a593Smuzhiyun 1215*4882a593Smuzhiyun or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 1216*4882a593Smuzhiyun 1217*4882a593Smuzhiyun call dma_finish; 1218*4882a593Smuzhiyun 1219*4882a593Smuzhiyun mvi DINDEX, HADDR; 1220*4882a593Smuzhiyun call dfdat_in_7; 1221*4882a593Smuzhiyun mov SCB_RESIDUAL_DATACNT[3], DFDAT; 1222*4882a593Smuzhiyun } 1223*4882a593Smuzhiyun 1224*4882a593Smuzhiyun if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 1225*4882a593Smuzhiyun mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; 1226*4882a593Smuzhiyun 1227*4882a593Smuzhiyun /* 1228*4882a593Smuzhiyun * The lowest address byte must be loaded 1229*4882a593Smuzhiyun * last as it triggers the computation of 1230*4882a593Smuzhiyun * some items in the PCI block. The ULTRA2 1231*4882a593Smuzhiyun * chips do this on PRELOAD. 1232*4882a593Smuzhiyun */ 1233*4882a593Smuzhiyun mov HADDR, HADDR; 1234*4882a593Smuzhiyun } 1235*4882a593Smuzhiyun if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 1236*4882a593Smuzhiyun && ahc->pci_cachesize != 0) { 1237*4882a593Smuzhiyun call calc_mwi_residual; 1238*4882a593Smuzhiyun } 1239*4882a593Smuzhiyun 1240*4882a593Smuzhiyun /* Point to the new next sg in memory */ 1241*4882a593Smuzhiyun call sg_advance; 1242*4882a593Smuzhiyun 1243*4882a593Smuzhiyunsg_load_done: 1244*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1245*4882a593Smuzhiyun bmov STCNT, HCNT, 3; 1246*4882a593Smuzhiyun } else { 1247*4882a593Smuzhiyun call set_stcnt_from_hcnt; 1248*4882a593Smuzhiyun } 1249*4882a593Smuzhiyun 1250*4882a593Smuzhiyun if ((ahc->flags & AHC_TARGETROLE) != 0) { 1251*4882a593Smuzhiyun test SSTAT0, TARGET jnz data_phase_loop; 1252*4882a593Smuzhiyun } 1253*4882a593Smuzhiyun } 1254*4882a593Smuzhiyundata_phase_finish: 1255*4882a593Smuzhiyun /* 1256*4882a593Smuzhiyun * If the target has left us in data phase, loop through 1257*4882a593Smuzhiyun * the dma code again. In the case of ULTRA2 adapters, 1258*4882a593Smuzhiyun * we should only loop if there is a data overrun. For 1259*4882a593Smuzhiyun * all other adapters, we'll loop after each S/G element 1260*4882a593Smuzhiyun * is loaded as well as if there is an overrun. 1261*4882a593Smuzhiyun */ 1262*4882a593Smuzhiyun if ((ahc->flags & AHC_TARGETROLE) != 0) { 1263*4882a593Smuzhiyun test SSTAT0, TARGET jnz data_phase_done; 1264*4882a593Smuzhiyun } 1265*4882a593Smuzhiyun if ((ahc->flags & AHC_INITIATORROLE) != 0) { 1266*4882a593Smuzhiyun test SSTAT1, REQINIT jz .; 1267*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 1268*4882a593Smuzhiyun test SSTAT1,PHASEMIS jz data_phase_loop; 1269*4882a593Smuzhiyun } else { 1270*4882a593Smuzhiyun test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; 1271*4882a593Smuzhiyun } 1272*4882a593Smuzhiyun } 1273*4882a593Smuzhiyun 1274*4882a593Smuzhiyundata_phase_done: 1275*4882a593Smuzhiyun /* 1276*4882a593Smuzhiyun * After a DMA finishes, save the SG and STCNT residuals back into 1277*4882a593Smuzhiyun * the SCB. We use STCNT instead of HCNT, since it's a reflection 1278*4882a593Smuzhiyun * of how many bytes were transferred on the SCSI (as opposed to the 1279*4882a593Smuzhiyun * host) bus. 1280*4882a593Smuzhiyun */ 1281*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1282*4882a593Smuzhiyun /* Kill off any pending prefetch */ 1283*4882a593Smuzhiyun call disable_ccsgen; 1284*4882a593Smuzhiyun } 1285*4882a593Smuzhiyun 1286*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) == 0) { 1287*4882a593Smuzhiyun /* 1288*4882a593Smuzhiyun * Clear the high address byte so that all other DMA 1289*4882a593Smuzhiyun * operations, which use 32bit addressing, can assume 1290*4882a593Smuzhiyun * HHADDR is 0. 1291*4882a593Smuzhiyun */ 1292*4882a593Smuzhiyun if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 1293*4882a593Smuzhiyun mov ALLZEROS call set_hhaddr; 1294*4882a593Smuzhiyun } 1295*4882a593Smuzhiyun } 1296*4882a593Smuzhiyun 1297*4882a593Smuzhiyun /* 1298*4882a593Smuzhiyun * Update our residual information before the information is 1299*4882a593Smuzhiyun * lost by some other type of SCSI I/O (e.g. PIO). If we have 1300*4882a593Smuzhiyun * transferred all data, no update is needed. 1301*4882a593Smuzhiyun * 1302*4882a593Smuzhiyun */ 1303*4882a593Smuzhiyun test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done; 1304*4882a593Smuzhiyun if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 1305*4882a593Smuzhiyun && ahc->pci_cachesize != 0) { 1306*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1307*4882a593Smuzhiyun test MWI_RESIDUAL, 0xFF jz bmov_resid; 1308*4882a593Smuzhiyun } 1309*4882a593Smuzhiyun mov A, MWI_RESIDUAL; 1310*4882a593Smuzhiyun add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; 1311*4882a593Smuzhiyun clr A; 1312*4882a593Smuzhiyun adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; 1313*4882a593Smuzhiyun adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; 1314*4882a593Smuzhiyun clr MWI_RESIDUAL; 1315*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1316*4882a593Smuzhiyun jmp . + 2; 1317*4882a593Smuzhiyunbmov_resid: 1318*4882a593Smuzhiyun bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 1319*4882a593Smuzhiyun } 1320*4882a593Smuzhiyun } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 1321*4882a593Smuzhiyun bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 1322*4882a593Smuzhiyun } else { 1323*4882a593Smuzhiyun mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; 1324*4882a593Smuzhiyun mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; 1325*4882a593Smuzhiyun mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; 1326*4882a593Smuzhiyun } 1327*4882a593Smuzhiyunresidual_update_done: 1328*4882a593Smuzhiyun /* 1329*4882a593Smuzhiyun * Since we've been through a data phase, the SCB_RESID* fields 1330*4882a593Smuzhiyun * are now initialized. Clear the full residual flag. 1331*4882a593Smuzhiyun */ 1332*4882a593Smuzhiyun and SCB_SGPTR[0], ~SG_FULL_RESID; 1333*4882a593Smuzhiyun 1334*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 1335*4882a593Smuzhiyun /* Clear the channel in case we return to data phase later */ 1336*4882a593Smuzhiyun or SXFRCTL0, CLRSTCNT|CLRCHN; 1337*4882a593Smuzhiyun or SXFRCTL0, CLRSTCNT|CLRCHN; 1338*4882a593Smuzhiyun } 1339*4882a593Smuzhiyun 1340*4882a593Smuzhiyun if ((ahc->flags & AHC_TARGETROLE) != 0) { 1341*4882a593Smuzhiyun test SEQ_FLAGS, DPHASE_PENDING jz ITloop; 1342*4882a593Smuzhiyun and SEQ_FLAGS, ~DPHASE_PENDING; 1343*4882a593Smuzhiyun /* 1344*4882a593Smuzhiyun * For data-in phases, wait for any pending acks from the 1345*4882a593Smuzhiyun * initiator before changing phase. We only need to 1346*4882a593Smuzhiyun * send Ignore Wide Residue messages for data-in phases. 1347*4882a593Smuzhiyun */ 1348*4882a593Smuzhiyun test DFCNTRL, DIRECTION jz target_ITloop; 1349*4882a593Smuzhiyun test SSTAT1, REQINIT jnz .; 1350*4882a593Smuzhiyun test SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop; 1351*4882a593Smuzhiyun test SCSIRATE, WIDEXFER jz target_ITloop; 1352*4882a593Smuzhiyun /* 1353*4882a593Smuzhiyun * Issue an Ignore Wide Residue Message. 1354*4882a593Smuzhiyun */ 1355*4882a593Smuzhiyun mvi P_MESGIN|BSYO call change_phase; 1356*4882a593Smuzhiyun mvi MSG_IGN_WIDE_RESIDUE call target_outb; 1357*4882a593Smuzhiyun mvi 1 call target_outb; 1358*4882a593Smuzhiyun jmp target_ITloop; 1359*4882a593Smuzhiyun } else { 1360*4882a593Smuzhiyun jmp ITloop; 1361*4882a593Smuzhiyun } 1362*4882a593Smuzhiyun 1363*4882a593Smuzhiyunif ((ahc->flags & AHC_INITIATORROLE) != 0) { 1364*4882a593Smuzhiyun/* 1365*4882a593Smuzhiyun * Command phase. Set up the DMA registers and let 'er rip. 1366*4882a593Smuzhiyun */ 1367*4882a593Smuzhiyunp_command: 1368*4882a593Smuzhiyun test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay; 1369*4882a593Smuzhiyun mvi PROTO_VIOLATION call set_seqint; 1370*4882a593Smuzhiyunp_command_okay: 1371*4882a593Smuzhiyun 1372*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 1373*4882a593Smuzhiyun bmov HCNT[0], SCB_CDB_LEN, 1; 1374*4882a593Smuzhiyun bmov HCNT[1], ALLZEROS, 2; 1375*4882a593Smuzhiyun mvi SG_CACHE_PRE, LAST_SEG; 1376*4882a593Smuzhiyun } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 1377*4882a593Smuzhiyun bmov STCNT[0], SCB_CDB_LEN, 1; 1378*4882a593Smuzhiyun bmov STCNT[1], ALLZEROS, 2; 1379*4882a593Smuzhiyun } else { 1380*4882a593Smuzhiyun mov STCNT[0], SCB_CDB_LEN; 1381*4882a593Smuzhiyun clr STCNT[1]; 1382*4882a593Smuzhiyun clr STCNT[2]; 1383*4882a593Smuzhiyun } 1384*4882a593Smuzhiyun add NONE, -13, SCB_CDB_LEN; 1385*4882a593Smuzhiyun mvi SCB_CDB_STORE jnc p_command_embedded; 1386*4882a593Smuzhiyunp_command_from_host: 1387*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 1388*4882a593Smuzhiyun bmov HADDR[0], SCB_CDB_PTR, 4; 1389*4882a593Smuzhiyun mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); 1390*4882a593Smuzhiyun } else { 1391*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1392*4882a593Smuzhiyun bmov HADDR[0], SCB_CDB_PTR, 4; 1393*4882a593Smuzhiyun bmov HCNT, STCNT, 3; 1394*4882a593Smuzhiyun } else { 1395*4882a593Smuzhiyun mvi DINDEX, HADDR; 1396*4882a593Smuzhiyun mvi SCB_CDB_PTR call bcopy_4; 1397*4882a593Smuzhiyun mov SCB_CDB_LEN call set_hcnt; 1398*4882a593Smuzhiyun } 1399*4882a593Smuzhiyun mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); 1400*4882a593Smuzhiyun } 1401*4882a593Smuzhiyun jmp p_command_xfer; 1402*4882a593Smuzhiyunp_command_embedded: 1403*4882a593Smuzhiyun /* 1404*4882a593Smuzhiyun * The data fifo seems to require 4 byte aligned 1405*4882a593Smuzhiyun * transfers from the sequencer. Force this to 1406*4882a593Smuzhiyun * be the case by clearing HADDR[0] even though 1407*4882a593Smuzhiyun * we aren't going to touch host memory. 1408*4882a593Smuzhiyun */ 1409*4882a593Smuzhiyun clr HADDR[0]; 1410*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 1411*4882a593Smuzhiyun mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); 1412*4882a593Smuzhiyun bmov DFDAT, SCB_CDB_STORE, 12; 1413*4882a593Smuzhiyun } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 1414*4882a593Smuzhiyun if ((ahc->flags & AHC_SCB_BTT) != 0) { 1415*4882a593Smuzhiyun /* 1416*4882a593Smuzhiyun * On the 7895 the data FIFO will 1417*4882a593Smuzhiyun * get corrupted if you try to dump 1418*4882a593Smuzhiyun * data from external SCB memory into 1419*4882a593Smuzhiyun * the FIFO while it is enabled. So, 1420*4882a593Smuzhiyun * fill the fifo and then enable SCSI 1421*4882a593Smuzhiyun * transfers. 1422*4882a593Smuzhiyun */ 1423*4882a593Smuzhiyun mvi DFCNTRL, (DIRECTION|FIFORESET); 1424*4882a593Smuzhiyun } else { 1425*4882a593Smuzhiyun mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 1426*4882a593Smuzhiyun } 1427*4882a593Smuzhiyun bmov DFDAT, SCB_CDB_STORE, 12; 1428*4882a593Smuzhiyun if ((ahc->flags & AHC_SCB_BTT) != 0) { 1429*4882a593Smuzhiyun mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); 1430*4882a593Smuzhiyun } else { 1431*4882a593Smuzhiyun or DFCNTRL, FIFOFLUSH; 1432*4882a593Smuzhiyun } 1433*4882a593Smuzhiyun } else { 1434*4882a593Smuzhiyun mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 1435*4882a593Smuzhiyun call copy_to_fifo_6; 1436*4882a593Smuzhiyun call copy_to_fifo_6; 1437*4882a593Smuzhiyun or DFCNTRL, FIFOFLUSH; 1438*4882a593Smuzhiyun } 1439*4882a593Smuzhiyunp_command_xfer: 1440*4882a593Smuzhiyun and SEQ_FLAGS, ~NO_CDB_SENT; 1441*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 1442*4882a593Smuzhiyun test SSTAT0, SDONE jnz . + 2; 1443*4882a593Smuzhiyun test SSTAT1, PHASEMIS jz . - 1; 1444*4882a593Smuzhiyun /* 1445*4882a593Smuzhiyun * Wait for our ACK to go-away on it's own 1446*4882a593Smuzhiyun * instead of being killed by SCSIEN getting cleared. 1447*4882a593Smuzhiyun */ 1448*4882a593Smuzhiyun test SCSISIGI, ACKI jnz .; 1449*4882a593Smuzhiyun } else { 1450*4882a593Smuzhiyun test DFCNTRL, SCSIEN jnz .; 1451*4882a593Smuzhiyun } 1452*4882a593Smuzhiyun test SSTAT0, SDONE jnz p_command_successful; 1453*4882a593Smuzhiyun /* 1454*4882a593Smuzhiyun * Don't allow a data phase if the command 1455*4882a593Smuzhiyun * was not fully transferred. 1456*4882a593Smuzhiyun */ 1457*4882a593Smuzhiyun or SEQ_FLAGS, NO_CDB_SENT; 1458*4882a593Smuzhiyunp_command_successful: 1459*4882a593Smuzhiyun and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 1460*4882a593Smuzhiyun test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; 1461*4882a593Smuzhiyun jmp ITloop; 1462*4882a593Smuzhiyun 1463*4882a593Smuzhiyun/* 1464*4882a593Smuzhiyun * Status phase. Wait for the data byte to appear, then read it 1465*4882a593Smuzhiyun * and store it into the SCB. 1466*4882a593Smuzhiyun */ 1467*4882a593Smuzhiyunp_status: 1468*4882a593Smuzhiyun test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; 1469*4882a593Smuzhiyunp_status_okay: 1470*4882a593Smuzhiyun mov SCB_SCSI_STATUS, SCSIDATL; 1471*4882a593Smuzhiyun or SCB_CONTROL, STATUS_RCVD; 1472*4882a593Smuzhiyun jmp ITloop; 1473*4882a593Smuzhiyun 1474*4882a593Smuzhiyun/* 1475*4882a593Smuzhiyun * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full 1476*4882a593Smuzhiyun * indentify message sequence and send it to the target. The host may 1477*4882a593Smuzhiyun * override this behavior by setting the MK_MESSAGE bit in the SCB 1478*4882a593Smuzhiyun * control byte. This will cause us to interrupt the host and allow 1479*4882a593Smuzhiyun * it to handle the message phase completely on its own. If the bit 1480*4882a593Smuzhiyun * associated with this target is set, we will also interrupt the host, 1481*4882a593Smuzhiyun * thereby allowing it to send a message on the next selection regardless 1482*4882a593Smuzhiyun * of the transaction being sent. 1483*4882a593Smuzhiyun * 1484*4882a593Smuzhiyun * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. 1485*4882a593Smuzhiyun * This is done to allow the host to send messages outside of an identify 1486*4882a593Smuzhiyun * sequence while protecting the seqencer from testing the MK_MESSAGE bit 1487*4882a593Smuzhiyun * on an SCB that might not be for the current nexus. (For example, a 1488*4882a593Smuzhiyun * BDR message in response to a bad reselection would leave us pointed to 1489*4882a593Smuzhiyun * an SCB that doesn't have anything to do with the current target). 1490*4882a593Smuzhiyun * 1491*4882a593Smuzhiyun * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, 1492*4882a593Smuzhiyun * bus device reset). 1493*4882a593Smuzhiyun * 1494*4882a593Smuzhiyun * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, 1495*4882a593Smuzhiyun * in case the target decides to put us in this phase for some strange 1496*4882a593Smuzhiyun * reason. 1497*4882a593Smuzhiyun */ 1498*4882a593Smuzhiyunp_mesgout_retry: 1499*4882a593Smuzhiyun /* Turn on ATN for the retry */ 1500*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 1501*4882a593Smuzhiyun or SCSISIGO, ATNO, LASTPHASE; 1502*4882a593Smuzhiyun } else { 1503*4882a593Smuzhiyun mvi SCSISIGO, ATNO; 1504*4882a593Smuzhiyun } 1505*4882a593Smuzhiyunp_mesgout: 1506*4882a593Smuzhiyun mov SINDEX, MSG_OUT; 1507*4882a593Smuzhiyun cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; 1508*4882a593Smuzhiyun test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; 1509*4882a593Smuzhiyunp_mesgout_identify: 1510*4882a593Smuzhiyun or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN; 1511*4882a593Smuzhiyun test SCB_CONTROL, DISCENB jnz . + 2; 1512*4882a593Smuzhiyun and SINDEX, ~DISCENB; 1513*4882a593Smuzhiyun/* 1514*4882a593Smuzhiyun * Send a tag message if TAG_ENB is set in the SCB control block. 1515*4882a593Smuzhiyun * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 1516*4882a593Smuzhiyun */ 1517*4882a593Smuzhiyunp_mesgout_tag: 1518*4882a593Smuzhiyun test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; 1519*4882a593Smuzhiyun mov SCSIDATL, SINDEX; /* Send the identify message */ 1520*4882a593Smuzhiyun call phase_lock; 1521*4882a593Smuzhiyun cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 1522*4882a593Smuzhiyun and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 1523*4882a593Smuzhiyun call phase_lock; 1524*4882a593Smuzhiyun cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 1525*4882a593Smuzhiyun mov SCB_TAG jmp p_mesgout_onebyte; 1526*4882a593Smuzhiyun/* 1527*4882a593Smuzhiyun * Interrupt the driver, and allow it to handle this message 1528*4882a593Smuzhiyun * phase and any required retries. 1529*4882a593Smuzhiyun */ 1530*4882a593Smuzhiyunp_mesgout_from_host: 1531*4882a593Smuzhiyun cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; 1532*4882a593Smuzhiyun jmp host_message_loop; 1533*4882a593Smuzhiyun 1534*4882a593Smuzhiyunp_mesgout_onebyte: 1535*4882a593Smuzhiyun mvi CLRSINT1, CLRATNO; 1536*4882a593Smuzhiyun mov SCSIDATL, SINDEX; 1537*4882a593Smuzhiyun 1538*4882a593Smuzhiyun/* 1539*4882a593Smuzhiyun * If the next bus phase after ATN drops is message out, it means 1540*4882a593Smuzhiyun * that the target is requesting that the last message(s) be resent. 1541*4882a593Smuzhiyun */ 1542*4882a593Smuzhiyun call phase_lock; 1543*4882a593Smuzhiyun cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; 1544*4882a593Smuzhiyun 1545*4882a593Smuzhiyunp_mesgout_done: 1546*4882a593Smuzhiyun mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 1547*4882a593Smuzhiyun mov LAST_MSG, MSG_OUT; 1548*4882a593Smuzhiyun mvi MSG_OUT, MSG_NOOP; /* No message left */ 1549*4882a593Smuzhiyun jmp ITloop; 1550*4882a593Smuzhiyun 1551*4882a593Smuzhiyun/* 1552*4882a593Smuzhiyun * Message in phase. Bytes are read using Automatic PIO mode. 1553*4882a593Smuzhiyun */ 1554*4882a593Smuzhiyunp_mesgin: 1555*4882a593Smuzhiyun mvi ACCUM call inb_first; /* read the 1st message byte */ 1556*4882a593Smuzhiyun 1557*4882a593Smuzhiyun test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 1558*4882a593Smuzhiyun cmp A,MSG_DISCONNECT je mesgin_disconnect; 1559*4882a593Smuzhiyun cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 1560*4882a593Smuzhiyun cmp ALLZEROS,A je mesgin_complete; 1561*4882a593Smuzhiyun cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 1562*4882a593Smuzhiyun cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; 1563*4882a593Smuzhiyun cmp A,MSG_NOOP je mesgin_done; 1564*4882a593Smuzhiyun 1565*4882a593Smuzhiyun/* 1566*4882a593Smuzhiyun * Pushed message loop to allow the kernel to 1567*4882a593Smuzhiyun * run it's own message state engine. To avoid an 1568*4882a593Smuzhiyun * extra nop instruction after signaling the kernel, 1569*4882a593Smuzhiyun * we perform the phase_lock before checking to see 1570*4882a593Smuzhiyun * if we should exit the loop and skip the phase_lock 1571*4882a593Smuzhiyun * in the ITloop. Performing back to back phase_locks 1572*4882a593Smuzhiyun * shouldn't hurt, but why do it twice... 1573*4882a593Smuzhiyun */ 1574*4882a593Smuzhiyunhost_message_loop: 1575*4882a593Smuzhiyun mvi HOST_MSG_LOOP call set_seqint; 1576*4882a593Smuzhiyun call phase_lock; 1577*4882a593Smuzhiyun cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; 1578*4882a593Smuzhiyun jmp host_message_loop; 1579*4882a593Smuzhiyun 1580*4882a593Smuzhiyunmesgin_ign_wide_residue: 1581*4882a593Smuzhiyunif ((ahc->features & AHC_WIDE) != 0) { 1582*4882a593Smuzhiyun test SCSIRATE, WIDEXFER jz mesgin_reject; 1583*4882a593Smuzhiyun /* Pull the residue byte */ 1584*4882a593Smuzhiyun mvi ARG_1 call inb_next; 1585*4882a593Smuzhiyun cmp ARG_1, 0x01 jne mesgin_reject; 1586*4882a593Smuzhiyun test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; 1587*4882a593Smuzhiyun test SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done; 1588*4882a593Smuzhiyun mvi IGN_WIDE_RES call set_seqint; 1589*4882a593Smuzhiyun jmp mesgin_done; 1590*4882a593Smuzhiyun} 1591*4882a593Smuzhiyun 1592*4882a593Smuzhiyunmesgin_proto_violation: 1593*4882a593Smuzhiyun mvi PROTO_VIOLATION call set_seqint; 1594*4882a593Smuzhiyun jmp mesgin_done; 1595*4882a593Smuzhiyunmesgin_reject: 1596*4882a593Smuzhiyun mvi MSG_MESSAGE_REJECT call mk_mesg; 1597*4882a593Smuzhiyunmesgin_done: 1598*4882a593Smuzhiyun mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 1599*4882a593Smuzhiyun jmp ITloop; 1600*4882a593Smuzhiyun 1601*4882a593Smuzhiyun/* 1602*4882a593Smuzhiyun * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, 1603*4882a593Smuzhiyun * and trigger a completion interrupt. Before doing so, check to see if there 1604*4882a593Smuzhiyun * is a residual or the status byte is something other than STATUS_GOOD (0). 1605*4882a593Smuzhiyun * In either of these conditions, we upload the SCB back to the host so it can 1606*4882a593Smuzhiyun * process this information. In the case of a non zero status byte, we 1607*4882a593Smuzhiyun * additionally interrupt the kernel driver synchronously, allowing it to 1608*4882a593Smuzhiyun * decide if sense should be retrieved. If the kernel driver wishes to request 1609*4882a593Smuzhiyun * sense, it will fill the kernel SCB with a request sense command, requeue 1610*4882a593Smuzhiyun * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 1611*4882a593Smuzhiyun * RETURN_1 to SEND_SENSE. 1612*4882a593Smuzhiyun */ 1613*4882a593Smuzhiyunmesgin_complete: 1614*4882a593Smuzhiyun 1615*4882a593Smuzhiyun /* 1616*4882a593Smuzhiyun * If ATN is raised, we still want to give the target a message. 1617*4882a593Smuzhiyun * Perhaps there was a parity error on this last message byte. 1618*4882a593Smuzhiyun * Either way, the target should take us to message out phase 1619*4882a593Smuzhiyun * and then attempt to complete the command again. We should use a 1620*4882a593Smuzhiyun * critical section here to guard against a timeout triggering 1621*4882a593Smuzhiyun * for this command and setting ATN while we are still processing 1622*4882a593Smuzhiyun * the completion. 1623*4882a593Smuzhiyun test SCSISIGI, ATNI jnz mesgin_done; 1624*4882a593Smuzhiyun */ 1625*4882a593Smuzhiyun 1626*4882a593Smuzhiyun /* 1627*4882a593Smuzhiyun * If we are identified and have successfully sent the CDB, 1628*4882a593Smuzhiyun * any status will do. Optimize this fast path. 1629*4882a593Smuzhiyun */ 1630*4882a593Smuzhiyun test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation; 1631*4882a593Smuzhiyun test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; 1632*4882a593Smuzhiyun 1633*4882a593Smuzhiyun /* 1634*4882a593Smuzhiyun * If the target never sent an identify message but instead went 1635*4882a593Smuzhiyun * to mesgin to give an invalid message, let the host abort us. 1636*4882a593Smuzhiyun */ 1637*4882a593Smuzhiyun test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; 1638*4882a593Smuzhiyun 1639*4882a593Smuzhiyun /* 1640*4882a593Smuzhiyun * If we recevied good status but never successfully sent the 1641*4882a593Smuzhiyun * cdb, abort the command. 1642*4882a593Smuzhiyun */ 1643*4882a593Smuzhiyun test SCB_SCSI_STATUS,0xff jnz complete_accepted; 1644*4882a593Smuzhiyun test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation; 1645*4882a593Smuzhiyun 1646*4882a593Smuzhiyuncomplete_accepted: 1647*4882a593Smuzhiyun /* 1648*4882a593Smuzhiyun * See if we attempted to deliver a message but the target ingnored us. 1649*4882a593Smuzhiyun */ 1650*4882a593Smuzhiyun test SCB_CONTROL, MK_MESSAGE jz . + 2; 1651*4882a593Smuzhiyun mvi MKMSG_FAILED call set_seqint; 1652*4882a593Smuzhiyun 1653*4882a593Smuzhiyun /* 1654*4882a593Smuzhiyun * Check for residuals 1655*4882a593Smuzhiyun */ 1656*4882a593Smuzhiyun test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ 1657*4882a593Smuzhiyun test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ 1658*4882a593Smuzhiyun test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; 1659*4882a593Smuzhiyuncheck_status: 1660*4882a593Smuzhiyun test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ 1661*4882a593Smuzhiyunupload_scb: 1662*4882a593Smuzhiyun or SCB_SGPTR, SG_RESID_VALID; 1663*4882a593Smuzhiyun mvi DMAPARAMS, FIFORESET; 1664*4882a593Smuzhiyun mov SCB_TAG call dma_scb; 1665*4882a593Smuzhiyun test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ 1666*4882a593Smuzhiyun mvi BAD_STATUS call set_seqint; /* let driver know */ 1667*4882a593Smuzhiyun cmp RETURN_1, SEND_SENSE jne complete; 1668*4882a593Smuzhiyun call add_scb_to_free_list; 1669*4882a593Smuzhiyun jmp await_busfree; 1670*4882a593Smuzhiyuncomplete: 1671*4882a593Smuzhiyun mov SCB_TAG call complete_post; 1672*4882a593Smuzhiyun jmp await_busfree; 1673*4882a593Smuzhiyun} 1674*4882a593Smuzhiyun 1675*4882a593Smuzhiyuncomplete_post: 1676*4882a593Smuzhiyun /* Post the SCBID in SINDEX and issue an interrupt */ 1677*4882a593Smuzhiyun call add_scb_to_free_list; 1678*4882a593Smuzhiyun mov ARG_1, SINDEX; 1679*4882a593Smuzhiyun if ((ahc->features & AHC_QUEUE_REGS) != 0) { 1680*4882a593Smuzhiyun mov A, SDSCB_QOFF; 1681*4882a593Smuzhiyun } else { 1682*4882a593Smuzhiyun mov A, QOUTPOS; 1683*4882a593Smuzhiyun } 1684*4882a593Smuzhiyun mvi QOUTFIFO_OFFSET call post_byte_setup; 1685*4882a593Smuzhiyun mov ARG_1 call post_byte; 1686*4882a593Smuzhiyun if ((ahc->features & AHC_QUEUE_REGS) == 0) { 1687*4882a593Smuzhiyun inc QOUTPOS; 1688*4882a593Smuzhiyun } 1689*4882a593Smuzhiyun mvi INTSTAT,CMDCMPLT ret; 1690*4882a593Smuzhiyun 1691*4882a593Smuzhiyunif ((ahc->flags & AHC_INITIATORROLE) != 0) { 1692*4882a593Smuzhiyun/* 1693*4882a593Smuzhiyun * Is it a disconnect message? Set a flag in the SCB to remind us 1694*4882a593Smuzhiyun * and await the bus going free. If this is an untagged transaction 1695*4882a593Smuzhiyun * store the SCB id for it in our untagged target table for lookup on 1696*4882a593Smuzhiyun * a reselection. 1697*4882a593Smuzhiyun */ 1698*4882a593Smuzhiyunmesgin_disconnect: 1699*4882a593Smuzhiyun /* 1700*4882a593Smuzhiyun * If ATN is raised, we still want to give the target a message. 1701*4882a593Smuzhiyun * Perhaps there was a parity error on this last message byte 1702*4882a593Smuzhiyun * or we want to abort this command. Either way, the target 1703*4882a593Smuzhiyun * should take us to message out phase and then attempt to 1704*4882a593Smuzhiyun * disconnect again. 1705*4882a593Smuzhiyun * XXX - Wait for more testing. 1706*4882a593Smuzhiyun test SCSISIGI, ATNI jnz mesgin_done; 1707*4882a593Smuzhiyun */ 1708*4882a593Smuzhiyun test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT 1709*4882a593Smuzhiyun jnz mesgin_proto_violation; 1710*4882a593Smuzhiyun or SCB_CONTROL,DISCONNECTED; 1711*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 1712*4882a593Smuzhiyun call add_scb_to_disc_list; 1713*4882a593Smuzhiyun } 1714*4882a593Smuzhiyun test SCB_CONTROL, TAG_ENB jnz await_busfree; 1715*4882a593Smuzhiyun mov ARG_1, SCB_TAG; 1716*4882a593Smuzhiyun and SAVED_LUN, LID, SCB_LUN; 1717*4882a593Smuzhiyun mov SCB_SCSIID call set_busy_target; 1718*4882a593Smuzhiyun jmp await_busfree; 1719*4882a593Smuzhiyun 1720*4882a593Smuzhiyun/* 1721*4882a593Smuzhiyun * Save data pointers message: 1722*4882a593Smuzhiyun * Copying RAM values back to SCB, for Save Data Pointers message, but 1723*4882a593Smuzhiyun * only if we've actually been into a data phase to change them. This 1724*4882a593Smuzhiyun * protects against bogus data in scratch ram and the residual counts 1725*4882a593Smuzhiyun * since they are only initialized when we go into data_in or data_out. 1726*4882a593Smuzhiyun * Ack the message as soon as possible. For chips without S/G pipelining, 1727*4882a593Smuzhiyun * we can only ack the message after SHADDR has been saved. On these 1728*4882a593Smuzhiyun * chips, SHADDR increments with every bus transaction, even PIO. 1729*4882a593Smuzhiyun */ 1730*4882a593Smuzhiyunmesgin_sdptrs: 1731*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 1732*4882a593Smuzhiyun mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 1733*4882a593Smuzhiyun test SEQ_FLAGS, DPHASE jz ITloop; 1734*4882a593Smuzhiyun } else { 1735*4882a593Smuzhiyun test SEQ_FLAGS, DPHASE jz mesgin_done; 1736*4882a593Smuzhiyun } 1737*4882a593Smuzhiyun 1738*4882a593Smuzhiyun /* 1739*4882a593Smuzhiyun * If we are asked to save our position at the end of the 1740*4882a593Smuzhiyun * transfer, just mark us at the end rather than perform a 1741*4882a593Smuzhiyun * full save. 1742*4882a593Smuzhiyun */ 1743*4882a593Smuzhiyun test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full; 1744*4882a593Smuzhiyun or SCB_SGPTR, SG_LIST_NULL; 1745*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) != 0) { 1746*4882a593Smuzhiyun jmp ITloop; 1747*4882a593Smuzhiyun } else { 1748*4882a593Smuzhiyun jmp mesgin_done; 1749*4882a593Smuzhiyun } 1750*4882a593Smuzhiyun 1751*4882a593Smuzhiyunmesgin_sdptrs_full: 1752*4882a593Smuzhiyun 1753*4882a593Smuzhiyun /* 1754*4882a593Smuzhiyun * The SCB_SGPTR becomes the next one we'll download, 1755*4882a593Smuzhiyun * and the SCB_DATAPTR becomes the current SHADDR. 1756*4882a593Smuzhiyun * Use the residual number since STCNT is corrupted by 1757*4882a593Smuzhiyun * any message transfer. 1758*4882a593Smuzhiyun */ 1759*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 1760*4882a593Smuzhiyun bmov SCB_DATAPTR, SHADDR, 4; 1761*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) == 0) { 1762*4882a593Smuzhiyun mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 1763*4882a593Smuzhiyun } 1764*4882a593Smuzhiyun bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; 1765*4882a593Smuzhiyun } else { 1766*4882a593Smuzhiyun mvi DINDEX, SCB_DATAPTR; 1767*4882a593Smuzhiyun mvi SHADDR call bcopy_4; 1768*4882a593Smuzhiyun mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 1769*4882a593Smuzhiyun mvi SCB_RESIDUAL_DATACNT call bcopy_8; 1770*4882a593Smuzhiyun } 1771*4882a593Smuzhiyun jmp ITloop; 1772*4882a593Smuzhiyun 1773*4882a593Smuzhiyun/* 1774*4882a593Smuzhiyun * Restore pointers message? Data pointers are recopied from the 1775*4882a593Smuzhiyun * SCB anytime we enter a data phase for the first time, so all 1776*4882a593Smuzhiyun * we need to do is clear the DPHASE flag and let the data phase 1777*4882a593Smuzhiyun * code do the rest. We also reset/reallocate the FIFO to make 1778*4882a593Smuzhiyun * sure we have a clean start for the next data or command phase. 1779*4882a593Smuzhiyun */ 1780*4882a593Smuzhiyunmesgin_rdptrs: 1781*4882a593Smuzhiyun and SEQ_FLAGS, ~DPHASE; /* 1782*4882a593Smuzhiyun * We'll reload them 1783*4882a593Smuzhiyun * the next time through 1784*4882a593Smuzhiyun * the dataphase. 1785*4882a593Smuzhiyun */ 1786*4882a593Smuzhiyun or SXFRCTL0, CLRSTCNT|CLRCHN; 1787*4882a593Smuzhiyun jmp mesgin_done; 1788*4882a593Smuzhiyun 1789*4882a593Smuzhiyun/* 1790*4882a593Smuzhiyun * Index into our Busy Target table. SINDEX and DINDEX are modified 1791*4882a593Smuzhiyun * upon return. SCBPTR may be modified by this action. 1792*4882a593Smuzhiyun */ 1793*4882a593Smuzhiyunset_busy_target: 1794*4882a593Smuzhiyun shr DINDEX, 4, SINDEX; 1795*4882a593Smuzhiyun if ((ahc->flags & AHC_SCB_BTT) != 0) { 1796*4882a593Smuzhiyun mov SCBPTR, SAVED_LUN; 1797*4882a593Smuzhiyun add DINDEX, SCB_64_BTT; 1798*4882a593Smuzhiyun } else { 1799*4882a593Smuzhiyun add DINDEX, BUSY_TARGETS; 1800*4882a593Smuzhiyun } 1801*4882a593Smuzhiyun mov DINDIR, ARG_1 ret; 1802*4882a593Smuzhiyun 1803*4882a593Smuzhiyun/* 1804*4882a593Smuzhiyun * Identify message? For a reconnecting target, this tells us the lun 1805*4882a593Smuzhiyun * that the reconnection is for - find the correct SCB and switch to it, 1806*4882a593Smuzhiyun * clearing the "disconnected" bit so we don't "find" it by accident later. 1807*4882a593Smuzhiyun */ 1808*4882a593Smuzhiyunmesgin_identify: 1809*4882a593Smuzhiyun /* 1810*4882a593Smuzhiyun * Determine whether a target is using tagged or non-tagged 1811*4882a593Smuzhiyun * transactions by first looking at the transaction stored in 1812*4882a593Smuzhiyun * the busy target array. If there is no untagged transaction 1813*4882a593Smuzhiyun * for this target or the transaction is for a different lun, then 1814*4882a593Smuzhiyun * this must be a tagged transaction. 1815*4882a593Smuzhiyun */ 1816*4882a593Smuzhiyun shr SINDEX, 4, SAVED_SCSIID; 1817*4882a593Smuzhiyun and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; 1818*4882a593Smuzhiyun if ((ahc->flags & AHC_SCB_BTT) != 0) { 1819*4882a593Smuzhiyun add SINDEX, SCB_64_BTT; 1820*4882a593Smuzhiyun mov SCBPTR, SAVED_LUN; 1821*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1822*4882a593Smuzhiyun add NONE, -SCB_64_BTT, SINDEX; 1823*4882a593Smuzhiyun jc . + 2; 1824*4882a593Smuzhiyun mvi INTSTAT, OUT_OF_RANGE; 1825*4882a593Smuzhiyun nop; 1826*4882a593Smuzhiyun add NONE, -(SCB_64_BTT + 16), SINDEX; 1827*4882a593Smuzhiyun jnc . + 2; 1828*4882a593Smuzhiyun mvi INTSTAT, OUT_OF_RANGE; 1829*4882a593Smuzhiyun nop; 1830*4882a593Smuzhiyun } 1831*4882a593Smuzhiyun } else { 1832*4882a593Smuzhiyun add SINDEX, BUSY_TARGETS; 1833*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1834*4882a593Smuzhiyun add NONE, -BUSY_TARGETS, SINDEX; 1835*4882a593Smuzhiyun jc . + 2; 1836*4882a593Smuzhiyun mvi INTSTAT, OUT_OF_RANGE; 1837*4882a593Smuzhiyun nop; 1838*4882a593Smuzhiyun add NONE, -(BUSY_TARGETS + 16), SINDEX; 1839*4882a593Smuzhiyun jnc . + 2; 1840*4882a593Smuzhiyun mvi INTSTAT, OUT_OF_RANGE; 1841*4882a593Smuzhiyun nop; 1842*4882a593Smuzhiyun } 1843*4882a593Smuzhiyun } 1844*4882a593Smuzhiyun mov ARG_1, SINDIR; 1845*4882a593Smuzhiyun cmp ARG_1, SCB_LIST_NULL je snoop_tag; 1846*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 1847*4882a593Smuzhiyun mov ARG_1 call findSCB; 1848*4882a593Smuzhiyun } else { 1849*4882a593Smuzhiyun mov SCBPTR, ARG_1; 1850*4882a593Smuzhiyun } 1851*4882a593Smuzhiyun if ((ahc->flags & AHC_SCB_BTT) != 0) { 1852*4882a593Smuzhiyun jmp setup_SCB_id_lun_okay; 1853*4882a593Smuzhiyun } else { 1854*4882a593Smuzhiyun /* 1855*4882a593Smuzhiyun * We only allow one untagged command per-target 1856*4882a593Smuzhiyun * at a time. So, if the lun doesn't match, look 1857*4882a593Smuzhiyun * for a tag message. 1858*4882a593Smuzhiyun */ 1859*4882a593Smuzhiyun and A, LID, SCB_LUN; 1860*4882a593Smuzhiyun cmp SAVED_LUN, A je setup_SCB_id_lun_okay; 1861*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 1862*4882a593Smuzhiyun /* 1863*4882a593Smuzhiyun * findSCB removes the SCB from the 1864*4882a593Smuzhiyun * disconnected list, so we must replace 1865*4882a593Smuzhiyun * it there should this SCB be for another 1866*4882a593Smuzhiyun * lun. 1867*4882a593Smuzhiyun */ 1868*4882a593Smuzhiyun call cleanup_scb; 1869*4882a593Smuzhiyun } 1870*4882a593Smuzhiyun } 1871*4882a593Smuzhiyun 1872*4882a593Smuzhiyun/* 1873*4882a593Smuzhiyun * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 1874*4882a593Smuzhiyun * If we get one, we use the tag returned to find the proper 1875*4882a593Smuzhiyun * SCB. With SCB paging, we must search for non-tagged 1876*4882a593Smuzhiyun * transactions since the SCB may exist in any slot. If we're not 1877*4882a593Smuzhiyun * using SCB paging, we can use the tag as the direct index to the 1878*4882a593Smuzhiyun * SCB. 1879*4882a593Smuzhiyun */ 1880*4882a593Smuzhiyunsnoop_tag: 1881*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1882*4882a593Smuzhiyun or SEQ_FLAGS, 0x80; 1883*4882a593Smuzhiyun } 1884*4882a593Smuzhiyun mov NONE,SCSIDATL; /* ACK Identify MSG */ 1885*4882a593Smuzhiyun call phase_lock; 1886*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1887*4882a593Smuzhiyun or SEQ_FLAGS, 0x1; 1888*4882a593Smuzhiyun } 1889*4882a593Smuzhiyun cmp LASTPHASE, P_MESGIN jne not_found; 1890*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1891*4882a593Smuzhiyun or SEQ_FLAGS, 0x2; 1892*4882a593Smuzhiyun } 1893*4882a593Smuzhiyun cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 1894*4882a593Smuzhiyunget_tag: 1895*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 1896*4882a593Smuzhiyun mvi ARG_1 call inb_next; /* tag value */ 1897*4882a593Smuzhiyun mov ARG_1 call findSCB; 1898*4882a593Smuzhiyun } else { 1899*4882a593Smuzhiyun mvi ARG_1 call inb_next; /* tag value */ 1900*4882a593Smuzhiyun mov SCBPTR, ARG_1; 1901*4882a593Smuzhiyun } 1902*4882a593Smuzhiyun 1903*4882a593Smuzhiyun/* 1904*4882a593Smuzhiyun * Ensure that the SCB the tag points to is for 1905*4882a593Smuzhiyun * an SCB transaction to the reconnecting target. 1906*4882a593Smuzhiyun */ 1907*4882a593Smuzhiyunsetup_SCB: 1908*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1909*4882a593Smuzhiyun or SEQ_FLAGS, 0x4; 1910*4882a593Smuzhiyun } 1911*4882a593Smuzhiyun mov A, SCB_SCSIID; 1912*4882a593Smuzhiyun cmp SAVED_SCSIID, A jne not_found_cleanup_scb; 1913*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1914*4882a593Smuzhiyun or SEQ_FLAGS, 0x8; 1915*4882a593Smuzhiyun } 1916*4882a593Smuzhiyunsetup_SCB_id_okay: 1917*4882a593Smuzhiyun and A, LID, SCB_LUN; 1918*4882a593Smuzhiyun cmp SAVED_LUN, A jne not_found_cleanup_scb; 1919*4882a593Smuzhiyunsetup_SCB_id_lun_okay: 1920*4882a593Smuzhiyun if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1921*4882a593Smuzhiyun or SEQ_FLAGS, 0x10; 1922*4882a593Smuzhiyun } 1923*4882a593Smuzhiyun test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; 1924*4882a593Smuzhiyun and SCB_CONTROL,~DISCONNECTED; 1925*4882a593Smuzhiyun test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; 1926*4882a593Smuzhiyun if ((ahc->flags & AHC_SCB_BTT) != 0) { 1927*4882a593Smuzhiyun mov A, SCBPTR; 1928*4882a593Smuzhiyun } 1929*4882a593Smuzhiyun mvi ARG_1, SCB_LIST_NULL; 1930*4882a593Smuzhiyun mov SAVED_SCSIID call set_busy_target; 1931*4882a593Smuzhiyun if ((ahc->flags & AHC_SCB_BTT) != 0) { 1932*4882a593Smuzhiyun mov SCBPTR, A; 1933*4882a593Smuzhiyun } 1934*4882a593Smuzhiyunsetup_SCB_tagged: 1935*4882a593Smuzhiyun clr SEQ_FLAGS; /* make note of IDENTIFY */ 1936*4882a593Smuzhiyun call set_transfer_settings; 1937*4882a593Smuzhiyun /* See if the host wants to send a message upon reconnection */ 1938*4882a593Smuzhiyun test SCB_CONTROL, MK_MESSAGE jz mesgin_done; 1939*4882a593Smuzhiyun mvi HOST_MSG call mk_mesg; 1940*4882a593Smuzhiyun jmp mesgin_done; 1941*4882a593Smuzhiyun 1942*4882a593Smuzhiyunnot_found_cleanup_scb: 1943*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 1944*4882a593Smuzhiyun call cleanup_scb; 1945*4882a593Smuzhiyun } 1946*4882a593Smuzhiyunnot_found: 1947*4882a593Smuzhiyun mvi NO_MATCH call set_seqint; 1948*4882a593Smuzhiyun jmp mesgin_done; 1949*4882a593Smuzhiyun 1950*4882a593Smuzhiyunmk_mesg: 1951*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 1952*4882a593Smuzhiyun or SCSISIGO, ATNO, LASTPHASE; 1953*4882a593Smuzhiyun } else { 1954*4882a593Smuzhiyun mvi SCSISIGO, ATNO; 1955*4882a593Smuzhiyun } 1956*4882a593Smuzhiyun mov MSG_OUT,SINDEX ret; 1957*4882a593Smuzhiyun 1958*4882a593Smuzhiyun/* 1959*4882a593Smuzhiyun * Functions to read data in Automatic PIO mode. 1960*4882a593Smuzhiyun * 1961*4882a593Smuzhiyun * According to Adaptec's documentation, an ACK is not sent on input from 1962*4882a593Smuzhiyun * the target until SCSIDATL is read from. So we wait until SCSIDATL is 1963*4882a593Smuzhiyun * latched (the usual way), then read the data byte directly off the bus 1964*4882a593Smuzhiyun * using SCSIBUSL. When we have pulled the ATN line, or we just want to 1965*4882a593Smuzhiyun * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 1966*4882a593Smuzhiyun * spec guarantees that the target will hold the data byte on the bus until 1967*4882a593Smuzhiyun * we send our ACK. 1968*4882a593Smuzhiyun * 1969*4882a593Smuzhiyun * The assumption here is that these are called in a particular sequence, 1970*4882a593Smuzhiyun * and that REQ is already set when inb_first is called. inb_{first,next} 1971*4882a593Smuzhiyun * use the same calling convention as inb. 1972*4882a593Smuzhiyun */ 1973*4882a593Smuzhiyuninb_next_wait_perr: 1974*4882a593Smuzhiyun mvi PERR_DETECTED call set_seqint; 1975*4882a593Smuzhiyun jmp inb_next_wait; 1976*4882a593Smuzhiyuninb_next: 1977*4882a593Smuzhiyun mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 1978*4882a593Smuzhiyuninb_next_wait: 1979*4882a593Smuzhiyun /* 1980*4882a593Smuzhiyun * If there is a parity error, wait for the kernel to 1981*4882a593Smuzhiyun * see the interrupt and prepare our message response 1982*4882a593Smuzhiyun * before continuing. 1983*4882a593Smuzhiyun */ 1984*4882a593Smuzhiyun test SSTAT1, REQINIT jz inb_next_wait; 1985*4882a593Smuzhiyun test SSTAT1, SCSIPERR jnz inb_next_wait_perr; 1986*4882a593Smuzhiyuninb_next_check_phase: 1987*4882a593Smuzhiyun and LASTPHASE, PHASE_MASK, SCSISIGI; 1988*4882a593Smuzhiyun cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 1989*4882a593Smuzhiyuninb_first: 1990*4882a593Smuzhiyun mov DINDEX,SINDEX; 1991*4882a593Smuzhiyun mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 1992*4882a593Smuzhiyuninb_last: 1993*4882a593Smuzhiyun mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 1994*4882a593Smuzhiyun} 1995*4882a593Smuzhiyun 1996*4882a593Smuzhiyunif ((ahc->flags & AHC_TARGETROLE) != 0) { 1997*4882a593Smuzhiyun/* 1998*4882a593Smuzhiyun * Change to a new phase. If we are changing the state of the I/O signal, 1999*4882a593Smuzhiyun * from out to in, wait an additional data release delay before continuing. 2000*4882a593Smuzhiyun */ 2001*4882a593Smuzhiyunchange_phase: 2002*4882a593Smuzhiyun /* Wait for preceding I/O session to complete. */ 2003*4882a593Smuzhiyun test SCSISIGI, ACKI jnz .; 2004*4882a593Smuzhiyun 2005*4882a593Smuzhiyun /* Change the phase */ 2006*4882a593Smuzhiyun and DINDEX, IOI, SCSISIGI; 2007*4882a593Smuzhiyun mov SCSISIGO, SINDEX; 2008*4882a593Smuzhiyun and A, IOI, SINDEX; 2009*4882a593Smuzhiyun 2010*4882a593Smuzhiyun /* 2011*4882a593Smuzhiyun * If the data direction has changed, from 2012*4882a593Smuzhiyun * out (initiator driving) to in (target driving), 2013*4882a593Smuzhiyun * we must wait at least a data release delay plus 2014*4882a593Smuzhiyun * the normal bus settle delay. [SCSI III SPI 10.11.0] 2015*4882a593Smuzhiyun */ 2016*4882a593Smuzhiyun cmp DINDEX, A je change_phase_wait; 2017*4882a593Smuzhiyun test SINDEX, IOI jz change_phase_wait; 2018*4882a593Smuzhiyun call change_phase_wait; 2019*4882a593Smuzhiyunchange_phase_wait: 2020*4882a593Smuzhiyun nop; 2021*4882a593Smuzhiyun nop; 2022*4882a593Smuzhiyun nop; 2023*4882a593Smuzhiyun nop ret; 2024*4882a593Smuzhiyun 2025*4882a593Smuzhiyun/* 2026*4882a593Smuzhiyun * Send a byte to an initiator in Automatic PIO mode. 2027*4882a593Smuzhiyun */ 2028*4882a593Smuzhiyuntarget_outb: 2029*4882a593Smuzhiyun or SXFRCTL0, SPIOEN; 2030*4882a593Smuzhiyun test SSTAT0, SPIORDY jz .; 2031*4882a593Smuzhiyun mov SCSIDATL, SINDEX; 2032*4882a593Smuzhiyun test SSTAT0, SPIORDY jz .; 2033*4882a593Smuzhiyun and SXFRCTL0, ~SPIOEN ret; 2034*4882a593Smuzhiyun} 2035*4882a593Smuzhiyun 2036*4882a593Smuzhiyun/* 2037*4882a593Smuzhiyun * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will 2038*4882a593Smuzhiyun * be set to the position of the SCB. If the SCB cannot be found locally, 2039*4882a593Smuzhiyun * it will be paged in from host memory. RETURN_2 stores the address of the 2040*4882a593Smuzhiyun * preceding SCB in the disconnected list which can be used to speed up 2041*4882a593Smuzhiyun * removal of the found SCB from the disconnected list. 2042*4882a593Smuzhiyun */ 2043*4882a593Smuzhiyunif ((ahc->flags & AHC_PAGESCBS) != 0) { 2044*4882a593SmuzhiyunBEGIN_CRITICAL; 2045*4882a593SmuzhiyunfindSCB: 2046*4882a593Smuzhiyun mov A, SINDEX; /* Tag passed in SINDEX */ 2047*4882a593Smuzhiyun cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; 2048*4882a593Smuzhiyun mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ 2049*4882a593Smuzhiyun mvi ARG_2, SCB_LIST_NULL; /* Head of list */ 2050*4882a593Smuzhiyun jmp findSCB_loop; 2051*4882a593SmuzhiyunfindSCB_next: 2052*4882a593Smuzhiyun cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; 2053*4882a593Smuzhiyun mov ARG_2, SCBPTR; 2054*4882a593Smuzhiyun mov SCBPTR,SCB_NEXT; 2055*4882a593SmuzhiyunfindSCB_loop: 2056*4882a593Smuzhiyun cmp SCB_TAG, A jne findSCB_next; 2057*4882a593Smuzhiyunrem_scb_from_disc_list: 2058*4882a593Smuzhiyun cmp ARG_2, SCB_LIST_NULL je rHead; 2059*4882a593Smuzhiyun mov DINDEX, SCB_NEXT; 2060*4882a593Smuzhiyun mov SINDEX, SCBPTR; 2061*4882a593Smuzhiyun mov SCBPTR, ARG_2; 2062*4882a593Smuzhiyun mov SCB_NEXT, DINDEX; 2063*4882a593Smuzhiyun mov SCBPTR, SINDEX ret; 2064*4882a593SmuzhiyunrHead: 2065*4882a593Smuzhiyun mov DISCONNECTED_SCBH,SCB_NEXT ret; 2066*4882a593SmuzhiyunEND_CRITICAL; 2067*4882a593SmuzhiyunfindSCB_notFound: 2068*4882a593Smuzhiyun /* 2069*4882a593Smuzhiyun * We didn't find it. Page in the SCB. 2070*4882a593Smuzhiyun */ 2071*4882a593Smuzhiyun mov ARG_1, A; /* Save tag */ 2072*4882a593Smuzhiyun mov ALLZEROS call get_free_or_disc_scb; 2073*4882a593Smuzhiyun mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 2074*4882a593Smuzhiyun mov ARG_1 jmp dma_scb; 2075*4882a593Smuzhiyun} 2076*4882a593Smuzhiyun 2077*4882a593Smuzhiyun/* 2078*4882a593Smuzhiyun * Prepare the hardware to post a byte to host memory given an 2079*4882a593Smuzhiyun * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. 2080*4882a593Smuzhiyun */ 2081*4882a593Smuzhiyunpost_byte_setup: 2082*4882a593Smuzhiyun mov ARG_2, SINDEX; 2083*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 2084*4882a593Smuzhiyun mvi DINDEX, CCHADDR; 2085*4882a593Smuzhiyun mvi SHARED_DATA_ADDR call set_1byte_addr; 2086*4882a593Smuzhiyun mvi CCHCNT, 1; 2087*4882a593Smuzhiyun mvi CCSCBCTL, CCSCBRESET ret; 2088*4882a593Smuzhiyun } else { 2089*4882a593Smuzhiyun mvi DINDEX, HADDR; 2090*4882a593Smuzhiyun mvi SHARED_DATA_ADDR call set_1byte_addr; 2091*4882a593Smuzhiyun mvi 1 call set_hcnt; 2092*4882a593Smuzhiyun mvi DFCNTRL, FIFORESET ret; 2093*4882a593Smuzhiyun } 2094*4882a593Smuzhiyun 2095*4882a593Smuzhiyunpost_byte: 2096*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 2097*4882a593Smuzhiyun bmov CCSCBRAM, SINDEX, 1; 2098*4882a593Smuzhiyun or CCSCBCTL, CCSCBEN|CCSCBRESET; 2099*4882a593Smuzhiyun test CCSCBCTL, CCSCBDONE jz .; 2100*4882a593Smuzhiyun clr CCSCBCTL ret; 2101*4882a593Smuzhiyun } else { 2102*4882a593Smuzhiyun mov DFDAT, SINDEX; 2103*4882a593Smuzhiyun or DFCNTRL, HDMAEN|FIFOFLUSH; 2104*4882a593Smuzhiyun jmp dma_finish; 2105*4882a593Smuzhiyun } 2106*4882a593Smuzhiyun 2107*4882a593Smuzhiyunphase_lock_perr: 2108*4882a593Smuzhiyun mvi PERR_DETECTED call set_seqint; 2109*4882a593Smuzhiyunphase_lock: 2110*4882a593Smuzhiyun /* 2111*4882a593Smuzhiyun * If there is a parity error, wait for the kernel to 2112*4882a593Smuzhiyun * see the interrupt and prepare our message response 2113*4882a593Smuzhiyun * before continuing. 2114*4882a593Smuzhiyun */ 2115*4882a593Smuzhiyun test SSTAT1, REQINIT jz phase_lock; 2116*4882a593Smuzhiyun test SSTAT1, SCSIPERR jnz phase_lock_perr; 2117*4882a593Smuzhiyunphase_lock_latch_phase: 2118*4882a593Smuzhiyun if ((ahc->features & AHC_DT) == 0) { 2119*4882a593Smuzhiyun and SCSISIGO, PHASE_MASK, SCSISIGI; 2120*4882a593Smuzhiyun } 2121*4882a593Smuzhiyun and LASTPHASE, PHASE_MASK, SCSISIGI ret; 2122*4882a593Smuzhiyun 2123*4882a593Smuzhiyunif ((ahc->features & AHC_CMD_CHAN) == 0) { 2124*4882a593Smuzhiyunset_hcnt: 2125*4882a593Smuzhiyun mov HCNT[0], SINDEX; 2126*4882a593Smuzhiyunclear_hcnt: 2127*4882a593Smuzhiyun clr HCNT[1]; 2128*4882a593Smuzhiyun clr HCNT[2] ret; 2129*4882a593Smuzhiyun 2130*4882a593Smuzhiyunset_stcnt_from_hcnt: 2131*4882a593Smuzhiyun mov STCNT[0], HCNT[0]; 2132*4882a593Smuzhiyun mov STCNT[1], HCNT[1]; 2133*4882a593Smuzhiyun mov STCNT[2], HCNT[2] ret; 2134*4882a593Smuzhiyun 2135*4882a593Smuzhiyunbcopy_8: 2136*4882a593Smuzhiyun mov DINDIR, SINDIR; 2137*4882a593Smuzhiyunbcopy_7: 2138*4882a593Smuzhiyun mov DINDIR, SINDIR; 2139*4882a593Smuzhiyun mov DINDIR, SINDIR; 2140*4882a593Smuzhiyunbcopy_5: 2141*4882a593Smuzhiyun mov DINDIR, SINDIR; 2142*4882a593Smuzhiyunbcopy_4: 2143*4882a593Smuzhiyun mov DINDIR, SINDIR; 2144*4882a593Smuzhiyunbcopy_3: 2145*4882a593Smuzhiyun mov DINDIR, SINDIR; 2146*4882a593Smuzhiyun mov DINDIR, SINDIR; 2147*4882a593Smuzhiyun mov DINDIR, SINDIR ret; 2148*4882a593Smuzhiyun} 2149*4882a593Smuzhiyun 2150*4882a593Smuzhiyunif ((ahc->flags & AHC_TARGETROLE) != 0) { 2151*4882a593Smuzhiyun/* 2152*4882a593Smuzhiyun * Setup addr assuming that A is an index into 2153*4882a593Smuzhiyun * an array of 32byte objects, SINDEX contains 2154*4882a593Smuzhiyun * the base address of that array, and DINDEX 2155*4882a593Smuzhiyun * contains the base address of the location 2156*4882a593Smuzhiyun * to store the indexed address. 2157*4882a593Smuzhiyun */ 2158*4882a593Smuzhiyunset_32byte_addr: 2159*4882a593Smuzhiyun shr ARG_2, 3, A; 2160*4882a593Smuzhiyun shl A, 5; 2161*4882a593Smuzhiyun jmp set_1byte_addr; 2162*4882a593Smuzhiyun} 2163*4882a593Smuzhiyun 2164*4882a593Smuzhiyun/* 2165*4882a593Smuzhiyun * Setup addr assuming that A is an index into 2166*4882a593Smuzhiyun * an array of 64byte objects, SINDEX contains 2167*4882a593Smuzhiyun * the base address of that array, and DINDEX 2168*4882a593Smuzhiyun * contains the base address of the location 2169*4882a593Smuzhiyun * to store the indexed address. 2170*4882a593Smuzhiyun */ 2171*4882a593Smuzhiyunset_64byte_addr: 2172*4882a593Smuzhiyun shr ARG_2, 2, A; 2173*4882a593Smuzhiyun shl A, 6; 2174*4882a593Smuzhiyun 2175*4882a593Smuzhiyun/* 2176*4882a593Smuzhiyun * Setup addr assuming that A + (ARG_2 * 256) is an 2177*4882a593Smuzhiyun * index into an array of 1byte objects, SINDEX contains 2178*4882a593Smuzhiyun * the base address of that array, and DINDEX contains 2179*4882a593Smuzhiyun * the base address of the location to store the computed 2180*4882a593Smuzhiyun * address. 2181*4882a593Smuzhiyun */ 2182*4882a593Smuzhiyunset_1byte_addr: 2183*4882a593Smuzhiyun add DINDIR, A, SINDIR; 2184*4882a593Smuzhiyun mov A, ARG_2; 2185*4882a593Smuzhiyun adc DINDIR, A, SINDIR; 2186*4882a593Smuzhiyun clr A; 2187*4882a593Smuzhiyun adc DINDIR, A, SINDIR; 2188*4882a593Smuzhiyun adc DINDIR, A, SINDIR ret; 2189*4882a593Smuzhiyun 2190*4882a593Smuzhiyun/* 2191*4882a593Smuzhiyun * Either post or fetch an SCB from host memory based on the 2192*4882a593Smuzhiyun * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. 2193*4882a593Smuzhiyun */ 2194*4882a593Smuzhiyundma_scb: 2195*4882a593Smuzhiyun mov A, SINDEX; 2196*4882a593Smuzhiyun if ((ahc->features & AHC_CMD_CHAN) != 0) { 2197*4882a593Smuzhiyun mvi DINDEX, CCHADDR; 2198*4882a593Smuzhiyun mvi HSCB_ADDR call set_64byte_addr; 2199*4882a593Smuzhiyun mov CCSCBPTR, SCBPTR; 2200*4882a593Smuzhiyun test DMAPARAMS, DIRECTION jz dma_scb_tohost; 2201*4882a593Smuzhiyun if ((ahc->flags & AHC_SCB_BTT) != 0) { 2202*4882a593Smuzhiyun mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; 2203*4882a593Smuzhiyun } else { 2204*4882a593Smuzhiyun mvi CCHCNT, SCB_DOWNLOAD_SIZE; 2205*4882a593Smuzhiyun } 2206*4882a593Smuzhiyun mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; 2207*4882a593Smuzhiyun cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; 2208*4882a593Smuzhiyun jmp dma_scb_finish; 2209*4882a593Smuzhiyundma_scb_tohost: 2210*4882a593Smuzhiyun mvi CCHCNT, SCB_UPLOAD_SIZE; 2211*4882a593Smuzhiyun if ((ahc->features & AHC_ULTRA2) == 0) { 2212*4882a593Smuzhiyun mvi CCSCBCTL, CCSCBRESET; 2213*4882a593Smuzhiyun bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; 2214*4882a593Smuzhiyun or CCSCBCTL, CCSCBEN|CCSCBRESET; 2215*4882a593Smuzhiyun test CCSCBCTL, CCSCBDONE jz .; 2216*4882a593Smuzhiyun } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { 2217*4882a593Smuzhiyun mvi CCSCBCTL, CCARREN|CCSCBRESET; 2218*4882a593Smuzhiyun cmp CCSCBCTL, ARRDONE|CCARREN jne .; 2219*4882a593Smuzhiyun mvi CCHCNT, SCB_UPLOAD_SIZE; 2220*4882a593Smuzhiyun mvi CCSCBCTL, CCSCBEN|CCSCBRESET; 2221*4882a593Smuzhiyun cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; 2222*4882a593Smuzhiyun } else { 2223*4882a593Smuzhiyun mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; 2224*4882a593Smuzhiyun cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; 2225*4882a593Smuzhiyun } 2226*4882a593Smuzhiyundma_scb_finish: 2227*4882a593Smuzhiyun clr CCSCBCTL; 2228*4882a593Smuzhiyun test CCSCBCTL, CCARREN|CCSCBEN jnz .; 2229*4882a593Smuzhiyun ret; 2230*4882a593Smuzhiyun } else { 2231*4882a593Smuzhiyun mvi DINDEX, HADDR; 2232*4882a593Smuzhiyun mvi HSCB_ADDR call set_64byte_addr; 2233*4882a593Smuzhiyun mvi SCB_DOWNLOAD_SIZE call set_hcnt; 2234*4882a593Smuzhiyun mov DFCNTRL, DMAPARAMS; 2235*4882a593Smuzhiyun test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 2236*4882a593Smuzhiyun /* Fill it with the SCB data */ 2237*4882a593Smuzhiyuncopy_scb_tofifo: 2238*4882a593Smuzhiyun mvi SINDEX, SCB_BASE; 2239*4882a593Smuzhiyun add A, SCB_DOWNLOAD_SIZE, SINDEX; 2240*4882a593Smuzhiyuncopy_scb_tofifo_loop: 2241*4882a593Smuzhiyun call copy_to_fifo_8; 2242*4882a593Smuzhiyun cmp SINDEX, A jne copy_scb_tofifo_loop; 2243*4882a593Smuzhiyun or DFCNTRL, HDMAEN|FIFOFLUSH; 2244*4882a593Smuzhiyun jmp dma_finish; 2245*4882a593Smuzhiyundma_scb_fromhost: 2246*4882a593Smuzhiyun mvi DINDEX, SCB_BASE; 2247*4882a593Smuzhiyun if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 2248*4882a593Smuzhiyun /* 2249*4882a593Smuzhiyun * The PCI module will only issue a PCI 2250*4882a593Smuzhiyun * retry if the data FIFO is empty. If the 2251*4882a593Smuzhiyun * host disconnects in the middle of a 2252*4882a593Smuzhiyun * transfer, we must empty the fifo of all 2253*4882a593Smuzhiyun * available data to force the chip to 2254*4882a593Smuzhiyun * continue the transfer. This does not 2255*4882a593Smuzhiyun * happen for SCSI transfers as the SCSI module 2256*4882a593Smuzhiyun * will drain the FIFO as data are made available. 2257*4882a593Smuzhiyun * When the hang occurs, we know that a multiple 2258*4882a593Smuzhiyun * of 8 bytes is in the FIFO because the PCI 2259*4882a593Smuzhiyun * module has an 8 byte input latch that only 2260*4882a593Smuzhiyun * dumps to the FIFO when HCNT == 0 or the 2261*4882a593Smuzhiyun * latch is full. 2262*4882a593Smuzhiyun */ 2263*4882a593Smuzhiyun clr A; 2264*4882a593Smuzhiyun /* Wait for at least 8 bytes of data to arrive. */ 2265*4882a593Smuzhiyundma_scb_hang_fifo: 2266*4882a593Smuzhiyun test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; 2267*4882a593Smuzhiyundma_scb_hang_wait: 2268*4882a593Smuzhiyun test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; 2269*4882a593Smuzhiyun test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 2270*4882a593Smuzhiyun test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 2271*4882a593Smuzhiyun test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 2272*4882a593Smuzhiyun /* 2273*4882a593Smuzhiyun * The PCI module no longer intends to perform 2274*4882a593Smuzhiyun * a PCI transaction. Drain the fifo. 2275*4882a593Smuzhiyun */ 2276*4882a593Smuzhiyundma_scb_hang_dma_drain_fifo: 2277*4882a593Smuzhiyun not A, HCNT; 2278*4882a593Smuzhiyun add A, SCB_DOWNLOAD_SIZE+SCB_BASE+1; 2279*4882a593Smuzhiyun and A, ~0x7; 2280*4882a593Smuzhiyun mov DINDIR,DFDAT; 2281*4882a593Smuzhiyun cmp DINDEX, A jne . - 1; 2282*4882a593Smuzhiyun cmp DINDEX, SCB_DOWNLOAD_SIZE+SCB_BASE 2283*4882a593Smuzhiyun je dma_finish_nowait; 2284*4882a593Smuzhiyun /* Restore A as the lines left to transfer. */ 2285*4882a593Smuzhiyun add A, -SCB_BASE, DINDEX; 2286*4882a593Smuzhiyun shr A, 3; 2287*4882a593Smuzhiyun jmp dma_scb_hang_fifo; 2288*4882a593Smuzhiyundma_scb_hang_dma_done: 2289*4882a593Smuzhiyun and DFCNTRL, ~HDMAEN; 2290*4882a593Smuzhiyun test DFCNTRL, HDMAEN jnz .; 2291*4882a593Smuzhiyun add SEQADDR0, A; 2292*4882a593Smuzhiyun } else { 2293*4882a593Smuzhiyun call dma_finish; 2294*4882a593Smuzhiyun } 2295*4882a593Smuzhiyun call dfdat_in_8; 2296*4882a593Smuzhiyun call dfdat_in_8; 2297*4882a593Smuzhiyun call dfdat_in_8; 2298*4882a593Smuzhiyundfdat_in_8: 2299*4882a593Smuzhiyun mov DINDIR,DFDAT; 2300*4882a593Smuzhiyundfdat_in_7: 2301*4882a593Smuzhiyun mov DINDIR,DFDAT; 2302*4882a593Smuzhiyun mov DINDIR,DFDAT; 2303*4882a593Smuzhiyun mov DINDIR,DFDAT; 2304*4882a593Smuzhiyun mov DINDIR,DFDAT; 2305*4882a593Smuzhiyun mov DINDIR,DFDAT; 2306*4882a593Smuzhiyundfdat_in_2: 2307*4882a593Smuzhiyun mov DINDIR,DFDAT; 2308*4882a593Smuzhiyun mov DINDIR,DFDAT ret; 2309*4882a593Smuzhiyun } 2310*4882a593Smuzhiyun 2311*4882a593Smuzhiyuncopy_to_fifo_8: 2312*4882a593Smuzhiyun mov DFDAT,SINDIR; 2313*4882a593Smuzhiyun mov DFDAT,SINDIR; 2314*4882a593Smuzhiyuncopy_to_fifo_6: 2315*4882a593Smuzhiyun mov DFDAT,SINDIR; 2316*4882a593Smuzhiyuncopy_to_fifo_5: 2317*4882a593Smuzhiyun mov DFDAT,SINDIR; 2318*4882a593Smuzhiyuncopy_to_fifo_4: 2319*4882a593Smuzhiyun mov DFDAT,SINDIR; 2320*4882a593Smuzhiyun mov DFDAT,SINDIR; 2321*4882a593Smuzhiyun mov DFDAT,SINDIR; 2322*4882a593Smuzhiyun mov DFDAT,SINDIR ret; 2323*4882a593Smuzhiyun 2324*4882a593Smuzhiyun/* 2325*4882a593Smuzhiyun * Wait for DMA from host memory to data FIFO to complete, then disable 2326*4882a593Smuzhiyun * DMA and wait for it to acknowledge that it's off. 2327*4882a593Smuzhiyun */ 2328*4882a593Smuzhiyundma_finish: 2329*4882a593Smuzhiyun test DFSTATUS,HDONE jz dma_finish; 2330*4882a593Smuzhiyundma_finish_nowait: 2331*4882a593Smuzhiyun /* Turn off DMA */ 2332*4882a593Smuzhiyun and DFCNTRL, ~HDMAEN; 2333*4882a593Smuzhiyun test DFCNTRL, HDMAEN jnz .; 2334*4882a593Smuzhiyun ret; 2335*4882a593Smuzhiyun 2336*4882a593Smuzhiyun/* 2337*4882a593Smuzhiyun * Restore an SCB that failed to match an incoming reselection 2338*4882a593Smuzhiyun * to the correct/safe state. If the SCB is for a disconnected 2339*4882a593Smuzhiyun * transaction, it must be returned to the disconnected list. 2340*4882a593Smuzhiyun * If it is not in the disconnected state, it must be free. 2341*4882a593Smuzhiyun */ 2342*4882a593Smuzhiyuncleanup_scb: 2343*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 2344*4882a593Smuzhiyun test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list; 2345*4882a593Smuzhiyun } 2346*4882a593Smuzhiyunadd_scb_to_free_list: 2347*4882a593Smuzhiyun if ((ahc->flags & AHC_PAGESCBS) != 0) { 2348*4882a593SmuzhiyunBEGIN_CRITICAL; 2349*4882a593Smuzhiyun mov SCB_NEXT, FREE_SCBH; 2350*4882a593Smuzhiyun mvi SCB_TAG, SCB_LIST_NULL; 2351*4882a593Smuzhiyun mov FREE_SCBH, SCBPTR ret; 2352*4882a593SmuzhiyunEND_CRITICAL; 2353*4882a593Smuzhiyun } else { 2354*4882a593Smuzhiyun mvi SCB_TAG, SCB_LIST_NULL ret; 2355*4882a593Smuzhiyun } 2356*4882a593Smuzhiyun 2357*4882a593Smuzhiyunif ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 2358*4882a593Smuzhiyunset_hhaddr: 2359*4882a593Smuzhiyun or DSCOMMAND1, HADDLDSEL0; 2360*4882a593Smuzhiyun and HADDR, SG_HIGH_ADDR_BITS, SINDEX; 2361*4882a593Smuzhiyun and DSCOMMAND1, ~HADDLDSEL0 ret; 2362*4882a593Smuzhiyun} 2363*4882a593Smuzhiyun 2364*4882a593Smuzhiyunif ((ahc->flags & AHC_PAGESCBS) != 0) { 2365*4882a593Smuzhiyunget_free_or_disc_scb: 2366*4882a593SmuzhiyunBEGIN_CRITICAL; 2367*4882a593Smuzhiyun cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 2368*4882a593Smuzhiyun cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 2369*4882a593Smuzhiyunreturn_error: 2370*4882a593Smuzhiyun mvi NO_FREE_SCB call set_seqint; 2371*4882a593Smuzhiyun mvi SINDEX, SCB_LIST_NULL ret; 2372*4882a593Smuzhiyundequeue_disc_scb: 2373*4882a593Smuzhiyun mov SCBPTR, DISCONNECTED_SCBH; 2374*4882a593Smuzhiyun mov DISCONNECTED_SCBH, SCB_NEXT; 2375*4882a593SmuzhiyunEND_CRITICAL; 2376*4882a593Smuzhiyun mvi DMAPARAMS, FIFORESET; 2377*4882a593Smuzhiyun mov SCB_TAG jmp dma_scb; 2378*4882a593SmuzhiyunBEGIN_CRITICAL; 2379*4882a593Smuzhiyundequeue_free_scb: 2380*4882a593Smuzhiyun mov SCBPTR, FREE_SCBH; 2381*4882a593Smuzhiyun mov FREE_SCBH, SCB_NEXT ret; 2382*4882a593SmuzhiyunEND_CRITICAL; 2383*4882a593Smuzhiyun 2384*4882a593Smuzhiyunadd_scb_to_disc_list: 2385*4882a593Smuzhiyun/* 2386*4882a593Smuzhiyun * Link this SCB into the DISCONNECTED list. This list holds the 2387*4882a593Smuzhiyun * candidates for paging out an SCB if one is needed for a new command. 2388*4882a593Smuzhiyun * Modifying the disconnected list is a critical(pause dissabled) section. 2389*4882a593Smuzhiyun */ 2390*4882a593SmuzhiyunBEGIN_CRITICAL; 2391*4882a593Smuzhiyun mov SCB_NEXT, DISCONNECTED_SCBH; 2392*4882a593Smuzhiyun mov DISCONNECTED_SCBH, SCBPTR ret; 2393*4882a593SmuzhiyunEND_CRITICAL; 2394*4882a593Smuzhiyun} 2395*4882a593Smuzhiyunset_seqint: 2396*4882a593Smuzhiyun mov INTSTAT, SINDEX; 2397*4882a593Smuzhiyun nop; 2398*4882a593Smuzhiyunreturn: 2399*4882a593Smuzhiyun ret; 2400