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

1.1       root        1: /*
                      2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: 
                     23:     /**
                     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.