mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 08:03:01 +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