mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 19:11:55 +00:00
[CLASSPNP] Import Microsoft SCSI class driver from GitHub
The source code is licensed under MS-PL license, taken from Windows Driver Samples repository (https://github.com/microsoft/Windows-driver-samples/tree/master/storage/class/classpnp/) Synched with commit 88541f70c4273ecd30c8c7c72135bc038a00fd88 The driver is written for Windows 8+, so we compile it with ntoskrnl_vista statically linked and with NTDDI_WIN8 defined CORE-17129
This commit is contained in:
parent
d9864ca6c5
commit
bf1b3cb175
24 changed files with 45624 additions and 0 deletions
51
drivers/storage/class/classpnp/CMakeLists.txt
Normal file
51
drivers/storage/class/classpnp/CMakeLists.txt
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
spec2def(classpnp.sys classpnp.spec ADD_IMPORTLIB)
|
||||
|
||||
remove_definitions(-D_WIN32_WINNT=0x502)
|
||||
|
||||
list(APPEND SOURCE
|
||||
autorun.c
|
||||
class.c
|
||||
classwmi.c
|
||||
clntirp.c
|
||||
create.c
|
||||
data.c
|
||||
debug.c
|
||||
dictlib.c
|
||||
dispatch.c
|
||||
guid.c
|
||||
history.c
|
||||
lock.c
|
||||
obsolete.c
|
||||
power.c
|
||||
retry.c
|
||||
srblib.c
|
||||
utils.c
|
||||
xferpkt.c)
|
||||
|
||||
add_library(classpnp MODULE
|
||||
${SOURCE}
|
||||
class.rc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/classpnp.def)
|
||||
|
||||
target_compile_definitions(classpnp PUBLIC
|
||||
DEBUG_USE_KDPRINT
|
||||
_WIN32_WINNT=0x602
|
||||
NTDDI_VERSION=0x06020000) # NTDDI_WIN8
|
||||
|
||||
target_compile_definitions(classpnp PRIVATE
|
||||
CLASS_GLOBAL_BREAK_ON_LOST_IRPS=0
|
||||
CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB=100
|
||||
CLASS_GLOBAL_USE_DELAYED_RETRY=1
|
||||
CLASS_GLOBAL_BUFFERED_DEBUG_PRINT=0
|
||||
CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE=512
|
||||
CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS=512)
|
||||
|
||||
if(GCC)
|
||||
target_compile_options(classpnp PRIVATE -Wno-unused-but-set-variable -Wno-pointer-to-int-cast -Wno-switch)
|
||||
endif()
|
||||
|
||||
set_module_type(classpnp kernelmodedriver)
|
||||
target_link_libraries(classpnp ntoskrnl_vista libcntpr ${PSEH_LIB})
|
||||
add_importlibs(classpnp ntoskrnl hal)
|
||||
add_cd_file(TARGET classpnp DESTINATION reactos/system32/drivers NO_CAB FOR all)
|
4436
drivers/storage/class/classpnp/autorun.c
Normal file
4436
drivers/storage/class/classpnp/autorun.c
Normal file
File diff suppressed because it is too large
Load diff
16552
drivers/storage/class/classpnp/class.c
Normal file
16552
drivers/storage/class/classpnp/class.c
Normal file
File diff suppressed because it is too large
Load diff
22
drivers/storage/class/classpnp/class.rc
Normal file
22
drivers/storage/class/classpnp/class.rc
Normal file
|
@ -0,0 +1,22 @@
|
|||
//+-------------------------------------------------------------------------
|
||||
//
|
||||
// Microsoft Windows
|
||||
//
|
||||
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
||||
//
|
||||
// File: class.rc
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#include <verrsrc.h>
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
#define VER_FILETYPE VFT_DRV
|
||||
#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
|
||||
#define VER_FILEDESCRIPTION_STR "SCSI Class System Dll"
|
||||
#define VER_INTERNALNAME_STR "Classpnp.sys"
|
||||
#define VER_ORIGINALFILENAME_STR "Classpnp.sys"
|
||||
#define VER_LANGNEUTRAL
|
||||
|
||||
#include "common.ver"
|
178
drivers/storage/class/classpnp/classlog.mof
Normal file
178
drivers/storage/class/classpnp/classlog.mof
Normal file
|
@ -0,0 +1,178 @@
|
|||
#pragma autorecover
|
||||
#pragma namespace("\\\\.\\Root\\WMI")
|
||||
|
||||
[WMI, guid("F903D6EC-8647-438f-9E42-891F4733EDAF")]
|
||||
|
||||
class MSStorageDriver_ScsiRequestBlock {
|
||||
[read, WmiDataId(1), Description("Length")]
|
||||
uint16 length;
|
||||
|
||||
[read, WmiDataId(2), DisplayInHex, Description("Function")]
|
||||
uint8 function;
|
||||
|
||||
[read, WmiDataId(3), DisplayInHex, Description("SRB Status")]
|
||||
uint8 srbStatus;
|
||||
|
||||
[read, WmiDataId(4), DisplayInHex, Description("SCSI Status")]
|
||||
uint8 scsiStatus;
|
||||
|
||||
[read, WmiDataId(5), DisplayInHex, Description("Path ID")]
|
||||
uint8 pathID;
|
||||
|
||||
[read, WmiDataId(6), DisplayInHex, Description("Target ID")]
|
||||
uint8 targetID;
|
||||
|
||||
[read, WmiDataId(7), DisplayInHex, Description("LUN")]
|
||||
uint8 lun;
|
||||
|
||||
[read, WmiDataId(8), DisplayInHex, Description("Queue Tag")]
|
||||
uint8 queueTag;
|
||||
|
||||
[read, WmiDataId(9), DisplayInHex, Description("Queue Action")]
|
||||
uint8 queueAction;
|
||||
|
||||
[read, WmiDataId(10), DisplayInHex, Description("CDB Length")]
|
||||
uint8 cdbLength;
|
||||
|
||||
[read, WmiDataId(11), DisplayInHex, Description("Sense Info Buffer Length")]
|
||||
uint8 senseInfoBufferLength;
|
||||
|
||||
[read, WmiDataId(12), DisplayInHex, Description("SRB Flags")]
|
||||
uint32 srbFlags;
|
||||
|
||||
[read, WmiDataId(13), DisplayInHex, Description("Data Transfer Length")]
|
||||
uint32 dataTransferLength;
|
||||
|
||||
[read, WmiDataId(14), DisplayInHex, Description("Time Out Value")]
|
||||
uint32 timeOutValue;
|
||||
|
||||
[read, WmiDataId(15), DisplayInHex, Description("Data Buffer Pointer")]
|
||||
uint64 dataBuffer;
|
||||
|
||||
[read, WmiDataId(16), DisplayInHex, Description("Sense Info Buffer Pointer")]
|
||||
uint64 senseInfoBuffer;
|
||||
|
||||
[read, WmiDataId(17), DisplayInHex, Description("Next SRB Pointer")]
|
||||
uint64 nextSRB;
|
||||
|
||||
[read, WmiDataId(18), DisplayInHex, Description("Original Request Pointer")]
|
||||
uint64 originalRequest;
|
||||
|
||||
[read, WmiDataId(19), DisplayInHex, Description("SRB Extension Pointer")]
|
||||
uint64 srbExtension;
|
||||
|
||||
[read, WmiDataId(20), DisplayInHex, Description("Internal Status")]
|
||||
uint32 internalStatus;
|
||||
|
||||
[read, WmiDataId(21), DisplayInHex, Description("Reserved (only available in Win64)")]
|
||||
uint32 reserved;
|
||||
|
||||
[read, WmiDataId(22), DisplayInHex, Description("CDB")]
|
||||
uint8 cdb[16];
|
||||
};
|
||||
|
||||
[WMI, guid("9065566F-5FD6-4b40-9961-98E3A3DD174E")]
|
||||
|
||||
class MSStorageDriver_SenseData {
|
||||
[read, WmiDataId(1), Description("Error Code")]
|
||||
uint8 errorCode;
|
||||
|
||||
[read, WmiDataId(2), Description("Valid")]
|
||||
boolean valid;
|
||||
|
||||
[read, WmiDataId(3), Description("Segment Number")]
|
||||
uint8 segmentNumber;
|
||||
|
||||
[read, WmiDataId(4), Description("Sense Key")]
|
||||
uint8 senseKey;
|
||||
|
||||
[read, WmiDataId(5), Description("Reserved")]
|
||||
boolean reserved;
|
||||
|
||||
[read, WmiDataId(6), Description("Incorrect Length")]
|
||||
boolean incorrectLength;
|
||||
|
||||
[read, WmiDataId(7), Description("End Of Media")]
|
||||
boolean endOfMedia;
|
||||
|
||||
[read, WmiDataId(8), Description("File Mark")]
|
||||
boolean fileMark;
|
||||
|
||||
[read, WmiDataId(9), Description("Information")]
|
||||
uint8 information[4];
|
||||
|
||||
[read, WmiDataId(10), Description("Additional Sense Length")]
|
||||
uint8 additionalSenseLength;
|
||||
|
||||
[read, WmiDataId(11), Description("Command Specific Information")]
|
||||
uint8 commandSpecificInformation[4];
|
||||
|
||||
[read, WmiDataId(12), Description("Additional Sense Code")]
|
||||
uint8 additionalSenseCode;
|
||||
|
||||
[read, WmiDataId(13), Description("Additional Sense Code Qualifier")]
|
||||
uint8 additionalSenseCodeQualifier;
|
||||
|
||||
[read, WmiDataId(14), Description("Field Replaceable Unit Code")]
|
||||
uint8 fieldReplaceableUnitCode;
|
||||
|
||||
[read, WmiDataId(15), Description("Sense Key Specific")]
|
||||
uint8 senseKeySpecific[3];
|
||||
};
|
||||
|
||||
[WMI, guid("0C9BF007-50E9-407e-A9DA-0F33800E4B45")]
|
||||
|
||||
class MSStorageDriver_ClassErrorLogEntry {
|
||||
[read, WmiDataId(1), Description("Tick Count")]
|
||||
uint64 tickCount;
|
||||
|
||||
[read, WmiDataId(2), Description("Port Number")]
|
||||
uint32 portNumber;
|
||||
|
||||
[read, WmiDataId(3), Description("Error Paging")]
|
||||
boolean errorPaging;
|
||||
|
||||
[read, WmiDataId(4), Description("Error Retried")]
|
||||
boolean errorRetried;
|
||||
|
||||
[read, WmiDataId(5), Description("Error Unhandled")]
|
||||
boolean errorUnhandled;
|
||||
|
||||
[read, WmiDataId(6), DisplayInHex, Description("Error Reserved")]
|
||||
uint8 errorReserved;
|
||||
|
||||
[read, WmiDataId(7), DisplayInHex, Description("Reserved")]
|
||||
uint8 reserved[3];
|
||||
|
||||
[read, WmiDataId(8), Description("SCSI Request Block")]
|
||||
MSStorageDriver_ScsiRequestBlock srb;
|
||||
|
||||
[read, WmiDataId(9), Description("Sense Data")]
|
||||
MSStorageDriver_SenseData senseData;
|
||||
|
||||
[read, WmiDataId(10), Description("Event Time")]
|
||||
datetime eventTime;
|
||||
};
|
||||
|
||||
[Dynamic, Provider("WMIProv"),
|
||||
WMI, Description("MS Storage Class Driver Error Log"),
|
||||
guid("D5A9A51E-03F9-404d-9722-15F90EB07038"),
|
||||
locale("MS\\0x409")]
|
||||
|
||||
class MSStorageDriver_ClassErrorLog {
|
||||
[key, read]
|
||||
string InstanceName;
|
||||
|
||||
[read]
|
||||
boolean Active;
|
||||
|
||||
[read,
|
||||
WmiDataId(1),
|
||||
Description("Number of Error Log Entries")]
|
||||
uint32 numEntries;
|
||||
|
||||
[read,
|
||||
WmiDataId(2),
|
||||
Description("Error Log Array")]
|
||||
MSStorageDriver_ClassErrorLogEntry logEntries[16];
|
||||
};
|
2682
drivers/storage/class/classpnp/classp.h
Normal file
2682
drivers/storage/class/classpnp/classp.h
Normal file
File diff suppressed because it is too large
Load diff
62
drivers/storage/class/classpnp/classpnp.spec
Normal file
62
drivers/storage/class/classpnp/classpnp.spec
Normal file
|
@ -0,0 +1,62 @@
|
|||
|
||||
@ stdcall ClassInitialize(ptr ptr ptr)
|
||||
@ stdcall ClassInitializeEx(ptr ptr ptr)
|
||||
@ stdcall ClassGetDescriptor(ptr ptr ptr)
|
||||
@ stdcall ClassReadDriveCapacity(ptr)
|
||||
@ stdcall ClassReleaseQueue(ptr)
|
||||
@ stdcall ClassAsynchronousCompletion(ptr ptr ptr)
|
||||
@ stdcall ClassSplitRequest(ptr ptr long)
|
||||
@ stdcall ClassDeviceControl(ptr ptr)
|
||||
@ stdcall ClassIoComplete(ptr ptr ptr)
|
||||
@ stdcall ClassIoCompleteAssociated(ptr ptr ptr)
|
||||
@ stdcall ClassInterpretSenseInfo(ptr ptr long long long ptr ptr)
|
||||
@ stdcall ClassSendDeviceIoControlSynchronous(long ptr ptr long long long ptr)
|
||||
@ stdcall ClassSendIrpSynchronous(ptr ptr)
|
||||
@ stdcall ClassForwardIrpSynchronous(ptr ptr)
|
||||
@ stdcall ClassSendSrbSynchronous(ptr ptr ptr long long)
|
||||
@ stdcall ClassSendSrbAsynchronous(ptr ptr ptr ptr long long)
|
||||
@ stdcall ClassBuildRequest(ptr ptr)
|
||||
@ stdcall ClassModeSense(ptr ptr long long)
|
||||
@ stdcall ClassModeSenseEx(ptr ptr long long long)
|
||||
@ stdcall ClassModeSelect(ptr ptr long long)
|
||||
@ stdcall ClassFindModePage(ptr long long long)
|
||||
@ stdcall ClassClaimDevice(ptr long)
|
||||
@ stdcall ClassInternalIoControl(ptr ptr)
|
||||
@ stdcall ClassCreateDeviceObject(ptr ptr ptr long ptr)
|
||||
@ stdcall ClassRemoveDevice(ptr long)
|
||||
@ stdcall ClassInitializeSrbLookasideList(ptr long)
|
||||
@ stdcall ClassDeleteSrbLookasideList(ptr)
|
||||
@ stdcall ClassQueryTimeOutRegistryValue(ptr)
|
||||
@ stdcall ClassInvalidateBusRelations(ptr)
|
||||
@ stdcall ClassMarkChildrenMissing(ptr)
|
||||
@ stdcall ClassMarkChildMissing(ptr long)
|
||||
@ varargs ClassDebugPrint(long long)
|
||||
@ stdcall ClassGetDriverExtension(ptr)
|
||||
@ stdcall ClassCompleteRequest(ptr ptr long)
|
||||
@ stdcall ClassReleaseRemoveLock(ptr ptr)
|
||||
@ stdcall ClassAcquireRemoveLockEx(ptr ptr ptr long)
|
||||
@ stdcall ClassUpdateInformationInRegistry(ptr ptr long ptr long)
|
||||
@ stdcall ClassWmiCompleteRequest(ptr ptr long long long)
|
||||
@ stdcall ClassWmiFireEvent(ptr ptr long long ptr)
|
||||
@ stdcall ClassGetVpb(ptr)
|
||||
@ stdcall ClassSetFailurePredictionPoll(ptr long long)
|
||||
@ stdcall ClassNotifyFailurePredicted(ptr ptr long long long long long long)
|
||||
@ stdcall ClassInitializeTestUnitPolling(ptr long)
|
||||
@ stdcall ClassSignalCompletion(ptr ptr ptr)
|
||||
@ stdcall ClassSendStartUnit(ptr)
|
||||
@ stdcall ClassSetMediaChangeState(ptr long long)
|
||||
@ stdcall ClassResetMediaChangeTimer(ptr)
|
||||
@ stdcall ClassCheckMediaState(ptr)
|
||||
@ stdcall ClassInitializeMediaChangeDetection(ptr ptr)
|
||||
@ stdcall ClassCleanupMediaChangeDetection(ptr)
|
||||
@ stdcall ClassEnableMediaChangeDetection(ptr)
|
||||
@ stdcall ClassDisableMediaChangeDetection(ptr)
|
||||
@ stdcall ClassSpinDownPowerHandler(ptr ptr)
|
||||
@ stdcall ClassStopUnitPowerHandler(ptr ptr)
|
||||
@ stdcall ClassAcquireChildLock(ptr)
|
||||
@ stdcall ClassReleaseChildLock(ptr)
|
||||
@ stdcall ClassScanForSpecial(ptr ptr ptr)
|
||||
@ stdcall ClassSetDeviceParameter(ptr ptr ptr long)
|
||||
@ stdcall ClassGetDeviceParameter(ptr ptr ptr ptr)
|
||||
@ stdcall ClassGetFsContext(ptr ptr)
|
||||
@ stdcall ClassSendNotification(ptr ptr long ptr)
|
1221
drivers/storage/class/classpnp/classwmi.c
Normal file
1221
drivers/storage/class/classpnp/classwmi.c
Normal file
File diff suppressed because it is too large
Load diff
770
drivers/storage/class/classpnp/clntirp.c
Normal file
770
drivers/storage/class/classpnp/clntirp.c
Normal file
|
@ -0,0 +1,770 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
clntirp.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Client IRP queuing routines for CLASSPNP
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#ifdef DEBUG_USE_WPP
|
||||
#include "clntirp.tmh"
|
||||
#endif
|
||||
|
||||
VOID
|
||||
ClasspStartIdleTimer(
|
||||
IN PCLASS_PRIVATE_FDO_DATA FdoData
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspStopIdleTimer(
|
||||
PCLASS_PRIVATE_FDO_DATA FdoData
|
||||
);
|
||||
|
||||
KDEFERRED_ROUTINE ClasspIdleTimerDpc;
|
||||
|
||||
VOID
|
||||
ClasspServiceIdleRequest(
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
BOOLEAN PostToDpc
|
||||
);
|
||||
|
||||
|
||||
PIRP
|
||||
ClasspDequeueIdleRequest(
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
);
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
EnqueueDeferredClientIrp
|
||||
|
||||
Routine Description:
|
||||
|
||||
Insert the deferred irp into the list.
|
||||
|
||||
Note: we currently do not support Cancel for storage irps.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fdo - Pointer to the device object
|
||||
Irp - Pointer to the I/O request packet
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
VOID
|
||||
EnqueueDeferredClientIrp(
|
||||
PDEVICE_OBJECT Fdo,
|
||||
PIRP Irp
|
||||
)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
|
||||
KIRQL oldIrql;
|
||||
|
||||
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
InsertTailList(&fdoData->DeferredClientIrpList, &Irp->Tail.Overlay.ListEntry);
|
||||
|
||||
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
DequeueDeferredClientIrp
|
||||
|
||||
Routine Description:
|
||||
|
||||
Remove the deferred irp from the list.
|
||||
|
||||
Arguments:
|
||||
|
||||
Fdo - Pointer to the device object
|
||||
|
||||
Return Value:
|
||||
|
||||
Pointer to removed IRP
|
||||
|
||||
--*/
|
||||
PIRP
|
||||
DequeueDeferredClientIrp(
|
||||
PDEVICE_OBJECT Fdo
|
||||
)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
|
||||
PIRP irp;
|
||||
|
||||
//
|
||||
// The DeferredClientIrpList is almost always empty.
|
||||
// We don't want to grab the spinlock every time we check it (which is on every xfer completion)
|
||||
// so check once first before we grab the spinlock.
|
||||
//
|
||||
if (IsListEmpty(&fdoData->DeferredClientIrpList)){
|
||||
irp = NULL;
|
||||
}
|
||||
else {
|
||||
PLIST_ENTRY listEntry;
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
if (IsListEmpty(&fdoData->DeferredClientIrpList)){
|
||||
listEntry = NULL;
|
||||
}
|
||||
else {
|
||||
listEntry = RemoveHeadList(&fdoData->DeferredClientIrpList);
|
||||
}
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
|
||||
if (listEntry == NULL) {
|
||||
irp = NULL;
|
||||
}
|
||||
else {
|
||||
irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
|
||||
NT_ASSERT(irp->Type == IO_TYPE_IRP);
|
||||
|
||||
|
||||
InitializeListHead(&irp->Tail.Overlay.ListEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return irp;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspInitializeIdleTimer
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize the idle timer for the given device.
|
||||
|
||||
Arguments:
|
||||
|
||||
FdoExtension - Pointer to the device extension
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
VOID
|
||||
ClasspInitializeIdleTimer(
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
)
|
||||
{
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
|
||||
ULONG idleInterval = CLASS_IDLE_INTERVAL;
|
||||
ULONG idlePrioritySupported = TRUE;
|
||||
ULONG activeIdleIoMax = 1;
|
||||
|
||||
ClassGetDeviceParameter(FdoExtension,
|
||||
CLASSP_REG_SUBKEY_NAME,
|
||||
CLASSP_REG_IDLE_PRIORITY_SUPPORTED,
|
||||
&idlePrioritySupported);
|
||||
|
||||
|
||||
if (idlePrioritySupported == FALSE) {
|
||||
//
|
||||
// User has set the registry to disable idle priority for this disk.
|
||||
// No need to initialize any further.
|
||||
// Always ensure that none of the other fields used for idle priority
|
||||
// io are ever used without checking if it is supported.
|
||||
//
|
||||
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspInitializeIdleTimer: Idle priority not supported for disk %p\n", FdoExtension));
|
||||
fdoData->IdlePrioritySupported = FALSE;
|
||||
fdoData->IdleIoCount = 0;
|
||||
fdoData->ActiveIoCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ClassGetDeviceParameter(FdoExtension,
|
||||
CLASSP_REG_SUBKEY_NAME,
|
||||
CLASSP_REG_IDLE_INTERVAL_NAME,
|
||||
&idleInterval);
|
||||
|
||||
if ((idleInterval < CLASS_IDLE_INTERVAL_MIN) || (idleInterval > USHORT_MAX)) {
|
||||
//
|
||||
// If the interval is too low or too high, reset it to the default value.
|
||||
//
|
||||
idleInterval = CLASS_IDLE_INTERVAL;
|
||||
}
|
||||
|
||||
fdoData->IdlePrioritySupported = TRUE;
|
||||
KeInitializeSpinLock(&fdoData->IdleListLock);
|
||||
KeInitializeTimer(&fdoData->IdleTimer);
|
||||
KeInitializeDpc(&fdoData->IdleDpc, ClasspIdleTimerDpc, FdoExtension);
|
||||
InitializeListHead(&fdoData->IdleIrpList);
|
||||
fdoData->IdleTimerStarted = FALSE;
|
||||
fdoData->StarvationDuration = CLASS_STARVATION_INTERVAL;
|
||||
fdoData->IdleInterval = (USHORT)(idleInterval);
|
||||
fdoData->IdleIoCount = 0;
|
||||
fdoData->ActiveIoCount = 0;
|
||||
fdoData->ActiveIdleIoCount = 0;
|
||||
|
||||
ClassGetDeviceParameter(FdoExtension,
|
||||
CLASSP_REG_SUBKEY_NAME,
|
||||
CLASSP_REG_IDLE_ACTIVE_MAX,
|
||||
&activeIdleIoMax);
|
||||
|
||||
activeIdleIoMax = max(activeIdleIoMax, 1);
|
||||
activeIdleIoMax = min(activeIdleIoMax, USHORT_MAX);
|
||||
|
||||
fdoData->IdleActiveIoMax = (USHORT)activeIdleIoMax;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspStartIdleTimer
|
||||
|
||||
Routine Description:
|
||||
|
||||
Start the idle timer if not already running. Reset the
|
||||
timer counters before starting the timer. Use the IdleInterval
|
||||
in the private fdo data to setup the timer.
|
||||
|
||||
Arguments:
|
||||
|
||||
FdoData - Pointer to the private fdo data
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
VOID
|
||||
ClasspStartIdleTimer(
|
||||
IN PCLASS_PRIVATE_FDO_DATA FdoData
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER dueTime;
|
||||
LONG mstotimer;
|
||||
LONG timerStarted;
|
||||
|
||||
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspStartIdleTimer: Start idle timer\n"));
|
||||
|
||||
timerStarted = InterlockedCompareExchange(&FdoData->IdleTimerStarted, 1, 0);
|
||||
|
||||
if (!timerStarted) {
|
||||
|
||||
//
|
||||
// Reset the anti-starvation start time.
|
||||
//
|
||||
FdoData->AntiStarvationStartTime = ClasspGetCurrentTime();
|
||||
|
||||
//
|
||||
// convert milliseconds to a relative 100ns
|
||||
//
|
||||
mstotimer = (-10) * 1000;
|
||||
|
||||
//
|
||||
// multiply the period
|
||||
//
|
||||
dueTime.QuadPart = Int32x32To64(FdoData->IdleInterval, mstotimer);
|
||||
|
||||
KeSetTimerEx(&FdoData->IdleTimer,
|
||||
dueTime,
|
||||
FdoData->IdleInterval,
|
||||
&FdoData->IdleDpc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspStopIdleTimer
|
||||
|
||||
Routine Description:
|
||||
|
||||
Stop the idle timer if running. Also reset the timer counters.
|
||||
|
||||
Arguments:
|
||||
|
||||
FdoData - Pointer to the private fdo data
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
VOID
|
||||
ClasspStopIdleTimer(
|
||||
PCLASS_PRIVATE_FDO_DATA FdoData
|
||||
)
|
||||
{
|
||||
LONG timerStarted;
|
||||
|
||||
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspStopIdleTimer: Stop idle timer\n"));
|
||||
|
||||
timerStarted = InterlockedCompareExchange(&FdoData->IdleTimerStarted, 0, 1);
|
||||
|
||||
if (timerStarted) {
|
||||
(VOID)KeCancelTimer(&FdoData->IdleTimer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspGetIdleTime
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine returns how long it has been since the last non-idle request
|
||||
completed by checking the actual time.
|
||||
|
||||
Arguments:
|
||||
|
||||
FdoData - Pointer to the private fdo data
|
||||
|
||||
Return Value:
|
||||
|
||||
The idle interval in ms.
|
||||
|
||||
--*/
|
||||
ULONGLONG
|
||||
ClasspGetIdleTime (
|
||||
IN PCLASS_PRIVATE_FDO_DATA FdoData,
|
||||
IN LARGE_INTEGER CurrentTime
|
||||
)
|
||||
{
|
||||
ULONGLONG idleTime;
|
||||
NTSTATUS status;
|
||||
|
||||
//
|
||||
// Get the time difference between current time and last I/O
|
||||
// complete time.
|
||||
//
|
||||
|
||||
status = RtlULongLongSub((ULONGLONG)CurrentTime.QuadPart,
|
||||
(ULONGLONG)FdoData->LastNonIdleIoTime.QuadPart,
|
||||
&idleTime);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Convert the time to milliseconds.
|
||||
//
|
||||
idleTime = ClasspTimeDiffToMs(idleTime);
|
||||
} else {
|
||||
//
|
||||
// Failed to get time difference, assume enough time passed.
|
||||
//
|
||||
idleTime = FdoData->IdleInterval;
|
||||
}
|
||||
|
||||
return idleTime;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspIdleDurationSufficient
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine computes whether enough idle duration has elapsed since the
|
||||
completion of the last non-idle request.
|
||||
|
||||
Arguments:
|
||||
|
||||
FdoData - Pointer to the private fdo data
|
||||
|
||||
CurrentTimeIn - If CurrentTimeIn is non-NULL
|
||||
- contents are set to NULL if the time is not updated.
|
||||
- time is updated otherwise
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE if sufficient idle duration has elapsed to issue the next idle request.
|
||||
|
||||
--*/
|
||||
LOGICAL
|
||||
ClasspIdleDurationSufficient (
|
||||
IN PCLASS_PRIVATE_FDO_DATA FdoData,
|
||||
OUT LARGE_INTEGER** CurrentTimeIn
|
||||
)
|
||||
{
|
||||
ULONGLONG idleInterval;
|
||||
LARGE_INTEGER CurrentTime;
|
||||
|
||||
//
|
||||
// If there are any outstanding non-idle requests, then there has been no
|
||||
// idle time.
|
||||
//
|
||||
if (FdoData->ActiveIoCount > 0) {
|
||||
if (CurrentTimeIn != NULL) {
|
||||
*CurrentTimeIn = NULL;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Check whether an idle request should be issued now or on the next timer
|
||||
// expiration.
|
||||
//
|
||||
|
||||
CurrentTime = ClasspGetCurrentTime();
|
||||
idleInterval = ClasspGetIdleTime(FdoData, CurrentTime);
|
||||
|
||||
if (CurrentTimeIn != NULL) {
|
||||
**CurrentTimeIn = CurrentTime;
|
||||
}
|
||||
|
||||
if (idleInterval >= FdoData->IdleInterval) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspIdleTimerDpc
|
||||
|
||||
Routine Description:
|
||||
|
||||
Timer dpc function. This function will be called once every
|
||||
IdleInterval. An idle request will be queued if sufficient idle time
|
||||
has elapsed since the last non-idle request.
|
||||
|
||||
Arguments:
|
||||
|
||||
Dpc - Pointer to DPC object
|
||||
Context - Pointer to the fdo device extension
|
||||
SystemArgument1 - Not used
|
||||
SystemArgument2 - Not used
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
VOID
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
ClasspIdleTimerDpc(
|
||||
IN PKDPC Dpc,
|
||||
IN PVOID Context,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2
|
||||
)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Context;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData;
|
||||
ULONGLONG idleTime;
|
||||
NTSTATUS status;
|
||||
LARGE_INTEGER currentTime;
|
||||
LARGE_INTEGER* pCurrentTime;
|
||||
|
||||
UNREFERENCED_PARAMETER(Dpc);
|
||||
UNREFERENCED_PARAMETER(SystemArgument1);
|
||||
UNREFERENCED_PARAMETER(SystemArgument2);
|
||||
|
||||
if (fdoExtension == NULL) {
|
||||
NT_ASSERT(fdoExtension != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
fdoData = fdoExtension->PrivateFdoData;
|
||||
|
||||
if (fdoData->ActiveIoCount <= 0) {
|
||||
|
||||
//
|
||||
// If there are max active idle requests, do not issue another one here.
|
||||
//
|
||||
if (fdoData->ActiveIdleIoCount >= fdoData->IdleActiveIoMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Check whether enough idle time has passed since the last non-idle
|
||||
// request has completed.
|
||||
//
|
||||
|
||||
pCurrentTime = ¤tTime;
|
||||
if (ClasspIdleDurationSufficient(fdoData, &pCurrentTime)) {
|
||||
//
|
||||
// We are going to issue an idle request so reset the anti-starvation
|
||||
// timer counter.
|
||||
// If we are here (Idle duration is sufficient), pCurrentTime is
|
||||
// expected to be set.
|
||||
//
|
||||
NT_ASSERT(pCurrentTime != NULL);
|
||||
fdoData->AntiStarvationStartTime = *pCurrentTime;
|
||||
ClasspServiceIdleRequest(fdoExtension, FALSE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the time difference between current time and last I/O
|
||||
// complete time.
|
||||
//
|
||||
|
||||
currentTime = ClasspGetCurrentTime();
|
||||
status = RtlULongLongSub((ULONGLONG)currentTime.QuadPart,
|
||||
(ULONGLONG)fdoData->AntiStarvationStartTime.QuadPart,
|
||||
&idleTime);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
//
|
||||
// Convert the time to milliseconds.
|
||||
//
|
||||
idleTime = ClasspTimeDiffToMs(idleTime);
|
||||
} else {
|
||||
//
|
||||
// Failed to get time difference, assume enough time passed.
|
||||
//
|
||||
idleTime = fdoData->StarvationDuration;
|
||||
}
|
||||
|
||||
//
|
||||
// If the timer is running then there must be at least one idle priority I/O pending
|
||||
//
|
||||
if (idleTime >= fdoData->StarvationDuration) {
|
||||
fdoData->AntiStarvationStartTime = currentTime;
|
||||
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspIdleTimerDpc: Starvation timer. Send one idle request\n"));
|
||||
ClasspServiceIdleRequest(fdoExtension, FALSE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspEnqueueIdleRequest
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function will insert the idle request into the list.
|
||||
If the inserted reqeust is the first request then it will
|
||||
start the timer.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - Pointer to device object
|
||||
Irp - Pointer to the idle I/O request packet
|
||||
|
||||
Return Value:
|
||||
|
||||
NT status code.
|
||||
|
||||
--*/
|
||||
NTSTATUS
|
||||
ClasspEnqueueIdleRequest(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp
|
||||
)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
|
||||
KIRQL oldIrql;
|
||||
BOOLEAN issueRequest = TRUE;
|
||||
LARGE_INTEGER currentTime;
|
||||
LARGE_INTEGER* pCurrentTime;
|
||||
|
||||
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspEnqueueIdleRequest: Queue idle request %p\n", Irp));
|
||||
|
||||
IoMarkIrpPending(Irp);
|
||||
|
||||
//
|
||||
// Reset issueRequest if the idle duration is not sufficient.
|
||||
//
|
||||
pCurrentTime = ¤tTime;
|
||||
if (ClasspIdleDurationSufficient(fdoData, &pCurrentTime) == FALSE) {
|
||||
issueRequest = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// If there are already max active idle requests in the port driver, then
|
||||
// queue this idle request.
|
||||
//
|
||||
if (fdoData->ActiveIdleIoCount >= fdoData->IdleActiveIoMax) {
|
||||
issueRequest = FALSE;
|
||||
}
|
||||
|
||||
|
||||
KeAcquireSpinLock(&fdoData->IdleListLock, &oldIrql);
|
||||
if (IsListEmpty(&fdoData->IdleIrpList)) {
|
||||
NT_ASSERT(fdoData->IdleIoCount == 0);
|
||||
}
|
||||
InsertTailList(&fdoData->IdleIrpList, &Irp->Tail.Overlay.ListEntry);
|
||||
|
||||
|
||||
fdoData->IdleIoCount++;
|
||||
if (!fdoData->IdleTimerStarted) {
|
||||
ClasspStartIdleTimer(fdoData);
|
||||
}
|
||||
|
||||
if (fdoData->IdleIoCount != 1) {
|
||||
issueRequest = FALSE;
|
||||
}
|
||||
|
||||
|
||||
KeReleaseSpinLock(&fdoData->IdleListLock, oldIrql);
|
||||
|
||||
if (issueRequest) {
|
||||
ClasspServiceIdleRequest(fdoExtension, FALSE);
|
||||
}
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspDequeueIdleRequest
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function will remove the next idle request from the list.
|
||||
If there are no requests in the queue, then it will return NULL.
|
||||
|
||||
Arguments:
|
||||
|
||||
FdoExtension - Pointer to the functional device extension
|
||||
|
||||
Return Value:
|
||||
|
||||
Pointer to removed IRP
|
||||
|
||||
--*/
|
||||
PIRP
|
||||
ClasspDequeueIdleRequest(
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
)
|
||||
{
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
|
||||
PLIST_ENTRY listEntry = NULL;
|
||||
PIRP irp = NULL;
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&fdoData->IdleListLock, &oldIrql);
|
||||
|
||||
if (fdoData->IdleIoCount > 0) {
|
||||
listEntry = RemoveHeadList(&fdoData->IdleIrpList);
|
||||
//
|
||||
// Make sure we actaully removed a request from the list
|
||||
//
|
||||
NT_ASSERT(listEntry != &fdoData->IdleIrpList);
|
||||
//
|
||||
// Decrement the idle I/O count.
|
||||
//
|
||||
fdoData->IdleIoCount--;
|
||||
//
|
||||
// Stop the timer on last request
|
||||
//
|
||||
if (fdoData->IdleIoCount == 0) {
|
||||
ClasspStopIdleTimer(fdoData);
|
||||
}
|
||||
irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
|
||||
NT_ASSERT(irp->Type == IO_TYPE_IRP);
|
||||
|
||||
|
||||
InitializeListHead(&irp->Tail.Overlay.ListEntry);
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&fdoData->IdleListLock, oldIrql);
|
||||
|
||||
|
||||
return irp;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspCompleteIdleRequest
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function will be called every time an idle request is completed.
|
||||
This will call ClasspServiceIdleRequest to process any other pending idle requests.
|
||||
|
||||
Arguments:
|
||||
|
||||
FdoExtension - Pointer to the device extension
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
VOID
|
||||
ClasspCompleteIdleRequest(
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
)
|
||||
{
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
|
||||
|
||||
//
|
||||
// Issue the next idle request if there are any left in the queue, there are
|
||||
// no non-idle requests outstanding, there are less than max idle requests
|
||||
// outstanding, and it has been long enough since the completion of the last
|
||||
// non-idle request.
|
||||
//
|
||||
if ((fdoData->IdleIoCount > 0) &&
|
||||
(fdoData->ActiveIdleIoCount < fdoData->IdleActiveIoMax) &&
|
||||
(fdoData->ActiveIoCount <= 0) &&
|
||||
(ClasspIdleDurationSufficient(fdoData, NULL))) {
|
||||
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspCompleteIdleRequest: Service next idle reqeusts\n"));
|
||||
ClasspServiceIdleRequest(FdoExtension, TRUE);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
ClasspServiceIdleRequest
|
||||
|
||||
Routine Description:
|
||||
|
||||
Remove the next pending idle request from the queue and process it.
|
||||
If a request was removed then it will be processed otherwise it will
|
||||
just return.
|
||||
|
||||
Arguments:
|
||||
|
||||
FdoExtension - Pointer to the device extension
|
||||
PostToDpc - Flag to pass to ServiceTransferRequest to indicate if request must be posted to a DPC
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
VOID
|
||||
ClasspServiceIdleRequest(
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
BOOLEAN PostToDpc
|
||||
)
|
||||
{
|
||||
PIRP irp;
|
||||
|
||||
irp = ClasspDequeueIdleRequest(FdoExtension);
|
||||
if (irp != NULL) {
|
||||
ServiceTransferRequest(FdoExtension->DeviceObject, irp, PostToDpc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
1022
drivers/storage/class/classpnp/create.c
Normal file
1022
drivers/storage/class/classpnp/create.c
Normal file
File diff suppressed because it is too large
Load diff
222
drivers/storage/class/classpnp/data.c
Normal file
222
drivers/storage/class/classpnp/data.c
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 2010
|
||||
|
||||
Module Name:
|
||||
|
||||
disk.c
|
||||
|
||||
Abstract:
|
||||
|
||||
SCSI disk class driver
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
|
||||
|
||||
/*
|
||||
* Entry in static list used by debug extension to quickly find all class FDOs.
|
||||
*/
|
||||
LIST_ENTRY AllFdosList = {&AllFdosList, &AllFdosList};
|
||||
|
||||
#ifdef ALLOC_DATA_PRAGMA
|
||||
#pragma data_seg("PAGEDATA")
|
||||
#endif
|
||||
|
||||
/*
|
||||
#define FDO_HACK_CANNOT_LOCK_MEDIA (0x00000001)
|
||||
#define FDO_HACK_GESN_IS_BAD (0x00000002)
|
||||
#define FDO_HACK_NO_SYNC_CACHE (0x00000004)
|
||||
#define FDO_HACK_NO_RESERVE6 (0x00000008)
|
||||
#define FDO_HACK_GESN_IGNORE_OPCHANGE (0x00000010)
|
||||
*/
|
||||
|
||||
CLASSPNP_SCAN_FOR_SPECIAL_INFO ClassBadItems[] = { // Type (HH, slim) + WHQL Date, if known
|
||||
{ "" , "MITSUMI CD-ROM FX240" , NULL , 0x02 },
|
||||
{ "" , "MITSUMI CD-ROM FX320" , NULL , 0x02 },
|
||||
{ "" , "MITSUMI CD-ROM FX322" , NULL , 0x02 },
|
||||
{ "" , "TEAC DV-28E-A" , "2.0A", 0x02 },
|
||||
{ "" , "HP CD-Writer cd16h" , "Q000", 0x02 },
|
||||
{ "" , "_NEC NR-7800A" , "1.33", 0x02 },
|
||||
{ "" , "COMPAQ CRD-8481B" , NULL , 0x04 },
|
||||
// The following is a list of device that report too many OpChange/Add events.
|
||||
// They require ignoring (or not sending) the OpChange flag in the GESN command.
|
||||
// This list contains vendor ID and product ID as separate strings for USB/1394 interface.
|
||||
{ "HL-DT-ST", "DVDRAM GMA-4020B" , NULL , 0x10 }, // hh , 2002/04/22
|
||||
{ "HL-DT-ST", "DVD-RW GCA-4020B" , NULL , 0x10 }, // hh , 2002/05/14
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4040B" , NULL , 0x10 }, // hh , 2003/05/06
|
||||
{ "HL-DT-ST", "DVDRAM GMA-4040B" , NULL , 0x10 }, // hh , 2003/07/27
|
||||
{ "HL-DT-ST", "DVD-RW GWA-4040B" , NULL , 0x10 }, // hh , 2003/11/18
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4081B" , NULL , 0x10 }, // hh , 2003/11/06
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4082B" , NULL , 0x10 }, // hh , 2004/01/27
|
||||
{ "HL-DT-ST", "DVD-RW GWA-4082B" , NULL , 0x10 }, // hh , 2004/03/11
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4120B" , NULL , 0x10 }, // hh , 2004/05/16
|
||||
{ "HL-DT-ST", "DVD+RW GRA-4120B" , NULL , 0x10 }, // hh , 2004/04/28
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4160B" , NULL , 0x10 }, // hh , 2004/08/12
|
||||
{ "HL-DT-ST", "DVD-RW GWA-4160B" , NULL , 0x10 }, // hh , 2004/08/24
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4163B" , NULL , 0x10 }, // hh , 2004/11/09
|
||||
{ "HL-DT-ST", "DVD-RW GWA-4163B" , NULL , 0x10 }, // hh , 2004/12/29
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4165B" , NULL , 0x10 }, // hh , 2005/06/09
|
||||
{ "HL-DT-ST", "DVDRAM_GSA-4165B" , NULL , 0x10 }, // hh , 2005/06/28
|
||||
{ "HL-DT-ST", "DVD-RW GWA-4165B" , NULL , 0x10 }, // hh , 2005/08/23
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4167B" , NULL , 0x10 }, // hh , 2005/07/01
|
||||
{ "HL-DT-ST", "DVDRAM GSA-H10N" , NULL , 0x10 }, // hh , 2006/02/16
|
||||
{ "HL-DT-ST", "DVDRAM_GSA-H10N" , NULL , 0x10 }, // hh , 2006/02/16
|
||||
{ "HL-DT-ST", "DVDRAM GSA-H10L" , NULL , 0x10 }, // hh , 2006/02/27
|
||||
{ "HL-DT-ST", "DVDRAM_GSA-H10L" , NULL , 0x10 }, // hh , 2006/04/21
|
||||
{ "HL-DT-ST", "DVDRAM GSA-H10A" , NULL , 0x10 }, // hh , 2006/01/03
|
||||
{ "HL-DT-ST", "DVDRAM_GSA-H10A" , NULL , 0x10 }, // hh , 2006/05/14
|
||||
{ "HL-DT-ST", "DVD-RW GSA-H11N" , NULL , 0x10 }, // hh , 2006/04/28
|
||||
{ "HL-DT-ST", "DVD-RW_GSA-H11N" , NULL , 0x10 }, // hh , 2006/02/22
|
||||
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4080N" , NULL , 0x10 }, // slim, 2004/08/08
|
||||
{ "HL-DT-ST", "DVDRAM GMA-4080N" , NULL , 0x10 }, // slim, 2004/11/09
|
||||
{ "HL-DT-ST", "DVD-RW GCA-4080N" , NULL , 0x10 }, // slim, 2004/11/22
|
||||
{ "HL-DT-ST", "DVD-RW GWA-4080N" , NULL , 0x10 }, // slim, 2004/08/17
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4082N" , NULL , 0x10 }, // slim, 2005/07/12
|
||||
{ "HL-DT-ST", "DVDRAM_GSA-4082N" , NULL , 0x10 }, // slim, 2005/09/21
|
||||
{ "HL-DT-ST", "DVDRAM GMA-4082N" , NULL , 0x10 }, // slim, 2005/10/20
|
||||
{ "HL-DT-ST", "DVD-RW GRA-4082N" , NULL , 0x10 }, // slim, 2006/06/07
|
||||
{ "HL-DT-ST", "DVD-RW GWA-4082N" , NULL , 0x10 }, // slim, 2005/05/24
|
||||
{ "HL-DT-ST", "DVDRAM GMA4082Nf" , NULL , 0x10 }, // slim, 2006/02/28
|
||||
{ "HL-DT-ST", "DVDRAM GMA4082Nj" , NULL , 0x10 }, // slim, 2006/01/26
|
||||
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4084N" , NULL , 0x10 }, // slim, 2005/12/21
|
||||
{ "HL-DT-ST", "DVDRAM GMA-4084N" , NULL , 0x10 }, // slim, 2006/02/15
|
||||
{ "HP" , "DVD Writer 550s" , NULL , 0x10 }, // slim, 2006/05/08
|
||||
{ "HL-DT-ST", "DVDRAM GSA-T10N" , NULL , 0x10 }, // slim, 2006/07/26
|
||||
{ "HL-DT-ST", "DVDRAM_GSA-T10N" , NULL , 0x10 }, // slim, 2006/07/26
|
||||
{ "HL-DT-ST", "DVD+-RW GSA-T11N" , NULL , 0x10 }, // slim, 2006/07/25
|
||||
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8160B" , NULL , 0x10 }, // hh , 2001/10/12
|
||||
{ "COMPAQ" , "DVD-ROM GDR8160B" , NULL , 0x10 }, // hh , 2001/11/08
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8161B" , NULL , 0x10 }, // hh , 2002/07/19
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8162B" , NULL , 0x10 }, // hh , 2003/04/22
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8163B" , NULL , 0x10 }, // hh , 2004/05/19
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8164B" , NULL , 0x10 }, // hh , 2005/06/29
|
||||
{ "HL-DT-ST", "DVD-ROM GDRH10N" , NULL , 0x10 }, // hh , 2006/03/07
|
||||
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8081N" , NULL , 0x10 }, // slim, 2001/08/27
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8082N" , NULL , 0x10 }, // slim, 2003/02/02
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8083N" , NULL , 0x10 }, // slim, 2003/02/02
|
||||
{ "HL-DT-ST", "DVD-ROM GDR8085N" , NULL , 0x10 }, // slim, 2005/11/10
|
||||
|
||||
{ "HL-DT-ST", "RW/DVD GCC-4080N" , NULL , 0x10 }, // slim, 2001/08/21
|
||||
{ "HL-DT-ST", "RW/DVD_GCC-4080N" , NULL , 0x10 }, // slim,
|
||||
{ "HL-DT-ST", "RW/DVD GCC-4160N" , NULL , 0x10 }, // slim, 2002/04/08
|
||||
{ "HL-DT-ST", "RW/DVD GCC-4240N" , NULL , 0x10 }, // slim, 2002/04/26
|
||||
{ "HL-DT-ST", "RW/DVD GCC-4241N" , NULL , 0x10 }, // slim, 2003/04/07
|
||||
{ "HL-DT-ST", "RW/DVD_GCC-4241N" , NULL , 0x10 }, // slim, 2004/03/07
|
||||
{ "HL-DT-ST", "RW/DVD GCC-4242N" , NULL , 0x10 }, // slim, 2003/12/21
|
||||
{ "HL-DT-ST", "RW/DVD GCC-4246N" , NULL , 0x10 }, // slim, 2005/05/23
|
||||
{ "HL-DT-ST", "BD-RE GBW-H10N" , NULL , 0x10 }, // hh , 2006/06/27
|
||||
|
||||
{ "HL-DT-ST", "DVDRAM GSA-4083N" , NULL , 0x10 }, // hh , 2006/05/17
|
||||
{ "HL-DT-ST", "DVD+-RW GWA4083N" , NULL , 0x10 }, // hh , 2006/06/05
|
||||
|
||||
{ "PIONEER", "DVD-RW DVR-106D" , NULL , 0x10 }, // hh , ?
|
||||
{ "ASUS", "DVD-RW DRW-0402P" , NULL , 0x10 }, // hh , ?
|
||||
|
||||
//
|
||||
// This list contains vendor ID and product ID as a single string for ATAPI interface.
|
||||
//
|
||||
|
||||
{ "", "HL-DT-ST DVDRAM GMA-4020B" , NULL , 0x10 }, // hh , 2002/04/22
|
||||
{ "", "HL-DT-ST DVD-RW GCA-4020B" , NULL , 0x10 }, // hh , 2002/05/14
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4040B" , NULL , 0x10 }, // hh , 2003/05/06
|
||||
{ "", "HL-DT-ST DVDRAM GMA-4040B" , NULL , 0x10 }, // hh , 2003/07/27
|
||||
{ "", "HL-DT-ST DVD-RW GWA-4040B" , NULL , 0x10 }, // hh , 2003/11/18
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4081B" , NULL , 0x10 }, // hh , 2003/11/06
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4082B" , NULL , 0x10 }, // hh , 2004/01/27
|
||||
{ "", "HL-DT-ST DVD-RW GWA-4082B" , NULL , 0x10 }, // hh , 2004/03/11
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4120B" , NULL , 0x10 }, // hh , 2004/05/16
|
||||
{ "", "HL-DT-ST DVD+RW GRA-4120B" , NULL , 0x10 }, // hh , 2004/04/28
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4160B" , NULL , 0x10 }, // hh , 2004/08/12
|
||||
{ "", "HL-DT-ST DVD-RW GWA-4160B" , NULL , 0x10 }, // hh , 2004/08/24
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4163B" , NULL , 0x10 }, // hh , 2004/11/09
|
||||
{ "", "HL-DT-ST DVD-RW GWA-4163B" , NULL , 0x10 }, // hh , 2004/12/29
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4165B" , NULL , 0x10 }, // hh , 2005/06/09
|
||||
{ "", "HL-DT-ST DVDRAM_GSA-4165B" , NULL , 0x10 }, // hh , 2005/06/28
|
||||
{ "", "HL-DT-ST DVD-RW GWA-4165B" , NULL , 0x10 }, // hh , 2005/08/23
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4167B" , NULL , 0x10 }, // hh , 2005/07/01
|
||||
{ "", "HL-DT-ST DVDRAM GSA-H10N" , NULL , 0x10 }, // hh , 2006/02/16
|
||||
{ "", "HL-DT-ST DVDRAM_GSA-H10N" , NULL , 0x10 }, // hh , 2006/02/16
|
||||
{ "", "HL-DT-ST DVDRAM GSA-H10L" , NULL , 0x10 }, // hh , 2006/02/27
|
||||
{ "", "HL-DT-ST DVDRAM_GSA-H10L" , NULL , 0x10 }, // hh , 2006/04/21
|
||||
{ "", "HL-DT-ST DVDRAM GSA-H10A" , NULL , 0x10 }, // hh , 2006/01/03
|
||||
{ "", "HL-DT-ST DVDRAM_GSA-H10A" , NULL , 0x10 }, // hh , 2006/05/14
|
||||
{ "", "HL-DT-ST DVD-RW GSA-H11N" , NULL , 0x10 }, // hh , 2006/04/28
|
||||
{ "", "HL-DT-ST DVD-RW_GSA-H11N" , NULL , 0x10 }, // hh , 2006/02/22
|
||||
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4080N" , NULL , 0x10 }, // slim, 2004/08/08
|
||||
{ "", "HL-DT-ST DVDRAM GMA-4080N" , NULL , 0x10 }, // slim, 2004/11/09
|
||||
{ "", "HL-DT-ST DVD-RW GCA-4080N" , NULL , 0x10 }, // slim, 2004/11/22
|
||||
{ "", "HL-DT-ST DVD-RW GWA-4080N" , NULL , 0x10 }, // slim, 2004/08/17
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4082N" , NULL , 0x10 }, // slim, 2005/07/12
|
||||
{ "", "HL-DT-ST DVDRAM_GSA-4082N" , NULL , 0x10 }, // slim, 2005/09/21
|
||||
{ "", "HL-DT-ST DVDRAM GMA-4082N" , NULL , 0x10 }, // slim, 2005/10/20
|
||||
{ "", "HL-DT-ST DVD-RW GRA-4082N" , NULL , 0x10 }, // slim, 2006/06/07
|
||||
{ "", "HL-DT-ST DVD-RW GWA-4082N" , NULL , 0x10 }, // slim, 2005/05/24
|
||||
{ "", "HL-DT-ST DVDRAM GMA4082Nf" , NULL , 0x10 }, // slim, 2006/02/28
|
||||
{ "", "HL-DT-ST DVDRAM GMA4082Nj" , NULL , 0x10 }, // slim, 2006/01/26
|
||||
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4084N" , NULL , 0x10 }, // slim, 2005/12/21
|
||||
{ "", "HL-DT-ST DVDRAM GMA-4084N" , NULL , 0x10 }, // slim, 2006/02/15
|
||||
{ "", "HP DVD Writer 550s" , NULL , 0x10 }, // slim, 2006/05/08
|
||||
{ "", "HL-DT-ST DVDRAM GSA-T10N" , NULL , 0x10 }, // slim, 2006/07/26
|
||||
{ "", "HL-DT-ST DVDRAM_GSA-T10N" , NULL , 0x10 }, // slim, 2006/07/26
|
||||
{ "", "HL-DT-ST DVD+-RW GSA-T11N" , NULL , 0x10 }, // slim, 2006/07/25
|
||||
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8160B" , NULL , 0x10 }, // hh , 2001/10/12
|
||||
{ "", "COMPAQ DVD-ROM GDR8160B" , NULL , 0x10 }, // hh , 2001/11/08
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8161B" , NULL , 0x10 }, // hh , 2002/07/19
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8162B" , NULL , 0x10 }, // hh , 2003/04/22
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8163B" , NULL , 0x10 }, // hh , 2004/05/19
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8164B" , NULL , 0x10 }, // hh , 2005/06/29
|
||||
{ "", "HL-DT-ST DVD-ROM GDRH10N" , NULL , 0x10 }, // hh , 2006/03/07
|
||||
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8081N" , NULL , 0x10 }, // slim, 2001/08/27
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8082N" , NULL , 0x10 }, // slim, 2003/02/02
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8083N" , NULL , 0x10 }, // slim, 2003/02/02
|
||||
{ "", "HL-DT-ST DVD-ROM GDR8085N" , NULL , 0x10 }, // slim, 2005/11/10
|
||||
|
||||
{ "", "HL-DT-ST RW/DVD GCC-4080N" , NULL , 0x10 }, // slim, 2001/08/21
|
||||
{ "", "HL-DT-ST RW/DVD_GCC-4080N" , NULL , 0x10 }, // slim,
|
||||
{ "", "HL-DT-ST RW/DVD GCC-4160N" , NULL , 0x10 }, // slim, 2002/04/08
|
||||
{ "", "HL-DT-ST RW/DVD GCC-4240N" , NULL , 0x10 }, // slim, 2002/04/26
|
||||
{ "", "HL-DT-ST RW/DVD GCC-4241N" , NULL , 0x10 }, // slim, 2003/04/07
|
||||
{ "", "HL-DT-ST RW/DVD_GCC-4241N" , NULL , 0x10 }, // slim, 2004/03/07
|
||||
{ "", "HL-DT-ST RW/DVD GCC-4242N" , NULL , 0x10 }, // slim, 2003/12/21
|
||||
{ "", "HL-DT-ST RW/DVD GCC-4246N" , NULL , 0x10 }, // slim, 2005/05/23
|
||||
{ "", "HL-DT-ST BD-RE GBW-H10N" , NULL , 0x10 }, // hh , 2006/06/27
|
||||
|
||||
{ "", "HL-DT-ST DVDRAM GSA-4083N" , NULL , 0x10 }, // hh , 2006/05/17
|
||||
{ "", "HL-DT-ST DVD+-RW GWA4083N" , NULL , 0x10 }, // hh , 2006/06/05
|
||||
|
||||
{ "", "PIONEER DVD-RW DVR-106D" , NULL , 0x10 }, // hh , ?
|
||||
{ "", "ASUS DVD-RW DRW-0402P" , NULL , 0x10 }, // hh , ?
|
||||
|
||||
|
||||
// Sony sourced some drives from LG also....
|
||||
|
||||
{ NULL , NULL , NULL , 0x00 },
|
||||
};
|
||||
|
||||
|
||||
GUID ClassGuidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX;
|
||||
GUID ClassGuidSenseInfo2 = GUID_CLASSPNP_SENSEINFO2;
|
||||
GUID ClassGuidWorkingSet = GUID_CLASSPNP_WORKING_SET;
|
||||
GUID ClassGuidSrbSupport = GUID_CLASSPNP_SRB_SUPPORT;
|
||||
|
||||
#ifdef ALLOC_DATA_PRAGMA
|
||||
#pragma data_seg()
|
||||
#endif
|
972
drivers/storage/class/classpnp/debug.c
Normal file
972
drivers/storage/class/classpnp/debug.c
Normal file
|
@ -0,0 +1,972 @@
|
|||
/*++
|
||||
|
||||
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.
|
||||
|
||||
--*/
|
||||
__inline 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;
|
||||
}
|
||||
|
||||
|
132
drivers/storage/class/classpnp/debug.h
Normal file
132
drivers/storage/class/classpnp/debug.h
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
debug.h
|
||||
|
||||
Abstract:
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#define DBGGETIOCTLSTR(_ioctl) DbgGetIoctlStr(_ioctl)
|
||||
#define DBGGETSCSIOPSTR(_pSrb) DbgGetScsiOpStr(_pSrb)
|
||||
#define DBGGETSRBSTATUSSTR(_pSrb) DbgGetSrbStatusStr(_pSrb)
|
||||
#define DBGGETSENSECODESTR(_pSrb) DbgGetSenseCodeStr(_pSrb)
|
||||
#define DBGGETADSENSECODESTR(_pSrb) DbgGetAdditionalSenseCodeStr(_pSrb)
|
||||
#define DBGGETADSENSEQUALIFIERSTR(_pSrb) DbgGetAdditionalSenseCodeQualifierStr(_pSrb)
|
||||
|
||||
char *DbgGetIoctlStr(ULONG ioctl);
|
||||
char *DbgGetScsiOpStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb);
|
||||
char *DbgGetSrbStatusStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb);
|
||||
char *DbgGetSenseCodeStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb);
|
||||
char *DbgGetAdditionalSenseCodeStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb);
|
||||
char *DbgGetAdditionalSenseCodeQualifierStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb);
|
||||
|
||||
#if DBG
|
||||
|
||||
typedef struct _CLASSPNP_GLOBALS {
|
||||
|
||||
//
|
||||
// whether or not to NT_ASSERT for lost irps
|
||||
//
|
||||
|
||||
ULONG BreakOnLostIrps;
|
||||
ULONG SecondsToWaitForIrps;
|
||||
|
||||
//
|
||||
// use a buffered debug print to help
|
||||
// catch timing issues that do not
|
||||
// reproduce with std debugprints enabled
|
||||
//
|
||||
|
||||
ULONG UseBufferedDebugPrint;
|
||||
ULONG UseDelayedRetry;
|
||||
|
||||
//
|
||||
// the next four are the buffered printing support
|
||||
// (currently unimplemented) and require the spinlock
|
||||
// to use
|
||||
//
|
||||
|
||||
ULONG Index; // index into buffer
|
||||
KSPIN_LOCK SpinLock;
|
||||
PUCHAR Buffer; // requires spinlock to access
|
||||
ULONG NumberOfBuffers; // number of buffers available
|
||||
SIZE_T EachBufferSize; // size of each buffer
|
||||
|
||||
//
|
||||
// interlocked variables to initialize
|
||||
// this data only once
|
||||
//
|
||||
|
||||
LONG Initializing;
|
||||
LONG Initialized;
|
||||
|
||||
} CLASSPNP_GLOBALS, *PCLASSPNP_GLOBALS;
|
||||
|
||||
|
||||
//
|
||||
// Define a structure used to capture stack traces when we
|
||||
// get an access request and the disks are powered off. This
|
||||
// will help us determine who's causing disk respins.
|
||||
//
|
||||
|
||||
//
|
||||
// How many stack frames to capture each time?
|
||||
//
|
||||
#define DISK_SPINUP_BACKTRACE_LENGTH (0x18)
|
||||
|
||||
//
|
||||
// How many stack traces can we capture before
|
||||
// out buffer wraps? (needs to be power of 2)
|
||||
//
|
||||
#define NUMBER_OF_DISK_SPINUP_TRACES (0x10)
|
||||
|
||||
typedef struct _DISK_SPINUP_TRACES {
|
||||
|
||||
LARGE_INTEGER TimeStamp; // timestamp of the spinup event.
|
||||
PVOID StackTrace[DISK_SPINUP_BACKTRACE_LENGTH]; // Holds stack trace
|
||||
} DISK_SPINUP_TRACES, *PDISK_SPINUP_TRACES;
|
||||
|
||||
|
||||
#define DBGCHECKRETURNEDPKT(_pkt) DbgCheckReturnedPkt(_pkt)
|
||||
#define DBGLOGSENDPACKET(_pkt) DbgLogSendPacket(_pkt)
|
||||
#define DBGLOGRETURNPACKET(_pkt) DbgLogReturnPacket(_pkt)
|
||||
#define DBGLOGFLUSHINFO(_fdoData, _isIO, _isFUA, _isFlush) DbgLogFlushInfo(_fdoData, _isIO, _isFUA, _isFlush)
|
||||
|
||||
VOID ClasspInitializeDebugGlobals();
|
||||
VOID DbgCheckReturnedPkt(TRANSFER_PACKET *Pkt);
|
||||
VOID DbgLogSendPacket(TRANSFER_PACKET *Pkt);
|
||||
VOID DbgLogReturnPacket(TRANSFER_PACKET *Pkt);
|
||||
VOID DbgLogFlushInfo(PCLASS_PRIVATE_FDO_DATA FdoData, BOOLEAN IsIO, BOOLEAN IsFUA, BOOLEAN IsFlush);
|
||||
VOID SnapDiskStartup(VOID);
|
||||
extern CLASSPNP_GLOBALS ClasspnpGlobals;
|
||||
extern LONG ClassDebug;
|
||||
extern BOOLEAN DebugTrapOnWarn;
|
||||
|
||||
#else
|
||||
|
||||
#define ClasspInitializeDebugGlobals()
|
||||
#define SnapDiskStartup()
|
||||
|
||||
#define DBGCHECKRETURNEDPKT(_pkt)
|
||||
#define DBGLOGSENDPACKET(_pkt)
|
||||
#define DBGLOGRETURNPACKET(_pkt)
|
||||
#define DBGLOGFLUSHINFO(_fdoData, _isIO, _isFUA, _isFlush)
|
||||
|
||||
#endif
|
||||
|
231
drivers/storage/class/classpnp/dictlib.c
Normal file
231
drivers/storage/class/classpnp/dictlib.c
Normal file
|
@ -0,0 +1,231 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1990 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
dictlib.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Support library for maintaining a dictionary list (list of objects
|
||||
referenced by a key value).
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
This module generates a static library
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <classpnp.h>
|
||||
|
||||
#ifdef __REACTOS__
|
||||
#undef MdlMappingNoExecute
|
||||
#define MdlMappingNoExecute 0
|
||||
#define NonPagedPoolNx NonPagedPool
|
||||
#define NonPagedPoolNxCacheAligned NonPagedPoolCacheAligned
|
||||
#undef POOL_NX_ALLOCATION
|
||||
#define POOL_NX_ALLOCATION 0
|
||||
#endif
|
||||
|
||||
#define DICTIONARY_SIGNATURE 'tciD'
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union
|
||||
#endif
|
||||
struct _DICTIONARY_HEADER {
|
||||
PDICTIONARY_HEADER Next;
|
||||
ULONGLONG Key;
|
||||
UCHAR Data[0];
|
||||
};
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
struct _DICTIONARY_HEADER;
|
||||
typedef struct _DICTIONARY_HEADER DICTIONARY_HEADER, *PDICTIONARY_HEADER;
|
||||
|
||||
|
||||
VOID
|
||||
InitializeDictionary(
|
||||
IN PDICTIONARY Dictionary
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(Dictionary, sizeof(DICTIONARY));
|
||||
Dictionary->Signature = DICTIONARY_SIGNATURE;
|
||||
KeInitializeSpinLock(&Dictionary->SpinLock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
TestDictionarySignature(
|
||||
IN PDICTIONARY Dictionary
|
||||
)
|
||||
{
|
||||
return Dictionary->Signature == DICTIONARY_SIGNATURE;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
AllocateDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN ULONGLONG Key,
|
||||
_In_range_(0, sizeof(FILE_OBJECT_EXTENSION)) IN ULONG Size,
|
||||
IN ULONG Tag,
|
||||
OUT PVOID *Entry
|
||||
)
|
||||
{
|
||||
PDICTIONARY_HEADER header;
|
||||
KIRQL oldIrql;
|
||||
PDICTIONARY_HEADER *entry;
|
||||
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
*Entry = NULL;
|
||||
|
||||
header = ExAllocatePoolWithTag(NonPagedPoolNx,
|
||||
Size + sizeof(DICTIONARY_HEADER),
|
||||
Tag);
|
||||
|
||||
if(header == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlZeroMemory(header, sizeof(DICTIONARY_HEADER) + Size);
|
||||
header->Key = Key;
|
||||
|
||||
//
|
||||
// Find the correct location for this entry in the dictionary.
|
||||
//
|
||||
|
||||
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
|
||||
|
||||
TRY {
|
||||
|
||||
entry = &(Dictionary->List);
|
||||
|
||||
while(*entry != NULL) {
|
||||
if((*entry)->Key == Key) {
|
||||
|
||||
//
|
||||
// Dictionary must have unique keys.
|
||||
//
|
||||
|
||||
status = STATUS_OBJECT_NAME_COLLISION;
|
||||
LEAVE;
|
||||
|
||||
} else if ((*entry)->Key < Key) {
|
||||
|
||||
//
|
||||
// We will go ahead and insert the key in here.
|
||||
//
|
||||
break;
|
||||
} else {
|
||||
entry = &((*entry)->Next);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If we make it here then we will go ahead and do the insertion.
|
||||
//
|
||||
|
||||
header->Next = *entry;
|
||||
*entry = header;
|
||||
|
||||
} FINALLY {
|
||||
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
|
||||
|
||||
if(!NT_SUCCESS(status)) {
|
||||
FREE_POOL(header);
|
||||
} else {
|
||||
*Entry = (PVOID) header->Data;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
PVOID
|
||||
GetDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN ULONGLONG Key
|
||||
)
|
||||
{
|
||||
PDICTIONARY_HEADER entry;
|
||||
PVOID data;
|
||||
KIRQL oldIrql;
|
||||
|
||||
|
||||
data = NULL;
|
||||
|
||||
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
|
||||
|
||||
entry = Dictionary->List;
|
||||
while (entry != NULL) {
|
||||
|
||||
if (entry->Key == Key) {
|
||||
data = entry->Data;
|
||||
break;
|
||||
} else {
|
||||
entry = entry->Next;
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FreeDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN PVOID Entry
|
||||
)
|
||||
{
|
||||
PDICTIONARY_HEADER header;
|
||||
PDICTIONARY_HEADER *entry;
|
||||
KIRQL oldIrql;
|
||||
BOOLEAN found;
|
||||
|
||||
found = FALSE;
|
||||
header = CONTAINING_RECORD(Entry, DICTIONARY_HEADER, Data);
|
||||
|
||||
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
|
||||
|
||||
entry = &(Dictionary->List);
|
||||
while(*entry != NULL) {
|
||||
|
||||
if(*entry == header) {
|
||||
*entry = header->Next;
|
||||
found = TRUE;
|
||||
break;
|
||||
} else {
|
||||
entry = &(*entry)->Next;
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
|
||||
|
||||
//
|
||||
// calling this w/an invalid pointer invalidates the dictionary system,
|
||||
// so NT_ASSERT() that we never try to Free something not in the list
|
||||
//
|
||||
|
||||
NT_ASSERT(found);
|
||||
if (found) {
|
||||
FREE_POOL(header);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
133
drivers/storage/class/classpnp/dispatch.c
Normal file
133
drivers/storage/class/classpnp/dispatch.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 2005
|
||||
|
||||
Module Name:
|
||||
|
||||
dispatch.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Code to support multiple dispatch tables.
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, ClassInitializeDispatchTables)
|
||||
#endif
|
||||
|
||||
DRIVER_DISPATCH ClassDispatchUnimplemented;
|
||||
|
||||
//
|
||||
// Routines start
|
||||
//
|
||||
|
||||
|
||||
VOID
|
||||
ClassInitializeDispatchTables(
|
||||
PCLASS_DRIVER_EXTENSION DriverExtension
|
||||
)
|
||||
{
|
||||
ULONG idx;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Initialize the standard device dispatch table
|
||||
//
|
||||
|
||||
for (idx = 0; idx <= IRP_MJ_MAXIMUM_FUNCTION; idx++) {
|
||||
DriverExtension->DeviceMajorFunctionTable[idx] = ClassDispatchUnimplemented;
|
||||
}
|
||||
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_CREATE] = ClassCreateClose;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_CLOSE] = ClassCreateClose;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_READ] = ClassReadWrite;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_WRITE] = ClassReadWrite;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControlDispatch;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_SCSI] = ClassInternalIoControl;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_SHUTDOWN] = ClassShutdownFlush;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_FLUSH_BUFFERS] = ClassShutdownFlush;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_PNP] = ClassDispatchPnp;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_POWER] = ClassDispatchPower;
|
||||
DriverExtension->DeviceMajorFunctionTable[IRP_MJ_SYSTEM_CONTROL] = ClassSystemControl;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
ClassGlobalDispatch(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
// Code Analysis cannot analyze the code paths specific to clients.
|
||||
_Analysis_assume_(FALSE);
|
||||
return (commonExtension->DispatchTable[irpStack->MajorFunction])(DeviceObject, Irp);
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
ClassDispatchUnimplemented(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This function is the default dispatch routine. Its
|
||||
responsibility is simply to set the status in the packet to indicate
|
||||
that the operation requested is invalid for this device type, and then
|
||||
complete the packet.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - Specifies the device object for which this request is
|
||||
bound. Ignored by this routine.
|
||||
|
||||
Irp - Specifies the address of the I/O Request Packet (IRP) for this
|
||||
request.
|
||||
|
||||
Return Value:
|
||||
|
||||
The final status is always STATUS_INVALID_DEVICE_REQUEST.
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
UNREFERENCED_PARAMETER( DeviceObject );
|
||||
|
||||
//
|
||||
// Simply store the appropriate status, complete the request, and return
|
||||
// the same status stored in the packet.
|
||||
//
|
||||
|
||||
if ((IoGetCurrentIrpStackLocation(Irp))->MajorFunction == IRP_MJ_POWER) {
|
||||
PoStartNextPowerIrp(Irp);
|
||||
}
|
||||
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
|
8
drivers/storage/class/classpnp/guid.c
Normal file
8
drivers/storage/class/classpnp/guid.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
|
||||
|
||||
#include <ntdef.h>
|
||||
#include <initguid.h>
|
||||
#include <ioevent.h>
|
||||
#include <ntifs.h>
|
||||
|
||||
/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */
|
146
drivers/storage/class/classpnp/history.c
Normal file
146
drivers/storage/class/classpnp/history.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*++
|
||||
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
history.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Packet history routines for CLASSPNP
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef DEBUG_USE_WPP
|
||||
#include "history.tmh"
|
||||
#endif
|
||||
|
||||
//#ifdef ALLOC_PRAGMA
|
||||
// #pragma alloc_text(PAGE, InitializeTransferPackets)
|
||||
//#endif
|
||||
|
||||
VOID HistoryInitializeRetryLogs(_Out_ PSRB_HISTORY History, ULONG HistoryCount) {
|
||||
ULONG tmpSize = HistoryCount * sizeof(SRB_HISTORY_ITEM);
|
||||
tmpSize += sizeof(SRB_HISTORY) - sizeof(SRB_HISTORY_ITEM);
|
||||
RtlZeroMemory(History, tmpSize);
|
||||
History->TotalHistoryCount = HistoryCount;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID HistoryLogSendPacket(TRANSFER_PACKET * Pkt) {
|
||||
|
||||
PSRB_HISTORY history;
|
||||
PSRB_HISTORY_ITEM item;
|
||||
|
||||
NT_ASSERT( Pkt->RetryHistory != NULL );
|
||||
history = Pkt->RetryHistory;
|
||||
// sending a packet implies a new history unit is to be used.
|
||||
NT_ASSERT( history->UsedHistoryCount <= history->TotalHistoryCount );
|
||||
|
||||
// if already all used up, request class driver to remove at least one history unit
|
||||
if (history->UsedHistoryCount == history->TotalHistoryCount )
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
|
||||
NT_ASSERT( fdoData->InterpretSenseInfo != NULL );
|
||||
NT_ASSERT( fdoData->InterpretSenseInfo->Compress != NULL );
|
||||
fdoData->InterpretSenseInfo->Compress( fdoExtension->DeviceObject, history );
|
||||
NT_ASSERT( history->UsedHistoryCount < history->TotalHistoryCount );
|
||||
}
|
||||
|
||||
// thus, since we are about to increment the count, it must now be less...
|
||||
NT_ASSERT( history->UsedHistoryCount < history->TotalHistoryCount );
|
||||
|
||||
// increment the number of history units in use
|
||||
history->UsedHistoryCount++;
|
||||
|
||||
// determine index to use
|
||||
item = &( history->History[ history->UsedHistoryCount-1 ] );
|
||||
|
||||
// zero out the history item
|
||||
RtlZeroMemory(item, sizeof(SRB_HISTORY_ITEM));
|
||||
|
||||
// Query the tick count and store in the history
|
||||
KeQueryTickCount(&item->TickCountSent);
|
||||
return;
|
||||
}
|
||||
|
||||
VOID HistoryLogReturnedPacket(TRANSFER_PACKET *Pkt) {
|
||||
|
||||
PSRB_HISTORY history;
|
||||
PSRB_HISTORY_ITEM item;
|
||||
UCHAR senseSize;
|
||||
PVOID senseInfoBuffer;
|
||||
UCHAR senseInfoBufferLength;
|
||||
SENSE_DATA convertedSenseBuffer = {0};
|
||||
BOOLEAN validSense = TRUE;
|
||||
|
||||
NT_ASSERT( Pkt->RetryHistory != NULL );
|
||||
history = Pkt->RetryHistory;
|
||||
NT_ASSERT( history->UsedHistoryCount <= history->TotalHistoryCount );
|
||||
item = &( history->History[ history->UsedHistoryCount-1 ] );
|
||||
|
||||
// Query the tick count and store in the history
|
||||
KeQueryTickCount(&item->TickCountCompleted);
|
||||
|
||||
// Copy the SRB Status...
|
||||
item->SrbStatus = Pkt->Srb->SrbStatus;
|
||||
|
||||
//
|
||||
// Process sense data
|
||||
//
|
||||
|
||||
senseInfoBuffer = ClasspTransferPacketGetSenseInfoBuffer(Pkt);
|
||||
senseInfoBufferLength = ClasspTransferPacketGetSenseInfoBufferLength(Pkt);
|
||||
|
||||
if (IsDescriptorSenseDataFormat(senseInfoBuffer)) {
|
||||
|
||||
validSense = ScsiConvertToFixedSenseFormat(senseInfoBuffer,
|
||||
senseInfoBufferLength,
|
||||
(PVOID)&convertedSenseBuffer,
|
||||
sizeof(convertedSenseBuffer));
|
||||
|
||||
if (validSense) {
|
||||
senseInfoBuffer = (PVOID)&convertedSenseBuffer;
|
||||
senseInfoBufferLength = sizeof(convertedSenseBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
RtlZeroMemory(&(item->NormalizedSenseData), sizeof(item->NormalizedSenseData));
|
||||
|
||||
if (validSense) {
|
||||
|
||||
// Determine the amount of valid sense data
|
||||
|
||||
if (!ScsiGetTotalSenseByteCountIndicated(senseInfoBuffer,
|
||||
senseInfoBufferLength,
|
||||
&senseSize)) {
|
||||
senseSize = senseInfoBufferLength;
|
||||
}
|
||||
|
||||
// Normalize the sense data copy in the history
|
||||
senseSize = min(senseSize, sizeof(item->NormalizedSenseData));
|
||||
RtlCopyMemory(&(item->NormalizedSenseData),
|
||||
senseInfoBuffer,
|
||||
senseSize
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
560
drivers/storage/class/classpnp/lock.c
Normal file
560
drivers/storage/class/classpnp/lock.c
Normal file
|
@ -0,0 +1,560 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1990 - 1998
|
||||
|
||||
Module Name:
|
||||
|
||||
lock.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the NT SCSI port driver.
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
This module is a driver dll for scsi miniports.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef DEBUG_USE_WPP
|
||||
#include "lock.tmh"
|
||||
#endif
|
||||
|
||||
|
||||
LONG LockHighWatermark = 0;
|
||||
LONG LockLowWatermark = 0;
|
||||
LONG MaxLockedMinutes = 5;
|
||||
|
||||
//
|
||||
// Structure used for tracking remove lock allocations in checked builds
|
||||
//
|
||||
typedef struct _REMOVE_TRACKING_BLOCK {
|
||||
PVOID Tag;
|
||||
LARGE_INTEGER TimeLocked;
|
||||
PCSTR File;
|
||||
ULONG Line;
|
||||
} REMOVE_TRACKING_BLOCK, *PREMOVE_TRACKING_BLOCK;
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Classpnp RemoveLockRundown
|
||||
|
||||
RemoveLockRundown is a cacheaware rundown protection for the classpnp device object. While this
|
||||
rundown protection is held successfully, the caller can assume that no pending pnp REMOVE
|
||||
requests will be completed.
|
||||
|
||||
The RemoveLockRundown is a replacement of the original RemoveLock to improve the scalability.
|
||||
For backward compatibility, we still keep the RemoveLock field in the device common extension structure.
|
||||
However, the old RemoveLock is only being used in the DBG build.
|
||||
|
||||
The usage of the RemoveLockRundown is slightly different from the normal rundown protection usage.
|
||||
The RemoveLockRundown is acquired via ClassAcquireRemoveLockEx() function
|
||||
and released via ClassReleaseRemoveLock() function. Usually, we bail out when the acquisition
|
||||
of rundown protection fails (calls to ExAcquireRundownProtectionCacheAware returns FALSE) and
|
||||
will not release the rundown protection in acquisition failure. For the RemoveLockRundown,
|
||||
the caller will always call ClassAcquireRemoveLockEx() and ClassReleaseRemoveLock() in a pair no
|
||||
matter the return value of ClassAcquireRemoveLockEx(). Therefore, a thread may still call
|
||||
ClassReleaseRemoveLock() even the previous acquisition RemoveLockRundown protection failed.
|
||||
|
||||
To deal with the previous acquisition failure case, we introduced a new field RemoveLockFailAcquire
|
||||
as a counter for rundown acquisition failures. In the ClassReleaseRemoveLock() function, we only
|
||||
release the rundown protection when this counter is decremented to zero. Since the change of RemoveLockFailAcquire
|
||||
and release rundown protection is not protected by a lock as an atomic operation, we use a while loop over
|
||||
InterlockedCompareExchange operation to make sure when we release the rundown protection, this counter is
|
||||
actually zero.
|
||||
|
||||
--*/
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassAcquireRemoveLockEx()
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to acquire the remove lock on the device object.
|
||||
While the lock is held, the caller can assume that no pending pnp REMOVE
|
||||
requests will be completed.
|
||||
|
||||
The lock should be acquired immediately upon entering a dispatch routine.
|
||||
It should also be acquired before creating any new reference to the
|
||||
device object if there's a chance of releasing the reference before the
|
||||
new one is done.
|
||||
|
||||
This routine will return TRUE if the lock was successfully acquired or
|
||||
FALSE if it cannot be because the device object has already been removed.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - the device object to lock
|
||||
|
||||
Tag - Used for tracking lock allocation and release. If an irp is
|
||||
specified when acquiring the lock then the same Tag must be
|
||||
used to release the lock before the Tag is completed.
|
||||
|
||||
Return Value:
|
||||
|
||||
The value of the IsRemoved flag in the device extension. If this is
|
||||
non-zero then the device object has received a Remove irp and non-cleanup
|
||||
IRP's should fail.
|
||||
|
||||
If the value is REMOVE_COMPLETE, the caller should not even release the
|
||||
lock.
|
||||
|
||||
--*/
|
||||
ULONG
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
ClassAcquireRemoveLockEx(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_ PVOID Tag,
|
||||
_In_ PCSTR File,
|
||||
_In_ ULONG Line
|
||||
)
|
||||
// This function implements the acquisition of Tag
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(suppress:28104)
|
||||
#endif
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
BOOLEAN rundownAcquired;
|
||||
PEX_RUNDOWN_REF_CACHE_AWARE removeLockRundown = NULL;
|
||||
|
||||
//
|
||||
// Grab the remove lock
|
||||
//
|
||||
|
||||
#if DBG
|
||||
|
||||
LONG lockValue;
|
||||
|
||||
lockValue = InterlockedIncrement(&commonExtension->RemoveLock);
|
||||
|
||||
|
||||
TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassAcquireRemoveLock: "
|
||||
"Acquired for Object %p & irp %p - count is %d\n",
|
||||
DeviceObject, Tag, lockValue));
|
||||
|
||||
NT_ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ",
|
||||
(lockValue > 0));
|
||||
|
||||
NT_ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
|
||||
((LockHighWatermark == 0) ||
|
||||
(lockValue != LockHighWatermark)));
|
||||
|
||||
if (commonExtension->IsRemoved != REMOVE_COMPLETE) {
|
||||
PRTL_GENERIC_TABLE removeTrackingList = NULL;
|
||||
REMOVE_TRACKING_BLOCK trackingBlock;
|
||||
PREMOVE_TRACKING_BLOCK insertedTrackingBlock = NULL;
|
||||
BOOLEAN newElement = FALSE;
|
||||
|
||||
KIRQL oldIrql;
|
||||
|
||||
trackingBlock.Tag = Tag;
|
||||
|
||||
trackingBlock.File = File;
|
||||
trackingBlock.Line = Line;
|
||||
|
||||
KeQueryTickCount((&trackingBlock.TimeLocked));
|
||||
|
||||
KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
&oldIrql);
|
||||
|
||||
removeTrackingList = commonExtension->RemoveTrackingList;
|
||||
|
||||
if (removeTrackingList != NULL) {
|
||||
insertedTrackingBlock = RtlInsertElementGenericTable(removeTrackingList,
|
||||
&trackingBlock,
|
||||
sizeof(REMOVE_TRACKING_BLOCK),
|
||||
&newElement);
|
||||
}
|
||||
|
||||
if (insertedTrackingBlock != NULL) {
|
||||
if (!newElement) {
|
||||
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: "
|
||||
"already tracking Tag %p\n", Tag));
|
||||
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: "
|
||||
"acquired in file %s on line %d\n",
|
||||
insertedTrackingBlock->File, insertedTrackingBlock->Line));
|
||||
// NT_ASSERT(FALSE);
|
||||
|
||||
}
|
||||
} else {
|
||||
commonExtension->RemoveTrackingUntrackedCount++;
|
||||
|
||||
TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: "
|
||||
"Cannot track Tag %p - currently %d untracked requsts\n",
|
||||
Tag, commonExtension->RemoveTrackingUntrackedCount));
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);
|
||||
}
|
||||
#else
|
||||
|
||||
UNREFERENCED_PARAMETER(Tag);
|
||||
UNREFERENCED_PARAMETER(File);
|
||||
UNREFERENCED_PARAMETER(Line);
|
||||
|
||||
#endif
|
||||
|
||||
removeLockRundown = (PEX_RUNDOWN_REF_CACHE_AWARE)
|
||||
((PCHAR)commonExtension->PrivateCommonData + sizeof(CLASS_PRIVATE_COMMON_DATA));
|
||||
rundownAcquired = ExAcquireRundownProtectionCacheAware(removeLockRundown);
|
||||
if (!rundownAcquired) {
|
||||
InterlockedIncrement((volatile LONG*) &(commonExtension->PrivateCommonData->RemoveLockFailAcquire));
|
||||
TracePrint((TRACE_LEVEL_VERBOSE,
|
||||
TRACE_FLAG_LOCK,
|
||||
"ClassAcquireRemoveLockEx: RemoveLockRundown acquisition failed"
|
||||
"RemoveLockFailAcquire = %d\n",
|
||||
commonExtension->PrivateCommonData->RemoveLockFailAcquire));
|
||||
}
|
||||
|
||||
return (commonExtension->IsRemoved);
|
||||
}
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassReleaseRemoveLock()
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to release the remove lock on the device object. It
|
||||
must be called when finished using a previously locked reference to the
|
||||
device object. If an Tag was specified when acquiring the lock then the
|
||||
same Tag must be specified when releasing the lock.
|
||||
|
||||
When the lock count reduces to zero, this routine will signal the waiting
|
||||
remove Tag to delete the device object. As a result the DeviceObject
|
||||
pointer should not be used again once the lock has been released.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - the device object to lock
|
||||
|
||||
Tag - The irp (if any) specified when acquiring the lock. This is used
|
||||
for lock tracking purposes
|
||||
|
||||
Return Value:
|
||||
|
||||
none
|
||||
|
||||
--*/
|
||||
VOID
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
ClassReleaseRemoveLock(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_opt_ PIRP Tag
|
||||
)
|
||||
// This function implements the release of Tag
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(suppress:28103)
|
||||
#endif
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
LONG lockValue;
|
||||
LONG oldValue;
|
||||
PEX_RUNDOWN_REF_CACHE_AWARE removeLockRundown = NULL;
|
||||
|
||||
#if DBG
|
||||
PRTL_GENERIC_TABLE removeTrackingList = NULL;
|
||||
REMOVE_TRACKING_BLOCK searchDataBlock;
|
||||
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
BOOLEAN isRemoved = (commonExtension->IsRemoved == REMOVE_COMPLETE);
|
||||
|
||||
KIRQL oldIrql;
|
||||
|
||||
if (isRemoved) {
|
||||
TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen"));
|
||||
InterlockedDecrement(&(commonExtension->RemoveLock));
|
||||
return;
|
||||
}
|
||||
|
||||
KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
&oldIrql);
|
||||
|
||||
removeTrackingList = commonExtension->RemoveTrackingList;
|
||||
|
||||
if (removeTrackingList != NULL) {
|
||||
searchDataBlock.Tag = Tag;
|
||||
found = RtlDeleteElementGenericTable(removeTrackingList, &searchDataBlock);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if(commonExtension->RemoveTrackingUntrackedCount == 0) {
|
||||
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassReleaseRemoveLock: "
|
||||
"Couldn't find Tag %p in the lock tracking list\n", Tag));
|
||||
//
|
||||
// This might happen if the device is being removed and the tracking list
|
||||
// has already been freed. Don't assert if that is the case.
|
||||
//
|
||||
NT_ASSERT((removeTrackingList == NULL) && (commonExtension->IsRemoved != NO_REMOVE));
|
||||
} else {
|
||||
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassReleaseRemoveLock: "
|
||||
"Couldn't find Tag %p in the lock tracking list - "
|
||||
"may be one of the %d untracked requests still outstanding\n",
|
||||
Tag, commonExtension->RemoveTrackingUntrackedCount));
|
||||
|
||||
commonExtension->RemoveTrackingUntrackedCount--;
|
||||
NT_ASSERT(commonExtension->RemoveTrackingUntrackedCount >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
oldIrql);
|
||||
|
||||
lockValue = InterlockedDecrement(&commonExtension->RemoveLock);
|
||||
|
||||
TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassReleaseRemoveLock: "
|
||||
"Released for Object %p & irp %p - count is %d\n",
|
||||
DeviceObject, Tag, lockValue));
|
||||
|
||||
NT_ASSERT(lockValue >= 0);
|
||||
|
||||
NT_ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
|
||||
((LockLowWatermark == 0) || !(lockValue == LockLowWatermark)));
|
||||
|
||||
if (lockValue == 0) {
|
||||
|
||||
NT_ASSERT(commonExtension->IsRemoved);
|
||||
|
||||
//
|
||||
// The device needs to be removed. Signal the remove event
|
||||
// that it's safe to go ahead.
|
||||
//
|
||||
|
||||
TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassReleaseRemoveLock: "
|
||||
"Release for object %p & irp %p caused lock to go to zero\n",
|
||||
DeviceObject, Tag));
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
UNREFERENCED_PARAMETER(Tag);
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Decrement the RemoveLockFailAcquire by 1 when RemoveLockFailAcquire is non-zero.
|
||||
// Release the RemoveLockRundown only when RemoveLockFailAcquire is zero.
|
||||
//
|
||||
|
||||
oldValue = 1;
|
||||
lockValue = commonExtension->PrivateCommonData->RemoveLockFailAcquire;
|
||||
while (lockValue != 0) {
|
||||
oldValue =
|
||||
InterlockedCompareExchange((volatile LONG *) &commonExtension->PrivateCommonData->RemoveLockFailAcquire,
|
||||
lockValue - 1,
|
||||
lockValue);
|
||||
|
||||
if (oldValue == lockValue) {
|
||||
break;
|
||||
}
|
||||
|
||||
lockValue = oldValue;
|
||||
}
|
||||
|
||||
if (lockValue == 0) {
|
||||
removeLockRundown = (PEX_RUNDOWN_REF_CACHE_AWARE)
|
||||
((PCHAR)commonExtension->PrivateCommonData + sizeof(CLASS_PRIVATE_COMMON_DATA));
|
||||
ExReleaseRundownProtectionCacheAware(removeLockRundown);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassCompleteRequest()
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is a wrapper around (and should be used instead of)
|
||||
IoCompleteRequest. It is used primarily for debugging purposes.
|
||||
The routine will assert if the Irp being completed is still holding
|
||||
the release lock.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - the device object that was handling this request
|
||||
|
||||
Irp - the irp to be completed by IoCompleteRequest
|
||||
|
||||
PriorityBoost - the priority boost to pass to IoCompleteRequest
|
||||
|
||||
Return Value:
|
||||
|
||||
none
|
||||
|
||||
--*/
|
||||
VOID
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
ClassCompleteRequest(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_ PIRP Irp,
|
||||
_In_ CCHAR PriorityBoost
|
||||
)
|
||||
{
|
||||
#if DBG
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
|
||||
PRTL_GENERIC_TABLE removeTrackingList = NULL;
|
||||
REMOVE_TRACKING_BLOCK searchDataBlock;
|
||||
PREMOVE_TRACKING_BLOCK foundTrackingBlock;
|
||||
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock, &oldIrql);
|
||||
|
||||
removeTrackingList = commonExtension->RemoveTrackingList;
|
||||
|
||||
if (removeTrackingList != NULL)
|
||||
{
|
||||
searchDataBlock.Tag = Irp;
|
||||
|
||||
foundTrackingBlock = RtlLookupElementGenericTable(removeTrackingList, &searchDataBlock);
|
||||
|
||||
if(foundTrackingBlock != NULL) {
|
||||
|
||||
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassCompleteRequest: "
|
||||
"Irp %p completed while still holding the remove lock\n", Irp));
|
||||
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassCompleteRequest: "
|
||||
"Lock acquired in file %s on line %d\n",
|
||||
foundTrackingBlock->File, foundTrackingBlock->Line));
|
||||
NT_ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);
|
||||
#endif
|
||||
|
||||
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
|
||||
IoCompleteRequest(Irp, PriorityBoost);
|
||||
return;
|
||||
} // end ClassCompleteRequest()
|
||||
|
||||
|
||||
RTL_GENERIC_COMPARE_RESULTS
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
RemoveTrackingCompareRoutine(
|
||||
PRTL_GENERIC_TABLE Table,
|
||||
PVOID FirstStruct,
|
||||
PVOID SecondStruct
|
||||
)
|
||||
{
|
||||
PVOID tag1, tag2;
|
||||
|
||||
UNREFERENCED_PARAMETER(Table);
|
||||
|
||||
tag1 = ((PREMOVE_TRACKING_BLOCK)FirstStruct)->Tag;
|
||||
tag2 = ((PREMOVE_TRACKING_BLOCK)SecondStruct)->Tag;
|
||||
|
||||
if (tag1 < tag2)
|
||||
{
|
||||
return GenericLessThan;
|
||||
}
|
||||
else if (tag1 > tag2)
|
||||
{
|
||||
return GenericGreaterThan;
|
||||
}
|
||||
|
||||
return GenericEqual;
|
||||
}
|
||||
|
||||
PVOID
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
RemoveTrackingAllocateRoutine(
|
||||
PRTL_GENERIC_TABLE Table,
|
||||
CLONG ByteSize
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Table);
|
||||
|
||||
return ExAllocatePoolWithTag(NonPagedPoolNx, ByteSize, CLASS_TAG_LOCK_TRACKING);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
RemoveTrackingFreeRoutine(
|
||||
PRTL_GENERIC_TABLE Table,
|
||||
PVOID Buffer
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Table);
|
||||
|
||||
FREE_POOL(Buffer);
|
||||
}
|
||||
|
||||
VOID
|
||||
ClasspInitializeRemoveTracking(
|
||||
_In_ PDEVICE_OBJECT DeviceObject
|
||||
)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
|
||||
#if DBG
|
||||
KeInitializeSpinLock(&commonExtension->RemoveTrackingSpinlock);
|
||||
|
||||
commonExtension->RemoveTrackingList = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(RTL_GENERIC_TABLE), CLASS_TAG_LOCK_TRACKING);
|
||||
|
||||
if (commonExtension->RemoveTrackingList != NULL)
|
||||
{
|
||||
RtlInitializeGenericTable(commonExtension->RemoveTrackingList,
|
||||
RemoveTrackingCompareRoutine,
|
||||
RemoveTrackingAllocateRoutine,
|
||||
RemoveTrackingFreeRoutine,
|
||||
NULL);
|
||||
}
|
||||
#else
|
||||
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
|
||||
commonExtension->RemoveTrackingSpinlock = (ULONG_PTR) -1;
|
||||
commonExtension->RemoveTrackingList = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID
|
||||
ClasspUninitializeRemoveTracking(
|
||||
_In_ PDEVICE_OBJECT DeviceObject
|
||||
)
|
||||
{
|
||||
#if DBG
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
PRTL_GENERIC_TABLE removeTrackingList = commonExtension->RemoveTrackingList;
|
||||
|
||||
ASSERTMSG("Removing the device while still holding remove locks",
|
||||
commonExtension->RemoveTrackingUntrackedCount == 0 &&
|
||||
removeTrackingList != NULL ? RtlNumberGenericTableElements(removeTrackingList) == 0 : TRUE);
|
||||
|
||||
if (removeTrackingList != NULL)
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock, &oldIrql);
|
||||
|
||||
FREE_POOL(removeTrackingList);
|
||||
commonExtension->RemoveTrackingList = NULL;
|
||||
|
||||
KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
1139
drivers/storage/class/classpnp/obsolete.c
Normal file
1139
drivers/storage/class/classpnp/obsolete.c
Normal file
File diff suppressed because it is too large
Load diff
2663
drivers/storage/class/classpnp/power.c
Normal file
2663
drivers/storage/class/classpnp/power.c
Normal file
File diff suppressed because it is too large
Load diff
798
drivers/storage/class/classpnp/retry.c
Normal file
798
drivers/storage/class/classpnp/retry.c
Normal file
|
@ -0,0 +1,798 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 2010
|
||||
|
||||
Module Name:
|
||||
|
||||
retry.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Packet retry routines for CLASSPNP
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef DEBUG_USE_WPP
|
||||
#include "retry.tmh"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* InterpretTransferPacketError
|
||||
*
|
||||
* Interpret the SRB error into a meaningful IRP status.
|
||||
* ClassInterpretSenseInfo also may modify the SRB for the retry.
|
||||
*
|
||||
* Return TRUE iff packet should be retried.
|
||||
*/
|
||||
BOOLEAN InterpretTransferPacketError(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
|
||||
ULONG timesAlreadyRetried;
|
||||
BOOLEAN shouldRetry = FALSE;
|
||||
PCDB pCdb = ClasspTransferPacketGetCdb(Pkt);
|
||||
|
||||
/*
|
||||
* Interpret the error using the returned sense info first.
|
||||
*/
|
||||
Pkt->RetryIn100nsUnits = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Pre-calculate the number of times the IO has already been
|
||||
* retried, so that all InterpretSenseInfo routines get the right value.
|
||||
*/
|
||||
if (ClasspTransferPacketGetNumberOfRetriesDone(Pkt, pCdb, ×AlreadyRetried) == FALSE)
|
||||
{
|
||||
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
|
||||
}
|
||||
|
||||
if (fdoData->InterpretSenseInfo != NULL) {
|
||||
|
||||
SCSI_REQUEST_BLOCK tempSrb = { 0 };
|
||||
PSCSI_REQUEST_BLOCK srbPtr = (PSCSI_REQUEST_BLOCK)Pkt->Srb;
|
||||
|
||||
// SAL annotation and ClassInitializeEx() both validate this
|
||||
NT_ASSERT(fdoData->InterpretSenseInfo->Interpret != NULL);
|
||||
|
||||
//
|
||||
// If class driver does not support extended SRB and this is
|
||||
// an extended SRB, convert to legacy SRB and pass to class
|
||||
// driver.
|
||||
//
|
||||
if ((Pkt->Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) &&
|
||||
((fdoExtension->CommonExtension.DriverExtension->SrbSupport &
|
||||
CLASS_SRB_STORAGE_REQUEST_BLOCK) == 0)) {
|
||||
ClasspConvertToScsiRequestBlock(&tempSrb, (PSTORAGE_REQUEST_BLOCK)Pkt->Srb);
|
||||
srbPtr = &tempSrb;
|
||||
}
|
||||
|
||||
shouldRetry = fdoData->InterpretSenseInfo->Interpret(Pkt->Fdo,
|
||||
Pkt->OriginalIrp,
|
||||
srbPtr,
|
||||
IRP_MJ_SCSI,
|
||||
0,
|
||||
timesAlreadyRetried,
|
||||
Pkt->RetryHistory,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&Pkt->RetryIn100nsUnits);
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// In this case, fdoData->InterpretSenseInfo == NULL so we must do our
|
||||
// own error code and sense info processing.
|
||||
//
|
||||
|
||||
PVOID senseInfoBuffer = ClasspTransferPacketGetSenseInfoBuffer(Pkt);
|
||||
UCHAR senseInfoBufferLength = ClasspTransferPacketGetSenseInfoBufferLength(Pkt);
|
||||
BOOLEAN validSense = FALSE;
|
||||
UCHAR senseKey = 0;
|
||||
UCHAR additionalSenseCode = 0;
|
||||
UCHAR additionalSenseQual = 0;
|
||||
|
||||
NT_ASSERT(senseInfoBuffer);
|
||||
|
||||
validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer,
|
||||
senseInfoBufferLength,
|
||||
SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
|
||||
&senseKey,
|
||||
&additionalSenseCode,
|
||||
&additionalSenseQual);
|
||||
|
||||
if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL) {
|
||||
|
||||
ULONG retryIntervalSeconds = 0;
|
||||
/*
|
||||
* This is an Ejection Control SRB. Interpret its sense info specially.
|
||||
*/
|
||||
shouldRetry = ClassInterpretSenseInfo(
|
||||
Pkt->Fdo,
|
||||
(PSCSI_REQUEST_BLOCK)Pkt->Srb,
|
||||
IRP_MJ_SCSI,
|
||||
0,
|
||||
timesAlreadyRetried,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&retryIntervalSeconds);
|
||||
|
||||
if (shouldRetry) {
|
||||
/*
|
||||
* If the device is not ready, wait at least 2 seconds before retrying.
|
||||
*/
|
||||
BOOLEAN setRetryIntervalSeconds = FALSE;
|
||||
|
||||
if (validSense) {
|
||||
|
||||
if ((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
|
||||
(additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) {
|
||||
setRetryIntervalSeconds = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!setRetryIntervalSeconds && (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
|
||||
setRetryIntervalSeconds = TRUE;
|
||||
}
|
||||
|
||||
if (setRetryIntervalSeconds) {
|
||||
retryIntervalSeconds = MAX(retryIntervalSeconds, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldRetry)
|
||||
{
|
||||
Pkt->RetryIn100nsUnits = retryIntervalSeconds;
|
||||
Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
|
||||
}
|
||||
|
||||
}
|
||||
else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
|
||||
(pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10)) {
|
||||
|
||||
ULONG retryIntervalSeconds = 0;
|
||||
/*
|
||||
* This is an Mode Sense SRB. Interpret its sense info specially.
|
||||
*/
|
||||
shouldRetry = ClassInterpretSenseInfo(
|
||||
Pkt->Fdo,
|
||||
(PSCSI_REQUEST_BLOCK)Pkt->Srb,
|
||||
IRP_MJ_SCSI,
|
||||
0,
|
||||
timesAlreadyRetried,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&retryIntervalSeconds);
|
||||
if (shouldRetry) {
|
||||
/*
|
||||
* If the device is not ready, wait at least 2 seconds before retrying.
|
||||
*/
|
||||
BOOLEAN setRetryIntervalSeconds = FALSE;
|
||||
|
||||
if (validSense) {
|
||||
if ((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
|
||||
(additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) {
|
||||
setRetryIntervalSeconds = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!setRetryIntervalSeconds && (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
|
||||
setRetryIntervalSeconds = TRUE;
|
||||
}
|
||||
|
||||
if (setRetryIntervalSeconds) {
|
||||
retryIntervalSeconds = MAX(retryIntervalSeconds, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some special cases for mode sense.
|
||||
*/
|
||||
if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED) {
|
||||
shouldRetry = TRUE;
|
||||
}
|
||||
else if (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
|
||||
/*
|
||||
* This is a HACK.
|
||||
* Atapi returns SRB_STATUS_DATA_OVERRUN when it really means
|
||||
* underrun (i.e. success, and the buffer is longer than needed).
|
||||
* So treat this as a success.
|
||||
* When the caller of this function sees that the status was changed to success,
|
||||
* it will add the transferred length to the original irp.
|
||||
*/
|
||||
Pkt->Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
shouldRetry = FALSE;
|
||||
}
|
||||
|
||||
if (shouldRetry)
|
||||
{
|
||||
Pkt->RetryIn100nsUnits = retryIntervalSeconds;
|
||||
Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
|
||||
}
|
||||
|
||||
}
|
||||
else if ((pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY) ||
|
||||
(pCdb->CDB16.OperationCode == SCSIOP_READ_CAPACITY16)) {
|
||||
|
||||
ULONG retryIntervalSeconds = 0;
|
||||
|
||||
/*
|
||||
* This is a Drive Capacity SRB. Interpret its sense info specially.
|
||||
*/
|
||||
shouldRetry = ClassInterpretSenseInfo(
|
||||
Pkt->Fdo,
|
||||
(PSCSI_REQUEST_BLOCK)Pkt->Srb,
|
||||
IRP_MJ_SCSI,
|
||||
0,
|
||||
timesAlreadyRetried,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&retryIntervalSeconds);
|
||||
if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED) {
|
||||
shouldRetry = TRUE;
|
||||
}
|
||||
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
|
||||
else if (ClasspSrbTimeOutStatus(Pkt->Srb)) {
|
||||
|
||||
Pkt->TimedOut = TRUE;
|
||||
|
||||
if (shouldRetry) {
|
||||
//
|
||||
// For requests that have timed-out we may only perform a limited
|
||||
// number of retries. This is typically less than the general
|
||||
// number of retries allowed.
|
||||
//
|
||||
if (Pkt->NumIoTimeoutRetries == 0) {
|
||||
shouldRetry = FALSE;
|
||||
} else {
|
||||
Pkt->NumIoTimeoutRetries--;
|
||||
//
|
||||
// We expect to be able to retry if there are some general retries remaining.
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (shouldRetry)
|
||||
{
|
||||
Pkt->RetryIn100nsUnits = retryIntervalSeconds;
|
||||
Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
|
||||
}
|
||||
|
||||
}
|
||||
else if (IS_SCSIOP_READWRITE(pCdb->CDB10.OperationCode)) {
|
||||
|
||||
ULONG retryIntervalSeconds = 0;
|
||||
/*
|
||||
* This is a Read/Write Data packet.
|
||||
*/
|
||||
PIO_STACK_LOCATION origCurrentSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);
|
||||
|
||||
shouldRetry = ClassInterpretSenseInfo(Pkt->Fdo,
|
||||
(PSCSI_REQUEST_BLOCK)Pkt->Srb,
|
||||
origCurrentSp->MajorFunction,
|
||||
0,
|
||||
timesAlreadyRetried,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&retryIntervalSeconds);
|
||||
|
||||
/*
|
||||
* Deal with some special cases.
|
||||
*/
|
||||
if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES) {
|
||||
/*
|
||||
* We are in extreme low-memory stress.
|
||||
* We will retry in smaller chunks.
|
||||
*/
|
||||
shouldRetry = TRUE;
|
||||
}
|
||||
else if (TEST_FLAG(origCurrentSp->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
|
||||
(Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED)) {
|
||||
/*
|
||||
* We are still verifying a (possibly) reloaded disk/cdrom.
|
||||
* So retry the request.
|
||||
*/
|
||||
Pkt->Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
|
||||
shouldRetry = TRUE;
|
||||
|
||||
}
|
||||
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
|
||||
else if (ClasspSrbTimeOutStatus(Pkt->Srb)) {
|
||||
|
||||
Pkt->TimedOut = TRUE;
|
||||
|
||||
if (shouldRetry) {
|
||||
//
|
||||
// For requests that have timed-out we may only perform a limited
|
||||
// number of retries. This is typically less than the general
|
||||
// number of retries allowed.
|
||||
//
|
||||
if (Pkt->NumIoTimeoutRetries == 0) {
|
||||
shouldRetry = FALSE;
|
||||
} else {
|
||||
Pkt->NumIoTimeoutRetries--;
|
||||
//
|
||||
// We expect to be able to retry if there are some general retries remaining.
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (shouldRetry)
|
||||
{
|
||||
Pkt->RetryIn100nsUnits = retryIntervalSeconds;
|
||||
Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
|
||||
}
|
||||
|
||||
} else if (ClasspIsOffloadDataTransferCommand(pCdb)) {
|
||||
|
||||
ULONG retryIntervalSeconds = 0;
|
||||
|
||||
Pkt->TransferCount = 0;
|
||||
|
||||
shouldRetry = ClassInterpretSenseInfo(
|
||||
Pkt->Fdo,
|
||||
(PSCSI_REQUEST_BLOCK)Pkt->Srb,
|
||||
IRP_MJ_SCSI,
|
||||
0,
|
||||
timesAlreadyRetried,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&retryIntervalSeconds);
|
||||
|
||||
if (shouldRetry) {
|
||||
|
||||
Pkt->RetryIn100nsUnits = retryIntervalSeconds;
|
||||
Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
|
||||
|
||||
} else {
|
||||
|
||||
if (ClasspIsTokenOperation(pCdb)) {
|
||||
|
||||
BOOLEAN isInformationValid = FALSE;
|
||||
ULONGLONG information = 0;
|
||||
|
||||
if (validSense) {
|
||||
|
||||
//
|
||||
// If this is a data underrun condition (i.e. target truncated the offload data transfer),
|
||||
// the SenseData's Information field may have the TransferCount.
|
||||
//
|
||||
if ((senseKey == SCSI_SENSE_COPY_ABORTED || senseKey == SCSI_SENSE_ABORTED_COMMAND) &&
|
||||
(additionalSenseCode == SCSI_ADSENSE_COPY_TARGET_DEVICE_ERROR && additionalSenseQual == SCSI_SENSEQ_DATA_UNDERRUN)) {
|
||||
|
||||
//
|
||||
// Sense data in Descriptor format
|
||||
//
|
||||
if (IsDescriptorSenseDataFormat(senseInfoBuffer)) {
|
||||
|
||||
PVOID startBuffer = NULL;
|
||||
UCHAR startBufferLength = 0;
|
||||
|
||||
|
||||
if (ScsiGetSenseDescriptor(senseInfoBuffer,
|
||||
SrbGetSenseInfoBufferLength(Pkt->Srb),
|
||||
&startBuffer,
|
||||
&startBufferLength)) {
|
||||
UCHAR outType;
|
||||
PVOID outBuffer = NULL;
|
||||
UCHAR outBufferLength = 0;
|
||||
|
||||
UCHAR typeList[1] = { SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION };
|
||||
|
||||
if (ScsiGetNextSenseDescriptorByType(startBuffer,
|
||||
startBufferLength,
|
||||
typeList,
|
||||
ARRAYSIZE(typeList),
|
||||
&outType,
|
||||
&outBuffer,
|
||||
&outBufferLength)) {
|
||||
|
||||
if (outType == SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION) {
|
||||
|
||||
if (ScsiValidateInformationSenseDescriptor(outBuffer, outBufferLength)) {
|
||||
REVERSE_BYTES_QUAD(&information, &(((PSCSI_SENSE_DESCRIPTOR_INFORMATION)outBuffer)->Information));
|
||||
isInformationValid = TRUE;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// ScsiGetNextDescriptorByType should only return a type that is specified by us.
|
||||
//
|
||||
NT_ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
//
|
||||
// Sense data in Fixed format
|
||||
//
|
||||
REVERSE_BYTES(&information, &(((PFIXED_SENSE_DATA)senseInfoBuffer)->Information));
|
||||
isInformationValid = TRUE;
|
||||
}
|
||||
|
||||
if (isInformationValid) {
|
||||
Pkt->TransferCount = information;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
|
||||
}
|
||||
}
|
||||
|
||||
return shouldRetry;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RetryTransferPacket
|
||||
*
|
||||
* Retry sending a TRANSFER_PACKET.
|
||||
*
|
||||
* Return TRUE iff the packet is complete.
|
||||
* (if so the status in pkt->irp is the final status).
|
||||
*/
|
||||
BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
BOOLEAN packetDone;
|
||||
BOOLEAN scaleDown = FALSE;
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
|
||||
PCDB pCdb = SrbGetCdb(Pkt->Srb);
|
||||
|
||||
#if !defined(__REACTOS__) && NTDDI_VERSION >= NTDDI_WINBLUE
|
||||
if(ClasspIsThinProvisioningError((PSCSI_REQUEST_BLOCK)Pkt->Srb) &&
|
||||
(pCdb != NULL) && IS_SCSIOP_READWRITE(pCdb->CDB10.OperationCode)) {
|
||||
|
||||
if(Pkt->NumThinProvisioningRetries >= NUM_THIN_PROVISIONING_RETRIES) {
|
||||
//We've already retried this the maximum times. Bail out.
|
||||
return TRUE;
|
||||
}
|
||||
Pkt->NumThinProvisioningRetries++;
|
||||
}
|
||||
else {
|
||||
NT_ASSERT(Pkt->NumRetries > 0 || Pkt->RetryHistory);
|
||||
Pkt->NumRetries--;
|
||||
}
|
||||
#else
|
||||
NT_ASSERT(Pkt->NumRetries > 0 || Pkt->RetryHistory);
|
||||
Pkt->NumRetries--;
|
||||
#endif
|
||||
|
||||
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(Pkt->Srb)));
|
||||
|
||||
if (!fdoData->DisableThrottling) {
|
||||
|
||||
//
|
||||
// If this is the last retry, then turn off disconnect, sync transfer,
|
||||
// and tagged queuing. On all other retries, leave the original settings.
|
||||
// Do not apply this for thin provisioning soft threshold errors, since
|
||||
// they should succeed as soon as they're retried on the right IT nexus.
|
||||
//
|
||||
if ((Pkt->NumRetries == 0) && !ClasspIsThinProvisioningError((PSCSI_REQUEST_BLOCK)Pkt->Srb)) {
|
||||
scaleDown = TRUE;
|
||||
}
|
||||
|
||||
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
|
||||
//
|
||||
// If this request previously timed-out and there are no more retries left
|
||||
// for timed-out requests, then we should also apply the scale down.
|
||||
//
|
||||
if (Pkt->TimedOut && Pkt->NumIoTimeoutRetries == 0) {
|
||||
scaleDown = TRUE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (scaleDown) {
|
||||
/*
|
||||
* Tone down performance on the retry.
|
||||
* This increases the chance for success on the retry.
|
||||
* We've seen instances of drives that fail consistently but then start working
|
||||
* once this scale-down is applied.
|
||||
*/
|
||||
SrbSetSrbFlags(Pkt->Srb, SRB_FLAGS_DISABLE_DISCONNECT);
|
||||
SrbSetSrbFlags(Pkt->Srb, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
SrbClearSrbFlags(Pkt->Srb, SRB_FLAGS_QUEUE_ACTION_ENABLE);
|
||||
SrbSetRequestTag(Pkt->Srb, SP_UNTAGGED);
|
||||
}
|
||||
|
||||
if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES) {
|
||||
|
||||
UCHAR cdbOpcode = 0;
|
||||
BOOLEAN isReadWrite = FALSE;
|
||||
|
||||
if (pCdb) {
|
||||
cdbOpcode = pCdb->CDB10.OperationCode;
|
||||
isReadWrite = IS_SCSIOP_READWRITE(cdbOpcode);
|
||||
}
|
||||
|
||||
if ((Pkt->DriverUsesStartIO) &&
|
||||
( (cdbOpcode == SCSIOP_WRITE6 ) ||
|
||||
(cdbOpcode == SCSIOP_WRITE ) ||
|
||||
(cdbOpcode == SCSIOP_WRITE12) ||
|
||||
(cdbOpcode == SCSIOP_WRITE16) )) {
|
||||
|
||||
/* don't retry writes in super-low-memory conditions if the
|
||||
* driver must serialize against StartIO. This is because
|
||||
* some write methods used in such drivers cannot accept
|
||||
* random-sized writes. (i.e CD-RW in packet writing mode)
|
||||
* Reads, however, are always safe to split up.
|
||||
*/
|
||||
SET_FLAG(fdoData->TrackingFlags, TRACKING_FORWARD_PROGRESS_PATH1);
|
||||
packetDone = TRUE;
|
||||
}
|
||||
else if (Pkt->InLowMemRetry || !isReadWrite){
|
||||
/*
|
||||
* This should never happen under normal circumstances.
|
||||
* The memory manager guarantees that at least four pages will
|
||||
* be available to allow forward progress in the port driver.
|
||||
* So a one-page transfer should never fail with insufficient resources.
|
||||
*
|
||||
* However, it is possible to get in here with virtual storage
|
||||
* or thin provisioned storage for example.
|
||||
* A single sector write can trigger an allocation request and
|
||||
* presently a forward progress guarantee is not provided.
|
||||
* VHD also may have some limitations in forward progress guarantee.
|
||||
* And USB too might also fall into this category.
|
||||
*/
|
||||
SET_FLAG(fdoData->TrackingFlags, TRACKING_FORWARD_PROGRESS_PATH2);
|
||||
packetDone = TRUE;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* We are in low-memory stress.
|
||||
* Start the low-memory retry state machine, which tries to
|
||||
* resend the packet in little one-page chunks.
|
||||
*/
|
||||
SET_FLAG(fdoData->TrackingFlags, TRACKING_FORWARD_PROGRESS_PATH3);
|
||||
InitLowMemRetry(Pkt,
|
||||
Pkt->BufPtrCopy,
|
||||
Pkt->BufLenCopy,
|
||||
Pkt->TargetLocationCopy);
|
||||
StepLowMemRetry(Pkt);
|
||||
packetDone = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Retry the packet by simply resending it after a delay.
|
||||
* Put the packet back in the pending queue and
|
||||
* schedule a timer to retry the transfer.
|
||||
*
|
||||
* Do not call SetupReadWriteTransferPacket again because:
|
||||
* (1) The minidriver may have set some bits
|
||||
* in the SRB that it needs again and
|
||||
* (2) doing so would reset numRetries.
|
||||
*
|
||||
* BECAUSE we do not call SetupReadWriteTransferPacket again,
|
||||
* we have to reset a couple fields in the SRB that
|
||||
* some miniports overwrite when they fail an SRB.
|
||||
*/
|
||||
|
||||
SrbSetDataBuffer(Pkt->Srb, Pkt->BufPtrCopy);
|
||||
SrbSetDataTransferLength(Pkt->Srb, Pkt->BufLenCopy);
|
||||
|
||||
TransferPacketQueueRetryDpc(Pkt);
|
||||
|
||||
packetDone = FALSE;
|
||||
}
|
||||
|
||||
return packetDone;
|
||||
}
|
||||
|
||||
|
||||
VOID TransferPacketQueueRetryDpc(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
KeInitializeDpc(&Pkt->RetryTimerDPC, TransferPacketRetryTimerDpc, Pkt);
|
||||
|
||||
if (Pkt->RetryIn100nsUnits == 0){
|
||||
KeInsertQueueDpc(&Pkt->RetryTimerDPC, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
LARGE_INTEGER timerPeriod;
|
||||
|
||||
NT_ASSERT(Pkt->RetryIn100nsUnits < 100 * 1000 * 1000 * 10); // sanity check -- 100 seconds is normally too long
|
||||
timerPeriod.QuadPart = -(Pkt->RetryIn100nsUnits);
|
||||
KeInitializeTimer(&Pkt->RetryTimer);
|
||||
KeSetTimer(&Pkt->RetryTimer, timerPeriod, &Pkt->RetryTimerDPC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
|
||||
TransferPacketRetryTimerDpc( IN PKDPC Dpc,
|
||||
IN PVOID DeferredContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2)
|
||||
{
|
||||
PTRANSFER_PACKET pkt;
|
||||
PDEVICE_OBJECT fdo;
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
|
||||
|
||||
_Analysis_assume_(DeferredContext != NULL);
|
||||
|
||||
pkt = (PTRANSFER_PACKET)DeferredContext;
|
||||
|
||||
fdo = pkt->Fdo;
|
||||
fdoExtension = fdo->DeviceExtension;
|
||||
|
||||
UNREFERENCED_PARAMETER(Dpc);
|
||||
UNREFERENCED_PARAMETER(SystemArgument1);
|
||||
UNREFERENCED_PARAMETER(SystemArgument2);
|
||||
|
||||
|
||||
/*
|
||||
* Sometimes the port driver can allocates a new 'sense' buffer
|
||||
* to report transfer errors, e.g. when the default sense buffer
|
||||
* is too small. If so, it is up to us to free it.
|
||||
* Now that we're done using the sense info, free it if appropriate.
|
||||
* Then clear the sense buffer so it doesn't pollute future errors returned in this packet.
|
||||
*/
|
||||
if (PORT_ALLOCATED_SENSE_EX(fdoExtension, pkt->Srb)) {
|
||||
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "Freeing port-allocated sense buffer for pkt %ph.", pkt));
|
||||
FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(fdoExtension, pkt->Srb);
|
||||
SrbSetSenseInfoBuffer(pkt->Srb, &pkt->SrbErrorSenseData);
|
||||
SrbSetSenseInfoBufferLength(pkt->Srb, sizeof(pkt->SrbErrorSenseData));
|
||||
}
|
||||
else {
|
||||
NT_ASSERT(SrbGetSenseInfoBuffer(pkt->Srb) == &pkt->SrbErrorSenseData);
|
||||
NT_ASSERT(SrbGetSenseInfoBufferLength(pkt->Srb) <= sizeof(pkt->SrbErrorSenseData));
|
||||
}
|
||||
|
||||
RtlZeroMemory(&pkt->SrbErrorSenseData, sizeof(pkt->SrbErrorSenseData));
|
||||
|
||||
SubmitTransferPacket(pkt);
|
||||
|
||||
}
|
||||
|
||||
|
||||
VOID InitLowMemRetry(PTRANSFER_PACKET Pkt, PVOID BufPtr, ULONG Len, LARGE_INTEGER TargetLocation)
|
||||
{
|
||||
NT_ASSERT(Len > 0);
|
||||
NT_ASSERT(!Pkt->InLowMemRetry);
|
||||
|
||||
if (Pkt->DriverUsesStartIO)
|
||||
{
|
||||
/*
|
||||
* special case: StartIO-based writing must stay serialized for performance
|
||||
* and proper operations (i.e. sequential writing mode). If need more than
|
||||
* one transfer to perform this operation, and it's a StartIO-based driver
|
||||
* (such as CDROM), then just use a single packet and use the retry logic
|
||||
* that's already built-in to the packet engine. Note that low-mem retry
|
||||
* cannot be used directly because some write methods do not work if the
|
||||
* writes are only PAGE_SIZE (i.e. packet writing may corrupt data).
|
||||
*/
|
||||
Pkt->InLowMemRetry = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pkt->InLowMemRetry = TRUE;
|
||||
}
|
||||
Pkt->LowMemRetry_remainingBufPtr = BufPtr;
|
||||
Pkt->LowMemRetry_remainingBufLen = Len;
|
||||
Pkt->LowMemRetry_nextChunkTargetLocation = TargetLocation;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* StepLowMemRetry
|
||||
*
|
||||
* During extreme low-memory stress, this function retries
|
||||
* a packet in small one-page chunks, sent serially.
|
||||
*
|
||||
* Returns TRUE iff the packet is done.
|
||||
*/
|
||||
BOOLEAN StepLowMemRetry(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
BOOLEAN packetDone;
|
||||
|
||||
if (Pkt->LowMemRetry_remainingBufLen == 0){
|
||||
packetDone = TRUE;
|
||||
}
|
||||
else {
|
||||
ULONG thisChunkLen;
|
||||
if (Pkt->DriverUsesStartIO)
|
||||
{
|
||||
/*
|
||||
* Need the fdoData for the HwMaxXferLen
|
||||
*/
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
|
||||
/*
|
||||
* Need the adapterDesc to limit transfers based on byte count
|
||||
*/
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension;
|
||||
PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExtension->PartitionZeroExtension->AdapterDescriptor;
|
||||
|
||||
ULONG hwMaxXferLen;
|
||||
|
||||
/*
|
||||
* special case: StartIO-based writing must stay serialized for performance
|
||||
* and proper operations (i.e. sequential writing mode). If need more than
|
||||
* one transfer to perform this operation, and it's a StartIO-based driver
|
||||
* (such as CDROM), then just use a single packet and use the retry logic
|
||||
* that's already built-in to the packet engine. Note that low-mem retry
|
||||
* cannot be used directly because some write methods do not work if the
|
||||
* writes are only PAGE_SIZE (i.e. packet writing may corrupt data).
|
||||
*/
|
||||
NT_ASSERT(!Pkt->InLowMemRetry);
|
||||
|
||||
/*
|
||||
* We precomputed fdoData->HwMaxXferLen using (MaximumPhysicalPages-1).
|
||||
* If the buffer is page-aligned, that's one less page crossing so we can add the page back in.
|
||||
* Note: adapters that return MaximumPhysicalPages=0x10 depend on this to
|
||||
* transfer aligned 64K requests in one piece.
|
||||
* Also note: make sure adding PAGE_SIZE back in doesn't wrap to zero.
|
||||
*/
|
||||
|
||||
if (((ULONG_PTR)(Pkt->LowMemRetry_remainingBufPtr) & (PAGE_SIZE-1)) || (fdoData->HwMaxXferLen > 0xffffffff-PAGE_SIZE)){
|
||||
hwMaxXferLen = fdoData->HwMaxXferLen;
|
||||
}
|
||||
else {
|
||||
NT_ASSERT((PAGE_SIZE%fdoExt->DiskGeometry.BytesPerSector) == 0);
|
||||
hwMaxXferLen = min(fdoData->HwMaxXferLen+PAGE_SIZE, adapterDesc->MaximumTransferLength);
|
||||
}
|
||||
thisChunkLen = MIN(Pkt->LowMemRetry_remainingBufLen, hwMaxXferLen);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Make sure the little chunk we send is <= a page length
|
||||
* AND that it does not cross any page boundaries.
|
||||
*/
|
||||
ULONG bytesToNextPageBoundary;
|
||||
bytesToNextPageBoundary = PAGE_SIZE-(ULONG)((ULONG_PTR)Pkt->LowMemRetry_remainingBufPtr%PAGE_SIZE);
|
||||
thisChunkLen = MIN(Pkt->LowMemRetry_remainingBufLen, bytesToNextPageBoundary);
|
||||
NT_ASSERT(Pkt->InLowMemRetry);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set up the transfer packet for the new little chunk.
|
||||
* This will reset numRetries so that we retry each chunk as required.
|
||||
*/
|
||||
SetupReadWriteTransferPacket(Pkt,
|
||||
Pkt->LowMemRetry_remainingBufPtr,
|
||||
thisChunkLen,
|
||||
Pkt->LowMemRetry_nextChunkTargetLocation,
|
||||
Pkt->OriginalIrp);
|
||||
|
||||
Pkt->LowMemRetry_remainingBufPtr += thisChunkLen;
|
||||
Pkt->LowMemRetry_remainingBufLen -= thisChunkLen;
|
||||
Pkt->LowMemRetry_nextChunkTargetLocation.QuadPart += thisChunkLen;
|
||||
|
||||
//
|
||||
// When running in low-memory stress, always use a partial MDL.
|
||||
// This allows lower drivers to potentially map a smaller buffer.
|
||||
//
|
||||
Pkt->UsePartialMdl = TRUE;
|
||||
|
||||
TransferPacketQueueRetryDpc(Pkt);
|
||||
|
||||
packetDone = FALSE;
|
||||
}
|
||||
|
||||
return packetDone;
|
||||
}
|
||||
|
376
drivers/storage/class/classpnp/srblib.c
Normal file
376
drivers/storage/class/classpnp/srblib.c
Normal file
|
@ -0,0 +1,376 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation 2010
|
||||
|
||||
Module Name:
|
||||
|
||||
srblib.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Header for SRB utility functions
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "classp.h"
|
||||
|
||||
PVOID
|
||||
DefaultStorageRequestBlockAllocateRoutine(
|
||||
_In_ CLONG ByteSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Default allocation routine.
|
||||
|
||||
Arguments:
|
||||
|
||||
ByteSize - SRB size in bytes.
|
||||
|
||||
Return Value:
|
||||
|
||||
Pointer to the SRB buffer. NULL if SRB buffer could not be allocated.
|
||||
|
||||
--*/
|
||||
{
|
||||
return ExAllocatePoolWithTag(NonPagedPoolNx, ByteSize, '+brs');
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
pInitializeStorageRequestBlock(
|
||||
_Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb,
|
||||
_In_ USHORT AddressType,
|
||||
_In_ ULONG ByteSize,
|
||||
_In_ ULONG NumSrbExData,
|
||||
_In_ va_list ap
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize a STORAGE_REQUEST_BLOCK.
|
||||
|
||||
Arguments:
|
||||
|
||||
Srb - Pointer to STORAGE_REQUEST_BLOCK to initialize.
|
||||
|
||||
AddressType - Storage address type.
|
||||
|
||||
ByteSize - STORAGE_REQUEST_BLOCK size in bytes.
|
||||
|
||||
NumSrbExData - Number of SRB extended data.
|
||||
|
||||
ap - Variable argument list matching the SRB extended data in the
|
||||
STORAGE_REQUEST_BLOCK.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PSTOR_ADDRESS address;
|
||||
PSRBEX_DATA srbExData;
|
||||
ULONG offset;
|
||||
ULONG length = (ULONG)-1;
|
||||
SRBEXDATATYPE type;
|
||||
ULONG srbExDataLength = (ULONG)-1;
|
||||
ULONG varLength;
|
||||
ULONG i;
|
||||
|
||||
if (ByteSize < sizeof(STORAGE_REQUEST_BLOCK)) {
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
RtlZeroMemory(Srb, ByteSize);
|
||||
|
||||
Srb->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
|
||||
Srb->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
|
||||
Srb->Signature = SRB_SIGNATURE;
|
||||
Srb->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
|
||||
Srb->SrbLength = ByteSize;
|
||||
Srb->NumSrbExData = NumSrbExData;
|
||||
|
||||
offset = sizeof(STORAGE_REQUEST_BLOCK);
|
||||
if (NumSrbExData > 0) {
|
||||
offset += ((NumSrbExData - 1) * sizeof(ULONG));
|
||||
|
||||
// Ensure offset is pointer type aligned
|
||||
if (offset % sizeof(PVOID)) {
|
||||
offset += (sizeof(PVOID) - (offset % sizeof(PVOID)));
|
||||
}
|
||||
}
|
||||
Srb->AddressOffset = offset;
|
||||
|
||||
if (AddressType == STORAGE_ADDRESS_TYPE_BTL8)
|
||||
{
|
||||
if ((ByteSize < offset) ||
|
||||
(ByteSize < (offset + sizeof(STOR_ADDR_BTL8)))) {
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
address = (PSTOR_ADDRESS)((PUCHAR)Srb + offset);
|
||||
address->Type = STOR_ADDRESS_TYPE_BTL8;
|
||||
address->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
|
||||
offset += sizeof(STOR_ADDR_BTL8);
|
||||
} else
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
for (i = 0; i < NumSrbExData && status == STATUS_SUCCESS; i++)
|
||||
{
|
||||
if (ByteSize <= offset) {
|
||||
status = STATUS_BUFFER_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
srbExData = (PSRBEX_DATA)((PUCHAR)Srb + offset);
|
||||
Srb->SrbExDataOffset[i] = offset;
|
||||
|
||||
type = va_arg(ap, SRBEXDATATYPE);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SrbExDataTypeBidirectional:
|
||||
length = sizeof(SRBEX_DATA_BIDIRECTIONAL);
|
||||
srbExDataLength = SRBEX_DATA_BIDIRECTIONAL_LENGTH;
|
||||
break;
|
||||
case SrbExDataTypeScsiCdb16:
|
||||
length = sizeof(SRBEX_DATA_SCSI_CDB16);
|
||||
srbExDataLength = SRBEX_DATA_SCSI_CDB16_LENGTH;
|
||||
break;
|
||||
case SrbExDataTypeScsiCdb32:
|
||||
length = sizeof(SRBEX_DATA_SCSI_CDB32);
|
||||
srbExDataLength = SRBEX_DATA_SCSI_CDB32_LENGTH;
|
||||
break;
|
||||
case SrbExDataTypeScsiCdbVar:
|
||||
varLength = va_arg(ap, ULONG);
|
||||
length = sizeof(SRBEX_DATA_SCSI_CDB_VAR) + varLength;
|
||||
srbExDataLength = SRBEX_DATA_SCSI_CDB_VAR_LENGTH_MIN + varLength;
|
||||
break;
|
||||
case SrbExDataTypeWmi:
|
||||
length = sizeof(SRBEX_DATA_WMI);
|
||||
srbExDataLength = SRBEX_DATA_WMI_LENGTH;
|
||||
break;
|
||||
case SrbExDataTypePower:
|
||||
length = sizeof(SRBEX_DATA_POWER);
|
||||
srbExDataLength = SRBEX_DATA_POWER_LENGTH;
|
||||
break;
|
||||
case SrbExDataTypePnP:
|
||||
length = sizeof(SRBEX_DATA_PNP);
|
||||
srbExDataLength = SRBEX_DATA_PNP_LENGTH;
|
||||
break;
|
||||
case SrbExDataTypeIoInfo:
|
||||
length = sizeof(SRBEX_DATA_IO_INFO);
|
||||
srbExDataLength = SRBEX_DATA_IO_INFO_LENGTH;
|
||||
break;
|
||||
default:
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == STATUS_SUCCESS)
|
||||
{
|
||||
NT_ASSERT(length != (ULONG)-1);
|
||||
|
||||
if (ByteSize < (offset + length)) {
|
||||
status = STATUS_BUFFER_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
|
||||
NT_ASSERT(srbExDataLength != (ULONG)-1);
|
||||
|
||||
srbExData->Type = type;
|
||||
srbExData->Length = srbExDataLength;
|
||||
offset += length;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
InitializeStorageRequestBlock(
|
||||
_Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb,
|
||||
_In_ USHORT AddressType,
|
||||
_In_ ULONG ByteSize,
|
||||
_In_ ULONG NumSrbExData,
|
||||
...
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize an extended SRB.
|
||||
|
||||
Arguments:
|
||||
|
||||
Srb - Pointer to SRB buffer to initialize.
|
||||
|
||||
AddressType - Storage address type.
|
||||
|
||||
ByteSize - STORAGE_REQUEST_BLOCK size in bytes.
|
||||
|
||||
NumSrbExData - Number of SRB extended data.
|
||||
|
||||
... - Variable argument list matching the SRB extended data in the
|
||||
STORAGE_REQUEST_BLOCK.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
NTSTATUS status;
|
||||
va_list ap;
|
||||
va_start(ap, NumSrbExData);
|
||||
status = pInitializeStorageRequestBlock(Srb, AddressType, ByteSize, NumSrbExData, ap);
|
||||
va_end(ap);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CreateStorageRequestBlock(
|
||||
_Inout_ PSTORAGE_REQUEST_BLOCK *Srb,
|
||||
_In_ USHORT AddressType,
|
||||
_In_opt_ PSRB_ALLOCATE_ROUTINE AllocateRoutine,
|
||||
_Inout_opt_ ULONG *ByteSize,
|
||||
_In_ ULONG NumSrbExData,
|
||||
...
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Create an extended SRB.
|
||||
|
||||
Arguments:
|
||||
|
||||
Srb - Pointer to buffer to store SRB pointer.
|
||||
|
||||
AddressType - Storage address type.
|
||||
|
||||
AllocateRoutine - Buffer allocation function (optional).
|
||||
|
||||
ByteSize - Pointer to ULONG to store size of SRB in bytes (optional).
|
||||
|
||||
NumSrbExData - Number of SRB extended data.
|
||||
|
||||
... - Variable argument list matching the SRB extended data in the
|
||||
STORAGE_REQUEST_BLOCK.
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
ULONG sizeNeeded = 0;
|
||||
va_list ap;
|
||||
ULONG i;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
// Ensure SrbExData offsets are pointer type aligned
|
||||
sizeNeeded = sizeof(STORAGE_REQUEST_BLOCK);
|
||||
if (NumSrbExData > 0) {
|
||||
sizeNeeded += ((NumSrbExData - 1) * sizeof(ULONG));
|
||||
if (sizeNeeded % sizeof(PVOID)) {
|
||||
sizeNeeded += (sizeof(PVOID) - (sizeNeeded % sizeof(PVOID)));
|
||||
}
|
||||
}
|
||||
|
||||
if (AddressType == STORAGE_ADDRESS_TYPE_BTL8)
|
||||
{
|
||||
sizeNeeded += sizeof(STOR_ADDR_BTL8);
|
||||
} else
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
va_start(ap, NumSrbExData);
|
||||
|
||||
for (i = 0; i < NumSrbExData && status == STATUS_SUCCESS; i++)
|
||||
{
|
||||
switch (va_arg(ap, SRBEXDATATYPE))
|
||||
{
|
||||
case SrbExDataTypeBidirectional:
|
||||
sizeNeeded += sizeof(SRBEX_DATA_BIDIRECTIONAL);
|
||||
break;
|
||||
case SrbExDataTypeScsiCdb16:
|
||||
sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB16);
|
||||
break;
|
||||
case SrbExDataTypeScsiCdb32:
|
||||
sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB32);
|
||||
break;
|
||||
case SrbExDataTypeScsiCdbVar:
|
||||
sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB_VAR) + va_arg(ap, ULONG);
|
||||
break;
|
||||
case SrbExDataTypeWmi:
|
||||
sizeNeeded += sizeof(SRBEX_DATA_WMI);
|
||||
break;
|
||||
case SrbExDataTypePower:
|
||||
sizeNeeded += sizeof(SRBEX_DATA_POWER);
|
||||
break;
|
||||
case SrbExDataTypePnP:
|
||||
sizeNeeded += sizeof(SRBEX_DATA_PNP);
|
||||
break;
|
||||
case SrbExDataTypeIoInfo:
|
||||
sizeNeeded += sizeof(SRBEX_DATA_IO_INFO);
|
||||
break;
|
||||
default:
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (status == STATUS_SUCCESS)
|
||||
{
|
||||
if (AllocateRoutine)
|
||||
{
|
||||
*Srb = AllocateRoutine(sizeNeeded);
|
||||
if (*Srb == NULL)
|
||||
{
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
if (ByteSize != NULL)
|
||||
{
|
||||
*ByteSize = sizeNeeded;
|
||||
}
|
||||
|
||||
if (*Srb)
|
||||
{
|
||||
va_start(ap, NumSrbExData);
|
||||
#ifdef _MSC_VER
|
||||
#pragma prefast(suppress:26015, "pInitializeStorageRequestBlock will set the SrbLength field")
|
||||
#endif
|
||||
status = pInitializeStorageRequestBlock(*Srb, AddressType, sizeNeeded, NumSrbExData, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
9165
drivers/storage/class/classpnp/utils.c
Normal file
9165
drivers/storage/class/classpnp/utils.c
Normal file
File diff suppressed because it is too large
Load diff
2083
drivers/storage/class/classpnp/xferpkt.c
Normal file
2083
drivers/storage/class/classpnp/xferpkt.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue