/* * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.0 (the 'License'). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ //----------------------------------------------------------------------------- // Includes //----------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef KERNEL_PRIVATE #define KERNEL_PRIVATE #include #undef KERNEL_PRIVATE #else #include #endif /*KERNEL_PRIVATE*/ #include #include #include #include #define DEBUG 0 //----------------------------------------------------------------------------- // Structures //----------------------------------------------------------------------------- typedef struct SCSITaskLogEntry { TAILQ_ENTRY(SCSITaskLogEntry) chain; unsigned int taskID; uint8_t cdb[16]; } SCSITaskLogEntry; //----------------------------------------------------------------------------- // Constants //----------------------------------------------------------------------------- enum { kSCSITaskTracePointCDBLog1Code = SCSITASK_TRACE ( kSCSITaskTracePointCDBLog1 ), kSCSITaskTracePointCDBLog2Code = SCSITASK_TRACE ( kSCSITaskTracePointCDBLog2 ), kSCSITaskTracePointResponseLog1Code = SCSITASK_TRACE ( kSCSITaskTracePointResponseLog1 ), kSCSITaskTracePointResponseLog2Code = SCSITASK_TRACE ( kSCSITaskTracePointResponseLog2 ), }; enum { kATADeviceInfoCode = ATAPI_TRACE( kATADeviceInfo ), kATASendSCSICommandCode = ATAPI_TRACE( kATASendSCSICommand ), kATASendSCSICommandFailedCode = ATAPI_TRACE( kATASendSCSICommandFailed ), kATACompleteSCSICommandCode = ATAPI_TRACE( kATACompleteSCSICommand ), kATAAbortCode = ATAPI_TRACE( kATAAbort ), kATAResetCode = ATAPI_TRACE( kATAReset ), kATAResetCompleteCode = ATAPI_TRACE( kATAResetComplete ), kATAHandlePowerOnCode = ATAPI_TRACE( kATAHandlePowerOn ), kATAPowerOnResetCode = ATAPI_TRACE( kATAPowerOnReset ), kATAPowerOnNoResetCode = ATAPI_TRACE( kATAPowerOnNoReset ), kATAHandlePowerOffCode = ATAPI_TRACE( kATAHandlePowerOff ), kATADriverPowerOffCode = ATAPI_TRACE( kATADriverPowerOff ), }; #define kTraceBufferSampleSize 60000 #define kMicrosecondsPerSecond 1000000 #define kMicrosecondsPerMillisecond 1000 //----------------------------------------------------------------------------- // Globals //----------------------------------------------------------------------------- int gBiasSeconds = 0; double gDivisor = 0.0; /* Trace divisor converts to microseconds */ kd_buf * gTraceBuffer = NULL; boolean_t gTraceEnabled = FALSE; boolean_t gSetRemoveFlag = TRUE; boolean_t gVerbose = FALSE; boolean_t gEnableTraceOnly = FALSE; const char * gProgramName = NULL; uint32_t gPrintfMask = 0; uint32_t gSavedSAMTraceMask = 0; uint32_t gSavedATAPIDebugMask = 0; TAILQ_HEAD(SCSITaskLogEntryHead, SCSITaskLogEntry) gListHead = TAILQ_HEAD_INITIALIZER(gListHead); //----------------------------------------------------------------------------- // Prototypes //----------------------------------------------------------------------------- static void EnableTraceBuffer ( int val ); static void CollectTrace ( void ); static void SignalHandler ( int signal ); static void GetDivisor ( void ); static void RegisterSignalHandlers ( void ); static void AllocateTraceBuffer ( void ); static void RemoveTraceBuffer ( void ); static void SetTraceBufferSize ( int nbufs ); static void Quit ( const char * s ); static void InitializeTraceBuffer ( void ); static void ParseArguments ( int argc, const char * argv[] ); static void PrintUsage ( void ); static void LoadATAPIExtension ( void ); static void ResetDebugFlags ( void ); //----------------------------------------------------------------------------- // Main //----------------------------------------------------------------------------- int main ( int argc, const char * argv[] ) { SAMSysctlArgs samArgs; ATAPISysctlArgs atapiArgs; int error; gProgramName = argv[0]; if ( geteuid ( ) != 0 ) { fprintf ( stderr, "'%s' must be run as root...\n", gProgramName ); exit ( 1 ); } if ( reexec_to_match_kernel ( ) ) { fprintf ( stderr, "Could not re-execute to match kernel architecture. (Error = %d)\n", errno ); exit ( 1 ); } // Get program arguments. ParseArguments ( argc, argv ); bzero ( &samArgs, sizeof ( samArgs ) ); bzero ( &atapiArgs, sizeof ( atapiArgs ) ); samArgs.type = kSAMTypeDebug; samArgs.operation = kSAMOperationGetFlags; samArgs.validBits = kSAMTraceFlagsValidMask; error = sysctlbyname ( SAM_SYSCTL, NULL, NULL, &samArgs, sizeof ( samArgs ) ); if ( error != 0 ) { fprintf ( stderr, "sysctlbyname failed to get old samtrace flags\n" ); } gSavedSAMTraceMask = samArgs.samTraceFlags; atapiArgs.type = kATAPITypeDebug; atapiArgs.operation = kATAPIOperationGetFlags; error = sysctlbyname ( ATAPI_SYSCTL, NULL, NULL, &atapiArgs, sizeof ( atapiArgs ) ); if ( error != 0 ) { LoadATAPIExtension ( ); error = sysctlbyname ( ATAPI_SYSCTL, NULL, NULL, &atapiArgs, sizeof ( atapiArgs ) ); if ( error != 0 ) { fprintf ( stderr, "sysctlbyname failed to get old atapi debug flags second time\n" ); } } gSavedATAPIDebugMask = atapiArgs.debugFlags; samArgs.type = kSAMTypeDebug; samArgs.operation = kSAMOperationSetFlags; samArgs.validBits = kSAMTraceFlagsValidMask; samArgs.samDebugFlags = 0; samArgs.samTraceFlags = gPrintfMask; error = sysctlbyname ( SAM_SYSCTL, NULL, NULL, &samArgs, sizeof ( samArgs ) ); if ( error != 0 ) { fprintf ( stderr, "sysctlbyname failed to set new samtrace flags\n" ); } atapiArgs.type = kATAPITypeDebug; atapiArgs.operation = kATAPIOperationSetFlags; atapiArgs.debugFlags = 1; error = sysctlbyname ( ATAPI_SYSCTL, NULL, NULL, &atapiArgs, sizeof ( atapiArgs ) ); if ( error != 0 ) { fprintf ( stderr, "sysctlbyname failed to set new atapi debug flags\n" ); } #if DEBUG printf ( "gSavedSAMTraceMask = 0x%08X\n", gSavedSAMTraceMask ); printf ( "gSavedATAPIDebugMask = 0x%08X\n", gSavedATAPIDebugMask ); printf ( "gPrintfMask = 0x%08X\n", gPrintfMask ); printf ( "gVerbose = %s\n", gVerbose == TRUE ? "True" : "False" ); fflush ( stdout ); #endif // Set up signal handlers. RegisterSignalHandlers ( ); // Allocate trace buffer. AllocateTraceBuffer ( ); // Remove the trace buffer. RemoveTraceBuffer ( ); // Set the new trace buffer size. SetTraceBufferSize ( kTraceBufferSampleSize ); // Initialize the trace buffer. InitializeTraceBuffer ( ); // Enable the trace buffer. EnableTraceBuffer ( 1 ); // Get the clock divisor. GetDivisor ( ); // Does the user only want the trace points enabled and no logging? if ( gEnableTraceOnly == FALSE ) { printf ( "ATAPILogger v1.0\n" ); // No, they want logging. Start main loop. while ( 1 ) { usleep ( 20 * kMicrosecondsPerMillisecond ); CollectTrace ( ); } } return 0; } //----------------------------------------------------------------------------- // PrintUsage //----------------------------------------------------------------------------- static void PrintUsage ( void ) { printf ( "\n" ); printf ( "Usage: %s [--help] [--enable] [--disable] [--scsitask] [--all] [--verbose]\n", gProgramName ); printf ( "\n" ); exit ( 0 ); } //----------------------------------------------------------------------------- // ParseArguments //----------------------------------------------------------------------------- static void ParseArguments ( int argc, const char * argv[] ) { int c; struct option long_options[] = { { "all", no_argument, 0, 'a' }, { "enable", no_argument, 0, 'e' }, { "disable", no_argument, 0, 'd' }, { "scsitask", no_argument, 0, 's' }, { "verbose", no_argument, 0, 'v' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; // If no args specified, enable firewire sbp2 driver logging only... if ( argc == 1 ) { return; } while ( ( c = getopt_long ( argc, ( char * const * ) argv , "asptlgbrmvh?", long_options, NULL ) ) != -1 ) { switch ( c ) { case 'a': gPrintfMask = ~0; break; case 'e': gEnableTraceOnly = TRUE; break; case 'd': gSavedSAMTraceMask = 0; gSavedATAPIDebugMask = 0; gSetRemoveFlag = FALSE; Quit ( "Quit via user-specified trace disable\n" ); break; case 's': gPrintfMask |= (1 << kSAMClassSCSITask); break; case 'v': gVerbose = TRUE; break; case 'h': PrintUsage ( ); break; default: break; } } } //----------------------------------------------------------------------------- // RegisterSignalHandlers //----------------------------------------------------------------------------- static void RegisterSignalHandlers ( void ) { signal ( SIGINT, SignalHandler ); signal ( SIGQUIT, SignalHandler ); signal ( SIGHUP, SignalHandler ); signal ( SIGTERM, SignalHandler ); } //----------------------------------------------------------------------------- // AllocateTraceBuffer //----------------------------------------------------------------------------- static void AllocateTraceBuffer ( void ) { gTraceBuffer = ( kd_buf * ) malloc ( kTraceBufferSampleSize * sizeof ( kd_buf ) ); if ( gTraceBuffer == NULL ) { Quit ( "Can't allocate memory for tracing info\n" ); } } //----------------------------------------------------------------------------- // SignalHandler //----------------------------------------------------------------------------- static void SignalHandler ( int signal ) { #pragma unused ( signal ) EnableTraceBuffer ( 0 ); RemoveTraceBuffer ( ); ResetDebugFlags ( ); exit ( 0 ); } //----------------------------------------------------------------------------- // EnableTraceBuffer //----------------------------------------------------------------------------- static void EnableTraceBuffer ( int val ) { int mib[6]; size_t needed; mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDENABLE; /* protocol */ mib[3] = val; mib[4] = 0; mib[5] = 0; /* no flags */ if ( sysctl ( mib, 4, NULL, &needed, NULL, 0 ) < 0 ) Quit ( "trace facility failure, KERN_KDENABLE\n" ); if ( val ) gTraceEnabled = TRUE; else gTraceEnabled = FALSE; } //----------------------------------------------------------------------------- // SetTraceBufferSize //----------------------------------------------------------------------------- static void SetTraceBufferSize ( int nbufs ) { int mib[6]; size_t needed; mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDSETBUF; mib[3] = nbufs; mib[4] = 0; mib[5] = 0; /* no flags */ if ( sysctl ( mib, 4, NULL, &needed, NULL, 0 ) < 0 ) Quit ( "trace facility failure, KERN_KDSETBUF\n" ); mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDSETUP; mib[3] = 0; mib[4] = 0; mib[5] = 0; /* no flags */ if ( sysctl ( mib, 3, NULL, &needed, NULL, 0 ) < 0 ) Quit ( "trace facility failure, KERN_KDSETUP\n" ); } //----------------------------------------------------------------------------- // GetTraceBufferInfo //----------------------------------------------------------------------------- static void GetTraceBufferInfo ( kbufinfo_t * val ) { int mib[6]; size_t needed; needed = sizeof ( *val ); mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDGETBUF; mib[3] = 0; mib[4] = 0; mib[5] = 0; /* no flags */ if ( sysctl ( mib, 3, val, &needed, 0, 0 ) < 0 ) Quit ( "trace facility failure, KERN_KDGETBUF\n" ); } //----------------------------------------------------------------------------- // RemoveTraceBuffer //----------------------------------------------------------------------------- static void RemoveTraceBuffer ( void ) { int mib[6]; size_t needed; errno = 0; mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDREMOVE; /* protocol */ mib[3] = 0; mib[4] = 0; mib[5] = 0; /* no flags */ if ( sysctl ( mib, 3, NULL, &needed, NULL, 0 ) < 0 ) { gSetRemoveFlag = FALSE; if ( errno == EBUSY ) Quit ( "The trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n" ); else Quit ( "Trace facility failure, KERN_KDREMOVE\n" ); } } //----------------------------------------------------------------------------- // InitializeTraceBuffer //----------------------------------------------------------------------------- static void InitializeTraceBuffer ( void ) { int mib[6]; size_t needed; kd_regtype kr; kr.type = KDBG_RANGETYPE; kr.value1 = 0; kr.value2 = -1; needed = sizeof ( kd_regtype ); mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDSETREG; mib[3] = 0; mib[4] = 0; mib[5] = 0; /* no flags */ if ( sysctl ( mib, 3, &kr, &needed, NULL, 0 ) < 0 ) Quit ( "trace facility failure, KERN_KDSETREG\n" ); mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDSETUP; mib[3] = 0; mib[4] = 0; mib[5] = 0; /* no flags */ if ( sysctl ( mib, 3, NULL, &needed, NULL, 0 ) < 0 ) Quit ( "trace facility failure, KERN_KDSETUP\n" ); } //----------------------------------------------------------------------------- // CollectTrace //----------------------------------------------------------------------------- static void CollectTrace ( void ) { int mib[6]; int index; int count; size_t needed; kbufinfo_t bufinfo = { 0, 0, 0, 0, 0 }; /* Get kernel buffer information */ GetTraceBufferInfo ( &bufinfo ); needed = bufinfo.nkdbufs * sizeof ( kd_buf ); mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDREADTR; mib[3] = 0; mib[4] = 0; mib[5] = 0; /* no flags */ if ( sysctl ( mib, 3, gTraceBuffer, &needed, NULL, 0 ) < 0 ) Quit ( "trace facility failure, KERN_KDREADTR\n" ); count = needed; if ( bufinfo.flags & KDBG_WRAPPED ) { EnableTraceBuffer ( 0 ); EnableTraceBuffer ( 1 ); } for ( index = 0; index < count; index++ ) { int debugID; int type; uint64_t now; int64_t usecs; int secs; time_t currentTime; debugID = gTraceBuffer[index].debugid; type = debugID & ~(DBG_FUNC_START | DBG_FUNC_END); now = gTraceBuffer[index].timestamp & KDBG_TIMESTAMP_MASK; if ( index == 0 ) { /* * Compute bias seconds after each trace buffer read. * This helps resync timestamps with the system clock * in the event of a system sleep. */ usecs = ( int64_t )( now / gDivisor ); secs = usecs / kMicrosecondsPerSecond; currentTime = time ( NULL ); gBiasSeconds = currentTime - secs; } switch ( type ) { case kSCSITaskTracePointCDBLog1Code: { SCSITaskLogEntry * entry = NULL; // If this isn't asked for, don't do any work. if ( ( gPrintfMask & ( 1 << kSAMClassSCSITask ) ) == 0 ) continue; entry = TAILQ_FIRST ( &gListHead ); while ( entry != NULL ) { if ( entry->taskID == gTraceBuffer[index].arg2 ) { break; } entry = TAILQ_NEXT ( entry, chain ); } if ( entry == NULL ) { entry = ( SCSITaskLogEntry * ) malloc ( sizeof ( SCSITaskLogEntry ) ); TAILQ_INSERT_TAIL ( &gListHead, entry, chain ); } bzero ( entry->cdb, sizeof ( entry->cdb ) ); entry->taskID = gTraceBuffer[index].arg2; entry->cdb[0] = gTraceBuffer[index].arg3 & 0xFF; entry->cdb[1] = ( gTraceBuffer[index].arg3 >> 8 ) & 0xFF; entry->cdb[2] = ( gTraceBuffer[index].arg3 >> 16 ) & 0xFF; entry->cdb[3] = ( gTraceBuffer[index].arg3 >> 24 ) & 0xFF; entry->cdb[4] = gTraceBuffer[index].arg4 & 0xFF; entry->cdb[5] = ( gTraceBuffer[index].arg4 >> 8 ) & 0xFF; entry->cdb[6] = ( gTraceBuffer[index].arg4 >> 16 ) & 0xFF; entry->cdb[7] = ( gTraceBuffer[index].arg4 >> 24 ) & 0xFF; } break; case kSCSITaskTracePointCDBLog2Code: { // If this isn't asked for, don't do any work. if ( ( gPrintfMask & ( 1 << kSAMClassSCSITask ) ) == 0 ) continue; if ( !TAILQ_EMPTY ( &gListHead ) ) { SCSITaskLogEntry * entry = NULL; entry = TAILQ_FIRST ( &gListHead ); while ( entry != NULL ) { if ( entry->taskID == gTraceBuffer[index].arg2 ) { entry->cdb[ 8] = gTraceBuffer[index].arg3 & 0xFF; entry->cdb[ 9] = ( gTraceBuffer[index].arg3 >> 8 ) & 0xFF; entry->cdb[10] = ( gTraceBuffer[index].arg3 >> 16 ) & 0xFF; entry->cdb[11] = ( gTraceBuffer[index].arg3 >> 24 ) & 0xFF; entry->cdb[12] = gTraceBuffer[index].arg4 & 0xFF; entry->cdb[13] = ( gTraceBuffer[index].arg4 >> 8 ) & 0xFF; entry->cdb[14] = ( gTraceBuffer[index].arg4 >> 16 ) & 0xFF; entry->cdb[15] = ( gTraceBuffer[index].arg4 >> 24 ) & 0xFF; printf ( "%-8.8s Request: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", &( ctime ( ¤tTime )[11] ), entry->cdb[ 0], entry->cdb[ 1], entry->cdb[ 2], entry->cdb[ 3], entry->cdb[ 4], entry->cdb[ 5], entry->cdb[ 6], entry->cdb[ 7], entry->cdb[ 8], entry->cdb[ 9], entry->cdb[10], entry->cdb[11], entry->cdb[12], entry->cdb[13], entry->cdb[14], entry->cdb[15] ); } entry = TAILQ_NEXT ( entry, chain ); } } } break; case kSCSITaskTracePointResponseLog1Code: { // If this isn't asked for, don't do any work. if ( ( gPrintfMask & ( 1 << kSAMClassSCSITask ) ) == 0 ) continue; if ( !TAILQ_EMPTY ( &gListHead ) ) { SCSITaskLogEntry * entry = NULL; entry = TAILQ_FIRST ( &gListHead ); while ( entry != NULL ) { if ( entry->taskID == gTraceBuffer[index].arg2 ) { printf ( "%-8.8s Response: serviceResponse = 0x%02X, taskStatus = 0x%02X\n", &( ctime ( ¤tTime )[11] ), ( unsigned int ) gTraceBuffer[index].arg3 & 0xFF, ( unsigned int ) ( gTraceBuffer[index].arg3 >> 8 ) & 0xFF ); break; } entry = TAILQ_NEXT ( entry, chain ); } } } break; case kSCSITaskTracePointResponseLog2Code: { // If this isn't asked for, don't do any work. if ( ( gPrintfMask & ( 1 << kSAMClassSCSITask ) ) == 0 ) continue; fflush ( stdout ); if ( !TAILQ_EMPTY ( &gListHead ) ) { SCSITaskLogEntry * entry = NULL; entry = TAILQ_FIRST ( &gListHead ); while ( entry != NULL ) { if ( entry->taskID == gTraceBuffer[index].arg2 ) { if ( gTraceBuffer[index].arg4 & kSenseDataValidMask ) { printf ( "%-8.8s Response: serviceResponse = %d, taskStatus = %d, senseKey = %d, ASC = 0x%02X, ASCQ = 0x%02X\n", &( ctime ( ¤tTime )[11] ), ( unsigned int ) gTraceBuffer[index].arg3 & 0xFF, ( unsigned int ) ( gTraceBuffer[index].arg3 >> 8 ) & 0xFF, ( unsigned int ) gTraceBuffer[index].arg4 & 0xFF, ( unsigned int ) ( gTraceBuffer[index].arg4 >> 8 ) & 0xFF, ( unsigned int ) ( gTraceBuffer[index].arg4 >> 16 ) & 0xFF ); } else { printf ( "%-8.8s Response: serviceResponse = 0x%02X, taskStatus = 0x%02X\n", &( ctime ( ¤tTime )[11] ), ( unsigned int ) gTraceBuffer[index].arg3 & 0xFF, ( unsigned int ) ( gTraceBuffer[index].arg3 >> 8 ) & 0xFF ); } break; } entry = TAILQ_NEXT ( entry, chain ); } if ( entry != NULL ) { TAILQ_REMOVE ( &gListHead, entry, chain ); free ( entry ); } } } break; case kATADeviceInfoCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI start, obj = 0x%08X, UnitID = 0x%08X, Device Type = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATASendSCSICommandCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Send SCSI Command, obj = 0x%08X, UnitID = 0x%08X, cmd = 0x%08X, SCSITaskIdentifier = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3, ( unsigned int ) gTraceBuffer[index].arg4 ); } break; case kATASendSCSICommandFailedCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Send SCSI Command failed!, obj = 0x%08X, UnitID = 0x%08X, SCSITaskIdentifier = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATACompleteSCSICommandCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Complete SCSI Command, obj = 0x%08X, UnitID = 0x%08X, SCSITaskIdentifier = 0x%08X, serviceResponse = 0x%02X, taskStatus = 0x%02X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3, ( unsigned int ) ( gTraceBuffer[index].arg4 >> 8 ) & 0xFF, ( unsigned int ) gTraceBuffer[index].arg4 & 0xFF ); } break; case kATAAbortCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Abort, obj = 0x%08X, UnitID = 0x%08X, SCSITaskIdentifier = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATAPowerOnResetCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Resetting device at Handle Power On, obj = 0x%08X, UnitID = 0x%08X Device Type = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATAPowerOnNoResetCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Not resetting device at Handle Power On, obj = 0x%08X, UnitID = 0x%08X Device Type = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATAHandlePowerOffCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Handle Power Off, obj = 0x%08X, UnitID = 0x%08X Device Type = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATAResetCompleteCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Reset complete, UnitID = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1 ); } break; case kATAResetCode: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Device Reset, obj = 0x%08X, UnitID = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2 ); } break; case kATADriverPowerOff: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Driver Power Off, obj = 0x%08X, UnitID = 0x%08X, cmd = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATAStartStatusPolling: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Start polling Status Register, obj = 0x%08X, UnitID = 0x%08X, Device Type = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATAStatusPoll: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Polling Status Register, obj = 0x%08X, UnitID = 0x%08X, Device Type = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATAStopStatusPolling: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Stop polling Status Register, obj = 0x%08X, UnitID = 0x%08X, Device Type = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; case kATASendATASleepCmd: { printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) ); printf ( "ATAPI Send ATA Sleep Command, obj = 0x%08X, UnitID = 0x%08X, cmd = Device Type = 0x%08X\n", ( unsigned int ) gTraceBuffer[index].arg1, ( unsigned int ) gTraceBuffer[index].arg2, ( unsigned int ) gTraceBuffer[index].arg3 ); } break; default: { continue; } break; } } fflush ( 0 ); } //----------------------------------------------------------------------------- // LoadATAPIExtension //----------------------------------------------------------------------------- static void LoadATAPIExtension ( void ) { posix_spawn_file_actions_t fileActions; char argv0 [] = "/sbin/kextload"; char argv1 [] = "/System/Library/Extensions/IOATAFamily.kext/Contents/PlugIns/IOATAPIProtocolTransport.kext"; char * const argv[] = { argv0, argv1, NULL }; char * const env[] = { NULL }; pid_t child = 0; union wait status; posix_spawn_file_actions_init ( &fileActions ); posix_spawn_file_actions_addclose ( &fileActions, STDOUT_FILENO ); posix_spawn_file_actions_addclose ( &fileActions, STDERR_FILENO ); posix_spawn ( &child, "/sbin/kextload", &fileActions, NULL, argv, env ); if ( !( ( wait4 ( child, ( int * ) &status, 0, NULL ) == child ) && ( WIFEXITED ( status ) ) ) ) { printf ( "Error loading ATAPI extension\n" ); } posix_spawn_file_actions_destroy ( &fileActions ); } //----------------------------------------------------------------------------- // Quit //----------------------------------------------------------------------------- static void Quit ( const char * s ) { if ( gTraceEnabled == TRUE ) EnableTraceBuffer ( 0 ); if ( gSetRemoveFlag == TRUE ) RemoveTraceBuffer ( ); ResetDebugFlags ( ); fprintf ( stderr, "%s: ", gProgramName ); if ( s != NULL ) { fprintf ( stderr, "%s", s ); } fprintf ( stderr, "\n" ); exit ( 1 ); } //----------------------------------------------------------------------------- // ResetDebugFlags //----------------------------------------------------------------------------- static void ResetDebugFlags ( void ) { SAMSysctlArgs samArgs; ATAPISysctlArgs atapiArgs; int error; samArgs.type = kSAMTypeDebug; samArgs.operation = kSAMOperationSetFlags; samArgs.validBits = kSAMTraceFlagsValidMask; samArgs.samDebugFlags = 0; samArgs.samTraceFlags = gSavedSAMTraceMask; error = sysctlbyname ( SAM_SYSCTL, NULL, NULL, &samArgs, sizeof ( samArgs ) ); atapiArgs.type = kATAPITypeDebug; atapiArgs.operation = kATAPIOperationSetFlags; atapiArgs.debugFlags = gSavedATAPIDebugMask; error = sysctlbyname ( ATAPI_SYSCTL, NULL, NULL, &atapiArgs, sizeof ( atapiArgs ) ); } //----------------------------------------------------------------------------- // GetDivisor //----------------------------------------------------------------------------- static void GetDivisor ( void ) { struct mach_timebase_info mti; mach_timebase_info ( &mti ); gDivisor = ( ( double ) mti.denom / ( double ) mti.numer) * 1000; }