You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1019 lines
27 KiB
1019 lines
27 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1991 - 1999
|
|
|
|
Module Name:
|
|
|
|
classp.h
|
|
|
|
Abstract:
|
|
|
|
Private header file for classpnp.sys modules. This contains private
|
|
structure and function declarations as well as constant values which do
|
|
not need to be exported.
|
|
|
|
Author:
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include <stddef.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <ntddk.h>
|
|
|
|
#include <scsi.h>
|
|
#include <wmidata.h>
|
|
#include <classpnp.h>
|
|
|
|
#if CLASS_INIT_GUID
|
|
#include <initguid.h>
|
|
#endif
|
|
|
|
#include <mountdev.h>
|
|
#include <ioevent.h>
|
|
|
|
|
|
/*
|
|
* IA64 requires 8-byte alignment for pointers, but the IA64 NT kernel expects 16-byte alignment
|
|
*/
|
|
#ifdef _WIN64
|
|
#define PTRALIGN DECLSPEC_ALIGN(16)
|
|
#else
|
|
#define PTRALIGN
|
|
#endif
|
|
|
|
|
|
extern CLASSPNP_SCAN_FOR_SPECIAL_INFO ClassBadItems[];
|
|
|
|
extern GUID ClassGuidQueryRegInfoEx;
|
|
|
|
extern ULONG ClassMaxInterleavePerCriticalIo;
|
|
|
|
#define CLASSP_REG_SUBKEY_NAME (L"Classpnp")
|
|
|
|
#define CLASSP_REG_HACK_VALUE_NAME (L"HackMask")
|
|
#define CLASSP_REG_MMC_DETECTION_VALUE_NAME (L"MMCDetectionState")
|
|
#define CLASSP_REG_WRITE_CACHE_VALUE_NAME (L"WriteCacheEnableOverride")
|
|
#define CLASSP_REG_PERF_RESTORE_VALUE_NAME (L"RestorePerfAtCount")
|
|
#define CLASSP_REG_REMOVAL_POLICY_VALUE_NAME (L"UserRemovalPolicy")
|
|
|
|
#define CLASS_PERF_RESTORE_MINIMUM (0x10)
|
|
#define CLASS_ERROR_LEVEL_1 (0x4)
|
|
#define CLASS_ERROR_LEVEL_2 (0x8)
|
|
#define CLASS_MAX_INTERLEAVE_PER_CRITICAL_IO (0x4)
|
|
|
|
#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_VALID_FLAGS (0x0000000F)
|
|
#define FDO_HACK_INVALID_FLAGS (~FDO_HACK_VALID_FLAGS)
|
|
|
|
/*
|
|
* Lots of retries of synchronized SCSI commands that devices may not
|
|
* even support really slows down the system (especially while booting).
|
|
* (Even GetDriveCapacity may be failed on purpose if an external disk is powered off).
|
|
* If a disk cannot return a small initialization buffer at startup
|
|
* in two attempts (with delay interval) then we cannot expect it to return
|
|
* data consistently with four retries.
|
|
* So don't set the retry counts as high here as for data SRBs.
|
|
*
|
|
* If we find that these requests are failing consecutively,
|
|
* despite the retry interval, on otherwise reliable media,
|
|
* then we should either increase the retry interval for
|
|
* that failure or (by all means) increase these retry counts as appropriate.
|
|
*/
|
|
#define NUM_LOCKMEDIAREMOVAL_RETRIES 1
|
|
#define NUM_MODESENSE_RETRIES 1
|
|
#define NUM_DRIVECAPACITY_RETRIES 1
|
|
|
|
/*
|
|
* We retry failed I/O requests at 1-second intervals.
|
|
* In the case of a failure due to bus reset, we want to make sure that we retry after the allowable
|
|
* reset time. For SCSI, the allowable reset time is 5 seconds. ScsiPort queues requests during
|
|
* a bus reset, which should cause us to retry after the reset is over; but the requests queued in
|
|
* the miniport are failed all the way back to us immediately. In any event, in order to make
|
|
* extra sure that our retries span the allowable reset time, we should retry more than 5 times.
|
|
*/
|
|
#define NUM_IO_RETRIES 8
|
|
|
|
#define CLASS_FILE_OBJECT_EXTENSION_KEY 'eteP'
|
|
#define CLASSP_VOLUME_VERIFY_CHECKED 0x34
|
|
|
|
#define CLASS_TAG_PRIVATE_DATA 'CPcS'
|
|
#define CLASS_TAG_PRIVATE_DATA_FDO 'FPcS'
|
|
#define CLASS_TAG_PRIVATE_DATA_PDO 'PPcS'
|
|
|
|
//
|
|
// Definitions from ntos\rtl\time.c
|
|
//
|
|
|
|
extern CONST LARGE_INTEGER Magic10000;
|
|
#define SHIFT10000 13
|
|
|
|
#define Convert100nsToMilliseconds(LARGE_INTEGER) \
|
|
( \
|
|
RtlExtendedMagicDivide((LARGE_INTEGER), Magic10000, SHIFT10000) \
|
|
)
|
|
|
|
typedef struct _MEDIA_CHANGE_DETECTION_INFO {
|
|
|
|
//
|
|
// Mutex to synchronize enable/disable requests and media state changes
|
|
//
|
|
|
|
KMUTEX MediaChangeMutex;
|
|
|
|
//
|
|
// The current state of the media (present, not present, unknown)
|
|
// protected by MediaChangeSynchronizationEvent
|
|
//
|
|
|
|
MEDIA_CHANGE_DETECTION_STATE MediaChangeDetectionState;
|
|
|
|
//
|
|
// This is a count of how many time MCD has been disabled. if it is
|
|
// set to zero, then we'll poll the device for MCN events with the
|
|
// then-current method (ie. TEST UNIT READY or GESN). this is
|
|
// protected by MediaChangeMutex
|
|
//
|
|
|
|
LONG MediaChangeDetectionDisableCount;
|
|
|
|
|
|
//
|
|
// The timer value to support media change events. This is a countdown
|
|
// value used to determine when to poll the device for a media change.
|
|
// The max value for the timer is 255 seconds. This is not protected
|
|
// by an event -- simply InterlockedExchanged() as needed.
|
|
//
|
|
|
|
LONG MediaChangeCountDown;
|
|
|
|
//
|
|
// recent changes allowed instant retries of the MCN irp. Since this
|
|
// could cause an infinite loop, keep a count of how many times we've
|
|
// retried immediately so that we can catch if the count exceeds an
|
|
// arbitrary limit.
|
|
//
|
|
|
|
LONG MediaChangeRetryCount;
|
|
|
|
//
|
|
// use GESN if it's available
|
|
//
|
|
|
|
struct {
|
|
BOOLEAN Supported;
|
|
BOOLEAN HackEventMask;
|
|
UCHAR EventMask;
|
|
UCHAR NoChangeEventMask;
|
|
PUCHAR Buffer;
|
|
PMDL Mdl;
|
|
ULONG BufferSize;
|
|
} Gesn;
|
|
|
|
//
|
|
// If this value is one, then the irp is currently in use.
|
|
// If this value is zero, then the irp is available.
|
|
// Use InterlockedCompareExchange() to set from "available" to "in use".
|
|
// ASSERT that InterlockedCompareExchange() showed previous value of
|
|
// "in use" when changing back to "available" state.
|
|
// This also implicitly protects the MediaChangeSrb and SenseBuffer
|
|
//
|
|
|
|
LONG MediaChangeIrpInUse;
|
|
|
|
//
|
|
// Pointer to the irp to be used for media change detection.
|
|
// protected by Interlocked MediaChangeIrpInUse
|
|
//
|
|
|
|
PIRP MediaChangeIrp;
|
|
|
|
//
|
|
// The srb for the media change detection.
|
|
// protected by Interlocked MediaChangeIrpInUse
|
|
//
|
|
|
|
SCSI_REQUEST_BLOCK MediaChangeSrb;
|
|
PUCHAR SenseBuffer;
|
|
ULONG SrbFlags;
|
|
|
|
//
|
|
// Second timer to keep track of how long the media change IRP has been
|
|
// in use. If this value exceeds the timeout (#defined) then we should
|
|
// print out a message to the user and set the MediaChangeIrpLost flag
|
|
// protected by using Interlocked() operations in ClasspSendMediaStateIrp,
|
|
// the only routine which should modify this value.
|
|
//
|
|
|
|
LONG MediaChangeIrpTimeInUse;
|
|
|
|
//
|
|
// Set by CdRomTickHandler when we determine that the media change irp has
|
|
// been lost
|
|
//
|
|
|
|
BOOLEAN MediaChangeIrpLost;
|
|
|
|
};
|
|
|
|
typedef enum {
|
|
SimpleMediaLock,
|
|
SecureMediaLock,
|
|
InternalMediaLock
|
|
} MEDIA_LOCK_TYPE, *PMEDIA_LOCK_TYPE;
|
|
|
|
typedef struct _FAILURE_PREDICTION_INFO {
|
|
FAILURE_PREDICTION_METHOD Method;
|
|
ULONG CountDown; // Countdown timer
|
|
ULONG Period; // Countdown period
|
|
|
|
PIO_WORKITEM WorkQueueItem;
|
|
|
|
KEVENT Event;
|
|
} FAILURE_PREDICTION_INFO, *PFAILURE_PREDICTION_INFO;
|
|
|
|
|
|
|
|
//
|
|
// This struct must always fit within four PVOIDs of info,
|
|
// as it uses the irp's "PVOID DriverContext[4]" to store
|
|
// this info
|
|
//
|
|
typedef struct _CLASS_RETRY_INFO {
|
|
struct _CLASS_RETRY_INFO *Next;
|
|
} CLASS_RETRY_INFO, *PCLASS_RETRY_INFO;
|
|
|
|
|
|
|
|
typedef struct _CSCAN_LIST {
|
|
|
|
//
|
|
// The current block which has an outstanding request.
|
|
//
|
|
|
|
ULONGLONG BlockNumber;
|
|
|
|
//
|
|
// The list of blocks past the CurrentBlock to which we're going to do
|
|
// i/o. This list is maintained in sorted order.
|
|
//
|
|
|
|
LIST_ENTRY CurrentSweep;
|
|
|
|
//
|
|
// The list of blocks behind the current block for which we'll have to
|
|
// wait until the next scan across the disk. This is kept as a stack,
|
|
// the cost of sorting it is taken when it's moved over to be the
|
|
// running list.
|
|
//
|
|
|
|
LIST_ENTRY NextSweep;
|
|
|
|
} CSCAN_LIST, *PCSCAN_LIST;
|
|
|
|
//
|
|
// add to the front of this structure to help prevent illegal
|
|
// snooping by other utilities.
|
|
//
|
|
|
|
|
|
|
|
typedef enum _CLASS_DETECTION_STATE {
|
|
ClassDetectionUnknown = 0,
|
|
ClassDetectionUnsupported = 1,
|
|
ClassDetectionSupported = 2
|
|
} CLASS_DETECTION_STATE, *PCLASS_DETECTION_STATE;
|
|
|
|
|
|
typedef struct _CLASS_ERROR_LOG_DATA {
|
|
LARGE_INTEGER TickCount; // Offset 0x00
|
|
ULONG PortNumber; // Offset 0x08
|
|
|
|
UCHAR ErrorPaging : 1; // Offset 0x0c
|
|
UCHAR ErrorRetried : 1;
|
|
UCHAR ErrorUnhandled : 1;
|
|
UCHAR ErrorReserved : 5;
|
|
|
|
UCHAR Reserved[3];
|
|
|
|
SCSI_REQUEST_BLOCK Srb; // Offset 0x10
|
|
|
|
/*
|
|
* We define the SenseData as the default length.
|
|
* Since the sense data returned by the port driver may be longer,
|
|
* SenseData must be at the end of this structure.
|
|
* For our internal error log, we only log the default length.
|
|
*/
|
|
SENSE_DATA SenseData; // Offset 0x50 for x86 (or 0x68 for ia64) (ULONG32 Alignment required!)
|
|
} CLASS_ERROR_LOG_DATA, *PCLASS_ERROR_LOG_DATA;
|
|
|
|
#define NUM_ERROR_LOG_ENTRIES 16
|
|
#define DBG_NUM_PACKET_LOG_ENTRIES (64*2) // 64 send&receive's
|
|
|
|
typedef struct _TRANSFER_PACKET {
|
|
|
|
LIST_ENTRY AllPktsListEntry; // entry in fdoData's static AllTransferPacketsList
|
|
SLIST_ENTRY SlistEntry; // for when in free list (use fast slist)
|
|
|
|
PIRP Irp;
|
|
PDEVICE_OBJECT Fdo;
|
|
|
|
/*
|
|
* This is the client IRP that this TRANSFER_PACKET is currently
|
|
* servicing.
|
|
*/
|
|
PIRP OriginalIrp;
|
|
BOOLEAN CompleteOriginalIrpWhenLastPacketCompletes;
|
|
|
|
/*
|
|
* Stuff for retrying the transfer.
|
|
*/
|
|
ULONG NumRetries;
|
|
KTIMER RetryTimer;
|
|
KDPC RetryTimerDPC;
|
|
ULONG RetryIntervalSec;
|
|
|
|
/*
|
|
* Event for synchronizing the transfer (optional).
|
|
* (Note that we can't have the event in the packet itself because
|
|
* by the time a thread waits on an event the packet may have
|
|
* been completed and re-issued.
|
|
*/
|
|
PKEVENT SyncEventPtr;
|
|
|
|
/*
|
|
* Stuff for retrying during extreme low-memory stress
|
|
* (when we retry 1 page at a time).
|
|
*/
|
|
BOOLEAN InLowMemRetry;
|
|
PUCHAR LowMemRetry_remainingBufPtr;
|
|
ULONG LowMemRetry_remainingBufLen;
|
|
LARGE_INTEGER LowMemRetry_nextChunkTargetLocation;
|
|
|
|
/*
|
|
* Fields used for cancelling the packet.
|
|
*/
|
|
// BOOLEAN Cancelled;
|
|
// KEVENT CancelledEvent;
|
|
|
|
/*
|
|
* We keep the buffer and length values here as well
|
|
* as in the SRB because some miniports return
|
|
* the transferred length in SRB.DataTransferLength,
|
|
* and if the SRB failed we need that value again for the retry.
|
|
* We don't trust the lower stack to preserve any of these values in the SRB.
|
|
*/
|
|
PUCHAR BufPtrCopy;
|
|
ULONG BufLenCopy;
|
|
LARGE_INTEGER TargetLocationCopy;
|
|
|
|
/*
|
|
* This is a standard SCSI structure that receives a detailed
|
|
* report about a SCSI error on the hardware.
|
|
*/
|
|
SENSE_DATA SrbErrorSenseData;
|
|
|
|
/*
|
|
* This is the SRB block for this TRANSFER_PACKET.
|
|
* For IOCTLs, the SRB block includes two DWORDs for
|
|
* device object and ioctl code; so these must
|
|
* immediately follow the SRB block.
|
|
*/
|
|
SCSI_REQUEST_BLOCK Srb;
|
|
// ULONG SrbIoctlDevObj; // not handling ioctls yet
|
|
// ULONG SrbIoctlCode;
|
|
|
|
#if DBG
|
|
LARGE_INTEGER DbgTimeSent;
|
|
LARGE_INTEGER DbgTimeReturned;
|
|
ULONG DbgPktId;
|
|
IRP DbgOriginalIrpCopy;
|
|
MDL DbgMdlCopy;
|
|
#endif
|
|
|
|
} TRANSFER_PACKET, *PTRANSFER_PACKET;
|
|
|
|
/*
|
|
* MIN_INITIAL_TRANSFER_PACKETS is the minimum number of packets that
|
|
* we preallocate at startup for each device (we need at least one packet
|
|
* to guarantee forward progress during memory stress).
|
|
* MIN_WORKINGSET_TRANSFER_PACKETS is the number of TRANSFER_PACKETs
|
|
* we allow to build up and remain for each device;
|
|
* we _lazily_ work down to this number when they're not needed.
|
|
* MAX_WORKINGSET_TRANSFER_PACKETS is the number of TRANSFER_PACKETs
|
|
* that we _immediately_ reduce to when they are not needed.
|
|
*
|
|
* The absolute maximum number of packets that we will allocate is
|
|
* whatever is required by the current activity, up to the memory limit;
|
|
* as soon as stress ends, we snap down to MAX_WORKINGSET_TRANSFER_PACKETS;
|
|
* we then lazily work down to MIN_WORKINGSET_TRANSFER_PACKETS.
|
|
*/
|
|
#define MIN_INITIAL_TRANSFER_PACKETS 1
|
|
#define MIN_WORKINGSET_TRANSFER_PACKETS_Consumer 4
|
|
#define MAX_WORKINGSET_TRANSFER_PACKETS_Consumer 64
|
|
#define MIN_WORKINGSET_TRANSFER_PACKETS_Server 64
|
|
#define MAX_WORKINGSET_TRANSFER_PACKETS_Server 1024
|
|
#define MIN_WORKINGSET_TRANSFER_PACKETS_Enterprise 256
|
|
#define MAX_WORKINGSET_TRANSFER_PACKETS_Enterprise 2048
|
|
|
|
|
|
//
|
|
// add to the front of this structure to help prevent illegal
|
|
// snooping by other utilities.
|
|
//
|
|
struct _CLASS_PRIVATE_FDO_DATA {
|
|
|
|
/*
|
|
* Entry in static list used by debug extension to quickly find all class FDOs.
|
|
*/
|
|
LIST_ENTRY AllFdosListEntry;
|
|
|
|
//
|
|
// this private structure allows us to
|
|
// dynamically re-enable the perf benefits
|
|
// lost due to transient error conditions.
|
|
// in w2k, a reboot was required. :(
|
|
//
|
|
struct {
|
|
ULONG OriginalSrbFlags;
|
|
ULONG SuccessfulIO;
|
|
ULONG ReEnableThreshhold; // 0 means never
|
|
} Perf;
|
|
|
|
ULONG_PTR HackFlags;
|
|
|
|
STORAGE_HOTPLUG_INFO HotplugInfo;
|
|
|
|
// Legacy. Still used by obsolete legacy code.
|
|
struct {
|
|
LARGE_INTEGER Delta; // in ticks
|
|
LARGE_INTEGER Tick; // when it should fire
|
|
PCLASS_RETRY_INFO ListHead; // singly-linked list
|
|
ULONG Granularity; // static
|
|
KSPIN_LOCK Lock; // protective spin lock
|
|
KDPC Dpc; // DPC routine object
|
|
KTIMER Timer; // timer to fire DPC
|
|
} Retry;
|
|
|
|
BOOLEAN TimerStarted;
|
|
BOOLEAN LoggedTURFailureSinceLastIO;
|
|
BOOLEAN LoggedSYNCFailure;
|
|
|
|
//
|
|
// privately allocated release queue irp
|
|
// protected by fdoExtension->ReleaseQueueSpinLock
|
|
//
|
|
BOOLEAN ReleaseQueueIrpAllocated;
|
|
PIRP ReleaseQueueIrp;
|
|
|
|
/*
|
|
* Queues for TRANSFER_PACKETs that contextualize the IRPs and SRBs
|
|
* that we send down to the port driver.
|
|
* (The free list is an slist so that we can use fast
|
|
* interlocked operations on it; but the relatively-static
|
|
* AllTransferPacketsList list has to be
|
|
* a doubly-linked list since we have to dequeue from the middle).
|
|
*/
|
|
LIST_ENTRY AllTransferPacketsList;
|
|
SLIST_HEADER FreeTransferPacketsList;
|
|
ULONG NumFreeTransferPackets;
|
|
ULONG NumTotalTransferPackets;
|
|
ULONG DbgPeakNumTransferPackets;
|
|
|
|
/*
|
|
* Queue for deferred client irps
|
|
*/
|
|
LIST_ENTRY DeferredClientIrpList;
|
|
|
|
/*
|
|
* Precomputed maximum transfer length for the hardware.
|
|
*/
|
|
ULONG HwMaxXferLen;
|
|
|
|
/*
|
|
* SCSI_REQUEST_BLOCK template preconfigured with the constant values.
|
|
* This is slapped into the SRB in the TRANSFER_PACKET for each transfer.
|
|
*/
|
|
SCSI_REQUEST_BLOCK SrbTemplate;
|
|
|
|
KSPIN_LOCK SpinLock;
|
|
|
|
/*
|
|
* For non-removable media, we read the drive capacity at start time and cache it.
|
|
* This is so that ReadDriveCapacity failures at runtime (e.g. due to memory stress)
|
|
* don't cause I/O on the paging disk to start failing.
|
|
*/
|
|
READ_CAPACITY_DATA LastKnownDriveCapacityData;
|
|
BOOLEAN IsCachedDriveCapDataValid;
|
|
|
|
/*
|
|
* Circular array of timestamped logs of errors that occurred on this device.
|
|
*/
|
|
ULONG ErrorLogNextIndex;
|
|
CLASS_ERROR_LOG_DATA ErrorLogs[NUM_ERROR_LOG_ENTRIES];
|
|
|
|
//
|
|
// Number of outstanding critical Io requests from Mm
|
|
//
|
|
ULONG NumHighPriorityPagingIo;
|
|
|
|
//
|
|
// Maximum number of normal Io requests that can be interleaved with the critical ones
|
|
//
|
|
ULONG MaxInterleavedNormalIo;
|
|
|
|
//
|
|
// The timestamp when entering throttle mode
|
|
//
|
|
LARGE_INTEGER ThrottleStartTime;
|
|
|
|
//
|
|
// The timestamp when exiting throttle mode
|
|
//
|
|
LARGE_INTEGER ThrottleStopTime;
|
|
|
|
//
|
|
// The longest time ever spent in throttle mode
|
|
//
|
|
LARGE_INTEGER LongestThrottlePeriod;
|
|
|
|
#if DBG
|
|
ULONG DbgMaxPktId;
|
|
|
|
/*
|
|
* Logging fields for ForceUnitAccess and Flush
|
|
*/
|
|
BOOLEAN DbgInitFlushLogging; // must reset this to 1 for each logging session
|
|
ULONG DbgNumIORequests;
|
|
ULONG DbgNumFUAs; // num I/O requests with ForceUnitAccess bit set
|
|
ULONG DbgNumFlushes; // num SRB_FUNCTION_FLUSH_QUEUE
|
|
ULONG DbgIOsSinceFUA;
|
|
ULONG DbgIOsSinceFlush;
|
|
ULONG DbgAveIOsToFUA; // average number of I/O requests between FUAs
|
|
ULONG DbgAveIOsToFlush; // ...
|
|
ULONG DbgMaxIOsToFUA;
|
|
ULONG DbgMaxIOsToFlush;
|
|
ULONG DbgMinIOsToFUA;
|
|
ULONG DbgMinIOsToFlush;
|
|
|
|
/*
|
|
* Debug log of previously sent packets (including retries).
|
|
*/
|
|
ULONG DbgPacketLogNextIndex;
|
|
TRANSFER_PACKET DbgPacketLogs[DBG_NUM_PACKET_LOG_ENTRIES];
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
|
|
|
|
#define NOT_READY_RETRY_INTERVAL 10
|
|
#define MINIMUM_RETRY_UNITS ((LONGLONG)32)
|
|
|
|
|
|
/*
|
|
* Simple singly-linked-list queuing macros, with no synchronization.
|
|
*/
|
|
__inline VOID SimpleInitSlistHdr(SINGLE_LIST_ENTRY *SListHdr)
|
|
{
|
|
SListHdr->Next = NULL;
|
|
}
|
|
__inline VOID SimplePushSlist(SINGLE_LIST_ENTRY *SListHdr, SINGLE_LIST_ENTRY *SListEntry)
|
|
{
|
|
SListEntry->Next = SListHdr->Next;
|
|
SListHdr->Next = SListEntry;
|
|
}
|
|
__inline SINGLE_LIST_ENTRY *SimplePopSlist(SINGLE_LIST_ENTRY *SListHdr)
|
|
{
|
|
SINGLE_LIST_ENTRY *sListEntry = SListHdr->Next;
|
|
if (sListEntry){
|
|
SListHdr->Next = sListEntry->Next;
|
|
sListEntry->Next = NULL;
|
|
}
|
|
return sListEntry;
|
|
}
|
|
__inline BOOLEAN SimpleIsSlistEmpty(SINGLE_LIST_ENTRY *SListHdr)
|
|
{
|
|
return (SListHdr->Next == NULL);
|
|
}
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
VOID
|
|
ClassUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassCreateClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspCreateClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
ClasspCleanupProtectedLocks(
|
|
IN PFILE_OBJECT_EXTENSION FsContext
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspEjectionControl(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp,
|
|
IN MEDIA_LOCK_TYPE LockType,
|
|
IN BOOLEAN Lock
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassReadWrite(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassDeviceControlDispatch(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassDeviceControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassDispatchPnp(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassPnpStartDevice(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassInternalIoControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassShutdownFlush(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassSystemControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
//
|
|
// Class internal routines
|
|
//
|
|
|
|
NTSTATUS
|
|
ClassAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN OUT PDEVICE_OBJECT PhysicalDeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspSendSynchronousCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
RetryRequest(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PSCSI_REQUEST_BLOCK Srb,
|
|
BOOLEAN Associated,
|
|
ULONG RetryInterval
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassIoCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassPnpQueryFdoRelations(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassRetrieveDeviceRelations(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN DEVICE_RELATION_TYPE RelationType,
|
|
OUT PDEVICE_RELATIONS *DeviceRelations
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassGetPdoId(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN BUS_QUERY_ID_TYPE IdType,
|
|
IN PUNICODE_STRING IdString
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassQueryPnpCapabilities(
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
IN PDEVICE_CAPABILITIES Capabilities
|
|
);
|
|
|
|
VOID
|
|
ClasspStartIo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspPagingNotificationCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PDEVICE_OBJECT RealDeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspMediaChangeCompletion(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PVOID Context
|
|
);
|
|
|
|
PFILE_OBJECT_EXTENSION
|
|
ClasspGetFsContext(
|
|
IN PCOMMON_DEVICE_EXTENSION CommonExtension,
|
|
IN PFILE_OBJECT FileObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspMcnControl(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
|
IN PIRP Irp,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
);
|
|
|
|
VOID
|
|
ClasspRegisterMountedDeviceInterface(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspDisableTimer(
|
|
PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspEnableTimer(
|
|
PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
//
|
|
// routines for dictionary list support
|
|
//
|
|
|
|
VOID
|
|
InitializeDictionary(
|
|
IN PDICTIONARY Dictionary
|
|
);
|
|
|
|
BOOLEAN
|
|
TestDictionarySignature(
|
|
IN PDICTIONARY Dictionary
|
|
);
|
|
|
|
NTSTATUS
|
|
AllocateDictionaryEntry(
|
|
IN PDICTIONARY Dictionary,
|
|
IN ULONGLONG Key,
|
|
IN ULONG Size,
|
|
IN ULONG Tag,
|
|
OUT PVOID *Entry
|
|
);
|
|
|
|
PVOID
|
|
GetDictionaryEntry(
|
|
IN PDICTIONARY Dictionary,
|
|
IN ULONGLONG Key
|
|
);
|
|
|
|
VOID
|
|
FreeDictionaryEntry(
|
|
IN PDICTIONARY Dictionary,
|
|
IN PVOID Entry
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
ClasspAllocateReleaseRequest(
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
VOID
|
|
ClasspFreeReleaseRequest(
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassReleaseQueueCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
ClasspReleaseQueue(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP ReleaseQueueIrp
|
|
);
|
|
|
|
VOID
|
|
ClasspDisablePowerNotification(
|
|
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
|
);
|
|
|
|
//
|
|
// class power routines
|
|
//
|
|
|
|
NTSTATUS
|
|
ClassDispatchPower(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ClassMinimalPowerHandler(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
//
|
|
// Child list routines
|
|
//
|
|
|
|
VOID
|
|
ClassAddChild(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION Parent,
|
|
IN PPHYSICAL_DEVICE_EXTENSION Child,
|
|
IN BOOLEAN AcquireLock
|
|
);
|
|
|
|
PPHYSICAL_DEVICE_EXTENSION
|
|
ClassRemoveChild(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION Parent,
|
|
IN PPHYSICAL_DEVICE_EXTENSION Child,
|
|
IN BOOLEAN AcquireLock
|
|
);
|
|
|
|
VOID
|
|
ClasspRetryDpcTimer(
|
|
IN PCLASS_PRIVATE_FDO_DATA FdoData
|
|
);
|
|
|
|
VOID
|
|
ClasspRetryRequestDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Arg1,
|
|
IN PVOID Arg2
|
|
);
|
|
|
|
VOID
|
|
ClassFreeOrReuseSrb(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
);
|
|
|
|
VOID
|
|
ClassRetryRequest(
|
|
IN PDEVICE_OBJECT SelfDeviceObject,
|
|
IN PIRP Irp,
|
|
IN LARGE_INTEGER TimeDelta100ns // in 100ns units
|
|
);
|
|
|
|
VOID
|
|
ClasspBuildRequestEx(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION Fdo,
|
|
IN PIRP Irp,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspAllocateReleaseQueueIrp(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspInitializeGesn(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
|
IN PMEDIA_CHANGE_DETECTION_INFO Info
|
|
);
|
|
|
|
VOID
|
|
ClasspSendNotification(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
|
IN const GUID * Guid,
|
|
IN ULONG ExtraDataSize,
|
|
IN PVOID ExtraData
|
|
);
|
|
|
|
VOID
|
|
ClassSendEjectionNotification(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
|
);
|
|
|
|
VOID
|
|
ClasspScanForSpecialInRegistry(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
|
);
|
|
|
|
VOID
|
|
ClasspScanForClassHacks(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
|
IN ULONG_PTR Data
|
|
);
|
|
|
|
NTSTATUS
|
|
ClasspInitializeHotplugInfo(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
|
);
|
|
|
|
VOID
|
|
ClasspPerfIncrementErrorCount(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
|
);
|
|
VOID
|
|
ClasspPerfIncrementSuccessfulIo(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
|
);
|
|
|
|
VOID
|
|
ClassLogThrottleComplete(
|
|
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
|
IN LARGE_INTEGER Period
|
|
);
|
|
|
|
PTRANSFER_PACKET NewTransferPacket(PDEVICE_OBJECT Fdo);
|
|
VOID DestroyTransferPacket(PTRANSFER_PACKET Pkt);
|
|
VOID EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo, PTRANSFER_PACKET Pkt);
|
|
PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded);
|
|
VOID SetupReadWriteTransferPacket(PTRANSFER_PACKET pkt, PVOID Buf, ULONG Len, LARGE_INTEGER DiskLocation, PIRP OriginalIrp);
|
|
NTSTATUS SubmitTransferPacket(PTRANSFER_PACKET Pkt);
|
|
NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Context);
|
|
NTSTATUS ServiceTransferRequest(PDEVICE_OBJECT Fdo, PIRP Irp);
|
|
VOID TransferPacketRetryTimerDpc(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
|
|
BOOLEAN InterpretTransferPacketError(PTRANSFER_PACKET Pkt);
|
|
BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt);
|
|
VOID EnqueueDeferredClientIrp(PCLASS_PRIVATE_FDO_DATA FdoData, PIRP Irp);
|
|
PIRP DequeueDeferredClientIrp(PCLASS_PRIVATE_FDO_DATA FdoData);
|
|
VOID InitLowMemRetry(PTRANSFER_PACKET Pkt, PVOID BufPtr, ULONG Len, LARGE_INTEGER TargetLocation);
|
|
BOOLEAN StepLowMemRetry(PTRANSFER_PACKET Pkt);
|
|
VOID SetupEjectionTransferPacket(TRANSFER_PACKET *Pkt, BOOLEAN PreventMediaRemoval, PKEVENT SyncEventPtr, PIRP OriginalIrp);
|
|
VOID SetupModeSenseTransferPacket(TRANSFER_PACKET *Pkt, PKEVENT SyncEventPtr, PVOID ModeSenseBuffer, UCHAR ModeSenseBufferLen, UCHAR PageMode, PIRP OriginalIrp);
|
|
VOID SetupDriveCapacityTransferPacket(TRANSFER_PACKET *Pkt, PVOID ReadCapacityBuffer, ULONG ReadCapacityBufferLen, PKEVENT SyncEventPtr, PIRP OriginalIrp);
|
|
PMDL BuildDeviceInputMdl(PVOID Buffer, ULONG BufferLen);
|
|
VOID FreeDeviceInputMdl(PMDL Mdl);
|
|
NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo);
|
|
VOID DestroyAllTransferPackets(PDEVICE_OBJECT Fdo);
|
|
VOID InterpretCapacityData(PDEVICE_OBJECT Fdo, PREAD_CAPACITY_DATA ReadCapacityData);
|
|
|
|
|
|
extern LIST_ENTRY AllFdosList;
|
|
|