Annotation of XNU/iokit/Drivers/scsi/drvMESH/mesh.cpp, revision 1.1

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

unix.superglobalmegacorp.com

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