Annotation of kernel/bsd/dev/ppc/drvAppleMesh_SCSI/MESH_DBDMA.m, revision 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.