1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 2010
4
5 Module Name:
6
7 disk.c
8
9 Abstract:
10
11 SCSI disk class driver
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19 Revision History:
20
21 --*/
22
23 #include "ntddk.h"
24 #include "scsi.h"
25 #include <wmidata.h>
26 #include "classpnp.h"
27
28 #include <wmistr.h>
29 #include "ntstrsafe.h"
30
31 //
32 // Set component ID for DbgPrintEx calls
33 //
34 #ifndef DEBUG_COMP_ID
35 #define DEBUG_COMP_ID DPFLTR_DISK_ID
36 #endif
37
38 //
39 // Include header file and setup GUID for tracing
40 //
41 #include <storswtr.h>
42 #define WPP_GUID_DISK (945186BF, 3DD6, 4f3f, 9C8E, 9EDD3FC9D558)
43 #ifndef WPP_CONTROL_GUIDS
44 #define WPP_CONTROL_GUIDS WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_DISK)
45 #endif
46
47
48 #ifdef ExAllocatePool
49 #undef ExAllocatePool
50 #define ExAllocatePool #NT_ASSERT(FALSE)
51 #endif
52
53 #define DISK_TAG_GENERAL ' DcS' // "ScD " - generic tag
54 #define DISK_TAG_SMART 'aDcS' // "ScDa" - SMART allocations
55 #define DISK_TAG_INFO_EXCEPTION 'ADcS' // "ScDA" - Info Exceptions
56 #define DISK_TAG_DISABLE_CACHE 'CDcS' // "ScDC" - disable cache paths
57 #define DISK_TAG_CCONTEXT 'cDcS' // "ScDc" - disk allocated completion context
58 #define DISK_TAG_DISK_GEOM 'GDcS' // "ScDG" - disk geometry buffer
59 #define DISK_TAG_UPDATE_GEOM 'gDcS' // "ScDg" - update disk geometry paths
60 #define DISK_TAG_SENSE_INFO 'IDcS' // "ScDI" - sense info buffers
61 #define DISK_TAG_PNP_ID 'iDcS' // "ScDp" - pnp ids
62 #define DISK_TAG_MODE_DATA 'MDcS' // "ScDM" - mode data buffer
63 #define DISK_CACHE_MBR_CHECK 'mDcS' // "ScDM" - mbr checksum code
64 #define DISK_TAG_NAME 'NDcS' // "ScDN" - disk name code
65 #define DISK_TAG_READ_CAP 'PDcS' // "ScDP" - read capacity buffer
66 #define DISK_TAG_PART_LIST 'pDcS' // "ScDp" - disk partition lists
67 #define DISK_TAG_SRB 'SDcS' // "ScDS" - srb allocation
68 #define DISK_TAG_START 'sDcS' // "ScDs" - start device paths
69 #define DISK_TAG_UPDATE_CAP 'UDcS' // "ScDU" - update capacity path
70 #define DISK_TAG_WI_CONTEXT 'WDcS' // "ScDW" - work-item context
71
72 #ifdef __REACTOS__
73 #undef MdlMappingNoExecute
74 #define MdlMappingNoExecute 0
75 #define NonPagedPoolNx NonPagedPool
76 #define NonPagedPoolNxCacheAligned NonPagedPoolCacheAligned
77 #undef POOL_NX_ALLOCATION
78 #define POOL_NX_ALLOCATION 0
79 #endif
80
81
82 #if defined(_X86_) || defined(_AMD64_)
83
84 //
85 // Disk device data
86 //
87
88 typedef enum _DISK_GEOMETRY_SOURCE {
89 DiskGeometryUnknown,
90 DiskGeometryFromBios,
91 DiskGeometryFromPort,
92 DiskGeometryFromNec98,
93 DiskGeometryGuessedFromBios,
94 DiskGeometryFromDefault,
95 DiskGeometryFromNT4
96 } DISK_GEOMETRY_SOURCE, *PDISK_GEOMETRY_SOURCE;
97 #endif
98
99 //
100 // Context for requests that can be combined and sent down
101 //
102
103 typedef struct _DISK_GROUP_CONTEXT
104 {
105 //
106 // Queue of requests whose representative is currently outstanding at the port driver
107 //
108 LIST_ENTRY CurrList;
109
110 //
111 // The representative for the above queue
112 //
113 PIRP CurrIrp;
114
115 //
116 // Queue of requests whose representative is waiting to go down
117 //
118 LIST_ENTRY NextList;
119
120 //
121 // The representative for the above queue
122 //
123 PIRP NextIrp;
124
125 //
126 // The srb associated with this group
127 //
128 #if (NTDDI_VERSION >= NTDDI_WIN8)
129
130 union {
131 SCSI_REQUEST_BLOCK Srb;
132 STORAGE_REQUEST_BLOCK SrbEx;
133 UCHAR SrbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE];
134 } Srb;
135
136 #else
137 SCSI_REQUEST_BLOCK Srb;
138 #endif
139
140 //
141 // The spinlock that will synchronize access to this context
142 //
143 KSPIN_LOCK Spinlock;
144
145 //
146 // This event will allow for the requests to be sent down synchronously
147 //
148 KEVENT Event;
149
150
151 #if DBG
152
153 //
154 // This counter maintains the number of requests currently tagged
155 // to the request that is waiting to go down
156 //
157 ULONG DbgTagCount;
158
159 //
160 // This counter maintains the number of requests that were avoided
161 //
162 ULONG DbgSavCount;
163
164 //
165 // This counter maintains the total number of times that we combined
166 // requests and the respective number of requests that were tagged
167 //
168 ULONG DbgRefCount[64];
169
170 #endif
171
172 } DISK_GROUP_CONTEXT, *PDISK_GROUP_CONTEXT;
173
174 //
175 // Write cache setting as defined by the user
176 //
177 typedef enum _DISK_USER_WRITE_CACHE_SETTING
178 {
179 DiskWriteCacheDisable = 0,
180 DiskWriteCacheEnable = 1,
181 DiskWriteCacheDefault = -1
182
183 } DISK_USER_WRITE_CACHE_SETTING, *PDISK_USER_WRITE_CACHE_SETTING;
184
185 typedef struct _DISK_DATA {
186
187 //
188 // This field is the ordinal of a partition as it appears on a disk.
189 //
190
191 ULONG PartitionOrdinal;
192
193 //
194 // How has this disk been partitioned? Either EFI or MBR.
195 //
196
197 PARTITION_STYLE PartitionStyle;
198
199 union {
200
201 struct {
202
203 //
204 // Disk signature (from MBR)
205 //
206
207 ULONG Signature;
208
209 //
210 // MBR checksum
211 //
212
213 ULONG MbrCheckSum;
214
215 //
216 // Number of hidden sectors for BPB.
217 //
218
219 ULONG HiddenSectors;
220
221 //
222 // Partition type of this device object
223 //
224 // This field is set by:
225 //
226 // 1. Initially set according to the partition list entry
227 // partition type returned by IoReadPartitionTable.
228 //
229 // 2. Subsequently set by the
230 // IOCTL_DISK_SET_PARTITION_INFORMATION I/O control
231 // function when IoSetPartitionInformation function
232 // successfully updates the partition type on the disk.
233 //
234
235 UCHAR PartitionType;
236
237 //
238 // Boot indicator - indicates whether this partition is a
239 // bootable (active) partition for this device
240 //
241 // This field is set according to the partition list entry boot
242 // indicator returned by IoReadPartitionTable.
243 //
244
245 BOOLEAN BootIndicator;
246
247 } Mbr;
248
249 struct {
250
251 //
252 // The DiskGUID field from the EFI partition header.
253 //
254
255 GUID DiskId;
256
257 //
258 // Partition type of this device object.
259 //
260
261 GUID PartitionType;
262
263 //
264 // Unique partition identifier for this partition.
265 //
266
267 GUID PartitionId;
268
269 //
270 // EFI partition attributes for this partition.
271 //
272
273 ULONG64 Attributes;
274
275 //
276 // EFI partition name of this partition.
277 //
278
279 WCHAR PartitionName[36];
280
281 } Efi;
282
283 #ifdef _MSC_VER
284 #pragma warning(suppress: 4201) //this is intended to be an unnamed union
285 #endif
286 };
287
288 struct {
289 //
290 // This flag is set when the well known name is created (through
291 // DiskCreateSymbolicLinks) and cleared when destroying it
292 // (by calling DiskDeleteSymbolicLinks).
293 //
294
295 unsigned int WellKnownNameCreated : 1;
296
297 //
298 // This flag is set when the PhysicalDriveN link is created (through
299 // DiskCreateSymbolicLinks) and is cleared when destroying it (through
300 // DiskDeleteSymbolicLinks)
301 //
302
303 unsigned int PhysicalDriveLinkCreated : 1;
304
305 } LinkStatus;
306
307 //
308 // ReadyStatus - STATUS_SUCCESS indicates that the drive is ready for
309 // use. Any error status is to be returned as an explaination for why
310 // a request is failed.
311 //
312 // This was done solely for the zero-length partition case of having no
313 // media in a removable disk drive. When that occurs, and a read is sent
314 // to the zero-length non-partition-zero PDO that was created, we had to
315 // be able to fail the request with a reasonable value. This may not have
316 // been the best way to do this, but it works.
317 //
318
319 NTSTATUS ReadyStatus;
320
321 //
322 // SCSI address used for SMART operations.
323 //
324
325 SCSI_ADDRESS ScsiAddress;
326
327 //
328 // What type of failure prediction mechanism is available
329 //
330
331 FAILURE_PREDICTION_METHOD FailurePredictionCapability;
332 BOOLEAN AllowFPPerfHit;
333
334 //
335 // Indicates that the SCSI Informational Exceptions mode page is supported.
336 // Note that this only indicates *support* and does not necessarily
337 // indicate that Informational Exception reporting via sense code is
338 // actually enabled.
339 //
340 BOOLEAN ScsiInfoExceptionsSupported;
341
342 //
343 // Indicates if failure prediction is actually enabled (via whatever)
344 // method is applicable as indicated by FailurePredictionCapability.
345 //
346 BOOLEAN FailurePredictionEnabled;
347
348 #if defined(_X86_) || defined(_AMD64_)
349 //
350 // This flag indiciates that a non-default geometry for this drive has
351 // already been determined by the disk driver. This field is ignored
352 // for removable media drives.
353 //
354
355 DISK_GEOMETRY_SOURCE GeometrySource;
356
357 //
358 // If GeometryDetermined is TRUE this will contain the geometry which was
359 // reported by the firmware or by the BIOS. For removable media drives
360 // this will contain the last geometry used when media was present.
361 //
362
363 DISK_GEOMETRY RealGeometry;
364 #endif
365
366 //
367 // This mutex prevents more than one IOCTL_DISK_VERIFY from being
368 // sent down to the disk. This greatly reduces the possibility of
369 // a Denial-of-Service attack
370 //
371
372 KMUTEX VerifyMutex;
373
374 //
375 // This allows for parallel flush requests to be combined into one so as to
376 // reduce the number of outstanding requests that are sent down to the disk
377 //
378
379 DISK_GROUP_CONTEXT FlushContext;
380
381 //
382 // The user-specified disk write cache setting
383 //
384
385 DISK_USER_WRITE_CACHE_SETTING WriteCacheOverride;
386
387
388 } DISK_DATA, *PDISK_DATA;
389
390 //
391 // Define a general structure of identfing disk controllers with bad
392 // hardware.
393 //
394
395 #define HackDisableTaggedQueuing (0x01)
396 #define HackDisableSynchronousTransfers (0x02)
397 #define HackDisableSpinDown (0x04)
398 #define HackDisableWriteCache (0x08)
399 #define HackCauseNotReportableHack (0x10)
400 #define HackRequiresStartUnitCommand (0x20)
401
402
403 #define DiskDeviceParameterSubkey L"Disk"
404 #define DiskDeviceUserWriteCacheSetting L"UserWriteCacheSetting"
405 #define DiskDeviceCacheIsPowerProtected L"CacheIsPowerProtected"
406
407
408 #define FUNCTIONAL_EXTENSION_SIZE sizeof(FUNCTIONAL_DEVICE_EXTENSION) + sizeof(DISK_DATA)
409
410 #define MODE_DATA_SIZE 192
411 #define VALUE_BUFFER_SIZE 2048
412 #define SCSI_DISK_TIMEOUT 10
413 #define PARTITION0_LIST_SIZE 4
414
415 #define MAX_MEDIA_TYPES 4
416 typedef struct _DISK_MEDIA_TYPES_LIST {
417 PCCHAR VendorId;
418 PCCHAR ProductId;
419 PCCHAR Revision;
420 const ULONG NumberOfTypes;
421 const ULONG NumberOfSides;
422 const STORAGE_MEDIA_TYPE MediaTypes[MAX_MEDIA_TYPES];
423 } DISK_MEDIA_TYPES_LIST, *PDISK_MEDIA_TYPES_LIST;
424
425 //
426 // WMI reregistration structures used for reregister work item
427 //
428 typedef struct
429 {
430 SINGLE_LIST_ENTRY Next;
431 PDEVICE_OBJECT DeviceObject;
432 PIRP Irp;
433 } DISKREREGREQUEST, *PDISKREREGREQUEST;
434
435 #define MAX_SECTORS_PER_VERIFY 0x100
436
437 //
438 // This is based off 100ns units
439 //
440 #define ONE_MILLI_SECOND ((ULONGLONG)10 * 1000)
441
442 //
443 // Context for the work-item
444 //
445 typedef struct _DISK_VERIFY_WORKITEM_CONTEXT
446 {
447 PIRP Irp;
448 PSCSI_REQUEST_BLOCK Srb;
449 PIO_WORKITEM WorkItem;
450
451 } DISK_VERIFY_WORKITEM_CONTEXT, *PDISK_VERIFY_WORKITEM_CONTEXT;
452
453 //
454 // Poll for Failure Prediction every hour
455 //
456 #define DISK_DEFAULT_FAILURE_POLLING_PERIOD 1 * 60 * 60
457
458 #define CHECK_IRQL() \
459 if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { \
460 NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); \
461 return STATUS_INVALID_LEVEL; \
462 }
463
464 //
465 // Static global lookup tables.
466 //
467
468 extern CLASSPNP_SCAN_FOR_SPECIAL_INFO DiskBadControllers[];
469 extern const DISK_MEDIA_TYPES_LIST DiskMediaTypes[];
470 extern const DISK_MEDIA_TYPES_LIST DiskMediaTypesExclude[];
471
472 #if defined(__REACTOS__) && defined(_MSC_VER)
473 # pragma section("PAGECONS", read)
474 # pragma section("PAGEDATA", read,write)
475 #endif
476 //
477 // Macros
478 //
479
480 //
481 // Routine prototypes.
482 //
483
484
485 DRIVER_INITIALIZE DriverEntry;
486
487 VOID
488 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
489 DiskUnload(
490 IN PDRIVER_OBJECT DriverObject
491 );
492
493 NTSTATUS
494 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
495 DiskAddDevice(
496 IN PDRIVER_OBJECT DriverObject,
497 IN PDEVICE_OBJECT Pdo
498 );
499
500 NTSTATUS
501 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
502 DiskInitFdo(
503 IN PDEVICE_OBJECT Fdo
504 );
505
506 NTSTATUS
507 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
508 DiskStartFdo(
509 IN PDEVICE_OBJECT Fdo
510 );
511
512 NTSTATUS
513 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
514 DiskStopDevice(
515 IN PDEVICE_OBJECT DeviceObject,
516 IN UCHAR Type
517 );
518
519 NTSTATUS
520 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
521 DiskRemoveDevice(
522 IN PDEVICE_OBJECT DeviceObject,
523 IN UCHAR Type
524 );
525
526 NTSTATUS
527 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
528 DiskReadWriteVerification(
529 IN PDEVICE_OBJECT DeviceObject,
530 IN PIRP Irp
531 );
532
533 NTSTATUS
534 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
535 DiskDeviceControl(
536 IN PDEVICE_OBJECT DeviceObject,
537 IN PIRP Irp
538 );
539
540 VOID
541 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
542 DiskFdoProcessError(
543 PDEVICE_OBJECT DeviceObject,
544 PSCSI_REQUEST_BLOCK Srb,
545 NTSTATUS *Status,
546 BOOLEAN *Retry
547 );
548
549 NTSTATUS
550 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
551 DiskShutdownFlush(
552 IN PDEVICE_OBJECT DeviceObject,
553 IN PIRP Irp
554 );
555
556 NTSTATUS
557 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
558 DiskGetCacheInformation(
559 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
560 IN PDISK_CACHE_INFORMATION CacheInfo
561 );
562
563 NTSTATUS
564 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
565 DiskSetCacheInformation(
566 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
567 IN PDISK_CACHE_INFORMATION CacheInfo
568 );
569
570 VOID
571 DiskLogCacheInformation(
572 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
573 IN PDISK_CACHE_INFORMATION CacheInfo,
574 IN NTSTATUS Status
575 );
576
577 NTSTATUS
578 DiskIoctlGetCacheSetting(
579 IN PDEVICE_OBJECT DeviceObject,
580 IN PIRP Irp
581 );
582
583 NTSTATUS
584 DiskIoctlSetCacheSetting(
585 IN PDEVICE_OBJECT DeviceObject,
586 IN PIRP Irp
587 );
588
589 IO_WORKITEM_ROUTINE DisableWriteCache;
590
591 IO_WORKITEM_ROUTINE DiskIoctlVerifyThread;
592
593 VOID
594 DiskFlushDispatch(
595 IN PDEVICE_OBJECT Fdo,
596 IN PDISK_GROUP_CONTEXT FlushContext
597 );
598
599 IO_COMPLETION_ROUTINE DiskFlushComplete;
600
601
602 NTSTATUS
603 DiskModeSelect(
604 IN PDEVICE_OBJECT DeviceObject,
605 _In_reads_bytes_(Length) PCHAR ModeSelectBuffer,
606 IN ULONG Length,
607 IN BOOLEAN SavePage
608 );
609
610 //
611 // We need to validate that the self test subcommand is valid and
612 // appropriate. Right now we allow subcommands 0, 1 and 2 which are non
613 // captive mode tests. Once we figure out a way to know if it is safe to
614 // run a captive test then we can allow captive mode tests. Also if the
615 // atapi 5 spec is ever updated to denote that bit 7 is the captive
616 // mode bit, we can allow any request that does not have bit 7 set. Until
617 // that is done we want to be sure
618 //
619 #define DiskIsValidSmartSelfTest(Subcommand) \
620 ( ((Subcommand) == SMART_OFFLINE_ROUTINE_OFFLINE) || \
621 ((Subcommand) == SMART_SHORT_SELFTEST_OFFLINE) || \
622 ((Subcommand) == SMART_EXTENDED_SELFTEST_OFFLINE) )
623
624
625 NTSTATUS
626 DiskPerformSmartCommand(
627 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
628 IN ULONG SrbControlCode,
629 IN UCHAR Command,
630 IN UCHAR Feature,
631 IN UCHAR SectorCount,
632 IN UCHAR SectorNumber,
633 IN OUT PSRB_IO_CONTROL SrbControl,
634 OUT PULONG BufferSize
635 );
636
637 NTSTATUS
638 DiskGetInfoExceptionInformation(
639 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
640 OUT PMODE_INFO_EXCEPTIONS ReturnPageData
641 );
642
643 NTSTATUS
644 DiskSetInfoExceptionInformation(
645 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
646 IN PMODE_INFO_EXCEPTIONS PageData
647 );
648
649 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
650 NTSTATUS
651 DiskGetModePage(
652 _In_ PDEVICE_OBJECT Fdo,
653 _In_ UCHAR PageMode,
654 _In_ UCHAR PageControl,
655 _In_ PMODE_PARAMETER_HEADER ModeData,
656 _Inout_ PULONG ModeDataSize,
657 _Out_ PVOID* PageData
658 );
659
660 NTSTATUS
661 DiskEnableInfoExceptions(
662 _In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
663 _In_ BOOLEAN Enable
664 );
665 #endif // (NTDDI_VERSION >= NTDDI_WINBLUE)
666
667 NTSTATUS
668 DiskDetectFailurePrediction(
669 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
670 PFAILURE_PREDICTION_METHOD FailurePredictCapability,
671 BOOLEAN ScsiAddressAvailable
672 );
673
674 NTSTATUS
675 DiskCreateFdo(
676 IN PDRIVER_OBJECT DriverObject,
677 IN PDEVICE_OBJECT LowerDeviceObject,
678 IN PULONG DeviceCount,
679 IN BOOLEAN DasdAccessOnly
680 );
681
682 VOID
683 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
684 DiskSetSpecialHacks(
685 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
686 IN ULONG_PTR Data
687 );
688
689 VOID
690 ResetBus(
691 IN PDEVICE_OBJECT DeviceObject
692 );
693
694 NTSTATUS
695 DiskGenerateDeviceName(
696 IN ULONG DeviceNumber,
697 OUT PCCHAR *RawName
698 );
699
700 VOID
701 DiskCreateSymbolicLinks(
702 IN PDEVICE_OBJECT DeviceObject
703 );
704
705 VOID
706 DiskDeleteSymbolicLinks(
707 IN PDEVICE_OBJECT DeviceObject
708 );
709
710
711 NTSTATUS
712 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
713 DiskFdoQueryWmiRegInfo(
714 IN PDEVICE_OBJECT DeviceObject,
715 OUT ULONG *RegFlags,
716 OUT PUNICODE_STRING InstanceName
717 );
718
719 NTSTATUS
720 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
721 DiskFdoQueryWmiRegInfoEx(
722 IN PDEVICE_OBJECT DeviceObject,
723 OUT ULONG *RegFlags,
724 OUT PUNICODE_STRING InstanceName,
725 OUT PUNICODE_STRING MofName
726 );
727
728 NTSTATUS
729 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
730 DiskFdoQueryWmiDataBlock(
731 IN PDEVICE_OBJECT DeviceObject,
732 IN PIRP Irp,
733 IN ULONG GuidIndex,
734 IN ULONG BufferAvail,
735 OUT PUCHAR Buffer
736 );
737
738 NTSTATUS
739 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
740 DiskFdoSetWmiDataBlock(
741 IN PDEVICE_OBJECT DeviceObject,
742 IN PIRP Irp,
743 IN ULONG GuidIndex,
744 IN ULONG BufferSize,
745 IN PUCHAR Buffer
746 );
747
748 NTSTATUS
749 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
750 DiskFdoSetWmiDataItem(
751 IN PDEVICE_OBJECT DeviceObject,
752 IN PIRP Irp,
753 IN ULONG GuidIndex,
754 IN ULONG DataItemId,
755 IN ULONG BufferSize,
756 IN PUCHAR Buffer
757 );
758
759 NTSTATUS
760 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
761 DiskFdoExecuteWmiMethod(
762 IN PDEVICE_OBJECT DeviceObject,
763 IN PIRP Irp,
764 IN ULONG GuidIndex,
765 IN ULONG MethodId,
766 IN ULONG InBufferSize,
767 IN ULONG OutBufferSize,
768 IN PUCHAR Buffer
769 );
770
771 NTSTATUS
772 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
773 DiskWmiFunctionControl(
774 IN PDEVICE_OBJECT DeviceObject,
775 IN PIRP Irp,
776 IN ULONG GuidIndex,
777 IN CLASSENABLEDISABLEFUNCTION Function,
778 IN BOOLEAN Enable
779 );
780
781 NTSTATUS
782 DiskReadFailurePredictStatus(
783 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
784 PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus
785 );
786
787 NTSTATUS
788 DiskReadFailurePredictData(
789 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
790 PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData
791 );
792
793 NTSTATUS
794 DiskEnableDisableFailurePrediction(
795 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
796 BOOLEAN Enable
797 );
798
799 NTSTATUS
800 DiskEnableDisableFailurePredictPolling(
801 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
802 BOOLEAN Enable,
803 ULONG PollTimeInSeconds
804 );
805
806 NTSTATUS DiskInitializeReregistration(
807 VOID
808 );
809
810 extern GUIDREGINFO DiskWmiFdoGuidList[];
811
812 #if defined(_X86_) || defined(_AMD64_)
813 NTSTATUS
814 DiskReadDriveCapacity(
815 IN PDEVICE_OBJECT Fdo
816 );
817 #else
818 #define DiskReadDriveCapacity(Fdo) ClassReadDriveCapacity(Fdo)
819 #endif
820
821
822 #if defined(_X86_) || defined(_AMD64_)
823
824 NTSTATUS
825 DiskSaveDetectInfo(
826 PDRIVER_OBJECT DriverObject
827 );
828
829 VOID
830 DiskCleanupDetectInfo(
831 IN PDRIVER_OBJECT DriverObject
832 );
833
834 VOID
835 DiskDriverReinitialization (
836 IN PDRIVER_OBJECT DriverObject,
837 IN PVOID Nothing,
838 IN ULONG Count
839 );
840
841 #endif
842
843 #if defined(_X86_) || defined(_AMD64_)
844 NTSTATUS
845 DiskGetDetectInfo(
846 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
847 OUT PDISK_DETECTION_INFO DetectInfo
848 );
849
850 NTSTATUS
851 DiskReadSignature(
852 IN PDEVICE_OBJECT Fdo
853 );
854
855 BOOLEAN
856 DiskIsNT4Geometry(
857 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
858 );
859
860 #else
861 #define DiskGetDetectInfo(FdoExtension, DetectInfo) (STATUS_UNSUCCESSFUL)
862 #endif
863
864
865 #define DiskHashGuid(Guid) (((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0])
866
867
868 NTSTATUS
869 DiskDetermineMediaTypes(
870 IN PDEVICE_OBJECT Fdo,
871 IN PIRP Irp,
872 IN UCHAR MediumType,
873 IN UCHAR DensityCode,
874 IN BOOLEAN MediaPresent,
875 IN BOOLEAN IsWritable
876 );
877
878 NTSTATUS
879 DiskIoctlGetLengthInfo(
880 IN PDEVICE_OBJECT DeviceObject,
881 IN PIRP Irp
882 );
883
884 NTSTATUS
885 DiskIoctlGetDriveGeometry(
886 IN PDEVICE_OBJECT DeviceObject,
887 IN OUT PIRP Irp
888 );
889
890 NTSTATUS
891 DiskIoctlGetDriveGeometryEx(
892 IN PDEVICE_OBJECT DeviceObject,
893 IN PIRP Irp
894 );
895
896 NTSTATUS
897 DiskIoctlGetCacheInformation(
898 IN PDEVICE_OBJECT DeviceObject,
899 IN OUT PIRP Irp
900 );
901
902 NTSTATUS
903 DiskIoctlSetCacheInformation(
904 IN PDEVICE_OBJECT DeviceObject,
905 IN OUT PIRP Irp
906 );
907
908 NTSTATUS
909 DiskIoctlGetMediaTypesEx(
910 IN PDEVICE_OBJECT DeviceObject,
911 IN OUT PIRP Irp
912 );
913
914 NTSTATUS
915 DiskIoctlPredictFailure(
916 IN PDEVICE_OBJECT DeviceObject,
917 IN OUT PIRP Irp
918 );
919
920 NTSTATUS
921 DiskIoctlEnableFailurePrediction(
922 IN PDEVICE_OBJECT DeviceObject,
923 IN OUT PIRP Irp
924 );
925
926 NTSTATUS
927 DiskIoctlVerify(
928 IN PDEVICE_OBJECT DeviceObject,
929 IN OUT PIRP Irp
930 );
931
932 NTSTATUS
933 DiskIoctlReassignBlocks(
934 IN PDEVICE_OBJECT DeviceObject,
935 IN OUT PIRP Irp
936 );
937
938 NTSTATUS
939 DiskIoctlReassignBlocksEx(
940 IN PDEVICE_OBJECT DeviceObject,
941 IN OUT PIRP Irp
942 );
943
944 NTSTATUS
945 DiskIoctlIsWritable(
946 IN PDEVICE_OBJECT DeviceObject,
947 IN OUT PIRP Irp
948 );
949
950 NTSTATUS
951 DiskIoctlSetVerify(
952 IN PDEVICE_OBJECT DeviceObject,
953 IN OUT PIRP Irp
954 );
955
956 NTSTATUS
957 DiskIoctlClearVerify(
958 IN PDEVICE_OBJECT DeviceObject,
959 IN OUT PIRP Irp
960 );
961
962 NTSTATUS
963 DiskIoctlUpdateDriveSize(
964 IN PDEVICE_OBJECT DeviceObject,
965 IN OUT PIRP Irp
966 );
967
968 NTSTATUS
969 DiskIoctlGetVolumeDiskExtents(
970 IN PDEVICE_OBJECT DeviceObject,
971 IN OUT PIRP Irp
972 );
973
974 NTSTATUS
975 DiskIoctlSmartGetVersion(
976 IN PDEVICE_OBJECT DeviceObject,
977 IN OUT PIRP Irp
978 );
979
980 NTSTATUS
981 DiskIoctlSmartReceiveDriveData(
982 IN PDEVICE_OBJECT DeviceObject,
983 IN OUT PIRP Irp
984 );
985
986 NTSTATUS
987 DiskIoctlSmartSendDriveCommand(
988 IN PDEVICE_OBJECT DeviceObject,
989 IN OUT PIRP Irp
990 );
991
992 FORCEINLINE // __REACTOS__
993 PCDB
GetSrbScsiData(_In_ PSTORAGE_REQUEST_BLOCK SrbEx,_In_opt_ PUCHAR CdbLength8,_In_opt_ PULONG CdbLength32,_In_opt_ PUCHAR ScsiStatus,_In_opt_ PVOID * SenseInfoBuffer,_In_opt_ PUCHAR SenseInfoBufferLength)994 GetSrbScsiData(
995 _In_ PSTORAGE_REQUEST_BLOCK SrbEx,
996 _In_opt_ PUCHAR CdbLength8,
997 _In_opt_ PULONG CdbLength32,
998 _In_opt_ PUCHAR ScsiStatus,
999 _In_opt_ PVOID *SenseInfoBuffer,
1000 _In_opt_ PUCHAR SenseInfoBufferLength
1001 )
1002 /*++
1003
1004 Routine Description:
1005
1006 Helper function to retrieve SCSI related fields from an extended SRB. If SRB is
1007 not a SRB_FUNCTION_EXECUTE_SCSI or not an extended SRB, default values will be returned.
1008
1009 Arguments:
1010
1011 SrbEx - Pointer to extended SRB.
1012
1013 CdbLength8 - Pointer to buffer to hold CdbLength field value for
1014 SRBEX_DATA_SCSI_CDB16 or SRBEX_DATA_SCSI_CDB32
1015
1016 CdbLength32 - Pointer to buffer to hold CdbLength field value for
1017 SRBEX_DATA_SCSI_CDB_VAR
1018
1019 ScsiStatus - Pointer to buffer to hold ScsiStatus field value.
1020
1021 SenseInfoBuffer - Pointer to buffer to hold SenseInfoBuffer value.
1022
1023 SenseInfoBufferLength - Pointer to buffer to hold SenseInfoBufferLength value.
1024
1025 Return Value:
1026
1027 Pointer to Cdb field or NULL if SRB is not a SRB_FUNCTION_EXECUTE_SCSI.
1028
1029 --*/
1030 {
1031 PCDB Cdb = NULL;
1032 ULONG i;
1033 PSRBEX_DATA SrbExData = NULL;
1034 BOOLEAN FoundEntry = FALSE;
1035
1036 if ((SrbEx->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) &&
1037 (SrbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)) {
1038 NT_ASSERT(SrbEx->NumSrbExData > 0);
1039
1040 for (i = 0; i < SrbEx->NumSrbExData; i++) {
1041
1042 // Skip any invalid offsets
1043 if ((SrbEx->SrbExDataOffset[i] < sizeof(STORAGE_REQUEST_BLOCK)) ||
1044 (SrbEx->SrbExDataOffset[i] > SrbEx->SrbLength)){
1045 // Catch any invalid offsets
1046 NT_ASSERT(FALSE);
1047 continue;
1048 }
1049
1050 SrbExData = (PSRBEX_DATA)((PUCHAR)SrbEx + SrbEx->SrbExDataOffset[i]);
1051
1052 switch (SrbExData->Type) {
1053
1054 case SrbExDataTypeScsiCdb16:
1055 if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB16) <= SrbEx->SrbLength) {
1056 FoundEntry = TRUE;
1057 if (CdbLength8) {
1058 *CdbLength8 = ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength;
1059 }
1060
1061 if (((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength > 0) {
1062 Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB16) SrbExData)->Cdb;
1063 }
1064
1065 if (ScsiStatus) {
1066 *ScsiStatus =
1067 ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->ScsiStatus;
1068 }
1069
1070 if (SenseInfoBuffer) {
1071 *SenseInfoBuffer =
1072 ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBuffer;
1073 }
1074
1075 if (SenseInfoBufferLength) {
1076 *SenseInfoBufferLength =
1077 ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBufferLength;
1078 }
1079
1080 } else {
1081 // Catch invalid offset
1082 NT_ASSERT(FALSE);
1083 }
1084 break;
1085
1086 case SrbExDataTypeScsiCdb32:
1087 if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB32) <= SrbEx->SrbLength) {
1088 FoundEntry = TRUE;
1089 if (CdbLength8) {
1090 *CdbLength8 = ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength;
1091 }
1092
1093 if (((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength > 0) {
1094 Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB32) SrbExData)->Cdb;
1095 }
1096
1097 if (ScsiStatus) {
1098 *ScsiStatus =
1099 ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->ScsiStatus;
1100 }
1101
1102 if (SenseInfoBuffer) {
1103 *SenseInfoBuffer =
1104 ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBuffer;
1105 }
1106
1107 if (SenseInfoBufferLength) {
1108 *SenseInfoBufferLength =
1109 ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBufferLength;
1110 }
1111
1112 } else {
1113 // Catch invalid offset
1114 NT_ASSERT(FALSE);
1115 }
1116 break;
1117
1118 case SrbExDataTypeScsiCdbVar:
1119 if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB_VAR) <= SrbEx->SrbLength) {
1120 FoundEntry = TRUE;
1121 if (CdbLength32) {
1122 *CdbLength32 = ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength;
1123 }
1124
1125 if (((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength > 0) {
1126 Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->Cdb;
1127 }
1128
1129 if (ScsiStatus) {
1130 *ScsiStatus =
1131 ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->ScsiStatus;
1132 }
1133
1134 if (SenseInfoBuffer) {
1135 *SenseInfoBuffer =
1136 ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBuffer;
1137 }
1138
1139 if (SenseInfoBufferLength) {
1140 *SenseInfoBufferLength =
1141 ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBufferLength;
1142 }
1143
1144 } else {
1145 // Catch invalid offset
1146 NT_ASSERT(FALSE);
1147 }
1148 break;
1149 }
1150
1151 if (FoundEntry) {
1152 break;
1153 }
1154 }
1155
1156 } else {
1157
1158 if (CdbLength8) {
1159 *CdbLength8 = 0;
1160 }
1161
1162 if (CdbLength32) {
1163 *CdbLength32 = 0;
1164 }
1165
1166 if (ScsiStatus) {
1167 *ScsiStatus = 0;
1168 }
1169
1170 if (SenseInfoBuffer) {
1171 *SenseInfoBuffer = NULL;
1172 }
1173
1174 if (SenseInfoBufferLength) {
1175 *SenseInfoBufferLength = 0;
1176 }
1177 }
1178
1179 return Cdb;
1180 }
1181
1182 FORCEINLINE // __REACTOS__
1183 VOID
SetSrbScsiData(_In_ PSTORAGE_REQUEST_BLOCK SrbEx,_In_ UCHAR CdbLength8,_In_ ULONG CdbLength32,_In_ UCHAR ScsiStatus,_In_opt_ PVOID SenseInfoBuffer,_In_ UCHAR SenseInfoBufferLength)1184 SetSrbScsiData(
1185 _In_ PSTORAGE_REQUEST_BLOCK SrbEx,
1186 _In_ UCHAR CdbLength8,
1187 _In_ ULONG CdbLength32,
1188 _In_ UCHAR ScsiStatus,
1189 _In_opt_ PVOID SenseInfoBuffer,
1190 _In_ UCHAR SenseInfoBufferLength
1191 )
1192 /*++
1193
1194 Routine Description:
1195
1196 Helper function to set SCSI related fields from an extended SRB. If SRB is
1197 not a SRB_FUNCTION_EXECUTE_SCSI or not an extended SRB, no modifications will
1198 be made
1199
1200 Arguments:
1201
1202 SrbEx - Pointer to extended SRB.
1203
1204 CdbLength8 - CdbLength field value for SRBEX_DATA_SCSI_CDB16
1205 or SRBEX_DATA_SCSI_CDB32
1206
1207 CdbLength32 - CdbLength field value for SRBEX_DATA_SCSI_CDB_VAR
1208
1209 ScsiStatus - ScsiStatus field value.
1210
1211 SenseInfoBuffer - SenseInfoBuffer value.
1212
1213 SenseInfoBufferLength - SenseInfoBufferLength value.
1214
1215 Return Value:
1216
1217 None
1218
1219 --*/
1220 {
1221 ULONG i;
1222 PSRBEX_DATA SrbExData = NULL;
1223 BOOLEAN FoundEntry = FALSE;
1224
1225 if ((SrbEx->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) &&
1226 (SrbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)) {
1227 NT_ASSERT(SrbEx->NumSrbExData > 0);
1228
1229 for (i = 0; i < SrbEx->NumSrbExData; i++) {
1230
1231 // Skip any invalid offsets
1232 if ((SrbEx->SrbExDataOffset[i] < sizeof(STORAGE_REQUEST_BLOCK)) ||
1233 (SrbEx->SrbExDataOffset[i] > SrbEx->SrbLength)){
1234 // Catch any invalid offsets
1235 NT_ASSERT(FALSE);
1236 continue;
1237 }
1238
1239 SrbExData = (PSRBEX_DATA)((PUCHAR)SrbEx + SrbEx->SrbExDataOffset[i]);
1240
1241 switch (SrbExData->Type) {
1242
1243 case SrbExDataTypeScsiCdb16:
1244 if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB16) <= SrbEx->SrbLength) {
1245 FoundEntry = TRUE;
1246 ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength = CdbLength8;
1247 ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->ScsiStatus = ScsiStatus;
1248 ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBuffer = SenseInfoBuffer;
1249 ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength;
1250 } else {
1251 // Catch invalid offset
1252 NT_ASSERT(FALSE);
1253 }
1254 break;
1255
1256 case SrbExDataTypeScsiCdb32:
1257 if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB32) <= SrbEx->SrbLength) {
1258 FoundEntry = TRUE;
1259 ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength = CdbLength8;
1260 ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->ScsiStatus = ScsiStatus;
1261 ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBuffer = SenseInfoBuffer;
1262 ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength;
1263 } else {
1264 // Catch invalid offset
1265 NT_ASSERT(FALSE);
1266 }
1267 break;
1268
1269 case SrbExDataTypeScsiCdbVar:
1270 if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB_VAR) <= SrbEx->SrbLength) {
1271 FoundEntry = TRUE;
1272 ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength = CdbLength32;
1273 ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->ScsiStatus = ScsiStatus;
1274 ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBuffer = SenseInfoBuffer;
1275 ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength;
1276 } else {
1277 // Catch invalid offset
1278 NT_ASSERT(FALSE);
1279 }
1280 break;
1281 }
1282
1283 if (FoundEntry) {
1284 break;
1285 }
1286 }
1287
1288 }
1289
1290 return;
1291 }
1292
1293