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