#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <spawn.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <mach/clock_types.h>
#include <mach/mach_time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/wait.h>
#ifndef KERNEL_PRIVATE
#define KERNEL_PRIVATE
#include <sys/kdebug.h>
#undef KERNEL_PRIVATE
#else
#include <sys/kdebug.h>
#endif
#include <IOKit/scsi/IOSCSIArchitectureModelFamilyTimestamps.h>
#include <IOKit/scsi/IOSCSIArchitectureModelFamilyDebugging.h>
#include <IOKit/usb/IOUSBMassStorageClassTimestamps.h>
#include <IOKit/usb/USB.h>
#define DEBUG 0
enum
{
kAbortedTaskCode = UMC_TRACE ( kAbortedTask ),
kCompleteSCSICommandCode = UMC_TRACE ( kCompleteSCSICommand ),
kNewCommandWhileTerminatingCode = UMC_TRACE ( kNewCommandWhileTerminating ),
kLUNConfigurationCompleteCode = UMC_TRACE ( kLUNConfigurationComplete ),
kIOUMCStorageCharacDictFoundCode = UMC_TRACE ( kIOUMCStorageCharacDictFound ),
kNoProtocolForDeviceCode = UMC_TRACE ( kNoProtocolForDevice ),
kIOUSBMassStorageClassStartCode = UMC_TRACE ( kIOUSBMassStorageClassStart ),
kIOUSBMassStorageClassStopCode = UMC_TRACE ( kIOUSBMassStorageClassStop ),
kAtUSBAddressCode = UMC_TRACE ( kAtUSBAddress ),
kMessagedCalledCode = UMC_TRACE ( kMessagedCalled ),
kWillTerminateCalledCode = UMC_TRACE ( kWillTerminateCalled ),
kDidTerminateCalledCode = UMC_TRACE ( kDidTerminateCalled ),
kCDBLog1Code = UMC_TRACE ( kCDBLog1 ),
kCDBLog2Code = UMC_TRACE ( kCDBLog2 ),
kClearEndPointStallCode = UMC_TRACE ( kClearEndPointStall ),
kGetEndPointStatusCode = UMC_TRACE ( kGetEndPointStatus ),
kHandlePowerOnUSBResetCode = UMC_TRACE ( kHandlePowerOnUSBReset ),
kUSBDeviceResetWhileTerminatingCode = ( UMC_TRACE ( kUSBDeviceResetWhileTerminating ) | DBG_FUNC_START ),
kUSBDeviceResetWhileTerminating_2Code = ( UMC_TRACE ( kUSBDeviceResetWhileTerminating ) | DBG_FUNC_END ),
kUSBDeviceResetAfterDisconnectCode = UMC_TRACE ( kUSBDeviceResetAfterDisconnect ),
kUSBDeviceResetReturnedCode = UMC_TRACE ( kUSBDeviceResetReturned ),
kAbortCurrentSCSITaskCode = UMC_TRACE ( kAbortCurrentSCSITask ),
kCBIProtocolDeviceDetectedCode = UMC_TRACE ( kCBIProtocolDeviceDetected ),
kCBICommandAlreadyInProgressCode = UMC_TRACE ( kCBICommandAlreadyInProgress ),
kCBISendSCSICommandReturnedCode = UMC_TRACE ( kCBISendSCSICommandReturned ),
kBODeviceDetectedCode = UMC_TRACE ( kBODeviceDetected ),
kBOPreferredMaxLUNCode = UMC_TRACE ( kBOPreferredMaxLUN ),
kBOGetMaxLUNReturnedCode = UMC_TRACE ( kBOGetMaxLUNReturned ),
kBOCommandAlreadyInProgressCode = UMC_TRACE ( kBOCommandAlreadyInProgress ),
kBOSendSCSICommandReturnedCode = UMC_TRACE ( kBOSendSCSICommandReturned ),
kBOCBWDescriptionCode = UMC_TRACE ( kBOCBWDescription ),
kBOCBWBulkOutWriteResultCode = UMC_TRACE ( kBOCBWBulkOutWriteResult ),
kBODoubleCompleteionCode = UMC_TRACE ( kBODoubleCompleteion ),
kBOCompletionDuringTerminationCode = UMC_TRACE ( kBOCompletionDuringTermination ),
kBOCompletionCode = UMC_TRACE ( kBOCompletion )
};
static const char * kBulkOnlyStateNames[] = { " ",
"BulkOnlyCommandSent",
"BulkOnlyCheckCBWBulkStall",
"BulkOnlyClearCBWBulkStall",
"BulkOnlyBulkIOComplete",
"BulkOnlyCheckBulkStall",
"BulkOnlyClearBulkStall",
"BulkOnlyCheckBulkStallPostCSW",
"BulkOnlyClearBulkStallPostCSW",
"BulkOnlyStatusReceived",
"BulkOnlyStatusReceived2ndTime",
"BulkOnlyResetCompleted",
"BulkOnlyClearBulkInCompleted",
"BulkOnlyClearBulkOutCompleted" };
#define kTraceBufferSampleSize 60000
#define kMicrosecondsPerSecond 1000000
#define kMicrosecondsPerMillisecond 1000
int gBiasSeconds = 0;
double gDivisor = 0.0;
kd_buf * gTraceBuffer = NULL;
boolean_t gTraceEnabled = FALSE;
boolean_t gSetRemoveFlag = TRUE;
boolean_t gEnableTraceOnly = FALSE;
const char * gProgramName = NULL;
uint32_t gSavedTraceMask = 0;
boolean_t gHideBusyRejectedCommands = FALSE;
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
LoadUSBMassStorageExtension ( void );
static boolean_t
StringFromReturnCode ( unsigned returnCode, char * outString );
static boolean_t
StringFromIOReturn ( unsigned ioreturnCode, char * outString );
static boolean_t
StringFromUSBReturn ( unsigned ioReturnCode, char * outString );
int
main ( int argc, const char * argv[] )
{
USBSysctlArgs args;
int error;
gProgramName = argv[0];
if ( geteuid ( ) != 0 )
{
fprintf ( stderr, "'%s' must be run as root...\n", gProgramName );
exit ( 1 );
}
ParseArguments ( argc, argv );
bzero ( &args, sizeof ( args ) );
args.type = kUSBTypeDebug;
args.operation = kUSBOperationGetFlags;
error = sysctlbyname ( USBMASS_SYSCTL, NULL, NULL, &args, sizeof ( args ) );
if ( error != 0 )
{
fprintf ( stderr, "sysctlbyname failed to get old umctrace flags\n" );
}
args.type = kUSBTypeDebug;
args.operation = kUSBOperationSetFlags;
args.debugFlags = 1;
error = sysctlbyname ( USBMASS_SYSCTL, NULL, NULL, &args, sizeof ( args ) );
if ( error != 0 )
{
LoadUSBMassStorageExtension();
error = sysctlbyname ( USBMASS_SYSCTL, NULL, NULL, &args, sizeof ( args ) );
if ( error != 0 )
{
fprintf ( stderr, "sysctlbyname failed to set new umctrace flags\n" );
}
}
#if DEBUG
printf ( "gSavedTraceMask = 0x%08X\n", gSavedTraceMask );
printf ( "gPrintfMask = 0x%08X\n", gPrintfMask );
printf ( "gVerbose = %s\n", gVerbose == TRUE ? "True" : "False" );
fflush ( stdout );
#endif
RegisterSignalHandlers ( );
AllocateTraceBuffer ( );
RemoveTraceBuffer ( );
SetTraceBufferSize ( kTraceBufferSampleSize );
InitializeTraceBuffer ( );
EnableTraceBuffer ( 1 );
GetDivisor ( );
if ( gEnableTraceOnly == FALSE )
{
while ( 1 )
{
usleep ( 20 * kMicrosecondsPerMillisecond );
CollectTrace ( );
}
}
return 0;
}
static void
PrintUsage ( void )
{
printf ( "\n" );
printf ( "Usage: %s\n\n\t"
"-h help\n\t-r hide rejected SCSI tasks\n\t"
"-d disable\n",
gProgramName );
printf ( "\n" );
exit ( 0 );
}
static void
ParseArguments ( int argc, const char * argv[] )
{
int c;
struct option long_options[] =
{
{ "disable", no_argument, 0, 'd' },
{ "rejected", no_argument, 0, 'r' },
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
if ( argc == 1 )
{
return;
}
while ( ( c = getopt_long ( argc, ( char * const * ) argv , "drh?", long_options, NULL ) ) != -1 )
{
switch ( c )
{
case 'd':
gSavedTraceMask = 0;
gSetRemoveFlag = FALSE;
Quit ( "Quit via user-specified trace disable\n" );
break;
case 'r':
gHideBusyRejectedCommands = TRUE;
break;
case 'h':
PrintUsage ( );
break;
default:
break;
}
}
}
static void
RegisterSignalHandlers ( void )
{
signal ( SIGINT, SignalHandler );
signal ( SIGQUIT, SignalHandler );
signal ( SIGHUP, SignalHandler );
signal ( SIGTERM, SignalHandler );
}
static void
AllocateTraceBuffer ( void )
{
gTraceBuffer = ( kd_buf * ) malloc ( kTraceBufferSampleSize * sizeof ( kd_buf ) );
if ( gTraceBuffer == NULL )
{
Quit ( "Can't allocate memory for tracing info\n" );
}
}
static void
SignalHandler ( int signal )
{
#pragma unused ( signal )
EnableTraceBuffer ( 0 );
RemoveTraceBuffer ( );
exit ( 0 );
}
static void
EnableTraceBuffer ( int val )
{
int mib[6];
size_t needed;
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDENABLE;
mib[3] = val;
mib[4] = 0;
mib[5] = 0;
if ( sysctl ( mib, 4, NULL, &needed, NULL, 0 ) < 0 )
Quit ( "trace facility failure, KERN_KDENABLE\n" );
if ( val )
gTraceEnabled = TRUE;
else
gTraceEnabled = FALSE;
}
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;
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;
if ( sysctl ( mib, 3, NULL, &needed, NULL, 0 ) < 0 )
Quit ( "trace facility failure, KERN_KDSETUP\n" );
}
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;
if ( sysctl ( mib, 3, val, &needed, 0, 0 ) < 0 )
Quit ( "trace facility failure, KERN_KDGETBUF\n" );
}
static void
RemoveTraceBuffer ( void )
{
int mib[6];
size_t needed;
errno = 0;
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDREMOVE;
mib[3] = 0;
mib[4] = 0;
mib[5] = 0;
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" );
}
}
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;
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;
if ( sysctl ( mib, 3, NULL, &needed, NULL, 0 ) < 0 )
Quit ( "trace facility failure, KERN_KDSETUP\n" );
kr.type = KDBG_SUBCLSTYPE;
kr.value1 = DBG_IOKIT;
kr.value2 = DBG_IOSAM;
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;
if ( sysctl ( mib, 3, &kr, &needed, NULL, 0 ) < 0 )
Quit ( "trace facility failure, KERN_KDSETREG (subclstype)\n" );
}
static void
CollectTrace ( void )
{
int mib[6];
int index;
int count;
size_t needed;
kbufinfo_t bufinfo = { 0, 0, 0, 0, 0 };
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;
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;
char errorString_1[64];
debugID = gTraceBuffer[index].debugid;
type = debugID & ~(DBG_FUNC_START | DBG_FUNC_END);
now = gTraceBuffer[index].timestamp & KDBG_TIMESTAMP_MASK;
if ( index == 0 )
{
usecs = ( int64_t )( now / gDivisor );
secs = usecs / kMicrosecondsPerSecond;
currentTime = time ( NULL );
gBiasSeconds = currentTime - secs;
}
switch ( type )
{
#pragma mark -
#pragma mark *** Generic UMC Codes ***
#pragma mark -
case kAbortedTaskCode:
{
printf ( "[%p] Task %p Aborted!!!\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
break;
case kCompleteSCSICommandCode:
{
if ( StringFromReturnCode ( gTraceBuffer[index].arg3, errorString_1 ) )
{
printf ( "[%p] Task %p Completed with status = %s (0x%x)\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, errorString_1, gTraceBuffer[index].arg3 );
}
else
{
printf ( "[%p] Task %p Completed with status = %x\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
printf ( "[%p] -------------------------------------------------\n", gTraceBuffer[index].arg1 );
}
break;
case kLUNConfigurationCompleteCode:
{
printf ( "[%p] MaxLUN = %u\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
break;
case kNewCommandWhileTerminatingCode:
{
printf ( "[%p] Task = %p received while terminating!!!\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
break;
case kIOUMCStorageCharacDictFoundCode:
{
printf ( "[%p] This device has a USB Characteristics Dictionary\n", gTraceBuffer[index].arg1 );
}
break;
case kNoProtocolForDeviceCode:
{
printf ( "[%p] !!! NO USB TRANSPORT PROTOCOL FOR THIS DEVICE !!!\n", gTraceBuffer[index].arg1 );
}
break;
case kIOUSBMassStorageClassStartCode:
{
printf ( "[%p] Starting up!\n", gTraceBuffer[index].arg1 );
}
break;
case kIOUSBMassStorageClassStopCode:
{
printf ( "[%p] Stopping!\n", gTraceBuffer[index].arg1 );
}
break;
case kAtUSBAddressCode:
{
printf ( "[%p] @ USB Address: %u\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
break;
case kMessagedCalledCode:
{
printf ( "[%p] Message : %x recieved\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
break;
case kWillTerminateCalledCode:
{
printf ( "[%p] willTerminate called, CurrentInterface=%p, isInactive=%u\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3);
}
break;
case kDidTerminateCalledCode:
{
printf ( "[%p] didTerminate called, CurrentInterface=%p, isInactive=%u, fResetInProgress=%u\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3, gTraceBuffer[index].arg4);
}
break;
case kCDBLog1Code:
{
UInt8 * cdbData;
unsigned i;
printf ( "[%p] Request %p\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
printf ( "[%p] ", gTraceBuffer[index].arg1 );
cdbData = ( UInt8 * ) &gTraceBuffer[index].arg3;
for ( i = 0; i < 4; i++ ) printf ( "%x : ", cdbData[i] );
cdbData = ( UInt8 * ) &gTraceBuffer[index].arg4;
for ( i = 0; i < 4; i++ ) printf ( "%x : ", cdbData[i] );
}
break;
case kCDBLog2Code:
{
UInt8 * cdbData;
unsigned i;
cdbData = ( UInt8 * ) &gTraceBuffer[index].arg3;
for ( i = 0; i < 4; i++ ) printf ( "%x : ", cdbData[i] );
cdbData = ( UInt8 * ) &gTraceBuffer[index].arg4;
for ( i = 0; i < 3; i++ ) printf ( "%x : ", cdbData[i] );
printf ( "%x\n", cdbData[i] );
}
break;
case kClearEndPointStallCode:
{
if ( StringFromReturnCode ( gTraceBuffer[index].arg2, errorString_1 ) )
{
printf ( "[%p] ClearFeatureEndpointStall status=%s (0x%x), endpoint=%u\n",
gTraceBuffer[index].arg1, errorString_1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
else
{
printf ( "[%p] ClearFeatureEndpointStall status=%x, endpoint=%u\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
}
break;
case kGetEndPointStatusCode:
{
if ( StringFromReturnCode ( gTraceBuffer[index].arg2, errorString_1 ) )
{
printf ( "[%p] ClearFeatureEndpointStall status=%s (%x), endpoint=%u\n",
gTraceBuffer[index].arg1, errorString_1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
else
{
printf ( "[%p] ClearFeatureEndpointStall status=%x, endpoint=%u\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
}
break;
case kHandlePowerOnUSBResetCode:
{
printf ( "[%p] USB Device Reset on WAKE from SLEEP\n", gTraceBuffer[index].arg1 );
}
break;
case kUSBDeviceResetWhileTerminatingCode:
{
printf ( "%p Termination started before device reset could be initiated! fTerminating=%u, isInactive=%u\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
break;
case kUSBDeviceResetWhileTerminating_2Code:
{
printf ( "[%p] Termination occurred while we were reseting the device! fTerminating=%u, isInactive=%u\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
break;
case kUSBDeviceResetAfterDisconnectCode:
{
printf ( "[%p] Device reset was attempted after the device had been disconnected\n", gTraceBuffer[index].arg1 );
}
break;
case kUSBDeviceResetReturnedCode:
{
printf ( "[%p] DeviceReset returned: %u\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
break;
case kAbortCurrentSCSITaskCode:
{
printf ( "[%p] sAbortCurrentSCSITask device attached: %u\n", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
break;
#pragma mark -
#pragma mark *** Control Bulk Interrupt ( CBI ) Codess ***
#pragma mark -
case kCBIProtocolDeviceDetectedCode:
{
printf ( "[%p] CBI transport protocol device\n", gTraceBuffer[index].arg1 );
}
break;
case kCBICommandAlreadyInProgressCode:
{
if ( gHideBusyRejectedCommands == FALSE )
{
printf ( "[%p] CBI - Unable to accept task %p, still working on previous command\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
}
break;
case kCBISendSCSICommandReturnedCode:
{
if ( StringFromReturnCode ( gTraceBuffer[index].arg3, errorString_1 ) )
{
printf ( "[%p] CBI - SCSI Task %p was sent with status %s (0x%x)\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, errorString_1,
gTraceBuffer[index].arg3 );
}
else
{
printf ( "[%p] CBI - SCSI Task %p was sent with status %x\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
}
break;
#pragma mark -
#pragma mark *** Bulk-Only Protocol Codes ***
#pragma mark -
case kBODeviceDetectedCode:
{
printf ( "[%p] BULK-ONLY transport protocol device\n", gTraceBuffer[index].arg1 );
}
break;
case kBOCommandAlreadyInProgressCode:
{
if ( gHideBusyRejectedCommands == FALSE )
{
printf ( "[%p] B0 Unable to accept task %p, still working on previous request\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
}
break;
case kBOSendSCSICommandReturnedCode:
{
if ( StringFromIOReturn ( gTraceBuffer[index].arg3, errorString_1 ) )
{
printf ( "[%p] BO - SCSI Task %p was sent with status %s (0x%x)\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, errorString_1, gTraceBuffer[index].arg3 );
}
else
{
printf ( "[%p] BO - SCSI Task %p was sent with status %x\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
}
break;
case kBOPreferredMaxLUNCode:
{
printf ( "[%p] BO - Preferred MaxLUN: %d\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2 );
}
break;
case kBOGetMaxLUNReturnedCode:
{
if ( StringFromReturnCode ( gTraceBuffer[index].arg2, errorString_1 ) )
{
printf ( "[%p] BO - GetMaxLUN returned: %s (0x%x), triedReset=%u, MaxLun: %d\n",
gTraceBuffer[index].arg1, errorString_1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg4, gTraceBuffer[index].arg3 );
}
else
{
printf ( "[%p] BO - GetMaxLUN returned: %x, triedReset=%u, MaxLun: %d\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg4, gTraceBuffer[index].arg3 );
}
}
break;
case kBOCBWDescriptionCode:
{
printf ( "[%p] BO - Request %p, LUN: %u, CBW Tag: %u (0x%x)\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3, gTraceBuffer[index].arg4, gTraceBuffer[index].arg4 );
}
break;
case kBOCBWBulkOutWriteResultCode:
{
if ( StringFromReturnCode ( gTraceBuffer[index].arg2, errorString_1 ) )
{
printf ( "[%p] BO - Request %p, LUN: %u, Bulk-Out Write Status: %s (0x%x)\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg4, gTraceBuffer[index].arg3, errorString_1, gTraceBuffer[index].arg2 );
}
else
{
printf ( "[%p] BO - Request %p, LUN: %u, Bulk-Out Write Status: %x\n",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg4, gTraceBuffer[index].arg3, gTraceBuffer[index].arg2 );
}
}
break;
case kBODoubleCompleteionCode:
{
printf ( "[%p] BO - DOUBLE Comletion\n", gTraceBuffer[index].arg1 );
printf ( "[%p] BO - DOUBLE Comletion\n", gTraceBuffer[index].arg1 );
}
break;
case kBOCompletionDuringTerminationCode:
{
printf ( "[%p] BO - Completion during termination\n", gTraceBuffer[index].arg1 );
}
break;
case kBOCompletionCode:
{
if ( StringFromReturnCode ( gTraceBuffer[index].arg2, errorString_1 ) )
{
printf ( "[%p] BO - Completion, State: %s, Status: %s (0x%x), for Request: %p\n",
gTraceBuffer[index].arg1, kBulkOnlyStateNames [ gTraceBuffer[index].arg3 ],
errorString_1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg4 );
}
else
{
printf ( "[%p] BO - Completion, State: %s, Status: %x, for Request: %p\n",
gTraceBuffer[index].arg1, kBulkOnlyStateNames [ gTraceBuffer[index].arg3 ],
gTraceBuffer[index].arg2, gTraceBuffer[index].arg4 );
}
}
break;
default:
{
continue;
}
break;
}
}
fflush ( 0 );
}
static void
Quit ( const char * s )
{
USBSysctlArgs args;
int error;
if ( gTraceEnabled == TRUE )
EnableTraceBuffer ( 0 );
if ( gSetRemoveFlag == TRUE )
RemoveTraceBuffer ( );
args.type = kUSBTypeDebug;
args.debugFlags = 0;
error = sysctlbyname ( USBMASS_SYSCTL, NULL, NULL, &args, sizeof ( args ) );
if ( error != 0 )
{
fprintf ( stderr, "sysctlbyname failed to set old UMC trace flags back\n" );
}
fprintf ( stderr, "%s: ", gProgramName );
if ( s != NULL )
{
fprintf ( stderr, "%s", s );
}
exit ( 1 );
}
static void
GetDivisor ( void )
{
struct mach_timebase_info mti;
mach_timebase_info ( &mti );
gDivisor = ( ( double ) mti.denom / ( double ) mti.numer) * 1000;
}
static void
LoadUSBMassStorageExtension ( void )
{
posix_spawn_file_actions_t fileActions;
char * const argv[] = { "/sbin/kextload", "/System/Library/Extensions/IOUSBMassStorageClass.kext", 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 USB Mass Storage extension\n" );
}
posix_spawn_file_actions_destroy ( &fileActions );
}
static boolean_t
StringFromReturnCode ( unsigned returnCode, char * outString )
{
boolean_t returnValue = FALSE;
returnValue = StringFromIOReturn ( returnCode, outString );
if ( returnValue ) goto Exit;
returnValue = StringFromUSBReturn ( returnCode, outString );
if ( returnValue ) goto Exit;
Exit:
return returnValue;
}
static boolean_t
StringFromIOReturn ( unsigned ioReturnCode, char * outString )
{
boolean_t returnValue = FALSE;
switch ( ioReturnCode )
{
case kIOReturnSuccess:
{
strncpy ( outString, "kIOReturnSuccess", sizeof ( "kIOReturnSuccess" ) );
}
break;
case kIOReturnError:
{
strncpy ( outString, "kIOReturnError", sizeof ( "kIOReturnError" ) );
}
break;
case kIOReturnNoMemory:
{
strncpy ( outString, "kIOReturnNoMemory", sizeof ( "kIOReturnNoMemory" ) );
}
break;
case kIOReturnNoResources:
{
strncpy ( outString, "kIOReturnNoResources", sizeof ( "kIOReturnNoResources" ) );
}
break;
case kIOReturnIPCError:
{
strncpy ( outString, "kIOReturnIPCError", sizeof ( "kIOReturnIPCError" ) );
}
break;
case kIOReturnNoDevice:
{
strncpy ( outString, "kIOReturnNoDevice", sizeof ( "kIOReturnNoDevice" ) );
}
break;
case kIOReturnNotPrivileged:
{
strncpy ( outString, "kIOReturnNotPrivileged", sizeof ( "kIOReturnNotPrivileged" ) );
}
break;
case kIOReturnBadArgument:
{
strncpy ( outString, "kIOReturnBadArgument", sizeof ( "kIOReturnBadArgument" ) );
}
break;
case kIOReturnLockedRead:
{
strncpy ( outString, "kIOReturnLockedRead", sizeof ( "kIOReturnLockedRead" ) );
}
break;
case kIOReturnLockedWrite:
{
strncpy ( outString, "kIOReturnLockedWrite", sizeof ( "kIOReturnLockedWrite" ) );
}
break;
case kIOReturnExclusiveAccess:
{
strncpy ( outString, "kIOReturnExclusiveAccess", sizeof ( "kIOReturnExclusiveAccess" ) );
}
break;
case kIOReturnBadMessageID:
{
strncpy ( outString, "kIOReturnExclusiveAccess", sizeof ( "kIOReturnExclusiveAccess" ) );
}
break;
case kIOReturnUnsupported:
{
strncpy ( outString, "kIOReturnUnsupported", sizeof ( "kIOReturnUnsupported" ) );
}
break;
case kIOReturnVMError:
{
strncpy ( outString, "kIOReturnVMError", sizeof ( "kIOReturnVMError" ) );\
}
break;
case kIOReturnInternalError:
{
strncpy ( outString, "kIOReturnInternalError", sizeof ( "kIOReturnInternalError" ) );
}
break;
case kIOReturnIOError:
{
strncpy ( outString, "kIOReturnIOError", sizeof ( "kIOReturnIOError" ) );
}
break;
case kIOReturnCannotLock:
{
strncpy ( outString, "kIOReturnCannotLock", sizeof ( "kIOReturnCannotLock" ) );
}
break;
case kIOReturnNotOpen:
{
strncpy ( outString, "kIOReturnNotOpen", sizeof ( "kIOReturnNotOpen" ) );
}
break;
case kIOReturnNotReadable:
{
strncpy ( outString, "kIOReturnNotReadable", sizeof ( "kIOReturnNotReadable" ) );
}
break;
case kIOReturnNotWritable:
{
strncpy ( outString, "kIOReturnNotWritable", sizeof ( "kIOReturnNotWritable" ) );
}
break;
case kIOReturnNotAligned:
{
strncpy ( outString, "kIOReturnNotAligned", sizeof ( "kIOReturnNotAligned" ) );
}
break;
case kIOReturnBadMedia:
{
strncpy ( outString, "kIOReturnBadMedia", sizeof ( "kIOReturnBadMedia" ) );
}
break;
case kIOReturnStillOpen:
{
strncpy ( outString, "kIOReturnStillOpen", sizeof ( "kIOReturnStillOpen" ) );
}
break;
case kIOReturnRLDError:
{
strncpy ( outString, "kIOReturnRLDError", sizeof ( "kIOReturnRLDError" ) );
}
break;
case kIOReturnDMAError:
{
strncpy ( outString, "kIOReturnDMAError", sizeof ( "kIOReturnDMAError" ) );
}
break;
case kIOReturnBusy:
{
strncpy ( outString, "kIOReturnBusy", sizeof ( "kIOReturnBusy" ) );
}
break;
case kIOReturnTimeout:
{
strncpy ( outString, "kIOReturnBusy", sizeof ( "kIOReturnBusy" ) );
}
break;
case kIOReturnOffline:
{
strncpy ( outString, "kIOReturnOffline", sizeof ( "kIOReturnOffline" ) );
}
break;
case kIOReturnNotReady:
{
strncpy ( outString, "kIOReturnNotReady", sizeof ( "kIOReturnNotReady" ) );
}
break;
case kIOReturnNotAttached:
{
strncpy ( outString, "kIOReturnNotAttached", sizeof ( "kIOReturnNotAttached" ) );
}
break;
case kIOReturnNoChannels:
{
strncpy ( outString, "kIOReturnNoChannels", sizeof ( "kIOReturnNoChannels" ) );
}
break;
case kIOReturnNoSpace:
{
strncpy ( outString, "kIOReturnNoSpace", sizeof ( "kIOReturnNoSpace" ) );
}
break;
case kIOReturnPortExists:
{
strncpy ( outString, "kIOReturnPortExists", sizeof ( "kIOReturnPortExists" ) );
}
break;
case kIOReturnCannotWire:
{
strncpy ( outString, "kIOReturnCannotWire", sizeof ( "kIOReturnCannotWire" ) );
}
break;
case kIOReturnNoInterrupt:
{
strncpy ( outString, "kIOReturnNoInterrupt", sizeof ( "kIOReturnNoInterrupt" ) );
}
break;
case kIOReturnNoFrames:
{
strncpy ( outString, "kIOReturnNoFrames", sizeof ( "kIOReturnNoFrames" ) );
}
break;
case kIOReturnMessageTooLarge:
{
strncpy ( outString, "kIOReturnMessageTooLarge", sizeof ( "kIOReturnMessageTooLarge" ) );
}
break;
case kIOReturnNotPermitted:
{
strncpy ( outString, "kIOReturnNotPermitted", sizeof ( "kIOReturnNotPermitted" ) );
}
break;
case kIOReturnNoPower:
{
strncpy ( outString, "kIOReturnNoPower", sizeof ( "kIOReturnNoPower" ) );
}
break;
case kIOReturnNoMedia:
{
strncpy ( outString, "kIOReturnNoMedia", sizeof ( "kIOReturnNoMedia" ) );
}
break;
case kIOReturnUnformattedMedia:
{
strncpy ( outString, "kIOReturnUnformattedMedia", sizeof ( "kIOReturnUnformattedMedia" ) );
}
break;
case kIOReturnUnsupportedMode:
{
strncpy ( outString, "kIOReturnUnsupportedMode", sizeof ( "kIOReturnUnsupportedMode" ) );
}
break;
case kIOReturnUnderrun:
{
strncpy ( outString, "kIOReturnUnderrun", sizeof ( "kIOReturnUnderrun" ) );
}
break;
case kIOReturnOverrun:
{
strncpy ( outString, "kIOReturnOverrun", sizeof ( "kIOReturnOverrun" ) );
}
break;
case kIOReturnDeviceError:
{
strncpy ( outString, "kIOReturnDeviceError", sizeof ( "kIOReturnDeviceError" ) );
}
break;
case kIOReturnAborted:
{
strncpy ( outString, "kIOReturnAborted", sizeof ( "kIOReturnAborted" ) );
}
break;
case kIOReturnNoBandwidth:
{
strncpy ( outString, "kIOReturnNoBandwidth", sizeof ( "kIOReturnNoBandwidth" ) );
}
break;
case kIOReturnNotResponding:
{
strncpy ( outString, "kIOReturnNoBandwidth", sizeof ( "kIOReturnNoBandwidth" ) );
}
break;
case kIOReturnIsoTooOld:
{
strncpy ( outString, "kIOReturnIsoTooOld", sizeof ( "kIOReturnIsoTooOld" ) );
}
break;
case kIOReturnIsoTooNew:
{
strncpy ( outString, "kIOReturnIsoTooNew", sizeof ( "kIOReturnIsoTooNew" ) );
}
break;
case kIOReturnNotFound:
{
strncpy ( outString, "kIOReturnNotFound", sizeof ( "kIOReturnNotFound" ) );
}
break;
case kIOReturnInvalid:
{
strncpy ( outString, "kIOReturnInvalid", sizeof ( "kIOReturnInvalid" ) );
}
break;
default:
{
strncpy ( outString, "NO STRING", sizeof ( "NO STRING" ) );
}
break;
}
returnValue = TRUE;
ErrorExit:
return returnValue;
}
static boolean_t
StringFromUSBReturn ( unsigned ioReturnCode, char * outString )
{
boolean_t returnValue = FALSE;
switch ( ioReturnCode )
{
case kIOUSBUnknownPipeErr:
{
strncpy ( outString, "kIOUSBUnknownPipeErr", sizeof ( "kIOUSBUnknownPipeErr" ) );
}
break;
case kIOUSBTooManyPipesErr:
{
strncpy ( outString, "kIOUSBTooManyPipesErr", sizeof ( "kIOUSBTooManyPipesErr" ) );
}
break;
case kIOUSBNoAsyncPortErr:
{
strncpy ( outString, "kIOUSBNoAsyncPortErr", sizeof ( "kIOUSBNoAsyncPortErr" ) );
}
break;
case kIOUSBNotEnoughPipesErr:
{
strncpy ( outString, "kIOUSBNotEnoughPipesErr", sizeof ( "kIOUSBNotEnoughPipesErr" ) );
}
break;
case kIOUSBNotEnoughPowerErr:
{
strncpy ( outString, "kIOUSBNotEnoughPowerErr", sizeof ( "kIOUSBNotEnoughPowerErr" ) );
}
break;
case kIOUSBEndpointNotFound:
{
strncpy ( outString, "kIOUSBEndpointNotFound", sizeof ( "kIOUSBEndpointNotFound" ) );
}
break;
case kIOUSBConfigNotFound:
{
strncpy ( outString, "kIOUSBConfigNotFound", sizeof ( "kIOUSBConfigNotFound" ) );
}
break;
case kIOUSBTransactionTimeout:
{
strncpy ( outString, "kIOUSBTransactionTimeout", sizeof ( "kIOUSBTransactionTimeout" ) );
}
break;
case kIOUSBTransactionReturned:
{
strncpy ( outString, "kIOUSBTransactionReturned", sizeof ( "kIOUSBTransactionReturned" ) );
}
break;
case kIOUSBPipeStalled:
{
strncpy ( outString, "kIOUSBPipeStalled", sizeof ( "kIOUSBPipeStalled" ) );
}
break;
case kIOUSBInterfaceNotFound:
{
strncpy ( outString, "kIOUSBInterfaceNotFound", sizeof ( "kIOUSBInterfaceNotFound" ) );
}
break;
case kIOUSBLowLatencyBufferNotPreviouslyAllocated:
{
strncpy ( outString, "kIOUSBLowLatencyBufferNotPreviouslyAllocated", sizeof ( "kIOUSBLowLatencyBufferNotPreviouslyAllocated" ) );
}
break;
case kIOUSBLowLatencyFrameListNotPreviouslyAllocated:
{
strncpy ( outString, "kIOUSBLowLatencyFrameListNotPreviouslyAllocated", sizeof ( "kIOUSBLowLatencyFrameListNotPreviouslyAllocated" ) );
}
break;
case kIOUSBHighSpeedSplitError:
{
strncpy ( outString, "kIOUSBHighSpeedSplitError", sizeof ( "kIOUSBHighSpeedSplitError" ) );
}
break;
case kIOUSBSyncRequestOnWLThread:
{
strncpy ( outString, "kIOUSBSyncRequestOnWLThread", sizeof ( "kIOUSBSyncRequestOnWLThread" ) );
}
break;
case kIOUSBDeviceNotHighSpeed:
{
strncpy ( outString, "kIOUSBDeviceNotHighSpeed", sizeof ( "kIOUSBDeviceNotHighSpeed" ) );
}
break;
case kIOUSBLinkErr:
{
strncpy ( outString, "kIOUSBLinkErr", sizeof ( "kIOUSBLinkErr" ) );
}
break;
case kIOUSBNotSent2Err:
{
strncpy ( outString, "kIOUSBNotSent2Err", sizeof ( "kIOUSBNotSent2Err" ) );
}
break;
case kIOUSBNotSent1Err:
{
strncpy ( outString, "kIOUSBNotSent1Err", sizeof ( "kIOUSBNotSent1Err" ) );
}
break;
case kIOUSBBufferUnderrunErr:
{
strncpy ( outString, "kIOUSBBufferUnderrunErr", sizeof ( "kIOUSBBufferUnderrunErr" ) );
}
break;
case kIOUSBBufferOverrunErr:
{
strncpy ( outString, "kIOUSBBufferOverrunErr", sizeof ( "kIOUSBBufferOverrunErr" ) );
}
break;
case kIOUSBReserved2Err:
{
strncpy ( outString, "kIOUSBReserved2Err", sizeof ( "kIOUSBReserved2Err" ) );
}
break;
case kIOUSBReserved1Err:
{
strncpy ( outString, "kIOUSBReserved1Err", sizeof ( "kIOUSBReserved1Err" ) );
}
break;
case kIOUSBWrongPIDErr:
{
strncpy ( outString, "kIOUSBWrongPIDErr", sizeof ( "kIOUSBWrongPIDErr" ) );
}
break;
case kIOUSBPIDCheckErr:
{
strncpy ( outString, "kIOUSBPIDCheckErr", sizeof ( "kIOUSBPIDCheckErr" ) );
}
break;
case kIOUSBDataToggleErr:
{
strncpy ( outString, "kIOUSBDataToggleErr", sizeof ( "kIOUSBDataToggleErr" ) );
}
break;
case kIOUSBBitstufErr:
{
strncpy ( outString, "kIOUSBBitstufErr", sizeof ( "kIOUSBBitstufErr" ) );
}
break;
case kIOUSBCRCErr:
{
strncpy ( outString, "kIOUSBCRCErr", sizeof ( "kIOUSBCRCErr" ) );
}
break;
default:
{
strncpy ( outString, "NO STRING", sizeof ( "NO STRING" ) );
}
break;
}
returnValue = TRUE;
ErrorExit:
return returnValue;
}