#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/storage/ata/IOATAPIProtocolTransportTimeStamps.h>
#include <IOKit/storage/ata/IOATAPIProtocolTransportDebugging.h>
#define DEBUG 0
typedef struct SCSITaskLogEntry
{
TAILQ_ENTRY(SCSITaskLogEntry) chain;
unsigned int taskID;
uint8_t cdb[16];
} SCSITaskLogEntry;
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
int gBiasSeconds = 0;
double gDivisor = 0.0;
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);
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 );
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 );
}
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
RegisterSignalHandlers ( );
AllocateTraceBuffer ( );
RemoveTraceBuffer ( );
SetTraceBufferSize ( kTraceBufferSampleSize );
InitializeTraceBuffer ( );
EnableTraceBuffer ( 1 );
GetDivisor ( );
if ( gEnableTraceOnly == FALSE )
{
printf ( "ATAPILogger v1.0\n" );
while ( 1 )
{
usleep ( 20 * kMicrosecondsPerMillisecond );
CollectTrace ( );
}
}
return 0;
}
static void
PrintUsage ( void )
{
printf ( "\n" );
printf ( "Usage: %s [--help] [--enable] [--disable] [--scsitask] [--all] [--verbose]\n", gProgramName );
printf ( "\n" );
exit ( 0 );
}
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 ( 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;
}
}
}
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 ( );
ResetDebugFlags ( );
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" );
}
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;
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 )
{
case kSCSITaskTracePointCDBLog1Code:
{
SCSITaskLogEntry * entry = NULL;
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 ( 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 ( 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] ),
gTraceBuffer[index].arg3 & 0xFF, ( gTraceBuffer[index].arg3 >> 8 ) & 0xFF );
break;
}
entry = TAILQ_NEXT ( entry, chain );
}
}
}
break;
case kSCSITaskTracePointResponseLog2Code:
{
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] ),
gTraceBuffer[index].arg3 & 0xFF,
( gTraceBuffer[index].arg3 >> 8 ) & 0xFF,
gTraceBuffer[index].arg4 & 0xFF,
( gTraceBuffer[index].arg4 >> 8 ) & 0xFF,
( gTraceBuffer[index].arg4 >> 16 ) & 0xFF );
}
else
{
printf ( "%-8.8s Response: serviceResponse = 0x%02X, taskStatus = 0x%02X\n",
&( ctime ( ¤tTime )[11] ),
gTraceBuffer[index].arg3 & 0xFF, ( 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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",
gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3, ( gTraceBuffer[index].arg4 >> 8 ) & 0xFF, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
break;
case kATAResetCompleteCode:
{
printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) );
printf ( "ATAPI Reset complete, UnitID = 0x%08X\n", gTraceBuffer[index].arg1 );
}
break;
case kATAResetCode:
{
printf ( "%-8.8s ", &( ctime ( ¤tTime )[11] ) );
printf ( "ATAPI Device Reset, obj = 0x%08X, UnitID = 0x%08X\n", gTraceBuffer[index].arg1, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, 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", gTraceBuffer[index].arg1, gTraceBuffer[index].arg2, gTraceBuffer[index].arg3 );
}
break;
default:
{
continue;
}
break;
}
}
fflush ( 0 );
}
static void
LoadATAPIExtension ( void )
{
posix_spawn_file_actions_t fileActions;
char * const argv[] = { "/sbin/kextload", "/System/Library/Extensions/IOATAFamily.kext/Contents/PlugIns/IOATAPIProtocolTransport.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 ATAPI extension\n" );
}
posix_spawn_file_actions_destroy ( &fileActions );
}
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 );
}
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 ) );
}
static void
GetDivisor ( void )
{
struct mach_timebase_info mti;
mach_timebase_info ( &mti );
gDivisor = ( ( double ) mti.denom / ( double ) mti.numer) * 1000;
}