Sample Code
Windows Driver Samples/ ClassPnP Storage Class Driver Library/ C++/ src/ classp.h/
/*++ 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 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' // // 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. */ ULONG NumRetries; 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; #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 8 #define MAX_WORKINGSET_TRANSFER_PACKETS_Consumer 128 #define MIN_WORKINGSET_TRANSFER_PACKETS_Server 128 #define MAX_WORKINGSET_TRANSFER_PACKETS_Server 2048 #define MIN_WORKINGSET_TRANSFER_PACKETS_Enterprise 512 #define MAX_WORKINGSET_TRANSFER_PACKETS_Enterprise 2048 #define MAX_CLEANUP_TRANSFER_PACKETS_AT_ONCE 8192 // // !!! 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. // KTIMER TickTimer; KDPC TickTimerDpc; // // 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; /* * 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; 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. */ #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; }; 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 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); 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 CleanupTransferPacketToWorkingSetSizeWorker; VOID CleanupTransferPacketToWorkingSetSize(PDEVICE_OBJECT Fdo, BOOLEAN LimitNumPktToDelete); _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); } __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 );
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials