2020-08-29 03:06:22 +00:00
/*++
Copyright ( C ) Microsoft Corporation , 1991 - 2010
Module Name :
debug . c
Abstract :
CLASSPNP debug code and data
Environment :
kernel mode only
Notes :
Revision History :
- - */
# include "classp.h"
# include "debug.h"
# ifdef DEBUG_USE_WPP
# include "debug.tmh"
# endif
# if DBG
//
// default to not breaking in for lost irps, five minutes before we even
// bother checking for lost irps, using standard debug print macros, and
// using a 64k debug print buffer
//
# ifndef CLASS_GLOBAL_BREAK_ON_LOST_IRPS
# error "CLASS_GLOBAL_BREAK_ON_LOST_IRPS undefined"
# define CLASS_GLOBAL_BREAK_ON_LOST_IRPS 0
# endif // CLASS_GLOBAL_BREAK_ON_LOST_IRPS
# ifndef CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB
# error "CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB undefined"
# define CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB 300
# endif // CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB
# ifndef CLASS_GLOBAL_BUFFERED_DEBUG_PRINT
# error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT undefined"
# define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT 0
# endif // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT
# ifndef CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE
# error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE undefined"
# define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE 512
# endif // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE
# ifndef CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS
# error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS undefined"
# define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS 512
# endif // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS
# ifdef _MSC_VER
# pragma data_seg("NONPAGE")
# endif
CLASSPNP_GLOBALS ClasspnpGlobals ;
//
// the low sixteen bits are used to see if the debug level is high enough
// the high sixteen bits are used to singly enable debug levels 1-16
//
LONG ClassDebug = 0x00000000 ;
BOOLEAN DebugTrapOnWarn = FALSE ;
//
// Used to track callers when we receive an access and the disk
// is powered down.
//
ULONG DiskSpinupIndex = 0 ;
DISK_SPINUP_TRACES DiskSpinupTraces [ NUMBER_OF_DISK_SPINUP_TRACES ] ;
VOID ClasspInitializeDebugGlobals ( )
{
KIRQL irql ;
if ( InterlockedCompareExchange ( & ClasspnpGlobals . Initializing , 1 , 0 ) = = 0 ) {
KeInitializeSpinLock ( & ClasspnpGlobals . SpinLock ) ;
KeAcquireSpinLock ( & ClasspnpGlobals . SpinLock , & irql ) ;
TracePrint ( ( TRACE_LEVEL_INFORMATION , TRACE_FLAG_INIT , " CLASSPNP.SYS => Initializing ClasspnpGlobals... \n " ) ) ;
ClasspnpGlobals . Buffer = NULL ;
ClasspnpGlobals . Index = ( ULONG ) - 1 ;
ClasspnpGlobals . BreakOnLostIrps = CLASS_GLOBAL_BREAK_ON_LOST_IRPS ;
ClasspnpGlobals . EachBufferSize = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE ;
ClasspnpGlobals . NumberOfBuffers = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS ;
ClasspnpGlobals . SecondsToWaitForIrps = CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB ;
//
// this should be the last item set
//
ClasspnpGlobals . UseBufferedDebugPrint = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT ;
KeReleaseSpinLock ( & ClasspnpGlobals . SpinLock , irql ) ;
InterlockedExchange ( & ClasspnpGlobals . Initialized , 1 ) ;
}
}
/*++////////////////////////////////////////////////////////////////////////////
ClassDebugPrint ( )
Routine Description :
Debug print for all class drivers , NOOP on FRE versions .
Allows printing to a debug buffer ( with auto fallback to kdprint ) by
properly setting the Globals in classpnp on CHK versions .
Arguments :
Debug print level , or from 0 to 3 for legacy drivers .
Return Value :
None
- - */
VOID ClassDebugPrint ( _In_ CLASS_DEBUG_LEVEL DebugPrintLevel , _In_z_ PCCHAR DebugMessage , . . . )
{
va_list ap ;
va_start ( ap , DebugMessage ) ;
if ( ( DebugPrintLevel < = ( ClassDebug & 0x0000ffff ) ) | |
( ( 1 < < ( DebugPrintLevel + 15 ) ) & ClassDebug ) ) {
if ( ClasspnpGlobals . UseBufferedDebugPrint & &
ClasspnpGlobals . Buffer = = NULL ) {
//
// this double-check prevents always taking
// a spinlock just to ensure we have a buffer
//
KIRQL irql ;
KeAcquireSpinLock ( & ClasspnpGlobals . SpinLock , & irql ) ;
if ( ClasspnpGlobals . Buffer = = NULL ) {
SIZE_T bufferSize ;
if ( NT_SUCCESS (
RtlSIZETMult ( ClasspnpGlobals . NumberOfBuffers ,
ClasspnpGlobals . EachBufferSize ,
& bufferSize ) ) ) {
DbgPrintEx ( DPFLTR_CLASSPNP_ID , DPFLTR_ERROR_LEVEL ,
" ClassDebugPrint: Allocating %x bytes for "
" classdebugprint buffer \n " , ( ULONG ) bufferSize ) ;
ClasspnpGlobals . Index = ( ULONG ) - 1 ;
ClasspnpGlobals . Buffer =
ExAllocatePoolWithTag ( NonPagedPoolNx , bufferSize , ' bDcS ' ) ;
DbgPrintEx ( DPFLTR_CLASSPNP_ID , DPFLTR_ERROR_LEVEL ,
" ClassDebugPrint: Allocated buffer at %p \n " ,
ClasspnpGlobals . Buffer ) ;
if ( ClasspnpGlobals . Buffer ) {
RtlZeroMemory ( ClasspnpGlobals . Buffer , bufferSize ) ;
}
}
}
KeReleaseSpinLock ( & ClasspnpGlobals . SpinLock , irql ) ;
}
if ( ClasspnpGlobals . UseBufferedDebugPrint & &
ClasspnpGlobals . Buffer ! = NULL ) {
//
// we never free the buffer, so once it exists,
// we can just print to it with immunity
//
ULONG index ;
PUCHAR buffer ;
NTSTATUS status ;
index = InterlockedIncrement ( ( volatile LONG * ) & ClasspnpGlobals . Index ) ;
index % = ClasspnpGlobals . NumberOfBuffers ;
index * = ( ULONG ) ClasspnpGlobals . EachBufferSize ;
buffer = ClasspnpGlobals . Buffer ;
buffer + = index ;
RtlZeroMemory ( buffer , ClasspnpGlobals . EachBufferSize ) ;
status = RtlStringCchVPrintfA ( ( NTSTRSAFE_PSTR ) buffer , ClasspnpGlobals . EachBufferSize , DebugMessage , ap ) ;
if ( ! NT_SUCCESS ( status ) )
{
* buffer = 0 ; // force-null on failure
}
} else {
//
// either we could not allocate a buffer for debug prints
// or buffered debug prints are disabled
//
vDbgPrintEx ( DPFLTR_CLASSPNP_ID , DPFLTR_INFO_LEVEL , DebugMessage , ap ) ;
}
}
va_end ( ap ) ;
}
/*
* DbgCheckReturnedPkt
*
* Check a completed TRANSFER_PACKET for all sorts of error conditions
* and warn / trap appropriately .
*/
VOID DbgCheckReturnedPkt ( TRANSFER_PACKET * Pkt )
{
PCDB pCdb = ClasspTransferPacketGetCdb ( Pkt ) ;
NT_ASSERT ( SrbGetOriginalRequest ( Pkt - > Srb ) = = Pkt - > Irp ) ;
NT_ASSERT ( SrbGetDataBuffer ( Pkt - > Srb ) = = Pkt - > BufPtrCopy ) ;
NT_ASSERT ( SrbGetDataTransferLength ( Pkt - > Srb ) < = Pkt - > BufLenCopy ) ;
NT_ASSERT ( ! Pkt - > Irp - > CancelRoutine ) ;
if ( SRB_STATUS ( Pkt - > Srb - > SrbStatus ) = = SRB_STATUS_PENDING ) {
TracePrint ( ( TRACE_LEVEL_ERROR , TRACE_FLAG_RW , " SRB completed with status PENDING in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh) " ,
Pkt ,
DBGGETSCSIOPSTR ( Pkt - > Srb ) ,
DBGGETSRBSTATUSSTR ( Pkt - > Srb ) ,
( ULONG ) Pkt - > Srb - > SrbStatus ,
Pkt - > Irp - > IoStatus . Status ) ) ;
}
else if ( SRB_STATUS ( Pkt - > Srb - > SrbStatus ) = = SRB_STATUS_SUCCESS ) {
/*
* Make sure SRB and IRP status match .
*/
if ( ! NT_SUCCESS ( Pkt - > Irp - > IoStatus . Status ) ) {
TracePrint ( ( TRACE_LEVEL_WARNING , TRACE_FLAG_RW , " SRB and IRP status don't match in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh) " ,
Pkt ,
DBGGETSCSIOPSTR ( Pkt - > Srb ) ,
DBGGETSRBSTATUSSTR ( Pkt - > Srb ) ,
( ULONG ) Pkt - > Srb - > SrbStatus ,
Pkt - > Irp - > IoStatus . Status ) ) ;
}
if ( Pkt - > Irp - > IoStatus . Information ! = SrbGetDataTransferLength ( Pkt - > Srb ) ) {
TracePrint ( ( TRACE_LEVEL_ERROR , TRACE_FLAG_RW , " SRB and IRP result transfer lengths don't match in succeeded packet %ph: (op=%s, SrbStatus=%s, Srb.DataTransferLength=%xh, Irp->IoStatus.Information=%Ixh). " ,
Pkt ,
DBGGETSCSIOPSTR ( Pkt - > Srb ) ,
DBGGETSRBSTATUSSTR ( Pkt - > Srb ) ,
SrbGetDataTransferLength ( Pkt - > Srb ) ,
Pkt - > Irp - > IoStatus . Information ) ) ;
}
}
else {
if ( NT_SUCCESS ( Pkt - > Irp - > IoStatus . Status ) ) {
TracePrint ( ( TRACE_LEVEL_WARNING , TRACE_FLAG_RW , " SRB and IRP status don't match in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh) " ,
Pkt ,
DBGGETSCSIOPSTR ( Pkt - > Srb ) ,
DBGGETSRBSTATUSSTR ( Pkt - > Srb ) ,
( ULONG ) Pkt - > Srb - > SrbStatus ,
Pkt - > Irp - > IoStatus . Status ) ) ;
}
TracePrint ( ( TRACE_LEVEL_WARNING , TRACE_FLAG_RW , " Packet %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s) " ,
Pkt ,
DBGGETSCSIOPSTR ( Pkt - > Srb ) ,
DBGGETSRBSTATUSSTR ( Pkt - > Srb ) ,
( ULONG ) Pkt - > Srb - > SrbStatus ,
Pkt - > Irp - > IoStatus . Status ,
DBGGETSENSECODESTR ( Pkt - > Srb ) ,
DBGGETADSENSECODESTR ( Pkt - > Srb ) ,
DBGGETADSENSEQUALIFIERSTR ( Pkt - > Srb ) ) ) ;
/*
* If the SRB failed with underrun or overrun , then the actual
* transferred length should be returned in both SRB and IRP .
* ( SRB ' s only have an error status for overrun , so it ' s overloaded ) .
*/
if ( ( SRB_STATUS ( Pkt - > Srb - > SrbStatus ) = = SRB_STATUS_DATA_OVERRUN ) & &
( Pkt - > Irp - > IoStatus . Information ! = SrbGetDataTransferLength ( Pkt - > Srb ) ) ) {
TracePrint ( ( TRACE_LEVEL_ERROR , TRACE_FLAG_RW , " SRB and IRP result transfer lengths don't match in failed packet %ph: (op=%s, SrbStatus=%s, Srb.DataTransferLength=%xh, Irp->IoStatus.Information=%Ixh). " ,
Pkt ,
DBGGETSCSIOPSTR ( Pkt - > Srb ) ,
DBGGETSRBSTATUSSTR ( Pkt - > Srb ) ,
SrbGetDataTransferLength ( Pkt - > Srb ) ,
Pkt - > Irp - > IoStatus . Information ) ) ;
}
}
/*
* If the port driver returned STATUS_INSUFFICIENT_RESOURCES ,
* make sure this is also the InternalStatus in the SRB so that we process it correctly .
*/
if ( Pkt - > Irp - > IoStatus . Status = = STATUS_INSUFFICIENT_RESOURCES ) {
NT_ASSERT ( SRB_STATUS ( Pkt - > Srb - > SrbStatus ) = = SRB_STATUS_INTERNAL_ERROR ) ;
NT_ASSERT ( SrbGetSystemStatus ( Pkt - > Srb ) = = STATUS_INSUFFICIENT_RESOURCES ) ;
}
/*
* Some miniport drivers have been caught changing the SCSI operation
* code in the SRB . This is absolutely disallowed as it breaks our error handling .
*/
switch ( pCdb - > CDB10 . OperationCode ) {
case SCSIOP_MEDIUM_REMOVAL :
case SCSIOP_MODE_SENSE :
case SCSIOP_READ_CAPACITY :
case SCSIOP_READ :
case SCSIOP_WRITE :
case SCSIOP_START_STOP_UNIT :
case SCSIOP_READ_CAPACITY16 :
case SCSIOP_READ16 :
case SCSIOP_WRITE16 :
break ;
default :
TracePrint ( ( TRACE_LEVEL_ERROR , TRACE_FLAG_RW , " Miniport illegally changed Srb.Cdb.OperationCode in packet %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s) " ,
Pkt ,
DBGGETSCSIOPSTR ( Pkt - > Srb ) ,
DBGGETSRBSTATUSSTR ( Pkt - > Srb ) ,
( ULONG ) Pkt - > Srb - > SrbStatus ,
Pkt - > Irp - > IoStatus . Status ,
DBGGETSENSECODESTR ( Pkt - > Srb ) ,
DBGGETADSENSECODESTR ( Pkt - > Srb ) ,
DBGGETADSENSEQUALIFIERSTR ( Pkt - > Srb ) ) ) ;
break ;
}
}
VOID DbgLogSendPacket ( TRANSFER_PACKET * Pkt )
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt - > Fdo - > DeviceExtension ;
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt - > PrivateFdoData ;
KIRQL oldIrql ;
if ( Pkt - > OriginalIrp ) {
Pkt - > DbgOriginalIrpCopy = * Pkt - > OriginalIrp ;
if ( Pkt - > OriginalIrp - > MdlAddress ) {
Pkt - > DbgMdlCopy = * Pkt - > OriginalIrp - > MdlAddress ;
}
}
KeQueryTickCount ( & Pkt - > DbgTimeSent ) ;
Pkt - > DbgTimeReturned . QuadPart = 0L ;
KeAcquireSpinLock ( & fdoData - > SpinLock , & oldIrql ) ;
fdoData - > DbgPacketLogs [ fdoData - > DbgPacketLogNextIndex ] = * Pkt ;
fdoData - > DbgPacketLogNextIndex + + ;
fdoData - > DbgPacketLogNextIndex % = DBG_NUM_PACKET_LOG_ENTRIES ;
KeReleaseSpinLock ( & fdoData - > SpinLock , oldIrql ) ;
}
VOID DbgLogReturnPacket ( TRANSFER_PACKET * Pkt )
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt - > Fdo - > DeviceExtension ;
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt - > PrivateFdoData ;
KIRQL oldIrql ;
KeQueryTickCount ( & Pkt - > DbgTimeReturned ) ;
#if 0
// ISSUE: there are some problems with this check (e.g. multiproc), so don't include it yet
if ( Pkt - > OriginalIrp ) {
/*
* No one should have touched the original irp while the packet was outstanding ,
* except for a couple fields that we ourselves update during the transfer
* or that are allowed to change ;
* make those couple fields the same and then to a bytewise compare
*/
ULONG lenSame ;
Pkt - > DbgOriginalIrpCopy . IoStatus . Status = Pkt - > OriginalIrp - > IoStatus . Status ;
Pkt - > DbgOriginalIrpCopy . IoStatus . Information = Pkt - > OriginalIrp - > IoStatus . Information ;
Pkt - > DbgOriginalIrpCopy . Tail . Overlay . DriverContext [ 0 ] = Pkt - > OriginalIrp - > Tail . Overlay . DriverContext [ 0 ] ;
Pkt - > DbgOriginalIrpCopy . ThreadListEntry = Pkt - > OriginalIrp - > ThreadListEntry ;
Pkt - > DbgOriginalIrpCopy . Cancel = Pkt - > OriginalIrp - > Cancel ;
lenSame = ( ULONG ) RtlCompareMemory ( Pkt - > OriginalIrp , & Pkt - > DbgOriginalIrpCopy , sizeof ( IRP ) ) ;
NT_ASSERT ( lenSame = = sizeof ( IRP ) ) ;
}
# endif
KeAcquireSpinLock ( & fdoData - > SpinLock , & oldIrql ) ;
fdoData - > DbgPacketLogs [ fdoData - > DbgPacketLogNextIndex ] = * Pkt ;
fdoData - > DbgPacketLogNextIndex + + ;
fdoData - > DbgPacketLogNextIndex % = DBG_NUM_PACKET_LOG_ENTRIES ;
KeReleaseSpinLock ( & fdoData - > SpinLock , oldIrql ) ;
}
/*++////////////////////////////////////////////////////////////////////////////
DbgSafeInc ( )
Routine Description :
Safely increments a ULONG . If the increment would result in an overflow ,
the value is unchanged .
Arguments :
A pointer to the value to be incremented .
- - */
2020-12-05 17:52:13 +00:00
static VOID DbgSafeInc ( PULONG pValue )
2020-08-29 03:06:22 +00:00
{
ULONG incrementResult ;
if ( NT_SUCCESS ( RtlULongAdd ( * pValue , 1 , & incrementResult ) ) ) {
* pValue = incrementResult ;
} else {
//
// Leave *pValue unchanged (i.e. at ULONG_MAX).
//
}
}
VOID DbgLogFlushInfo ( PCLASS_PRIVATE_FDO_DATA FdoData , BOOLEAN IsIO , BOOLEAN IsFUA , BOOLEAN IsFlush )
{
/*
* Reset all FUA / Flush logging fields .
*/
if ( FdoData - > DbgInitFlushLogging ) {
FdoData - > DbgNumIORequests = 0 ;
FdoData - > DbgNumFUAs = 0 ;
FdoData - > DbgNumFlushes = 0 ;
FdoData - > DbgIOsSinceFUA = 0 ;
FdoData - > DbgIOsSinceFlush = 0 ;
FdoData - > DbgAveIOsToFUA = 0 ;
FdoData - > DbgAveIOsToFlush = 0 ;
FdoData - > DbgMaxIOsToFUA = 0 ;
FdoData - > DbgMaxIOsToFlush = 0 ;
FdoData - > DbgMinIOsToFUA = 0xffffffff ;
FdoData - > DbgMinIOsToFlush = 0xffffffff ;
FdoData - > DbgInitFlushLogging = FALSE ;
}
//
// Using DbgSafeInc for all increments (instead of ++) guarantees
// that there will be no overflow hence no division by 0. All counters
// are capped at ULONG_MAX.
//
if ( IsIO ) {
DbgSafeInc ( & FdoData - > DbgNumIORequests ) ;
DbgSafeInc ( & FdoData - > DbgIOsSinceFlush ) ;
if ( IsFUA ) {
if ( FdoData - > DbgNumFUAs > 0 ) {
FdoData - > DbgMinIOsToFUA = min ( FdoData - > DbgMinIOsToFUA , FdoData - > DbgIOsSinceFUA ) ;
}
DbgSafeInc ( & FdoData - > DbgNumFUAs ) ;
FdoData - > DbgAveIOsToFUA = FdoData - > DbgNumIORequests / FdoData - > DbgNumFUAs ;
FdoData - > DbgIOsSinceFUA = 0 ;
}
else {
DbgSafeInc ( & FdoData - > DbgIOsSinceFUA ) ;
FdoData - > DbgMaxIOsToFUA = max ( FdoData - > DbgMaxIOsToFUA , FdoData - > DbgIOsSinceFUA ) ;
}
FdoData - > DbgMaxIOsToFlush = max ( FdoData - > DbgMaxIOsToFlush , FdoData - > DbgIOsSinceFlush ) ;
}
else if ( IsFlush ) {
if ( FdoData - > DbgNumFlushes > 0 ) {
FdoData - > DbgMinIOsToFlush = min ( FdoData - > DbgMinIOsToFlush , FdoData - > DbgIOsSinceFlush ) ;
}
DbgSafeInc ( & FdoData - > DbgNumFlushes ) ;
FdoData - > DbgAveIOsToFlush = FdoData - > DbgNumIORequests / FdoData - > DbgNumFlushes ;
FdoData - > DbgIOsSinceFlush = 0 ;
}
}
/*++////////////////////////////////////////////////////////////////////////////
SnapDiskStartup ( )
Routine Description :
This function will attempt to record the caller responsible for spinning
up the disk .
Arguments :
NONE .
Return Value :
NONE .
- - */
VOID
SnapDiskStartup (
VOID
)
{
ULONG Index ;
PDISK_SPINUP_TRACES Entry ;
LARGE_INTEGER SpinUpTime ;
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4210) // nonstandard extension used : function given file scope
# endif
extern NTSYSAPI USHORT NTAPI RtlCaptureStackBackTrace (
_In_ ULONG FramesToSkip ,
_In_ ULONG FramesToCapture ,
_Out_writes_to_ ( FramesToCapture , return ) PVOID * BackTrace ,
_Out_opt_ PULONG BackTraceHash ) ;
# ifdef _MSC_VER
# pragma warning(pop)
# endif
//
// Grab the current count, then mod it so that it
// becomes an index into the DiskSpinupTraces array.
//
Index = InterlockedIncrement ( ( volatile LONG * ) & DiskSpinupIndex ) ;
Index = Index & ( NUMBER_OF_DISK_SPINUP_TRACES - 1 ) ;
Entry = & DiskSpinupTraces [ Index ] ;
//
// Timestamp the instance.
//
KeQueryTickCount ( & SpinUpTime ) ;
SpinUpTime . QuadPart = ( SpinUpTime . QuadPart * KeQueryTimeIncrement ( ) ) / ( 10000000 ) ;
//
// Ask the kernel to read back up our stack by
// DISK_SPINUP_BACKTRACE_LENGTH frames.
//
Entry - > TimeStamp . QuadPart = SpinUpTime . QuadPart ;
RtlZeroMemory ( & Entry - > StackTrace [ 0 ] , DISK_SPINUP_BACKTRACE_LENGTH * sizeof ( PVOID ) ) ;
RtlCaptureStackBackTrace ( 5 , // stacks to skip
DISK_SPINUP_BACKTRACE_LENGTH , // buffer size
Entry - > StackTrace ,
& Index ) ;
}
# else
// We have to keep this in the retail build for legacy.
VOID ClassDebugPrint ( _In_ CLASS_DEBUG_LEVEL DebugPrintLevel , _In_z_ PCCHAR DebugMessage , . . . )
{
UNREFERENCED_PARAMETER ( DebugPrintLevel ) ;
UNREFERENCED_PARAMETER ( DebugMessage ) ;
}
# endif
char * DbgGetIoctlStr ( ULONG ioctl )
{
char * ioctlStr = " ? " ;
switch ( ioctl ) {
# undef MAKE_CASE
# define MAKE_CASE(ioctlCode) case ioctlCode: ioctlStr = #ioctlCode; break;
MAKE_CASE ( IOCTL_STORAGE_CHECK_VERIFY )
MAKE_CASE ( IOCTL_STORAGE_CHECK_VERIFY2 )
MAKE_CASE ( IOCTL_STORAGE_MEDIA_REMOVAL )
MAKE_CASE ( IOCTL_STORAGE_EJECT_MEDIA )
MAKE_CASE ( IOCTL_STORAGE_LOAD_MEDIA )
MAKE_CASE ( IOCTL_STORAGE_LOAD_MEDIA2 )
MAKE_CASE ( IOCTL_STORAGE_RESERVE )
MAKE_CASE ( IOCTL_STORAGE_RELEASE )
MAKE_CASE ( IOCTL_STORAGE_PERSISTENT_RESERVE_IN )
MAKE_CASE ( IOCTL_STORAGE_PERSISTENT_RESERVE_OUT )
MAKE_CASE ( IOCTL_STORAGE_FIND_NEW_DEVICES )
MAKE_CASE ( IOCTL_STORAGE_EJECTION_CONTROL )
MAKE_CASE ( IOCTL_STORAGE_MCN_CONTROL )
MAKE_CASE ( IOCTL_STORAGE_GET_MEDIA_TYPES )
MAKE_CASE ( IOCTL_STORAGE_GET_MEDIA_TYPES_EX )
MAKE_CASE ( IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER )
MAKE_CASE ( IOCTL_STORAGE_GET_HOTPLUG_INFO )
MAKE_CASE ( IOCTL_STORAGE_RESET_BUS )
MAKE_CASE ( IOCTL_STORAGE_RESET_DEVICE )
MAKE_CASE ( IOCTL_STORAGE_GET_DEVICE_NUMBER )
MAKE_CASE ( IOCTL_STORAGE_PREDICT_FAILURE )
MAKE_CASE ( IOCTL_STORAGE_QUERY_PROPERTY )
MAKE_CASE ( OBSOLETE_IOCTL_STORAGE_RESET_BUS )
MAKE_CASE ( OBSOLETE_IOCTL_STORAGE_RESET_DEVICE )
}
return ioctlStr ;
}
char * DbgGetScsiOpStr ( PSTORAGE_REQUEST_BLOCK_HEADER Srb )
{
PCDB pCdb = SrbGetCdb ( Srb ) ;
char * scsiOpStr = " ? " ;
if ( pCdb ) {
switch ( pCdb - > CDB6GENERIC . OperationCode ) {
# undef MAKE_CASE
# define MAKE_CASE(scsiOpCode) case scsiOpCode: scsiOpStr = #scsiOpCode; break;
MAKE_CASE ( SCSIOP_TEST_UNIT_READY )
MAKE_CASE ( SCSIOP_REWIND ) // aka SCSIOP_REZERO_UNIT
MAKE_CASE ( SCSIOP_REQUEST_BLOCK_ADDR )
MAKE_CASE ( SCSIOP_REQUEST_SENSE )
MAKE_CASE ( SCSIOP_FORMAT_UNIT )
MAKE_CASE ( SCSIOP_READ_BLOCK_LIMITS )
MAKE_CASE ( SCSIOP_INIT_ELEMENT_STATUS ) // aka SCSIOP_REASSIGN_BLOCKS
MAKE_CASE ( SCSIOP_RECEIVE ) // aka SCSIOP_READ6
MAKE_CASE ( SCSIOP_SEND ) // aka SCSIOP_WRITE6, SCSIOP_PRINT
MAKE_CASE ( SCSIOP_SLEW_PRINT ) // aka SCSIOP_SEEK6, SCSIOP_TRACK_SELECT
MAKE_CASE ( SCSIOP_SEEK_BLOCK )
MAKE_CASE ( SCSIOP_PARTITION )
MAKE_CASE ( SCSIOP_READ_REVERSE )
MAKE_CASE ( SCSIOP_FLUSH_BUFFER ) // aka SCSIOP_WRITE_FILEMARKS
MAKE_CASE ( SCSIOP_SPACE )
MAKE_CASE ( SCSIOP_INQUIRY )
MAKE_CASE ( SCSIOP_VERIFY6 )
MAKE_CASE ( SCSIOP_RECOVER_BUF_DATA )
MAKE_CASE ( SCSIOP_MODE_SELECT )
MAKE_CASE ( SCSIOP_RESERVE_UNIT )
MAKE_CASE ( SCSIOP_RELEASE_UNIT )
MAKE_CASE ( SCSIOP_COPY )
MAKE_CASE ( SCSIOP_ERASE )
MAKE_CASE ( SCSIOP_MODE_SENSE )
MAKE_CASE ( SCSIOP_START_STOP_UNIT ) // aka SCSIOP_STOP_PRINT, SCSIOP_LOAD_UNLOAD
MAKE_CASE ( SCSIOP_RECEIVE_DIAGNOSTIC )
MAKE_CASE ( SCSIOP_SEND_DIAGNOSTIC )
MAKE_CASE ( SCSIOP_MEDIUM_REMOVAL )
MAKE_CASE ( SCSIOP_READ_FORMATTED_CAPACITY )
MAKE_CASE ( SCSIOP_READ_CAPACITY )
MAKE_CASE ( SCSIOP_READ )
MAKE_CASE ( SCSIOP_WRITE )
MAKE_CASE ( SCSIOP_SEEK ) // aka SCSIOP_LOCATE, SCSIOP_POSITION_TO_ELEMENT
MAKE_CASE ( SCSIOP_WRITE_VERIFY )
MAKE_CASE ( SCSIOP_VERIFY )
MAKE_CASE ( SCSIOP_SEARCH_DATA_HIGH )
MAKE_CASE ( SCSIOP_SEARCH_DATA_EQUAL )
MAKE_CASE ( SCSIOP_SEARCH_DATA_LOW )
MAKE_CASE ( SCSIOP_SET_LIMITS )
MAKE_CASE ( SCSIOP_READ_POSITION )
MAKE_CASE ( SCSIOP_SYNCHRONIZE_CACHE )
MAKE_CASE ( SCSIOP_COMPARE )
MAKE_CASE ( SCSIOP_COPY_COMPARE )
MAKE_CASE ( SCSIOP_WRITE_DATA_BUFF )
MAKE_CASE ( SCSIOP_READ_DATA_BUFF )
MAKE_CASE ( SCSIOP_CHANGE_DEFINITION )
MAKE_CASE ( SCSIOP_READ_SUB_CHANNEL )
MAKE_CASE ( SCSIOP_READ_TOC )
MAKE_CASE ( SCSIOP_READ_HEADER )
MAKE_CASE ( SCSIOP_PLAY_AUDIO )
MAKE_CASE ( SCSIOP_GET_CONFIGURATION )
MAKE_CASE ( SCSIOP_PLAY_AUDIO_MSF )
MAKE_CASE ( SCSIOP_PLAY_TRACK_INDEX )
MAKE_CASE ( SCSIOP_PLAY_TRACK_RELATIVE )
MAKE_CASE ( SCSIOP_GET_EVENT_STATUS )
MAKE_CASE ( SCSIOP_PAUSE_RESUME )
MAKE_CASE ( SCSIOP_LOG_SELECT )
MAKE_CASE ( SCSIOP_LOG_SENSE )
MAKE_CASE ( SCSIOP_STOP_PLAY_SCAN )
MAKE_CASE ( SCSIOP_READ_DISK_INFORMATION )
MAKE_CASE ( SCSIOP_READ_TRACK_INFORMATION )
MAKE_CASE ( SCSIOP_RESERVE_TRACK_RZONE )
MAKE_CASE ( SCSIOP_SEND_OPC_INFORMATION )
MAKE_CASE ( SCSIOP_MODE_SELECT10 )
MAKE_CASE ( SCSIOP_MODE_SENSE10 )
MAKE_CASE ( SCSIOP_CLOSE_TRACK_SESSION )
MAKE_CASE ( SCSIOP_READ_BUFFER_CAPACITY )
MAKE_CASE ( SCSIOP_SEND_CUE_SHEET )
MAKE_CASE ( SCSIOP_PERSISTENT_RESERVE_IN )
MAKE_CASE ( SCSIOP_PERSISTENT_RESERVE_OUT )
MAKE_CASE ( SCSIOP_REPORT_LUNS )
MAKE_CASE ( SCSIOP_BLANK )
MAKE_CASE ( SCSIOP_SEND_KEY )
MAKE_CASE ( SCSIOP_REPORT_KEY )
MAKE_CASE ( SCSIOP_MOVE_MEDIUM )
MAKE_CASE ( SCSIOP_LOAD_UNLOAD_SLOT ) // aka SCSIOP_EXCHANGE_MEDIUM
MAKE_CASE ( SCSIOP_SET_READ_AHEAD )
MAKE_CASE ( SCSIOP_READ_DVD_STRUCTURE )
MAKE_CASE ( SCSIOP_REQUEST_VOL_ELEMENT )
MAKE_CASE ( SCSIOP_SEND_VOLUME_TAG )
MAKE_CASE ( SCSIOP_READ_ELEMENT_STATUS )
MAKE_CASE ( SCSIOP_READ_CD_MSF )
MAKE_CASE ( SCSIOP_SCAN_CD )
MAKE_CASE ( SCSIOP_SET_CD_SPEED )
MAKE_CASE ( SCSIOP_PLAY_CD )
MAKE_CASE ( SCSIOP_MECHANISM_STATUS )
MAKE_CASE ( SCSIOP_READ_CD )
MAKE_CASE ( SCSIOP_SEND_DVD_STRUCTURE )
MAKE_CASE ( SCSIOP_INIT_ELEMENT_RANGE )
MAKE_CASE ( SCSIOP_READ16 )
MAKE_CASE ( SCSIOP_WRITE16 )
MAKE_CASE ( SCSIOP_VERIFY16 )
MAKE_CASE ( SCSIOP_SYNCHRONIZE_CACHE16 )
MAKE_CASE ( SCSIOP_READ_CAPACITY16 )
}
}
return scsiOpStr ;
}
char * DbgGetSrbStatusStr ( PSTORAGE_REQUEST_BLOCK_HEADER Srb )
{
char * srbStatStr = " ? " ;
switch ( Srb - > SrbStatus ) {
# undef MAKE_CASE
# define MAKE_CASE(srbStat) \
case srbStat : \
srbStatStr = # srbStat ; \
break ; \
case srbStat | SRB_STATUS_QUEUE_FROZEN : \
srbStatStr = # srbStat " |SRB_STATUS_QUEUE_FROZEN " ; \
break ; \
case srbStat | SRB_STATUS_AUTOSENSE_VALID : \
srbStatStr = # srbStat " |SRB_STATUS_AUTOSENSE_VALID " ; \
break ; \
case srbStat | SRB_STATUS_QUEUE_FROZEN | SRB_STATUS_AUTOSENSE_VALID : \
srbStatStr = # srbStat " |SRB_STATUS_QUEUE_FROZEN|SRB_STATUS_AUTOSENSE_VALID " ; \
break ;
MAKE_CASE ( SRB_STATUS_PENDING )
MAKE_CASE ( SRB_STATUS_SUCCESS )
MAKE_CASE ( SRB_STATUS_ABORTED )
MAKE_CASE ( SRB_STATUS_ABORT_FAILED )
MAKE_CASE ( SRB_STATUS_ERROR )
MAKE_CASE ( SRB_STATUS_BUSY )
MAKE_CASE ( SRB_STATUS_INVALID_REQUEST )
MAKE_CASE ( SRB_STATUS_INVALID_PATH_ID )
MAKE_CASE ( SRB_STATUS_NO_DEVICE )
MAKE_CASE ( SRB_STATUS_TIMEOUT )
MAKE_CASE ( SRB_STATUS_SELECTION_TIMEOUT )
MAKE_CASE ( SRB_STATUS_COMMAND_TIMEOUT )
MAKE_CASE ( SRB_STATUS_MESSAGE_REJECTED )
MAKE_CASE ( SRB_STATUS_BUS_RESET )
MAKE_CASE ( SRB_STATUS_PARITY_ERROR )
MAKE_CASE ( SRB_STATUS_REQUEST_SENSE_FAILED )
MAKE_CASE ( SRB_STATUS_NO_HBA )
MAKE_CASE ( SRB_STATUS_DATA_OVERRUN )
MAKE_CASE ( SRB_STATUS_UNEXPECTED_BUS_FREE )
MAKE_CASE ( SRB_STATUS_PHASE_SEQUENCE_FAILURE )
MAKE_CASE ( SRB_STATUS_BAD_SRB_BLOCK_LENGTH )
MAKE_CASE ( SRB_STATUS_REQUEST_FLUSHED )
MAKE_CASE ( SRB_STATUS_INVALID_LUN )
MAKE_CASE ( SRB_STATUS_INVALID_TARGET_ID )
MAKE_CASE ( SRB_STATUS_BAD_FUNCTION )
MAKE_CASE ( SRB_STATUS_ERROR_RECOVERY )
MAKE_CASE ( SRB_STATUS_NOT_POWERED )
MAKE_CASE ( SRB_STATUS_INTERNAL_ERROR )
}
return srbStatStr ;
}
char * DbgGetSenseCodeStr ( PSTORAGE_REQUEST_BLOCK_HEADER Srb )
{
char * senseCodeStr = " ? " ;
if ( Srb - > SrbStatus & SRB_STATUS_AUTOSENSE_VALID ) {
PVOID senseData ;
UCHAR senseCode ;
BOOLEAN validSense ;
senseData = SrbGetSenseInfoBuffer ( Srb ) ;
NT_ASSERT ( senseData ) ;
validSense = ScsiGetSenseKeyAndCodes ( senseData ,
SrbGetSenseInfoBufferLength ( Srb ) ,
SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED ,
& senseCode ,
NULL ,
NULL ) ;
if ( validSense ) {
switch ( senseCode ) {
# undef MAKE_CASE
# define MAKE_CASE(snsCod) case snsCod: senseCodeStr = #snsCod; break;
MAKE_CASE ( SCSI_SENSE_NO_SENSE )
MAKE_CASE ( SCSI_SENSE_RECOVERED_ERROR )
MAKE_CASE ( SCSI_SENSE_NOT_READY )
MAKE_CASE ( SCSI_SENSE_MEDIUM_ERROR )
MAKE_CASE ( SCSI_SENSE_HARDWARE_ERROR )
MAKE_CASE ( SCSI_SENSE_ILLEGAL_REQUEST )
MAKE_CASE ( SCSI_SENSE_UNIT_ATTENTION )
MAKE_CASE ( SCSI_SENSE_DATA_PROTECT )
MAKE_CASE ( SCSI_SENSE_BLANK_CHECK )
MAKE_CASE ( SCSI_SENSE_UNIQUE )
MAKE_CASE ( SCSI_SENSE_COPY_ABORTED )
MAKE_CASE ( SCSI_SENSE_ABORTED_COMMAND )
MAKE_CASE ( SCSI_SENSE_EQUAL )
MAKE_CASE ( SCSI_SENSE_VOL_OVERFLOW )
MAKE_CASE ( SCSI_SENSE_MISCOMPARE )
MAKE_CASE ( SCSI_SENSE_RESERVED )
}
}
}
return senseCodeStr ;
}
char * DbgGetAdditionalSenseCodeStr ( PSTORAGE_REQUEST_BLOCK_HEADER Srb )
{
char * adSenseCodeStr = " ? " ;
if ( Srb - > SrbStatus & SRB_STATUS_AUTOSENSE_VALID ) {
PVOID senseData ;
UCHAR adSenseCode ;
BOOLEAN validSense ;
senseData = SrbGetSenseInfoBuffer ( Srb ) ;
NT_ASSERT ( senseData ) ;
validSense = ScsiGetSenseKeyAndCodes ( senseData ,
SrbGetSenseInfoBufferLength ( Srb ) ,
SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED ,
NULL ,
& adSenseCode ,
NULL ) ;
if ( validSense ) {
switch ( adSenseCode ) {
# undef MAKE_CASE
# define MAKE_CASE(adSnsCod) case adSnsCod: adSenseCodeStr = #adSnsCod; break;
MAKE_CASE ( SCSI_ADSENSE_NO_SENSE )
MAKE_CASE ( SCSI_ADSENSE_LUN_NOT_READY )
MAKE_CASE ( SCSI_ADSENSE_TRACK_ERROR )
MAKE_CASE ( SCSI_ADSENSE_SEEK_ERROR )
MAKE_CASE ( SCSI_ADSENSE_REC_DATA_NOECC )
MAKE_CASE ( SCSI_ADSENSE_REC_DATA_ECC )
MAKE_CASE ( SCSI_ADSENSE_ILLEGAL_COMMAND )
MAKE_CASE ( SCSI_ADSENSE_ILLEGAL_BLOCK )
MAKE_CASE ( SCSI_ADSENSE_INVALID_CDB )
MAKE_CASE ( SCSI_ADSENSE_INVALID_LUN )
MAKE_CASE ( SCSI_ADSENSE_WRITE_PROTECT ) // aka SCSI_ADWRITE_PROTECT
MAKE_CASE ( SCSI_ADSENSE_MEDIUM_CHANGED )
MAKE_CASE ( SCSI_ADSENSE_BUS_RESET )
MAKE_CASE ( SCSI_ADSENSE_INVALID_MEDIA )
MAKE_CASE ( SCSI_ADSENSE_NO_MEDIA_IN_DEVICE )
MAKE_CASE ( SCSI_ADSENSE_POSITION_ERROR )
MAKE_CASE ( SCSI_ADSENSE_OPERATOR_REQUEST )
MAKE_CASE ( SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED )
MAKE_CASE ( SCSI_ADSENSE_COPY_PROTECTION_FAILURE )
MAKE_CASE ( SCSI_ADSENSE_VENDOR_UNIQUE )
MAKE_CASE ( SCSI_ADSENSE_MUSIC_AREA )
MAKE_CASE ( SCSI_ADSENSE_DATA_AREA )
MAKE_CASE ( SCSI_ADSENSE_VOLUME_OVERFLOW )
}
}
}
return adSenseCodeStr ;
}
char * DbgGetAdditionalSenseCodeQualifierStr ( PSTORAGE_REQUEST_BLOCK_HEADER Srb )
{
char * adSenseCodeQualStr = " ? " ;
if ( Srb - > SrbStatus & SRB_STATUS_AUTOSENSE_VALID ) {
PVOID senseData ;
UCHAR adSenseCode ;
UCHAR adSenseCodeQual ;
BOOLEAN validSense ;
senseData = SrbGetSenseInfoBuffer ( Srb ) ;
NT_ASSERT ( senseData ) ;
validSense = ScsiGetSenseKeyAndCodes ( senseData ,
SrbGetSenseInfoBufferLength ( Srb ) ,
SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED ,
NULL ,
& adSenseCode ,
& adSenseCodeQual ) ;
if ( validSense ) {
switch ( adSenseCode ) {
# undef MAKE_CASE
# define MAKE_CASE(adSnsCodQual) case adSnsCodQual: adSenseCodeQualStr = #adSnsCodQual; break;
case SCSI_ADSENSE_LUN_NOT_READY :
switch ( adSenseCodeQual ) {
MAKE_CASE ( SCSI_SENSEQ_CAUSE_NOT_REPORTABLE )
MAKE_CASE ( SCSI_SENSEQ_BECOMING_READY )
MAKE_CASE ( SCSI_SENSEQ_INIT_COMMAND_REQUIRED )
MAKE_CASE ( SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED )
MAKE_CASE ( SCSI_SENSEQ_FORMAT_IN_PROGRESS )
MAKE_CASE ( SCSI_SENSEQ_REBUILD_IN_PROGRESS )
MAKE_CASE ( SCSI_SENSEQ_RECALCULATION_IN_PROGRESS )
MAKE_CASE ( SCSI_SENSEQ_OPERATION_IN_PROGRESS )
MAKE_CASE ( SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS )
}
break ;
case SCSI_ADSENSE_NO_SENSE :
switch ( adSenseCodeQual ) {
MAKE_CASE ( SCSI_SENSEQ_FILEMARK_DETECTED )
MAKE_CASE ( SCSI_SENSEQ_END_OF_MEDIA_DETECTED )
MAKE_CASE ( SCSI_SENSEQ_SETMARK_DETECTED )
MAKE_CASE ( SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED )
}
break ;
case SCSI_ADSENSE_ILLEGAL_BLOCK :
switch ( adSenseCodeQual ) {
MAKE_CASE ( SCSI_SENSEQ_ILLEGAL_ELEMENT_ADDR )
}
break ;
case SCSI_ADSENSE_POSITION_ERROR :
switch ( adSenseCodeQual ) {
MAKE_CASE ( SCSI_SENSEQ_DESTINATION_FULL )
MAKE_CASE ( SCSI_SENSEQ_SOURCE_EMPTY )
}
break ;
case SCSI_ADSENSE_INVALID_MEDIA :
switch ( adSenseCodeQual ) {
MAKE_CASE ( SCSI_SENSEQ_INCOMPATIBLE_MEDIA_INSTALLED )
MAKE_CASE ( SCSI_SENSEQ_UNKNOWN_FORMAT )
MAKE_CASE ( SCSI_SENSEQ_INCOMPATIBLE_FORMAT )
MAKE_CASE ( SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED )
}
break ;
case SCSI_ADSENSE_OPERATOR_REQUEST :
switch ( adSenseCodeQual ) {
MAKE_CASE ( SCSI_SENSEQ_STATE_CHANGE_INPUT )
MAKE_CASE ( SCSI_SENSEQ_MEDIUM_REMOVAL )
MAKE_CASE ( SCSI_SENSEQ_WRITE_PROTECT_ENABLE )
MAKE_CASE ( SCSI_SENSEQ_WRITE_PROTECT_DISABLE )
}
break ;
case SCSI_ADSENSE_COPY_PROTECTION_FAILURE :
switch ( adSenseCodeQual ) {
MAKE_CASE ( SCSI_SENSEQ_AUTHENTICATION_FAILURE )
MAKE_CASE ( SCSI_SENSEQ_KEY_NOT_PRESENT )
MAKE_CASE ( SCSI_SENSEQ_KEY_NOT_ESTABLISHED )
MAKE_CASE ( SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION )
MAKE_CASE ( SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT )
MAKE_CASE ( SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR )
}
break ;
}
}
}
return adSenseCodeQualStr ;
}