|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /** ! 26: * Copyright (c) 1994-1996 NeXT Software, Inc. All rights reserved. ! 27: * Copyright 1997 Apple Computer Inc. All Rights Reserved. ! 28: * @author Martin Minow mailto:[email protected] ! 29: * @revision 1997.02.17 Initial conversion from AMDPCSCSIDriver sources. ! 30: * ! 31: * Set tabs every 4 characters. ! 32: * ! 33: * Apple96Chip.m - Chip-specific methods for Apple96 SCSI driver. ! 34: * ! 35: * Edit History ! 36: * 1997.02.18 MM Initial conversion from AMDPCSCSIDriver sources. ! 37: * 1997.04.17 MM Removed SCS_PHASECHANGE (not needed) ! 38: */ ! 39: #import "Apple96SCSI.h" ! 40: #import "Apple96ISR.h" ! 41: #import "Apple96BusState.h" ! 42: #import "Apple96Curio.h" ! 43: #import "Apple96CurioPublic.h" ! 44: #import "Apple96CurioPrivate.h" ! 45: #import "Apple96SCSIPrivate.h" ! 46: #import "MacSCSICommand.h" ! 47: #import "bringup.h" ! 48: #import <driverkit/generalFuncs.h> ! 49: #import <kernserv/prototypes.h> ! 50: ! 51: IONamedValue scsiMsgValues[] = { ! 52: { kScsiMsgCmdComplete, "Command Complete" }, ! 53: { kScsiMsgExtended, "Extended Message" }, ! 54: { kScsiMsgSaveDataPointers, "Save Pointers" }, ! 55: { kScsiMsgRestorePointers, "Restore Pointers" }, ! 56: { kScsiMsgDisconnect, "Disconnect" }, ! 57: { kScsiMsgInitiatorDetectedErr, "Initiator Det Error" }, ! 58: { kScsiMsgAbort, "Abort" }, ! 59: { kScsiMsgRejectMsg, "Message Reject" }, ! 60: { kScsiMsgNop, "Nop" }, ! 61: { kScsiMsgParityErr, "Message parity Error" }, ! 62: { 0, NULL } ! 63: }; ! 64: ! 65: IONamedValue scsiPhaseValues[] = { ! 66: { kBusPhaseDATO, "data out" }, ! 67: { kBusPhaseDATI, "data in" }, ! 68: { kBusPhaseCMD, "command" }, ! 69: { kBusPhaseSTS, "status" }, ! 70: { kBusPhaseMSGO, "message out" }, ! 71: { kBusPhaseMSGI, "message in" }, ! 72: { kBusPhaseBusFree, "bus free" }, ! 73: { 0, NULL } ! 74: }; ! 75: ! 76: /* ! 77: * For IOFindNameForValue() and ddm's. ! 78: */ ! 79: IONamedValue gAutomatonStateValues[] = { ! 80: {SCS_UNINITIALIZED, "uninitialized" }, ! 81: {SCS_DISCONNECTED, "disconnected" }, ! 82: {SCS_SELECTING, "selecting" }, ! 83: {SCS_RESELECTING, "reselection in progress" }, ! 84: {SCS_INITIATOR, "in progress, initiator" }, ! 85: {SCS_COMPLETING, "completing command" }, ! 86: {SCS_WAIT_FOR_BUS_FREE, "waiting for bus free" }, ! 87: {SCS_DMACOMPLETE, "waiting for dma completion" }, ! 88: {SCS_SENDINGMSG, "sending message bytes" }, ! 89: {SCS_GETTINGMSG, "receiving message bytes" }, ! 90: {SCS_SENDINGCMD, "sending command bytes" }, ! 91: {SCS_DEATH_MARCH, "error recovery" }, ! 92: {0, NULL }, ! 93: }; ! 94: ! 95: @implementation Apple96_SCSI(InterruptService) ! 96: ! 97: /* ! 98: * SCSI device interrupt handler. We are called with interrupts disabled. ! 99: * ** ** ** Check whether interrupts are actually disabled! ! 100: */ ! 101: - (void) hardwareInterrupt ! 102: { ! 103: ENTRY("Hin hardwareInterrupt"); ! 104: if (CURIOinterruptPending()) { ! 105: ddmChip("hardwareInterrupt entry: cmd %08x [%02x]," ! 106: " status %02x, intr %02x, bus state: %s\n", ! 107: gActiveCommand, ! 108: (gCurrentTarget << 4) | gCurrentLUN, ! 109: gSaveStatus, ! 110: gSaveInterrupt, ! 111: IOFindNameForValue(gBusState, gAutomatonStateValues) ! 112: ); ! 113: /* ! 114: * There is an interrupt pending for this device. Note: ! 115: * because we can cycle through this sequence, it must ! 116: * be executed from a (high-priority) I/O thread, and not ! 117: * from a primary interrupt service routine. ! 118: */ ! 119: gFlagCheckForAnotherInterrupt = TRUE; ! 120: do { ! 121: gFlagNeedAnotherInterrupt = FALSE; ! 122: ddmChip("hardwareInterrupt loop: cmd %08x [%02x]," ! 123: " status %02x, intr %02x, bus state: %s\n", ! 124: gActiveCommand, ! 125: (gCurrentTarget << 4) | gCurrentLUN, ! 126: gSaveStatus, ! 127: gSaveInterrupt, ! 128: IOFindNameForValue(gBusState, gAutomatonStateValues) ! 129: ); ! 130: if ((gSaveInterrupt & sGrossErr) != 0) { ! 131: /* ! 132: * Gross error is set incorrectly (according to ! 133: * Clinton Bauder). ! 134: */ ! 135: ddmChip("Gross error: ignored, sts %02x, int %02x\n", ! 136: gSaveStatus, gSaveInterrupt, 3, 4, 5); ! 137: gSaveInterrupt &= ~sGrossErr; ! 138: } ! 139: if ((gSaveInterrupt & iIlegalCmd) != 0) { ! 140: /* ! 141: * Software screwup (gross error). Start over from scratch. ! 142: * We can get this if we write too many commands into the register. ! 143: */ ! 144: [self logRegisters : FALSE reason : "Illegal command interrupt"]; ! 145: if (gBusState != SCS_DEATH_MARCH) { ! 146: [self fsmStartErrorRecovery ! 147: : SR_IOST_INT ! 148: reason : "Illegal command interrupt" ! 149: ]; ! 150: } ! 151: gFlagCheckForAnotherInterrupt = FALSE; ! 152: } /* If chip error */ ! 153: if ((gSaveInterrupt & iDisconnect) != 0) { ! 154: ddmChip("hardwareInterrupt: enabling reselection\n", 1,2,3,4,5); ! 155: CURIOenableSelectionOrReselection(); ! 156: /* ! 157: * Radar 1678545: this is the only (normal) place ! 158: * that gFlagBusBusy is cleared. (It's also cleared by ! 159: * bus reset and driver initialization.) ! 160: */ ! 161: gFlagBusBusy = FALSE; ! 162: } ! 163: if ((gSaveInterrupt & iResetDetect) != 0) { ! 164: IOLog("%s: SCSI Bus Reset\n", [self name]); ! 165: /* ! 166: * While we would like to abort all pending and active commands, ! 167: * we can't do this without taking the pending command lock, ! 168: * which can, conceivably, lead to a race condition. If this ! 169: * (quick and dirty) analysis is incorrect, enable the following: ! 170: * [self abortAllCommands : SR_IOST_RESET]; ! 171: */ ! 172: [self curioHardwareReset ! 173: : FALSE ! 174: reason : "SCSI Bus Reset" ! 175: ]; ! 176: gFlagCheckForAnotherInterrupt = FALSE; ! 177: } /* If bus reset */ ! 178: else if ((gSaveStatus & sParityErr) != 0 && gFlagBusBusy) { ! 179: [self fsmStartErrorRecovery ! 180: : SR_IOST_PARITY ! 181: reason : "SCSI bus parity error" ! 182: ]; ! 183: gFlagCheckForAnotherInterrupt = FALSE; ! 184: } /* If device parity error and not disconnected */ ! 185: else { ! 186: /* ! 187: * Only certain states are legal if the bus is busy. ! 188: */ ! 189: if (gFlagBusBusy) { ! 190: /* ! 191: * This is a legitimate interrupt (parity error and bus reset ! 192: * have already been handled). The entity that started the ! 193: * chip action that caused the interrupt (deep breath) ! 194: * set gBusState to indicate why the interrupt happened. ! 195: * Call the proper finite-state machine function. On return, ! 196: * gBusState will be set to one of the following values: ! 197: * SCS_INITIATOR Start an action on the current phase. ! 198: * SCS_DISCONNECT The bus is free. ! 199: * SCS_WAIT_FOR_BUS_FREE The bus should go free shortly. ! 200: * Note that SCS_WAIT_FOR_BUS_FREE and fsmWaitForBusFree ! 201: * short-circuit some of the automaton to avoid unnecessary ! 202: * interrupt events. ! 203: */ ! 204: switch (gBusState) { ! 205: case SCS_DISCONNECTED: [self fsmDisconnected]; break; ! 206: case SCS_SELECTING: [self fsmSelecting]; break; ! 207: case SCS_RESELECTING: [self fsmReselecting]; break; ! 208: case SCS_INITIATOR: [self fsmInitiator]; break; ! 209: case SCS_COMPLETING: [self fsmCompleting]; break; ! 210: case SCS_DMACOMPLETE: [self fsmDMAComplete]; break; ! 211: case SCS_SENDINGMSG: [self fsmSendingMsg]; break; ! 212: case SCS_GETTINGMSG: [self fsmGettingMsg]; break; ! 213: case SCS_SENDINGCMD: [self fsmSendingCmd]; break; ! 214: case SCS_WAIT_FOR_BUS_FREE: [self fsmWaitForBusFree]; break; ! 215: case SCS_DEATH_MARCH: [self fsmErrorRecoveryInterruptService]; break; ! 216: case SCS_UNINITIALIZED: /* Illegal here */ ! 217: default: ! 218: IOLog("%s: Bug: illegal interrupt state: %s\n", ! 219: [self name], ! 220: IOFindNameForValue(gSaveStatus & mPhase, scsiPhaseValues) ! 221: ); ! 222: IOPanic("Apple96 SCSI: Illegal bus automaton state."); ! 223: } /* switch gBusState */ ! 224: } ! 225: else { ! 226: /* ! 227: * The bus is (or just went) free. We only allow selection, reselection, ! 228: * wait for disconnect, or death march interrupts. ! 229: */ ! 230: switch (gBusState) { ! 231: case SCS_DISCONNECTED: [self fsmDisconnected]; break; ! 232: case SCS_SELECTING: [self fsmSelecting]; break; ! 233: case SCS_WAIT_FOR_BUS_FREE: [self fsmWaitForBusFree]; break; ! 234: case SCS_DEATH_MARCH: [self fsmErrorRecoveryInterruptService]; break; ! 235: default: ! 236: [self fsmStartErrorRecovery ! 237: : SR_IOST_HW ! 238: reason : "Strange SCSI state when bus free" ! 239: ]; ! 240: gFlagCheckForAnotherInterrupt = FALSE; ! 241: } /* switch gBusState */ ! 242: } ! 243: } ! 244: /* ! 245: * We have (presumably) completely handled the previous interrupt. ! 246: * At this point, there are five legitimate gBusState values: ! 247: * SCS_RESELECTING Just got a reselection interrupt ! 248: * SCS_INITIATOR Continue operation for this target. ! 249: * SCS_DISCONNECTED Enable selection/reselection ! 250: * SCS_WAIT_FOR_BUS_FREE Command completion transition ! 251: * SCS_DEATH_MARCH Error recovery ! 252: * Handle a SCSI Phase change if necessary. This will leave ! 253: * the bus state in the "expected" state for the next operation. ! 254: */ ! 255: switch (gBusState) { ! 256: case SCS_DEATH_MARCH: ! 257: gFlagCheckForAnotherInterrupt = FALSE; ! 258: break; ! 259: case SCS_RESELECTING: ! 260: [self fsmReselectionAction]; ! 261: break; ! 262: case SCS_INITIATOR: ! 263: if ( gFlagNeedAnotherInterrupt ) // from tagged reselect ! 264: { ! 265: gFlagNeedAnotherInterrupt = FALSE; ! 266: if ( [ self curioQuickCheckForChipInterrupt ] ) ! 267: [ self fsmPhaseChange ]; ! 268: } ! 269: else ! 270: { ! 271: [ self fsmPhaseChange ]; ! 272: } ! 273: break; ! 274: case SCS_WAIT_FOR_BUS_FREE: ! 275: break; ! 276: default: ! 277: break; ! 278: } ! 279: /* ! 280: * This is the final check: if we determine that the previous action will ! 281: * complete quickly (for example, it's a message in byte), we'll spin for ! 282: * up to ten microseconds to see if the chip is ready for another operation. ! 283: */ ! 284: } while (gFlagCheckForAnotherInterrupt && CURIOquickCheckForChipInterrupt()); ! 285: if (gBusState == SCS_DEATH_MARCH) { ! 286: [self fsmContinueErrorRecovery]; ! 287: } ! 288: if (gBusState == SCS_DISCONNECTED) { ! 289: [self busFree]; ! 290: } ! 291: ddmChip("hardwareInterrupt: DONE; state: %s, phase %s\n", ! 292: IOFindNameForValue(gBusState, gAutomatonStateValues), ! 293: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues), ! 294: 3,4,5 ! 295: ); ! 296: } ! 297: EXIT(); ! 298: } ! 299: ! 300: @end /* Apple96_SCSI(InterruptService) */ ! 301: ! 302: /* end of Apple96_Chip.m */ ! 303:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.