summaryrefslogtreecommitdiff
path: root/storage/class/classpnp/src/classp.h
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /storage/class/classpnp/src/classp.h
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'storage/class/classpnp/src/classp.h')
-rw-r--r--storage/class/classpnp/src/classp.h2619
1 files changed, 2619 insertions, 0 deletions
diff --git a/storage/class/classpnp/src/classp.h b/storage/class/classpnp/src/classp.h
new file mode 100644
index 00000000..3c32c25d
--- /dev/null
+++ b/storage/class/classpnp/src/classp.h
@@ -0,0 +1,2619 @@
+/*++
+
+Copyright (C) Microsoft Corporation, 1991 - 2010
+
+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:
+
+--*/
+
+#define RTL_USE_AVL_TABLES 0
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <ntddk.h>
+
+#include <scsi.h>
+
+#include <wmidata.h>
+#include <classpnp.h>
+#include <storduid.h>
+
+#if CLASS_INIT_GUID
+#include <initguid.h>
+#endif
+
+#include <mountdev.h>
+#include <ioevent.h>
+#include <ntstrsafe.h>
+#include <ntintsafe.h>
+
+#include <wdmguid.h>
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+
+#include <ntpoapi.h>
+
+#include <srbhelper.h>
+
+#endif
+
+//
+// Set component ID for DbgPrintEx calls
+//
+#ifndef DEBUG_COMP_ID
+#define DEBUG_COMP_ID DPFLTR_CLASSPNP_ID
+#endif
+
+//
+// Include header file and setup GUID for tracing
+//
+#include <storswtr.h>
+#define WPP_GUID_CLASSPNP (FA8DE7C4, ACDE, 4443, 9994, C4E2359A9EDB)
+#ifndef WPP_CONTROL_GUIDS
+#define WPP_CONTROL_GUIDS WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_CLASSPNP)
+#endif
+
+
+/*
+ * 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 GUID ClassGuidSenseInfo2;
+extern GUID ClassGuidWorkingSet;
+extern GUID ClassGuidSrbSupport;
+
+extern ULONG ClassMaxInterleavePerCriticalIo;
+
+
+#define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I)))
+
+#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 CLASSP_REG_IDLE_INTERVAL_NAME (L"IdleInterval")
+#define CLASSP_REG_IDLE_ACTIVE_MAX (L"IdleOutstandingIoMax")
+#define CLASSP_REG_IDLE_PRIORITY_SUPPORTED (L"IdlePrioritySupported")
+#define CLASSP_REG_ACCESS_ALIGNMENT_NOT_SUPPORTED (L"AccessAlignmentQueryNotSupported")
+#define CLASSP_REG_DISBALE_IDLE_POWER_NAME (L"DisableIdlePowerManagement")
+#define CLASSP_REG_IDLE_TIMEOUT_IN_SECONDS (L"IdleTimeoutInSeconds")
+#define CLASSP_REG_DISABLE_D3COLD (L"DisableD3Cold")
+#define CLASSP_REG_QERR_OVERRIDE_MODE (L"QERROverrideMode")
+#define CLASSP_REG_LEGACY_ERROR_HANDLING (L"LegacyErrorHandling")
+#define CLASSP_REG_IO_TIMEOUT_RETRY_COUNT (L"MaxIoTimeoutRetryCount")
+
+#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_GESN_IGNORE_OPCHANGE (0x00000010)
+
+#define FDO_HACK_VALID_FLAGS (0x0000001F)
+#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_MODESELECT_RETRIES 1
+#define NUM_DRIVECAPACITY_RETRIES 1
+
+#if (NTDDI_VERSION >= NTDDI_WINBLUE)
+
+//
+// New code should use the MAXIMUM_RETRIES value.
+//
+#define NUM_IO_RETRIES MAXIMUM_RETRIES
+#define LEGACY_NUM_IO_RETRIES 8
+
+#else
+
+/*
+ * 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
+
+#endif // NTDDI_VERSION >= NTDDI_WINBLUE
+
+#define CLASS_FILE_OBJECT_EXTENSION_KEY 'eteP'
+#define CLASSP_VOLUME_VERIFY_CHECKED 0x34
+
+#define CLASS_TAG_PRIVATE_DATA 'CPcS'
+#define CLASS_TAG_SENSE2 '2ScS'
+#define CLASS_TAG_WORKING_SET 'sWcS'
+#define CLASSPNP_POOL_TAG_GENERIC 'pCcS'
+#define CLASSPNP_POOL_TAG_TOKEN_OPERATION 'oTcS'
+#define CLASSPNP_POOL_TAG_SRB 'rScS'
+#define CLASSPNP_POOL_TAG_VPD 'pVcS'
+#define CLASSPNP_POOL_TAG_LOG_MESSAGE 'mlcS'
+#define CLASSPNP_POOL_TAG_ADDITIONAL_DATA 'DAcS'
+#define CLASSPNP_POOL_TAG_FIRMWARE 'wFcS'
+
+//
+// Macros related to Token Operation commands
+//
+#define MAX_LIST_IDENTIFIER MAXULONG
+#define NUM_POPULATE_TOKEN_RETRIES 1
+#define NUM_WRITE_USING_TOKEN_RETRIES 2
+#define NUM_RECEIVE_TOKEN_INFORMATION_RETRIES 2
+#define MAX_TOKEN_OPERATION_PARAMETER_DATA_LENGTH MAXUSHORT
+#define MAX_RECEIVE_TOKEN_INFORMATION_PARAMETER_DATA_LENGTH MAXULONG
+#define MAX_TOKEN_TRANSFER_SIZE MAXULONGLONG
+#define MAX_NUMBER_BLOCKS_PER_BLOCK_DEVICE_RANGE_DESCRIPTOR MAXULONG
+#define MAX_TARGET_DURATION (4ULL * 10 * 1000 * 1000) // 4sec in 100ns units
+#define DEFAULT_MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN (64ULL * 1024 * 1024) // 64MB
+#define MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN (256ULL * 1024 * 1024) // 256MB
+#define MIN_TOKEN_LIST_IDENTIFIERS 256
+#define MAX_TOKEN_LIST_IDENTIFIERS MAXULONG
+#define MAX_NUMBER_BLOCK_DEVICE_DESCRIPTORS 64
+
+#define REG_DISK_CLASS_CONTROL L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\DISK"
+#define REG_MAX_LIST_IDENTIFIER_VALUE L"MaximumListIdentifier"
+
+#define VPD_PAGE_HEADER_SIZE 0x04
+
+
+//
+// Number of times to retry get LBA status in case of an error
+// that can be caused by VPD data change
+//
+
+#define GET_LBA_STATUS_RETRY_COUNT_MAX (2)
+
+extern ULONG MaxTokenOperationListIdentifier;
+extern volatile ULONG TokenOperationListIdentifier;
+
+extern LIST_ENTRY IdlePowerFDOList;
+extern PVOID PowerSettingNotificationHandle;
+extern PVOID ScreenStateNotificationHandle;
+extern BOOLEAN ClasspScreenOff;
+extern KGUARDED_MUTEX IdlePowerFDOListMutex;
+extern ULONG DiskIdleTimeoutInMS;
+
+//
+// Definitions from ntos\rtl\time.c
+//
+
+extern CONST LARGE_INTEGER Magic10000;
+#define SHIFT10000 13
+
+#define Convert100nsToMilliseconds(LARGE_INTEGER) \
+ ( \
+ RtlExtendedMagicDivide((LARGE_INTEGER), Magic10000, SHIFT10000) \
+ )
+
+#define ConvertMillisecondsTo100ns(MILLISECONDS) ( \
+ RtlExtendedIntegerMultiply ((MILLISECONDS), 10000) \
+ )
+
+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
+ //
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+ union {
+ SCSI_REQUEST_BLOCK Srb;
+ STORAGE_REQUEST_BLOCK SrbEx;
+ UCHAR SrbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE];
+ } MediaChangeSrb;
+#else
+ SCSI_REQUEST_BLOCK MediaChangeSrb;
+#endif
+ 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;
+
+ //
+ // Buffer size of SenseBuffer
+ //
+ UCHAR SenseBufferLength;
+
+};
+
+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;
+
+ //
+ // Timestamp of last time the failure prediction info was queried.
+ //
+ LARGE_INTEGER LastFailurePredictionQueryTime;
+
+} 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;
+
+#if _MSC_VER >= 1600
+#pragma warning(push)
+#endif
+#pragma warning(disable:4214) // bit field types other than int
+//
+// CLASS_ERROR_LOG_DATA will still use SCSI_REQUEST_BLOCK even
+// when using extended SRB as an extended SRB is too large to
+// fit into. Should revisit this code once classpnp starts to
+// use greater than 16 byte CDB.
+//
+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;
+#if _MSC_VER >= 1600
+#pragma warning(pop)
+#endif
+
+#define NUM_ERROR_LOG_ENTRIES 16
+#define DBG_NUM_PACKET_LOG_ENTRIES (64*2) // 64 send&receive's
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+typedef
+VOID
+(*PCONTINUATION_ROUTINE)(
+ _In_ PVOID Context
+ );
+#endif
+
+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.
+ */
+#if (NTDDI_VERSION >= NTDDI_WINBLUE)
+ USHORT NumRetries; // Total number of retries remaining.
+ UCHAR NumIoTimeoutRetries; // Number of retries remaining for a timed-out request.
+ UCHAR TimedOut; // Indicates if this packet has timed-out.
+#else
+ ULONG NumRetries;
+#endif
+ KTIMER RetryTimer;
+ KDPC RetryTimerDPC;
+
+ _Field_range_(0,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS)
+ LONGLONG RetryIn100nsUnits;
+
+ /*
+ * 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).
+ * NOTE: These fields are also used for StartIO-based
+ * class drivers, even when not in low memory conditions.
+ */
+ BOOLEAN DriverUsesStartIO; // if this is set, then the below low-mem flags are always used
+ 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_EX 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.
+ */
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+ PSTORAGE_REQUEST_BLOCK_HEADER Srb;
+#else
+ SCSI_REQUEST_BLOCK Srb;
+#endif
+ // ULONG SrbIoctlDevObj; // not handling ioctls yet
+ // ULONG SrbIoctlCode;
+
+ #if DBG
+ LARGE_INTEGER DbgTimeSent;
+ LARGE_INTEGER DbgTimeReturned;
+ ULONG DbgPktId;
+ IRP DbgOriginalIrpCopy;
+ MDL DbgMdlCopy;
+ #endif
+
+ BOOLEAN UsePartialMdl;
+ PMDL PartialMdl;
+
+ PSRB_HISTORY RetryHistory;
+
+ // The time at which this request was sent to port driver.
+ ULONGLONG RequestStartTime;
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+ // ActivityId that is associated with the IRP that this transfer packet services.
+ GUID ActivityId;
+
+ // If non-NULL, called at packet completion with this context.
+ PCONTINUATION_ROUTINE ContinuationRoutine;
+ PVOID ContinuationContext;
+ ULONGLONG TransferCount;
+ ULONG AllocateNode;
+#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_Client 16
+#define MAX_WORKINGSET_TRANSFER_PACKETS_Client 32
+#define MIN_WORKINGSET_TRANSFER_PACKETS_Server_UpperBound 256
+#define MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound 32
+#define MAX_WORKINGSET_TRANSFER_PACKETS_Server 1024
+#define MIN_WORKINGSET_TRANSFER_PACKETS_SPACES 512
+#define MAX_WORKINGSET_TRANSFER_PACKETS_SPACES 2048
+#define MAX_OUTSTANDING_IO_PER_LUN_DEFAULT 16
+#define MAX_CLEANUP_TRANSFER_PACKETS_AT_ONCE 8192
+
+
+
+typedef struct _PNL_SLIST_HEADER {
+ DECLSPEC_CACHEALIGN SLIST_HEADER SListHeader;
+ DECLSPEC_CACHEALIGN ULONG NumFreeTransferPackets;
+ ULONG NumTotalTransferPackets;
+ ULONG DbgPeakNumTransferPackets;
+} PNL_SLIST_HEADER, *PPNL_SLIST_HEADER;
+
+//
+// !!! WARNING !!!
+// DO NOT use the following structure in code outside of classpnp
+// as structure will not be guaranteed between OS versions.
+//
+// add to the front of this structure to help prevent illegal
+// snooping by other utilities.
+//
+struct _CLASS_PRIVATE_FDO_DATA {
+
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+
+ //
+ // Periodic timer for polling for media change detection, failure prediction
+ // and class tick function.
+ //
+
+#if (NTDDI_VERSION >= NTDDI_WINBLUE)
+ PEX_TIMER TickTimer;
+ LONGLONG CurrentNoWakeTolerance;
+#else
+ KTIMER TickTimer;
+ KDPC TickTimerDpc;
+#endif // (NTDDI_VERSION >= NTDDI_WINBLUE)
+
+ //
+ // Power related and release queue SRBs
+ //
+ union {
+ STORAGE_REQUEST_BLOCK SrbEx;
+ UCHAR PowerSrbBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE];
+ } PowerSrb;
+
+ union {
+ STORAGE_REQUEST_BLOCK SrbEx;
+ UCHAR ReleaseQueueSrbBuffer[CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE];
+ } ReleaseQueueSrb;
+
+#endif
+
+ ULONG TrackingFlags;
+
+ /*
+ * Flag to detect recursion caused by devices
+ * reporting different capacity per each request
+ */
+ ULONG UpdateDiskPropertiesWorkItemActive;
+
+ //
+ // Local equivalents of MinWorkingSetTransferPackets and MaxWorkingSetTransferPackets.
+ // These values are initialized by the global equivalents but are then adjusted as
+ // requested by the class driver.
+ //
+ ULONG LocalMinWorkingSetTransferPackets;
+ ULONG LocalMaxWorkingSetTransferPackets;
+
+#if DBG
+
+ ULONG MaxOutstandingIOPerLUN;
+
+#endif
+
+ /*
+ * 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 TimerInitialized;
+ 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;
+ PPNL_SLIST_HEADER FreeTransferPacketsLists;
+
+ /*
+ * 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.
+ */
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+ PSTORAGE_REQUEST_BLOCK_HEADER SrbTemplate;
+#else
+ SCSI_REQUEST_BLOCK SrbTemplate;
+#endif
+
+ 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_EX LastKnownDriveCapacityData;
+ BOOLEAN IsCachedDriveCapDataValid;
+
+ //
+ // Idle priority support flag
+ //
+ BOOLEAN IdlePrioritySupported;
+
+ //
+ // Tick timer enabled
+ //
+ BOOLEAN TickTimerEnabled;
+
+ BOOLEAN ReservedBoolean;
+
+ /*
+ * 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
+
+ //
+ // Spin lock for low priority I/O list
+ //
+ KSPIN_LOCK IdleListLock;
+
+ //
+ // Queue for low priority I/O
+ //
+ LIST_ENTRY IdleIrpList;
+
+ //
+ // Timer for low priority I/O
+ //
+ KTIMER IdleTimer;
+
+ //
+ // DPC for low priority I/O
+ //
+ KDPC IdleDpc;
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+
+ //
+ // Time (ms) since the completion of the last non-idle request before the
+ // first idle request should be issued. Due to the coarseness of the idle
+ // timer frequency, some variability in the idle interval will be tolerated
+ // such that it is the desired idle interval on average.
+ //
+ USHORT IdleInterval;
+
+ //
+ // Max number of active idle requests.
+ //
+ USHORT IdleActiveIoMax;
+
+#endif
+
+ //
+ // Timer interval for sending low priority I/O
+ //
+ USHORT IdleTimerInterval;
+
+ //
+ // Idle counts required to process idle request
+ // to avoid starvation
+ //
+ USHORT StarvationCount;
+
+ //
+ // Idle timer tick count
+ //
+ ULONG IdleTimerTicks;
+
+ //
+ // Idle timer tick count
+ //
+ ULONG IdleTicks;
+
+ //
+ // Idle I/O count
+ //
+ ULONG IdleIoCount;
+
+ //
+ // Flag to indicate timer status
+ //
+ LONG IdleTimerStarted;
+
+ //
+ // Normal priority I/O time
+ //
+ LARGE_INTEGER LastIoTime;
+
+ //
+ // Count of active normal priority I/O
+ //
+ LONG ActiveIoCount;
+
+ //
+ // Count of active idle priority I/O
+ //
+ LONG ActiveIdleIoCount;
+
+ //
+ // Support for class drivers to extend
+ // the interpret sense information routine
+ // and retry history per-packet. Copy of
+ // values in driver extension.
+ //
+ PCLASS_INTERPRET_SENSE_INFO2 InterpretSenseInfo;
+
+ //
+ // power process parameters. they work closely with CLASS_POWER_CONTEXT structure.
+ //
+ ULONG MaxPowerOperationRetryCount;
+ PIRP PowerProcessIrp;
+
+ // Counter frequency : Currently used for KeQueryPerferformanceCounter
+ LARGE_INTEGER PerfCounterFrequency;
+
+ //
+ // Indicates legacy error handling should be used.
+ // This means:
+ // - Max number of retries for an IO request is 8 (instead of 4).
+ //
+ BOOLEAN LegacyErrorHandling;
+
+ //
+ // Maximum number of retries allowed for IO requests for this device.
+ //
+ UCHAR MaxNumberOfIoRetries;
+};
+
+//
+// !!! WARNING !!!
+// DO NOT use the following structure in code outside of classpnp
+// as structure will not be guaranteed between OS versions.
+//
+// EX_RUNDOWN_REF_CACHE_AWARE is variable size and follows
+// RemoveLockFailAcquire. EX_RUNDOWN_REF_CACHE_AWARE must be part
+// of the device extension allocation to avoid issues with a device
+// that has been PNP remove but still has outstanding references.
+// In this case, the removed object may still receive incoming requests.
+//
+// There are code dependencies on the structure layout. To minimize
+// code changes, new fields to _CLASS_PRIVATE_COMMON_DATA should be
+// added based on the following guidance.
+// - Fixed size: beginning of _CLASS_PRIVATE_COMMON_DATA
+// - Variable size: at the end of _CLASS_PRIVATE_COMMON_DATA after the
+// last variable size field.
+//
+
+struct _CLASS_PRIVATE_COMMON_DATA {
+
+ //
+ // Cacheaware rundown lock reference
+ //
+
+ LONG RemoveLockFailAcquire;
+
+ //
+ // N.B. EX_RUNDOWN_REF_CACHE_AWARE begins with a pointer-sized item that is
+ // accessed interlocked, and must be aligned on ARM platforms. In order
+ // for this to work on ARM64, an additional 32-bit slot must be allocated.
+ //
+
+#if defined(_WIN64)
+ LONG Align;
+#endif
+
+ // EX_RUNDOWN_REF_CACHE_AWARE (variable size) follows
+
+};
+
+//
+// Verify that the size of _CLASS_PRIVATE_COMMON_DATA is pointer size aligned
+// to ensure the EX_RUNDOWN_REF_CACHE_AWARE following it is properly aligned.
+//
+
+C_ASSERT((sizeof(struct _CLASS_PRIVATE_COMMON_DATA) % sizeof(PVOID)) == 0);
+
+typedef struct _IDLE_POWER_FDO_LIST_ENTRY {
+ LIST_ENTRY ListEntry;
+ PDEVICE_OBJECT Fdo;
+} IDLE_POWER_FDO_LIST_ENTRY, *PIDLE_POWER_FDO_LIST_ENTRY;
+
+typedef struct _OFFLOAD_READ_CONTEXT {
+
+ PDEVICE_OBJECT Fdo;
+
+ //
+ // Upper offload read DSM irp.
+ //
+
+ PIRP OffloadReadDsmIrp;
+
+ //
+ // A pseudo-irp is used despite the operation being async. This is in
+ // contrast to normal read and write, which let TransferPktComplete()
+ // complete the upper IRP directly. Offload requests are enough different
+ // that it makes more sense to let them manage their own async steps with
+ // minimal help from TransferPktComplete() (just a continuation function
+ // call during TransferPktComplete()).
+ //
+
+ IRP PseudoIrp;
+
+ //
+ // The offload read context tracks one packet in flight at a time - it'll be
+ // the POPULATE TOKEN packet first, then RECEIVE ROD TOKEN INFORMATION.
+ //
+ // This field exists only for debug purposes.
+ //
+
+ PTRANSFER_PACKET Pkt;
+
+ PMDL PopulateTokenMdl;
+
+ ULONG BufferLength;
+
+ ULONG ListIdentifier;
+
+ ULONG ReceiveTokenInformationBufferLength;
+
+ //
+ // Total sectors that the operation is attempting to process.
+ //
+
+ ULONGLONG TotalSectorsToProcess;
+
+ //
+ // Total sectors actually processed.
+ //
+
+ ULONGLONG TotalSectorsProcessed;
+
+ //
+ // Total upper request size in bytes.
+ //
+
+ ULONGLONG EntireXferLen;
+
+ //
+ // Just a cached copy of what was in the transfer packet.
+ //
+
+ SCSI_REQUEST_BLOCK Srb;
+
+ //
+ // Pointer into the token part of the SCSI buffer (the buffer immediately
+ // after this struct), for easy reference.
+ //
+
+ PUCHAR Token;
+
+ // The SCSI buffer (in/out buffer, not CDB) for the commands immediately
+ // follows this struct, so no need to have a field redundantly pointing to
+ // the buffer.
+} OFFLOAD_READ_CONTEXT, *POFFLOAD_READ_CONTEXT;
+
+
+typedef struct _OFFLOAD_WRITE_CONTEXT {
+
+ PDEVICE_OBJECT Fdo;
+
+ PIRP OffloadWriteDsmIrp;
+
+ ULONGLONG EntireXferLen;
+ ULONGLONG TotalRequestSizeSectors;
+
+ ULONG DataSetRangesCount;
+
+ PDEVICE_MANAGE_DATA_SET_ATTRIBUTES DsmAttributes;
+ PDEVICE_DATA_SET_RANGE DataSetRanges;
+ PDEVICE_DSM_OFFLOAD_WRITE_PARAMETERS OffloadWriteParameters;
+ ULONGLONG LogicalBlockOffset;
+
+ ULONG MaxBlockDescrCount;
+ ULONGLONG MaxLbaCount;
+
+ ULONG BufferLength;
+ ULONG ReceiveTokenInformationBufferLength;
+
+ IRP PseudoIrp;
+
+ PMDL WriteUsingTokenMdl;
+
+ ULONGLONG TotalSectorsProcessedSuccessfully;
+ ULONG DataSetRangeIndex;
+ ULONGLONG DataSetRangeByteOffset;
+
+ PTRANSFER_PACKET Pkt;
+
+ //
+ // Per-WUT (WRITE USING TOKEN), not overall.
+ //
+
+ ULONGLONG TotalSectorsToProcess;
+ ULONGLONG TotalSectorsProcessed;
+
+ ULONG ListIdentifier;
+
+ BOOLEAN TokenInvalidated;
+
+ //
+ // Just a cached copy of what was in the transfer packet.
+ //
+
+ SCSI_REQUEST_BLOCK Srb;
+
+ ULONGLONG OperationStartTime;
+
+} OFFLOAD_WRITE_CONTEXT, *POFFLOAD_WRITE_CONTEXT;
+
+
+typedef struct _OPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT_HEADER {
+ PIO_WORKITEM WorkItem;
+ PVOID SenseData;
+ ULONG SenseDataSize;
+ UCHAR SrbStatus;
+ UCHAR ScsiStatus;
+ UCHAR OpCode;
+ UCHAR Reserved;
+ ULONG ErrorCode;
+} OPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT_HEADER, *POPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT_HEADER;
+
+typedef struct _IO_RETRIED_LOG_MESSAGE_CONTEXT {
+ OPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT_HEADER ContextHeader;
+ LARGE_INTEGER Lba;
+ ULONG DeviceNumber;
+} IO_RETRIED_LOG_MESSAGE_CONTEXT, *PIO_RETRIED_LOG_MESSAGE_CONTEXT;
+
+
+#define QERR_SET_ZERO_ODX_OR_TP_ONLY 0
+#define QERR_SET_ZERO_ALWAYS 1
+#define QERR_SET_ZERO_NEVER 2
+
+
+#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)
+#define MODE_PAGE_DATA_SIZE 192
+
+#define CLASS_IDLE_INTERVAL 50 // 50 milliseconds
+#define CLASS_STARVATION_INTERVAL 500 // 500 milliseconds
+#define CLASS_IDLE_TIMER_TICKS 4
+
+
+/*
+ * 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);
+}
+
+__inline
+BOOLEAN
+ClasspIsIdleRequestSupported(
+ PCLASS_PRIVATE_FDO_DATA FdoData,
+ PIRP Irp
+ )
+{
+ IO_PRIORITY_HINT ioPriority = IoGetIoPriorityHint(Irp);
+ return ((ioPriority <= IoPriorityLow) && (FdoData->IdlePrioritySupported == TRUE));
+}
+
+__inline
+VOID
+ClasspMarkIrpAsIdle(
+ PIRP Irp,
+ BOOLEAN Idle
+ )
+{
+// truncation is not an issue for this use case
+// nonstandard extension used is not an issue for this use case
+#pragma warning(suppress:4305; suppress:4213)
+ ((BOOLEAN)Irp->Tail.Overlay.DriverContext[1]) = Idle;
+}
+
+__inline
+BOOLEAN
+ClasspIsIdleRequest(
+ PIRP Irp
+ )
+{
+#pragma warning(suppress:4305) // truncation is not an issue for this use case
+ return ((BOOLEAN)Irp->Tail.Overlay.DriverContext[1]);
+}
+
+extern BOOLEAN UseQPCTime;
+
+__inline
+LARGE_INTEGER
+ClasspGetCurrentTime(
+ PLARGE_INTEGER Frequency
+ )
+{
+ LARGE_INTEGER currentTime;
+
+ if (UseQPCTime) {
+ currentTime = KeQueryPerformanceCounter(Frequency);
+ } else {
+ currentTime.QuadPart = (LONGLONG)KeQueryUnbiasedInterruptTime();
+ }
+
+ return currentTime;
+}
+
+__inline
+ULONGLONG
+ClasspTimeDiffToMs(
+ PCLASS_PRIVATE_FDO_DATA FdoData,
+ ULONGLONG TimeDiff
+ )
+{
+ if (UseQPCTime) {
+ TimeDiff *= 1000;
+ TimeDiff /= FdoData->PerfCounterFrequency.QuadPart;
+ } else {
+ TimeDiff /= (10 * 1000);
+ }
+
+ return TimeDiff;
+}
+
+__inline
+BOOLEAN
+ClasspSupportsUnmap(
+ _In_ PCLASS_FUNCTION_SUPPORT_INFO SupportInfo
+ )
+{
+ return SupportInfo->LBProvisioningData.LBPU;
+}
+
+__inline
+BOOLEAN
+ClasspIsThinProvisioned(
+ _In_ PCLASS_FUNCTION_SUPPORT_INFO SupportInfo
+ )
+{
+ //
+ // We only support thinly provisioned devices that also support UNMAP.
+ //
+ if (SupportInfo->LBProvisioningData.ProvisioningType == PROVISIONING_TYPE_THIN &&
+ SupportInfo->LBProvisioningData.LBPU == TRUE)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+__inline
+BOOLEAN
+ClasspIsObsoletePortDriver(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ )
+{
+ if ( (FdoExtension->MiniportDescriptor != NULL) &&
+ (FdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetSCSIport) ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+ULONG
+ClasspCalculateLogicalSectorSize (
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_ ULONG BytesPerBlockInBigEndian
+ );
+
+DRIVER_INITIALIZE DriverEntry;
+
+DRIVER_UNLOAD ClassUnload;
+
+_Dispatch_type_(IRP_MJ_CREATE)
+_Dispatch_type_(IRP_MJ_CLOSE)
+DRIVER_DISPATCH ClassCreateClose;
+
+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
+ );
+
+_Dispatch_type_(IRP_MJ_READ)
+_Dispatch_type_(IRP_MJ_WRITE)
+DRIVER_DISPATCH ClassReadWrite;
+
+_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
+DRIVER_DISPATCH ClassDeviceControlDispatch;
+
+_Dispatch_type_(IRP_MJ_PNP)
+DRIVER_DISPATCH ClassDispatchPnp;
+
+NTSTATUS
+ClassPnpStartDevice(
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+_Dispatch_type_(IRP_MJ_SHUTDOWN)
+_Dispatch_type_(IRP_MJ_FLUSH_BUFFERS)
+DRIVER_DISPATCH ClassShutdownFlush;
+
+_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
+DRIVER_DISPATCH ClassSystemControl;
+
+
+//
+// Class internal routines
+//
+
+DRIVER_ADD_DEVICE ClassAddDevice;
+
+IO_COMPLETION_ROUTINE ClasspSendSynchronousCompletion;
+
+VOID
+RetryRequest(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PSCSI_REQUEST_BLOCK Srb,
+ BOOLEAN Associated,
+ LONGLONG TimeDelta100ns
+ );
+
+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
+ );
+
+DRIVER_STARTIO ClasspStartIo;
+
+NTSTATUS
+ClasspPagingNotificationCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PDEVICE_OBJECT RealDeviceObject
+ );
+
+NTSTATUS
+ClasspMediaChangeCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ );
+
+NTSTATUS
+ClasspMcnControl(
+ IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ IN PIRP Irp,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+ClasspRegisterMountedDeviceInterface(
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+VOID
+ClasspDisableTimer(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+VOID
+ClasspEnableTimer(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+NTSTATUS
+ClasspInitializeTimer(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+);
+
+VOID
+ClasspDeleteTimer(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+);
+
+#if (NTDDI_VERSION >= NTDDI_WINBLUE)
+BOOLEAN
+ClasspUpdateTimerNoWakeTolerance(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+);
+#endif
+
+NTSTATUS
+ClasspDuidQueryProperty(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+_Dispatch_type_(IRP_MJ_CREATE)
+_Dispatch_type_(IRP_MJ_CLOSE)
+_Dispatch_type_(IRP_MJ_READ)
+_Dispatch_type_(IRP_MJ_WRITE)
+_Dispatch_type_(IRP_MJ_SCSI)
+_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
+_Dispatch_type_(IRP_MJ_SHUTDOWN)
+_Dispatch_type_(IRP_MJ_FLUSH_BUFFERS)
+_Dispatch_type_(IRP_MJ_PNP)
+_Dispatch_type_(IRP_MJ_POWER)
+_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
+DRIVER_DISPATCH ClassGlobalDispatch;
+
+VOID
+ClassInitializeDispatchTables(
+ PCLASS_DRIVER_EXTENSION DriverExtension
+ );
+
+NTSTATUS
+ClasspPersistentReserve(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// 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
+ );
+
+IO_COMPLETION_ROUTINE ClassReleaseQueueCompletion;
+
+VOID
+ClasspReleaseQueue(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP ReleaseQueueIrp
+ );
+
+VOID
+ClasspDisablePowerNotification(
+ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+);
+
+//
+// class power routines
+//
+
+_Dispatch_type_(IRP_MJ_POWER)
+DRIVER_DISPATCH ClassDispatchPower;
+
+NTSTATUS
+ClassMinimalPowerHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+_IRQL_requires_same_
+NTSTATUS
+ClasspEnableIdlePower(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+POWER_SETTING_CALLBACK ClasspPowerSettingCallback;
+
+//
+// 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
+ );
+
+KDEFERRED_ROUTINE ClasspRetryRequestDpc;
+
+VOID
+ClassFreeOrReuseSrb(
+ IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ IN __drv_freesMem(mem) PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+ClassRetryRequest(
+ IN PDEVICE_OBJECT SelfDeviceObject,
+ IN PIRP Irp,
+ _In_ _In_range_(0,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) // this is 100 seconds; already an assert in classpnp based on this
+ IN LONGLONG TimeDelta100ns // in 100ns units
+ );
+
+VOID
+ClasspBuildRequestEx(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _In_ PIRP Irp,
+ _In_ __drv_aliasesMem PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS
+ClasspAllocateReleaseQueueIrp(
+ IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+NTSTATUS
+ClasspAllocatePowerProcessIrp(
+ IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+NTSTATUS
+ClasspInitializeGesn(
+ IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ IN PMEDIA_CHANGE_DETECTION_INFO Info
+ );
+
+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
+ );
+
+IO_WORKITEM_ROUTINE ClasspUpdateDiskProperties;
+
+__drv_allocatesMem(Mem)
+PTRANSFER_PACKET NewTransferPacket(PDEVICE_OBJECT Fdo);
+VOID DestroyTransferPacket(_In_ __drv_freesMem(mem) PTRANSFER_PACKET Pkt);
+VOID EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo, __drv_aliasesMem PTRANSFER_PACKET Pkt);
+PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded);
+PTRANSFER_PACKET DequeueFreeTransferPacketEx(_In_ PDEVICE_OBJECT Fdo, _In_ BOOLEAN AllocIfNeeded, _In_ ULONG Node);
+VOID SetupReadWriteTransferPacket(PTRANSFER_PACKET pkt, PVOID Buf, ULONG Len, LARGE_INTEGER DiskLocation, PIRP OriginalIrp);
+NTSTATUS SubmitTransferPacket(PTRANSFER_PACKET Pkt);
+IO_COMPLETION_ROUTINE TransferPktComplete;
+NTSTATUS ServiceTransferRequest(PDEVICE_OBJECT Fdo, PIRP Irp, BOOLEAN PostToDpc);
+VOID TransferPacketQueueRetryDpc(PTRANSFER_PACKET Pkt);
+KDEFERRED_ROUTINE TransferPacketRetryTimerDpc;
+BOOLEAN InterpretTransferPacketError(PTRANSFER_PACKET Pkt);
+BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt);
+VOID EnqueueDeferredClientIrp(PDEVICE_OBJECT Fdo, PIRP Irp);
+PIRP DequeueDeferredClientIrp(PDEVICE_OBJECT Fdo);
+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, UCHAR SubPage, PIRP OriginalIrp, UCHAR PageControl);
+VOID SetupModeSelectTransferPacket(TRANSFER_PACKET *Pkt, PKEVENT SyncEventPtr, PVOID ModeSelectBuffer, UCHAR ModeSelectBufferLen, BOOLEAN SavePages, PIRP OriginalIrp);
+VOID SetupDriveCapacityTransferPacket(TRANSFER_PACKET *Pkt, PVOID ReadCapacityBuffer, ULONG ReadCapacityBufferLen, PKEVENT SyncEventPtr, PIRP OriginalIrp, BOOLEAN Use16ByteCdb);
+PMDL BuildDeviceInputMdl(PVOID Buffer, ULONG BufferLen);
+PMDL ClasspBuildDeviceMdl(PVOID Buffer, ULONG BufferLen, BOOLEAN WriteToDevice);
+VOID FreeDeviceInputMdl(PMDL Mdl);
+VOID ClasspFreeDeviceMdl(PMDL Mdl);
+NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo);
+VOID DestroyAllTransferPackets(PDEVICE_OBJECT Fdo);
+VOID InterpretCapacityData(PDEVICE_OBJECT Fdo, PREAD_CAPACITY_DATA_EX ReadCapacityData);
+IO_WORKITEM_ROUTINE_EX CleanupTransferPacketToWorkingSetSizeWorker;
+VOID CleanupTransferPacketToWorkingSetSize(_In_ PDEVICE_OBJECT Fdo, _In_ BOOLEAN LimitNumPktToDelete, _In_ ULONG Node);
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+VOID
+ClasspSetupPopulateTokenTransferPacket(
+ _In_ __drv_aliasesMem POFFLOAD_READ_CONTEXT OffloadReadContext,
+ _In_ PTRANSFER_PACKET Pkt,
+ _In_ ULONG Length,
+ _In_reads_bytes_(Length) PUCHAR PopulateTokenBuffer,
+ _In_ PIRP OriginalIrp,
+ _In_ ULONG ListIdentifier
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+VOID
+ClasspSetupReceivePopulateTokenInformationTransferPacket(
+ _In_ POFFLOAD_READ_CONTEXT OffloadReadContext,
+ _In_ PTRANSFER_PACKET Pkt,
+ _In_ ULONG Length,
+ _In_reads_bytes_(Length) PUCHAR ReceivePopulateTokenInformationBuffer,
+ _In_ PIRP OriginalIrp,
+ _In_ ULONG ListIdentifier
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+VOID
+ClasspSetupWriteUsingTokenTransferPacket(
+ _In_ __drv_aliasesMem POFFLOAD_WRITE_CONTEXT OffloadWriteContext,
+ _In_ PTRANSFER_PACKET Pkt,
+ _In_ ULONG Length,
+ _In_reads_bytes_(Length) PUCHAR WriteUsingTokenBuffer,
+ _In_ PIRP OriginalIrp,
+ _In_ ULONG ListIdentifier
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+VOID
+ClasspSetupReceiveWriteUsingTokenInformationTransferPacket(
+ _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext,
+ _In_ PTRANSFER_PACKET Pkt,
+ _In_ ULONG Length,
+ _In_reads_bytes_(Length) PUCHAR ReceiveWriteUsingTokenInformationBuffer,
+ _In_ PIRP OriginalIrp,
+ _In_ ULONG ListIdentifier
+ );
+
+ULONG ClasspModeSense(
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_reads_bytes_(Length) PCHAR ModeSenseBuffer,
+ _In_ ULONG Length,
+ _In_ UCHAR PageMode,
+ _In_ UCHAR PageControl
+ );
+
+NTSTATUS
+ClasspModeSelect(
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_reads_bytes_(Length) PCHAR ModeSelectBuffer,
+ _In_ ULONG Length,
+ _In_ BOOLEAN SavePages
+ );
+
+NTSTATUS ClasspWriteCacheProperty(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspAccessAlignmentProperty(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspDeviceSeekPenaltyProperty(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspDeviceGetLBProvisioningVPDPage(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_opt_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspDeviceGetBlockDeviceCharacteristicsVPDPage(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension,
+ _In_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspDeviceGetBlockLimitsVPDPage(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _Inout_bytecount_(SrbSize) PSCSI_REQUEST_BLOCK Srb,
+ _In_ ULONG SrbSize,
+ _Out_ PCLASS_VPD_B0_DATA BlockLimitsData
+ );
+
+NTSTATUS ClasspDeviceTrimProperty(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspDeviceLBProvisioningProperty(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspDeviceTrimProcess(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspDeviceGetLBAStatus(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS ClasspDeviceGetLBAStatusWorker(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PCLASS_VPD_B0_DATA BlockLimitsData,
+ _In_ ULONGLONG StartingOffset,
+ _In_ ULONGLONG LengthInBytes,
+ _Out_ PDEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT DsmOutput,
+ _Inout_ PULONG DsmOutputLength,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb,
+ _In_ BOOLEAN ConsolidateableBlocksOnly,
+ _In_ ULONG OutputVersion,
+ _Out_ PBOOLEAN BlockLimitsDataMayHaveChanged
+ );
+
+VOID ClassQueueThresholdEventWorker(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+VOID ClassQueueResourceExhaustionEventWorker(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+VOID ClassQueueCapacityChangedEventWorker(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+VOID ClassQueueProvisioningTypeChangedEventWorker(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+IO_WORKITEM_ROUTINE ClasspLogIOEventWithContext;
+
+VOID
+ClasspQueueLogIOEventWithContextWorker(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ ULONG SenseBufferSize,
+ _In_ PVOID SenseData,
+ _In_ UCHAR SrbStatus,
+ _In_ UCHAR ScsiStatus,
+ _In_ ULONG ErrorCode,
+ _In_ ULONG CdbLength,
+ _In_opt_ PCDB Cdb,
+ _In_opt_ PTRANSFER_PACKET Pkt
+ );
+
+VOID
+ClasspZeroQERR(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+ClasspGetMaximumTokenListIdentifier(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_z_ PWSTR RegistryPath,
+ _Out_ PULONG MaximumListIdentifier
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+ClasspDeviceCopyOffloadProperty(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+ClasspValidateOffloadSupported(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+ClasspValidateOffloadInputParameters(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp
+ );
+
+_IRQL_requires_same_
+NTSTATUS
+ClasspGetTokenOperationCommandBufferLength(
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_ ULONG ServiceAction,
+ _Inout_ PULONG CommandBufferLength,
+ _Out_opt_ PULONG TokenOperationBufferLength,
+ _Out_opt_ PULONG ReceiveTokenInformationBufferLength
+ );
+
+_IRQL_requires_same_
+NTSTATUS
+ClasspGetTokenOperationDescriptorLimits(
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_ ULONG ServiceAction,
+ _In_ ULONG MaxParameterBufferLength,
+ _Out_ PULONG MaxBlockDescriptorsCount,
+ _Out_ PULONGLONG MaxBlockDescriptorsLength
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+VOID
+ClasspConvertDataSetRangeToBlockDescr(
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_ PVOID BlockDescr,
+ _Inout_ PULONG CurrentBlockDescrIndex,
+ _In_ ULONG MaxBlockDescrCount,
+ _Inout_ PULONG CurrentLbaCount,
+ _In_ ULONGLONG MaxLbaCount,
+ _Inout_ PDEVICE_DATA_SET_RANGE DataSetRange,
+ _Inout_ PULONGLONG TotalSectorsProcessed
+ );
+
+NTSTATUS
+ClasspDeviceMediaTypeProperty(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+_IRQL_requires_same_
+PUCHAR
+ClasspBinaryToAscii(
+ _In_reads_(Length) PUCHAR HexBuffer,
+ _In_ ULONG Length,
+ _Inout_ PULONG UpdateLength
+ );
+
+__inline
+BOOLEAN
+ClasspIsTokenOperationComplete(
+ _In_ ULONG CurrentStatus
+ )
+{
+ BOOLEAN operationCompleted = FALSE;
+
+ switch (CurrentStatus) {
+ case OPERATION_COMPLETED_WITH_SUCCESS:
+ case OPERATION_COMPLETED_WITH_ERROR:
+ case OPERATION_COMPLETED_WITH_RESIDUAL_DATA:
+ case OPERATION_TERMINATED: {
+
+ operationCompleted = TRUE;
+ }
+ }
+
+ return operationCompleted;
+}
+
+__inline
+BOOLEAN
+ClasspIsTokenOperation(
+ _In_ PCDB Cdb
+ )
+{
+ BOOLEAN tokenOperation = FALSE;
+
+ if (Cdb) {
+ ULONG opCode = Cdb->AsByte[0];
+ ULONG serviceAction = Cdb->AsByte[1];
+
+ if ((opCode == SCSIOP_POPULATE_TOKEN && serviceAction == SERVICE_ACTION_POPULATE_TOKEN) ||
+ (opCode == SCSIOP_WRITE_USING_TOKEN && serviceAction == SERVICE_ACTION_WRITE_USING_TOKEN)) {
+
+ tokenOperation = TRUE;
+ }
+ }
+
+ return tokenOperation;
+}
+
+__inline
+BOOLEAN
+ClasspIsReceiveTokenInformation(
+ _In_ PCDB Cdb
+ )
+{
+ BOOLEAN receiveTokenInformation = FALSE;
+
+ if (Cdb) {
+ ULONG opCode = Cdb->AsByte[0];
+ ULONG serviceAction = Cdb->AsByte[1];
+
+ if (opCode == SCSIOP_RECEIVE_ROD_TOKEN_INFORMATION && serviceAction == SERVICE_ACTION_RECEIVE_TOKEN_INFORMATION) {
+
+ receiveTokenInformation = TRUE;
+ }
+ }
+
+ return receiveTokenInformation;
+}
+
+__inline
+BOOLEAN
+ClasspIsOffloadDataTransferCommand(
+ _In_ PCDB Cdb
+ )
+{
+ BOOLEAN offloadCommand = (ClasspIsTokenOperation(Cdb) || ClasspIsReceiveTokenInformation(Cdb)) ? TRUE : FALSE;
+
+ return offloadCommand;
+}
+
+extern LIST_ENTRY AllFdosList;
+
+
+VOID
+ClasspInitializeIdleTimer(
+ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+NTSTATUS
+ClasspIsPortable(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _Out_ PBOOLEAN IsPortable
+ );
+
+VOID
+ClasspGetInquiryVpdSupportInfo(
+ _Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+NTSTATUS
+ClasspGetLBProvisioningInfo(
+ _Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+
+_IRQL_requires_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+ClassDetermineTokenOperationCommandSupport(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+_IRQL_requires_same_
+NTSTATUS
+ClasspGetBlockDeviceTokenLimitsInfo(
+ _Inout_ PDEVICE_OBJECT DeviceObject
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+ClassDeviceProcessOffloadRead(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+ClassDeviceProcessOffloadWrite(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+ClasspServicePopulateTokenTransferRequest(
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_ PIRP Irp
+ );
+
+_IRQL_requires_same_
+VOID
+ClasspReceivePopulateTokenInformation(
+ _In_ POFFLOAD_READ_CONTEXT OffloadReadContext
+ );
+
+_IRQL_requires_max_(APC_LEVEL)
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+ClasspServiceWriteUsingTokenTransferRequest(
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_ PIRP Irp
+ );
+
+_IRQL_requires_same_
+VOID
+ClasspReceiveWriteUsingTokenInformation(
+ _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext
+ );
+
+VOID
+ClasspCompleteOffloadRequest(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _In_ NTSTATUS CompletionStatus
+ );
+
+VOID
+ClasspCleanupOffloadReadContext(
+ _In_ __drv_freesMem(mem) POFFLOAD_READ_CONTEXT OffloadReadContext
+ );
+
+VOID
+ClasspCompleteOffloadRead(
+ _In_ POFFLOAD_READ_CONTEXT OffloadReadContext,
+ _In_ NTSTATUS CompletionStatus
+ );
+
+// PCONTINUATION_ROUTINE
+VOID
+ClasspPopulateTokenTransferPacketDone(
+ _In_ PVOID Context
+ );
+
+// PCONTINUATION_ROUTINE
+VOID
+ClasspReceivePopulateTokenInformationTransferPacketDone(
+ _In_ PVOID Context
+ );
+
+VOID
+ClasspContinueOffloadWrite(
+ _In_ __drv_aliasesMem POFFLOAD_WRITE_CONTEXT OffloadWriteContext
+ );
+
+VOID
+ClasspCleanupOffloadWriteContext(
+ _In_ __drv_freesMem(mem) POFFLOAD_WRITE_CONTEXT OffloadWriteContext
+ );
+
+VOID
+ClasspCompleteOffloadWrite(
+ _In_ __drv_freesMem(Mem) POFFLOAD_WRITE_CONTEXT OffloadWriteContext,
+ _In_ NTSTATUS CompletionCausingStatus
+ );
+
+VOID
+ClasspReceiveWriteUsingTokenInformationDone(
+ _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext,
+ _In_ NTSTATUS CompletionCausingStatus
+ );
+
+VOID
+ClasspWriteUsingTokenTransferPacketDone(
+ _In_ PVOID Context
+ );
+
+VOID
+ClasspReceiveWriteUsingTokenInformationTransferPacketDone(
+ _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext
+ );
+
+NTSTATUS
+ClasspRefreshFunctionSupportInfo(
+ _Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _In_ BOOLEAN ForceQuery
+ );
+
+NTSTATUS
+ClasspBlockLimitsDataSnapshot(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _In_ BOOLEAN ForceQuery,
+ _Out_ PCLASS_VPD_B0_DATA BlockLimitsData,
+ _Out_ PULONG GenerationCount
+ );
+
+NTSTATUS
+InterpretReadCapacity16Data (
+ _Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _In_ PREAD_CAPACITY16_DATA ReadCapacity16Data
+ );
+
+NTSTATUS
+ClassReadCapacity16 (
+ _Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS
+ClassDeviceGetLBProvisioningResources(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+_IRQL_requires_same_
+NTSTATUS
+ClasspStorageEventNotification(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+ClasspPowerActivateDevice(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+ClasspPowerIdleDevice(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+IO_WORKITEM_ROUTINE ClassLogThresholdEvent;
+
+NTSTATUS
+ClasspLogSystemEventWithDeviceNumber(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ NTSTATUS IoErrorCode
+ );
+
+IO_WORKITEM_ROUTINE ClassLogResourceExhaustionEvent;
+
+NTSTATUS
+ClasspEnqueueIdleRequest(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+ClasspCompleteIdleRequest(
+ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+NTSTATUS
+ClasspPriorityHint(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+HistoryInitializeRetryLogs(
+ _Out_ PSRB_HISTORY History,
+ ULONG HistoryCount
+ );
+#define HISTORYINITIALIZERETRYLOGS(_packet) \
+ { \
+ if (_packet->RetryHistory != NULL) \
+ { \
+ HistoryInitializeRetryLogs( \
+ _packet->RetryHistory, \
+ _packet->RetryHistory->TotalHistoryCount \
+ ); \
+ } \
+ }
+
+VOID
+HistoryLogSendPacket(
+ TRANSFER_PACKET *Pkt
+ );
+#define HISTORYLOGSENDPACKET(_packet) \
+ { \
+ if (_packet->RetryHistory != NULL) { \
+ HistoryLogSendPacket(_packet); \
+ } \
+ }
+
+VOID
+HistoryLogReturnedPacket(
+ TRANSFER_PACKET *Pkt
+ );
+
+#define HISTORYLOGRETURNEDPACKET(_packet) \
+ { \
+ if (_packet->RetryHistory != NULL) { \
+ HistoryLogReturnedPacket(_packet); \
+ } \
+ }
+
+BOOLEAN
+InterpretSenseInfoWithoutHistory(
+ _In_ PDEVICE_OBJECT Fdo,
+ _In_opt_ PIRP OriginalRequest,
+ _In_ PSCSI_REQUEST_BLOCK Srb,
+ UCHAR MajorFunctionCode,
+ ULONG IoDeviceCode,
+ ULONG PreviousRetryCount,
+ _Out_ NTSTATUS * Status,
+ _Out_opt_ _Deref_out_range_(0,MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS)
+ LONGLONG * RetryIn100nsUnits
+ );
+
+BOOLEAN
+ClasspMyStringMatches(
+ _In_opt_z_ PCHAR StringToMatch,
+ _In_z_ PCHAR TargetString
+ );
+
+
+
+#define TRACKING_FORWARD_PROGRESS_PATH1 (0x00000001)
+#define TRACKING_FORWARD_PROGRESS_PATH2 (0x00000002)
+#define TRACKING_FORWARD_PROGRESS_PATH3 (0x00000004)
+
+
+VOID
+ClasspInitializeRemoveTracking(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+VOID
+ClasspUninitializeRemoveTracking(
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+RTL_GENERIC_COMPARE_ROUTINE RemoveTrackingCompareRoutine;
+
+RTL_GENERIC_ALLOCATE_ROUTINE RemoveTrackingAllocateRoutine;
+
+RTL_GENERIC_FREE_ROUTINE RemoveTrackingFreeRoutine;
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+
+typedef PVOID
+(*PSRB_ALLOCATE_ROUTINE) (
+ _In_ CLONG ByteSize
+ );
+
+PVOID
+DefaultStorageRequestBlockAllocateRoutine(
+ _In_ CLONG ByteSize
+ );
+
+
+NTSTATUS
+CreateStorageRequestBlock(
+ _Inout_ PSTORAGE_REQUEST_BLOCK *Srb,
+ _In_ USHORT AddressType,
+ _In_opt_ PSRB_ALLOCATE_ROUTINE AllocateRoutine,
+ _Inout_opt_ ULONG *ByteSize,
+ _In_ ULONG NumSrbExData,
+ ...
+ );
+
+NTSTATUS
+InitializeStorageRequestBlock(
+ _Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb,
+ _In_ USHORT AddressType,
+ _In_ ULONG ByteSize,
+ _In_ ULONG NumSrbExData,
+ ...
+ );
+
+VOID
+ClasspConvertToScsiRequestBlock(
+ _Out_ PSCSI_REQUEST_BLOCK Srb,
+ _In_ PSTORAGE_REQUEST_BLOCK SrbEx
+ );
+
+__inline PCDB
+ClasspTransferPacketGetCdb(
+ _In_ PTRANSFER_PACKET Pkt
+ )
+{
+ return SrbGetCdb(Pkt->Srb);
+}
+
+//
+// This inline function calculates number of retries already happened till now for known operation codes
+// and set the out parameter - TimesAlreadyRetried with the value, returns True
+//
+// For unknown operation codes this function will return false and will set TimesAlreadyRetried with zero
+//
+__inline BOOLEAN
+ClasspTransferPacketGetNumberOfRetriesDone(
+ _In_ PTRANSFER_PACKET Pkt,
+ _In_ PCDB Cdb,
+ _Out_ PULONG TimesAlreadyRetried
+ )
+{
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension;
+ PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
+
+ if (Cdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL)
+ {
+ *TimesAlreadyRetried = NUM_LOCKMEDIAREMOVAL_RETRIES - Pkt->NumRetries;
+ }
+ else if ((Cdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
+ (Cdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10))
+ {
+ *TimesAlreadyRetried = NUM_MODESENSE_RETRIES - Pkt->NumRetries;
+ }
+ else if ((Cdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY) ||
+ (Cdb->CDB16.OperationCode == SCSIOP_READ_CAPACITY16))
+ {
+ *TimesAlreadyRetried = NUM_DRIVECAPACITY_RETRIES - Pkt->NumRetries;
+ }
+ else if (IS_SCSIOP_READWRITE(Cdb->CDB10.OperationCode))
+ {
+ *TimesAlreadyRetried = fdoData->MaxNumberOfIoRetries - Pkt->NumRetries;
+ }
+ else if (Cdb->TOKEN_OPERATION.OperationCode == SCSIOP_POPULATE_TOKEN &&
+ Cdb->TOKEN_OPERATION.ServiceAction == SERVICE_ACTION_POPULATE_TOKEN)
+ {
+ *TimesAlreadyRetried = NUM_POPULATE_TOKEN_RETRIES - Pkt->NumRetries;
+ }
+ else if (Cdb->TOKEN_OPERATION.OperationCode == SCSIOP_WRITE_USING_TOKEN &&
+ Cdb->TOKEN_OPERATION.ServiceAction == SERVICE_ACTION_WRITE_USING_TOKEN)
+ {
+ *TimesAlreadyRetried = NUM_WRITE_USING_TOKEN_RETRIES - Pkt->NumRetries;
+ }
+ else if (ClasspIsReceiveTokenInformation(Cdb))
+ {
+ *TimesAlreadyRetried = NUM_RECEIVE_TOKEN_INFORMATION_RETRIES - Pkt->NumRetries;
+ }
+
+ else
+ {
+ *TimesAlreadyRetried = 0;
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+__inline PVOID
+ClasspTransferPacketGetSenseInfoBuffer(
+ _In_ PTRANSFER_PACKET Pkt
+ )
+{
+ return SrbGetSenseInfoBuffer(Pkt->Srb);
+}
+
+__inline UCHAR
+ClasspTransferPacketGetSenseInfoBufferLength(
+ _In_ PTRANSFER_PACKET Pkt
+ )
+{
+ return SrbGetSenseInfoBufferLength(Pkt->Srb);
+}
+
+
+__inline VOID
+ClasspSrbSetOriginalIrp(
+ _In_ PSTORAGE_REQUEST_BLOCK_HEADER Srb,
+ _In_ PIRP Irp
+ )
+{
+ if (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK)
+ {
+ ((PSTORAGE_REQUEST_BLOCK)Srb)->MiniportContext = (PVOID)Irp;
+ }
+ else
+ {
+ ((PSCSI_REQUEST_BLOCK)Srb)->SrbExtension = (PVOID)Irp;
+ }
+}
+
+__inline
+BOOLEAN
+PORT_ALLOCATED_SENSE_EX(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _In_ PSTORAGE_REQUEST_BLOCK_HEADER Srb
+ )
+{
+ return ((BOOLEAN)((TEST_FLAG(SrbGetSrbFlags(Srb), SRB_FLAGS_PORT_DRIVER_ALLOCSENSE) &&
+ TEST_FLAG(SrbGetSrbFlags(Srb), SRB_FLAGS_FREE_SENSE_BUFFER)) &&
+ (SrbGetSenseInfoBuffer(Srb) != FdoExtension->SenseData))
+ );
+}
+
+__inline
+VOID
+FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
+ _In_ PSTORAGE_REQUEST_BLOCK_HEADER Srb
+ )
+{
+ NT_ASSERT(TEST_FLAG(SrbGetSrbFlags(Srb), SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
+ NT_ASSERT(TEST_FLAG(SrbGetSrbFlags(Srb), SRB_FLAGS_FREE_SENSE_BUFFER));
+ NT_ASSERT(SrbGetSenseInfoBuffer(Srb) != FdoExtension->SenseData);
+
+ ExFreePool(SrbGetSenseInfoBuffer(Srb));
+ SrbSetSenseInfoBuffer(Srb, FdoExtension->SenseData);
+ SrbSetSenseInfoBufferLength(Srb, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(FdoExtension));
+ SrbClearSrbFlags(Srb, SRB_FLAGS_FREE_SENSE_BUFFER);
+ return;
+}
+
+#endif //NTDDI_WIN8
+
+BOOLEAN
+ClasspFailurePredictionPeriodMissed(
+ _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ );
+
+__inline
+ULONG
+ClasspGetMaxUsableBufferLengthFromOffset(
+ _In_ PVOID BaseAddress,
+ _In_ ULONG OffsetInBytes,
+ _In_ ULONG BaseStructureSizeInBytes
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the maximum size of a buffer that starts at a given offset,
+ based on the size of the containing structure.
+
+Arguments:
+
+ BaseAddress - The base address of the structure. The offset is computed relative to this.
+
+ OffsetInBytes - (BaseAddress + OffsetInBytes) points to the beginning of the buffer.
+
+ BaseStructureSizeInBytes - The size of the structure which contains the buffer.
+
+Return Value:
+
+ max(BaseStructureSizeInBytes - OffsetInBytes, 0). If any operations wrap around,
+ the return value is 0.
+
+--*/
+
+{
+
+ ULONG_PTR offsetAddress = ((ULONG_PTR)BaseAddress + OffsetInBytes);
+
+ if (offsetAddress < (ULONG_PTR)BaseAddress) {
+ //
+ // This means BaseAddress + OffsetInBytes > ULONG_PTR_MAX.
+ //
+ return 0;
+ }
+
+ if (OffsetInBytes > BaseStructureSizeInBytes) {
+ return 0;
+ }
+
+ return BaseStructureSizeInBytes - OffsetInBytes;
+}
+
+
+__inline
+BOOLEAN
+ClasspLowerLayerNotSupport (
+ _In_ NTSTATUS Status
+ )
+{
+ return ((Status == STATUS_NOT_SUPPORTED) ||
+ (Status == STATUS_NOT_IMPLEMENTED) ||
+ (Status == STATUS_INVALID_DEVICE_REQUEST) ||
+ (Status == STATUS_INVALID_PARAMETER_1));
+}
+
+NTSTATUS
+ClassDeviceHwFirmwareGetInfoProcess(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp
+ );
+
+NTSTATUS
+ClassDeviceHwFirmwareDownloadProcess(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+
+NTSTATUS
+ClassDeviceHwFirmwareActivateProcess(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb
+ );
+