Annotation of XNU/iokit/Drivers/scsi/drvCurio/curio.cpp, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.