|
|
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: /** ! 24: * Copyright 1997-2000 Apple Computer Inc. All Rights Reserved. ! 25: * author Mike Johnson ! 26: * ! 27: * Set tabs every 4 characters. ! 28: * ! 29: * Edit History ! 30: * 25feb99 mlj Initial conversion from banana sources. ! 31: */ ! 32: ! 33: ! 34: #include <IOKit/scsi/IOSCSIParallelInterface.h> ! 35: #include <IOKit/pci/IOPCIDevice.h> ! 36: #include <mach/clock_types.h> ! 37: ! 38: #include <IOKit/IOInterruptEventSource.h> ! 39: #include <IOKit/ppc/IODBDMA.h> ! 40: ! 41: #include "mesh.h" ! 42: ! 43: extern void IOGetTime( mach_timespec_t *clock_time ); ! 44: extern void kprintf( const char *, ... ); ! 45: extern void call_kdp(); // for debugging ! 46: ! 47: ! 48: ! 49: #define super IOSCSIParallelController ! 50: ! 51: OSDefineMetaClassAndStructors( meshSCSIController, IOSCSIParallelController ) ; ! 52: ! 53: ! 54: ! 55: static globals g; /**** Instantiate the globals ****/ ! 56: ! 57: ! 58: /* Channel Program. Note that this script must match the offsets */ ! 59: /* specified in mesh.h. This script is copied into the */ ! 60: /* channel command area (with appropriate entries byte-swapped so */ ! 61: /* it ends up with the correct endian-ness). */ ! 62: /* Lines beginning with "slash, star, star, slash" are modified */ ! 63: /* by the driver before it starts the Channel Program. */ ! 64: ! 65: static const DBDMADescriptor gDescriptorList[] = ! 66: { ! 67: /* 0x00 kcclProblem - Branch here for anomalies */ ! 68: ! 69: { MESH_REG( kMeshInterruptMask, kMeshIntrMask ) }, // Enable MESH interrupt ! 70: { STOP( kcclStageCCLx ) }, // anomaly ! 71: ! 72: /* 0x20 through 0x60 - Data for information phases: */ ! 73: ! 74: { RESERVE }, // kcclCMDOdata - CDB ( 6,10,12,16 bytes) ! 75: { RESERVE }, // kcclMSGOdata - MSGO data (last byte @3F) ! 76: { RESERVE }, // kcclMSGIdata - MSGI data & STATUS ! 77: { RESERVE }, // kcclSenseCDB - CDB for (auto) Sense ! 78: { RESERVE }, // kcclBatchSize, kcclStageLabel ! 79: ! 80: /* 0x70 - kcclSense - AutoSense input: */ ! 81: ! 82: { MESH_REG( kMeshTransferCount1, 0x00 ) }, // set MESH xfer count to 255 ! 83: { MESH_REG( kMeshTransferCount0, kMaxAutosenseByteCount & 0xFF )}, ! 84: { MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA )},// Data-In to Seq register ! 85: { SENSE( kMaxAutosenseByteCount ) }, // Sense INPUT ! 86: { BRANCH( kcclGetStatus ) }, // do finish sequence ! 87: ! 88: /* 0xC0 - kcclPrototype - Prototype MESH 4-command Transfer sequence: */ ! 89: ! 90: { MOVE_4( kcclBatchSize, 0, kRelAddressCP ) }, // MESH batch size ! 91: { MESH_REG( kMeshTransferCount1, 0 ) }, // Set high order Transfer Count ! 92: { MESH_REG( kMeshTransferCount0, 0 ) }, // Set low order Transfer Count ! 93: { MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA )}, // Assume Data-In ! 94: ! 95: { RESERVE }, // kcclReadBuf8 ! 96: { RESERVE }, // spare ! 97: ! 98: /* 0x120 kcclStart - Arbitrate (START CHANNEL PROGRAM HERE): */ ! 99: /* 0x140 kcclBrProblem */ ! 100: ! 101: { STAGE( kcclStageArb ) }, ! 102: { MESH_REG( kMeshSequence, kMeshArbitrateCmd ) }, // issue Arbitrate ! 103: { BR_IF_PROBLEM }, // branch if exception or error ! 104: ! 105: /* 0x150 - Select with Attention: */ ! 106: ! 107: { STAGE( kcclStageSelA ) }, ! 108: { CLEAR_CMD_DONE }, ! 109: { MESH_REG( kMeshSequence, kMeshSelectCmd | kMeshSeqAtn ) }, // select with attention ! 110: { BR_IF_PROBLEM }, // branch if failed ! 111: ! 112: /* 0x190 kcclMsgoStage - Message-Out: */ ! 113: ! 114: { STAGE( kcclStageMsgO ) }, ! 115: { CLEAR_CMD_DONE }, ! 116: ! 117: /* 0x1B0 kcclMsgoBranch - modify this BRANCH to fall through for multibyte messages: */ ! 118: ! 119: /**/{ BRANCH( kcclLastMsgo ) }, // kcclMsgoBranch - go do only byte of Msg ! 120: ! 121: /* 0x1C0 - do all but last byte of multibyte message: */ ! 122: ! 123: { MESH_REG( kMeshTransferCount1, 0x00 ) }, // count does include last byte ! 124: /**/{ MESH_REG( kMeshTransferCount0, 0xFF ) }, // kcclMsgoMTC - modify MESH xfer count here ! 125: { MESH_REG( kMeshSequence, kMeshMessageOutCmd | kMeshSeqAtn | kMeshSeqDMA ) }, // DMA MsgO with ATN ! 126: /**/{ MSGO( kcclMSGOdata, 255 ) }, // kcclMsgoDTC - output all but last byte ! 127: { CLEAR_CMD_DONE }, ! 128: ! 129: /* 0x210 kcclLastMsgo - wait for REQ signal before dropping ATN: */ ! 130: ! 131: { MESH_REG( kMeshInterruptMask, 0 ) }, // inhibit MESH interrupt ! 132: { MESH_REG_WAIT( kMeshSequence, kMeshStatusCmd | kMeshSeqAtn ) }, // gen PhaseMM ! 133: { CLEAR_INT_REG }, // clear PhaseMM & CmdDone ! 134: { MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) }, // re-enable ERR/EXC Ints ! 135: ! 136: /* 0x250 - put out the last or only byte of Message-Out phase: */ ! 137: ! 138: { MESH_REG( kMeshTransferCount1, 0x00 ) }, ! 139: { MESH_REG( kMeshTransferCount0, 0x01 ) }, ! 140: { MESH_REG( kMeshSequence, kMeshMessageOutCmd | kMeshSeqDMA ) },// no more ATN ! 141: { MSGO( kcclMSGOLast, 1 ) }, ! 142: ! 143: /* 0x290 kcclCmdoStage - Command Out: */ ! 144: ! 145: { STAGE( kcclStageCmdO ) }, ! 146: { CLEAR_CMD_DONE }, ! 147: { MESH_REG( kMeshTransferCount1, 0x00 ) }, ! 148: /**/{ MESH_REG( kMeshTransferCount0, 0x06 ) }, // kcclCmdoMTC - Set MESH xfer count to 6 ! 149: { MESH_REG( kMeshSequence, kMeshCommandCmd | kMeshSeqDMA )}, // Command phase with DMA on ! 150: /**/{ CMDO( 6 ) }, // kcclCmdoDTC - output the CDB ! 151: ! 152: /* 0x2F0 - DATA XFER - branch to the built CCL @ 0x05D0: */ ! 153: /* also, kcclReselect - reselect code enters here: */ ! 154: ! 155: { CLEAR_CMD_DONE }, ! 156: { STAGE( kcclStageXfer ) }, ! 157: { BRANCH( kcclDataXfer ) }, // go do Xfer CCL ! 158: ! 159: /* 0x320 kcclOverrun - dump excess data in the bit bucket: */ ! 160: /* Exc and Err are still disabled. */ ! 161: ! 162: { STAGE( kcclStageBucket ) }, ! 163: { MESH_REG( kMeshTransferCount1, 0x00 ) }, // set MESH Transfer Count to max ! 164: { MESH_REG( kMeshTransferCount0, 0x00 ) }, ! 165: { CLR_PHASEMM }, ! 166: { MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) }, // re-enable ERR/EXC Ints ! 167: /**/{ MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA ) }, // set Seq Reg ! 168: /**/{ BUCKET }, // OUT/INPUT_LAST the bits ! 169: { BR_NO_PROBLEM( kcclOverrunDBDMA ) }, // loop til PhaseMismatch ! 170: { BR_IF_PROBLEM }, // take the interrupt now ! 171: ! 172: /* 0x3B0 kcclSyncCleanUp - clean up after Sync xfer: */ ! 173: { CLEAR_INT_REG }, // clear PhaseMM & CmdDone (& Err?) ! 174: { MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) }, // re-enable ERR/EXC Ints ! 175: ! 176: /* 0x3D0 kcclGetStatus - setup CCL for status, command complete and bus free: */ ! 177: ! 178: { STAGE( kcclStageStat ) }, ! 179: { MESH_REG( kMeshTransferCount1, 0x00 ) }, ! 180: { MESH_REG( kMeshTransferCount0, 0x01 ) }, // set MESH xfer count to 1 ! 181: { MESH_REG( kMeshSequence, kMeshStatusCmd | kMeshSeqDMA )},// Status-in phase with DMA on ! 182: { STATUS_IN }, // input the status byte ! 183: ! 184: /* 0x420 - Message In: */ ! 185: ! 186: { STAGE( kcclStageMsgI ) }, ! 187: { CLEAR_CMD_DONE }, ! 188: { MESH_REG( kMeshTransferCount1, 0x00 ) }, ! 189: { MESH_REG( kMeshTransferCount0, 0x01 ) }, // set MESH xfer count to 1 ! 190: { MESH_REG( kMeshSequence, kMeshMessageInCmd | kMeshSeqDMA )}, // Status-in phase with DMA on ! 191: { MSGI( 1 ) }, // get the Message-In byte ! 192: ! 193: /* 0x480 - Bus Free: */ ! 194: ! 195: { STAGE( kcclStageFree ) }, ! 196: { CLEAR_CMD_DONE }, ! 197: { MESH_REG( kMeshSequence, kMeshEnableReselect ) }, // Enable Reselect ! 198: { MESH_REG( kMeshSequence, kMeshBusFreeCmd ) }, // Bus Free phase ! 199: { BR_IF_PROBLEM }, // branch if failed ! 200: ! 201: /* 0x4D0 kcclMESHintr - Good completion: */ ! 202: ! 203: { STAGE( kcclStageGood ) }, ! 204: { MESH_REG( kMeshInterruptMask, kMeshIntrMask ) }, // latch MESH interrupt ! 205: { STOP( kcclStageStop ) }, // Stop ! 206: ! 207: /* The rest of the Channel Program area is used for autosense */ ! 208: /* and data transfer channel commands: */ ! 209: /* kcclSenseBuffer Autosense area */ ! 210: /* kcclDataXfer Start of data transfer channel commands */ ! 211: /* kcclSenseResult Autosense result stored here */ ! 212: ! 213: }; /* end gDescriptorList structure */ ! 214: ! 215: const UInt32 gDescriptorListSize = sizeof( gDescriptorList ); ! 216: ! 217: ! 218: /* MAX_DMA_XFER is set so that we don't have to worry about the */ ! 219: /* ambiguous "zero" value in the MESH and DBDMA transfer registers */ ! 220: /* that can mean either 65536 bytes or zero bytes. */ ! 221: ! 222: #define MAX_DMA_XFER 0x0000F000 // round down to nearest page ! 223: ! 224: ! 225: enum /***** values for g.intLevel: *****/ ! 226: { ! 227: kLevelISR = 0x80, /* In Interrupt Service Routine */ ! 228: kLevelLocked = 0x40, /* MESH interrupts locked out */ ! 229: kLevelSIH = 0x20, /* In Secondary Interrupt Handler */ ! 230: kLevelLatched = 0x10 /* Interrupt latched */ ! 231: }; ! 232: ! 233: ! 234: #if USE_ELG ! 235: static void AllocateEventLog( UInt32 size ) ! 236: { ! 237: if ( g.evLogBuf ) ! 238: return; ! 239: ! 240: g.evLogFlag = 0; /* assume insufficient memory */ ! 241: g.evLogBuf = (UInt8*)IOMalloc( size ); ! 242: if ( !g.evLogBuf ) ! 243: { ! 244: kprintf( "probe - MESH evLog allocation failed " ); ! 245: return; ! 246: } ! 247: ! 248: bzero( g.evLogBuf, size ); ! 249: g.evLogBufp = g.evLogBuf; ! 250: g.evLogBufe = g.evLogBufp + kEvLogSize - 0x20; // ??? overran buffer? ! 251: g.evLogFlag = 0xFEEDBEEF; // continuous wraparound ! 252: // g.evLogFlag = 'step'; // stop at each ELG ! 253: // g.evLogFlag = 0x0333; // any nonzero - don't wrap - stop logging at buffer end ! 254: return; ! 255: }/* end AllocateEventLog */ ! 256: ! 257: ! 258: static void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str ) ! 259: { ! 260: register UInt32 *lp; /* Long pointer */ ! 261: mach_timespec_t time; ! 262: ! 263: if ( g.evLogFlag == 0 ) ! 264: return; ! 265: ! 266: IOGetTime( &time ); ! 267: ! 268: lp = (UInt32*)g.evLogBufp; ! 269: g.evLogBufp += 0x10; ! 270: ! 271: if ( g.evLogBufp >= g.evLogBufe ) /* handle buffer wrap around if any */ ! 272: { g.evLogBufp = g.evLogBuf; ! 273: if ( g.evLogFlag != 0xFEEDBEEF ) // make 0xFEEDBEEF a symbolic ??? ! 274: g.evLogFlag = 0; /* stop tracing if wrap undesired */ ! 275: } ! 276: ! 277: /* compose interrupt level with 3 byte time stamp: */ ! 278: ! 279: *lp++ = (g.intLevel << 24) | ((time.tv_nsec >> 10) & 0x003FFFFF); // ~ 1 microsec resolution ! 280: *lp++ = a; ! 281: *lp++ = b; ! 282: *lp = ascii; ! 283: ! 284: if( g.evLogFlag == 'step' ) ! 285: { static char code[ 5 ] = {0,0,0,0,0}; ! 286: *(UInt32*)&code = ascii; ! 287: // kprintf( "%8x mesh: %8x %8x %s %s\n", time.tv_nsec>>10, a, b, code, str ); ! 288: kprintf( "%8x mesh: %8x %8x %s\n", time.tv_nsec>>10, a, b, code ); ! 289: } ! 290: ! 291: return; ! 292: }/* end EvLog */ ! 293: ! 294: ! 295: static void Pause( UInt32 a, UInt32 b, UInt32 ascii, char* str ) ! 296: { ! 297: char work [ 256 ]; ! 298: char name[] = "meshSCSIController:"; ! 299: char *bp = work; ! 300: UInt8 x; ! 301: int i; ! 302: ! 303: ! 304: EvLog( a, b, ascii, str ); ! 305: EvLog( '****', '** P', 'ause', "*** Pause" ); ! 306: ! 307: bcopy( name, bp, sizeof( name ) ); ! 308: bp += sizeof( name ) - 1; ! 309: ! 310: *bp++ = '{'; // prepend p1 in hex: ! 311: for ( i = 7; i >= 0; --i ) ! 312: { ! 313: x = a & 0x0F; ! 314: if ( x < 10 ) ! 315: x += '0'; ! 316: else x += 'A' - 10; ! 317: bp[ i ] = x; ! 318: a >>= 4; ! 319: } ! 320: bp += 8; ! 321: ! 322: *bp++ = ' '; // prepend p2 in hex: ! 323: ! 324: for ( i = 7; i >= 0; --i ) ! 325: { ! 326: x = b & 0x0F; ! 327: if ( x < 10 ) ! 328: x += '0'; ! 329: else x += 'A' - 10; ! 330: bp[ i ] = x; ! 331: b >>= 4; ! 332: } ! 333: bp += 8; ! 334: *bp++ = '}'; ! 335: ! 336: *bp++ = ' '; ! 337: ! 338: for ( i = sizeof( work ) - (int)(bp - work); i && (*bp++ = *str++); --i ) ; ! 339: ! 340: // kprintf( work ); ! 341: panic( work ); ! 342: // call_kdp(); // ??? use kdp=3 in boot parameters ! 343: return; ! 344: }/* end Pause */ ! 345: #endif // USE_ELG ! 346: ! 347: ! 348: ! 349: bool meshSCSIController::configure( IOService *provider, ! 350: SCSIControllerInfo *controllerInfo ) ! 351: { ! 352: IOReturn ioReturn = kIOReturnInternalError; ! 353: ! 354: ! 355: g.intLevel = 0; ! 356: g.meshInstance = this; ! 357: #if USE_ELG ! 358: AllocateEventLog( kEvLogSize ); ! 359: ELG( g.evLogBufp, &g.evLogFlag, 'MESH', "configure - event logging set up." ); ! 360: #endif /* USE_ELG */ ! 361: ! 362: ELG( this, provider, 'Cnfg', "configure" ); ! 363: ! 364: fProvider = (IOPCIDevice*)provider; ! 365: ! 366: ioReturn = initializeHardware(); ! 367: if ( ioReturn != kIOReturnSuccess ) ! 368: return false; ! 369: ! 370: /* Register our interrupt handler routine: */ ! 371: ! 372: fInterruptEvent = IOInterruptEventSource::interruptEventSource( ! 373: (OSObject*)this, ! 374: (IOInterruptEventAction)&meshSCSIController::interruptOccurred, ! 375: provider, ! 376: 0 ); ! 377: ! 378: if ( fInterruptEvent == NULL ) ! 379: { ! 380: PAUSE( 0, 0, 'IES-', "registerMESHInterrupt - can't register interrupt action" ); ! 381: return false; ! 382: } ! 383: ! 384: getWorkLoop()->addEventSource( fInterruptEvent ); ! 385: fInterruptEvent->enable(); ! 386: ! 387: /* allocate a big-endian memory cursor: */ ! 388: ! 389: fMemoryCursor = IOBigMemoryCursor::withSpecification( kMaxDMATransfer, kMaxDMATransfer ); ! 390: if ( fMemoryCursor == NULL ) ! 391: { ! 392: PAUSE( 0, kMaxDMATransfer, 'Mem-', "mesh::start - IOBigMemoryCursor::withSpecification NG" ); ! 393: return false; ! 394: } ! 395: ! 396: ! 397: /* Fill in the SCSIControllerInfo structure and return: */ ! 398: ! 399: controllerInfo->initiatorId = 7; ! 400: ! 401: controllerInfo->maxTargetsSupported = 8; ! 402: controllerInfo->maxLunsSupported = 8; ! 403: ! 404: controllerInfo->minTransferPeriodpS = 100000; /* picoSecs for 10 MHz */ ! 405: controllerInfo->maxTransferOffset = 15; ! 406: controllerInfo->maxTransferWidth = 1; ! 407: ! 408: controllerInfo->maxCommandsPerController= 0; ! 409: controllerInfo->maxCommandsPerTarget = 8; // 0 is unlimited ! 410: controllerInfo->maxCommandsPerLun = 0; ! 411: ! 412: controllerInfo->tagAllocationMethod = kTagAllocationPerLun; ! 413: controllerInfo->maxTags = 256; ! 414: ! 415: controllerInfo->commandPrivateDataSize = sizeof( PrivCmdData ); ! 416: ! 417: controllerInfo->disableCancelCommands = false; ! 418: ! 419: return true; ! 420: }/* end configure */ ! 421: ! 422: ! 423: void meshSCSIController::executeCommand( IOSCSICommand *scsiCommand ) ! 424: { ! 425: SCSICDBInfo scsiCDB; ! 426: SCSITargetParms targetParms; ! 427: UInt8 msgByte; ! 428: UInt8 rc; ! 429: ! 430: ! 431: if ( fCmd || (g.intLevel & kLevelLatched) ) ! 432: { ! 433: disableCommands(); ! 434: rescheduleCommand( scsiCommand ); ! 435: ELG( fCmd, scsiCommand, 'Busy', "executeCommand - bus busy so bounce this cmd" ); ! 436: return; ! 437: } ! 438: ! 439: fCmd = scsiCommand; ! 440: fCmdData = (PrivCmdData*)scsiCommand->getCommandData(); ! 441: bzero( fCmdData, sizeof( fCmdData ) ); /// ??? unnecessary? ! 442: ! 443: scsiCommand->getTargetLun( &fCurrentTargetLun ); ! 444: scsiCommand->getCDB( &scsiCDB ); ! 445: scsiCommand->getDevice( kIOSCSIDevice )->getTargetParms( &targetParms ); ! 446: ! 447: ELG( scsiCommand, *(UInt16*)&fCurrentTargetLun<<16 | (scsiCDB.cdbTag & 0xFFFF), 'Exec', "meshSCSIController::executeCommand" ); ! 448: ELG( *(UInt32*)&scsiCDB.cdb[0], *(UInt32*)&scsiCDB.cdb[4] , '=CDB', "executeCommand - CDB" ); ! 449: ! 450: fMsgOutFlag = 0; ! 451: fMsgOutPtr = &fCCL[ kcclMSGOdata ]; ! 452: ! 453: /* Identify byte: */ ! 454: ! 455: msgByte = kSCSIMsgIdentify | kSCSIMsgEnableDisconnectMask | fCurrentTargetLun.lun; ! 456: if ( scsiCDB.cdbFlags & kCDBFlagsNoDisconnect ) ! 457: msgByte &= ~kSCSIMsgEnableDisconnectMask; ! 458: *fMsgOutPtr++ = msgByte; ! 459: ! 460: /* Tag msg: */ ! 461: ! 462: if ( scsiCDB.cdbTagMsg ) ! 463: { ! 464: *fMsgOutPtr++ = scsiCDB.cdbTagMsg; ! 465: *fMsgOutPtr++ = scsiCDB.cdbTag; ! 466: ELG( 0, scsiCDB.cdbTagMsg<<16 | scsiCDB.cdbTag, ' tag', "meshSCSIController::executeCommand - tag" ); ! 467: } ! 468: ! 469: /* Abort msg: */ ! 470: ! 471: if ( scsiCDB.cdbAbortMsg ) ! 472: { ! 473: ELG( scsiCommand->getOriginalCmd(), scsiCDB.cdbAbortMsg, 'Abor', "meshSCSIController::executeCommand - abort msg." ); ! 474: *fMsgOutPtr++ = scsiCDB.cdbAbortMsg; ! 475: } ! 476: ! 477: /* Sync negotiation msg: */ ! 478: ! 479: fNegotiatingSDTR = false; ! 480: if ( scsiCDB.cdbFlags & kCDBFlagsNegotiateSDTR ) ! 481: { fNegotiatingSDTR = true; ! 482: *fMsgOutPtr++ = kSCSIMsgExtended; ! 483: *fMsgOutPtr++ = 3; ! 484: *fMsgOutPtr++ = kSCSIMsgSyncXferReq; ! 485: *fMsgOutPtr++ = targetParms.transferPeriodpS / 4000; ! 486: *fMsgOutPtr++ = targetParms.transferOffset; ! 487: } ! 488: ! 489: ! 490: /***** Try to start the command on the hardware: *****/ ! 491: ! 492: rc = startCommand(); /* Call the hardware layer. */ ! 493: ! 494: if ( rc != kHardwareStartOK ) ! 495: { /* Hardware can't start now */ ! 496: ELG( fCmd, 0, 'Exe-', "meshSCSIController::executeCommand - command bounced back" ); ! 497: rescheduleCommand( fCmd ); ! 498: fCmd = NULL; ! 499: } ! 500: ! 501: return; ! 502: }/* end executeCommand */ ! 503: ! 504: ! 505: void meshSCSIController::cancelCommand( IOSCSICommand *scsiCommand ) ! 506: { ! 507: IOSCSICommand *origCmd; ! 508: PrivCmdData *origCmdData; ! 509: SCSIResults results; ! 510: ! 511: origCmd = scsiCommand->getOriginalCmd(); ! 512: ! 513: ELG( scsiCommand, origCmd, 'Can-', "meshSCSIController::cancelCommand" ); ! 514: ! 515: if ( origCmd ) /* if original command still around, complete it: */ ! 516: { ! 517: origCmd->getResults( &results ); ! 518: origCmdData = (PrivCmdData*)origCmd->getCommandData(); ! 519: results.bytesTransferred = origCmdData->results.bytesTransferred; ! 520: origCmd->setResults( &results ); ! 521: origCmd->complete(); ! 522: } ! 523: ! 524: scsiCommand->complete(); ! 525: return; ! 526: }/* end cancelCommand */ ! 527: ! 528: ! 529: void meshSCSIController::resetCommand( IOSCSICommand *scsiCommand ) ! 530: { ! 531: ELG( scsiCommand, 0, 'Rst-', "meshSCSIController::resetCommand" ); ! 532: resetBus(); ! 533: fCmdData = (PrivCmdData*)scsiCommand->getCommandData(); ! 534: bzero( &fCmdData->results, sizeof( fCmdData->results ) ); ! 535: scsiCommand->setResults( &fCmdData->results ); ! 536: scsiCommand->complete(); ! 537: return; ! 538: }/* end resetCommand */ ! 539: ! 540: ! 541: /* Fetch the device's bus address and interrupt port number. */ ! 542: /* Also, allocate one page of memory for the channel program. */ ! 543: ! 544: IOReturn meshSCSIController::initializeHardware() ! 545: { ! 546: IOReturn ioReturn; ! 547: int i; ! 548: ! 549: ELG( 0, 0, 'IniH', "initializeHardware" ); ! 550: ! 551: ! 552: fInitiatorID = kInitiatorIDDefault; ! 553: fInitiatorIDMask = 1 << kInitiatorIDDefault; /* BusID bitmask for reselection. */ ! 554: ! 555: for ( i = 0; i < 8; ++i) ! 556: fSyncParms[ i ] = kSyncParmsAsync; ! 557: ! 558: ioReturn = getHardwareMemoryMaps(); ! 559: ! 560: if ( ioReturn == kIOReturnSuccess ) ! 561: ioReturn = allocHdwAndChanMem(); ! 562: ! 563: if ( ioReturn == kIOReturnSuccess ) ! 564: ioReturn = doHBASelfTest(); ! 565: ! 566: if ( ioReturn == kIOReturnSuccess ) ! 567: { ! 568: ioReturn = resetBus(); ! 569: fMESHAddr->sourceID = fInitiatorID; ! 570: } ! 571: ! 572: return ioReturn; ! 573: }/* end initializeHardware */ ! 574: ! 575: ! 576: IOReturn meshSCSIController::getHardwareMemoryMaps() ! 577: { ! 578: ! 579: if ( !fSCSIMemoryMap ) ! 580: { ! 581: fSCSIMemoryMap = fProvider->mapDeviceMemoryWithIndex( kMESHRegisterBase ); ! 582: if ( !fSCSIMemoryMap ) ! 583: { ! 584: ELG( 0, 0, 'Map-', "getHardwareMemoryMaps - can't map MESH." ); ! 585: return kIOReturnInternalError; ! 586: } ! 587: ! 588: fMESHPhysAddr = fSCSIMemoryMap->getPhysicalAddress(); ! 589: fMESHAddr = (MeshRegister*)fSCSIMemoryMap->getVirtualAddress(); ! 590: ELG( fMESHPhysAddr, fMESHAddr, '=MSH', "getHardwareMemoryMaps - MESH regs" ); ! 591: g.meshAddr = (UInt32)fMESHAddr; // for debugging, miniMon ... ! 592: } ! 593: ! 594: if ( !fDBDMAMemoryMap ) ! 595: { ! 596: fDBDMAMemoryMap = fProvider->mapDeviceMemoryWithIndex( kDBDMARegisterBase ); ! 597: if ( !fDBDMAMemoryMap ) ! 598: { ! 599: ELG( 0, 0, 'map-', "getHardwareMemoryMaps - can't map DBDMA." ); ! 600: return kIOReturnInternalError; ! 601: } ! 602: dbdmaAddrPhys = fDBDMAMemoryMap->getPhysicalAddress(); ! 603: dbdmaAddr = (UInt8*)fDBDMAMemoryMap->getVirtualAddress(); ! 604: ELG( dbdmaAddrPhys, dbdmaAddr, '=DMA', "getHardwareMemoryMaps - DBDMA regs" ); ! 605: #if CustomMiniMon ! 606: gMESH_DBDMA = (UInt32)dbdmaAddr; ! 607: gMESH_DBDMA_Phys = (UInt32)dbdmaAddrPhys; ! 608: #endif /* CustomMiniMon */ ! 609: } ! 610: ! 611: return kIOReturnSuccess; ! 612: }/* end getHardwareMemoryMaps */ ! 613: ! 614: ! 615: ! 616: /* Fetch the device's bus address and allocate one page of memory */ ! 617: /* for the channel command. (Strictly speaking, we don't need an */ ! 618: /* entire page, but we can use the rest of the page for a permanent */ ! 619: /* status log). */ ! 620: /* @param deviceDescription Specify the device to initialize. */ ! 621: /* @return kIOReturnSuccess if successful, else an error status. */ ! 622: ! 623: IOReturn meshSCSIController::allocHdwAndChanMem() ! 624: { ! 625: /* Set the default selection timeout to the MESH value (10 msec units). */ ! 626: ! 627: fSelectionTimeout = 250 / 10; // ??? symbolic ! 628: ! 629: /* Allocate a page of wired-down memory in the kernel: */ ! 630: ! 631: fCCLSize = page_size; ! 632: fCCL = (UInt8*)IOMallocContiguous( fCCLSize, page_size, &fCCLPhysAddr ); ! 633: if ( !fCCL ) ! 634: { PAUSE( 0, fCCLSize, 'CCA-', "allocHdwAndChanMem - can't allocate channel command area.\n" ); ! 635: return kIOReturnNoMemory; ! 636: } ! 637: ! 638: /* Remember the number of DBDMA descriptors that */ ! 639: /* can be used for data transfer channel commands. */ ! 640: ! 641: fDBDMADescriptorMax = (fCCLSize - kcclDataXfer) / sizeof( DBDMADescriptor ); ! 642: ! 643: g.cclPhysAddr = (UInt32)fCCLPhysAddr; // for debugging ease ! 644: g.cclLogAddr = (UInt32)fCCL; ! 645: ! 646: ELG( fCCLPhysAddr, fCCL, '=CCL', "allocHdwAndChanMem - CCL phys/logical addresses." ); ! 647: initCP(); ! 648: ! 649: /* What do we do on failure? Should we try to deallocate */ ! 650: /* the stuff we created, or will the system do this for us? */ ! 651: ! 652: return kIOReturnSuccess; ! 653: }/* end allocHdwAndChanMem */ ! 654: ! 655: ! 656: /* Perform one-time-only channel command program initialization. */ ! 657: ! 658: void meshSCSIController::initCP() ! 659: { ! 660: register DBDMADescriptor *dst = (DBDMADescriptor*)fCCL; ! 661: register const DBDMADescriptor *src = gDescriptorList; ! 662: UInt32 i; ! 663: UInt8 *bp; ! 664: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr; ! 665: ! 666: ! 667: ELG( src, dst, 'I CP', "initCP - Init the Channel Program" ); ! 668: ! 669: /* Set the interrupt, branch, and wait DBDMA registers. */ ! 670: /* Caution: the following MESH interrupt register bits are */ ! 671: /* EndianSwapped, reverse polarity and in a different position. */ ! 672: /* The pattern is: 0xvv00mm00, where mm is a mask byte */ ! 673: /* and vv is a value byte to match. (After EndianSwapping). */ ! 674: /* 0x80 means NO errors (kMeshIntrError) */ ! 675: /* 0x40 means NO exceptions (kMeshIntrException) */ ! 676: /* 0x20 means NO command done (kMeshIntrCmdDone) */ ! 677: /* Branch Select is used with BRANCH_FALSE */ ! 678: ! 679: // DBDMASetInterruptSelect( 0x00000000 ); /* Never let DBDMA interrupt */ ! 680: // DBDMASetWaitSelect( 0x00200020 ); /* Wait until command done */ ! 681: // DBDMASetBranchSelect( 0x00C000C0 ); /* Branch if exception or error */ ! 682: ! 683: DBDMARegs->interruptSelect = 0x00000000; /* Never let DBDMA interrupt */ ! 684: DBDMARegs->waitSelect = 0x20002000; /* Wait until command done */ ! 685: DBDMARegs->branchSelect = 0xC000C000; /* Br if Exc or Err */ ! 686: SynchronizeIO(); ! 687: ! 688: /* Relocate and EndianSwap the global channel command list */ ! 689: /* into the page that is shared with the DBDMA device. */ ! 690: ! 691: for ( i = 0; i < gDescriptorListSize; i += sizeof( DBDMADescriptor ) ) ! 692: { ! 693: dst->operation = SWAP( src->operation ); /* copy command with count */ ! 694: ! 695: switch ( src->result & kRelAddress ) ! 696: { ! 697: case kRelAddressMESH: ! 698: dst->address = SWAP( src->address + fMESHPhysAddr ); ! 699: break; ! 700: case kRelAddressCP: ! 701: dst->address = SWAP( src->address + (UInt32)fCCLPhysAddr ); ! 702: break; ! 703: case kRelAddressPhys: ! 704: dst->address = SWAP( src->address ); ! 705: break; ! 706: default: ! 707: dst->address = SWAP( src->address ); ! 708: break; ! 709: } ! 710: ! 711: switch ( src->result & kRelCmdDep ) ! 712: { ! 713: case kRelCmdDepCP: ! 714: dst->cmdDep = SWAP( src->cmdDep + (UInt32)fCCLPhysAddr ); ! 715: break; ! 716: case kRelCmdDepLabel: ! 717: dst->cmdDep = src->cmdDep; ! 718: break; ! 719: default: ! 720: dst->cmdDep = SWAP( src->cmdDep ); ! 721: break; ! 722: } ! 723: ! 724: dst->result = 0; ! 725: src++; ! 726: dst++; ! 727: } /* FOR all elements in the descriptor list */ ! 728: ! 729: /* Build a SCSI CDB for the autosense Request Sense command. */ ! 730: ! 731: bp = &fCCL[ kcclSenseCDB ]; ! 732: *bp++ = kSCSICmdRequestSense; /* Command */ ! 733: *bp++ = 0; /* LUN to be filled in */ ! 734: *bp++ = 0; /* reserved */ ! 735: *bp++ = 0; /* reserved */ ! 736: *bp++ = kMaxAutosenseByteCount; /* Allocation length - to be filled in */ ! 737: *bp++ = 0; /* Control (flag) */ ! 738: return; ! 739: }/* end initCP */ ! 740: ! 741: ! 742: /* doHBASelfTest - MESH chip self-test. (Minimal: it could be extended.) */ ! 743: ! 744: IOReturn meshSCSIController::doHBASelfTest() ! 745: { ! 746: IOReturn ioReturn = kIOReturnSuccess; ! 747: UInt8 tempByte; ! 748: ! 749: ! 750: ELG( fMESHPhysAddr, fMESHAddr, 'Test', "doHBASelfTest" ); ! 751: ! 752: if ( ioReturn == kIOReturnSuccess ) ! 753: { ! 754: tempByte = fMESHAddr->MESHID & 0x1F; ! 755: if ( tempByte < kMeshMESHID_Value ) ! 756: { ! 757: PAUSE( 0, tempByte, 'hba-', "doHBASelfTest - Invalid MESH chip ID .\n" ); ! 758: ioReturn = kIOReturnNoDevice; ! 759: } ! 760: } ! 761: return ioReturn; ! 762: }/* end doHBASelfTest */ ! 763: ! 764: ! 765: void meshSCSIController::interruptOccurred( IOInterruptEventSource *ies, int intCount ) ! 766: { ! 767: // DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr; ! 768: ! 769: ! 770: // ELG( ies, intCount, 'Int+', "interruptOccurred" ); ! 771: g.intLevel |= kLevelISR; /* set ISR flag */ ! 772: g.intLevel &= ~kLevelLatched; /* clear latched */ ! 773: // ELG( DBDMARegs->channelStatus, DBDMARegs->commandPtrLo, 'Int+', "interruptOccurred." ); ! 774: ELG( fCmd, *(UInt32*)&fCCL[ kcclStageLabel ], 'Int+', "interruptOccurred." ); ! 775: // ELG( *(UInt32*)0xF3000024, *(UInt32*)0xF300002C, 'Int ', "interruptOccurred." ); ! 776: ! 777: doHardwareInterrupt(); /**** HANDLE THE INTERRUPT ****/ ! 778: ! 779: // ELG( fCmd, *(UInt32*)0xF300002C, 'Intx', "interruptOccurred." ); ! 780: ! 781: g.intLevel &= ~kLevelISR; /* clear ISR flag */ ! 782: return; ! 783: }/* end interruptOccurred */ ! 784: ! 785: ! 786: /* doHardwareInterrupt - called from Workloop in superclass */ ! 787: ! 788: void meshSCSIController::doHardwareInterrupt() ! 789: { ! 790: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr; ! 791: ! 792: ! 793: getHBARegsAndClear( true ); /* get the MESH registers */ ! 794: setIntMask( 0 ); /* Disable MESH interrupts */ ! 795: ! 796: fFlagReselecting = false; ! 797: ! 798: if ( g.shadow.mesh.interrupt == 0 ) ! 799: { /* Interrupts can occur with no bits set in the */ ! 800: /* interrupt register one way: */ ! 801: /* - Eating interrupts in the driver (the ASIC */ ! 802: /* latches the interrupt even though the */ ! 803: /* driver or Channel Program clears the MESH */ ! 804: /* interrupt register). */ ! 805: PAUSE( DBDMARegs->commandPtrLo, ! 806: (g.shadow.mesh.busStatus0 << 8) | g.shadow.mesh.busStatus1, ! 807: 'ISR?', ! 808: "doHardwareInterrupt - spurious interrupt" ); ! 809: ! 810: if ( !fCmd ) ! 811: { /* if no request: */ ! 812: setIntMask( kMeshIntrMask ); /* Enable interrupts */ ! 813: enableCommands(); /* let superclass issue another command */ ! 814: } ! 815: return; ! 816: }/* end IF no bit set in interrupt register */ ! 817: ! 818: /// dbdma_flush( DBDMA_MESH_SCSI ); /* DBDMA may be hung in */ ! 819: /// dbdma_stop( DBDMA_MESH_SCSI ); /* middle of transfer. */ ! 820: DBDMARegs->channelControl = SWAP( 0x20002000 ); // set FLUSH bit ! 821: SynchronizeIO(); ! 822: DBDMARegs->channelControl = SWAP( 0x80000000 ); // clr RUN bit ! 823: SynchronizeIO(); ! 824: ! 825: // invalidate_cache_v( (vm_offset_t)fCCL, fCCLSize ); ! 826: ! 827: /* If the DBDMA was running a channel command, handle this */ ! 828: /* (this could be done at a lower priority level). */ ! 829: ! 830: if ( *(UInt32*)&fCCL[ kcclStageLabel ] ) ! 831: { ! 832: processInterrupt(); ! 833: return; ! 834: } ! 835: ! 836: /* This was not a DBDMA completion. */ ! 837: /* See if the last MESH operation completed */ ! 838: /* without errors or exceptions. */ ! 839: ! 840: if ( g.shadow.mesh.interrupt == kMeshIntrCmdDone ) ! 841: { ! 842: /* This was presumably a Programmed IO completion. */ ! 843: ! 844: if ( fCmd ) ! 845: { /* The command has not completed yet. */ ! 846: /* We need to wait for a phase stabilizing interrupt. */ ! 847: ! 848: PAUSE( 0, 0, 'dhi-', "doHardwareInterrupt - MESH interrupt problem: need phase stabilizing wait.\n" ); ! 849: return; ! 850: } ! 851: else ! 852: { /* There is no active command. */ ! 853: /* This is presumably a bus-free completion. */ ! 854: setIntMask( kMeshIntrMask ); /* Re-enable interrupts */ ! 855: enableCommands(); /* let superclass issue another command */ ! 856: return; ! 857: } ! 858: }/* end IF CmdDone without Err or Exc */ ! 859: ! 860: /* None of the above "completion" states occurred. */ ! 861: /* Either a command completed unsuccessfully, or we */ ! 862: /* were reselected. First, check for phase mismatch. */ ! 863: if ( g.shadow.mesh.interrupt == (kMeshIntrCmdDone | kMeshIntrException) ! 864: && g.shadow.mesh.exception == kMeshExcPhaseMM ) ! 865: { ! 866: PAUSE( 0, 0, 'DHI-', "doHardwareInterrupt - MESH interrupt problem: phase mismatch interrupt.\n" ); ! 867: } ! 868: else ! 869: { /* Handle reselection and all other problems separately. */ ! 870: processInterrupt(); ! 871: } ! 872: return; ! 873: }/* end doHardwareInterrupt */ ! 874: ! 875: ! 876: /* Respond to a DBDMA channel command completion interrupt */ ! 877: /* or some error or exception condition. */ ! 878: ! 879: void meshSCSIController::processInterrupt() ! 880: { ! 881: UInt32 stage; /* Stage in the Channel Program */ ! 882: UInt32 cclIndex; /* Index of CCL descriptor */ ! 883: UInt32 count; /* transfer count */ ! 884: UInt8 phase; /* Current bus phase */ ! 885: IOReturn rc; ! 886: ! 887: ! 888: /* Get the state of the DBDMA: */ ! 889: ! 890: stage = *(UInt32*)&fCCL[ kcclStageLabel ]; ! 891: cclIndex = SWAP( ((DBDMAChannelRegisters*)dbdmaAddr)->commandPtrLo ) - (UInt32)fCCLPhysAddr; ! 892: *(UInt32*)&fCCL[ kcclStageLabel ] = 0; ! 893: ! 894: /* Check for SCSI Bus Reset Detected: */ ! 895: ! 896: if ( g.shadow.mesh.error & kMeshErrSCSIRst ) ! 897: { ! 898: ELG( fCmd, stage, 'BRst', "Process interrupt with no active request\n" ); ! 899: fCmd = NULL; ! 900: super::resetOccurred(); ! 901: setIntMask( kMeshIntrMask ); ! 902: enableCommands(); /* let superclass issue another command */ ! 903: return; ! 904: } ! 905: ! 906: if ( fCmd == NULL ) ! 907: { ! 908: if ( g.shadow.mesh.exception & kMeshExcResel ) ! 909: { ! 910: handleReselectionInterrupt(); ! 911: return; ! 912: } ! 913: /* There is no active request and we are not reselecting. */ ! 914: /* Can get here if Reject/Abort occurs or after a BusFree */ ! 915: /* command is put in the Sequence register and we exit the */ ! 916: /* interrupt. */ ! 917: ELG( 0, 0, 'Int0', "Process interrupt with no active request\n" ); ! 918: setIntMask( kMeshIntrException | kMeshIntrError ); ! 919: ! 920: enableCommands(); /* let superclass issue another command */ ! 921: return; ! 922: }/* end IF had no active command */ ! 923: ! 924: /* There is an active request - switch on stage of the DBDMA: */ ! 925: ! 926: switch ( stage ) ! 927: { ! 928: case kcclStageGood: /* Normal completion */ ! 929: doInterruptStageGood(); ! 930: break; ! 931: ! 932: case kcclStageInit: /* Value before DBDMA runs */ ! 933: case kcclStageArb: /* Arbitration anomaly */ ! 934: doInterruptStageArb(); ! 935: break; ! 936: ! 937: case kcclStageSelA: /* Selection anomaly */ ! 938: doInterruptStageSelA(); ! 939: break; ! 940: ! 941: case kcclStageMsgO: /* Message Out */ ! 942: doInterruptStageMsgO(); ! 943: break; ! 944: ! 945: case kcclStageCmdO: /* Command stage anomaly */ ! 946: doInterruptStageCmdO(); ! 947: break; ! 948: ! 949: case kcclStageXfer: ! 950: // if ( cmdBuf->resultFlags & scsiAutosenseStarted ) ! 951: // doInterruptStageXferAutosense(); ! 952: // else ! 953: doInterruptStageXfer(); /* DMA transfer complete */ ! 954: break; ! 955: ! 956: case kcclStageStat: /* Synchronous, odd transfer, data-out */ ! 957: /* OR no data, disconnect */ ! 958: ! 959: /* Don't use updateCurrentIndex here because */ ! 960: /* kcclStageStat destroys TC with a 1. */ ! 961: count = *(UInt32*)&fCCL[ kcclBatchSize ]; /* Our transfer count */ ! 962: fCmdData->results.bytesTransferred += count; /* Increment data index */ ! 963: ! 964: if ( fReadAlignmentCount ) // Hack for Radar 1670626 ! 965: { ! 966: fCmdData->mdp->writeBytes( fReadAlignmentIndex, &fCCL[ kcclReadBuf8 ], fReadAlignmentCount ); ! 967: fReadAlignmentCount = 0; ! 968: } ! 969: ! 970: ELG( count, fCmdData->results.bytesTransferred, 'Uidx', "processInterrupt" ); ! 971: *(UInt32*)&fCCL[ kcclBatchSize ] = 0; /* Clear our count */ ! 972: ! 973: /* Analyze the current bus signals: */ ! 974: ! 975: if ( !(g.shadow.mesh.busStatus0 & kMeshReq) ) ! 976: { /* Get here if Sync Read or Write is too short as */ ! 977: /* in reading 512 bytes from a 2K block of CD-ROM. */ ! 978: startBucket(); ! 979: return; ! 980: }/* end IF no REQ signal */ ! 981: ! 982: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask; ! 983: switch ( phase ) ! 984: { ! 985: case kBusPhaseMSGI: ! 986: rc = DoMessageInPhase(); ! 987: break; ! 988: ! 989: case kBusPhaseDATO: ! 990: case kBusPhaseDATI: ! 991: /* Get here if Async Read or Write is too short as */ ! 992: /* in reading 512 bytes from a 2K block of CD-ROM */ ! 993: startBucket(); ! 994: break; ! 995: ! 996: default: ! 997: PAUSE( 0, phase, 'pmm-', "processInterrupt - expected Status phase.\n" ); ! 998: break; ! 999: }/* end SWITCH on phase */ ! 1000: break; ! 1001: ! 1002: case kcclStageBucket: ! 1003: count = *(UInt32*)&fCCL[ kcclBatchSize ]; /* Our transfer count */ ! 1004: fCmdData->results.bytesTransferred += count; /* Increment data index */ ! 1005: *(UInt32*)&fCCL[ kcclBatchSize ] = 0; /* Clear our count */ ! 1006: ! 1007: ELG( count, fCmdData->results.bytesTransferred, 'Buck', ! 1008: "processInterrupt - bit bucket done.\n" ); ! 1009: ! 1010: /* MESH doesn't always have a phase mismatch when completing a */ ! 1011: /* synchronous data write. It may be that the drive is going to */ ! 1012: /* MsgIn with SDP and/or disconnect instead of Status and the */ ! 1013: /* timing is different. If the current phase is not a data phase, */ ! 1014: /* AND the TC and FIFO count indicate no data overflowed AND */ ! 1015: /* and all the data transferred, don't set an error condition. */ ! 1016: ! 1017: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask; ! 1018: ! 1019: count = g.shadow.mesh.transferCount1 << 8 | g.shadow.mesh.transferCount0; ! 1020: count += g.shadow.mesh.FIFOCount; ! 1021: count &= 0xFFFF; ! 1022: ! 1023: if ( (count != 0) ! 1024: || (fCmdData->xferCount != fCmdData->results.bytesTransferred) ! 1025: || !(phase > kBusPhaseDATI) ) ! 1026: { ! 1027: fCmdData->results.returnCode = kIOReturnOverrun; ! 1028: } ! 1029: setSeqReg( kMeshFlushFIFO ); /* flush the FIFO */ ! 1030: runDBDMA( kcclGetStatus, kcclStageStat ); ! 1031: break; ! 1032: ! 1033: case kcclStageMsgI: /* Message-in: */ ! 1034: case kcclStageFree: /* Bus free: */ ! 1035: default: /* Can't happen? */ ! 1036: PAUSE( cclIndex, stage, 'P i-', "processInterrupt - strange or unknown interrupt for device.\n" ); ! 1037: break; ! 1038: }/* end SWITCH on Channel Program stage */ ! 1039: ! 1040: return; ! 1041: }/* end processInterrupt */ ! 1042: ! 1043: ! 1044: /* Start a SCSI transaction for the specified command. */ ! 1045: ! 1046: UInt8 meshSCSIController::startCommand() ! 1047: { ! 1048: fCmd->getPointers( &fCmdData->mdp, &fCmdData->xferCount, &fCmdData->isWrite ); ! 1049: ! 1050: clearCPResults(); /* clear the result field in all the Channel Commands */ ! 1051: ! 1052: { ! 1053: fCmdData->results.bytesTransferred = 0; ! 1054: fCmdData->savedDataPosition = 0; ! 1055: updateCP( false ); /* Update the DBDMA Channel Program */ ! 1056: } ! 1057: ! 1058: /***** Can a caller override the default timeout? *****/ ! 1059: ! 1060: fMESHAddr->selectionTimeOut = fSelectionTimeout; ! 1061: fMESHAddr->destinationID = fCurrentTargetLun.target; ! 1062: // fMESHAddr->syncParms = kSyncParmsAsync; ! 1063: fMESHAddr->syncParms = fSyncParms[ fCurrentTargetLun.target ]; ! 1064: SynchronizeIO(); ! 1065: runDBDMA( kcclStart, kcclStageInit ); ! 1066: if ( g.intLevel & kLevelLatched ) /* return Busy if reselecting */ ! 1067: return kHardwareStartBusy; /* or some other issue. */ ! 1068: return kHardwareStartOK; ! 1069: }/* end startCommand */ ! 1070: ! 1071: ! 1072: /* Initialize the data transfer channel command list for a normal SCSI */ ! 1073: /* command. The channel command list has a complex structure of */ ! 1074: /* transfer groups and items, where: */ ! 1075: /* transfer group The number of bytes transferred by a single */ ! 1076: /* MESH operation. This will be from 1 to */ ! 1077: /* kMaxDMATransfer (65536 - 4096). */ ! 1078: /* transfer item The number of bytes transferred by a single */ ! 1079: /* DBDMA operation. These bytes are guaranteed */ ! 1080: /* to be physically-contiguous. */ ! 1081: /* Thus, the data transfer CCL looks like the following: */ ! 1082: /* Prolog 1: Load MESH with the first group count. */ ! 1083: /* Item 1.1: Load DBDMA with the first physical address and */ ! 1084: /* item count. */ ! 1085: /* Item 1.2 etc: Load DBDMA with the next physical address and */ ! 1086: /* item count. */ ! 1087: /* Prolog 2, etc. Load MESH with the next group count. */ ! 1088: /* Item 2.1, etc. Load DBDMA with the next group of physical */ ! 1089: /* addresses. */ ! 1090: /* Stop/Branch If all of the data transfer commands fit in the */ ! 1091: /* channel command list, branch to the Status phase*/ ! 1092: /* channel command. Otherwise, stop transfer */ ! 1093: /* (which stops in Data phase) and rebuild the */ ! 1094: /* command list for the next set of data. */ ! 1095: /* Note that the last DBDMA command must be INPUT_LAST or OUTPUT_LAST */ ! 1096: /* to handle synchronous transfer odd-byte disconnect. */ ! 1097: ! 1098: void meshSCSIController::updateCP( bool reselecting ) ! 1099: { ! 1100: DBDMADescriptor *descProto = (DBDMADescriptor*)&fCCL[ kcclPrototype ]; ! 1101: DBDMADescriptor *descriptorPtr; /* current data descriptor */ ! 1102: DBDMADescriptor *descriptorMax; /* beyond the last data descriptor */ ! 1103: DBDMADescriptor *preamblePtr; /* current prolog descriptor */ ! 1104: SCSICDBInfo scsiCDB; ! 1105: UInt32 dbdmaOpProto; /* prototype Opcode for DBDMA */ ! 1106: UInt32 dbdmaOp; /* Opcode for DBDMA */ ! 1107: UInt32 meshSeq; /* Opcode for MESH request */ ! 1108: SInt32 transferLength; /* Number of bytes left to transfer */ ! 1109: UInt32 totalXferLen = 0; /* Total length of this transfer */ ! 1110: UInt32 groupLength; /* Number of bytes in this group */ ! 1111: UInt8 syncParms; /* Fast synchronous param value */ ! 1112: UInt32 actualRanges; ! 1113: IOPhysicalSegment range[ kMaxMemCursorSegs ]; ! 1114: DBDMADescriptor *dp; ! 1115: UInt32 rangeLength, rangeLocation; ! 1116: UInt32 i; ! 1117: IOReturn ioReturn = kIOReturnSuccess; ! 1118: ! 1119: ! 1120: fReadAlignmentCount = 0; /* Clear Read misalignment condition */ ! 1121: ! 1122: /* How many descriptors can we store (need some slop for the */ ! 1123: /* terminator commands). Get a pointer to the first free */ ! 1124: /* descriptor and the total number of bytes left to transfer in */ ! 1125: /* this IO request. */ ! 1126: ! 1127: descriptorPtr = (DBDMADescriptor*)&fCCL[ kcclDataXfer ]; ! 1128: descriptorMax = &descriptorPtr[ fDBDMADescriptorMax - 16 ]; ! 1129: transferLength = fCmdData->xferCount - fCmdData->results.bytesTransferred; ! 1130: ELG( descriptorPtr, transferLength, 'UpCP', "updateCP" ); ! 1131: ! 1132: if ( !reselecting ) ! 1133: { ! 1134: setupMsgO(); /* Setup for Message Out phase. */ ! 1135: fCmd->getCDB( &scsiCDB ); ! 1136: ! 1137: /* Setup for Command phase: */ ! 1138: fCCL[ kcclCmdoMTC ] = scsiCDB.cdbLength; /* MESH transfer count */ ! 1139: fCCL[ kcclCmdoDTC ] = scsiCDB.cdbLength; /* DBDMA count */ ! 1140: bcopy( &scsiCDB.cdb[0], &fCCL[ kcclCMDOdata ], scsiCDB.cdbLength ); ! 1141: }/* end IF not reselecting */ ! 1142: ! 1143: /* Generate MESH "sequence" & DBDMA "operation" for Input or Output: */ ! 1144: ! 1145: if ( fCmdData->isWrite ) ! 1146: { dbdmaOpProto = OUTPUT_MORE | kBranchIfFalse; ! 1147: meshSeq = kMeshDataOutCmd | kMeshSeqDMA; ! 1148: } ! 1149: else ! 1150: { dbdmaOpProto = INPUT_MORE | kBranchIfFalse; ! 1151: meshSeq = kMeshDataInCmd | kMeshSeqDMA; ! 1152: } ! 1153: ! 1154: *(UInt32*)&fCCL[ kcclBatchSize ] = 0; ! 1155: ! 1156: while ( ioReturn == kIOReturnSuccess ! 1157: && transferLength > 0 ! 1158: && descriptorPtr < descriptorMax ) ! 1159: { ! 1160: /* Do one group, ie, enough CCs to fill a MESH transfer count. */ ! 1161: /* There are more data to be transferred, and CCL space to store*/ ! 1162: /* another group of data. First, leave space for the preamble. */ ! 1163: ! 1164: preamblePtr = descriptorPtr; ! 1165: groupLength = 0; ! 1166: descriptorPtr += 4; /* Preamble takes 4 descriptors */ ! 1167: ! 1168: /* Do one group of pages: */ ! 1169: ! 1170: actualRanges = fMemoryCursor->getPhysicalSegments( ! 1171: fCmdData->mdp, ! 1172: fCmdData->results.bytesTransferred + totalXferLen, ! 1173: range, ! 1174: kMaxMemCursorSegs ); ! 1175: if ( actualRanges == 0 ) ! 1176: break; ! 1177: ! 1178: ELG( range[0].length, range[0].location, 'Rng1', "updateCP - 1st range" ); ! 1179: ! 1180: for ( i = 0; i < actualRanges; i++ ) ! 1181: { rangeLocation = range[i].location; ! 1182: rangeLength = range[i].length; ! 1183: groupLength += rangeLength; ! 1184: ! 1185: // 29apr99 mlj Radar 1670626 - the DBDMAs in Grand Central (and ! 1186: // either Heathrow or O'Hare) have a bug. On the initial ! 1187: // data xfer of a Read, if the buffer is not aligned on an ! 1188: // 8-byte boundary, and the transfer ends before the boundary is ! 1189: // reached, then the memory in front of the buffer is trashed. ! 1190: // If these conditions apply, we read the misaligned bytes ! 1191: // into the CCL at kcclReadBuf8 now and copy them to the ! 1192: // user buffer later when we get an interrupt. The 1st range ! 1193: // is split and 2 DBDMA Channel Commands are generated. ! 1194: ! 1195: if ( (i == 0) // 1st range of group ! 1196: && (totalXferLen == 0) // 1st group of batch ! 1197: && (!fCmdData->isWrite) // READing ! 1198: && (rangeLocation & 0x07) ) // not 8-byte aligned ! 1199: { ! 1200: ELG( rangeLength, rangeLocation, 'Rd-8', "updateCP - non-8-byte-aligned read" ); ! 1201: fReadAlignmentIndex = fCmdData->results.bytesTransferred; ! 1202: fReadAlignmentCount = 8 - (rangeLocation & 0x07); ! 1203: dbdmaOp = dbdmaOpProto | fReadAlignmentCount; ! 1204: rangeLength -= fReadAlignmentCount; ! 1205: transferLength -= fReadAlignmentCount; ! 1206: if ( transferLength <= 0 ) ! 1207: dbdmaOp |= (INPUT_MORE ^ INPUT_LAST); /* add LAST to cmd */ ! 1208: ! 1209: descriptorPtr->operation = SWAP( dbdmaOp ); ! 1210: descriptorPtr->address = SWAP( (UInt32)fCCLPhysAddr + kcclReadBuf8 ); ! 1211: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclProblem ); ! 1212: descriptorPtr->result = 0; // for debugging ! 1213: ! 1214: descriptorPtr++; ! 1215: ! 1216: if ( rangeLength == 0 ) ! 1217: continue; ! 1218: rangeLocation += fReadAlignmentCount; ! 1219: }/* end IF READing and buffer is misaligned at batch start */ ! 1220: ! 1221: dbdmaOp = dbdmaOpProto | rangeLength; ! 1222: transferLength -= rangeLength; ! 1223: if ( transferLength <= 0 ) ! 1224: dbdmaOp |= (INPUT_MORE ^ INPUT_LAST); /* add LAST to cmd */ ! 1225: ! 1226: descriptorPtr->operation = SWAP( dbdmaOp ); ! 1227: descriptorPtr->address = SWAP( rangeLocation ); ! 1228: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclProblem ); ! 1229: descriptorPtr->result = 0; // for debugging ! 1230: ! 1231: descriptorPtr++; ! 1232: }/* end FOR each range in this group */ ! 1233: ! 1234: if ( groupLength == 0 ) ! 1235: { ! 1236: /* Nothing was built - we apparently failed to get */ ! 1237: /* a physical address. Note: there is a potential problem with */ ! 1238: /* the following sequence as the *previous* DBDMA command, if */ ! 1239: /* any, should be changed to set xxPUT_LAST. */ ! 1240: ! 1241: ELG( 0, 0, 'Grp-', "updateCP - groupLength is 0" ); ! 1242: preamblePtr->operation = SWAP( NOP_CMD | kBranchIfFalse | kWaitIfTrue ); ! 1243: preamblePtr->address = 0; ! 1244: preamblePtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclProblem ); ! 1245: preamblePtr->result = 0; ! 1246: descriptorPtr = preamblePtr + 1; ! 1247: ioReturn = kIOReturnInvalid; /* Exit the outer loop */ ! 1248: } ! 1249: else ! 1250: { ! 1251: totalXferLen += groupLength; ! 1252: ! 1253: /* This group is complete. Fill in the preamble. */ ! 1254: /* The preamble consists of the following commands: */ ! 1255: /* [0] Move <totalXferLen> to kcclBatchSize */ ! 1256: /* [1] Store group length high-byte in MESH */ ! 1257: /* transfer count 1 register */ ! 1258: /* [2] Store group length low-byte in MESH */ ! 1259: /* transfer count 1 register */ ! 1260: /* [3] Store the input/output command in the MESH */ ! 1261: /* sequence register. */ ! 1262: /* If the command finishes prematurely (perhaps the */ ! 1263: /* device wants to disconnect), the interrupt service */ ! 1264: /* routine will use totalXferLen - the residual byte */ ! 1265: /* count to determine the number of bytes xferred. */ ! 1266: ! 1267: descProto[0].cmdDep = totalXferLen; // update batch size ! 1268: descProto[1].cmdDep = SWAP( groupLength >> 8 ); ! 1269: descProto[2].cmdDep = SWAP( groupLength & 0xFF ); ! 1270: descProto[3].cmdDep = SWAP( meshSeq ); ! 1271: bcopy( descProto, preamblePtr, sizeof( DBDMADescriptor ) * 4 ); ! 1272: ELG( preamblePtr, totalXferLen, '=Tot', "updateCP - set preamble" ); ! 1273: ! 1274: /* If there is another group, wait for */ ! 1275: /* cmdDone and clear it: */ ! 1276: if ( transferLength > 0 ) ! 1277: { /* Wait for CmdDone: */ ! 1278: bcopy( &fCCL[ kcclBrProblem ], descriptorPtr, sizeof( DBDMADescriptor ) ); ! 1279: ++descriptorPtr; ! 1280: /* Clear CmdDone: */ ! 1281: /* HACK - if we reached the end of the CCL page, */ ! 1282: /* we don't want to clear cmdDone because we will lose */ ! 1283: /* an interrupt. So, this instruction may be deleted */ ! 1284: /* down below. (Radar 2298440) */ ! 1285: descriptorPtr->operation = SWAP( STORE_QUAD | KEY_SYSTEM | 1 ); ! 1286: descriptorPtr->address = SWAP( fMESHPhysAddr + kMeshInterrupt ); ! 1287: descriptorPtr->cmdDep = SWAP( kMeshIntrCmdDone ); ! 1288: descriptorPtr->result = 0; ! 1289: ++descriptorPtr; ! 1290: }/* end IF not last group */ ! 1291: }/* end if/ELSE a group was built */ ! 1292: }/* end outer WHILE */ ! 1293: ! 1294: /* All of the data have been transferred (or we ran off the end */ ! 1295: /* of the CCL). Update the transfer start index to reflect on */ ! 1296: /* what we attempt to transfer in this DATA operation. If */ ! 1297: /* we completed DATA phase, branch to the Status Phase CCL; */ ! 1298: /* if not, stop the channel command so we can reload the CCL */ ! 1299: /* with the next big chunk. */ ! 1300: /* When the transfer completes, the last prolog will have stored*/ ! 1301: /* the total number of bytes transferred in a known location in */ ! 1302: /* the CCL area. */ ! 1303: /* Now, append the data transfer postamble to handle */ ! 1304: /* synchronous odd-byte disconnect and jump to status phase */ ! 1305: /* (or just stop if there's more DMA) */ ! 1306: ! 1307: ! 1308: /* Do some synchronous data transfer cleanup: */ ! 1309: ! 1310: syncParms = fSyncParms[ fCurrentTargetLun.target ]; ! 1311: fMESHAddr->syncParms = syncParms; ! 1312: SynchronizeIO(); ! 1313: ELG( fMsgOutFlag, syncParms, 'SynP', "updateCP - sync parms" ); ! 1314: ! 1315: if ( ((syncParms & 0xF0) || (fMsgOutFlag & kFlagMsgOut_SDTR)) // Sync? ! 1316: && (totalXferLen > 0) // any data moving? ! 1317: && (transferLength == 0) ) // end of xfer? ! 1318: { ! 1319: fFlagIncompleteDBDMA = false; /* indicate complete xfer */ ! 1320: ! 1321: /* MESH has a problem at the end of Synchronous transfers. */ ! 1322: /* If the target is fast enough, it can move from data phase to */ ! 1323: /* Status phase while MESH still has ACKed bytes in its FIFO and */ ! 1324: /* the DBDMA is still running. MESH raises PhaseMismatch Exception */ ! 1325: /* causing an interrupt in which we must empty the FIFO and move */ ! 1326: /* the bytes to the user's buffer by programmed IO. */ ! 1327: /* If the target is not fast enough, we can save the interrupt and */ ! 1328: /* bypass the mess. */ ! 1329: /* So, we do the following: */ ! 1330: /* 1) Enable only MESH Err interrupts; disable Exc and CmdDone. */ ! 1331: /* 2) Don't Wait; Branch if an interrupt may have already occurred.*/ ! 1332: /* 3) Wait for cmdDone at least for TC = FIFO count = 0 and */ ! 1333: /* maybe including PhaseMismatch. Branch to SyncCleanup if PMM. */ ! 1334: /* 4) Assume an interphase condition as opposed to an */ ! 1335: /* overrun condition and Branch Always to get Status. */ ! 1336: ! 1337: /* If the Channel Program gets this far, the OUTPUT_LAST */ ! 1338: /* has finished writing its data to the FIFO and MESH may still */ ! 1339: /* be putting bytes on the bus OR the INPUT_LAST has read all */ ! 1340: /* its data from the FIFO and MESH has already ACKed them. */ ! 1341: /* There may be or not some time before REQ appears again, */ ! 1342: /* either for data overrun or the next phase. */ ! 1343: ! 1344: /* Disable Exc and CmdDone (leave Err enabled): */ ! 1345: ! 1346: descriptorPtr->operation = SWAP( STORE_QUAD | KEY_SYSTEM | 1 ); ! 1347: descriptorPtr->address = SWAP( fMESHPhysAddr + kMeshInterruptMask ); ! 1348: descriptorPtr->cmdDep = SWAP( kMeshIntrError ); ! 1349: descriptorPtr->result = 0; ! 1350: ++descriptorPtr; ! 1351: ! 1352: /* Take the interrupt if PhaseMismatch not definitely caught. */ ! 1353: /* Branch (don't wait for cmdDone) if Exc may have already occurred: */ ! 1354: ! 1355: descriptorPtr->operation = SWAP( NOP_CMD | kBranchIfFalse ); ! 1356: descriptorPtr->address = 0; ! 1357: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclProblem ); ! 1358: descriptorPtr->result = 0; ! 1359: /* Radar 2281306 ( and 2272931 ): */ ! 1360: /* Output may completely fit in the FIFO and not make it out */ ! 1361: /* to the SCSI bus if the target disconnects after the command. */ ! 1362: /* If that's possible, wait here for cmdDone and */ ! 1363: /* take the PhaseMismatch interrupt. This situation occurred on a */ ! 1364: /* Mode Select with an output of 12 bytes. Do this to prevent */ ! 1365: /* the Stage from advancing from kcclStageXfer so that proper */ ! 1366: /* cleanup can take place. */ ! 1367: if ( (totalXferLen <= 16) && fCmdData->isWrite ) ! 1368: { ! 1369: descriptorPtr->operation = SWAP( NOP_CMD | kWaitIfTrue | kBranchIfFalse ); ! 1370: } ! 1371: ++descriptorPtr; ! 1372: ! 1373: /* Possible PhaseMisMatch caught after FIFO emptied. */ ! 1374: /* Wait for cmdDone. If Exc, branch to SyncCleanUp: */ ! 1375: ! 1376: descriptorPtr->operation = SWAP( NOP_CMD | kWaitIfTrue | kBranchIfFalse ); ! 1377: descriptorPtr->address = 0; ! 1378: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclSyncCleanUp ); ! 1379: descriptorPtr->result = 0; ! 1380: descriptorPtr++; ! 1381: ! 1382: /* Interphase condition or possible overrun. */ ! 1383: /* 29sep98 PhaseMismatch occurred even after */ ! 1384: /* CmdDone was set. */ ! 1385: ! 1386: ! 1387: /* Branch Always to assume we will bit bucket some data: */ ! 1388: ! 1389: descriptorPtr->operation = SWAP( NOP_CMD | kBranchAlways ); ! 1390: descriptorPtr->address = 0; ! 1391: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclOverrun ); ! 1392: descriptorPtr->result = 0; ! 1393: descriptorPtr++; ! 1394: ! 1395: /* Fix up the DataOverrun code just in case: */ ! 1396: ! 1397: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunMESH ]; ! 1398: if ( fCmdData->isWrite ) ! 1399: { dp->cmdDep = SWAP( kMeshDataOutCmd | kMeshSeqDMA ); ! 1400: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunDBDMA ]; ! 1401: dp->operation = SWAP( OUTPUT_LAST | kBranchIfFalse | 8 ); ! 1402: } ! 1403: else ! 1404: { dp->cmdDep = SWAP( kMeshDataInCmd | kMeshSeqDMA ); ! 1405: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunDBDMA ]; ! 1406: dp->operation = SWAP( INPUT_LAST | kBranchIfFalse | 8 ); ! 1407: } ! 1408: }/* end IF last of Synchronous transfer */ ! 1409: else ! 1410: { ! 1411: /* Async or incomplete Sync. Append Branches to finish this process: */ ! 1412: ! 1413: /* If this is a partial transfer, set 'incomplete' flag. */ ! 1414: ! 1415: if ( transferLength > 0 ) ! 1416: fFlagIncompleteDBDMA = true; /* set incomplete */ ! 1417: else fFlagIncompleteDBDMA = false; /* assume complete xfer */ ! 1418: ! 1419: ! 1420: if ( fFlagIncompleteDBDMA ) ! 1421: { /* Delete the ccl to clear cmdDone: */ ! 1422: --descriptorPtr; /* see HACK note above. */ ! 1423: } ! 1424: else if ( totalXferLen > 0 ) ! 1425: { /* If something moved AND (Radar 2298440) xfer completed, */ ! 1426: /* Wait & Branch if problem: */ ! 1427: /* Radar 2272931 - If entire output fits in FIFO, then */ ! 1428: /* the OUTPUT_LAST completes OK without a PhaseMismatch if */ ! 1429: /* the target disconnects right after the command phase. */ ! 1430: bcopy( &fCCL[ kcclBrProblem ], descriptorPtr, sizeof( DBDMADescriptor ) ); ! 1431: descriptorPtr++; ! 1432: } ! 1433: /* Assume all's well - Branch to get status: */ ! 1434: descriptorPtr->operation = SWAP( NOP_CMD | kBranchAlways ); ! 1435: descriptorPtr->address = 0; ! 1436: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclGetStatus ); ! 1437: descriptorPtr->result = 0; ! 1438: ! 1439: /* If this is a partial transfer, set 'incomplete' flag and */ ! 1440: /* change the Branch from GetStatus to Good: */ ! 1441: ! 1442: if ( fFlagIncompleteDBDMA ) ! 1443: { /* change last Branch from Status to Good: */ ! 1444: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclMESHintr ); ! 1445: ELG( descriptorPtr, transferLength, 'Part', "updateCP - built partial CCL." ); ! 1446: } ! 1447: descriptorPtr++; ! 1448: }/* end if/ELSE Async or partial xfer */ ! 1449: return; ! 1450: }/* end updateCP */ ! 1451: ! 1452: ! 1453: void meshSCSIController::clearCPResults() ! 1454: { ! 1455: register DBDMADescriptor *dp = (DBDMADescriptor*)&fCCL[ kcclStart ]; ! 1456: register int i; ! 1457: ! 1458: ! 1459: /* Don't clear the reserved areas or prototypes */ ! 1460: ! 1461: for ( i = (gDescriptorListSize - kcclStart) / sizeof ( DBDMADescriptor ); i; --i ) ! 1462: { ! 1463: dp->result = 0; ! 1464: dp++; ! 1465: } ! 1466: ! 1467: return; ! 1468: }/* end clearCPResults */ ! 1469: ! 1470: ! 1471: /* Set up the channel commands for MsgO phase. */ ! 1472: ! 1473: void meshSCSIController::setupMsgO() ! 1474: { ! 1475: UInt8 msgoSize; ! 1476: ! 1477: ! 1478: fMsgOutPtr--; /* treat the last or only byte special (drop ATN) */ ! 1479: msgoSize = fMsgOutPtr - &fCCL[ kcclMSGOdata ]; ! 1480: if( msgoSize == 0 ) ! 1481: { /* Identify byte only: */ ! 1482: *(UInt32*)&fCCL[ kcclMsgoBranch ] = SWAP( NOP_CMD | kBranchAlways ); ! 1483: } ! 1484: else /* multibyte message - set counts for all but last byte: */ ! 1485: { fCCL[ kcclMsgoMTC ] = msgoSize; ! 1486: fCCL[ kcclMsgoDTC ] = msgoSize; ! 1487: /* NOP the BRANCH: */ ! 1488: *(UInt32*)&fCCL[ kcclMsgoBranch ] = SWAP( NOP_CMD ); ! 1489: } ! 1490: fCCL[ kcclMSGOLast ] = *fMsgOutPtr; /* position last byte */ ! 1491: return; ! 1492: }/* end setupMsgO */ ! 1493: ! 1494: ! 1495: /* Start a Channel Program at the given offset */ ! 1496: /* with the specified stage label. */ ! 1497: ! 1498: void meshSCSIController::runDBDMA( UInt32 offset, UInt32 stageLabel ) ! 1499: { ! 1500: register UInt8 intReg; ! 1501: mach_timespec_t arbEndTime, curTime; ! 1502: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr; ! 1503: ! 1504: ! 1505: fMsgInFlag = 0; /* clear message-in flags. */ ! 1506: ! 1507: *(UInt32*)&fCCL[ kcclStageLabel ] = stageLabel; /* set the stage */ ! 1508: ! 1509: /* Let MESH interrupt only for errors or exceptions, but not cmdDone */ ! 1510: setIntMask( kMeshIntrException | kMeshIntrError ); ! 1511: ! 1512: intReg = fMESHAddr->interrupt; ! 1513: switch ( intReg ) ! 1514: { ! 1515: case kMeshIntrCmdDone: ! 1516: if ( !fFlagReselecting ) // ??? Don't drop ACK fm MSG-IN or Sync data flows ! 1517: /* clear any pending command interrupts (but not reselect et al) */ ! 1518: fMESHAddr->interrupt = kMeshIntrCmdDone; SynchronizeIO(); ! 1519: /***** fall through *****/ ! 1520: case 0: ! 1521: /* This is a Go: */ ! 1522: /* Flush any CCL and related data to the CCL physical page */ ! 1523: /* that may still be sitting in cache: */ ! 1524: flush_dcache( (vm_offset_t)fCCL, fCCLSize, false ); ! 1525: ! 1526: // ELG( *(UInt32*)0xF3000020, *(UInt32*)0xF300002C, 'G C+', "runDBDMA." ); ! 1527: ! 1528: if ( offset == kcclStart ) ! 1529: { ! 1530: fFlagReselecting = false; ! 1531: setSeqReg( kMeshArbitrateCmd ); /* ARBITRATE */ ! 1532: ! 1533: /* wait 50 mikes or cmdDone, whichever comes first: */ ! 1534: ! 1535: IOGetTime( &arbEndTime ); ! 1536: arbEndTime.tv_nsec += 50000; ! 1537: if ( arbEndTime.tv_nsec >= NSEC_PER_SEC ) ! 1538: { arbEndTime.tv_nsec -= NSEC_PER_SEC; ! 1539: arbEndTime.tv_sec += 1; ! 1540: } ! 1541: ! 1542: while ( true ) ! 1543: { ! 1544: getHBARegsAndClear( false ); /* get regs without hosing */ ! 1545: IOGetTime( &curTime ); ! 1546: if ( g.shadow.mesh.interrupt & kMeshIntrCmdDone ) ! 1547: break; ! 1548: if ( curTime.tv_sec < arbEndTime.tv_sec ) continue; ! 1549: if ( curTime.tv_nsec >= arbEndTime.tv_nsec ) break; ! 1550: }/* end wait cmdDone or 50 mikes */ ! 1551: ! 1552: if ( g.shadow.mesh.interrupt == kMeshIntrCmdDone ) ! 1553: { /* No err, no exc: Arbitration won: */ ! 1554: fMESHAddr->interrupt = kMeshIntrCmdDone; ! 1555: SynchronizeIO(); ! 1556: setSeqReg( kMeshDisableReselect ); /* disable reselect */ ! 1557: offset = 0x150; // ??? fix this. Point to Select/Atn ! 1558: *(UInt32*)&fCCL[ kcclStageLabel ] = kcclStageSelA; /* set stage to Select */ ! 1559: }/* end IF won Arbitration */ ! 1560: else /* Arbitration not won - CAUTION - HACK AHEAD. */ ! 1561: { /* Sometimes, MESH does not return ArbLost as it says in */ ! 1562: /* the documentation. Instead, it waits for the winner to */ ! 1563: /* get off the bus (usually after the 250 ms timeout) and */ ! 1564: /* then MESH continues its arbitration. This wastes 250 ms */ ! 1565: /* of valuable bus time. Further, IOmega's Zip drive has a */ ! 1566: /* nasty bug whereby if its reselection is snubbed and it */ ! 1567: /* times out, it leaves the I/O signal asserted on the bus */ ! 1568: /* even as other activity on the bus unrelated to the Zip */ ! 1569: /* is ongoing. */ ! 1570: /* We don't need to hack if ArbLost is indicated correctly */ ! 1571: /* or Reselect is indicated. If either is true, don't bother*/ ! 1572: /* starting the DBDMA; rather, let the interrupt already */ ! 1573: /* latched handle the situation. */ ! 1574: ! 1575: if ( !(g.shadow.mesh.exception & (kMeshExcArbLost | kMeshExcResel)) ) ! 1576: { ! 1577: ELG( '****', '****', 'HACK', "runDBDMA - Arbitrate HACK." ); ! 1578: // ??? check FIFO count for presence of Target ID ??? ! 1579: setSeqReg( kMeshResetMESH ); /* hack it: whack it */ ! 1580: getHBARegsAndClear( true ); /* get regs/clear */ ! 1581: setSeqReg( kMeshEnableReselect ); /* Let reselect again */ ! 1582: getHBARegsAndClear( false ); /* get regs/preserve */ ! 1583: if ( g.shadow.mesh.interrupt == 0 ) ! 1584: PAUSE( 0, 0, 'Arb*', "runDBDMA - Arbitrate/Reselect problem." ); ! 1585: } ! 1586: if ( g.shadow.mesh.interrupt ) /* If Err or Exc set, */ ! 1587: break; /* break SWITCH - Don't start the DBDMA. */ ! 1588: }/* end ELSE lost Arbitration */ ! 1589: }/* end IF DBDMA to start at Arbitrate */ ! 1590: ! 1591: getHBARegsAndClear( false ); // ??? debug: see if ACK still set ! 1592: ELG( 0, offset<<16 | stageLabel, 'DMA+', "runDBDMA" ); ! 1593: /// dbdma_start( DBDMA_MESH_SCSI, (dbdma_command_t*)((UInt32)fCCLPhysAddr + offset) ); ! 1594: DBDMARegs->commandPtrLo = SWAP( (UInt32)fCCLPhysAddr + offset ); ! 1595: SynchronizeIO(); ! 1596: DBDMARegs->channelControl = SWAP( 0x80008000 ); // set RUN bit ! 1597: SynchronizeIO(); ! 1598: return; ! 1599: }/* end SWITCH on interrupt register */ ! 1600: ! 1601: ! 1602: ELG( 0, intReg, 'Pnd-', "runDBDMA - interrupt probably pending (reselect?)." ); ! 1603: getHBARegsAndClear( false ); /* display regs without clearing */ ! 1604: *(UInt32*)&fCCL[ kcclStageLabel ] = kcclStageIdle; /* set stage to none */ ! 1605: g.intLevel |= kLevelLatched; /* set latched-interrupt flag. */ ! 1606: setIntMask( kMeshIntrMask ); /* make sure MESH interrupts enabled */ ! 1607: return; ! 1608: }/* end runDBDMA */ ! 1609: ! 1610: ! 1611: void meshSCSIController::completeCommand() ! 1612: { ! 1613: ELG( fCmdData->results.bytesTransferred, fCmdData->results.scsiStatus, ' IOC', "meshSCSIController::completeCommand" ); ! 1614: ! 1615: { ! 1616: switch ( fCmdData->results.scsiStatus ) ! 1617: { ! 1618: case kSCSIStatusGood: ! 1619: if ( fCmdData->results.bytesTransferred != fCmdData->xferCount ! 1620: && fCmdData->results.returnCode == kIOReturnSuccess ) ! 1621: { ! 1622: fCmdData->results.returnCode = kIOReturnUnderrun; ! 1623: } ! 1624: break; ! 1625: ! 1626: case kSCSIStatusCheckCondition: ! 1627: ! 1628: ELG( 0, 0, 'Chek', "meshSCSIController::completeCommand - Check Condition" ); ! 1629: fCmdData->results.returnCode = kIOReturnError; ! 1630: break; ! 1631: ! 1632: case kSCSIStatusQueueFull: ! 1633: default: ! 1634: ELG( fCmd, fCmdData->results.scsiStatus, 'Sta?', "meshSCSIController::completeCommand - bad status" ); ! 1635: fCmdData->results.returnCode = kIOReturnError; ! 1636: break; ! 1637: }/* end SWITCH on SCSI status */ ! 1638: }/* end IF not autosense */ ! 1639: ! 1640: fCmd->setResults( &fCmdData->results ); ! 1641: fCmd->complete(); ! 1642: ! 1643: fCmd = NULL; ! 1644: fCmdData = NULL; ! 1645: fCurrentTargetLun.target = kInvalidTarget; ! 1646: fCurrentTargetLun.lun = kInvalidLUN; ! 1647: return; ! 1648: }/* end completeCommand */ ! 1649: ! 1650: ! 1651: void meshSCSIController::free() ! 1652: { ! 1653: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr; ! 1654: ! 1655: ! 1656: if ( fMESHAddr ) ! 1657: { ! 1658: setSeqReg( kMeshResetMESH ); ! 1659: } ! 1660: ! 1661: if ( DBDMARegs ) ! 1662: { ! 1663: // dbdma_stop( DBDMA_MESH_SCSI ); ! 1664: DBDMARegs->channelControl = SWAP( 0x20002000 ); // set FLUSH bit ! 1665: SynchronizeIO(); ! 1666: DBDMARegs->channelControl = SWAP( 0x80000000 ); // clr RUN bit ! 1667: SynchronizeIO(); ! 1668: } ! 1669: ! 1670: if ( fInterruptEvent ) ! 1671: { ! 1672: fInterruptEvent->disable(); ! 1673: fInterruptEvent->release(); ! 1674: fInterruptEvent = 0; ! 1675: } ! 1676: ! 1677: if ( fCCL ) ! 1678: { ! 1679: IOFreeContiguous( (void*)fCCL, fCCLSize ); ! 1680: fCCL = NULL; ! 1681: } ! 1682: ! 1683: if ( fMemoryCursor ) ! 1684: { ! 1685: fMemoryCursor->release(); ! 1686: fMemoryCursor = 0; ! 1687: } ! 1688: ! 1689: if ( g.evLogBuf ) ! 1690: { ! 1691: IOFree( (void*)g.evLogBuf, kEvLogSize ); ! 1692: g.evLogBuf = 0; ! 1693: } ! 1694: ! 1695: super::free(); ! 1696: return; ! 1697: }/* end free */ ! 1698: ! 1699: ! 1700: /* startBucket - Start the channel commands to run the bit bucket. */ ! 1701: ! 1702: void meshSCSIController::startBucket() ! 1703: { ! 1704: DBDMADescriptor *dp; /* current data descriptor */ ! 1705: UInt32 dbdmaOp; /* Opcode for DBDMA */ ! 1706: UInt32 meshSeq; /* Opcode for MESH request */ ! 1707: ! 1708: ! 1709: ELG( fCmd, fCmdData, 'Bkt-', "startBucket" ); ! 1710: ! 1711: /* Generate MESH "sequence" & DBDMA "operation" for Input or Output: */ ! 1712: ! 1713: if ( fCmdData->isWrite ) ! 1714: { dbdmaOp = OUTPUT_MORE | kBranchIfFalse | 8; ! 1715: meshSeq = kMeshDataOutCmd | kMeshSeqDMA; ! 1716: } ! 1717: else ! 1718: { dbdmaOp = INPUT_MORE | kBranchIfFalse | 8; ! 1719: meshSeq = kMeshDataInCmd | kMeshSeqDMA; ! 1720: } ! 1721: ! 1722: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunMESH ]; dp->cmdDep = meshSeq; ! 1723: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunDBDMA ]; dp->operation = dbdmaOp; ! 1724: ! 1725: runDBDMA( kcclDataXfer, kcclStageBucket ); ! 1726: return; ! 1727: }/* end startBucket */ ! 1728: ! 1729: ! 1730: /* The Channel Program ran to completion without problems. */ ! 1731: ! 1732: void meshSCSIController::doInterruptStageGood() ! 1733: { ! 1734: UInt32 totalXferLen; ! 1735: ! 1736: ! 1737: /* Retrieve the total number of bytes transferred */ ! 1738: /* in the last data phase and reset it: */ ! 1739: totalXferLen = *(UInt32*)&fCCL[ kcclBatchSize ]; ! 1740: *(UInt32*)&fCCL[ kcclBatchSize ] = 0; ! 1741: ! 1742: ELG( fCmd, totalXferLen, 'Good', "doInterruptStageGood" ); ! 1743: ! 1744: /* We are completing a normal command. */ ! 1745: /* Update the transfer count and current data pointer. */ ! 1746: ! 1747: fCmdData->results.bytesTransferred += totalXferLen; ! 1748: ! 1749: if ( fReadAlignmentCount ) // Hack for Radar 1670626 ! 1750: { ! 1751: fCmdData->mdp->writeBytes( fReadAlignmentIndex, &fCCL[ kcclReadBuf8 ], fReadAlignmentCount ); ! 1752: fReadAlignmentCount = 0; ! 1753: } ! 1754: ! 1755: if ( fFlagIncompleteDBDMA == false ) ! 1756: { ! 1757: /* Yes, the IO is really complete: */ ! 1758: ! 1759: fCmdData->results.returnCode = kIOReturnSuccess; ! 1760: fCmdData->results.scsiStatus = fCCL[ kcclStatusData ]; ! 1761: fCmd->setResults( &fCmdData->results ); ! 1762: ! 1763: completeCommand(); ! 1764: } ! 1765: else ! 1766: { /* The CCL ended, but the caller expected more data. */ ! 1767: /* Restart the CCL. */ ! 1768: /* Don't regenerate arbitration or command stuff. */ ! 1769: ! 1770: updateCP( true ); ! 1771: runDBDMA( kcclDataXfer, kcclStageXfer ); ! 1772: return; ! 1773: }/* end ELSE need to continue Channel Program */ ! 1774: ! 1775: /* Since IO completed (otherwise, we would have exited in the */ ! 1776: /* "return" above), check whether a reselection attempt */ ! 1777: /* is piggy-backed on top of the good DBDMA completion. */ ! 1778: ! 1779: if ( g.shadow.mesh.exception & kMeshExcResel ) ! 1780: handleReselectionInterrupt(); ! 1781: else /* Nothing happening. Try to start another request. */ ! 1782: { ! 1783: setIntMask( kMeshIntrException | kMeshIntrError ); /* Re-enable ints for reselect */ ! 1784: enableCommands(); /* let superclass issue another cmd */ ! 1785: } ! 1786: ! 1787: return; ! 1788: }/* end doInterruptStageGood */ ! 1789: ! 1790: ! 1791: /* Process a normal data phase interrupt. IO is not complete. */ ! 1792: /* There are several reasons why we might get here: */ ! 1793: /* -- autosense completion (which could be a separate stage) */ ! 1794: /* -- DMA completion with more DMA to do */ ! 1795: /* -- Bus phase mismatch (short transfer or disconnect, MsgIn) */ ! 1796: /* Note that we know that we are not in autosense. */ ! 1797: ! 1798: void meshSCSIController::doInterruptStageXfer() ! 1799: { ! 1800: UInt32 count; /* DMA transfer count */ ! 1801: UInt8 phase; /* Current bus phase */ ! 1802: IOReturn rc; ! 1803: int goAround; ! 1804: ! 1805: ! 1806: count = fCmdData->results.bytesTransferred; ! 1807: ! 1808: updateCurrentIndex(); ! 1809: ! 1810: do ! 1811: { goAround = false; /* assume loop not repeated */ ! 1812: setSeqReg( kMeshFlushFIFO ); ! 1813: ! 1814: /* We've cleaned up the mess from the previous data transfer. */ ! 1815: /* Look at the current bus phase. The channel command waited */ ! 1816: /* for REQ to be set before interrupting the processor. */ ! 1817: ! 1818: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask; ! 1819: /* REQ is set, right? */ ! 1820: ! 1821: switch ( phase ) ! 1822: { ! 1823: case kBusPhaseSTS: ! 1824: fFlagIncompleteDBDMA = false; /* indicate no-more-data */ ! 1825: runDBDMA( kcclGetStatus, kcclStageStat ); ! 1826: break; ! 1827: ! 1828: case kBusPhaseMSGI: ! 1829: rc = DoMessageInPhase(); ! 1830: if ( rc == kIOReturnSuccess && fCmd ) ! 1831: goAround = true; /* msg ok & not disconnect */ ! 1832: break; ! 1833: ! 1834: case kBusPhaseDATO: ! 1835: case kBusPhaseDATI: ! 1836: if ( count != fCmdData->results.bytesTransferred ) ! 1837: { /* Data phase had already started: */ ! 1838: PAUSE( 0, phase, 'dat-', "doInterruptStageXfer - unexpected Data phase.\n" ); ! 1839: } ! 1840: else ! 1841: { /* try starting data phase again */ ! 1842: runDBDMA( kcclDataXfer, kcclStageXfer ); ! 1843: } ! 1844: break; ! 1845: ! 1846: default: ! 1847: PAUSE( 0, phase, 'Phs-', "doInterruptStageXfer - bogus phase.\n" ); ! 1848: break; ! 1849: }/* end SWITCH on phase */ ! 1850: } while ( goAround ); ! 1851: return; ! 1852: }/* end doInterruptStageXfer */ ! 1853: ! 1854: ! 1855: /* doInterruptStageArb - Process an anomaly during arbitration. */ ! 1856: ! 1857: void meshSCSIController::doInterruptStageArb() ! 1858: { ! 1859: PAUSE( 0, 0, 'Arb-', "doInterruptStageArb - Lost arbitration.\n" ); ! 1860: ! 1861: disableCommands(); ! 1862: rescheduleCommand( fCmd ); ! 1863: fCmd = 0; ! 1864: ! 1865: if ( g.shadow.mesh.exception & kMeshExcResel ) ! 1866: { if ( g.shadow.mesh.error & kMeshErrDisconnected ) ! 1867: { ! 1868: /* 18sep98 - Sometimes MESH gets real confused when its */ ! 1869: /* arbitration loses to a target's reselect arbitration. */ ! 1870: /* The registers show Exc:ArbLost, Resel and Err:UnExpDisc. */ ! 1871: /* The FIFO count is 1 (should be SCSI ID bits) while the */ ! 1872: /* BusStatus0,1 registers show IO and Sel both of which are */ ! 1873: /* set by the reselecting Target. */ ! 1874: /* The SCSI bus analyzer shows the following events occcurring */ ! 1875: /* within a few microseconds of BSY being set by the target: */ ! 1876: /* bus free for at least hundreds of microseconds */ ! 1877: /* Target raises BSY along with its ID bit */ ! 1878: /* Target raises SEL */ ! 1879: /* Target raises IO to indicate reselection */ ! 1880: /* Target adds MESH's ID bit */ ! 1881: /* Target drops BSY */ ! 1882: /* MESH raises BSY to accept reselection */ ! 1883: /* **** MESH drops BSY **** here is where MESH is confused */ ! 1884: /* Target stays on bus for 250 milliseconds. */ ! 1885: /* To solve this problem, whack MESH with a RstMESH. */ ! 1886: ! 1887: ELG( ' Rst', 'MESH', 'UEP-', "doInterruptStageArb - Resel/Unexpected Disconnect.\n" ); ! 1888: setSeqReg( kMeshResetMESH ); /* completes quickly */ ! 1889: getHBARegsAndClear( true ); /* clear cmdDone */ ! 1890: setSeqReg( kMeshEnableReselect ); ! 1891: setIntMask( kMeshIntrMask ); /* Enable Interrupts */ ! 1892: return; /* now wait for another reselect interrupt */ ! 1893: } ! 1894: handleReselectionInterrupt(); ! 1895: } ! 1896: else ! 1897: { /* 22sep97 - lost arbitration without reselection. */ ! 1898: /* Probably lost the reselect condition processing an */ ! 1899: /* error or something. */ ! 1900: ELG( 0, 0, 'ARB-', "doInterruptStageArb - Lost arbitration without reselect.\n" ); ! 1901: } ! 1902: return; ! 1903: }/* end doInterruptStageArb */ ! 1904: ! 1905: ! 1906: /* Process an anomaly during target selection. */ ! 1907: ! 1908: void meshSCSIController::doInterruptStageSelA() ! 1909: { ! 1910: ELG( fCmd, 0, 'Sel-', "doInterruptStageSelA - Selection stage.\n" ); ! 1911: if ( fCmd ) ! 1912: { fCmdData->results.returnCode = kIOReturnNoDevice; ! 1913: completeCommand(); ! 1914: } ! 1915: setSeqReg( kMeshEnableReselect ); ! 1916: setSeqReg( kMeshBusFreeCmd ); /* clear ATN signal MESH left on */ ! 1917: getHBARegsAndClear( false ); /* check MESH registers */ ! 1918: ! 1919: if ( g.shadow.mesh.exception & kMeshExcResel ) ! 1920: { ! 1921: handleReselectionInterrupt(); ! 1922: } ! 1923: else ! 1924: { setIntMask( kMeshIntrMask ); /* Enable Interrupts */ ! 1925: /* enableCommands on the Bus-Free interrupt. */ ! 1926: /* If we do it here, we'll get a command, start the DBDMA, */ ! 1927: /* and get the Bus-Free interrupt seeming to be spurious. */ ! 1928: } ! 1929: return; ! 1930: }/* end doInterruptStageSelA */ ! 1931: ! 1932: ! 1933: /* Process an anomaly during Message-Out phase. */ ! 1934: /* Target probably doing Message Reject (0x07). */ ! 1935: ! 1936: void meshSCSIController::doInterruptStageMsgO() ! 1937: { ! 1938: UInt8 phase; ! 1939: IOReturn rc; ! 1940: ! 1941: ! 1942: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask; /* phase me */ ! 1943: ELG( fCmd, phase, 'Mgo-', "doInterruptStageMsgO - error during msg-out phase.\n" ); ! 1944: ! 1945: switch ( phase ) /* Probably negotiating Sync */ ! 1946: { ! 1947: case kBusPhaseMSGI: ! 1948: rc = DoMessageInPhase(); ! 1949: if ( rc != kIOReturnSuccess ) ! 1950: { ! 1951: PAUSE( 0, rc, ' MI-', ! 1952: "doInterruptStageMsgO - MsgIn during MsgOut phase.\n" ); ! 1953: // ??? need to get to bus-free from here ! 1954: // ??? need to blow off the IO ! 1955: } ! 1956: else ! 1957: { ELG( 0, fMsgInFlag, 'rej?', "doInterruptStageMsgO - got MsgIn.\n" ); ! 1958: if ( fMsgInFlag & kFlagMsgIn_Reject ) ! 1959: abortActiveCommand(); ! 1960: } ! 1961: break; ! 1962: ! 1963: default: ! 1964: PAUSE( fMsgInFlag, phase, 'mgo-', ! 1965: "doInterruptStageMsgO - unknown phase during MsgOut phase.\n" ); ! 1966: break; ! 1967: } ! 1968: return; ! 1969: }/* end doInterruptStageMsgO */ ! 1970: ! 1971: ! 1972: /* doInterruptStageCmdO - Process an anomaly during command stage. */ ! 1973: ! 1974: void meshSCSIController::doInterruptStageCmdO() ! 1975: { ! 1976: SCSICDBInfo scsiCDB; ! 1977: UInt8 phase; ! 1978: IOReturn rc; ! 1979: ! 1980: ! 1981: /* See if this is part of the normal AbortTag/BusDeviceReset process: */ ! 1982: ! 1983: fCmd->getCDB( &scsiCDB ); ! 1984: if ( scsiCDB.cdbAbortMsg ) ! 1985: { ! 1986: setSeqReg( kMeshFlushFIFO ); /* flush the FIFO */ ! 1987: getHBARegsAndClear( true ); /* clear cmdDone */ ! 1988: ! 1989: ELG( fCmd, fCmd->getOriginalCmd(), 'Abo-', "doInterruptStageCmdO - Aborting." ); ! 1990: ! 1991: completeCommand(); /* complete the cmd with Abort msg */ ! 1992: setIntMask( kMeshIntrMask ); /* Re-enable interrupts */ ! 1993: enableCommands(); /* let superclass issue another command */ ! 1994: return; ! 1995: } ! 1996: ! 1997: /* Not aborting - something bad happened: */ ! 1998: ! 1999: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask; /* phase me */ ! 2000: ELG( fCmd, phase, 'CMD?', "doInterruptStageCmdO - anomaly during Cmd phase.\n" ); ! 2001: ! 2002: if ( phase == kBusPhaseMSGI ) ! 2003: { /* We are probably negotiating SDTR or */ ! 2004: /* getting rejected on a nonzero LUN. */ ! 2005: rc = DoMessageInPhase(); ! 2006: if ( rc != kIOReturnSuccess ) ! 2007: { ! 2008: PAUSE( 0, rc, ' mi-', ! 2009: "doInterruptStageCmdO - MsgIn during Cmd phase.\n" ); ! 2010: } ! 2011: else ! 2012: { /* Message processed - where do we go from here? */ ! 2013: ! 2014: if ( !fCmd ) /* if Rejected, */ ! 2015: return; /* return */ ! 2016: ! 2017: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask; ! 2018: switch ( phase ) ! 2019: { ! 2020: case kBusPhaseSTS: ! 2021: runDBDMA( kcclCmdoStage, kcclStageInit ); ! 2022: break; ! 2023: ! 2024: case kBusPhaseMSGO: ! 2025: fMsgOutPtr = &fCCL[ kcclMSGOdata ]; ! 2026: setupMsgO(); ! 2027: runDBDMA( kcclMsgoStage, kcclStageInit ); ! 2028: break; ! 2029: ! 2030: case kBusPhaseCMD: ! 2031: runDBDMA( kcclCmdoStage, kcclStageInit ); ! 2032: break; ! 2033: } ! 2034: } ! 2035: } ! 2036: else if ( phase == kBusPhaseSTS ) /* Probably Check Condition */ ! 2037: { /* Perhaps block # invalid */ ! 2038: fFlagIncompleteDBDMA = false; /* indicate no-more-data */ ! 2039: runDBDMA( kcclGetStatus, kcclStageStat ); ! 2040: } ! 2041: else ! 2042: { ! 2043: PAUSE( 0, phase, 'Phs?', "doInterruptStageCmdO - error during Command phase.\n" ); ! 2044: } ! 2045: return; ! 2046: }/* end doInterruptStageCmdO */ ! 2047: ! 2048: ! 2049: /* We are in MSGI phase. Read the bytes. Return true if an entire */ ! 2050: /* message was read (we may still be in MSGI phase). Note that this */ ! 2051: /* is done by programmed IO, which will fail (logging the error) if */ ! 2052: /* the target sets MSGI but does not send us a message quickly enough. */ ! 2053: /* This method is called from the normal data transfer interrupt when */ ! 2054: /* the target enters message in phase, and from the reselection */ ! 2055: /* interrupt handler when we read a valid reselection target ID. */ ! 2056: /* Note that MESH interrupts are disabled on exit. */ ! 2057: enum /// ??? header file ! 2058: { ! 2059: kSCSIMsgOneByteMax = 0x1Fu, ! 2060: kSCSIMsgTwoByteMin = 0x20u, ! 2061: kSCSIMsgTwoByteMax = 0x2Fu ! 2062: }; ! 2063: ! 2064: IOReturn meshSCSIController::DoMessageInPhase() ! 2065: { ! 2066: register UInt8 messageByte; ! 2067: UInt32 index = 0; ! 2068: IOReturn ioReturn = kIOReturnSuccess; ! 2069: ! 2070: ! 2071: /* We do not necessarily have a valid command in this method. */ ! 2072: /* While we're processing Message-In bytes, we don't want any */ ! 2073: /* MESH hardware interrupts. */ ! 2074: ! 2075: setIntMask( 0 ); /* no MESH interrupt latching */ ! 2076: setSeqReg( kMeshFlushFIFO ); /* Flush the FIFO */ ! 2077: ! 2078: fMsgInCount = 0; ! 2079: fMsgInState = kMsgInInit; ! 2080: ! 2081: while ( fMsgInState != kMsgInReady /* Disconnect makes fCmd */ ! 2082: && ioReturn == kIOReturnSuccess ) /* go away */ ! 2083: { ! 2084: fMESHAddr->transferCount1 = 0; ! 2085: fMESHAddr->transferCount0 = 1; /* get single byte */ ! 2086: setSeqReg( kMeshMessageInCmd ); /* issue MsgIn */ ! 2087: ! 2088: ioReturn = waitForMesh( true ); /* wait for cmdDone */ ! 2089: if ( ioReturn != kIOReturnSuccess ) ! 2090: { ! 2091: PAUSE( *(UInt32*)&fCurrentTargetLun, ioReturn, 'Mgi-', "DoMessageInPhase - Target hung: message in timeout.\n" ); ! 2092: break; /* Bus reset here? */ ! 2093: } ! 2094: ! 2095: if ( (g.shadow.mesh.exception & kMeshExcPhaseMM) ! 2096: || (g.shadow.mesh.busStatus0 & kMeshPhaseMask) != kBusPhaseMSGI ) ! 2097: { ! 2098: break; /* exit loop if no longer in Msg-In phase */ ! 2099: } ! 2100: ! 2101: if ( g.shadow.mesh.FIFOCount == 0 ) ! 2102: { ! 2103: PAUSE( *(UInt16*)&fCurrentTargetLun, 0, 'mgi-', "DoMessageInPhase - no message byte.\n" ); ! 2104: break; ! 2105: } ! 2106: ! 2107: fMsgInBuffer[ index++ ] = messageByte = fMESHAddr->xFIFO; /***** get msg byte *****/ ! 2108: ! 2109: switch ( fMsgInState ) ! 2110: { ! 2111: case kMsgInInit: /* This is the first message byte. */ ! 2112: if ( (messageByte == kSCSIMsgCmdComplete) ! 2113: || (messageByte >= (UInt8)kSCSIMsgIdentify) ) ! 2114: { /* This is 1-byte cmdComplete or Identify message. */ ! 2115: fMsgInState = kMsgInReady; ! 2116: } ! 2117: else if ( messageByte == kSCSIMsgExtended ) ! 2118: { /* This is an extended message. The next byte has the count. */ ! 2119: fMsgInState = kMsgInCounting; ! 2120: } ! 2121: else if ( messageByte <= kSCSIMsgOneByteMax ) ! 2122: { /* These are other 1-byte messages. */ ! 2123: fMsgInState = kMsgInReady; ! 2124: } ! 2125: else if ( messageByte >= kSCSIMsgTwoByteMin ! 2126: && messageByte <= kSCSIMsgTwoByteMax ) ! 2127: { /* This is a two-byte message. */ ! 2128: /* Set the count and read the next byte. */ ! 2129: fMsgInState = kMsgInReading; /* Need one more */ ! 2130: fMsgInCount = 1; ! 2131: } ! 2132: else ! 2133: { /* This is an unknown message. */ ! 2134: fMsgInState = kMsgInReady; ! 2135: } ! 2136: break; ! 2137: ! 2138: case kMsgInCounting: /* Count byte of multi-byte message: */ ! 2139: fMsgInCount = messageByte; ! 2140: fMsgInState = kMsgInReading; ! 2141: break; ! 2142: ! 2143: case kMsgInReading: /* Body of multi-byte message: */ ! 2144: if ( --fMsgInCount <= 0 ) ! 2145: fMsgInState = kMsgInReady; ! 2146: break; ! 2147: ! 2148: default: ! 2149: PAUSE( 0, 0, 'Msg-', "DoMessageInPhase - Bogus MSGI state!\n" ); ! 2150: fMsgInState = kMsgInReady; ! 2151: break; ! 2152: }/* end SWITCH on MSGI state */ ! 2153: ! 2154: if ( fMsgInState == kMsgInReady ) ! 2155: { ! 2156: ProcessMSGI(); ! 2157: fMsgInState = kMsgInInit; ! 2158: index = 0; ! 2159: if ( fMsgInBuffer[0] == kSCSIMsgDisconnect ) ! 2160: ioReturn = kIOReturnIOError; /* break out of WHILE loop */ ! 2161: ! 2162: if ( fMsgInFlag & kFlagMsgIn_Reject ) ! 2163: { ! 2164: abortActiveCommand(); ! 2165: break; ! 2166: } ! 2167: ! 2168: if ( fFlagReselecting ) ! 2169: break; /* Take Identify only - leave +ACK */ ! 2170: }/* end IF have a complete message-in to process */ ! 2171: }/* end WHILE there are more message bytes */ ! 2172: ! 2173: /***** If the target switches out of MSGI phase without *****/ ! 2174: /***** sending a complete message, we should do some *****/ ! 2175: /***** sort of error recovery. *****/ ! 2176: ! 2177: if ( fMsgInState != kMsgInInit ) ! 2178: { ! 2179: PAUSE( *(UInt32*)&fCurrentTargetLun, fMsgInState, 'MGI-', "DoMessageInPhase - incomplete message.\n" ); ! 2180: if ( ioReturn == kIOReturnSuccess ) ! 2181: ioReturn = kIOReturnIOError; /* General IO error */ ! 2182: } ! 2183: ! 2184: return ioReturn; ! 2185: }/* end DoMessageInPhase */ ! 2186: ! 2187: ! 2188: /* ProcessMSGI - DoMessageInPhase has read a complete message. */ ! 2189: /* Process it (this will probably change our internal state). */ ! 2190: ! 2191: void meshSCSIController::ProcessMSGI() ! 2192: { ! 2193: /* Note that, during reselection, we may not have */ ! 2194: /* a current target or LUN, nor possibly a valid command */ ! 2195: ! 2196: ! 2197: UInt8 sdtr; ! 2198: UInt8 period, offset; ! 2199: ! 2200: ! 2201: ELG( fCmd, *(UInt32*)fMsgInBuffer, '<Msg', "ProcessMSGI" ); ! 2202: ! 2203: switch ( fMsgInBuffer[0] ) ! 2204: { ! 2205: case kSCSIMsgCmdComplete: ! 2206: if ( fCmd ) ! 2207: { ! 2208: /* This command is complete. Clear interrupts and */ ! 2209: /* allow subsequent MESH interrupts. Then tell the */ ! 2210: /* MESH to wait for the target to release the bus. */ ! 2211: ! 2212: setSeqReg( kMeshEnableReselect ); ! 2213: setSeqReg( kMeshBusFreeCmd ); /* cause Int */ ! 2214: completeCommand(); ! 2215: } ! 2216: goto exit; /* Don't exit through the SWITCH end */ ! 2217: ! 2218: case kSCSIMsgLinkedCmdComplete: ! 2219: case kSCSIMsgLinkedCmdCompleteFlag: ! 2220: PAUSE( *(UInt16*)&fCurrentTargetLun, 0, 'pmi-', "ProcessMSGI - linked command complete not supported.\n" ); ! 2221: abortActiveCommand(); ! 2222: break; ! 2223: ! 2224: case kSCSIMsgNop: ! 2225: break; ! 2226: ! 2227: case kSCSIMsgRestorePointers: ! 2228: if ( fCmd ) ! 2229: fCmdData->results.bytesTransferred = fCmdData->savedDataPosition; ! 2230: break; ! 2231: ! 2232: case kSCSIMsgSaveDataPointers: ! 2233: if ( fCmd ) ! 2234: fCmdData->savedDataPosition = fCmdData->results.bytesTransferred; ! 2235: break; ! 2236: ! 2237: case kSCSIMsgDisconnect: ! 2238: /* Move this request to the disconnect queue, enable reselection, */ ! 2239: /* re-enable MESH interrupts, and wait (here) for bus free, but */ ! 2240: /* don't eat the interrupt. */ ! 2241: ! 2242: fMsgInFlag |= kFlagMsgIn_Disconnect; ! 2243: disconnect(); /* requeue active */ ! 2244: setSeqReg( kMeshEnableReselect ); /* enable reselect */ ! 2245: setIntMask( kMeshIntrMask ); /* Enable Ints */ ! 2246: setSeqReg( kMeshBusFreeCmd ); /* issue BusFree */ ! 2247: ! 2248: /* wait for Bus Free command to complete: */ ! 2249: ! 2250: waitForMesh( false ); /* don't clear possible reselect */ ! 2251: ! 2252: /* Interrupt for bus-free now latched. Prevent a double interrupt, */ ! 2253: /* 1 from bus-free + 1 from reselect from occurring. */ ! 2254: /* This fixes the following BADNESS: */ ! 2255: /* Issue bus-free for disconnect. */ ! 2256: /* Interrupt occurs in microseconds - even before exiting */ ! 2257: /* "interruptOccurred" routine. */ ! 2258: /* Mach queues message to driverKit. */ ! 2259: /* Exit "interruptOccurred" routine. */ ! 2260: /* DriverKit dequeues and starts handling 1st Mach message. */ ! 2261: /* Interrupt occurs for reselect while driverKit running. */ ! 2262: /* Mach queues 2nd message to driverKit. */ ! 2263: /* DriverKit invokes MESH driver for 1st msg. */ ! 2264: /* MESH driver sees cmdDone fm bus-free AND reselect exception.*/ ! 2265: /* MESH driver handles reselect by setting up and running */ ! 2266: /* DBDMA. MESH driver exits. */ ! 2267: /* DriverKit invokes MESH driver with 2nd Mach message. */ ! 2268: /* MESH driver handles this as a DBDMA completion and royally */ ! 2269: /* messes up. */ ! 2270: ! 2271: g.intLevel |= kLevelLatched; /* set latched-interrupt flag */ ! 2272: setIntMask( 0 ); /* prevent multiple MESH ints */ ! 2273: break; ! 2274: ! 2275: case kSCSIMsgRejectMsg: ! 2276: ELG( *(UInt16*)&fCurrentTargetLun, fMsgOutFlag, 'Rej-', "ProcessMSGI - Reject." ); ! 2277: fMsgInFlag |= kFlagMsgIn_Reject; ! 2278: break; ! 2279: ! 2280: case kSCSIMsgSimpleQueueTag: ! 2281: fTagType = fMsgInBuffer[0]; ! 2282: fTag = fMsgInBuffer[1]; ! 2283: ELG( 0, fTag, '=Tag', "Simple Queue Tag" ); ! 2284: break; ! 2285: ! 2286: case kSCSIMsgExtended: ! 2287: ! 2288: /* Multi-byte message, presumably Synchronous Negotiation: */ ! 2289: ! 2290: switch ( fMsgInBuffer[ 2 ] ) /* switch on the msg code byte */ ! 2291: { ! 2292: case kSCSIMsgSyncXferReq: /* handle sync negotiation: */ ! 2293: /* Get period in nanoseconds */ ! 2294: period = fMsgInBuffer[ 3 ] * 4; /* SCSI uses 4ns granularity */ ! 2295: ! 2296: /* determine target responding or initiating? */ ! 2297: if ( fNegotiatingSDTR ) ! 2298: { ! 2299: if ( fMsgInBuffer[ 4 ] == 0 ) /* check offset */ ! 2300: { ! 2301: sdtr = kSyncParmsAsync; /* Offset == 0 implies async */ ! 2302: } ! 2303: else /* synchronous: */ ! 2304: { ! 2305: if ( period == 100 ) /* special-case 100=FAST */ ! 2306: { ! 2307: sdtr = kSyncParmsFast & 0x0F; ! 2308: } ! 2309: else /* Older CD-ROMs get here. */ ! 2310: { /* The MESH manual says: */ ! 2311: /* period = 4 * clk + 2 * clk * P */ ! 2312: /* where: */ ! 2313: /* period is the target nanoseconds */ ! 2314: /* clk is the MESH clock rate which is */ ! 2315: /* 20 nanoseconds for a 50 MHz clock */ ! 2316: /* P is the 1-nibble period code we stuff */ ! 2317: /* in the syncParms register */ ! 2318: /* So: */ ! 2319: /* period = 4 * 20 + 2 * 20 * P */ ! 2320: /* period = 80 + 40 * P */ ! 2321: /* P = (period - 80) / 40 */ ! 2322: /* Since P must round up for safety: */ ! 2323: /* P = ((period - 80) + 39) / 40 */ ! 2324: /* P = (period - 41) / 40 */ ! 2325: /* A value of P == 3 results in 5 MB/s */ ! 2326: sdtr = (UInt8)((period - 41) / 40); ! 2327: } ! 2328: }/* end ELSE have offset ergo Synchronous */ ! 2329: ! 2330: /* OR in the offset. */ ! 2331: sdtr |= (fMsgInBuffer[ 4 ] << 4); ! 2332: }/* end IF Target is responding to negotiation */ ! 2333: ! 2334: else /* target is initiating negotiation: */ ! 2335: { ! 2336: fMsgOutPtr = &fCCL[ kcclMSGOdata ]; ! 2337: *fMsgOutPtr++ = kSCSIMsgExtended; /* 0x01 Ext Msg */ ! 2338: *fMsgOutPtr++ = 0x03; /* 0x03 Message Len */ ! 2339: *fMsgOutPtr++ = kSCSIMsgSyncXferReq; /* 0x01 SDTR code */ ! 2340: offset = fMsgInBuffer[ 4 ]; ! 2341: if ( offset == 0 ) /* Offset == 0 means async: */ ! 2342: { ! 2343: *fMsgOutPtr++ = 0; /* clear period byte */ ! 2344: *fMsgOutPtr++ = 0; /* offset byte = 0 for async*/ ! 2345: sdtr = kSyncParmsAsync; /* set value for MESH reg */ ! 2346: } ! 2347: else /* have offset ergo sync: */ ! 2348: { ! 2349: if ( offset > 15 ) ! 2350: offset = 15; /* MESH can only handle 15 */ ! 2351: ! 2352: if ( period <= 100 ) /* special-case 100=FAST */ ! 2353: period = 100; ! 2354: else ! 2355: { /* round up to MESH's 40 ns granularity */ ! 2356: period = ((period + 39) / 40) * 40; ! 2357: } ! 2358: *fMsgOutPtr++ = period / 4; /* SCSI 4ns granularity */ ! 2359: *fMsgOutPtr++ = offset; ! 2360: sdtr = (offset << 8) | (UInt8)((period - 41) / 40); ! 2361: }/* end target is negotiating Sync */ ! 2362: /* respond to target: */ ! 2363: runDBDMA( kcclMsgoStage, kcclStageInit ); ! 2364: }/* end ELSE target is initiating negotiation */ ! 2365: ! 2366: fMESHAddr->syncParms = sdtr; ! 2367: SynchronizeIO(); ! 2368: fSyncParms[ fCurrentTargetLun.target ] = sdtr; ! 2369: ELG( *(UInt32*)&fMsgInBuffer[0], fMsgInBuffer[4]<<24 | sdtr, 'SDTR', "ProcessMSGI - SDTR" ); ! 2370: break; ! 2371: ! 2372: default: ! 2373: PAUSE( *(UInt16*)&fCurrentTargetLun, fMsgInBuffer[0], 'PMi-', "ProcessMSGI - unsupported extended message.\n" ); ! 2374: abortActiveCommand(); ! 2375: break; ! 2376: }/* end SWITCH on extended message code */ ! 2377: break; ! 2378: ! 2379: default: /* Better be Identify with LUN: */ ! 2380: if ( fMsgInBuffer[0] >= kSCSIMsgIdentify ) ! 2381: { ! 2382: fCurrentTargetLun.lun = fMsgInBuffer[0] & 0x07; ! 2383: } ! 2384: else ! 2385: { ! 2386: PAUSE( *(UInt16*)&fCurrentTargetLun, fMsgInBuffer[0], 'mi -', "ProcessMSGI - unsupported message: rejected.\n" ); ! 2387: abortActiveCommand(); ! 2388: } ! 2389: }/* end SWITCH on message selection */ ! 2390: ! 2391: exit: ! 2392: return; ! 2393: }/* end ProcessMSGI */ ! 2394: ! 2395: ! 2396: /* Process a reselection interrupt. */ ! 2397: ! 2398: void meshSCSIController::handleReselectionInterrupt() ! 2399: { ! 2400: IOReturn ioReturn; ! 2401: ! 2402: ! 2403: fFlagReselecting = true; ! 2404: disableCommands(); /* tell superclass we're busy */ ! 2405: ! 2406: fMESHAddr->interrupt = kMeshIntrMask; /* clr Exc, Err regs to prevent SeqErr*/ ! 2407: ! 2408: /* Sometimes MESH gives a bogus Disconnected error during Reselection. */ ! 2409: /* 31mar98 - Issuing an Abort message, causes "unexpected disconnect". */ ! 2410: /* When Err:UnexpDisc and Exc:Resel are simultaneously set, the */ ! 2411: /* busStatus0,1 registers may not be current. */ ! 2412: if ( g.shadow.mesh.error & kMeshErrDisconnected ) ! 2413: { ! 2414: setSeqReg( kMeshBusFreeCmd ); ! 2415: waitForMesh( true ); // now maybe busStatus0,1 are live ! 2416: PAUSE( 0, 0, 'Dsc-', ! 2417: "handleReselectionInterrupt: Caught disconnected glitch\n" ); ! 2418: }/* End IF bus disconnect error */ ! 2419: ! 2420: /* Read the target ID (which should be our initiator ID OR'd with the */ ! 2421: /* Target and the Identify byte with the reselecting LUN. Store this */ ! 2422: /* in fCurrentTargetLun. Note that, during reselection, we will */ ! 2423: /* have a NULL gCurrentCommand and a valid fCurrentTargetLun. */ ! 2424: /* If we get a valid reselection target, call the message in phase */ ! 2425: /* directly to read the LUN byte. */ ! 2426: /* @return true if successful. */ ! 2427: ! 2428: if ( fMESHAddr->FIFOCount == 0 ) ! 2429: { ! 2430: PAUSE( 0, 0, 'HRI-', "handleReselectionInterrupt - Empty FIFO in reselection.\n" ); ! 2431: return; ! 2432: } ! 2433: else /* get the Target ID bit from the bus out of the FIFO */ ! 2434: { /* then, get the msg-in Identify byte for the LUN. */ ! 2435: if ( getReselectionTargetID() ) ! 2436: { ! 2437: if ( DoMessageInPhase() != kIOReturnSuccess ) /* get Identify */ ! 2438: { ! 2439: PAUSE( 0, 0, 'Id -', "handleReselectionInterrupt - Expected Identify byte after reselection.\n" ); ! 2440: } ! 2441: } ! 2442: else return; ! 2443: } ! 2444: ! 2445: /* Try to find an untagged command for this Target/LUN: */ ! 2446: ! 2447: fTag = kInvalidTag; ! 2448: ioReturn = reselectNexus(); ! 2449: ! 2450: if ( ioReturn != kIOReturnSuccess ) ! 2451: { /* No untagged command, try to get a Tag. Hope that */ ! 2452: /* you're still in Message-In phase at this point. */ ! 2453: if ( DoMessageInPhase() != kIOReturnSuccess ) /* get Tag msg */ ! 2454: { ! 2455: PAUSE( 0, 0, 'tag-', "handleReselectionInterrupt - Expected tag message.\n" ); ! 2456: /// need to bus device reset since it seems confused. ! 2457: } ! 2458: ioReturn = reselectNexus(); ! 2459: } ! 2460: ! 2461: if ( ioReturn == kIOReturnSuccess ) ! 2462: { ! 2463: ELG( fCmd, ! 2464: fTag<<16 | fCurrentTargetLun.lun<<8 | fCurrentTargetLun.target, ! 2465: 'Resl', "handleReselectionInterrupt" ); ! 2466: /* If reselectNexus succeeded, fCmd is set to the command. */ ! 2467: /* Clear out the channel command Results and build the channel */ ! 2468: /* command to continue operation. */ ! 2469: ! 2470: clearCPResults(); ! 2471: updateCP( true ); /* Bypass arbitrate/select/command sequence */ ! 2472: runDBDMA( kcclReselect, kcclStageInit ); ! 2473: } ! 2474: else ! 2475: { /* There is no associated command. */ ! 2476: /* Reject the reselection attempt. */ ! 2477: PAUSE( *(UInt16*)&fCurrentTargetLun, fTag, 'Rsl-', ! 2478: "handleReselectionInterrupt - No command for reselection attempt.\n" ); ! 2479: abortActiveCommand(); ! 2480: } ! 2481: return; ! 2482: }/* end handleReselectionInterrupt */ ! 2483: ! 2484: ! 2485: /* Validate the target's reselection byte (put on the bus before */ ! 2486: /* reselecting us). Erase the initiator ID and convert the other */ ! 2487: /* bit into an index. The algorithm should be faster than a */ ! 2488: /* sequential search, but it probably doesn't matter much. */ ! 2489: /* Return true if successful (fCurrentTarget is now valid). */ ! 2490: ! 2491: bool meshSCSIController::getReselectionTargetID() ! 2492: { ! 2493: register UInt8 targetID = 0; ! 2494: register UInt8 bitValue = 0; /* Suppress warning */ ! 2495: register UInt8 targetBits; ! 2496: bool success = false; ! 2497: ! 2498: ! 2499: targetBits = fMESHAddr->xFIFO; /***** Read the FIFO *****/ ! 2500: targetBits &= ~fInitiatorIDMask; /* Remove our bit */ ! 2501: if ( targetBits ) ! 2502: { /* Is there another bit? */ ! 2503: bitValue = targetBits; ! 2504: if ( bitValue > 0x0F ) ! 2505: { ! 2506: targetID += 4; ! 2507: bitValue >>= 4; ! 2508: } ! 2509: if ( bitValue > 0x03 ) ! 2510: { ! 2511: targetID += 2; ! 2512: bitValue >>= 2; ! 2513: } ! 2514: if ( bitValue > 0x01 ) ! 2515: { ! 2516: targetID += 1; ! 2517: } ! 2518: targetBits &= ~(1 << targetID); /* Remove the target mask */ ! 2519: if ( targetBits == 0 ) ! 2520: { /* Was exactly one set? */ ! 2521: success = true; /* Yes: success! */ ! 2522: fCurrentTargetLun.target = targetID; /* Save the current target */ ! 2523: } ! 2524: } ! 2525: ! 2526: if ( !success ) ! 2527: PAUSE( targetID, targetBits, 'rsl-', "getReselectionTargetID - Expected Identify byte after reselection.\n" ); ! 2528: ! 2529: return success; ! 2530: }/* end getReselectionTargetID */ ! 2531: ! 2532: ! 2533: ! 2534: IOReturn meshSCSIController::resetBus() ! 2535: { ! 2536: UInt8 defaultSelectionTimeout = 25; // mlj ??? fix this value ! 2537: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr; ! 2538: ! 2539: ! 2540: ELG( 0, 0, 'RstB', "resetBus" ); ! 2541: ! 2542: /* Stop the DBDMA: */ ! 2543: ! 2544: DBDMARegs->channelControl = SWAP( 0x20002000 ); // set FLUSH bit ! 2545: SynchronizeIO(); ! 2546: DBDMARegs->channelControl = SWAP( 0x80000000 ); // clr RUN bit ! 2547: SynchronizeIO(); ! 2548: ! 2549: /* Reset interrupts, the MESH Hardware Bus Adapter, and the DMA engine. */ ! 2550: ! 2551: setIntMask( 0 ); ! 2552: ! 2553: setSeqReg( kMeshResetMESH ); /* completes quickly */ ! 2554: getHBARegsAndClear( true ); /* clear cmdDone */ ! 2555: ! 2556: /// dbdma_reset( DBDMA_MESH_SCSI ); ! 2557: ! 2558: /* Init state variables: */ ! 2559: ! 2560: fFlagIncompleteDBDMA = false; ! 2561: ! 2562: /* Smash all active command state (just in case): */ ! 2563: ! 2564: fCmd = NULL; ! 2565: fCmdData = NULL; ! 2566: fCurrentTargetLun.target = kInvalidTarget; ! 2567: fCurrentTargetLun.lun = kInvalidLUN; ! 2568: fMsgInState = kMsgInInit; ! 2569: fMsgOutPtr = &fCCL[ kcclMSGOdata ]; ! 2570: ! 2571: fMESHAddr->busStatus1 = kMeshRst; /***** ASSERT RESET SIGNAL *****/ ! 2572: SynchronizeIO(); ! 2573: IODelay( 25 ); /* leave asserted for 25 mikes */ ! 2574: fMESHAddr->busStatus1 = 0; /***** CLEAR RESET SIGNAL *****/ ! 2575: SynchronizeIO(); ! 2576: ! 2577: /* Delay for 250 msec after resetting the bus. */ ! 2578: /* This serves two purposes: it gives the MESH time to */ ! 2579: /* stabilize (about 10 msec is sufficient) and gives */ ! 2580: /* some devices time to re-initialize themselves. */ ! 2581: ! 2582: IOSleep( APPLE_SCSI_RESET_DELAY ); /* Give Targets time to clean up */ ! 2583: setSeqReg( kMeshResetMESH ); /* clear Err condition */ ! 2584: getHBARegsAndClear( true ); /* check regs */ ! 2585: ! 2586: fMESHAddr->selectionTimeOut = defaultSelectionTimeout; ! 2587: SynchronizeIO(); ! 2588: ! 2589: enableCommands(); /* let superclass issue another command */ ! 2590: ! 2591: return kIOReturnSuccess; ! 2592: }/* end resetBus */ ! 2593: ! 2594: ! 2595: /* Wait for an immediate (non-interrupting) command to complete. */ ! 2596: /* Note that it spins while waiting. It is timed to prevent a buggy */ ! 2597: /* chip or target from hanging the system. */ ! 2598: ! 2599: IOReturn meshSCSIController::waitForMesh( bool clearInterrupts ) ! 2600: { ! 2601: mach_timespec_t time, startTime, endTime, waitTime; ! 2602: IOReturn ioReturn = kIOReturnSuccess; ! 2603: ! 2604: ! 2605: IOGetTime( &time ); ! 2606: startTime = endTime = time; ! 2607: waitTime.tv_sec = 0; ! 2608: waitTime.tv_nsec = 250000000; // mlj - make it 250 milliseconds for SONY CD-ROM; ! 2609: ADD_MACH_TIMESPEC( &endTime, &waitTime ); ! 2610: ! 2611: for ( g.shadow.mesh.interrupt = 0; g.shadow.mesh.interrupt == 0; ) ! 2612: { ! 2613: getHBARegsAndClear( clearInterrupts ); ! 2614: ! 2615: IOGetTime( &time ); ! 2616: if ( time.tv_sec < endTime.tv_sec ) ! 2617: continue; ! 2618: if ( time.tv_nsec > endTime.tv_nsec ) ! 2619: { /* It took too long! We're dead. */ ! 2620: PAUSE( 0, 0, 'WFM-', "waitForMesh - MESH chip does not respond to command.\n" ); ! 2621: ioReturn = kIOReturnInternalError; ! 2622: break; ! 2623: } ! 2624: }/* end FOR */ ! 2625: ELG( time.tv_sec - startTime.tv_sec, time.tv_nsec - startTime.tv_nsec, ' WFM', "waitForMesh" ); ! 2626: return ioReturn; ! 2627: }/* end waitForMesh */ ! 2628: ! 2629: ! 2630: /* Send a command to the MESH chip. This may cause an interrupt. */ ! 2631: ! 2632: void meshSCSIController::setSeqReg( MeshCommand meshCommand ) ! 2633: { ! 2634: ELG( (fMESHAddr->interruptMask<<16) | fMESHAddr->interrupt, meshCommand, '=Seq', "setSeqReg" ); ! 2635: ! 2636: if ( fMESHAddr->interruptMask & kMeshIntrCmdDone ! 2637: && meshCommand <= kMeshBusFreeCmd ) ! 2638: ELG( fMESHAddr->interrupt, fMESHAddr->interruptMask, 'Trig', ! 2639: "setSeqReg - may trigger interrupt." ); ! 2640: ! 2641: fMESHAddr->sequence = (UInt8)meshCommand; /***** DO IT *****/ ! 2642: SynchronizeIO(); ! 2643: IODelay( 1 ); /* G3 is too fast */ ! 2644: ! 2645: return; ! 2646: }/* end setSeqReg */ ! 2647: ! 2648: ! 2649: /* Retrieve the MESH volatile register contents, */ ! 2650: /* storing them in the global register shadow. */ ! 2651: /* @param clearInts YES to clear MESH interrupts. */ ! 2652: ! 2653: void meshSCSIController::getHBARegsAndClear( bool clearInts ) ! 2654: { ! 2655: register MeshRegister *mesh = fMESHAddr; ! 2656: ! 2657: ! 2658: g.shadow.mesh.interrupt = mesh->interrupt; ! 2659: g.shadow.mesh.error = mesh->error; ! 2660: g.shadow.mesh.exception = mesh->exception; ! 2661: g.shadow.mesh.FIFOCount = mesh->FIFOCount; ! 2662: ! 2663: g.shadow.mesh.busStatus0 = mesh->busStatus0; ! 2664: g.shadow.mesh.busStatus1 = mesh->busStatus1; ! 2665: g.shadow.mesh.transferCount1 = mesh->transferCount1; ! 2666: g.shadow.mesh.transferCount0 = mesh->transferCount0; ! 2667: ! 2668: g.shadow.mesh.sequence = mesh->sequence; // debugging ! 2669: g.shadow.mesh.interruptMask = mesh->interruptMask; // debugging ! 2670: g.shadow.mesh.syncParms = mesh->syncParms; // debugging ! 2671: g.shadow.mesh.destinationID = mesh->destinationID; // debugging ! 2672: ! 2673: ELG( g.shadow.longWord[ 0 ], g.shadow.longWord[ 1 ], clearInts ? 'Regs' : 'regs', "getHBARegsAndClear." ); ! 2674: ! 2675: if ( g.shadow.mesh.error ) // this occurs when DBDMA -> Seq while reselect ! 2676: { // OR Exc:reselect occurs just before busFree->Seq reg. ! 2677: ELG( g.shadow.mesh.interruptMask, g.shadow.mesh.sequence, 'Err-', ! 2678: "getHBARegsAndClear - MESH error detected" ); ! 2679: mesh->interrupt = kMeshIntrError; ! 2680: SynchronizeIO(); ! 2681: } ! 2682: ! 2683: /* It is possible to have the Reselected bit set in the Exception */ ! 2684: /* register without an Exception bit in the interrupt register. */ ! 2685: /* This may be caused by timing window where we clear the interrupt */ ! 2686: /* register with the interrupt register instead of 0x07. */ ! 2687: /* Handle this by faking an exception. */ ! 2688: /* 04may98 - it is also possible to have PhaseMisMatch set in the */ ! 2689: /* Exception register without Exception indicated in the Interrupt */ ! 2690: /* register. This happened when a Synchronous output finished and */ ! 2691: /* the target went to Message-In phase with Save-Data-Pointer. */ ! 2692: ! 2693: ! 2694: if ( g.shadow.mesh.exception ) ! 2695: g.shadow.mesh.interrupt |= kMeshIntrException; ! 2696: ! 2697: if ( clearInts && g.shadow.mesh.interrupt ) ! 2698: { ! 2699: mesh->interrupt = g.shadow.mesh.interrupt; ! 2700: SynchronizeIO(); ! 2701: } ! 2702: return; ! 2703: }/* end getHBARegsAndClear */ ! 2704: ! 2705: ! 2706: void meshSCSIController::setIntMask( UInt8 mask ) ! 2707: { ! 2708: ELG( (fMESHAddr->interrupt<<16) | fMESHAddr->interruptMask, mask, 'Mask', "setIntMask" ); ! 2709: fMESHAddr->interruptMask = mask; /* enable whatever */ ! 2710: SynchronizeIO(); ! 2711: return; ! 2712: }/* end setIntMask */ ! 2713: ! 2714: ! 2715: void meshSCSIController::abortActiveCommand() ! 2716: { ! 2717: IOReturn ioReturn; ! 2718: ! 2719: ! 2720: ELG( fCmd, 0, '-AB*', "abortActiveCommand" ); ! 2721: if ( fCmd ) ! 2722: { ! 2723: fCmdData->results.returnCode = kIOReturnError; // ??? use kIOAborted? ! 2724: completeCommand(); ! 2725: } ! 2726: ! 2727: getHBARegsAndClear( true ); /* clear possible cmdDone et al */ ! 2728: setIntMask( 0 ); /* Disable MESH interrupts */ ! 2729: ! 2730: fMsgInFlag = 0; /* clear kFlagMsgIn_Reject et al */ ! 2731: ! 2732: fMESHAddr->busStatus0 = kMeshAtn; /***** Raise ATN signal *****/ ! 2733: SynchronizeIO(); ! 2734: ! 2735: setSeqReg( kMeshBusFreeCmd ); /* clear ACK */ ! 2736: waitForMesh( true ); /* wait for PhaseMM */ ! 2737: ! 2738: if ( (g.shadow.mesh.busStatus0 & (kMeshPhaseMask | kMeshReq)) ! 2739: == (kBusPhaseMSGO | kMeshReq) ) ! 2740: { /* this is what we want: */ ! 2741: setSeqReg( kMeshFlushFIFO ); /* Flush the FIFO */ ! 2742: fMESHAddr->transferCount0 = 1; /* set TC low = 1 */ ! 2743: fMESHAddr->transferCount1 = 0; ! 2744: fMESHAddr->busStatus0 = 0; /***** clear ATN signal *****/ ! 2745: SynchronizeIO(); ! 2746: ! 2747: /* Issue the Message Out sending the Abort on its way. */ ! 2748: /* Note that this will cause an Unexpected-Disconnect. */ ! 2749: setSeqReg( kMeshMessageOutCmd ); /* drop ATN signal */ ! 2750: fMESHAddr->xFIFO = kSCSIMsgAbort; /* put out the Abort byte */ ! 2751: ioReturn = waitForMesh( true ); /* wait for cmdDone */ ! 2752: if ( ioReturn == kIOReturnSuccess ) ! 2753: { ! 2754: setSeqReg( kMeshEnableReselect ); /* bus about to go free */ ! 2755: setIntMask( kMeshIntrMask ); /* Enable interrupts */ ! 2756: setSeqReg( kMeshBusFreeCmd ); /* Clr ACK & go Bus-Free */ ! 2757: g.intLevel |= kLevelLatched; /* set latched-int flag */ ! 2758: return; ! 2759: } ! 2760: }/* end IF MSGO phase and REQ is set */ ! 2761: ! 2762: /***** USE THE HAMMER - NUKE THE BUS: *****/ ! 2763: ! 2764: ELG( 0, 0, '-AB-', "abortActiveCommand - target refused to enter MSGO phase" ); ! 2765: resetBus(); ! 2766: super::resetOccurred(); ! 2767: return; ! 2768: }/* end abortActiveCommand */ ! 2769: ! 2770: ! 2771: /* IO associated with fCmd has disconnected. */ ! 2772: /* Place it on the disconnected command queue and */ ! 2773: /* enable another transaction. */ ! 2774: ! 2775: void meshSCSIController::disconnect() ! 2776: { ! 2777: fCmd = NULL; ! 2778: fCmdData = NULL; ! 2779: fCurrentTargetLun.target = kInvalidTarget; ! 2780: fCurrentTargetLun.lun = kInvalidLUN; ! 2781: ! 2782: /* Since there is no active command, the caller */ ! 2783: /* must configure the bus interface to wait for */ ! 2784: /* bus free, then allow reselection. */ ! 2785: ! 2786: return; ! 2787: }/* end disconnect */ ! 2788: ! 2789: ! 2790: /* The specified target, LUN, and queueTag is trying to reselect. */ ! 2791: /* If we have a xxxCommandBuffer for this TLQ nexus on disconnectQ, */ ! 2792: /* remove it, make it the current fCmd, and return YES. */ ! 2793: /* Else return NO. A value of zero for queueTag indicates a */ ! 2794: /* nontagged command (zero is never used as the queue tag value for */ ! 2795: /* a tagged command). */ ! 2796: ! 2797: IOReturn meshSCSIController::reselectNexus() ! 2798: { ! 2799: fCmd = findCommandWithNexus( fCurrentTargetLun, fTag ); ! 2800: if ( fCmd ) ! 2801: { fCmdData = (PrivCmdData*)fCmd->getCommandData(); ! 2802: ELG( fCmd, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, '=Nex', "reselectNexus" ); ! 2803: return kIOReturnSuccess; ! 2804: } ! 2805: else ! 2806: { if ( fTag != kInvalidTag ) ! 2807: PAUSE( 0, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, 'Nex-', "reselectNexus" ); ! 2808: } ! 2809: ! 2810: return kIOReturnInternalError; ! 2811: }/* end reselectNexus */ ! 2812: ! 2813: ! 2814: void meshSCSIController::updateCurrentIndex() ! 2815: { ! 2816: UInt32 count; /* DMA transfer count */ ! 2817: UInt32 length = g.shadow.mesh.FIFOCount; ! 2818: UInt8 buffer[ 16 ]; ! 2819: UInt32 i; ! 2820: ! 2821: ! 2822: /* Calculate the number of bytes xferred by this channel command. */ ! 2823: /* We don't trust the DBDMA residual count. */ ! 2824: ! 2825: count = *(UInt32*)&fCCL[ kcclBatchSize ]; /* Our transfer count */ ! 2826: if ( count == 0 ) /* If batch is empty, */ ! 2827: return; /* look at nothing else.*/ ! 2828: count -= g.shadow.mesh.transferCount1 << 8; /* MESH residual high */ ! 2829: count -= g.shadow.mesh.transferCount0; /* MESH residual low */ ! 2830: fCmdData->results.bytesTransferred += count; /* Increment data index */ ! 2831: *(UInt32*)&fCCL[ kcclBatchSize ] = 0; /* Clear DBDMA count */ ! 2832: ! 2833: if ( fReadAlignmentCount ) // Hack for Radar 1670626 ! 2834: { ! 2835: fCmdData->mdp->writeBytes( fReadAlignmentIndex, &fCCL[ kcclReadBuf8 ], fReadAlignmentCount ); ! 2836: fReadAlignmentCount = 0; ! 2837: } ! 2838: ! 2839: /* Check the FIFO, if empty, increment the current data pointer. */ ! 2840: /* If there is stuff in it, we have more work to do. */ ! 2841: ! 2842: if ( g.shadow.mesh.FIFOCount ) /* If data in FIFO: */ ! 2843: { ! 2844: /* We didn't process these bytes in the FIFO - adjust index */ ! 2845: fCmdData->results.bytesTransferred -= g.shadow.mesh.FIFOCount; ! 2846: ! 2847: if ( fCmdData->isWrite ) /* If Writing: */ ! 2848: { ! 2849: setSeqReg( kMeshFlushFIFO ); ! 2850: } ! 2851: else /* Must be Reading: */ ! 2852: { /* On a Read with data left in the FIFO, we must copy */ ! 2853: /* the FIFO directly into the user's data buffer: */ ! 2854: ! 2855: ELG( fCmdData->results.bytesTransferred, g.shadow.mesh.FIFOCount, 'FIFO', ! 2856: "updateCurrentIndex - copy FIFO to user buffer." ); ! 2857: count = fCmdData->xferCount - fCmdData->results.bytesTransferred; ! 2858: if ( count > length ) ! 2859: count = length; ! 2860: ! 2861: /* FYI - emptying the FIFO causes cmdDone to get set. */ ! 2862: ! 2863: for ( i = 0; i < count; i++ ) ! 2864: buffer[ i ] = fMESHAddr->xFIFO; ! 2865: ! 2866: fCmdData->mdp->writeBytes( fCmdData->results.bytesTransferred, buffer, count ); ! 2867: ! 2868: fCmdData->results.bytesTransferred += count; ! 2869: }/* end if/ELSE must be Reading */ ! 2870: }/* end IF FIFO was not empty */ ! 2871: ! 2872: ELG( 0, fCmdData->results.bytesTransferred, 'UpIx', "updateCurrentIndex" ); ! 2873: return; ! 2874: }/* end updateCurrentIndex */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.