xref: /reactos/drivers/storage/class/disk/disk.c (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 #define DEBUG_MAIN_SOURCE   1
24 #include "disk.h"
25 
26 
27 //
28 // Now instantiate the GUIDs
29 //
30 
31 #include "initguid.h"
32 #include "ntddstor.h"
33 #include "ntddvol.h"
34 #include "ioevent.h"
35 
36 #ifdef DEBUG_USE_WPP
37 #include "disk.tmh"
38 #endif
39 
40 #ifdef ALLOC_PRAGMA
41 
42 #pragma alloc_text(INIT, DriverEntry)
43 #pragma alloc_text(PAGE, DiskUnload)
44 #pragma alloc_text(PAGE, DiskCreateFdo)
45 #pragma alloc_text(PAGE, DiskDetermineMediaTypes)
46 #pragma alloc_text(PAGE, DiskModeSelect)
47 #pragma alloc_text(PAGE, DisableWriteCache)
48 #pragma alloc_text(PAGE, DiskSetSpecialHacks)
49 #pragma alloc_text(PAGE, DiskGetCacheInformation)
50 #pragma alloc_text(PAGE, DiskSetCacheInformation)
51 #pragma alloc_text(PAGE, DiskLogCacheInformation)
52 #pragma alloc_text(PAGE, DiskSetInfoExceptionInformation)
53 #pragma alloc_text(PAGE, DiskGetInfoExceptionInformation)
54 #pragma alloc_text(PAGE, DiskIoctlGetCacheSetting)
55 #pragma alloc_text(PAGE, DiskIoctlSetCacheSetting)
56 #pragma alloc_text(PAGE, DiskIoctlGetLengthInfo)
57 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometry)
58 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometryEx)
59 #pragma alloc_text(PAGE, DiskIoctlGetCacheInformation)
60 #pragma alloc_text(PAGE, DiskIoctlSetCacheInformation)
61 #pragma alloc_text(PAGE, DiskIoctlGetMediaTypesEx)
62 #pragma alloc_text(PAGE, DiskIoctlPredictFailure)
63 #pragma alloc_text(PAGE, DiskIoctlEnableFailurePrediction)
64 #pragma alloc_text(PAGE, DiskIoctlReassignBlocks)
65 #pragma alloc_text(PAGE, DiskIoctlReassignBlocksEx)
66 #pragma alloc_text(PAGE, DiskIoctlIsWritable)
67 #pragma alloc_text(PAGE, DiskIoctlUpdateDriveSize)
68 #pragma alloc_text(PAGE, DiskIoctlGetVolumeDiskExtents)
69 #pragma alloc_text(PAGE, DiskIoctlSmartGetVersion)
70 #pragma alloc_text(PAGE, DiskIoctlSmartReceiveDriveData)
71 #pragma alloc_text(PAGE, DiskIoctlSmartSendDriveCommand)
72 #pragma alloc_text(PAGE, DiskIoctlVerifyThread)
73 
74 #endif
75 
76 //
77 //  ETW related globals
78 //
79 BOOLEAN DiskETWEnabled = FALSE;
80 
81 BOOLEAN DiskIsPastReinit = FALSE;
82 
83 const GUID GUID_NULL = { 0 };
84 #define DiskCompareGuid(_First,_Second) \
85     (memcmp ((_First),(_Second), sizeof (GUID)))
86 
87 //
88 // This macro is used to work around a bug in the definition of
89 // DISK_CACHE_RETENTION_PRIORITY.  The value KeepReadData should be
90 // assigned 0xf rather than 0x2.  Since the interface was already published
91 // when this was discovered the disk driver has been modified to translate
92 // between the interface value and the correct scsi value.
93 //
94 // 0x2 is turned into 0xf
95 // 0xf is turned into 0x2 - this ensures that future SCSI defintions can be
96 //                          accomodated.
97 //
98 
99 #define TRANSLATE_RETENTION_PRIORITY(_x)\
100         ((_x) == 0xf ?  0x2 :           \
101             ((_x) == 0x2 ? 0xf : _x)    \
102         )
103 
104 #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN  CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_READ_ACCESS)
105 
106 VOID
107 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskDriverReinit(IN PDRIVER_OBJECT DriverObject,IN PVOID Nothing,IN ULONG Count)108 DiskDriverReinit(
109     IN PDRIVER_OBJECT DriverObject,
110     IN PVOID Nothing,
111     IN ULONG Count
112     )
113 {
114     UNREFERENCED_PARAMETER(DriverObject);
115     UNREFERENCED_PARAMETER(Nothing);
116     UNREFERENCED_PARAMETER(Count);
117 
118     DiskIsPastReinit = TRUE;
119 }
120 
121 VOID
122 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskBootDriverReinit(IN PDRIVER_OBJECT DriverObject,IN PVOID Nothing,IN ULONG Count)123 DiskBootDriverReinit(
124     IN PDRIVER_OBJECT DriverObject,
125     IN PVOID Nothing,
126     IN ULONG Count
127     )
128 {
129     IoRegisterDriverReinitialization(DriverObject, DiskDriverReinit, NULL);
130 
131 #if defined(_X86_) || defined(_AMD64_)
132 
133     DiskDriverReinitialization(DriverObject, Nothing, Count);
134 
135 #else
136 
137     UNREFERENCED_PARAMETER(Nothing);
138     UNREFERENCED_PARAMETER(Count);
139 
140 #endif
141 
142 }
143 
144 NTSTATUS
145 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)146 DriverEntry(
147     IN PDRIVER_OBJECT DriverObject,
148     IN PUNICODE_STRING RegistryPath
149     )
150 
151 /*++
152 
153 Routine Description:
154 
155     This routine initializes the SCSI hard disk class driver.
156 
157 Arguments:
158 
159     DriverObject - Pointer to driver object created by system.
160 
161     RegistryPath - Pointer to the name of the services node for this driver.
162 
163 Return Value:
164 
165     The function value is the final status from the initialization operation.
166 
167 --*/
168 
169 {
170     CLASS_INIT_DATA InitializationData = { 0 };
171     CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList = { 0 };
172     GUID guidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX;
173     GUID guidSrbSupport = GUID_CLASSPNP_SRB_SUPPORT;
174     ULONG srbSupport;
175 
176     NTSTATUS status;
177 
178     //
179     // Initializes tracing
180     //
181     WPP_INIT_TRACING(DriverObject, RegistryPath);
182 
183 #if defined(_X86_) || defined(_AMD64_)
184 
185     //
186     // Read the information NtDetect squirreled away about the disks in this
187     // system.
188     //
189 
190     DiskSaveDetectInfo(DriverObject);
191 
192 #endif
193 
194     InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
195 
196     //
197     // Setup sizes and entry points for functional device objects
198     //
199 
200     InitializationData.FdoData.DeviceExtensionSize   = FUNCTIONAL_EXTENSION_SIZE;
201     InitializationData.FdoData.DeviceType            = FILE_DEVICE_DISK;
202     InitializationData.FdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN;
203 
204     InitializationData.FdoData.ClassInitDevice    = DiskInitFdo;
205     InitializationData.FdoData.ClassStartDevice   = DiskStartFdo;
206     InitializationData.FdoData.ClassStopDevice    = DiskStopDevice;
207     InitializationData.FdoData.ClassRemoveDevice  = DiskRemoveDevice;
208     InitializationData.FdoData.ClassPowerDevice   = ClassSpinDownPowerHandler;
209 
210     InitializationData.FdoData.ClassError         = DiskFdoProcessError;
211     InitializationData.FdoData.ClassReadWriteVerification = DiskReadWriteVerification;
212     InitializationData.FdoData.ClassDeviceControl = DiskDeviceControl;
213     InitializationData.FdoData.ClassShutdownFlush = DiskShutdownFlush;
214     InitializationData.FdoData.ClassCreateClose   = NULL;
215 
216 
217     InitializationData.FdoData.ClassWmiInfo.GuidCount               = 7;
218     InitializationData.FdoData.ClassWmiInfo.GuidRegInfo             = DiskWmiFdoGuidList;
219     InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo    = DiskFdoQueryWmiRegInfo;
220     InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock  = DiskFdoQueryWmiDataBlock;
221     InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock    = DiskFdoSetWmiDataBlock;
222     InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem     = DiskFdoSetWmiDataItem;
223     InitializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod   = DiskFdoExecuteWmiMethod;
224     InitializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl;
225 
226     InitializationData.ClassAddDevice = DiskAddDevice;
227     InitializationData.ClassUnload = DiskUnload;
228 
229     //
230     // Initialize regregistration data structures
231     //
232 
233     DiskInitializeReregistration();
234 
235     //
236     // Call the class init routine
237     //
238 
239     status = ClassInitialize(DriverObject, RegistryPath, &InitializationData);
240 
241     if (NT_SUCCESS(status)) {
242 
243         IoRegisterBootDriverReinitialization(DriverObject,
244                                              DiskBootDriverReinit,
245                                              NULL);
246     }
247 
248     //
249     // Call class init Ex routine to register a
250     // PCLASS_QUERY_WMI_REGINFO_EX routine
251     //
252 
253     classQueryWmiRegInfoExList.Size = sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST);
254     classQueryWmiRegInfoExList.ClassFdoQueryWmiRegInfoEx = DiskFdoQueryWmiRegInfoEx;
255 
256     (VOID)ClassInitializeEx(DriverObject,
257                             &guidQueryRegInfoEx,
258                             &classQueryWmiRegInfoExList);
259 
260     //
261     // Call class init Ex routine to register SRB support
262     //
263     srbSupport = CLASS_SRB_SCSI_REQUEST_BLOCK | CLASS_SRB_STORAGE_REQUEST_BLOCK;
264     if (!NT_SUCCESS(ClassInitializeEx(DriverObject,
265                                       &guidSrbSupport,
266                                       &srbSupport))) {
267         //
268         // Should not fail
269         //
270         NT_ASSERT(FALSE);
271     }
272 
273 
274     return status;
275 
276 } // end DriverEntry()
277 
278 
279 VOID
280 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskUnload(IN PDRIVER_OBJECT DriverObject)281 DiskUnload(
282     IN PDRIVER_OBJECT DriverObject
283     )
284 {
285     PAGED_CODE();
286 
287 #if defined(_X86_) || defined(_AMD64_)
288     DiskCleanupDetectInfo(DriverObject);
289 #else
290     // NB: Need to use UNREFERENCED_PARAMETER to prevent build error
291     //     DriverObject is not referenced below in WPP_CLEANUP.
292     //     WPP_CLEANUP is currently an "NOOP" marco.
293     UNREFERENCED_PARAMETER(DriverObject);
294 #endif
295 
296 
297     //
298     // Cleans up tracing
299     //
300     WPP_CLEANUP(DriverObject);
301 
302     return;
303 }
304 
305 
306 NTSTATUS
DiskCreateFdo(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject,IN PULONG DeviceCount,IN BOOLEAN DasdAccessOnly)307 DiskCreateFdo(
308     IN PDRIVER_OBJECT DriverObject,
309     IN PDEVICE_OBJECT PhysicalDeviceObject,
310     IN PULONG DeviceCount,
311     IN BOOLEAN DasdAccessOnly
312     )
313 
314 /*++
315 
316 Routine Description:
317 
318     This routine creates an object for the functional device
319 
320 Arguments:
321 
322     DriverObject - Pointer to driver object created by system.
323 
324     PhysicalDeviceObject - Lower level driver we should attach to
325 
326     DeviceCount  - Number of previously installed devices.
327 
328     DasdAccessOnly - indicates whether or not a file system is allowed to mount
329                      on this device object.  Used to avoid double-mounting of
330                      file systems on super-floppies (which can unfortunately be
331                      fixed disks).  If set the i/o system will only allow rawfs
332                      to be mounted.
333 
334 Return Value:
335 
336     NTSTATUS
337 
338 --*/
339 
340 {
341     PCCHAR deviceName = NULL;
342     HANDLE handle = NULL;
343     PDEVICE_OBJECT lowerDevice  = NULL;
344     PDEVICE_OBJECT deviceObject = NULL;
345     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
346     NTSTATUS status;
347 
348     PAGED_CODE();
349 
350     *DeviceCount = 0;
351 
352     //
353     // Set up an object directory to contain the objects for this
354     // device and all its partitions.
355     //
356 
357     do {
358 
359         WCHAR dirBuffer[64] = { 0 };
360         UNICODE_STRING dirName;
361         OBJECT_ATTRIBUTES objectAttribs;
362 
363         status = RtlStringCchPrintfW(dirBuffer, sizeof(dirBuffer) / sizeof(dirBuffer[0]) - 1, L"\\Device\\Harddisk%d", *DeviceCount);
364         if (!NT_SUCCESS(status)) {
365             TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Format symbolic link failed with error: 0x%X\n", status));
366             return status;
367         }
368 
369         RtlInitUnicodeString(&dirName, dirBuffer);
370 
371         InitializeObjectAttributes(&objectAttribs,
372                                    &dirName,
373                                    OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
374                                    NULL,
375                                    NULL);
376 
377         status = ZwCreateDirectoryObject(&handle,
378                                          DIRECTORY_ALL_ACCESS,
379                                          &objectAttribs);
380 
381         (*DeviceCount)++;
382 
383     } while((status == STATUS_OBJECT_NAME_COLLISION) ||
384             (status == STATUS_OBJECT_NAME_EXISTS));
385 
386     if (!NT_SUCCESS(status)) {
387 
388         TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Could not create directory - %lx\n", status));
389 
390         return(status);
391     }
392 
393     //
394     // When this loop exits the count is inflated by one - fix that.
395     //
396 
397     (*DeviceCount)--;
398 
399     //
400     // Claim the device.
401     //
402 
403     lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
404 
405     status = ClassClaimDevice(lowerDevice, FALSE);
406 
407     if (!NT_SUCCESS(status)) {
408         ZwMakeTemporaryObject(handle);
409         ZwClose(handle);
410         ObDereferenceObject(lowerDevice);
411         return status;
412     }
413 
414     //
415     // Create a device object for this device. Each physical disk will
416     // have at least one device object. The required device object
417     // describes the entire device. Its directory path is
418     // \Device\HarddiskN\Partition0, where N = device number.
419     //
420 
421     status = DiskGenerateDeviceName(*DeviceCount, &deviceName);
422 
423     if(!NT_SUCCESS(status)) {
424         TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo - couldn't create name %lx\n", status));
425 
426         goto DiskCreateFdoExit;
427 
428     }
429 
430     status = ClassCreateDeviceObject(DriverObject,
431                                      deviceName,
432                                      PhysicalDeviceObject,
433                                      TRUE,
434                                      &deviceObject);
435 
436     if (!NT_SUCCESS(status)) {
437         TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Can not create device object %s\n", deviceName));
438         goto DiskCreateFdoExit;
439     }
440 
441     FREE_POOL(deviceName);
442 
443     //
444     // Indicate that IRPs should include MDLs for data transfers.
445     //
446 
447     SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
448 
449     fdoExtension = deviceObject->DeviceExtension;
450 
451     if(DasdAccessOnly) {
452 
453         //
454         // Inidicate that only RAW should be allowed to mount on the root
455         // partition object.  This ensures that a file system can't doubly
456         // mount on a super-floppy by mounting once on P0 and once on P1.
457         //
458 
459 #ifdef _MSC_VER
460 #pragma prefast(suppress:28175);
461 #endif
462         SET_FLAG(deviceObject->Vpb->Flags, VPB_RAW_MOUNT);
463     }
464 
465     //
466     // Initialize lock count to zero. The lock count is used to
467     // disable the ejection mechanism on devices that support
468     // removable media. Only the lock count in the physical
469     // device extension is used.
470     //
471 
472     fdoExtension->LockCount = 0;
473 
474     //
475     // Save system disk number.
476     //
477 
478     fdoExtension->DeviceNumber = *DeviceCount;
479 
480     //
481     // Set the alignment requirements for the device based on the
482     // host adapter requirements
483     //
484 
485     if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
486         deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
487     }
488 
489     //
490     // Finally, attach to the pdo
491     //
492 
493     fdoExtension->LowerPdo = PhysicalDeviceObject;
494 
495     fdoExtension->CommonExtension.LowerDeviceObject =
496         IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
497 
498 
499     if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
500 
501         //
502         // Uh - oh, we couldn't attach
503         // cleanup and return
504         //
505 
506         status = STATUS_UNSUCCESSFUL;
507         goto DiskCreateFdoExit;
508     }
509 
510     //
511     // Clear the init flag.
512     //
513 
514     CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
515 
516     //
517     // Store a handle to the device object directory for this disk
518     //
519 
520     fdoExtension->DeviceDirectory = handle;
521 
522     ObDereferenceObject(lowerDevice);
523 
524     return STATUS_SUCCESS;
525 
526 DiskCreateFdoExit:
527 
528     if (deviceObject != NULL)
529     {
530         IoDeleteDevice(deviceObject);
531     }
532 
533     FREE_POOL(deviceName);
534 
535     ObDereferenceObject(lowerDevice);
536 
537     ZwMakeTemporaryObject(handle);
538     ZwClose(handle);
539 
540     return status;
541 }
542 
543 
544 NTSTATUS
545 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskReadWriteVerification(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)546 DiskReadWriteVerification(
547     IN PDEVICE_OBJECT DeviceObject,
548     IN PIRP Irp
549     )
550 
551 /*++
552 
553 Routine Description:
554 
555     I/O System entry for read and write requests to SCSI disks.
556 
557 Arguments:
558 
559     DeviceObject - Pointer to driver object created by system.
560     Irp - IRP involved.
561 
562 Return Value:
563 
564     NT Status
565 
566 --*/
567 
568 {
569     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
570     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
571     ULONG residualBytes;
572     ULONG residualOffset;
573     NTSTATUS status = STATUS_SUCCESS;
574 
575     //
576     // Make sure that the request is within the bounds of the partition,
577     // the number of bytes to transfer and the byte offset are a
578     // multiple of the sector size.
579     //
580 
581     residualBytes = irpSp->Parameters.Read.Length & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1);
582     residualOffset = irpSp->Parameters.Read.ByteOffset.LowPart & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1);
583 
584     if ((irpSp->Parameters.Read.ByteOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
585         (irpSp->Parameters.Read.ByteOffset.QuadPart < 0) ||
586         (residualBytes != 0) ||
587         (residualOffset != 0))
588     {
589         NT_ASSERT(residualOffset == 0);
590         status = STATUS_INVALID_PARAMETER;
591     }
592     else
593     {
594         ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - irpSp->Parameters.Read.ByteOffset.QuadPart;
595 
596         if ((ULONGLONG)irpSp->Parameters.Read.Length > bytesRemaining)
597         {
598             status = STATUS_INVALID_PARAMETER;
599         }
600     }
601 
602     if (!NT_SUCCESS(status))
603     {
604         //
605         // This error may be caused by the fact that the drive is not ready.
606         //
607 
608         status = ((PDISK_DATA) commonExtension->DriverData)->ReadyStatus;
609 
610         if (!NT_SUCCESS(status)) {
611 
612             //
613             // Flag this as a user error so that a popup is generated.
614             //
615 
616             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DiskReadWriteVerification: ReadyStatus is %lx\n", status));
617 
618             if (IoIsErrorUserInduced(status) && Irp->Tail.Overlay.Thread != NULL) {
619                 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
620             }
621 
622             //
623             // status will keep the current error
624             //
625 
626         } else if ((residualBytes == 0) && (residualOffset == 0)) {
627 
628             //
629             // This failed because we think the physical disk is too small.
630             // Send it down to the drive and let the hardware decide for
631             // itself.
632             //
633 
634             status = STATUS_SUCCESS;
635 
636         } else {
637 
638             //
639             // Note fastfat depends on this parameter to determine when to
640             // remount due to a sector size change.
641             //
642 
643             status = STATUS_INVALID_PARAMETER;
644         }
645     }
646 
647     Irp->IoStatus.Status = status;
648 
649     return status;
650 
651 } // end DiskReadWrite()
652 
653 
654 NTSTATUS
DiskDetermineMediaTypes(IN PDEVICE_OBJECT Fdo,IN PIRP Irp,IN UCHAR MediumType,IN UCHAR DensityCode,IN BOOLEAN MediaPresent,IN BOOLEAN IsWritable)655 DiskDetermineMediaTypes(
656     IN PDEVICE_OBJECT Fdo,
657     IN PIRP     Irp,
658     IN UCHAR    MediumType,
659     IN UCHAR    DensityCode,
660     IN BOOLEAN  MediaPresent,
661     IN BOOLEAN  IsWritable
662     )
663 
664 /*++
665 
666 Routine Description:
667 
668     Determines number of types based on the physical device, validates the user buffer
669     and builds the MEDIA_TYPE information.
670 
671 Arguments:
672 
673     DeviceObject - Pointer to functional device object created by system.
674     Irp - IOCTL_STORAGE_GET_MEDIA_TYPES_EX Irp.
675     MediumType - byte returned in mode data header.
676     DensityCode - byte returned in mode data block descriptor.
677     NumberOfTypes - pointer to be updated based on actual device.
678 
679 Return Value:
680 
681     Status is returned.
682 
683 --*/
684 
685 {
686     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
687     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
688 
689     PGET_MEDIA_TYPES  mediaTypes = Irp->AssociatedIrp.SystemBuffer;
690     PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
691     BOOLEAN deviceMatched = FALSE;
692 
693     PAGED_CODE();
694 
695     //
696     // this should be checked prior to calling into this routine
697     // as we use the buffer as mediaTypes
698     //
699 
700     NT_ASSERT(irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
701            sizeof(GET_MEDIA_TYPES));
702 
703     //
704     // Determine if this device is removable or fixed.
705     //
706 
707     if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
708 
709         //
710         // Fixed disk.
711         //
712 
713         mediaTypes->DeviceType = FILE_DEVICE_DISK;
714         mediaTypes->MediaInfoCount = 1;
715 
716         mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart   = fdoExtension->DiskGeometry.Cylinders.QuadPart;
717         mediaInfo->DeviceSpecific.DiskInfo.MediaType            = FixedMedia;
718         mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder    = fdoExtension->DiskGeometry.TracksPerCylinder;
719         mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack      = fdoExtension->DiskGeometry.SectorsPerTrack;
720         mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector       = fdoExtension->DiskGeometry.BytesPerSector;
721         mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides     = 1;
722         mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE);
723 
724         if (!IsWritable) {
725 
726             SET_FLAG(mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics,
727                      MEDIA_WRITE_PROTECTED);
728         }
729 
730     } else {
731 
732         PCCHAR vendorId = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->VendorIdOffset;
733         PCCHAR productId = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductIdOffset;
734         PCCHAR productRevision = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductRevisionOffset;
735         DISK_MEDIA_TYPES_LIST const *mediaListEntry;
736         ULONG  currentMedia;
737         ULONG  i;
738         ULONG  j;
739         ULONG  sizeNeeded;
740 
741         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
742                    "DiskDetermineMediaTypes: Vendor %s, Product %s\n",
743                    vendorId,
744                    productId));
745 
746 
747         //
748         // If there's an entry with such vendorId & ProductId in the DiskMediaTypesExclude list,
749         // this device shouldn't be looked up in the DiskMediaTypes list to determine a medium type.
750         // The exclude table allows to narrow down the set of devices described by the DiskMediaTypes
751         // list (e.g.: DiskMediaTypes says "all HP devices" and DiskMediaTypesExlclude says
752         // "except for HP RDX")
753         //
754 
755         for (i = 0; DiskMediaTypesExclude[i].VendorId != NULL; i++) {
756             mediaListEntry = &DiskMediaTypesExclude[i];
757 
758             if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) {
759                 continue;
760             }
761 
762             if ((mediaListEntry->ProductId != NULL) &&
763                  strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) {
764                 continue;
765             }
766 
767             goto SkipTable;
768         }
769 
770         //
771         // Run through the list until we find the entry with a NULL Vendor Id.
772         //
773 
774         for (i = 0; DiskMediaTypes[i].VendorId != NULL; i++) {
775 
776             mediaListEntry = &DiskMediaTypes[i];
777 
778             if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) {
779                 continue;
780             }
781 
782             if ((mediaListEntry->ProductId != NULL) &&
783                  strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) {
784                 continue;
785             }
786 
787             if ((mediaListEntry->Revision != NULL) &&
788                  strncmp(mediaListEntry->Revision, productRevision, strlen(mediaListEntry->Revision))) {
789                 continue;
790             }
791 
792             deviceMatched = TRUE;
793 
794             mediaTypes->DeviceType = FILE_DEVICE_DISK;
795             mediaTypes->MediaInfoCount = mediaListEntry->NumberOfTypes;
796 
797             //
798             // Ensure that buffer is large enough.
799             //
800 
801             sizeNeeded = FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
802                          (mediaListEntry->NumberOfTypes *
803                           sizeof(DEVICE_MEDIA_INFO)
804                           );
805 
806             if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
807                 sizeNeeded) {
808 
809                 //
810                 // Buffer too small
811                 //
812 
813                 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
814                 return STATUS_BUFFER_TOO_SMALL;
815             }
816 
817             for (j = 0; j < mediaListEntry->NumberOfTypes; j++) {
818 
819                 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
820                 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
821                 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
822                 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
823                 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = mediaListEntry->NumberOfSides;
824 
825                 //
826                 // Set the type.
827                 //
828 
829                 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = mediaListEntry->MediaTypes[j];
830 
831                 if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == MO_5_WO) {
832                     mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_WRITE_ONCE;
833                 } else {
834                     mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
835                 }
836 
837                 //
838                 // Status will either be success, if media is present, or no media.
839                 // It would be optimal to base from density code and medium type, but not all devices
840                 // have values for these fields.
841                 //
842 
843                 if (MediaPresent) {
844 
845                     //
846                     // The usage of MediumType and DensityCode is device specific, so this may need
847                     // to be extended to further key off of product/vendor ids.
848                     // Currently, the MO units are the only devices that return this information.
849                     //
850 
851                     if (MediumType == 2) {
852                         currentMedia = MO_5_WO;
853                     } else if (MediumType == 3) {
854                         currentMedia = MO_5_RW;
855 
856                         if (DensityCode == 0x87) {
857 
858                             //
859                             // Indicate that the pinnacle 4.6 G media
860                             // is present. Other density codes will default to normal
861                             // RW MO media.
862                             //
863 
864                             currentMedia = PINNACLE_APEX_5_RW;
865                         }
866                     } else {
867                         currentMedia = 0;
868                     }
869 
870                     if (currentMedia) {
871                         if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == (STORAGE_MEDIA_TYPE)currentMedia) {
872                             SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
873                         }
874 
875                     } else {
876                         SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
877                     }
878                 }
879 
880                 if (!IsWritable) {
881                     SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
882                 }
883 
884                 //
885                 // Advance to next entry.
886                 //
887 
888                 mediaInfo++;
889             }
890         }
891 
892 SkipTable:
893 
894         if (!deviceMatched) {
895 
896             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
897                        "DiskDetermineMediaTypes: Unknown device. Vendor: %s Product: %s Revision: %s\n",
898                                    vendorId,
899                                    productId,
900                                    productRevision));
901             //
902             // Build an entry for unknown.
903             //
904 
905             mediaTypes->DeviceType = FILE_DEVICE_DISK;
906             mediaTypes->MediaInfoCount = 1;
907 
908             mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart   = fdoExtension->DiskGeometry.Cylinders.QuadPart;
909             mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType            = RemovableMedia;
910             mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder    = fdoExtension->DiskGeometry.TracksPerCylinder;
911             mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack      = fdoExtension->DiskGeometry.SectorsPerTrack;
912             mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector       = fdoExtension->DiskGeometry.BytesPerSector;
913             mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides     = 1;
914             mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
915 
916             if (MediaPresent) {
917 
918                 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
919             }
920 
921             if (!IsWritable) {
922 
923                 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
924             }
925         }
926     }
927 
928     Irp->IoStatus.Information =
929         FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
930         (mediaTypes->MediaInfoCount * sizeof(DEVICE_MEDIA_INFO));
931 
932     return STATUS_SUCCESS;
933 }
934 
935 NTSTATUS
936 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskDeviceControl(PDEVICE_OBJECT DeviceObject,PIRP Irp)937 DiskDeviceControl(
938     PDEVICE_OBJECT DeviceObject,
939     PIRP Irp
940     )
941 
942 /*++
943 
944 Routine Description:
945 
946     I/O system entry for device controls to SCSI disks.
947 
948 Arguments:
949 
950     Fdo - Pointer to functional device object created by system.
951     Irp - IRP involved.
952 
953 Return Value:
954 
955     Status is returned.
956 
957 --*/
958 
959 {
960     PIO_STACK_LOCATION  irpStack = IoGetCurrentIrpStackLocation(Irp);
961     NTSTATUS            status = STATUS_SUCCESS;
962     ULONG               ioctlCode;
963 
964     NT_ASSERT(DeviceObject != NULL);
965 
966     Irp->IoStatus.Information = 0;
967     ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
968 
969     TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DiskDeviceControl: Received IOCTL 0x%X for device %p through IRP %p\n",
970                 ioctlCode, DeviceObject, Irp));
971 
972 
973     switch (ioctlCode) {
974 
975         case IOCTL_DISK_GET_CACHE_INFORMATION: {
976             status = DiskIoctlGetCacheInformation(DeviceObject, Irp);
977             break;
978         }
979 
980         case IOCTL_DISK_SET_CACHE_INFORMATION: {
981             status = DiskIoctlSetCacheInformation(DeviceObject, Irp);
982             break;
983         }
984 
985         case IOCTL_DISK_GET_CACHE_SETTING: {
986             status = DiskIoctlGetCacheSetting(DeviceObject, Irp);
987             break;
988         }
989 
990         case IOCTL_DISK_SET_CACHE_SETTING: {
991             status = DiskIoctlSetCacheSetting(DeviceObject, Irp);
992             break;
993         }
994 
995         case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
996             status = DiskIoctlGetDriveGeometry(DeviceObject, Irp);
997             break;
998         }
999 
1000         case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: {
1001             status = DiskIoctlGetDriveGeometryEx( DeviceObject, Irp );
1002             break;
1003         }
1004 
1005         case IOCTL_DISK_VERIFY: {
1006             status = DiskIoctlVerify(DeviceObject, Irp);
1007             break;
1008         }
1009 
1010         case IOCTL_DISK_GET_LENGTH_INFO: {
1011             status = DiskIoctlGetLengthInfo(DeviceObject, Irp);
1012             break;
1013         }
1014 
1015         case IOCTL_DISK_IS_WRITABLE: {
1016             status = DiskIoctlIsWritable(DeviceObject, Irp);
1017             break;
1018         }
1019 
1020         case IOCTL_DISK_UPDATE_DRIVE_SIZE: {
1021             status = DiskIoctlUpdateDriveSize(DeviceObject, Irp);
1022             break;
1023         }
1024 
1025         case IOCTL_DISK_REASSIGN_BLOCKS: {
1026             status = DiskIoctlReassignBlocks(DeviceObject, Irp);
1027             break;
1028         }
1029 
1030         case IOCTL_DISK_REASSIGN_BLOCKS_EX: {
1031             status = DiskIoctlReassignBlocksEx(DeviceObject, Irp);
1032             break;
1033         }
1034 
1035         case IOCTL_DISK_INTERNAL_SET_VERIFY: {
1036             status = DiskIoctlSetVerify(DeviceObject, Irp);
1037             break;
1038         }
1039 
1040         case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: {
1041             status = DiskIoctlClearVerify(DeviceObject, Irp);
1042             break;
1043         }
1044 
1045         case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
1046             status = DiskIoctlGetMediaTypesEx(DeviceObject, Irp);
1047             break;
1048         }
1049 
1050         case IOCTL_STORAGE_PREDICT_FAILURE : {
1051             status = DiskIoctlPredictFailure(DeviceObject, Irp);
1052             break;
1053         }
1054 
1055         #if (NTDDI_VERSION >= NTDDI_WINBLUE)
1056         case IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG : {
1057             status = DiskIoctlEnableFailurePrediction(DeviceObject, Irp);
1058             break;
1059         }
1060         #endif
1061 
1062         case SMART_GET_VERSION: {
1063             status = DiskIoctlSmartGetVersion(DeviceObject, Irp);
1064             break;
1065         }
1066 
1067         case SMART_RCV_DRIVE_DATA: {
1068             status = DiskIoctlSmartReceiveDriveData(DeviceObject, Irp);
1069             break;
1070         }
1071 
1072         case SMART_SEND_DRIVE_COMMAND: {
1073             status = DiskIoctlSmartSendDriveCommand(DeviceObject, Irp);
1074             break;
1075         }
1076 
1077         case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
1078         case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN: {
1079             status = DiskIoctlGetVolumeDiskExtents(DeviceObject, Irp);
1080             break;
1081         }
1082 
1083         default: {
1084 
1085             //
1086             // Pass the request to the common device control routine.
1087             //
1088             return(ClassDeviceControl(DeviceObject, Irp));
1089             break;
1090         }
1091     } // end switch
1092 
1093     if (!NT_SUCCESS(status)) {
1094 
1095         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskDeviceControl: IOCTL 0x%X to device %p failed with error 0x%X\n",
1096                     ioctlCode, DeviceObject, status));
1097         if (IoIsErrorUserInduced(status) &&
1098             (Irp->Tail.Overlay.Thread != NULL)) {
1099             IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1100         }
1101     }
1102 
1103     //
1104     // DiskIoctlVerify() (IOCTL_DISK_VERIFY) function returns STATUS_PENDING
1105     // and completes the IRP in the work item. Do not touch or complete
1106     // the IRP if STATUS_PENDING is returned.
1107     //
1108 
1109     if (status != STATUS_PENDING) {
1110 
1111 
1112         Irp->IoStatus.Status = status;
1113         ClassReleaseRemoveLock(DeviceObject, Irp);
1114         ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1115     }
1116 
1117     return(status);
1118 } // end DiskDeviceControl()
1119 
1120 NTSTATUS
1121 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskShutdownFlush(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1122 DiskShutdownFlush(
1123     IN PDEVICE_OBJECT DeviceObject,
1124     IN PIRP Irp
1125     )
1126 
1127 /*++
1128 
1129 Routine Description:
1130 
1131     This routine is the handler for shutdown and flush requests. It sends
1132     down a synch cache command to the device if its cache is enabled.  If
1133     the request is a  shutdown and the media is removable,  it sends down
1134     an unlock request
1135 
1136     Finally,  an SRB_FUNCTION_SHUTDOWN or SRB_FUNCTION_FLUSH is sent down
1137     the stack
1138 
1139 Arguments:
1140 
1141     DeviceObject - The device object processing the request
1142     Irp - The shutdown | flush request being serviced
1143 
1144 Return Value:
1145 
1146     STATUS_PENDING if successful, an error code otherwise
1147 
1148 --*/
1149 
1150 {
1151     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1152     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension;
1153     PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData;
1154     PIO_STACK_LOCATION irpStack;
1155     NTSTATUS status = STATUS_SUCCESS;
1156     ULONG srbSize;
1157     PSCSI_REQUEST_BLOCK srb;
1158     PSTORAGE_REQUEST_BLOCK srbEx = NULL;
1159     PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
1160     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
1161     PCDB cdb;
1162     KIRQL irql;
1163 
1164     //
1165     // Flush requests are combined and need to be handled in a special manner
1166     //
1167 
1168     irpStack = IoGetCurrentIrpStackLocation(Irp);
1169 
1170     if (irpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
1171 
1172         if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED)) {
1173 
1174             //
1175             // We've been assured that both the disk
1176             // and adapter caches are battery-backed
1177             //
1178 
1179             Irp->IoStatus.Status = STATUS_SUCCESS;
1180             ClassReleaseRemoveLock(DeviceObject, Irp);
1181             ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1182             return STATUS_SUCCESS;
1183         }
1184 
1185         KeAcquireSpinLock(&diskData->FlushContext.Spinlock, &irql);
1186 
1187         TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: IRP %p flags = 0x%x\n", Irp, irpStack->Flags));
1188 
1189         //
1190         // This request will most likely be completed asynchronously
1191         //
1192         IoMarkIrpPending(Irp);
1193 
1194         //
1195         // Look to see if a flush is in progress
1196         //
1197 
1198         if (diskData->FlushContext.CurrIrp != NULL) {
1199 
1200             //
1201             // There is an outstanding flush. Queue this
1202             // request to the group that is next in line
1203             //
1204 
1205             if (diskData->FlushContext.NextIrp != NULL) {
1206 
1207                 #if DBG
1208                     diskData->FlushContext.DbgTagCount++;
1209                 #endif
1210 
1211                 InsertTailList(&diskData->FlushContext.NextList, &Irp->Tail.Overlay.ListEntry);
1212 
1213                 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql);
1214 
1215                 //
1216                 // This request will be completed by its representative
1217                 //
1218 
1219             } else {
1220 
1221                 #if DBG
1222                     if (diskData->FlushContext.DbgTagCount < 64) {
1223 
1224                         diskData->FlushContext.DbgRefCount[diskData->FlushContext.DbgTagCount]++;
1225                     }
1226 
1227                     diskData->FlushContext.DbgSavCount += diskData->FlushContext.DbgTagCount;
1228                     diskData->FlushContext.DbgTagCount  = 0;
1229                 #endif
1230 
1231                 diskData->FlushContext.NextIrp = Irp;
1232                 NT_ASSERT(IsListEmpty(&diskData->FlushContext.NextList));
1233 
1234 
1235                 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql);
1236 
1237 
1238                     TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: waiting for event\n"));
1239 
1240                     //
1241                     // Wait for the outstanding flush to complete
1242                     //
1243                     KeWaitForSingleObject(&diskData->FlushContext.Event, Executive, KernelMode, FALSE, NULL);
1244 
1245                     TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: event signal\n"));
1246 
1247                     //
1248                     // Make this group the outstanding one and free up the next slot
1249                     //
1250 
1251                     KeAcquireSpinLock(&diskData->FlushContext.Spinlock, &irql);
1252 
1253                     NT_ASSERT(IsListEmpty(&diskData->FlushContext.CurrList));
1254 
1255                     while (!IsListEmpty(&diskData->FlushContext.NextList)) {
1256 
1257                         PLIST_ENTRY listEntry = RemoveHeadList(&diskData->FlushContext.NextList);
1258                         InsertTailList(&diskData->FlushContext.CurrList, listEntry);
1259                     }
1260 
1261 #ifndef __REACTOS__
1262                     // ReactOS hits this assert, because CurrIrp can already be freed at this point
1263                     // and it's possible that NextIrp has the same pointer value
1264                     NT_ASSERT(diskData->FlushContext.CurrIrp != diskData->FlushContext.NextIrp);
1265 #endif
1266                     diskData->FlushContext.CurrIrp = diskData->FlushContext.NextIrp;
1267                     diskData->FlushContext.NextIrp = NULL;
1268 
1269                     KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql);
1270 
1271                     //
1272                     // Send this request down to the device
1273                     //
1274                     DiskFlushDispatch(DeviceObject, &diskData->FlushContext);
1275             }
1276 
1277         } else {
1278 
1279             diskData->FlushContext.CurrIrp = Irp;
1280             NT_ASSERT(IsListEmpty(&diskData->FlushContext.CurrList));
1281 
1282             NT_ASSERT(diskData->FlushContext.NextIrp == NULL);
1283             NT_ASSERT(IsListEmpty(&diskData->FlushContext.NextList));
1284 
1285 
1286             KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql);
1287 
1288                 DiskFlushDispatch(DeviceObject, &diskData->FlushContext);
1289         }
1290 
1291     } else {
1292 
1293         //
1294         // Allocate SCSI request block.
1295         //
1296 
1297         if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1298             srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
1299         } else {
1300             srbSize = sizeof(SCSI_REQUEST_BLOCK);
1301         }
1302 
1303         srb = ExAllocatePoolWithTag(NonPagedPoolNx,
1304                                     srbSize,
1305                                     DISK_TAG_SRB);
1306         if (srb == NULL) {
1307 
1308             //
1309             // Set the status and complete the request.
1310             //
1311 
1312             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1313             ClassReleaseRemoveLock(DeviceObject, Irp);
1314             ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1315             return(STATUS_INSUFFICIENT_RESOURCES);
1316         }
1317 
1318         RtlZeroMemory(srb, srbSize);
1319         if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1320 
1321             srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
1322 
1323             //
1324             // Set up STORAGE_REQUEST_BLOCK fields
1325             //
1326 
1327             srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1328             srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1329             srbEx->Signature = SRB_SIGNATURE;
1330             srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1331             srbEx->SrbLength = srbSize;
1332             srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1333             srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
1334             srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1335             srbEx->NumSrbExData = 1;
1336 
1337             // Set timeout value and mark the request as not being a tagged request.
1338             srbEx->TimeOutValue = fdoExtension->TimeOutValue * 4;
1339             srbEx->RequestTag = SP_UNTAGGED;
1340             srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
1341             srbEx->SrbFlags = fdoExtension->SrbFlags;
1342 
1343             //
1344             // Set up address fields
1345             //
1346 
1347             storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1348             storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1349             storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1350 
1351             //
1352             // Set up SCSI SRB extended data fields
1353             //
1354 
1355             srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1356                 sizeof(STOR_ADDR_BTL8);
1357             if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1358                 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1359                 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1360                 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1361 
1362                 cdb = (PCDB)srbExDataCdb16->Cdb;
1363             } else {
1364                 // Should not happen
1365                 NT_ASSERT(FALSE);
1366 
1367                 //
1368                 // Set the status and complete the request.
1369                 //
1370 
1371                 Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
1372                 ClassReleaseRemoveLock(DeviceObject, Irp);
1373                 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1374                 return(STATUS_INTERNAL_ERROR);
1375             }
1376 
1377         } else {
1378 
1379             //
1380             // Write length to SRB.
1381             //
1382 
1383             srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1384 
1385             //
1386             // Set timeout value and mark the request as not being a tagged request.
1387             //
1388 
1389             srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
1390             srb->QueueTag = SP_UNTAGGED;
1391             srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
1392             srb->SrbFlags = fdoExtension->SrbFlags;
1393             srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1394 
1395             cdb = (PCDB)srb->Cdb;
1396         }
1397 
1398         //
1399         // If the write cache is enabled then send a synchronize cache request.
1400         //
1401 
1402         if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE)) {
1403 
1404             if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1405                 srbExDataCdb16->CdbLength = 10;
1406             } else {
1407                 srb->CdbLength = 10;
1408             }
1409 
1410             cdb->CDB10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
1411 
1412             status = ClassSendSrbSynchronous(DeviceObject,
1413                                              srb,
1414                                              NULL,
1415                                              0,
1416                                              TRUE);
1417 
1418             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status));
1419         }
1420 
1421         //
1422         // Unlock the device if it contains removable media
1423         //
1424 
1425         if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
1426         {
1427 
1428             if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1429 
1430                 //
1431                 // Reinitialize status fields to 0 in case there was a previous request
1432                 //
1433 
1434                 srbEx->SrbStatus = 0;
1435                 srbExDataCdb16->ScsiStatus = 0;
1436 
1437                 srbExDataCdb16->CdbLength = 6;
1438 
1439                 //
1440                 // Set timeout value
1441                 //
1442 
1443                 srbEx->TimeOutValue = fdoExtension->TimeOutValue;
1444 
1445             } else {
1446 
1447                 //
1448                 // Reinitialize status fields to 0 in case there was a previous request
1449                 //
1450 
1451                 srb->SrbStatus = 0;
1452                 srb->ScsiStatus = 0;
1453 
1454                 srb->CdbLength = 6;
1455 
1456                 //
1457                 // Set timeout value.
1458                 //
1459 
1460                 srb->TimeOutValue = fdoExtension->TimeOutValue;
1461             }
1462 
1463             cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
1464             cdb->MEDIA_REMOVAL.Prevent = FALSE;
1465 
1466             status = ClassSendSrbSynchronous(DeviceObject,
1467                                              srb,
1468                                              NULL,
1469                                              0,
1470                                              TRUE);
1471 
1472             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Unlock device request sent. Status = %lx\n", status));
1473         }
1474 
1475         //
1476         // Set up a SHUTDOWN SRB
1477         //
1478 
1479         if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1480             srbEx->NumSrbExData = 0;
1481             srbEx->SrbExDataOffset[0] = 0;
1482             srbEx->SrbFunction = SRB_FUNCTION_SHUTDOWN;
1483             srbEx->OriginalRequest = Irp;
1484             srbEx->SrbLength = CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE;
1485             srbEx->SrbStatus = 0;
1486         } else {
1487             srb->CdbLength = 0;
1488             srb->Function = SRB_FUNCTION_SHUTDOWN;
1489             srb->SrbStatus = 0;
1490             srb->OriginalRequest = Irp;
1491         }
1492 
1493         //
1494         // Set the retry count to zero.
1495         //
1496 
1497         irpStack->Parameters.Others.Argument4 = (PVOID) 0;
1498 
1499         //
1500         // Set up IoCompletion routine address.
1501         //
1502 
1503         IoSetCompletionRoutine(Irp, ClassIoComplete, srb, TRUE, TRUE, TRUE);
1504 
1505         //
1506         // Get next stack location and
1507         // set major function code.
1508         //
1509 
1510         irpStack = IoGetNextIrpStackLocation(Irp);
1511 
1512         irpStack->MajorFunction = IRP_MJ_SCSI;
1513 
1514         //
1515         // Set up SRB for execute scsi request.
1516         // Save SRB address in next stack for port driver.
1517         //
1518 
1519         irpStack->Parameters.Scsi.Srb = srb;
1520 
1521         //
1522         // Call the port driver to process the request.
1523         //
1524 
1525         IoMarkIrpPending(Irp);
1526         IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1527     }
1528 
1529     return STATUS_PENDING;
1530 }
1531 
1532 
1533 VOID
DiskFlushDispatch(IN PDEVICE_OBJECT Fdo,IN PDISK_GROUP_CONTEXT FlushContext)1534 DiskFlushDispatch(
1535     IN PDEVICE_OBJECT Fdo,
1536     IN PDISK_GROUP_CONTEXT FlushContext
1537     )
1538 
1539 /*++
1540 
1541 Routine Description:
1542 
1543     This routine is the handler for flush requests. It sends down a synch
1544     cache command to the device if its cache is enabled. This is followed
1545     by an SRB_FUNCTION_FLUSH
1546 
1547 Arguments:
1548 
1549     Fdo - The device object processing the flush request
1550     FlushContext - The flush group context
1551 
1552 Return Value:
1553 
1554     None
1555 
1556 --*/
1557 
1558 {
1559     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
1560     PSCSI_REQUEST_BLOCK srb = &FlushContext->Srb.Srb;
1561     PSTORAGE_REQUEST_BLOCK srbEx = &FlushContext->Srb.SrbEx;
1562     PIO_STACK_LOCATION  irpSp = NULL;
1563     PSTOR_ADDR_BTL8 storAddrBtl8;
1564     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
1565     NTSTATUS SyncCacheStatus = STATUS_SUCCESS;
1566 
1567     //
1568     // Fill in the srb fields appropriately
1569     //
1570     if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1571         RtlZeroMemory(srbEx, sizeof(FlushContext->Srb.SrbExBuffer));
1572 
1573         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1574         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1575         srbEx->Signature = SRB_SIGNATURE;
1576         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1577         srbEx->SrbLength = sizeof(FlushContext->Srb.SrbExBuffer);
1578         srbEx->RequestPriority = IoGetIoPriorityHint(FlushContext->CurrIrp);
1579         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1580         srbEx->TimeOutValue = fdoExt->TimeOutValue * 4;
1581         srbEx->RequestTag = SP_UNTAGGED;
1582         srbEx->RequestAttribute  = SRB_SIMPLE_TAG_REQUEST;
1583         srbEx->SrbFlags = fdoExt->SrbFlags;
1584 
1585         //
1586         // Set up address fields
1587         //
1588 
1589         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1590         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1591         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1592 
1593     } else {
1594         RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1595 
1596         srb->Length       = SCSI_REQUEST_BLOCK_SIZE;
1597         srb->TimeOutValue = fdoExt->TimeOutValue * 4;
1598         srb->QueueTag     = SP_UNTAGGED;
1599         srb->QueueAction  = SRB_SIMPLE_TAG_REQUEST;
1600         srb->SrbFlags     = fdoExt->SrbFlags;
1601     }
1602 
1603     //
1604     // If write caching is enabled then send down a synchronize cache request
1605     //
1606     if (TEST_FLAG(fdoExt->DeviceFlags, DEV_WRITE_CACHE))
1607     {
1608 
1609         if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1610             srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1611             srbEx->NumSrbExData = 1;
1612 
1613             //
1614             // Set up SCSI SRB extended data fields
1615             //
1616 
1617             srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1618                 sizeof(STOR_ADDR_BTL8);
1619             if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1620                 srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1621                 srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1622                 srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1623                 srbExDataCdb16->CdbLength = 10;
1624                 srbExDataCdb16->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1625             } else {
1626                 // Should not happen
1627                 NT_ASSERT(FALSE);
1628                 return;
1629             }
1630 
1631         } else {
1632             srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1633             srb->CdbLength = 10;
1634             srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1635         }
1636 
1637         TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending sync cache\n"));
1638 
1639         SyncCacheStatus = ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE);
1640     }
1641 
1642     //
1643     // Set up a FLUSH SRB
1644     //
1645     if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1646         srbEx->SrbFunction = SRB_FUNCTION_FLUSH;
1647         srbEx->NumSrbExData = 0;
1648         srbEx->SrbExDataOffset[0] = 0;
1649         srbEx->OriginalRequest = FlushContext->CurrIrp;
1650         srbEx->SrbStatus = 0;
1651 
1652         //
1653         // Make sure that this srb does not get freed
1654         //
1655         SET_FLAG(srbEx->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT);
1656 
1657    } else {
1658         srb->Function  = SRB_FUNCTION_FLUSH;
1659         srb->CdbLength = 0;
1660         srb->OriginalRequest = FlushContext->CurrIrp;
1661         srb->SrbStatus = 0;
1662         srb->ScsiStatus = 0;
1663 
1664         //
1665         // Make sure that this srb does not get freed
1666         //
1667         SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT);
1668     }
1669 
1670     //
1671     // Make sure that this request does not get retried
1672     //
1673     irpSp = IoGetCurrentIrpStackLocation(FlushContext->CurrIrp);
1674 
1675     irpSp->Parameters.Others.Argument4 = (PVOID) 0;
1676 
1677     //
1678     // Fill in the irp fields appropriately
1679     //
1680     irpSp = IoGetNextIrpStackLocation(FlushContext->CurrIrp);
1681 
1682     irpSp->MajorFunction       = IRP_MJ_SCSI;
1683     irpSp->Parameters.Scsi.Srb = srb;
1684 
1685     IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, (PVOID)(ULONG_PTR)SyncCacheStatus, TRUE, TRUE, TRUE);
1686 
1687     TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending srb flush on irp %p\n", FlushContext->CurrIrp));
1688 
1689     //
1690     // Send down the flush request
1691     //
1692     IoCallDriver(((PCOMMON_DEVICE_EXTENSION)fdoExt)->LowerDeviceObject, FlushContext->CurrIrp);
1693 }
1694 
1695 
1696 
1697 NTSTATUS
1698 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFlushComplete(IN PDEVICE_OBJECT Fdo,IN PIRP Irp,IN PVOID Context)1699 DiskFlushComplete(
1700     IN PDEVICE_OBJECT Fdo,
1701     IN PIRP Irp,
1702     IN PVOID Context
1703     )
1704 
1705 /*++
1706 
1707 Routine Description:
1708 
1709     This completion routine is a wrapper around ClassIoComplete. It
1710     will complete all the flush requests that are tagged to it, set
1711     an event to signal the next group to proceed and return
1712 
1713 Arguments:
1714 
1715     Fdo - The device object which requested the completion routine
1716     Irp - The irp that is being completed
1717     Context - If disk had write cache enabled and SYNC CACHE command was sent as 1st part of FLUSH processing
1718                    then context must carry the completion status of SYNC CACHE request,
1719               else context must be set to STATUS_SUCCESS.
1720 
1721 Return Value:
1722 
1723     STATUS_SUCCESS if successful, an error code otherwise
1724 
1725 --*/
1726 
1727 {
1728     PDISK_GROUP_CONTEXT FlushContext;
1729     NTSTATUS status;
1730     PFUNCTIONAL_DEVICE_EXTENSION fdoExt;
1731     PDISK_DATA diskData;
1732 #ifdef _MSC_VER
1733     #pragma warning(suppress:4311) // pointer truncation from 'PVOID' to 'NTSTATUS'
1734 #endif
1735     NTSTATUS SyncCacheStatus = (NTSTATUS)(ULONG_PTR)Context;
1736 
1737     TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DiskFlushComplete: %p %p\n", Fdo, Irp));
1738 
1739     //
1740     // Get the flush context from the device extension
1741     //
1742     fdoExt = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
1743     diskData = (PDISK_DATA)fdoExt->CommonExtension.DriverData;
1744     NT_ASSERT(diskData != NULL);
1745     _Analysis_assume_(diskData != NULL);
1746 
1747     FlushContext = &diskData->FlushContext;
1748 
1749     //
1750     // Make sure everything is in order
1751     //
1752     NT_ASSERT(Irp == FlushContext->CurrIrp);
1753 
1754     TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: completing irp %p\n", Irp));
1755     status = ClassIoComplete(Fdo, Irp, &FlushContext->Srb.Srb);
1756 
1757     //
1758     // Make sure that ClassIoComplete did not decide to retry this request
1759     //
1760     NT_ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED);
1761 
1762     //
1763     // If sync cache failed earlier, final status of the flush request needs to be failure
1764     // even if SRB_FUNCTION_FLUSH srb request succeeded
1765     //
1766     if (NT_SUCCESS(status) &&
1767         (!NT_SUCCESS(SyncCacheStatus))) {
1768         Irp->IoStatus.Status = status = SyncCacheStatus;
1769     }
1770 
1771     //
1772     // Complete the flush requests tagged to this one
1773     //
1774 
1775     while (!IsListEmpty(&FlushContext->CurrList)) {
1776 
1777         PLIST_ENTRY listEntry = RemoveHeadList(&FlushContext->CurrList);
1778         PIRP tempIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
1779 
1780         InitializeListHead(&tempIrp->Tail.Overlay.ListEntry);
1781         tempIrp->IoStatus = Irp->IoStatus;
1782 
1783         ClassReleaseRemoveLock(Fdo, tempIrp);
1784         ClassCompleteRequest(Fdo, tempIrp, IO_NO_INCREMENT);
1785     }
1786 
1787 
1788         //
1789         // Notify the next group's representative that it may go ahead now
1790         //
1791         KeSetEvent(&FlushContext->Event, IO_NO_INCREMENT, FALSE);
1792 
1793 
1794     TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: irp %p status = 0x%x\n", Irp, status));
1795 
1796     return status;
1797 }
1798 
1799 
1800 
1801 NTSTATUS
DiskModeSelect(IN PDEVICE_OBJECT Fdo,_In_reads_bytes_ (Length)PCHAR ModeSelectBuffer,IN ULONG Length,IN BOOLEAN SavePage)1802 DiskModeSelect(
1803     IN PDEVICE_OBJECT Fdo,
1804     _In_reads_bytes_(Length) PCHAR ModeSelectBuffer,
1805     IN ULONG Length,
1806     IN BOOLEAN SavePage
1807     )
1808 
1809 /*++
1810 
1811 Routine Description:
1812 
1813     This routine sends a mode select command.
1814 
1815 Arguments:
1816 
1817     DeviceObject - Supplies the device object associated with this request.
1818 
1819     ModeSelectBuffer - Supplies a buffer containing the page data.
1820 
1821     Length - Supplies the length in bytes of the mode select buffer.
1822 
1823     SavePage - Indicates that parameters should be written to disk.
1824 
1825 Return Value:
1826 
1827     Length of the transferred data is returned.
1828 
1829 --*/
1830 
1831 {
1832     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1833     PCDB cdb;
1834     SCSI_REQUEST_BLOCK srb = {0};
1835     ULONG retries = 1;
1836     ULONG length2;
1837     NTSTATUS status;
1838     PULONG buffer;
1839     PMODE_PARAMETER_BLOCK blockDescriptor;
1840     UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0};
1841     PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer;
1842     PSTOR_ADDR_BTL8 storAddrBtl8;
1843     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
1844     PSCSI_REQUEST_BLOCK srbPtr;
1845 
1846     PAGED_CODE();
1847 
1848     //
1849     // Check whether block length is available
1850     //
1851 
1852     if (fdoExtension->DiskGeometry.BytesPerSector == 0) {
1853 
1854         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Block length is not available. Unable to send mode select\n"));
1855         NT_ASSERT(fdoExtension->DiskGeometry.BytesPerSector != 0);
1856         return STATUS_INVALID_PARAMETER;
1857     }
1858 
1859 
1860 
1861     length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
1862 
1863     //
1864     // Allocate buffer for mode select header, block descriptor, and mode page.
1865     //
1866 
1867     buffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
1868                                    length2,
1869                                    DISK_TAG_MODE_DATA);
1870 
1871     if (buffer == NULL) {
1872         return STATUS_INSUFFICIENT_RESOURCES;
1873     }
1874 
1875     RtlZeroMemory(buffer, length2);
1876 
1877     //
1878     // Set length in header to size of mode page.
1879     //
1880 
1881     ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
1882 
1883     blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
1884 
1885     //
1886     // Set block length from the cached disk geometry
1887     //
1888 
1889     blockDescriptor->BlockLength[2] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 16);
1890     blockDescriptor->BlockLength[1] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 8);
1891     blockDescriptor->BlockLength[0] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector);
1892 
1893     //
1894     // Copy mode page to buffer.
1895     //
1896 
1897     RtlCopyMemory(buffer + 3, ModeSelectBuffer, Length);
1898 
1899     //
1900     // Build the MODE SELECT CDB.
1901     //
1902 
1903     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1904 
1905         //
1906         // Set up STORAGE_REQUEST_BLOCK fields
1907         //
1908 
1909         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1910         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1911         srbEx->Signature = SRB_SIGNATURE;
1912         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1913         srbEx->SrbLength = sizeof(srbExBuffer);
1914         srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1915         srbEx->RequestPriority = IoPriorityNormal;
1916         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1917         srbEx->NumSrbExData = 1;
1918 
1919         // Set timeout value from device extension.
1920         srbEx->TimeOutValue = fdoExtension->TimeOutValue * 2;
1921 
1922        //
1923        // Set up address fields
1924        //
1925 
1926        storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1927        storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1928        storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1929 
1930        //
1931        // Set up SCSI SRB extended data fields
1932        //
1933 
1934        srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1935            sizeof(STOR_ADDR_BTL8);
1936        if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1937            srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1938            srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1939            srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1940            srbExDataCdb16->CdbLength = 6;
1941 
1942            cdb = (PCDB)srbExDataCdb16->Cdb;
1943        } else {
1944            // Should not happen
1945            NT_ASSERT(FALSE);
1946 
1947            FREE_POOL(buffer);
1948            TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Insufficient extended SRB size\n"));
1949            return STATUS_INTERNAL_ERROR;
1950        }
1951 
1952        srbPtr = (PSCSI_REQUEST_BLOCK)srbEx;
1953 
1954     } else {
1955 
1956         srb.CdbLength = 6;
1957         cdb = (PCDB)srb.Cdb;
1958 
1959         //
1960         // Set timeout value from device extension.
1961         //
1962 
1963         srb.TimeOutValue = fdoExtension->TimeOutValue * 2;
1964 
1965         srbPtr = &srb;
1966     }
1967 
1968     cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1969     cdb->MODE_SELECT.SPBit = SavePage;
1970     cdb->MODE_SELECT.PFBit = 1;
1971     cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
1972 
1973 Retry:
1974 
1975     status = ClassSendSrbSynchronous(Fdo,
1976                                      srbPtr,
1977                                      buffer,
1978                                      length2,
1979                                      TRUE);
1980 
1981     if (status == STATUS_VERIFY_REQUIRED) {
1982 
1983         //
1984         // Routine ClassSendSrbSynchronous does not retry requests returned with
1985         // this status.
1986         //
1987 
1988         if (retries--) {
1989 
1990             //
1991             // Retry request.
1992             //
1993 
1994             goto Retry;
1995         }
1996 
1997     } else if (SRB_STATUS(srbPtr->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
1998         status = STATUS_SUCCESS;
1999     }
2000 
2001     FREE_POOL(buffer);
2002 
2003     return status;
2004 } // end DiskModeSelect()
2005 
2006 
2007 //
2008 // This routine is structured as a work-item routine
2009 //
2010 VOID
2011 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DisableWriteCache(IN PDEVICE_OBJECT Fdo,IN PVOID Context)2012 DisableWriteCache(
2013     IN PDEVICE_OBJECT Fdo,
2014     IN PVOID Context
2015     )
2016 
2017 {
2018     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
2019     DISK_CACHE_INFORMATION cacheInfo = { 0 };
2020     NTSTATUS status;
2021     PIO_WORKITEM WorkItem = (PIO_WORKITEM)Context;
2022 
2023     PAGED_CODE();
2024 
2025     NT_ASSERT(WorkItem != NULL);
2026     _Analysis_assume_(WorkItem != NULL);
2027 
2028     status = DiskGetCacheInformation(fdoExtension, &cacheInfo);
2029 
2030     if (NT_SUCCESS(status) && (cacheInfo.WriteCacheEnabled == TRUE)) {
2031 
2032         cacheInfo.WriteCacheEnabled = FALSE;
2033 
2034         DiskSetCacheInformation(fdoExtension, &cacheInfo);
2035     }
2036 
2037     IoFreeWorkItem(WorkItem);
2038 }
2039 
2040 
2041 //
2042 // This routine is structured as a work-item routine
2043 //
2044 VOID
2045 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskIoctlVerifyThread(IN PDEVICE_OBJECT Fdo,IN PVOID Context)2046 DiskIoctlVerifyThread(
2047     IN PDEVICE_OBJECT Fdo,
2048     IN PVOID Context
2049     )
2050 {
2051     PDISK_VERIFY_WORKITEM_CONTEXT WorkContext = (PDISK_VERIFY_WORKITEM_CONTEXT)Context;
2052     PIRP Irp = NULL;
2053     PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
2054     PDISK_DATA DiskData = (PDISK_DATA)FdoExtension->CommonExtension.DriverData;
2055     PVERIFY_INFORMATION verifyInfo = NULL;
2056     PSCSI_REQUEST_BLOCK Srb = NULL;
2057     PCDB Cdb = NULL;
2058     LARGE_INTEGER byteOffset;
2059     LARGE_INTEGER sectorOffset;
2060     ULONG sectorCount;
2061     NTSTATUS status = STATUS_SUCCESS;
2062     PSTORAGE_REQUEST_BLOCK srbEx = NULL;
2063     PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
2064     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
2065 
2066     PAGED_CODE();
2067 
2068     NT_ASSERT(WorkContext != NULL);
2069     _Analysis_assume_(WorkContext != NULL);
2070 
2071     Srb = WorkContext->Srb;
2072     Irp = WorkContext->Irp;
2073     verifyInfo = (PVERIFY_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2074 
2075     //
2076     // We don't need to hold on to this memory as
2077     // the following operation may take some time
2078     //
2079 
2080     IoFreeWorkItem(WorkContext->WorkItem);
2081 
2082     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerifyThread: Spliting up the request\n"));
2083 
2084     //
2085     // Add disk offset to starting the sector
2086     //
2087 
2088     byteOffset.QuadPart = FdoExtension->CommonExtension.StartingOffset.QuadPart +
2089                           verifyInfo->StartingOffset.QuadPart;
2090 
2091     //
2092     // Convert byte offset to the sector offset
2093     //
2094 
2095     sectorOffset.QuadPart = byteOffset.QuadPart >> FdoExtension->SectorShift;
2096 
2097     //
2098     // Convert byte count to sector count.
2099     //
2100 
2101     sectorCount = verifyInfo->Length >> FdoExtension->SectorShift;
2102 
2103     //
2104     // Make sure  that all previous verify requests have indeed completed
2105     // This greatly reduces the possibility of a Denial-of-Service attack
2106     //
2107 
2108     KeWaitForMutexObject(&DiskData->VerifyMutex,
2109                          Executive,
2110                          KernelMode,
2111                          FALSE,
2112                          NULL);
2113 
2114     //
2115     // Initialize SCSI SRB for a verify CDB
2116     //
2117     if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2118         RtlZeroMemory(Srb, CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE);
2119         srbEx = (PSTORAGE_REQUEST_BLOCK)Srb;
2120 
2121         //
2122         // Set up STORAGE_REQUEST_BLOCK fields
2123         //
2124 
2125         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
2126         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
2127         srbEx->Signature = SRB_SIGNATURE;
2128         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
2129         srbEx->SrbLength = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
2130         srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
2131         srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
2132         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
2133         srbEx->NumSrbExData = 1;
2134 
2135         //
2136         // Set up address fields
2137         //
2138 
2139         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
2140         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
2141         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
2142 
2143         //
2144         // Set up SCSI SRB extended data fields
2145         //
2146 
2147         srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
2148                sizeof(STOR_ADDR_BTL8);
2149         if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
2150             srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
2151             srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
2152             srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
2153 
2154             Cdb = (PCDB)srbExDataCdb16->Cdb;
2155             if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2156                 srbExDataCdb16->CdbLength = 16;
2157                 Cdb->CDB16.OperationCode = SCSIOP_VERIFY16;
2158             } else {
2159                 srbExDataCdb16->CdbLength = 10;
2160                 Cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2161             }
2162         } else {
2163             // Should not happen
2164             NT_ASSERT(FALSE);
2165 
2166             FREE_POOL(Srb);
2167             FREE_POOL(WorkContext);
2168             status = STATUS_INTERNAL_ERROR;
2169         }
2170 
2171     } else {
2172         RtlZeroMemory(Srb, SCSI_REQUEST_BLOCK_SIZE);
2173 
2174         Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2175         Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2176 
2177         Cdb = (PCDB)Srb->Cdb;
2178         if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2179             Srb->CdbLength = 16;
2180             Cdb->CDB16.OperationCode = SCSIOP_VERIFY16;
2181         } else {
2182             Srb->CdbLength = 10;
2183             Cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2184         }
2185 
2186     }
2187 
2188     while (NT_SUCCESS(status) && (sectorCount != 0)) {
2189 
2190         USHORT numSectors = (USHORT) min(sectorCount, MAX_SECTORS_PER_VERIFY);
2191 
2192         if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2193 
2194             //
2195             // Reset status fields
2196             //
2197 
2198             srbEx->SrbStatus = 0;
2199             srbExDataCdb16->ScsiStatus = 0;
2200 
2201             //
2202             // Calculate the request timeout value based
2203             // on  the number of sectors  being verified
2204             //
2205 
2206             srbEx->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue;
2207         } else {
2208 
2209             //
2210             // Reset status fields
2211             //
2212 
2213             Srb->SrbStatus = 0;
2214             Srb->ScsiStatus = 0;
2215 
2216             //
2217             // Calculate the request timeout value based
2218             // on  the number of sectors  being verified
2219             //
2220 
2221             Srb->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue;
2222         }
2223 
2224         //
2225         // Update verify CDB info.
2226         // NOTE - CDB opcode and length has been initialized prior to entering
2227         // the while loop
2228         //
2229 
2230         if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2231 
2232             REVERSE_BYTES_QUAD(&Cdb->CDB16.LogicalBlock, &sectorOffset);
2233             REVERSE_BYTES_SHORT(&Cdb->CDB16.TransferLength[2], &numSectors);
2234         } else {
2235 
2236             //
2237             // Move little endian values into CDB in big endian format
2238             //
2239 
2240             Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2241             Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2242             Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2243             Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2244 
2245             Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numSectors)->Byte1;
2246             Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numSectors)->Byte0;
2247         }
2248 
2249         status = ClassSendSrbSynchronous(Fdo,
2250                                          Srb,
2251                                          NULL,
2252                                          0,
2253                                          FALSE);
2254 
2255         NT_ASSERT(status != STATUS_NONEXISTENT_SECTOR);
2256 
2257         sectorCount  -= numSectors;
2258         sectorOffset.QuadPart += numSectors;
2259     }
2260 
2261     KeReleaseMutex(&DiskData->VerifyMutex, FALSE);
2262 
2263     Irp->IoStatus.Status = status;
2264     Irp->IoStatus.Information = 0;
2265 
2266     ClassReleaseRemoveLock(Fdo, Irp);
2267     ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
2268 
2269     FREE_POOL(Srb);
2270     FREE_POOL(WorkContext);
2271 }
2272 
2273 
2274 VOID
2275 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoProcessError(PDEVICE_OBJECT Fdo,PSCSI_REQUEST_BLOCK Srb,NTSTATUS * Status,BOOLEAN * Retry)2276 DiskFdoProcessError(
2277     PDEVICE_OBJECT Fdo,
2278     PSCSI_REQUEST_BLOCK Srb,
2279     NTSTATUS *Status,
2280     BOOLEAN *Retry
2281     )
2282 
2283 /*++
2284 
2285 Routine Description:
2286 
2287    This routine checks the type of error.  If the error indicates an underrun
2288    then indicate the request should be retried.
2289 
2290 Arguments:
2291 
2292     Fdo - Supplies a pointer to the functional device object.
2293 
2294     Srb - Supplies a pointer to the failing Srb.
2295 
2296     Status - Status with which the IRP will be completed.
2297 
2298     Retry - Indication of whether the request will be retried.
2299 
2300 Return Value:
2301 
2302     None.
2303 
2304 --*/
2305 
2306 {
2307     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2308     PSTORAGE_REQUEST_BLOCK srbEx;
2309     PCDB cdb = NULL;
2310     UCHAR scsiStatus = 0;
2311     UCHAR senseBufferLength = 0;
2312     PVOID senseBuffer = NULL;
2313     CDB noOp = {0};
2314 
2315     //
2316     // Get relevant fields from SRB
2317     //
2318     if (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) {
2319 
2320         srbEx = (PSTORAGE_REQUEST_BLOCK)Srb;
2321 
2322         //
2323         // Look for SCSI SRB specific fields
2324         //
2325         if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) &&
2326             (srbEx->NumSrbExData > 0)) {
2327             cdb = GetSrbScsiData(srbEx, NULL, NULL, &scsiStatus, &senseBuffer, &senseBufferLength);
2328 
2329             //
2330             // cdb and sense buffer should not be NULL
2331             //
2332             NT_ASSERT(cdb != NULL);
2333             NT_ASSERT(senseBuffer != NULL);
2334 
2335         }
2336 
2337         if (cdb == NULL) {
2338 
2339             //
2340             // Use a cdb that is all 0s
2341             //
2342             cdb = &noOp;
2343         }
2344 
2345     } else {
2346 
2347         cdb = (PCDB)(Srb->Cdb);
2348         scsiStatus = Srb->ScsiStatus;
2349         senseBufferLength = Srb->SenseInfoBufferLength;
2350         senseBuffer = Srb->SenseInfoBuffer;
2351     }
2352 
2353     if (*Status == STATUS_DATA_OVERRUN &&
2354         (cdb != NULL) &&
2355         (IS_SCSIOP_READWRITE(cdb->CDB10.OperationCode))) {
2356 
2357             *Retry = TRUE;
2358 
2359             //
2360             // Update the error count for the device.
2361             //
2362 
2363             fdoExtension->ErrorCount++;
2364 
2365     } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
2366                scsiStatus == SCSISTAT_BUSY) {
2367 
2368         //
2369         // a disk drive should never be busy this long. Reset the scsi bus
2370         // maybe this will clear the condition.
2371         //
2372 
2373         ResetBus(Fdo);
2374 
2375         //
2376         // Update the error count for the device.
2377         //
2378 
2379         fdoExtension->ErrorCount++;
2380 
2381     } else {
2382 
2383         BOOLEAN invalidatePartitionTable = FALSE;
2384 
2385         //
2386         // See if this might indicate that something on the drive has changed.
2387         //
2388 
2389         if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
2390             (senseBuffer != NULL) && (cdb != NULL)) {
2391 
2392             BOOLEAN validSense = FALSE;
2393             UCHAR senseKey = 0;
2394             UCHAR asc = 0;
2395             UCHAR ascq = 0;
2396 
2397             validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
2398                                                  senseBufferLength,
2399                                                  SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
2400                                                  &senseKey,
2401                                                  &asc,
2402                                                  &ascq);
2403 
2404             if (validSense) {
2405 
2406                 switch (senseKey) {
2407 
2408                     case SCSI_SENSE_ILLEGAL_REQUEST: {
2409 
2410                         switch (asc) {
2411 
2412                             case SCSI_ADSENSE_INVALID_CDB:
2413                             {
2414                                 //
2415                                 // Look to see if this is an Io request with the ForceUnitAccess flag set
2416                                 //
2417                                 if (((cdb->CDB10.OperationCode == SCSIOP_WRITE)   ||
2418                                     (cdb->CDB10.OperationCode == SCSIOP_WRITE16)) &&
2419                                     (cdb->CDB10.ForceUnitAccess))
2420                                 {
2421                                     PDISK_DATA diskData = (PDISK_DATA)fdoExtension->CommonExtension.DriverData;
2422 
2423                                     if (diskData->WriteCacheOverride == DiskWriteCacheEnable)
2424                                     {
2425                                         PIO_ERROR_LOG_PACKET logEntry = NULL;
2426 
2427                                         //
2428                                         // The user has explicitly requested that write caching be turned on.
2429                                         // Warn the user that writes with FUA enabled are not working and that
2430                                         // they should disable write cache.
2431                                         //
2432 
2433                                         logEntry = IoAllocateErrorLogEntry(fdoExtension->DeviceObject,
2434                                                                            sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG)));
2435 
2436                                         if (logEntry != NULL)
2437                                         {
2438                                             logEntry->FinalStatus       = *Status;
2439                                             logEntry->ErrorCode         = IO_WARNING_WRITE_FUA_PROBLEM;
2440                                             logEntry->SequenceNumber    = 0;
2441                                             logEntry->MajorFunctionCode = IRP_MJ_SCSI;
2442                                             logEntry->IoControlCode     = 0;
2443                                             logEntry->RetryCount        = 0;
2444                                             logEntry->UniqueErrorValue  = 0;
2445                                             logEntry->DumpDataSize      = 4 * sizeof(ULONG);
2446 
2447                                             logEntry->DumpData[0] = diskData->ScsiAddress.PortNumber;
2448                                             logEntry->DumpData[1] = diskData->ScsiAddress.PathId;
2449                                             logEntry->DumpData[2] = diskData->ScsiAddress.TargetId;
2450                                             logEntry->DumpData[3] = diskData->ScsiAddress.Lun;
2451 
2452                                             //
2453                                             // Write the error log packet.
2454                                             //
2455 
2456                                             IoWriteErrorLogEntry(logEntry);
2457                                         }
2458                                     }
2459                                     else
2460                                     {
2461                                         //
2462                                         // Turn off write caching on this device. This is so that future
2463                                         // critical requests need not be sent down with  ForceUnitAccess
2464                                         //
2465                                         PIO_WORKITEM workItem = IoAllocateWorkItem(Fdo);
2466 
2467                                         if (workItem)
2468                                         {
2469                                             IoQueueWorkItem(workItem, DisableWriteCache, CriticalWorkQueue, workItem);
2470                                         }
2471                                     }
2472 
2473                                     SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED);
2474                                     ADJUST_FUA_FLAG(fdoExtension);
2475 
2476 
2477                                     cdb->CDB10.ForceUnitAccess = FALSE;
2478                                     *Retry = TRUE;
2479 
2480                                 } else if ((cdb->CDB6FORMAT.OperationCode == SCSIOP_MODE_SENSE) &&
2481                                            (cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL)) {
2482 
2483                                     //
2484                                     // Mode sense for all pages failed. This command could fail with
2485                                     // SCSI_SENSE_ILLEGAL_REQUEST / SCSI_ADSENSE_INVALID_CDB if the data
2486                                     // to be returned is more than 256 bytes. In which case, try to get
2487                                     // only MODE_PAGE_CACHING since we only need the block descriptor.
2488                                     //
2489                                     // Simply change the page code and retry the request
2490                                     //
2491 
2492                                     cdb->MODE_SENSE.PageCode = MODE_PAGE_CACHING;
2493                                     *Retry = TRUE;
2494                                 }
2495 
2496                                 break;
2497                             }
2498                         } // end switch(asc)
2499                         break;
2500                     }
2501 
2502                     case SCSI_SENSE_NOT_READY: {
2503 
2504                         switch (asc) {
2505                         case SCSI_ADSENSE_LUN_NOT_READY: {
2506                             switch (ascq) {
2507                             case SCSI_SENSEQ_BECOMING_READY:
2508                             case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
2509                             case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: {
2510                                 invalidatePartitionTable = TRUE;
2511                                 break;
2512                             }
2513                             } // end switch(ascq)
2514                             break;
2515                         }
2516 
2517                         case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
2518                             invalidatePartitionTable = TRUE;
2519                             break;
2520                         }
2521                         } // end switch(asc)
2522                         break;
2523                     }
2524 
2525                     case SCSI_SENSE_MEDIUM_ERROR: {
2526                         invalidatePartitionTable = TRUE;
2527                         break;
2528                     }
2529 
2530                     case SCSI_SENSE_HARDWARE_ERROR: {
2531                         invalidatePartitionTable = TRUE;
2532                         break;
2533                     }
2534 
2535                     case SCSI_SENSE_UNIT_ATTENTION:
2536                     {
2537                         invalidatePartitionTable = TRUE;
2538                         break;
2539                     }
2540 
2541                     case SCSI_SENSE_RECOVERED_ERROR: {
2542                         invalidatePartitionTable = TRUE;
2543                         break;
2544                     }
2545 
2546                 } // end switch(senseKey)
2547             } // end if (validSense)
2548         } else {
2549 
2550             //
2551             // On any exceptional scsi condition which might indicate that the
2552             // device was changed we will flush out the state of the partition
2553             // table.
2554             //
2555 
2556             switch (SRB_STATUS(Srb->SrbStatus)) {
2557                 case SRB_STATUS_INVALID_LUN:
2558                 case SRB_STATUS_INVALID_TARGET_ID:
2559                 case SRB_STATUS_NO_DEVICE:
2560                 case SRB_STATUS_NO_HBA:
2561                 case SRB_STATUS_INVALID_PATH_ID:
2562                 case SRB_STATUS_COMMAND_TIMEOUT:
2563                 case SRB_STATUS_TIMEOUT:
2564                 case SRB_STATUS_SELECTION_TIMEOUT:
2565                 case SRB_STATUS_REQUEST_FLUSHED:
2566                 case SRB_STATUS_UNEXPECTED_BUS_FREE:
2567                 case SRB_STATUS_PARITY_ERROR:
2568                 {
2569                     invalidatePartitionTable = TRUE;
2570                     break;
2571                 }
2572 
2573                 case SRB_STATUS_ERROR:
2574                 {
2575                     if (scsiStatus == SCSISTAT_RESERVATION_CONFLICT)
2576                     {
2577                         invalidatePartitionTable = TRUE;
2578                     }
2579 
2580                     break;
2581                 }
2582             } // end switch(Srb->SrbStatus)
2583         }
2584 
2585         if (invalidatePartitionTable && TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
2586 
2587             //
2588             // Inform the upper layers that the volume
2589             // on this disk is in need of verification
2590             //
2591 
2592             SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME);
2593         }
2594     }
2595 
2596     return;
2597 }
2598 
2599 
2600 VOID
2601 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskSetSpecialHacks(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN ULONG_PTR Data)2602 DiskSetSpecialHacks(
2603     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
2604     IN ULONG_PTR Data
2605     )
2606 
2607 /*++
2608 
2609 Routine Description:
2610 
2611     This function checks to see if an SCSI logical unit requires speical
2612     flags to be set.
2613 
2614 Arguments:
2615 
2616     Fdo - Supplies the device object to be tested.
2617 
2618     InquiryData - Supplies the inquiry data returned by the device of interest.
2619 
2620     AdapterDescriptor - Supplies the capabilities of the device object.
2621 
2622 Return Value:
2623 
2624     None.
2625 
2626 --*/
2627 
2628 {
2629     PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
2630 
2631     PAGED_CODE();
2632 
2633     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "Disk SetSpecialHacks, Setting Hacks %p\n", (void*) Data));
2634 
2635     //
2636     // Found a listed controller.  Determine what must be done.
2637     //
2638 
2639     if (TEST_FLAG(Data, HackDisableTaggedQueuing)) {
2640 
2641         //
2642         // Disable tagged queuing.
2643         //
2644 
2645         CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
2646     }
2647 
2648     if (TEST_FLAG(Data, HackDisableSynchronousTransfers)) {
2649 
2650         //
2651         // Disable synchronous data transfers.
2652         //
2653 
2654         SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2655 
2656     }
2657 
2658     if (TEST_FLAG(Data, HackDisableSpinDown)) {
2659 
2660         //
2661         // Disable spinning down of drives.
2662         //
2663 
2664         SET_FLAG(FdoExtension->ScanForSpecialFlags,
2665                  CLASS_SPECIAL_DISABLE_SPIN_DOWN);
2666 
2667     }
2668 
2669     if (TEST_FLAG(Data, HackDisableWriteCache)) {
2670 
2671         //
2672         // Disable the drive's write cache
2673         //
2674 
2675         SET_FLAG(FdoExtension->ScanForSpecialFlags,
2676                  CLASS_SPECIAL_DISABLE_WRITE_CACHE);
2677 
2678     }
2679 
2680     if (TEST_FLAG(Data, HackCauseNotReportableHack)) {
2681 
2682         SET_FLAG(FdoExtension->ScanForSpecialFlags,
2683                  CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK);
2684     }
2685 
2686     if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) &&
2687         TEST_FLAG(Data, HackRequiresStartUnitCommand)
2688         ) {
2689 
2690         //
2691         // this is a list of vendors who require the START_UNIT command
2692         //
2693 
2694         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DiskScanForSpecial (%p) => This unit requires "
2695                     " START_UNITS\n", fdo));
2696         SET_FLAG(FdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
2697 
2698     }
2699 
2700     return;
2701 }
2702 
2703 
2704 VOID
ResetBus(IN PDEVICE_OBJECT Fdo)2705 ResetBus(
2706     IN PDEVICE_OBJECT Fdo
2707     )
2708 
2709 /*++
2710 
2711 Routine Description:
2712 
2713     This command sends a reset bus command to the SCSI port driver.
2714 
2715 Arguments:
2716 
2717     Fdo - The functional device object for the logical unit with hardware problem.
2718 
2719 Return Value:
2720 
2721     None.
2722 
2723 --*/
2724 
2725 {
2726     PIO_STACK_LOCATION irpStack;
2727     PIRP irp;
2728 
2729     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2730     PSCSI_REQUEST_BLOCK srb;
2731     PCOMPLETION_CONTEXT context;
2732     PSTORAGE_REQUEST_BLOCK srbEx = NULL;
2733     PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
2734 
2735     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "Disk ResetBus: Sending reset bus request to port driver.\n"));
2736 
2737     //
2738     // Allocate Srb from nonpaged pool.
2739     //
2740 
2741     context = ExAllocatePoolWithTag(NonPagedPoolNx,
2742                                     sizeof(COMPLETION_CONTEXT),
2743                                     DISK_TAG_CCONTEXT);
2744 
2745     if(context == NULL) {
2746         return;
2747     }
2748 
2749     //
2750     // Save the device object in the context for use by the completion
2751     // routine.
2752     //
2753 
2754     context->DeviceObject = Fdo;
2755     srb = &context->Srb.Srb;
2756 
2757     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2758         srbEx = &context->Srb.SrbEx;
2759 
2760         //
2761         // Zero out srb
2762         //
2763 
2764         RtlZeroMemory(srbEx, sizeof(context->Srb.SrbExBuffer));
2765 
2766         //
2767         // Set up STORAGE_REQUEST_BLOCK fields
2768         //
2769 
2770         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
2771         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
2772         srbEx->Signature = SRB_SIGNATURE;
2773         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
2774         srbEx->SrbLength = sizeof(context->Srb.SrbExBuffer);
2775         srbEx->SrbFunction = SRB_FUNCTION_RESET_BUS;
2776         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
2777 
2778         //
2779         // Set up address fields
2780         //
2781 
2782         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
2783         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
2784         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
2785 
2786     } else {
2787 
2788         //
2789         // Zero out srb.
2790         //
2791 
2792         RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2793 
2794         //
2795         // Write length to SRB.
2796         //
2797 
2798         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2799 
2800         srb->Function = SRB_FUNCTION_RESET_BUS;
2801 
2802     }
2803 
2804     //
2805     // Build the asynchronous request to be sent to the port driver.
2806     // Since this routine is called from a DPC the IRP should always be
2807     // available.
2808     //
2809 
2810     irp = IoAllocateIrp(Fdo->StackSize, FALSE);
2811 
2812     if (irp == NULL) {
2813         FREE_POOL(context);
2814         return;
2815     }
2816 
2817     ClassAcquireRemoveLock(Fdo, irp);
2818 
2819     IoSetCompletionRoutine(irp,
2820                            (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
2821                            context,
2822                            TRUE,
2823                            TRUE,
2824                            TRUE);
2825 
2826     irpStack = IoGetNextIrpStackLocation(irp);
2827 
2828     irpStack->MajorFunction = IRP_MJ_SCSI;
2829 
2830     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2831         srbEx->RequestPriority = IoGetIoPriorityHint(irp);
2832         srbEx->OriginalRequest = irp;
2833     } else {
2834         srb->OriginalRequest = irp;
2835     }
2836 
2837     //
2838     // Store the SRB address in next stack for port driver.
2839     //
2840 
2841     irpStack->Parameters.Scsi.Srb = srb;
2842 
2843     //
2844     // Call the port driver with the IRP.
2845     //
2846 
2847     IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
2848 
2849     return;
2850 
2851 } // end ResetBus()
2852 
2853 
2854 
2855 VOID
DiskLogCacheInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PDISK_CACHE_INFORMATION CacheInfo,IN NTSTATUS Status)2856 DiskLogCacheInformation(
2857     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
2858     IN PDISK_CACHE_INFORMATION CacheInfo,
2859     IN NTSTATUS Status
2860     )
2861 {
2862     PIO_ERROR_LOG_PACKET logEntry = NULL;
2863 
2864     PAGED_CODE();
2865 
2866     logEntry = IoAllocateErrorLogEntry(FdoExtension->DeviceObject, sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG)));
2867 
2868     if (logEntry != NULL)
2869     {
2870         PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
2871         BOOLEAN bIsEnabled  = TEST_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
2872 
2873         logEntry->FinalStatus       = Status;
2874         logEntry->ErrorCode         = (bIsEnabled) ? IO_WRITE_CACHE_ENABLED : IO_WRITE_CACHE_DISABLED;
2875         logEntry->SequenceNumber    = 0;
2876         logEntry->MajorFunctionCode = IRP_MJ_SCSI;
2877         logEntry->IoControlCode     = 0;
2878         logEntry->RetryCount        = 0;
2879         logEntry->UniqueErrorValue  = 0x1;
2880         logEntry->DumpDataSize      = 4 * sizeof(ULONG);
2881 
2882         logEntry->DumpData[0] = diskData->ScsiAddress.PathId;
2883         logEntry->DumpData[1] = diskData->ScsiAddress.TargetId;
2884         logEntry->DumpData[2] = diskData->ScsiAddress.Lun;
2885         logEntry->DumpData[3] = CacheInfo->WriteCacheEnabled;
2886 
2887         //
2888         // Write the error log packet.
2889         //
2890 
2891         IoWriteErrorLogEntry(logEntry);
2892     }
2893 }
2894 
2895 NTSTATUS
DiskGetInfoExceptionInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PMODE_INFO_EXCEPTIONS ReturnPageData)2896 DiskGetInfoExceptionInformation(
2897     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
2898     IN PMODE_INFO_EXCEPTIONS ReturnPageData
2899     )
2900 {
2901     PMODE_PARAMETER_HEADER modeData;
2902     PMODE_INFO_EXCEPTIONS pageData;
2903     ULONG length;
2904 
2905     NTSTATUS status;
2906 
2907     PAGED_CODE();
2908 
2909     //
2910     // ReturnPageData is allocated by the caller
2911     //
2912 
2913     modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
2914                                          MODE_DATA_SIZE,
2915                                          DISK_TAG_INFO_EXCEPTION);
2916 
2917     if (modeData == NULL) {
2918 
2919         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Unable to allocate mode "
2920                        "data buffer\n"));
2921         return STATUS_INSUFFICIENT_RESOURCES;
2922     }
2923 
2924     RtlZeroMemory(modeData, MODE_DATA_SIZE);
2925 
2926     length = ClassModeSense(FdoExtension->DeviceObject,
2927                             (PCHAR) modeData,
2928                             MODE_DATA_SIZE,
2929                             MODE_PAGE_FAULT_REPORTING);
2930 
2931     if (length < sizeof(MODE_PARAMETER_HEADER)) {
2932 
2933         //
2934         // Retry the request in case of a check condition.
2935         //
2936 
2937         length = ClassModeSense(FdoExtension->DeviceObject,
2938                                 (PCHAR) modeData,
2939                                 MODE_DATA_SIZE,
2940                                 MODE_PAGE_FAULT_REPORTING);
2941 
2942         if (length < sizeof(MODE_PARAMETER_HEADER)) {
2943             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Mode Sense failed\n"));
2944             FREE_POOL(modeData);
2945             return STATUS_IO_DEVICE_ERROR;
2946         }
2947     }
2948 
2949     //
2950     // If the length is greater than length indicated by the mode data reset
2951     // the data to the mode data.
2952     //
2953 
2954     if (length > (ULONG) (modeData->ModeDataLength + 1)) {
2955         length = modeData->ModeDataLength + 1;
2956     }
2957 
2958     //
2959     // Find the mode page for info exceptions
2960     //
2961 
2962     pageData = ClassFindModePage((PCHAR) modeData,
2963                                  length,
2964                                  MODE_PAGE_FAULT_REPORTING,
2965                                  TRUE);
2966 
2967     if (pageData != NULL) {
2968         RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS));
2969         status =  STATUS_SUCCESS;
2970     } else {
2971         status = STATUS_NOT_SUPPORTED;
2972     }
2973 
2974     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: %s support SMART for device %p\n",
2975                   NT_SUCCESS(status) ? "does" : "does not",
2976                   FdoExtension->DeviceObject));
2977 
2978     FREE_POOL(modeData);
2979 
2980     return(status);
2981 }
2982 
2983 
2984 NTSTATUS
DiskSetInfoExceptionInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PMODE_INFO_EXCEPTIONS PageData)2985 DiskSetInfoExceptionInformation(
2986     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
2987     IN PMODE_INFO_EXCEPTIONS PageData
2988     )
2989 
2990 {
2991     ULONG i;
2992     NTSTATUS status = STATUS_SUCCESS;
2993 
2994     PAGED_CODE();
2995 
2996     //
2997     // We will attempt (twice) to issue the mode select with the page.
2998     // Make the setting persistant so that we don't have to turn it back
2999     // on after a bus reset.
3000     //
3001 
3002     for (i = 0; i < 2; i++)
3003     {
3004         status = DiskModeSelect(FdoExtension->DeviceObject,
3005                                 (PCHAR) PageData,
3006                                 sizeof(MODE_INFO_EXCEPTIONS),
3007                                 TRUE);
3008     }
3009 
3010     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskSetInfoExceptionInformation: %s for device %p\n",
3011                         NT_SUCCESS(status) ? "succeeded" : "failed",
3012                         FdoExtension->DeviceObject));
3013 
3014     return status;
3015 }
3016 
3017 NTSTATUS
3018 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskGetCacheInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PDISK_CACHE_INFORMATION CacheInfo)3019 DiskGetCacheInformation(
3020     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
3021     IN PDISK_CACHE_INFORMATION CacheInfo
3022     )
3023 /*++
3024 
3025 Routine Description:
3026 
3027     This function gets the caching mode page from the drive. This function
3028     is called from DiskIoctlGetCacheInformation() in response to the IOCTL
3029     IOCTL_DISK_GET_CACHE_INFORMATION. This is also called from the
3030     DisableWriteCache() worker thread to disable caching when write commands fail.
3031 
3032 Arguments:
3033 
3034     FdoExtension - The device extension for this device.
3035 
3036     CacheInfo - Buffer to receive the Cache Information.
3037 
3038 Return Value:
3039 
3040     NTSTATUS code
3041 
3042 --*/
3043 
3044 {
3045     PMODE_PARAMETER_HEADER modeData;
3046     PMODE_CACHING_PAGE pageData;
3047 
3048     ULONG length;
3049 
3050     PAGED_CODE();
3051 
3052 
3053 
3054     modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3055                                      MODE_DATA_SIZE,
3056                                      DISK_TAG_DISABLE_CACHE);
3057 
3058     if (modeData == NULL) {
3059 
3060         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetSetCacheInformation: Unable to allocate mode "
3061                        "data buffer\n"));
3062         return STATUS_INSUFFICIENT_RESOURCES;
3063     }
3064 
3065     RtlZeroMemory(modeData, MODE_DATA_SIZE);
3066 
3067     length = ClassModeSense(FdoExtension->DeviceObject,
3068                             (PCHAR) modeData,
3069                             MODE_DATA_SIZE,
3070                             MODE_PAGE_CACHING);
3071 
3072     if (length < sizeof(MODE_PARAMETER_HEADER)) {
3073 
3074         //
3075         // Retry the request in case of a check condition.
3076         //
3077 
3078         length = ClassModeSense(FdoExtension->DeviceObject,
3079                                 (PCHAR) modeData,
3080                                 MODE_DATA_SIZE,
3081                                 MODE_PAGE_CACHING);
3082 
3083         if (length < sizeof(MODE_PARAMETER_HEADER)) {
3084 
3085             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Mode Sense failed\n"));
3086 
3087             FREE_POOL(modeData);
3088             return STATUS_IO_DEVICE_ERROR;
3089         }
3090     }
3091 
3092     //
3093     // If the length is greater than length indicated by the mode data reset
3094     // the data to the mode data.
3095     //
3096 
3097     if (length > (ULONG) (modeData->ModeDataLength + 1)) {
3098         length = modeData->ModeDataLength + 1;
3099     }
3100 
3101     //
3102     // Check to see if the write cache is enabled.
3103     //
3104 
3105     pageData = ClassFindModePage((PCHAR) modeData,
3106                                  length,
3107                                  MODE_PAGE_CACHING,
3108                                  TRUE);
3109 
3110     //
3111     // Check if valid caching page exists.
3112     //
3113 
3114     if (pageData == NULL) {
3115         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Unable to find caching mode page.\n"));
3116         FREE_POOL(modeData);
3117         return STATUS_NOT_SUPPORTED;
3118     }
3119 
3120     //
3121     // Copy the parameters over.
3122     //
3123 
3124     RtlZeroMemory(CacheInfo, sizeof(DISK_CACHE_INFORMATION));
3125 
3126     CacheInfo->ParametersSavable = pageData->PageSavable;
3127 
3128     CacheInfo->ReadCacheEnabled = !(pageData->ReadDisableCache);
3129     CacheInfo->WriteCacheEnabled = pageData->WriteCacheEnable;
3130 
3131 
3132     //
3133     // Translate the values in the mode page into the ones defined in
3134     // ntdddisk.h.
3135     //
3136 
3137     CacheInfo->ReadRetentionPriority =
3138         TRANSLATE_RETENTION_PRIORITY(pageData->ReadRetensionPriority);
3139     CacheInfo->WriteRetentionPriority =
3140         TRANSLATE_RETENTION_PRIORITY(pageData->WriteRetensionPriority);
3141 
3142     CacheInfo->DisablePrefetchTransferLength =
3143         ((pageData->DisablePrefetchTransfer[0] << 8) +
3144          pageData->DisablePrefetchTransfer[1]);
3145 
3146     CacheInfo->ScalarPrefetch.Minimum =
3147         ((pageData->MinimumPrefetch[0] << 8) + pageData->MinimumPrefetch[1]);
3148 
3149     CacheInfo->ScalarPrefetch.Maximum =
3150         ((pageData->MaximumPrefetch[0] << 8) + pageData->MaximumPrefetch[1]);
3151 
3152     if(pageData->MultiplicationFactor) {
3153         CacheInfo->PrefetchScalar = TRUE;
3154         CacheInfo->ScalarPrefetch.MaximumBlocks =
3155             ((pageData->MaximumPrefetchCeiling[0] << 8) +
3156              pageData->MaximumPrefetchCeiling[1]);
3157     }
3158 
3159 
3160     FREE_POOL(modeData);
3161     return STATUS_SUCCESS;
3162 }
3163 
3164 
3165 NTSTATUS
3166 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskSetCacheInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PDISK_CACHE_INFORMATION CacheInfo)3167 DiskSetCacheInformation(
3168     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
3169     IN PDISK_CACHE_INFORMATION CacheInfo
3170     )
3171 /*++
3172 
3173 Routine Description:
3174 
3175     This function sets the caching mode page in the drive. This function
3176     is also called from the DisableWriteCache() worker thread to disable
3177     caching when write commands fail.
3178 
3179 Arguments:
3180 
3181     FdoExtension - The device extension for this device.
3182 
3183     CacheInfo - Buffer the contains the Cache Information to be set on the drive.
3184 
3185 Return Value:
3186 
3187     NTSTATUS code
3188 
3189 --*/
3190 {
3191     PMODE_PARAMETER_HEADER modeData;
3192     ULONG length;
3193     PMODE_CACHING_PAGE pageData;
3194     ULONG i;
3195     NTSTATUS status = STATUS_SUCCESS;
3196 
3197     PAGED_CODE();
3198 
3199     modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3200                                      MODE_DATA_SIZE,
3201                                      DISK_TAG_DISABLE_CACHE);
3202 
3203     if (modeData == NULL) {
3204 
3205         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Unable to allocate mode "
3206                        "data buffer\n"));
3207         return STATUS_INSUFFICIENT_RESOURCES;
3208     }
3209 
3210     RtlZeroMemory(modeData, MODE_DATA_SIZE);
3211 
3212     length = ClassModeSense(FdoExtension->DeviceObject,
3213                             (PCHAR) modeData,
3214                             MODE_DATA_SIZE,
3215                             MODE_PAGE_CACHING);
3216 
3217     if (length < sizeof(MODE_PARAMETER_HEADER)) {
3218 
3219         //
3220         // Retry the request in case of a check condition.
3221         //
3222 
3223         length = ClassModeSense(FdoExtension->DeviceObject,
3224                                 (PCHAR) modeData,
3225                                 MODE_DATA_SIZE,
3226                                 MODE_PAGE_CACHING);
3227 
3228         if (length < sizeof(MODE_PARAMETER_HEADER)) {
3229 
3230             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Mode Sense failed\n"));
3231 
3232             FREE_POOL(modeData);
3233             return STATUS_IO_DEVICE_ERROR;
3234         }
3235     }
3236 
3237     //
3238     // If the length is greater than length indicated by the mode data reset
3239     // the data to the mode data.
3240     //
3241 
3242     if (length > (ULONG) (modeData->ModeDataLength + 1)) {
3243         length = modeData->ModeDataLength + 1;
3244     }
3245 
3246     //
3247     // Check to see if the write cache is enabled.
3248     //
3249 
3250     pageData = ClassFindModePage((PCHAR) modeData,
3251                                  length,
3252                                  MODE_PAGE_CACHING,
3253                                  TRUE);
3254 
3255     //
3256     // Check if valid caching page exists.
3257     //
3258 
3259     if (pageData == NULL) {
3260         FREE_POOL(modeData);
3261         return STATUS_NOT_SUPPORTED;
3262     }
3263 
3264     //
3265     // Don't touch any of the normal parameters - not all drives actually
3266     // use the correct size of caching mode page.  Just change the things
3267     // which the user could have modified.
3268     //
3269 
3270     pageData->PageSavable = FALSE;
3271 
3272     pageData->ReadDisableCache = !(CacheInfo->ReadCacheEnabled);
3273     pageData->MultiplicationFactor = CacheInfo->PrefetchScalar;
3274     pageData->WriteCacheEnable = CacheInfo->WriteCacheEnabled;
3275 
3276     pageData->WriteRetensionPriority = (UCHAR)
3277         TRANSLATE_RETENTION_PRIORITY(CacheInfo->WriteRetentionPriority);
3278     pageData->ReadRetensionPriority = (UCHAR)
3279         TRANSLATE_RETENTION_PRIORITY(CacheInfo->ReadRetentionPriority);
3280 
3281     pageData->DisablePrefetchTransfer[0] =
3282         (UCHAR) (CacheInfo->DisablePrefetchTransferLength >> 8);
3283     pageData->DisablePrefetchTransfer[1] =
3284         (UCHAR) (CacheInfo->DisablePrefetchTransferLength & 0x00ff);
3285 
3286     pageData->MinimumPrefetch[0] =
3287         (UCHAR) (CacheInfo->ScalarPrefetch.Minimum >> 8);
3288     pageData->MinimumPrefetch[1] =
3289         (UCHAR) (CacheInfo->ScalarPrefetch.Minimum & 0x00ff);
3290 
3291     pageData->MaximumPrefetch[0] =
3292         (UCHAR) (CacheInfo->ScalarPrefetch.Maximum >> 8);
3293     pageData->MaximumPrefetch[1] =
3294         (UCHAR) (CacheInfo->ScalarPrefetch.Maximum & 0x00ff);
3295 
3296     if(pageData->MultiplicationFactor) {
3297 
3298         pageData->MaximumPrefetchCeiling[0] =
3299             (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks >> 8);
3300         pageData->MaximumPrefetchCeiling[1] =
3301             (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks & 0x00ff);
3302     }
3303 
3304     //
3305     // We will attempt (twice) to issue the mode select with the page.
3306     //
3307 
3308     for (i = 0; i < 2; i++) {
3309 
3310         status = DiskModeSelect(FdoExtension->DeviceObject,
3311                                 (PCHAR) pageData,
3312                                 (pageData->PageLength + 2),
3313                                 CacheInfo->ParametersSavable);
3314 
3315         if (NT_SUCCESS(status)) {
3316 
3317             if (CacheInfo->WriteCacheEnabled)
3318             {
3319                 SET_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3320             }
3321             else
3322             {
3323                 CLEAR_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3324             }
3325             ADJUST_FUA_FLAG(FdoExtension);
3326 
3327             break;
3328         }
3329     }
3330 
3331     if (NT_SUCCESS(status))
3332     {
3333     } else {
3334 
3335         //
3336         // We were unable to modify the disk write cache setting
3337         //
3338 
3339         SET_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL);
3340     }
3341 
3342     FREE_POOL(modeData);
3343     return status;
3344 }
3345 
3346 NTSTATUS
DiskIoctlGetCacheSetting(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)3347 DiskIoctlGetCacheSetting(
3348     IN PDEVICE_OBJECT DeviceObject,
3349     IN PIRP Irp
3350     )
3351 
3352 /*++
3353 
3354 Routine description:
3355 
3356     This routine services IOCTL_DISK_GET_CACHE_SETTING. It looks to
3357     see if there are any issues with the disk cache and whether the
3358     user had previously indicated that the cache is power-protected
3359 
3360 Arguments:
3361 
3362     Fdo - The functional device object processing the request
3363     Irp - The ioctl to be processed
3364 
3365 Return Value:
3366 
3367     STATUS_SUCCESS if successful, an error code otherwise
3368 
3369 --*/
3370 
3371 {
3372     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3373     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
3374     NTSTATUS status = STATUS_SUCCESS;
3375 
3376     PAGED_CODE();
3377 
3378     if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_SETTING))
3379     {
3380         status = STATUS_BUFFER_TOO_SMALL;
3381     }
3382     else
3383     {
3384         PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer;
3385 
3386         cacheSetting->Version = sizeof(DISK_CACHE_SETTING);
3387         cacheSetting->State   = DiskCacheNormal;
3388 
3389         //
3390         // Determine whether it is safe to turn on the cache
3391         //
3392         if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED))
3393         {
3394             cacheSetting->State = DiskCacheWriteThroughNotSupported;
3395         }
3396 
3397         //
3398         // Determine whether it is possible to modify the cache setting
3399         //
3400         if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL))
3401         {
3402             cacheSetting->State = DiskCacheModifyUnsuccessful;
3403         }
3404 
3405         cacheSetting->IsPowerProtected = TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3406 
3407         Irp->IoStatus.Information = sizeof(DISK_CACHE_SETTING);
3408     }
3409 
3410     return status;
3411 }
3412 
3413 
3414 NTSTATUS
DiskIoctlSetCacheSetting(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)3415 DiskIoctlSetCacheSetting(
3416     IN PDEVICE_OBJECT DeviceObject,
3417     IN PIRP Irp
3418     )
3419 
3420 /*++
3421 
3422 Routine description:
3423 
3424     This routine services IOCTL_DISK_SET_CACHE_SETTING. It allows
3425     the user to specify whether the disk cache is power-protected
3426     or not
3427 
3428     This function must be called at IRQL < DISPATCH_LEVEL.
3429 
3430 Arguments:
3431 
3432     Fdo - The functional device object processing the request
3433     Irp - The ioctl to be processed
3434 
3435 Return Value:
3436 
3437     STATUS_SUCCESS if successful, an error code otherwise
3438 
3439 --*/
3440 
3441 {
3442     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3443     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
3444     NTSTATUS status = STATUS_SUCCESS;
3445 
3446     //
3447     // This function must be called at less than dispatch level.
3448     // Fail if IRQL >= DISPATCH_LEVEL.
3449     //
3450     PAGED_CODE();
3451     CHECK_IRQL();
3452 
3453     if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_SETTING))
3454     {
3455         status = STATUS_INFO_LENGTH_MISMATCH;
3456     }
3457     else
3458     {
3459         PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer;
3460 
3461         if (cacheSetting->Version == sizeof(DISK_CACHE_SETTING))
3462         {
3463             ULONG isPowerProtected;
3464 
3465             //
3466             // Save away the user-defined override in our extension and the registry
3467             //
3468             if (cacheSetting->IsPowerProtected)
3469             {
3470                 SET_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3471                 isPowerProtected = 1;
3472             }
3473             else
3474             {
3475                 CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3476                 isPowerProtected = 0;
3477             }
3478             ADJUST_FUA_FLAG(fdoExtension);
3479 
3480             ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, DiskDeviceCacheIsPowerProtected, isPowerProtected);
3481         }
3482         else
3483         {
3484             status = STATUS_INVALID_PARAMETER;
3485         }
3486     }
3487 
3488     return status;
3489 }
3490 
3491 NTSTATUS
DiskIoctlGetLengthInfo(IN OUT PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3492 DiskIoctlGetLengthInfo(
3493     IN OUT PDEVICE_OBJECT DeviceObject,
3494     IN OUT PIRP Irp
3495     )
3496 
3497 /*++
3498 
3499 Routine Description:
3500 
3501     This routine services IOCTL_DISK_GET_LENGTH_INFO. It returns
3502     the disk geometry to the caller.
3503 
3504     This function must be called at IRQL < DISPATCH_LEVEL.
3505 
3506 Arguments:
3507 
3508     DeviceObject - Supplies the device object associated with this request.
3509 
3510     Irp - The IRP to be processed
3511 
3512 Return Value:
3513 
3514     NTSTATUS code
3515 
3516 --*/
3517 
3518 {
3519     NTSTATUS status;
3520     PIO_STACK_LOCATION irpStack;
3521     PGET_LENGTH_INFORMATION lengthInfo;
3522     PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
3523     PCOMMON_DEVICE_EXTENSION commonExtension;
3524     PDISK_DATA partitionZeroData;
3525     NTSTATUS oldReadyStatus;
3526 
3527     //
3528     // This function must be called at less than dispatch level.
3529     // Fail if IRQL >= DISPATCH_LEVEL.
3530     //
3531     PAGED_CODE();
3532     CHECK_IRQL();
3533 
3534     //
3535     // Initialization
3536     //
3537 
3538     commonExtension = DeviceObject->DeviceExtension;
3539     irpStack = IoGetCurrentIrpStackLocation(Irp);
3540     p0Extension = commonExtension->PartitionZeroExtension;
3541     partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
3542 
3543     //
3544     // Check that the buffer is large enough.
3545     //
3546 
3547     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_LENGTH_INFORMATION)) {
3548         return STATUS_BUFFER_TOO_SMALL;
3549     }
3550 
3551     //
3552     // Update the geometry in case it has changed
3553     //
3554 
3555     status = DiskReadDriveCapacity(p0Extension->DeviceObject);
3556 
3557     //
3558     // Note whether the drive is ready.  If the status has changed then
3559     // notify pnp.
3560     //
3561 
3562     oldReadyStatus = InterlockedExchange(&(partitionZeroData->ReadyStatus), status);
3563 
3564     if(partitionZeroData->ReadyStatus != oldReadyStatus) {
3565         IoInvalidateDeviceRelations(p0Extension->LowerPdo, BusRelations);
3566     }
3567 
3568     if(!NT_SUCCESS(status)) {
3569         return status;
3570     }
3571     lengthInfo = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
3572 
3573     lengthInfo->Length = commonExtension->PartitionLength;
3574 
3575     status = STATUS_SUCCESS;
3576     Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
3577 
3578     return status;
3579 }
3580 
3581 NTSTATUS
DiskIoctlGetDriveGeometry(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3582 DiskIoctlGetDriveGeometry(
3583     IN PDEVICE_OBJECT DeviceObject,
3584     IN OUT PIRP Irp
3585     )
3586 
3587 /*++
3588 
3589 Routine Description:
3590 
3591     This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY. It returns
3592     the disk geometry to the caller.
3593 
3594     This function must be called at IRQL < DISPATCH_LEVEL.
3595 
3596 Arguments:
3597 
3598     DeviceObject - Supplies the device object associated with this request.
3599 
3600     Irp - IRP with a return buffer large enough to receive the
3601             extended geometry information.
3602 
3603 Return Value:
3604 
3605     NTSTATUS code
3606 
3607 --*/
3608 
3609 {
3610     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3611     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3612     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
3613     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
3614     NTSTATUS status;
3615 
3616     //
3617     // This function must be called at less than dispatch level.
3618     // Fail if IRQL >= DISPATCH_LEVEL.
3619     //
3620     PAGED_CODE();
3621     CHECK_IRQL();
3622 
3623     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
3624 
3625         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometry: Output buffer too small.\n"));
3626         return STATUS_BUFFER_TOO_SMALL;
3627     }
3628 
3629     if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
3630 
3631         //
3632         // Issue ReadCapacity to update device extension
3633         // with information for current media.
3634         //
3635 
3636         status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
3637 
3638         //
3639         // Note whether the drive is ready.
3640         //
3641 
3642         diskData->ReadyStatus = status;
3643 
3644         if (!NT_SUCCESS(status)) {
3645             return status;
3646         }
3647     }
3648 
3649     //
3650     // Copy drive geometry information from device extension.
3651     //
3652 
3653     RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
3654                   &(fdoExtension->DiskGeometry),
3655                   sizeof(DISK_GEOMETRY));
3656 
3657     if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) {
3658         ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512;
3659     }
3660     Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3661     return STATUS_SUCCESS;
3662 }
3663 
3664 typedef struct _DISK_GEOMETRY_EX_INTERNAL {
3665     DISK_GEOMETRY Geometry;
3666     LARGE_INTEGER DiskSize;
3667     DISK_PARTITION_INFO Partition;
3668     DISK_DETECTION_INFO Detection;
3669 } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL;
3670 
3671 NTSTATUS
DiskIoctlGetDriveGeometryEx(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3672 DiskIoctlGetDriveGeometryEx(
3673     IN PDEVICE_OBJECT DeviceObject,
3674     IN OUT PIRP Irp
3675     )
3676 
3677 /*++
3678 
3679 Routine Description:
3680 
3681     This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY_EX. It returns
3682     the extended disk geometry to the caller.
3683 
3684     This function must be called at IRQL < DISPATCH_LEVEL.
3685 
3686 Arguments:
3687 
3688     DeviceObject - The device object to obtain the geometry for.
3689 
3690     Irp - IRP with a return buffer large enough to receive the
3691             extended geometry information.
3692 
3693 Return Value:
3694 
3695     NTSTATUS code
3696 
3697 --*/
3698 
3699 {
3700     NTSTATUS status;
3701     PIO_STACK_LOCATION irpStack;
3702     PCOMMON_DEVICE_EXTENSION commonExtension;
3703     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
3704     PDISK_DATA diskData;
3705     PDISK_GEOMETRY_EX_INTERNAL geometryEx;
3706     ULONG OutputBufferLength;
3707 
3708     //
3709     // This function must be called at less than dispatch level.
3710     // Fail if IRQL >= DISPATCH_LEVEL.
3711     //
3712     PAGED_CODE();
3713     CHECK_IRQL();
3714 
3715     //
3716     // Setup parameters
3717     //
3718 
3719     commonExtension = DeviceObject->DeviceExtension;
3720     fdoExtension = DeviceObject->DeviceExtension;
3721     diskData = (PDISK_DATA)(commonExtension->DriverData);
3722     irpStack = IoGetCurrentIrpStackLocation ( Irp );
3723     geometryEx = NULL;
3724     OutputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
3725 
3726     //
3727     // Check that the buffer is large enough. It must be large enough
3728     // to hold at lest the Geometry and DiskSize fields of of the
3729     // DISK_GEOMETRY_EX structure.
3730     //
3731 
3732     if ( (LONG)OutputBufferLength < FIELD_OFFSET (DISK_GEOMETRY_EX, Data) ) {
3733 
3734         //
3735         // Buffer too small. Bail out, telling the caller the required
3736         // size.
3737         //
3738 
3739         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometryEx: Output buffer too small.\n"));
3740         status = STATUS_BUFFER_TOO_SMALL;
3741         return status;
3742     }
3743 
3744     if (TEST_FLAG (DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
3745 
3746         //
3747         // Issue a ReadCapacity to update device extension
3748         // with information for the current media.
3749         //
3750 
3751         status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
3752 
3753         diskData->ReadyStatus = status;
3754 
3755         if (!NT_SUCCESS (status)) {
3756             return status;
3757         }
3758     }
3759 
3760     //
3761     // Copy drive geometry.
3762     //
3763 
3764     geometryEx = (PDISK_GEOMETRY_EX_INTERNAL)Irp->AssociatedIrp.SystemBuffer;
3765     geometryEx->Geometry = fdoExtension->DiskGeometry;
3766     if (geometryEx->Geometry.BytesPerSector == 0) {
3767         geometryEx->Geometry.BytesPerSector = 512;
3768     }
3769     geometryEx->DiskSize = commonExtension->PartitionZeroExtension->CommonExtension.PartitionLength;
3770 
3771     //
3772     // If the user buffer is large enough to hold the partition information
3773     // then add that as well.
3774     //
3775 
3776     if ((LONG)OutputBufferLength >=  FIELD_OFFSET (DISK_GEOMETRY_EX_INTERNAL, Detection)) {
3777 
3778         geometryEx->Partition.SizeOfPartitionInfo = sizeof (geometryEx->Partition);
3779         geometryEx->Partition.PartitionStyle = diskData->PartitionStyle;
3780 
3781         switch ( diskData->PartitionStyle ) {
3782 
3783             case PARTITION_STYLE_GPT:
3784 
3785                 //
3786                 // Copy GPT signature.
3787                 //
3788 
3789                 geometryEx->Partition.Gpt.DiskId = diskData->Efi.DiskId;
3790                 break;
3791 
3792             case PARTITION_STYLE_MBR:
3793 
3794                 //
3795                 // Copy MBR signature and checksum.
3796                 //
3797 
3798                 geometryEx->Partition.Mbr.Signature = diskData->Mbr.Signature;
3799                 geometryEx->Partition.Mbr.CheckSum = diskData->Mbr.MbrCheckSum;
3800                 break;
3801 
3802             default:
3803 
3804                 //
3805                 // This is a raw disk. Zero out the signature area so
3806                 // nobody gets confused.
3807                 //
3808 
3809                 RtlZeroMemory(&geometryEx->Partition, sizeof (geometryEx->Partition));
3810         }
3811     }
3812 
3813     //
3814     // If the buffer is large enough to hold the detection information,
3815     // then also add that.
3816     //
3817 
3818     if (OutputBufferLength >= sizeof (DISK_GEOMETRY_EX_INTERNAL)) {
3819 
3820         geometryEx->Detection.SizeOfDetectInfo = sizeof (geometryEx->Detection);
3821 
3822         status = DiskGetDetectInfo(fdoExtension, &geometryEx->Detection);
3823 
3824         //
3825         // Failed to obtain detection information, set to none.
3826         //
3827 
3828         if (!NT_SUCCESS (status)) {
3829             geometryEx->Detection.DetectionType = DetectNone;
3830         }
3831     }
3832 
3833     status = STATUS_SUCCESS;
3834     Irp->IoStatus.Information = min (OutputBufferLength, sizeof (DISK_GEOMETRY_EX_INTERNAL));
3835 
3836     return status;
3837 }
3838 
3839 NTSTATUS
DiskIoctlGetCacheInformation(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3840 DiskIoctlGetCacheInformation(
3841     IN PDEVICE_OBJECT DeviceObject,
3842     IN OUT PIRP Irp
3843     )
3844 
3845 /*++
3846 
3847 Routine Description:
3848 
3849     This routine services IOCTL_DISK_GET_CACHE_INFORMATION. It reads
3850     the caching mode page from the device and returns information to
3851     the caller. After validating the user parameter it calls the
3852     DiskGetCacheInformation() function to get the mode page.
3853 
3854     This function must be called at IRQL < DISPATCH_LEVEL.
3855 
3856 Arguments:
3857 
3858     DeviceObject - Supplies the device object associated with this request.
3859 
3860     Irp - The IRP to be processed
3861 
3862 Return Value:
3863 
3864     NTSTATUS code
3865 
3866 --*/
3867 
3868 {
3869     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3870     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
3871     PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
3872     NTSTATUS status;
3873 
3874     //
3875     // This function must be called at less than dispatch level.
3876     // Fail if IRQL >= DISPATCH_LEVEL.
3877     //
3878     PAGED_CODE();
3879     CHECK_IRQL();
3880 
3881     //
3882     // Validate the request.
3883     //
3884 
3885     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp));
3886 
3887     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_INFORMATION)) {
3888 
3889         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: Output buffer too small.\n"));
3890         return STATUS_BUFFER_TOO_SMALL;
3891     }
3892 
3893     status = DiskGetCacheInformation(fdoExtension, cacheInfo);
3894 
3895     if (NT_SUCCESS(status)) {
3896         Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION);
3897 
3898         //
3899         // Make sure write cache setting is reflected in device extension
3900         //
3901         if (cacheInfo->WriteCacheEnabled)
3902         {
3903             SET_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3904         }
3905         else
3906         {
3907             CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3908         }
3909         ADJUST_FUA_FLAG(fdoExtension);
3910 
3911     }
3912     return status;
3913 }
3914 
3915 
3916 NTSTATUS
DiskIoctlSetCacheInformation(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3917 DiskIoctlSetCacheInformation(
3918     IN PDEVICE_OBJECT DeviceObject,
3919     IN OUT PIRP Irp
3920     )
3921 
3922 /*++
3923 
3924 Routine Description:
3925 
3926     This routine services IOCTL_DISK_SET_CACHE_INFORMATION. It allows
3927     the caller to set the caching mode page on the device. This function
3928     validates the user parameter and calls the DiskSetCacheInformation()
3929     function to set the mode page. It also stores the cache value in the
3930     device extension and registry.
3931 
3932     This function must be called at IRQL < DISPATCH_LEVEL.
3933 
3934 Arguments:
3935 
3936     DeviceObject - Supplies the device object associated with this request.
3937 
3938     Irp - The IRP to be processed
3939 
3940 Return Value:
3941 
3942     NTSTATUS code
3943 
3944 --*/
3945 
3946 {
3947     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3948     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3949     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
3950     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
3951     PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
3952     NTSTATUS status;
3953 
3954     //
3955     // This function must be called at less than dispatch level.
3956     // Fail if IRQL is equal or above DISPATCH_LEVEL.
3957     //
3958 
3959     PAGED_CODE();
3960     CHECK_IRQL();
3961 
3962     //
3963     // Validate the request.
3964     //
3965 
3966     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp));
3967 
3968     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_INFORMATION)) {
3969 
3970         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: Input buffer length mismatch.\n"));
3971         return STATUS_INFO_LENGTH_MISMATCH;
3972     }
3973 
3974     status = DiskSetCacheInformation(fdoExtension, cacheInfo);
3975 
3976     //
3977     // Save away the user-defined override in our extension and the registry
3978     //
3979     if (cacheInfo->WriteCacheEnabled) {
3980         diskData->WriteCacheOverride = DiskWriteCacheEnable;
3981     } else {
3982         diskData->WriteCacheOverride = DiskWriteCacheDisable;
3983     }
3984 
3985     ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey,
3986                             DiskDeviceUserWriteCacheSetting, diskData->WriteCacheOverride);
3987 
3988     DiskLogCacheInformation(fdoExtension, cacheInfo, status);
3989 
3990     return status;
3991 }
3992 
3993 NTSTATUS
DiskIoctlGetMediaTypesEx(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3994 DiskIoctlGetMediaTypesEx(
3995     IN PDEVICE_OBJECT DeviceObject,
3996     IN OUT PIRP Irp
3997     )
3998 
3999 /*++
4000 
4001 Routine Description:
4002 
4003     This routine services IOCTL_STORAGE_GET_MEDIA_TYPES_EX. It returns
4004     the media type information to the caller. After validating the user
4005     parameter it calls DiskDetermineMediaTypes() to get the media type.
4006 
4007     This function must be called at IRQL < DISPATCH_LEVEL.
4008 
4009 Arguments:
4010 
4011     DeviceObject - Supplies the device object associated with this request.
4012 
4013     Irp - The IRP to be processed
4014 
4015 Return Value:
4016 
4017     NTSTATUS code
4018 
4019 --*/
4020 
4021 {
4022     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4023     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4024     NTSTATUS status;
4025 
4026     PMODE_PARAMETER_HEADER modeData;
4027     PMODE_PARAMETER_BLOCK blockDescriptor;
4028     PSCSI_REQUEST_BLOCK srb;
4029     PCDB cdb;
4030     ULONG modeLength;
4031     ULONG retries = 4;
4032     UCHAR densityCode = 0;
4033     BOOLEAN writable = TRUE;
4034     BOOLEAN mediaPresent = FALSE;
4035     ULONG srbSize;
4036     PSTORAGE_REQUEST_BLOCK srbEx = NULL;
4037     PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
4038     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
4039 
4040     //
4041     // This function must be called at less than dispatch level.
4042     // Fail if IRQL >= DISPATCH_LEVEL.
4043     //
4044     PAGED_CODE();
4045     CHECK_IRQL();
4046 
4047     //
4048     // Validate the request.
4049     //
4050 
4051     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4052 
4053     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_MEDIA_TYPES)) {
4054 
4055         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Output buffer too small.\n"));
4056         return STATUS_BUFFER_TOO_SMALL;
4057     }
4058 
4059     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4060         srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
4061     } else {
4062         srbSize = SCSI_REQUEST_BLOCK_SIZE;
4063     }
4064 
4065     srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4066                                 srbSize,
4067                                 DISK_TAG_SRB);
4068 
4069     if (srb == NULL) {
4070         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n"));
4071         return STATUS_INSUFFICIENT_RESOURCES;
4072     }
4073 
4074     RtlZeroMemory(srb, srbSize);
4075 
4076     //
4077     // Send a TUR to determine if media is present.
4078     //
4079 
4080     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4081         srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4082 
4083         //
4084         // Set up STORAGE_REQUEST_BLOCK fields
4085         //
4086 
4087         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
4088         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4089         srbEx->Signature = SRB_SIGNATURE;
4090         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4091         srbEx->SrbLength = srbSize;
4092         srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4093         srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4094         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
4095         srbEx->NumSrbExData = 1;
4096 
4097         // Set timeout value.
4098         srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4099 
4100         //
4101         // Set up address fields
4102         //
4103 
4104         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
4105         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
4106         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
4107 
4108         //
4109         // Set up SCSI SRB extended data fields
4110         //
4111 
4112         srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
4113             sizeof(STOR_ADDR_BTL8);
4114         if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
4115             srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
4116             srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
4117             srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
4118             srbExDataCdb16->CdbLength = 6;
4119 
4120             cdb = (PCDB)srbExDataCdb16->Cdb;
4121         } else {
4122             // Should not happen
4123             NT_ASSERT(FALSE);
4124 
4125             FREE_POOL(srb);
4126             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Insufficient extended SRB size.\n"));
4127             return STATUS_INTERNAL_ERROR;
4128         }
4129 
4130     } else {
4131 
4132         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4133         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4134         srb->CdbLength = 6;
4135         cdb = (PCDB)srb->Cdb;
4136 
4137         //
4138         // Set timeout value.
4139         //
4140 
4141         srb->TimeOutValue = fdoExtension->TimeOutValue;
4142 
4143     }
4144     cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
4145 
4146     status = ClassSendSrbSynchronous(DeviceObject,
4147                                      srb,
4148                                      NULL,
4149                                      0,
4150                                      FALSE);
4151 
4152     if (NT_SUCCESS(status)) {
4153         mediaPresent = TRUE;
4154     }
4155 
4156     modeLength = MODE_DATA_SIZE;
4157     modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
4158                                      modeLength,
4159                                      DISK_TAG_MODE_DATA);
4160 
4161     if (modeData == NULL) {
4162         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n"));
4163         FREE_POOL(srb);
4164         return STATUS_INSUFFICIENT_RESOURCES;
4165     }
4166 
4167     RtlZeroMemory(modeData, modeLength);
4168 
4169     //
4170     // Build the MODE SENSE CDB using previous SRB.
4171     //
4172 
4173     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4174         srbEx->SrbStatus = 0;
4175         srbExDataCdb16->ScsiStatus = 0;
4176         srbExDataCdb16->CdbLength = 6;
4177 
4178         //
4179         // Set timeout value from device extension.
4180         //
4181 
4182         srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4183     } else {
4184         srb->SrbStatus = 0;
4185         srb->ScsiStatus = 0;
4186         srb->CdbLength = 6;
4187 
4188         //
4189         // Set timeout value from device extension.
4190         //
4191 
4192         srb->TimeOutValue = fdoExtension->TimeOutValue;
4193     }
4194 
4195     //
4196     // Page code of 0x3F will return all pages.
4197     // This command could fail if the data to be returned is
4198     // more than 256 bytes. In which case, we should get only
4199     // the caching page since we only need the block descriptor.
4200     // DiskFdoProcessError will change the page code to
4201     // MODE_PAGE_CACHING if there is an error.
4202     //
4203 
4204     cdb->MODE_SENSE.OperationCode    = SCSIOP_MODE_SENSE;
4205     cdb->MODE_SENSE.PageCode         = MODE_SENSE_RETURN_ALL;
4206     cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
4207 
4208 Retry:
4209     status = ClassSendSrbSynchronous(DeviceObject,
4210                                      srb,
4211                                      modeData,
4212                                      modeLength,
4213                                      FALSE);
4214 
4215     if (status == STATUS_VERIFY_REQUIRED) {
4216 
4217         if (retries--) {
4218 
4219             //
4220             // Retry request.
4221             //
4222 
4223             goto Retry;
4224         }
4225     } else if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
4226         status = STATUS_SUCCESS;
4227     }
4228 
4229     if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
4230 
4231         //
4232         // Get the block descriptor.
4233         //
4234 
4235         if (modeData->BlockDescriptorLength != 0) {
4236 
4237             blockDescriptor = (PMODE_PARAMETER_BLOCK)((ULONG_PTR)modeData + sizeof(MODE_PARAMETER_HEADER));
4238             densityCode = blockDescriptor->DensityCode;
4239         }
4240 
4241         if (TEST_FLAG(modeData->DeviceSpecificParameter,
4242                       MODE_DSP_WRITE_PROTECT)) {
4243 
4244             writable = FALSE;
4245         }
4246 
4247         status = DiskDetermineMediaTypes(DeviceObject,
4248                                          Irp,
4249                                          modeData->MediumType,
4250                                          densityCode,
4251                                          mediaPresent,
4252                                          writable);
4253         //
4254         // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail.
4255         //
4256 
4257     } else {
4258         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Mode sense for header/bd failed. %lx\n", status));
4259     }
4260 
4261     FREE_POOL(srb);
4262     FREE_POOL(modeData);
4263 
4264     return status;
4265 }
4266 
4267 NTSTATUS
DiskIoctlPredictFailure(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4268 DiskIoctlPredictFailure(
4269     IN PDEVICE_OBJECT DeviceObject,
4270     IN OUT PIRP Irp
4271     )
4272 
4273 /*++
4274 
4275 Routine Description:
4276 
4277     This routine services IOCTL_STORAGE_PREDICT_FAILURE. If the device
4278     supports SMART then it returns any available failure data.
4279 
4280     This function must be called at IRQL < DISPATCH_LEVEL.
4281 
4282 Arguments:
4283 
4284     DeviceObject - Supplies the device object associated with this request.
4285 
4286     Irp - The IRP to be processed
4287 
4288 Return Value:
4289 
4290     NTSTATUS code
4291 
4292 --*/
4293 
4294 {
4295     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4296     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4297     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
4298     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4299     NTSTATUS status = STATUS_SUCCESS;
4300 
4301     PSTORAGE_PREDICT_FAILURE checkFailure;
4302     STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
4303     IO_STATUS_BLOCK ioStatus = { 0 };
4304     KEVENT event;
4305 
4306     //
4307     // This function must be called at less than dispatch level.
4308     // Fail if IRQL >= DISPATCH_LEVEL.
4309     //
4310     PAGED_CODE();
4311     CHECK_IRQL();
4312 
4313     //
4314     // Validate the request.
4315     //
4316 
4317     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4318 
4319     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_PREDICT_FAILURE)) {
4320 
4321         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: Output buffer too small.\n"));
4322         return STATUS_BUFFER_TOO_SMALL;
4323     }
4324 
4325     //
4326     // See if the disk is predicting failure
4327     //
4328 
4329     checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer;
4330 
4331     if (diskData->FailurePredictionCapability == FailurePredictionSense) {
4332         ULONG readBufferSize;
4333         PUCHAR readBuffer;
4334         PIRP readIrp;
4335         PDEVICE_OBJECT topOfStack;
4336 
4337         checkFailure->PredictFailure = 0;
4338 
4339         KeInitializeEvent(&event, SynchronizationEvent, FALSE);
4340 
4341         topOfStack = IoGetAttachedDeviceReference(DeviceObject);
4342 
4343         //
4344         // SCSI disks need to have a read sent down to provoke any
4345         // failures to be reported.
4346         //
4347         // Issue a normal read operation.  The error-handling code in
4348         // classpnp will take care of a failure prediction by logging the
4349         // correct event.
4350         //
4351 
4352         readBufferSize = fdoExtension->DiskGeometry.BytesPerSector;
4353         readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
4354                                            readBufferSize,
4355                                            DISK_TAG_SMART);
4356 
4357         if (readBuffer != NULL) {
4358             LARGE_INTEGER offset;
4359 
4360             offset.QuadPart = 0;
4361             readIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
4362                                                    topOfStack,
4363                                                    readBuffer,
4364                                                    readBufferSize,
4365                                                    &offset,
4366                                                    &event,
4367                                                    &ioStatus);
4368 
4369             if (readIrp != NULL) {
4370 
4371                 status = IoCallDriver(topOfStack, readIrp);
4372                 if (status == STATUS_PENDING) {
4373                     KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
4374                     status = ioStatus.Status;
4375                 }
4376 
4377 
4378             } else {
4379                 status = STATUS_INSUFFICIENT_RESOURCES;
4380             }
4381 
4382             FREE_POOL(readBuffer);
4383         } else {
4384             status = STATUS_INSUFFICIENT_RESOURCES;
4385         }
4386 
4387         ObDereferenceObject(topOfStack);
4388     }
4389 
4390     if (status != STATUS_INSUFFICIENT_RESOURCES)
4391     {
4392         if ((diskData->FailurePredictionCapability == FailurePredictionSmart) ||
4393             (diskData->FailurePredictionCapability == FailurePredictionSense)) {
4394 
4395             status = DiskReadFailurePredictStatus(fdoExtension, &diskSmartStatus);
4396 
4397             if (NT_SUCCESS(status)) {
4398 
4399                 status = DiskReadFailurePredictData(fdoExtension,
4400                                                     Irp->AssociatedIrp.SystemBuffer);
4401 
4402                 if (diskSmartStatus.PredictFailure) {
4403                     checkFailure->PredictFailure = 1;
4404                 } else {
4405                     checkFailure->PredictFailure = 0;
4406                 }
4407 
4408                 Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
4409             }
4410         } else {
4411             status = STATUS_INVALID_DEVICE_REQUEST;
4412         }
4413     }
4414     return status;
4415 }
4416 
4417 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
4418 NTSTATUS
DiskIoctlEnableFailurePrediction(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4419 DiskIoctlEnableFailurePrediction(
4420     IN PDEVICE_OBJECT DeviceObject,
4421     IN OUT PIRP Irp
4422     )
4423 
4424 /*++
4425 
4426 Routine Description:
4427 
4428     This routine services IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG. If the device
4429     supports SMART then it returns any available failure data.
4430 
4431     This function must be called at IRQL < DISPATCH_LEVEL.
4432 
4433 Arguments:
4434 
4435     DeviceObject - Supplies the device object associated with this request.
4436 
4437     Irp - The IRP to be processed
4438 
4439 Return Value:
4440 
4441     NTSTATUS code
4442 
4443 --*/
4444 
4445 {
4446     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4447     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4448     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
4449     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4450     NTSTATUS status = STATUS_SUCCESS;
4451     PSTORAGE_FAILURE_PREDICTION_CONFIG enablePrediction;
4452 
4453     //
4454     // This function must be called at less than dispatch level.
4455     // Fail if IRQL >= DISPATCH_LEVEL.
4456     //
4457     PAGED_CODE();
4458     CHECK_IRQL();
4459 
4460     //
4461     // Validate the request.
4462     //
4463 
4464     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4465 
4466     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG) ||
4467         irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) {
4468 
4469         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer too small.\n"));
4470         return STATUS_BUFFER_TOO_SMALL;
4471     }
4472 
4473     enablePrediction = (PSTORAGE_FAILURE_PREDICTION_CONFIG)Irp->AssociatedIrp.SystemBuffer;
4474 
4475     if (enablePrediction->Version != STORAGE_FAILURE_PREDICTION_CONFIG_V1 ||
4476         enablePrediction->Size < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) {
4477         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer version or size is incorrect.\n"));
4478         status = STATUS_INVALID_PARAMETER;
4479     }
4480 
4481     if (enablePrediction->Reserved != 0) {
4482         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Reserved bytes are not zero!\n"));
4483         status = STATUS_INVALID_PARAMETER;
4484     }
4485 
4486     //
4487     // Default to success.  This might get overwritten on failure below.
4488     //
4489     status = STATUS_SUCCESS;
4490 
4491     //
4492     // If this is a "set" and the current state (enabled/disabled) is
4493     // different from the sender's desired state,
4494     //
4495     if (enablePrediction->Set && enablePrediction->Enabled != diskData->FailurePredictionEnabled) {
4496         if (diskData->FailurePredictionCapability == FailurePredictionSmart ||
4497             diskData->FailurePredictionCapability == FailurePredictionIoctl) {
4498             //
4499             // SMART or IOCTL based failure prediction is being used so call
4500             // the generic function that is normally called in the WMI path.
4501             //
4502             status = DiskEnableDisableFailurePrediction(fdoExtension, enablePrediction->Enabled);
4503         } else if (diskData->ScsiInfoExceptionsSupported) {
4504             //
4505             // If we know that the device supports the Informational Exceptions
4506             // mode page, try to enable/disable failure prediction that way.
4507             //
4508             status = DiskEnableInfoExceptions(fdoExtension, enablePrediction->Enabled);
4509         }
4510     }
4511 
4512     //
4513     // Return the current state regardless if this was a "set" or a "get".
4514     //
4515     enablePrediction->Enabled = diskData->FailurePredictionEnabled;
4516 
4517     if (NT_SUCCESS(status)) {
4518         Irp->IoStatus.Information = sizeof(STORAGE_FAILURE_PREDICTION_CONFIG);
4519     }
4520 
4521     return status;
4522 }
4523 #endif //(NTDDI_VERSION >= NTDDI_WINBLUE)
4524 
4525 NTSTATUS
DiskIoctlVerify(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4526 DiskIoctlVerify(
4527     IN PDEVICE_OBJECT DeviceObject,
4528     IN OUT PIRP Irp
4529     )
4530 
4531 /*++
4532 
4533 Routine Description:
4534 
4535     This routine services IOCTL_DISK_VERIFY. After verifying
4536     user input, it starts the worker thread DiskIoctlVerifyThread()
4537     to verify the device.
4538 
4539 Arguments:
4540 
4541     DeviceObject - Supplies the device object associated with this request.
4542 
4543     Irp - The IRP to be processed
4544 
4545 Return Value:
4546 
4547     NTSTATUS code
4548 
4549 --*/
4550 
4551 {
4552     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4553     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4554     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4555     PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
4556     PDISK_VERIFY_WORKITEM_CONTEXT Context = NULL;
4557     PSCSI_REQUEST_BLOCK srb;
4558     LARGE_INTEGER byteOffset;
4559     ULONG srbSize;
4560 
4561     //
4562     // Validate the request.
4563     //
4564 
4565     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4566 
4567     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VERIFY_INFORMATION)) {
4568         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Input buffer length mismatch.\n"));
4569         return STATUS_INFO_LENGTH_MISMATCH;
4570     }
4571 
4572     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4573         srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
4574     } else {
4575         srbSize = SCSI_REQUEST_BLOCK_SIZE;
4576     }
4577     srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4578                                 srbSize,
4579                                 DISK_TAG_SRB);
4580 
4581     if (srb == NULL) {
4582         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Unable to allocate memory.\n"));
4583         return STATUS_INSUFFICIENT_RESOURCES;
4584     }
4585 
4586     RtlZeroMemory(srb, srbSize);
4587 
4588     //
4589     // Add disk offset to starting sector.
4590     //
4591 
4592     byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
4593                           verifyInfo->StartingOffset.QuadPart;
4594 
4595     //
4596     // Perform a bounds check on the sector range
4597     //
4598 
4599     if ((verifyInfo->StartingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
4600         (verifyInfo->StartingOffset.QuadPart < 0)) {
4601 
4602         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n"));
4603         FREE_POOL(srb)
4604         return STATUS_NONEXISTENT_SECTOR;
4605     } else {
4606 
4607         ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;
4608 
4609         if ((ULONGLONG)verifyInfo->Length > bytesRemaining) {
4610 
4611             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n"));
4612             FREE_POOL(srb)
4613             return STATUS_NONEXISTENT_SECTOR;
4614         }
4615     }
4616 
4617     Context = ExAllocatePoolWithTag(NonPagedPoolNx,
4618                                     sizeof(DISK_VERIFY_WORKITEM_CONTEXT),
4619                                     DISK_TAG_WI_CONTEXT);
4620     if (Context) {
4621 
4622         Context->Irp = Irp;
4623         Context->Srb = srb;
4624         Context->WorkItem = IoAllocateWorkItem(DeviceObject);
4625 
4626         if (Context->WorkItem) {
4627 
4628             //
4629             // Queue the work item and return.
4630             //
4631 
4632             IoMarkIrpPending(Irp);
4633 
4634             IoQueueWorkItem(Context->WorkItem,
4635                             DiskIoctlVerifyThread,
4636                             DelayedWorkQueue,
4637                             Context);
4638 
4639             return STATUS_PENDING;
4640         }
4641         FREE_POOL(Context);
4642     }
4643     FREE_POOL(srb)
4644     return STATUS_INSUFFICIENT_RESOURCES;
4645 }
4646 
4647 NTSTATUS
DiskIoctlReassignBlocks(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4648 DiskIoctlReassignBlocks(
4649     IN PDEVICE_OBJECT DeviceObject,
4650     IN OUT PIRP Irp
4651     )
4652 
4653 /*++
4654 
4655 Routine Description:
4656 
4657     This routine services IOCTL_DISK_REASSIGN_BLOCKS. This IOCTL
4658     allows the caller to remap the defective blocks to a new
4659     location on the disk.
4660 
4661     This function must be called at IRQL < DISPATCH_LEVEL.
4662 
4663 Arguments:
4664 
4665     DeviceObject - Supplies the device object associated with this request.
4666 
4667     Irp - The IRP to be processed
4668 
4669 Return Value:
4670 
4671     NTSTATUS code
4672 
4673 --*/
4674 
4675 {
4676     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4677     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4678     NTSTATUS status;
4679     PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
4680     PSCSI_REQUEST_BLOCK srb;
4681     PCDB cdb;
4682     ULONG bufferSize;
4683     ULONG blockNumber;
4684     ULONG blockCount;
4685     ULONG srbSize;
4686     PSTORAGE_REQUEST_BLOCK srbEx;
4687     PSTOR_ADDR_BTL8 storAddrBtl8;
4688     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
4689 
4690     //
4691     // This function must be called at less than dispatch level.
4692     // Fail if IRQL >= DISPATCH_LEVEL.
4693     //
4694     PAGED_CODE();
4695     CHECK_IRQL();
4696 
4697     //
4698     // Validate the request.
4699     //
4700 
4701     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4702 
4703     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS)) {
4704         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch.\n"));
4705         return STATUS_INFO_LENGTH_MISMATCH;
4706     }
4707 
4708     //
4709     // Make sure we have some data in the input buffer.
4710     //
4711 
4712     if (badBlocks->Count == 0) {
4713         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Invalid block count\n"));
4714         return STATUS_INVALID_PARAMETER;
4715     }
4716 
4717     bufferSize = sizeof(REASSIGN_BLOCKS) + ((badBlocks->Count - 1) * sizeof(ULONG));
4718 
4719     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) {
4720         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch for bad blocks.\n"));
4721         return STATUS_INFO_LENGTH_MISMATCH;
4722     }
4723 
4724     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4725         srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
4726     } else {
4727         srbSize = SCSI_REQUEST_BLOCK_SIZE;
4728     }
4729     srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4730                                 srbSize,
4731                                 DISK_TAG_SRB);
4732 
4733     if (srb == NULL) {
4734         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n"));
4735         return STATUS_INSUFFICIENT_RESOURCES;
4736     }
4737 
4738     RtlZeroMemory(srb, srbSize);
4739 
4740     //
4741     // Build the data buffer to be transferred in the input buffer.
4742     // The format of the data to the device is:
4743     //
4744     //      2 bytes Reserved
4745     //      2 bytes Length
4746     //      x * 4 btyes Block Address
4747     //
4748     // All values are big endian.
4749     //
4750 
4751     badBlocks->Reserved = 0;
4752     blockCount = badBlocks->Count;
4753 
4754     //
4755     // Convert # of entries to # of bytes.
4756     //
4757 
4758     blockCount *= 4;
4759     badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
4760     badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
4761 
4762     //
4763     // Convert back to number of entries.
4764     //
4765 
4766     blockCount /= 4;
4767 
4768     for (; blockCount > 0; blockCount--) {
4769 
4770         blockNumber = badBlocks->BlockNumber[blockCount-1];
4771         REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], (PFOUR_BYTE) &blockNumber);
4772     }
4773 
4774     //
4775     // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb
4776     //
4777 
4778     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4779         srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4780 
4781         //
4782         // Set up STORAGE_REQUEST_BLOCK fields
4783         //
4784 
4785         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
4786         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4787         srbEx->Signature = SRB_SIGNATURE;
4788         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4789         srbEx->SrbLength = srbSize;
4790         srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4791         srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4792         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
4793         srbEx->NumSrbExData = 1;
4794 
4795         // Set timeout value.
4796         srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4797 
4798         //
4799         // Set up address fields
4800         //
4801 
4802         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
4803         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
4804         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
4805 
4806         //
4807         // Set up SCSI SRB extended data fields
4808         //
4809 
4810         srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
4811             sizeof(STOR_ADDR_BTL8);
4812         if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
4813             srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
4814             srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
4815             srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
4816             srbExDataCdb16->CdbLength = 6;
4817 
4818             cdb = (PCDB)srbExDataCdb16->Cdb;
4819         } else {
4820             // Should not happen
4821             NT_ASSERT(FALSE);
4822 
4823             FREE_POOL(srb);
4824             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n"));
4825             return STATUS_INTERNAL_ERROR;
4826         }
4827 
4828     } else {
4829         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4830         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4831         srb->CdbLength = 6;
4832 
4833         //
4834         // Set timeout value.
4835         //
4836 
4837         srb->TimeOutValue = fdoExtension->TimeOutValue;
4838 
4839         cdb = (PCDB)srb->Cdb;
4840     }
4841 
4842     cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
4843 
4844     status = ClassSendSrbSynchronous(DeviceObject,
4845                                      srb,
4846                                      badBlocks,
4847                                      bufferSize,
4848                                      TRUE);
4849 
4850     FREE_POOL(srb);
4851     return status;
4852 }
4853 
4854 NTSTATUS
DiskIoctlReassignBlocksEx(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4855 DiskIoctlReassignBlocksEx(
4856     IN PDEVICE_OBJECT DeviceObject,
4857     IN OUT PIRP Irp
4858     )
4859 
4860 /*++
4861 
4862 Routine Description:
4863 
4864     This routine services IOCTL_DISK_REASSIGN_BLOCKS_EX. This IOCTL
4865     allows the caller to remap the defective blocks to a new
4866     location on the disk. The input buffer contains 8-byte LBAs.
4867 
4868     This function must be called at IRQL < DISPATCH_LEVEL.
4869 
4870 Arguments:
4871 
4872     DeviceObject - Supplies the device object associated with this request.
4873 
4874     Irp - The IRP to be processed
4875 
4876 Return Value:
4877 
4878     NTSTATUS code
4879 
4880 --*/
4881 
4882 {
4883     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4884     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4885     NTSTATUS status;
4886     PREASSIGN_BLOCKS_EX badBlocks = Irp->AssociatedIrp.SystemBuffer;
4887     PSCSI_REQUEST_BLOCK srb;
4888     PCDB cdb;
4889     LARGE_INTEGER blockNumber;
4890     ULONG bufferSize;
4891     ULONG blockCount;
4892     ULONG srbSize;
4893     PSTORAGE_REQUEST_BLOCK srbEx;
4894     PSTOR_ADDR_BTL8 storAddrBtl8;
4895     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
4896 
4897     //
4898     // This function must be called at less than dispatch level.
4899     // Fail if IRQL >= DISPATCH_LEVEL.
4900     //
4901     PAGED_CODE();
4902     CHECK_IRQL();
4903 
4904     //
4905     // Validate the request.
4906     //
4907 
4908     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4909 
4910     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS_EX)) {
4911         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch.\n"));
4912         return STATUS_INFO_LENGTH_MISMATCH;
4913     }
4914 
4915     //
4916     // Make sure we have some data in the input buffer.
4917     //
4918 
4919     if (badBlocks->Count == 0) {
4920         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Invalid block count\n"));
4921         return STATUS_INVALID_PARAMETER;
4922     }
4923 
4924     bufferSize = sizeof(REASSIGN_BLOCKS_EX) + ((badBlocks->Count - 1) * sizeof(LARGE_INTEGER));
4925 
4926     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) {
4927         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch for bad blocks.\n"));
4928         return STATUS_INFO_LENGTH_MISMATCH;
4929     }
4930 
4931     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4932         srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
4933     } else {
4934         srbSize = SCSI_REQUEST_BLOCK_SIZE;
4935     }
4936     srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4937                                 srbSize,
4938                                 DISK_TAG_SRB);
4939 
4940     if (srb == NULL) {
4941         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n"));
4942         return STATUS_INSUFFICIENT_RESOURCES;
4943     }
4944 
4945     RtlZeroMemory(srb, srbSize);
4946 
4947     //
4948     // Build the data buffer to be transferred in the input buffer.
4949     // The format of the data to the device is:
4950     //
4951     //      2 bytes Reserved
4952     //      2 bytes Length
4953     //      x * 8 btyes Block Address
4954     //
4955     // All values are big endian.
4956     //
4957 
4958     badBlocks->Reserved = 0;
4959     blockCount = badBlocks->Count;
4960 
4961     //
4962     // Convert # of entries to # of bytes.
4963     //
4964 
4965     blockCount *= 8;
4966     badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
4967     badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
4968 
4969     //
4970     // Convert back to number of entries.
4971     //
4972 
4973     blockCount /= 8;
4974 
4975     for (; blockCount > 0; blockCount--) {
4976 
4977         blockNumber = badBlocks->BlockNumber[blockCount-1];
4978         REVERSE_BYTES_QUAD(&badBlocks->BlockNumber[blockCount-1], &blockNumber);
4979     }
4980 
4981     //
4982     // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb
4983     //
4984 
4985     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4986         srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4987 
4988         //
4989         // Set up STORAGE_REQUEST_BLOCK fields
4990         //
4991 
4992         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
4993         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4994         srbEx->Signature = SRB_SIGNATURE;
4995         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4996         srbEx->SrbLength = srbSize;
4997         srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4998         srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4999         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
5000         srbEx->NumSrbExData = 1;
5001 
5002         // Set timeout value.
5003         srbEx->TimeOutValue = fdoExtension->TimeOutValue;
5004 
5005         //
5006         // Set up address fields
5007         //
5008 
5009         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
5010         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
5011         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
5012 
5013         //
5014         // Set up SCSI SRB extended data fields
5015         //
5016 
5017         srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
5018             sizeof(STOR_ADDR_BTL8);
5019         if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
5020             srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
5021             srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
5022             srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
5023             srbExDataCdb16->CdbLength = 6;
5024 
5025             cdb = (PCDB)srbExDataCdb16->Cdb;
5026         } else {
5027             // Should not happen
5028             NT_ASSERT(FALSE);
5029 
5030             FREE_POOL(srb);
5031             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n"));
5032             return STATUS_INTERNAL_ERROR;
5033         }
5034 
5035     } else {
5036         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5037         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5038         srb->CdbLength = 6;
5039 
5040         //
5041         // Set timeout value.
5042         //
5043 
5044         srb->TimeOutValue = fdoExtension->TimeOutValue;
5045 
5046         cdb = (PCDB)srb->Cdb;
5047     }
5048 
5049     cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
5050     cdb->CDB6GENERIC.CommandUniqueBits =  1; // LONGLBA
5051 
5052     status = ClassSendSrbSynchronous(DeviceObject,
5053                                      srb,
5054                                      badBlocks,
5055                                      bufferSize,
5056                                      TRUE);
5057 
5058     FREE_POOL(srb);
5059     return status;
5060 }
5061 
5062 NTSTATUS
DiskIoctlIsWritable(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5063 DiskIoctlIsWritable(
5064     IN PDEVICE_OBJECT DeviceObject,
5065     IN OUT PIRP Irp
5066     )
5067 
5068 /*++
5069 
5070 Routine Description:
5071 
5072     This routine services IOCTL_DISK_IS_WRITABLE. This function
5073     returns whether the disk is writable. If the device is not
5074     writable then STATUS_MEDIA_WRITE_PROTECTED will be returned.
5075 
5076     This function must be called at IRQL < DISPATCH_LEVEL.
5077 
5078 Arguments:
5079 
5080     DeviceObject - Supplies the device object associated with this request.
5081 
5082     Irp - The IRP to be processed
5083 
5084 Return Value:
5085 
5086     NTSTATUS code
5087 
5088 --*/
5089 
5090 {
5091     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5092     NTSTATUS status = STATUS_SUCCESS;
5093 
5094     PMODE_PARAMETER_HEADER modeData;
5095     PSCSI_REQUEST_BLOCK srb;
5096     PCDB cdb = NULL;
5097     ULONG modeLength;
5098     ULONG retries = 4;
5099     ULONG srbSize;
5100     PSTORAGE_REQUEST_BLOCK srbEx;
5101     PSTOR_ADDR_BTL8 storAddrBtl8;
5102     PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
5103 
5104     //
5105     // This function must be called at less than dispatch level.
5106     // Fail if IRQL >= DISPATCH_LEVEL.
5107     //
5108     PAGED_CODE();
5109     CHECK_IRQL();
5110 
5111     //
5112     // Validate the request.
5113     //
5114 
5115     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5116 
5117     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
5118         srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
5119     } else {
5120         srbSize = SCSI_REQUEST_BLOCK_SIZE;
5121     }
5122     srb = ExAllocatePoolWithTag(NonPagedPoolNx,
5123                                 srbSize,
5124                                 DISK_TAG_SRB);
5125 
5126     if (srb == NULL) {
5127         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n"));
5128         return STATUS_INSUFFICIENT_RESOURCES;
5129     }
5130 
5131     RtlZeroMemory(srb, srbSize);
5132 
5133     //
5134     // Allocate memory for a mode header and then some
5135     // for port drivers that need to convert to MODE10
5136     // or always return the MODE_PARAMETER_BLOCK (even
5137     // when memory was not allocated for this purpose)
5138     //
5139 
5140     modeLength = MODE_DATA_SIZE;
5141     modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
5142                                      modeLength,
5143                                      DISK_TAG_MODE_DATA);
5144 
5145     if (modeData == NULL) {
5146         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n"));
5147         FREE_POOL(srb);
5148         return STATUS_INSUFFICIENT_RESOURCES;
5149     }
5150 
5151     RtlZeroMemory(modeData, modeLength);
5152 
5153     //
5154     // Build the MODE SENSE CDB
5155     //
5156 
5157     if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
5158         srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
5159 
5160         //
5161         // Set up STORAGE_REQUEST_BLOCK fields
5162         //
5163 
5164         srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
5165         srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
5166         srbEx->Signature = SRB_SIGNATURE;
5167         srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
5168         srbEx->SrbLength = srbSize;
5169         srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
5170         srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
5171         srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
5172         srbEx->NumSrbExData = 1;
5173 
5174         // Set timeout value.
5175         srbEx->TimeOutValue = fdoExtension->TimeOutValue;
5176 
5177         //
5178         // Set up address fields
5179         //
5180 
5181         storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
5182         storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
5183         storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
5184 
5185         //
5186         // Set up SCSI SRB extended data fields
5187         //
5188 
5189         srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
5190             sizeof(STOR_ADDR_BTL8);
5191         if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
5192             srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
5193             srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
5194             srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
5195             srbExDataCdb16->CdbLength = 6;
5196 
5197             cdb = (PCDB)srbExDataCdb16->Cdb;
5198         } else {
5199             // Should not happen
5200             NT_ASSERT(FALSE);
5201 
5202             FREE_POOL(srb);
5203             FREE_POOL(modeData);
5204             return STATUS_INTERNAL_ERROR;
5205         }
5206 
5207     } else {
5208         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5209         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5210         srb->CdbLength = 6;
5211 
5212         //
5213         // Set timeout value.
5214         //
5215 
5216         srb->TimeOutValue = fdoExtension->TimeOutValue;
5217 
5218         cdb = (PCDB)srb->Cdb;
5219     }
5220 
5221     //
5222     // Page code of 0x3F will return all pages.
5223     // This command could fail if the data to be returned is
5224     // more than 256 bytes. In which case, we should get only
5225     // the caching page since we only need the block descriptor.
5226     // DiskFdoProcessError will change the page code to
5227     // MODE_PAGE_CACHING if there is an error.
5228     //
5229 
5230     cdb->MODE_SENSE.OperationCode    = SCSIOP_MODE_SENSE;
5231     cdb->MODE_SENSE.PageCode         = MODE_SENSE_RETURN_ALL;
5232     cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
5233 
5234     while (retries != 0) {
5235 
5236         status = ClassSendSrbSynchronous(DeviceObject,
5237                                          srb,
5238                                          modeData,
5239                                          modeLength,
5240                                          FALSE);
5241 
5242         if (status != STATUS_VERIFY_REQUIRED) {
5243             if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
5244                 status = STATUS_SUCCESS;
5245             }
5246             break;
5247         }
5248         retries--;
5249     }
5250 
5251     if (NT_SUCCESS(status)) {
5252 
5253         if (TEST_FLAG(modeData->DeviceSpecificParameter, MODE_DSP_WRITE_PROTECT)) {
5254             status = STATUS_MEDIA_WRITE_PROTECTED;
5255         }
5256     }
5257 
5258     FREE_POOL(srb);
5259     FREE_POOL(modeData);
5260     return status;
5261 }
5262 
5263 NTSTATUS
DiskIoctlSetVerify(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5264 DiskIoctlSetVerify(
5265     IN PDEVICE_OBJECT DeviceObject,
5266     IN OUT PIRP Irp
5267     )
5268 
5269 /*++
5270 
5271 Routine Description:
5272 
5273     This routine services IOCTL_DISK_INTERNAL_SET_VERIFY.
5274     This is an internal function used to set the DO_VERIFY_VOLUME
5275     device object flag. Only a kernel mode component can send this
5276     IOCTL.
5277 
5278 Arguments:
5279 
5280     DeviceObject - Supplies the device object associated with this request.
5281 
5282     Irp - The IRP to be processed
5283 
5284 Return Value:
5285 
5286     NTSTATUS code
5287 
5288 --*/
5289 
5290 {
5291     NTSTATUS status = STATUS_NOT_SUPPORTED;
5292 
5293     //
5294     // Validate the request.
5295     //
5296 
5297     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5298 
5299     //
5300     // If the caller is kernel mode, set the verify bit.
5301     //
5302 
5303     if (Irp->RequestorMode == KernelMode) {
5304 
5305         SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
5306         status = STATUS_SUCCESS;
5307 
5308     }
5309     return status;
5310 }
5311 
5312 NTSTATUS
DiskIoctlClearVerify(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5313 DiskIoctlClearVerify(
5314     IN PDEVICE_OBJECT DeviceObject,
5315     IN OUT PIRP Irp
5316     )
5317 
5318 /*++
5319 
5320 Routine Description:
5321 
5322     This routine services IOCTL_DISK_INTERNAL_CLEAR_VERIFY.
5323     This is an internal function used to clear the DO_VERIFY_VOLUME
5324     device object flag. Only a kernel mode component can send this
5325     IOCTL.
5326 
5327 Arguments:
5328 
5329     DeviceObject - Supplies the device object associated with this request.
5330 
5331     Irp - The IRP to be processed
5332 
5333 Return Value:
5334 
5335     NTSTATUS code
5336 
5337 --*/
5338 
5339 {
5340     NTSTATUS status = STATUS_NOT_SUPPORTED;
5341 
5342     //
5343     // Validate the request.
5344     //
5345 
5346     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlClearVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5347 
5348     //
5349     // If the caller is kernel mode, set the verify bit.
5350     //
5351 
5352     if (Irp->RequestorMode == KernelMode) {
5353 
5354         CLEAR_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
5355         status = STATUS_SUCCESS;
5356 
5357     }
5358     return status;
5359 }
5360 
5361 NTSTATUS
DiskIoctlUpdateDriveSize(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5362 DiskIoctlUpdateDriveSize(
5363     IN PDEVICE_OBJECT DeviceObject,
5364     IN OUT PIRP Irp
5365     )
5366 
5367 /*++
5368 
5369 Routine Description:
5370 
5371     This routine services IOCTL_DISK_UPDATE_DRIVE_SIZE.
5372     This function is used to inform the disk driver to update
5373     the device geometry information cached in the device extension
5374     This is normally initiated from the drivers layers above disk
5375     driver.
5376 
5377     This function must be called at IRQL < DISPATCH_LEVEL.
5378 
5379 Arguments:
5380 
5381     DeviceObject - Supplies the device object associated with this request.
5382 
5383     Irp - The IRP to be processed
5384 
5385 Return Value:
5386 
5387     NTSTATUS code
5388 
5389 --*/
5390 
5391 {
5392     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5393     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5394     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5395     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5396     TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
5397     NTSTATUS status;
5398 
5399     //
5400     // This function must be called at less than dispatch level.
5401     // Fail if IRQL >= DISPATCH_LEVEL.
5402     //
5403     PAGED_CODE();
5404     CHECK_IRQL();
5405 
5406     //
5407     // Validate the request.
5408     //
5409 
5410     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5411 
5412     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
5413 
5414         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: Output buffer too small.\n"));
5415         return STATUS_BUFFER_TOO_SMALL;
5416     }
5417 
5418     status = DiskReadDriveCapacity(DeviceObject);
5419 
5420     //
5421     // Note whether the drive is ready.
5422     //
5423 
5424     diskData->ReadyStatus = status;
5425 
5426     if (NT_SUCCESS(status)) {
5427 
5428         //
5429         // Copy drive geometry information from the device extension.
5430         //
5431 
5432         RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
5433                       &(fdoExtension->DiskGeometry),
5434                       sizeof(DISK_GEOMETRY));
5435 
5436         if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) {
5437             ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512;
5438         }
5439         Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
5440         status = STATUS_SUCCESS;
5441 
5442         //
5443         // Notify everyone that the disk layout may have changed
5444         //
5445 
5446         Notification.Event   = GUID_IO_DISK_LAYOUT_CHANGE;
5447         Notification.Version = 1;
5448         Notification.Size    = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
5449         Notification.FileObject = NULL;
5450         Notification.NameBufferOffset = -1;
5451 
5452         IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
5453                                                &Notification,
5454                                                NULL,
5455                                                NULL);
5456     }
5457     return status;
5458 }
5459 
5460 NTSTATUS
DiskIoctlGetVolumeDiskExtents(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5461 DiskIoctlGetVolumeDiskExtents(
5462     IN PDEVICE_OBJECT DeviceObject,
5463     IN OUT PIRP Irp
5464     )
5465 
5466 /*++
5467 
5468 Routine Description:
5469 
5470     This routine services IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
5471     and IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN. This function
5472     returns the physical location of a volume.
5473 
5474     This function must be called at IRQL < DISPATCH_LEVEL.
5475 
5476 Arguments:
5477 
5478     DeviceObject - Supplies the device object associated with this request.
5479 
5480     Irp - The IRP to be processed
5481 
5482 Return Value:
5483 
5484     NTSTATUS code
5485 
5486 --*/
5487 
5488 {
5489     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5490     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5491     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5492     NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
5493 
5494     //
5495     // This function must be called at less than dispatch level.
5496     // Fail if IRQL >= DISPATCH_LEVEL.
5497     //
5498     PAGED_CODE();
5499     CHECK_IRQL();
5500 
5501     //
5502     // Validate the request.
5503     //
5504 
5505     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5506 
5507 
5508     if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
5509 
5510         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_DISK_EXTENTS)) {
5511             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: Output buffer too small.\n"));
5512             return STATUS_BUFFER_TOO_SMALL;
5513         }
5514 
5515         status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
5516 
5517         //
5518         // Note whether the drive is ready.
5519         //
5520 
5521         diskData->ReadyStatus = status;
5522 
5523         if (NT_SUCCESS(status)) {
5524 
5525             PVOLUME_DISK_EXTENTS pVolExt = (PVOLUME_DISK_EXTENTS)Irp->AssociatedIrp.SystemBuffer;
5526 
5527             pVolExt->NumberOfDiskExtents = 1;
5528             pVolExt->Extents[0].DiskNumber     = commonExtension->PartitionZeroExtension->DeviceNumber;
5529             pVolExt->Extents[0].StartingOffset = commonExtension->StartingOffset;
5530             pVolExt->Extents[0].ExtentLength   = commonExtension->PartitionLength;
5531 
5532             Irp->IoStatus.Information = sizeof(VOLUME_DISK_EXTENTS);
5533         }
5534     }
5535 
5536     return status;
5537 }
5538 
5539 NTSTATUS
DiskIoctlSmartGetVersion(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5540 DiskIoctlSmartGetVersion(
5541     IN PDEVICE_OBJECT DeviceObject,
5542     IN OUT PIRP Irp
5543     )
5544 
5545 /*++
5546 
5547 Routine Description:
5548 
5549     This routine services SMART_GET_VERSION. It returns the
5550     SMART version information.
5551 
5552     This function must be called at IRQL < DISPATCH_LEVEL.
5553 
5554 Arguments:
5555 
5556     DeviceObject - Supplies the device object associated with this request.
5557 
5558     Irp - The IRP to be processed
5559 
5560 Return Value:
5561 
5562     NTSTATUS code
5563 
5564 --*/
5565 
5566 {
5567     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5568     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5569     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5570     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5571     NTSTATUS status;
5572 
5573     PGETVERSIONINPARAMS versionParams;
5574     PSRB_IO_CONTROL srbControl;
5575     IO_STATUS_BLOCK ioStatus = { 0 };
5576     PUCHAR buffer;
5577 
5578     //
5579     // This function must be called at less than dispatch level.
5580     // Fail if IRQL >= DISPATCH_LEVEL.
5581     //
5582     PAGED_CODE();
5583     CHECK_IRQL();
5584 
5585     //
5586     // Validate the request.
5587     //
5588 
5589     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5590 
5591 
5592     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GETVERSIONINPARAMS)) {
5593         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: Output buffer too small.\n"));
5594         return STATUS_BUFFER_TOO_SMALL;
5595     }
5596 
5597     srbControl = ExAllocatePoolWithTag(NonPagedPoolNx,
5598                                        sizeof(SRB_IO_CONTROL) +
5599                                        sizeof(GETVERSIONINPARAMS),
5600                                        DISK_TAG_SMART);
5601 
5602     if (srbControl == NULL) {
5603         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: Unable to allocate memory.\n"));
5604         return STATUS_INSUFFICIENT_RESOURCES;
5605     }
5606 
5607     RtlZeroMemory(srbControl, sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
5608 
5609     //
5610     // fill in srbControl fields
5611     //
5612 
5613     srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
5614     RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
5615     srbControl->Timeout = fdoExtension->TimeOutValue;
5616     srbControl->Length = sizeof(GETVERSIONINPARAMS);
5617     srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
5618 
5619     //
5620     // Point to the 'buffer' portion of the SRB_CONTROL
5621     //
5622 
5623     buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
5624 
5625     //
5626     // Ensure correct target is set in the cmd parameters.
5627     //
5628 
5629     versionParams = (PGETVERSIONINPARAMS)buffer;
5630     versionParams->bIDEDeviceMap = diskData->ScsiAddress.TargetId;
5631 
5632     ClassSendDeviceIoControlSynchronous(
5633                                     IOCTL_SCSI_MINIPORT,
5634                                     commonExtension->LowerDeviceObject,
5635                                     srbControl,
5636                                     sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
5637                                     sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
5638                                     FALSE,
5639                                     &ioStatus);
5640 
5641     status = ioStatus.Status;
5642 
5643     //
5644     // If successful, copy the data received into the output buffer.
5645     // This should only fail in the event that the IDE driver is older
5646     // than this driver.
5647     //
5648 
5649     if (NT_SUCCESS(status)) {
5650 
5651         buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
5652 
5653         RtlMoveMemory (Irp->AssociatedIrp.SystemBuffer, buffer, sizeof(GETVERSIONINPARAMS));
5654         Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
5655     }
5656 
5657     FREE_POOL(srbControl);
5658 
5659     return status;
5660 }
5661 
5662 NTSTATUS
DiskIoctlSmartReceiveDriveData(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5663 DiskIoctlSmartReceiveDriveData(
5664     IN PDEVICE_OBJECT DeviceObject,
5665     IN OUT PIRP Irp
5666     )
5667 
5668 /*++
5669 
5670 Routine Description:
5671 
5672     This routine services SMART_RCV_DRIVE_DATA. This function
5673     allows the caller to read SMART information from the device.
5674 
5675     This function must be called at IRQL < DISPATCH_LEVEL.
5676 
5677 Arguments:
5678 
5679     DeviceObject - Supplies the device object associated with this request.
5680 
5681     Irp - The IRP to be processed
5682 
5683 Return Value:
5684 
5685     NTSTATUS code
5686 
5687 --*/
5688 
5689 {
5690     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5691     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5692     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5693     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5694     NTSTATUS status = STATUS_INVALID_PARAMETER;
5695 
5696     PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
5697     PSRB_IO_CONTROL srbControl;
5698     IO_STATUS_BLOCK ioStatus = { 0 };
5699     ULONG controlCode = 0;
5700     PUCHAR buffer;
5701     PIRP irp2;
5702     KEVENT event;
5703     ULONG length = 0;
5704 
5705     //
5706     // This function must be called at less than dispatch level.
5707     // Fail if IRQL >= DISPATCH_LEVEL.
5708     //
5709     PAGED_CODE();
5710     CHECK_IRQL();
5711 
5712     //
5713     // Validate the request.
5714     //
5715 
5716     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5717 
5718     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < (sizeof(SENDCMDINPARAMS) - 1)) {
5719         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Input buffer length invalid.\n"));
5720         return STATUS_INVALID_PARAMETER;
5721     }
5722 
5723     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
5724         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Output buffer too small.\n"));
5725         return STATUS_BUFFER_TOO_SMALL;
5726     }
5727 
5728     //
5729     // Create notification event object to be used to signal the
5730     // request completion.
5731     //
5732 
5733     KeInitializeEvent(&event, NotificationEvent, FALSE);
5734 
5735     //
5736     // use controlCode as a sort of 'STATUS_SUCCESS' to see if it's
5737     // a valid request type
5738     //
5739 
5740     if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
5741 
5742         length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
5743         controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
5744 
5745     } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
5746 
5747         switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
5748 
5749             case READ_ATTRIBUTES:
5750                 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
5751                 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
5752                 break;
5753 
5754             case READ_THRESHOLDS:
5755                 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
5756                 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
5757                 break;
5758 
5759             case SMART_READ_LOG: {
5760 
5761                 if (diskData->FailurePredictionCapability != FailurePredictionSmart) {
5762                     TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: SMART failure prediction not supported.\n"));
5763                     return STATUS_INVALID_DEVICE_REQUEST;
5764                 }
5765 
5766                 //
5767                 // Calculate additional length based on number of sectors to be read.
5768                 // Then verify the output buffer is large enough.
5769                 //
5770 
5771                 length = cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE;
5772 
5773                 //
5774                 // Ensure at least 1 sector is going to be read
5775                 //
5776                 if (length == 0) {
5777                     return STATUS_INVALID_PARAMETER;
5778                 }
5779 
5780                 length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS));
5781 
5782                 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < length - 1) {
5783                     TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Output buffer too small for SMART_READ_LOG.\n"));
5784                     return STATUS_BUFFER_TOO_SMALL;
5785                 }
5786 
5787                 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG;
5788                 break;
5789             }
5790         }
5791     }
5792 
5793     if (controlCode == 0) {
5794         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Invalid request.\n"));
5795         return STATUS_INVALID_PARAMETER;
5796     }
5797 
5798     srbControl = ExAllocatePoolWithTag(NonPagedPoolNx,
5799                                        sizeof(SRB_IO_CONTROL) + length,
5800                                        DISK_TAG_SMART);
5801 
5802     if (srbControl == NULL) {
5803         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Unable to allocate memory.\n"));
5804         return  STATUS_INSUFFICIENT_RESOURCES;
5805     }
5806 
5807     //
5808     // fill in srbControl fields
5809     //
5810 
5811     srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
5812     RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
5813     srbControl->Timeout = fdoExtension->TimeOutValue;
5814     srbControl->Length = length;
5815     srbControl->ControlCode = controlCode;
5816 
5817     //
5818     // Point to the 'buffer' portion of the SRB_CONTROL
5819     //
5820 
5821     buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
5822 
5823     //
5824     // Ensure correct target is set in the cmd parameters.
5825     //
5826 
5827     cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
5828 
5829     //
5830     // Copy the IOCTL parameters to the srb control buffer area.
5831     //
5832 
5833     RtlMoveMemory(buffer,
5834                   Irp->AssociatedIrp.SystemBuffer,
5835                   sizeof(SENDCMDINPARAMS) - 1);
5836 
5837     irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
5838                                         commonExtension->LowerDeviceObject,
5839                                         srbControl,
5840                                         sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
5841                                         srbControl,
5842                                         sizeof(SRB_IO_CONTROL) + length,
5843                                         FALSE,
5844                                         &event,
5845                                         &ioStatus);
5846 
5847     if (irp2 == NULL) {
5848         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Unable to allocate IRP.\n"));
5849         FREE_POOL(srbControl);
5850         return STATUS_INSUFFICIENT_RESOURCES;
5851     }
5852 
5853     //
5854     // Call the port driver with the request and wait for it to complete.
5855     //
5856 
5857     status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
5858 
5859     if (status == STATUS_PENDING) {
5860         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
5861         status = ioStatus.Status;
5862     }
5863 
5864     //
5865     // Copy the data received into the output buffer. Since the status buffer
5866     // contains error information also, always perform this copy. IO will
5867     // either pass this back to the app, or zero it, in case of error.
5868     //
5869 
5870     buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
5871 
5872     if (NT_SUCCESS(status)) {
5873 
5874         RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length - 1);
5875         Irp->IoStatus.Information = length - 1;
5876 
5877     } else {
5878 
5879         RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
5880         Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
5881 
5882     }
5883 
5884     FREE_POOL(srbControl);
5885 
5886     return status;
5887 }
5888 
5889 NTSTATUS
DiskIoctlSmartSendDriveCommand(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5890 DiskIoctlSmartSendDriveCommand(
5891     IN PDEVICE_OBJECT DeviceObject,
5892     IN OUT PIRP Irp
5893     )
5894 
5895 /*++
5896 
5897 Routine Description:
5898 
5899     This routine services SMART_SEND_DRIVE_COMMAND. This function
5900     allows the caller to send SMART commands to the device.
5901 
5902     This function must be called at IRQL < DISPATCH_LEVEL.
5903 
5904 Arguments:
5905 
5906     DeviceObject - Supplies the device object associated with this request.
5907 
5908     Irp - The IRP to be processed
5909 
5910 Return Value:
5911 
5912     NTSTATUS code
5913 
5914 --*/
5915 
5916 {
5917     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5918     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5919     PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5920     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5921     NTSTATUS status = STATUS_INVALID_PARAMETER;
5922 
5923     PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
5924     PSRB_IO_CONTROL srbControl;
5925     IO_STATUS_BLOCK ioStatus = { 0 };
5926     ULONG controlCode = 0;
5927     PUCHAR buffer;
5928     PIRP irp2;
5929     KEVENT event;
5930     ULONG length = 0;
5931 
5932     //
5933     // This function must be called at less than dispatch level.
5934     // Fail if IRQL >= DISPATCH_LEVEL.
5935     //
5936     PAGED_CODE();
5937     CHECK_IRQL();
5938 
5939     //
5940     // Validate the request.
5941     //
5942 
5943     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5944 
5945     if (irpStack->Parameters.DeviceIoControl.InputBufferLength < (sizeof(SENDCMDINPARAMS) - 1)) {
5946         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Input buffer size invalid.\n"));
5947         return STATUS_INVALID_PARAMETER;
5948     }
5949 
5950     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SENDCMDOUTPARAMS) - 1)) {
5951         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Output buffer too small.\n"));
5952         return STATUS_BUFFER_TOO_SMALL;
5953     }
5954 
5955     //
5956     // Create notification event object to be used to signal the
5957     // request completion.
5958     //
5959 
5960     KeInitializeEvent(&event, NotificationEvent, FALSE);
5961 
5962     if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
5963 
5964         switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
5965 
5966             case SMART_WRITE_LOG: {
5967 
5968                 if (diskData->FailurePredictionCapability != FailurePredictionSmart) {
5969 
5970                     TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: SMART failure prediction not supported.\n"));
5971                     return STATUS_INVALID_DEVICE_REQUEST;
5972                 }
5973 
5974                 //
5975                 // Calculate additional length based on number of sectors to be written.
5976                 // Then verify the input buffer is large enough.
5977                 //
5978 
5979                 length = cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE;
5980 
5981                 //
5982                 // Ensure at least 1 sector is going to be written
5983                 //
5984 
5985                 if (length == 0) {
5986                     return STATUS_INVALID_PARAMETER;
5987                 }
5988 
5989                 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
5990                         (sizeof(SENDCMDINPARAMS) - 1) + length) {
5991 
5992                     TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Input buffer too small for SMART_WRITE_LOG.\n"));
5993                     return STATUS_BUFFER_TOO_SMALL;
5994                 }
5995 
5996                 controlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG;
5997                 break;
5998             }
5999 
6000             case ENABLE_SMART:
6001                 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
6002                 break;
6003 
6004             case DISABLE_SMART:
6005                 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
6006                 break;
6007 
6008             case RETURN_SMART_STATUS:
6009 
6010                 //
6011                 // Ensure bBuffer is at least 2 bytes (to hold the values of
6012                 // cylinderLow and cylinderHigh).
6013                 //
6014 
6015                 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
6016                     (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
6017 
6018                     return STATUS_BUFFER_TOO_SMALL;
6019                     break;
6020                 }
6021 
6022                 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
6023                 length = sizeof(IDEREGS);
6024                 break;
6025 
6026             case ENABLE_DISABLE_AUTOSAVE:
6027                 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
6028                 break;
6029 
6030             case SAVE_ATTRIBUTE_VALUES:
6031                 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
6032                 break;
6033 
6034             case EXECUTE_OFFLINE_DIAGS:
6035                 //
6036                 // Validate that this is an ok self test command
6037                 //
6038                 if (DiskIsValidSmartSelfTest(cmdInParameters->irDriveRegs.bSectorNumberReg)) {
6039 
6040                     controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
6041                 }
6042                 break;
6043 
6044             case ENABLE_DISABLE_AUTO_OFFLINE:
6045                 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE;
6046                 break;
6047         }
6048     }
6049 
6050     if (controlCode == 0) {
6051         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Invalid request.\n"));
6052         return STATUS_INVALID_PARAMETER;
6053     }
6054 
6055     length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS));
6056     srbControl = ExAllocatePoolWithTag(NonPagedPoolNx,
6057                                        sizeof(SRB_IO_CONTROL) + length,
6058                                        DISK_TAG_SMART);
6059 
6060     if (srbControl == NULL) {
6061         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Unable to allocate memory.\n"));
6062         return  STATUS_INSUFFICIENT_RESOURCES;
6063     }
6064 
6065     //
6066     // fill in srbControl fields
6067     //
6068 
6069     srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
6070     RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
6071     srbControl->Timeout = fdoExtension->TimeOutValue;
6072     srbControl->Length = length;
6073     srbControl->ControlCode = controlCode;
6074 
6075     //
6076     // Point to the 'buffer' portion of the SRB_CONTROL
6077     //
6078 
6079     buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
6080 
6081     //
6082     // Ensure correct target is set in the cmd parameters.
6083     //
6084 
6085     cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
6086 
6087     //
6088     // Copy the IOCTL parameters to the srb control buffer area.
6089     //
6090 
6091     if (cmdInParameters->irDriveRegs.bFeaturesReg == SMART_WRITE_LOG) {
6092         RtlMoveMemory(buffer,
6093                      Irp->AssociatedIrp.SystemBuffer,
6094                      sizeof(SENDCMDINPARAMS) - 1 +
6095                         cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE);
6096     } else {
6097         RtlMoveMemory(buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
6098     }
6099 
6100     irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
6101                                         commonExtension->LowerDeviceObject,
6102                                         srbControl,
6103                                         sizeof(SRB_IO_CONTROL) + length,
6104                                         srbControl,
6105                                         sizeof(SRB_IO_CONTROL) + length,
6106                                         FALSE,
6107                                         &event,
6108                                         &ioStatus);
6109 
6110     if (irp2 == NULL) {
6111         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Unable to allocate IRP.\n"));
6112         FREE_POOL(srbControl);
6113         return STATUS_INSUFFICIENT_RESOURCES;
6114     }
6115 
6116     //
6117     // Call the port driver with the request and wait for it to complete.
6118     //
6119 
6120     status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
6121 
6122     if (status == STATUS_PENDING) {
6123         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
6124         status = ioStatus.Status;
6125     }
6126 
6127     //
6128     // Copy the data received into the output buffer. Since the status buffer
6129     // contains error information also, always perform this copy. IO will
6130     // either pass this back to the app, or zero it, in case of error.
6131     //
6132 
6133     buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
6134 
6135     //
6136     // Update the return buffer size based on the sub-command.
6137     //
6138 
6139     if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
6140         length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
6141     } else {
6142         length = sizeof(SENDCMDOUTPARAMS) - 1;
6143     }
6144 
6145     RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length);
6146     Irp->IoStatus.Information = length;
6147 
6148     FREE_POOL(srbControl);
6149 
6150     return status;
6151 }
6152 
6153 
6154 VOID
DiskEtwEnableCallback(_In_ LPCGUID SourceId,_In_ ULONG IsEnabled,_In_ UCHAR Level,_In_ ULONGLONG MatchAnyKeyword,_In_ ULONGLONG MatchAllKeyword,_In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData,_In_opt_ PVOID CallbackContext)6155 DiskEtwEnableCallback (
6156     _In_ LPCGUID                      SourceId,
6157     _In_ ULONG                        IsEnabled,
6158     _In_ UCHAR                        Level,
6159     _In_ ULONGLONG                    MatchAnyKeyword,
6160     _In_ ULONGLONG                    MatchAllKeyword,
6161     _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData,
6162     _In_opt_ PVOID                    CallbackContext
6163     )
6164 /*+++
6165 
6166 Routine Description:
6167 
6168     This routine is the enable callback routine for ETW. It gets called when
6169     tracing is enabled or disabled for our provider.
6170 
6171 Arguments:
6172 
6173     As per the ETW callback.
6174 
6175 Return Value:
6176 
6177     None.
6178 --*/
6179 
6180 {
6181     //
6182     // Initialize locals.
6183     //
6184     UNREFERENCED_PARAMETER(SourceId);
6185     UNREFERENCED_PARAMETER(Level);
6186     UNREFERENCED_PARAMETER(MatchAnyKeyword);
6187     UNREFERENCED_PARAMETER(MatchAllKeyword);
6188     UNREFERENCED_PARAMETER(FilterData);
6189     UNREFERENCED_PARAMETER(CallbackContext);
6190 
6191     //
6192     // Set the ETW tracing enable state.
6193     //
6194     DiskETWEnabled = IsEnabled ? TRUE : FALSE;
6195 
6196     return;
6197 }
6198 
6199 
6200