/*++ 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. --*/ static VOID DbgSafeInc(PULONG pValue) { 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; }