3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI disk class driver
26 // Now instantiate the GUIDs
34 DiskDetermineMediaTypes(
35 IN PDEVICE_OBJECT Fdo
,
39 IN BOOLEAN MediaPresent
,
43 PPARTITION_INFORMATION_EX
45 DiskPdoFindPartitionEntry(
46 IN PPHYSICAL_DEVICE_EXTENSION Pdo
,
47 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
50 PPARTITION_INFORMATION_EX
52 DiskFindAdjacentPartition(
53 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
,
54 IN PPARTITION_INFORMATION_EX BasePartition
57 PPARTITION_INFORMATION_EX
59 DiskFindContainingPartition(
60 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
,
61 IN PPARTITION_INFORMATION_EX BasePartition
,
62 IN BOOLEAN SearchTopToBottom
68 IN PDEVICE_OBJECT DeviceObject
,
74 DiskIoctlGetDriveLayout(
75 IN PDEVICE_OBJECT DeviceObject
,
81 DiskIoctlGetDriveLayoutEx(
82 IN PDEVICE_OBJECT DeviceObject
,
88 DiskIoctlSetDriveLayout(
89 IN PDEVICE_OBJECT DeviceObject
,
95 DiskIoctlSetDriveLayoutEx(
96 IN PDEVICE_OBJECT DeviceObject
,
102 DiskIoctlGetPartitionInfo(
103 IN PDEVICE_OBJECT DeviceObject
,
109 DiskIoctlGetPartitionInfoEx(
110 IN PDEVICE_OBJECT DeviceObject
,
116 DiskIoctlGetLengthInfo(
117 IN PDEVICE_OBJECT DeviceObject
,
123 DiskIoctlSetPartitionInfo(
124 IN PDEVICE_OBJECT DeviceObject
,
130 DiskIoctlSetPartitionInfoEx(
131 IN PDEVICE_OBJECT DeviceObject
,
137 DiskIoctlSetPartitionInfoEx(
138 IN PDEVICE_OBJECT DeviceObject
,
144 DiskIoctlGetDriveGeometryEx(
145 IN PDEVICE_OBJECT DeviceObject
,
151 #pragma alloc_text(INIT, DriverEntry)
152 #pragma alloc_text(PAGE, DiskUnload)
153 #pragma alloc_text(PAGE, DiskCreateFdo)
154 #pragma alloc_text(PAGE, DiskDetermineMediaTypes)
155 #pragma alloc_text(PAGE, DiskModeSelect)
156 #pragma alloc_text(PAGE, DisableWriteCache)
157 #pragma alloc_text(PAGE, DiskIoctlVerify)
158 #pragma alloc_text(PAGE, DiskSetSpecialHacks)
159 #pragma alloc_text(PAGE, DiskScanRegistryForSpecial)
160 #pragma alloc_text(PAGE, DiskQueryPnpCapabilities)
161 #pragma alloc_text(PAGE, DiskGetCacheInformation)
162 #pragma alloc_text(PAGE, DiskSetCacheInformation)
163 #pragma alloc_text(PAGE, DiskSetInfoExceptionInformation)
164 #pragma alloc_text(PAGE, DiskGetInfoExceptionInformation)
166 #pragma alloc_text(PAGE, DiskPdoFindPartitionEntry)
167 #pragma alloc_text(PAGE, DiskFindAdjacentPartition)
168 #pragma alloc_text(PAGE, DiskFindContainingPartition)
170 #pragma alloc_text(PAGE, DiskIoctlCreateDisk)
171 #pragma alloc_text(PAGE, DiskIoctlGetDriveLayout)
172 #pragma alloc_text(PAGE, DiskIoctlGetDriveLayoutEx)
173 #pragma alloc_text(PAGE, DiskIoctlSetDriveLayout)
174 #pragma alloc_text(PAGE, DiskIoctlSetDriveLayoutEx)
175 #pragma alloc_text(PAGE, DiskIoctlGetPartitionInfo)
176 #pragma alloc_text(PAGE, DiskIoctlGetPartitionInfoEx)
177 #pragma alloc_text(PAGE, DiskIoctlGetLengthInfo)
178 #pragma alloc_text(PAGE, DiskIoctlSetPartitionInfo)
179 #pragma alloc_text(PAGE, DiskIoctlSetPartitionInfoEx)
180 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometryEx)
183 extern ULONG DiskDisableGpt
;
185 const GUID GUID_NULL
= { 0 };
186 #define DiskCompareGuid(_First,_Second) \
187 (memcmp ((_First),(_Second), sizeof (GUID)))
192 IN PDRIVER_OBJECT DriverObject
,
193 IN PUNICODE_STRING RegistryPath
200 This routine initializes the SCSI hard disk class driver.
204 DriverObject - Pointer to driver object created by system.
206 RegistryPath - Pointer to the name of the services node for this driver.
210 The function value is the final status from the initialization operation.
215 CLASS_INIT_DATA InitializationData
;
216 CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList
;
217 GUID guidQueryRegInfoEx
= GUID_CLASSPNP_QUERY_REGINFOEX
;
223 // Read the information NtDetect squirreled away about the disks in this
227 status
= DiskSaveDetectInfo(DriverObject
);
229 if(!NT_SUCCESS(status
)) {
230 DebugPrint((1, "Disk: couldn't save NtDetect information (%#08lx)\n",
239 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
241 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
244 // Setup sizes and entry points for functional device objects
247 InitializationData
.FdoData
.DeviceExtensionSize
= FUNCTIONAL_EXTENSION_SIZE
;
248 InitializationData
.FdoData
.DeviceType
= FILE_DEVICE_DISK
;
249 InitializationData
.FdoData
.DeviceCharacteristics
= FILE_DEVICE_SECURE_OPEN
;
251 InitializationData
.FdoData
.ClassInitDevice
= DiskInitFdo
;
252 InitializationData
.FdoData
.ClassStartDevice
= DiskStartFdo
;
253 InitializationData
.FdoData
.ClassStopDevice
= DiskStopDevice
;
254 InitializationData
.FdoData
.ClassRemoveDevice
= DiskRemoveDevice
;
255 InitializationData
.FdoData
.ClassPowerDevice
= ClassSpinDownPowerHandler
;
257 InitializationData
.FdoData
.ClassError
= DiskFdoProcessError
;
258 InitializationData
.FdoData
.ClassReadWriteVerification
= DiskReadWriteVerification
;
259 InitializationData
.FdoData
.ClassDeviceControl
= DiskDeviceControl
;
260 InitializationData
.FdoData
.ClassShutdownFlush
= DiskShutdownFlush
;
261 InitializationData
.FdoData
.ClassCreateClose
= NULL
;
264 // Setup sizes and entry points for physical device objects
267 InitializationData
.PdoData
.DeviceExtensionSize
= PHYSICAL_EXTENSION_SIZE
;
268 InitializationData
.PdoData
.DeviceType
= FILE_DEVICE_DISK
;
269 InitializationData
.PdoData
.DeviceCharacteristics
= FILE_DEVICE_SECURE_OPEN
;
271 InitializationData
.PdoData
.ClassInitDevice
= DiskInitPdo
;
272 InitializationData
.PdoData
.ClassStartDevice
= DiskStartPdo
;
273 InitializationData
.PdoData
.ClassStopDevice
= DiskStopDevice
;
274 InitializationData
.PdoData
.ClassRemoveDevice
= DiskRemoveDevice
;
277 // Use default power routine for PDOs
280 InitializationData
.PdoData
.ClassPowerDevice
= NULL
;
282 InitializationData
.PdoData
.ClassError
= NULL
;
283 InitializationData
.PdoData
.ClassReadWriteVerification
= DiskReadWriteVerification
;
284 InitializationData
.PdoData
.ClassDeviceControl
= DiskDeviceControl
;
285 InitializationData
.PdoData
.ClassShutdownFlush
= DiskShutdownFlush
;
286 InitializationData
.PdoData
.ClassCreateClose
= NULL
;
288 InitializationData
.PdoData
.ClassDeviceControl
= DiskDeviceControl
;
290 InitializationData
.PdoData
.ClassQueryPnpCapabilities
= DiskQueryPnpCapabilities
;
292 InitializationData
.ClassAddDevice
= DiskAddDevice
;
293 InitializationData
.ClassEnumerateDevice
= DiskEnumerateDevice
;
295 InitializationData
.ClassQueryId
= DiskQueryId
;
298 InitializationData
.FdoData
.ClassWmiInfo
.GuidCount
= 7;
299 InitializationData
.FdoData
.ClassWmiInfo
.GuidRegInfo
= DiskWmiFdoGuidList
;
300 InitializationData
.FdoData
.ClassWmiInfo
.ClassQueryWmiRegInfo
= DiskFdoQueryWmiRegInfo
;
301 InitializationData
.FdoData
.ClassWmiInfo
.ClassQueryWmiDataBlock
= DiskFdoQueryWmiDataBlock
;
302 InitializationData
.FdoData
.ClassWmiInfo
.ClassSetWmiDataBlock
= DiskFdoSetWmiDataBlock
;
303 InitializationData
.FdoData
.ClassWmiInfo
.ClassSetWmiDataItem
= DiskFdoSetWmiDataItem
;
304 InitializationData
.FdoData
.ClassWmiInfo
.ClassExecuteWmiMethod
= DiskFdoExecuteWmiMethod
;
305 InitializationData
.FdoData
.ClassWmiInfo
.ClassWmiFunctionControl
= DiskWmiFunctionControl
;
310 // Enable this to add WMI support for PDOs
311 InitializationData
.PdoData
.ClassWmiInfo
.GuidCount
= 1;
312 InitializationData
.PdoData
.ClassWmiInfo
.GuidRegInfo
= DiskWmiPdoGuidList
;
313 InitializationData
.PdoData
.ClassWmiInfo
.ClassQueryWmiRegInfo
= DiskPdoQueryWmiRegInfo
;
314 InitializationData
.PdoData
.ClassWmiInfo
.ClassQueryWmiDataBlock
= DiskPdoQueryWmiDataBlock
;
315 InitializationData
.PdoData
.ClassWmiInfo
.ClassSetWmiDataBlock
= DiskPdoSetWmiDataBlock
;
316 InitializationData
.PdoData
.ClassWmiInfo
.ClassSetWmiDataItem
= DiskPdoSetWmiDataItem
;
317 InitializationData
.PdoData
.ClassWmiInfo
.ClassExecuteWmiMethod
= DiskPdoExecuteWmiMethod
;
318 InitializationData
.PdoData
.ClassWmiInfo
.ClassWmiFunctionControl
= DiskWmiFunctionControl
;
321 InitializationData
.ClassUnload
= DiskUnload
;
324 // Initialize regregistration data structures
327 DiskInitializeReregistration();
330 // Call the class init routine
333 status
= ClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
336 if(NT_SUCCESS(status
)) {
337 IoRegisterBootDriverReinitialization(DriverObject
,
338 DiskDriverReinitialization
,
344 // Call class init Ex routine to register a
345 // PCLASS_QUERY_WMI_REGINFO_EX routine
347 RtlZeroMemory(&classQueryWmiRegInfoExList
, sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST
));
348 classQueryWmiRegInfoExList
.Size
= sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST
);
349 classQueryWmiRegInfoExList
.ClassFdoQueryWmiRegInfoEx
= DiskFdoQueryWmiRegInfoEx
;
351 ClassInitializeEx(DriverObject
,
353 &classQueryWmiRegInfoExList
);
357 } // end DriverEntry()
362 IN PDRIVER_OBJECT DriverObject
368 DiskCleanupDetectInfo(DriverObject
);
376 IN PDRIVER_OBJECT DriverObject
,
377 IN PDEVICE_OBJECT PhysicalDeviceObject
,
378 IN PULONG DeviceCount
,
379 IN BOOLEAN DasdAccessOnly
386 This routine creates an object for the functional device
390 DriverObject - Pointer to driver object created by system.
392 PhysicalDeviceObject - Lower level driver we should attach to
394 DeviceCount - Number of previously installed devices.
396 DasdAccessOnly - indicates whether or not a file system is allowed to mount
397 on this device object. Used to avoid double-mounting of
398 file systems on super-floppies (which can unfortunately be
399 fixed disks). If set the i/o system will only allow rawfs
409 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
410 //STRING ntNameString;
411 //UNICODE_STRING ntUnicodeString;
413 PUCHAR deviceName
= NULL
;
415 OBJECT_ATTRIBUTES objectAttributes
;
420 PDEVICE_OBJECT lowerDevice
= NULL
;
421 PDEVICE_OBJECT deviceObject
= NULL
;
423 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
424 //STORAGE_PROPERTY_ID propertyId;
425 //PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
432 // Set up an object directory to contain the objects for this
433 // device and all its partitions.
439 UNICODE_STRING unicodeDirectoryName
;
441 swprintf(buffer
, L
"\\Device\\Harddisk%d", *DeviceCount
);
443 RtlInitUnicodeString(&unicodeDirectoryName
, buffer
);
445 InitializeObjectAttributes(&objectAttributes
,
446 &unicodeDirectoryName
,
447 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
451 status
= ZwCreateDirectoryObject(&handle
,
452 DIRECTORY_ALL_ACCESS
,
457 } while((status
== STATUS_OBJECT_NAME_COLLISION
) ||
458 (status
== STATUS_OBJECT_NAME_EXISTS
));
460 if (!NT_SUCCESS(status
)) {
462 DebugPrint((1, "DiskCreateFdo: Could not create directory - %lx\n",
469 // When this loop exits the count is inflated by one - fix that.
478 lowerDevice
= IoGetAttachedDeviceReference(PhysicalDeviceObject
);
480 status
= ClassClaimDevice(lowerDevice
, FALSE
);
482 if (!NT_SUCCESS(status
)) {
483 ZwMakeTemporaryObject(handle
);
485 ObDereferenceObject(lowerDevice
);
490 // Create a device object for this device. Each physical disk will
491 // have at least one device object. The required device object
492 // describes the entire device. Its directory path is
493 // \Device\HarddiskN\Partition0, where N = device number.
496 status
= DiskGenerateDeviceName(TRUE
,
503 if(!NT_SUCCESS(status
)) {
504 DebugPrint((1, "DiskCreateFdo - couldn't create name %lx\n",
507 goto DiskCreateFdoExit
;
511 status
= ClassCreateDeviceObject(DriverObject
,
513 PhysicalDeviceObject
,
517 if (!NT_SUCCESS(status
)) {
520 "DiskCreateFdo: Can not create device object %s\n",
523 goto DiskCreateFdoExit
;
527 // Indicate that IRPs should include MDLs for data transfers.
530 SET_FLAG(deviceObject
->Flags
, DO_DIRECT_IO
);
532 fdoExtension
= deviceObject
->DeviceExtension
;
537 // Indicate that only RAW should be allowed to mount on the root
538 // partition object. This ensures that a file system can't doubly
539 // mount on a super-floppy by mounting once on P0 and once on P1.
542 SET_FLAG(deviceObject
->Vpb
->Flags
, VPB_RAW_MOUNT
);
546 // Initialize lock count to zero. The lock count is used to
547 // disable the ejection mechanism on devices that support
548 // removable media. Only the lock count in the physical
549 // device extension is used.
552 fdoExtension
->LockCount
= 0;
555 // Save system disk number.
558 fdoExtension
->DeviceNumber
= *DeviceCount
;
561 // Set the alignment requirements for the device based on the
562 // host adapter requirements
565 if (lowerDevice
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
566 deviceObject
->AlignmentRequirement
= lowerDevice
->AlignmentRequirement
;
570 // Finally, attach to the pdo
573 fdoExtension
->LowerPdo
= PhysicalDeviceObject
;
575 fdoExtension
->CommonExtension
.LowerDeviceObject
=
576 IoAttachDeviceToDeviceStack(
578 PhysicalDeviceObject
);
580 if(fdoExtension
->CommonExtension
.LowerDeviceObject
== NULL
) {
583 // Uh - oh, we couldn't attach
584 // cleanup and return
587 status
= STATUS_UNSUCCESSFUL
;
588 goto DiskCreateFdoExit
;
592 PDISK_DATA diskData
= fdoExtension
->CommonExtension
.DriverData
;
595 // Initialize the partitioning lock as it may be used in the remove
599 KeInitializeEvent(&(diskData
->PartitioningEvent
),
600 SynchronizationEvent
,
606 // Clear the init flag.
609 CLEAR_FLAG(deviceObject
->Flags
, DO_DEVICE_INITIALIZING
);
612 // Store a handle to the device object directory for this disk
615 fdoExtension
->DeviceDirectory
= handle
;
617 ObDereferenceObject(lowerDevice
);
619 return STATUS_SUCCESS
;
624 // Release the device since an error occurred.
627 if (deviceObject
!= NULL
) {
628 IoDeleteDevice(deviceObject
);
632 // Delete directory and return.
635 if (!NT_SUCCESS(status
)) {
636 ZwMakeTemporaryObject(handle
);
640 ObDereferenceObject(lowerDevice
);
647 DiskReadWriteVerification(
648 IN PDEVICE_OBJECT DeviceObject
,
656 I/O System entry for read and write requests to SCSI disks.
660 DeviceObject - Pointer to driver object created by system.
670 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
672 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
673 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
674 LARGE_INTEGER startingOffset
;
676 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
677 commonExtension
->PartitionZeroExtension
;
683 // Verify parameters of this request.
684 // Check that ending sector is within partition and
685 // that number of bytes to transfer is a multiple of
689 startingOffset
.QuadPart
=
690 (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
693 residualBytes
= transferByteCount
&
694 (fdoExtension
->DiskGeometry
.BytesPerSector
- 1);
697 if ((startingOffset
.QuadPart
> commonExtension
->PartitionLength
.QuadPart
) ||
698 (residualBytes
!= 0)) {
701 // This error may be caused by the fact that the drive is not ready.
704 status
= ((PDISK_DATA
) commonExtension
->DriverData
)->ReadyStatus
;
706 if (!NT_SUCCESS(status
)) {
709 // Flag this as a user error so that a popup is generated.
712 DebugPrint((1, "DiskReadWriteVerification: ReadyStatus is %lx\n",
715 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
718 // status will keep the current error
721 ASSERT( status
!= STATUS_INSUFFICIENT_RESOURCES
);
723 } else if((commonExtension
->IsFdo
== TRUE
) && (residualBytes
== 0)) {
726 // This failed because we think the physical disk is too small.
727 // Send it down to the drive and let the hardware decide for
731 status
= STATUS_SUCCESS
;
736 // Note fastfat depends on this parameter to determine when to
737 // remount due to a sector size change.
740 status
= STATUS_INVALID_PARAMETER
;
747 // the drive is ready, so ok the read/write
750 status
= STATUS_SUCCESS
;
754 Irp
->IoStatus
.Status
= status
;
757 } // end DiskReadWrite()
761 DiskDetermineMediaTypes(
762 IN PDEVICE_OBJECT Fdo
,
765 IN UCHAR DensityCode
,
766 IN BOOLEAN MediaPresent
,
767 IN BOOLEAN IsWritable
774 Determines number of types based on the physical device, validates the user buffer
775 and builds the MEDIA_TYPE information.
779 DeviceObject - Pointer to functional device object created by system.
780 Irp - IOCTL_STORAGE_GET_MEDIA_TYPES_EX Irp.
781 MediumType - byte returned in mode data header.
782 DensityCode - byte returned in mode data block descriptor.
783 NumberOfTypes - pointer to be updated based on actual device.
792 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
793 //PPHYSICAL_DEVICE_EXTENSION pdoExtension = Fdo->DeviceExtension;
794 //PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
795 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
797 PGET_MEDIA_TYPES mediaTypes
= Irp
->AssociatedIrp
.SystemBuffer
;
798 PDEVICE_MEDIA_INFO mediaInfo
= &mediaTypes
->MediaInfo
[0];
799 BOOLEAN deviceMatched
= FALSE
;
804 // this should be checked prior to calling into this routine
805 // as we use the buffer as mediaTypes
807 ASSERT(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>=
808 sizeof(GET_MEDIA_TYPES
));
812 // Determine if this device is removable or fixed.
815 if (!TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
821 mediaTypes
->DeviceType
= FILE_DEVICE_DISK
;
822 mediaTypes
->MediaInfoCount
= 1;
824 mediaInfo
->DeviceSpecific
.DiskInfo
.Cylinders
.QuadPart
= fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
;
825 mediaInfo
->DeviceSpecific
.DiskInfo
.TracksPerCylinder
= fdoExtension
->DiskGeometry
.TracksPerCylinder
;
826 mediaInfo
->DeviceSpecific
.DiskInfo
.SectorsPerTrack
= fdoExtension
->DiskGeometry
.SectorsPerTrack
;
827 mediaInfo
->DeviceSpecific
.DiskInfo
.BytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
828 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.NumberMediaSides
= 1;
830 mediaInfo
->DeviceSpecific
.DiskInfo
.MediaCharacteristics
= (MEDIA_CURRENTLY_MOUNTED
| MEDIA_READ_WRITE
);
833 SET_FLAG(mediaInfo
->DeviceSpecific
.DiskInfo
.MediaCharacteristics
,
834 MEDIA_WRITE_PROTECTED
);
837 mediaInfo
->DeviceSpecific
.DiskInfo
.MediaType
= FixedMedia
;
842 PUCHAR vendorId
= (PUCHAR
) fdoExtension
->DeviceDescriptor
+ fdoExtension
->DeviceDescriptor
->VendorIdOffset
;
843 PUCHAR productId
= (PUCHAR
) fdoExtension
->DeviceDescriptor
+ fdoExtension
->DeviceDescriptor
->ProductIdOffset
;
844 PUCHAR productRevision
= (PUCHAR
) fdoExtension
->DeviceDescriptor
+ fdoExtension
->DeviceDescriptor
->ProductRevisionOffset
;
845 DISK_MEDIA_TYPES_LIST
const *mediaListEntry
;
852 "DiskDetermineMediaTypes: Vendor %s, Product %s\n",
857 // Run through the list until we find the entry with a NULL Vendor Id.
860 for (i
= 0; DiskMediaTypes
[i
].VendorId
!= NULL
; i
++) {
862 mediaListEntry
= &DiskMediaTypes
[i
];
864 if (strncmp(mediaListEntry
->VendorId
,vendorId
,strlen(mediaListEntry
->VendorId
))) {
868 if ((mediaListEntry
->ProductId
!= NULL
) &&
869 strncmp(mediaListEntry
->ProductId
, productId
, strlen(mediaListEntry
->ProductId
))) {
873 if ((mediaListEntry
->Revision
!= NULL
) &&
874 strncmp(mediaListEntry
->Revision
, productRevision
, strlen(mediaListEntry
->Revision
))) {
878 deviceMatched
= TRUE
;
880 mediaTypes
->DeviceType
= FILE_DEVICE_DISK
;
881 mediaTypes
->MediaInfoCount
= mediaListEntry
->NumberOfTypes
;
884 // Ensure that buffer is large enough.
887 sizeNeeded
= FIELD_OFFSET(GET_MEDIA_TYPES
, MediaInfo
[0]) +
888 (mediaListEntry
->NumberOfTypes
*
889 sizeof(DEVICE_MEDIA_INFO
)
892 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
899 Irp
->IoStatus
.Information
= sizeNeeded
;
900 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
901 return STATUS_BUFFER_TOO_SMALL
;
904 for (j
= 0; j
< mediaListEntry
->NumberOfTypes
; j
++) {
906 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.Cylinders
.QuadPart
= fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
;
907 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.TracksPerCylinder
= fdoExtension
->DiskGeometry
.TracksPerCylinder
;
908 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.SectorsPerTrack
= fdoExtension
->DiskGeometry
.SectorsPerTrack
;
909 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.BytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
910 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.NumberMediaSides
= mediaListEntry
->NumberOfSides
;
916 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaType
= mediaListEntry
->MediaTypes
[j
];
918 if (mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaType
== MO_5_WO
) {
919 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
= MEDIA_WRITE_ONCE
;
921 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
= MEDIA_READ_WRITE
;
925 // Status will either be success, if media is present, or no media.
926 // It would be optimal to base from density code and medium type, but not all devices
927 // have values for these fields.
933 // The usage of MediumType and DensityCode is device specific, so this may need
934 // to be extended to further key off of product/vendor ids.
935 // Currently, the MO units are the only devices that return this information.
938 if (MediumType
== 2) {
939 currentMedia
= MO_5_WO
;
940 } else if (MediumType
== 3) {
941 currentMedia
= MO_5_RW
;
943 if (DensityCode
== 0x87) {
946 // Indicate that the pinnacle 4.6 G media
947 // is present. Other density codes will default to normal
951 currentMedia
= PINNACLE_APEX_5_RW
;
958 if (mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaType
== (STORAGE_MEDIA_TYPE
)currentMedia
) {
959 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
, MEDIA_CURRENTLY_MOUNTED
);
963 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
, MEDIA_CURRENTLY_MOUNTED
);
968 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
, MEDIA_WRITE_PROTECTED
);
972 // Advance to next entry.
979 if (!deviceMatched
) {
982 "DiskDetermineMediaTypes: Unknown device. Vendor: %s Product: %s Revision: %s\n",
987 // Build an entry for unknown.
990 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.Cylinders
.QuadPart
= fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
;
991 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.TracksPerCylinder
= fdoExtension
->DiskGeometry
.TracksPerCylinder
;
992 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.SectorsPerTrack
= fdoExtension
->DiskGeometry
.SectorsPerTrack
;
993 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.BytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
999 mediaTypes
->DeviceType
= FILE_DEVICE_DISK
;
1000 mediaTypes
->MediaInfoCount
= 1;
1002 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaType
= RemovableMedia
;
1003 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.NumberMediaSides
= 1;
1005 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
= MEDIA_READ_WRITE
;
1007 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
, MEDIA_CURRENTLY_MOUNTED
);
1011 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
, MEDIA_WRITE_PROTECTED
);
1016 Irp
->IoStatus
.Information
=
1017 FIELD_OFFSET(GET_MEDIA_TYPES
, MediaInfo
[0]) +
1018 (mediaTypes
->MediaInfoCount
* sizeof(DEVICE_MEDIA_INFO
));
1020 return STATUS_SUCCESS
;
1027 PDEVICE_OBJECT DeviceObject
,
1033 Routine Description:
1035 I/O system entry for device controls to SCSI disks.
1039 Fdo - Pointer to functional device object created by system.
1048 #define SendToFdo(Dev, Irp, Rval) { \
1049 PCOMMON_DEVICE_EXTENSION ce = Dev->DeviceExtension; \
1051 IoCopyCurrentIrpStackLocationToNext(Irp); \
1052 Rval = IoCallDriver(ce->LowerDeviceObject, Irp); \
1056 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
1057 //PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension;
1058 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
1060 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1061 PDISK_DATA diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
1062 PSCSI_REQUEST_BLOCK srb
;
1064 PMODE_PARAMETER_HEADER modeData
;
1069 IO_STATUS_BLOCK ioStatus
;
1073 srb
= ExAllocatePoolWithTag(NonPagedPool
,
1074 SCSI_REQUEST_BLOCK_SIZE
,
1076 Irp
->IoStatus
.Information
= 0;
1080 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1081 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1082 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
1083 return(STATUS_INSUFFICIENT_RESOURCES
);
1087 // Write zeros to Srb.
1090 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1092 cdb
= (PCDB
)srb
->Cdb
;
1094 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1096 case IOCTL_DISK_GET_CACHE_INFORMATION
:
1098 case IOCTL_DISK_SET_CACHE_INFORMATION
: {
1100 BOOLEAN getCaching
= b
;
1101 PDISK_CACHE_INFORMATION cacheInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
1103 if(!commonExtension
->IsFdo
) {
1105 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1107 SendToFdo(DeviceObject
, Irp
, status
);
1112 // Validate the request.
1116 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1117 sizeof(DISK_CACHE_INFORMATION
))
1119 status
= STATUS_BUFFER_TOO_SMALL
;
1120 Irp
->IoStatus
.Information
= sizeof(DISK_CACHE_INFORMATION
);
1124 if ((!getCaching
) &&
1125 (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1126 sizeof(DISK_CACHE_INFORMATION
))
1129 status
= STATUS_INFO_LENGTH_MISMATCH
;
1133 ASSERT(Irp
->AssociatedIrp
.SystemBuffer
!= NULL
);
1137 status
= DiskGetCacheInformation(fdoExtension
, cacheInfo
);
1139 if (NT_SUCCESS(status
)) {
1140 Irp
->IoStatus
.Information
= sizeof(DISK_CACHE_INFORMATION
);
1145 if (!cacheInfo
->WriteCacheEnabled
)
1147 if (TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1148 CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED
))
1151 // This request wants to disable write cache, which is
1152 // not supported on this device. Instead of sending it
1153 // down only to see it fail, return the error code now
1155 status
= STATUS_INVALID_DEVICE_REQUEST
;
1161 if (TEST_FLAG(fdoExtension
->ScanForSpecialFlags
,
1162 CLASS_SPECIAL_DISABLE_WRITE_CACHE
))
1165 // This request wants to enable write cache, which
1166 // has been disabled to protect data integrity. So
1167 // fail this request with access denied
1169 status
= STATUS_ACCESS_DENIED
;
1174 status
= DiskSetCacheInformation(fdoExtension
, cacheInfo
);
1176 if (NT_SUCCESS(status
))
1179 // Store the user-defined override in the registry
1181 ClassSetDeviceParameter(fdoExtension
,
1182 DiskDeviceParameterSubkey
,
1183 DiskDeviceUserWriteCacheSetting
,
1184 (cacheInfo
->WriteCacheEnabled
) ? DiskWriteCacheEnable
: DiskWriteCacheDisable
);
1186 else if (status
== STATUS_INVALID_DEVICE_REQUEST
)
1188 if (cacheInfo
->WriteCacheEnabled
== FALSE
)
1191 // This device does not allow for
1192 // the write cache to be disabled
1194 ULONG specialFlags
= 0;
1196 ClassGetDeviceParameter(fdoExtension
,
1197 DiskDeviceParameterSubkey
,
1198 DiskDeviceSpecialFlags
,
1201 SET_FLAG(specialFlags
, HackDisableWriteCacheNotSupported
);
1203 SET_FLAG(fdoExtension
->ScanForSpecialFlags
,
1204 CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED
);
1206 ClassSetDeviceParameter(fdoExtension
,
1207 DiskDeviceParameterSubkey
,
1208 DiskDeviceSpecialFlags
,
1217 #if(_WIN32_WINNT >= 0x0500)
1218 case IOCTL_DISK_GET_WRITE_CACHE_STATE
: {
1220 PDISK_WRITE_CACHE_STATE writeCacheState
= (PDISK_WRITE_CACHE_STATE
)Irp
->AssociatedIrp
.SystemBuffer
;
1222 if(!commonExtension
->IsFdo
) {
1224 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1226 SendToFdo(DeviceObject
, Irp
, status
);
1231 // Validate the request.
1234 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_WRITE_CACHE_STATE
)) {
1236 status
= STATUS_BUFFER_TOO_SMALL
;
1237 Irp
->IoStatus
.Information
= sizeof(DISK_WRITE_CACHE_STATE
);
1241 *writeCacheState
= DiskWriteCacheNormal
;
1244 // Determine whether it is possible to disable the write cache
1247 if (TEST_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED
))
1249 *writeCacheState
= DiskWriteCacheDisableNotSupported
;
1253 // Determine whether it is safe to toggle the write cache
1256 if (TEST_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_WRITE_CACHE
))
1258 *writeCacheState
= DiskWriteCacheForceDisable
;
1261 Irp
->IoStatus
.Information
= sizeof(DISK_WRITE_CACHE_STATE
);
1262 status
= STATUS_SUCCESS
;
1267 case SMART_GET_VERSION
: {
1270 PSRB_IO_CONTROL srbControl
;
1271 PGETVERSIONINPARAMS versionParams
;
1273 if(!commonExtension
->IsFdo
) {
1274 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1276 SendToFdo(DeviceObject
, Irp
, status
);
1280 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1281 sizeof(GETVERSIONINPARAMS
)) {
1282 status
= STATUS_BUFFER_TOO_SMALL
;
1283 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1288 // Create notification event object to be used to signal the
1289 // request completion.
1292 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1294 srbControl
= ExAllocatePoolWithTag(NonPagedPool
,
1295 sizeof(SRB_IO_CONTROL
) +
1296 sizeof(GETVERSIONINPARAMS
),
1300 status
= STATUS_INSUFFICIENT_RESOURCES
;
1304 RtlZeroMemory(srbControl
,
1305 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
)
1309 // fill in srbControl fields
1312 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1313 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1314 srbControl
->Timeout
= fdoExtension
->TimeOutValue
;
1315 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1316 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1319 // Point to the 'buffer' portion of the SRB_CONTROL
1322 buffer
= (PUCHAR
)srbControl
;
1323 buffer
+= srbControl
->HeaderLength
;
1326 // Ensure correct target is set in the cmd parameters.
1329 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1330 versionParams
->bIDEDeviceMap
= diskData
->ScsiAddress
.TargetId
;
1333 // Copy the IOCTL parameters to the srb control buffer area.
1336 RtlMoveMemory(buffer
,
1337 Irp
->AssociatedIrp
.SystemBuffer
,
1338 sizeof(GETVERSIONINPARAMS
));
1340 ClassSendDeviceIoControlSynchronous(
1341 IOCTL_SCSI_MINIPORT
,
1342 commonExtension
->LowerDeviceObject
,
1344 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1345 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1349 status
= ioStatus
.Status
;
1352 // If successful, copy the data received into the output buffer.
1353 // This should only fail in the event that the IDE driver is older
1354 // than this driver.
1357 if (NT_SUCCESS(status
)) {
1359 buffer
= (PUCHAR
)srbControl
;
1360 buffer
+= srbControl
->HeaderLength
;
1362 RtlMoveMemory (Irp
->AssociatedIrp
.SystemBuffer
, buffer
,
1363 sizeof(GETVERSIONINPARAMS
));
1364 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1367 ExFreePool(srbControl
);
1371 case SMART_RCV_DRIVE_DATA
: {
1373 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1374 ULONG controlCode
= 0;
1375 PSRB_IO_CONTROL srbControl
;
1378 if(!commonExtension
->IsFdo
) {
1379 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1381 SendToFdo(DeviceObject
, Irp
, status
);
1385 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1386 (sizeof(SENDCMDINPARAMS
) - 1)) {
1387 status
= STATUS_INVALID_PARAMETER
;
1388 Irp
->IoStatus
.Information
= 0;
1391 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1392 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1393 status
= STATUS_BUFFER_TOO_SMALL
;
1394 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) + 512 - 1;
1399 // Create notification event object to be used to signal the
1400 // request completion.
1403 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1406 // use controlCode as a sort of 'STATUS_SUCCESS' to see if it's
1407 // a valid request type
1410 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1412 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1413 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1415 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1416 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1417 case READ_ATTRIBUTES
:
1418 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1419 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1421 case READ_THRESHOLDS
:
1422 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1423 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1426 status
= STATUS_INVALID_PARAMETER
;
1431 status
= STATUS_INVALID_PARAMETER
;
1434 if (controlCode
== 0) {
1435 status
= STATUS_INVALID_PARAMETER
;
1439 srbControl
= ExAllocatePoolWithTag(NonPagedPool
,
1440 sizeof(SRB_IO_CONTROL
) + length
,
1444 status
= STATUS_INSUFFICIENT_RESOURCES
;
1449 // fill in srbControl fields
1452 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1453 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1454 srbControl
->Timeout
= fdoExtension
->TimeOutValue
;
1455 srbControl
->Length
= length
;
1456 srbControl
->ControlCode
= controlCode
;
1459 // Point to the 'buffer' portion of the SRB_CONTROL
1462 buffer
= (PUCHAR
)srbControl
;
1463 buffer
+= srbControl
->HeaderLength
;
1466 // Ensure correct target is set in the cmd parameters.
1469 cmdInParameters
->bDriveNumber
= diskData
->ScsiAddress
.TargetId
;
1472 // Copy the IOCTL parameters to the srb control buffer area.
1475 RtlMoveMemory(buffer
,
1476 Irp
->AssociatedIrp
.SystemBuffer
,
1477 sizeof(SENDCMDINPARAMS
) - 1);
1479 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1480 commonExtension
->LowerDeviceObject
,
1482 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1484 sizeof(SRB_IO_CONTROL
) + length
,
1490 status
= STATUS_INSUFFICIENT_RESOURCES
;
1491 ExFreePool(srbControl
);
1496 // Call the port driver with the request and wait for it to complete.
1499 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, irp2
);
1501 if (status
== STATUS_PENDING
) {
1502 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
1503 status
= ioStatus
.Status
;
1507 // Copy the data received into the output buffer. Since the status buffer
1508 // contains error information also, always perform this copy. IO will will
1509 // either pass this back to the app, or zero it, in case of error.
1512 buffer
= (PUCHAR
)srbControl
;
1513 buffer
+= srbControl
->HeaderLength
;
1515 if (NT_SUCCESS(status
)) {
1517 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, buffer
, length
- 1);
1518 Irp
->IoStatus
.Information
= length
- 1;
1522 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1523 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1527 ExFreePool(srbControl
);
1532 case SMART_SEND_DRIVE_COMMAND
: {
1534 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1535 PSRB_IO_CONTROL srbControl
;
1536 ULONG controlCode
= 0;
1539 if(!commonExtension
->IsFdo
) {
1540 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1542 SendToFdo(DeviceObject
, Irp
, status
);
1546 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1547 (sizeof(SENDCMDINPARAMS
) - 1)) {
1548 status
= STATUS_INVALID_PARAMETER
;
1549 Irp
->IoStatus
.Information
= 0;
1552 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1553 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1554 status
= STATUS_BUFFER_TOO_SMALL
;
1555 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1560 // Create notification event object to be used to signal the
1561 // request completion.
1564 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1568 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1569 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1572 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1576 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1579 case RETURN_SMART_STATUS
:
1582 // Ensure bBuffer is at least 2 bytes (to hold the values of
1583 // cylinderLow and cylinderHigh).
1586 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1587 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1589 status
= STATUS_BUFFER_TOO_SMALL
;
1590 Irp
->IoStatus
.Information
=
1591 sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
1595 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1596 length
= sizeof(IDEREGS
);
1599 case ENABLE_DISABLE_AUTOSAVE
:
1600 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1603 case SAVE_ATTRIBUTE_VALUES
:
1604 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1607 case EXECUTE_OFFLINE_DIAGS
:
1609 // Validate that this is an ok self test command
1611 if (DiskIsValidSmartSelfTest(cmdInParameters
->irDriveRegs
.bSectorNumberReg
))
1613 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1617 case ENABLE_DISABLE_AUTO_OFFLINE
:
1618 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
;
1622 status
= STATUS_INVALID_PARAMETER
;
1627 status
= STATUS_INVALID_PARAMETER
;
1630 if (controlCode
== 0) {
1631 status
= STATUS_INVALID_PARAMETER
;
1635 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1636 srbControl
= ExAllocatePoolWithTag(NonPagedPool
,
1637 sizeof(SRB_IO_CONTROL
) + length
,
1641 status
= STATUS_INSUFFICIENT_RESOURCES
;
1646 // fill in srbControl fields
1649 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1650 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1651 srbControl
->Timeout
= fdoExtension
->TimeOutValue
;
1652 srbControl
->Length
= length
;
1655 // Point to the 'buffer' portion of the SRB_CONTROL
1658 buffer
= (PUCHAR
)srbControl
;
1659 buffer
+= srbControl
->HeaderLength
;
1662 // Ensure correct target is set in the cmd parameters.
1665 cmdInParameters
->bDriveNumber
= diskData
->ScsiAddress
.TargetId
;
1668 // Copy the IOCTL parameters to the srb control buffer area.
1671 RtlMoveMemory(buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1673 srbControl
->ControlCode
= controlCode
;
1675 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1676 commonExtension
->LowerDeviceObject
,
1678 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1680 sizeof(SRB_IO_CONTROL
) + length
,
1686 status
= STATUS_INSUFFICIENT_RESOURCES
;
1687 ExFreePool(srbControl
);
1692 // Call the port driver with the request and wait for it to complete.
1695 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, irp2
);
1697 if (status
== STATUS_PENDING
) {
1698 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
1699 status
= ioStatus
.Status
;
1703 // Copy the data received into the output buffer. Since the status buffer
1704 // contains error information also, always perform this copy. IO will will
1705 // either pass this back to the app, or zero it, in case of error.
1708 buffer
= (PUCHAR
)srbControl
;
1709 buffer
+= srbControl
->HeaderLength
;
1712 // Update the return buffer size based on the sub-command.
1715 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
1716 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
1718 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
1721 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, buffer
, length
);
1722 Irp
->IoStatus
.Information
= length
;
1724 ExFreePool(srbControl
);
1729 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX
: {
1731 PMODE_PARAMETER_BLOCK blockDescriptor
;
1734 BOOLEAN writable
= FALSE
;
1735 BOOLEAN mediaPresent
= FALSE
;
1738 "Disk.DiskDeviceControl: GetMediaTypes\n"));
1740 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1741 sizeof(GET_MEDIA_TYPES
)) {
1742 status
= STATUS_BUFFER_TOO_SMALL
;
1743 Irp
->IoStatus
.Information
= sizeof(GET_MEDIA_TYPES
);
1747 if(!commonExtension
->IsFdo
) {
1748 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1750 SendToFdo(DeviceObject
, Irp
, status
);
1755 // Send a TUR to determine if media is present.
1759 cdb
= (PCDB
)srb
->Cdb
;
1760 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1763 // Set timeout value.
1766 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
1768 status
= ClassSendSrbSynchronous(DeviceObject
,
1775 if (NT_SUCCESS(status
)) {
1776 mediaPresent
= TRUE
;
1779 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1782 // Allocate memory for mode header and block descriptor.
1785 modeLength
= sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
1786 modeData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1788 DISK_TAG_MODE_DATA
);
1790 if (modeData
== NULL
) {
1791 status
= STATUS_INSUFFICIENT_RESOURCES
;
1795 RtlZeroMemory(modeData
, modeLength
);
1798 // Build the MODE SENSE CDB.
1802 cdb
= (PCDB
)srb
->Cdb
;
1805 // Set timeout value from device extension.
1808 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
1811 // Page code of 0 will return header and block descriptor only.
1814 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
1815 cdb
->MODE_SENSE
.PageCode
= 0;
1816 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)modeLength
;
1819 status
= ClassSendSrbSynchronous(DeviceObject
,
1826 if (status
== STATUS_VERIFY_REQUIRED
) {
1836 } else if (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
1837 status
= STATUS_SUCCESS
;
1840 if (NT_SUCCESS(status
) || (status
== STATUS_NO_MEDIA_IN_DEVICE
)) {
1843 // Get the block descriptor.
1846 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)modeData
;
1847 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)((ULONG_PTR
)blockDescriptor
+ sizeof(MODE_PARAMETER_HEADER
));
1850 // Do some validation.
1853 if (modeData
->BlockDescriptorLength
!= sizeof(MODE_PARAMETER_BLOCK
)) {
1856 "DiskDeviceControl: BlockDescriptor length - "
1857 "Expected %x, actual %x\n",
1858 modeData
->BlockDescriptorLength
,
1859 sizeof(MODE_PARAMETER_BLOCK
)));
1863 "DiskDeviceControl: DensityCode %x, MediumType %x\n",
1864 blockDescriptor
->DensityCode
,
1865 modeData
->MediumType
));
1867 if (TEST_FLAG(modeData
->DeviceSpecificParameter
,
1868 MODE_DSP_WRITE_PROTECT
)) {
1874 status
= DiskDetermineMediaTypes(DeviceObject
,
1876 modeData
->MediumType
,
1877 blockDescriptor
->DensityCode
,
1882 // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail.
1887 "DiskDeviceControl: Mode sense for header/bd failed. %lx\n",
1891 ExFreePool(modeData
);
1895 case IOCTL_DISK_GET_DRIVE_GEOMETRY
: {
1897 DebugPrint((2, "IOCTL_DISK_GET_DRIVE_GEOMETRY to device %p through irp %p\n",
1898 DeviceObject
, Irp
));
1899 DebugPrint((2, "Device is a%s.\n",
1900 commonExtension
->IsFdo
? "n fdo" : " pdo"));
1902 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1903 sizeof(DISK_GEOMETRY
)) {
1905 status
= STATUS_BUFFER_TOO_SMALL
;
1906 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1910 if(!commonExtension
->IsFdo
) {
1913 // Pdo should issue this request to the lower device object
1916 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1918 SendToFdo(DeviceObject
, Irp
, status
);
1922 // DiskAcquirePartitioningLock(fdoExtension);
1924 if (TEST_FLAG(DeviceObject
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
1927 // Issue ReadCapacity to update device extension
1928 // with information for current media.
1931 status
= DiskReadDriveCapacity(
1932 commonExtension
->PartitionZeroExtension
->DeviceObject
);
1935 // Note whether the drive is ready.
1938 diskData
->ReadyStatus
= status
;
1940 if (!NT_SUCCESS(status
)) {
1941 // DiskReleasePartitioningLock(fdoExtension);
1947 // Copy drive geometry information from device extension.
1950 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1951 &(fdoExtension
->DiskGeometry
),
1952 sizeof(DISK_GEOMETRY
));
1954 status
= STATUS_SUCCESS
;
1955 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1956 // DiskReleasePartitioningLock(fdoExtension);
1960 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
: {
1961 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_GEOMETRY_EX to device %p through irp %p\n",
1962 DeviceObject
, Irp
));
1963 DebugPrint((1, "Device Is a%s.\n",
1964 commonExtension
->IsFdo
? "n fdo" : " pdo"));
1967 if (!commonExtension
->IsFdo
) {
1970 // Pdo should issue this request to the lower device object
1973 ClassReleaseRemoveLock (DeviceObject
, Irp
);
1975 SendToFdo (DeviceObject
, Irp
, status
);
1980 status
= DiskIoctlGetDriveGeometryEx( DeviceObject
, Irp
);
1986 case IOCTL_STORAGE_PREDICT_FAILURE
: {
1988 PSTORAGE_PREDICT_FAILURE checkFailure
;
1989 STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus
;
1991 DebugPrint((2, "IOCTL_STORAGE_PREDICT_FAILURE to device %p through irp %p\n",
1992 DeviceObject
, Irp
));
1993 DebugPrint((2, "Device is a%s.\n",
1994 commonExtension
->IsFdo
? "n fdo" : " pdo"));
1996 checkFailure
= (PSTORAGE_PREDICT_FAILURE
)Irp
->AssociatedIrp
.SystemBuffer
;
1998 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1999 sizeof(STORAGE_PREDICT_FAILURE
)) {
2001 status
= STATUS_BUFFER_TOO_SMALL
;
2002 Irp
->IoStatus
.Information
= sizeof(STORAGE_PREDICT_FAILURE
);
2006 if(!commonExtension
->IsFdo
) {
2009 // Pdo should issue this request to the lower device object
2012 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2014 SendToFdo(DeviceObject
, Irp
, status
);
2019 // See if the disk is predicting failure
2022 if (diskData
->FailurePredictionCapability
== FailurePredictionSense
) {
2023 ULONG readBufferSize
;
2026 IO_STATUS_BLOCK ioStatus
;
2027 PDEVICE_OBJECT topOfStack
;
2029 checkFailure
->PredictFailure
= 0;
2031 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
2033 topOfStack
= IoGetAttachedDeviceReference(DeviceObject
);
2036 // SCSI disks need to have a read sent down to provoke any
2037 // failures to be reported.
2039 // Issue a normal read operation. The error-handling code in
2040 // classpnp will take care of a failure prediction by logging the
2044 readBufferSize
= fdoExtension
->DiskGeometry
.BytesPerSector
;
2045 readBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
2049 if (readBuffer
!= NULL
) {
2050 LARGE_INTEGER offset
;
2052 offset
.QuadPart
= 0;
2053 readIrp
= IoBuildSynchronousFsdRequest(
2063 if (readIrp
!= NULL
) {
2064 status
= IoCallDriver(topOfStack
, readIrp
);
2065 if (status
== STATUS_PENDING
) {
2066 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
2067 status
= ioStatus
.Status
;
2071 ExFreePool(readBuffer
);
2073 ObDereferenceObject(topOfStack
);
2076 if ((diskData
->FailurePredictionCapability
== FailurePredictionSmart
) ||
2077 (diskData
->FailurePredictionCapability
== FailurePredictionSense
))
2079 status
= DiskReadFailurePredictStatus(fdoExtension
,
2082 if (NT_SUCCESS(status
))
2084 status
= DiskReadFailurePredictData(fdoExtension
,
2085 Irp
->AssociatedIrp
.SystemBuffer
);
2087 if (diskSmartStatus
.PredictFailure
)
2089 checkFailure
->PredictFailure
= 1;
2091 checkFailure
->PredictFailure
= 0;
2094 Irp
->IoStatus
.Information
= sizeof(STORAGE_PREDICT_FAILURE
);
2097 status
= STATUS_INVALID_DEVICE_REQUEST
;
2103 case IOCTL_DISK_VERIFY
: {
2105 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2106 LARGE_INTEGER byteOffset
;
2108 DebugPrint((2, "IOCTL_DISK_VERIFY to device %p through irp %p\n",
2109 DeviceObject
, Irp
));
2110 DebugPrint((2, "Device is a%s.\n",
2111 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2114 // Validate buffer length.
2117 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2118 sizeof(VERIFY_INFORMATION
)) {
2120 status
= STATUS_INFO_LENGTH_MISMATCH
;
2125 // Add disk offset to starting sector.
2128 byteOffset
.QuadPart
= commonExtension
->StartingOffset
.QuadPart
+
2129 verifyInfo
->StartingOffset
.QuadPart
;
2131 if(!commonExtension
->IsFdo
) {
2134 // Adjust the request and forward it down
2137 verifyInfo
->StartingOffset
.QuadPart
= byteOffset
.QuadPart
;
2139 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2140 SendToFdo(DeviceObject
, Irp
, status
);
2146 // Perform a bounds check on the sector range
2149 if ((verifyInfo
->StartingOffset
.QuadPart
> commonExtension
->PartitionLength
.QuadPart
) ||
2150 (verifyInfo
->StartingOffset
.QuadPart
< 0))
2152 status
= STATUS_NONEXISTENT_SECTOR
;
2157 ULONGLONG bytesRemaining
= commonExtension
->PartitionLength
.QuadPart
- verifyInfo
->StartingOffset
.QuadPart
;
2159 if ((ULONGLONG
)verifyInfo
->Length
> bytesRemaining
)
2161 status
= STATUS_NONEXISTENT_SECTOR
;
2167 PDISK_VERIFY_WORKITEM_CONTEXT Context
= NULL
;
2169 Context
= ExAllocatePoolWithTag(NonPagedPool
,
2170 sizeof(DISK_VERIFY_WORKITEM_CONTEXT
),
2171 DISK_TAG_WI_CONTEXT
);
2177 Context
->WorkItem
= IoAllocateWorkItem(DeviceObject
);
2179 if (Context
->WorkItem
)
2181 IoMarkIrpPending(Irp
);
2183 IoQueueWorkItem(Context
->WorkItem
,
2184 (PIO_WORKITEM_ROUTINE
)DiskIoctlVerify
,
2188 return STATUS_PENDING
;
2191 ExFreePool(Context
);
2194 status
= STATUS_INSUFFICIENT_RESOURCES
;
2200 case IOCTL_DISK_CREATE_DISK
: {
2202 if (!commonExtension
->IsFdo
) {
2203 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2205 SendToFdo(DeviceObject
, Irp
, status
);
2209 status
= DiskIoctlCreateDisk (
2216 case IOCTL_DISK_GET_DRIVE_LAYOUT
: {
2218 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_LAYOUT to device %p through irp %p\n",
2219 DeviceObject
, Irp
));
2220 DebugPrint((1, "Device is a%s.\n",
2221 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2223 if (!commonExtension
->IsFdo
) {
2224 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2226 SendToFdo(DeviceObject
, Irp
, status
);
2230 status
= DiskIoctlGetDriveLayout(
2236 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
: {
2238 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_LAYOUT_EX to device %p through irp %p\n",
2239 DeviceObject
, Irp
));
2240 DebugPrint((1, "Device is a%s.\n",
2241 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2243 if (!commonExtension
->IsFdo
) {
2244 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2246 SendToFdo(DeviceObject
, Irp
, status
);
2250 status
= DiskIoctlGetDriveLayoutEx(
2257 case IOCTL_DISK_SET_DRIVE_LAYOUT
: {
2259 DebugPrint((1, "IOCTL_DISK_SET_DRIVE_LAYOUT to device %p through irp %p\n",
2260 DeviceObject
, Irp
));
2261 DebugPrint((1, "Device is a%s.\n",
2262 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2264 if(!commonExtension
->IsFdo
) {
2265 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2267 SendToFdo(DeviceObject
, Irp
, status
);
2271 status
= DiskIoctlSetDriveLayout(DeviceObject
, Irp
);
2274 // Notify everyone that the disk layout has changed
2277 TARGET_DEVICE_CUSTOM_NOTIFICATION Notification
;
2279 Notification
.Event
= GUID_IO_DISK_LAYOUT_CHANGE
;
2280 Notification
.Version
= 1;
2281 Notification
.Size
= (USHORT
)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION
, CustomDataBuffer
);
2282 Notification
.FileObject
= NULL
;
2283 Notification
.NameBufferOffset
= -1;
2285 IoReportTargetDeviceChangeAsynchronous(fdoExtension
->LowerPdo
,
2294 case IOCTL_DISK_SET_DRIVE_LAYOUT_EX
: {
2296 DebugPrint((1, "IOCTL_DISK_SET_DRIVE_LAYOUT_EX to device %p through irp %p\n",
2297 DeviceObject
, Irp
));
2298 DebugPrint((1, "Device is a%s.\n",
2299 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2301 if (!commonExtension
->IsFdo
) {
2302 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2304 SendToFdo(DeviceObject
, Irp
, status
);
2309 status
= DiskIoctlSetDriveLayoutEx(
2314 // Notify everyone that the disk layout has changed
2317 TARGET_DEVICE_CUSTOM_NOTIFICATION Notification
;
2319 Notification
.Event
= GUID_IO_DISK_LAYOUT_CHANGE
;
2320 Notification
.Version
= 1;
2321 Notification
.Size
= (USHORT
)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION
, CustomDataBuffer
);
2322 Notification
.FileObject
= NULL
;
2323 Notification
.NameBufferOffset
= -1;
2325 IoReportTargetDeviceChangeAsynchronous(fdoExtension
->LowerPdo
,
2334 case IOCTL_DISK_GET_PARTITION_INFO
: {
2336 DebugPrint((1, "IOCTL_DISK_GET_PARTITION_INFO to device %p through irp %p\n",
2337 DeviceObject
, Irp
));
2338 DebugPrint((1, "Device is a%s.\n",
2339 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2341 status
= DiskIoctlGetPartitionInfo(
2347 case IOCTL_DISK_GET_PARTITION_INFO_EX
: {
2349 DebugPrint((1, "IOCTL_DISK_GET_PARTITION_INFO to device %p through irp %p\n",
2350 DeviceObject
, Irp
));
2351 DebugPrint((1, "Device is a%s.\n",
2352 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2354 status
= DiskIoctlGetPartitionInfoEx(
2360 case IOCTL_DISK_GET_LENGTH_INFO
: {
2361 DebugPrint((1, "IOCTL_DISK_GET_LENGTH_INFO to device %p through irp %p\n",
2362 DeviceObject
, Irp
));
2363 DebugPrint((1, "Device is a%s.\n",
2364 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2366 status
= DiskIoctlGetLengthInfo(
2372 case IOCTL_DISK_SET_PARTITION_INFO
: {
2374 DebugPrint((1, "IOCTL_DISK_SET_PARTITION_INFO to device %p through irp %p\n",
2375 DeviceObject
, Irp
));
2376 DebugPrint((1, "Device is a%s.\n",
2377 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2380 status
= DiskIoctlSetPartitionInfo (
2387 case IOCTL_DISK_SET_PARTITION_INFO_EX
: {
2389 DebugPrint((1, "IOCTL_DISK_SET_PARTITION_INFO_EX to device %p through irp %p\n",
2390 DeviceObject
, Irp
));
2391 DebugPrint((1, "Device is a%s.\n",
2392 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2394 status
= DiskIoctlSetPartitionInfoEx(
2400 case IOCTL_DISK_DELETE_DRIVE_LAYOUT
: {
2402 CREATE_DISK CreateDiskInfo
;
2405 // Update the disk with new partition information.
2408 DebugPrint((1, "IOCTL_DISK_DELETE_DRIVE_LAYOUT to device %p through irp %p\n",
2409 DeviceObject
, Irp
));
2410 DebugPrint((1, "Device is a%s.\n",
2411 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2413 if(!commonExtension
->IsFdo
) {
2415 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2417 SendToFdo(DeviceObject
, Irp
, status
);
2421 DiskAcquirePartitioningLock(fdoExtension
);
2423 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
2426 // IoCreateDisk called with a partition style of raw
2427 // will remove any partition tables from the disk.
2430 RtlZeroMemory (&CreateDiskInfo
, sizeof (CreateDiskInfo
));
2431 CreateDiskInfo
.PartitionStyle
= PARTITION_STYLE_RAW
;
2433 status
= IoCreateDisk(
2438 DiskReleasePartitioningLock(fdoExtension
);
2439 ClassInvalidateBusRelations(DeviceObject
);
2441 Irp
->IoStatus
.Status
= status
;
2446 case IOCTL_DISK_REASSIGN_BLOCKS
: {
2449 // Map defective blocks to new location on disk.
2452 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2457 DebugPrint((2, "IOCTL_DISK_REASSIGN_BLOCKS to device %p through irp %p\n",
2458 DeviceObject
, Irp
));
2459 DebugPrint((2, "Device is a%s.\n",
2460 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2463 // Validate buffer length.
2466 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2467 sizeof(REASSIGN_BLOCKS
)) {
2469 status
= STATUS_INFO_LENGTH_MISMATCH
;
2477 if(!commonExtension
->IsFdo
) {
2479 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2481 SendToFdo(DeviceObject
, Irp
, status
);
2485 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2486 ((badBlocks
->Count
- 1) * sizeof(ULONG
));
2488 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2491 status
= STATUS_INFO_LENGTH_MISMATCH
;
2496 // Build the data buffer to be transferred in the input buffer.
2497 // The format of the data to the device is:
2501 // x * 4 btyes Block Address
2503 // All values are big endian.
2506 badBlocks
->Reserved
= 0;
2507 blockCount
= badBlocks
->Count
;
2510 // Convert # of entries to # of bytes.
2514 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2515 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2518 // Convert back to number of entries.
2523 for (; blockCount
> 0; blockCount
--) {
2525 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2527 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2528 (PFOUR_BYTE
) &blockNumber
);
2533 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2536 // Set timeout value.
2539 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2541 status
= ClassSendSrbSynchronous(DeviceObject
,
2547 Irp
->IoStatus
.Status
= status
;
2548 Irp
->IoStatus
.Information
= 0;
2550 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2551 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
2556 case IOCTL_DISK_IS_WRITABLE
: {
2559 // This routine mimics IOCTL_STORAGE_GET_MEDIA_TYPES_EX
2565 DebugPrint((3, "Disk.DiskDeviceControl: IOCTL_DISK_IS_WRITABLE\n"));
2567 if (!commonExtension
->IsFdo
)
2569 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2571 SendToFdo(DeviceObject
, Irp
, status
);
2575 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
2578 // Allocate memory for a mode header and then some
2579 // for port drivers that need to convert to MODE10
2580 // or always return the MODE_PARAMETER_BLOCK (even
2581 // when memory was not allocated for this purpose)
2584 modeLength
= sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
2585 modeData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2587 DISK_TAG_MODE_DATA
);
2589 if (modeData
== NULL
)
2591 status
= STATUS_INSUFFICIENT_RESOURCES
;
2595 RtlZeroMemory(modeData
, modeLength
);
2598 // Build the MODE SENSE CDB
2602 cdb
= (PCDB
)srb
->Cdb
;
2605 // Set the timeout value from the device extension
2608 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2610 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
2611 cdb
->MODE_SENSE
.PageCode
= MODE_SENSE_RETURN_ALL
;
2612 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)modeLength
;
2614 while (retries
!= 0)
2616 status
= ClassSendSrbSynchronous(DeviceObject
,
2622 if (status
!= STATUS_VERIFY_REQUIRED
)
2624 if (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
2626 status
= STATUS_SUCCESS
;
2635 if (NT_SUCCESS(status
))
2637 if (TEST_FLAG(modeData
->DeviceSpecificParameter
, MODE_DSP_WRITE_PROTECT
))
2639 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2643 ExFreePool(modeData
);
2647 case IOCTL_DISK_INTERNAL_SET_VERIFY
: {
2650 // If the caller is kernel mode, set the verify bit.
2653 if (Irp
->RequestorMode
== KernelMode
) {
2655 SET_FLAG(DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
2657 if(commonExtension
->IsFdo
) {
2659 Irp
->IoStatus
.Information
= 0;
2663 DiskInvalidatePartitionTable(fdoExtension
, FALSE
);
2665 status
= STATUS_SUCCESS
;
2669 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
: {
2672 // If the caller is kernel mode, clear the verify bit.
2675 if (Irp
->RequestorMode
== KernelMode
) {
2676 CLEAR_FLAG(DeviceObject
->Flags
, DO_VERIFY_VOLUME
);
2678 status
= STATUS_SUCCESS
;
2682 case IOCTL_DISK_UPDATE_DRIVE_SIZE
: {
2684 DebugPrint((2, "IOCTL_DISK_UPDATE_DRIVE_SIZE to device %p "
2686 DeviceObject
, Irp
));
2688 DebugPrint((2, "Device is a%s.\n",
2689 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2691 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2692 sizeof(DISK_GEOMETRY
)) {
2694 status
= STATUS_BUFFER_TOO_SMALL
;
2695 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
2699 if(!commonExtension
->IsFdo
) {
2702 // Pdo should issue this request to the lower device object.
2705 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2707 SendToFdo(DeviceObject
, Irp
, status
);
2711 DiskAcquirePartitioningLock(fdoExtension
);
2714 // Invalidate the cached partition table.
2717 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
2720 // At this point, commonExtension *is* the FDO extension. This
2721 // should be the same as PartitionZeroExtension.
2724 ASSERT(commonExtension
==
2725 &(commonExtension
->PartitionZeroExtension
->CommonExtension
));
2728 // Issue ReadCapacity to update device extension with information
2729 // for current media.
2732 status
= DiskReadDriveCapacity(DeviceObject
);
2735 // Note whether the drive is ready.
2738 diskData
->ReadyStatus
= status
;
2741 // The disk's partition tables may be invalid after the drive geometry
2742 // has been updated. The call to IoValidatePartitionTable (below) will
2743 // fix it if this is the case.
2746 if (NT_SUCCESS(status
)) {
2748 status
= DiskVerifyPartitionTable (fdoExtension
, TRUE
);
2752 if (NT_SUCCESS(status
)) {
2755 // Copy drive geometry information from the device extension.
2758 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2759 &(fdoExtension
->DiskGeometry
),
2760 sizeof(DISK_GEOMETRY
));
2762 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
2763 status
= STATUS_SUCCESS
;
2767 DiskReleasePartitioningLock(fdoExtension
);
2772 case IOCTL_DISK_GROW_PARTITION
: {
2774 PDISK_GROW_PARTITION inputBuffer
;
2776 // PDEVICE_OBJECT pdo;
2777 PCOMMON_DEVICE_EXTENSION pdoExtension
;
2779 LARGE_INTEGER bytesPerCylinder
;
2780 LARGE_INTEGER newStoppingOffset
;
2781 LARGE_INTEGER newPartitionLength
;
2783 PPHYSICAL_DEVICE_EXTENSION sibling
;
2785 PDRIVE_LAYOUT_INFORMATION_EX layoutInfo
;
2786 PPARTITION_INFORMATION_EX pdoPartition
;
2787 PPARTITION_INFORMATION_EX containerPartition
;
2788 //ULONG partitionIndex;
2790 DebugPrint((2, "IOCTL_DISK_GROW_PARTITION to device %p through "
2792 DeviceObject
, Irp
));
2794 DebugPrint((2, "Device is a%s.\n",
2795 commonExtension
->IsFdo
? "n fdo" : " pdo"));
2797 Irp
->IoStatus
.Information
= 0;
2799 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2800 sizeof(DISK_GROW_PARTITION
)) {
2802 status
= STATUS_INFO_LENGTH_MISMATCH
;
2803 Irp
->IoStatus
.Information
= sizeof(DISK_GROW_PARTITION
);
2807 if(!commonExtension
->IsFdo
) {
2810 // Pdo should issue this request to the lower device object
2813 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2815 SendToFdo(DeviceObject
, Irp
, status
);
2819 DiskAcquirePartitioningLock(fdoExtension
);
2820 ClassAcquireChildLock(fdoExtension
);
2823 // At this point, commonExtension *is* the FDO extension. This should
2824 // be the same as PartitionZeroExtension.
2827 ASSERT(commonExtension
==
2828 &(commonExtension
->PartitionZeroExtension
->CommonExtension
));
2831 // Get the input parameters
2834 inputBuffer
= (PDISK_GROW_PARTITION
) Irp
->AssociatedIrp
.SystemBuffer
;
2836 ASSERT(inputBuffer
);
2839 // Make sure that we are actually being asked to grow the partition.
2842 if(inputBuffer
->BytesToGrow
.QuadPart
== 0) {
2844 status
= STATUS_INVALID_PARAMETER
;
2845 ClassReleaseChildLock(fdoExtension
);
2846 DiskReleasePartitioningLock(fdoExtension
);
2851 // Find the partition that matches the supplied number
2854 pdoExtension
= &commonExtension
->ChildList
->CommonExtension
;
2856 while(pdoExtension
!= NULL
) {
2859 // Is this the partition we are searching for?
2862 if(inputBuffer
->PartitionNumber
== pdoExtension
->PartitionNumber
) {
2866 pdoExtension
= &pdoExtension
->ChildList
->CommonExtension
;
2869 // Did we find the partition?
2871 if(pdoExtension
== NULL
) {
2872 status
= STATUS_INVALID_PARAMETER
;
2873 ClassReleaseChildLock(fdoExtension
);
2874 DiskReleasePartitioningLock(fdoExtension
);
2878 ASSERT(pdoExtension
);
2881 // Compute the new values for the partition to grow.
2884 newPartitionLength
.QuadPart
=
2885 (pdoExtension
->PartitionLength
.QuadPart
+
2886 inputBuffer
->BytesToGrow
.QuadPart
);
2888 newStoppingOffset
.QuadPart
=
2889 (pdoExtension
->StartingOffset
.QuadPart
+
2890 newPartitionLength
.QuadPart
- 1);
2893 // Test the partition alignment before getting to involved.
2896 // All partition stopping offsets should be one byte less
2897 // than a cylinder boundary offset. Also, all first partitions
2898 // (within partition0 and within an extended partition) start
2899 // on the second track while all other partitions start on a
2900 // cylinder boundary.
2902 bytesPerCylinder
.QuadPart
=
2903 ((LONGLONG
) fdoExtension
->DiskGeometry
.TracksPerCylinder
*
2904 (LONGLONG
) fdoExtension
->DiskGeometry
.SectorsPerTrack
*
2905 (LONGLONG
) fdoExtension
->DiskGeometry
.BytesPerSector
);
2907 // Temporarily adjust up to cylinder boundary.
2909 newStoppingOffset
.QuadPart
+= 1;
2911 if(newStoppingOffset
.QuadPart
% bytesPerCylinder
.QuadPart
) {
2913 // Adjust the length first...
2914 newPartitionLength
.QuadPart
-=
2915 (newStoppingOffset
.QuadPart
% bytesPerCylinder
.QuadPart
);
2917 // ...and then the stopping offset.
2918 newStoppingOffset
.QuadPart
-=
2919 (newStoppingOffset
.QuadPart
% bytesPerCylinder
.QuadPart
);
2921 DebugPrint((2, "IOCTL_DISK_GROW_PARTITION: "
2922 "Adjusted the requested partition size to cylinder boundary"));
2925 // Restore to one byte less than a cylinder boundary.
2926 newStoppingOffset
.QuadPart
-= 1;
2929 // Will the new partition fit within Partition0?
2930 // Remember: commonExtension == &PartitionZeroExtension->CommonExtension
2933 if(newStoppingOffset
.QuadPart
>
2934 (commonExtension
->StartingOffset
.QuadPart
+
2935 commonExtension
->PartitionLength
.QuadPart
- 1)) {
2938 // The new partition falls outside Partition0
2941 status
= STATUS_UNSUCCESSFUL
;
2942 ClassReleaseChildLock(fdoExtension
);
2943 DiskReleasePartitioningLock(fdoExtension
);
2948 // Search for any partition that will conflict with the new partition.
2949 // This is done before testing for any containing partitions to
2950 // simplify the container handling.
2953 sibling
= commonExtension
->ChildList
;
2955 while(sibling
!= NULL
) {
2956 //LARGE_INTEGER sibStoppingOffset;
2957 PCOMMON_DEVICE_EXTENSION siblingExtension
;
2959 siblingExtension
= &(sibling
->CommonExtension
);
2961 ASSERT( siblingExtension
);
2963 /* sibStoppingOffset.QuadPart =
2964 (siblingExtension->StartingOffset.QuadPart +
2965 siblingExtension->PartitionLength.QuadPart - 1); */
2968 // Only check the siblings that start beyond the new partition
2969 // starting offset. Also, assume that since the starting offset
2970 // has not changed, it will not be in conflict with any other
2971 // partitions; only the new stopping offset needs to be tested.
2974 if((inputBuffer
->PartitionNumber
!=
2975 siblingExtension
->PartitionNumber
) &&
2977 (siblingExtension
->StartingOffset
.QuadPart
>
2978 pdoExtension
->StartingOffset
.QuadPart
) &&
2980 (newStoppingOffset
.QuadPart
>=
2981 siblingExtension
->StartingOffset
.QuadPart
)) {
2984 // We have a conflict; bail out leaving pdoSibling set.
2989 sibling
= siblingExtension
->ChildList
;
2994 // If there is a sibling that conflicts, it will be in pdoSibling; there
2995 // could be more than one, but this is the first one detected.
2998 if(sibling
!= NULL
) {
3000 // Report the conflict and abort the grow request.
3003 status
= STATUS_UNSUCCESSFUL
;
3004 ClassReleaseChildLock(fdoExtension
);
3005 DiskReleasePartitioningLock(fdoExtension
);
3010 // Read the partition table. Since we're planning on modifying it
3011 // we should bypass the cache.
3014 status
= DiskReadPartitionTableEx(fdoExtension
, TRUE
, &layoutInfo
);
3016 if( !NT_SUCCESS(status
) ) {
3017 ClassReleaseChildLock(fdoExtension
);
3018 DiskReleasePartitioningLock(fdoExtension
);
3022 ASSERT( layoutInfo
);
3025 // Search the layout for the partition that matches the
3030 DiskPdoFindPartitionEntry(
3031 (PPHYSICAL_DEVICE_EXTENSION
) pdoExtension
,
3034 if(pdoPartition
== NULL
) {
3035 // Looks like something is wrong interally-- error ok?
3036 status
= STATUS_DRIVER_INTERNAL_ERROR
;
3038 ClassReleaseChildLock(fdoExtension
);
3039 DiskReleasePartitioningLock(fdoExtension
);
3044 // Search the on-disk partition information to find the root containing
3045 // partition (top-to-bottom).
3047 // Remember: commonExtension == &PartitionZeroExtension->CommonExtension
3051 // All affected containers will have a new stopping offset
3052 // that is equal to the new partition (logical drive)
3053 // stopping offset. Walk the layout information from
3054 // bottom-to-top searching for logical drive containers and
3055 // propagating the change.
3058 containerPartition
=
3059 DiskFindContainingPartition(
3065 // This loop should only execute at most 2 times; once for
3066 // the logical drive container, and once for the root
3067 // extended partition container. If the growing partition
3068 // is not contained, the loop does not run.
3071 while(containerPartition
!= NULL
) {
3072 LARGE_INTEGER containerStoppingOffset
;
3073 PPARTITION_INFORMATION_EX nextContainerPartition
;
3076 // Plan ahead and get the container's container before
3077 // modifying the current size.
3080 nextContainerPartition
=
3081 DiskFindContainingPartition(
3087 // Figure out where the current container ends and test
3088 // to see if it already encompasses the containee.
3091 containerStoppingOffset
.QuadPart
=
3092 (containerPartition
->StartingOffset
.QuadPart
+
3093 containerPartition
->PartitionLength
.QuadPart
- 1);
3095 if(newStoppingOffset
.QuadPart
<=
3096 containerStoppingOffset
.QuadPart
) {
3099 // No need to continue since this container fits
3105 // Adjust the container to have a stopping offset that
3106 // matches the grown partition stopping offset.
3109 containerPartition
->PartitionLength
.QuadPart
=
3110 newStoppingOffset
.QuadPart
+ 1 -
3111 containerPartition
->StartingOffset
.QuadPart
;
3113 containerPartition
->RewritePartition
= TRUE
;
3115 // Continue with the next container
3116 containerPartition
= nextContainerPartition
;
3120 // Wait until after searching the containers to update the
3124 pdoPartition
->PartitionLength
.QuadPart
=
3125 newPartitionLength
.QuadPart
;
3127 pdoPartition
->RewritePartition
= TRUE
;
3130 // Commit the changes to disk
3133 status
= DiskWritePartitionTableEx(fdoExtension
, layoutInfo
);
3135 if( NT_SUCCESS(status
) ) {
3138 // Everything looks good so commit the new length to the
3139 // PDO. This has to be done carefully. We may potentially
3140 // grow the partition in three steps:
3141 // * increase the high-word of the partition length
3142 // to be just below the new size - the high word should
3143 // be greater than or equal to the current length.
3145 // * change the low-word of the partition length to the
3146 // new value - this value may potentially be lower than
3147 // the current value (if the high part was changed which
3148 // is why we changed that first)
3150 // * change the high part to the correct value.
3153 if(newPartitionLength
.HighPart
>
3154 pdoExtension
->PartitionLength
.HighPart
) {
3157 // Swap in one less than the high word.
3160 InterlockedExchange(
3161 &(pdoExtension
->PartitionLength
.HighPart
),
3162 (newPartitionLength
.HighPart
- 1));
3166 // Swap in the low part.
3169 InterlockedExchange(
3170 &(pdoExtension
->PartitionLength
.LowPart
),
3171 newPartitionLength
.LowPart
);
3173 if(newPartitionLength
.HighPart
!=
3174 pdoExtension
->PartitionLength
.HighPart
) {
3177 // Swap in one less than the high word.
3180 InterlockedExchange(
3181 &(pdoExtension
->PartitionLength
.HighPart
),
3182 newPartitionLength
.HighPart
);
3187 // Invalidate and free the cached partition table.
3190 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
3193 // Free the partition buffer regardless of the status
3196 ClassReleaseChildLock(fdoExtension
);
3197 DiskReleasePartitioningLock(fdoExtension
);
3203 case IOCTL_DISK_UPDATE_PROPERTIES
: {
3206 // Invalidate the partition table and re-enumerate the device.
3209 if(DiskInvalidatePartitionTable(fdoExtension
, FALSE
)) {
3210 IoInvalidateDeviceRelations(fdoExtension
->LowerPdo
, BusRelations
);
3212 status
= STATUS_SUCCESS
;
3217 case IOCTL_DISK_MEDIA_REMOVAL
: {
3220 // If the disk is not removable then don't allow this command.
3223 DebugPrint((2, "IOCTL_DISK_MEDIA_REMOVAL to device %p through irp %p\n",
3224 DeviceObject
, Irp
));
3225 DebugPrint((2, "Device is a%s.\n",
3226 commonExtension
->IsFdo
? "n fdo" : " pdo"));
3228 if(!commonExtension
->IsFdo
) {
3229 ClassReleaseRemoveLock(DeviceObject
, Irp
);
3231 SendToFdo(DeviceObject
,Irp
,status
);
3235 if (!TEST_FLAG(DeviceObject
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
3236 status
= STATUS_INVALID_DEVICE_REQUEST
;
3241 // Fall through and let the class driver process the request.
3243 goto defaultHandler
;
3253 // Free the Srb, since it is not needed.
3259 // Pass the request to the common device control routine.
3262 return(ClassDeviceControl(DeviceObject
, Irp
));
3269 Irp
->IoStatus
.Status
= status
;
3271 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3273 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
3276 ClassReleaseRemoveLock(DeviceObject
, Irp
);
3277 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
3281 } // end DiskDeviceControl()
3286 IN PDEVICE_OBJECT DeviceObject
,
3292 Routine Description:
3294 This routine is called for a shutdown and flush IRPs. These are sent by the
3295 system before it actually shuts down or when the file system does a flush.
3296 A synchronize cache command is sent to the device if it is write caching.
3297 If the device is removable an unlock command will be sent. This routine
3298 will sent a shutdown or flush Srb to the port driver.
3302 DriverObject - Pointer to device object to being shutdown by system.
3313 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3314 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= commonExtension
->PartitionZeroExtension
;
3316 PIO_STACK_LOCATION irpStack
;
3317 PSCSI_REQUEST_BLOCK srb
;
3322 // Send partition flush requests to the FDO
3325 if(!commonExtension
->IsFdo
) {
3327 PDEVICE_OBJECT lowerDevice
= commonExtension
->LowerDeviceObject
;
3329 ClassReleaseRemoveLock(DeviceObject
, Irp
);
3330 IoMarkIrpPending(Irp
);
3331 IoCopyCurrentIrpStackLocationToNext(Irp
);
3332 IoCallDriver(lowerDevice
, Irp
);
3333 return STATUS_PENDING
;
3337 // Allocate SCSI request block.
3340 srb
= ExAllocatePoolWithTag(NonPagedPool
,
3341 sizeof(SCSI_REQUEST_BLOCK
),
3347 // Set the status and complete the request.
3350 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3351 ClassReleaseRemoveLock(DeviceObject
, Irp
);
3352 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
3353 return(STATUS_INSUFFICIENT_RESOURCES
);
3356 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3359 // Write length to SRB.
3362 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3365 // Set timeout value and mark the request as not being a tagged request.
3368 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 4;
3369 srb
->QueueTag
= SP_UNTAGGED
;
3370 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3371 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3374 // If the write cache is enabled then send a synchronize cache request.
3377 if (TEST_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
)) {
3379 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3380 srb
->CdbLength
= 10;
3382 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
3384 status
= ClassSendSrbSynchronous(DeviceObject
,
3390 DebugPrint((1, "DiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status
));
3394 // Unlock the device if it is removable and this is a shutdown.
3397 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3399 if (TEST_FLAG(DeviceObject
->Characteristics
, FILE_REMOVABLE_MEDIA
) &&
3400 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
3403 cdb
= (PVOID
) srb
->Cdb
;
3404 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3405 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3408 // Set timeout value.
3411 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3412 status
= ClassSendSrbSynchronous(DeviceObject
,
3418 DebugPrint((1, "DiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3424 // Save a few parameters in the current stack location.
3427 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3428 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3431 // Set the retry count to zero.
3434 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3437 // Set up IoCompletion routine address.
3440 IoSetCompletionRoutine(Irp
, ClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3443 // Get next stack location and
3444 // set major function code.
3447 irpStack
= IoGetNextIrpStackLocation(Irp
);
3449 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3452 // Set up SRB for execute scsi request.
3453 // Save SRB address in next stack for port driver.
3456 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3459 // Set up Irp Address.
3462 srb
->OriginalRequest
= Irp
;
3465 // Call the port driver to process the request.
3468 IoMarkIrpPending(Irp
);
3469 IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
3470 return STATUS_PENDING
;
3471 } // end DiskShutdown()
3476 IN PDEVICE_OBJECT Fdo
,
3477 IN PCHAR ModeSelectBuffer
,
3484 Routine Description:
3486 This routine sends a mode select command.
3490 DeviceObject - Supplies the device object associated with this request.
3492 ModeSelectBuffer - Supplies a buffer containing the page data.
3494 Length - Supplies the length in bytes of the mode select buffer.
3496 SavePage - Indicates that parameters should be written to disk.
3500 Length of the transferred data is returned.
3505 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3507 SCSI_REQUEST_BLOCK srb
;
3512 PMODE_PARAMETER_BLOCK blockDescriptor
;
3518 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3521 // Allocate buffer for mode select header, block descriptor, and mode page.
3524 buffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3526 DISK_TAG_MODE_DATA
);
3528 if(buffer
== NULL
) {
3529 return STATUS_INSUFFICIENT_RESOURCES
;
3532 RtlZeroMemory(buffer
, length2
);
3535 // Set length in header to size of mode page.
3538 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3540 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3546 blockDescriptor
->BlockLength
[1]=0x02;
3549 // Copy mode page to buffer.
3552 RtlCopyMemory(buffer
+ 3, ModeSelectBuffer
, Length
);
3558 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3561 // Build the MODE SELECT CDB.
3565 cdb
= (PCDB
)srb
.Cdb
;
3568 // Set timeout value from device extension.
3571 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
3573 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3574 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3575 cdb
->MODE_SELECT
.PFBit
= 1;
3576 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3580 status
= ClassSendSrbSynchronous(Fdo
,
3586 if (status
== STATUS_VERIFY_REQUIRED
) {
3589 // Routine ClassSendSrbSynchronous does not retry requests returned with
3602 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3603 status
= STATUS_SUCCESS
;
3609 } // end DiskModeSelect()
3612 // This routine is structured as a work-item routine
3617 IN PDEVICE_OBJECT Fdo
,
3618 IN PIO_WORKITEM WorkItem
3622 ULONG specialFlags
= 0;
3623 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
3624 DISK_CACHE_INFORMATION cacheInfo
;
3629 fdoExtension
= Fdo
->DeviceExtension
;
3631 ASSERT(fdoExtension
->CommonExtension
.IsFdo
);
3633 DebugPrint((1, "Disk.DisableWriteCache: Disabling Write Cache\n"));
3635 ClassGetDeviceParameter(fdoExtension
,
3636 DiskDeviceParameterSubkey
,
3637 DiskDeviceSpecialFlags
,
3640 RtlZeroMemory(&cacheInfo
, sizeof(DISK_CACHE_INFORMATION
));
3642 status
= DiskGetCacheInformation(fdoExtension
, &cacheInfo
);
3644 if (NT_SUCCESS(status
) && (cacheInfo
.WriteCacheEnabled
== TRUE
)) {
3646 cacheInfo
.WriteCacheEnabled
= FALSE
;
3648 status
= DiskSetCacheInformation(fdoExtension
, &cacheInfo
);
3650 if (status
== STATUS_INVALID_DEVICE_REQUEST
)
3653 // This device does not allow for
3654 // the write cache to be disabled
3656 SET_FLAG(specialFlags
, HackDisableWriteCacheNotSupported
);
3658 SET_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED
);
3662 // ISSUE ( April 5, 2001 ) : This should happen inside of DiskSetCacheInformation
3664 CLEAR_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
3668 // Set a flag in the registry to help
3669 // identify this device across boots
3671 SET_FLAG(specialFlags
, HackDisableWriteCache
);
3673 SET_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_WRITE_CACHE
);
3675 ClassSetDeviceParameter(fdoExtension
,
3676 DiskDeviceParameterSubkey
,
3677 DiskDeviceSpecialFlags
,
3680 IoFreeWorkItem(WorkItem
);
3684 // This routine is structured as a work-item routine
3689 IN PDEVICE_OBJECT Fdo
,
3690 IN PDISK_VERIFY_WORKITEM_CONTEXT Context
3694 PIRP Irp
= Context
->Irp
;
3695 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
= Fdo
->DeviceExtension
;
3696 PDISK_DATA DiskData
= (PDISK_DATA
)FdoExtension
->CommonExtension
.DriverData
;
3697 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
3698 PSCSI_REQUEST_BLOCK Srb
= Context
->Srb
;
3699 PCDB Cdb
= (PCDB
)Srb
->Cdb
;
3700 LARGE_INTEGER byteOffset
;
3703 NTSTATUS status
= STATUS_SUCCESS
;
3707 ASSERT(FdoExtension
->CommonExtension
.IsFdo
);
3710 // We don't need to hold on to this memory as
3711 // the following operation may take some time
3714 IoFreeWorkItem(Context
->WorkItem
);
3716 DebugPrint((1, "Disk.DiskIoctlVerify: Splitting up the request\n"));
3719 // Add disk offset to starting the sector
3722 byteOffset
.QuadPart
= FdoExtension
->CommonExtension
.StartingOffset
.QuadPart
+
3723 verifyInfo
->StartingOffset
.QuadPart
;
3726 // Convert byte offset to the sector offset
3729 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> FdoExtension
->SectorShift
);
3732 // Convert ULONG byte count to USHORT sector count.
3735 sectorCount
= (USHORT
)(verifyInfo
->Length
>> FdoExtension
->SectorShift
);
3738 // Make sure that all previous verify requests have indeed completed
3739 // This greatly reduces the possibility of a Denial-of-Service attack
3742 KeWaitForMutexObject(&DiskData
->VerifyMutex
,
3748 while (NT_SUCCESS(status
) && (sectorCount
!= 0))
3750 USHORT numSectors
= min(sectorCount
, MAX_SECTORS_PER_VERIFY
);
3752 RtlZeroMemory(Srb
, SCSI_REQUEST_BLOCK_SIZE
);
3754 Srb
->CdbLength
= 10;
3756 Cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
3759 // Move little endian values into CDB in big endian format
3762 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
3763 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
3764 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
3765 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
3767 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&numSectors
)->Byte1
;
3768 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&numSectors
)->Byte0
;
3771 // Calculate the request timeout value based
3772 // on the number of sectors being verified
3775 Srb
->TimeOutValue
= ((numSectors
+ 0x7F) >> 7) * FdoExtension
->TimeOutValue
;
3777 status
= ClassSendSrbSynchronous(Fdo
,
3783 ASSERT(status
!= STATUS_NONEXISTENT_SECTOR
);
3785 sectorCount
-= numSectors
;
3786 sectorOffset
+= numSectors
;
3789 KeReleaseMutex(&DiskData
->VerifyMutex
, FALSE
);
3791 Irp
->IoStatus
.Status
= status
;
3792 Irp
->IoStatus
.Information
= 0;
3794 ClassReleaseRemoveLock(Fdo
, Irp
);
3795 ClassCompleteRequest(Fdo
, Irp
, IO_NO_INCREMENT
);
3798 ExFreePool(Context
);
3803 DiskFdoProcessError(
3805 PSCSI_REQUEST_BLOCK Srb
,
3812 Routine Description:
3814 This routine checks the type of error. If the error indicates an underrun
3815 then indicate the request should be retried.
3819 Fdo - Supplies a pointer to the functional device object.
3821 Srb - Supplies a pointer to the failing Srb.
3823 Status - Status with which the IRP will be completed.
3825 Retry - Indication of whether the request will be retried.
3834 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3835 PCDB cdb
= (PCDB
)(Srb
->Cdb
);
3837 ASSERT(fdoExtension
->CommonExtension
.IsFdo
);
3839 if (*Status
== STATUS_DATA_OVERRUN
&&
3840 ( cdb
->CDB10
.OperationCode
== SCSIOP_WRITE
||
3841 cdb
->CDB10
.OperationCode
== SCSIOP_READ
)) {
3846 // Update the error count for the device.
3849 fdoExtension
->ErrorCount
++;
3851 } else if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
3852 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
3855 // a disk drive should never be busy this long. Reset the scsi bus
3856 // maybe this will clear the condition.
3862 // Update the error count for the device.
3865 fdoExtension
->ErrorCount
++;
3869 BOOLEAN invalidatePartitionTable
= FALSE
;
3872 // See if this might indicate that something on the drive has changed.
3875 if ((Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
3876 (Srb
->SenseInfoBufferLength
>=
3877 FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
))) {
3879 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
3880 ULONG senseKey
= senseBuffer
->SenseKey
& 0xf;
3881 ULONG asc
= senseBuffer
->AdditionalSenseCode
;
3882 ULONG ascq
= senseBuffer
->AdditionalSenseCodeQualifier
;
3886 case SCSI_SENSE_ILLEGAL_REQUEST
: {
3890 case SCSI_ADSENSE_INVALID_CDB
: {
3892 if (((cdb
->CDB10
.OperationCode
== SCSIOP_READ
) ||
3893 (cdb
->CDB10
.OperationCode
== SCSIOP_WRITE
)) &&
3894 (cdb
->CDB10
.ForceUnitAccess
) &&
3895 TEST_FLAG(fdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
)) {
3898 // This device does not permit FUA while
3899 // the DEV_WRITE_CACHE flag is turned on
3902 PIO_WORKITEM workItem
= IoAllocateWorkItem(Fdo
);
3905 IoQueueWorkItem(workItem
,
3906 (PIO_WORKITEM_ROUTINE
)DisableWriteCache
,
3911 cdb
->CDB10
.ForceUnitAccess
= FALSE
;
3917 } // end switch(asc)
3921 case SCSI_SENSE_NOT_READY
: {
3924 case SCSI_ADSENSE_LUN_NOT_READY
: {
3926 case SCSI_SENSEQ_BECOMING_READY
:
3927 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
3928 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE
: {
3929 invalidatePartitionTable
= TRUE
;
3932 } // end switch(ascq)
3936 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
: {
3937 invalidatePartitionTable
= TRUE
;
3940 } // end switch(asc)
3944 case SCSI_SENSE_MEDIUM_ERROR
: {
3945 invalidatePartitionTable
= TRUE
;
3949 case SCSI_SENSE_HARDWARE_ERROR
: {
3950 invalidatePartitionTable
= TRUE
;
3954 case SCSI_SENSE_UNIT_ATTENTION
: {
3955 switch (senseBuffer
->AdditionalSenseCode
) {
3956 case SCSI_ADSENSE_MEDIUM_CHANGED
: {
3957 invalidatePartitionTable
= TRUE
;
3964 case SCSI_SENSE_RECOVERED_ERROR
: {
3965 invalidatePartitionTable
= TRUE
;
3969 } // end switch(senseKey)
3973 // On any exceptional scsi condition which might indicate that the
3974 // device was changed we will flush out the state of the partition
3978 switch (SRB_STATUS(Srb
->SrbStatus
)) {
3979 case SRB_STATUS_INVALID_LUN
:
3980 case SRB_STATUS_INVALID_TARGET_ID
:
3981 case SRB_STATUS_NO_DEVICE
:
3982 case SRB_STATUS_NO_HBA
:
3983 case SRB_STATUS_INVALID_PATH_ID
:
3984 case SRB_STATUS_COMMAND_TIMEOUT
:
3985 case SRB_STATUS_TIMEOUT
:
3986 case SRB_STATUS_SELECTION_TIMEOUT
:
3987 case SRB_STATUS_REQUEST_FLUSHED
:
3988 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
3989 case SRB_STATUS_PARITY_ERROR
:
3990 case SRB_STATUS_ERROR
: {
3991 invalidatePartitionTable
= TRUE
;
3994 } // end switch(Srb->SrbStatus)
3997 if(invalidatePartitionTable
) {
3998 if(DiskInvalidatePartitionTable(fdoExtension
, FALSE
)) {
3999 IoInvalidateDeviceRelations(fdoExtension
->LowerPdo
,
4009 DiskSetSpecialHacks(
4010 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
4016 Routine Description:
4018 This function checks to see if an SCSI logical unit requires special
4023 Fdo - Supplies the device object to be tested.
4025 InquiryData - Supplies the inquiry data returned by the device of interest.
4027 AdapterDescriptor - Supplies the capabilities of the device object.
4036 PDEVICE_OBJECT fdo
= FdoExtension
->DeviceObject
;
4040 DebugPrint((1, "Disk SetSpecialHacks, Setting Hacks %p\n", Data
));
4043 // Found a listed controller. Determine what must be done.
4046 if (TEST_FLAG(Data
, HackDisableTaggedQueuing
)) {
4049 // Disable tagged queuing.
4052 CLEAR_FLAG(FdoExtension
->SrbFlags
, SRB_FLAGS_QUEUE_ACTION_ENABLE
);
4055 if (TEST_FLAG(Data
, HackDisableSynchronousTransfers
)) {
4058 // Disable synchronous data transfers.
4061 SET_FLAG(FdoExtension
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
4065 if (TEST_FLAG(Data
, HackDisableSpinDown
)) {
4068 // Disable spinning down of drives.
4071 SET_FLAG(FdoExtension
->ScanForSpecialFlags
,
4072 CLASS_SPECIAL_DISABLE_SPIN_DOWN
);
4076 if (TEST_FLAG(Data
, HackDisableWriteCache
)) {
4079 // Disable the drive's write cache
4082 SET_FLAG(FdoExtension
->ScanForSpecialFlags
,
4083 CLASS_SPECIAL_DISABLE_WRITE_CACHE
);
4087 if (TEST_FLAG(Data
, HackCauseNotReportableHack
)) {
4089 SET_FLAG(FdoExtension
->ScanForSpecialFlags
,
4090 CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK
);
4093 if (TEST_FLAG(fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
) &&
4094 TEST_FLAG(Data
, HackRequiresStartUnitCommand
)
4098 // this is a list of vendors who require the START_UNIT command
4101 DebugPrint((1, "DiskScanForSpecial (%p) => This unit requires "
4102 " START_UNITS\n", fdo
));
4103 SET_FLAG(FdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
4112 DiskScanRegistryForSpecial(
4113 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
4118 Routine Description:
4120 This function checks the registry to see if the SCSI logical unit
4121 requires special attention.
4125 Fdo - Supplies the device object to be tested.
4134 ULONG specialFlags
= 0;
4138 ClassGetDeviceParameter(FdoExtension
, DiskDeviceParameterSubkey
, DiskDeviceSpecialFlags
, &specialFlags
);
4140 if (TEST_FLAG(specialFlags
, HackDisableWriteCache
))
4143 // This device had previously failed to perform an FUA with the DEV_WRITE_CACHE
4144 // flag turned on. Set a bit to inform DiskStartFdo() to disable the write cache
4147 SET_FLAG(FdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_WRITE_CACHE
);
4150 if (TEST_FLAG(specialFlags
, HackDisableWriteCacheNotSupported
))
4153 // This device does not permit disabling of the write cache
4156 SET_FLAG(FdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED
);
4163 IN PDEVICE_OBJECT Fdo
4168 Routine Description:
4170 This command sends a reset bus command to the SCSI port driver.
4174 Fdo - The functional device object for the logical unit with hardware problem.
4183 PIO_STACK_LOCATION irpStack
;
4186 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
4187 PSCSI_REQUEST_BLOCK srb
;
4188 PCOMPLETION_CONTEXT context
;
4190 DebugPrint((1, "Disk ResetBus: Sending reset bus request to port driver.\n"));
4193 // Allocate Srb from nonpaged pool.
4196 context
= ExAllocatePoolWithTag(NonPagedPool
,
4197 sizeof(COMPLETION_CONTEXT
),
4200 if(context
== NULL
) {
4205 // Save the device object in the context for use by the completion
4209 context
->DeviceObject
= Fdo
;
4210 srb
= &context
->Srb
;
4216 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4219 // Write length to SRB.
4222 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4224 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4227 // Build the asynchronous request to be sent to the port driver.
4228 // Since this routine is called from a DPC the IRP should always be
4232 irp
= IoAllocateIrp(Fdo
->StackSize
, FALSE
);
4235 ExFreePool(context
);
4239 ClassAcquireRemoveLock(Fdo
, irp
);
4241 IoSetCompletionRoutine(irp
,
4242 (PIO_COMPLETION_ROUTINE
)ClassAsynchronousCompletion
,
4248 irpStack
= IoGetNextIrpStackLocation(irp
);
4250 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4252 srb
->OriginalRequest
= irp
;
4255 // Store the SRB address in next stack for port driver.
4258 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4261 // Call the port driver with the IRP.
4264 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp
);
4272 DiskQueryPnpCapabilities(
4273 IN PDEVICE_OBJECT DeviceObject
,
4274 IN PDEVICE_CAPABILITIES Capabilities
4278 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
4279 //PDISK_DATA diskData = commonExtension->DriverData;
4283 ASSERT(DeviceObject
);
4284 ASSERT(Capabilities
);
4286 if(commonExtension
->IsFdo
) {
4287 return STATUS_NOT_IMPLEMENTED
;
4290 //PPHYSICAL_DEVICE_EXTENSION physicalExtension = DeviceObject->DeviceExtension;
4292 Capabilities
->SilentInstall
= 1;
4293 Capabilities
->RawDeviceOK
= 1;
4294 Capabilities
->Address
= commonExtension
->PartitionNumber
;
4296 if(!TEST_FLAG(DeviceObject
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
4299 // Media's not removable, deviceId/DeviceInstance should be
4303 Capabilities
->UniqueID
= 1;
4305 Capabilities
->UniqueID
= 0;
4309 return STATUS_SUCCESS
;
4314 DiskGetCacheInformation(
4315 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
4316 IN PDISK_CACHE_INFORMATION CacheInfo
4320 PMODE_PARAMETER_HEADER modeData
;
4321 PMODE_CACHING_PAGE pageData
;
4329 modeData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4331 DISK_TAG_DISABLE_CACHE
);
4333 if (modeData
== NULL
) {
4335 DebugPrint((1, "DiskGetSetCacheInformation: Unable to allocate mode "
4337 return STATUS_INSUFFICIENT_RESOURCES
;
4340 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
4342 length
= ClassModeSense(FdoExtension
->DeviceObject
,
4345 MODE_SENSE_RETURN_ALL
);
4347 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
4350 // Retry the request in case of a check condition.
4353 length
= ClassModeSense(FdoExtension
->DeviceObject
,
4356 MODE_SENSE_RETURN_ALL
);
4358 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
4361 DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
4363 ExFreePool(modeData
);
4364 return STATUS_IO_DEVICE_ERROR
;
4369 // If the length is greater than length indicated by the mode data reset
4370 // the data to the mode data.
4373 if (length
> (ULONG
) (modeData
->ModeDataLength
+ 1)) {
4374 length
= modeData
->ModeDataLength
+ 1;
4378 // Check to see if the write cache is enabled.
4381 pageData
= ClassFindModePage((PUCHAR
) modeData
,
4387 // Check if valid caching page exists.
4390 if (pageData
== NULL
) {
4391 ExFreePool(modeData
);
4392 return STATUS_NOT_SUPPORTED
;
4396 // Copy the parameters over.
4399 RtlZeroMemory(CacheInfo
, sizeof(DISK_CACHE_INFORMATION
));
4401 CacheInfo
->ParametersSavable
= pageData
->PageSavable
;
4403 CacheInfo
->ReadCacheEnabled
= !(pageData
->ReadDisableCache
);
4404 CacheInfo
->WriteCacheEnabled
= pageData
->WriteCacheEnable
;
4406 CacheInfo
->ReadRetentionPriority
= pageData
->ReadRetensionPriority
;
4407 CacheInfo
->WriteRetentionPriority
= pageData
->WriteRetensionPriority
;
4409 CacheInfo
->DisablePrefetchTransferLength
=
4410 ((pageData
->DisablePrefetchTransfer
[0] << 8) +
4411 pageData
->DisablePrefetchTransfer
[1]);
4413 CacheInfo
->ScalarPrefetch
.Minimum
=
4414 ((pageData
->MinimumPrefetch
[0] << 8) + pageData
->MinimumPrefetch
[1]);
4416 CacheInfo
->ScalarPrefetch
.Maximum
=
4417 ((pageData
->MaximumPrefetch
[0] << 8) + pageData
->MaximumPrefetch
[1]);
4419 if(pageData
->MultiplicationFactor
) {
4420 CacheInfo
->PrefetchScalar
= TRUE
;
4421 CacheInfo
->ScalarPrefetch
.MaximumBlocks
=
4422 ((pageData
->MaximumPrefetchCeiling
[0] << 8) +
4423 pageData
->MaximumPrefetchCeiling
[1]);
4426 ExFreePool(modeData
);
4427 return STATUS_SUCCESS
;
4432 DiskSetCacheInformation(
4433 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
4434 IN PDISK_CACHE_INFORMATION CacheInfo
4438 PMODE_PARAMETER_HEADER modeData
;
4441 PMODE_CACHING_PAGE pageData
;
4450 modeData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4452 DISK_TAG_DISABLE_CACHE
);
4454 if (modeData
== NULL
) {
4456 DebugPrint((1, "DiskSetCacheInformation: Unable to allocate mode "
4458 return STATUS_INSUFFICIENT_RESOURCES
;
4461 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
4463 length
= ClassModeSense(FdoExtension
->DeviceObject
,
4468 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
4471 // Retry the request in case of a check condition.
4474 length
= ClassModeSense(FdoExtension
->DeviceObject
,
4479 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
4482 DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
4484 ExFreePool(modeData
);
4485 return STATUS_IO_DEVICE_ERROR
;
4490 // If the length is greater than length indicated by the mode data reset
4491 // the data to the mode data.
4494 if (length
> (ULONG
) (modeData
->ModeDataLength
+ 1)) {
4495 length
= modeData
->ModeDataLength
+ 1;
4499 // Check to see if the write cache is enabled.
4502 pageData
= ClassFindModePage((PUCHAR
) modeData
,
4508 // Check if valid caching page exists.
4511 if (pageData
== NULL
) {
4512 ExFreePool(modeData
);
4513 return STATUS_NOT_SUPPORTED
;
4517 // Don't touch any of the normal parameters - not all drives actually
4518 // use the correct size of caching mode page. Just change the things
4519 // which the user could have modified.
4522 pageData
->PageSavable
= FALSE
;
4524 pageData
->ReadDisableCache
= !(CacheInfo
->ReadCacheEnabled
);
4525 pageData
->MultiplicationFactor
= CacheInfo
->PrefetchScalar
;
4526 pageData
->WriteCacheEnable
= CacheInfo
->WriteCacheEnabled
;
4528 pageData
->WriteRetensionPriority
= (UCHAR
) CacheInfo
->WriteRetentionPriority
;
4529 pageData
->ReadRetensionPriority
= (UCHAR
) CacheInfo
->ReadRetentionPriority
;
4531 pageData
->DisablePrefetchTransfer
[0] =
4532 (UCHAR
) (CacheInfo
->DisablePrefetchTransferLength
>> 8);
4533 pageData
->DisablePrefetchTransfer
[1] =
4534 (UCHAR
) (CacheInfo
->DisablePrefetchTransferLength
& 0x00ff);
4536 pageData
->MinimumPrefetch
[0] =
4537 (UCHAR
) (CacheInfo
->ScalarPrefetch
.Minimum
>> 8);
4538 pageData
->MinimumPrefetch
[1] =
4539 (UCHAR
) (CacheInfo
->ScalarPrefetch
.Minimum
& 0x00ff);
4541 pageData
->MaximumPrefetch
[0] =
4542 (UCHAR
) (CacheInfo
->ScalarPrefetch
.Maximum
>> 8);
4543 pageData
->MaximumPrefetch
[1] =
4544 (UCHAR
) (CacheInfo
->ScalarPrefetch
.Maximum
& 0x00ff);
4546 if(pageData
->MultiplicationFactor
) {
4548 pageData
->MaximumPrefetchCeiling
[0] =
4549 (UCHAR
) (CacheInfo
->ScalarPrefetch
.MaximumBlocks
>> 8);
4550 pageData
->MaximumPrefetchCeiling
[1] =
4551 (UCHAR
) (CacheInfo
->ScalarPrefetch
.MaximumBlocks
& 0x00ff);
4555 // We will attempt (twice) to issue the mode select with the page.
4559 // First save away the current state of the disk cache so we know what to
4560 // log if the request fails.
4563 if(TEST_FLAG(FdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
)) {
4564 errorCode
= IO_WRITE_CACHE_ENABLED
;
4566 errorCode
= IO_WRITE_CACHE_DISABLED
;
4569 for(i
= 0; i
< 2; i
++) {
4570 status
= DiskModeSelect(FdoExtension
->DeviceObject
,
4572 (pageData
->PageLength
+ 2),
4573 CacheInfo
->ParametersSavable
);
4575 if(NT_SUCCESS(status
)) {
4576 if(CacheInfo
->WriteCacheEnabled
) {
4577 SET_FLAG(FdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
4578 errorCode
= IO_WRITE_CACHE_ENABLED
;
4580 CLEAR_FLAG(FdoExtension
->DeviceFlags
, DEV_WRITE_CACHE
);
4581 errorCode
= IO_WRITE_CACHE_DISABLED
;
4589 PIO_ERROR_LOG_PACKET logEntry
;
4592 // Log the appropriate informational or error entry.
4595 logEntry
= IoAllocateErrorLogEntry(
4596 FdoExtension
->DeviceObject
,
4597 sizeof(IO_ERROR_LOG_PACKET
) + (4 * sizeof(ULONG
)));
4599 if (logEntry
!= NULL
) {
4601 PDISK_DATA diskData
= FdoExtension
->CommonExtension
.DriverData
;
4603 logEntry
->FinalStatus
= status
;
4604 logEntry
->ErrorCode
= errorCode
;
4605 logEntry
->SequenceNumber
= 0;
4606 logEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
4607 logEntry
->IoControlCode
= 0;
4608 logEntry
->RetryCount
= 0;
4609 logEntry
->UniqueErrorValue
= 0x1;
4610 logEntry
->DumpDataSize
= 4;
4612 logEntry
->DumpData
[0] = diskData
->ScsiAddress
.PathId
;
4613 logEntry
->DumpData
[1] = diskData
->ScsiAddress
.TargetId
;
4614 logEntry
->DumpData
[2] = diskData
->ScsiAddress
.Lun
;
4615 logEntry
->DumpData
[3] = CacheInfo
->WriteCacheEnabled
;
4618 // Write the error log packet.
4621 IoWriteErrorLogEntry(logEntry
);
4625 ExFreePool(modeData
);
4629 PPARTITION_INFORMATION_EX
4631 DiskPdoFindPartitionEntry(
4632 IN PPHYSICAL_DEVICE_EXTENSION Pdo
,
4633 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
4637 PCOMMON_DEVICE_EXTENSION commonExtension
= &(Pdo
->CommonExtension
);
4638 ULONG partitionIndex
;
4643 DebugPrint((1, "DiskPdoFindPartitionEntry: Searching layout for "
4644 "matching partition.\n"));
4646 for(partitionIndex
= 0;
4647 partitionIndex
< LayoutInfo
->PartitionCount
;
4650 PPARTITION_INFORMATION_EX partitionInfo
;
4653 // Get the partition entry
4656 partitionInfo
= &LayoutInfo
->PartitionEntry
[partitionIndex
];
4659 // See if it is the one we are looking for...
4662 if( LayoutInfo
->PartitionStyle
== PARTITION_STYLE_MBR
&&
4663 (partitionInfo
->Mbr
.PartitionType
== PARTITION_ENTRY_UNUSED
||
4664 IsContainerPartition(partitionInfo
->Mbr
.PartitionType
)) ) {
4669 if( LayoutInfo
->PartitionStyle
== PARTITION_STYLE_GPT
&&
4670 DiskCompareGuid (&partitionInfo
->Gpt
.PartitionType
, &GUID_NULL
) == 00) {
4675 if( (commonExtension
->StartingOffset
.QuadPart
==
4676 partitionInfo
->StartingOffset
.QuadPart
) &&
4677 (commonExtension
->PartitionLength
.QuadPart
==
4678 partitionInfo
->PartitionLength
.QuadPart
)) {
4684 DebugPrint((1, "DiskPdoFindPartitionEntry: Found matching "
4686 return partitionInfo
;
4693 PPARTITION_INFORMATION_EX
4695 DiskFindAdjacentPartition(
4696 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
,
4697 IN PPARTITION_INFORMATION_EX BasePartition
4700 ULONG partitionIndex
;
4701 LONGLONG baseStoppingOffset
;
4702 LONGLONG adjacentStartingOffset
;
4703 PPARTITION_INFORMATION_EX adjacentPartition
= 0;
4705 ASSERT(LayoutInfo
&& BasePartition
);
4709 DebugPrint((1, "DiskPdoFindAdjacentPartition: Searching layout for adjacent partition.\n"));
4712 // Construct the base stopping offset for comparison
4715 baseStoppingOffset
= (BasePartition
->StartingOffset
.QuadPart
+
4716 BasePartition
->PartitionLength
.QuadPart
-
4719 adjacentStartingOffset
= MAXLONGLONG
;
4721 for(partitionIndex
= 0;
4722 partitionIndex
< LayoutInfo
->PartitionCount
;
4725 PPARTITION_INFORMATION_EX partitionInfo
;
4728 // Get the partition entry
4731 partitionInfo
= &LayoutInfo
->PartitionEntry
[partitionIndex
];
4734 // See if it is the one we are looking for...
4737 if( LayoutInfo
->PartitionStyle
== PARTITION_STYLE_MBR
&&
4738 partitionInfo
->Mbr
.PartitionType
== PARTITION_ENTRY_UNUSED
) {
4743 if( LayoutInfo
->PartitionStyle
== PARTITION_STYLE_GPT
&&
4744 DiskCompareGuid (&partitionInfo
->Gpt
.PartitionType
, &GUID_NULL
) == 00 ) {
4750 if((partitionInfo
->StartingOffset
.QuadPart
> baseStoppingOffset
) &&
4751 (partitionInfo
->StartingOffset
.QuadPart
< adjacentStartingOffset
)) {
4753 // Found a closer neighbor...update and remember.
4754 adjacentPartition
= partitionInfo
;
4756 adjacentStartingOffset
= adjacentPartition
->StartingOffset
.QuadPart
;
4758 DebugPrint((1, "DiskPdoFindAdjacentPartition: Found adjacent "
4762 return adjacentPartition
;
4765 PPARTITION_INFORMATION_EX
4767 DiskFindContainingPartition(
4768 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
,
4769 IN PPARTITION_INFORMATION_EX BasePartition
,
4770 IN BOOLEAN SearchTopToBottom
4775 LONG partitionIndex
;
4780 LONGLONG baseStoppingOffset
;
4781 LONGLONG containerStoppingOffset
;
4783 PPARTITION_INFORMATION_EX partitionInfo
= 0;
4784 PPARTITION_INFORMATION_EX containerPartition
= 0;
4788 ASSERT( LayoutInfo
&& BasePartition
);
4790 DebugPrint((1, "DiskFindContainingPartition: Searching for extended partition.\n"));
4792 if( LayoutInfo
->PartitionCount
!= 0) {
4794 baseStoppingOffset
= (BasePartition
->StartingOffset
.QuadPart
+
4795 BasePartition
->PartitionLength
.QuadPart
- 1);
4798 // Determine the search direction and setup the loop
4800 if(SearchTopToBottom
== TRUE
) {
4803 stopIndex
= LayoutInfo
->PartitionCount
;
4806 startIndex
= LayoutInfo
->PartitionCount
- 1;
4812 // Using the loop parameters, walk the layout information and
4813 // return the first containing partition.
4816 for(partitionIndex
= startIndex
;
4817 partitionIndex
!= stopIndex
;
4818 partitionIndex
+= stepIndex
) {
4821 // Get the next partition entry
4824 partitionInfo
= &LayoutInfo
->PartitionEntry
[partitionIndex
];
4826 containerStoppingOffset
= (partitionInfo
->StartingOffset
.QuadPart
+
4827 partitionInfo
->PartitionLength
.QuadPart
-
4831 // Search for a containing partition without detecting the
4832 // same partition as a container of itself. The starting
4833 // offset of a partition and its container should never be
4834 // the same; however, the stopping offset can be the same.
4838 // NOTE: Container partitions are MBR only.
4841 if((LayoutInfo
->PartitionStyle
== PARTITION_STYLE_MBR
) &&
4842 (IsContainerPartition(partitionInfo
->Mbr
.PartitionType
)) &&
4843 (BasePartition
->StartingOffset
.QuadPart
>
4844 partitionInfo
->StartingOffset
.QuadPart
) &&
4845 (baseStoppingOffset
<= containerStoppingOffset
)) {
4847 containerPartition
= partitionInfo
;
4849 DebugPrint((1, "DiskFindContainingPartition: Found a "
4850 "containing extended partition.\n"));
4857 return containerPartition
;
4862 DiskGetInfoExceptionInformation(
4863 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
4864 IN PMODE_INFO_EXCEPTIONS ReturnPageData
4867 PMODE_PARAMETER_HEADER modeData
;
4868 PMODE_INFO_EXCEPTIONS pageData
;
4876 // ReturnPageData is allocated by the caller
4879 modeData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4881 DISK_TAG_INFO_EXCEPTION
);
4883 if (modeData
== NULL
) {
4885 DebugPrint((1, "DiskGetInfoExceptionInformation: Unable to allocate mode "
4887 return STATUS_INSUFFICIENT_RESOURCES
;
4890 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
4892 length
= ClassModeSense(FdoExtension
->DeviceObject
,
4895 MODE_PAGE_FAULT_REPORTING
);
4897 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
4900 // Retry the request in case of a check condition.
4903 length
= ClassModeSense(FdoExtension
->DeviceObject
,
4906 MODE_PAGE_FAULT_REPORTING
);
4908 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
4911 DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
4913 ExFreePool(modeData
);
4914 return STATUS_IO_DEVICE_ERROR
;
4919 // If the length is greater than length indicated by the mode data reset
4920 // the data to the mode data.
4923 if (length
> (ULONG
) (modeData
->ModeDataLength
+ 1)) {
4924 length
= modeData
->ModeDataLength
+ 1;
4928 // Find the mode page for info exceptions
4931 pageData
= ClassFindModePage((PUCHAR
) modeData
,
4933 MODE_PAGE_FAULT_REPORTING
,
4936 if (pageData
!= NULL
) {
4937 RtlCopyMemory(ReturnPageData
, pageData
, sizeof(MODE_INFO_EXCEPTIONS
));
4938 status
= STATUS_SUCCESS
;
4940 status
= STATUS_NOT_SUPPORTED
;
4943 DebugPrint((3, "DiskGetInfoExceptionInformation: %s support SMART for device %x\n",
4944 NT_SUCCESS(status
) ? "does" : "does not",
4945 FdoExtension
->DeviceObject
));
4948 ExFreePool(modeData
);
4954 DiskSetInfoExceptionInformation(
4955 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
4956 IN PMODE_INFO_EXCEPTIONS PageData
4966 // We will attempt (twice) to issue the mode select with the page.
4967 // Make the setting persistent so that we don't have to turn it back
4968 // on after a bus reset.
4971 for (i
= 0; i
< 2; i
++)
4973 status
= DiskModeSelect(FdoExtension
->DeviceObject
,
4975 sizeof(MODE_INFO_EXCEPTIONS
),
4980 DebugPrint((3, "DiskSetInfoExceptionInformation: %s for device %p\n",
4981 NT_SUCCESS(status
) ? "succeeded" : "failed",
4982 FdoExtension
->DeviceObject
));
4992 DiskQuerySuggestedLinkName(
4993 IN PDEVICE_OBJECT DeviceObject
,
4999 Routine Description:
5001 The routine try to find a suggested link name from registry for Removable
5002 using device object names of NT4 and NT3.51.
5006 DeviceObject - Pointer to driver object created by system.
5016 PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName
;
5017 WCHAR driveLetterNameBuffer
[10];
5018 RTL_QUERY_REGISTRY_TABLE queryTable
[2];
5020 UNICODE_STRING driveLetterName
;
5022 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5023 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
5024 PFUNCTIONAL_DEVICE_EXTENSION p0Extension
= commonExtension
->PartitionZeroExtension
;
5026 PCONFIGURATION_INFORMATION configurationInformation
;
5030 DebugPrint((1, "DISK: IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME to device %#08lx"
5031 " through irp %#08lx\n",
5032 DeviceObject
, Irp
));
5034 DebugPrint((1, " - DeviceNumber %d, - PartitionNumber %d\n",
5035 p0Extension
->DeviceNumber
,
5036 commonExtension
->PartitionNumber
));
5038 if (!TEST_FLAG(DeviceObject
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
5040 status
= STATUS_NOT_FOUND
;
5044 if (commonExtension
->PartitionNumber
== 0) {
5046 status
= STATUS_NOT_FOUND
;
5050 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
5051 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME
)) {
5053 status
= STATUS_INVALID_PARAMETER
;
5057 valueName
= ExAllocatePoolWithTag(PagedPool
,
5062 status
= STATUS_INSUFFICIENT_RESOURCES
;
5067 // Look for a device object name of NT4.
5069 swprintf(valueName
, L
"\\Device\\Harddisk%d\\Partition%d",
5070 p0Extension
->DeviceNumber
,
5071 commonExtension
->PartitionNumber
);
5073 driveLetterName
.Buffer
= driveLetterNameBuffer
;
5074 driveLetterName
.MaximumLength
= 20;
5075 driveLetterName
.Length
= 0;
5077 RtlZeroMemory(queryTable
, 2*sizeof(RTL_QUERY_REGISTRY_TABLE
));
5078 queryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
|
5079 RTL_QUERY_REGISTRY_DIRECT
;
5080 queryTable
[0].Name
= valueName
;
5081 queryTable
[0].EntryContext
= &driveLetterName
;
5083 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
5084 L
"\\Registry\\Machine\\System\\DISK",
5085 queryTable
, NULL
, NULL
);
5087 if (!NT_SUCCESS(status
)) {
5090 // Look for a device object name of NT3.51.
5091 // scsimo.sys on NT3.51 created it as \Device\OpticalDiskX.
5092 // The number X were a serial number from zero on only Removable,
5093 // so we look for it serially without above DeviceNumber and PartitionNumber.
5096 configurationInformation
= IoGetConfigurationInformation();
5097 diskCount
= configurationInformation
->DiskCount
;
5099 for (i
= 0; i
< diskCount
; i
++) {
5100 swprintf(valueName
, L
"\\Device\\OpticalDisk%d",i
);
5102 driveLetterName
.Buffer
= driveLetterNameBuffer
;
5103 driveLetterName
.MaximumLength
= 20;
5104 driveLetterName
.Length
= 0;
5106 RtlZeroMemory(queryTable
, 2*sizeof(RTL_QUERY_REGISTRY_TABLE
));
5107 queryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
|
5108 RTL_QUERY_REGISTRY_DIRECT
;
5109 queryTable
[0].Name
= valueName
;
5110 queryTable
[0].EntryContext
= &driveLetterName
;
5112 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
5113 L
"\\Registry\\Machine\\System\\DISK",
5114 queryTable
, NULL
, NULL
);
5116 if (NT_SUCCESS(status
)) {
5121 if (!NT_SUCCESS(status
)) {
5122 ExFreePool(valueName
);
5127 if (driveLetterName
.Length
!= 4 ||
5128 driveLetterName
.Buffer
[0] < 'A' ||
5129 driveLetterName
.Buffer
[0] > 'Z' ||
5130 driveLetterName
.Buffer
[1] != ':') {
5132 status
= STATUS_NOT_FOUND
;
5133 ExFreePool(valueName
);
5137 suggestedName
= Irp
->AssociatedIrp
.SystemBuffer
;
5138 suggestedName
->UseOnlyIfThereAreNoOtherLinks
= TRUE
;
5139 suggestedName
->NameLength
= 28;
5141 Irp
->IoStatus
.Information
=
5142 FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME
, Name
) + 28;
5144 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
5145 Irp
->IoStatus
.Information
) {
5147 Irp
->IoStatus
.Information
=
5148 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME
);
5149 status
= STATUS_BUFFER_OVERFLOW
;
5150 ExFreePool(valueName
);
5154 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
5155 L
"\\Registry\\Machine\\System\\DISK",
5158 ExFreePool(valueName
);
5160 RtlCopyMemory(suggestedName
->Name
, L
"\\DosDevices\\", 24);
5161 suggestedName
->Name
[12] = driveLetterName
.Buffer
[0];
5162 suggestedName
->Name
[13] = ':';
5171 DiskIoctlCreateDisk(
5172 IN OUT PDEVICE_OBJECT DeviceObject
,
5178 Routine Description:
5180 Handler for IOCTL_DISK_CREATE_DISK ioctl.
5184 DeviceObject - Device object representing a disk that will be created or
5187 Irp - The IRP for this request.
5197 PCOMMON_DEVICE_EXTENSION commonExtension
;
5198 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
5199 PIO_STACK_LOCATION irpStack
;
5200 //PDISK_DATA diskData;
5201 PCREATE_DISK createDiskInfo
;
5206 ASSERT ( DeviceObject
!= NULL
);
5207 ASSERT ( Irp
!= NULL
);
5213 commonExtension
= DeviceObject
->DeviceExtension
;
5214 fdoExtension
= DeviceObject
->DeviceExtension
;
5216 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5217 //diskData = (PDISK_DATA)(commonExtension->DriverData);
5220 ASSERT (commonExtension
->IsFdo
);
5223 // Check the input buffer size.
5226 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
5227 sizeof (CREATE_DISK
) ) {
5229 return STATUS_INFO_LENGTH_MISMATCH
;
5233 // If we are being asked to create a GPT disk on a system that doesn't
5234 // support GPT, fail.
5237 createDiskInfo
= (PCREATE_DISK
)Irp
->AssociatedIrp
.SystemBuffer
;
5239 if (DiskDisableGpt
&&
5240 createDiskInfo
->PartitionStyle
== PARTITION_STYLE_GPT
) {
5242 return STATUS_INVALID_PARAMETER
;
5246 // Call the lower level Io routine to do the dirty work of writing a
5247 // new partition table.
5250 DiskAcquirePartitioningLock(fdoExtension
);
5252 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
5254 status
= IoCreateDisk (
5255 commonExtension
->PartitionZeroExtension
->CommonExtension
.DeviceObject
,
5256 Irp
->AssociatedIrp
.SystemBuffer
5258 DiskReleasePartitioningLock(fdoExtension
);
5259 ClassInvalidateBusRelations(DeviceObject
);
5261 Irp
->IoStatus
.Status
= status
;
5268 DiskIoctlGetDriveLayout(
5269 IN OUT PDEVICE_OBJECT DeviceObject
,
5275 Routine Description:
5277 Handler for IOCTL_DISK_GET_DRIVE_LAYOUT ioctl.
5279 This ioctl has been replace by IOCTL_DISK_GET_DRIVE_LAYOUT_EX.
5283 DeviceObject - Device object representing a disk the layout information
5284 will be obtained for.
5286 Irp - The IRP for this request.
5298 PDRIVE_LAYOUT_INFORMATION partitionList
;
5299 PDRIVE_LAYOUT_INFORMATION_EX partitionListEx
;
5300 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
5301 //PPHYSICAL_DEVICE_EXTENSION pdoExtension;
5302 PCOMMON_DEVICE_EXTENSION commonExtension
;
5303 PIO_STACK_LOCATION irpStack
;
5304 PDISK_DATA diskData
;
5305 //BOOLEAN invalidateBusRelations;
5310 ASSERT ( DeviceObject
);
5317 partitionListEx
= NULL
;
5318 partitionList
= NULL
;
5319 fdoExtension
= DeviceObject
->DeviceExtension
;
5320 commonExtension
= DeviceObject
->DeviceExtension
;
5322 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5323 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
5326 // Issue a read capacity to update the apparent size of the disk.
5329 DiskReadDriveCapacity(fdoExtension
->DeviceObject
);
5331 DiskAcquirePartitioningLock(fdoExtension
);
5333 status
= DiskReadPartitionTableEx(fdoExtension
, FALSE
, &partitionListEx
);
5335 if (!NT_SUCCESS(status
)) {
5336 DiskReleasePartitioningLock(fdoExtension
);
5341 // This ioctl is only supported on MBR partitioned disks. Fail the
5345 if (partitionListEx
->PartitionStyle
!= PARTITION_STYLE_MBR
) {
5346 DiskReleasePartitioningLock(fdoExtension
);
5347 return STATUS_INVALID_DEVICE_REQUEST
;
5352 // The disk layout has been returned in the partitionListEx
5353 // buffer. Determine its size and, if the data will fit
5354 // into the intermediate buffer, return it.
5357 size
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
, PartitionEntry
[0]);
5358 size
+= partitionListEx
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
5360 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
5363 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
5364 Irp
->IoStatus
.Information
= size
;
5366 DiskReleasePartitioningLock(fdoExtension
);
5367 return STATUS_BUFFER_TOO_SMALL
;
5371 // Update the partition device objects and set valid partition
5375 ASSERT(diskData
->UpdatePartitionRoutine
!= NULL
);
5376 diskData
->UpdatePartitionRoutine(DeviceObject
, partitionListEx
);
5379 // Convert the extended drive layout structure to a regular drive layout
5380 // structure to return. DiskConvertExtendedToLayout() allocates pool
5381 // that we must free.
5384 partitionList
= DiskConvertExtendedToLayout(partitionListEx
);
5386 if (partitionList
== NULL
) {
5387 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
5388 DiskReleasePartitioningLock (fdoExtension
);
5389 return STATUS_INSUFFICIENT_RESOURCES
;
5393 // We're done with the extended partition list now.
5396 partitionListEx
= NULL
;
5399 // Copy partition information to system buffer.
5402 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
5406 Irp
->IoStatus
.Information
= size
;
5407 Irp
->IoStatus
.Status
= status
;
5410 // Finally, free the buffer allocated by reading the
5414 ExFreePool(partitionList
);
5415 DiskReleasePartitioningLock(fdoExtension
);
5416 ClassInvalidateBusRelations(DeviceObject
);
5423 DiskIoctlGetDriveLayoutEx(
5424 IN OUT PDEVICE_OBJECT DeviceObject
,
5430 Routine Description:
5432 Handler for IOCTL_DISK_GET_DRIVE_LAYOUT_EX ioctl.
5434 This ioctl replaces IOCTL_DISK_GET_DRIVE_LAYOUT.
5438 DeviceObject - Device object representing a disk the layout information
5439 will be obtained for.
5441 Irp - The IRP for this request.
5453 PDRIVE_LAYOUT_INFORMATION_EX partitionList
;
5454 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
5455 //PPHYSICAL_DEVICE_EXTENSION pdoExtension;
5456 PCOMMON_DEVICE_EXTENSION commonExtension
;
5457 PIO_STACK_LOCATION irpStack
;
5458 PDISK_DATA diskData
;
5459 BOOLEAN invalidateBusRelations
;
5464 ASSERT ( DeviceObject
);
5471 fdoExtension
= DeviceObject
->DeviceExtension
;
5472 //pdoExtension = DeviceObject->DeviceExtension;
5473 commonExtension
= DeviceObject
->DeviceExtension
;
5475 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5476 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
5479 // Issue a read capacity to update the apparent size of the disk.
5482 DiskReadDriveCapacity(fdoExtension
->DeviceObject
);
5485 // Get the drive layout information.
5488 DiskAcquirePartitioningLock (fdoExtension
);
5490 status
= DiskReadPartitionTableEx (fdoExtension
, FALSE
, &partitionList
);
5492 if ( !NT_SUCCESS (status
) ) {
5493 DiskReleasePartitioningLock (fdoExtension
);
5498 // Update the partition device objects and set valid partition
5502 ASSERT(diskData
->UpdatePartitionRoutine
!= NULL
);
5503 diskData
->UpdatePartitionRoutine(DeviceObject
, partitionList
);
5506 size
= FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX
, PartitionEntry
[0]) +
5507 partitionList
->PartitionCount
* sizeof (PARTITION_INFORMATION_EX
);
5511 // If the output buffer is large enough, copy data to the output buffer,
5515 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>=
5518 RtlCopyMemory (Irp
->AssociatedIrp
.SystemBuffer
,
5523 Irp
->IoStatus
.Information
= size
;
5524 Irp
->IoStatus
.Status
= status
;
5525 invalidateBusRelations
= TRUE
;
5529 Irp
->IoStatus
.Information
= size
;
5530 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
5531 status
= STATUS_BUFFER_TOO_SMALL
;
5532 invalidateBusRelations
= FALSE
;
5535 DiskReleasePartitioningLock(fdoExtension
);
5537 if ( invalidateBusRelations
) {
5538 ClassInvalidateBusRelations(DeviceObject
);
5546 DiskIoctlSetDriveLayout(
5547 IN OUT PDEVICE_OBJECT DeviceObject
,
5553 Routine Description:
5555 Handler for IOCTL_DISK_SET_DRIVE_LAYOUT ioctl.
5557 This ioctl has been replaced by IOCTL_DISK_SET_DRIVE_LAYOUT_EX.
5561 DeviceObject - Device object for which partition table should be written.
5573 PDRIVE_LAYOUT_INFORMATION partitionList
;
5574 PDRIVE_LAYOUT_INFORMATION_EX partitionListEx
;
5575 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
5576 //PPHYSICAL_DEVICE_EXTENSION pdoExtension;
5577 PCOMMON_DEVICE_EXTENSION commonExtension
;
5578 PIO_STACK_LOCATION irpStack
;
5579 PDISK_DATA diskData
;
5580 //BOOLEAN invalidateBusRelations;
5582 SIZE_T inputBufferLength
;
5583 SIZE_T outputBufferLength
;
5587 ASSERT ( DeviceObject
);
5594 partitionListEx
= NULL
;
5595 partitionList
= NULL
;
5596 fdoExtension
= DeviceObject
->DeviceExtension
;
5597 //pdoExtension = DeviceObject->DeviceExtension;
5598 commonExtension
= DeviceObject
->DeviceExtension
;
5600 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5601 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
5602 partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
5604 inputBufferLength
= irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
5605 outputBufferLength
= irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
5608 // Update the partition table.
5611 if (inputBufferLength
< sizeof (DRIVE_LAYOUT_INFORMATION
)) {
5613 status
= STATUS_INFO_LENGTH_MISMATCH
;
5614 Irp
->IoStatus
.Information
= sizeof (DRIVE_LAYOUT_INFORMATION
);
5618 DiskAcquirePartitioningLock(fdoExtension
);
5620 listSize
= (partitionList
->PartitionCount
- 1);
5621 listSize
*= sizeof(PARTITION_INFORMATION
);
5622 listSize
+= sizeof(DRIVE_LAYOUT_INFORMATION
);
5624 if (inputBufferLength
< listSize
) {
5627 // The remaining size of the input buffer not big enough to
5628 // hold the additional partition entries
5631 status
= STATUS_INFO_LENGTH_MISMATCH
;
5632 Irp
->IoStatus
.Information
= listSize
;
5633 DiskReleasePartitioningLock(fdoExtension
);
5638 // Convert the partition information structure into an extended
5642 partitionListEx
= DiskConvertLayoutToExtended (partitionList
);
5644 if ( partitionListEx
== NULL
) {
5646 status
= STATUS_INSUFFICIENT_RESOURCES
;
5647 Irp
->IoStatus
.Status
= status
;
5648 DiskReleasePartitioningLock(fdoExtension
);
5653 // Redo all the partition numbers in the partition information
5656 ASSERT(diskData
->UpdatePartitionRoutine
!= NULL
);
5657 diskData
->UpdatePartitionRoutine(DeviceObject
, partitionListEx
);
5660 // Write changes to disk.
5663 status
= DiskWritePartitionTableEx(fdoExtension
, partitionListEx
);
5666 // Update IRP with bytes returned. Make sure we don't claim to be
5667 // returning more bytes than the caller is expecting to get back.
5670 if (NT_SUCCESS (status
)) {
5671 if (outputBufferLength
< listSize
) {
5672 Irp
->IoStatus
.Information
= outputBufferLength
;
5676 Irp
->IoStatus
.Information
= listSize
;
5679 // Also update the partition numbers.
5682 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
5684 PPARTITION_INFORMATION partition
;
5685 PPARTITION_INFORMATION_EX partitionEx
;
5687 partition
= &partitionList
->PartitionEntry
[i
];
5688 partitionEx
= &partitionListEx
->PartitionEntry
[i
];
5689 partition
->PartitionNumber
= partitionEx
->PartitionNumber
;
5695 ExFreePool (partitionListEx
);
5696 DiskReleasePartitioningLock(fdoExtension
);
5697 ClassInvalidateBusRelations(DeviceObject
);
5699 Irp
->IoStatus
.Status
= status
;
5705 DiskIoctlSetDriveLayoutEx(
5706 IN OUT PDEVICE_OBJECT DeviceObject
,
5712 Routine Description:
5714 Handler for IOCTL_DISK_SET_DRIVE_LAYOUT_EX ioctl.
5716 This ioctl replaces IOCTL_DISK_SET_DRIVE_LAYOUT.
5720 DeviceObject - Device object for which partition table should be written.
5733 PDRIVE_LAYOUT_INFORMATION_EX partitionListEx
;
5734 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
5735 PCOMMON_DEVICE_EXTENSION commonExtension
;
5737 PIO_STACK_LOCATION irpStack
;
5738 PDISK_DATA diskData
;
5739 //BOOLEAN invalidateBusRelations;
5741 SIZE_T inputBufferLength
;
5742 SIZE_T outputBufferLength
;
5746 ASSERT ( DeviceObject
);
5753 partitionListEx
= NULL
;
5754 fdoExtension
= DeviceObject
->DeviceExtension
;
5755 commonExtension
= DeviceObject
->DeviceExtension
;
5757 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5758 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
5759 partitionListEx
= Irp
->AssociatedIrp
.SystemBuffer
;
5761 inputBufferLength
= irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
5762 outputBufferLength
= irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
5765 // Update the partition table.
5768 if (inputBufferLength
<
5769 FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX
, PartitionEntry
)) {
5770 status
= STATUS_INFO_LENGTH_MISMATCH
;
5771 Irp
->IoStatus
.Information
=
5772 FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX
, PartitionEntry
);
5776 DiskAcquirePartitioningLock(fdoExtension
);
5778 listSize
= partitionListEx
->PartitionCount
;
5779 listSize
*= sizeof(PARTITION_INFORMATION_EX
);
5780 listSize
+= FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX
, PartitionEntry
);
5782 if (inputBufferLength
< listSize
) {
5785 // The remaining size of the input buffer not big enough to
5786 // hold the additional partition entries
5789 status
= STATUS_INFO_LENGTH_MISMATCH
;
5790 Irp
->IoStatus
.Information
= listSize
;
5791 DiskReleasePartitioningLock(fdoExtension
);
5797 // If the partition count is zero, this is a request to clear
5798 // the partition table.
5801 if (partitionListEx
->PartitionCount
== 0) {
5803 CREATE_DISK CreateDiskInfo
;
5805 RtlZeroMemory (&CreateDiskInfo
, sizeof (CreateDiskInfo
));
5806 CreateDiskInfo
.PartitionStyle
= diskData
->PartitionStyle
;
5807 if (diskData
->PartitionStyle
== PARTITION_STYLE_MBR
) {
5808 CreateDiskInfo
.Mbr
.Signature
= partitionListEx
->Mbr
.Signature
;
5810 ASSERT (diskData
->PartitionStyle
== PARTITION_STYLE_GPT
);
5811 CreateDiskInfo
.Gpt
.DiskId
= partitionListEx
->Gpt
.DiskId
;
5813 // NB: Setting MaxPartitionCount to zero will
5814 // force the GPT partition table writing code
5815 // to use the default minimum for this value.
5817 CreateDiskInfo
.Gpt
.MaxPartitionCount
= 0;
5819 DiskInvalidatePartitionTable(fdoExtension
, TRUE
);
5822 status
= IoCreateDisk(DeviceObject
, &CreateDiskInfo
);
5827 // Redo all the partition numbers in the partition information
5830 ASSERT(diskData
->UpdatePartitionRoutine
!= NULL
);
5831 diskData
->UpdatePartitionRoutine(DeviceObject
, partitionListEx
);
5834 // Write changes to disk.
5837 status
= DiskWritePartitionTableEx(fdoExtension
, partitionListEx
);
5841 // Update IRP with bytes returned. Make sure we don't claim to be
5842 // returning more bytes than the caller is expecting to get back.
5845 if (NT_SUCCESS(status
)) {
5846 if (outputBufferLength
< listSize
) {
5847 Irp
->IoStatus
.Information
= outputBufferLength
;
5849 Irp
->IoStatus
.Information
= listSize
;
5853 DiskReleasePartitioningLock(fdoExtension
);
5854 ClassInvalidateBusRelations(DeviceObject
);
5856 Irp
->IoStatus
.Status
= status
;
5862 DiskIoctlGetPartitionInfo(
5863 IN OUT PDEVICE_OBJECT DeviceObject
,
5869 Routine Description:
5871 Handle the IOCTL_DISK_GET_PARTITION_INFO ioctl. Return the information
5872 about the partition specified by the device object. Note that no
5873 information is ever returned about the size or partition type of the
5874 physical disk, as this doesn't make any sense.
5876 This ioctl has been replaced by IOCTL_DISK_GET_PARTITION_INFO_EX.
5892 PIO_STACK_LOCATION irpStack
;
5893 PDISK_DATA diskData
;
5894 PPARTITION_INFORMATION partitionInfo
;
5895 PFUNCTIONAL_DEVICE_EXTENSION p0Extension
;
5896 PCOMMON_DEVICE_EXTENSION commonExtension
;
5897 PDISK_DATA partitionZeroData
;
5898 NTSTATUS oldReadyStatus
;
5903 ASSERT ( DeviceObject
);
5911 commonExtension
= DeviceObject
->DeviceExtension
;
5912 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5913 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
5914 p0Extension
= commonExtension
->PartitionZeroExtension
;
5915 partitionZeroData
= ((PDISK_DATA
) p0Extension
->CommonExtension
.DriverData
);
5919 // Check that the buffer is large enough.
5922 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
5923 sizeof(PARTITION_INFORMATION
)) {
5925 status
= STATUS_BUFFER_TOO_SMALL
;
5926 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
5931 // Update the geometry in case it has changed
5934 status
= DiskReadDriveCapacity(p0Extension
->DeviceObject
);
5937 // Note whether the drive is ready. If the status has changed then
5941 oldReadyStatus
= InterlockedExchange(
5942 &(partitionZeroData
->ReadyStatus
),
5945 if(partitionZeroData
->ReadyStatus
!= oldReadyStatus
) {
5946 IoInvalidateDeviceRelations(p0Extension
->LowerPdo
,
5950 if(!NT_SUCCESS(status
)) {
5956 // Partition zero, the partition representing the entire disk, is
5957 // special cased. The logic below allows for sending this ioctl to
5958 // a GPT disk only for partition zero. This allows us to obtain
5959 // the size of a GPT disk using Win2k compatible IOCTLs.
5962 if (commonExtension
->PartitionNumber
== 0) {
5964 partitionInfo
= (PPARTITION_INFORMATION
) Irp
->AssociatedIrp
.SystemBuffer
;
5966 partitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
5967 partitionInfo
->StartingOffset
= commonExtension
->StartingOffset
;
5968 partitionInfo
->PartitionLength
= commonExtension
->PartitionLength
;
5969 partitionInfo
->HiddenSectors
= 0;
5970 partitionInfo
->PartitionNumber
= commonExtension
->PartitionNumber
;
5971 partitionInfo
->BootIndicator
= FALSE
;
5972 partitionInfo
->RewritePartition
= FALSE
;
5973 partitionInfo
->RecognizedPartition
= FALSE
;
5978 // We do not support this IOCTL on an EFI partitioned disk
5979 // for any partition other than partition zero.
5982 if (diskData
->PartitionStyle
!= PARTITION_STYLE_MBR
) {
5983 status
= STATUS_INVALID_DEVICE_REQUEST
;
5984 Irp
->IoStatus
.Status
= status
;
5988 DiskEnumerateDevice(p0Extension
->DeviceObject
);
5989 DiskAcquirePartitioningLock(p0Extension
);
5992 partitionInfo
= (PPARTITION_INFORMATION
) Irp
->AssociatedIrp
.SystemBuffer
;
5994 partitionInfo
->PartitionType
= diskData
->Mbr
.PartitionType
;
5995 partitionInfo
->StartingOffset
= commonExtension
->StartingOffset
;
5996 partitionInfo
->PartitionLength
= commonExtension
->PartitionLength
;
5997 partitionInfo
->HiddenSectors
= diskData
->Mbr
.HiddenSectors
;
5998 partitionInfo
->PartitionNumber
= commonExtension
->PartitionNumber
;
5999 partitionInfo
->BootIndicator
= diskData
->Mbr
.BootIndicator
;
6000 partitionInfo
->RewritePartition
= FALSE
;
6001 partitionInfo
->RecognizedPartition
=
6002 IsRecognizedPartition(diskData
->Mbr
.PartitionType
);
6004 DiskReleasePartitioningLock(p0Extension
);
6007 status
= STATUS_SUCCESS
;
6008 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
6015 DiskIoctlGetPartitionInfoEx(
6016 IN OUT PDEVICE_OBJECT DeviceObject
,
6021 PIO_STACK_LOCATION irpStack
;
6022 PDISK_DATA diskData
;
6023 PPARTITION_INFORMATION_EX partitionInfo
;
6024 PFUNCTIONAL_DEVICE_EXTENSION p0Extension
;
6025 PCOMMON_DEVICE_EXTENSION commonExtension
;
6026 PDISK_DATA partitionZeroData
;
6027 NTSTATUS oldReadyStatus
;
6032 ASSERT ( DeviceObject
);
6040 commonExtension
= DeviceObject
->DeviceExtension
;
6041 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6042 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
6043 p0Extension
= commonExtension
->PartitionZeroExtension
;
6044 partitionZeroData
= ((PDISK_DATA
) p0Extension
->CommonExtension
.DriverData
);
6048 // Check that the buffer is large enough.
6051 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
6052 sizeof(PARTITION_INFORMATION_EX
)) {
6054 status
= STATUS_BUFFER_TOO_SMALL
;
6055 Irp
->IoStatus
.Status
= status
;
6056 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
6061 // Update the geometry in case it has changed
6064 status
= DiskReadDriveCapacity(p0Extension
->DeviceObject
);
6067 // Note whether the drive is ready. If the status has changed then
6071 oldReadyStatus
= InterlockedExchange(
6072 &(partitionZeroData
->ReadyStatus
),
6075 if(partitionZeroData
->ReadyStatus
!= oldReadyStatus
) {
6076 IoInvalidateDeviceRelations(p0Extension
->LowerPdo
,
6080 if(!NT_SUCCESS(status
)) {
6085 // If this is something other than partition 0 then do a
6086 // re-enumeration to make sure we've got up-to-date information.
6089 if(commonExtension
->PartitionNumber
!= 0) {
6090 DiskEnumerateDevice(p0Extension
->DeviceObject
);
6091 DiskAcquirePartitioningLock(p0Extension
);
6094 partitionInfo
= (PPARTITION_INFORMATION_EX
) Irp
->AssociatedIrp
.SystemBuffer
;
6096 partitionInfo
->StartingOffset
= commonExtension
->StartingOffset
;
6097 partitionInfo
->PartitionLength
= commonExtension
->PartitionLength
;
6098 partitionInfo
->RewritePartition
= FALSE
;
6099 partitionInfo
->PartitionNumber
= commonExtension
->PartitionNumber
;
6100 partitionInfo
->PartitionStyle
= diskData
->PartitionStyle
;
6102 if ( diskData
->PartitionStyle
== PARTITION_STYLE_MBR
) {
6104 partitionInfo
->Mbr
.PartitionType
= diskData
->Mbr
.PartitionType
;
6105 partitionInfo
->Mbr
.HiddenSectors
= diskData
->Mbr
.HiddenSectors
;
6106 partitionInfo
->Mbr
.BootIndicator
= diskData
->Mbr
.BootIndicator
;
6107 partitionInfo
->Mbr
.RecognizedPartition
=
6108 IsRecognizedPartition(diskData
->Mbr
.PartitionType
);
6113 // ISSUE - 2000/02/09 - math: Review for Partition0.
6114 // Is this correct for Partition0?
6117 partitionInfo
->Gpt
.PartitionType
= diskData
->Efi
.PartitionType
;
6118 partitionInfo
->Gpt
.PartitionId
= diskData
->Efi
.PartitionId
;
6119 partitionInfo
->Gpt
.Attributes
= diskData
->Efi
.Attributes
;
6121 partitionInfo
->Gpt
.Name
,
6122 diskData
->Efi
.PartitionName
,
6123 sizeof (partitionInfo
->Gpt
.Name
)
6127 status
= STATUS_SUCCESS
;
6128 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
6130 if(commonExtension
->PartitionNumber
!= 0) {
6131 DiskReleasePartitioningLock(p0Extension
);
6139 DiskIoctlGetLengthInfo(
6140 IN OUT PDEVICE_OBJECT DeviceObject
,
6145 PIO_STACK_LOCATION irpStack
;
6146 //PDISK_DATA diskData;
6147 PGET_LENGTH_INFORMATION lengthInfo
;
6148 PFUNCTIONAL_DEVICE_EXTENSION p0Extension
;
6149 PCOMMON_DEVICE_EXTENSION commonExtension
;
6150 PDISK_DATA partitionZeroData
;
6151 NTSTATUS oldReadyStatus
;
6156 ASSERT ( DeviceObject
);
6164 commonExtension
= DeviceObject
->DeviceExtension
;
6165 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6166 //diskData = (PDISK_DATA)(commonExtension->DriverData);
6167 p0Extension
= commonExtension
->PartitionZeroExtension
;
6168 partitionZeroData
= ((PDISK_DATA
) p0Extension
->CommonExtension
.DriverData
);
6172 // Check that the buffer is large enough.
6175 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
6176 sizeof(GET_LENGTH_INFORMATION
)) {
6178 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
6179 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
6180 return STATUS_BUFFER_TOO_SMALL
;
6184 // Update the geometry in case it has changed
6187 status
= DiskReadDriveCapacity(p0Extension
->DeviceObject
);
6190 // Note whether the drive is ready. If the status has changed then
6194 oldReadyStatus
= InterlockedExchange(
6195 &(partitionZeroData
->ReadyStatus
),
6198 if(partitionZeroData
->ReadyStatus
!= oldReadyStatus
) {
6199 IoInvalidateDeviceRelations(p0Extension
->LowerPdo
,
6203 if(!NT_SUCCESS(status
)) {
6208 // If this is something other than partition 0 then do a
6209 // re-enumeration to make sure we've got up-to-date information.
6212 if(commonExtension
->PartitionNumber
!= 0) {
6213 DiskEnumerateDevice(p0Extension
->DeviceObject
);
6214 DiskAcquirePartitioningLock(p0Extension
);
6217 lengthInfo
= (PGET_LENGTH_INFORMATION
) Irp
->AssociatedIrp
.SystemBuffer
;
6219 lengthInfo
->Length
= commonExtension
->PartitionLength
;
6221 status
= STATUS_SUCCESS
;
6222 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
6224 if(commonExtension
->PartitionNumber
!= 0) {
6225 DiskReleasePartitioningLock(p0Extension
);
6233 DiskIoctlSetPartitionInfo(
6234 IN OUT PDEVICE_OBJECT DeviceObject
,
6239 PSET_PARTITION_INFORMATION inputBuffer
;
6240 PDISK_DATA diskData
;
6241 PIO_STACK_LOCATION irpStack
;
6242 PCOMMON_DEVICE_EXTENSION commonExtension
;
6247 ASSERT ( DeviceObject
!= NULL
);
6248 ASSERT ( Irp
!= NULL
);
6255 commonExtension
= DeviceObject
->DeviceExtension
;
6256 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6257 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
6258 inputBuffer
= (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
6260 if(commonExtension
->IsFdo
) {
6262 return STATUS_UNSUCCESSFUL
;
6266 if (diskData
->PartitionStyle
!= PARTITION_STYLE_MBR
) {
6267 return STATUS_INVALID_DEVICE_REQUEST
;
6271 // Validate buffer length
6274 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
6275 sizeof(SET_PARTITION_INFORMATION
)) {
6277 return STATUS_INFO_LENGTH_MISMATCH
;
6280 DiskAcquirePartitioningLock(commonExtension
->PartitionZeroExtension
);
6283 // The HAL routines IoGet- and IoSetPartitionInformation were
6284 // developed before support of dynamic partitioning and therefore
6285 // don't distinguish between partition ordinal (that is the order
6286 // of a partition on a disk) and the partition number. (The
6287 // partition number is assigned to a partition to identify it to
6288 // the system.) Use partition ordinals for these legacy calls.
6291 status
= DiskSetPartitionInformation(
6292 commonExtension
->PartitionZeroExtension
,
6293 commonExtension
->PartitionZeroExtension
->DiskGeometry
.BytesPerSector
,
6294 diskData
->PartitionOrdinal
,
6295 inputBuffer
->PartitionType
);
6297 if(NT_SUCCESS(status
)) {
6299 diskData
->Mbr
.PartitionType
= inputBuffer
->PartitionType
;
6302 DiskReleasePartitioningLock(commonExtension
->PartitionZeroExtension
);
6309 DiskIoctlSetPartitionInfoEx(
6310 IN OUT PDEVICE_OBJECT DeviceObject
,
6315 PSET_PARTITION_INFORMATION_EX inputBuffer
;
6316 PDISK_DATA diskData
;
6317 PIO_STACK_LOCATION irpStack
;
6318 PCOMMON_DEVICE_EXTENSION commonExtension
;
6323 ASSERT ( DeviceObject
!= NULL
);
6324 ASSERT ( Irp
!= NULL
);
6331 commonExtension
= DeviceObject
->DeviceExtension
;
6332 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
6333 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
6334 inputBuffer
= (PSET_PARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
6336 if(commonExtension
->IsFdo
) {
6338 return STATUS_UNSUCCESSFUL
;
6342 // Validate buffer length
6345 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
6346 sizeof(SET_PARTITION_INFORMATION_EX
)) {
6348 return STATUS_INFO_LENGTH_MISMATCH
;
6351 DiskAcquirePartitioningLock(commonExtension
->PartitionZeroExtension
);
6354 // The HAL routines IoGet- and IoSetPartitionInformation were
6355 // developed before support of dynamic partitioning and therefore
6356 // don't distinguish between partition ordinal (that is the order
6357 // of a partition on a disk) and the partition number. (The
6358 // partition number is assigned to a partition to identify it to
6359 // the system.) Use partition ordinals for these legacy calls.
6362 status
= DiskSetPartitionInformationEx(
6363 commonExtension
->PartitionZeroExtension
,
6364 diskData
->PartitionOrdinal
,
6368 if(NT_SUCCESS(status
)) {
6370 if (diskData
->PartitionStyle
== PARTITION_STYLE_MBR
) {
6372 diskData
->Mbr
.PartitionType
= inputBuffer
->Mbr
.PartitionType
;
6376 ASSERT ( diskData
->PartitionStyle
== PARTITION_STYLE_MBR
);
6378 diskData
->Efi
.PartitionType
= inputBuffer
->Gpt
.PartitionType
;
6379 diskData
->Efi
.PartitionId
= inputBuffer
->Gpt
.PartitionId
;
6380 diskData
->Efi
.Attributes
= inputBuffer
->Gpt
.Attributes
;
6383 diskData
->Efi
.PartitionName
,
6384 inputBuffer
->Gpt
.Name
,
6385 sizeof (diskData
->Efi
.PartitionName
)
6390 DiskReleasePartitioningLock(commonExtension
->PartitionZeroExtension
);
6395 typedef struct _DISK_GEOMETRY_EX_INTERNAL
{
6396 DISK_GEOMETRY Geometry
;
6397 LARGE_INTEGER DiskSize
;
6398 DISK_PARTITION_INFO Partition
;
6399 DISK_DETECTION_INFO Detection
;
6400 } DISK_GEOMETRY_EX_INTERNAL
, *PDISK_GEOMETRY_EX_INTERNAL
;
6405 DiskIoctlGetDriveGeometryEx(
6406 IN PDEVICE_OBJECT DeviceObject
,
6412 Routine Description:
6414 Obtain the extended geometry information for the drive.
6418 DeviceObject - The device object to obtain the geometry for.
6420 Irp - IRP with a return buffer large enough to receive the
6421 extended geometry information.
6431 PIO_STACK_LOCATION irpStack
;
6432 PCOMMON_DEVICE_EXTENSION commonExtension
;
6433 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
6434 PDISK_DATA diskData
;
6435 PDISK_GEOMETRY_EX_INTERNAL geometryEx
;
6436 ULONG OutputBufferLength
;
6444 ASSERT ( DeviceObject
!= NULL
);
6445 ASSERT ( Irp
!= NULL
);
6451 commonExtension
= DeviceObject
->DeviceExtension
;
6452 fdoExtension
= DeviceObject
->DeviceExtension
;
6453 diskData
= (PDISK_DATA
)(commonExtension
->DriverData
);
6454 irpStack
= IoGetCurrentIrpStackLocation ( Irp
);
6456 OutputBufferLength
= irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
6459 // This is only valid for the FDO.
6462 ASSERT ( commonExtension
->IsFdo
);
6465 // Check that the buffer is large enough. It must be large enough
6466 // to hold at lest the Geometry and DiskSize fields of of the
6467 // DISK_GEOMETRY_EX structure.
6470 if ( OutputBufferLength
< FIELD_OFFSET (DISK_GEOMETRY_EX
, Data
) ) {
6473 // Buffer too small. Bail out, telling the caller the required
6477 status
= STATUS_BUFFER_TOO_SMALL
;
6478 Irp
->IoStatus
.Status
= FIELD_OFFSET (DISK_GEOMETRY_EX
, Data
);
6482 if (TEST_FLAG (DeviceObject
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
6485 // Issue a ReadCapacity to update device extension
6486 // with information for the current media.
6489 status
= DiskReadDriveCapacity (
6490 commonExtension
->PartitionZeroExtension
->DeviceObject
);
6492 diskData
->ReadyStatus
= status
;
6494 if (!NT_SUCCESS (status
)) {
6500 // Copy drive geometry.
6503 geometryEx
= (PDISK_GEOMETRY_EX_INTERNAL
)Irp
->AssociatedIrp
.SystemBuffer
;
6504 geometryEx
->Geometry
= fdoExtension
->DiskGeometry
;
6505 geometryEx
->DiskSize
= commonExtension
->PartitionZeroExtension
->CommonExtension
.PartitionLength
;
6508 // If the user buffer is large enough to hold the partition information
6509 // then add that as well.
6512 if (OutputBufferLength
>= FIELD_OFFSET (DISK_GEOMETRY_EX_INTERNAL
, Detection
)) {
6514 geometryEx
->Partition
.SizeOfPartitionInfo
= sizeof (geometryEx
->Partition
);
6515 geometryEx
->Partition
.PartitionStyle
= diskData
->PartitionStyle
;
6517 switch ( diskData
->PartitionStyle
) {
6519 case PARTITION_STYLE_GPT
:
6522 // Copy GPT signature.
6525 geometryEx
->Partition
.Gpt
.DiskId
= diskData
->Efi
.DiskId
;
6528 case PARTITION_STYLE_MBR
:
6531 // Copy MBR signature and checksum.
6534 geometryEx
->Partition
.Mbr
.Signature
= diskData
->Mbr
.Signature
;
6535 geometryEx
->Partition
.Mbr
.CheckSum
= diskData
->Mbr
.MbrCheckSum
;
6541 // This is a raw disk. Zero out the signature area so
6542 // nobody gets confused.
6546 &geometryEx
->Partition
,
6547 sizeof (geometryEx
->Partition
));
6552 // If the buffer is large enough to hold the detection information,
6553 // then also add that.
6556 if (OutputBufferLength
>= sizeof (DISK_GEOMETRY_EX_INTERNAL
)) {
6558 geometryEx
->Detection
.SizeOfDetectInfo
=
6559 sizeof (geometryEx
->Detection
);
6561 status
= DiskGetDetectInfo (
6563 &geometryEx
->Detection
);
6566 // Failed to obtain detection information, set to none.
6569 if (!NT_SUCCESS (status
)) {
6570 geometryEx
->Detection
.DetectionType
= DetectNone
;
6575 status
= STATUS_SUCCESS
;
6576 Irp
->IoStatus
.Information
= min (OutputBufferLength
,
6577 sizeof (DISK_GEOMETRY_EX_INTERNAL
));