Annotation of kernel/bsd/dev/ppc/drvAppleMesh_SCSI/MESH_DBDMA.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25:     /**
                     26:      * Copyright (c) 1994-1996 NeXT Software, Inc.  All rights reserved.
                     27:      * Copyright 1993-1995 by Apple Computer, Inc., all rights reserved.
                     28:      * Copyright 1997-1998 Apple Computer Inc. All Rights Reserved.
                     29:      * @author    Martin Minow  mailto:[email protected]
                     30:      * @revision  1997.02.13    Initial conversion from Copland sources.
                     31:      *
                     32:      * Set tabs every 4 characters.
                     33:      *
                     34:      * Edit History
                     35:      * 1997.02.25   MM      Initial conversion from Copland sources.
                     36:      */
                     37: 
                     38: #import <sys/systm.h>
                     39: #import <driverkit/generalFuncs.h>
                     40: #import <driverkit/kernelDriver.h>
                     41: #import <driverkit/align.h>
                     42: #import <driverkit/interruptMsg.h>
                     43: #import <driverkit/scsiTypes.h>
                     44: #import <driverkit/debugging.h>
                     45: #import <driverkit/IODirectDevice.h>
                     46: #import <driverkit/IOMemoryDescriptor.h>
                     47: #import <driverkit/IOSimpleMemoryDescriptor.h>
                     48: #import <driverkit/IOSCSIController.h>
                     49: #import <driverkit/IOPower.h>
                     50: #import <driverkit/return.h>
                     51: #import <bsd/dev/scsireg.h>
                     52: #import <mach/kern_return.h>
                     53: #import <mach/mach_interface.h>
                     54: #import <mach/message.h>
                     55: #import <machkit/NXLock.h>
                     56: #import <machdep/ppc/proc_reg.h>
                     57: #import <machdep/ppc/powermac.h>
                     58: #import <machdep/ppc/interrupts.h>
                     59: #import <machdep/ppc/dbdma.h>
                     60: #import <kernserv/prototypes.h>
                     61: #import <objc/objc.h>
                     62: 
                     63:     extern void             flush_cache_v( vm_offset_t pa, unsigned length );       /* Should be available from kernel headers! */
                     64: //  extern void             invalidate_cache_v( vm_offset_t pa, unsigned length );
                     65:     extern void             kprintf( const char *, ... );
                     66:     extern kern_return_t    msg_send_from_kernel( msg_header_t*, int, int );
                     67: 
                     68: 
                     69: #import "MESH_DBDMA.h"
                     70: 
                     71: #undef  ASSERT
                     72: #define ASSERT(x)
                     73: 
                     74: #if CustomMiniMon
                     75:     extern globals      g;  /**** Use custom MiniMon's globals   ****/
                     76:     extern UInt32       gMESH_DBDMA, gMESH_DBDMA_Phys;
                     77: #else
                     78:     globals             g;      /**** Instantiate the globals ****/
                     79: #endif /* CustomMiniMon */
                     80: 
                     81: 
                     82: 
                     83:     /* Channel Program. Note that this script must match the offsets    */
                     84:     /* specified in AppleMeshDefinitions.h. This script is copied into  */
                     85:     /* the channel command area (with appropriate entries byte-swapped  */
                     86:     /* so it ends up with the correct endian-ness).                     */
                     87:     /* Lines beginning with "slash, star, star, slash" are modified     */
                     88:     /* by the driver before it starts the Channel Program.              */
                     89: 
                     90: const DBDMADescriptor   gDescriptorList[] =
                     91: {
                     92:             /* 0x00 kcclProblem - Branch here for anomalies */
                     93: 
                     94:     {   MESH_REG( kMeshInterruptMask, kMeshIntrMask )   },  // Enable MESH interrupt
                     95:     {   STOP( kcclStageCCLx )                           },  // anomaly
                     96: 
                     97:             /* 0x20 through 0x60 - Data for information phases: */
                     98: 
                     99:     {   RESERVE                                         },  // kcclCMDOdata - CDB ( 6,10,12,16 bytes)
                    100:     {   RESERVE                                         },  // kcclMSGOdata - MSGO data (last byte @3F)
                    101:     {   RESERVE                                         },  // kcclMSGIdata - MSGI data & STATUS
                    102:     {   RESERVE                                         },  // kcclSenseCDB - CDB for (auto) Sense
                    103:     {   RESERVE                                         },  // kcclBatchSize, kcclStageLabel
                    104: 
                    105:             /* 0x70 - kcclSense - AutoSense input:  */
                    106: 
                    107:     {   MESH_REG( kMeshTransferCount1,  0x00 )          },  // set MESH xfer count to 255
                    108:     {   MESH_REG( kMeshTransferCount0,  kMaxAutosenseByteCount & 0xFF )},
                    109:     {   MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA )},// Data-In to Seq register
                    110:     {   SENSE( kMaxAutosenseByteCount )                 },  // Sense INPUT
                    111:     {   BRANCH( kcclGetStatus )                         },  // do finish sequence
                    112: 
                    113:             /* 0xC0 - kcclPrototype - Prototype MESH 4-command Transfer sequence:   */
                    114: 
                    115:     {   MOVE_4( kcclBatchSize, 0, kRelAddressCP )       },  // MESH batch size
                    116:     {   MESH_REG( kMeshTransferCount1, 0 )              },  // Set high order Transfer Count
                    117:     {   MESH_REG( kMeshTransferCount0, 0 )              },  // Set low order Transfer Count
                    118:     {   MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA )},  // Assume Data-In
                    119: 
                    120:     {   RESERVE                                         },  // spare
                    121:     {   RESERVE                                         },  // spare
                    122: 
                    123:             /* 0x120 kcclStart - Arbitrate (START CHANNEL PROGRAM HERE):    */
                    124:             /* 0x140 kcclBrProblem                                          */
                    125: 
                    126:     {   STAGE( kcclStageArb )                           },
                    127:     {   MESH_REG( kMeshSequence, kMeshArbitrateCmd )    },  // issue Arbitrate
                    128:     {   BR_IF_PROBLEM                                   },  // branch if exception or error
                    129: 
                    130:             /* 0x150 - Select with Attention:  */
                    131: 
                    132:     {   STAGE( kcclStageSelA )                          },
                    133:     {   CLEAR_CMD_DONE                                  },
                    134:     {   MESH_REG( kMeshSequence, kMeshSelectCmd | kMeshSeqAtn ) },  // select with attention
                    135:     {   BR_IF_PROBLEM                                   },  // branch if failed
                    136: 
                    137:             /* 0x190 kcclMsgoStage- Message-Out:    */
                    138: 
                    139:     {   STAGE( kcclStageMsgO )                          },
                    140:     {   CLEAR_CMD_DONE                                  },
                    141: 
                    142:             /* 0x1B0 kcclMsgoBranch - modify this BRANCH to fall through for multibyte messages:    */
                    143: 
                    144: /**/{   BRANCH( kcclLastMsgo )                          },  // kcclMsgoBranch - go do only byte of Msg
                    145: 
                    146:             /* 0x1C0 - do all but last byte of multibyte message:  */
                    147: 
                    148:     {   MESH_REG( kMeshTransferCount1,  0x00 )          },  // count does include last byte
                    149: /**/{   MESH_REG( kMeshTransferCount0,  0xFF )          },  // kcclMsgoMTC - modify MESH xfer count here
                    150:     {   MESH_REG( kMeshSequence, kMeshMessageOutCmd | kMeshSeqAtn | kMeshSeqDMA )   },  // DMA MsgO with ATN
                    151: /**/{   MSGO( kcclMSGOdata, 255 )                       },  // kcclMsgoDTC - output all but last byte
                    152:     {   CLEAR_CMD_DONE                                  },
                    153: 
                    154:             /* 0x210 kcclLastMsgo - wait for REQ signal before dropping ATN:    */
                    155: 
                    156:     {   MESH_REG( kMeshInterruptMask, 0 )               },  // inhibit MESH interrupt
                    157:     {   MESH_REG_WAIT( kMeshSequence, kMeshStatusCmd | kMeshSeqAtn ) }, // gen PhaseMM
                    158:     {   CLEAR_INT_REG                                   },  // clear PhaseMM & CmdDone
                    159:     {   MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) },  // re-enable ERR/EXC Ints
                    160: 
                    161:             /* 0x250 - put out the last or only byte of Message-Out phase:  */
                    162: 
                    163:     {   MESH_REG( kMeshTransferCount1,  0x00 )          },
                    164:     {   MESH_REG( kMeshTransferCount0,  0x01 )          },
                    165:     {   MESH_REG( kMeshSequence, kMeshMessageOutCmd | kMeshSeqDMA ) },// no more ATN
                    166:     {   MSGO( kcclMSGOLast, 1 )                         },
                    167: 
                    168:             /* 0x290 kcclCmdoStage - Command Out:  */
                    169: 
                    170:     {   STAGE( kcclStageCmdO )                          },
                    171:     {   CLEAR_CMD_DONE                                  },
                    172:     {   MESH_REG( kMeshTransferCount1,  0x00 )          },
                    173: /**/{   MESH_REG( kMeshTransferCount0,  0x06 )          },  // kcclCmdoMTC - Set MESH xfer count to 6
                    174:     {   MESH_REG( kMeshSequence, kMeshCommandCmd | kMeshSeqDMA )},  // Command phase with DMA on
                    175: /**/{   CMDO( 6 )                                       },  // kcclCmdoDTC - output the CDB
                    176: 
                    177:             /* 0x2F0 - DATA XFER - branch to the built CCL @ 0x05D0:    */
                    178:             /* also, kcclReselect - reselect code enters here:          */
                    179: 
                    180:     {   CLEAR_CMD_DONE                                  },
                    181:     {   STAGE( kcclStageXfer )                          },
                    182:     {   BRANCH( kcclDataXfer )                          },  // go do Xfer CCL
                    183: 
                    184:             /* 0x320 kcclOverrun - dump excess data in the bit bucket:  */
                    185:             /* Exc and Err are still disabled.                          */
                    186: 
                    187:     {   STAGE( kcclStageBucket )                        },
                    188:     {   MESH_REG( kMeshTransferCount1,  0x00 )          },  // set MESH Transfer Count to max
                    189:     {   MESH_REG( kMeshTransferCount0,  0x00 )          },
                    190:     {   CLR_PHASEMM                                     },
                    191:     {   MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) },  // re-enable ERR/EXC Ints
                    192: /**/{   MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA ) }, // set Seq Reg
                    193: /**/{   BUCKET                                          },  // OUT/INPUT_LAST the bits
                    194:     {   BR_NO_PROBLEM( kcclOverrunDBDMA )               },  // loop til PhaseMismatch
                    195:     {   BR_IF_PROBLEM                                   },  // take the interrupt now
                    196: 
                    197:             /* 0x3B0 kcclSyncCleanUp - clean up after Sync xfer:  */
                    198:     {   CLEAR_INT_REG                                   },  // clear PhaseMM & CmdDone (& Err?)
                    199:     {   MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) },  // re-enable ERR/EXC Ints
                    200: 
                    201:             /* 0x3D0 kcclGetStatus - setup CCL for status, command complete and bus free:   */
                    202: 
                    203:     {   STAGE( kcclStageStat )                          },
                    204:     {   MESH_REG( kMeshTransferCount1,  0x00 )          },
                    205:     {   MESH_REG( kMeshTransferCount0,  0x01 )          },  // set MESH xfer count to 1
                    206:     {   MESH_REG( kMeshSequence, kMeshStatusCmd | kMeshSeqDMA )},// Status-in phase with DMA on
                    207:     {   STATUS_IN                                       },  // input the status byte
                    208: 
                    209:             /* 0x420 - Message In:  */
                    210: 
                    211:     {   STAGE( kcclStageMsgI )                          },
                    212:     {   CLEAR_CMD_DONE                                  },
                    213:     {   MESH_REG( kMeshTransferCount1, 0x00 )           },
                    214:     {   MESH_REG( kMeshTransferCount0, 0x01 )           },  // set MESH xfer count to 1
                    215:     {   MESH_REG( kMeshSequence, kMeshMessageInCmd | kMeshSeqDMA )},   // Status-in phase with DMA on
                    216:     {   MSGI( 1 )                                       },  // get the Message-In byte
                    217: 
                    218:             /* 0x480 - Bus Free:   */
                    219: 
                    220:     {   STAGE( kcclStageFree )                          },
                    221:     {   CLEAR_CMD_DONE                                  },
                    222:     {   MESH_REG( kMeshSequence, kMeshEnableReselect )  },  // Enable Reselect
                    223:     {   MESH_REG( kMeshSequence, kMeshBusFreeCmd )      },  // Bus Free phase
                    224:     {   BR_IF_PROBLEM                                   },  // branch if failed
                    225: 
                    226:             /* 0x4D0 kcclMESHintr - Good completion:    */
                    227: 
                    228:     {   STAGE( kcclStageGood )                          },
                    229:     {   MESH_REG( kMeshInterruptMask, kMeshIntrMask )   },  // latch MESH interrupt
                    230:     {   STOP( kcclStageStop )                           },  // Stop
                    231: 
                    232:         /* The rest of the Channel Program area is used for autosense   */
                    233:         /* and data transfer channel commands:                          */
                    234:         /*  kcclSenseBuffer Autosense area                              */
                    235:         /*  kcclDataXfer    Start of data transfer channel commands     */
                    236:         /*  kcclSenseResult Autosense result stored here                */
                    237: 
                    238: }; /* end gDescriptorList structure */
                    239: 
                    240:     const UInt32 gDescriptorListSize = sizeof( gDescriptorList );
                    241: 
                    242:     enum                       /* values for g.intLevel:                */
                    243:     {
                    244:         kLevelISR       = 0x80, /* In Interrupt Service Routine         */
                    245:         kLevelLocked    = 0x40, /* MESH interrupts locked out           */
                    246:         kLevelSIH       = 0x20, /* In Secondary Interrupt Handler       */
                    247:         kLevelLatched   = 0x10  /* Interrupt latched                    */
                    248:     };
                    249: 
                    250: 
                    251: //  IONamedValue    scsiChipRegisterStrings[] = { { 0, NULL, } };
                    252: 
                    253:     static int          getConfigParam( id configTable, const char *paramName );
                    254:     static unsigned int GetSCSICommandLength( const cdb_t *cdbPtr, unsigned int defaultLength );
                    255: 
                    256: 
                    257:         /* MAX_DMA_XFER is set so that we don't have to worry about the     */
                    258:         /* ambiguous "zero" value in the MESH and DBDMA transfer registers  */
                    259:         /* that can mean either 65536 bytes or zero bytes.                  */
                    260: 
                    261: #define MAX_DMA_XFER    0x0000F000
                    262: 
                    263: #define ONE_SECOND      1    /* for IOScheduleFunc and serviceTimeoutInterrupt */
                    264: 
                    265:         /*  Template for command message sent to the IO thread: */
                    266: 
                    267:     static const msg_header_t     cmdMessageTemplate =
                    268:     {
                    269:         0,                          /* msg_unused                   */
                    270:         1,                          /* msg_simple                   */
                    271:         sizeof( msg_header_t ),     /* msg_size                     */
                    272:         MSG_TYPE_NORMAL,            /* msg_type                     */
                    273:         PORT_NULL,                  /* msg_local_port               */
                    274:         PORT_NULL,                  /* msg_remote_port - filled in  */
                    275:         IO_COMMAND_MSG              /* msg_id                       */
                    276:     };
                    277:     
                    278:         /* Template for timeout message.    */
                    279:     
                    280:     static const msg_header_t     gTimeoutMsgTemplate =
                    281:     {
                    282:         0,                          /* msg_unused                   */
                    283:         1,                          /* msg_simple                   */
                    284:         sizeof( msg_header_t ),     /* msg_size                     */
                    285:         MSG_TYPE_NORMAL,            /* msg_type                     */
                    286:         PORT_NULL,                  /* msg_local_port               */
                    287:         PORT_NULL,                  /* msg_remote_port - filled in  */
                    288:         IO_TIMEOUT_MSG              /* msg_id                       */
                    289:     };
                    290: 
                    291:     static port_t           gKernelInterruptPort;   /* for int/timeout msgs */
                    292: 
                    293:     static void             serviceTimeoutInterrupt( void *arg );
                    294:     static AppleMesh_SCSI   *gInstance;
                    295: 
                    296: 
                    297: #if USE_ELG && !CustomMiniMon
                    298: void AllocateEventLog( UInt32 size )
                    299: {
                    300:     if ( !g.evLogBuf )  g.evLogBuf = (UInt8*)kalloc( size );
                    301:     if ( !g.evLogBuf )
                    302:         kprintf( "probe - MESH evLog allocation failed " );
                    303: 
                    304:     g.evLogFlag = 0;            /* assume insufficient memory   */
                    305:     g.evLogBufp = g.evLogBuf;
                    306: 
                    307:     if ( g.evLogBuf )
                    308:     {
                    309:         g.evLogBufe  = g.evLogBufp + kEvLogSize - 0x20; // ??? overran buffer?
                    310:         g.evLogFlag  = 0xFEEDBEEF;
                    311:     //  g.evLogFlag  = 0x0333;
                    312:     }
                    313:     return;
                    314: }/* end AllocateEventLog */
                    315: 
                    316: 
                    317: void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
                    318: {
                    319:     register UInt32     *lp;           /* Long pointer      */
                    320:     ns_time_t           time;
                    321: 
                    322:     if ( g.evLogFlag == 0 )
                    323:         return;
                    324: 
                    325:     IOGetTimestamp( &time );
                    326: 
                    327:     lp = (UInt32*)g.evLogBufp;
                    328:     g.evLogBufp += 0x10;
                    329: 
                    330:     if ( g.evLogBufp >= g.evLogBufe )       /* handle buffer wrap around if any */
                    331:     {    g.evLogBufp  = g.evLogBuf;
                    332:         if ( g.evLogFlag != 0xFEEDBEEF )    // make 0xFEEDBEEF a symbolic ???
                    333:             g.evLogFlag = 0;                /* stop tracing if wrap undesired   */
                    334:     }
                    335: 
                    336:         /* compose interrupt level with 3 byte time stamp:  */
                    337: 
                    338:     *lp++ = (g.intLevel << 24) | ((time >> 10) & 0x003FFFFF);   // ~ 1 microsec resolution
                    339:     *lp++ = a;
                    340:     *lp++ = b;
                    341:     *lp   = ascii;
                    342: 
                    343:     if( g.evLogFlag == 'step' )
                    344:         kprintf( str );
                    345: 
                    346:     return;
                    347: }/* end EvLog */
                    348: 
                    349: 
                    350: void Pause( UInt32 a, UInt32 b, UInt32 ascii, char* str )
                    351: {
                    352:     char        work [256 ];
                    353:     char        name[] = "AppleMeshSCSI:";
                    354:     char        *bp = work;
                    355:     UInt8       x;
                    356:     int         i;
                    357: 
                    358: 
                    359:     EvLog( a, b, ascii, str );
                    360:     EvLog( '****', '** P', 'ause', "*** Pause" );
                    361: 
                    362:     bcopy( name, bp, sizeof( name ) );
                    363:     bp += sizeof( name ) - 1;
                    364: 
                    365:     *bp++ = '{';                               // prepend p1 in hex:
                    366:     for ( i = 7; i >= 0; --i )
                    367:     {
                    368:         x = a & 0x0F;
                    369:         if ( x < 10 )
                    370:              x += '0';
                    371:         else x += 'A' - 10;
                    372:         bp[ i ] = x;
                    373:         a >>= 4;
                    374:     }
                    375:     bp += 8;
                    376: 
                    377:     *bp++ = ' ';                               // prepend p2 in hex:
                    378: 
                    379:     for ( i = 7; i >= 0; --i )
                    380:     {
                    381:         x = b & 0x0F;
                    382:         if ( x < 10 )
                    383:              x += '0';
                    384:         else x += 'A' - 10;
                    385:         bp[ i ] = x;
                    386:         b >>= 4;
                    387:     }
                    388:     bp += 8;
                    389:     *bp++ = '}';
                    390: 
                    391:     *bp++ = ' ';
                    392: 
                    393:     for ( i = sizeof( work ) - (int)(bp - work); i && (*bp++ = *str++); --i )   ;
                    394: 
                    395:     kprintf( work );
                    396: //  call_kdp();         // ??? use kdp=3 in boot parameters
                    397:     return;
                    398: }/* end Pause */
                    399: #endif /* not CustomMiniMon */
                    400: 
                    401: 
                    402:     /* serviceTimeoutInterrupt - Handle timeouts.                         */
                    403:     /* This  function is invoked in kernel context on a DriverKit thread. */
                    404:     /* Just send a timeout message to the IO thread to wake it up.        */
                    405: 
                    406: static void serviceTimeoutInterrupt( void *arg )
                    407: {
                    408:     msg_header_t    msg = gTimeoutMsgTemplate;
                    409: 
                    410: 
                    411:     ELG( 0, 0, 'Tick', "serviceTimeoutInterrupt\n" );
                    412: 
                    413:          /* roll me another one: */
                    414:     IOScheduleFunc( serviceTimeoutInterrupt, (void*)0x333, ONE_SECOND );
                    415: 
                    416:         /* Tell the IO thread: */
                    417:     msg.msg_remote_port = gKernelInterruptPort;
                    418:     msg_send_from_kernel( &msg, MSG_OPTION_NONE, 0 );
                    419:     return;
                    420: }/* end serviceTimeoutInterrupt */
                    421: 
                    422: 
                    423:     /* Used in timeoutOccurred to determine if specified cmdBuf has timed out.  */
                    424:     /* Returns YES if timeout, else NO.                                         */
                    425: 
                    426: static Boolean isCmdTimedOut( CommandBuffer *cmdBuf )
                    427: {
                    428:     IOSCSIRequest   *scsiReq = cmdBuf->scsiReq;
                    429:     ns_time_t       now, expire;
                    430:     Boolean         result;
                    431: 
                    432: 
                    433:     IOGetTimestamp( &now );
                    434:     expire  = cmdBuf->startTime +
                    435:                 (1000000000ULL * (unsigned long long)scsiReq->timeoutLength);
                    436:     result = (now > expire);
                    437:     if ( result ) ELG( cmdBuf, cmdBuf->scsiReq->timeoutLength, 'Tim-', "isCmdTimedOut" );
                    438:     return  result;
                    439: }/* end isCmdTimedOut */
                    440: 
                    441: 
                    442:     /* Implement the public methods for the MESH controller. */
                    443: 
                    444: @implementation AppleMesh_SCSI
                    445: 
                    446:     /* Create and initialize one instance of AppleMesh_SCSI.        */
                    447:     /* The work is done by architecture- and chip-specific modules. */
                    448: 
                    449: + (Boolean) probe : deviceDescription
                    450: {
                    451:     Boolean     result;
                    452: 
                    453: 
                    454:     gInstance   = [ self alloc ];   /* Instantiate yourself   */
                    455:     g.intLevel  = 0;
                    456: 
                    457:     MakeTimestampRecord( 512 );     /* conditionally compiled */
                    458: 
                    459: #if USE_ELG
                    460:     AllocateEventLog( kEvLogSize );
                    461:     ELG( g.evLogBufp, &g.evLogFlag, 'Prob', "probe - event logging set up.\n" );
                    462: #endif /* USE_ELG */
                    463: 
                    464:         /* Perform device-specific initialization. */
                    465:         /* Free the instance on failure.           */
                    466: 
                    467:     if ( [ gInstance InitializeHardware : deviceDescription ] == nil )
                    468:          result = NO;
                    469:     else result = YES;
                    470: 
                    471:     return result;
                    472: }/* end probe */
                    473: 
                    474: 
                    475:     /* The driver is shutting down. Kill everything worth killing.  */
                    476: 
                    477: - free
                    478: {
                    479:     CommandBuffer  cmdBuf;
                    480: 
                    481: 
                    482:         /* First kill the IO thread if running. */
                    483: 
                    484:     if ( gFlagIOThreadRunning )
                    485:     {
                    486:         cmdBuf.op       = kCommandAbortRequest;
                    487:         cmdBuf.scsiReq  = NULL;
                    488:         [ self executeCmdBuf : &cmdBuf ];
                    489:     }
                    490: 
                    491:     if (  incomingCmdLock )
                    492:         [ incomingCmdLock free ];
                    493: 
                    494:     dbdma_stop( DBDMA_MESH_SCSI );
                    495: 
                    496:     if ( cclLogAddr )
                    497:     {
                    498:         IOFree( cclLogAddr, cclLogAddrSize );
                    499:         cclLogAddr = NULL;
                    500:     }
                    501:         /* ??? Unmap physical address mapping to registers. */
                    502: 
                    503:     return [ super free ];
                    504: }/* end free */
                    505: 
                    506: 
                    507:     /* Return required DMA alignment for current architecture.              */
                    508:     /* We specify 8-byte alignment to avoid a bug in the Grand Central chip:*/
                    509:     /*  if (Reading                                                         */
                    510:     /*   && (kdbdmaSetFlush || kdbdmaClrRun)                                */
                    511:     /*   && no bytes transferred yet                                        */
                    512:     /*   && buffer not 8-byte aligned)                                      */
                    513:     /*  {                                                                   */
                    514:     /*      THEN memory in front of buffer will be trashed.                 */
                    515:     /*  }                                                                   */
                    516: 
                    517: - (void) getDMAAlignment : (IODMAAlignment*)alignment
                    518: {
                    519:     alignment->readStart   = DBDMA_ReadStartAlignment;
                    520:     alignment->writeStart  = DBDMA_WriteStartAlignment;
                    521:     alignment->readLength  = 0;
                    522:     alignment->writeLength = 0;
                    523:     return;
                    524: }/* end getDMAAlignment */
                    525: 
                    526: 
                    527:     /* Statistics support.  */
                    528: 
                    529: - (unsigned int) numQueueSamples
                    530: {
                    531:     return gTotalCommands;
                    532: }/* end numQueueSamples */
                    533: 
                    534: 
                    535: - (unsigned int) sumQueueLengths
                    536: {
                    537:     return gQueueLenTotal;
                    538: }/* end sumQueueLengths */
                    539: 
                    540: 
                    541: - (unsigned int) maxQueueLength
                    542: {
                    543:     return gMaxQueueLen;
                    544: }/* end maxQueueLength */
                    545: 
                    546: 
                    547: - (void) resetStatistics
                    548: {
                    549:     gMaxQueueLen    = 0;
                    550:     gQueueLenTotal  = 0;
                    551:     gMaxQueueLen    = 0;
                    552:     return;
                    553: }/* resetStatistics */
                    554: 
                    555: 
                    556:     /* Do a SCSI command, as specified by an IOSCSIRequest.                 */
                    557:     /* All the work is done by the IO thread.                               */
                    558:     /* @param   scsiReq     The request to execute                          */
                    559:     /* @param   buffer      The data buffer to transfer to/from, if any     */
                    560:     /* @param   client      The data buffer owner task (for VM munging)     */
                    561:     /*                                                                      */
                    562:     /* This method is called from IOSCSIDevice                              */
                    563: - (sc_status_t) executeRequest  : (IOSCSIRequest*)scsiReq
                    564:                         buffer  : (void*)buffer 
                    565:                         client  : (vm_task_t)client
                    566: {
                    567:     IOMemoryDescriptor  *mem        = NULL;
                    568:     sc_status_t         scsiStatus  = SR_IOST_GOOD;     /* Fool compiler */
                    569: 
                    570: 
                    571:     ELG( scsiReq->lun<<16 | scsiReq->target, scsiReq, 'sReq', "executeRequest (buffer)" );
                    572:     ELG( buffer, scsiReq->maxTransfer, 'Buff', "executeRequest" );
                    573: 
                    574:         /* Create a simple IO memory descriptor for this client,    */
                    575:         /* then toss it to the common method.                       */
                    576: 
                    577:     if ( buffer )
                    578:     {
                    579:         if ( scsiReq->read && ((UInt32)buffer & (DBDMA_ReadStartAlignment - 1)) )
                    580:         {
                    581:             ELG( scsiReq->maxTransfer, buffer, 'Aln-', "executeRequest/simple buffer - unaligned read buffer." );
                    582:             return SR_IOST_ALIGN;
                    583:         }
                    584:         mem = [ [ IOSimpleMemoryDescriptor alloc ]
                    585:                                     initWithAddress : (void*)buffer
                    586:                                     length          : scsiReq->maxTransfer ];
                    587:         [ mem setClient : client ];
                    588:     }
                    589: 
                    590:     scsiStatus = [ self executeRequest : scsiReq    ioMemoryDescriptor : mem ];
                    591: 
                    592:     if (  mem )
                    593:         [ mem release ];
                    594: 
                    595:     return scsiStatus;
                    596: }/* end executeRequest buffer */
                    597: 
                    598: 
                    599:     /* Execute a SCSI request using an IOMemoryDescriptor.      */
                    600:     /* This allows callers to provide (kernel-resident) logical */
                    601:     /* scatter-gather lists. For compatibility with existing    */
                    602:     /* implementations, the low-level SCSI device driver must   */
                    603:     /* first ensure that executeRequestWithIOMemoryDescriptor   */
                    604:     /* is supported by executing:                               */
                    605:     /*  [ controller respondsToSelector : executeRequestWithIOMemoryDescriptor ]    */
                    606: 
                    607: - (sc_status_t) executeRequest  : (IOSCSIRequest*)scsiReq
                    608:             ioMemoryDescriptor  : (IOMemoryDescriptor*)ioMemoryDescriptor
                    609: {
                    610:     CommandBuffer    commandBuffer;
                    611: 
                    612: 
                    613:     ELG( scsiReq->lun<<16 | scsiReq->target, scsiReq, 'dReq', "executeRequest (IOMemoryDescriptor)" );
                    614:     ELG( 0, ioMemoryDescriptor, 'iomd', "executeRequest" );
                    615: 
                    616:     scsiReq->driverStatus = SR_IOST_INVALID;   /* "In progress" */
                    617:     if ( ioMemoryDescriptor )
                    618:     {
                    619:         [ ioMemoryDescriptor setMaxSegmentCount : MAX_DMA_XFER ];
                    620:         [ ioMemoryDescriptor state : &commandBuffer.savedDataState ];
                    621:     }
                    622:     bzero( &commandBuffer, sizeof( CommandBuffer ) );
                    623:     commandBuffer.op            = kCommandExecute;
                    624:     commandBuffer.scsiReq       = scsiReq;
                    625:     commandBuffer.mem           = ioMemoryDescriptor;
                    626: 
                    627:     [ self executeCmdBuf : &commandBuffer ];
                    628: 
                    629: #if TIMESTAMP_AT_IOCOMPLETE
                    630:     [ self logTimestamp : "IO complete" ];      /* After RESULT macro   */
                    631: #endif
                    632: 
                    633:     return commandBuffer.scsiReq->driverStatus;
                    634: }/* end executeRequest IOMemoryDescriptor */
                    635: 
                    636: 
                    637:     /* Reset the SCSI bus. All the work is done by the IO thread.   */
                    638: 
                    639: - (sc_status_t) resetSCSIBus
                    640: {
                    641:     CommandBuffer   commandBuffer;
                    642: 
                    643: 
                    644:     commandBuffer.op        = kCommandResetBus;
                    645:     commandBuffer.scsiReq   = NULL;
                    646: 
                    647:     [ self executeCmdBuf : &commandBuffer ];
                    648:     return  SR_IOST_GOOD;           /* can not fail */
                    649: }/* end resetSCSIBus */
                    650: 
                    651: 
                    652:     /* The following 6 methods,                                             */
                    653:     /*     interruptOccurred, interruptOccurredAt, otherOccurred,           */
                    654:     /*     receiveMsg, timeoutOccurred, commandRequestOccurred,             */
                    655:     /* are all called from the IO thread in IODirectDevice.                 */
                    656: 
                    657:     /* Called from the IO thread when it receives an interrupt message.     */
                    658:     /* Currently all work is done by chip-specific module; maybe we should  */
                    659:     /* put this method there....                                            */
                    660: 
                    661: - (void) interruptOccurred
                    662: {
                    663:     g.intLevel |=  kLevelISR;                               /* set ISR flag     */
                    664:     g.intLevel &= ~kLevelLatched;                           /* clear latched    */
                    665:     ELG( dbdmaAddr->d_status, dbdmaAddr->d_cmdptrlo, 'Int+', "interruptOccurred." );
                    666: //  ELG( *(UInt32*)0xF3000024, *(UInt32*)0xF300002C, 'Int ', "interruptOccurred." );
                    667: 
                    668:     [ self DoHardwareInterrupt ];      /**** HANDLE THE INTERRUPT  ****/
                    669: 
                    670: //  ELG( gActiveCommand, *(UInt32*)0xF300002C, 'Intx', "interruptOccurred." );
                    671: 
                    672:     g.intLevel &= ~kLevelISR;                  /* clear ISR flag    */
                    673:     return;
                    674: }/* end interruptOccurred */
                    675: 
                    676: 
                    677:     /* These three should not occur; they are here as error traps.  */
                    678:     /* All three are called out from the IO thread upon receipt of  */
                    679:     /* messages which it should not be seeing.                      */
                    680: 
                    681: - (void) interruptOccurredAt : (int)localNum
                    682: {
                    683:     PAUSE( 0, localNum, 'int@', "interruptOccurredAt.\n" );
                    684:     return;
                    685: }/* end interruptOccurredAt */
                    686: 
                    687: 
                    688: - (void) otherOccurred : (int)id
                    689: {
                    690:     PAUSE( 0, id, 'Othr', "otherOccurred.\n" );
                    691:     return;
                    692: }/* end otherOccurred */
                    693: 
                    694: 
                    695: - (void) receiveMsg
                    696: {
                    697:     PAUSE( 0, 0, 'RcvM', "receiveMsg.\n" );
                    698: 
                    699:         /* We have to let IODirectDevice take care of this (i.e.,   */
                    700:         /* dequeue the bogus message).                              */
                    701: 
                    702:     [ super receiveMsg ];
                    703:     return;
                    704: }/* end receiveMsg */
                    705: 
                    706: 
                    707:     /* This method is invoked by DriverKit when it receives a message       */
                    708:     /* generated by the function serviceTimeoutInterrupt() which was called */
                    709:     /* by the kernel on some DriverKit thread.                              */
                    710: 
                    711: - (void) timeoutOccurred
                    712: {
                    713:     CommandBuffer       *cmdBuf = gActiveCommand;
                    714:     CommandBuffer       *nextCmdBuf;
                    715: 
                    716: 
                    717:     if ( g.intLevel & kLevelLatched )
                    718:     {
                    719:         ELG( cmdBuf, 0, 'TocL', "timeoutOccurred - interrupt already latched; do nothing" );
                    720:         return;
                    721:     }
                    722: 
                    723:     g.intLevel |= kLevelISR;                /* set IOthread-running-flag */
                    724:     ELG( CCLWord( kcclStageLabel ), dbdmaAddr->d_cmdptrlo, 'Tock', "timeoutOccurred - tick.\n" );
                    725:     [ self GetHBARegsAndClear : FALSE ];    /* get the MESH registers    */
                    726: 
                    727:         /* If gActiveCommand timed out: */
                    728: 
                    729:     if ( cmdBuf )
                    730:     {   if ( isCmdTimedOut( cmdBuf )
                    731:           && ((CCLWord( kcclStageLabel ) != kcclStageFree)
                    732:             ||  (CCLWord( kcclStageLabel ) != kcclStageGood) ) )
                    733:         {
                    734:             dbdma_flush( DBDMA_MESH_SCSI );         /* DBDMA may be hung in */
                    735:             dbdma_stop(  DBDMA_MESH_SCSI );         /* middle of transfer.  */
                    736:         //  invalidate_cache_v( (vm_offset_t)cclLogAddr, cclLogAddrSize );
                    737: 
                    738:             cmdBuf->scsiReq->driverStatus = SR_IOST_IOTO;
                    739:             [ self ioComplete : cmdBuf ];
                    740: 
                    741:             [ self AbortActiveCommand ];
                    742: 
                    743:             g.intLevel &= ~kLevelISR;       /* clear IOthread-running-flag */
                    744:             return;
                    745:         }
                    746:     }
                    747:     else    /* Move any/all timed-out disconnected commands to abortCmdQ: */
                    748:     {
                    749:         cmdBuf = (CommandBuffer*)queue_first( &disconnectedCmdQ );
                    750:         while ( !queue_end( &disconnectedCmdQ, (queue_entry_t)cmdBuf ) )
                    751:         {
                    752:             nextCmdBuf = (CommandBuffer*)queue_next( &cmdBuf->link );
                    753:             if ( isCmdTimedOut( cmdBuf ) )
                    754:             {       /* Move cmdBuf from disconnectQ to abortQ:  */
                    755:                 queue_remove( &disconnectedCmdQ, cmdBuf, CommandBuffer*, link );
                    756:                 queue_enter( &abortCmdQ, cmdBuf, CommandBuffer*, link );
                    757:                 cmdBuf->scsiReq->driverStatus = SR_IOST_IOTO;
                    758:             }
                    759:             cmdBuf = nextCmdBuf;
                    760:         }/* end WHILE scanning commands in the disconnected queue */
                    761:         [ self AbortDisconnectedCommand ];
                    762:     }
                    763:     g.intLevel &= ~kLevelISR;                /* clear IOthread-running-flag */
                    764:     return;
                    765: }/* end timeoutOccurred */
                    766: 
                    767: 
                    768:     /* Process all commands in incomingCmdQ. At most one of these          */
                    769:     /* will become gActiveCommand. The remainder of kCommandExecute commands*/
                    770:     /* go to pendingCmdQ. Other types of commands (such as bus reset)      */
                    771:     /* are executed immediately.                                            */
                    772:     /* This method is called from IODirectDevice.                           */
                    773:     /*                                                                      */
                    774:     /* Note that we don't have a concept of frozen queue.                   */
                    775: 
                    776: - (void) commandRequestOccurred
                    777: {
                    778:     CommandBuffer      *cmdBuf, *pendCmd;
                    779: 
                    780: 
                    781:     [ incomingCmdLock lock ];
                    782: 
                    783:     while ( !queue_empty( &incomingCmdQ ) )
                    784:     {
                    785:         cmdBuf = (CommandBuffer*)queue_first( &incomingCmdQ );
                    786:         queue_remove( &incomingCmdQ, cmdBuf, CommandBuffer*, link );
                    787:         [ incomingCmdLock unlock ];
                    788:         ELG( gActiveCommand, cmdBuf, 'CRO+', "commandRequestOccurred" );
                    789: 
                    790:         switch ( cmdBuf->op )
                    791:         {
                    792:         case kCommandResetBus:
                    793:                 /* Note all active and disconnected commands will be terminated.*/
                    794:             [ self threadResetBus : "Reset Command Received" ];
                    795:             [ self ioComplete : cmdBuf ];
                    796:             break;
                    797: 
                    798:         case kCommandAbortRequest:
                    799:                 /* 1. Abort all active, pending, and disconnected commands. */
                    800:                 /* 2. Notify caller of completion.                          */
                    801:                 /* 3. Self-terminate.                                       */
                    802: 
                    803:             [ self abortAllCommands : SR_IOST_INT ];
                    804:             pendCmd = (CommandBuffer*)queue_first( &pendingCmdQ );
                    805: 
                    806:             while ( !queue_end( &pendingCmdQ, (queue_entry_t)pendCmd ) )
                    807:             {
                    808:                 pendCmd->scsiReq->driverStatus = SR_IOST_INT;
                    809:                 [ self ioComplete : pendCmd ];
                    810:                 pendCmd = (CommandBuffer*)queue_next( &pendCmd->link );
                    811:             }
                    812: 
                    813:             [ cmdBuf->cmdLock lock ];
                    814:             [ cmdBuf->cmdLock unlockWith : CMD_COMPLETE ];
                    815:             IOExitThread();
                    816:             /***** not reached *****/
                    817: 
                    818:         case kCommandExecute:
                    819:             [ self threadExecuteRequest : cmdBuf ];
                    820:             break;
                    821:         }/* end SWITCH */
                    822: 
                    823:         [ incomingCmdLock lock ];
                    824:     }/* end WHILE queue not empty */
                    825: 
                    826:     [ incomingCmdLock unlock ];
                    827:     return;
                    828: }/* end commandRequestOccurred */
                    829: 
                    830: 
                    831:     /* Power management methods. All we care about is power off, when   */
                    832:     /* we must reset the SCSI bus due to the Compaq BIOS's lack of a    */
                    833:     /* SCSI reset, which causes a hang if we have set up targets for    */
                    834:     /* sync data transfer mode.                                         */
                    835: 
                    836: - (IOReturn) getPowerState : (PMPowerState*)state_p
                    837: {
                    838:     return IO_R_UNSUPPORTED;
                    839: }/* end getPowerState */
                    840: 
                    841: 
                    842: - (IOReturn) setPowerState : (PMPowerState) state
                    843: {
                    844:     ELG( 0, state, 'sPwr', "setPowerState.\n" );
                    845: 
                    846:     if ( state == PM_OFF )
                    847:     {
                    848:     //  [ self scsiReset ];
                    849:             // ** ** ** TBS: [ self powerDown ];
                    850:         return IO_R_SUCCESS;
                    851:     }
                    852:     return IO_R_UNSUPPORTED;
                    853: }/* end setPowerState */
                    854: 
                    855: 
                    856: - (IOReturn) getPowerManagement : (PMPowerManagementState*)state_p
                    857: {
                    858:     return IO_R_UNSUPPORTED;
                    859: }/* end getPowerManagement */
                    860: 
                    861: 
                    862: - (IOReturn) setPowerManagement : (PMPowerManagementState)state
                    863: {
                    864:     return IO_R_UNSUPPORTED;
                    865: }/* end setPowerManagement */
                    866: 
                    867: 
                    868: #if APPLE_MESH_ENABLE_GET_SET
                    869: 
                    870: - (IOReturn) setIntValues       : (unsigned*)       parameterArray
                    871:                 forParameter    : (IOParameterName) parameterName
                    872:                 count           : (unsigned int)    count
                    873: {
                    874:     int             target;
                    875:     PerTargetData   *perTargetPtr;
                    876:     IOReturn        ioReturn = IO_R_INVALID_ARG;
                    877: 
                    878: 
                    879:     if ( strcmp( parameterName, APPLE_MESH_AUTOSENSE ) == 0 )
                    880:     {
                    881:         if ( count == 1 )
                    882:         {
                    883:             autoSenseEnable = parameterArray[0] ? 1 : 0;
                    884:             ELG( 0, autoSenseEnable, 'sVas', "setIntValues - autoSense\n" );
                    885:             ioReturn = IO_R_SUCCESS;
                    886:         }
                    887:     }
                    888:     else if ( strcmp( parameterName, APPLE_MESH_CMD_QUEUE ) == 0 )
                    889:     {
                    890:         if ( count == 1 )
                    891:         {
                    892:             cmdQueueEnable = parameterArray[0] ? 1 : 0;
                    893:             ELG( 0, cmdQueueEnable, 'sVqe', "setIntValues - cmdQueueEnable\n" );
                    894:             ioReturn = IO_R_SUCCESS;
                    895:         }
                    896:     }
                    897:     else if ( strcmp( parameterName, APPLE_MESH_SYNC ) == 0 )
                    898:     {
                    899:         if ( count == 1 )
                    900:         {
                    901:             syncModeEnable = parameterArray[0] ? 1 : 0;
                    902:             ELG( 0, syncModeEnable, 'sVse', "setIntValues - syncModeEnable\n" );
                    903:             ioReturn = IO_R_SUCCESS;
                    904:         }
                    905:     }
                    906:     else if ( strcmp( parameterName, APPLE_MESH_FAST_SCSI ) == 0 )
                    907:     {
                    908:         if ( count == 1 )
                    909:         {
                    910:             fastModeEnable = parameterArray[0] ? 1 : 0;
                    911:             ELG( 0, fastModeEnable, 'sVfe', "setIntValues - fastModeEnable\n" );
                    912:             ioReturn = IO_R_SUCCESS;
                    913:         }
                    914:     }
                    915:     else if ( strcmp( parameterName, APPLE_MESH_RESET_TARGETS ) == 0 )
                    916:     {
                    917:         if ( count == 0 )
                    918:         {
                    919:                 /* Re-enable sync and command queuing.      */
                    920:                 /* The disable bits persist after a reset.  */
                    921:             for ( target = 0; target < SCSI_NTARGETS; target++ )
                    922:             {
                    923:                 perTargetPtr = &gPerTargetData[ target ];
                    924:                 perTargetPtr->syncDisable       = FALSE;
                    925:                 perTargetPtr->maxQueue          = 0;
                    926:                 perTargetPtr->inquiry_7         = 0;
                    927:             }
                    928:             ELG( 0, 0, 'sVrt', "setIntValues - reset targets\n" );
                    929:             ioReturn = IO_R_SUCCESS;
                    930:         }
                    931:     }
                    932:     else if ( strcmp( parameterName, APPLE_MESH_RESET_TIMESTAMP ) == 0 )
                    933:     {
                    934:         ResetTimestampIndex();
                    935:         ioReturn = IO_R_SUCCESS;
                    936:     }
                    937:     else if ( strcmp( parameterName, APPLE_MESH_ENABLE_TIMESTAMP ) == 0 )
                    938:     {
                    939:         EnableTimestamp( TRUE );
                    940:         ioReturn = IO_R_SUCCESS;
                    941:     }
                    942:     else if ( strcmp( parameterName, APPLE_MESH_DISABLE_TIMESTAMP ) == 0 )
                    943:     {
                    944:         EnableTimestamp( FALSE );
                    945:         ioReturn = IO_R_SUCCESS;
                    946:     }
                    947:     else if ( strcmp( parameterName, APPLE_MESH_PRESERVE_FIRST_TIMESTAMP ) == 0 )
                    948:     {
                    949:         PreserveTimestamp( TRUE );
                    950:         ioReturn = IO_R_SUCCESS;
                    951:     }
                    952:     else if ( strcmp( parameterName, APPLE_MESH_PRESERVE_LAST_TIMESTAMP ) == 0 )
                    953:     {
                    954:         PreserveTimestamp( FALSE );
                    955:         ioReturn = IO_R_SUCCESS;
                    956:     }
                    957:     else
                    958:     {
                    959:         ioReturn [ super setIntValues   : parameterArray
                    960:                         forParameter    : parameterName
                    961:                         count           : count ];
                    962:     }
                    963:     return ioReturn;
                    964: }/* end setIntValues */
                    965: 
                    966: 
                    967: - (IOReturn) getIntValues   : (unsigned*)       parameterArray
                    968:         forParameter        : (IOParameterName) parameterName
                    969:         count               : (unsigned*)       count      /* in/out  */
                    970: {
                    971:     IOReturn        ioReturn = IO_R_INVALID_ARG;
                    972: 
                    973: 
                    974:     if ( strcmp( parameterName, APPLE_MESH_AUTOSENSE) == 0 )
                    975:     {
                    976:         if ( *count == 1 )
                    977:         {
                    978:             parameterArray[0] = autoSenseEnable;
                    979:             ioReturn = IO_R_SUCCESS;
                    980:         }
                    981:     }
                    982:     else if ( strcmp( parameterName, APPLE_MESH_CMD_QUEUE ) == 0 )
                    983:     {
                    984:         if ( *count == 1 )
                    985:         {
                    986:             parameterArray[0] = cmdQueueEnable;
                    987:             ioReturn = IO_R_SUCCESS;
                    988:         }
                    989:     }
                    990:     else if ( strcmp( parameterName, APPLE_MESH_SYNC ) == 0 )
                    991:     {
                    992:         if ( *count == 1 )
                    993:         {
                    994:             parameterArray[0] = syncModeEnable;
                    995:             ioReturn = IO_R_SUCCESS;
                    996:         }
                    997:     }
                    998:     else if ( strcmp( parameterName, APPLE_MESH_FAST_SCSI ) == 0 )
                    999:     {
                   1000:         if ( *count == 1 )
                   1001:         {
                   1002:             parameterArray[0] = fastModeEnable;
                   1003:             ioReturn = IO_R_SUCCESS;
                   1004:         }
                   1005:     }
                   1006:     else if ( strcmp( parameterName, APPLE_MESH_RESET_TIMESTAMP ) == 0 )
                   1007:     {
                   1008:         ResetTimestampIndex();
                   1009:         ioReturn = IO_R_SUCCESS;
                   1010:     }
                   1011:     else if ( strcmp( parameterName, APPLE_MESH_ENABLE_TIMESTAMP ) == 0 )
                   1012:     {
                   1013:         EnableTimestamp( TRUE );
                   1014:         ioReturn = IO_R_SUCCESS;
                   1015:     }
                   1016:     else if ( strcmp( parameterName, APPLE_MESH_DISABLE_TIMESTAMP ) == 0 )
                   1017:     {
                   1018:         EnableTimestamp( FALSE );
                   1019:         ioReturn = IO_R_SUCCESS;
                   1020:     }
                   1021:     else if ( strcmp( parameterName, APPLE_MESH_PRESERVE_FIRST_TIMESTAMP ) == 0 )
                   1022:     {
                   1023:         PreserveTimestamp( TRUE );
                   1024:         ioReturn = IO_R_SUCCESS;
                   1025:     }
                   1026:     else if ( strcmp( parameterName, APPLE_MESH_PRESERVE_LAST_TIMESTAMP ) == 0 )
                   1027:     {
                   1028:         PreserveTimestamp( FALSE );
                   1029:         ioReturn = IO_R_SUCCESS;
                   1030:     }
                   1031:     else
                   1032:     {
                   1033:         ioReturn = [ super  getIntValues    : parameterArray
                   1034:                             forParameter    : parameterName
                   1035:                             count           : count ];
                   1036:     }
                   1037:     return  ioReturn;
                   1038: }/* end getIntValues */
                   1039: 
                   1040: #endif APPLE_MESH_ENABLE_GET_SET
                   1041: 
                   1042: @end /* AppleMesh_SCSI */
                   1043: 
                   1044: 
                   1045: 
                   1046: @implementation AppleMesh_SCSI( Hardware )
                   1047: 
                   1048:     /* Perform MESH-specific initialization.                      */
                   1049:     /* Fetch the device's bus address and interrupt port number.  */
                   1050:     /* Also, allocate one page of memory for the channel program. */
                   1051: 
                   1052: - InitializeHardware : deviceDescription
                   1053: {
                   1054:     IOReturn        ioReturn    = IO_R_SUCCESS;
                   1055:     id              result      = self;
                   1056:     kern_return_t   kernelReturn;
                   1057:     UInt8           target, lun;
                   1058:     id              configTable;
                   1059:     const char      *configValue;
                   1060:     UInt8           deviceNumber;
                   1061:     UInt8           functionNumber;
                   1062:     UInt8           busNumber;
                   1063: 
                   1064: 
                   1065:     configTable = [ deviceDescription configTable ];
                   1066:     ASSERT( configTable );
                   1067:     configValue = [ configTable valueForStringKey: "Bus Type" ];
                   1068: 
                   1069:     if ( configValue == NULL || strcmp( configValue, "PPC" ) )
                   1070:     {
                   1071:         PAUSE( 0, 'init', 'Hdw-', "InitializeHardware - bus type NG.\n" );
                   1072:         ioReturn = IO_R_NO_DEVICE;
                   1073:     }
                   1074: 
                   1075:     if ( ioReturn == IO_R_SUCCESS )
                   1076:     {
                   1077: #if 0 // ** ** ** Need correct definition ** ** **
                   1078:         ioReturn = [ deviceDescription getPCIDevice
                   1079:                                     : &deviceNumber
                   1080:                         function    : &functionNumber
                   1081:                         bus         : &busNumber ];
                   1082: #else
                   1083:         deviceNumber    = 0;
                   1084:         functionNumber  = 0;
                   1085:         busNumber       = 0;
                   1086:         kernelReturn    = 0;
                   1087: #endif
                   1088:         if ( ioReturn != IO_R_SUCCESS )
                   1089:             PAUSE( 0, ioReturn, 'iHd-', "InitializeHardware - Can't get PCI device information.\n" );
                   1090:     }
                   1091: 
                   1092:     if ( configValue )
                   1093:     {
                   1094:         [ configTable freeString : configValue ];
                   1095:         configValue = NULL;
                   1096:     }
                   1097: 
                   1098:     if ( ioReturn == IO_R_SUCCESS )
                   1099:         ioReturn = [ self AllocHdwAndChanMem : deviceDescription ];
                   1100: 
                   1101:     if ( ioReturn == IO_R_SUCCESS )
                   1102:     {
                   1103:         for ( target = 0; target < SCSI_NTARGETS; target++ )
                   1104:         {
                   1105:             gPerTargetData[ target ].syncParms      = kSyncParmsAsync;
                   1106:             gPerTargetData[ target ].negotiateSDTR  = kSyncParmsFast;   // negotiate Fast
                   1107:             gPerTargetData[ target ].inquiry_7      = 0;
                   1108:         }
                   1109: 
                   1110:             /* All of the addresses are established.           */
                   1111:             /* Check that the hardware is present and working. */
                   1112:         ioReturn = [ self DoHBASelfTest ];
                   1113:     }
                   1114: 
                   1115:     if ( ioReturn == IO_R_SUCCESS )
                   1116:     {
                   1117:             /* Tell the superclass to initialize our IO thread.        */
                   1118:             /* After this, we should be able to execute SCSI requests. */
                   1119: 
                   1120:         if ( [ super initFromDeviceDescription : deviceDescription ] == NULL )
                   1121:         {
                   1122:             PAUSE( 0, 0, 'i h-', "InitializeHardware - Host Adaptor was not initialized. Fatal.\n" );
                   1123:             ioReturn = IO_R_NO_DEVICE;
                   1124:         }
                   1125:     }
                   1126: 
                   1127:     if ( ioReturn == IO_R_SUCCESS )
                   1128:     {
                   1129:         gFlagIOThreadRunning = 1;
                   1130: 
                   1131:             /* Initialize local variables. Note that activeArray and    */
                   1132:             /* perTarget arrays are zeroed by objc runtime.             */
                   1133: 
                   1134:         queue_init( &disconnectedCmdQ );
                   1135:         queue_init( &incomingCmdQ );
                   1136:         queue_init( &pendingCmdQ );
                   1137:         queue_init( &abortCmdQ );
                   1138:         incomingCmdLock = [ [ NXLock alloc ] init ];
                   1139:         gActiveCommand = NULL;
                   1140:         [ self resetStatistics ];
                   1141:         gNextQueueTag       = QUEUE_TAG_NONTAGGED + 1;
                   1142:         gInitiatorID        = kInitiatorIDDefault;
                   1143:         gInitiatorIDMask    = 1 << gInitiatorID;    /* BusID bitmask for selection. */
                   1144:         gFlagReselecting    = FALSE;
                   1145: 
                   1146:             /* Reserve the initiator ID for all LUNs:   */
                   1147: 
                   1148:         for ( lun = 0; lun < SCSI_NLUNS; lun++ )
                   1149:             [ self reserveTarget : gInitiatorID     lun : lun   forOwner : self ];
                   1150: 
                   1151:             /* Get tagged command queueing, sync mode,  */
                   1152:             /* fast mode enables from configTable.      */
                   1153: 
                   1154:         gOptionCmdQueueEnable   = getConfigParam( configTable, CMD_QUEUE_ENABLE );
                   1155:         gOptionSyncModeEnable   = getConfigParam( configTable, SYNC_ENABLE );
                   1156:         gOptionFastModeEnable   = getConfigParam( configTable, FAST_ENABLE );
                   1157:         gOptionExtendTiming     = getConfigParam( configTable, EXTENDED_TIMING );
                   1158:         gOptionAutoSenseEnable  = AUTO_SENSE_ENABLE;       // from bringup.h
                   1159: 
                   1160:         gOptionCmdQueueEnable   = 1;    /* Temp for testing???  */
                   1161: 
                   1162:             /* Get internal version of interruptPort;           */
                   1163:             /* set the port queue length to the maximum size.   */
                   1164:             /* It is not clear if we want to do this.           */
                   1165: 
                   1166:         gKernelInterruptPort = IOConvertPort(   [ self interruptPort ],
                   1167:                                                 IO_KernelIOTask,
                   1168:                                                 IO_Kernel );
                   1169: #if 0 /***** Need correct header file   *****/
                   1170:         kernelReturn = port_set_backlog(    task_self(),
                   1171:                                             [ self interruptPort ],
                   1172:                                             PORT_BACKLOG_MAX );
                   1173:         if ( kernelReturn != KERN_SUCCESS )
                   1174:             PAUSE( 0, kernelReturn, 'i H-', "InitializeHardware - warning, port_set_backlog error.\n" );
                   1175: #endif
                   1176: 
                   1177:             /* Initialize the chip and reset the bus:   */
                   1178: 
                   1179:         ioReturn = [ self ResetHardware : TRUE ];
                   1180:         meshAddr->sourceID  = gInitiatorID; // mlj ??? fix this
                   1181:     }
                   1182: 
                   1183:     if ( ioReturn == IO_R_SUCCESS )
                   1184:     {
                   1185:             /* OK, we're ready to roll. */
                   1186: 
                   1187:         [ self enableInterrupt : 0 ];
                   1188:         [ self registerDevice ];
                   1189: 
                   1190:         IOScheduleFunc( serviceTimeoutInterrupt, (void*)0x333, ONE_SECOND );
                   1191:     }
                   1192:     else
                   1193:     {       /* Do we need to free the locks and similar?    */
                   1194:         [ self free ];
                   1195:         result = NULL;
                   1196:     }
                   1197: 
                   1198:     return  result;
                   1199: }/* end InitializeHardware */
                   1200: 
                   1201: 
                   1202:     /* This includes a SCSI reset.                                  */
                   1203:     /* Handling of ioComplete of active and disconnected commands   */
                   1204:     /* must be done elsewhere. Returns IO_R_SUCCESS if successful.  */
                   1205:     /* This is called from a Task thread. It will disable and       */
                   1206:     /* re-enable interrupts. Reason is for error logging.           */
                   1207: 
                   1208: - (IOReturn) ResetHardware : (Boolean)resetSCSIBus
                   1209: {
                   1210:     ELG( 0, resetSCSIBus, 'RstH', "ResetHardware - Bus Reset.\n" );
                   1211: 
                   1212:     [ self abortAllCommands : SR_IOST_RESET ];
                   1213:     [ self ResetMESH        : resetSCSIBus  ];
                   1214: 
                   1215:     return  IO_R_SUCCESS;
                   1216: }/* end ResetHardware */
                   1217: 
                   1218: 
                   1219:     /* Start a SCSI transaction for the specified command.                  */
                   1220:     /* ActiveCmd must be NULL. A return of kHardwareStartRejected           */
                   1221:     /* indicates that caller may try again with another command;            */
                   1222:     /* kHardwareStartBusy indicates a condition other than                  */
                   1223:     /* (activeCmd != NULL) which prevents the processing of the command.    */
                   1224: 
                   1225: - (HardwareStartResult) hardwareStart : (CommandBuffer*) cmdBuf
                   1226: {
                   1227:     IOSCSIRequest       *scsiReq;
                   1228:     HardwareStartResult result          = kHardwareStartOK;
                   1229:     cdb_t               *cdbp;
                   1230:     Boolean             okToDisconnect  = TRUE;
                   1231:     Boolean             okToQueue       = gOptionCmdQueueEnable;
                   1232:     UInt8               msgByte;
                   1233: 
                   1234: 
                   1235:     ASSERT( cmdBuf && cmdBuf->scsiReq );
                   1236: 
                   1237:     scsiReq         = cmdBuf->scsiReq;
                   1238:     gCurrentTarget  = scsiReq->target;
                   1239:     gCurrentLUN     = scsiReq->lun;
                   1240:     cdbp            = &scsiReq->cdb;
                   1241:     gMsgOutFlag     = 0;
                   1242: 
                   1243:     cmdBuf->cdbLength = GetSCSICommandLength( cdbp, scsiReq->cdbLength );
                   1244:     if ( cmdBuf->cdbLength == 0 )
                   1245:     {
                   1246:             /* Failure: we can't determine the length of this command.  */
                   1247: 
                   1248:         scsiReq->driverStatus = SR_IOST_CMDREJ;
                   1249:         [ self ioComplete : cmdBuf ];
                   1250:         result = kHardwareStartRejected;
                   1251:     }
                   1252:     {   UInt8   *bp = (UInt8*)cdbp;
                   1253:         ELG(    ( bp[0]<<24) | (bp[1]<<16) | (bp[2]<<8) | bp[3],
                   1254:                 ( bp[4]<<24) | (bp[5]<<16) | (bp[6]<<8) | bp[7],
                   1255:                 '=CDB', "hardwareStart - CDB" );
                   1256:     }
                   1257: 
                   1258:     if ( result == kHardwareStartOK )
                   1259:     {
                   1260:             /* Peek at the control byte (the last byte in the command). */
                   1261: 
                   1262:         msgByte = ((UInt8*)cdbp)[ cmdBuf->cdbLength - 1 ];
                   1263:         if ( (msgByte & CTRL_LINKFLAG) != CTRL_NOLINK )
                   1264:         {
                   1265:                 /* Failure: we don't support linked commands.   */
                   1266: 
                   1267:             scsiReq->driverStatus = SR_IOST_CMDREJ;
                   1268:             [ self ioComplete : cmdBuf ];
                   1269:             result = kHardwareStartRejected;
                   1270:         }
                   1271:     }
                   1272: 
                   1273:     if ( result == kHardwareStartOK )
                   1274:     {
                   1275:             /* Autosense always renegotiates synchronous transfer mode. */
                   1276:             /* This is necessary as the target might have been reset    */
                   1277:             /* or hit with a power-cycle. Autosense is never issued     */
                   1278:             /* with a queue tag.                                        */
                   1279: 
                   1280:         cmdBuf->queueTag = QUEUE_TAG_NONTAGGED;     /* No tag just yet  */
                   1281:         if ( cmdBuf->flagIsAutosense )
                   1282:         {
                   1283:             okToDisconnect = FALSE;
                   1284:             gPerTargetData[ gCurrentTarget ].negotiateSDTR  = gPerTargetData[ gCurrentTarget ].syncParms;
                   1285:         }
                   1286:         else
                   1287:         {
                   1288:                 /* This is a real command. Setup the user data pointers */
                   1289:                 /* and counters and build a SCSI request CCL.           */
                   1290:                 /* First, peek at the command for some special cases.   */
                   1291: 
                   1292:             switch ( cdbp->cdb_opcode )
                   1293:             {
                   1294:             case kScsiCmdInquiry:
                   1295: 
                   1296:                     /* The first command SCSIDisk sends us is an Inquiry.   */
                   1297:                     /* This never gets retried, so avoid a possible         */
                   1298:                     /* reject of a command queue tag. Avoid this hack if    */
                   1299:                     /* there are any other commands outstanding for this    */
                   1300:                     /* Target/LUN.                                          */
                   1301: 
                   1302:                 if ( gActiveArray[ scsiReq->target ][ scsiReq->lun ] == 0 )
                   1303:                     scsiReq->cmdQueueDisable = TRUE;
                   1304: 
                   1305:                 okToDisconnect   = FALSE;  /* no disconnect, no queuing */
                   1306:                 break;
                   1307: 
                   1308:             case kScsiCmdRequestSense:
                   1309:                     /* Always force sync renegotiation on any Request Sense */
                   1310:                     /* to catch independent target power cycles.            */
                   1311:                     /* (Sync renegotiation needed should be set after all   */
                   1312:                     /* target-detected errors -- fix needed in MessageIn).  */
                   1313:                     /* Sense is always issued with disconnect disabled to   */
                   1314:                     /* maintain T/L/Q nexus.                                */
                   1315:                     /* Watch it: request sense from a client is incompatible*/
                   1316:                     /* with tagged queuing.                                 */
                   1317: 
                   1318:                 gPerTargetData[ gCurrentTarget ].negotiateSDTR
                   1319:                                     = gPerTargetData[ gCurrentTarget ].syncParms;
                   1320:                 okToDisconnect  = FALSE;
                   1321:                 break;
                   1322: 
                   1323:             case kScsiCmdTestUnitReady:
                   1324:             case kScsiCmdReadCapacity:
                   1325:                 okToDisconnect  = FALSE;
                   1326:                 break;
                   1327:             }/* end SWITCH on opcode */
                   1328:         }/* end ELSE not auto sense */
                   1329:     }/* end IF kHardwareStartOK */
                   1330: 
                   1331:     okToDisconnect &= scsiReq->disconnect;
                   1332: 
                   1333:     okToQueue   &= okToDisconnect
                   1334:                 && (scsiReq->cmdQueueDisable == FALSE)
                   1335:                 && (gPerTargetData[ scsiReq->target ].inquiry_7 & 0x02);
                   1336: 
                   1337:     cmdBuf->flagActive = 0;     /* Initialize flags for this command.   */
                   1338: 
                   1339:         /* Make sure that the HBA is stable before we  */
                   1340:         /* try to start a request.                     */
                   1341: 
                   1342:     if ( result == kHardwareStartOK )
                   1343:     {
                   1344:         if ( gActiveCommand )
                   1345:         {
                   1346:                 /* This should never happen. It ensures that there are  */
                   1347:                 /* no race conditions that reselect us between the time */
                   1348:                 /* threadExecuteRequest looked at gActiveCommand and    */
                   1349:                 /* the time we disabled interrupts.                     */
                   1350: 
                   1351:             queue_enter( &pendingCmdQ, cmdBuf, CommandBuffer*, link );
                   1352:             result = kHardwareStartBusy;
                   1353:         }
                   1354:     }
                   1355: 
                   1356:     if ( result == kHardwareStartOK )
                   1357:     {
                   1358:             /* Activate this command - if we fail later, we'll de-activate it.  */
                   1359: 
                   1360:         ASSERT( gActiveCommand == NULL );
                   1361:         [ self activateCommand : cmdBuf ];
                   1362:         ASSERT( scsiReq->target == gCurrentTarget && scsiReq->lun == gCurrentLUN );
                   1363:         [ self ClearCPResults ];
                   1364: 
                   1365:             /* Reset the message-out buffer pointer for the */
                   1366:             /* Identify, SDTR, and queue tag messages.      */
                   1367: 
                   1368:         msgOutPtr = (UInt8*)CCLAddress( kcclMSGOdata );
                   1369:         msgByte   = kScsiMsgIdentify | scsiReq->lun;
                   1370: 
                   1371:         if ( okToDisconnect )
                   1372:             msgByte |= kScsiMsgEnableDisconnectMask;
                   1373: 
                   1374:         *msgOutPtr++ = msgByte;
                   1375: 
                   1376:             /* According to the SCSI Spec, the tag command              */
                   1377:             /* immediately follows the selection.                       */
                   1378:             /* Note that autosense is never tagged..                    */
                   1379:             /* The command was initialized with QUEUE_TAG_NONTAGGED.    */
                   1380:             /***** Driver Kit only supports simple queue tags.      *****/
                   1381: 
                   1382:         if ( okToQueue )
                   1383:         {
                   1384:                 /* Avoid using tag QUEUE_TAG_NONTAGGED (zero).  */
                   1385: 
                   1386:             cmdBuf->queueTag = gNextQueueTag;
                   1387:             if ( ++gNextQueueTag == QUEUE_TAG_NONTAGGED )
                   1388:                 gNextQueueTag++;
                   1389:             *msgOutPtr++   = kScsiMsgSimpleQueueTag;
                   1390:             *msgOutPtr++   = cmdBuf->queueTag;
                   1391:             gMsgOutFlag    |= kFlagMsgOut_Queuing;
                   1392:         }
                   1393: 
                   1394:             /* Do we need to negotiate SDTR for this target?    */
                   1395: 
                   1396:         msgByte = gPerTargetData[ scsiReq->target ].negotiateSDTR;
                   1397:         ELG(    scsiReq->target << 16   | gPerTargetData[ scsiReq->target ].inquiry_7,
                   1398:                 gPerTargetData[ scsiReq->target ].syncParms << 16 | msgByte,
                   1399:                 'SYN?', "Sync" );
                   1400:         if ( !(gPerTargetData[ scsiReq->target ].inquiry_7 & 0x10) )
                   1401:         {
                   1402:             msgByte = 0;        /* if Inquiry data doesn't permit Synchronous   */
                   1403:         }
                   1404:         if ( msgByte )
                   1405:         {
                   1406:         //  gPerTargetData[ scsiReq->target ].negotiateSDTR = 0;
                   1407:             *msgOutPtr++   = kScsiMsgExtended; /* Extended Message */
                   1408:             *msgOutPtr++   = 0x03;             /* Message Length   */
                   1409:             *msgOutPtr++   = kScsiMsgSyncXferReq;
                   1410:             if ( msgByte == kSyncParmsAsync )
                   1411:             {
                   1412:                 *msgOutPtr++   = 200 >> 4;     /* Period? used?    */
                   1413:                 *msgOutPtr++   = 0;            /* Offset (async)   */
                   1414:             }
                   1415:             else
                   1416:             {
                   1417:                 *msgOutPtr++   = 100 >> 2;     /* 100 nSec period  */
                   1418:                 *msgOutPtr++   = msgByte >> 4; /* FIFO size        */
                   1419:             }
                   1420:             gMsgOutFlag |= kFlagMsgOut_SDTR;
                   1421:         }/* end IF need to negotiate (a)sync */
                   1422: 
                   1423:         if ( cmdBuf->flagIsAutosense )
                   1424:         {
                   1425:             [ self InitAutosenseCCL ];
                   1426:         }
                   1427:         else
                   1428:         {
                   1429:             cmdBuf->currentDataIndex    = 0;
                   1430:             cmdBuf->savedDataIndex      = 0;
                   1431:             if ( cmdBuf->mem )
                   1432:             {
                   1433:                 [ cmdBuf->mem setPosition : 0 ];
                   1434:                 [ cmdBuf->mem state : &cmdBuf->savedDataState ];
                   1435:             }
                   1436:             scsiReq->driverStatus       = SR_IOST_INVALID;
                   1437:             scsiReq->totalTime          = 0;
                   1438:             scsiReq->latentTime         = 0;
                   1439:             [ self UpdateCP : FALSE ];   /* Update the DBDMA Channel Program    */
                   1440:         }
                   1441:     
                   1442:             /***** Can a caller override the default timeout?   *****/
                   1443:     
                   1444:         meshAddr->selectionTimeOut  = gSelectionTimeout;
                   1445:         meshAddr->destinationID     = scsiReq->target;
                   1446:         meshAddr->syncParms         = gPerTargetData[ scsiReq->target ].syncParms;
                   1447:         SynchronizeIO();
                   1448:         [ self RunDBDMA : kcclStart  stageLabel : kcclStageInit ];
                   1449:         IOGetTimestamp( &cmdBuf->startTime );
                   1450:     }
                   1451:     return result;
                   1452: }/* end hardwareStart */
                   1453: 
                   1454: 
                   1455: @end /* AppleMesh_SCSI( Hardware ) */
                   1456: 
                   1457: 
                   1458:     /* Obtain a YES/NO type parameter from the config table.    */
                   1459:     /* @param   configTable The table to examine.               */
                   1460:     /* @param   paramName  The parameter to look for.           */
                   1461:     /* @result  Zero if missing from the table or the table     */
                   1462:     /* value is not YES. One if present in the table and the    */
                   1463:     /* table value is YES.                                      */
                   1464: 
                   1465: static int getConfigParam( id configTable, const char *paramName )
                   1466: {
                   1467:     const char  *value;
                   1468:     int         rtn = 0;    // default if not present in table
                   1469: 
                   1470: 
                   1471:     value = [ configTable valueForStringKey : paramName ];
                   1472:     if ( value )
                   1473:     {
                   1474:         if ( strcmp( value, "YES" ) == 0 )
                   1475:             rtn = 1;
                   1476:         [ configTable freeString : value ];
                   1477:     }
                   1478:     return rtn;
                   1479: }/* end getConfigParam */
                   1480: 
                   1481: 
                   1482: static unsigned int GetSCSICommandLength( const cdb_t *cdbPtr, unsigned int defaultLength )
                   1483: {
                   1484:     unsigned int    result;
                   1485: 
                   1486:         /* Warning: don't use sizeof here - the compiler rounds */
                   1487:         /* the value up to the next word boundary.              */
                   1488: 
                   1489:     switch ( ((UInt8*)cdbPtr)[0] & 0xE0 )
                   1490:     {
                   1491:     case (0 << 5):  result = 6;                                         break;
                   1492:     case (1 << 5):
                   1493:     case (2 << 5):  result = 10;                                        break;
                   1494:     case (5 << 5):  result = 12;                                        break;
                   1495:     case (6 << 5):  result = (defaultLength != 0) ? defaultLength : 6;  break;
                   1496:     case (7 << 5):  result = (defaultLength != 0) ? defaultLength : 10; break;
                   1497:     default:        result = 0;                                         break;
                   1498:     }
                   1499:     return result;
                   1500: }/* end GetSCSICommandLength */
                   1501: 
                   1502: 
                   1503:     /* These are the hardware-specific methods that are not */
                   1504:     /* explicitly tied to Mesh and DBDMA.                   */
                   1505: 
                   1506: @implementation AppleMesh_SCSI( HardwarePrivate )
                   1507: 
                   1508:     /* Fetch the device's bus address and allocate one page of memory   */
                   1509:     /* for the channel command. (Strictly speaking, we don't need an    */
                   1510:     /* entire page, but we can use the rest of the page for a permanent */
                   1511:     /* status log).                                                     */
                   1512:     /* @param   deviceDescription   Specify the device to initialize.   */
                   1513:     /* @return  IO_R_SUCCESS if successful, else an error status.       */
                   1514: 
                   1515: - (IOReturn) AllocHdwAndChanMem : deviceDescription
                   1516: {
                   1517:     IOReturn    ioReturn = IO_R_SUCCESS;
                   1518:     enum
                   1519:     {   kMESHRegisterBase   = 0,
                   1520:         kDBDMARegisterBase  = 1,
                   1521:         kNumberRegisters    = 2
                   1522:     };
                   1523: 
                   1524: 
                   1525:     meshAddr    = (MeshRegister*)gMESHPhysAddr      =   0;
                   1526:     dbdmaAddr   = (dbdma_regmap_t*)dbdmaAddrPhys    =   0;
                   1527: 
                   1528:         /* Set the default selection timeout to the MESH value (10 msec units). */
                   1529: 
                   1530:     gSelectionTimeout = 250 / 10;   // ??? symbolic
                   1531: 
                   1532:         /* Allocate a page of wired-down memory in the kernel. Although */
                   1533:         /* Driver Kit provides a memory allocator, IOMalloc, it does    */
                   1534:         /* not guarantee page alignment. Thus, we call the Mach kernel  */
                   1535:         /* routine. According to the description of kalloc(), 8192 is   */
                   1536:         /* the smallest amount of memory we can allocate. The channel   */
                   1537:         /* command area will fit into the start of this area.           */
                   1538: 
                   1539:     cclLogAddrSize  = page_size;
                   1540:     cclLogAddr      = (DBDMADescriptor*)kalloc( cclLogAddrSize );
                   1541:     if ( !cclLogAddr )
                   1542:     {   PAUSE( 0, cclLogAddrSize, 'CCA-', "AllocHdwAndChanMem - can't allocate channel command area.\n" );
                   1543:         ioReturn = IO_R_NO_MEMORY;
                   1544:     }
                   1545: 
                   1546:     if ( ioReturn == IO_R_SUCCESS )
                   1547:     {
                   1548:         if ( IOIsAligned( cclLogAddr, page_size ) == 0 )
                   1549:         {
                   1550:             PAUSE( 0, cclLogAddr, 'cca-', "AllocHdwAndChanMem - not page-aligned.\n" );
                   1551:             ioReturn = IO_R_NO_MEMORY;
                   1552:         }
                   1553:     }
                   1554: 
                   1555:     if ( ioReturn == IO_R_SUCCESS )
                   1556:     {
                   1557:             /* Remember the number of DBDMA descriptors that    */
                   1558:             /* can be used for data transfer channel commands.  */
                   1559: 
                   1560:         gDBDMADescriptorMax = (cclLogAddrSize - kcclDataXfer)
                   1561:                             / sizeof( DBDMADescriptor );
                   1562: #if 0
                   1563:             /* Fetch the logical and physical addresses */
                   1564:             /* to access the MESH and DBDMA hardware.   */
                   1565: 
                   1566:         memoryRangeList     = [ deviceDescription memoryRangeList ];
                   1567:         numMemoryRanges     = [ deviceDescription numMemoryRanges ];
                   1568:         for ( i = 0; i < numMemoryRanges; i++ )
                   1569:             ELG( memoryRangeList[ i ].start, memoryRangeList[ i ].size, 'Rang', "AllocHdwAndChanMem - range start & size.\n" );
                   1570:         if ( numMemoryRanges != kNumberRegisters )
                   1571:         {   PAUSE( memoryRangeList[ i ].start, memoryRangeList[ i ].size, 'Rng-', "AllocHdwAndChanMem - numMemoryRanges != kNumberRegisters.\n" );
                   1572:             ioReturn = IO_R_INVALID;   /* This "can't happen"   */
                   1573:         }
                   1574: #endif
                   1575:     }
                   1576: 
                   1577: #if 0
                   1578:     if ( ioReturn == IO_R_SUCCESS )
                   1579:     {
                   1580:             /* We know that the first range describes the MESH chip,    */
                   1581:             /* and the second range describes the DBDMA chip.           */
                   1582: 
                   1583:         gMESHPhysAddr   = (PhysicalAddress)memoryRangeList[ kMESHRegisterBase  ].start;
                   1584:         dbdmaAddrPhys   = (PhysicalAddress)memoryRangeList[ kDBDMARegisterBase ].start;
                   1585: 
                   1586:             /* Weave together the logical and physical addresses.           */
                   1587:             /* First, map the MESH and DBDMA chips into our address space.  */
                   1588: 
                   1589:         ioReturn = IOMapPhysicalIntoIOTask( (UInt32)gMESHPhysAddr,
                   1590:                                             sizeof( MeshRegister ),
                   1591:                                             (vm_address_t*)&meshAddr );
                   1592:         if ( ioReturn != IO_R_SUCCESS )
                   1593:             PAUSE( 0, ioReturn, 'map-', "AllocHdwAndChanMem - MESH mapping err.\n" );
                   1594:     }
                   1595: 
                   1596:     if ( ioReturn == IO_R_SUCCESS )
                   1597:     {
                   1598:         ioReturn = IOMapPhysicalIntoIOTask( (UInt32)dbdmaAddrPhys,
                   1599:                                             sizeof( dbdma_regmap_t ),
                   1600:                                             (vm_address_t*)&dbdmaAddr );
                   1601:         if ( ioReturn != IO_R_SUCCESS )
                   1602:             PAUSE( 0, ioReturn, 'Map-', "AllocHdwAndChanMem - DBDMA mapping err.\n" );
                   1603:     }
                   1604: #else
                   1605:     if ( ioReturn == IO_R_SUCCESS )
                   1606:     {
                   1607:         meshAddr        = (MeshRegister*)gMESHPhysAddr = (PhysicalAddress)PCI_MESH_BASE_PHYS;
                   1608: 
                   1609:     //  dbdmaAddr       = (dbdma_regmap_t*)PCI_MESH_DMA_BASE_PHYS;
                   1610:         dbdmaAddr       = (dbdma_regmap_t*)DBDMA_REGMAP( DBDMA_MESH_SCSI );
                   1611:     //  dbdmaAddrPhys   = (PhysicalAddress)KVTOPHYS( (vm_offset_t)dbdmaAddr );
                   1612:         dbdmaAddrPhys   = (PhysicalAddress)dbdmaAddr;
                   1613: 
                   1614:         ELG( dbdmaAddrPhys, dbdmaAddr, 'DBDM',
                   1615:                 "AllocHdwAndChanMem - DBDMA phys/logical addresses." );
                   1616:         g.meshAddr = (UInt32)meshAddr;      // for debugging, miniMon ...
                   1617: #if CustomMiniMon
                   1618:         gMESH_DBDMA      = (UInt32)dbdmaAddr;
                   1619:         gMESH_DBDMA_Phys = (UInt32)dbdmaAddrPhys;
                   1620: #endif /* CustomMiniMon */
                   1621:     }
                   1622: 
                   1623: #endif
                   1624: 
                   1625:     if ( ioReturn == IO_R_SUCCESS )
                   1626:     {
                   1627:             /* Ensure that the addresses are valid: */
                   1628: 
                   1629:         ASSERT( probe_rb( meshAddr  ) == 0 );
                   1630:         ASSERT( probe_rb( dbdmaAddr ) == 0 );
                   1631: 
                   1632:             /* Get the physical address corresponding the DBDMA channel area:   */
                   1633: 
                   1634:         ioReturn = IOPhysicalFromVirtual(   IOVmTaskSelf(),
                   1635:                                             (UInt32)cclLogAddr,
                   1636:                                             (vm_offset_t*)&cclPhysAddr );
                   1637:         g.cclPhysAddr   = (UInt32)cclPhysAddr;  // for debugging ease
                   1638:         g.cclLogAddr    = (UInt32)cclLogAddr;
                   1639:         if ( ioReturn != IO_R_SUCCESS )
                   1640:             PAUSE( 0, ioReturn, 'MAP-', "AllocHdwAndChanMem - DBDMA mapping err.\n" );
                   1641:     }
                   1642: 
                   1643:     if ( ioReturn == IO_R_SUCCESS)
                   1644:     {
                   1645:         ELG( cclPhysAddr, cclLogAddr, '=CCL',
                   1646:                 "AllocHdwAndChanMem - CCL phys/logical addresses." );
                   1647:         [ self InitCP ];
                   1648:     }
                   1649:         /* What do we do on failure? Should we try to deallocate    */
                   1650:         /* the stuff we created, or will the system do this for us? */
                   1651: 
                   1652:     return  ioReturn;
                   1653: }/* end AllocHdwAndChanMem */
                   1654: 
                   1655: 
                   1656:     /* Perform one-time-only channel command program initialization.    */
                   1657: 
                   1658: - (void) InitCP
                   1659: {
                   1660:     register DBDMADescriptor        *dst = cclLogAddr;
                   1661:     register const DBDMADescriptor  *src = gDescriptorList;
                   1662:     UInt32                          i;
                   1663:     UInt8                           *bp;
                   1664: 
                   1665: 
                   1666: 
                   1667:         /* Set the interrupt, branch, and wait DBDMA registers.         */
                   1668:         /* Caution: the following MESH interrupt register bits are      */
                   1669:         /* EndianSwapped, reverse polarity and in a different position. */
                   1670:         /* The pattern is: 0xvv00mm00, where mm is a mask byte          */
                   1671:         /* and vv is a value byte to match. (After EndianSwapping).     */
                   1672:         /*  0x80    means NO errors         (kMeshIntrError)            */
                   1673:         /*  0x40    means NO exceptions     (kMeshIntrException)        */
                   1674:         /*  0x20    means NO command done   (kMeshIntrCmdDone)          */
                   1675:         /*  Branch Select is used with BRANCH_FALSE                     */
                   1676: 
                   1677: //  DBDMASetInterruptSelect( 0x00000000 );  /* Never let DBDMA interrupt    */
                   1678: //  DBDMASetWaitSelect( 0x00200020 );       /* Wait until command done      */
                   1679: //  DBDMASetBranchSelect( 0x00C000C0 );     /* Branch if exception or error */
                   1680: 
                   1681:     *(volatile UInt32*)&dbdmaAddr->d_intselect  = 0x00000000;   /* Never let DBDMA interrupt    */
                   1682:     *(volatile UInt32*)&dbdmaAddr->d_wait       = 0x20002000;   /* Wait until command done      */
                   1683:     *(volatile UInt32*)&dbdmaAddr->d_branch     = 0xC000C000;   /* Br if Exc or Err             */
                   1684:     SynchronizeIO();
                   1685: 
                   1686:         /* Relocate and EndianSwap the global channel command list   */
                   1687:         /* into the page that is shared with the DBDMA device.       */
                   1688: 
                   1689:     for ( i = 0; i < gDescriptorListSize; i += sizeof( DBDMADescriptor )  )
                   1690:     {
                   1691:         dst->operation  = SWAP( src->operation );    /* copy command with count  */
                   1692: 
                   1693:         switch ( src->result & kRelAddress )
                   1694:         {
                   1695:         case kRelAddressMESH:
                   1696:             dst->address = SWAP( src->address + (UInt32)gMESHPhysAddr );
                   1697:             break;
                   1698:         case kRelAddressCP:
                   1699:             dst->address = SWAP( src->address + (UInt32)cclPhysAddr );
                   1700:             break;
                   1701:         case kRelAddressPhys:
                   1702:             dst->address = SWAP( src->address );
                   1703:             break;
                   1704:         default:
                   1705:             dst->address = SWAP( src->address );
                   1706:             break;
                   1707:         }
                   1708: 
                   1709:         switch ( src->result & kRelCmdDep )
                   1710:         {
                   1711:         case kRelCmdDepCP:
                   1712:             dst->cmdDep = SWAP( src->cmdDep + (UInt32)cclPhysAddr );
                   1713:             break;
                   1714:         case kRelCmdDepLabel:
                   1715:             dst->cmdDep = src->cmdDep;
                   1716:             break;
                   1717:         default:
                   1718:             dst->cmdDep = SWAP( src->cmdDep );
                   1719:             break;
                   1720:         }
                   1721: 
                   1722:         dst->result = 0;
                   1723:         src++;
                   1724:         dst++;
                   1725:     } /* FOR all elements in the descriptor list */
                   1726: 
                   1727:         /* Build a SCSI CDB for the autosense Request Sense command.    */
                   1728: 
                   1729:     bp = (UInt8*)CCLAddress( kcclSenseCDB );
                   1730:     *bp++ = kScsiCmdRequestSense;   /* Command                              */
                   1731:     *bp++ = 0;                      /* LUN to be filled in                  */
                   1732:     *bp++ = 0;                      /* reserved                             */
                   1733:     *bp++ = 0;                      /* reserved                             */
                   1734:     *bp++ = kMaxAutosenseByteCount; /* Allocation length - to be filled in  */
                   1735:     *bp++ = 0;                      /* Control (flag)                       */
                   1736:     return;
                   1737: }/* end InitCP */
                   1738: 
                   1739: 
                   1740:     /* Initialize the data transfer channel command list for a normal SCSI  */
                   1741:     /* command. The channel command list has a complex structure of         */
                   1742:     /* transfer groups and items, where:                                    */
                   1743:     /*  transfer group      The number of bytes transferred by a single     */
                   1744:     /*                      MESH operation. This will be from 1 to          */
                   1745:     /*                      kMaxDMATransferLength (65536 - 4096).           */
                   1746:     /*  transfer item       The number of bytes transferred by a single     */
                   1747:     /*                      DBDMA operation. These bytes are guaranteed     */
                   1748:     /*                      to be physically-contiguous.                    */
                   1749:     /* Thus, the data transfer CCL looks like the following:                */
                   1750:     /*      Prolog 1:       Load MESH with the first group count.           */
                   1751:     /*      Item 1.1:       Load DBDMA with the first physical address and  */
                   1752:     /*                      item count.                                     */
                   1753:     /*      Item 1.2 etc:   Load DBDMA with the next physical address and   */
                   1754:     /*                      item count.                                     */
                   1755:     /*      Prolog 2, etc.  Load MESH with the next group count.            */
                   1756:     /*      Item 2.1, etc.  Load DBDMA with the next group of physical      */
                   1757:     /*                      addresses.                                      */
                   1758:     /*      Stop/Branch     If all of the data transfer commands fit in the */
                   1759:     /*                      channel command list, branch to the Status phase*/
                   1760:     /*                      channel command. Otherwise, stop transfer       */
                   1761:     /*                      (which stops in Data phase) and re-build the    */
                   1762:     /*                      command list for the next set of data.          */
                   1763:     /* Note that the last DBDMA command must be INPUT_LAST or OUTPUT_LAST   */
                   1764:     /* to handle synchronous transfer odd-byte disconnect.                  */
                   1765: 
                   1766: - (void) UpdateCP : (Boolean) reselecting
                   1767: {
                   1768:     CommandBuffer       *cmdBuf;
                   1769:     IOSCSIRequest       *scsiReq;
                   1770:     DBDMADescriptor     *descProto = CCLDescriptor( kcclPrototype );
                   1771:     IOReturn            ioReturn   = IO_R_SUCCESS;
                   1772:     DBDMADescriptor     *descriptorPtr;     /* current data descriptor          */
                   1773:     DBDMADescriptor     *descriptorMax;     /* beyond the last data descriptor  */
                   1774:     DBDMADescriptor     *preamblePtr;       /* current prolog descriptor        */
                   1775:     UInt32              dbdmaOpProto;       /* prototype Opcode for DBDMA       */
                   1776:     UInt32              dbdmaOp;            /* Opcode for DBDMA                 */
                   1777:     UInt32              meshSeq;            /* Opcode for MESH request          */
                   1778:     SInt32              transferLength;     /* Number of bytes left to transfer */
                   1779:     UInt32              totalXferLen   = 0; /* Total length of this transfer    */
                   1780:     UInt32              groupLength;        /* Number of bytes in this group    */
                   1781:     UInt8               syncParms;          /* Fast synchronous param value     */
                   1782:     ByteCount           bc;
                   1783:     PhysicalRange       range;
                   1784:     ItemCount           rangeByteCount;
                   1785:     DBDMADescriptor     *dp;
                   1786: 
                   1787: 
                   1788:     ASSERT( gActiveCommand && gActiveCommand->scsiReq );
                   1789:     cmdBuf  = gActiveCommand;
                   1790:     scsiReq = cmdBuf->scsiReq;
                   1791:     ASSERT( scsiReq->target == gCurrentTarget && scsiReq->lun == gCurrentLUN );
                   1792: 
                   1793:         /* How many descriptors can we store (need some slop for the    */
                   1794:         /* terminator commands). Get a pointer to the first free        */
                   1795:         /* descriptor and the total number of bytes left to transfer in */
                   1796:         /* this IO request.                                             */
                   1797: 
                   1798:     descriptorPtr   = CCLDescriptor( kcclDataXfer );
                   1799:     descriptorMax   = &descriptorPtr[ gDBDMADescriptorMax - 16 ];
                   1800:     transferLength  = scsiReq->maxTransfer - cmdBuf->currentDataIndex;
                   1801:     ELG( cmdBuf, transferLength, 'UpCP', "UpdateCP" );
                   1802: 
                   1803:     if ( reselecting == FALSE )
                   1804:     {
                   1805:         [ self SetupMsgO ];     /* Setup for Message Out phase. */
                   1806: 
                   1807:                                 /* Setup for Command phase:     */
                   1808:         CCLByte( kcclCmdoMTC )  = cmdBuf->cdbLength;    /* MESH transfer count  */
                   1809:         CCLByte( kcclCmdoDTC )  = cmdBuf->cdbLength;    /* DBDMA count          */
                   1810:         bcopy( &scsiReq->cdb, CCLAddress( kcclCMDOdata ), cmdBuf->cdbLength );
                   1811:     }
                   1812: 
                   1813:         /* Generate MESH "sequence" & DBDMA "operation" for Input or Output:    */
                   1814: 
                   1815:     if ( scsiReq->read )
                   1816:     {   dbdmaOpProto    = INPUT_MORE | kBranchIfFalse;
                   1817:         meshSeq         = kMeshDataInCmd | kMeshSeqDMA;
                   1818:     }
                   1819:     else
                   1820:     {   dbdmaOpProto    = OUTPUT_MORE | kBranchIfFalse;
                   1821:         meshSeq         = kMeshDataOutCmd | kMeshSeqDMA;
                   1822:     }
                   1823: 
                   1824:     CCLWord( kcclBatchSize ) = 0;
                   1825: 
                   1826:     while ( ioReturn == IO_R_SUCCESS
                   1827:             && transferLength > 0
                   1828:             && descriptorPtr < descriptorMax )
                   1829:     {
                   1830:             /* Do one group, ie, enough CCs to fill a MESH transfer count.  */
                   1831:             /* There are more data to be transferred, and CCL space to store*/
                   1832:             /* another group of data. First, leave space for the preamble.  */
                   1833: 
                   1834:         preamblePtr      = descriptorPtr;
                   1835:         groupLength      = 0;
                   1836:         descriptorPtr   += 4;               /* Preamble takes 4 descriptors */
                   1837: 
                   1838:         while ( transferLength  > 0                     /* more to xfer     */
                   1839:              && descriptorPtr   < descriptorMax )       /* room in CCL      */
                   1840:         {
                   1841:                 /* Do one physically contiguous segment:   */
                   1842: 
                   1843:             bc = MAX_DMA_XFER - groupLength; /* calc room left in group  */
                   1844:             if ( bc < page_size )
                   1845:                 break;
                   1846:             rangeByteCount = [ cmdBuf->mem getPhysicalRanges : (ItemCount) 1
                   1847:                                 maxByteCount    : bc
                   1848:                                 newPosition     : NULL
                   1849:                                 actualRanges    : NULL
                   1850:                                 physicalRanges  : &range ];
                   1851: 
                   1852:             if ( rangeByteCount == 0 )
                   1853:                 break;
                   1854: 
                   1855:             ASSERT( range.length > 0 );
                   1856:             groupLength     += range.length;
                   1857:             transferLength  -= range.length;
                   1858:             dbdmaOp          = dbdmaOpProto | range.length;
                   1859:             if ( transferLength <= 0 )
                   1860:                  dbdmaOp |= (OUTPUT_MORE ^ OUTPUT_LAST);    /* add LAST to cmd  */
                   1861:             descriptorPtr->operation    = SWAP( dbdmaOp );
                   1862:             descriptorPtr->address      = SWAP( (UInt32)range.address );
                   1863:             descriptorPtr->cmdDep       = SWAP( (UInt32)cclPhysAddr + kcclProblem );
                   1864:             descriptorPtr->result       = 0;    // for debugging
                   1865:             descriptorPtr++;
                   1866:         }/* end inner WHILE */
                   1867: 
                   1868:         if ( groupLength == 0 )
                   1869:         {
                   1870:                 /* Nothing was built - we apparently failed to get              */
                   1871:                 /* a physical address. Note: there is a potential problem with  */
                   1872:                 /* the following sequence as the *previous* DBDMA command, if   */
                   1873:                 /* any, should be changed to set xxPUT_LAST.                    */
                   1874: 
                   1875:             ELG( 0, 0, 'Grp-', "UpdateCP - groupLength is 0" );
                   1876:             preamblePtr->operation  = SWAP(
                   1877:                                         NOP_CMD | kBranchIfFalse | kWaitIfTrue );
                   1878:             preamblePtr->address    = 0;
                   1879:             preamblePtr->cmdDep     = SWAP( (UInt32)cclPhysAddr + kcclProblem );
                   1880:             preamblePtr->result     = 0;
                   1881:             descriptorPtr           = preamblePtr + 1;
                   1882:             ioReturn = IO_R_INVALID;    /* Exit the outer loop      */
                   1883:         }
                   1884:         else
                   1885:         {
                   1886:             totalXferLen += groupLength;
                   1887: 
                   1888:                 /* This group is complete. Fill in the preamble.        */
                   1889:                 /* The preamble consists of the following commands:     */
                   1890:                 /*  [0] Move <totalXferLen> to kcclBatchSize            */
                   1891:                 /*  [1] Store group length high-byte in MESH            */
                   1892:                 /*      transfer count 1 register                       */
                   1893:                 /*  [2] Store group length low-byte in MESH             */
                   1894:                 /*      transfer count 1 register                       */
                   1895:                 /*  [3] Store the input/output command in the MESH      */
                   1896:                 /*      sequence register.                              */
                   1897:                 /* If the command finishes prematurely (perhaps the     */
                   1898:                 /* device wants to disconnect), the interrupt service   */
                   1899:                 /* routine will use totalXferLen - the residual byte    */
                   1900:                 /* count to determine the number of bytes xferred.      */
                   1901: 
                   1902:             descProto[0].cmdDep = totalXferLen; // update batch size
                   1903:             descProto[1].cmdDep = SWAP( groupLength >> 8 );
                   1904:             descProto[2].cmdDep = SWAP( groupLength & 0xFF );
                   1905:             descProto[3].cmdDep = SWAP( meshSeq );
                   1906:             bcopy( descProto, preamblePtr, sizeof( DBDMADescriptor ) * 4 );
                   1907:             ELG( preamblePtr, totalXferLen, '=Tot', "UpdateCP - set preamble" );
                   1908: 
                   1909:                 /* If there is another group, wait for */
                   1910:                 /* cmdDone and clear it:               */
                   1911:             if ( transferLength > 0 )
                   1912:             {       /* Wait for CmdDone: */
                   1913:                 bcopy( CCLDescriptor( kcclBrProblem ), descriptorPtr, sizeof( DBDMADescriptor ) );
                   1914:                 ++descriptorPtr;
                   1915:                     /* Clear CmdDone:    */
                   1916:                     /* HACK - if we reached the end of the CCL page,       */
                   1917:                     /* we don't want to clear cmdDone because we will lose */
                   1918:                     /* an interrupt. So, this instruction may be deleted   */
                   1919:                     /* down below. (Radar 2298440)                         */
                   1920:                 descriptorPtr->operation = SWAP( STORE_QUAD | KEY_SYSTEM | 1 );
                   1921:                 descriptorPtr->address   = SWAP( (UInt32)gMESHPhysAddr + kMeshInterrupt );
                   1922:                 descriptorPtr->cmdDep    = SWAP( kMeshIntrCmdDone );
                   1923:                 descriptorPtr->result    = 0;
                   1924:                 ++descriptorPtr;
                   1925:             }/* end IF not last group */
                   1926:         }/* end if/ELSE a group was built */
                   1927:     }/* end outer WHILE */
                   1928: 
                   1929:         /* All of the data have been transferred (or we ran off the end */
                   1930:         /* of the CCL). Update the transfer start index to reflect on   */
                   1931:         /* what we *think* we will transfer in this DATA operation. If  */
                   1932:         /* we completed DATA phase, branch to the Status Phase CCL;     */
                   1933:         /* if not, stop the channel command so we can reload the CCL    */
                   1934:         /* with the next big chunk.                                     */
                   1935:         /* When the transfer completes, the last prolog will have stored*/
                   1936:         /* the total number of bytes transferred in a known location in */
                   1937:         /* the CCL area.                                                */
                   1938:         /* Now, append the data transfer postamble to handle            */
                   1939:         /* synchronous odd-byte disconnect and jump to status phase     */
                   1940:         /* (or just stop if there's more DMA)                           */
                   1941: 
                   1942: #define kMaxPostamble           9
                   1943: #define kDBDMADescriptorEnd     (CCLDescriptor(kcclDataXfer) + gDBDMADescriptorMax)
                   1944: 
                   1945:      ASSERT( descriptorPtr + kMaxPostamble < kDBDMADescriptorEnd );
                   1946: 
                   1947:          /* Do some synchronous data transfer cleanup: */
                   1948: 
                   1949:     syncParms = gPerTargetData[ scsiReq->target ].syncParms;
                   1950:     meshAddr->syncParms = syncParms;
                   1951:     SynchronizeIO();
                   1952:     ELG( gMsgOutFlag, syncParms, 'SynP', "UpdateCP - sync parms" );
                   1953: 
                   1954:     if ( ((syncParms & 0xF0) || (gMsgOutFlag & kFlagMsgOut_SDTR))  // Sync?
                   1955:      && (totalXferLen > 0)         // any data moving?
                   1956:      && (transferLength == 0) )    // end of xfer?
                   1957:     {
                   1958:         gFlagIncompleteDBDMA = FALSE;               /* indicate complete xfer  */
                   1959: 
                   1960:             /* MESH has a problem at the end of Synchronous transfers.          */
                   1961:             /* If the target is fast enough, it can move from data phase to     */
                   1962:             /* Status phase while MESH still has ACKed bytes in its FIFO and    */
                   1963:             /* the DBDMA is still running. MESH raises PhaseMismatch Exception  */
                   1964:             /* causing an interrupt in which we must empty the FIFO and move    */
                   1965:             /* the bytes to the user's buffer by programmed IO.                 */
                   1966:             /* If the target is not fast enough, we can save the interrupt and  */
                   1967:             /* bypass the mess.                                                 */
                   1968:             /* So, we do the following:                                         */
                   1969:             /* 1)  Enable only MESH Err interrupts; disable Exc and CmdDone.    */
                   1970:             /* 2)  Don't Wait; Branch if an interrupt may have already occurred.*/
                   1971:             /* 3)  Wait for cmdDone at least for TC = FIFO count = 0 and        */
                   1972:             /*     maybe including PhaseMismatch. Branch to SyncCleanup if PMM. */
                   1973:             /* 4)  Assume an interphase condition as opposed to an              */
                   1974:             /*     overrun condition and Branch Always to get Status.           */
                   1975: 
                   1976:             /* If the Channel Program gets this far, the OUTPUT_LAST        */
                   1977:             /* has finished writing its data to the FIFO and MESH may still */
                   1978:             /* be putting bytes on the bus OR the INPUT_LAST has read all   */
                   1979:             /* its data from the FIFO and MESH has already ACKed them.      */
                   1980:             /* There may be or not some time before REQ appears again,      */
                   1981:             /* either for data overrun or the next phase.                   */
                   1982: 
                   1983:             /* Disable Exc and CmdDone (leave Err enabled): */
                   1984: 
                   1985:         descriptorPtr->operation    = SWAP( STORE_QUAD | KEY_SYSTEM | 1 );
                   1986:         descriptorPtr->address      = SWAP( (UInt32)gMESHPhysAddr + kMeshInterruptMask );
                   1987:         descriptorPtr->cmdDep       = SWAP( kMeshIntrError );
                   1988:         descriptorPtr->result       = 0;
                   1989:         ++descriptorPtr;
                   1990: 
                   1991:             /* Take the interrupt if PhaseMismatch not definitely caught.        */
                   1992:             /* Branch (don't wait for cmdDone) if Exc may have already occurred: */
                   1993: 
                   1994:         descriptorPtr->operation    = SWAP( NOP_CMD | kBranchIfFalse );
                   1995:         descriptorPtr->address      = 0;
                   1996:         descriptorPtr->cmdDep       = SWAP( (UInt32)cclPhysAddr + kcclProblem );
                   1997:         descriptorPtr->result       = 0;
                   1998:             /* Radar 2281306 ( and 2272931 ):                                 */
                   1999:             /* Output may completely fit in the FIFO and not make it out      */
                   2000:             /* to the SCSI bus if the target disconnects after the command.   */
                   2001:             /* If that's possible, wait here for cmdDone and                  */
                   2002:             /* take the PhaseMismatch interrupt. This situation occurred on a */
                   2003:             /* Mode Select with an output of 12 bytes. Do this to prevent     */
                   2004:             /* the Stage from advancing from kcclStageXfer so that proper     */
                   2005:             /* cleanup can take place.                                        */
                   2006:         if ( (totalXferLen < 16) && !scsiReq->read )
                   2007:             descriptorPtr->operation= SWAP( NOP_CMD | kWaitIfTrue | kBranchIfFalse );
                   2008:         ++descriptorPtr;
                   2009: 
                   2010:             /* Possible PhaseMisMatch caught after FIFO emptied. */
                   2011:             /* Wait for cmdDone. If Exc, branch to SyncCleanUp:  */
                   2012: 
                   2013:         descriptorPtr->operation    = SWAP( NOP_CMD | kWaitIfTrue | kBranchIfFalse );
                   2014:         descriptorPtr->address      = 0;
                   2015:         descriptorPtr->cmdDep       = SWAP( (UInt32)cclPhysAddr + kcclSyncCleanUp );
                   2016:         descriptorPtr->result       = 0;
                   2017:         descriptorPtr++;
                   2018: 
                   2019:             /* Interphase condition or possible overrun.  */
                   2020:             /* 29sep98 PhaseMismatch occurred even after  */
                   2021:             /* CmdDone was set.                           */
                   2022: 
                   2023: 
                   2024:             /* Branch Always to assume we will bit bucket some data: */
                   2025: 
                   2026:         descriptorPtr->operation    = SWAP( NOP_CMD | kBranchAlways );
                   2027:         descriptorPtr->address      = 0;
                   2028:         descriptorPtr->cmdDep       = SWAP( (UInt32)cclPhysAddr + kcclOverrun );
                   2029:         descriptorPtr->result       = 0;
                   2030:         descriptorPtr++;
                   2031: 
                   2032:             /* Fix up the DataOverrun code just in case: */
                   2033: 
                   2034:         dp = CCLDescriptor( kcclOverrunMESH );
                   2035:         if ( scsiReq->read )
                   2036:         {   dp->cmdDep = SWAP( kMeshDataInCmd | kMeshSeqDMA );
                   2037:             dp = CCLDescriptor( kcclOverrunDBDMA ); 
                   2038:             dp->operation = SWAP( INPUT_LAST | kBranchIfFalse | 8 );
                   2039:         }
                   2040:         else
                   2041:         {   dp->cmdDep = SWAP( kMeshDataOutCmd | kMeshSeqDMA );
                   2042:             dp = CCLDescriptor( kcclOverrunDBDMA ); 
                   2043:             dp->operation = SWAP( OUTPUT_LAST | kBranchIfFalse | 8 );
                   2044:         }
                   2045:     }/* end IF last of Synchronous transfer */
                   2046:     else
                   2047:     {
                   2048:             /* Async or incomplete Sync. Append Branches to finish this process: */
                   2049: 
                   2050:             /* If this is a partial transfer, set 'incomplete' flag.  */
                   2051: 
                   2052:         if ( transferLength > 0 )
                   2053:              gFlagIncompleteDBDMA = TRUE;    /* set incomplete        */
                   2054:         else gFlagIncompleteDBDMA = FALSE;   /* assume complete xfer  */
                   2055: 
                   2056: 
                   2057:         if ( gFlagIncompleteDBDMA )
                   2058:         {                        /* Delete the ccl to clear cmdDone:  */
                   2059:              --descriptorPtr;    /* see HACK note above.              */
                   2060:         }
                   2061:         else if ( totalXferLen > 0 )
                   2062:         {       /* If something moved AND (Radar 2298440) xfer completed,  */
                   2063:                 /*  Wait & Branch if problem:                              */
                   2064:                 /* Radar 2272931 - If entire output fits in FIFO, then     */
                   2065:                 /* the OUTPUT_LAST completes OK without a PhaseMismatch if */
                   2066:                 /* the target disconnects right after the command phase.   */
                   2067:             bcopy( CCLDescriptor( kcclBrProblem ), descriptorPtr, sizeof( DBDMADescriptor ) );
                   2068:             descriptorPtr++;
                   2069:         }
                   2070:             /* Assume all's well - Branch to get status: */
                   2071:         descriptorPtr->operation    = SWAP( NOP_CMD | kBranchAlways );
                   2072:         descriptorPtr->address      = 0;
                   2073:         descriptorPtr->cmdDep       = SWAP( (UInt32)cclPhysAddr + kcclGetStatus );
                   2074:         descriptorPtr->result       = 0;
                   2075: 
                   2076:             /* If this is a partial transfer, set 'incomplete' flag and */
                   2077:             /* change the Branch from GetStatus to Good:                */
                   2078: 
                   2079:         if ( gFlagIncompleteDBDMA )
                   2080:         {       /* change last Branch from Status to Good: */
                   2081:             descriptorPtr->cmdDep = SWAP( (UInt32)cclPhysAddr + kcclMESHintr );
                   2082:             ELG( descriptorPtr, transferLength, 'Part', "UpdateCP - built partial CCL." );
                   2083:         }
                   2084:         descriptorPtr++;
                   2085:     }/* end if/ELSE Async or partial xfer */
                   2086: 
                   2087:     ASSERT( descriptorPtr < kDBDMADescriptorEnd );
                   2088:     return;
                   2089: }/* end UpdateCP */
                   2090: 
                   2091: 
                   2092:     /* StartBucket -  Start the channel commands to run the bit bucket. */
                   2093: 
                   2094: - (void) StartBucket
                   2095: {
                   2096:     CommandBuffer       *cmdBuf;
                   2097:     IOSCSIRequest       *scsiReq;
                   2098:     DBDMADescriptor     *dp;      /* current data descriptor          */
                   2099:     UInt32              dbdmaOp;  /* Opcode for DBDMA                 */
                   2100:     UInt32              meshSeq;  /* Opcode for MESH request          */
                   2101: 
                   2102: 
                   2103:     cmdBuf  = gActiveCommand;
                   2104:     scsiReq = cmdBuf->scsiReq;
                   2105:     ELG( cmdBuf, scsiReq, 'Bkt-', "StartBucket" );
                   2106: 
                   2107:         /* Generate MESH "sequence" & DBDMA "operation" for Input or Output:   */
                   2108: 
                   2109:     if ( scsiReq->read )
                   2110:     {   dbdmaOp = INPUT_MORE | kBranchIfFalse | 8;
                   2111:         meshSeq = kMeshDataInCmd | kMeshSeqDMA;
                   2112:     }
                   2113:     else
                   2114:     {   dbdmaOp = OUTPUT_MORE | kBranchIfFalse | 8;
                   2115:         meshSeq = kMeshDataOutCmd | kMeshSeqDMA;
                   2116:     }
                   2117: 
                   2118:     dp = CCLDescriptor( kcclOverrunMESH );   dp->cmdDep    = meshSeq;
                   2119:     dp = CCLDescriptor( kcclOverrunDBDMA );  dp->operation = dbdmaOp;
                   2120: 
                   2121:     [ self RunDBDMA : kcclDataXfer  stageLabel : kcclStageBucket ];
                   2122:     return;
                   2123: }/* end StartBucket */
                   2124: 
                   2125: 
                   2126:     /* Set up the channel commands for MsgO phase.  */
                   2127: 
                   2128: - (void) SetupMsgO
                   2129: {
                   2130:     UInt8       msgoSize;
                   2131: 
                   2132: 
                   2133:     msgOutPtr--;       /* treat the last or only byte special (drop ATN)   */
                   2134:     msgoSize = msgOutPtr - CCLAddress( kcclMSGOdata );
                   2135:     if( msgoSize == 0 )
                   2136:     {       /* Identify byte only:  */
                   2137:         CCLWord( kcclMsgoBranch ) = SWAP( NOP_CMD | kBranchAlways );
                   2138:     }
                   2139:     else    /* multibyte message - set counts for all but last byte:    */
                   2140:     {   CCLByte( kcclMsgoMTC )  = msgoSize;
                   2141:         CCLByte( kcclMsgoDTC )  = msgoSize;
                   2142:             /* NOP the BRANCH:  */
                   2143:         CCLWord( kcclMsgoBranch ) = SWAP( NOP_CMD );
                   2144:     }
                   2145:     CCLByte( kcclMSGOLast )= *msgOutPtr;           /* position last byte   */
                   2146:     return;
                   2147: }/* end SetupMsgO */
                   2148: 
                   2149: 
                   2150:     /* Initialize the autosense area and build the autosense channel command.   */
                   2151: 
                   2152: - (void) InitAutosenseCCL
                   2153: {
                   2154:     ELG( 0, 0, 'Auto', "InitAutosenseCCL" );
                   2155:         /* Make sure we've allocated enough space in the CCL area.  */
                   2156: 
                   2157:     ASSERT( kcclSenseBuffer + kMaxAutosenseByteCount < kcclSenseResult );
                   2158:     bzero( CCLAddress( kcclSenseBuffer ), kMaxAutosenseByteCount );
                   2159: 
                   2160:         /* Copy the Sense CDB to the CDB area and   */
                   2161:         /* copy the Sense CCL to the Xfer area      */
                   2162: 
                   2163:         /* Copy the Sense CDB & Sense CCL */
                   2164:     bcopy( CCLAddress( kcclSenseCDB ), CCLAddress( kcclCMDOdata ), 6 );
                   2165:     bcopy( CCLAddress( kcclSense ), CCLAddress( kcclDataXfer ), 5 * sizeof( DBDMADescriptor ) );
                   2166: 
                   2167:         /* Set the MESH and DBDMA transfer counts for the command.  */
                   2168:     CCLByte( kcclCmdoMTC ) = 6;
                   2169:     CCLByte( kcclCmdoDTC ) = 6;
                   2170: 
                   2171:         /* Set the data transfer count (use a hard-wired value).   */
                   2172: 
                   2173:     CCLWord( kcclBatchSize ) = kMaxAutosenseByteCount;
                   2174: 
                   2175:     [ self SetupMsgO ];
                   2176: 
                   2177:     return;
                   2178: }/* end InitAutosenseCCL */
                   2179: 
                   2180: 
                   2181: - (void) ClearCPResults
                   2182: {
                   2183:     register DBDMADescriptor    *dp = CCLDescriptor( kcclStart );
                   2184:     register int                i;
                   2185: 
                   2186: 
                   2187:         /*  Don't clear the reserved areas or prototypes    */
                   2188: 
                   2189:     for ( i = (gDescriptorListSize - kcclStart) / sizeof ( DBDMADescriptor ); i; --i )
                   2190:     {
                   2191:         dp->result = 0;
                   2192:         dp++;
                   2193:     }
                   2194: 
                   2195:     return;
                   2196: }/* end ClearCPResults */
                   2197: 
                   2198: 
                   2199: @end /* AppleMesh_SCSI(HardwarePrivate) */
                   2200: 
                   2201: 
                   2202: 
                   2203: 
                   2204: @implementation AppleMesh_SCSI( MeshInterrupt )
                   2205: 
                   2206: 
                   2207:     /* DoHardwareInterrupt - Handle an Interrupt Service message    */
                   2208: 
                   2209: - (void) DoHardwareInterrupt    /* called from interruptOccurred    */
                   2210: {
                   2211:     [ self GetHBARegsAndClear : TRUE ];     /* get the MESH registers   */
                   2212:     [ self SetIntMask : 0 ];                /* Disable MESH interrupts  */
                   2213: 
                   2214:     gFlagReselecting = FALSE;
                   2215: 
                   2216:     if ( g.shadow.mesh.interrupt == 0 )
                   2217:     {       /* Interrupts can occur with no bits set in the         */
                   2218:             /* interrupt register one way:                          */
                   2219:             /*  -   Eating interrupts in the driver (the ASIC       */
                   2220:             /*          latches the interrupt even though the       */
                   2221:             /*          driver or Channel Program clears the MESH   */
                   2222:             /*          interrupt register).                        */
                   2223:         PAUSE(  dbdmaAddr->d_cmdptrlo,
                   2224:                 (g.shadow.mesh.busStatus0 << 8) | g.shadow.mesh.busStatus1,
                   2225:                 'ISR?',
                   2226:                 "DoHardwareInterrupt - spurious interrupt" );
                   2227: 
                   2228:         if ( !gActiveCommand )
                   2229:         {
                   2230:             [ self selectNextRequest ];
                   2231:             if ( !gActiveCommand && queue_empty( &abortCmdQ ) )
                   2232:                     /* if neither new request nor aborting:   */
                   2233:                 [ self SetIntMask : kMeshIntrMask ];/* Enable interrupts    */
                   2234:         }
                   2235:         return;
                   2236:     }/* end IF no bit set in interrupt register */
                   2237: 
                   2238:     dbdma_flush( DBDMA_MESH_SCSI );         /* DBDMA may be hung in */
                   2239:     dbdma_stop(  DBDMA_MESH_SCSI );         /* middle of transfer.  */
                   2240: //  invalidate_cache_v( (vm_offset_t)cclLogAddr, cclLogAddrSize );
                   2241: 
                   2242:         /* If the DBDMA was running a channel command, handle this  */
                   2243:         /* (this could be done at a lower priority level).          */
                   2244: 
                   2245:     if ( CCLWord( kcclStageLabel ) )
                   2246:     {
                   2247:         [ self ProcessInterrupt ];
                   2248:         return;
                   2249:     }
                   2250: 
                   2251:         /* This was not a DBDMA completion.         */
                   2252:         /* See if the last MESH operation completed */
                   2253:         /* without errors or exceptions.            */
                   2254: 
                   2255:     if ( g.shadow.mesh.interrupt == kMeshIntrCmdDone )
                   2256:     {
                   2257:             /* This was presumably a Programmed IO completion.  */
                   2258: 
                   2259:         if ( gActiveCommand )
                   2260:         {       /* The command has not completed yet.                   */
                   2261:                 /* We need to wait for a phase stabilizing interrupt.   */
                   2262:     
                   2263:             PAUSE( 0, 0, 'dhi-', "DoHardwareInterrupt - MESH interrupt problem: need phase stabilizing wait.\n" );
                   2264:             return;
                   2265:         }
                   2266:         else
                   2267:         {       /* There is no active command.                  */
                   2268:                 /* This is presumably a bus-free completion.    */
                   2269: 
                   2270:             [ self selectNextRequest ]; /* Try to start another request.*/
                   2271: 
                   2272:             if ( !gActiveCommand && queue_empty( &abortCmdQ ) )
                   2273:                     /* If still nothing to do:  */
                   2274:                 [ self SetIntMask : kMeshIntrMask ];/* Re-enable ints   */
                   2275:             return;
                   2276:         }
                   2277:     }/* end IF CmdDone without Err or Exc */
                   2278: 
                   2279:         /* None of the above "completion" states occurred.      */
                   2280:         /* Either a command completed unsuccessfully, or we     */
                   2281:         /* were reselected. First, check for phase mismatch.    */
                   2282:     if ( g.shadow.mesh.interrupt == (kMeshIntrCmdDone | kMeshIntrException)
                   2283:      &&  g.shadow.mesh.exception == kMeshExcPhaseMM )
                   2284:     {
                   2285:             PAUSE( 0, 0, 'DHI-', "DoHardwareInterrupt - MESH interrupt problem: phase mismatch interrupt.\n" );
                   2286:     }
                   2287:     else
                   2288:     {       /* Handle reselection and all other problems separately.    */
                   2289:             /* (This can be done at a lower priority.)                  */
                   2290:         [ self ProcessInterrupt ];
                   2291:     }
                   2292:     return;
                   2293: }/* end DoHardwareInterrupt */
                   2294: 
                   2295: 
                   2296:     /* Respond to a DBDMA channel command completion interrupt  */
                   2297:     /* or some error or exception condition.                    */
                   2298: 
                   2299: - (void) ProcessInterrupt
                   2300: {
                   2301:     register CommandBuffer  *cmdBuf;
                   2302:     register IOSCSIRequest  *scsiReq;
                   2303:     UInt32                  stage;          /* Stage in the Channel Program */
                   2304:     UInt32                  cclIndex;       /* Index of CCL descriptor      */
                   2305:     UInt32                  count;          /* transfer count               */
                   2306:     UInt8                   phase;          /* Current bus phase            */
                   2307:     IOReturn                rc;
                   2308: 
                   2309: 
                   2310:     if ( gActiveCommand == NULL )
                   2311:     {
                   2312:         if ( g.shadow.mesh.exception & kMeshExcResel )
                   2313:         {
                   2314:             [ self HandleReselectionInterrupt ];
                   2315:         }
                   2316:         else
                   2317:         {       /* There is no active request and we are not reselecting.   */
                   2318:                 /* Can get here if Reject/Abort occurs or after a BusFree   */
                   2319:                 /* command is put in the Sequence register and we exit the  */
                   2320:                 /* interrupt.                                               */
                   2321:             if ( !queue_empty( &abortCmdQ ) )
                   2322:             {
                   2323:                 [ self SetSeqReg : kMeshFlushFIFO ];     /* flush the FIFO  */
                   2324:                 queue_remove_first( &abortCmdQ, cmdBuf, CommandBuffer*, link );
                   2325:                 [ self ioComplete : cmdBuf ];
                   2326:             }/* end IF Aborting disconnected commands */
                   2327:             else
                   2328:             {       /* This should be a Bus Free interrupt: */
                   2329:                 ELG( 0, 0, 'Int0', "Process interrupt with no active request\n" );
                   2330:             }
                   2331: 
                   2332:             [ self selectNextRequest ];
                   2333:             if ( !gActiveCommand && queue_empty( &abortCmdQ ) )
                   2334:                     /* Re-enable ints for reselect  */
                   2335:                 [ self SetIntMask : (kMeshIntrException | kMeshIntrError) ];
                   2336:         }
                   2337:         return;
                   2338:     }/* end IF had no active command */
                   2339: 
                   2340:         /* There is an active request:                  */
                   2341:         /* get the stage of the CCL and Switch on it.   */
                   2342:     stage       = CCLWord( kcclStageLabel );
                   2343:     cmdBuf      = gActiveCommand;
                   2344:     scsiReq     = cmdBuf->scsiReq;
                   2345:     cclIndex    = SWAP( dbdmaAddr->d_cmdptrlo )
                   2346:                 - (UInt32) cclPhysAddr;
                   2347:     CCLWord( kcclStageLabel ) = 0;
                   2348:     ASSERT( scsiReq->target == gCurrentTarget && scsiReq->lun == gCurrentLUN );
                   2349: 
                   2350:         /* Analyse where the DBDMA ended up:    */
                   2351: 
                   2352:     switch ( stage )
                   2353:     {
                   2354:     case kcclStageGood:                         /* Normal completion        */
                   2355:         [ self DoInterruptStageGood ];
                   2356:         break;
                   2357: 
                   2358:     case kcclStageInit:                         /* Value before DBDMA runs  */
                   2359:     case kcclStageArb:                          /* Arbitration anomaly      */
                   2360:         [ self DoInterruptStageArb ];
                   2361:         break;
                   2362: 
                   2363:     case kcclStageSelA:                         /* Selection anomaly       */
                   2364:         [ self DoInterruptStageSelA ];
                   2365:         break;
                   2366: 
                   2367:     case kcclStageMsgO:                         /* Message Out              */
                   2368:         [ self DoInterruptStageMsgO ];
                   2369:         break;
                   2370: 
                   2371:     case kcclStageCmdO:                         /* Command stage anomaly   */
                   2372:         [ self DoInterruptStageCmdO ];
                   2373:         break;
                   2374: 
                   2375:     case kcclStageXfer:
                   2376:         if ( cmdBuf->flagIsAutosense )
                   2377:              [ self DoInterruptStageXferAutosense ];
                   2378:         else [ self DoInterruptStageXfer ];     /* DMA transfer complete    */
                   2379:         break;
                   2380:     
                   2381:     case kcclStageStat:             /* Synchronous, odd transfer, data-out  */
                   2382:                                     /* OR no data, disconnect               */
                   2383: 
                   2384:             /* Don't use UpdateCurrentIndex here because */
                   2385:             /* kcclStageStat destroys TC with a 1.       */
                   2386:         count  = CCLWord( kcclBatchSize );          /* Our transfer count   */
                   2387:         cmdBuf->currentDataIndex += count;          /* Increment data index */
                   2388:         if (  cmdBuf->mem )
                   2389:             [ cmdBuf->mem setPosition : cmdBuf->currentDataIndex ];
                   2390: 
                   2391:         ELG( count, cmdBuf->currentDataIndex, 'Uidx', "ProcessInterrupt" );
                   2392:         CCLWord( kcclBatchSize ) = 0;              /* Clear our count       */
                   2393: 
                   2394:             /* Analyze the current bus signals: */
                   2395: 
                   2396:         if ( !(g.shadow.mesh.busStatus0 & kMeshReq) )
                   2397:         {       /* Get here if Sync Read or Write is too short as   */
                   2398:                 /* in reading 512 bytes from a 2K block of CD-ROM.  */
                   2399:             [ self StartBucket ];
                   2400:             return;
                   2401:         }/* end IF no REQ signal */
                   2402: 
                   2403:         phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;
                   2404:         switch ( phase )
                   2405:         {
                   2406:         case kBusPhaseMSGI:
                   2407:             rc = [ self DoMessageInPhase ];
                   2408:         //  if ( rc == IO_R_SUCCESS && gActiveCommand )
                   2409:         //      break;              /* msg processed ok & not disconnect    */
                   2410:                     /* Enable Exc (for Reselect) and Err interrupts (not CmdDone)*/
                   2411:             break;
                   2412: 
                   2413:         case kBusPhaseDATO:
                   2414:         case kBusPhaseDATI:
                   2415:                 /* Get here if Async Read or Write is too short as  */
                   2416:                 /* in reading 512 bytes from a 2K block of CD-ROM   */
                   2417:             [ self StartBucket ];
                   2418:             break;
                   2419: 
                   2420:         default:
                   2421:             PAUSE( scsiReq->target, phase, 'pmm-',
                   2422:                             "ProcessInterrupt - expected Status phase.\n" );
                   2423:             break;
                   2424:         }/* end SWITCH on phase */
                   2425:         break;
                   2426: 
                   2427:     case kcclStageBucket:
                   2428:         count  = CCLWord( kcclBatchSize );          /* Our transfer count   */
                   2429:         cmdBuf->currentDataIndex += count;          /* Increment data index */
                   2430:         if (  cmdBuf->mem )
                   2431:             [ cmdBuf->mem setPosition : cmdBuf->currentDataIndex ];
                   2432:         CCLWord( kcclBatchSize ) = 0;              /* Clear our count       */
                   2433:  
                   2434:         ELG( count, cmdBuf->currentDataIndex, 'Buck', "ProcessInterrupt - bit bucket done.\n" );
                   2435: 
                   2436:     //  scsiReq->driverStatus = SR_IOST_DMAOR;     /* set DMA OverRun error */
                   2437: 
                   2438:         [ self SetSeqReg : kMeshFlushFIFO ];       /* flush the FIFO        */
                   2439:         [ self RunDBDMA : kcclGetStatus stageLabel : kcclStageStat ];
                   2440:         break;
                   2441: 
                   2442:     case kcclStageMsgI:         /* Message-in:     */
                   2443:     case kcclStageFree:         /* Bus free:       */
                   2444:     default:                    /* Can't happen?   */
                   2445:         PAUSE( cclIndex, stage, 'P i-', "ProcessInterrupt - strange or unknown interrupt for device.\n" );
                   2446:         break;
                   2447:     }/* end SWITCH on Channel Program stage */
                   2448:     return;
                   2449: }/* end ProcessInterrupt */
                   2450: 
                   2451: 
                   2452:     /* The channel command (and, hence, the IO request) ran to  */
                   2453:     /* completion without problems. Complete this IO request    */
                   2454:     /* and try to start another.                                */
                   2455: 
                   2456: - (void) DoInterruptStageGood
                   2457: {
                   2458:     register CommandBuffer      *cmdBuf;
                   2459:     register IOSCSIRequest      *scsiReq;
                   2460:     UInt32                      totalXferLen;
                   2461:     IOMemoryDescriptorState     state;
                   2462:     UInt8                       byte;
                   2463: 
                   2464: 
                   2465:     ASSERT( gActiveCmd && gActiveCmd->scsiReq );
                   2466: 
                   2467: //  [ self SetSeqReg : kMeshEnableReselect ];   // done by CCL
                   2468: 
                   2469:     cmdBuf  = gActiveCommand;
                   2470:     scsiReq = cmdBuf->scsiReq;
                   2471: 
                   2472:             /* Retrieve the total number of bytes transferred   */
                   2473:             /* in the last data phase.                          */
                   2474: 
                   2475:     cmdBuf->flagRequestSelectOK = FALSE;
                   2476:     totalXferLen = CCLWord( kcclBatchSize );
                   2477:     CCLWord( kcclBatchSize ) = 0;
                   2478: 
                   2479:     ELG( scsiReq, totalXferLen, 'Good', "DoInterruptStageGood" );
                   2480: 
                   2481:     if ( cmdBuf->flagIsAutosense )
                   2482:     {
                   2483:             /* We are completing an autosense command.      */
                   2484:             /* Copy the status byte (which had better be    */
                   2485:             /* "good" ) from the CCL to the autosense status*/
                   2486:             /* and complete the IO request. The autosense   */
                   2487:             /* data itself was copied into the user buffer  */
                   2488:             /* by a previous 'Xfer' interrupt.              */
                   2489: 
                   2490:         cmdBuf->autosenseStatus = CCLByte( kcclStatusData );
                   2491:         [ self deactivateCmd : cmdBuf ];
                   2492:         [ self ioComplete    : cmdBuf ];
                   2493:     }
                   2494:     else
                   2495:     {       /* We are completing a normal command.                  */
                   2496:             /* Update the transfer count and current data pointer.  */
                   2497: 
                   2498:         cmdBuf->currentDataIndex += totalXferLen;
                   2499:         if (  cmdBuf->mem )
                   2500:             [ cmdBuf->mem setPosition : cmdBuf->currentDataIndex ];
                   2501: 
                   2502:         if ( gFlagIncompleteDBDMA == FALSE )
                   2503:         {
                   2504:                 /* Yes, the IO is really complete:  */
                   2505: 
                   2506:             scsiReq->scsiStatus     = CCLByte( kcclStatusData );
                   2507:             scsiReq->driverStatus   = SR_IOST_GOOD;
                   2508: 
                   2509:                 /* If this was an Inquiry, peek at the data */
                   2510:                 /* for Synchronous and Queuing support:     */
                   2511: 
                   2512:             if ( (*(UInt8*)&scsiReq->cdb == kScsiCmdInquiry)
                   2513:              &&  (cmdBuf->currentDataIndex > 7) )
                   2514:             {
                   2515:                 [ cmdBuf->mem state : &state ];     /* save context */
                   2516:                 [ cmdBuf->mem setPosition : 7 ];
                   2517:                 if ( [ cmdBuf->mem readFromClient : &byte count : 1 ] == 1 )
                   2518:                 {
                   2519:                     gPerTargetData[ scsiReq->target ].inquiry_7 = byte;
                   2520:                     ELG( scsiReq->target, byte, 'Inq+',
                   2521:                         "DoInterruptStageGood - peek at Inquiry data" );
                   2522:                 }
                   2523:                 [ cmdBuf->mem setState : &state ];  /* restore context  */
                   2524:             }
                   2525:             [ self deactivateCmd    : cmdBuf ];
                   2526:             [ self ioComplete       : cmdBuf ];
                   2527:         }
                   2528:         else
                   2529:         {       /* The CCL ended, but the caller expected more data.    */
                   2530:                 /* Restart the CCL.                                     */
                   2531:                 /* Don't regenerate arbitration or command stuff.       */
                   2532: 
                   2533:             [ self UpdateCP : TRUE ];
                   2534:             [ self RunDBDMA : kcclDataXfer  stageLabel : kcclStageXfer ];
                   2535:             return;
                   2536:         }/* end ELSE need to continue Channel Program */
                   2537:     }/* end ELSE not AutoSense */
                   2538: 
                   2539:         /* Since IO completed (otherwise, we would have exited in the   */
                   2540:         /* "return" above), check whether a reselection attempt         */
                   2541:         /* is piggy-backed on top of the good DBDMA completion.         */
                   2542: 
                   2543:     if ( g.shadow.mesh.exception & kMeshExcResel )
                   2544:         [ self HandleReselectionInterrupt ];
                   2545:     else           /* Nothing happening. Try to start another request.  */
                   2546:     {
                   2547:         [ self selectNextRequest ];
                   2548:         if ( !gActiveCommand && queue_empty( &abortCmdQ ) )
                   2549:                    /* Re-enable ints for reselect  */
                   2550:             [ self SetIntMask : (kMeshIntrException | kMeshIntrError) ];
                   2551:     }
                   2552: 
                   2553:     return;
                   2554: }/* end DoInterruptStageGood */
                   2555: 
                   2556: 
                   2557:     /* Process the autosense data transfer phase. IO is not complete.   */
                   2558:     /* There are several reasons why we might get here:                 */
                   2559:     /*  -- autosense completion (which could be a separate stage)       */
                   2560:     /*  -- DMA completion with more DMA to do                           */
                   2561:     /*  -- Bus phase mismatch (short transfer or disconnect)            */
                   2562: 
                   2563: - (void) DoInterruptStageXferAutosense
                   2564: {
                   2565:     register CommandBuffer  *cmdBuf     = gActiveCommand;
                   2566:     IOSCSIRequest           *scsiReq    = cmdBuf->scsiReq;
                   2567:     UInt32                  residual;
                   2568:     UInt32                  count;
                   2569: 
                   2570: 
                   2571:     cmdBuf->flagRequestSelectOK = FALSE;
                   2572: 
                   2573:         /* An autosense Data In transfer is complete. Copy the  */
                   2574:         /* autosense data from our private buffer to the        */
                   2575:         /* caller's sense_data area and restart IO to get the   */
                   2576:         /* status and command-complete message byte.            */
                   2577: 
                   2578:     residual = SWAP( CCLWord( kcclSenseResult ) ) & 0xFF;
                   2579:     count = kMaxAutosenseByteCount - residual;
                   2580:     ASSERT( count <= sizeof( esense_reply_t ) );
                   2581:     bcopy( CCLAddress( kcclSenseBuffer ), &scsiReq->senseData, count );
                   2582: 
                   2583:         /* Driver Kit does not return "sense valid" or  */
                   2584:         /* the actual sense transfer count.             */
                   2585:         /* Restart the channel command to fetch the     */
                   2586:         /* status byte and Command Completion byte.     */
                   2587: 
                   2588:     [ self RunDBDMA : kcclGetStatus stageLabel : kcclStageStat ];
                   2589:     return;
                   2590: }/* end DoInterruptStageXferAutosense */
                   2591: 
                   2592: 
                   2593:     /* Process a normal data phase interrupt. IO is not complete.   */
                   2594:     /* There are several reasons why we might get here:             */
                   2595:     /*  -- autosense completion (which could be a separate stage)   */
                   2596:     /*  -- DMA completion with more DMA to do                       */
                   2597:     /*  -- Bus phase mismatch (short transfer or disconnect, MsgIn) */
                   2598:     /* Note that we know that we are not in autosense.              */
                   2599: 
                   2600: - (void) DoInterruptStageXfer
                   2601: {
                   2602:     register CommandBuffer  *cmdBuf     = gActiveCommand;
                   2603:     UInt32                  count;          /* DMA transfer count   */
                   2604:     UInt8                   phase;          /* Current bus phase    */
                   2605:     IOReturn                rc;
                   2606:     int                     goAround;
                   2607: 
                   2608: 
                   2609:     cmdBuf->flagRequestSelectOK = FALSE;
                   2610:     count = cmdBuf->currentDataIndex;
                   2611: 
                   2612:     [ self UpdateCurrentIndex ];
                   2613: 
                   2614:     do
                   2615:     {   goAround = FALSE;       /* assume loop not repeated */
                   2616:         [ self SetSeqReg : kMeshFlushFIFO ];
                   2617: 
                   2618:             /* We've cleaned up the mess from the previous data transfer.   */
                   2619:             /* Look at the current bus phase. The channel command waited    */
                   2620:             /* for REQ to be set before interrupting the processor.         */
                   2621: 
                   2622:         phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;
                   2623:         ASSERT( g.shadow.mesh.busStatus0 & kMeshReq );  /* REQ is set, right?   */
                   2624: 
                   2625:         switch ( phase )
                   2626:         {
                   2627:         case kBusPhaseSTS:
                   2628:             gFlagIncompleteDBDMA = FALSE;       /* indicate no-more-data    */
                   2629:             [ self RunDBDMA : kcclGetStatus     stageLabel : kcclStageStat ];
                   2630:             break;
                   2631: 
                   2632:         case kBusPhaseMSGI:
                   2633:             rc = [ self DoMessageInPhase ];
                   2634:             if ( rc == IO_R_SUCCESS && gActiveCommand )
                   2635:                 goAround = TRUE;                /* msg ok & not disconnect  */
                   2636:             break;
                   2637: 
                   2638:         case kBusPhaseDATO:
                   2639:         case kBusPhaseDATI:
                   2640:             if ( count != cmdBuf->currentDataIndex )
                   2641:             {       /* Data phase had already started:  */
                   2642:                 PAUSE( 0, phase, 'dat-', "DoInterruptStageXfer - unexpected Data phase.\n" );
                   2643:             }
                   2644:             else
                   2645:             {       /* try starting data phase again    */
                   2646:                 [ self RunDBDMA : kcclDataXfer  stageLabel : kcclStageXfer ];
                   2647:             }
                   2648:             break;
                   2649: 
                   2650:         default:
                   2651:             PAUSE( cmdBuf->scsiReq->target, phase, 'Phs-', "DoInterruptStageXfer - bogus phase.\n" );
                   2652:             break;
                   2653:         }/* end SWITCH on phase */
                   2654:     } while ( goAround );
                   2655:     return;
                   2656: }/* end DoInterruptStageXfer */
                   2657: 
                   2658: 
                   2659:     /* DoInterruptStageArb - Process an anomaly during arbitration.                 */
                   2660: 
                   2661: - (void) DoInterruptStageArb
                   2662: {
                   2663:     ASSERT( gActiveCommand );
                   2664:     ELG( 0, 0, 'Arb-', "DoInterruptStageArb - Lost arbitration.\n" );
                   2665: 
                   2666:     [ self pushbackCurrentRequest : gActiveCommand ];
                   2667:     ASSERT( gActiveCommand == NULL );
                   2668: 
                   2669:     if ( g.shadow.mesh.exception & kMeshExcResel )
                   2670:     {   if ( g.shadow.mesh.error & kMeshErrDisconnected )
                   2671:         {
                   2672:                 /* 18sep98 - Sometimes MESH gets real confused when its        */
                   2673:                 /* arbitration loses to a target's reselect arbitration.       */
                   2674:                 /* The registers show Exc:ArbLost, Resel and Err:UnExpDisc.    */
                   2675:                 /* The FIFO count is 1 (should be SCSI ID bits) while the      */
                   2676:                 /* BusStatus0,1 registers show IO and Sel both of which are    */
                   2677:                 /* set by the reselecting Target.                              */
                   2678:                 /* The SCSI bus anaylzer shows the following events occcurring */
                   2679:                 /* within a few microseconds of BSY being set by the target:   */
                   2680:                 /*      bus free for at least hundreds of microseconds         */
                   2681:                 /*      Target raises BSY along with its ID bit                */
                   2682:                 /*      Target raises SEL                                      */
                   2683:                 /*      Target raises IO to indicate reselection               */
                   2684:                 /*      Target adds MESH's ID bit                              */
                   2685:                 /*      Target drops BSY                                       */
                   2686:                 /*      MESH raises BSY to accept reselection                  */
                   2687:                 /* **** MESH drops BSY **** here is where MESH is confused     */
                   2688:                 /*      Target stays on bus for 250 milliseconds.              */
                   2689:                 /* To solve this problem, whack MESH with a RstMESH.           */
                   2690: 
                   2691:             ELG( ' Rst', 'MESH', 'UEP-', "DoInterruptStageArb - Resel/Unexpected Disconnect.\n" );
                   2692:             [ self SetSeqReg            : kMeshResetMESH ]; /* completes quickly */
                   2693:             [ self GetHBARegsAndClear   : TRUE ];           /* clear cmdDone     */
                   2694:             [ self SetSeqReg            : kMeshEnableReselect ];
                   2695:             [ self SetIntMask           : kMeshIntrMask ];  /* Enable Interrupts */
                   2696:             return;                      /* now wait for another reselect interrupt */
                   2697:         }
                   2698:         [ self HandleReselectionInterrupt ];
                   2699:     }
                   2700:     else
                   2701:     {       /* 22sep97 - lost arbitration without reselection.      */
                   2702:             /* Probably lost the reselect condition processing an   */
                   2703:             /* error or something.                                  */
                   2704:         ELG( 0, 0, 'ARB-', "DoInterruptStageArb - Lost arbitration without reselect.\n" );
                   2705:     }
                   2706:     return;
                   2707: }/* end DoInterruptStageArb */
                   2708: 
                   2709: 
                   2710:     /* Process an anomaly during target selection.  */
                   2711: 
                   2712: - (void) DoInterruptStageSelA
                   2713: {
                   2714:     ASSERT( gActiveCommand );
                   2715:     [ self SetSeqReg : kMeshEnableReselect ];
                   2716:     [ self SetSeqReg : kMeshBusFreeCmd ];   /* clear ATN signal MESH left on    */
                   2717:     [ self killCurrentRequest ];
                   2718:     [ self GetHBARegsAndClear : FALSE ];            /* check MESH registers */
                   2719:     [ self SetIntMask : kMeshIntrMask ];            /* Enable Interrupts    */
                   2720:     return;
                   2721: }/* end DoInterruptStageSelA */
                   2722: 
                   2723: 
                   2724:     /* Process an anomaly during Message-Out phase. */
                   2725:     /* Target probably doing Message Reject (0x07). */ 
                   2726: 
                   2727: - (void) DoInterruptStageMsgO
                   2728: {
                   2729:     UInt8       phase;
                   2730:     IOReturn    rc;
                   2731: 
                   2732: 
                   2733:     ASSERT( gActiveCommand );
                   2734: 
                   2735:     phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;      /* phase me */
                   2736:     PAUSE( gActiveCommand, phase, 'Mgo-',
                   2737:                 "DoInterruptStageMsgO - error during msg-out phase.\n" );
                   2738: 
                   2739:     switch ( phase )
                   2740:     {
                   2741:         case kBusPhaseMSGI:
                   2742:             rc = [ self DoMessageInPhase ];
                   2743:             if ( rc != IO_R_SUCCESS )
                   2744:             {
                   2745:                 PAUSE( 0, rc, ' MI-',
                   2746:                             "DoInterruptStageMsgO - MsgIn during MsgOut phase.\n" );
                   2747:             //  ??? need to get to bus-free from here
                   2748:             //  ??? need to blow off the IO
                   2749:             }
                   2750:             else
                   2751:             {   ELG( 0, gMsgInFlag, 'rej?', "DoInterruptStageMsgO - got MsgIn.\n" );
                   2752:                 if ( gMsgInFlag & kFlagMsgIn_Reject )
                   2753:                     [ self AbortActiveCommand ];
                   2754:             }
                   2755:             break;
                   2756: 
                   2757:         default:
                   2758:             PAUSE( gMsgInFlag, phase, 'mgo-',
                   2759:                         "DoInterruptStageMsgO - unknown phase during MsgOut phase.\n" );
                   2760:             break;
                   2761:     }
                   2762:     return;
                   2763: }/* end DoInterruptStageMsgO */
                   2764: 
                   2765: 
                   2766:     /* DoInterruptStageCmdO - Process an anomaly during command stage.  */
                   2767: 
                   2768: - (void) DoInterruptStageCmdO
                   2769: {
                   2770:     register CommandBuffer  *cmdBuf;
                   2771:     UInt8                   phase;
                   2772:     IOReturn                rc;
                   2773: 
                   2774: 
                   2775:         /* See if this is part of the normal AbortTag/BusDeviceReset process: */
                   2776: 
                   2777: 
                   2778:     if ( !queue_empty( &abortCmdQ ) )
                   2779:     {
                   2780:         [ self SetSeqReg : kMeshFlushFIFO ];                /* flush the FIFO  */
                   2781:         cmdBuf = (CommandBuffer*)queue_first( &abortCmdQ );
                   2782:         ELG( cmdBuf, 0, 'Abo-', "DoInterruptStageCmdO - Aborting." );
                   2783:         queue_remove( &abortCmdQ, cmdBuf, CommandBuffer*, link );
                   2784:         [ self ioComplete : cmdBuf ];
                   2785:         [ self AbortDisconnectedCommand ];    /* do the next, if any */
                   2786:         return;
                   2787:     }
                   2788: 
                   2789:         /* Not aborting - something bad happened: */
                   2790: 
                   2791:     ASSERT( gActiveCommand );
                   2792:     cmdBuf = gActiveCommand;
                   2793:     cmdBuf->flagRequestSelectOK = FALSE;
                   2794:     phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;      /* phase me */
                   2795:     ELG( cmdBuf, phase, 'CMD?', "DoInterruptStageCmdO - anomaly during Cmd phase.\n" );
                   2796: 
                   2797:     if ( phase == kBusPhaseMSGI )
                   2798:     {       /* We are probably negotiating SDTR or          */
                   2799:             /* getting rejected on a nonzero LUN.           */
                   2800:         rc = [ self DoMessageInPhase ];
                   2801:         if ( rc != IO_R_SUCCESS )
                   2802:         {
                   2803:             PAUSE( 0, rc, ' mi-',
                   2804:                         "DoInterruptStageCmdO - MsgIn during Cmd phase.\n" );
                   2805:         }
                   2806:         else
                   2807:         {       /* Message processed - where do we go from here?    */
                   2808: 
                   2809:             if ( !gActiveCommand )                  /* if Rejected, */
                   2810:                 return;                             /* return       */
                   2811: 
                   2812:             phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;
                   2813:             switch ( phase )
                   2814:             {
                   2815:             case kBusPhaseSTS:
                   2816:                 [ self RunDBDMA : kcclCmdoStage     stageLabel : kcclStageInit ];
                   2817:                 break;
                   2818: 
                   2819:             case kBusPhaseMSGO:
                   2820:                 msgOutPtr = (UInt8*)CCLAddress( kcclMSGOdata );
                   2821:                 [ self SetupMsgO ];
                   2822:                 [ self RunDBDMA : kcclMsgoStage     stageLabel : kcclStageInit ];
                   2823:                 break;
                   2824: 
                   2825:             case kBusPhaseCMD:
                   2826:                 [ self RunDBDMA : kcclCmdoStage     stageLabel : kcclStageInit ];
                   2827:                 break;
                   2828:             }
                   2829:         }
                   2830:     }
                   2831:     else if ( phase == kBusPhaseSTS )           /* Probably Check Condition    */
                   2832:     {                                           /* Perhaps block # invalid     */
                   2833:         gFlagIncompleteDBDMA = FALSE;           /* indicate no-more-data       */
                   2834:         [ self RunDBDMA : kcclGetStatus         stageLabel : kcclStageStat ];
                   2835:     }
                   2836:     else
                   2837:     {
                   2838:         PAUSE( 0, phase, 'Phs?', "DoInterruptStageCmdO - error during Command phase.\n" );
                   2839:     }
                   2840:     return;
                   2841: }/* end DoInterruptStageCmdO */
                   2842: 
                   2843: 
                   2844:     /* We are in MSGI phase. Read the bytes. Return TRUE if an entire       */
                   2845:     /* message was read (we may still be in MSGI phase). Note that this     */
                   2846:     /* is done by programmed IO, which will fail (logging the error) if     */
                   2847:     /* the target sets MSGI but does not send us a message quickly enough.  */
                   2848:     /* This method is called from the normal data transfer interrupt when   */
                   2849:     /* the target enters message in phase, and from the reselection         */
                   2850:     /* interrupt handler when we read a valid reselection target ID.        */
                   2851:     /* Note that MESH interrupts are disabled on exit.                      */
                   2852: 
                   2853: - (IOReturn) DoMessageInPhase
                   2854: {
                   2855:     register UInt8      messageByte;
                   2856:     UInt32              index = 0;
                   2857:     IOReturn            ioReturn = IO_R_SUCCESS;
                   2858: 
                   2859: 
                   2860:         /* We do not necessarily have a valid command in this method.   */
                   2861:         /* While we're processing Message-In bytes, we don't want any   */
                   2862:         /* MESH hardware interrupts.                                    */
                   2863: 
                   2864:     [ self SetIntMask   : 0 ];          /* no MESH interrupt latching   */
                   2865:     [ self SetSeqReg    : kMeshFlushFIFO ];         /* Flush the FIFO   */
                   2866: 
                   2867:     gMsgInCount = 0;
                   2868:     gMsgInState = kMsgInInit;
                   2869: 
                   2870:     while ( gMsgInState != kMsgInReady  /* Disconnect makes gActiveCommand  */
                   2871:          && ioReturn == IO_R_SUCCESS )  /* go away                          */
                   2872:     {
                   2873:         meshAddr->transferCount1    = 0;
                   2874:         meshAddr->transferCount0    = 1;                /* get single byte  */
                   2875:         [ self SetSeqReg : kMeshMessageInCmd ];         /* issue MsgIn      */
                   2876: 
                   2877:         ioReturn = [ self WaitForMesh : TRUE ];         /* wait for cmdDone */
                   2878:         if ( ioReturn != IO_R_SUCCESS )
                   2879:         {
                   2880:             PAUSE( gCurrentTarget, ioReturn, 'Mgi-', "DoMessageInPhase - Target hung: message in timeout.\n" );
                   2881:             break;           /* Bus reset here? */
                   2882:         }
                   2883: 
                   2884:         if ( (g.shadow.mesh.exception  & kMeshExcPhaseMM)
                   2885:          ||  (g.shadow.mesh.busStatus0 & kMeshPhaseMask) != kBusPhaseMSGI )
                   2886:         {
                   2887:             break;                  /* exit loop if no longer in Msg-In phase   */
                   2888:         }
                   2889: 
                   2890:         if ( g.shadow.mesh.FIFOCount == 0 )
                   2891:         {
                   2892:             PAUSE( gCurrentTarget, 0, 'mgi-', "DoMessageInPhase - no message byte.\n" );
                   2893:             break;
                   2894:         }
                   2895: 
                   2896:         messageByte = meshAddr->xFIFO;
                   2897: 
                   2898:         ASSERT( index < 256 );
                   2899:         gMsgInBuffer[ index++ ] = messageByte;
                   2900: 
                   2901:         switch ( gMsgInState )
                   2902:         {
                   2903:         case kMsgInInit:
                   2904:                 /* This is the first message byte. Check for 1-byte codes.  */
                   2905:             if ( messageByte == kScsiMsgCmdComplete
                   2906:              || (messageByte >= kScsiMsgOneByteMin && messageByte <= kScsiMsgOneByteMax)
                   2907:              ||  messageByte >= kScsiMsgIdentify )
                   2908:             {
                   2909:                 gMsgInState = kMsgInReady;
                   2910:             }
                   2911:             else if ( messageByte >= kScsiMsgTwoByteMin
                   2912:                   &&  messageByte <= kScsiMsgTwoByteMax )
                   2913:             {
                   2914:                     /* This is a two-byte message.              */
                   2915:                     /* Set the count and read the next byte.    */
                   2916: 
                   2917:                 gMsgInState = kMsgInReading;       /* Need one more */
                   2918:                 gMsgInCount = 1;
                   2919:             }
                   2920:             else
                   2921:             {       /* This is an extended message. */
                   2922:                     /* The next byte has the count. */
                   2923:                 gMsgInState = kMsgInCounting;
                   2924:             }
                   2925:             break;
                   2926: 
                   2927:         case kMsgInCounting:        /* Count byte of multi-byte message:   */
                   2928:             gMsgInCount = messageByte;
                   2929:             gMsgInState = kMsgInReading;
                   2930:             break;
                   2931: 
                   2932:         case kMsgInReading:                 /* Body of multi-byte message:  */
                   2933:             if ( --gMsgInCount <= 0 )
                   2934:                 gMsgInState = kMsgInReady;
                   2935:             break;
                   2936: 
                   2937:         default:
                   2938:             ASSERT( gMsgInState );                  /* Bogus state  */
                   2939:             PAUSE( 0, 0, 'Msg-', "DoMessageInPhase  - Bogus MSGI state!\n" );
                   2940:             gMsgInState = kMsgInReady;
                   2941:             break;
                   2942:         }/* end SWITCH on MSGI state */
                   2943: 
                   2944:         if ( gMsgInState == kMsgInReady )
                   2945:         {
                   2946:             [ self ProcessMSGI ];
                   2947:             gMsgInState = kMsgInInit;
                   2948:             index = 0;
                   2949:             if ( gMsgInBuffer[0] == kScsiMsgDisconnect )
                   2950:                 ioReturn = IO_R_IO;     /* break out of WHILE loop  */
                   2951: 
                   2952:             if ( gMsgInFlag & kFlagMsgIn_Reject )
                   2953:             {
                   2954:                 [ self AbortActiveCommand ];
                   2955:                 break;
                   2956:             }
                   2957: 
                   2958:             if ( gFlagReselecting )
                   2959:                 break;  /* Take Identify only - leave +ACK  */
                   2960:         }/* end IF have a complete message-in to process */
                   2961:     }/* end WHILE there are more message bytes */
                   2962: 
                   2963:         /***** If the target switches out of MSGI phase without *****/
                   2964:         /***** sending a complete message, we should do some    *****/
                   2965:         /***** sort of error recovery.                          *****/
                   2966: 
                   2967:     if ( gMsgInState != kMsgInInit )
                   2968:     {
                   2969:         PAUSE( gCurrentTarget, gMsgInState, 'MGI-', "DoMessageInPhase - incomplete message.\n" );
                   2970:         if ( ioReturn == IO_R_SUCCESS )
                   2971:              ioReturn  = IO_R_IO;       /* General IO error     */
                   2972:     }
                   2973: 
                   2974:     return  ioReturn;
                   2975: }/* end DoMessageInPhase */
                   2976: 
                   2977: 
                   2978:     /* ProcessMSGI - DoMessageInPhase has read a complete message.  */
                   2979:     /* Process it (this will probably change our internal state).   */
                   2980: 
                   2981: - (void) ProcessMSGI
                   2982: {
                   2983:         /* Note that, during reselection, we may not have           */
                   2984:         /* a current target or LUN, nor possibly a valid command    */
                   2985: 
                   2986:     register CommandBuffer  *cmdBuf;
                   2987:     register IOSCSIRequest  *scsiReq;
                   2988: 
                   2989:     UInt8       sdtr;
                   2990:     UInt8       currentTarget, currentLUN;
                   2991:     UInt8       period, offset;
                   2992:     UInt8       targetResponse;     /* responding or requesting?   */
                   2993: 
                   2994: 
                   2995:     cmdBuf  = gActiveCommand;                       /* May be NULL      */
                   2996:     scsiReq = (cmdBuf == NULL) ? NULL : cmdBuf->scsiReq;
                   2997:     if ( scsiReq )
                   2998:     {   currentTarget   = scsiReq->target;
                   2999:         currentLUN      = scsiReq->lun;
                   3000:         ASSERT( currentTarget == gCurrentTarget && currentLUN == gCurrentLUN );
                   3001:     }
                   3002:     else
                   3003:     {   currentTarget   = gCurrentTarget;
                   3004:         currentLUN      = gCurrentLUN;
                   3005:     }
                   3006: 
                   3007:     ELG( 0, *(UInt32*)gMsgInBuffer, '<Msg', "ProcessMSGI" );
                   3008: 
                   3009:     switch ( gMsgInBuffer[0] )
                   3010:     {
                   3011:     case kScsiMsgCmdComplete:
                   3012:         if ( cmdBuf )
                   3013:         {
                   3014:                 /* This command is complete. Clear interrupts and   */
                   3015:                 /* allow subsequent MESH interrupts. Then tell the  */
                   3016:                 /* MESH to wait for the target to release the bus.  */
                   3017: 
                   3018:             [ self SetSeqReg : kMeshEnableReselect ];
                   3019:             [ self SetSeqReg : kMeshBusFreeCmd ];    /* cause Int   */
                   3020: 
                   3021:             if ( cmdBuf->flagIsAutosense == FALSE )
                   3022:             {
                   3023:                 if ( scsiReq )
                   3024:                     scsiReq->scsiStatus = CCLByte( kcclStatusData );
                   3025: 
                   3026:                     /* Driver Kit does not return the command-complete byte.    */
                   3027: 
                   3028:             }
                   3029:             [ self ioComplete : cmdBuf ];
                   3030:         }
                   3031:         goto exit; /* Don't exit through the SWITCH end */
                   3032: 
                   3033:     case kScsiMsgLinkedCmdComplete:
                   3034:     case kScsiMsgLinkedCmdCompleteFlag:
                   3035:         PAUSE( gCurrentTarget, 0, 'pmi-', "ProcessMSGI - linked command complete not supported.\n" );
                   3036:         [ self AbortActiveCommand ];
                   3037:         break;
                   3038: 
                   3039:     case kScsiMsgNop:
                   3040:         break;
                   3041: 
                   3042:     case kScsiMsgRestorePointers:
                   3043:         if ( cmdBuf )
                   3044:         {
                   3045:             cmdBuf->currentDataIndex = cmdBuf->savedDataIndex;
                   3046:             if (  cmdBuf->mem )
                   3047:                 [ cmdBuf->mem setState : &cmdBuf->savedDataState ];
                   3048:         }
                   3049:         break;
                   3050: 
                   3051:     case kScsiMsgSaveDataPointers:
                   3052:         if ( cmdBuf )
                   3053:         {
                   3054:             cmdBuf->savedDataIndex = cmdBuf->currentDataIndex;
                   3055:             if (  cmdBuf->mem )
                   3056:                 [ cmdBuf->mem state : &cmdBuf->savedDataState ];
                   3057:         }
                   3058:         break;
                   3059: 
                   3060:     case kScsiMsgDisconnect:
                   3061:             /* Driver Kit does not support automatic Save Data Pointers on      */
                   3062:             /* Disconnect.                                                      */
                   3063:             /* Move this request to the disconnect queue, enable reselection,   */
                   3064:             /* re-enable MESH interrupts, and wait (here) for bus free, but     */
                   3065:             /* don't eat the interrupt.                                         */
                   3066: 
                   3067:         gMsgInFlag |= kFlagMsgIn_Disconnect;
                   3068:         [ self disconnect ];                            /* requeue active   */
                   3069:         [ self SetSeqReg    : kMeshEnableReselect ];    /* enable reselect  */
                   3070:         [ self SetIntMask   : kMeshIntrMask ];          /* Enable Ints      */
                   3071:         [ self SetSeqReg    : kMeshBusFreeCmd ];        /* issue BusFree    */
                   3072: 
                   3073:             /* wait for Bus Free command to complete:    */
                   3074: 
                   3075:         [ self WaitForMesh : FALSE ];       /* don't clear possible reselect    */
                   3076: 
                   3077:             /* Interrupt for bus-free now latched. Prevent a double interrupt,  */
                   3078:             /* 1 from bus-free + 1 from reselect from occurring.                */
                   3079:             /* This fixes the following BADNESS:                                */
                   3080:             /*      Issue bus-free for disconnect.                              */
                   3081:             /*      Interrupt occurs in microseconds - even before exiting      */
                   3082:             /*      "interruptOccurred" routine.                                */
                   3083:             /*      Mach queues message to driverKit.                           */
                   3084:             /*      Exit "interruptOccurred" routine.                           */
                   3085:             /*      DriverKit dequeues and starts handling 1st Mach message.    */
                   3086:             /*      Interrupt occurs for reselect while driverKit running.      */
                   3087:             /*      Mach queues 2nd message to driverKit.                       */
                   3088:             /*      DriverKit invokes MESH driver for 1st msg.                  */
                   3089:             /*      MESH driver sees cmdDone fm bus-free AND reselect exception.*/
                   3090:             /*      MESH driver handles reselect by setting up and running      */
                   3091:             /*      DBDMA. MESH driver exits.                                   */
                   3092:             /*      DriverKit invokes MESH driver with 2nd Mach message.        */
                   3093:             /*      MESH driver handles this as a DBDMA completion and royally  */
                   3094:             /*      screws up.                                                  */
                   3095: 
                   3096:         g.intLevel |= kLevelLatched;            /* set latched-interrupt flag   */
                   3097:         [ self SetIntMask : 0 ];                /* prevent multiple MESH ints   */
                   3098:         break;
                   3099: 
                   3100:     case kScsiMsgRejectMsg:
                   3101:         ELG( currentTarget, gMsgOutFlag, 'Rej-', "ProcessMSGI - Reject." );
                   3102:         gMsgInFlag |= kFlagMsgIn_Reject;
                   3103:         break;
                   3104: 
                   3105:     case kScsiMsgSimpleQueueTag:
                   3106:         msgInTagType   = gMsgInBuffer[0];
                   3107:         msgInTag       = gMsgInBuffer[1];
                   3108:         ELG( 0, msgInTag, '=Tag', "Simple Queue Tag" );
                   3109:         break;
                   3110: 
                   3111:     case kScsiMsgExtended:
                   3112: 
                   3113:             /* Multi-byte message, presumably Synchronous Negotiation:  */
                   3114: 
                   3115:         switch ( gMsgInBuffer[ 2 ] )    /* switch on the msg code byte  */
                   3116:         {
                   3117:         case kScsiMsgSyncXferReq:       /* handle sync negotiation:     */
                   3118:             if ( scsiReq == NULL )      // ??? can this happen?
                   3119:             {
                   3120:                 PAUSE( currentTarget, 0, 'pMI-', "ProcessMSGI - attempted to negotiate SDTR without a nexus.\n" );
                   3121:                 [ self AbortActiveCommand ];
                   3122:             }
                   3123:             else
                   3124:             {       /* Get period in  nanoseconds  */
                   3125:                 period = gMsgInBuffer[ 3 ] * 4; /* SCSI uses 4ns granularity    */
                   3126: 
                   3127:                     /* determine target responding or initiating?   */
                   3128:                 targetResponse = gPerTargetData[ scsiReq->target ].negotiateSDTR;
                   3129:                 gPerTargetData[ scsiReq->target ].negotiateSDTR = 0;
                   3130:                 if ( targetResponse )
                   3131:                 {   
                   3132:                     if ( gMsgInBuffer[ 4 ] == 0 )   /* check offset                 */
                   3133:                     {
                   3134:                         sdtr = kSyncParmsAsync;     /* Offset == 0 implies async    */
                   3135:                     }
                   3136:                     else                            /* synchronous:                 */
                   3137:                     {
                   3138:                         if ( period == 100 )        /* special-case 100=FAST    */
                   3139:                         {
                   3140:                             sdtr = kSyncParmsFast & 0x0F;
                   3141:                         }
                   3142:                         else    /* Older CD-ROMs get here.                      */
                   3143:                         {       /* The MESH manual says:                        */
                   3144:                                 /* period = 4 * clk + 2 * clk * P               */
                   3145:                                 /* where:                                       */
                   3146:                                 /*      period is the target nanoseconds        */
                   3147:                                 /*      clk is the MESH clock rate which is     */
                   3148:                                 /*          20 nanoseconds for a 50 MHz clock   */
                   3149:                                 /*      P is the 1-nibble period code we stuff  */
                   3150:                                 /*          in the syncParms register           */
                   3151:                                 /* So:                                          */
                   3152:                                 /*      period = 4 * 20 + 2 * 20 * P            */
                   3153:                                 /*      period = 80 + 40 * P                    */
                   3154:                                 /*      P = (period - 80) / 40                  */
                   3155:                                 /* Since P must round up for safety:            */
                   3156:                                 /*      P = ((period - 80) + 39) / 40           */
                   3157:                                 /*      P = (period - 41) / 40                  */
                   3158:                                 /* A value of P == 3 results in 5 MB/s          */
                   3159:                             sdtr = (UInt8)((period - 41) / 40);
                   3160:                         }
                   3161: #ifdef CRAP
                   3162:                                 /* If period is longer than 200 ns resulting    */
                   3163:                                 /* in less than 5 MB/s, renegotiate async later.*/
                   3164:                         if ( period >= 200 )
                   3165:                             gPerTargetData[ scsiReq->target ].negotiateSDTR = kSyncParmsAsync;
                   3166: #endif /* CRAP */
                   3167:                     }/* end ELSE have offset ergo Synchronous */
                   3168: 
                   3169:                         /*  OR in the offset.   */
                   3170:                     sdtr |= (gMsgInBuffer[ 4 ] << 4);
                   3171:                 }/* end IF Target is responding to negotiation */
                   3172: 
                   3173:                 else                    /* target is initiating negotiation:    */
                   3174:                 {
                   3175:                     msgOutPtr = (UInt8*)CCLAddress( kcclMSGOdata );
                   3176:                     *msgOutPtr++   = kScsiMsgExtended;     /* 0x01 Ext Msg     */
                   3177:                     *msgOutPtr++   = 0x03;                 /* 0x03 Message Len */
                   3178:                     *msgOutPtr++   = kScsiMsgSyncXferReq;  /* 0x01 SDTR code   */
                   3179:                     offset = gMsgInBuffer[ 4 ];
                   3180:                     if ( offset == 0 )              /* Offset == 0 means async: */
                   3181:                     {
                   3182:                         *msgOutPtr++ = 0;          /* clear period byte        */
                   3183:                         *msgOutPtr++ = 0;          /* offset byte = 0 for async*/
                   3184:                         sdtr = kSyncParmsAsync;     /* set value for MESH reg   */
                   3185:                     }
                   3186:                     else                            /* have offset ergo sync:   */
                   3187:                     {
                   3188:                         if ( offset > 15 )
                   3189:                              offset = 15;           /* MESH can only handle 15  */
                   3190:                         
                   3191:                         if ( period <= 100 )        /* special-case 100=FAST    */
                   3192:                              period  = 100;
                   3193:                         else
                   3194:                         {       /* round up to MESH's 40 ns granularity */
                   3195:                             period = ((period + 39) / 40) * 40;
                   3196:                         }
                   3197:                         *msgOutPtr++ = period / 4; /* SCSI 4ns granularity     */
                   3198:                         *msgOutPtr++ = offset;
                   3199:                         sdtr = (offset << 8) | (UInt8)((period - 41) / 40);
                   3200:                     }/* end target is negotiating Sync */
                   3201:                         /* respond to target:  */
                   3202:                     [ self RunDBDMA : kcclMsgoStage stageLabel : kcclStageInit ];
                   3203:                     gPerTargetData[ scsiReq->target ].negotiateSDTR = 0;
                   3204:                 }/* end ELSE target is initiating negotiation */
                   3205: 
                   3206:                 meshAddr->syncParms = sdtr;
                   3207:                 SynchronizeIO();
                   3208:                 gPerTargetData[ scsiReq->target ].syncParms = sdtr;
                   3209:                 ELG( *(UInt32*)&gMsgInBuffer[0], gMsgInBuffer[4]<<24 | sdtr, 'SDTR', "ProcessMSGI - SDTR" );
                   3210:             } /* end ELSE have a nexus */
                   3211:             break;
                   3212: 
                   3213:         default:
                   3214:             PAUSE( currentTarget, gMsgInBuffer[0], 'PMi-', "ProcessMSGI - unsupported extended message.\n" );
                   3215:             [ self AbortActiveCommand ];
                   3216:             break;
                   3217:         }/* end SWITCH on extended message code */
                   3218:         break;
                   3219: 
                   3220:     default:
                   3221:         if ( gMsgInBuffer[0] >= kScsiMsgIdentify )
                   3222:         {
                   3223:             ASSERT( gCurrentTarget != kInvalidTarget );
                   3224:             ASSERT( gCurrentLUN == kInvalidLUN );
                   3225:             gCurrentLUN = gMsgInBuffer[0] & kScsiMsgIdentifyLUNMask;
                   3226:             currentLUN  = gCurrentLUN;
                   3227:         }
                   3228:         else
                   3229:         {
                   3230:             PAUSE( currentTarget, gMsgInBuffer[0], 'mi -', "ProcessMSGI - unsupported message: rejected.\n" );
                   3231:             [ self AbortActiveCommand ];
                   3232:         }
                   3233:     }/* end SWITCH on message selection */
                   3234: 
                   3235: exit:
                   3236:     return;
                   3237: }/* end ProcessMSGI */
                   3238: 
                   3239: 
                   3240:     /* Process a reselection interrupt. */
                   3241: 
                   3242: - (void) HandleReselectionInterrupt
                   3243: {
                   3244:     IOReturn    ioReturn;
                   3245: 
                   3246: 
                   3247:     ASSERT( gActiveCommand == NULL );
                   3248: 
                   3249:     gFlagReselecting = TRUE;
                   3250: 
                   3251:         /* Sometimes MESH gives a bogus Disconnected error during Reselection.  */
                   3252:         /* 31mar98 - Issuing an Abort message, causes "unexpected disconnect".  */
                   3253:         /* When Err:UnexpDisc and Exc:Resel are simultaneously set, the         */
                   3254:         /* busStatus0,1 registers may not be current.                           */
                   3255:     if ( g.shadow.mesh.error & kMeshErrDisconnected )
                   3256:     {
                   3257:         [ self SetSeqReg    : kMeshBusFreeCmd ];
                   3258:         [ self WaitForMesh  : TRUE ];    // now maybe busStatus0,1 are live
                   3259:         PAUSE( 0, 0, 'Dsc-',
                   3260:                 "HandleReselectionInterrupt: Caught disconnected glitch\n" );
                   3261:     }/* End IF bus disconnect error */
                   3262: 
                   3263:         /* Read the target ID (which should be our initiator ID OR'd with the       */
                   3264:         /* Target and the Identify byte with the reselecting LUN. Store this        */
                   3265:         /* in gTargetID and gTargetLUN. Note that, during reselection, we will      */
                   3266:         /* have a NULL gCurrentCommand and a valid gCurrentTarget and gCurrentLUN.  */
                   3267:         /* If we get a valid reselection target, call the message in phase          */
                   3268:         /* directly to read the LUN byte.                                           */
                   3269:         /* @return TRUE if successful.                                              */
                   3270: 
                   3271:     msgInTag = 0;
                   3272:     if ( meshAddr->FIFOCount == 0 )
                   3273:     {
                   3274:         PAUSE( 0, 0, 'HRI-', "HandleReselectionInterrupt - Empty FIFO in reselection.\n" );
                   3275:         return;
                   3276:     }
                   3277:     else    /* get the Target ID bit from the bus out of the FIFO   */
                   3278:     {       /* then, get the msg-in Identify byte for the LUN.      */
                   3279:         if ( [ self getReselectionTargetID ] )
                   3280:         {
                   3281:             if ( [ self DoMessageInPhase ] != IO_R_SUCCESS )   /* get Identify  */
                   3282:             {
                   3283:                 PAUSE( 0, 0, 'Id -', "HandleReselectionInterrupt - Expected Identify byte after reselection.\n" );
                   3284:             }
                   3285:         }
                   3286:         else return;
                   3287:     }
                   3288: 
                   3289:         /* Try to find an untagged command for this Target/LUN: */
                   3290: 
                   3291:     ioReturn = [ self reselectNexus : gCurrentTarget
                   3292:                         lun         : gCurrentLUN
                   3293:                         queueTag    : 0 ];
                   3294: 
                   3295:     if ( ioReturn != IO_R_SUCCESS )
                   3296:     {       /* No untagged command, try to get a Tag. Hope that */
                   3297:             /* you're still in Message-In phase at this point.  */
                   3298:         if ( [ self DoMessageInPhase ] != IO_R_SUCCESS )   /* get Tag msg  */
                   3299:         {
                   3300:             PAUSE( 0, 0, 'tag-', "HandleReselectionInterrupt - Expected tag message.\n" );
                   3301:         }
                   3302:         ioReturn = [ self reselectNexus : gCurrentTarget
                   3303:                             lun         : gCurrentLUN
                   3304:                             queueTag    : msgInTag ];
                   3305:     }
                   3306: 
                   3307:     if ( ioReturn == IO_R_SUCCESS )
                   3308:     {
                   3309:         ELG(    gActiveCommand,
                   3310:                 (msgInTag<<16) | (gCurrentLUN<<8) | gCurrentTarget,
                   3311:                 'Resl',     "HandleReselectionInterrupt" );
                   3312:             /* If reselectNexus succeeded, gActiveCommand is set to the command.*/
                   3313:             /* Clear out the channel command results and build the channel      */
                   3314:             /* command to continue operation. The TRUE flag prevents            */
                   3315:             /* constructing an arbitrate/select/command sequence.               */
                   3316: 
                   3317:         [ self ClearCPResults ];
                   3318:         [ self UpdateCP : TRUE ];
                   3319:         [ self RunDBDMA : kcclReselect  stageLabel : kcclStageInit ];
                   3320:     }
                   3321:     else
                   3322:     {       /* There is no associated command.              */
                   3323:             /* Reject the reselection attempt.              */
                   3324:             /* This should cycle back to selectNextRequest. */
                   3325:         PAUSE( gCurrentTarget, msgInTag, 'Rsl-',
                   3326:             "HandleReselectionInterrupt - No command for reselection attempt.\n" );
                   3327:         [ self AbortActiveCommand ];
                   3328:     }
                   3329:     return;
                   3330: }/* end HandleReselectionInterrupt */
                   3331: 
                   3332: 
                   3333:     /* Validate the target's reselection byte (put on the bus before    */
                   3334:     /* reselecting us). Erase the initiator ID and convert the other    */
                   3335:     /* bit into an index. The algorithm should be faster than a         */
                   3336:     /* sequential search, but it probably doesn't matter much.          */
                   3337:     /* @return  TRUE if successful (gCurrentTarget is now valid).       */
                   3338:     /*          This function does not check whether there actually     */
                   3339:     /*          is a command pending for this target.                   */
                   3340: 
                   3341: - (Boolean) getReselectionTargetID
                   3342: {
                   3343:     Boolean             success     = FALSE;
                   3344:     register UInt8      targetID    = 0;
                   3345:     register UInt8      bitValue    = 0;        /* Suppress warning         */
                   3346:     register UInt8      targetBits;
                   3347: 
                   3348: 
                   3349:     targetBits  = meshAddr->xFIFO;              /***** Read the FIFO    *****/
                   3350:     targetBits &= ~gInitiatorIDMask;            /* Remove our bit           */
                   3351:     if ( targetBits )
                   3352:     {                       /* Is there another bit?    */
                   3353:         bitValue        = targetBits;
                   3354:         if ( bitValue > 0x0F )
                   3355:         {
                   3356:             targetID    += 4;
                   3357:             bitValue    >>= 4;
                   3358:         }
                   3359:         if ( bitValue > 0x03 )
                   3360:         {
                   3361:             targetID    += 2;
                   3362:             bitValue    >>= 2;
                   3363:         }
                   3364:         if ( bitValue > 0x01 )
                   3365:         {
                   3366:             targetID    += 1;
                   3367:         }
                   3368:         targetBits      &= ~(1 << targetID);    /* Remove the target mask   */
                   3369:         if ( targetBits == 0 )
                   3370:         {                                       /* Was exactly one set?     */
                   3371:             success = TRUE;                     /* Yes: success!            */
                   3372:             gCurrentTarget = targetID;          /* Save the current target  */
                   3373:         }
                   3374:     }
                   3375: 
                   3376:     if ( !success )
                   3377:         PAUSE( targetID, targetBits, 'rsl-', "getReselectionTargetID - Expected Identify byte after reselection.\n" );
                   3378: 
                   3379:     return  success;
                   3380: }/* end getReselectionTargetID */
                   3381: 
                   3382: 
                   3383: @end /* AppleMesh_SCSI(MeshInterrupt) */
                   3384: 
                   3385: 
                   3386: @implementation AppleMesh_SCSI( Mesh )
                   3387: 
                   3388:     /* Reusable hardware initializer function. if resetSCSIBus is TRUE,     */
                   3389:     /* this includes a SCSI reset. Handling of ioComplete of active and     */
                   3390:     /* disconnected commands must be done elsewhere. Returns IO_R_SUCCESS.  */
                   3391: 
                   3392: - (IOReturn) ResetMESH : (Boolean)resetSCSIBus
                   3393: {
                   3394:     IOReturn    ioReturn = IO_R_SUCCESS;
                   3395:     UInt8       defaultSelectionTimeout = 25;   // mlj ??? fix this value
                   3396:     UInt8       target;
                   3397: 
                   3398: 
                   3399:         /* Reset interrupts, the MESH Hardware Bus Adapter, and the DMA engine. */
                   3400: 
                   3401: //  [ self SetIntMask           : 0 ];          /* ResetMESH clrs interruptMask */
                   3402:     [ self SetSeqReg            : kMeshResetMESH ]; /* completes quickly        */
                   3403:     [ self GetHBARegsAndClear   : TRUE ];       /* clear cmdDone                */
                   3404: 
                   3405:     dbdma_reset( DBDMA_MESH_SCSI );
                   3406: 
                   3407:         /* Init state variables:    */
                   3408: 
                   3409:     gFlagIncompleteDBDMA    = FALSE;
                   3410: //  gBusState               = SCS_DISCONNECTED;
                   3411: 
                   3412:         /* Smash all active command state (just in case):   */
                   3413: 
                   3414:     gActiveCommand  = NULL;
                   3415:     gCurrentTarget  = kInvalidTarget;
                   3416:     gCurrentLUN     = kInvalidLUN;
                   3417:     gMsgInState     = kMsgInInit;
                   3418:     msgOutPtr       = (UInt8*)CCLAddress( kcclMSGOdata );
                   3419: 
                   3420:     if ( resetSCSIBus )
                   3421:     {
                   3422:         ASSERT( gInterruptNestingLevel > 0 );
                   3423:         meshAddr->busStatus1 = kMeshRst; /***** ASSERT RESET SIGNAL *****/
                   3424:         SynchronizeIO();
                   3425:         IODelay( 25 );                   /* leave asserted for 25 mikes */
                   3426:         meshAddr->busStatus1 = 0;        /***** CLEAR  RESET SIGNAL *****/
                   3427:         SynchronizeIO();
                   3428: 
                   3429:             /* Delay for 250 msec after resetting the bus.          */
                   3430:             /* This serves two purposes: it gives the MESH time to  */
                   3431:             /* stabilize (about 10 msec is sufficient) and gives    */
                   3432:             /* some devices time to re-initialize themselves.       */
                   3433: 
                   3434:         IOSleep( APPLE_SCSI_RESET_DELAY );      /* Give Targets time to clean up */
                   3435:         [ self SetSeqReg : kMeshResetMESH ];    /* clear Err condition  */
                   3436:         [ self GetHBARegsAndClear : TRUE ];     /* check regs           */
                   3437: 
                   3438:         for ( target = 0; target < SCSI_NTARGETS; target++ )
                   3439:         {
                   3440:             gPerTargetData[ target ].syncParms      = kSyncParmsAsync;
                   3441:             gPerTargetData[ target ].negotiateSDTR  = kSyncParmsFast;   // negotiate Fast
                   3442:         }
                   3443:     }/* end IF resetSCSIBus */
                   3444: 
                   3445:     meshAddr->selectionTimeOut = defaultSelectionTimeout;
                   3446:     SynchronizeIO();
                   3447: 
                   3448:     return  ioReturn;
                   3449: }/* end ResetMESH */
                   3450: 
                   3451: 
                   3452:     /* Wait for an immediate (non-interrupting) command to complete.    */
                   3453:     /* Note that it spins while waiting. It is timed to prevent a buggy */
                   3454:     /* chip or target from hanging the system.                          */
                   3455: 
                   3456: - (IOReturn) WaitForMesh : (Boolean) clearInterrupts
                   3457: {
                   3458:     ns_time_t   startTime, endTime;
                   3459:     IOReturn    ioReturn = IO_R_SUCCESS;
                   3460: #if USE_ELG
                   3461:     UInt8      *logp = g.evLogBufp;
                   3462: #endif /* USE_ELG */
                   3463: //#define WAIT_TIME    (1000000000ULL)
                   3464: //#define WAIT_TIME    (3000000ULL)    // mlj - make it 3 milliseconds
                   3465: //#define WAIT_TIME    19000000        // mlj - make it 19 milliseconds for ZIP
                   3466: #define WAIT_TIME      250000000       // mlj - make it 250 milliseconds for SONY CD-ROM
                   3467: 
                   3468: 
                   3469:     IOGetTimestamp( &startTime );
                   3470: 
                   3471:     for ( g.shadow.mesh.interrupt = 0; g.shadow.mesh.interrupt == 0; )
                   3472:     {
                   3473: #if USE_ELG
                   3474:         g.evLogBufp = logp;    /* set back the log pointer */
                   3475: #endif /* USE_ELG */
                   3476:         [ self GetHBARegsAndClear : clearInterrupts ];
                   3477: 
                   3478:         IOGetTimestamp( &endTime );
                   3479:         if ( (endTime - startTime) >= WAIT_TIME )
                   3480:         {       /* It took too long! We're dead.    */
                   3481:             PAUSE( 0, 0, 'WFM-', "WaitForMesh - MESH chip does not respond to command.\n" );
                   3482:             ioReturn = IO_R_INTERNAL;
                   3483:             break;
                   3484:         }
                   3485:     }/* end FOR */
                   3486: 
                   3487:     return  ioReturn;
                   3488: }/* end WaitForMesh */
                   3489: 
                   3490: 
                   3491:     /* WaitForReq - spins while waiting. It is timed to prevent a buggy */
                   3492:     /* chip or target from hanging the system.                          */
                   3493: 
                   3494: - (IOReturn) WaitForReq             /* This method is currently unused. */
                   3495: {
                   3496:     ns_time_t   startTime, endTime;
                   3497:     IOReturn    ioReturn = IO_R_SUCCESS;
                   3498: 
                   3499: 
                   3500:     IOGetTimestamp( &startTime );
                   3501: 
                   3502:     g.shadow.mesh.busStatus0 = 0;
                   3503:     while ( (g.shadow.mesh.busStatus0 & kMeshReq) == 0 )
                   3504:     {
                   3505:         [ self GetHBARegsAndClear : FALSE ];
                   3506: 
                   3507:         IOGetTimestamp( &endTime );
                   3508:         if ( (endTime - startTime) >= 1000000000L )
                   3509:         {       /* It took too long!    */
                   3510:             PAUSE( endTime, startTime, 'WFR-', "WaitForReq - Target not in valid phase.\n" );
                   3511:             ioReturn = IO_R_INTERNAL;
                   3512:             break;
                   3513:         }
                   3514:         if ( (endTime - startTime) >= 1000000L
                   3515:          &&  (g.shadow.mesh.busStatus0 & kMeshReq) == 0  )
                   3516:         {
                   3517:             IODelay( 1000 );           /* After 1 ms, start yielding time   */
                   3518:         }
                   3519:     }/* end WHILE REQ not set */
                   3520: 
                   3521:     return  ioReturn;
                   3522: }/* end WaitForReq */
                   3523: 
                   3524: 
                   3525:     /* Send a command to the MESH chip. This may cause an interrupt.    */
                   3526: 
                   3527: - (void) SetSeqReg : (MeshCommand) meshCommand
                   3528: {
                   3529:     ELG( (meshAddr->interruptMask<<16) | meshAddr->interrupt, meshCommand, '=Seq', "SetSeqReg" );
                   3530: 
                   3531:     if ( meshAddr->interruptMask & kMeshIntrCmdDone
                   3532:       && meshCommand <= kMeshBusFreeCmd )
                   3533:         ELG( meshAddr->interrupt, meshAddr->interruptMask, 'Trig',
                   3534:                     "SetSeqReg - may trigger interrupt.\n" );
                   3535: 
                   3536:     meshAddr->sequence = (UInt8)meshCommand;    /***** DO IT    *****/
                   3537:     SynchronizeIO();
                   3538:     IODelay( 1 );                               /* G3 is too fast   */
                   3539: 
                   3540:     return;
                   3541: }/* end SetSeqReg */
                   3542: 
                   3543: 
                   3544:     /* MESH chip self-test. (Minimal: it could be extended.)    */
                   3545:     /* @return  IO_R_SUCCESS if successful.                     */
                   3546: 
                   3547: - (IOReturn) DoHBASelfTest
                   3548: {
                   3549:     IOReturn    ioReturn = IO_R_SUCCESS;
                   3550:     UInt8       tempByte;
                   3551: 
                   3552: 
                   3553:     ELG( gMESHPhysAddr, meshAddr, 'MESH', "DoHBASelfTest" );
                   3554: #ifdef CRAP
                   3555:     if ( probe_rb( ((void*)((UInt32)gMESHPhysAddr) + kMeshMESHID) ) == 0 )
                   3556:     {
                   3557:         PAUSE( 0, gMESHPhysAddr, 'HBA-', "DoHBASelfTest - Invalid MESH physical address.\n" );
                   3558:         ioReturn = IO_R_NO_DEVICE;
                   3559:     }
                   3560: #else
                   3561:      ASSERT( probe_rb( ((void*)((UInt32)gMESHPhysAddr) + kMeshMESHID) ) == 0 );
                   3562: #endif /* CRAP */
                   3563: 
                   3564:     if ( ioReturn == IO_R_SUCCESS )
                   3565:     {
                   3566:         tempByte = meshAddr->MESHID & 0x1f;
                   3567:         if ( tempByte < kMeshMESHID_Value )
                   3568:         {
                   3569:             PAUSE( 0, tempByte, 'hba-', "DoHBASelfTest - Invalid MESH chip ID .\n" );
                   3570:             ioReturn = IO_R_NO_DEVICE;
                   3571:         }
                   3572:     }
                   3573:     return  ioReturn;
                   3574: }/* end DoHBASelfTest */
                   3575: 
                   3576: 
                   3577:     /* Start a Channel Program at the given offset  */
                   3578:     /* with the specified stage label.              */
                   3579: 
                   3580: - (void) RunDBDMA : (UInt32) offset       stageLabel : (UInt32) stageLabel
                   3581: {
                   3582:     register UInt8      intReg;
                   3583:     ns_time_t           arbEndTime, curTime;
                   3584: 
                   3585: 
                   3586:     gMsgInFlag = 0;                                 /* clear message-in flags.  */
                   3587: 
                   3588:     CCLWord( kcclStageLabel ) = stageLabel;         /* set the stage            */
                   3589: 
                   3590:         /* Let MESH interrupt only for errors or exceptions, but not cmdDone    */
                   3591:     [ self SetIntMask : (kMeshIntrException | kMeshIntrError) ];
                   3592: 
                   3593:     intReg = meshAddr->interrupt;
                   3594:     switch ( intReg )
                   3595:     {
                   3596:     case kMeshIntrCmdDone:
                   3597:         if ( !gFlagReselecting )    // ??? Don't drop ACK fm MSG-IN or Sync data flows
                   3598:                 /* clear any pending command interrupts (but not reselect et al)    */
                   3599:             meshAddr->interrupt = kMeshIntrCmdDone;     SynchronizeIO();
                   3600:         /***** fall through *****/
                   3601:     case 0:
                   3602:             /* This is a Go:                                            */
                   3603:             /* Flush any CCL and related data to the CCL physical page  */
                   3604:             /* that may still be sitting in cache:                      */
                   3605:         flush_cache_v( (vm_offset_t)cclLogAddr, cclLogAddrSize );
                   3606:     //ELG( *(UInt32*)0xF3000020, 0, 'G C+', "RunDBDMA." );
                   3607:     //ELG( 0, *(UInt32*)0xF300002C, 'G C ', "RunDBDMA." );
                   3608: 
                   3609:         if ( offset == kcclStart )
                   3610:         {
                   3611:             gFlagReselecting = FALSE;
                   3612:             [ self SetSeqReg : kMeshArbitrateCmd ];     /* ARBITRATE                */
                   3613:     
                   3614:                 /* wait 50 mikes or cmdDone, whichever comes first: */
                   3615:     
                   3616:             IOGetTimestamp( &arbEndTime );
                   3617:             arbEndTime += 50000;
                   3618:             do
                   3619:             {
                   3620:                 [ self GetHBARegsAndClear : FALSE ];        /* get regs without hosing  */
                   3621:                 IOGetTimestamp( &curTime );
                   3622:             }while ( !(g.shadow.mesh.interrupt & kMeshIntrCmdDone) && curTime < arbEndTime );
                   3623:     
                   3624:             if ( g.shadow.mesh.interrupt == kMeshIntrCmdDone )
                   3625:             {       /* No err, no exc: Arbitration won: */
                   3626:                 meshAddr->interrupt = kMeshIntrCmdDone;
                   3627:                 SynchronizeIO();
                   3628:                 [ self SetSeqReg : kMeshDisableReselect ];  /* disable reselect */
                   3629:                 offset = 0x150;             // ??? fix this. Point to Select/Atn
                   3630:                 CCLWord( kcclStageLabel ) = kcclStageArb;   /* set stage to Arbitrate  */
                   3631:             }/* end IF won Arbitration */
                   3632:             else    /* Arbitration not won - CAUTION - HACK AHEAD:              */
                   3633:             {       /* Sometimes, MESH does not return ArbLost as it says in    */
                   3634:                     /* the documentation. Instead, it waits for the winner to   */
                   3635:                     /* get off the bus (usually after the 250 ms timeout) and   */
                   3636:                     /* then MESH continues its arbitration. This wastes 250 ms  */
                   3637:                     /* of valuable bus time. Further, IOmega's Zip drive has a  */
                   3638:                     /* nasty bug whereby if its reselection is snubbed and it   */
                   3639:                     /* times out, it leaves the I/O signal asserted on the bus  */
                   3640:                     /* even as other activity on the bus unrelated to the Zip   */
                   3641:                     /* is ongoing.                                              */
                   3642:                     /* We don't need to hack if ArbLost is indicated correctly  */
                   3643:                     /* or Reselect is indicated. If either is true, don't bother*/
                   3644:                     /* starting the DBDMA; rather, let the interrupt already    */
                   3645:                     /* latched handle the situation.                            */
                   3646: 
                   3647:                 if ( !(g.shadow.mesh.exception & (kMeshExcArbLost | kMeshExcResel)) )
                   3648:                 {
                   3649:                     ELG( '****', '****', 'HACK', "RunDBDMA - Arbitrate HACK." );
                   3650:                     [ self SetSeqReg : kMeshResetMESH ];        /* hack it: whack it*/
                   3651:                     [ self GetHBARegsAndClear : TRUE ];         /* get regs/preserve*/
                   3652:                     [ self SetSeqReg : kMeshEnableReselect ];   /* Let reselect again*/
                   3653:                     [ self GetHBARegsAndClear : FALSE ];        /* get regs/preserve*/
                   3654:                     if ( g.shadow.mesh.interrupt == 0 )
                   3655:                         PAUSE( 0, 0, 'Arb*', "RunDBDMA - Arbitrate/Reselect problem." );
                   3656:                 }
                   3657:                 if ( g.shadow.mesh.interrupt )      /* If Err or Exc set:           */
                   3658:                 {   g.intLevel |= kLevelLatched;    /* set latched-interrupt flag.  */
                   3659:                     return;                         /* let pending Int clean up.    */
                   3660:                 }
                   3661:             }/* end ELSE lost Arbitration */
                   3662:         }/* end IF DBDMA to start at Arbitrate */
                   3663: 
                   3664:         [ self GetHBARegsAndClear : FALSE ];    // ??? debug: see if ACK still set
                   3665:         ELG( 0, offset<<16 | stageLabel, 'DMA+', "RunDBDMA" );
                   3666:         dbdma_start( DBDMA_MESH_SCSI, (dbdma_command_t*)((UInt32)cclPhysAddr + offset) );
                   3667:         break;
                   3668: 
                   3669:     default:                            /* Err or Exc or both are set   */
                   3670:         ELG( 'Err ', 'Exc ', 'Pnd-', "RunDBDMA - interrupt probably pending (reselect?)." );
                   3671:         [ self GetHBARegsAndClear : FALSE ];    // display without hosing
                   3672:     }/* end SWITCH on interrupt register */
                   3673:     return;
                   3674: }/* end RunDBDMA */
                   3675: 
                   3676: 
                   3677:     /* Retrieve the MESH volatile register contents,        */
                   3678:     /* storing them in the global register shadow.          */
                   3679:     /* @param   clearInts   YES to clear MESH interrupts.   */
                   3680: 
                   3681: - (void) GetHBARegsAndClear : (Boolean) clearInts
                   3682: {
                   3683:     register MeshRegister   *mesh = meshAddr;
                   3684: 
                   3685: 
                   3686:     g.shadow.mesh.interrupt         = mesh->interrupt;
                   3687:     g.shadow.mesh.error             = mesh->error;
                   3688:     g.shadow.mesh.exception         = mesh->exception;
                   3689:     g.shadow.mesh.FIFOCount         = mesh->FIFOCount;
                   3690: 
                   3691:     g.shadow.mesh.busStatus0        = mesh->busStatus0;
                   3692:     g.shadow.mesh.busStatus1        = mesh->busStatus1;
                   3693:     g.shadow.mesh.transferCount1    = mesh->transferCount1;
                   3694:     g.shadow.mesh.transferCount0    = mesh->transferCount0;
                   3695: 
                   3696:     g.shadow.mesh.sequence          = mesh->sequence;           // debugging
                   3697:     g.shadow.mesh.interruptMask     = mesh->interruptMask;      // debugging
                   3698:     g.shadow.mesh.syncParms         = mesh->syncParms;          // debugging
                   3699:     g.shadow.mesh.destinationID     = mesh->destinationID;      // debugging
                   3700: 
                   3701:     ELG( g.shadow.longWord[ 0 ], g.shadow.longWord[ 1 ], clearInts ? 'Regs' : 'regs', "GetHBARegsAndClear." );
                   3702: 
                   3703:     if ( g.shadow.mesh.error )  // this occurs when dbdma -> Seq while reselect
                   3704:         ELG( g.shadow.mesh.interruptMask, g.shadow.mesh.sequence, 'Err-',
                   3705:                                 "GetHBARegsAndClear - MESH error detected" );
                   3706: 
                   3707:         /* It is possible to have the Reselected bit set in the Exception   */
                   3708:         /* register without an Exception bit in the interrupt register.     */
                   3709:         /* This may be caused by timing window where we clear the interrupt */
                   3710:         /* register with the interrupt register instead of 0x07.            */
                   3711:         /* Handle this by faking an exception.                              */
                   3712:         /* 04may98 - it is also possible to have PhaseMisMatch set in the   */
                   3713:         /* Exception register without Exception indicated in the Interrupt  */
                   3714:         /* register. This happened when a Synchronous output finished and   */
                   3715:         /* the target went to Message-In phase with Save-Data-Pointer.      */
                   3716: 
                   3717: 
                   3718:     if ( g.shadow.mesh.exception )
                   3719:          g.shadow.mesh.interrupt |= kMeshIntrException;
                   3720: 
                   3721:     if ( clearInts && g.shadow.mesh.interrupt )
                   3722:     {
                   3723:         mesh->interrupt = g.shadow.mesh.interrupt;
                   3724:         SynchronizeIO();
                   3725:     }
                   3726:     return;
                   3727: }/* end GetHBARegsAndClear */
                   3728: 
                   3729: 
                   3730: - (void) SetIntMask : (UInt8) mask
                   3731: {
                   3732:     ELG( (meshAddr->interrupt<<16) | meshAddr->interruptMask, mask, 'Mask', "SetIntMask" );
                   3733:     meshAddr->interruptMask = mask;         /* enable whatever  */
                   3734:     SynchronizeIO();
                   3735:     return;
                   3736: }/* end SetIntMask */
                   3737: 
                   3738: 
                   3739: - (void) AbortActiveCommand
                   3740: {
                   3741:     IOReturn        ioReturn;
                   3742: 
                   3743: 
                   3744:     ELG( gActiveCommand, 0, '-AB*', "AbortActiveCommand" );
                   3745:     [ self GetHBARegsAndClear : TRUE ];   /* clear possible cmdDone et al  */
                   3746:     [ self SetIntMask : 0 ];              /* Disable MESH interrupts       */
                   3747: 
                   3748:     gMsgInFlag = 0;                       /* clear kFlagMsgIn_Reject et al */
                   3749: 
                   3750:     meshAddr->busStatus0 = kMeshAtn;      /***** Raise ATN signal      *****/
                   3751:     SynchronizeIO();
                   3752: 
                   3753:     [ self SetSeqReg : kMeshBusFreeCmd ]; /* clear ACK                     */
                   3754:     [ self WaitForMesh : TRUE ];          /* wait for PhaseMM              */
                   3755: 
                   3756:     if ( (g.shadow.mesh.busStatus0 & (kMeshPhaseMask | kMeshReq))
                   3757:                                    == (kBusPhaseMSGO | kMeshReq) )
                   3758:     {           /* this is what we want:    */
                   3759:             [ self SetSeqReg : kMeshFlushFIFO ];    /* Flush the FIFO           */
                   3760:             meshAddr->transferCount0    = 1;        /* set TC low = 1           */
                   3761:             meshAddr->transferCount1    = 0;
                   3762:             meshAddr->busStatus0        = 0;        /***** clear ATN signal *****/
                   3763:             SynchronizeIO();
                   3764: 
                   3765:                 /* Issue the Message Out sending the Abort on its way.  */
                   3766:                 /* Note that this will cause an Unexpected-Disconnect.  */
                   3767:             [ self SetSeqReg : kMeshMessageOutCmd ]; /* drop ATN signal         */
                   3768:             meshAddr->xFIFO = kScsiMsgAbort;         /* put out the Abort byte  */
                   3769:             ioReturn = [ self WaitForMesh : TRUE ];  /* wait for cmdDone        */
                   3770:             if ( ioReturn == IO_R_SUCCESS )
                   3771:             {
                   3772:                 [ self SetSeqReg : kMeshEnableReselect ];/* bus about to go free    */
                   3773:                 [ self SetIntMask : kMeshIntrMask ];     /* Enable interrupts       */
                   3774:                 [ self SetSeqReg : kMeshBusFreeCmd ];    /* Clr ACK & go Bus-Free   */
                   3775:                 g.intLevel |= kLevelLatched;             /* set latched-int flag    */
                   3776:                 return;
                   3777:             }
                   3778:     }/* end IF MSGO phase and REQ is set */
                   3779:  
                   3780:         /***** USE THE HAMMER - NUKE THE BUS: *****/
                   3781: 
                   3782:     ELG( 0, 0, '-AB-', "AbortActiveCommand - target refused to enter MSGO phase" );
                   3783:     [ self ResetHardware : TRUE ];
                   3784:     return;
                   3785: }/* end AbortActiveCommand */
                   3786: 
                   3787: 
                   3788: - (void) AbortDisconnectedCommand
                   3789: {
                   3790:     CommandBuffer       *cmdBuf;
                   3791:     IOSCSIRequest       *scsiReq;
                   3792:     UInt8               msgByte;
                   3793: 
                   3794: 
                   3795:     if ( !queue_empty( &abortCmdQ ) )
                   3796:     {
                   3797:         cmdBuf    = (CommandBuffer*)queue_first( &abortCmdQ );
                   3798:         scsiReq   = cmdBuf->scsiReq;
                   3799:         meshAddr->destinationID = scsiReq->target;
                   3800:         msgOutPtr = (UInt8*)CCLAddress( kcclMSGOdata );
                   3801:         msgByte   = kScsiMsgIdentify | scsiReq->lun;
                   3802:         *msgOutPtr++ = msgByte;
                   3803:         if ( cmdBuf->queueTag )
                   3804:         {       /* Tagged command: */
                   3805:             *msgOutPtr++ = kScsiMsgSimpleQueueTag;
                   3806:             *msgOutPtr++ = cmdBuf->queueTag;
                   3807:             *msgOutPtr++ = kScsiMsgAbortTag;
                   3808:             ELG( cmdBuf, cmdBuf->queueTag, 'AbT-', "AbortDisconnectedCommand - Tag" );
                   3809:         }
                   3810:         else
                   3811:         {       /* Untagged command: */
                   3812:             *msgOutPtr++ = kScsiMsgAbort;
                   3813:             ELG( cmdBuf, 0, 'AbU-', "AbortDisconnectedCommand - Abort (untagged)" );
                   3814:         }
                   3815:         [ self SetupMsgO ];     /* Setup for Message Out phase. */
                   3816: 
                   3817:         [ self RunDBDMA : kcclStart  stageLabel : kcclStageInit ];
                   3818:     }
                   3819:     return;
                   3820: }/* end AbortDisconnectedCommand */
                   3821: 
                   3822: 
                   3823: - (void) logTimestamp : (const char*) reason
                   3824: {
                   3825: #if DEBUG
                   3826:     /* kMaxTimestamp should be greater than twice the expected method depth     */
                   3827:     /* since, if we dump the timestamp after it has wrapped around, we expect   */
                   3828:     /* to lose earlier entries and, hence, the shallower method starts.         */
                   3829: #ifndef kMaxTimestampStack
                   3830: #define kMaxTimestampStack  64
                   3831: #endif
                   3832: 
                   3833:     TimestampDataRecord stack[ kMaxTimestampStack + 1 ];    /* Allocate one extra */
                   3834:     UInt32              index       = 0;
                   3835:     int                 start;
                   3836:     UInt32              count       = 0;
                   3837:     UInt32              maxDepth    = 0;
                   3838:     Boolean             wasEnabled, unused;
                   3839:     char                work[ 8 ];
                   3840:     struct timeval      tv;
                   3841:     ns_time_t           lastEventTime;
                   3842:     UInt32              elapsed;
                   3843:     UInt32              sinceMethodStart;
                   3844: 
                   3845: 
                   3846:     if ( reason )
                   3847:     {
                   3848:         IOLog( "%s: *** Log timestamp: %s\n",    [ self name ], reason );
                   3849:     }
                   3850: 
                   3851:         /* In case something we call causes timestamping,   */
                   3852:         /* we want to avoid getting into an infinite loop.  */
                   3853: 
                   3854:     wasEnabled = EnableTimestamp( FALSE );
                   3855:     lastEventTime = 0;
                   3856:     while ( ReadTimestamp( &stack[ index ] ) )
                   3857:     {
                   3858:         ++count;
                   3859:         work[0] = stack[ index ].timestampTag >> 24 & 0xFF;
                   3860:         work[1] = stack[ index ].timestampTag >> 16 & 0xFF;
                   3861:         work[2] = stack[ index ].timestampTag >>  8 & 0xFF;
                   3862:         work[3] = stack[ index ].timestampTag >>  0 & 0xFF;
                   3863:         work[4] = '\0';
                   3864: 
                   3865:         elapsed         = (unsigned)stack[ index ].eventTime - lastEventTime;
                   3866:         lastEventTime   = stack[ index ].eventTime;
                   3867:         ns_time_to_timeval( stack[ index ].eventTime, &tv );
                   3868: 
                   3869:         switch ( work[0] )
                   3870:         {
                   3871:         case '+':       /* Entering a method */
                   3872:             IOLog( "%s: '%s' %u.%06u %u.%03u 0.0 %d\n",
                   3873:                     [ self name ],  work,
                   3874:                     tv.tv_sec,      tv.tv_usec,
                   3875:                     elapsed / 1000, elapsed - ((elapsed / 1000) * 1000),
                   3876:                     stack[ index ].timestampValue );
                   3877:             if ( index < kMaxTimestampStack )
                   3878:             {   if ( ++index > maxDepth )
                   3879:                     maxDepth = index;
                   3880:             }
                   3881:             break;
                   3882: 
                   3883:         case '=':           /* Intermediate tag: find the method start  */
                   3884:         case '-':           /* End of method: find the method start     */
                   3885:             sinceMethodStart = 0;
                   3886:             for ( start = index - 1; start >= 0; --start )
                   3887:             {
                   3888:                 if ( (stack[ start ].timestampTag & 0x00FFFFFF)
                   3889:                         == (stack[ index ].timestampTag & 0x00FFFFFF) )
                   3890:                 {
                   3891:                     sinceMethodStart    = (unsigned)stack[ index ].eventTime
                   3892:                                         - stack[ start ].eventTime;
                   3893:                     break;
                   3894:                 }
                   3895:             }
                   3896:             IOLog( "%s: '%s' %u.%06u %u.%03u %u.%03u %d\n",
                   3897:                     [ self name ],  work,
                   3898:                     tv.tv_sec,      tv.tv_usec,
                   3899:                     elapsed / 1000, elapsed - ((elapsed / 1000) * 1000),
                   3900:                     sinceMethodStart / 1000,
                   3901:                     sinceMethodStart - ((sinceMethodStart / 1000) * 1000),
                   3902:                     stack[ index ].timestampValue );
                   3903:             if ( start >= 0 && work[0] == '-' )
                   3904:                 index = start;      /* Pop the stack */
                   3905:             break;
                   3906: 
                   3907:         default:
                   3908:             IOLog( "%s: '%s' %u.%06u %u.%03u 0.0 %d _NoNestMark_\n",
                   3909:                 [ self name ],
                   3910:                 work,
                   3911:                 tv.tv_sec,
                   3912:                 tv.tv_usec,
                   3913:                 elapsed / 1000,
                   3914:                 elapsed - ((elapsed / 1000) * 1000),
                   3915:                 stack[ index ].timestampValue );
                   3916:             break;
                   3917:         }
                   3918:     }/* end WHILE */
                   3919: 
                   3920:     IOLog( "%s: *** %d timestamps, %d max method depth\n",
                   3921:             [ self name ], count, maxDepth );
                   3922:     unused = EnableTimestamp( wasEnabled );
                   3923: #endif /* DEBUG */
                   3924:     return;
                   3925: }/* end logTimestamp */
                   3926: 
                   3927: @end /* AppleMesh_SCSI(Mesh) */
                   3928: 
                   3929: 
                   3930: @implementation AppleMesh_SCSI( Private )
                   3931: 
                   3932:     /* Private chip- and architecture-independent methods.  */
                   3933: 
                   3934:     /* Pass one CommandBuffer to the IO thread; wait for completion.    */
                   3935:     /* (We are called on the client's execution thread.)                */
                   3936:     /* Normal completion status is in cmdBuf->scsiReq->driverStatus;    */
                   3937:     /* a non-zero return from this function indicates a Mach IPC error. */
                   3938:     /* This method allocates and frees cmdBuf->cmdLock.                 */
                   3939: 
                   3940: - (IOReturn) executeCmdBuf : (CommandBuffer*) cmdBuf
                   3941: {
                   3942:     msg_header_t    msg             = cmdMessageTemplate;
                   3943:     kern_return_t   kernelReturn;
                   3944:     IOReturn        ioReturn        = IO_R_SUCCESS;
                   3945: 
                   3946: 
                   3947:     cmdBuf->flagActive  = 0;
                   3948:     cmdBuf->cmdLock     = [ [ NXConditionLock alloc ] initWith : CMD_PENDING ];
                   3949:     [ incomingCmdLock lock ];
                   3950:     queue_enter( &incomingCmdQ, cmdBuf, CommandBuffer*, link );
                   3951:     [ incomingCmdLock unlock ];
                   3952:     ELG( cmdBuf, *(UInt32*)&incomingCmdQ, 'ExeC', "executeCmdBuf" );
                   3953: 
                   3954:         /* Create a Mach message and send it in order to wake up the IO thread: */
                   3955: 
                   3956:     msg.msg_remote_port = gKernelInterruptPort;
                   3957:     kernelReturn        = msg_send_from_kernel( &msg, MSG_OPTION_NONE, 0 );
                   3958:     if ( kernelReturn != KERN_SUCCESS )
                   3959:     {
                   3960:         PAUSE( 0, kernelReturn, 'exe-', "executeCmdBuf - msg_send_from_kernel() error status .\n" );
                   3961:         ioReturn = IO_R_IPC_FAILURE;
                   3962:     }
                   3963:     else    /* Wait for IO complete:    */
                   3964:     {
                   3965:         [ cmdBuf->cmdLock lockWhen : CMD_COMPLETE ];
                   3966:     }
                   3967: 
                   3968:     [ cmdBuf->cmdLock free ];
                   3969:     return ioReturn;
                   3970: }/* end executeCmdBuf */
                   3971: 
                   3972: 
                   3973:     /* Abort all active and disconnected commands with specified status.    */
                   3974:     /* No hardware action. Currently used by threadResetBus and during      */
                   3975:     /* processing of a kCommandAbortRequest command.                        */
                   3976: 
                   3977: - (void) abortAllCommands : (sc_status_t)status
                   3978: {
                   3979:     ELG( 0, status, 'AbAl', "abortAllCommands" );
                   3980:     [ incomingCmdLock lock ];
                   3981: 
                   3982:     [ self killActiveCommand : status ];
                   3983: 
                   3984:     [ self killQueue  : &abortCmdQ         finalStatus : status ];
                   3985:     [ self killQueue  : &disconnectedCmdQ  finalStatus : status ];
                   3986:     [ self killQueue  : &pendingCmdQ       finalStatus : status ];
                   3987:     [ self killQueue  : &incomingCmdQ      finalStatus : status ];
                   3988: 
                   3989:     [ incomingCmdLock unlock ];
                   3990:     return;
                   3991: }/* end abortAllCommands */
                   3992: 
                   3993: 
                   3994:     /* Abort all active and disconnected commands with status SR_IOST_RESET. */
                   3995:     /* Reset hardware and SCSI bus.                                          */
                   3996:     /* If there is a command in pendingCmdQ, start it up.                    */
                   3997: 
                   3998: - (void) threadResetBus : (const char*) reason
                   3999: {
                   4000:     [ self abortAllCommands : SR_IOST_RESET ];
                   4001:     [ self ResetHardware : TRUE ];      /* Reset SCSI and chip               */
                   4002:     [ self selectNextRequest ];         /* This restarts processing commands */
                   4003:     return;
                   4004: }/* end threadResetBus */
                   4005: 
                   4006: 
                   4007:     /* Commence processing of the specified command. This is called by      */
                   4008:     /* commandRequestOccurred when it receives a kCommandExecute message    */
                   4009:     /* from IODirectDevice. There is a new SCSI request. Either start it    */
                   4010:     /* now, or add it to the end of our pending request queue.              */
                   4011: 
                   4012: - (void) threadExecuteRequest : (CommandBuffer*) cmdBuf
                   4013: {
                   4014:     HardwareStartResult rc;
                   4015: 
                   4016: 
                   4017:     if ( gActiveCommand || (g.intLevel & kLevelLatched) )
                   4018:     {
                   4019:             /* We are currently executing a request.    */
                   4020: 
                   4021:         ELG( gActiveCommand, cmdBuf, 'Busy', "threadExecuteRequest - bus busy so queue this cmd" );
                   4022:         queue_enter( &pendingCmdQ, cmdBuf, CommandBuffer*, link );
                   4023:     }
                   4024:     else if ( [ self commandCanBeStarted : cmdBuf ] == FALSE )
                   4025:     {
                   4026:             /* This request can't be started right now (perhaps the */
                   4027:             /* target's tagged command limit has been reached).     */
                   4028: 
                   4029:         ELG( cmdBuf, 0, 'qFul', "threadExecuteRequest - can't start cmd so queue this cmd" );
                   4030:         queue_enter( &pendingCmdQ, cmdBuf, CommandBuffer*, link );
                   4031:     }
                   4032:     else
                   4033:     {       /* Apparently, we can start this request. Call the hardware layer.  */
                   4034: 
                   4035:         rc = [ self hardwareStart : cmdBuf ];
                   4036:         switch ( rc )
                   4037:         {
                   4038:         case kHardwareStartOK:          /* Command started correctly        */
                   4039:         case kHardwareStartBusy:        /* Hardware can't start now         */
                   4040:             break;
                   4041:         case kHardwareStartRejected:    /* Command rejected, try another    */
                   4042:             [ self selectNextRequest ]; /* Try another command              */
                   4043:         }
                   4044:     }
                   4045:     return;
                   4046: }/* end threadExecuteRequest */
                   4047: 
                   4048: 
                   4049:     /* Called when a transaction associated with cmdBuf is complete.    */
                   4050:     /* Notify waiting thread. If cmdBuf->scsiReq exists (i.e., this     */
                   4051:     /* is not a reset or an abort), scsiReq->driverStatus must be valid.*/
                   4052:     /* If cmdBuf is active, caller must remove from gActiveCommand.     */
                   4053:     /* We decrement activeArray[][] counter if appropriate.             */
                   4054: 
                   4055: - (void) ioComplete : (CommandBuffer*) cmdBuf
                   4056: {
                   4057:     ns_time_t           currentTime;
                   4058:     IOSCSIRequest       *scsiReq;
                   4059: 
                   4060: 
                   4061:     ASSERT( cmdBuf );
                   4062:     ELG( cmdBuf->scsiReq, cmdBuf->scsiReq->driverStatus,  ' IOC', "ioComplete" );
                   4063: 
                   4064:     if ( cmdBuf == gActiveCommand )
                   4065:         [ self deactivateCmd : cmdBuf ];
                   4066: 
                   4067:     scsiReq = cmdBuf->scsiReq;
                   4068:     if ( scsiReq )
                   4069:     {
                   4070:         IOGetTimestamp( &currentTime );
                   4071:         scsiReq->totalTime          = currentTime - cmdBuf->startTime;
                   4072:         scsiReq->bytesTransferred   = cmdBuf->currentDataIndex;
                   4073: 
                   4074:             /* Catch bad SCSI status now.   */
                   4075: 
                   4076:         if ( scsiReq->driverStatus == SR_IOST_GOOD )
                   4077:         {
                   4078:             if ( cmdBuf->flagIsAutosense )
                   4079:             {
                   4080:                     /* We are completing an autosense command. Don't touch      */
                   4081:                     /* the request status (it should still be Check Condition). */
                   4082:                     /* Queue full is a real problem.                            */
                   4083: 
                   4084:                 ASSERT( scsiReq->scsiStatus == kScsiStatusCheckCondition );
                   4085:                 switch ( cmdBuf->autosenseStatus )
                   4086:                 {
                   4087:                 case kScsiStatusGood:
                   4088:                     scsiReq->driverStatus = SR_IOST_CHKSV;
                   4089:                     break;
                   4090: 
                   4091:                 case kScsiStatusQueueFull:
                   4092:                     if ( [ self pushbackFullTargetQueue : cmdBuf ] == SR_IOST_GOOD)
                   4093:                     {
                   4094:                         return;     /* We'll try this one again */
                   4095:                     }
                   4096:                     /* Fall through to failure */
                   4097: 
                   4098:                 default:
                   4099:                     scsiReq->driverStatus = SR_IOST_CHKSNV;
                   4100:                     break;
                   4101:                 }
                   4102:             }
                   4103:             else    /* not AutoSense:   */
                   4104:             {
                   4105:                 switch ( scsiReq->scsiStatus )
                   4106:                 {
                   4107:                 case kScsiStatusGood:
                   4108:                     break;
                   4109: 
                   4110:                 case kScsiStatusCheckCondition:
                   4111: 
                   4112:                         /***** The 386 hardware suppresses autosense for    ****/
                   4113:                         /***** Test Unit Ready to avoid request sense       ****/
                   4114:                         /***** when polling for removable devices. This     ****/
                   4115:                         /***** should be the caller's decision.             ****/
                   4116: 
                   4117:                     ELG( 0, 0, 'Chek', "ioComplete - Check Condition" );
                   4118:                     if ( gOptionAutoSenseEnable
                   4119:                      && (scsiReq->ignoreChkcond == FALSE) )
                   4120:                     {
                   4121:                         cmdBuf->flagIsAutosense = 1;/* We're doing autosense    */
                   4122:                         queue_enter_first( &pendingCmdQ, cmdBuf, CommandBuffer*, link );
                   4123:                         return;
                   4124:                     }
                   4125:                     else
                   4126:                     {       /* This command failed and we aren't doing autosense.   */
                   4127:                         scsiReq->driverStatus = SR_IOST_CHKSNV;
                   4128:                     }
                   4129:                     break;
                   4130: 
                   4131:                 case kScsiStatusQueueFull:
                   4132:                     if ( [ self pushbackFullTargetQueue : cmdBuf ] == SR_IOST_GOOD)
                   4133:                     {
                   4134:                         return;
                   4135:                     }
                   4136:                     /* Huh? we weren't doing tagged queuing, fall through */
                   4137: 
                   4138:                 default:
                   4139:                     scsiReq->driverStatus = SR_IOST_BADST;
                   4140:                     break;
                   4141:                 }/* end SWITCH on SCSI status */
                   4142: 
                   4143:             }/* end IF driverStatus is SR_IOST_GOOD */
                   4144:         }/* end IF not autosense */
                   4145:     }/* end IF have scsiReq */
                   4146: 
                   4147:     if ( cmdBuf->flagActive )
                   4148:     {       /* Note that the active flag is false for non-kCommandExecute   */
                   4149:             /* commands and commands aborted from pendingCmdQ.     */
                   4150: 
                   4151:         ASSERT( cmdBuf == gActiveCommand );
                   4152:         [ self deactivateCmd : cmdBuf ];
                   4153:     }
                   4154: 
                   4155:     [ cmdBuf->cmdLock lock ];
                   4156:     [ cmdBuf->cmdLock unlockWith : YES ];
                   4157: 
                   4158:     return;
                   4159: }/* end ioComplete */
                   4160: 
                   4161: 
                   4162:     /* A target reported a full queue. Push this command back       */
                   4163:     /* on the pending queue and try it again, later.                */
                   4164:     /* Return SR_IOST_GOOD if successful, SR_IOST_BADST on failure. */
                   4165: 
                   4166: - (sc_status_t) pushbackFullTargetQueue : (CommandBuffer*) cmdBuf
                   4167: {
                   4168:     IOSCSIRequest   *scsiReq;
                   4169:     int             target, lun;
                   4170:     IOReturn        ioReturn;
                   4171: 
                   4172: 
                   4173:     ASSERT( cmdBuf && cmdBuf->scsiReq );
                   4174:         /* Avoid notifying client of this condition; update           */
                   4175:         /* perTarget.maxQueue and place this request on pendingCmdQ. */
                   4176:         /* We'll try this again when we ioComplete at least one       */
                   4177:         /* command in this target's queue.                            */
                   4178:         /* Note that this can execute commands out of order.          */
                   4179:         /* This can be disastrous for directory commands.             */
                   4180:         /* In the long run, the client (disk/tape/whatever)           */
                   4181:         /* needs to tell us how to execute the command                */
                   4182:         /* (in-order, out-of-order, etc.) For example,                */
                   4183:         /* virtual-memory page faults can be executed                 */
                   4184:         /* out of order, but directory and volume bitmap              */
                   4185:         /* updates must be executed in-order to preserve              */
                   4186:         /* volume integrity.                                          */
                   4187:     if ( cmdBuf->queueTag == QUEUE_TAG_NONTAGGED )
                   4188:     {
                   4189:             /* Huh? We're not doing command queueing... */
                   4190:         ioReturn = SR_IOST_BADST;
                   4191:     }
                   4192:     else
                   4193:     {
                   4194:         scsiReq     = cmdBuf->scsiReq;
                   4195:         target      = scsiReq->target;
                   4196:         lun         = scsiReq->lun;
                   4197:         gPerTargetData[ target ].maxQueue = gActiveArray[ target ][ lun ];
                   4198:         [ self pushbackCurrentRequest : cmdBuf ];
                   4199:         ioReturn = SR_IOST_GOOD;
                   4200:     }
                   4201:     return ioReturn;
                   4202: }/* end pushbackFullTargetQueue */
                   4203: 
                   4204: 
                   4205:     /* Push this request back on the pending queue. */
                   4206: 
                   4207: - (void) pushbackCurrentRequest : (CommandBuffer*) cmdBuf
                   4208: {
                   4209:     ASSERT( cmdBuf );
                   4210:     if ( cmdBuf->flagActive )
                   4211:     {
                   4212:         ASSERT( cmdBuf == gActiveCommand );
                   4213:         [ self deactivateCmd : cmdBuf ];
                   4214:     }
                   4215:     queue_enter_first( &pendingCmdQ, cmdBuf, CommandBuffer*, link );
                   4216:     return;
                   4217: }/* end pushbackCurrentRequest */
                   4218: 
                   4219: 
                   4220:     /* Kill a request that can't be continued.  */
                   4221: 
                   4222: - (void) killCurrentRequest
                   4223: {
                   4224:     CommandBuffer   *cmdBuf;
                   4225:     IOSCSIRequest   *scsiReq;
                   4226: 
                   4227: 
                   4228:     if ( gActiveCommand )
                   4229:     {
                   4230:         cmdBuf = gActiveCommand;
                   4231:         ASSERT( cmdBuf->scsiReq );
                   4232:         scsiReq = cmdBuf->scsiReq;
                   4233: 
                   4234:         if ( cmdBuf->flagRequestSelectOK == FALSE )
                   4235:              scsiReq->driverStatus = SR_IOST_SELTO;     /* No such device   */
                   4236:         else scsiReq->driverStatus = SR_IOST_HW;        /* Target went away */
                   4237: 
                   4238:         [ self deactivateCmd    : cmdBuf ];
                   4239:         [ self ioComplete       : cmdBuf ];
                   4240:     }
                   4241:     return;
                   4242: }/* end killCurrentRequest */
                   4243: 
                   4244: 
                   4245:     /* IO associated with gActiveCommand has disconnected.  */
                   4246:     /* Place it on the disconnected command queue and       */
                   4247:     /* enable another transaction.                          */
                   4248: 
                   4249: - (void) disconnect
                   4250: {
                   4251:     ASSERT( gActiveCommand );
                   4252:     queue_enter( &disconnectedCmdQ, gActiveCommand, CommandBuffer*, link );
                   4253: 
                   4254: 
                   4255:         /* Record this time so that gActiveCommand can be billed    */
                   4256:         /* for disconnect latency at reselect time.                 */
                   4257: 
                   4258:     IOGetTimestamp( &gActiveCommand->disconnectTime );
                   4259:     gActiveCommand  = NULL;
                   4260:     gCurrentTarget  = kInvalidTarget;
                   4261:     gCurrentLUN     = kInvalidLUN;
                   4262: 
                   4263:         /* Since there is no active command, the caller */
                   4264:         /* must configure the bus interface to wait for */
                   4265:         /* bus free, then allow reselection.            */
                   4266: 
                   4267:     return;
                   4268: }/* end disconnect */
                   4269: 
                   4270: 
                   4271:     /* The specified target, LUN, and queueTag is trying to reselect.   */
                   4272:     /* If we have a CommandBuffer for this TLQ nexus on disconnectQ,    */
                   4273:     /* remove it, make it the current gActiveCommand, and return YES.   */
                   4274:     /* Else return NO. A value of zero for queueTag indicates a         */
                   4275:     /* nontagged command (zero is never used as the queue tag value for */
                   4276:     /* a tagged command).                                               */
                   4277: 
                   4278: - (IOReturn) reselectNexus  : (UInt8) target
                   4279:                 lun         : (UInt8) lun
                   4280:                 queueTag    : (UInt8) queueTag
                   4281: {
                   4282:     CommandBuffer   *cmdBuf;
                   4283:     IOSCSIRequest   *scsiReq;
                   4284:     ns_time_t       currentTime;
                   4285:     IOReturn        ioReturn = SR_IOST_BV;  /* Presume failure      */
                   4286: 
                   4287: 
                   4288:         /* Scan the disconnected queue looking for  */
                   4289:         /* a command for this nexus.                */
                   4290: 
                   4291:     ASSERT( gActiveCommand == NULL );
                   4292: 
                   4293:     cmdBuf = (CommandBuffer*)queue_first( &disconnectedCmdQ );
                   4294: 
                   4295:     while ( !queue_end( &disconnectedCmdQ, (queue_t)cmdBuf ) )
                   4296:     {
                   4297:         scsiReq = cmdBuf->scsiReq;
                   4298:         if (scsiReq->target     == target
                   4299:          && scsiReq->lun        == lun
                   4300:          && cmdBuf->queueTag    == queueTag )
                   4301:         {
                   4302:                 /* We found the correct command.    */
                   4303: 
                   4304:             queue_remove( &disconnectedCmdQ, cmdBuf, CommandBuffer*, link );
                   4305:             gActiveCommand = cmdBuf;
                   4306:             ASSERT( scsiReq->target == gCurrentTarget && scsiReq->lun == gCurrentLUN );
                   4307: 
                   4308:                 /* Bill this operation for latency time:    */
                   4309: 
                   4310:             IOGetTimestamp( &currentTime );
                   4311:             scsiReq->latentTime += (currentTime - gActiveCommand->disconnectTime);
                   4312:             ioReturn = IO_R_SUCCESS;
                   4313:             break;
                   4314:         }
                   4315:             /* Try next element in queue.   */
                   4316: 
                   4317:         cmdBuf = (CommandBuffer*)cmdBuf->link.next;
                   4318:     }/* end WHILE */
                   4319: 
                   4320:     return  ioReturn;
                   4321: }/* end reselectNexus */
                   4322: 
                   4323: 
                   4324:     /* Determine if gActiveArray[][], maxQueue, cmdQueueEnable, and a cmd's */
                   4325:     /* Target and LUN show that it's OK to start processing cmdBuf.         */
                   4326:     /* Returns YES if this command can be started.                          */
                   4327:     /***** Here's where we can test for a frozen LUN queue.             *****/
                   4328: 
                   4329: - (Boolean) commandCanBeStarted : (CommandBuffer*) cmdBuf
                   4330: {
                   4331:     IOSCSIRequest   *scsiReq;
                   4332:     unsigned        target;
                   4333:     unsigned        lun;
                   4334:     UInt8           active;
                   4335:     UInt8           maxQ;
                   4336:     Boolean         result;
                   4337: 
                   4338: 
                   4339:     ASSERT( cmdBuf && cmdBuf->scsiReq );
                   4340: 
                   4341:     scsiReq     = cmdBuf->scsiReq;
                   4342:     target      = scsiReq->target;
                   4343:     lun         = scsiReq->lun;
                   4344:     active = gActiveArray[ target ][ lun ];
                   4345:     if ( active == 0 )
                   4346:     {       /* No commands are active for this target, always ok.   */
                   4347:         result = TRUE;
                   4348:     }
                   4349:     else if ( gOptionCmdQueueEnable == FALSE
                   4350:           || ((gPerTargetData[ target ].inquiry_7 & 0x02) == 0) )
                   4351:     {
                   4352:         ELG( active, gOptionCmdQueueEnable, 'CQE-', "commandCanBeStarted - cmd q'n disabled" );
                   4353:         result = FALSE; /*  q'ing is disabled for target (or disabled globally) */
                   4354:     }
                   4355:     else
                   4356:     {
                   4357:         maxQ = gPerTargetData[ target ].maxQueue;
                   4358:         if ( maxQ == 0 || active < maxQ )
                   4359:         {       /* If maxQ is zero, we haven't reached the target's limit.  */
                   4360:                 /* Otherwise, we're under the limit.                        */
                   4361:                 /* In both cases, we can (presumably) start this command.   */
                   4362: 
                   4363:             result = TRUE;
                   4364:         }
                   4365:         else
                   4366:         {
                   4367:             ELG( maxQ, active, 'QLm-', "commandCanBeStarted - queue limit reached." );
                   4368:             result = FALSE; /* We're over the target limit. Wait on this one.   */
                   4369:         }
                   4370:     }
                   4371:     return  result;
                   4372: }/* end commandCanBeStarted */
                   4373: 
                   4374: 
                   4375:     /* The bus has gone free. Start up a command from pendingCmdQ,         */
                   4376:     /* if any, and if allowed by cmdQueueEnable and gActiveArray[][].       */
                   4377:     /* This is called from the interrupt routine when it is about to exit   */
                   4378:     /* (and the bus is free and there is no active command). It may also    */
                   4379:     /* be called from threadExecuteRequest when the selected command        */
                   4380:     /* couldn't be started.                                                 */
                   4381: 
                   4382: - (void) selectNextRequest
                   4383: {
                   4384:     CommandBuffer   *cmdBuf         = NULL;
                   4385:     Boolean         foundRequest    = FALSE;
                   4386: 
                   4387: 
                   4388:     if ( !queue_empty( &abortCmdQ ) )
                   4389:     {
                   4390:         [ self AbortDisconnectedCommand ];
                   4391:         return;
                   4392:     }
                   4393: 
                   4394:     if ( !queue_empty( &pendingCmdQ ) )
                   4395:     {
                   4396:             /* Attempt to find a CommandBuffer in pendingCmdQ  */
                   4397:             /* which we are in a position to process:           */
                   4398: 
                   4399:         cmdBuf = (CommandBuffer*)queue_first( &pendingCmdQ );
                   4400:         while ( !queue_end( &pendingCmdQ, (queue_entry_t)cmdBuf ) )
                   4401:         {
                   4402:             if ( [ self commandCanBeStarted : cmdBuf ] )
                   4403:             {
                   4404:                 queue_remove( &pendingCmdQ, cmdBuf, CommandBuffer*, link);
                   4405:                 ELG( cmdBuf, cmdBuf->scsiReq->lun<<16 | cmdBuf->scsiReq->target, 'De Q', "selectNextRequest - dequeued one." );
                   4406:                 foundRequest = TRUE;
                   4407:                 break;
                   4408: 
                   4409:                     /* Note that threadExecuteRequest may call selectNextRequest    */
                   4410:                     /* if the command was rejected. If so, the rejected */
                   4411:                     /* command will have been returned (with an error   */
                   4412:                     /* status) to its client, so there is no chance of  */
                   4413:                     /* an infinite loop here.                           */
                   4414:             }
                   4415:             else
                   4416:             {
                   4417:                 cmdBuf = (CommandBuffer*)queue_next( &cmdBuf->link );
                   4418:             }
                   4419:         }/* end WHILE */
                   4420:     }/* end IF queue not empty */
                   4421: 
                   4422:     if ( foundRequest )
                   4423:         [ self threadExecuteRequest : cmdBuf ];
                   4424: 
                   4425:     return;
                   4426: }/* end selectNextRequest */
                   4427: 
                   4428: 
                   4429: - (void) killActiveCommand : (sc_status_t)status
                   4430: {
                   4431:     ELG( gActiveCommand, status, 'KilA', "killActiveCommand" );
                   4432:     if ( gActiveCommand )
                   4433:     {
                   4434:         gActiveCommand->scsiReq->driverStatus = status;
                   4435:         [ self ioComplete : gActiveCommand ];
                   4436:         gActiveCommand  = NULL;
                   4437:         gCurrentTarget  = kInvalidTarget;
                   4438:         gCurrentLUN     = kInvalidLUN;
                   4439:     }
                   4440:     return;
                   4441: }/* end killActiveCommand */
                   4442: 
                   4443: 
                   4444:     /* Called by chip level to indicate that a command  */
                   4445:     /* has gone out to the hardware.                    */
                   4446: 
                   4447: - (void) activateCommand : (CommandBuffer*)cmdBuf
                   4448: {
                   4449:     ASSERT( gActiveCommand == NULL );
                   4450: 
                   4451:         /* This is the only place where a gActiveArray[][] counter      */
                   4452:         /* is incremented (and, hence, the only place where             */
                   4453:         /* cmdBuf->active is set). The only other place gActiveCommand  */
                   4454:         /* is set to non-NULL is in reselectNexus:target:lun:queueTag   */
                   4455:         /* (but that doesn't increment the active command counter)      */
                   4456: 
                   4457:     gActiveCommand      = cmdBuf;
                   4458:     gCurrentTarget      = cmdBuf->scsiReq->target;
                   4459:     gCurrentLUN         = cmdBuf->scsiReq->lun;
                   4460:     gActiveArray[ gCurrentTarget ][ gCurrentLUN ]++;
                   4461:     gActiveCount++;
                   4462: 
                   4463:     cmdBuf->flagActive  = TRUE;
                   4464: 
                   4465:         /* Accumulate statistics.   */
                   4466: 
                   4467:     gMaxQueueLen = MAX( gMaxQueueLen, gActiveCount );
                   4468:     gQueueLenTotal += gActiveCount;
                   4469:     gTotalCommands++;
                   4470:     return;
                   4471: }/* end activateCommand */
                   4472: 
                   4473: 
                   4474:     /* Remove specified cmdBuf from "active" status.                    */
                   4475:     /* Update activeArray, activeCount, and unschedule pending timer.   */
                   4476: 
                   4477: - (void) deactivateCmd : (CommandBuffer*)cmdBuf
                   4478: {
                   4479:     IOSCSIRequest   *scsiReq;
                   4480:     unsigned        target, lun;
                   4481: 
                   4482: 
                   4483:     ASSERT( cmdBuf  && cmdBuf->scsiReq );
                   4484:     ASSERT( cmdBuf == gActiveCommand );     /* ??  */
                   4485:     gActiveCommand      = NULL;
                   4486:     gCurrentTarget      = kInvalidTarget;
                   4487:     gCurrentLUN         = kInvalidLUN;
                   4488:     scsiReq             = cmdBuf->scsiReq;
                   4489:     target              = scsiReq->target;
                   4490:     lun                 = scsiReq->lun;
                   4491: 
                   4492:     ASSERT( gActiveArray[ target ][ lun ] );
                   4493:     gActiveArray[ target ][ lun ]--;
                   4494:     ASSERT( gActiveCount );
                   4495:     gActiveCount--;
                   4496: 
                   4497:         /* Cancel pending timeout request.                                      */
                   4498:         /* Commands which timed out don't have a timer request pending anymore. */
                   4499: 
                   4500:     if ( scsiReq->driverStatus != SR_IOST_IOTO )
                   4501:     {
                   4502:         IOUnscheduleFunc( serviceTimeoutInterrupt, cmdBuf );
                   4503:     }
                   4504:     cmdBuf->flagActive = FALSE;
                   4505:     return;
                   4506: }/* end deactivateCmd */
                   4507: 
                   4508: 
                   4509:     /* Kill everything in the indicated queue. Called after bus reset.  */
                   4510: 
                   4511: - (void) killQueue : (queue_head_t*)queuePtr   finalStatus : (sc_status_t)scsiStatus
                   4512: {
                   4513:     CommandBuffer   *cmdBuf;
                   4514: 
                   4515: 
                   4516:     ELG( 0, queuePtr, 'KilQ', "killQueue" );
                   4517:     while ( !queue_empty( queuePtr ) )
                   4518:     {
                   4519:         cmdBuf = (CommandBuffer*)queue_first( queuePtr );
                   4520:         queue_remove( queuePtr, cmdBuf, CommandBuffer*, link );
                   4521:         cmdBuf->scsiReq->driverStatus = scsiStatus;
                   4522:         [ self ioComplete : cmdBuf ];
                   4523:     }
                   4524:     return;
                   4525: }/* end killQueue */
                   4526: 
                   4527: 
                   4528: - (void) UpdateCurrentIndex
                   4529: {
                   4530:     CommandBuffer   *cmdBuf     = gActiveCommand;
                   4531:     IOSCSIRequest   *scsiReq    = cmdBuf->scsiReq;
                   4532:     UInt32          count;                           /* DMA transfer count */
                   4533:     UInt32          length = g.shadow.mesh.FIFOCount;
                   4534:     UInt8           buffer[ 16 ];
                   4535:     UInt32          i;
                   4536: 
                   4537:         /* Calculate the number of bytes xferred by this channel command.   */
                   4538:         /* We don't trust the DBDMA residual count.                         */
                   4539: 
                   4540:     count  = CCLWord( kcclBatchSize );              /* Our transfer count   */
                   4541:     if ( count == 0 )                               /* If batch is empty,   */
                   4542:         return;                                     /* look at nothing else.*/
                   4543:     count -= g.shadow.mesh.transferCount1 << 8;     /* MESH residual high   */
                   4544:     count -= g.shadow.mesh.transferCount0;          /* MESH residual low    */
                   4545:     cmdBuf->currentDataIndex += count;              /* Increment data index */
                   4546:     if ( cmdBuf->mem )
                   4547:         [ cmdBuf->mem setPosition : cmdBuf->currentDataIndex ];
                   4548:     CCLWord( kcclBatchSize ) = 0;                   /* Clear our count      */
                   4549: 
                   4550:         /* Check the FIFO, if empty, increment the current data pointer.    */
                   4551:         /* If there is stuff in it, we have more work to do.                */
                   4552: 
                   4553:     if ( g.shadow.mesh.FIFOCount )                /* If data in FIFO:       */
                   4554:     {
                   4555:         if ( scsiReq->read == FALSE )             /* If Writing:            */
                   4556:         {
                   4557:             [ self SetSeqReg : kMeshFlushFIFO ];
                   4558:                 /* We didn't write these bytes in the FIFO - adjust index   */
                   4559:             cmdBuf->currentDataIndex -= g.shadow.mesh.FIFOCount;
                   4560:             if (  cmdBuf->mem )
                   4561:                 [ cmdBuf->mem setPosition : cmdBuf->currentDataIndex ];
                   4562: 
                   4563:         }
                   4564:         else    /* Must be Reading:                                     */
                   4565:         {       /* On a Read with data left in the FIFO, we must copy   */
                   4566:                 /* the FIFO directly into the user's data buffer:       */
                   4567: 
                   4568:             ELG( cmdBuf->currentDataIndex, g.shadow.mesh.FIFOCount, 'FIFO',
                   4569:                                 "UpdateCurrentIndex - copy FIFO to user buffer." );
                   4570:             [ cmdBuf->mem setPosition : cmdBuf->currentDataIndex ];
                   4571:             count = scsiReq->maxTransfer - cmdBuf->currentDataIndex;
                   4572:             if ( count > length )
                   4573:                  count = length;
                   4574: 
                   4575:                 /* FYI - emptying the FIFO causes cmdDone to get set.   */
                   4576: 
                   4577:             for ( i = 0; i < count; i++ )
                   4578:                 buffer[ i ] = meshAddr->xFIFO;
                   4579: 
                   4580:             [ cmdBuf->mem writeToClient : buffer  count : count ];
                   4581:             cmdBuf->currentDataIndex += count;
                   4582:             [ cmdBuf->mem setPosition : cmdBuf->currentDataIndex ];
                   4583:         }/* end if/ELSE must be Reading */
                   4584:     }/* end IF FIFO was not empty */
                   4585:     ELG( 0, cmdBuf->currentDataIndex, 'UpIx', "UpdateCurrentIndex" );
                   4586:     return;
                   4587: }/* end UpdateCurrentIndex */
                   4588: 
                   4589: 
                   4590: @end   /* AppleMesh_SCSI( Private ) */

unix.superglobalmegacorp.com

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