3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 Private header file for classpnp.sys modules. This contains private
12 structure and function declarations as well as constant values which do
13 not need to be exported.
31 #include <pseh/pseh2.h>
33 extern CLASSPNP_SCAN_FOR_SPECIAL_INFO ClassBadItems
[];
35 extern GUID ClassGuidQueryRegInfoEx
;
38 #define CLASSP_REG_SUBKEY_NAME (L"Classpnp")
40 #define CLASSP_REG_HACK_VALUE_NAME (L"HackMask")
41 #define CLASSP_REG_MMC_DETECTION_VALUE_NAME (L"MMCDetectionState")
42 #define CLASSP_REG_WRITE_CACHE_VALUE_NAME (L"WriteCacheEnableOverride")
43 #define CLASSP_REG_PERF_RESTORE_VALUE_NAME (L"RestorePerfAtCount")
44 #define CLASSP_REG_REMOVAL_POLICY_VALUE_NAME (L"UserRemovalPolicy")
46 #define CLASS_PERF_RESTORE_MINIMUM (0x10)
47 #define CLASS_ERROR_LEVEL_1 (0x4)
48 #define CLASS_ERROR_LEVEL_2 (0x8)
50 #define FDO_HACK_CANNOT_LOCK_MEDIA (0x00000001)
51 #define FDO_HACK_GESN_IS_BAD (0x00000002)
52 #define FDO_HACK_NO_SYNC_CACHE (0x00000004)
54 #define FDO_HACK_VALID_FLAGS (0x00000007)
55 #define FDO_HACK_INVALID_FLAGS (~FDO_HACK_VALID_FLAGS)
58 * Lots of retries of synchronized SCSI commands that devices may not
59 * even support really slows down the system (especially while booting).
60 * (Even GetDriveCapacity may be failed on purpose if an external disk is powered off).
61 * If a disk cannot return a small initialization buffer at startup
62 * in two attempts (with delay interval) then we cannot expect it to return
63 * data consistently with four retries.
64 * So don't set the retry counts as high here as for data SRBs.
66 * If we find that these requests are failing consecutively,
67 * despite the retry interval, on otherwise reliable media,
68 * then we should either increase the retry interval for
69 * that failure or (by all means) increase these retry counts as appropriate.
71 #define NUM_LOCKMEDIAREMOVAL_RETRIES 1
72 #define NUM_MODESENSE_RETRIES 1
73 #define NUM_DRIVECAPACITY_RETRIES 1
76 #define CLASS_FILE_OBJECT_EXTENSION_KEY 'eteP'
77 #define CLASSP_VOLUME_VERIFY_CHECKED 0x34
79 #define CLASS_TAG_PRIVATE_DATA 'CPcS'
80 #define CLASS_TAG_PRIVATE_DATA_FDO 'FPcS'
81 #define CLASS_TAG_PRIVATE_DATA_PDO 'PPcS'
83 struct _MEDIA_CHANGE_DETECTION_INFO
{
86 // Mutex to synchronize enable/disable requests and media state changes
89 KMUTEX MediaChangeMutex
;
92 // The current state of the media (present, not present, unknown)
93 // protected by MediaChangeSynchronizationEvent
96 MEDIA_CHANGE_DETECTION_STATE MediaChangeDetectionState
;
99 // This is a count of how many time MCD has been disabled. if it is
100 // set to zero, then we'll poll the device for MCN events with the
101 // then-current method (ie. TEST UNIT READY or GESN). this is
102 // protected by MediaChangeMutex
105 LONG MediaChangeDetectionDisableCount
;
109 // The timer value to support media change events. This is a countdown
110 // value used to determine when to poll the device for a media change.
111 // The max value for the timer is 255 seconds. This is not protected
112 // by an event -- simply InterlockedExchanged() as needed.
115 LONG MediaChangeCountDown
;
118 // recent changes allowed instant retries of the MCN irp. Since this
119 // could cause an infinite loop, keep a count of how many times we've
120 // retried immediately so that we can catch if the count exceeds an
124 LONG MediaChangeRetryCount
;
127 // use GESN if it's available
132 BOOLEAN HackEventMask
;
134 UCHAR NoChangeEventMask
;
141 // If this value is one, then the irp is currently in use.
142 // If this value is zero, then the irp is available.
143 // Use InterlockedCompareExchange() to set from "available" to "in use".
144 // ASSERT that InterlockedCompareExchange() showed previous value of
145 // "in use" when changing back to "available" state.
146 // This also implicitly protects the MediaChangeSrb and SenseBuffer
149 LONG MediaChangeIrpInUse
;
152 // Pointer to the irp to be used for media change detection.
153 // protected by Interlocked MediaChangeIrpInUse
159 // The srb for the media change detection.
160 // protected by Interlocked MediaChangeIrpInUse
163 SCSI_REQUEST_BLOCK MediaChangeSrb
;
168 // Second timer to keep track of how long the media change IRP has been
169 // in use. If this value exceeds the timeout (#defined) then we should
170 // print out a message to the user and set the MediaChangeIrpLost flag
171 // protected by using Interlocked() operations in ClasspSendMediaStateIrp,
172 // the only routine which should modify this value.
175 LONG MediaChangeIrpTimeInUse
;
178 // Set by CdRomTickHandler when we determine that the media change irp has
182 BOOLEAN MediaChangeIrpLost
;
190 } MEDIA_LOCK_TYPE
, *PMEDIA_LOCK_TYPE
;
192 typedef struct _FAILURE_PREDICTION_INFO
{
193 FAILURE_PREDICTION_METHOD Method
;
194 ULONG CountDown
; // Countdown timer
195 ULONG Period
; // Countdown period
197 PIO_WORKITEM WorkQueueItem
;
200 } FAILURE_PREDICTION_INFO
, *PFAILURE_PREDICTION_INFO
;
205 // This struct must always fit within four PVOIDs of info,
206 // as it uses the irp's "PVOID DriverContext[4]" to store
209 typedef struct _CLASS_RETRY_INFO
{
210 struct _CLASS_RETRY_INFO
*Next
;
211 } CLASS_RETRY_INFO
, *PCLASS_RETRY_INFO
;
215 typedef struct _CSCAN_LIST
{
218 // The current block which has an outstanding request.
221 ULONGLONG BlockNumber
;
224 // The list of blocks past the CurrentBlock to which we're going to do
225 // i/o. This list is maintained in sorted order.
228 LIST_ENTRY CurrentSweep
;
231 // The list of blocks behind the current block for which we'll have to
232 // wait until the next scan across the disk. This is kept as a stack,
233 // the cost of sorting it is taken when it's moved over to be the
237 LIST_ENTRY NextSweep
;
239 } CSCAN_LIST
, *PCSCAN_LIST
;
242 // add to the front of this structure to help prevent illegal
243 // snooping by other utilities.
248 typedef enum _CLASS_DETECTION_STATE
{
249 ClassDetectionUnknown
= 0,
250 ClassDetectionUnsupported
= 1,
251 ClassDetectionSupported
= 2
252 } CLASS_DETECTION_STATE
, *PCLASS_DETECTION_STATE
;
255 typedef struct _CLASS_ERROR_LOG_DATA
{
256 LARGE_INTEGER TickCount
; // Offset 0x00
257 ULONG PortNumber
; // Offset 0x08
259 UCHAR ErrorPaging
: 1; // Offset 0x0c
260 UCHAR ErrorRetried
: 1;
261 UCHAR ErrorUnhandled
: 1;
262 UCHAR ErrorReserved
: 5;
266 SCSI_REQUEST_BLOCK Srb
; // Offset 0x10
269 * We define the SenseData as the default length.
270 * Since the sense data returned by the port driver may be longer,
271 * SenseData must be at the end of this structure.
272 * For our internal error log, we only log the default length.
274 SENSE_DATA SenseData
; // Offset 0x50 for x86 (or 0x68 for ia64) (ULONG32 Alignment required!)
275 } CLASS_ERROR_LOG_DATA
, *PCLASS_ERROR_LOG_DATA
;
277 #define NUM_ERROR_LOG_ENTRIES 16
281 typedef struct _TRANSFER_PACKET
{
283 LIST_ENTRY AllPktsListEntry
; // entry in fdoData's static AllTransferPacketsList
284 SINGLE_LIST_ENTRY SlistEntry
; // for when in free list (use fast slist)
290 * This is the client IRP that this TRANSFER_PACKET is currently
294 BOOLEAN CompleteOriginalIrpWhenLastPacketCompletes
;
297 * Stuff for retrying the transfer.
302 ULONG RetryIntervalSec
;
305 * Event for synchronizing the transfer (optional).
306 * (Note that we can't have the event in the packet itself because
307 * by the time a thread waits on an event the packet may have
308 * been completed and re-issued.
310 PKEVENT SyncEventPtr
;
313 * Stuff for retrying during extreme low-memory stress
314 * (when we retry 1 page at a time).
316 BOOLEAN InLowMemRetry
;
317 PUCHAR LowMemRetry_remainingBufPtr
;
318 ULONG LowMemRetry_remainingBufLen
;
319 LARGE_INTEGER LowMemRetry_nextChunkTargetLocation
;
322 * Fields used for cancelling the packet.
324 // BOOLEAN Cancelled;
325 // KEVENT CancelledEvent;
328 * We keep the buffer and length values here as well
329 * as in the SRB because some miniports return
330 * the transferred length in SRB.DataTransferLength,
331 * and if the SRB failed we need that value again for the retry.
332 * We don't trust the lower stack to preserve any of these values in the SRB.
336 LARGE_INTEGER TargetLocationCopy
;
339 * This is a standard SCSI structure that receives a detailed
340 * report about a SCSI error on the hardware.
342 SENSE_DATA SrbErrorSenseData
;
345 * This is the SRB block for this TRANSFER_PACKET.
346 * For IOCTLs, the SRB block includes two DWORDs for
347 * device object and ioctl code; so these must
348 * immediately follow the SRB block.
350 SCSI_REQUEST_BLOCK Srb
;
351 // ULONG SrbIoctlDevObj; // not handling ioctls yet
352 // ULONG SrbIoctlCode;
354 } TRANSFER_PACKET
, *PTRANSFER_PACKET
;
357 * MIN_INITIAL_TRANSFER_PACKETS is the minimum number of packets that
358 * we preallocate at startup for each device (we need at least one packet
359 * to guarantee forward progress during memory stress).
360 * MIN_WORKINGSET_TRANSFER_PACKETS is the number of TRANSFER_PACKETs
361 * we allow to build up and remain for each device;
362 * we _lazily_ work down to this number when they're not needed.
363 * MAX_WORKINGSET_TRANSFER_PACKETS is the number of TRANSFER_PACKETs
364 * that we _immediately_ reduce to when they are not needed.
366 * The absolute maximum number of packets that we will allocate is
367 * whatever is required by the current activity, up to the memory limit;
368 * as soon as stress ends, we snap down to MAX_WORKINGSET_TRANSFER_PACKETS;
369 * we then lazily work down to MIN_WORKINGSET_TRANSFER_PACKETS.
371 #define MIN_INITIAL_TRANSFER_PACKETS 1
372 #define MIN_WORKINGSET_TRANSFER_PACKETS_Consumer 4
373 #define MAX_WORKINGSET_TRANSFER_PACKETS_Consumer 64
374 #define MIN_WORKINGSET_TRANSFER_PACKETS_Server 64
375 #define MAX_WORKINGSET_TRANSFER_PACKETS_Server 1024
376 #define MIN_WORKINGSET_TRANSFER_PACKETS_Enterprise 256
377 #define MAX_WORKINGSET_TRANSFER_PACKETS_Enterprise 2048
381 // add to the front of this structure to help prevent illegal
382 // snooping by other utilities.
384 struct _CLASS_PRIVATE_FDO_DATA
{
387 // this private structure allows us to
388 // dynamically re-enable the perf benefits
389 // lost due to transient error conditions.
390 // in w2k, a reboot was required. :(
393 ULONG OriginalSrbFlags
;
395 ULONG ReEnableThreshhold
; // 0 means never
400 STORAGE_HOTPLUG_INFO HotplugInfo
;
402 // Legacy. Still used by obsolete legacy code.
404 LARGE_INTEGER Delta
; // in ticks
405 LARGE_INTEGER Tick
; // when it should fire
406 PCLASS_RETRY_INFO ListHead
; // singly-linked list
407 ULONG Granularity
; // static
408 KSPIN_LOCK Lock
; // protective spin lock
409 KDPC Dpc
; // DPC routine object
410 KTIMER Timer
; // timer to fire DPC
413 BOOLEAN TimerStarted
;
414 BOOLEAN LoggedTURFailureSinceLastIO
;
417 // privately allocated release queue irp
418 // protected by fdoExtension->ReleaseQueueSpinLock
420 BOOLEAN ReleaseQueueIrpAllocated
;
421 PIRP ReleaseQueueIrp
;
424 * Queues for TRANSFER_PACKETs that contextualize the IRPs and SRBs
425 * that we send down to the port driver.
426 * (The free list is an slist so that we can use fast
427 * interlocked operations on it; but the relatively-static
428 * AllTransferPacketsList list has to be
429 * a doubly-linked list since we have to dequeue from the middle).
431 LIST_ENTRY AllTransferPacketsList
;
432 SLIST_HEADER FreeTransferPacketsList
;
433 ULONG NumFreeTransferPackets
;
434 ULONG NumTotalTransferPackets
;
435 ULONG DbgPeakNumTransferPackets
;
438 * Queue for deferred client irps
440 LIST_ENTRY DeferredClientIrpList
;
443 * Precomputed maximum transfer length for the hardware.
448 * SCSI_REQUEST_BLOCK template preconfigured with the constant values.
449 * This is slapped into the SRB in the TRANSFER_PACKET for each transfer.
451 SCSI_REQUEST_BLOCK SrbTemplate
;
456 * Circular array of timestamped logs of errors that occurred on this device.
458 ULONG ErrorLogNextIndex
;
459 CLASS_ERROR_LOG_DATA ErrorLogs
[NUM_ERROR_LOG_ENTRIES
];
464 #define MIN(a, b) ((a) < (b) ? (a) : (b))
465 #define MAX(a, b) ((a) > (b) ? (a) : (b))
468 #define NOT_READY_RETRY_INTERVAL 10
469 #define MINIMUM_RETRY_UNITS ((LONGLONG)32)
473 * Simple singly-linked-list queuing macros, with no synchronization.
475 static inline VOID
SimpleInitSlistHdr(SINGLE_LIST_ENTRY
*SListHdr
)
477 SListHdr
->Next
= NULL
;
479 static inline VOID
SimplePushSlist(SINGLE_LIST_ENTRY
*SListHdr
, SINGLE_LIST_ENTRY
*SListEntry
)
481 SListEntry
->Next
= SListHdr
->Next
;
482 SListHdr
->Next
= SListEntry
;
484 static inline SINGLE_LIST_ENTRY
*SimplePopSlist(SINGLE_LIST_ENTRY
*SListHdr
)
486 SINGLE_LIST_ENTRY
*sListEntry
= SListHdr
->Next
;
488 SListHdr
->Next
= sListEntry
->Next
;
489 sListEntry
->Next
= NULL
;
493 static inline BOOLEAN
SimpleIsSlistEmpty(SINGLE_LIST_ENTRY
*SListHdr
)
495 return (SListHdr
->Next
== NULL
);
498 DRIVER_INITIALIZE DriverEntry
;
500 DRIVER_UNLOAD ClassUnload
;
502 DRIVER_DISPATCH ClassCreateClose
;
507 IN PDEVICE_OBJECT DeviceObject
,
513 ClasspCleanupProtectedLocks(
514 IN PFILE_OBJECT_EXTENSION FsContext
519 ClasspEjectionControl(
520 IN PDEVICE_OBJECT Fdo
,
522 IN MEDIA_LOCK_TYPE LockType
,
526 DRIVER_DISPATCH ClassReadWrite
;
528 DRIVER_DISPATCH ClassDeviceControlDispatch
;
530 DRIVER_DISPATCH ClassDispatchPnp
;
535 IN PDEVICE_OBJECT DeviceObject
541 IN PDEVICE_OBJECT DeviceObject
,
545 DRIVER_DISPATCH ClassSystemControl
;
548 // Class internal routines
551 DRIVER_ADD_DEVICE ClassAddDevice
;
553 IO_COMPLETION_ROUTINE ClasspSendSynchronousCompletion
;
558 PDEVICE_OBJECT DeviceObject
,
560 PSCSI_REQUEST_BLOCK Srb
,
568 IN PDEVICE_OBJECT DeviceObject
,
575 ClassPnpQueryFdoRelations(
576 IN PDEVICE_OBJECT Fdo
,
582 ClassRetrieveDeviceRelations(
583 IN PDEVICE_OBJECT Fdo
,
584 IN DEVICE_RELATION_TYPE RelationType
,
585 OUT PDEVICE_RELATIONS
*DeviceRelations
591 IN PDEVICE_OBJECT Pdo
,
592 IN BUS_QUERY_ID_TYPE IdType
,
593 IN PUNICODE_STRING IdString
598 ClassQueryPnpCapabilities(
599 IN PDEVICE_OBJECT PhysicalDeviceObject
,
600 IN PDEVICE_CAPABILITIES Capabilities
603 DRIVER_STARTIO ClasspStartIo
;
607 ClasspPagingNotificationCompletion(
608 IN PDEVICE_OBJECT DeviceObject
,
610 IN PDEVICE_OBJECT RealDeviceObject
615 ClasspMediaChangeCompletion(
616 PDEVICE_OBJECT DeviceObject
,
621 PFILE_OBJECT_EXTENSION
624 IN PCOMMON_DEVICE_EXTENSION CommonExtension
,
625 IN PFILE_OBJECT FileObject
631 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
633 IN PSCSI_REQUEST_BLOCK Srb
638 ClasspRegisterMountedDeviceInterface(
639 IN PDEVICE_OBJECT DeviceObject
645 PDEVICE_OBJECT DeviceObject
651 PDEVICE_OBJECT DeviceObject
655 // routines for dictionary list support
660 InitializeDictionary(
661 IN PDICTIONARY Dictionary
666 TestDictionarySignature(
667 IN PDICTIONARY Dictionary
672 AllocateDictionaryEntry(
673 IN PDICTIONARY Dictionary
,
683 IN PDICTIONARY Dictionary
,
690 IN PDICTIONARY Dictionary
,
697 ClasspAllocateReleaseRequest(
698 IN PDEVICE_OBJECT Fdo
703 ClasspFreeReleaseRequest(
704 IN PDEVICE_OBJECT Fdo
707 IO_COMPLETION_ROUTINE ClassReleaseQueueCompletion
;
712 IN PDEVICE_OBJECT DeviceObject
,
713 IN PIRP ReleaseQueueIrp
718 ClasspDisablePowerNotification(
719 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
723 // class power routines
726 DRIVER_DISPATCH ClassDispatchPower
;
730 ClassMinimalPowerHandler(
731 IN PDEVICE_OBJECT DeviceObject
,
736 // Child list routines
742 IN PFUNCTIONAL_DEVICE_EXTENSION Parent
,
743 IN PPHYSICAL_DEVICE_EXTENSION Child
,
744 IN BOOLEAN AcquireLock
747 PPHYSICAL_DEVICE_EXTENSION
750 IN PFUNCTIONAL_DEVICE_EXTENSION Parent
,
751 IN PPHYSICAL_DEVICE_EXTENSION Child
,
752 IN BOOLEAN AcquireLock
758 IN PCLASS_PRIVATE_FDO_DATA FdoData
761 KDEFERRED_ROUTINE ClasspRetryRequestDpc
;
766 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
767 IN PSCSI_REQUEST_BLOCK Srb
773 IN PDEVICE_OBJECT SelfDeviceObject
,
775 IN LARGE_INTEGER TimeDelta100ns
// in 100ns units
780 ClasspBuildRequestEx(
781 IN PFUNCTIONAL_DEVICE_EXTENSION Fdo
,
783 IN PSCSI_REQUEST_BLOCK Srb
788 ClasspAllocateReleaseQueueIrp(
789 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
794 ClasspInitializeGesn(
795 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
796 IN PMEDIA_CHANGE_DETECTION_INFO Info
801 ClasspSendNotification(
802 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
803 IN
const GUID
* Guid
,
804 IN ULONG ExtraDataSize
,
810 ClassSendEjectionNotification(
811 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
816 ClasspScanForSpecialInRegistry(
817 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
822 ClasspScanForClassHacks(
823 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
829 ClasspInitializeHotplugInfo(
830 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
835 ClasspPerfIncrementErrorCount(
836 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
840 ClasspPerfIncrementSuccessfulIo(
841 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
844 PTRANSFER_PACKET NTAPI
NewTransferPacket(PDEVICE_OBJECT Fdo
);
845 VOID NTAPI
DestroyTransferPacket(PTRANSFER_PACKET Pkt
);
846 VOID NTAPI
EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo
, PTRANSFER_PACKET Pkt
);
847 PTRANSFER_PACKET NTAPI
DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo
, BOOLEAN AllocIfNeeded
);
848 VOID NTAPI
SetupReadWriteTransferPacket(PTRANSFER_PACKET pkt
, PVOID Buf
, ULONG Len
, LARGE_INTEGER DiskLocation
, PIRP OriginalIrp
);
849 VOID NTAPI
SubmitTransferPacket(PTRANSFER_PACKET Pkt
);
850 NTSTATUS NTAPI
TransferPktComplete(IN PDEVICE_OBJECT NullFdo
, IN PIRP Irp
, IN PVOID Context
);
851 VOID NTAPI
ServiceTransferRequest(PDEVICE_OBJECT Fdo
, PIRP Irp
);
852 VOID NTAPI
TransferPacketRetryTimerDpc(IN PKDPC Dpc
, IN PVOID DeferredContext
, IN PVOID SystemArgument1
, IN PVOID SystemArgument2
);
853 BOOLEAN NTAPI
InterpretTransferPacketError(PTRANSFER_PACKET Pkt
);
854 BOOLEAN NTAPI
RetryTransferPacket(PTRANSFER_PACKET Pkt
);
855 VOID NTAPI
EnqueueDeferredClientIrp(PCLASS_PRIVATE_FDO_DATA FdoData
, PIRP Irp
);
856 PIRP NTAPI
DequeueDeferredClientIrp(PCLASS_PRIVATE_FDO_DATA FdoData
);
857 VOID NTAPI
InitLowMemRetry(PTRANSFER_PACKET Pkt
, PVOID BufPtr
, ULONG Len
, LARGE_INTEGER TargetLocation
);
858 BOOLEAN NTAPI
StepLowMemRetry(PTRANSFER_PACKET Pkt
);
859 VOID NTAPI
SetupEjectionTransferPacket(TRANSFER_PACKET
*Pkt
, BOOLEAN PreventMediaRemoval
, PKEVENT SyncEventPtr
, PIRP OriginalIrp
);
860 VOID NTAPI
SetupModeSenseTransferPacket(TRANSFER_PACKET
*Pkt
, PKEVENT SyncEventPtr
, PVOID ModeSenseBuffer
, UCHAR ModeSenseBufferLen
, UCHAR PageMode
, PIRP OriginalIrp
);
861 VOID NTAPI
SetupDriveCapacityTransferPacket(TRANSFER_PACKET
*Pkt
, PVOID ReadCapacityBuffer
, ULONG ReadCapacityBufferLen
, PKEVENT SyncEventPtr
, PIRP OriginalIrp
);
862 PMDL NTAPI
BuildDeviceInputMdl(PVOID Buffer
, ULONG BufferLen
);
863 VOID NTAPI
FreeDeviceInputMdl(PMDL Mdl
);
864 NTSTATUS NTAPI
InitializeTransferPackets(PDEVICE_OBJECT Fdo
);
865 VOID NTAPI
DestroyAllTransferPackets(PDEVICE_OBJECT Fdo
);