|
|
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 1997 Apple Computer Inc. All Rights Reserved. ! 27: * @revision 1997.02.17 Initial conversion from AMDPCSCSIDriver sources. ! 28: * ! 29: * Set tabs every 4 characters. ! 30: * ! 31: * Apple96Chip.m - Chip-specific methods for Apple96 SCSI driver. ! 32: * ! 33: * Edit History ! 34: * 1997.02.18 MM Initial conversion from AMDPCSCSIDriver sources. ! 35: * 1997.04.17 MM Removed SCS_PHASECHANGE (not needed) ! 36: * 1997.06.24 MM Radar 1669736 - correctly store autosense status ! 37: * 1997.09.10 MM Radar 1678545 - Don't clear the gBusBusy flag until we ! 38: * get a "disconnected" interrupt. ! 39: */ ! 40: #import "Apple96SCSI.h" ! 41: #import "Apple96BusState.h" ! 42: #import "Apple96SCSIPrivate.h" ! 43: #import "Apple96CurioPublic.h" ! 44: #import "Apple96CurioPrivate.h" ! 45: #import "Apple96CurioDBDMA.h" ! 46: #import "Apple96HWPrivate.h" ! 47: #import "Apple96ISR.h" ! 48: #import "MacSCSICommand.h" ! 49: #import "bringup.h" ! 50: #import <driverkit/generalFuncs.h> ! 51: #import <kernserv/prototypes.h> ! 52: ! 53: #define IO_R_BV 0xDEADBEEF /* TEMP */ ! 54: ! 55: extern IONamedValue scsiMsgValues[]; /* In Apple96ISR.m */ ! 56: ! 57: @implementation Apple96_SCSI(BusState) ! 58: /* ! 59: * Disconnected - only legal event here is reselection. ! 60: * [self fsmHandleReselectionInterrupt] may set gBusState to SCS_INITIATOR ! 61: */ ! 62: - (void) fsmDisconnected ! 63: { ! 64: UInt8 selectByte; ! 65: UInt8 target; ! 66: ! 67: ENTRY("Bdi fsmDisconnected"); ! 68: ddmChip("fsmDisconnected\n", 1,2,3,4,5); ! 69: if ((gSaveInterrupt & iReselected) != 0) { ! 70: [self fsmHandleReselectionInterrupt]; ! 71: } ! 72: else if ((gSaveInterrupt & (iSelected | iSelectWAtn)) != 0) { ! 73: /* ! 74: * To do: allow selection by an external target and support ! 75: * a few mandatory commands: ! 76: * (PowerUp: gPendingTargetError = Unit Attention) ! 77: * Inquiry We're a CPU ! 78: * Test Unit Ready: ! 79: * if (gPendingTargetError == Unit Attention) ! 80: * Check Condition ! 81: * else { ! 82: * Success ! 83: * } ! 84: * All others gPendingTargetError := Illegal Command. ! 85: * Check Condition ! 86: * Request Sense: Send current error, clear current error. ! 87: */ ! 88: SynchronizeIO(); ! 89: selectByte = CURIOgetFifoByte(); ! 90: selectByte &= ~gInitiatorIDMask; ! 91: for (target = 0; target < 8; target++) { ! 92: if ((selectByte & (1 << target)) != 0) { ! 93: break; ! 94: } ! 95: } ! 96: IOLog("%s: Selected by external target %d -- not supported\n", ! 97: [self name], ! 98: target ! 99: ); ! 100: CURIOdisconnect(); ! 101: } ! 102: else if (gFlagBusBusy == FALSE) { ! 103: /* ! 104: * disconnect interrupted while disconnected ! 105: * This always happens when we finish an I/O request. ! 106: * gFlagBusBusy is cleared when the "bus disconnected" bit ! 107: * is set in the NCR 53C96 interrupt register. ! 108: */ ! 109: } ! 110: else { ! 111: /* ! 112: * Since we're disconnected, just ignore the interrupt ! 113: */ ! 114: if (gActiveCommand != NULL ! 115: && gActiveCommand->scsiReq != NULL ! 116: && gActiveCommand->scsiReq->driverStatus == SR_IOST_INVALID) { ! 117: #if 0 /* Radar 1678545 */ ! 118: IOLog("fsmDisconnected: timeout, target %d, int %02x, status %02x, step %02x\n", ! 119: gActiveCommand->scsiReq->target, ! 120: gSaveInterrupt & 0xFF, ! 121: gSaveStatus & 0xFF, ! 122: gSaveSeqStep & 0xFF ! 123: ); ! 124: #endif ! 125: gActiveCommand->scsiReq->driverStatus = SR_IOST_SELTO; ! 126: } ! 127: if (gActiveCommand != NULL) { ! 128: [self ioComplete ! 129: : gActiveCommand ! 130: finalStatus : SR_IOST_INVALID ! 131: ]; ! 132: } ! 133: gCurrentBusPhase = kBusPhaseBusFree; ! 134: } ! 135: EXIT(); ! 136: } ! 137: ! 138: /* ! 139: * This state is called when we expect to disconnect from a target after ! 140: * receiving a Command Complete, Disconnect, or Abort message and the bus ! 141: * is still busy on exit from the finite state automaton (because ! 142: * curioQuickCheckForBusFree returned false). ! 143: */ ! 144: - (void) fsmWaitForBusFree ! 145: { ! 146: if ((gSaveInterrupt & (iReselected | iSelected | iSelectWAtn)) != 0) { ! 147: /* ! 148: * Hmm, we went straight from command completion to (presumably) ! 149: * reselection. Treat it as a normal selection/reselection ! 150: * interrupt from "disconnected" state. (This is an abuse of ! 151: * the finite-state automaton design.) ! 152: */ ! 153: [self fsmDisconnected]; ! 154: } ! 155: else if (gFlagBusBusy == FALSE) { ! 156: /* ! 157: * This is expected: the bus has just gone free after a command ! 158: * completed. We can now safely try to start another command. ! 159: */ ! 160: gBusState = SCS_DISCONNECTED; ! 161: } ! 162: else { ! 163: /* ! 164: * This is strange. It may not be an error, but I don't know ! 165: * if there are other legal bus states after disconnect ! 166: * (the one counter example would be after a linked command ! 167: * when the target goes to Command phase, but we should have ! 168: * rejected this at command complete. ! 169: */ ! 170: [self fsmStartErrorRecovery ! 171: : SR_IOST_HW ! 172: reason : "Unexpected interrupt when disconnecting" ! 173: ]; ! 174: } ! 175: } ! 176: ! 177: /* ! 178: * This is called from fsmDisconnected when we receive a reselected interrupt. ! 179: */ ! 180: - (void) fsmHandleReselectionInterrupt ! 181: { ! 182: UInt8 selectByte; ! 183: UInt32 fifoDepth; ! 184: UInt8 msgByte; ! 185: IOReturn ioReturn; ! 186: const char *reason = NULL; ! 187: ! 188: ENTRY("Bre fsmHandleReselectionInterrupt"); ! 189: /* ! 190: * Make sure there's a selection byte and an identify message in the fifo. ! 191: */ ! 192: ioReturn = IO_R_SUCCESS; ! 193: gFlagBusBusy = ((gSaveInterrupt & iDisconnect) == 0); /* Radar 1678545 */ ! 194: SynchronizeIO(); ! 195: fifoDepth = CURIOgetFifoCount(); ! 196: ddmChip("reselect: fifoDepth %d\n", fifoDepth, 2,3,4,5); ! 197: if (fifoDepth != 2) { ! 198: ddmError("reselection, fifoDepth %d\n", fifoDepth, ! 199: 2,3,4,5); ! 200: #if LOG_ERROR_RECOVERY ! 201: IOLog("%s: Bad FIFO count (%d) (expect 2) on Reselect\n", ! 202: [self name], ! 203: fifoDepth ! 204: ); ! 205: #endif /* LOG_ERROR_RECOVERY */ ! 206: ioReturn = SR_IOST_HW; ! 207: reason = "Bad FIFO count on reselect"; ! 208: } ! 209: if (ioReturn == IO_R_SUCCESS) { ! 210: SynchronizeIO(); ! 211: selectByte = CURIOgetFifoByte(); ! 212: ddmChip("reselection: select byte %02x\n", selectByte, 2, 3, 4, 5); ! 213: ioReturn = [self getReselectionTargetID : selectByte]; ! 214: if (ioReturn != IO_R_SUCCESS) { ! 215: reason = "Bad selection value on reselect"; ! 216: } ! 217: } ! 218: if (ioReturn == IO_R_SUCCESS) { ! 219: /* ! 220: * gCurrentTarget has the bus ID of the target that is reselecting. ! 221: * The first message byte must be an Identify with the LUN. ! 222: */ ! 223: SynchronizeIO(); ! 224: msgByte = CURIOgetFifoByte(); ! 225: if ((gSaveStatus & sParityErr) != 0) { ! 226: ioReturn = SR_IOST_PARITY; ! 227: reason = "Parity error on reselect"; ! 228: } ! 229: } ! 230: if (ioReturn == IO_R_SUCCESS) { ! 231: if ((msgByte & kScsiMsgIdentify) == 0) { ! 232: ioReturn = SR_IOST_BV; ! 233: reason = "Bad ID Message (no identify) on reselect"; ! 234: } ! 235: gCurrentLUN = msgByte & ~kScsiMsgIdentify; ! 236: /* gFlagBusBusy = TRUE; -- Radar 1678545: move to method start */ ! 237: gBusState = SCS_RESELECTING; ! 238: /* ! 239: * At this point, the chip is waiting for us to validate ! 240: * the identify message. While we have a target and LUN, ! 241: * we don't have a command to reconnect to (that's the ! 242: * job of fsmReselectionAction). ! 243: * ! 244: * In case of sync mode, we need to load target context right ! 245: * now, before dropping ACK, because the target might go ! 246: * straight to a data in or data out as soon as ACK drops. ! 247: */ ! 248: CURIOmessageAccept(); /* Accept the identify message */ ! 249: ddmChip("Successful reselect from %d.%d\n", ! 250: gCurrentTarget, ! 251: gCurrentLUN, ! 252: 3, 4, 5 ! 253: ); ! 254: } ! 255: if (ioReturn != IO_R_SUCCESS) { ! 256: [self fsmStartErrorRecovery ! 257: : ioReturn ! 258: reason : reason ! 259: ]; ! 260: } ! 261: EXIT(); ! 262: } ! 263: ! 264: /* ! 265: * One of three things can happen here - the selection could succeed (though ! 266: * with possible incomplete message out), it could time out, or we can be ! 267: * reselected. ! 268: */ ! 269: - (void) fsmSelecting ! 270: { ! 271: IOReturn ioReturn; ! 272: UInt8 fifoDepth; ! 273: CommandBuffer *cmdBuf; ! 274: IOSCSIRequest *scsiReq = NULL; ! 275: const char *reason = NULL; ! 276: ! 277: ENTRY("Bse fsmSelecting"); ! 278: ddmChip("fsmSelecting\n", 1,2,3,4,5); ! 279: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 280: scsiReq = gActiveCommand->scsiReq; ! 281: ioReturn = IO_R_SUCCESS; ! 282: gFlagBusBusy = ((gSaveInterrupt & iDisconnect) == 0); ! 283: if (gFlagBusBusy == FALSE) { ! 284: /* ! 285: * selection timed-out. Abort this request. ! 286: */ ! 287: ddmChip("***SELECTION TIMEOUT for target %d.%d\n", ! 288: scsiReq->target, ! 289: scsiReq->lun, ! 290: 3,4,5 ! 291: ); ! 292: CURIOflushFifo(); ! 293: gBusState = SCS_DISCONNECTED; ! 294: #if 0 /* Radar 1678545 */ ! 295: IOLog("fsmSelecting: timeout, target %d, int %02x, status %02x, step %02x\n", ! 296: gActiveCommand->scsiReq->target, ! 297: gSaveInterrupt & 0xFF, ! 298: gSaveStatus & 0xFF, ! 299: gSaveSeqStep & 0xFF ! 300: ); ! 301: #endif ! 302: [self ioComplete ! 303: : gActiveCommand ! 304: finalStatus : SR_IOST_SELTO ! 305: ]; ! 306: gActiveCommand = NULL; ! 307: } ! 308: else if (gSaveInterrupt == (iFuncComp | iBusService)) { ! 309: ddmChip("selection seqstep=%d\n", ! 310: gSaveSeqStep & INS_STATE_MASK, 2,3,4,5); ! 311: switch (gSaveSeqStep & INS_STATE_MASK) { ! 312: case 0: ! 313: /* ! 314: * No message phase. If we really wanted one, ! 315: * this could be significant... ! 316: */ ! 317: if (gActiveCommand->queueTag != QUEUE_TAG_NONTAGGED) { ! 318: /* ! 319: * This target can't do command queueing. ! 320: */ ! 321: [self disableMode : kTargetModeCmdQueue]; ! 322: /* ! 323: * Clear the queue tag so we don't get here on ! 324: * an eventual autosense. ! 325: */ ! 326: gActiveCommand->queueTag = QUEUE_TAG_NONTAGGED; ! 327: } ! 328: /* ! 329: * OK, let's try to continue following phase changes. ! 330: */ ! 331: gBusState = SCS_INITIATOR; ! 332: break; ! 333: case 3: /* didn't complete cmd phase, parity? */ ! 334: case 4: /* everything worked */ ! 335: case 1: /* everything worked, SCMD_SELECT_ATN_STOP case */ ! 336: /* ! 337: * We're connected. Start following the target's phase ! 338: * changes. ! 339: * ! 340: * If we're trying to do sync negotiation, ! 341: * this is the place to do it. In that case, we ! 342: * sent a SCMD_SELECT_ATN_STOP command, and ! 343: * ATN is now asserted (and we're hopefully in ! 344: * msg out phase). We want to send 5 bytes. ! 345: * Drop them into currMsgOut[] and prime the ! 346: * msgOutState machine. ! 347: */ ! 348: gBusState = SCS_INITIATOR; ! 349: break; ! 350: case 2: ! 351: /* ! 352: * Either no command phase, or incomplete message ! 353: * transfer. ! 354: */ ! 355: SynchronizeIO(); ! 356: fifoDepth = CURIOgetFifoCount(); ! 357: #if LOG_ERROR_RECOVERY ! 358: IOLog("%s: Incomplete select (step 2); fifoDepth %d phase %s\n", ! 359: [self name], ! 360: fifoDepth, ! 361: IOFindNameForValue(gSaveStatus & mPhase, scsiPhaseValues) ! 362: ); ! 363: #endif /* LOG_ERROR_RECOVERY */ ! 364: if (gActiveCommand->queueTag != QUEUE_TAG_NONTAGGED) { ! 365: /* ! 366: * This target can't do command queueing. ! 367: */ ! 368: [self disableMode : kTargetModeCmdQueue]; ! 369: } ! 370: /* ! 371: * Spec says ATN is asserted if all message bytes ! 372: * were not sent. ! 373: */ ! 374: if (fifoDepth > gActiveCommand->cdbLength) { ! 375: CURIOclearATN(); ! 376: } ! 377: /* ! 378: * 970611: clear the fifo. If we don't do this and the ! 379: * target is entering MSGI phase (trying to send us a ! 380: * Message Reject), it will sit on top of the fifo, and ! 381: * we'll read garbage from the fifo. ! 382: */ ! 383: CURIOflushFifo(); /* The command is still in the fifo */ ! 384: /* ! 385: * OK, let's try to continue following phase changes. ! 386: */ ! 387: gBusState = SCS_INITIATOR; ! 388: break; ! 389: default: ! 390: /* gFlagBusBusy = TRUE; -- Radar 1678545 */ ! 391: ioReturn = SR_IOST_HW; ! 392: reason = "Selection sequence Error (strange state)"; ! 393: break; ! 394: } ! 395: } ! 396: else if ((gSaveInterrupt & iReselected) != 0) { ! 397: /* ! 398: * We were reselected while trying to do a selection. ! 399: * Enqueue this cmdBuf on the HEAD of pendingQ, then deal ! 400: * with the reselect. ! 401: * Tricky case, we have to "deactivate" this command ! 402: * since this hardwareStart attempt failed. ! 403: */ ! 404: cmdBuf = gActiveCommand; ! 405: // [ self deactivateCmd ]; // mlj - done by pushbackCurrentRequest ! 406: [self pushbackCurrentRequest : cmdBuf]; ! 407: ddmChip("reselect while trying to select target %d.%d\n", ! 408: scsiReq->target, ! 409: scsiReq->lun, ! 410: 3,4,5 ! 411: ); ! 412: gBusState = SCS_DISCONNECTED; ! 413: /* ! 414: * Go deal with reselect. ! 415: */ ! 416: [self fsmDisconnected]; ! 417: } ! 418: else if (gSaveInterrupt == iFuncComp ! 419: && (gSaveSeqStep & INS_STATE_MASK) == 2 ! 420: && (gSaveStatus & mPhase) == kBusPhaseMSGI ! 421: && (gLastMsgOut[0] & kScsiMsgIdentify) == kScsiMsgIdentify ! 422: && (gLastMsgOut[0] & 0x07) != 0) { ! 423: /* ! 424: * This shouldn't happen according to the NCR documentation, ! 425: * but we saw it if the bus scanner executes INQUIRY on ! 426: * a non-zero LUN on an Apple CD-300. The CD is sending a ! 427: * Message Reject to our Identify message byte. We'll ! 428: * handle this in the Message In code. ! 429: */ ! 430: gBusState = SCS_INITIATOR; ! 431: } ! 432: else { ! 433: ioReturn = SR_IOST_HW; ! 434: reason = "Bogus select/reselect interrupt"; ! 435: } ! 436: if (ioReturn != IO_R_SUCCESS) { ! 437: [self fsmStartErrorRecovery ! 438: : ioReturn ! 439: reason : "Error selecting target" ! 440: ]; ! 441: } ! 442: EXIT(); ! 443: } ! 444: ! 445: /* ! 446: * This is a dummy interrupt service state that we enter after selection ! 447: * when the previous Curio operation has no interrupt-service completion ! 448: * requirement. For example, we can get here after a Message Out or ! 449: * reselection. Nothing happens here; we continue at fsmPhaseChange. ! 450: */ ! 451: - (void) fsmInitiator ! 452: { ! 453: ENTRY("Bin fsmInitiator"); ! 454: ddmChip("fsmInitiator\n", 1,2,3,4,5); ! 455: gBusState = SCS_INITIATOR; ! 456: EXIT(); ! 457: } ! 458: ! 459: /* ! 460: * We just did a SCMD_INIT_CMD_CMPLT command, hopefully all that's left is ! 461: * to drop ACK. Command Complete message is handled in fscAcceptingMsg. ! 462: * We can't go to SCS_DISCONNECTED until the target disconnects. If we ! 463: * go to "disconnected" state too soon, we'll encounter a load-dependent ! 464: * race condition that causes us to start another command before we've ! 465: * cleaned up from the last command. The actual state change is in ! 466: * fsmProcessMessage. ! 467: */ ! 468: - (void) fsmCompleting ! 469: { ! 470: unsigned fifoDepth; ! 471: IOReturn ioReturn; ! 472: UInt8 statusByte; ! 473: const char *reason = NULL; ! 474: ! 475: ENTRY("Bco fsmCompleting"); ! 476: ddmChip("fsmCompleting\n", 1,2,3,4,5); ! 477: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 478: ioReturn = IO_R_SUCCESS; ! 479: if ((gSaveInterrupt & iDisconnect) != 0) { ! 480: ddmError("unexpected disconnect\n", 1,2,3,4,5); ! 481: ioReturn = SR_IOST_HW; ! 482: reason = "I/O complete, bus free before target completion complete"; ! 483: } ! 484: if (ioReturn == IO_R_SUCCESS) { ! 485: SynchronizeIO(); ! 486: fifoDepth = CURIOgetFifoCount(); ! 487: if ((gSaveInterrupt & iFuncComp) != 0) { ! 488: /* ! 489: * Got both status and msg in fifo; ACK is still asserted. ! 490: */ ! 491: if (fifoDepth != 2) { ! 492: /* ! 493: * This is pretty bogus - we expect a status and ! 494: * msg in the fifo. ! 495: */ ! 496: ioReturn = SR_IOST_HW; ! 497: reason = "I/O complete, incorrect fifo count (expecting two bytes)"; ! 498: } ! 499: if (ioReturn == IO_R_SUCCESS) { ! 500: SynchronizeIO(); ! 501: statusByte = CURIOgetFifoByte(); ! 502: if (gActiveCommand->flagIsAutosense) { /* Radar 1669736 */ ! 503: gActiveCommand->autosenseStatus = statusByte; ! 504: } ! 505: else { ! 506: gActiveCommand->scsiReq->scsiStatus = statusByte; ! 507: } ! 508: SynchronizeIO(); ! 509: gMsgInBuffer[0] = CURIOgetFifoByte(); ! 510: gMsgInIndex = 1; ! 511: ioReturn = [self fsmProcessMessage]; ! 512: reason = "Message in failed"; ! 513: } ! 514: } ! 515: else { ! 516: /* ! 517: * We only received a status byte. This can occur ! 518: * if we responded to the interrupt before the device ! 519: * successfully transmitted the Command Complete message. ! 520: * This is kind of weird, but let's try to handle it. ! 521: */ ! 522: ddmError("fsmCompleting: status only on complete\n", ! 523: 1,2,3,4,5); ! 524: if (fifoDepth != 1) { ! 525: ioReturn = SR_IOST_HW; ! 526: reason = "I/O complete: incorrect fifo count (expecting one byte)"; ! 527: } ! 528: if (gActiveCommand->flagIsAutosense) { /* Radar 1669736 */ ! 529: SynchronizeIO(); ! 530: gActiveCommand->autosenseStatus = CURIOgetFifoByte(); ! 531: } ! 532: else { ! 533: SynchronizeIO(); ! 534: gActiveCommand->scsiReq->scsiStatus = CURIOgetFifoByte(); ! 535: } ! 536: /* ! 537: * Back to watching phase changes. Presumably, the target ! 538: * will switch to MSGI phase and complete the command ! 539: * at its leasure. ! 540: */ ! 541: gBusState = SCS_INITIATOR; ! 542: } ! 543: } ! 544: if (ioReturn != IO_R_SUCCESS) { ! 545: [self fsmStartErrorRecovery ! 546: : ioReturn ! 547: reason : reason ! 548: ]; ! 549: } ! 550: EXIT(); ! 551: } ! 552: ! 553: /* ! 554: * DMA Complete. ! 555: */ ! 556: - (void) fsmDMAComplete ! 557: { ! 558: unsigned bytesMoved; ! 559: ! 560: ENTRY("Bdc fsmDMAComplete"); ! 561: ddmChip("fsmDMAComplete\n", 1,2,3,4,5); ! 562: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 563: /* ! 564: * Stop the dma engine and retrieve the total number of ! 565: * bytes transferred. This will be ! 566: * gActiveCommand->thisTransferLength The number of bytes requested ! 567: * - the current DMA residual count ! 568: * - the current FIFO residual count ! 569: * Note that there may still be bytes in the fifo. ! 570: */ ! 571: bytesMoved = [self curioDMAComplete]; ! 572: if ((gSaveStatus & sParityErr) != 0) { ! 573: [self fsmStartErrorRecovery ! 574: : SR_IOST_PARITY ! 575: reason : "SCSI Data Parity Error" ! 576: ]; ! 577: } ! 578: else { ! 579: /* ! 580: * Continue following phase changes. ! 581: */ ! 582: gBusState = SCS_INITIATOR; ! 583: } ! 584: EXIT(); ! 585: } ! 586: ! 587: /* ! 588: * Just completed the SCMD_TRANSFER_INFO operation for message in. ACK is ! 589: * not asserted (we have not ACK'ed this byte). There is no parity error. ! 590: * We will not have a command if we're reselecting. ! 591: */ ! 592: - (void) fsmGettingMsg ! 593: { ! 594: IOReturn ioReturn; ! 595: const char *reason = NULL; ! 596: UInt32 fifoCount; ! 597: UInt8 msgInByte; ! 598: ! 599: ENTRY("Bmi fsmGettingMsg"); ! 600: ioReturn = IO_R_SUCCESS; ! 601: if (gFlagBusBusy == FALSE) { ! 602: ddmChip("fsmGettingMsg: message In Disconnect\n", 1,2,3,4,5); ! 603: /* ! 604: * This (non-fatal) error is handled on return... ! 605: */ ! 606: ioReturn = IO_R_INTERNAL; /* Any non-zero non-fatal error status */ ! 607: } ! 608: else { ! 609: SynchronizeIO(); ! 610: fifoCount = CURIOgetFifoCount(); ! 611: if (fifoCount != 1) { ! 612: ddmChip("Message in fifo count error, count = %d\n", ! 613: fifoCount, ! 614: 2, 3, 4, 5 ! 615: ); ! 616: ioReturn = SR_IOST_HW; ! 617: reason = "Message in fifo count error"; ! 618: } ! 619: } ! 620: if (ioReturn == IO_R_SUCCESS) { ! 621: SynchronizeIO(); ! 622: msgInByte = CURIOgetFifoByte(); ! 623: if ((gSaveStatus & sParityErr) != 0) { ! 624: ioReturn = SR_IOST_PARITY; ! 625: reason = "Parity error getting Command Complete message"; ! 626: } ! 627: } ! 628: if (ioReturn == IO_R_SUCCESS) { ! 629: if (gMsgInState == kMsgInIdle) { ! 630: gMsgInCount = 0; ! 631: gMsgInIndex = 0; ! 632: } ! 633: if (gMsgInIndex >= kMessageInBufferLength) { ! 634: ioReturn = SR_IOST_HW; ! 635: reason = "Message in too many bytes"; ! 636: } ! 637: } ! 638: if (ioReturn == IO_R_SUCCESS) { ! 639: gMsgInBuffer[gMsgInIndex++] = msgInByte; ! 640: switch (gMsgInState) { ! 641: case kMsgInIdle: ! 642: /* ! 643: * This is the first message byte. Check for 1-byte codes. ! 644: */ ! 645: ddmChip("fsmGettingMsg: msgByte = 0x%x (%s)\n", ! 646: msgInByte, ! 647: IOFindNameForValue(msgInByte, scsiMsgValues), ! 648: 3, 4, 5 ! 649: ); ! 650: if ((/* msgInByte >= kScsiMsgOneByteMin && */ msgInByte <= kScsiMsgOneByteMax) ! 651: || msgInByte >= kScsiMsgIdentify) { ! 652: gMsgInState = kMsgInReady; ! 653: } ! 654: else if (msgInByte >= kScsiMsgTwoByteMin ! 655: && msgInByte <= kScsiMsgTwoByteMax) { ! 656: /* ! 657: * This is a two-byte message. Set the count and ! 658: * read the next byte. ! 659: */ ! 660: gMsgInState = kMsgInReading; /* Need one more */ ! 661: gMsgInCount = 1; ! 662: } ! 663: else { ! 664: /* ! 665: * This is an extended message. The next byte has the count. ! 666: */ ! 667: gMsgInState = kMsgInCounting; ! 668: } ! 669: break; ! 670: case kMsgInCounting: ! 671: /* ! 672: * Read the count byte of an extended message. ! 673: */ ! 674: gMsgInCount = msgInByte; ! 675: gMsgInState = kMsgInReading; ! 676: break; ! 677: case kMsgInReading: ! 678: if (--gMsgInCount <= 0) { ! 679: gMsgInState = kMsgInReady; ! 680: } ! 681: break; ! 682: default: ! 683: ASSERT(gMsgInState != 0xDEADBEEF /* Bogus state */); ! 684: ioReturn = SR_IOST_BV; ! 685: reason = "Message in bogus state"; ! 686: } /* Switch on message state */ ! 687: } ! 688: if (ioReturn == IO_R_SUCCESS) { ! 689: switch (gMsgInState) { ! 690: case kMsgInReading: ! 691: case kMsgInCounting: ! 692: /* ! 693: * We have more message bytes to read. Accept this byte ! 694: * (this sets ACK) and setup to transfer the next byte. ! 695: */ ! 696: CURIOmessageAccept(); ! 697: /* ! 698: * Since the message accept command sets "interrupt", eat ! 699: * it here so we don't get a second interrupt. ! 700: */ ! 701: CURIOquickCheckForChipInterrupt(); ! 702: CURIOstartMSGIAction(); ! 703: gBusState = SCS_GETTINGMSG; ! 704: /* ! 705: * This would be a good place to spin-wait for ! 706: * completion, continuing at the start of this ! 707: * method if there is another byte (and we're still ! 708: * in message in phase). Perhaps this method should ! 709: * return a "spinwait" status to the mainline FSM. ! 710: */ ! 711: break; ! 712: case kMsgInReady: ! 713: gMsgInState = kMsgInIdle; ! 714: ioReturn = [self fsmProcessMessage]; ! 715: if (ioReturn != IO_R_SUCCESS) { ! 716: reason = "Can't process received message"; ! 717: } ! 718: break; ! 719: case kMsgInIdle: ! 720: default: ! 721: /* ! 722: * Hmm, that's strange: we should never be in idle state ! 723: * *after* successfully reading a message byte. ! 724: */ ! 725: ioReturn = SR_IOST_BV; ! 726: reason = "Getting message: bogus idle state"; ! 727: break; ! 728: } ! 729: } ! 730: if (ioReturn != IO_R_SUCCESS) { ! 731: [self fsmStartErrorRecovery ! 732: : ioReturn ! 733: reason : reason ! 734: ]; ! 735: } ! 736: EXIT(); ! 737: } ! 738: ! 739: /* ! 740: * Just finished a message in; ACK is false and the message has been read ! 741: * into gMsgInBuffer[0..gMsgInIndex]. We have not ACK'ed the last byte yet. ! 742: * If we fail here, the caller will start error recovery. ! 743: */ ! 744: - (IOReturn) fsmProcessMessage ! 745: { ! 746: IOReturn ioReturn = IO_R_SUCCESS; ! 747: const char *reason = "(Unknown)"; ! 748: UInt8 queueTag = QUEUE_TAG_NONTAGGED; ! 749: Boolean messageAckNeeded = TRUE; ! 750: ! 751: ENTRY("Bmp fsmProcessMessage"); ! 752: RAW_TAG(OSTag('*', "msg"), gMsgInBuffer[0]); ! 753: /* ! 754: * Message in complete. Handle message(s) in currMsgIn[]. ! 755: */ ! 756: if (gBusState == SCS_RESELECTING) { ! 757: /* ! 758: * The only interesting message here is queue tag. ! 759: * (Hmm, what about target SDTR or Abort?) ! 760: */ ! 761: ASSERT(gActiveCommand == NULL); ! 762: ASSERT(gCurrentTarget != kInvalidTarget && gCurrentLUN != kInvalidLUN); ! 763: ASSERT(gMsgInIndex > 0); ! 764: switch (gMsgInBuffer[0]) { ! 765: case kScsiMsgHeadOfQueueTag: ! 766: case kScsiMsgOrderedQueueTag: ! 767: case kScsiMsgSimpleQueueTag: ! 768: if (gMsgInIndex != 2) { ! 769: ioReturn = SR_IOST_HW; ! 770: reason = "Queue tag message: queue tag without tag value"; ! 771: } ! 772: else { ! 773: ioReturn = [self reselectNexusWithTag : gMsgInBuffer[1]]; ! 774: if (ioReturn != IO_R_SUCCESS) { ! 775: reason = "Tagged queue reselection failed to locate command"; ! 776: } ! 777: } ! 778: break; ! 779: default: ! 780: ddmError("Strange message byte %02x from %d.%d while reselecting (expect tag)\n", ! 781: gMsgInBuffer[0], ! 782: gCurrentTarget, ! 783: gCurrentLUN, ! 784: 4, 5 ! 785: ); ! 786: ioReturn = SR_IOST_HW; ! 787: reason = "Reselection failed (expecting queue tag message)"; ! 788: break; ! 789: } ! 790: if (ioReturn == IO_R_SUCCESS) { ! 791: ASSERT(gActiveCommand != NULL); ! 792: gActiveCommand->currentDataIndex = gActiveCommand->savedDataIndex; ! 793: if (gActiveCommand->mem != NULL) { ! 794: [gActiveCommand->mem setState : &gActiveCommand->savedDataState]; ! 795: } ! 796: } ! 797: /* ! 798: * Since we process commands one by one, whack this command ! 799: * so we fall through the regular message handler. ! 800: */ ! 801: gMsgInBuffer[0] = kScsiMsgNop; ! 802: gMsgInIndex = 1; ! 803: } ! 804: gBusState = SCS_INITIATOR; ! 805: gFlagNeedAnotherInterrupt = TRUE; ! 806: ! 807: switch (gMsgInBuffer[0]) { ! 808: case kScsiMsgNop: ! 809: break; ! 810: case kScsiMsgCmdComplete: ! 811: /* ! 812: * Normally, we get here from fsmCommandComplete. All we need ! 813: * to do is to ack the message and complete the command. Exit ! 814: * in a transitional bus state that becomes SCS_DISCONNECTED ! 815: * when the bus is no longer busy. ! 816: */ ! 817: gBusState = SCS_WAIT_FOR_BUS_FREE; ! 818: /* gFlagBusBusy = FALSE; -- Radar 1678545: wait for interrupt */ ! 819: if (gActiveCommand != NULL) { ! 820: [self ioComplete ! 821: : gActiveCommand ! 822: finalStatus : SR_IOST_GOOD ! 823: ]; ! 824: } ! 825: ASSERT(gActiveCommand == NULL); ! 826: break; ! 827: ! 828: case kScsiMsgDisconnect: ! 829: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 830: if (gActiveCommand->scsiReq->disconnect == FALSE) { ! 831: /* ! 832: * This is bogus; we could do a message reject, but ! 833: * ignoring it is simpler and, probably better. ! 834: */ ! 835: ddmChip("Illegal disconnect for %d.%d\n", ! 836: gActiveCommand->scsiReq->target, ! 837: gActiveCommand->scsiReq->lun, ! 838: 3, 4, 5 ! 839: ); ! 840: #if LOG_ERROR_RECOVERY ! 841: IOLog("%s: Unexpected disconnect attempt from target %d.%d\n", ! 842: [self name], ! 843: gActiveCommand->scsiReq->target, ! 844: gActiveCommand->scsiReq->lun ! 845: ); ! 846: #endif /* LOG_ERROR_RECOVERY */ ! 847: } ! 848: else { ! 849: /* ! 850: * Some targets fail to do a restore pointers before ! 851: * disconnect if all requested data has been transferred. ! 852: * Do an implied save pointers if this is the case. ! 853: */ ! 854: if ( gActiveCommand->currentDataIndex >= gActiveCommand->scsiReq->maxTransfer ) ! 855: gActiveCommand->savedDataIndex = gActiveCommand->currentDataIndex; ! 856: ! 857: if ( gActiveCommand->mem != NULL ) ! 858: [ gActiveCommand->mem state : &gActiveCommand->savedDataState ]; ! 859: [ self disconnect ]; ! 860: } ! 861: /* ! 862: * Exit the interrupt service routine so we don't miss a reselection interrupt. ! 863: */ ! 864: /* gFlagBusBusy = FALSE; -- Radar 1678545: wait for interrupt */ ! 865: gBusState = SCS_WAIT_FOR_BUS_FREE; ! 866: gFlagCheckForAnotherInterrupt = FALSE; ! 867: break; ! 868: case kScsiMsgSaveDataPointers: ! 869: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 870: gActiveCommand->savedDataIndex = gActiveCommand->currentDataIndex; ! 871: if (gActiveCommand->mem != NULL) { ! 872: [gActiveCommand->mem state : &gActiveCommand->savedDataState]; ! 873: } ! 874: break; ! 875: case kScsiMsgRestorePointers: ! 876: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 877: gActiveCommand->currentDataIndex = gActiveCommand->savedDataIndex; ! 878: if (gActiveCommand->mem != NULL) { ! 879: [gActiveCommand->mem setState : &gActiveCommand->savedDataState]; ! 880: } ! 881: break; ! 882: case kScsiMsgRejectMsg: ! 883: /* ! 884: * Hmm, the only message reject we should see would have to be ! 885: * a queue tag (to a device that doesn't do queuing). ! 886: */ ! 887: switch (gLastMsgOut[0]) { ! 888: case kScsiMsgHeadOfQueueTag: ! 889: case kScsiMsgOrderedQueueTag: ! 890: case kScsiMsgSimpleQueueTag: ! 891: [self disableMode : kTargetModeCmdQueue]; ! 892: break; ! 893: default: ! 894: if (gLastMsgOut[0] >= kScsiMsgIdentify ! 895: && (gLastMsgOut[0] & 0x07) != 0) { ! 896: ddmError("Target %d.%d rejected Identify message %02x\n", ! 897: gCurrentTarget, ! 898: gCurrentLUN, ! 899: gLastMsgOut[0], ! 900: 4, 5 ! 901: ); ! 902: #if LOG_ERROR_RECOVERY ! 903: /* ! 904: * The target rejected an identify message for a non-zero ! 905: * LUN. We treat this as a selection failure and tell the ! 906: * target to get off the bus. ! 907: */ ! 908: IOLog("%s: Target %d.%d rejected Identify message %02x\n", ! 909: [self name], ! 910: gCurrentTarget, ! 911: gCurrentLUN, ! 912: gLastMsgOut[0] ! 913: ); ! 914: #endif /* LOG_ERROR_RECOVERY */ ! 915: /* ! 916: * When we send an Abort to a target, we expect that it ! 917: * will immediately go to bus free. Unfortunately, some ! 918: * targets go to MSGI and send us an Abort, too. ! 919: */ ! 920: if (gActiveCommand != NULL) { ! 921: if (gActiveCommand->scsiReq != NULL ! 922: && gActiveCommand->scsiReq->driverStatus == SR_IOST_INVALID) { ! 923: #if 0 ! 924: IOLog("fsmProcessMsg abort: timeout, target %d, int %02x, status %02x, step %02x\n", ! 925: gActiveCommand->scsiReq->target, ! 926: gSaveInterrupt & 0xFF, ! 927: gSaveStatus & 0xFF, ! 928: gSaveSeqStep & 0xFF ! 929: ); ! 930: #endif ! 931: gActiveCommand->scsiReq->driverStatus = SR_IOST_SELTO; ! 932: } ! 933: /* [self ioComplete : gActiveCommand]; 970610 */ ! 934: } ! 935: } ! 936: else { ! 937: ddmError("%s Message rejected from target %d.%d\n", ! 938: IOFindNameForValue(gLastMsgOut[0], scsiMsgValues), ! 939: gCurrentTarget, ! 940: gCurrentLUN, ! 941: 4, 5 ! 942: ); ! 943: #if LOG_ERROR_RECOVERY ! 944: IOLog("%s: %s Message Rejected, that's strange.\n", ! 945: [self name], ! 946: IOFindNameForValue(gLastMsgOut[0], scsiMsgValues) ! 947: ); ! 948: #endif /* LOG_ERROR_RECOVERY */ ! 949: ioReturn = SR_IOST_HW; /* 970610 */ ! 950: } ! 951: /* ioReturn = SR_IOST_HW; 970610 */ ! 952: break; ! 953: } ! 954: case kScsiMsgAbort: ! 955: case kScsiMsgAbortTag: ! 956: if (gActiveCommand != NULL && gActiveCommand->scsiReq != NULL) { ! 957: /* ! 958: * Oops: something is terribly wrong with this command. ! 959: * This can happen if we get a parity error, set ATN, ! 960: * and send an inititor detected error to the target. ! 961: */ ! 962: if (gCurrentTarget != kInvalidTarget) { ! 963: ddmError("Target %d.%d aborted request\n", ! 964: gCurrentTarget, ! 965: gCurrentLUN, ! 966: 3, 4, 5 ! 967: ); ! 968: #if LOG_ERROR_RECOVERY ! 969: IOLog("%s: Target %d.%d aborted request\n", ! 970: [self name], ! 971: gCurrentTarget, ! 972: gCurrentLUN ! 973: ); ! 974: #endif /* LOG_ERROR_RECOVERY */ ! 975: } ! 976: [self ioComplete ! 977: : gActiveCommand ! 978: finalStatus : SR_IOST_HW ! 979: ]; ! 980: gFlagCheckForAnotherInterrupt = FALSE; ! 981: ASSERT(gActiveCommand == NULL); ! 982: } ! 983: /* ! 984: * After receiving an Abort, the target will go free ! 985: */ ! 986: /* gFlagBusBusy = FALSE; -- Radar 1678545: wait for interrupt */ ! 987: gBusState = SCS_WAIT_FOR_BUS_FREE; ! 988: break; ! 989: case kScsiMsgLinkedCmdComplete: ! 990: case kScsiMsgLinkedCmdCompleteFlag: ! 991: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 992: /* ! 993: * These are impossible: we reject commands with the link bit set. ! 994: * About all we can do is to fail the client's command and ! 995: * stagger onwards. ! 996: */ ! 997: IOLog("%s: Target %d.%d terminated with unexpected linked command complete\n", ! 998: [self name], ! 999: gActiveCommand->scsiReq->target, ! 1000: gActiveCommand->scsiReq->lun ! 1001: ); ! 1002: [self ioComplete ! 1003: : gActiveCommand ! 1004: finalStatus : SR_IOST_HW ! 1005: ]; ! 1006: ASSERT(gActiveCommand == NULL); ! 1007: /* gFlagBusBusy = FALSE; -- Radar 1678545: wait for interrupt */ ! 1008: gBusState = SCS_WAIT_FOR_BUS_FREE; ! 1009: break; ! 1010: case kScsiMsgExtended: ! 1011: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 1012: /* ! 1013: * The only expected extended message is synchronous negotiation. ! 1014: * We don't support this yet. ! 1015: */ ! 1016: switch (gMsgInBuffer[2]) { ! 1017: case kScsiMsgSyncXferReq: ! 1018: /* ! 1019: * We don't support SDTR (yet), so send a message reject ! 1020: * (Perhaps it would be better to send an "async only" response, ! 1021: * but message reject is legal.) ! 1022: */ ! 1023: CURIOmessageReject(); ! 1024: messageAckNeeded = FALSE; ! 1025: break; ! 1026: default: ! 1027: ddmError("Unexpected Extended Message (0x%x) received" ! 1028: "from target %d.%d\n", ! 1029: gMsgInBuffer[2], ! 1030: gActiveCommand->scsiReq->target, ! 1031: gActiveCommand->scsiReq->lun, ! 1032: 4, 5 ! 1033: ); ! 1034: CURIOmessageReject(); ! 1035: messageAckNeeded = FALSE; ! 1036: break; ! 1037: } ! 1038: break; ! 1039: default: ! 1040: /* ! 1041: * all others are unacceptable. ! 1042: */ ! 1043: ddmError("Unsupported message (0x%x) received" ! 1044: " from target %d.%d \n", ! 1045: gMsgInBuffer[0], ! 1046: gCurrentTarget, ! 1047: gCurrentLUN, ! 1048: 4, 5 ! 1049: ); ! 1050: CURIOmessageReject(); ! 1051: messageAckNeeded = FALSE; ! 1052: } /* Message byte switch */ ! 1053: if (messageAckNeeded) { ! 1054: CURIOmessageAccept(); ! 1055: } ! 1056: if (ioReturn != IO_R_SUCCESS && gCurrentTarget != kInvalidTarget) { ! 1057: ddmError("Message from target %d.%d failed: %s\n", ! 1058: gCurrentTarget, ! 1059: gCurrentLUN, ! 1060: reason, ! 1061: 4, 5 ! 1062: ); ! 1063: } ! 1064: RESULT(ioReturn); ! 1065: return (ioReturn); ! 1066: } ! 1067: ! 1068: /* ! 1069: * This writes the message byte into the staging buffer. When the target ! 1070: * cycles to MSGO phase, we will send the message from the state automaton. ! 1071: */ ! 1072: - (void) putMessageOutByte ! 1073: : (UInt8) messageByte ! 1074: setATN : (Boolean) setATN ! 1075: { ! 1076: ENTRY("Bmo putMessageOutByte"); ! 1077: ASSERT(gMsgOutPtr < &gMsgOutBuffer[kMessageOutBufferLength]); ! 1078: ASSERT(gMsgPutPtr <= gMsgOutPtr); ! 1079: *gMsgOutPtr++ = messageByte; ! 1080: if (setATN) { ! 1081: CURIOsetATN(); ! 1082: } ! 1083: EXIT(); ! 1084: } ! 1085: ! 1086: /* ! 1087: * Just completed the SCMD_TRANSFER_INFO operation for message out. ! 1088: */ ! 1089: - (void) fsmSendingMsg ! 1090: { ! 1091: ENTRY("Bms fsmSendingMsg"); ! 1092: ddmChip("fsmSendingMsg\n", 1,2,3,4,5); ! 1093: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 1094: EXIT(); ! 1095: } ! 1096: ! 1097: /* ! 1098: * Just completed the SCMD_TRANSFER_INFO operation for command. ! 1099: */ ! 1100: - (void) fsmSendingCmd ! 1101: { ! 1102: ENTRY("Bmc fsmSendingCmd"); ! 1103: ddmChip("fsmSendingCmd\n", 1,2,3,4,5); ! 1104: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 1105: gBusState = SCS_INITIATOR; ! 1106: EXIT(); ! 1107: } ! 1108: ! 1109: /* ! 1110: * Continue to process reselection interrupts. We expect to be in ! 1111: * message in phase in order to get the tagged queue message. Anything ! 1112: * else is an error. ! 1113: */ ! 1114: - (void) fsmReselecting ! 1115: { ! 1116: ENTRY("Bre fsmReselecting"); ! 1117: ! 1118: [self fsmGettingMsg]; ! 1119: if (gBusState == SCS_GETTINGMSG) { ! 1120: gBusState = SCS_RESELECTING; /* continue at fsmReselectinAction */ ! 1121: } ! 1122: EXIT(); ! 1123: } ! 1124: ! 1125: /* ! 1126: * Complete the processing of a reselection interrupt. We have just ack'ed ! 1127: * the identify message. Try to find the command that corresponds to this ! 1128: * target.lun (without a queue tag). If we're successful, complete the ! 1129: * reselection and start following phases by calling fsmPhaseChange directly. ! 1130: * If the first disconnected command has a non-zero tag queue, we expect to ! 1131: * be in messsage in phase, and will receive a tagged queue message in the ! 1132: * fullness of time. ! 1133: */ ! 1134: - (void) fsmReselectionAction ! 1135: { ! 1136: IOReturn ioReturn; ! 1137: ! 1138: ENTRY("Bra fsmReselectionAction"); ! 1139: ioReturn = [self reselectNexusWithoutTag]; ! 1140: if (ioReturn == IO_R_SUCCESS) { ! 1141: /* ! 1142: * We have successfully reselected this target. ! 1143: * Vamp until the target tells us what to do next. ! 1144: */ ! 1145: // [self fsmPhaseChange]; // mlj ??? ! 1146: gBusState = SCS_INITIATOR; ! 1147: } ! 1148: else { ! 1149: /* ! 1150: * We don't have a nexus yet. If we're in MSGI phase, ! 1151: * continue grabbing message bytes until we receive ! 1152: * a queue tag message (we might receive an SDTR), ! 1153: * continuing at fsmReselecting to process interrupts. ! 1154: */ ! 1155: gCurrentBusPhase = gSaveStatus & mPhase; ! 1156: // [curioQuickCheckForChipInterrupt]; ! 1157: if (gCurrentBusPhase == kBusPhaseMSGI) { ! 1158: CURIOstartMSGIAction(); ! 1159: } ! 1160: else { ! 1161: /* ! 1162: * We're in the wrong phase. Bail out. ! 1163: */ ! 1164: [self fsmStartErrorRecovery ! 1165: : ioReturn ! 1166: reason : "Unexpected SCSI bus phase while reselecting" ! 1167: ]; ! 1168: } ! 1169: } ! 1170: EXIT(); ! 1171: } ! 1172: ! 1173: ! 1174: /* ! 1175: * Follow SCSI Phase change. Called while SCS_INITIATOR. ! 1176: */ ! 1177: - (void) fsmPhaseChange ! 1178: { ! 1179: int i; ! 1180: ! 1181: ENTRY("Bph fsmPhaseChange"); ! 1182: ddmChip("fsmPhaseChange, target %d.%d\n", ! 1183: gCurrentTarget, ! 1184: gCurrentLUN, ! 1185: 3, 4, 5 ! 1186: ); ! 1187: gCurrentBusPhase = gSaveStatus & mPhase; ! 1188: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 1189: ASSERT(gCurrentTarget == gActiveCommand->scsiReq->target); ! 1190: ASSERT(gCurrentLUN == gActiveCommand->scsiReq->lun); ! 1191: ddmChip("fsmPhaseChange: phase = %s\n", ! 1192: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues), ! 1193: 2,3,4,5 ! 1194: ); ! 1195: switch (gCurrentBusPhase) { ! 1196: case kBusPhaseCMD: ! 1197: /* ! 1198: * The normal case here is after a host-initiated SDTR sequence. ! 1199: */ ! 1200: CURIOflushFifo(); ! 1201: CURIOputCommandIntoFifo(); ! 1202: CURIOstartNonDMATransfer(); ! 1203: gMsgInState = kMsgInIdle; ! 1204: gBusState = SCS_SENDINGCMD; ! 1205: break; ! 1206: case kBusPhaseDATI: /* From target to Initiator (read) */ ! 1207: case kBusPhaseDATO: /* To Target from Initiator (write) */ ! 1208: gMsgInState = kMsgInIdle; ! 1209: [self fsmStartDataPhase]; ! 1210: gFlagCheckForAnotherInterrupt = FALSE; ! 1211: break; ! 1212: case kBusPhaseSTS: /* Status from Target to Initiator */ ! 1213: /* ! 1214: * fsmCompleting will collect the STATUS byte (and hopefully ! 1215: * a MSG) from the fifo when this completes. ! 1216: */ ! 1217: gMsgInState = kMsgInIdle; ! 1218: gBusState = SCS_COMPLETING; ! 1219: CURIOflushFifo(); ! 1220: CURIOinitiatorCommandComplete(); ! 1221: break; ! 1222: case kBusPhaseMSGI: /* Message from Target to Initiator */ ! 1223: gBusState = SCS_GETTINGMSG; ! 1224: CURIOstartMSGIAction(); ! 1225: break; ! 1226: case kBusPhaseMSGO: /* Message from Initiator to Target */ ! 1227: gMsgInState = kMsgInIdle; ! 1228: CURIOflushFifo(); ! 1229: if (gMsgPutPtr == gMsgOutPtr) { ! 1230: /* ! 1231: * Hmm, there is no message waiting to be sent. ! 1232: */ ! 1233: *gMsgOutPtr++ = kScsiMsgNop; ! 1234: ddmChip("msg out (%d.%d): forced nop\n", ! 1235: gCurrentTarget, ! 1236: gCurrentLUN, ! 1237: 3, 4, 5 ! 1238: ); ! 1239: } ! 1240: for (i = 0; i < 16 && gMsgPutPtr < gMsgOutPtr; i++) { ! 1241: ddmChip("msg out[%d] = %02x\n", i, *gMsgPutPtr, 3, 4, 5); ! 1242: CURIOputByteIntoFifo(*gMsgPutPtr); ! 1243: gMsgPutPtr++; ! 1244: } ! 1245: if (gMsgPutPtr == gMsgOutPtr) { ! 1246: gMsgPutPtr = gMsgOutPtr = gMsgOutBuffer; ! 1247: } ! 1248: gBusState = SCS_SENDINGMSG; ! 1249: /* ! 1250: * ATN is automatically cleared when transfer info completes. ! 1251: */ ! 1252: CURIOstartNonDMATransfer(); ! 1253: break; ! 1254: default: ! 1255: [self fsmStartErrorRecovery ! 1256: : SR_IOST_HW ! 1257: reason : "Strange bus phase" ! 1258: ]; ! 1259: break; ! 1260: } ! 1261: EXIT(); ! 1262: } ! 1263: ! 1264: - (void) fsmStartDataPhase ! 1265: { ! 1266: UInt32 phase; ! 1267: IOReturn ioReturn = IO_R_SUCCESS; ! 1268: const char *reason = NULL; ! 1269: Boolean isReadOK; ! 1270: ! 1271: ! 1272: ENTRY("Bdp startDataPhase"); ! 1273: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 1274: phase = gSaveStatus & mPhase; ! 1275: /* ! 1276: * Data in phase is legal if this is a read command or we're ! 1277: * doing autosense. ! 1278: */ ! 1279: isReadOK = (gActiveCommand->scsiReq->read || gActiveCommand->flagIsAutosense); ! 1280: if ((phase == kBusPhaseDATI) != isReadOK) { ! 1281: ioReturn = SR_IOST_BV; ! 1282: reason = "bad I/O direction"; ! 1283: } ! 1284: if (ioReturn == IO_R_SUCCESS) { ! 1285: ioReturn = [self hardwareInitializeCCL]; ! 1286: if (ioReturn != IO_R_SUCCESS) { ! 1287: reason = "Cannot setup DBDMA Channel Command area"; ! 1288: } ! 1289: } ! 1290: if (ioReturn == IO_R_SUCCESS) { ! 1291: if (gActiveCommand->thisTransferLength == 0) { ! 1292: ioReturn = IO_R_BV; ! 1293: reason = "No data for transfer"; ! 1294: } ! 1295: } ! 1296: if (ioReturn == IO_R_SUCCESS) { ! 1297: DBDMASetCommandPtr((UInt32) gDBDMAChannelAddress); ! 1298: DBDMAstartTransfer(); ! 1299: CURIOstartDMATransfer(gActiveCommand->thisTransferLength); ! 1300: gBusState = SCS_DMACOMPLETE; ! 1301: } ! 1302: if (ioReturn != IO_R_SUCCESS) { ! 1303: [self fsmStartErrorRecovery ! 1304: : ioReturn ! 1305: reason : "Illegal Data Phase (wrong direction or length error)" ! 1306: ]; ! 1307: } ! 1308: EXIT(); ! 1309: } ! 1310: ! 1311: /* ! 1312: * Start error recovery by doing something reasonable for the current bus ! 1313: * phase. This is called when we enter error recovery (SCS_DEATH_MARCH) ! 1314: * from an interrupt or other bus phase action handler. ! 1315: */ ! 1316: - (void) fsmStartErrorRecovery ! 1317: : (sc_status_t) status ! 1318: reason : (const char *) reason ! 1319: { ! 1320: ENTRY("Bes fsmStartErrorRecovery"); ! 1321: TAG(__tag__, status); ! 1322: ddmChip("fsmStartErrorRecovery for %d.%d, phase \"%s\", status \"%s\": %s\n", ! 1323: gCurrentTarget, ! 1324: gCurrentLUN, ! 1325: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues), ! 1326: IOFindNameForValue(status, IOScStatusStrings), ! 1327: (reason == NULL) ? "unspecified" : reason ! 1328: ); ! 1329: #if LOG_ERROR_RECOVERY ! 1330: if (gActiveCommand != NULL ! 1331: && gActiveCommand->scsiReq != NULL ! 1332: && gActiveCommand->scsiReq->target == gCurrentTarget ! 1333: && gActiveCommand->scsiReq->lun == gCurrentLUN) { ! 1334: IOLog("%s: Error recovery: active target %d.%d, error \"%s\" (\"%s\"), bus phase %s\n", ! 1335: [self name], ! 1336: gCurrentTarget, ! 1337: gCurrentLUN, ! 1338: IOFindNameForValue(status, IOScStatusStrings), ! 1339: (reason == NULL) ? "no further explanation" : reason, ! 1340: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues) ! 1341: ); ! 1342: } ! 1343: else if (gActiveCommand != NULL && gActiveCommand->scsiReq != NULL) { ! 1344: IOLog("%s: Error recovery: command target %d.%d, error \"%s\" (\"%s\"), bus phase %s\n", ! 1345: [self name], ! 1346: gActiveCommand->scsiReq->target, ! 1347: gActiveCommand->scsiReq->lun, ! 1348: IOFindNameForValue(status, IOScStatusStrings), ! 1349: (reason == NULL) ? "no further explanation" : reason, ! 1350: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues) ! 1351: ); ! 1352: } ! 1353: else if (gCurrentTarget != kInvalidTarget && gCurrentLUN != kInvalidLUN) { ! 1354: IOLog("%s: Error Recovery: expected target %d.%d, error \"%s\" (\"%s\"), bus phase %s\n", ! 1355: [self name], ! 1356: gCurrentTarget, ! 1357: gCurrentLUN, ! 1358: IOFindNameForValue(status, IOScStatusStrings), ! 1359: (reason == NULL) ? "no further explanation" : reason, ! 1360: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues) ! 1361: ); ! 1362: } ! 1363: else if (gCurrentTarget != kInvalidTarget && gCurrentLUN == kInvalidLUN) { ! 1364: IOLog("%s: Error recovery: command target %d.[no lun], error \"%s\" (\"%s\"), bus phase %s\n", ! 1365: [self name], ! 1366: gCurrentTarget, ! 1367: IOFindNameForValue(status, IOScStatusStrings), ! 1368: (reason == NULL) ? "no further explanation" : reason, ! 1369: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues) ! 1370: ); ! 1371: } ! 1372: else { ! 1373: IOLog("%s: Error recovery: no current target, error \"%s\" (\"%s\"), bus phase %s\n", ! 1374: [self name], ! 1375: IOFindNameForValue(status, IOScStatusStrings), ! 1376: (reason == NULL) ? "no further explanation" : reason, ! 1377: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues) ! 1378: ); ! 1379: } ! 1380: [self logRegisters : FALSE reason : "At error recovery start"]; ! 1381: #endif /* LOG_ERROR_RECOVERY */ ! 1382: [self killActiveCommand : status]; ! 1383: /* ! 1384: * Clean out the scsi and dbdma chips ! 1385: */ ! 1386: CURIOflushFifo(); ! 1387: CURIOclearTransferCountZeroBit(); ! 1388: DBDMAreset(); ! 1389: if (gFlagBusBusy == FALSE) { ! 1390: gBusState = SCS_DISCONNECTED; ! 1391: } ! 1392: else { ! 1393: /* ! 1394: * We will continue at fsmContinueErrorRecovery ! 1395: */ ! 1396: gBusState = SCS_DEATH_MARCH; ! 1397: } ! 1398: gFlagCheckForAnotherInterrupt = FALSE; ! 1399: EXIT(); ! 1400: } ! 1401: ! 1402: /* ! 1403: * Manage error recovery by responding to a target interrupt while in ! 1404: * an error recovery state. On exit, the bus state will be as follows: ! 1405: * SCS_DEATH_MARCH Still in error recovery. Call fsmContinueErrorRecovery ! 1406: * to continue processing target requests. ! 1407: * SCS_DISCONNECTED The target is finally off the bus. We can restart ! 1408: * normal operation. ! 1409: * Each bus phase requires a different action: ! 1410: * Data Out Clean up after DMA. ! 1411: * Data In Clean up after DMA. ! 1412: * Command Flush the fifo ! 1413: * Status Drain the fifo, if we get two bytes, just ACK the message ! 1414: * Message Out Do nothing ! 1415: * Message In Read the message byte, ACK it. ! 1416: */ ! 1417: - (void) fsmErrorRecoveryInterruptService ! 1418: { ! 1419: ENTRY("Bei fsmErrorRecoveryInterruptService"); ! 1420: #if LOG_ERROR_RECOVERY ! 1421: [self logRegisters : FALSE reason : "At error recovery interrupt"]; ! 1422: IOLog("%s: Error recovery interrupt in bus phase %s, sts %02x, int %02x\n", ! 1423: [self name], ! 1424: IOFindNameForValue(gSaveStatus & mPhase, scsiPhaseValues), ! 1425: gSaveStatus, ! 1426: gSaveInterrupt ! 1427: ); ! 1428: #endif ! 1429: CURIOflushFifo(); ! 1430: switch (gCurrentBusPhase) { ! 1431: case kBusPhaseDATO: ! 1432: case kBusPhaseDATI: ! 1433: #if LOG_ERROR_RECOVERY ! 1434: IOLog("%s: Error recovery interrupt in data in/out phase\n", [self name]); ! 1435: #endif ! 1436: DBDMAreset(); ! 1437: CURIOclearTransferCountZeroBit(); ! 1438: break; ! 1439: case kBusPhaseCMD: ! 1440: #if LOG_ERROR_RECOVERY ! 1441: IOLog("%s: Error recovery interrupt in command phase\n", [self name]); ! 1442: #endif ! 1443: break; ! 1444: case kBusPhaseSTS: ! 1445: #if LOG_ERROR_RECOVERY ! 1446: IOLog("%s: Error recovery interrupt in status phase\n", [self name]); ! 1447: #endif ! 1448: if ((gSaveInterrupt & iFuncComp) != 0) { ! 1449: #if LOG_ERROR_RECOVERY ! 1450: IOLog("%s: Error recovery interrupt in status phase with complete msg\n", ! 1451: [self name] ! 1452: ); ! 1453: #endif ! 1454: /* ! 1455: * We got both bytes: ACK the command complete ! 1456: */ ! 1457: CURIOmessageAccept(); ! 1458: } ! 1459: break; ! 1460: case kBusPhaseMSGO: ! 1461: #if LOG_ERROR_RECOVERY ! 1462: IOLog("%s: Error recovery interrupt in message out phase\n", [self name]); ! 1463: #endif ! 1464: break; ! 1465: case kBusPhaseMSGI: ! 1466: #if LOG_ERROR_RECOVERY ! 1467: IOLog("%s: Error recovery interrupt in message in phase\n", [self name]); ! 1468: #endif ! 1469: CURIOmessageAccept(); ! 1470: break; ! 1471: case kBusPhaseBusFree: /* Selecting */ ! 1472: #if LOG_ERROR_RECOVERY ! 1473: IOLog("%s: Error recovery interrupt at bus free\n", [self name]); ! 1474: #endif ! 1475: break; ! 1476: default: ! 1477: #if LOG_ERROR_RECOVERY ! 1478: IOLog("%s: Strange bus phase %d in error recovery\n", ! 1479: [self name], ! 1480: gCurrentBusPhase ! 1481: ); ! 1482: #endif ! 1483: [self killActiveCommandAndResetBus ! 1484: : SR_IOST_HW ! 1485: reason : "Strange SCSI phase in error recovery interrupt" ! 1486: ]; ! 1487: break; ! 1488: } ! 1489: EXIT(); ! 1490: } ! 1491: ! 1492: /* ! 1493: * Continue to manage error recovery. We are here because the target ! 1494: * is still on the bus and doing strange bus phase things. Follow ! 1495: * the target bus phase (one phase at a time) until the target ! 1496: * disconnects. We just run bit-bucket commands until the target ! 1497: * gives up. (Note that this means that we might send a Command Complete ! 1498: * message to the target. We'll look for this case and send an Abort ! 1499: * or Abort Tag instead.) ! 1500: */ ! 1501: - (void) fsmContinueErrorRecovery ! 1502: { ! 1503: UInt8 msgByte; ! 1504: ! 1505: ENTRY("Bec fsmContinueErrorRecovery"); ! 1506: CURIOquickCheckForChipInterrupt(); ! 1507: #if LOG_ERROR_RECOVERY ! 1508: IOLog("%s: Error recovery continues in bus phase %s, sts %02x, int %02x\n", ! 1509: [self name], ! 1510: IOFindNameForValue(gSaveStatus & mPhase, scsiPhaseValues), ! 1511: gSaveStatus, ! 1512: gSaveInterrupt ! 1513: ); ! 1514: #endif ! 1515: if (gFlagBusBusy) { ! 1516: (void) CURIOinterruptPending(); ! 1517: if ((gSaveInterrupt & iDisconnect) != 0) { ! 1518: gFlagBusBusy = FALSE; ! 1519: } ! 1520: } ! 1521: if (gFlagBusBusy == FALSE) { ! 1522: gBusState = SCS_DISCONNECTED; ! 1523: } ! 1524: else { ! 1525: gCurrentBusPhase = gSaveStatus & mPhase; ! 1526: switch (gCurrentBusPhase) { ! 1527: case kBusPhaseMSGO: ! 1528: msgByte = kScsiMsgAbort; ! 1529: if (gActiveCommand != NULL ! 1530: && gActiveCommand->queueTag != QUEUE_TAG_NONTAGGED) { ! 1531: msgByte = kScsiMsgAbortTag; ! 1532: } ! 1533: CURIOputByteIntoFifo(msgByte); ! 1534: CURIOstartNonDMATransfer(); ! 1535: break; ! 1536: case kBusPhaseDATO: ! 1537: case kBusPhaseCMD: ! 1538: CURIOtransferPad(TRUE); /* Output pad */ ! 1539: break; ! 1540: case kBusPhaseMSGI: ! 1541: case kBusPhaseDATI: ! 1542: case kBusPhaseSTS: ! 1543: CURIOtransferPad(FALSE); /* Input pad */ ! 1544: break; ! 1545: default: ! 1546: [self killActiveCommandAndResetBus ! 1547: : SR_IOST_HW ! 1548: reason : "Strange SCSI phase in error recovery" ! 1549: ]; ! 1550: break; ! 1551: } ! 1552: } ! 1553: #if LOG_ERROR_RECOVERY ! 1554: [self logRegisters : FALSE reason : "Registers at error recovery action exit"]; ! 1555: #endif /* -Debug */ ! 1556: EXIT(); ! 1557: } ! 1558: ! 1559: /* ! 1560: * Disable specified mode for gActiveCommand's target. If mode is currently ! 1561: * enabled, we'll log a message to the console. ! 1562: */ ! 1563: - (void) disableMode : (TargetMode) mode ! 1564: { ! 1565: int target; ! 1566: PerTargetData *perTargetPtr; ! 1567: const char *modeStr = NULL; ! 1568: ! 1569: ENTRY("Bdm disableMode"); ! 1570: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL); ! 1571: target = gActiveCommand->scsiReq->target; ! 1572: perTargetPtr = &gPerTargetData[target]; ! 1573: switch (mode) { ! 1574: case kTargetModeCmdQueue: ! 1575: if (perTargetPtr->cmdQueueDisable == 0) { ! 1576: perTargetPtr->cmdQueueDisable = 1; ! 1577: modeStr = "Command Queueing"; ! 1578: } ! 1579: break; ! 1580: default: ! 1581: IOLog("%s: Bogus target mode %d for target %d\n", ! 1582: [self name], ! 1583: mode, ! 1584: target ! 1585: ); ! 1586: break; ! 1587: } ! 1588: ddmChip("DISABLING %s for target %d\n", modeStr, target, 3,4,5); ! 1589: if (modeStr != NULL) { ! 1590: IOLog("%s: DISABLING %s for target %d\n", ! 1591: [self name], ! 1592: modeStr, ! 1593: target ! 1594: ); ! 1595: } ! 1596: EXIT(); ! 1597: } ! 1598: ! 1599: /** ! 1600: * Validate the target's reselection byte (put on the bus before ! 1601: * reselecting us). Erase the initiator ID and convert the other ! 1602: * bit into an index. The algorithm should be faster than a ! 1603: * sequential search, but it probably doesn't matter much. ! 1604: * @return TRUE if successful (gCurrentTarget is now valid). ! 1605: * This function does not check whether there actually ! 1606: * is a command pending for this target. ! 1607: */ ! 1608: - (IOReturn) getReselectionTargetID ! 1609: : (UInt8) selectByte ! 1610: { ! 1611: IOReturn ioReturn = SR_IOST_BV; ! 1612: register UInt8 targetBits = selectByte; ! 1613: register UInt8 targetID = 0; ! 1614: register UInt8 bitValue = 0; /* Supress warning */ ! 1615: ! 1616: ENTRY("Brt getReselectionTargetID"); ! 1617: if ((targetBits & gInitiatorIDMask) == 0) { ! 1618: IOLog("%s: Reselection failed: initiator ID bit not set, got %02x\n", ! 1619: [self name], ! 1620: selectByte ! 1621: ); ! 1622: } ! 1623: else { ! 1624: targetBits &= ~gInitiatorIDMask; /* Remove our bit */ ! 1625: if (targetBits == 0) { ! 1626: IOLog("%s: Reselection failed: target ID bit not set, got %02x\n", ! 1627: [self name], ! 1628: selectByte ! 1629: ); ! 1630: } ! 1631: else { ! 1632: bitValue = targetBits; ! 1633: if ((bitValue > 0x0F) != 0) { ! 1634: targetID += 4; ! 1635: bitValue >>= 4; ! 1636: } ! 1637: if ((bitValue > 0x03) != 0) { ! 1638: targetID += 2; ! 1639: bitValue >>= 2; ! 1640: } ! 1641: if ((bitValue > 0x01) != 0) { ! 1642: targetID += 1; ! 1643: } ! 1644: targetBits &= ~(1 << targetID); /* Remove the target mask */ ! 1645: if (targetBits == 0) { /* Was exactly one set? */ ! 1646: ioReturn = IO_R_SUCCESS; /* Yes: success! */ ! 1647: gCurrentTarget = targetID; /* Save the current target */ ! 1648: ddmChip("Reselection from target %d\n", ! 1649: gCurrentTarget, ! 1650: 2, 3, 4, 5 ! 1651: ); ! 1652: } ! 1653: else { ! 1654: IOLog("%s: Reselection failed, multiple targets, got %02x\n", ! 1655: [self name], ! 1656: selectByte ! 1657: ); ! 1658: } ! 1659: } ! 1660: } ! 1661: RESULT(ioReturn); ! 1662: return (ioReturn); ! 1663: } ! 1664: ! 1665: @end /* Apple96_SCSI(BusState) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.