mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
15a7b9dd2f
CORE-17129
972 lines
38 KiB
C
972 lines
38 KiB
C
/*++
|
|
|
|
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;
|
|
}
|
|
|
|
|