|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: ! 23: /* Copyright 1997-1999 Apple Computer Inc. All Rights Reserved. */ ! 24: /* @author Martin Minow */ ! 25: /* Edit History */ ! 26: /* 1997.02.13 MM Initial conversion from AMDPCSCSIDriver sources. */ ! 27: /* */ ! 28: ! 29: ! 30: ! 31: ! 32: #include <string.h> /* bzero is defined in string.h */ ! 33: #include <mach/clock_types.h> ! 34: #include <libkern/OSByteOrder.h> ! 35: #include <IOKit/IOLib.h> ! 36: #include <IOKit/IOInterruptEventSource.h> ! 37: #include <IOKit/pci/IOPCIDevice.h> ! 38: #include <IOKit/ppc/IODBDMA.h> ! 39: #include <IOKit/system.h> /* Definition of flush_dcache */ ! 40: #include <IOKit/scsi/IOSCSIParallelInterface.h> ! 41: ! 42: #include "curio.h" ! 43: ! 44: ! 45: ! 46: ! 47: extern void IOGetTime( mach_timespec_t *clock_time ); ! 48: extern void kprintf( const char *, ... ); ! 49: extern void call_kdp(); // for debugging ! 50: ! 51: ! 52: #if CustomMiniMon ! 53: extern globals g; /**** Use custom MiniMon's globals ****/ ! 54: extern UInt32 gMESH_DBDMA, gMESH_DBDMA_Phys; ! 55: #else ! 56: // globals g; /**** Instantiate the globals ****/ ! 57: static globals g; /**** Instantiate the globals ****/ ! 58: #endif /* CustomMiniMon */ ! 59: ! 60: ! 61: OSDefineMetaClassAndStructors( CurioSCSIController, IOSCSIParallelController ) ; ! 62: ! 63: ! 64: #define kIOReturnParityError kIOReturnIOError /// ??? add to IOReturn.h ! 65: #define kIOReturnSelectionError kIOReturnIOError /// ??? add to IOReturn.h ! 66: ! 67: ! 68: enum /***** values for g.intLevel: *****/ ! 69: { ! 70: kLevelISR = 0x80, /* In Interrupt Service Routine */ ! 71: kLevelLocked = 0x40, /* Curio interrupts locked out */ ! 72: kLevelSIH = 0x20, /* In Secondary Interrupt Handler */ ! 73: kLevelLatched = 0x10 /* Interrupt latched */ ! 74: }; ! 75: ! 76: ! 77: ! 78: #if USE_ELG && !CustomMiniMon ! 79: static void AllocateEventLog( UInt32 size ) ! 80: { ! 81: if ( g.evLogBuf ) ! 82: return; ! 83: ! 84: g.evLogFlag = 0; /* assume insufficient memory */ ! 85: g.evLogBuf = (UInt8*)kalloc( size ); ! 86: if ( !g.evLogBuf ) ! 87: { ! 88: kprintf( "AllocateEventLog - CurioSCSIController evLog allocation failed " ); ! 89: return; ! 90: } ! 91: ! 92: bzero( g.evLogBuf, size ); ! 93: g.evLogBufp = g.evLogBuf; ! 94: g.evLogBufe = g.evLogBufp + kEvLogSize - 0x20; // ??? overran buffer? ! 95: g.evLogFlag = 0xFEEDBEEF; ! 96: // g.evLogFlag = 'step'; ! 97: // g.evLogFlag = 0x0333; ! 98: return; ! 99: }/* end AllocateEventLog */ ! 100: ! 101: ! 102: static void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str ) ! 103: { ! 104: register UInt32 *lp; /* Long pointer */ ! 105: mach_timespec_t time; ! 106: ! 107: if ( g.evLogFlag == 0 ) ! 108: return; ! 109: ! 110: IOGetTime( &time ); ! 111: ! 112: lp = (UInt32*)g.evLogBufp; ! 113: g.evLogBufp += 0x10; ! 114: ! 115: if ( g.evLogBufp >= g.evLogBufe ) /* handle buffer wrap around if any */ ! 116: { g.evLogBufp = g.evLogBuf; ! 117: if ( g.evLogFlag != 0xFEEDBEEF ) ! 118: g.evLogFlag = 0; /* stop tracing if wrap undesired */ ! 119: } ! 120: ! 121: /* compose interrupt level with 3 byte time stamp: */ ! 122: ! 123: *lp++ = (g.intLevel << 24) | ((time.tv_nsec >> 10) & 0x003FFFFF); // ~ 1 microsec resolution ! 124: *lp++ = a; ! 125: *lp++ = b; ! 126: *lp = ascii; ! 127: ! 128: if( g.evLogFlag == 'step' ) ! 129: { char code[ 5 ]; ! 130: *(UInt32*)&code = ascii; code[ 4 ] = 0; ! 131: // kprintf( "%8x curio: %8x %8x %s %s\n", time.tv_nsec>>10, a, b, code, str ); ! 132: kprintf( "%8x curio: %8x %8x %s\n", time.tv_nsec>>10, a, b, code ); ! 133: } ! 134: ! 135: return; ! 136: }/* end EvLog */ ! 137: ! 138: ! 139: static void Pause( UInt32 a, UInt32 b, UInt32 ascii, char* str ) ! 140: { ! 141: char work [ 256 ]; ! 142: char name[] = "CurioSCSIController:"; ! 143: char *bp = work; ! 144: UInt8 x; ! 145: int i; ! 146: ! 147: ! 148: EvLog( a, b, ascii, str ); ! 149: EvLog( '****', '** P', 'ause', "*** Pause" ); ! 150: ! 151: bcopy( name, bp, sizeof( name ) ); ! 152: bp += sizeof( name ) - 1; ! 153: ! 154: *bp++ = '{'; // prepend p1 in hex: ! 155: for ( i = 7; i >= 0; --i ) ! 156: { ! 157: x = a & 0x0F; ! 158: if ( x < 10 ) ! 159: x += '0'; ! 160: else x += 'A' - 10; ! 161: bp[ i ] = x; ! 162: a >>= 4; ! 163: } ! 164: bp += 8; ! 165: ! 166: *bp++ = ' '; // prepend p2 in hex: ! 167: ! 168: for ( i = 7; i >= 0; --i ) ! 169: { ! 170: x = b & 0x0F; ! 171: if ( x < 10 ) ! 172: x += '0'; ! 173: else x += 'A' - 10; ! 174: bp[ i ] = x; ! 175: b >>= 4; ! 176: } ! 177: bp += 8; ! 178: *bp++ = '}'; ! 179: ! 180: *bp++ = ' '; ! 181: ! 182: for ( i = sizeof( work ) - (int)(bp - work); i && (*bp++ = *str++); --i ) ; ! 183: ! 184: // kprintf( work ); ! 185: panic( work ); ! 186: // call_kdp(); // ??? use kdp=3 in boot parameters ! 187: return; ! 188: }/* end Pause */ ! 189: #endif /* not CustomMiniMon */ ! 190: ! 191: ! 192: ! 193: bool CurioSCSIController::configure( IOService *provider, ! 194: SCSIControllerInfo *controllerInfo ) ! 195: { ! 196: IOReturn ioReturn = kIOReturnInternalError; ! 197: ! 198: ! 199: g.intLevel = 0; ! 200: g.curioInstance = this; ! 201: #if USE_ELG ! 202: AllocateEventLog( kEvLogSize ); ! 203: ELG( g.evLogBufp, &g.evLogFlag, 'Curo', "configure - event logging set up." ); ! 204: #endif /* USE_ELG */ ! 205: ! 206: ELG( this, provider, 'Cnfg', "configure" ); ! 207: ! 208: fProvider = (IOPCIDevice*)provider; ! 209: ! 210: ioReturn = initHardware(); ! 211: if ( ioReturn != kIOReturnSuccess ) ! 212: return false; ! 213: ! 214: /* Register our interrupt handler routine: */ ! 215: ! 216: fInterruptEvent = IOInterruptEventSource::interruptEventSource( ! 217: (OSObject*)this, ! 218: ! 219: (IOInterruptEventAction)&CurioSCSIController::interruptOccurred, ! 220: provider, ! 221: 0 ); ! 222: ! 223: if ( fInterruptEvent == NULL ) ! 224: { ! 225: ELG( 0, 0, 'IES-', "CurioSCSIController::configure - can't register interrupt action" ); ! 226: return false; ! 227: } ! 228: ! 229: getWorkLoop()->addEventSource( fInterruptEvent ); ! 230: fInterruptEvent->enable(); ! 231: ! 232: /* allocate a big-endian memory cursor: */ ! 233: ! 234: fMemoryCursor = IOBigMemoryCursor::withSpecification( kMaxDMATransfer, kMaxDMATransfer ); ! 235: if ( fMemoryCursor == NULL ) ! 236: { ! 237: ELG( 0, kMaxDMATransfer, 'Mem-', "CurioSCSIController::start - IOBigMemoryCursor::withSpecification NG" ); ! 238: return false; ! 239: } ! 240: ! 241: ! 242: /* Fill in the SCSIControllerInfo structure and return: */ ! 243: ! 244: controllerInfo->initiatorId = 7; ! 245: ! 246: controllerInfo->maxTargetsSupported = 8; ! 247: controllerInfo->maxLunsSupported = 8; ! 248: ! 249: controllerInfo->minTransferPeriodpS = 200000; /* picoSecs for 5 MHz */ ! 250: controllerInfo->maxTransferOffset = 0; ! 251: controllerInfo->maxTransferWidth = 1; ! 252: ! 253: controllerInfo->maxCommandsPerController= 0; // 0 is unlimited ! 254: controllerInfo->maxCommandsPerTarget = 0; ! 255: controllerInfo->maxCommandsPerLun = 0; ! 256: ! 257: controllerInfo->tagAllocationMethod = kTagAllocationPerLun; ! 258: controllerInfo->maxTags = 256; ! 259: ! 260: controllerInfo->commandPrivateDataSize = sizeof( PrivCmdData ); ! 261: ! 262: controllerInfo->disableCancelCommands = false; ! 263: ! 264: return true; ! 265: }/* end configure */ ! 266: ! 267: ! 268: void CurioSCSIController::executeCommand( IOSCSICommand *scsiCommand ) ! 269: { ! 270: SCSICDBInfo scsiCDB; ! 271: SCSITargetParms targetParms; ! 272: UInt8 msgByte; ! 273: bool rc; ! 274: ! 275: ! 276: ! 277: if ( fCmd || fBusBusy ) ! 278: { ! 279: ELG( fCmd, scsiCommand, 'Busy', "CurioSCSIController::executeCommand - bus busy so bounce this cmd" ); ! 280: disableCommands(); ! 281: rescheduleCommand( scsiCommand ); ! 282: return; ! 283: } ! 284: ! 285: fCmd = scsiCommand; ! 286: fCmdData = (PrivCmdData*)scsiCommand->getCommandData(); ! 287: ! 288: scsiCommand->getTargetLun( &fCurrentTargetLun ); ! 289: scsiCommand->getCDB( &scsiCDB ); ! 290: scsiCommand->getDevice(kIOSCSIDevice)->getTargetParms( &targetParms ); ! 291: ! 292: ELG( scsiCommand, ! 293: *(UInt16*)&fCurrentTargetLun<<16 | (scsiCDB.cdbTag & 0xFF), ! 294: 'Exec', "CurioSCSIController::executeCommand" ); ! 295: ELG( *(UInt32*)&scsiCDB.cdb[0], *(UInt32*)&scsiCDB.cdb[4] , '=CDB', "executeCommand - CDB" ); ! 296: ! 297: fpMsgOut = fpMsgPut = &fMsgOutBuffer[ 0 ]; ! 298: ! 299: /* Identify byte: */ ! 300: ! 301: msgByte = kSCSIMsgIdentify | kSCSIMsgEnableDisconnectMask | fCurrentTargetLun.lun; ! 302: if ( scsiCDB.cdbFlags & kCDBFlagsNoDisconnect ) ! 303: msgByte &= ~kSCSIMsgEnableDisconnectMask; ! 304: *fpMsgOut++ = msgByte; ! 305: ! 306: /* Tag msg: */ ! 307: ! 308: if ( scsiCDB.cdbTagMsg ) ! 309: { ! 310: *fpMsgOut++ = scsiCDB.cdbTagMsg; ! 311: *fpMsgOut++ = scsiCDB.cdbTag; ! 312: ELG( 0, scsiCDB.cdbTagMsg<<16 | (scsiCDB.cdbTag & 0xFF), ' tag', "CurioSCSIController::executeCommand - tag" ); ! 313: } ! 314: ! 315: /* Abort msg: */ ! 316: ! 317: if ( scsiCDB.cdbAbortMsg ) ! 318: { ! 319: ELG( scsiCommand->getOriginalCmd(), scsiCDB.cdbAbortMsg, 'Abor', "CurioSCSIController::executeCommand - abort msg." ); ! 320: *fpMsgOut++ = scsiCDB.cdbAbortMsg; ! 321: } ! 322: ! 323: fMsgOutCount = (UInt8)(fpMsgOut - &fMsgOutBuffer[ 0 ]); ! 324: ELG( fMsgOutCount, *(UInt32*)&fMsgOutBuffer[0], '=MgO', "executeCommand" ); ! 325: ! 326: /***** Try to start the command on the hardware: *****/ ! 327: ! 328: rc = startCommand(); /* Call the hardware layer. */ ! 329: ! 330: if ( rc ) ! 331: { /* Hardware can't start now */ ! 332: ELG( fCmd, 0, 'Exe-', "CurioSCSIController::executeCommand - command bounced back" ); ! 333: fCmd = NULL; /// ?redundant? - rescheduleCommand done in fsmSelecting ! 334: return; ! 335: } ! 336: ! 337: return; ! 338: }/* end executeCommand */ ! 339: ! 340: ! 341: ! 342: bool CurioSCSIController::startCommand() ! 343: { ! 344: SCSICDBInfo scsiCDB; ! 345: UInt8 selectCmd; ! 346: ! 347: ! 348: fCmd->getPointers( &fCmdData->mdp, &fCmdData->xferCount, &fCmdData->isWrite ); ! 349: ! 350: fCmdData->results.bytesTransferred = 0; ! 351: fCmdData->savedDataPosition = 0; ! 352: ! 353: fCmd->getCDB( &scsiCDB ); ! 354: ! 355: setCmdReg( cFlshFFO ); ! 356: WRITE_REGISTER( rSTA, fCurrentTargetLun.target ); ! 357: ! 358: /* Put the contents of the message buffer into the FIFO. */ ! 359: /* Figure out which flavor of Select command is indicated. */ ! 360: /* The command depends on the number of message bytes. */ ! 361: ! 362: switch ( fMsgOutCount ) ! 363: { ! 364: case 0: /* Select, no ATN, send CDB */ ! 365: selectCmd = cSlctNoAtn; ! 366: break; ! 367: ! 368: case 1: /* Select, ATN, 1 Msg, send CDB */ ! 369: selectCmd = cSlctAtn; ! 370: break; ! 371: ! 372: case 3: /* Select, ATN, 3 Msg, send CDB */ ! 373: selectCmd = cSlctAtn3; ! 374: break; ! 375: ! 376: default: /* Select, ATN, 1 Msg, stop */ ! 377: selectCmd = cSlctAtnStp; ! 378: break; ! 379: }/* end SWITCH on size of MsgOut */ ! 380: ! 381: if ( (fMsgOutCount > 3) || (fMsgOutCount + scsiCDB.cdbLength >= 16) ) ! 382: { /* The FIFO only holds 16 bytes. */ ! 383: /* We have to do the command phase in the state automaton. */ ! 384: WRITE_REGISTER( rFFO, *fpMsgPut++ ); ! 385: selectCmd = cSlctAtnStp; ! 386: } ! 387: else ! 388: { /* MsgOut and CDB both fit in FIFO: */ ! 389: while ( fpMsgPut < fpMsgOut ) ! 390: { ! 391: WRITE_REGISTER( rFFO, *fpMsgPut++ ); ! 392: } ! 393: } ! 394: ! 395: if ( selectCmd != cSlctAtnStp ) ! 396: { /* If we're not stopping after the messages, */ ! 397: /* stuff the command into the FIFO, too. */ ! 398: putCDBIntoFIFO(); ! 399: } ! 400: /* Init the finite state automaton: */ ! 401: ! 402: fBusState = SCS_SELECTING; ! 403: fCurrentBusPhase = kBusPhaseBusFree; ! 404: ! 405: /***** Issue the Arbitrate/Select/MessageOut combo: *****/ ! 406: ! 407: setCmdReg( selectCmd ); ! 408: ! 409: return false; /* return No Problem */ ! 410: }/* end startCommand */ ! 411: ! 412: ! 413: void CurioSCSIController::completeCommand() ! 414: { ! 415: ELG( fCmdData->results.returnCode, fCmdData->results.bytesTransferred, ' IOC', "CurioSCSIController::completeCommand" ); ! 416: ! 417: switch ( fCmdData->results.scsiStatus ) ! 418: { ! 419: case kSCSIStatusGood: ! 420: break; ! 421: ! 422: case kSCSIStatusCheckCondition: ! 423: ELG( 0, 0, 'Chek', "CurioSCSIController::completeCommand - Check Condition" ); ! 424: fCmdData->results.returnCode = kIOReturnError; ! 425: break; ! 426: ! 427: default: ! 428: ELG( fCmd, fCmdData->results.scsiStatus, 'Sta?', "CurioSCSIController::completeCommand - bad status" ); ! 429: fCmdData->results.returnCode = kIOReturnError; ! 430: break; ! 431: }/* end SWITCH on SCSI status */ ! 432: ! 433: fCmd->setResults( &fCmdData->results ); ! 434: fCmd->complete(); ! 435: ! 436: fCmd = NULL; ! 437: fCmdData = NULL; ! 438: fCurrentTargetLun.target = kInvalidTarget; ! 439: fCurrentTargetLun.lun = kInvalidLUN; ! 440: return; ! 441: }/* end completeCommand */ ! 442: ! 443: ! 444: void CurioSCSIController::cancelCommand( IOSCSICommand *scsiCommand ) ! 445: { ! 446: IOSCSICommand *origCmd; ! 447: PrivCmdData *origCmdData; ! 448: SCSIResults results; ! 449: ! 450: origCmd = scsiCommand->getOriginalCmd(); ! 451: origCmdData = (PrivCmdData*)origCmd->getCommandData(); ! 452: ! 453: ELG( scsiCommand, origCmd, 'Can-', "CurioSCSIController::cancelCommand" ); ! 454: ! 455: origCmd->getResults( &results ); ! 456: results.bytesTransferred = origCmdData->results.bytesTransferred; ! 457: origCmd->setResults( &results ); ! 458: ! 459: origCmd->complete(); ! 460: ! 461: scsiCommand->complete(); ! 462: return; ! 463: }/* end cancelCommand */ ! 464: ! 465: ! 466: void CurioSCSIController::resetCommand( IOSCSICommand *scsiCommand ) ! 467: { ! 468: ELG( scsiCommand, 0, 'Rst-', "CurioSCSIController::resetCommand" ); ! 469: resetBus(); ! 470: fCmdData = scsiCommand->getCommandData(); ! 471: bzero( &fCmdData->results, sizeof( fCmdData->results ) ); ! 472: scsiCommand->setResults( &fCmdData->results ); ! 473: scsiCommand->complete(); ! 474: return; ! 475: }/* end resetCommand */ ! 476: ! 477: ! 478: /* Fetch the device's bus address and interrupt port number. */ ! 479: /* Also, allocate one page of memory for the Channel Program. */ ! 480: ! 481: IOReturn CurioSCSIController::initHardware() ! 482: { ! 483: IOReturn ioReturn; ! 484: ! 485: ! 486: fInitiatorID = kInitiatorIDDefault; ! 487: fInitiatorIDMask = 1 << kInitiatorIDDefault; /* BusID bitmask for reselection. */ ! 488: ! 489: ELG( 0, fInitiatorID, 'IniH', "initHardware" ); ! 490: ! 491: ioReturn = getHardwareMemoryMaps(); ! 492: ! 493: if ( ioReturn == kIOReturnSuccess ) ioReturn = allocHdwAndChanMem(); ! 494: if ( ioReturn == kIOReturnSuccess ) ioReturn = doHBASelfTest(); ! 495: if ( ioReturn == kIOReturnSuccess ) ioReturn = resetHardware( true ); ! 496: ! 497: if ( ioReturn != kIOReturnSuccess ) ! 498: this->free(); ! 499: ! 500: return ioReturn; ! 501: }/* end initHardware */ ! 502: ! 503: ! 504: IOReturn CurioSCSIController::getHardwareMemoryMaps() ! 505: { ! 506: ! 507: if ( !fSCSIMemoryMap ) ! 508: { ! 509: fSCSIMemoryMap = fProvider->mapDeviceMemoryWithIndex( kCurioRegisterBase ); ! 510: if ( !fSCSIMemoryMap ) ! 511: { ! 512: ELG( 0, 0, 'Map-', "CurioSCSIController::getHardwareMemoryMaps - can't map Curio." ); ! 513: return kIOReturnInternalError; ! 514: } ! 515: ! 516: fCurioPhysAddr = fSCSIMemoryMap->getPhysicalAddress(); ! 517: fCurioAddr = (UInt8*)fSCSIMemoryMap->getVirtualAddress(); ! 518: ELG( fCurioPhysAddr, fCurioAddr, '=Cur', "getHardwareMemoryMaps - MESH regs" ); ! 519: g.curioAddr = (UInt32)fCurioAddr; // for debugging, miniMon ... ! 520: } ! 521: ! 522: if ( !fDBDMAMemoryMap ) ! 523: { ! 524: fDBDMAMemoryMap = fProvider->mapDeviceMemoryWithIndex( kDBDMARegisterBase ); ! 525: if ( !fDBDMAMemoryMap ) ! 526: { ! 527: ELG( 0, 0, 'map-', "CurioSCSIController::getHardwareMemoryMaps - can't map DBDMA." ); ! 528: return kIOReturnInternalError; ! 529: } ! 530: fDBDMAAddrPhys = fDBDMAMemoryMap->getPhysicalAddress(); ! 531: fDBDMAAddr = (IODBDMAChannelRegisters*)fDBDMAMemoryMap->getVirtualAddress(); ! 532: ELG( fDBDMAAddrPhys, fDBDMAAddr, '=DMA', "getHardwareMemoryMaps - DBDMA regs" ); ! 533: #if CustomMiniMon ! 534: gMESH_DBDMA = (UInt32)fDBDMAAddr; ! 535: gMESH_DBDMA_Phys = (UInt32)fDBDMAAddrPhys; ! 536: #endif /* CustomMiniMon */ ! 537: } ! 538: ! 539: return kIOReturnSuccess; ! 540: }/* end getHardwareMemoryMaps */ ! 541: ! 542: ! 543: ! 544: /* Fetch the device's bus address and allocate one page of memory */ ! 545: /* for the channel command. (Strictly speaking, we don't need an */ ! 546: /* entire page, but we can use the rest of the page for a permanent */ ! 547: /* status log). */ ! 548: /* @param deviceDescription Specify the device to initialize. */ ! 549: /* @return kIOReturnSuccess if successful, else an error status. */ ! 550: ! 551: IOReturn CurioSCSIController::allocHdwAndChanMem() ! 552: { ! 553: IOReturn ioReturn = kIOReturnSuccess; ! 554: ! 555: ! 556: fCCLSize = page_size; ! 557: fCCL = (UInt8*)kalloc( fCCLSize ); ! 558: if ( !fCCL ) ! 559: { PAUSE( 0, fCCLSize, 'CCA-', "allocHdwAndChanMem - can't allocate channel command area.\n" ); ! 560: ioReturn = kIOReturnNoMemory; ! 561: } ! 562: ! 563: if ( ioReturn == kIOReturnSuccess ) ! 564: { ! 565: /* Get the physical address corresponding the DBDMA channel area: */ ! 566: ! 567: fCCLPhysAddr = pmap_extract( kernel_pmap, ! 568: (vm_offset_t)fCCL ); ! 569: ! 570: g.cclPhysAddr = (UInt32)fCCLPhysAddr; // for debugging ease ! 571: g.cclLogAddr = (UInt32)fCCL; ! 572: if ( ioReturn != kIOReturnSuccess ) ! 573: PAUSE( 0, ioReturn, 'MAP-', "allocHdwAndChanMem - DBDMA mapping err.\n" ); ! 574: } ! 575: ! 576: if ( ioReturn == kIOReturnSuccess ) ! 577: { ! 578: ELG( fCCLPhysAddr, fCCL, '=CCL', "allocHdwAndChanMem - CCL phys/logical addresses." ); ! 579: ! 580: /* Set the Interrupt, Branch, and Wait DBDMA registers. */ ! 581: /* Caution: the following Curio interrupt register bits */ ! 582: /* are reverse polarity and are in a different position. */ ! 583: /* The pattern is: 0x00MM00VV, where MM is a mask byte */ ! 584: /* and VV is a value byte to match. */ ! 585: /* 0x80 means NO errors (kMeshIntrError) */ ! 586: /* 0x40 means NO exceptions (kMeshIntrException) */ ! 587: /* 0x20 means NO command done (kMeshIntrCmdDone) */ ! 588: /* Branch Select is used with BRANCH_FALSE */ ! 589: ! 590: // IOSetDBDMAInterruptSelect( fDBDMAAddr, 0x00000000); /* Never let DBDMA interrupt */ ! 591: // IOSetDBDMAWaitSelect( fDBDMAAddr, 0x00200020); /* Wait until command done */ ! 592: // IOSetDBDMABranchSelect( fDBDMAAddr, 0x00000000); /* Never branch on error */ ! 593: fDBDMAAddr->interruptSelect = 0x00000000; ! 594: fDBDMAAddr->waitSelect = 0x20002000; ! 595: fDBDMAAddr->branchSelect = 0x00000000; ! 596: SynchronizeIO(); ! 597: } ! 598: /* What do we do on failure? Should we try to deallocate */ ! 599: /* the stuff we created, or will the system do this for us? */ ! 600: ! 601: return ioReturn; ! 602: }/* end allocHdwAndChanMem */ ! 603: ! 604: ! 605: /* doHBASelfTest - This should be extended to perform a real chip self-test. */ ! 606: ! 607: IOReturn CurioSCSIController::doHBASelfTest() ! 608: { ! 609: IOReturn ioReturn = kIOReturnSuccess; ! 610: UInt8 chipID; ! 611: UInt8 temp; ! 612: ! 613: ! 614: ELG( fCurioPhysAddr, fCurioAddr, 'Test', "doHBASelfTest" ); ! 615: resetCurio(); ! 616: ! 617: WRITE_REGISTER( rCF2, CF2_EPL ); ! 618: setCmdReg( cNOP | bDMAEnBit ); ! 619: ! 620: chipID = fCurioAddr[ rTCH ]; ! 621: ! 622: /* Check data integrity by writing a NOP to the command register */ ! 623: /* and verifying that it was read back correctly. */ ! 624: ! 625: setCmdReg( cNOP ); ! 626: temp = fCurioAddr[ rCMD ]; ! 627: if ( temp != cNOP ) ! 628: { ! 629: PAUSE( cNOP, temp, 'hba-', "doHBASelfTest - Expected NOP" ); ! 630: ioReturn = kIOReturnNoDevice; ! 631: } ! 632: /* To do: write a test pattern into the FIFO and */ ! 633: /* check for correct count and bits. */ ! 634: ! 635: return ioReturn; ! 636: }/* end doHBASelfTest */ ! 637: ! 638: ! 639: void CurioSCSIController::interruptOccurred( IOInterruptEventSource *ies, int intCount ) ! 640: { ! 641: // DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)fDBDMAAddr; ! 642: ! 643: ! 644: // ELG( ies, intCount, 'Int+', "interruptOccurred" ); ! 645: ! 646: g.intLevel |= kLevelISR; /* set ISR flag */ ! 647: g.intLevel &= ~kLevelLatched; /* clear latched */ ! 648: ! 649: // ELG( DBDMARegs->channelStatus, DBDMARegs->commandPtrLo, 'Int+', "interruptOccurred." ); ! 650: ELG( fCmd, 0, 'Int+', "interruptOccurred." ); ! 651: // ELG( *(UInt32*)0xF3000024, *(UInt32*)0xF300002C, 'Int ', "interruptOccurred." ); ! 652: ! 653: doHardwareInterrupt(); /**** HANDLE THE INTERRUPT ****/ ! 654: ! 655: // ELG( fCmd, *(UInt32*)0xF300002C, 'Intx', "interruptOccurred." ); ! 656: ! 657: g.intLevel &= ~kLevelISR; /* clear ISR flag */ ! 658: return; ! 659: }/* end interruptOccurred */ ! 660: ! 661: ! 662: ! 663: void CurioSCSIController::doHardwareInterrupt() ! 664: { ! 665: if ( !interruptPending() ) ! 666: { ! 667: ELG( 0, 0, 'Int?', "CurioSCSIController::doHardwareInterrupt - spurious interrupt" ); ! 668: return; ! 669: } ! 670: ! 671: fCkForAnotherInt = true; // keep going around ! 672: do ! 673: { ! 674: ELG( fCkForAnotherInt<<16 | fNeedAnotherInterrupt, fBusState, 'loop', "doHardwareInterrupt" ); ! 675: fNeedAnotherInterrupt = false; ! 676: ! 677: /* Gross error is set incorrectly (according to Clinton Bauder). */ ! 678: ! 679: if ( fSaveStatus & sGrossErr ) // ??? mlj was fSaveInterrupt ! 680: { ! 681: ELG( 0, fSaveInterrupt, 'GEr-', "doHardwareInterrupt - Gross Error set." ); ! 682: fSaveStatus &= ~sGrossErr; ! 683: } ! 684: ! 685: /* iIlegalCmd - Software messed up. */ ! 686: /* Start over from scratch. */ ! 687: /* We can get this if we write too */ ! 688: /* many commands into the register. */ ! 689: ! 690: if ( fSaveInterrupt & iIlegalCmd ) ! 691: { ! 692: ELG( 0, fSaveInterrupt, 'IllC', "doHardwareInterrupt - Illegal command interrupt" ); ! 693: if ( fBusState != SCS_DEATH_MARCH ) ! 694: fsmStartErrorRecovery( kIOReturnInternalError ); ! 695: ! 696: fCkForAnotherInt = false; ! 697: }/* end IF iIlegalCmd */ ! 698: ! 699: ! 700: /* Check for disconnect: */ ! 701: ! 702: if ( fSaveInterrupt & iDisconnect ) ! 703: { ! 704: setCmdReg( cEnSelResel ); ! 705: /* Radar 1678545: this is the only (normal) place */ ! 706: /* that fBusBusy is cleared. (It's also cleared by */ ! 707: /* bus reset and driver initialization.) */ ! 708: fBusBusy = false; ! 709: } ! 710: ! 711: if ( fSaveInterrupt & iResetDetect ) ! 712: { ! 713: ELG( fSaveStatus, fSaveInterrupt, 'BusR', "doHardwareInterrupt - SCSI Bus Reset\n" ); ! 714: if ( fCmd ) ! 715: { ! 716: fCmdData->results.returnCode = kIOReturnSelectionError; ! 717: completeCommand(); ! 718: } ! 719: super::resetOccurred(); ! 720: enableCommands(); /* let superclass issue another command */ ! 721: fCkForAnotherInt = false; ! 722: }/* end IF iResetDetect */ ! 723: else if ( (fSaveStatus & sParityErr) && fBusBusy ) ! 724: { ! 725: fsmStartErrorRecovery( kIOReturnParityError ); ! 726: fCkForAnotherInt = false; ! 727: } /* If Parity Error and not disconnected */ ! 728: else ! 729: { /* Only certain states are legal if the bus is busy. */ ! 730: if ( fBusBusy ) ! 731: { ! 732: /* This is a legitimate interrupt (parity error and */ ! 733: /* bus reset have already been handled). The entity */ ! 734: /* that started the chip action that caused the */ ! 735: /* interrupt (deep breath) set fBusState to indicate*/ ! 736: /* why the interrupt happened. */ ! 737: /* Call the proper finite-state machine function. */ ! 738: /* On return, fBusState will be set to one of the */ ! 739: /* following values: */ ! 740: /* SCS_INITIATOR Start an action on the */ ! 741: /* current phase. */ ! 742: /* SCS_DISCONNECT The bus is free. */ ! 743: /* SCS_WAIT_FOR_BUS_FREE The bus should go free */ ! 744: /* shortly. */ ! 745: /* Note that SCS_WAIT_FOR_BUS_FREE and */ ! 746: /* fsmWaitForBusFree short-circuit some of the */ ! 747: /* automaton to avoid unnecessary interrupt events. */ ! 748: switch ( fBusState ) ! 749: { ! 750: case SCS_DISCONNECTED: fsmDisconnected(); break; ! 751: case SCS_SELECTING: fsmSelecting(); break; ! 752: case SCS_RESELECTING: fsmReselecting(); break; ! 753: case SCS_INITIATOR: fsmInitiator(); break; ! 754: case SCS_COMPLETING: fsmCompleting(); break; ! 755: case SCS_DMACOMPLETE: fsmDMAComplete(); break; ! 756: case SCS_SENDINGMSG: break; ! 757: case SCS_GETTINGMSG: fsmGettingMsg(); break; ! 758: case SCS_SENDINGCMD: fsmSendingCmd(); break; ! 759: case SCS_WAIT_FOR_BUS_FREE: fsmWaitForBusFree();break; ! 760: case SCS_DEATH_MARCH: fsmErrorRecoveryInterruptService(); break; ! 761: ! 762: default: ! 763: PAUSE( fSaveStatus, fBusState, 'FSM-', "doHardwareInterrupt - Illegal bus automaton state." ); ! 764: }/* end SWITCH fBusState */ ! 765: }/* end IF bus is busy */ ! 766: else ! 767: { /* The bus is (or just went) free. */ ! 768: /* We only allow selection, reselection, */ ! 769: /* wait for disconnect, or death march interrupts. */ ! 770: switch ( fBusState ) ! 771: { ! 772: case SCS_DISCONNECTED: fsmDisconnected(); break; ! 773: case SCS_SELECTING: fsmSelecting(); break; ! 774: case SCS_WAIT_FOR_BUS_FREE: fsmWaitForBusFree(); break; ! 775: case SCS_DEATH_MARCH: fsmErrorRecoveryInterruptService(); break; ! 776: ! 777: default: ! 778: fsmStartErrorRecovery( kIOReturnInternalError ); ! 779: fCkForAnotherInt = false; ! 780: break; ! 781: }/* end SWITCH on fBusState */ ! 782: }/* end ELSE bus is not busy */ ! 783: } ! 784: ! 785: /* We have (presumably) completely handled the previous */ ! 786: /* interrupt. At this point, there are five legitimate */ ! 787: /* fBusState values: */ ! 788: /* SCS_RESELECTING Just got a reselection interrupt */ ! 789: /* SCS_INITIATOR Continue operation for this target. */ ! 790: /* SCS_DISCONNECTED Enable selection/reselection */ ! 791: /* SCS_WAIT_FOR_BUS_FREE Command completion transition */ ! 792: /* SCS_DEATH_MARCH Error recovery */ ! 793: /* Handle a SCSI Phase change if necessary. This will */ ! 794: /* leave the bus state in the "expected" state for the next */ ! 795: /* operation. */ ! 796: ! 797: switch ( fBusState ) ! 798: { ! 799: case SCS_DEATH_MARCH: ! 800: fCkForAnotherInt = false; ! 801: break; ! 802: ! 803: case SCS_INITIATOR: ! 804: ELG( fCkForAnotherInt<<16 | fNeedAnotherInterrupt, 0, 'SCSi', "doHardwareInterrupt" ); ! 805: if ( fNeedAnotherInterrupt ) ! 806: { // from tagged reselect ! 807: fNeedAnotherInterrupt = false; ! 808: if ( quickCheckForInterrupt() ) ! 809: { ! 810: fsmPhaseChange(); ! 811: } ! 812: } ! 813: else ! 814: { ! 815: fsmPhaseChange(); ! 816: } ! 817: break; ! 818: ! 819: case SCS_WAIT_FOR_BUS_FREE: ! 820: default: ! 821: break; ! 822: }/* end SWITCH on fBusState */ ! 823: ! 824: /* This is the final check: if we determine that the */ ! 825: /* previous action will complete quickly (for example, */ ! 826: /* it's a message in byte), we'll spin for up to ten */ ! 827: /* microseconds to see if the chip is ready for another */ ! 828: /* operation. */ ! 829: ! 830: } while ( fCkForAnotherInt && quickCheckForInterrupt() ); ! 831: ! 832: if ( fBusState == SCS_DEATH_MARCH ) ! 833: fsmContinueErrorRecovery(); ! 834: ! 835: if ( fBusState == SCS_DISCONNECTED ) ! 836: enableCommands(); /* Try to start another command */ ! 837: ! 838: return; ! 839: }/* end doHardwareInterrupt */ ! 840: ! 841: ! 842: /* This is called from fsmDisconnected when we receive a reselected interrupt. */ ! 843: ! 844: void CurioSCSIController::handleReselectionInterrupt() ! 845: { ! 846: UInt8 selectByte; ! 847: UInt32 fifoDepth; ! 848: UInt8 msgByte; ! 849: IOReturn ioReturn = kIOReturnSuccess; ! 850: ! 851: ! 852: /* Make sure there's a selection byte and an Identify message in the FIFO. */ ! 853: ! 854: fBusBusy = ((fSaveInterrupt & iDisconnect) == 0); ! 855: fifoDepth = fCurioAddr[ rFOS ] & kFIFOCountMask; ! 856: ! 857: ELG( fifoDepth, fSaveInterrupt, 'fHRI', "handleReselectionInterrupt" ); ! 858: if ( fifoDepth != 2 ) ! 859: { ! 860: ioReturn = kIOReturnInternalError; ! 861: PAUSE( 0, 0, 'Rsl-', "handleReselectionInterrupt - Bad FIFO count on reselect" ); ! 862: } ! 863: ! 864: if ( ioReturn == kIOReturnSuccess ) ! 865: { ! 866: selectByte = fCurioAddr[ rFFO ]; ! 867: /* During reselection, the first message byte */ ! 868: /* must be an Identify with the LUN. */ ! 869: ioReturn = getReselectionTargetID( selectByte ); ! 870: } ! 871: ! 872: if ( ioReturn == kIOReturnSuccess ) ! 873: { ! 874: msgByte = fCurioAddr[ rFFO ]; /* Pull the Identify byte */ ! 875: if ( fSaveStatus & sParityErr ) ! 876: ioReturn = kIOReturnParityError; ! 877: } ! 878: ! 879: if ( ioReturn == kIOReturnSuccess ) ! 880: { ! 881: if ( (msgByte & kSCSIMsgIdentify) == 0 ) ! 882: { ! 883: ioReturn = kIOReturnInternalError; ! 884: PAUSE( 0, msgByte, ' ID-', "handleReselectionInterrupt - Bad ID Message (no Identify) on reselect" ); ! 885: } ! 886: ! 887: fCurrentTargetLun.lun = msgByte & ~kSCSIMsgIdentify; ! 888: fTag = kInvalidTag; ! 889: fBusState = SCS_RESELECTING; ! 890: ! 891: /* At this point, the chip is waiting for us to validate */ ! 892: /* the Identify message. While we have a Target and LUN, */ ! 893: /* we don't have a command to reconnect to. */ ! 894: setCmdReg( cMsgAcep ); /* Accept the Identify message */ ! 895: } ! 896: ! 897: if ( ioReturn != kIOReturnSuccess ) ! 898: fsmStartErrorRecovery( ioReturn ); ! 899: ! 900: return; ! 901: }/* end handleReselectionInterrupt */ ! 902: ! 903: ! 904: /* Complete the processing of a reselection interrupt. */ ! 905: /* We have just ACK'd the Identify message. Try to find the command */ ! 906: /* that corresponds to this target.lun (without a queue tag). */ ! 907: /* If we're successful, complete the reselection and start */ ! 908: /* following phases by calling fsmPhaseChange directly. */ ! 909: /* If the first disconnected command has a non-zero tag queue, we */ ! 910: /* expect to be in messsage in phase, and will receive a tagged */ ! 911: /* queue message eventually. */ ! 912: ! 913: void CurioSCSIController::fsmReselecting() ! 914: { ! 915: ELG( fBusState, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, 'fRsl', "fsmReselecting" ); ! 916: ! 917: reselectNexus(); ! 918: if ( fCmd ) ! 919: { /* We have successfully reselected this target. */ ! 920: /* Wait until the target tells us what to do next. */ ! 921: fBusState = SCS_INITIATOR; ! 922: return; ! 923: } ! 924: ! 925: /* We don't have a nexus yet. If we're in MSGI phase, */ ! 926: /* continue grabbing message bytes until we receive */ ! 927: /* a queue tag message (we might receive an SDTR), */ ! 928: /* continuing at fsmReselecting to process interrupts. */ ! 929: ! 930: quickCheckForInterrupt(); // clear pending interrupt(s) and update phase ! 931: fCurrentBusPhase = fSaveStatus & mPhase; ! 932: if ( fCurrentBusPhase == kBusPhaseMSGI ) ! 933: { ! 934: if ( (fCurioAddr[ rFOS ] & kFIFOCountMask) == 0 ) ! 935: { ! 936: if ( fMsgInState == kMsgInInit ) ! 937: { ! 938: setCmdReg( cNOP | bDMAEnBit ); // clear TC zero bit ! 939: setCmdReg( cIOXfer ); ! 940: if ( !quickCheckForInterrupt() ) ! 941: { fCkForAnotherInt = true; ! 942: return; ! 943: } ! 944: } ! 945: } ! 946: fsmGettingMsg(); ! 947: } ! 948: else ! 949: { /* We're in the wrong phase. Bail out. */ ! 950: fsmStartErrorRecovery( kIOReturnInternalError ); ! 951: } ! 952: return; ! 953: }/* end fsmReselecting */ ! 954: ! 955: ! 956: ! 957: /* Disconnected - only legal event here is reselection. */ ! 958: /* handleReselectionInterrupt may set fBusState to SCS_INITIATOR */ ! 959: ! 960: void CurioSCSIController::fsmDisconnected() ! 961: { ! 962: UInt8 selectByte, target; ! 963: ! 964: ! 965: ELG( 0, fSaveInterrupt, 'fDis', "fsmDisconnected" ); ! 966: ! 967: if ( fSaveInterrupt & iReselected ) ! 968: { ! 969: handleReselectionInterrupt(); ! 970: return; ! 971: } ! 972: ! 973: /* See if some target trying to Select us - should never happen: */ ! 974: ! 975: if ( fSaveInterrupt & (iSelected | iSelectWAtn) ) ! 976: { ! 977: selectByte = fCurioAddr[ rFFO ]; ! 978: selectByte &= ~fInitiatorIDMask; ! 979: for ( target = 0; target < 8; target++ ) ! 980: { ! 981: if ( selectByte & (1 << target) ) ! 982: break; ! 983: } ! 984: PAUSE( selectByte, target, 'Tar-', "fsmDisconnected - Selected by external target - not supported." ); ! 985: setCmdReg( cDisconnect ); ! 986: return; ! 987: }/* end IF bogus selection by target */ ! 988: ! 989: ! 990: fCkForAnotherInt = false; ! 991: ! 992: if ( fBusBusy == false ) ! 993: { /* disconnect interrupted while disconnected */ ! 994: /* This always happens when we finish an IO request. */ ! 995: /* fBusBusy is cleared when the "bus disconnected" bit */ ! 996: /* is set in the NCR 53C96 interrupt register. */ ! 997: ELG( 0, 0, 'Dis-', "fsmDisconnected - disconnect interrupted while disconnected" ); ! 998: enableCommands(); ! 999: return; ! 1000: } ! 1001: ! 1002: /* Since we're disconnected, just ignore the interrupt */ ! 1003: ! 1004: if ( fCmd ) ! 1005: { ! 1006: fCmdData->results.returnCode = kIOReturnSelectionError; ! 1007: completeCommand(); ! 1008: } ! 1009: ! 1010: fCurrentBusPhase = kBusPhaseBusFree; ! 1011: return; ! 1012: }/* end fsmDisconnected */ ! 1013: ! 1014: ! 1015: /* This state is called when we expect to disconnect from a */ ! 1016: /* target after receiving a Command Complete, Disconnect, or */ ! 1017: /* Abort message and the bus is still busy on exit from the */ ! 1018: /* finite state automaton (because curioQuickCheckForBusFree */ ! 1019: /* returned false). */ ! 1020: ! 1021: void CurioSCSIController::fsmWaitForBusFree() ! 1022: { ! 1023: ELG( fBusBusy, fSaveInterrupt, 'fWBF', "fsmWaitForBusFree" ); ! 1024: ! 1025: if ( fSaveInterrupt & (iReselected | iSelected | iSelectWAtn) ) ! 1026: { ! 1027: /* We went straight from command completion to (presumably) */ ! 1028: /* reselection. Treat it as a normal selection/reselection */ ! 1029: /* interrupt from "disconnected" state. (This is an abuse of*/ ! 1030: /* the finite-state automaton design.) */ ! 1031: fsmDisconnected(); ! 1032: } ! 1033: else if ( fBusBusy == false ) ! 1034: { ! 1035: /* This is expected: the bus has just gone free after a */ ! 1036: /* command completed. We can now safely try to start */ ! 1037: /* another command. */ ! 1038: fBusState = SCS_DISCONNECTED; ! 1039: fCkForAnotherInt = false; ! 1040: enableCommands(); ! 1041: } ! 1042: else ! 1043: { /* This is strange. It may not be an error, but I don't know */ ! 1044: /* if there are other legal bus states after disconnect. */ ! 1045: /* (The one counter example would be after a linked command */ ! 1046: /* when the target goes to Command phase, but we should have */ ! 1047: /* rejected this at command complete.) */ ! 1048: ELG( fCmd, 0, 'WBF-', "fsmWaitForBusFree - strangeness" ); ! 1049: fsmStartErrorRecovery( kIOReturnInternalError ); ! 1050: } ! 1051: return; ! 1052: }/* end fsmWaitForBusFree */ ! 1053: ! 1054: ! 1055: /* fsmSelecting - One of three things can happen here: */ ! 1056: /* the selection could succeed (though with possible */ ! 1057: /* incomplete message out), */ ! 1058: /* it could time out, or */ ! 1059: /* we can be reselected. */ ! 1060: ! 1061: void CurioSCSIController::fsmSelecting() ! 1062: { ! 1063: SCSICDBInfo scsiCDB; ! 1064: UInt8 fifoDepth; ! 1065: IOReturn ioReturn = kIOReturnSuccess; ! 1066: ! 1067: ! 1068: ELG( 0, fSaveInterrupt, 'fSel', "fsmSelecting" ); ! 1069: ! 1070: fBusBusy = ((fSaveInterrupt & iDisconnect) == 0 ); ! 1071: if ( fBusBusy == false ) ! 1072: { /* Selection timed-out. Abort this request. */ ! 1073: ELG( fCmd, 0, 'Tim-', "fsmSelecting - timeout" ); ! 1074: ! 1075: setCmdReg( cFlshFFO ); ! 1076: fBusState = SCS_DISCONNECTED; ! 1077: fCmdData->results.returnCode = kIOReturnNoDevice; ! 1078: completeCommand(); ! 1079: return; ! 1080: } ! 1081: ! 1082: ELG( fSaveInterrupt, fSaveSeqStep, 'Sel-', "fsmSelecting - problem other than timeout" ); ! 1083: fCmd->getCDB( &scsiCDB ); ! 1084: ! 1085: if ( fSaveInterrupt == (iFuncComp | iBusService) ) ! 1086: { ! 1087: switch ( fSaveSeqStep & INS_STATE_MASK ) ! 1088: { ! 1089: case 0: /* No message phase. If we really wanted one, */ ! 1090: /* this could be significant. */ ! 1091: /* OK, let's try to continue following phase changes. */ ! 1092: fBusState = SCS_INITIATOR; ! 1093: break; ! 1094: ! 1095: case 3: /* didn't complete cmd phase, parity? */ ! 1096: case 4: /* everything worked */ ! 1097: case 1: /* everything worked, SCMD_SELECT_ATN_STOP case */ ! 1098: /* We're connected. Start following the target's phase changes. */ ! 1099: /* If we're trying to do sync negotiation, */ ! 1100: /* this is the place to do it. In that case, we */ ! 1101: /* sent a SCMD_SELECT_ATN_STOP command, and */ ! 1102: /* ATN is now asserted (and we're hopefully in */ ! 1103: /* msgOut phase). We want to send 5 bytes. */ ! 1104: /* Drop them into currMsgOut */ ! 1105: fBusState = SCS_INITIATOR; ! 1106: break; ! 1107: ! 1108: case 2: /* Either no command phase, or incomplete message transfer. */ ! 1109: fifoDepth = fCurioAddr[ rFOS ] & kFIFOCountMask; ! 1110: /* Spec says ATN is asserted if all message bytes were not sent. */ ! 1111: if ( fifoDepth > scsiCDB.cdbLength ) ! 1112: setCmdReg( cRstAtn ); ! 1113: ! 1114: /* 970611: clear the FIFO. If we don't do this and the */ ! 1115: /* target is entering MSGI phase (trying to send us a */ ! 1116: /* Message Reject), it will sit on top of the FIFO, and */ ! 1117: /* we'll read garbage from the FIFO. */ ! 1118: ! 1119: setCmdReg( cFlshFFO ); /* The command is still in the FIFO */ ! 1120: /* OK, let's try to continue following phase changes. */ ! 1121: fBusState = SCS_INITIATOR; ! 1122: break; ! 1123: ! 1124: default: /* fBusBusy = true; -- Radar 1678545 */ ! 1125: ioReturn = kIOReturnInternalError; ! 1126: break; ! 1127: }/* end SWITCH */ ! 1128: } ! 1129: else if ( fSaveInterrupt & iReselected ) ! 1130: { ! 1131: /* We were reselected while trying to do a selection. */ ! 1132: /* Enqueue this cmdBuf on the HEAD of pendingQ, then deal */ ! 1133: /* with the reselect. */ ! 1134: /* Tricky case, we have to "deactivate" this command */ ! 1135: /* since this hardwareStart attempt failed. */ ! 1136: ! 1137: ELG( fCmd, fSaveInterrupt, 'Arb-', "fsmSelecting - Reselection interrupt while selecting" ); ! 1138: disableCommands(); ! 1139: rescheduleCommand( fCmd ); ! 1140: fCmd = NULL; ! 1141: ! 1142: fBusState = SCS_DISCONNECTED; ! 1143: handleReselectionInterrupt(); /* Go deal with reselect. */ ! 1144: } ! 1145: else ! 1146: { ! 1147: ioReturn = kIOReturnInternalError; ! 1148: PAUSE( 0, 0, 'int-', "Bogus select/reselect interrupt" ); ! 1149: } ! 1150: ! 1151: if ( ioReturn != kIOReturnSuccess ) ! 1152: fsmStartErrorRecovery( ioReturn ); ! 1153: ! 1154: return; ! 1155: }/* end fsmSelecting */ ! 1156: ! 1157: ! 1158: /* This is a dummy interrupt service state that we enter after selection */ ! 1159: /* when the previous Curio operation has no interrupt-service completion */ ! 1160: /* requirement. For example, we can get here after a Message Out or */ ! 1161: /* reselection. Nothing happens here; we continue at fsmPhaseChange. */ ! 1162: ! 1163: void CurioSCSIController::fsmInitiator() ! 1164: { ! 1165: ELG( 0, fSaveInterrupt, 'fIni', "fsmInitiator" ); ! 1166: fBusState = SCS_INITIATOR; ! 1167: return; ! 1168: }/* end fsmInitiator */ ! 1169: ! 1170: ! 1171: /* We just did a SCMD_INIT_CMD_CMPLT command, hopefully all that's left */ ! 1172: /* is to drop ACK. Command Complete message is handled in fscAcceptinfMsg. */ ! 1173: /* We can't go to SCS_DISCONNECTED until the target disconnects. If we */ ! 1174: /* go to "disconnected" state too soon, we'll encounter a load-dependent */ ! 1175: /* race condition that causes us to start another command before we've */ ! 1176: /* cleaned up from the last command. The actual state change is in */ ! 1177: /* fsmProcessMessage. */ ! 1178: ! 1179: void CurioSCSIController::fsmCompleting() ! 1180: { ! 1181: unsigned fifoDepth; ! 1182: IOReturn ioReturn = kIOReturnSuccess; ! 1183: UInt8 statusByte; ! 1184: ! 1185: ! 1186: ELG( 0, fSaveInterrupt, 'fCmp', "fsmCompleting" ); ! 1187: ! 1188: if ( fSaveInterrupt & iDisconnect ) ! 1189: { ! 1190: ioReturn = kIOReturnInternalError; ! 1191: PAUSE( 0, 0, ' BF-', "fsmCompleting - Bus free before target completion complete" ); ! 1192: } ! 1193: ! 1194: if ( ioReturn == kIOReturnSuccess ) ! 1195: { ! 1196: fifoDepth = fCurioAddr[ rFOS ] & kFIFOCountMask; ! 1197: if ( fSaveInterrupt & iFuncComp ) ! 1198: { /* Got both Status and MsgIn in FIFO; ACK is still asserted. */ ! 1199: if ( fifoDepth != 2 ) ! 1200: { /* This is pretty bogus - we expect a status and msg in the FIFO. */ ! 1201: PAUSE( 0, fifoDepth, 'ffc-', "fsmCompleting - FIFO problem with Status/MsgIn" ); ! 1202: ioReturn = kIOReturnInternalError; ! 1203: } ! 1204: ! 1205: if ( ioReturn == kIOReturnSuccess ) ! 1206: { ! 1207: statusByte = fCurioAddr[ rFFO ]; ! 1208: fMsgInBuffer[0] = fCurioAddr[ rFFO ]; ! 1209: fCmdData->results.scsiStatus = statusByte; ! 1210: fMsgInIndex = 1; ! 1211: ioReturn = fsmProcessMessage(); ! 1212: } ! 1213: } ! 1214: else ! 1215: { /* We only received a status byte. */ ! 1216: /* This can occur if we responded to the interrupt before */ ! 1217: /* the device successfully transmitted the Command Complete */ ! 1218: /* message. This is kind of weird, but let's try to handle it. */ ! 1219: if ( fifoDepth != 1 ) ! 1220: { ! 1221: ioReturn = kIOReturnInternalError; ! 1222: PAUSE( 0, fifoDepth, 'Cmp-', "IO complete: incorrect FIFO count (expecting one byte)" ); ! 1223: } ! 1224: ! 1225: /* Back to watching phase changes. */ ! 1226: /* Presumably, the target will switch to MSGI phase and */ ! 1227: /* complete the command at its leisure. */ ! 1228: fBusState = SCS_INITIATOR; ! 1229: } ! 1230: } ! 1231: ! 1232: if ( ioReturn != kIOReturnSuccess ) ! 1233: fsmStartErrorRecovery( ioReturn ); ! 1234: ! 1235: return; ! 1236: }/* end fsmCompleting */ ! 1237: ! 1238: ! 1239: /* DMA Complete. */ ! 1240: ! 1241: void CurioSCSIController::fsmDMAComplete() ! 1242: { ! 1243: UInt32 fifoResidualCount, actualTransferCount, dmaResidualCount; ! 1244: UInt8 residualByte; ! 1245: ! 1246: ! 1247: /* Stop the DMA engine and retrieve the total number of */ ! 1248: /* bytes transferred. This will be */ ! 1249: /* fCmd->thisTransferLength The number of bytes requested */ ! 1250: /* - the current DMA residual count */ ! 1251: /* - the current FIFO residual count */ ! 1252: /* Note that there may still be bytes in the FIFO. */ ! 1253: ! 1254: // IODBDMAReset( fDBDMAAddr ); ! 1255: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit ! 1256: SynchronizeIO(); ! 1257: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit ! 1258: SynchronizeIO(); ! 1259: ! 1260: /* Get residual count from DMA transfer. */ ! 1261: ! 1262: dmaResidualCount = fCurioAddr[ rXCM ] << 8 | fCurioAddr[ rXCL ]; ! 1263: actualTransferCount = fThisTransferLength - dmaResidualCount; ! 1264: ! 1265: ELG( dmaResidualCount, actualTransferCount, 'fDMA', "fsmDMAComplete" ); ! 1266: ! 1267: /* Now, see if there are any bytes lurking in the FIFO: */ ! 1268: ! 1269: fifoResidualCount = fCurioAddr[ rFOS ] & kFIFOCountMask; ! 1270: ! 1271: if ( fifoResidualCount > 0 ) ! 1272: { /* Drain the FIFO after DMA for a normal transfer: */ ! 1273: ELG( 0, fifoResidualCount, 'MTFF', "fsmDMAComplete - empty the FIFO" ); ! 1274: ! 1275: if ( !fCmdData->isWrite ) ! 1276: { ! 1277: while ( fifoResidualCount > 0 ) ! 1278: { /* Try to move residual data from the FIFO into */ ! 1279: /* the user's buffer. */ ! 1280: residualByte = fCurioAddr[ rFFO ]; ! 1281: fCmdData->mdp->writeBytes( fCmdData->results.bytesTransferred + actualTransferCount, ! 1282: &residualByte, 1 ); ! 1283: ++actualTransferCount; ! 1284: }/* end WHILE bytes in FIFO */ ! 1285: } ! 1286: else ! 1287: { /* Write command - just flush the data */ ! 1288: setCmdReg( cFlshFFO ); ! 1289: setCmdReg( cNOP | bDMAEnBit ); // clear TC zero bit; ! 1290: actualTransferCount -= fifoResidualCount; ! 1291: }/* end IF Write */ ! 1292: }/* end IF bytes left in FIFO */ ! 1293: ! 1294: fCmdData->results.bytesTransferred += actualTransferCount; ! 1295: ! 1296: if ( fSaveStatus & sParityErr ) ! 1297: { ! 1298: PAUSE( 0, 0, 'par-', "fsmDMAComplete - parity error" ); ! 1299: fsmStartErrorRecovery( kIOReturnParityError ); ! 1300: } ! 1301: else ! 1302: { ! 1303: fBusState = SCS_INITIATOR; /* Continue following phase changes. */ ! 1304: } ! 1305: ! 1306: return; ! 1307: }/* end fsmDMAComplete */ ! 1308: ! 1309: ! 1310: /* Just completed the SCMD_TRANSFER_INFO operation for message in. */ ! 1311: /* ACK is not asserted (we have not ACK'ed this byte). */ ! 1312: /* There is no parity error. */ ! 1313: /* We will not have a command if we're reselecting. */ ! 1314: ! 1315: void CurioSCSIController::fsmGettingMsg() ! 1316: { ! 1317: UInt32 fifoCount; ! 1318: UInt8 msgInByte; ! 1319: IOReturn ioReturn = kIOReturnSuccess; ! 1320: ! 1321: ! 1322: ELG( fBusBusy, fMsgInState<<16 | fCurioAddr[ rFOS ], 'fGtM', "fsmGettingMsg" ); ! 1323: ! 1324: if ( fBusBusy == false ) ! 1325: { ! 1326: /* This (non-fatal) error is handled on return... */ ! 1327: ioReturn = kIOReturnInternalError; /* Any non-zero non-fatal error status */ ! 1328: } ! 1329: else ! 1330: { ! 1331: fifoCount = fCurioAddr[ rFOS ] & kFIFOCountMask; ! 1332: if ( fifoCount != 1 ) ! 1333: { ! 1334: PAUSE( 0, fifoCount, 'GtM-', "fsmGettingMsg - MsgIn FIFO count error" ); ! 1335: ioReturn = kIOReturnInternalError; ! 1336: } ! 1337: } ! 1338: ! 1339: if ( ioReturn == kIOReturnSuccess ) ! 1340: { ! 1341: msgInByte = fCurioAddr[ rFFO ]; ! 1342: ELG( 0, msgInByte, '=Msg', "fsmGettingMsg - got a byte" ); ! 1343: if ( fSaveStatus & sParityErr ) ! 1344: { ! 1345: PAUSE( 0, fSaveStatus, 'Par-', "fsmGettingMsg - Parity error getting MsgIn" ); ! 1346: ioReturn = kIOReturnParityError; ! 1347: } ! 1348: } ! 1349: ! 1350: if ( ioReturn == kIOReturnSuccess ) ! 1351: { ! 1352: if ( fMsgInState == kMsgInInit ) ! 1353: { ! 1354: fMsgInCount = 0; ! 1355: fMsgInIndex = 0; ! 1356: } ! 1357: if ( fMsgInIndex >= kMessageInBufferLength ) ! 1358: { ! 1359: PAUSE( 0, fMsgInIndex, 'Par-', "fsmGettingMsg - too many bytes" ); ! 1360: ioReturn = kIOReturnInternalError; ! 1361: } ! 1362: } ! 1363: ! 1364: if ( ioReturn == kIOReturnSuccess ) ! 1365: { ! 1366: fMsgInBuffer[ fMsgInIndex++ ] = msgInByte; ! 1367: switch ( fMsgInState ) ! 1368: { ! 1369: case kMsgInInit: /* This is the first message byte. */ ! 1370: if ( (msgInByte == kSCSIMsgCmdComplete) ! 1371: || (msgInByte >= (UInt8)kSCSIMsgIdentify) ) ! 1372: { /* This is 1-byte cmdComplete or Identify message. */ ! 1373: fMsgInState = kMsgInReady; ! 1374: } ! 1375: else if ( msgInByte == kSCSIMsgExtended ) ! 1376: { /* This is an extended message. The next byte has the count. */ ! 1377: fMsgInState = kMsgInCounting; ! 1378: } ! 1379: else if ( msgInByte <= kSCSIMsgOneByteMax ) ! 1380: { /* These are other 1-byte messages. */ ! 1381: fMsgInState = kMsgInReady; ! 1382: } ! 1383: else if ( msgInByte >= kSCSIMsgTwoByteMin ! 1384: && msgInByte <= kSCSIMsgTwoByteMax ) ! 1385: { /* This is a two-byte message. */ ! 1386: /* Set the count and read the next byte. */ ! 1387: fMsgInState = kMsgInReading; /* Need one more */ ! 1388: fMsgInCount = 1; ! 1389: } ! 1390: else ! 1391: { /* This is an unknown message. */ ! 1392: fMsgInState = kMsgInReady; ! 1393: } ! 1394: break; ! 1395: ! 1396: case kMsgInCounting: /* Count byte of multi-byte message: */ ! 1397: fMsgInCount = msgInByte; ! 1398: fMsgInState = kMsgInReading; ! 1399: break; ! 1400: ! 1401: case kMsgInReading: /* Body of multi-byte message: */ ! 1402: if ( --fMsgInCount <= 0 ) ! 1403: fMsgInState = kMsgInReady; ! 1404: break; ! 1405: ! 1406: default: ! 1407: PAUSE( 0, 0, 'Msg-', "DoMessageInPhase - Bogus MSGI state!\n" ); ! 1408: ioReturn = kIOReturnInternalError; ! 1409: }/* SWITCH on message state */ ! 1410: } ! 1411: ! 1412: if ( ioReturn == kIOReturnSuccess ) ! 1413: { ! 1414: switch ( fMsgInState ) ! 1415: { ! 1416: case kMsgInReading: ! 1417: case kMsgInCounting: /* We have more message bytes to read. */ ! 1418: /* Accept this byte (this sets ACK) and setup */ ! 1419: /* to transfer the next byte. */ ! 1420: setCmdReg( cMsgAcep ); ! 1421: /* Since the message accept command sets "interrupt", */ ! 1422: /* eat it here so we don't get a second interrupt. */ ! 1423: quickCheckForInterrupt(); ! 1424: setCmdReg( cNOP ); ! 1425: setCmdReg( cIOXfer ); ! 1426: if ( fBusState != SCS_RESELECTING ) ! 1427: fBusState = SCS_GETTINGMSG; ! 1428: /* This would be a good place to spin-wait for completion, */ ! 1429: /* continuing at the start of this method if there is */ ! 1430: /* another byte (and we're still in message in phase). */ ! 1431: /* Perhaps this method should return a "spinwait" status to */ ! 1432: /* the mainline FSM. */ ! 1433: break; ! 1434: ! 1435: case kMsgInReady: ! 1436: fMsgInState = kMsgInInit; ! 1437: ioReturn = fsmProcessMessage(); ! 1438: break; ! 1439: ! 1440: case kMsgInInit: ! 1441: default: ! 1442: /* that's strange: we should never be in idle state */ ! 1443: /* *after* successfully reading a message byte. */ ! 1444: ioReturn = kIOReturnInternalError; ! 1445: break; ! 1446: }/* end SWITCH */ ! 1447: } ! 1448: ! 1449: if ( ioReturn != kIOReturnSuccess ) ! 1450: fsmStartErrorRecovery( ioReturn ); ! 1451: ! 1452: return; ! 1453: }/* end fsmGettingMsg */ ! 1454: ! 1455: ! 1456: /* Just read a message; ACK is false and the message */ ! 1457: /* has been read into fMsgInBuffer[0..fMsgInIndex]. We have not */ ! 1458: /* ACK'ed the last byte yet. */ ! 1459: /* If we fail here, the caller will start error recovery. */ ! 1460: ! 1461: IOReturn CurioSCSIController::fsmProcessMessage() ! 1462: { ! 1463: IOReturn ioReturn = kIOReturnSuccess; ! 1464: bool messageAckNeeded = true; ! 1465: ! 1466: ! 1467: ELG( fBusState, *(UInt32*)fMsgInBuffer, 'fMgI', "fsmProcessMessage" ); ! 1468: ! 1469: /* Message-in complete. Handle message(s) in currMsgIn: */ ! 1470: ! 1471: if ( fBusState == SCS_RESELECTING ) ! 1472: { ! 1473: /* The only interesting message here is queue tag. */ ! 1474: /* (What about target SDTR or Abort?) */ ! 1475: ! 1476: switch ( fMsgInBuffer[0] ) ! 1477: { ! 1478: case kSCSIMsgHeadOfQueueTag: ! 1479: case kSCSIMsgOrderedQueueTag: ! 1480: case kSCSIMsgSimpleQueueTag: ! 1481: if ( fMsgInIndex != 2 ) ! 1482: { ! 1483: PAUSE( fMsgInBuffer[0], fMsgInIndex, 'Que-', "fsmProcessMessage - queue tag without tag value" ); ! 1484: ioReturn = kIOReturnInternalError; ! 1485: } ! 1486: else ! 1487: { fTag = fMsgInBuffer[ 1 ]; ! 1488: ELG( 0, fTag, '=Tag', "fsmProcessMessage - tag" ); ! 1489: reselectNexus(); ! 1490: if ( fCmd ) ! 1491: { ! 1492: setCmdReg( cMsgAcep ); ! 1493: fNeedAnotherInterrupt = true; ! 1494: fBusState = SCS_INITIATOR; ! 1495: return kIOReturnSuccess; ! 1496: } ! 1497: } ! 1498: break; ! 1499: ! 1500: default: ! 1501: ioReturn = kIOReturnInternalError; ! 1502: break; ! 1503: }/* end SWITCH on message */ ! 1504: ! 1505: /* Since we process commands one by one, whack this */ ! 1506: /* command so we fall through the regular message handler. */ ! 1507: fMsgInBuffer[0] = kSCSIMsgNop; ! 1508: fMsgInIndex = 1; ! 1509: } ! 1510: ! 1511: fBusState = SCS_INITIATOR; ! 1512: fNeedAnotherInterrupt = true; ! 1513: ! 1514: switch ( fMsgInBuffer[0] ) ! 1515: { ! 1516: case kSCSIMsgNop: ! 1517: break; ! 1518: ! 1519: case kSCSIMsgCmdComplete: ! 1520: /* Normally, we get here from fsmCommandComplete. */ ! 1521: /* All we need to do is to Ack the message and complete the */ ! 1522: /* command. Exit in a transitional bus state that becomes */ ! 1523: /* SCS_DISCONNECTED when the bus is no longer busy. */ ! 1524: fBusState = SCS_WAIT_FOR_BUS_FREE; ! 1525: completeCommand(); ! 1526: break; ! 1527: ! 1528: case kSCSIMsgDisconnect: ! 1529: fCmd = NULL; ! 1530: /* Exit the interrupt service routine so */ ! 1531: /* we don't miss a reselection interrupt. */ ! 1532: fBusState = SCS_WAIT_FOR_BUS_FREE; ! 1533: fCkForAnotherInt = false; ! 1534: break; ! 1535: ! 1536: case kSCSIMsgSaveDataPointers: ! 1537: if ( fCmd ) ! 1538: fCmdData->savedDataPosition = fCmdData->results.bytesTransferred; ! 1539: break; ! 1540: ! 1541: case kSCSIMsgRestorePointers: ! 1542: if ( fCmd ) ! 1543: fCmdData->results.bytesTransferred = fCmdData->savedDataPosition; ! 1544: break; ! 1545: ! 1546: case kSCSIMsgRejectMsg: ! 1547: ioReturn = kIOReturnInternalError; ! 1548: ! 1549: // don't break - fall through to kSCSIMsgAbort */ ! 1550: ! 1551: case kSCSIMsgAbort: ! 1552: case kSCSIMsgAbortTag: ! 1553: if ( fCmd ) ! 1554: { /* Oops: something is terribly wrong with this command. */ ! 1555: /* This can happen if we get a parity error, set ATN, */ ! 1556: /* and send an inititor detected error to the target. */ ! 1557: fCmdData->results.returnCode = kIOReturnInternalError; ! 1558: completeCommand(); ! 1559: fCkForAnotherInt = false; ! 1560: } ! 1561: /* After receiving an Abort, the target will go free */ ! 1562: fBusState = SCS_WAIT_FOR_BUS_FREE; ! 1563: break; ! 1564: ! 1565: case kSCSIMsgLinkedCmdComplete: ! 1566: case kSCSIMsgLinkedCmdCompleteFlag: ! 1567: /* These are impossible: we reject commands with the link bit set. */ ! 1568: /* About all we can do is to fail the client's command and */ ! 1569: /* stagger onwards. */ ! 1570: PAUSE( fCmd, 0, 'Abo-', "fsmProcessMessage - recv'd Abort" ); ! 1571: fCmdData->results.returnCode = kIOReturnInternalError; ! 1572: completeCommand(); ! 1573: fBusState = SCS_WAIT_FOR_BUS_FREE; ! 1574: break; ! 1575: ! 1576: case kSCSIMsgExtended: ! 1577: /* The only expected extended message is */ ! 1578: /* synchronous negotiation which isn't supported. */ ! 1579: switch ( fMsgInBuffer[2] ) ! 1580: { ! 1581: case kSCSIMsgSyncXferReq: ! 1582: /* We don't support SDTR (yet), so send a message reject */ ! 1583: /* Perhaps it would be better to send an "async only" */ ! 1584: /* response, but message reject is legal. */ ! 1585: WRITE_REGISTER( rFFO, kSCSIMsgRejectMsg ); ! 1586: setCmdReg( cSetAtn ); ! 1587: messageAckNeeded = false; ! 1588: break; ! 1589: ! 1590: default: ! 1591: WRITE_REGISTER( rFFO, kSCSIMsgRejectMsg ); ! 1592: setCmdReg( cSetAtn ); ! 1593: messageAckNeeded = false; ! 1594: break; ! 1595: } ! 1596: break; ! 1597: ! 1598: default: /* all others are unacceptable. */ ! 1599: WRITE_REGISTER( rFFO, kSCSIMsgRejectMsg ); ! 1600: setCmdReg( cSetAtn ); ! 1601: messageAckNeeded = false; ! 1602: }/* end SWITCH on Message byte */ ! 1603: ! 1604: if ( messageAckNeeded ) ! 1605: setCmdReg( cMsgAcep ); ! 1606: ! 1607: return ioReturn; ! 1608: }/* end fsmProcessMessage */ ! 1609: ! 1610: ! 1611: /* Just completed the SCMD_TRANSFER_INFO operation for command. */ ! 1612: void CurioSCSIController::fsmSendingCmd() ! 1613: { ! 1614: fBusState = SCS_INITIATOR; ! 1615: return; ! 1616: }/* end fsmSendingCmd */ ! 1617: ! 1618: ! 1619: /* Follow SCSI Phase change. Called while SCS_INITIATOR. */ ! 1620: ! 1621: void CurioSCSIController::fsmPhaseChange() ! 1622: { ! 1623: int i; ! 1624: ! 1625: ! 1626: ELG( 0, fSaveStatus, 'fPhC', "fsmPhaseChange" ); ! 1627: ! 1628: fCurrentBusPhase = fSaveStatus & mPhase; ! 1629: ! 1630: switch ( fCurrentBusPhase ) ! 1631: { ! 1632: case kBusPhaseCMD: ! 1633: /* The normal case here is after a host-initiated SDTR sequence. */ ! 1634: setCmdReg( cFlshFFO ); ! 1635: putCDBIntoFIFO(); ! 1636: setCmdReg( cIOXfer ); /* Start non-DMA xfer */ ! 1637: fMsgInState = kMsgInInit; ! 1638: fBusState = SCS_SENDINGCMD; ! 1639: break; ! 1640: ! 1641: case kBusPhaseDATI: /* From target to Initiator (read) */ ! 1642: case kBusPhaseDATO: /* To Target from Initiator (write) */ ! 1643: fMsgInState = kMsgInInit; ! 1644: fsmStartDataPhase( fCurrentBusPhase == kBusPhaseDATI ); ! 1645: fCkForAnotherInt = false; ! 1646: break; ! 1647: ! 1648: case kBusPhaseSTS: /* Status from Target to Initiator */ ! 1649: /* fsmCompleting will collect the STATUS byte (and */ ! 1650: /* hopefully a MSG) from the FIFO when this completes. */ ! 1651: fMsgInState = kMsgInInit; ! 1652: fBusState = SCS_COMPLETING; ! 1653: setCmdReg( cFlshFFO ); ! 1654: setCmdReg( cCmdComp ); ! 1655: break; ! 1656: ! 1657: case kBusPhaseMSGI: /* Message from Target to Initiator */ ! 1658: if ( fBusState != SCS_RESELECTING ) ! 1659: fBusState = SCS_GETTINGMSG; ! 1660: setCmdReg( cNOP ); ! 1661: setCmdReg( cIOXfer ); ! 1662: break; ! 1663: ! 1664: case kBusPhaseMSGO: /* Message from Initiator to Target */ ! 1665: fMsgInState = kMsgInInit; ! 1666: setCmdReg( cFlshFFO ); ! 1667: ! 1668: if ( fpMsgPut == fpMsgOut ) ! 1669: *fpMsgOut++ = kSCSIMsgNop; /* no message waiting to be sent. */ ! 1670: ! 1671: ! 1672: for ( i = 0; i < 16 && fpMsgPut < fpMsgOut; i++ ) ! 1673: { WRITE_REGISTER( rFFO , *fpMsgPut ); ! 1674: fpMsgPut++; ! 1675: } ! 1676: ! 1677: if ( fpMsgPut == fpMsgOut ) ! 1678: fpMsgPut = fpMsgOut = fMsgOutBuffer; ! 1679: ! 1680: fBusState = SCS_SENDINGMSG; ! 1681: /* ATN is automatically cleared when transfer info completes. */ ! 1682: setCmdReg( cIOXfer ); /* Start non-DMA xfer */ ! 1683: break; ! 1684: ! 1685: default: ! 1686: fsmStartErrorRecovery( kIOReturnInternalError ); ! 1687: break; ! 1688: } ! 1689: return; ! 1690: }/* end fsmPhaseChange */ ! 1691: ! 1692: ! 1693: void CurioSCSIController::fsmStartDataPhase( bool isDataInPhase ) ! 1694: { ! 1695: IOReturn ioReturn = kIOReturnSuccess; ! 1696: ! 1697: ! 1698: ELG( fCmd, fThisTransferLength, 'fDat', "fsmStartDataPhase" ); ! 1699: ! 1700: /* DataIn phase is legal if this is a read command: */ ! 1701: ! 1702: if ( isDataInPhase != !fCmdData->isWrite ) ! 1703: { ! 1704: ioReturn = kIOReturnInternalError; ! 1705: PAUSE( fCmd, isDataInPhase, 'Dir-', "fsmStartDataPhase - data direction" ); ! 1706: } ! 1707: ! 1708: if ( ioReturn == kIOReturnSuccess ) ! 1709: { ! 1710: ioReturn = generateCCL(); ! 1711: } ! 1712: ! 1713: if ( ioReturn == kIOReturnSuccess ) ! 1714: { ! 1715: if ( fThisTransferLength == 0 ) ! 1716: { ! 1717: ioReturn = kIOReturnInternalError; ! 1718: PAUSE( fCmd, 0, 'Dat0', "fsmStartDataPhase - no data" ); ! 1719: } ! 1720: } ! 1721: ! 1722: if ( ioReturn == kIOReturnSuccess ) ! 1723: { ! 1724: // IOSetDBDMACommandPtr( fDBDMAAddr, fCCLPhysAddr ); ! 1725: fDBDMAAddr->commandPtrLo = SWAP( fCCLPhysAddr ); ! 1726: SynchronizeIO(); ! 1727: ! 1728: // IOSetDBDMAChannelControl( fDBDMAAddr, kdbdmaRun * 0x1001 ); ! 1729: // fDBDMAAddr->channelControl = SWAP( kdbdmaRun * 0x1001 ); ! 1730: fDBDMAAddr->channelControl = SWAP( 0x80008000 ); // set RUN bit ! 1731: SynchronizeIO(); ! 1732: ! 1733: WRITE_REGISTER( rXCM, fThisTransferLength >> 8 ); ! 1734: WRITE_REGISTER( rXCL, fThisTransferLength & 0xFF ); ! 1735: setCmdReg( cDMAXfer ); ! 1736: ! 1737: fBusState = SCS_DMACOMPLETE; ! 1738: } ! 1739: ! 1740: if ( ioReturn != kIOReturnSuccess ) ! 1741: { ! 1742: PAUSE( 0, 0, 'Dat-', "fsmStartDataPhase - data phase error" ); ! 1743: fsmStartErrorRecovery( ioReturn ); ! 1744: } ! 1745: return; ! 1746: }/* end fsmStartDataPhase */ ! 1747: ! 1748: ! 1749: /* Start error recovery by doing something reasonable for the */ ! 1750: /* current bus phase. This is called when we enter error recovery */ ! 1751: /* (SCS_DEATH_MARCH) from an interrupt or other bus phase action handler. */ ! 1752: ! 1753: void CurioSCSIController::fsmStartErrorRecovery( IOReturn status ) ! 1754: { ! 1755: ! 1756: ELG( fCmd, 0, 'fSER', "fsmStartErrorRecovery" ); ! 1757: killActiveCommand( status ); ! 1758: /* Clean out the SCSI and DBDMA hardware */ ! 1759: setCmdReg( cFlshFFO ); ! 1760: setCmdReg( cNOP | bDMAEnBit ); // clear TC zero bit ! 1761: // IODBDMAReset( fDBDMAAddr ); ! 1762: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit ! 1763: SynchronizeIO(); ! 1764: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit ! 1765: SynchronizeIO(); ! 1766: ! 1767: if ( fBusBusy == false ) ! 1768: fBusState = SCS_DISCONNECTED; ! 1769: else fBusState = SCS_DEATH_MARCH;/* We will continue at fsmContinueErrorRecovery */ ! 1770: ! 1771: fCkForAnotherInt = false; ! 1772: return; ! 1773: }/* end fsmStartErrorRecovery */ ! 1774: ! 1775: ! 1776: /* Manage error recovery by responding to a target interrupt while in */ ! 1777: /* an error recovery state. On exit, the bus state will be as follows: */ ! 1778: /* SCS_DEATH_MARCH Still in error recovery. Call fsmContinueErrorRecovery */ ! 1779: /* to continue processing target requests. */ ! 1780: /* SCS_DISCONNECTED The target is finally off the bus. We can restart */ ! 1781: /* normal operation. */ ! 1782: /* Each bus phase requires a different action: */ ! 1783: /* Data Out Clean up after DMA. */ ! 1784: /* Data In Clean up after DMA. */ ! 1785: /* Command Flush the FIFO */ ! 1786: /* Status Drain the FIFO, if we get two bytes, just ACK the message */ ! 1787: /* Message Out Do nothing */ ! 1788: /* Message In Read the message byte, ACK it. */ ! 1789: ! 1790: void CurioSCSIController::fsmErrorRecoveryInterruptService() ! 1791: { ! 1792: setCmdReg( cFlshFFO ); ! 1793: ! 1794: switch ( fCurrentBusPhase ) ! 1795: { ! 1796: case kBusPhaseDATO: ! 1797: case kBusPhaseDATI: ! 1798: // IODBDMAReset( fDBDMAAddr ); ! 1799: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit ! 1800: SynchronizeIO(); ! 1801: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit ! 1802: SynchronizeIO(); ! 1803: setCmdReg( cNOP | bDMAEnBit ); // clear TC zero bit ! 1804: break; ! 1805: ! 1806: case kBusPhaseCMD: ! 1807: break; ! 1808: ! 1809: case kBusPhaseSTS: ! 1810: if ( fSaveInterrupt & iFuncComp ) ! 1811: { ! 1812: /* We got both bytes: ACK the command complete */ ! 1813: setCmdReg( cMsgAcep ); ! 1814: } ! 1815: break; ! 1816: ! 1817: case kBusPhaseMSGO: ! 1818: break; ! 1819: ! 1820: case kBusPhaseMSGI: ! 1821: setCmdReg( cMsgAcep ); ! 1822: break; ! 1823: ! 1824: case kBusPhaseBusFree: /* Selecting */ ! 1825: break; ! 1826: ! 1827: default: ! 1828: killActiveCommand( kIOReturnInternalError ); ! 1829: resetBus(); ! 1830: break; ! 1831: } ! 1832: return; ! 1833: }/* end fsmErrorRecoveryInterruptService */ ! 1834: ! 1835: ! 1836: /* Continue to manage error recovery. We are here because the target */ ! 1837: /* is still on the bus and doing strange bus phase things. Follow the */ ! 1838: /* target bus phase (one phase at a time) until the target disconnects. */ ! 1839: /* We just run bit-bucket commands until the target gives up. */ ! 1840: /* (Note that this means that we might send a Command Complete message */ ! 1841: /* to the target. We'll look for this case and send an Abort or */ ! 1842: /* Abort Tag instead.) */ ! 1843: ! 1844: void CurioSCSIController::fsmContinueErrorRecovery() ! 1845: { ! 1846: UInt8 msgByte; ! 1847: ! 1848: ! 1849: quickCheckForInterrupt(); ! 1850: ! 1851: ! 1852: if ( fBusBusy ) ! 1853: { ! 1854: interruptPending(); ! 1855: if ( fSaveInterrupt & iDisconnect ) ! 1856: fBusBusy = false; ! 1857: } ! 1858: ! 1859: if ( fBusBusy == false ) ! 1860: { ! 1861: fBusState = SCS_DISCONNECTED; ! 1862: } ! 1863: else ! 1864: { ! 1865: fCurrentBusPhase = fSaveStatus & mPhase; ! 1866: ! 1867: switch ( fCurrentBusPhase ) ! 1868: { ! 1869: case kBusPhaseMSGO: ! 1870: msgByte = kSCSIMsgAbort; ! 1871: WRITE_REGISTER( rFFO, msgByte ); ! 1872: setCmdReg( cIOXfer ); /* Start non-DMA xfer */ ! 1873: break; ! 1874: ! 1875: case kBusPhaseDATO: ! 1876: case kBusPhaseCMD: ! 1877: WRITE_REGISTER( rXCM, 0xFF ); ! 1878: WRITE_REGISTER( rXCL, 0xFF ); ! 1879: setCmdReg( cDMAXferPad ); /* DMA out pad */ ! 1880: break; ! 1881: ! 1882: case kBusPhaseMSGI: ! 1883: case kBusPhaseDATI: ! 1884: case kBusPhaseSTS: ! 1885: WRITE_REGISTER( rXCM, 0xFF ); ! 1886: WRITE_REGISTER( rXCL, 0xFF ); ! 1887: setCmdReg( cXferPad ); /* non-DMA out pad */ ! 1888: break; ! 1889: ! 1890: default: ! 1891: killActiveCommand( kIOReturnInternalError ); ! 1892: resetBus(); ! 1893: break; ! 1894: } ! 1895: }/* end SWITCH on current phase */ ! 1896: ! 1897: return; ! 1898: }/* end fsmContinueErrorRecovery */ ! 1899: ! 1900: ! 1901: ! 1902: IOReturn CurioSCSIController::getReselectionTargetID( UInt8 selectByte ) ! 1903: { ! 1904: register UInt8 targetBits = selectByte; ! 1905: register UInt8 targetID = 0; ! 1906: register UInt8 bitValue; /* Supress warning */ ! 1907: ! 1908: ! 1909: if ( (targetBits & fInitiatorIDMask) == 0 ) ! 1910: { ! 1911: PAUSE( 0, selectByte, 'IId-', "getReselectionTargetID - Reselection failed: initiator ID bit not set" ); ! 1912: return kIOReturnInternalError; ! 1913: } ! 1914: ! 1915: targetBits = selectByte; ! 1916: targetBits &= ~fInitiatorIDMask; /* Remove our bit */ ! 1917: if ( targetBits == 0 ) ! 1918: { ! 1919: PAUSE( 0, selectByte, 'TId-', "getReselectionTargetID - Reselection failed: Target ID bit not set" ); ! 1920: return kIOReturnInternalError; ! 1921: } ! 1922: ! 1923: bitValue = targetBits; ! 1924: ! 1925: if ( bitValue > 0x0F ) { targetID += 4; bitValue >>= 4; } ! 1926: if ( bitValue > 0x03 ) { targetID += 2; bitValue >>= 2; } ! 1927: if ( bitValue > 0x01 ) targetID += 1; ! 1928: ! 1929: targetBits &= ~(1 << targetID); /* Remove the target mask */ ! 1930: if ( targetBits != 0 ) ! 1931: { ! 1932: PAUSE( 0, selectByte, 'TTT-', "getReselectionTargetID - Reselection failed: multiple targets" ); ! 1933: return kIOReturnInternalError; ! 1934: } ! 1935: ! 1936: ELG( 0, targetID, '=Tar', "getReselectionTargetID" ); ! 1937: ! 1938: fCurrentTargetLun.target = targetID; /* Save the current target */ ! 1939: return kIOReturnSuccess; ! 1940: }/* end getReselectionTargetID */ ! 1941: ! 1942: ! 1943: void CurioSCSIController::reselectNexus() ! 1944: { ! 1945: fCmd = findCommandWithNexus( fCurrentTargetLun, fTag ); ! 1946: if ( fCmd ) ! 1947: { fCmdData = (PrivCmdData*)fCmd->getCommandData(); ! 1948: ELG( fCmd, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, '=Nex', "reselectNexus" ); ! 1949: } ! 1950: else ! 1951: { if ( fTag != kInvalidTag ) ! 1952: ELG( 0, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, 'Nex-', "reselectNexus" ); ! 1953: } ! 1954: ! 1955: return; ! 1956: }/* end reselectNexus */ ! 1957: ! 1958: ! 1959: /* Send a command to the MESH chip. This may cause an interrupt. */ ! 1960: ! 1961: void CurioSCSIController::setCmdReg( UInt8 command ) ! 1962: { ! 1963: ELG( 0, command, '=Cmd', "setCmdReg" ); ! 1964: ! 1965: fCurioAddr[ rCMD ] = command; /***** DO IT *****/ ! 1966: SynchronizeIO(); ! 1967: ! 1968: return; ! 1969: }/* end setCmdReg */ ! 1970: ! 1971: ! 1972: ! 1973: /* This spin-loop looks for another chip operation - it prevents */ ! 1974: /* exiting the interrupt service routine if the chip presents */ ! 1975: /* another operation within ten microseconds. Note that this */ ! 1976: /* must be called from an IOThread, not from a "real" primary */ ! 1977: /* interrupt service routine. */ ! 1978: /* @return true if an interrupt is pending. */ ! 1979: ! 1980: #define OVERTIME( now, end ) \ ! 1981: ( ((now)->tv_sec > (end)->tv_sec) \ ! 1982: || (((now)->tv_sec == (end)->tv_sec) && ((now)->tv_nsec > (end)->tv_nsec)) ) ! 1983: ! 1984: ! 1985: bool CurioSCSIController::quickCheckForInterrupt() ! 1986: { ! 1987: mach_timespec_t thisTime, endTime; ! 1988: ! 1989: ! 1990: IOGetTime( &endTime ); // calc the omega ! 1991: endTime.tv_nsec += 10000; // 10 mikes from now ! 1992: if ( endTime.tv_nsec >= NSEC_PER_SEC ) ! 1993: { ! 1994: endTime.tv_sec += 1; ! 1995: endTime.tv_nsec -= NSEC_PER_SEC; ! 1996: } ! 1997: /* whiz til interrupt or time's up: */ ! 1998: do ! 1999: { ! 2000: if ( interruptPending() ) ! 2001: return true; ! 2002: ! 2003: IOGetTime( &thisTime ); ! 2004: } while ( OVERTIME( &thisTime, &endTime ) == false ); ! 2005: ! 2006: return false; ! 2007: }/* end quickCheckForInterrupt */ ! 2008: ! 2009: ! 2010: /* Determine if SCSI interrupt is pending. If so, store the current */ ! 2011: /* chip state. Note that reading the interrupt register clears the */ ! 2012: /* interrupt source, so this should be done once for each interrupt.*/ ! 2013: /* @return true if an interrupt is pending. */ ! 2014: ! 2015: bool CurioSCSIController::interruptPending() ! 2016: { ! 2017: bool result = false; ! 2018: ! 2019: ! 2020: /* mlj - use WHILE to check for double interrupts */ ! 2021: /* and get get most recent conditions. */ ! 2022: ! 2023: while ( (fSaveStatus = fCurioAddr[ rSTA ]) & sIntPend ) // ??? volatile ! 2024: { ! 2025: result = true; ! 2026: fSaveSeqStep = fCurioAddr[ rSQS ]; ! 2027: fSaveInterrupt = fCurioAddr[ rINT ]; /* this clears rSTA and rSQS */ ! 2028: ELG( fSaveSeqStep, fSaveStatus<<16 | fSaveInterrupt, 'Regs', "interruptPending" ); ! 2029: } ! 2030: return result; ! 2031: }/* end interruptPending */ ! 2032: ! 2033: ! 2034: ! 2035: void CurioSCSIController::putCDBIntoFIFO() ! 2036: { ! 2037: SCSICDBInfo scsiCDB; ! 2038: UInt32 i; ! 2039: ! 2040: ! 2041: fCmd->getCDB( &scsiCDB ); ! 2042: for ( i = 0; i < scsiCDB.cdbLength; i++ ) ! 2043: WRITE_REGISTER( rFFO, scsiCDB.cdb[ i ] ); ! 2044: ! 2045: return; ! 2046: }/* end putCDBIntoFIFO */ ! 2047: ! 2048: ! 2049: /* resetCurio - Reset the chip to hardware power on state. */ ! 2050: ! 2051: void CurioSCSIController::resetCurio() ! 2052: { ! 2053: ELG( 0, 0, 'ResC', "resetCurio" ); ! 2054: setCmdReg( cRstSChp ); /* Reset chip */ ! 2055: IODelay( 50 ); /* Chip settle */ ! 2056: setCmdReg( cNOP ); /* Re-enable chip */ ! 2057: setCmdReg( cFlshFFO ); /* In a clean state */ ! 2058: return; ! 2059: }/* end resetCurio */ ! 2060: ! 2061: ! 2062: /* resetHardware - Reusable hardware initializer function. */ ! 2063: /* if busReset is true, this includes a SCSI bus reset. */ ! 2064: ! 2065: IOReturn CurioSCSIController::resetHardware( bool busReset ) ! 2066: { ! 2067: IOReturn ioReturn = kIOReturnSuccess; ! 2068: UInt8 configValue; ! 2069: UInt8 clockConversionFactor; ! 2070: UInt8 defaultSelectionTimeout; ! 2071: UInt8 temp; ! 2072: ! 2073: ! 2074: /* Temp for debugging */ ! 2075: ! 2076: fSCSIClockRate = kChipDefaultBusClockMHz; ! 2077: ! 2078: ELG( fSCSIClockRate, busReset, 'ResH', "resetHardware" ); ! 2079: ! 2080: /* First of all, reset interrupts, the SCSI chip, and the DMA engine. */ ! 2081: ! 2082: // resetCurio(); /* Clear out the chip */ ! 2083: ! 2084: temp = fCurioAddr[ rINT ]; /* Clear pending interrupt */ ! 2085: ! 2086: // IODBDMAReset( fDBDMAAddr ); /* Stop the DMA engine */ ! 2087: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit ! 2088: SynchronizeIO(); ! 2089: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit ! 2090: SynchronizeIO(); ! 2091: ! 2092: /* Initialize the chip: */ ! 2093: ! 2094: WRITE_REGISTER( rCF2, CF2_EPL ); /* Enable Phase Latching */ ! 2095: setCmdReg(cNOP | bDMAEnBit); /* DMA Nop */ ! 2096: ! 2097: /* Init state variables: */ ! 2098: ! 2099: fCkForAnotherInt = false; ! 2100: fBusState = SCS_DISCONNECTED; ! 2101: fBusBusy = false; ! 2102: fCurrentBusPhase = kBusPhaseBusFree; ! 2103: ! 2104: /* Smash all active command state (just in case). */ ! 2105: ! 2106: fCmd = NULL; ! 2107: fMsgInState = kMsgInInit; ! 2108: fpMsgOut = fpMsgPut = fMsgOutBuffer; ! 2109: ! 2110: fCurrentTargetLun.target = kInvalidTarget; ! 2111: fCurrentTargetLun.lun = kInvalidLUN; ! 2112: ! 2113: /* Configuration Register 1 */ ! 2114: /* Disable interrupt on initiator-instantiated bus reset */ ! 2115: /* (is this correct?) */ ! 2116: /* Enable parity. */ ! 2117: /* Set default bus ID (7) (This should be overriden by the */ ! 2118: /* Inspector) */ ! 2119: ! 2120: fInitiatorID = kDefaultInitiatorID; ! 2121: configValue = CF1_SRD | CF1_ENABPAR | fInitiatorID; ! 2122: ! 2123: #define gOptionExtendTiming 0 ! 2124: if ( gOptionExtendTiming ) ! 2125: { /* Per instance table. This slows down transfers on the bus. */ ! 2126: configValue |= CF1_SLOW; ! 2127: } ! 2128: ! 2129: WRITE_REGISTER( rCF1, configValue ); ! 2130: ! 2131: /* Clock factor and select timeout. */ ! 2132: ! 2133: /* Use the clock frequency (in MHz) to select the clock conversion */ ! 2134: /* factor. According to the NCR53CF94/96 data manual, the conversion */ ! 2135: /* factor is defined by the following table: Currently, we don't allow */ ! 2136: /* the caller to change selection timeout from the ANSI standard */ ! 2137: /* 250 Msec to avoid having to support floating-point register */ ! 2138: /* manipulation */ ! 2139: ! 2140: if ( fSCSIClockRate < 10) fSCSIClockRate = 10; ! 2141: if ( fSCSIClockRate > 40 ) fSCSIClockRate = 40; ! 2142: ! 2143: if ( fSCSIClockRate <= 10 ) ! 2144: { ! 2145: clockConversionFactor = ccf10MHz; ! 2146: defaultSelectionTimeout = SelTO16Mhz; ! 2147: } ! 2148: else if ( fSCSIClockRate <= 15 ) ! 2149: { ! 2150: clockConversionFactor = ccf11to15MHz; ! 2151: defaultSelectionTimeout = SelTO16Mhz; ! 2152: } ! 2153: else if ( fSCSIClockRate <= 20 ) ! 2154: { ! 2155: clockConversionFactor = ccf16to20MHz; ! 2156: defaultSelectionTimeout = SelTO16Mhz; ! 2157: } ! 2158: else if ( fSCSIClockRate <= 25 ) ! 2159: { ! 2160: clockConversionFactor = ccf21to25MHz; ! 2161: defaultSelectionTimeout = SelTO25Mhz; ! 2162: } ! 2163: else if ( fSCSIClockRate <= 30 ) ! 2164: { ! 2165: clockConversionFactor = ccf26to30MHz; ! 2166: defaultSelectionTimeout = SelTO33Mhz; ! 2167: } ! 2168: else if ( fSCSIClockRate <= 35 ) ! 2169: { ! 2170: clockConversionFactor = ccf31to35MHz; ! 2171: defaultSelectionTimeout = SelTO40Mhz; ! 2172: } ! 2173: else ! 2174: { ! 2175: clockConversionFactor = ccf31to35MHz; ! 2176: defaultSelectionTimeout = SelTO40Mhz; ! 2177: } ! 2178: ! 2179: WRITE_REGISTER( rCKF, clockConversionFactor ); ! 2180: ! 2181: WRITE_REGISTER( rINT, defaultSelectionTimeout); ! 2182: ! 2183: /* Configuration Register 2 - enable extended features */ ! 2184: /* - mainly, 24-bit transfer count. */ ! 2185: ! 2186: WRITE_REGISTER( rCF2, CF2_EPL ); ! 2187: ! 2188: /* Configuration Register 3 */ ! 2189: ! 2190: configValue = 0; ! 2191: ! 2192: #define gOptionFastModeEnable 0 ! 2193: #define gOptionFastModeSupportedByHardware 0 ! 2194: ! 2195: if ( (gOptionFastModeEnable && gOptionFastModeSupportedByHardware) ! 2196: || fSCSIClockRate > 25 ) ! 2197: { ! 2198: configValue |= CF3_FASTSCSI; ! 2199: } ! 2200: ! 2201: WRITE_REGISTER( rCF3, configValue ); ! 2202: ! 2203: /* Configuration Register 4 - glitch eater, active negation. */ ! 2204: /* Let's not worry about these whizzy features just yet. */ ! 2205: ! 2206: WRITE_REGISTER( rCF4, 0 ); ! 2207: ! 2208: /* Go to async xfer mode for now. */ ! 2209: ! 2210: WRITE_REGISTER( rFOS, 0 ); ! 2211: ! 2212: /* Reset SCSI bus, wait, clear possible interrupt. */ ! 2213: ! 2214: if ( busReset ) ! 2215: { ! 2216: setCmdReg( cRstSBus ); ! 2217: IOSleep( kSCSIResetDelay ); ! 2218: temp = fCurioAddr[ rINT ]; // clear the Interrupt register ! 2219: } ! 2220: return ioReturn; ! 2221: }/* end resetHardware */ ! 2222: ! 2223: ! 2224: void CurioSCSIController::releaseHardwareMemoryMaps() ! 2225: { ! 2226: if ( fDBDMAMemoryMap ) ! 2227: { ! 2228: fDBDMAMemoryMap->release(); ! 2229: fDBDMAMemoryMap = NULL; ! 2230: } ! 2231: ! 2232: if ( fSCSIMemoryMap ) ! 2233: { ! 2234: fSCSIMemoryMap->release(); ! 2235: fSCSIMemoryMap = NULL; ! 2236: } ! 2237: ! 2238: if ( fCCL ) ! 2239: { ! 2240: IOFree( fCCL, fCCLSize ); ! 2241: } ! 2242: ! 2243: return; ! 2244: }/* end releaseHardwareMemoryMaps */ ! 2245: ! 2246: ! 2247: /* When a legitimate data phase starts, this method */ ! 2248: /* is called to configure the DBDMA Channel Command list. */ ! 2249: ! 2250: IOReturn CurioSCSIController::generateCCL() ! 2251: { ! 2252: IODBDMADescriptor *dp; /* current descriptor */ ! 2253: IODBDMADescriptor *dpMax; /* past the last descriptor */ ! 2254: UInt32 dbdmaOp; /* DBDMA opcode */ ! 2255: UInt32 rangeByteCount, actualRanges; ! 2256: UInt32 i; ! 2257: IOPhysicalSegment range[ kMaxMemoryCursorSegments ]; ! 2258: ! 2259: ! 2260: ! 2261: // IODBDMAReset( fDBDMAAddr ); /* make sure that the DBDMA is idle. */ ! 2262: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit ! 2263: SynchronizeIO(); ! 2264: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit ! 2265: SynchronizeIO(); ! 2266: ! 2267: if ( fCmdData->isWrite ) /* Select the correct DBDMA: */ ! 2268: dbdmaOp = OUTPUT_MORE; ! 2269: else dbdmaOp = INPUT_MORE; ! 2270: ! 2271: /* How many descriptors can we store (need some slop for the */ ! 2272: /* terminator commands). */ ! 2273: /* Get a pointer to the first free descriptor and the total */ ! 2274: /* number of bytes left to transfer in this I/O request. */ ! 2275: ! 2276: dp = (IODBDMADescriptor*)fCCL; ! 2277: dpMax = (IODBDMADescriptor*)(fCCL + fCCLSize - 256); ! 2278: ! 2279: /* fThisTransferLength will contain the actual number */ ! 2280: /* of bytes we intend to transfer in this DMA request, */ ! 2281: /* which is needed when DMA completes to recover the */ ! 2282: /* residual transfer length. */ ! 2283: fThisTransferLength = 0; ! 2284: ! 2285: while ( (dp < dpMax) && (fThisTransferLength < kMaxDMATransfer) ) ! 2286: { ! 2287: actualRanges = fMemoryCursor->getPhysicalSegments( fCmdData->mdp, ! 2288: fCmdData->results.bytesTransferred + fThisTransferLength, ! 2289: range, ! 2290: (unsigned int)kMaxMemoryCursorSegments, ! 2291: 0, &rangeByteCount ); ! 2292: if ( actualRanges == 0 ) ! 2293: break; ! 2294: ! 2295: for ( i = 0; i < actualRanges; i++ ) ! 2296: { ! 2297: ELG( range[ i ].location, range[ i ].length, '=Rng', "generateCCL - range" ); ! 2298: dp->operation = SWAP( dbdmaOp | range[ i ].length ); ! 2299: dp->address = SWAP( (UInt32)range[ i ].location ); ! 2300: dp->cmdDep = 0; // no branch address ! 2301: dp->result = 0; ! 2302: dp++; ! 2303: }/* end FOR each range */ ! 2304: ! 2305: fThisTransferLength += rangeByteCount; ! 2306: }/* end WHILE there is data to xfer */ ! 2307: ! 2308: if ( (UInt8*)dp > fCCL ) ! 2309: { ! 2310: /* We stored at least one descriptor. */ ! 2311: /* Change the last one so it is an INPUT_LAST or OUTPUT_LAST. */ ! 2312: ! 2313: dp->operation |= SWAP( IO_LAST ); ! 2314: } ! 2315: ! 2316: dp->operation = SWAP( STOP_CMD ); ! 2317: dp->address = 0; ! 2318: dp->cmdDep = 0; ! 2319: dp->result = 0; ! 2320: dp++; ! 2321: ! 2322: if( dp >= dpMax ) ! 2323: PAUSE( dpMax, dp, 'Big-', "InitCmdCCL - CCL overrun" ); ! 2324: ! 2325: flush_dcache( (vm_offset_t)fCCL, (UInt32)dp - (UInt32)fCCL, false ); ! 2326: ! 2327: return kIOReturnSuccess; ! 2328: }/* end generateCCL */ ! 2329: ! 2330: ! 2331: void CurioSCSIController::killActiveCommand( IOReturn finalStatus ) ! 2332: { ! 2333: if ( fCmd ) ! 2334: { ! 2335: fCmdData->results.returnCode = finalStatus; ! 2336: completeCommand(); ! 2337: } ! 2338: return; ! 2339: }/* end killActiveCommand */ ! 2340: ! 2341: ! 2342: void CurioSCSIController::resetBus() ! 2343: { ! 2344: setCmdReg( cRstSBus ); ! 2345: super::resetOccurred(); ! 2346: IOSleep( kSCSIResetDelay ); ! 2347: enableCommands(); ! 2348: return; ! 2349: }/* end resetBus */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.