xref: /reactos/drivers/storage/class/disk/disk.h (revision 3088717b)
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