Annotation of XNU/iokit/Drivers/scsi/drvCurio/curio.cpp, revision 1.1.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.