2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/disk/disk.c
5 * PURPOSE: Disk class driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
15 #include <include/class2.h>
21 #define IO_WRITE_CACHE_ENABLED ((NTSTATUS)0x80040020L)
22 #define IO_WRITE_CACHE_DISABLED ((NTSTATUS)0x80040022L)
28 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
35 } PARTITION_LIST_STATE
;
41 typedef struct _DISK_DATA
{
47 PDEVICE_EXTENSION NextPartition
;
50 // Disk signature (from MBR)
62 // Number of hidden sectors for BPB.
68 // Partition number of this device object
70 // This field is set during driver initialization or when the partition
71 // is created to identify a parition to the system.
74 ULONG PartitionNumber
;
77 // This field is the ordinal of a partition as it appears on a disk.
80 ULONG PartitionOrdinal
;
83 // Partition type of this device object
85 // This field is set by:
87 // 1) Initially set according to the partition list entry partition
88 // type returned by IoReadPartitionTable.
90 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
91 // I/O control function when IoSetPartitionInformation function
92 // successfully updates the partition type on the disk.
98 // Boot indicator - indicates whether this partition is a bootable (active)
99 // partition for this device
101 // This field is set according to the partition list entry boot indicator
102 // returned by IoReadPartitionTable.
105 BOOLEAN BootIndicator
;
108 // DriveNotReady - inidicates that the this device is currenly not ready
109 // because there is no media in the device.
112 BOOLEAN DriveNotReady
;
115 // State of PartitionList initialization
118 PARTITION_LIST_STATE PartitionListState
;
120 } DISK_DATA
, *PDISK_DATA
;
123 // Define a general structure of identfing disk controllers with bad
127 typedef struct _BAD_CONTROLLER_INFORMATION
{
129 BOOLEAN DisableTaggedQueuing
;
130 BOOLEAN DisableSynchronousTransfers
;
131 BOOLEAN DisableDisconnects
;
132 BOOLEAN DisableWriteCache
;
133 }BAD_CONTROLLER_INFORMATION
, *PBAD_CONTROLLER_INFORMATION
;
135 BAD_CONTROLLER_INFORMATION
const ScsiDiskBadControllers
[] = {
136 { "TOSHIBA MK538FB 60", TRUE
, FALSE
, FALSE
, FALSE
},
137 { "CONNER CP3500", FALSE
, TRUE
, FALSE
, FALSE
},
138 { "OLIVETTICP3500", FALSE
, TRUE
, FALSE
, FALSE
},
139 { "SyQuest SQ5110 CHC", TRUE
, TRUE
, FALSE
, FALSE
},
140 { "SEAGATE ST41601N 0102", FALSE
, TRUE
, FALSE
, FALSE
},
141 { "SEAGATE ST3655N", FALSE
, FALSE
, FALSE
, TRUE
},
142 { "SEAGATE ST3390N", FALSE
, FALSE
, FALSE
, TRUE
},
143 { "SEAGATE ST12550N", FALSE
, FALSE
, FALSE
, TRUE
},
144 { "SEAGATE ST32430N", FALSE
, FALSE
, FALSE
, TRUE
},
145 { "SEAGATE ST31230N", FALSE
, FALSE
, FALSE
, TRUE
},
146 { "SEAGATE ST15230N", FALSE
, FALSE
, FALSE
, TRUE
},
147 { "FUJITSU M2652S-512", TRUE
, FALSE
, FALSE
, FALSE
},
148 { "MAXTOR MXT-540SL I1.2", TRUE
, FALSE
, FALSE
, FALSE
},
149 { "COMPAQ PD-1", FALSE
, TRUE
, FALSE
, FALSE
}
153 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
154 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
156 #define MODE_DATA_SIZE 192
157 #define VALUE_BUFFER_SIZE 2048
158 #define SCSI_DISK_TIMEOUT 10
159 #define PARTITION0_LIST_SIZE 4
165 IN PDRIVER_OBJECT DriverObject
,
166 IN PUNICODE_STRING RegistryPath
171 ScsiDiskDeviceVerification(
172 IN PINQUIRYDATA InquiryData
178 IN PDRIVER_OBJECT DriveObject
,
179 IN PUNICODE_STRING RegistryPath
,
180 IN PCLASS_INIT_DATA InitializationData
,
181 IN PDEVICE_OBJECT PortDeviceObject
,
187 ScsiDiskCreateClose (
188 IN PDEVICE_OBJECT DeviceObject
,
194 ScsiDiskReadWriteVerification(
195 IN PDEVICE_OBJECT DeviceObject
,
201 ScsiDiskDeviceControl(
202 IN PDEVICE_OBJECT DeviceObject
,
208 ScsiDiskProcessError(
209 PDEVICE_OBJECT DeviceObject
,
210 PSCSI_REQUEST_BLOCK Srb
,
217 ScsiDiskShutdownFlush(
218 IN PDEVICE_OBJECT DeviceObject
,
225 IN PDEVICE_OBJECT DeviceObject
,
226 IN PSCSI_INQUIRY_DATA LunInfo
232 IN PDEVICE_OBJECT DeviceObject
,
233 IN PCHAR ModeSelectBuffer
,
241 IN PDEVICE_OBJECT DeviceObject
246 CalculateMbrCheckSum(
247 IN PDEVICE_EXTENSION DeviceExtension
,
254 IN PDEVICE_EXTENSION DeviceExtension
,
262 IN PDEVICE_EXTENSION DeviceExtension
267 UpdateRemovableGeometry (
268 IN PDEVICE_OBJECT DeviceObject
,
274 CreateDiskDeviceObject(
275 IN PDRIVER_OBJECT DriverObject
,
276 IN PUNICODE_STRING RegistryPath
,
277 IN PDEVICE_OBJECT PortDeviceObject
,
279 IN PULONG DeviceCount
,
280 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
281 IN PSCSI_INQUIRY_DATA LunInfo
,
282 IN PCLASS_INIT_DATA InitData
287 CreatePartitionDeviceObjects(
288 IN PDEVICE_OBJECT PhysicalDeviceObject
,
289 IN PUNICODE_STRING RegistryPath
295 IN PDEVICE_OBJECT DeviceObject
,
302 PDEVICE_OBJECT DeviceObject
,
303 PSCSI_INQUIRY_DATA LunInfo
,
304 PIO_SCSI_CAPABILITIES PortCapabilities
310 IN PDEVICE_OBJECT DeviceObject
315 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject
,
319 #pragma alloc_text(PAGE, DriverEntry)
320 #pragma alloc_text(PAGE, FindScsiDisks)
321 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
322 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
323 #pragma alloc_text(PAGE, EnumerateBusKey)
324 #pragma alloc_text(PAGE, UpdateGeometry)
325 #pragma alloc_text(PAGE, IsFloppyDevice)
326 #pragma alloc_text(PAGE, ScanForSpecial)
327 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
328 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
335 IN PDRIVER_OBJECT DriverObject
,
336 IN PUNICODE_STRING RegistryPath
343 This routine initializes the SCSI hard disk class driver.
347 DriverObject - Pointer to driver object created by system.
349 RegistryPath - Pointer to the name of the services node for this driver.
353 The function value is the final status from the initialization operation.
358 CLASS_INIT_DATA InitializationData
;
364 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
370 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
371 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
373 InitializationData
.DeviceType
= FILE_DEVICE_DISK
;
374 InitializationData
.DeviceCharacteristics
= 0;
380 InitializationData
.ClassError
= ScsiDiskProcessError
;
381 InitializationData
.ClassReadWriteVerification
= ScsiDiskReadWriteVerification
;
382 InitializationData
.ClassFindDevices
= FindScsiDisks
;
383 InitializationData
.ClassFindDeviceCallBack
= ScsiDiskDeviceVerification
;
384 InitializationData
.ClassDeviceControl
= ScsiDiskDeviceControl
;
385 InitializationData
.ClassShutdownFlush
= ScsiDiskShutdownFlush
;
386 InitializationData
.ClassCreateClose
= NULL
;
389 // HACK! Please check below to the implementation of the function
391 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = ScsiDiskFileSystemControl
;
394 // Call the class init routine
397 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
399 } // end DriverEntry()
405 ScsiDiskDeviceVerification(
406 IN PINQUIRYDATA InquiryData
413 This routine checks InquiryData for the correct device type and qualifier.
417 InquiryData - Pointer to the inquiry data for the device in question.
421 True is returned if the correct device type is found.
426 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
427 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
428 InquiryData
->DeviceTypeQualifier
== 0) {
441 IN PDRIVER_OBJECT DriverObject
,
442 IN PUNICODE_STRING RegistryPath
,
443 IN PCLASS_INIT_DATA InitializationData
,
444 IN PDEVICE_OBJECT PortDeviceObject
,
452 This routine gets a port drivers capabilities, obtains the
453 inquiry data, searches the SCSI bus for the port driver and creates
454 the device objects for the disks found.
458 DriverObject - Pointer to driver object created by system.
460 PortDeviceObject - Device object use to send requests to port driver.
462 PortNumber - Number for port driver. Used to pass on to
463 CreateDiskDeviceObjects() and create device objects.
467 True is returned if one disk was found and successfully created.
472 PIO_SCSI_CAPABILITIES portCapabilities
;
474 PCONFIGURATION_INFORMATION configurationInformation
;
476 PSCSI_INQUIRY_DATA lunInfo
;
477 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
478 PINQUIRYDATA inquiryData
;
482 BOOLEAN foundOne
= FALSE
;
487 // Call port driver to get adapter capabilities.
490 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
492 if (!NT_SUCCESS(status
)) {
493 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
498 // Call port driver to get inquiry information to find disks.
501 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
503 if (!NT_SUCCESS(status
)) {
504 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
509 // Do a quick scan of the devices on this adapter to determine how many
510 // disks are on this adapter. This is used to determine the number of
511 // SRB zone elements to allocate.
515 adapterInfo
= (PVOID
) buffer
;
517 adapterDisk
= ScsiClassFindUnclaimedDevices(InitializationData
, adapterInfo
);
520 // Allocate a zone of SRB for disks on this adapter.
523 if (adapterDisk
== 0) {
526 // No free disks were found.
533 // Get the number of disks already initialized.
536 configurationInformation
= IoGetConfigurationInformation();
537 diskCount
= &configurationInformation
->DiskCount
;
540 // For each SCSI bus this adapter supports ...
543 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
546 // Get the SCSI bus scan data for this bus.
549 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
552 // Search list for unclaimed disk devices.
555 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
557 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
559 if (((inquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
560 (inquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
561 inquiryData
->DeviceTypeQualifier
== 0 &&
562 (!lunInfo
->DeviceClaimed
)) {
565 "FindScsiDevices: Vendor string is %.24s\n",
566 inquiryData
->VendorId
));
569 // Create device objects for disk
572 status
= CreateDiskDeviceObject(DriverObject
,
581 if (NT_SUCCESS(status
)) {
584 // Increment system disk device count.
597 if (lunInfo
->NextInquiryDataOffset
== 0) {
601 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
607 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
614 } // end FindScsiDisks()
619 CreateDiskDeviceObject(
620 IN PDRIVER_OBJECT DriverObject
,
621 IN PUNICODE_STRING RegistryPath
,
622 IN PDEVICE_OBJECT PortDeviceObject
,
624 IN PULONG DeviceCount
,
625 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
626 IN PSCSI_INQUIRY_DATA LunInfo
,
627 IN PCLASS_INIT_DATA InitData
634 This routine creates an object for the physical device and then searches
635 the device for partitions and creates an object for each partition.
639 DriverObject - Pointer to driver object created by system.
641 PortDeviceObject - Miniport device object.
643 PortNumber - port number. Used in creating disk objects.
645 DeviceCount - Number of previously installed devices.
647 PortCapabilities - Capabilities of this SCSI port.
649 LunInfo - LUN specific information.
657 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
659 UNICODE_STRING ntUnicodeString
;
660 OBJECT_ATTRIBUTES objectAttributes
;
663 PDEVICE_OBJECT deviceObject
= NULL
;
664 //PDEVICE_OBJECT physicalDevice;
665 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
666 PDEVICE_EXTENSION deviceExtension
= NULL
;
667 //PDEVICE_EXTENSION physicalDeviceExtension;
668 UCHAR pathId
= LunInfo
->PathId
;
669 UCHAR targetId
= LunInfo
->TargetId
;
670 UCHAR lun
= LunInfo
->Lun
;
671 //BOOLEAN writeCache;
672 PVOID senseData
= NULL
;
675 BOOLEAN srbListInitialized
= FALSE
;
681 // Set up an object directory to contain the objects for this
682 // device and all its partitions.
685 sprintf(ntNameBuffer
,
686 "\\Device\\Harddisk%lu",
689 RtlInitString(&ntNameString
,
692 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
696 if (!NT_SUCCESS(status
)) {
700 InitializeObjectAttributes(&objectAttributes
,
702 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
706 status
= ZwCreateDirectoryObject(&handle
,
707 DIRECTORY_ALL_ACCESS
,
710 RtlFreeUnicodeString(&ntUnicodeString
);
712 if (!NT_SUCCESS(status
)) {
715 "CreateDiskDeviceObjects: Could not create directory %s\n",
725 status
= ScsiClassClaimDevice(PortDeviceObject
,
730 if (!NT_SUCCESS(status
)) {
731 ZwMakeTemporaryObject(handle
);
737 // Create a device object for this device. Each physical disk will
738 // have at least one device object. The required device object
739 // describes the entire device. Its directory path is
740 // \Device\HarddiskN\Partition0, where N = device number.
743 sprintf(ntNameBuffer
,
744 "\\Device\\Harddisk%lu\\Partition0",
748 status
= ScsiClassCreateDeviceObject(DriverObject
,
754 if (!NT_SUCCESS(status
)) {
757 "CreateDiskDeviceObjects: Can not create device object %s\n",
760 goto CreateDiskDeviceObjectsExit
;
764 // Indicate that IRPs should include MDLs for data transfers.
767 deviceObject
->Flags
|= DO_DIRECT_IO
;
770 // Check if this is during initialization. If not indicate that
771 // system initialization already took place and this disk is ready
776 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
780 // Check for removable media support.
783 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->RemovableMedia
) {
784 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
788 // Set up required stack size in device object.
791 deviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
793 deviceExtension
= deviceObject
->DeviceExtension
;
796 // Allocate spinlock for split request completion.
799 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
802 // Initialize lock count to zero. The lock count is used to
803 // disable the ejection mechanism on devices that support
804 // removable media. Only the lock count in the physical
805 // device extension is used.
808 deviceExtension
->LockCount
= 0;
811 // Save system disk number.
814 deviceExtension
->DeviceNumber
= *DeviceCount
;
817 // Copy port device object pointer to the device extension.
820 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
823 // Set the alignment requirements for the device based on the
824 // host adapter requirements
827 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
828 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
832 // This is the physical device object.
835 //physicalDevice = deviceObject;
836 //physicalDeviceExtension = deviceExtension;
839 // Save address of port driver capabilities.
842 deviceExtension
->PortCapabilities
= PortCapabilities
;
845 // Build the lookaside list for srb's for the physical disk. Should only
849 ScsiClassInitializeSrbLookasideList(deviceExtension
,
850 PARTITION0_LIST_SIZE
);
852 srbListInitialized
= TRUE
;
855 // Initialize the srb flags.
858 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->CommandQueue
&&
859 PortCapabilities
->TaggedQueuing
) {
861 deviceExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
865 deviceExtension
->SrbFlags
= 0;
870 // Allow queued requests if this is not removable media.
873 if (!(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
875 deviceExtension
->SrbFlags
|= SRB_FLAGS_NO_QUEUE_FREEZE
;
880 // Look for controller that require special flags.
883 ScanForSpecial(deviceObject
,
887 //srbFlags = deviceExtension->SrbFlags;
890 // Allocate buffer for drive geometry.
893 diskGeometry
= ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
895 if (diskGeometry
== NULL
) {
898 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
899 status
= STATUS_INSUFFICIENT_RESOURCES
;
900 goto CreateDiskDeviceObjectsExit
;
903 deviceExtension
->DiskGeometry
= diskGeometry
;
906 // Allocate request sense buffer.
909 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
911 if (senseData
== NULL
) {
914 // The buffer can not be allocated.
918 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
920 status
= STATUS_INSUFFICIENT_RESOURCES
;
921 goto CreateDiskDeviceObjectsExit
;
925 // Set the sense data pointer in the device extension.
928 deviceExtension
->SenseData
= senseData
;
931 // Physical device object will describe the entire
932 // device, starting at byte offset 0.
935 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)(0);
938 // TargetId/LUN describes a device location on the SCSI bus.
939 // This information comes from the inquiry buffer.
942 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
943 deviceExtension
->PathId
= pathId
;
944 deviceExtension
->TargetId
= targetId
;
945 deviceExtension
->Lun
= lun
;
948 // Set timeout value in seconds.
951 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
953 deviceExtension
->TimeOutValue
= timeOut
;
955 deviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
959 // Back pointer to device object.
962 deviceExtension
->DeviceObject
= deviceObject
;
965 // If this is a removable device, then make sure it is not a floppy.
966 // Perform a mode sense command to determine the media type. Note
967 // IsFloppyDevice also checks for write cache enabled.
970 if (IsFloppyDevice(deviceObject
) && deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
971 (((PINQUIRYDATA
)LunInfo
->InquiryData
)->DeviceType
== DIRECT_ACCESS_DEVICE
)) {
973 status
= STATUS_NO_SUCH_DEVICE
;
974 goto CreateDiskDeviceObjectsExit
;
977 DisableWriteCache(deviceObject
,LunInfo
);
979 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
982 // NOTE: At this point one device object has been successfully created.
983 // from here on out return success.
987 // Do READ CAPACITY. This SCSI command
988 // returns the number of bytes on a device.
989 // Device extension is updated with device size.
992 status
= ScsiClassReadDriveCapacity(deviceObject
);
995 // If the read capcity failed then just return, unless this is a
996 // removable disk where a device object partition needs to be created.
999 if (!NT_SUCCESS(status
) &&
1000 !(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
1003 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
1006 return(STATUS_SUCCESS
);
1011 // Make sure the volume verification bit is off so that
1012 // IoReadPartitionTable will work.
1015 deviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
1018 status
= CreatePartitionDeviceObjects(deviceObject
, RegistryPath
);
1020 if (NT_SUCCESS(status
))
1021 return STATUS_SUCCESS
;
1024 CreateDiskDeviceObjectsExit
:
1027 // Release the device since an error occurred.
1030 ScsiClassClaimDevice(PortDeviceObject
,
1035 if (diskGeometry
!= NULL
) {
1036 ExFreePool(diskGeometry
);
1039 if (senseData
!= NULL
) {
1040 ExFreePool(senseData
);
1043 if (deviceObject
!= NULL
) {
1045 if (srbListInitialized
) {
1046 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1049 IoDeleteDevice(deviceObject
);
1053 // Delete directory and return.
1056 if (!NT_SUCCESS(status
)) {
1057 ZwMakeTemporaryObject(handle
);
1064 } // end CreateDiskDeviceObjects()
1069 CreatePartitionDeviceObjects(
1070 IN PDEVICE_OBJECT PhysicalDeviceObject
,
1071 IN PUNICODE_STRING RegistryPath
1074 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
1075 ULONG partitionNumber
= 0;
1077 PDEVICE_OBJECT deviceObject
= NULL
;
1078 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
1079 PDRIVE_LAYOUT_INFORMATION partitionList
= NULL
;
1080 PDEVICE_EXTENSION deviceExtension
;
1081 PDEVICE_EXTENSION physicalDeviceExtension
;
1082 PCLASS_INIT_DATA initData
= NULL
;
1083 PDISK_DATA diskData
;
1084 PDISK_DATA physicalDiskData
;
1085 ULONG bytesPerSector
;
1088 ULONG dmByteSkew
= 0;
1090 BOOLEAN dmActive
= FALSE
;
1091 ULONG numberListElements
= 0;
1095 // Get physical device geometry information for partition table reads.
1098 physicalDeviceExtension
= PhysicalDeviceObject
->DeviceExtension
;
1099 diskGeometry
= physicalDeviceExtension
->DiskGeometry
;
1100 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
;
1103 // Make sure sector size is not zero.
1106 if (bytesPerSector
== 0) {
1109 // Default sector size for disk is 512.
1112 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
= 512;
1115 sectorShift
= physicalDeviceExtension
->SectorShift
;
1118 // Set pointer to disk data area that follows device extension.
1121 diskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1122 diskData
->PartitionListState
= Initializing
;
1125 // Determine is DM Driver is loaded on an IDE drive that is
1126 // under control of Atapi - this could be either a crashdump or
1127 // an Atapi device is sharing the controller with an IDE disk.
1130 HalExamineMBR(PhysicalDeviceObject
,
1131 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1138 // Update the device extension, so that the call to IoReadPartitionTable
1139 // will get the correct information. Any I/O to this disk will have
1140 // to be skewed by *dmSkew sectors aka DMByteSkew.
1143 physicalDeviceExtension
->DMSkew
= *dmSkew
;
1144 physicalDeviceExtension
->DMActive
= TRUE
;
1145 physicalDeviceExtension
->DMByteSkew
= physicalDeviceExtension
->DMSkew
* bytesPerSector
;
1148 // Save away the infomation that we need, since this deviceExtension will soon be
1153 dmByteSkew
= physicalDeviceExtension
->DMByteSkew
;
1158 // Create objects for all the partitions on the device.
1161 status
= IoReadPartitionTable(PhysicalDeviceObject
,
1162 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1164 (PVOID
)&partitionList
);
1167 // If the I/O read partition table failed and this is a removable device,
1168 // then fix up the partition list to make it look like there is one
1169 // zero length partition.
1171 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status
);
1172 if ((!NT_SUCCESS(status
) || partitionList
->PartitionCount
== 0) &&
1173 PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1175 if (!NT_SUCCESS(status
)) {
1178 // Remember this disk is not ready.
1181 diskData
->DriveNotReady
= TRUE
;
1186 // Free the partition list allocated by IoReadPartitionTable.
1189 ExFreePool(partitionList
);
1193 // Allocate and zero a partition list.
1196 partitionList
= ExAllocatePool(NonPagedPool
, sizeof(*partitionList
));
1199 if (partitionList
!= NULL
) {
1201 RtlZeroMemory( partitionList
, sizeof( *partitionList
));
1204 // Set the partition count to one and the status to success
1205 // so one device object will be created. Set the partition type
1206 // to a bogus value.
1209 partitionList
->PartitionCount
= 1;
1211 status
= STATUS_SUCCESS
;
1215 if (NT_SUCCESS(status
)) {
1218 // Record disk signature.
1221 diskData
->Signature
= partitionList
->Signature
;
1224 // If disk signature is zero, then calculate the MBR checksum.
1227 if (!diskData
->Signature
) {
1229 if (!CalculateMbrCheckSum(physicalDeviceExtension
,
1230 &diskData
->MbrCheckSum
)) {
1233 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1234 physicalDeviceExtension
->DeviceNumber
));
1238 "SCSIDISK: MBR checksum for disk %x is %x\n",
1239 physicalDeviceExtension
->DeviceNumber
,
1240 diskData
->MbrCheckSum
));
1245 // Check the registry and determine if the BIOS knew about this drive. If
1246 // it did then update the geometry with the BIOS information.
1249 UpdateGeometry(physicalDeviceExtension
);
1251 srbFlags
= physicalDeviceExtension
->SrbFlags
;
1253 initData
= ExAllocatePool(NonPagedPool
, sizeof(CLASS_INIT_DATA
));
1257 "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n"));
1259 status
= STATUS_INSUFFICIENT_RESOURCES
;
1260 goto CreatePartitionDeviceObjectsExit
;
1263 RtlZeroMemory(initData
, sizeof(CLASS_INIT_DATA
));
1265 initData
->InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
1266 initData
->DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
1267 initData
->DeviceType
= FILE_DEVICE_DISK
;
1268 initData
->DeviceCharacteristics
= PhysicalDeviceObject
->Characteristics
;
1269 initData
->ClassError
= physicalDeviceExtension
->ClassError
;
1270 initData
->ClassReadWriteVerification
= physicalDeviceExtension
->ClassReadWriteVerification
;
1271 initData
->ClassFindDevices
= physicalDeviceExtension
->ClassFindDevices
;
1272 initData
->ClassDeviceControl
= physicalDeviceExtension
->ClassDeviceControl
;
1273 initData
->ClassShutdownFlush
= physicalDeviceExtension
->ClassShutdownFlush
;
1274 initData
->ClassCreateClose
= physicalDeviceExtension
->ClassCreateClose
;
1275 initData
->ClassStartIo
= physicalDeviceExtension
->ClassStartIo
;
1278 // Create device objects for the device partitions (if any).
1279 // PartitionCount includes physical device partition 0,
1280 // so only one partition means no objects to create.
1284 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1285 partitionList
->PartitionCount
));
1287 for (partitionNumber
= 0; partitionNumber
<
1288 partitionList
->PartitionCount
; partitionNumber
++) {
1291 // Create partition object and set up partition parameters.
1294 sprintf(ntNameBuffer
,
1295 "\\Device\\Harddisk%lu\\Partition%lu",
1296 physicalDeviceExtension
->DeviceNumber
,
1297 partitionNumber
+ 1);
1300 "CreateDiskDeviceObjects: Create device object %s\n",
1303 status
= ScsiClassCreateDeviceObject(PhysicalDeviceObject
->DriverObject
,
1305 PhysicalDeviceObject
,
1309 if (!NT_SUCCESS(status
)) {
1311 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer
));
1317 // Set up device object fields.
1320 deviceObject
->Flags
|= DO_DIRECT_IO
;
1323 // Check if this is during initialization. If not indicate that
1324 // system initialization already took place and this disk is ready
1328 if (!RegistryPath
) {
1329 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1332 deviceObject
->StackSize
= (CCHAR
)physicalDeviceExtension
->PortDeviceObject
->StackSize
+ 1;
1335 // Set up device extension fields.
1338 deviceExtension
= deviceObject
->DeviceExtension
;
1343 // Restore any saved DM values.
1346 deviceExtension
->DMByteSkew
= dmByteSkew
;
1347 deviceExtension
->DMSkew
= *dmSkew
;
1348 deviceExtension
->DMActive
= TRUE
;
1353 // Link new device extension to previous disk data
1354 // to support dynamic partitioning.
1357 diskData
->NextPartition
= deviceExtension
;
1360 // Get pointer to new disk data.
1363 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1366 // Set next partition pointer to NULL in case this is the
1370 diskData
->NextPartition
= NULL
;
1373 // Allocate spinlock for zoning for split-request completion.
1376 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
1379 // Copy port device object pointer to device extension.
1382 deviceExtension
->PortDeviceObject
= physicalDeviceExtension
->PortDeviceObject
;
1385 // Set the alignment requirements for the device based on the
1386 // host adapter requirements
1389 if (physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
1390 deviceObject
->AlignmentRequirement
= physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
;
1394 if (srbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
1395 numberListElements
= 30;
1397 numberListElements
= 8;
1401 // Build the lookaside list for srb's for this partition based on
1402 // whether the adapter and disk can do tagged queueing.
1405 ScsiClassInitializeSrbLookasideList(deviceExtension
,
1406 numberListElements
);
1408 deviceExtension
->SrbFlags
= srbFlags
;
1411 // Set the sense-data pointer in the device extension.
1414 deviceExtension
->SenseData
= physicalDeviceExtension
->SenseData
;
1415 deviceExtension
->PortCapabilities
= physicalDeviceExtension
->PortCapabilities
;
1416 deviceExtension
->DiskGeometry
= diskGeometry
;
1417 diskData
->PartitionOrdinal
= diskData
->PartitionNumber
= partitionNumber
+ 1;
1418 diskData
->PartitionType
= partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
1419 diskData
->BootIndicator
= partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
1421 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1422 diskData
->PartitionType
));
1424 deviceExtension
->StartingOffset
= partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
1425 deviceExtension
->PartitionLength
= partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
1426 diskData
->HiddenSectors
= partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
1427 deviceExtension
->PortNumber
= physicalDeviceExtension
->PortNumber
;
1428 deviceExtension
->PathId
= physicalDeviceExtension
->PathId
;
1429 deviceExtension
->TargetId
= physicalDeviceExtension
->TargetId
;
1430 deviceExtension
->Lun
= physicalDeviceExtension
->Lun
;
1433 // Check for removable media support.
1436 if (PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1437 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
1441 // Set timeout value in seconds.
1444 deviceExtension
->TimeOutValue
= physicalDeviceExtension
->TimeOutValue
;
1445 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bytesPerSector
;
1446 deviceExtension
->SectorShift
= sectorShift
;
1447 deviceExtension
->DeviceObject
= deviceObject
;
1448 deviceExtension
->DeviceFlags
|= physicalDeviceExtension
->DeviceFlags
;
1450 } // end for (partitionNumber) ...
1453 // Free the buffer allocated by reading the
1457 ExFreePool(partitionList
);
1465 CreatePartitionDeviceObjectsExit
:
1467 if (partitionList
) {
1468 ExFreePool(partitionList
);
1471 ExFreePool(initData
);
1483 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1484 physicalDiskData
->PartitionListState
= Initialized
;
1486 return(STATUS_SUCCESS
);
1489 } // end CreatePartitionDeviceObjects()
1494 ScsiDiskReadWriteVerification(
1495 IN PDEVICE_OBJECT DeviceObject
,
1501 Routine Description:
1503 I/O System entry for read and write requests to SCSI disks.
1507 DeviceObject - Pointer to driver object created by system.
1517 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1518 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1519 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1520 LARGE_INTEGER startingOffset
;
1523 // Verify parameters of this request.
1524 // Check that ending sector is within partition and
1525 // that number of bytes to transfer is a multiple of
1529 startingOffset
.QuadPart
= (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
1532 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
1533 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
1536 // This error maybe caused by the fact that the drive is not ready.
1539 if (((PDISK_DATA
)(deviceExtension
+ 1))->DriveNotReady
) {
1542 // Flag this as a user errror so that a popup is generated.
1545 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
1546 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1551 // Note fastfat depends on this parameter to determine when to
1552 // remount do to a sector size change.
1555 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1558 return STATUS_INVALID_PARAMETER
;
1561 return STATUS_SUCCESS
;
1563 } // end ScsiDiskReadWrite()
1568 ScsiDiskDeviceControl(
1569 PDEVICE_OBJECT DeviceObject
,
1575 Routine Description:
1577 I/O system entry for device controls to SCSI disks.
1581 DeviceObject - Pointer to driver object created by system.
1591 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1592 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1593 PDISK_DATA diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1594 PSCSI_REQUEST_BLOCK srb
;
1596 PMODE_PARAMETER_HEADER modeData
;
1601 IO_STATUS_BLOCK ioStatus
;
1605 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
1609 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1610 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1611 return(STATUS_INSUFFICIENT_RESOURCES
);
1615 // Write zeros to Srb.
1618 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1620 cdb
= (PCDB
)srb
->Cdb
;
1622 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1624 case SMART_GET_VERSION
: {
1627 PSRB_IO_CONTROL srbControl
;
1628 PGETVERSIONINPARAMS versionParams
;
1630 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1631 sizeof(GETVERSIONINPARAMS
)) {
1632 status
= STATUS_INVALID_PARAMETER
;
1637 // Create notification event object to be used to signal the
1638 // request completion.
1641 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1643 srbControl
= ExAllocatePool(NonPagedPool
,
1644 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
));
1647 status
= STATUS_INSUFFICIENT_RESOURCES
;
1652 // fill in srbControl fields
1655 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1656 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1657 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1658 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1659 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1662 // Point to the 'buffer' portion of the SRB_CONTROL
1665 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1668 // Ensure correct target is set in the cmd parameters.
1671 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1672 versionParams
->bIDEDeviceMap
= deviceExtension
->TargetId
;
1675 // Copy the IOCTL parameters to the srb control buffer area.
1678 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(GETVERSIONINPARAMS
));
1681 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1682 deviceExtension
->PortDeviceObject
,
1684 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1686 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1692 status
= STATUS_INSUFFICIENT_RESOURCES
;
1697 // Call the port driver with the request and wait for it to complete.
1700 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1702 if (status
== STATUS_PENDING
) {
1703 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1704 status
= ioStatus
.Status
;
1708 // If successful, copy the data received into the output buffer.
1709 // This should only fail in the event that the IDE driver is older than this driver.
1712 if (NT_SUCCESS(status
)) {
1714 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1716 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, sizeof(GETVERSIONINPARAMS
));
1717 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1720 ExFreePool(srbControl
);
1724 case SMART_RCV_DRIVE_DATA
: {
1726 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1727 ULONG controlCode
= 0;
1728 PSRB_IO_CONTROL srbControl
;
1731 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1732 (sizeof(SENDCMDINPARAMS
) - 1)) {
1733 status
= STATUS_INVALID_PARAMETER
;
1736 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1737 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1738 status
= STATUS_INVALID_PARAMETER
;
1743 // Create notification event object to be used to signal the
1744 // request completion.
1747 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1749 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1751 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1752 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1754 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1755 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1756 case READ_ATTRIBUTES
:
1757 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1758 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1760 case READ_THRESHOLDS
:
1761 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1762 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1765 status
= STATUS_INVALID_PARAMETER
;
1770 status
= STATUS_INVALID_PARAMETER
;
1773 if (controlCode
== 0) {
1774 status
= STATUS_INVALID_PARAMETER
;
1778 srbControl
= ExAllocatePool(NonPagedPool
,
1779 sizeof(SRB_IO_CONTROL
) + length
);
1782 status
= STATUS_INSUFFICIENT_RESOURCES
;
1787 // fill in srbControl fields
1790 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1791 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1792 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1793 srbControl
->Length
= length
;
1794 srbControl
->ControlCode
= controlCode
;
1797 // Point to the 'buffer' portion of the SRB_CONTROL
1800 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1803 // Ensure correct target is set in the cmd parameters.
1806 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1809 // Copy the IOCTL parameters to the srb control buffer area.
1812 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1814 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1815 deviceExtension
->PortDeviceObject
,
1817 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1819 sizeof(SRB_IO_CONTROL
) + length
,
1825 status
= STATUS_INSUFFICIENT_RESOURCES
;
1830 // Call the port driver with the request and wait for it to complete.
1833 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1835 if (status
== STATUS_PENDING
) {
1836 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1837 status
= ioStatus
.Status
;
1841 // If successful, copy the data received into the output buffer
1844 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1846 if (NT_SUCCESS(status
)) {
1848 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
- 1);
1849 Irp
->IoStatus
.Information
= length
- 1;
1853 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1854 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1858 ExFreePool(srbControl
);
1863 case SMART_SEND_DRIVE_COMMAND
: {
1865 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1866 PSRB_IO_CONTROL srbControl
;
1867 ULONG controlCode
= 0;
1870 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1871 (sizeof(SENDCMDINPARAMS
) - 1)) {
1872 status
= STATUS_INVALID_PARAMETER
;
1875 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1876 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1877 status
= STATUS_INVALID_PARAMETER
;
1882 // Create notification event object to be used to signal the
1883 // request completion.
1886 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1890 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1891 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1894 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1898 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1901 case RETURN_SMART_STATUS
:
1904 // Ensure bBuffer is at least 2 bytes (to hold the values of
1905 // cylinderLow and cylinderHigh).
1908 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1909 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1911 status
= STATUS_INVALID_PARAMETER
;
1915 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1916 length
= sizeof(IDEREGS
);
1919 case ENABLE_DISABLE_AUTOSAVE
:
1920 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1923 case SAVE_ATTRIBUTE_VALUES
:
1924 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1927 case EXECUTE_OFFLINE_DIAGS
:
1928 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1932 status
= STATUS_INVALID_PARAMETER
;
1937 status
= STATUS_INVALID_PARAMETER
;
1940 if (controlCode
== 0) {
1941 status
= STATUS_INVALID_PARAMETER
;
1945 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1946 srbControl
= ExAllocatePool(NonPagedPool
,
1947 sizeof(SRB_IO_CONTROL
) + length
);
1950 status
= STATUS_INSUFFICIENT_RESOURCES
;
1955 // fill in srbControl fields
1958 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1959 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1960 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1961 srbControl
->Length
= length
;
1964 // Point to the 'buffer' portion of the SRB_CONTROL
1967 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1970 // Ensure correct target is set in the cmd parameters.
1973 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1976 // Copy the IOCTL parameters to the srb control buffer area.
1979 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1981 srbControl
->ControlCode
= controlCode
;
1983 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1984 deviceExtension
->PortDeviceObject
,
1986 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1988 sizeof(SRB_IO_CONTROL
) + length
,
1994 status
= STATUS_INSUFFICIENT_RESOURCES
;
1999 // Call the port driver with the request and wait for it to complete.
2002 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2004 if (status
== STATUS_PENDING
) {
2005 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2006 status
= ioStatus
.Status
;
2010 // Copy the data received into the output buffer. Since the status buffer
2011 // contains error information also, always perform this copy. IO will will
2012 // either pass this back to the app, or zero it, in case of error.
2015 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2018 // Update the return buffer size based on the sub-command.
2021 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
2022 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
2024 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
2027 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
);
2028 Irp
->IoStatus
.Information
= length
;
2030 ExFreePool(srbControl
);
2035 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2036 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2039 PDEVICE_EXTENSION physicalDeviceExtension
;
2040 PDISK_DATA physicalDiskData
;
2041 BOOLEAN removable
= FALSE
;
2042 BOOLEAN listInitialized
= FALSE
;
2044 if ((irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
&&
2045 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2046 sizeof(DISK_GEOMETRY
)) ||
2047 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
&&
2048 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2049 sizeof(DISK_GEOMETRY_EX
))) {
2051 status
= STATUS_INFO_LENGTH_MISMATCH
;
2055 status
= STATUS_SUCCESS
;
2057 physicalDeviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2058 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
2060 removable
= (BOOLEAN
)DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
;
2061 listInitialized
= (physicalDiskData
->PartitionListState
== Initialized
);
2063 if (removable
|| (!listInitialized
))
2066 // Issue ReadCapacity to update device extension
2067 // with information for current media.
2070 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
2076 if (!NT_SUCCESS(status
)) {
2079 // Note the drive is not ready.
2082 diskData
->DriveNotReady
= TRUE
;
2088 // Note the drive is now ready.
2091 diskData
->DriveNotReady
= FALSE
;
2093 } else if (NT_SUCCESS(status
)) {
2095 // ReadDriveCapacity was allright, create Partition Objects
2097 if (physicalDiskData
->PartitionListState
== NotInitialized
) {
2098 status
= CreatePartitionDeviceObjects(deviceExtension
->PhysicalDevice
, NULL
);
2102 if (NT_SUCCESS(status
)) {
2105 // Copy drive geometry information from device extension.
2108 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2109 deviceExtension
->DiskGeometry
,
2110 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2111 sizeof(DISK_GEOMETRY
) :
2112 sizeof(DISK_GEOMETRY_EX
));
2114 status
= STATUS_SUCCESS
;
2115 Irp
->IoStatus
.Information
=
2116 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2117 sizeof(DISK_GEOMETRY
) :
2118 sizeof(DISK_GEOMETRY_EX
);
2125 case IOCTL_DISK_VERIFY
:
2129 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2130 LARGE_INTEGER byteOffset
;
2135 // Validate buffer length.
2138 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2139 sizeof(VERIFY_INFORMATION
)) {
2141 status
= STATUS_INFO_LENGTH_MISMATCH
;
2149 srb
->CdbLength
= 10;
2151 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2154 // Add disk offset to starting sector.
2157 byteOffset
.QuadPart
= deviceExtension
->StartingOffset
.QuadPart
+
2158 verifyInfo
->StartingOffset
.QuadPart
;
2161 // Convert byte offset to sector offset.
2164 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2167 // Convert ULONG byte count to USHORT sector count.
2170 sectorCount
= (USHORT
)(verifyInfo
->Length
>> deviceExtension
->SectorShift
);
2173 // Move little endian values into CDB in big endian format.
2176 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2177 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2178 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2179 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2181 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2182 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2185 // The verify command is used by the NT FORMAT utility and
2186 // requests are sent down for 5% of the volume size. The
2187 // request timeout value is calculated based on the number of
2188 // sectors verified.
2191 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2192 deviceExtension
->TimeOutValue
;
2194 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
2205 case IOCTL_DISK_GET_PARTITION_INFO
:
2208 // Return the information about the partition specified by the device
2209 // object. Note that no information is ever returned about the size
2210 // or partition type of the physical disk, as this doesn't make any
2214 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2215 sizeof(PARTITION_INFORMATION
)) {
2217 status
= STATUS_INFO_LENGTH_MISMATCH
;
2220 #if 0 // HACK: ReactOS partition numbers must be wrong
2221 else if (diskData
->PartitionNumber
== 0) {
2224 // Paritition zero is not a partition so this is not a
2225 // reasonable request.
2228 status
= STATUS_INVALID_DEVICE_REQUEST
;
2234 PPARTITION_INFORMATION outputBuffer
;
2237 // Update the geometry in case it has changed.
2240 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2242 if (!NT_SUCCESS(status
)) {
2245 // Note the drive is not ready.
2248 diskData
->DriveNotReady
= TRUE
;
2253 // Note the drive is now ready.
2256 diskData
->DriveNotReady
= FALSE
;
2257 // HACK: ReactOS partition numbers must be wrong (>0 part)
2258 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2260 status
= STATUS_INVALID_DEVICE_REQUEST
;
2265 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2267 outputBuffer
->PartitionType
= diskData
->PartitionType
;
2268 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2269 outputBuffer
->PartitionLength
.QuadPart
= (diskData
->PartitionNumber
) ?
2270 deviceExtension
->PartitionLength
.QuadPart
: 2305843009213693951LL; // HACK
2271 outputBuffer
->HiddenSectors
= diskData
->HiddenSectors
;
2272 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2273 outputBuffer
->BootIndicator
= diskData
->BootIndicator
;
2274 outputBuffer
->RewritePartition
= FALSE
;
2275 outputBuffer
->RecognizedPartition
=
2276 IsRecognizedPartition(diskData
->PartitionType
);
2278 status
= STATUS_SUCCESS
;
2279 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2284 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2287 // Return the information about the partition specified by the device
2288 // object. Note that no information is ever returned about the size
2289 // or partition type of the physical disk, as this doesn't make any
2293 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2294 sizeof(PARTITION_INFORMATION_EX
)) {
2296 status
= STATUS_INFO_LENGTH_MISMATCH
;
2299 else if (diskData
->PartitionNumber
== 0) {
2302 // Paritition zero is not a partition so this is not a
2303 // reasonable request.
2306 status
= STATUS_INVALID_DEVICE_REQUEST
;
2311 PPARTITION_INFORMATION_EX outputBuffer
;
2314 // Update the geometry in case it has changed.
2317 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2319 if (!NT_SUCCESS(status
)) {
2322 // Note the drive is not ready.
2325 diskData
->DriveNotReady
= TRUE
;
2330 // Note the drive is now ready.
2333 diskData
->DriveNotReady
= FALSE
;
2335 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2337 status
= STATUS_INVALID_DEVICE_REQUEST
;
2342 (PPARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
2345 // FIXME: hack of the year, assume that partition is MBR
2346 // Thing that can obviously be wrong...
2349 outputBuffer
->PartitionStyle
= PARTITION_STYLE_MBR
;
2350 outputBuffer
->Mbr
.PartitionType
= diskData
->PartitionType
;
2351 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2352 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2353 outputBuffer
->Mbr
.HiddenSectors
= diskData
->HiddenSectors
;
2354 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2355 outputBuffer
->Mbr
.BootIndicator
= diskData
->BootIndicator
;
2356 outputBuffer
->RewritePartition
= FALSE
;
2357 outputBuffer
->Mbr
.RecognizedPartition
=
2358 IsRecognizedPartition(diskData
->PartitionType
);
2360 status
= STATUS_SUCCESS
;
2361 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
2366 case IOCTL_DISK_SET_PARTITION_INFO
:
2368 if (diskData
->PartitionNumber
== 0) {
2370 status
= STATUS_UNSUCCESSFUL
;
2374 PSET_PARTITION_INFORMATION inputBuffer
=
2375 (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2378 // Validate buffer length.
2381 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2382 sizeof(SET_PARTITION_INFORMATION
)) {
2384 status
= STATUS_INFO_LENGTH_MISMATCH
;
2389 // The HAL routines IoGet- and IoSetPartitionInformation were
2390 // developed before support of dynamic partitioning and therefore
2391 // don't distinguish between partition ordinal (that is the order
2392 // of a partition on a disk) and the partition number. (The
2393 // partition number is assigned to a partition to identify it to
2394 // the system.) Use partition ordinals for these legacy calls.
2397 status
= IoSetPartitionInformation(
2398 deviceExtension
->PhysicalDevice
,
2399 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2400 diskData
->PartitionOrdinal
,
2401 inputBuffer
->PartitionType
);
2403 if (NT_SUCCESS(status
)) {
2405 diskData
->PartitionType
= inputBuffer
->PartitionType
;
2411 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2414 // Return the partition layout for the physical drive. Note that
2415 // the layout is returned for the actual physical drive, regardless
2416 // of which partition was specified for the request.
2419 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2420 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2421 status
= STATUS_INFO_LENGTH_MISMATCH
;
2425 PDRIVE_LAYOUT_INFORMATION partitionList
;
2426 PDEVICE_EXTENSION physicalExtension
= deviceExtension
;
2427 PPARTITION_INFORMATION partitionEntry
;
2428 PDISK_DATA diskData
;
2433 // Read partition information.
2436 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
2437 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2441 if (!NT_SUCCESS(status
)) {
2446 // The disk layout has been returned in the partitionList
2447 // buffer. Determine its size and, if the data will fit
2448 // into the intermediatery buffer, return it.
2451 tempSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,PartitionEntry
[0]);
2452 tempSize
+= partitionList
->PartitionCount
*
2453 sizeof(PARTITION_INFORMATION
);
2456 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
2458 status
= STATUS_BUFFER_TOO_SMALL
;
2459 ExFreePool(partitionList
);
2464 // Walk partition list to associate partition numbers with
2465 // partition entries.
2468 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
2471 // Walk partition chain anchored at physical disk extension.
2474 deviceExtension
= physicalExtension
;
2475 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2479 deviceExtension
= diskData
->NextPartition
;
2482 // Check if this is the last partition in the chain.
2485 if (!deviceExtension
) {
2490 // Get the partition device extension from disk data.
2493 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2496 // Check if this partition is not currently being used.
2499 if (!deviceExtension
->PartitionLength
.QuadPart
) {
2503 partitionEntry
= &partitionList
->PartitionEntry
[i
];
2506 // Check if empty, or describes extended partiton or hasn't changed.
2509 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2510 IsContainerPartition(partitionEntry
->PartitionType
)) {
2515 // Check if new partition starts where this partition starts.
2518 if (partitionEntry
->StartingOffset
.QuadPart
!=
2519 deviceExtension
->StartingOffset
.QuadPart
) {
2524 // Check if partition length is the same.
2527 if (partitionEntry
->PartitionLength
.QuadPart
==
2528 deviceExtension
->PartitionLength
.QuadPart
) {
2531 // Partitions match. Update partition number.
2534 partitionEntry
->PartitionNumber
=
2535 diskData
->PartitionNumber
;
2543 // Copy partition information to system buffer.
2546 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2549 status
= STATUS_SUCCESS
;
2550 Irp
->IoStatus
.Information
= tempSize
;
2553 // Finally, free the buffer allocated by reading the
2557 ExFreePool(partitionList
);
2562 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
2567 // Update the disk with new partition information.
2570 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
2573 // Validate buffer length.
2576 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2577 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2579 status
= STATUS_INFO_LENGTH_MISMATCH
;
2583 length
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2584 (partitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
);
2587 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2590 status
= STATUS_BUFFER_TOO_SMALL
;
2595 // Verify that device object is for physical disk.
2598 if (deviceExtension
->PhysicalDevice
->DeviceExtension
!= deviceExtension
) {
2599 status
= STATUS_INVALID_PARAMETER
;
2604 // Walk through partition table comparing partitions to
2605 // existing partitions to create, delete and change
2606 // device objects as necessary.
2609 UpdateDeviceObjects(DeviceObject
,
2613 // Write changes to disk.
2616 status
= IoWritePartitionTable(
2617 deviceExtension
->DeviceObject
,
2618 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2619 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
,
2620 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
,
2625 // Update IRP with bytes returned.
2628 if (NT_SUCCESS(status
)) {
2629 Irp
->IoStatus
.Information
= length
;
2634 case IOCTL_DISK_REASSIGN_BLOCKS
:
2637 // Map defective blocks to new location on disk.
2642 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2648 // Validate buffer length.
2651 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2652 sizeof(REASSIGN_BLOCKS
)) {
2654 status
= STATUS_INFO_LENGTH_MISMATCH
;
2658 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2659 (badBlocks
->Count
- 1) * sizeof(ULONG
);
2661 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2664 status
= STATUS_INFO_LENGTH_MISMATCH
;
2669 // Build the data buffer to be transferred in the input buffer.
2670 // The format of the data to the device is:
2674 // x * 4 btyes Block Address
2676 // All values are big endian.
2679 badBlocks
->Reserved
= 0;
2680 blockCount
= badBlocks
->Count
;
2683 // Convert # of entries to # of bytes.
2687 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2688 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2691 // Convert back to number of entries.
2696 for (; blockCount
> 0; blockCount
--) {
2698 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2700 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2701 (PFOUR_BYTE
) &blockNumber
);
2706 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2709 // Set timeout value.
2712 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2714 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2720 Irp
->IoStatus
.Status
= status
;
2721 Irp
->IoStatus
.Information
= 0;
2723 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2728 case IOCTL_DISK_IS_WRITABLE
:
2731 // Determine if the device is writable.
2734 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
2736 if (modeData
== NULL
) {
2737 status
= STATUS_INSUFFICIENT_RESOURCES
;
2741 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
2743 length
= ScsiClassModeSense(DeviceObject
,
2746 MODE_SENSE_RETURN_ALL
);
2748 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2751 // Retry the request in case of a check condition.
2754 length
= ScsiClassModeSense(DeviceObject
,
2757 MODE_SENSE_RETURN_ALL
);
2759 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2760 status
= STATUS_IO_DEVICE_ERROR
;
2761 ExFreePool(modeData
);
2766 if (modeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
) {
2767 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2769 status
= STATUS_SUCCESS
;
2772 ExFreePool(modeData
);
2775 case IOCTL_DISK_INTERNAL_SET_VERIFY
:
2778 // If the caller is kernel mode, set the verify bit.
2781 if (Irp
->RequestorMode
== KernelMode
) {
2782 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2784 status
= STATUS_SUCCESS
;
2787 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
:
2790 // If the caller is kernel mode, clear the verify bit.
2793 if (Irp
->RequestorMode
== KernelMode
) {
2794 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
2796 status
= STATUS_SUCCESS
;
2799 case IOCTL_DISK_FIND_NEW_DEVICES
:
2802 // Search for devices that have been powered on since the last
2803 // device search or system initialization.
2806 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2807 status
= DriverEntry(DeviceObject
->DriverObject
,
2810 Irp
->IoStatus
.Status
= status
;
2812 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2815 case IOCTL_DISK_MEDIA_REMOVAL
:
2818 // If the disk is not removable then don't allow this command.
2821 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
2822 status
= STATUS_INVALID_DEVICE_REQUEST
;
2827 // Fall through and let the class driver process the request.
2830 case IOCTL_DISK_GET_LENGTH_INFO
:
2833 // Validate buffer length.
2836 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2837 sizeof(GET_LENGTH_INFORMATION
)) {
2838 status
= STATUS_BUFFER_TOO_SMALL
;
2842 PGET_LENGTH_INFORMATION lengthInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
2845 // Update the geometry in case it has changed.
2848 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2850 if (!NT_SUCCESS(status
)) {
2853 // Note the drive is not ready.
2856 diskData
->DriveNotReady
= TRUE
;
2861 // Note the drive is now ready.
2864 diskData
->DriveNotReady
= FALSE
;
2867 // Output data, and return
2870 lengthInformation
->Length
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2871 status
= STATUS_SUCCESS
;
2872 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2880 // Free the Srb, since it is not needed.
2886 // Pass the request to the common device control routine.
2889 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
2893 } // end switch( ...
2895 Irp
->IoStatus
.Status
= status
;
2897 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2899 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2902 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2906 } // end ScsiDiskDeviceControl()
2910 ScsiDiskShutdownFlush (
2911 IN PDEVICE_OBJECT DeviceObject
,
2917 Routine Description:
2919 This routine is called for a shutdown and flush IRPs. These are sent by the
2920 system before it actually shuts down or when the file system does a flush.
2921 A synchronize cache command is sent to the device if it is write caching.
2922 If the device is removable an unlock command will be sent. This routine
2923 will sent a shutdown or flush Srb to the port driver.
2927 DriverObject - Pointer to device object to being shutdown by system.
2938 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2939 PIO_STACK_LOCATION irpStack
;
2940 PSCSI_REQUEST_BLOCK srb
;
2945 // Allocate SCSI request block.
2948 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
2953 // Set the status and complete the request.
2956 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2957 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2958 return(STATUS_INSUFFICIENT_RESOURCES
);
2961 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
2964 // Write length to SRB.
2967 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2970 // Set SCSI bus address.
2973 srb
->PathId
= deviceExtension
->PathId
;
2974 srb
->TargetId
= deviceExtension
->TargetId
;
2975 srb
->Lun
= deviceExtension
->Lun
;
2978 // Set timeout value and mark the request as not being a tagged request.
2981 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 4;
2982 srb
->QueueTag
= SP_UNTAGGED
;
2983 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
2984 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2987 // If the write cache is enabled then send a synchronize cache request.
2990 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2992 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2993 srb
->CdbLength
= 10;
2995 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
2997 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3003 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status
));
3007 // Unlock the device if it is removable and this is a shutdown.
3010 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3012 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
3013 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
3016 cdb
= (PVOID
) srb
->Cdb
;
3017 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3018 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3021 // Set timeout value.
3024 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3025 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3031 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3037 // Save a few parameters in the current stack location.
3040 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3041 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3044 // Set the retry count to zero.
3047 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3050 // Set up IoCompletion routine address.
3053 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3056 // Get next stack location and
3057 // set major function code.
3060 irpStack
= IoGetNextIrpStackLocation(Irp
);
3062 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3065 // Set up SRB for execute scsi request.
3066 // Save SRB address in next stack for port driver.
3069 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3072 // Set up Irp Address.
3075 srb
->OriginalRequest
= Irp
;
3078 // Call the port driver to process the request.
3081 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3083 } // end ScsiDiskShutdown()
3089 PDEVICE_OBJECT DeviceObject
3093 Routine Description:
3095 The routine performs the necessary functions to determine if a device is
3096 really a floppy rather than a harddisk. This is done by a mode sense
3097 command. First, a check is made to see if the medimum type is set. Second
3098 a check is made for the flexible parameters mode page. Also a check is
3099 made to see if the write cache is enabled.
3103 DeviceObject - Supplies the device object to be tested.
3107 Return TRUE if the indicated device is a floppy.
3111 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3118 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3120 if (modeData
== NULL
) {
3124 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3126 length
= ScsiClassModeSense(DeviceObject
,
3129 MODE_SENSE_RETURN_ALL
);
3131 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3134 // Retry the request in case of a check condition.
3137 length
= ScsiClassModeSense(DeviceObject
,
3140 MODE_SENSE_RETURN_ALL
);
3142 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3144 ExFreePool(modeData
);
3151 // If the length is greater than length indicated by the mode data reset
3152 // the data to the mode data.
3155 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3156 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3160 // Look for the flexible disk mode page.
3163 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_FLEXIBILE
, TRUE
);
3165 if (pageData
!= NULL
) {
3167 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3168 ExFreePool(modeData
);
3173 // Check to see if the write cache is enabled.
3176 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3179 // Assume that write cache is disabled or not supported.
3182 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3185 // Check if valid caching page exists.
3188 if (pageData
!= NULL
) {
3191 // Check if write cache is disabled.
3194 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3197 "SCSIDISK: Disk write cache enabled\n"));
3200 // Check if forced unit access (FUA) is supported.
3203 if (((PMODE_PARAMETER_HEADER
)modeData
)->DeviceSpecificParameter
& MODE_DSP_FUA_SUPPORTED
) {
3205 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3210 "SCSIDISK: Disk does not support FUA or DPO\n"));
3220 ExFreePool(modeData
);
3223 } // end IsFloppyDevice()
3229 IN PDEVICE_OBJECT DeviceObject
,
3230 IN PCHAR ModeSelectBuffer
,
3237 Routine Description:
3239 This routine sends a mode select command.
3243 DeviceObject - Supplies the device object associated with this request.
3245 ModeSelectBuffer - Supplies a buffer containing the page data.
3247 Length - Supplies the length in bytes of the mode select buffer.
3249 SavePage - Indicates that parameters should be written to disk.
3253 Length of the transferred data is returned.
3257 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3259 SCSI_REQUEST_BLOCK srb
;
3264 PMODE_PARAMETER_BLOCK blockDescriptor
;
3268 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3271 // Allocate buffer for mode select header, block descriptor, and mode page.
3274 buffer
= (ULONG_PTR
)ExAllocatePool(NonPagedPoolCacheAligned
,length2
);
3276 RtlZeroMemory((PVOID
)buffer
, length2
);
3279 // Set length in header to size of mode page.
3282 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3284 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3290 blockDescriptor
->BlockLength
[1]=0x02;
3293 // Copy mode page to buffer.
3296 RtlCopyMemory((PVOID
)(buffer
+ 3), ModeSelectBuffer
, Length
);
3302 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3305 // Build the MODE SELECT CDB.
3309 cdb
= (PCDB
)srb
.Cdb
;
3312 // Set timeout value from device extension.
3315 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
3317 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3318 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3319 cdb
->MODE_SELECT
.PFBit
= 1;
3320 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3324 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3331 if (status
== STATUS_VERIFY_REQUIRED
) {
3334 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3347 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3348 status
= STATUS_SUCCESS
;
3351 ExFreePool((PVOID
)buffer
);
3353 if (NT_SUCCESS(status
)) {
3359 } // end SciDiskModeSelect()
3365 IN PDEVICE_OBJECT DeviceObject
,
3366 IN PSCSI_INQUIRY_DATA LunInfo
3370 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3371 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3372 BAD_CONTROLLER_INFORMATION
const *controller
;
3377 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
3379 controller
= &ScsiDiskBadControllers
[j
];
3381 if (!controller
->DisableWriteCache
|| strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
3385 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller
->InquiryString
));
3387 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3389 if (modeData
== NULL
) {
3392 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3396 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3398 length
= ScsiClassModeSense(DeviceObject
,
3401 MODE_SENSE_RETURN_ALL
);
3403 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3406 // Retry the request in case of a check condition.
3409 length
= ScsiClassModeSense(DeviceObject
,
3412 MODE_SENSE_RETURN_ALL
);
3414 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3418 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3420 ExFreePool(modeData
);
3427 // If the length is greater than length indicated by the mode data reset
3428 // the data to the mode data.
3431 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3432 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3436 // Check to see if the write cache is enabled.
3439 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3442 // Assume that write cache is disabled or not supported.
3445 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3448 // Check if valid caching page exists.
3451 if (pageData
!= NULL
) {
3453 BOOLEAN savePage
= FALSE
;
3455 savePage
= (BOOLEAN
)(((PMODE_CACHING_PAGE
)pageData
)->PageSavable
);
3458 // Check if write cache is disabled.
3461 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3463 PIO_ERROR_LOG_PACKET errorLogEntry
;
3468 // Disable write cache and ensure necessary fields are zeroed.
3471 ((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
= FALSE
;
3472 ((PMODE_CACHING_PAGE
)pageData
)->Reserved
= 0;
3473 ((PMODE_CACHING_PAGE
)pageData
)->PageSavable
= 0;
3474 ((PMODE_CACHING_PAGE
)pageData
)->Reserved2
= 0;
3477 // Extract length from caching page.
3480 length
= ((PMODE_CACHING_PAGE
)pageData
)->PageLength
;
3483 // Compensate for page code and page length.
3489 // Issue mode select to set the parameter.
3492 if (ScsiDiskModeSelect(DeviceObject
,
3498 "SCSIDISK: Disk write cache disabled\n"));
3500 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3501 errorCode
= IO_WRITE_CACHE_DISABLED
;
3504 if (ScsiDiskModeSelect(DeviceObject
,
3510 "SCSIDISK: Disk write cache disabled\n"));
3513 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3514 errorCode
= IO_WRITE_CACHE_DISABLED
;
3519 "SCSIDISK: Mode select to disable write cache failed\n"));
3521 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3522 errorCode
= IO_WRITE_CACHE_ENABLED
;
3527 // Log the appropriate informational or error entry.
3530 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3532 sizeof(IO_ERROR_LOG_PACKET
) + 3
3535 if (errorLogEntry
!= NULL
) {
3537 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3538 errorLogEntry
->ErrorCode
= errorCode
;
3539 errorLogEntry
->SequenceNumber
= 0;
3540 errorLogEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
3541 errorLogEntry
->IoControlCode
= 0;
3542 errorLogEntry
->RetryCount
= 0;
3543 errorLogEntry
->UniqueErrorValue
= 0x1;
3544 errorLogEntry
->DumpDataSize
= 3 * sizeof(ULONG
);
3545 errorLogEntry
->DumpData
[0] = LunInfo
->PathId
;
3546 errorLogEntry
->DumpData
[1] = LunInfo
->TargetId
;
3547 errorLogEntry
->DumpData
[2] = LunInfo
->Lun
;
3550 // Write the error log packet.
3553 IoWriteErrorLogEntry(errorLogEntry
);
3559 // Found device so exit the loop and return.
3571 CalculateMbrCheckSum(
3572 IN PDEVICE_EXTENSION DeviceExtension
,
3578 Routine Description:
3580 Read MBR and calculate checksum.
3584 DeviceExtension - Supplies a pointer to the device information for disk.
3585 Checksum - Memory location to return MBR checksum.
3589 Returns TRUE if checksum is valid.
3593 LARGE_INTEGER sectorZero
;
3595 IO_STATUS_BLOCK ioStatus
;
3603 sectorZero
.QuadPart
= (LONGLONG
) 0;
3606 // Create notification event object to be used to signal the inquiry
3607 // request completion.
3610 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
3616 sectorSize
= DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
3619 // Make sure sector size is at least 512 bytes.
3622 if (sectorSize
< 512) {
3627 // Allocate buffer for sector read.
3630 mbr
= ExAllocatePool(NonPagedPoolCacheAligned
, sectorSize
);
3637 // Build IRP to read MBR.
3640 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
3641 DeviceExtension
->DeviceObject
,
3654 // Pass request to port driver and wait for request to complete.
3657 status
= IoCallDriver(DeviceExtension
->DeviceObject
,
3660 if (status
== STATUS_PENDING
) {
3661 KeWaitForSingleObject(&event
,
3666 status
= ioStatus
.Status
;
3669 if (!NT_SUCCESS(status
)) {
3675 // Calculate MBR checksum.
3680 for (i
= 0; i
< 128; i
++) {
3681 *Checksum
+= mbr
[i
];
3684 *Checksum
= ~*Checksum
+ 1;
3694 IN PDEVICE_EXTENSION DeviceExtension
,
3701 Routine Description:
3703 The routine queries the registry to determine if this disk is visible to
3704 the BIOS. If the disk is visable to the BIOS, then the geometry information
3709 DeviceExtension - Supplies a pointer to the device information for disk.
3710 Signature - Unique identifier recorded in MBR.
3711 BusKey - Handle of bus key.
3712 DiskNumber - Returns ordinal of disk as BIOS sees it.
3716 TRUE is disk signature matched.
3720 PDISK_DATA diskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
3721 BOOLEAN diskFound
= FALSE
;
3722 OBJECT_ATTRIBUTES objectAttributes
;
3723 UNICODE_STRING unicodeString
;
3724 UNICODE_STRING identifier
;
3726 ULONG adapterNumber
;
3734 STRING anotherString
;
3737 PKEY_VALUE_FULL_INFORMATION keyData
;
3741 for (busNumber
= 0; ; busNumber
++) {
3744 // Open controller name key.
3747 sprintf((PCHAR
)buffer
,
3751 RtlInitString(&string
,
3754 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3758 if (!NT_SUCCESS(status
)){
3762 InitializeObjectAttributes(&objectAttributes
,
3764 OBJ_CASE_INSENSITIVE
,
3766 (PSECURITY_DESCRIPTOR
)NULL
);
3768 status
= ZwOpenKey(&spareKey
,
3772 RtlFreeUnicodeString(&unicodeString
);
3774 if (!NT_SUCCESS(status
)) {
3779 // Open up controller ordinal key.
3782 RtlInitUnicodeString(&unicodeString
, L
"DiskController");
3783 InitializeObjectAttributes(&objectAttributes
,
3785 OBJ_CASE_INSENSITIVE
,
3787 (PSECURITY_DESCRIPTOR
)NULL
);
3789 status
= ZwOpenKey(&adapterKey
,
3794 // This could fail even with additional adapters of this type
3798 if (!NT_SUCCESS(status
)) {
3802 for (adapterNumber
= 0; ; adapterNumber
++) {
3808 sprintf((PCHAR
)buffer
,
3809 "%lu\\DiskPeripheral",
3812 RtlInitString(&string
,
3815 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3819 if (!NT_SUCCESS(status
)){
3823 InitializeObjectAttributes(&objectAttributes
,
3825 OBJ_CASE_INSENSITIVE
,
3827 (PSECURITY_DESCRIPTOR
)NULL
);
3829 status
= ZwOpenKey(&diskKey
,
3833 RtlFreeUnicodeString(&unicodeString
);
3835 if (!NT_SUCCESS(status
)) {
3839 for (diskNumber
= 0; ; diskNumber
++) {
3841 sprintf((PCHAR
)buffer
,
3845 RtlInitString(&string
,
3848 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3852 if (!NT_SUCCESS(status
)){
3856 InitializeObjectAttributes(&objectAttributes
,
3858 OBJ_CASE_INSENSITIVE
,
3860 (PSECURITY_DESCRIPTOR
)NULL
);
3862 status
= ZwOpenKey(&targetKey
,
3866 RtlFreeUnicodeString(&unicodeString
);
3868 if (!NT_SUCCESS(status
)) {
3873 // Allocate buffer for registry query.
3876 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
3878 if (keyData
== NULL
) {
3884 // Get disk peripheral identifier.
3887 RtlInitUnicodeString(&unicodeString
, L
"Identifier");
3888 status
= ZwQueryValueKey(targetKey
,
3890 KeyValueFullInformation
,
3897 if (!NT_SUCCESS(status
)) {
3902 // Complete unicode string.
3906 (PWSTR
)((PUCHAR
)keyData
+ keyData
->DataOffset
);
3907 identifier
.Length
= (USHORT
)keyData
->DataLength
;
3908 identifier
.MaximumLength
= (USHORT
)keyData
->DataLength
;
3911 // Convert unicode identifier to ansi string.
3915 RtlUnicodeStringToAnsiString(&anotherString
,
3919 if (!NT_SUCCESS(status
)) {
3924 // If checksum is zero, then the MBR is valid and
3925 // the signature is meaningful.
3928 if (diskData
->MbrCheckSum
) {
3931 // Convert checksum to ansi string.
3934 sprintf((PCHAR
)buffer
, "%08lx", diskData
->MbrCheckSum
);
3939 // Convert signature to ansi string.
3942 sprintf((PCHAR
)buffer
, "%08lx", diskData
->Signature
);
3945 // Make string point at signature. Can't use scan
3946 // functions because they are not exported for driver use.
3949 anotherString
.Buffer
+=9;
3953 // Convert to ansi string.
3956 RtlInitString(&string
,
3961 // Make string lengths equal.
3964 anotherString
.Length
= string
.Length
;
3967 // Check if strings match.
3970 if (RtlCompareString(&string
,
3975 *DiskNumber
= diskNumber
;
3978 ExFreePool(keyData
);
3981 // Readjust indentifier string if necessary.
3984 if (!diskData
->MbrCheckSum
) {
3985 anotherString
.Buffer
-=9;
3988 RtlFreeAnsiString(&anotherString
);
3998 ZwClose(adapterKey
);
4004 } // end EnumerateBusKey()
4010 IN PDEVICE_EXTENSION DeviceExtension
4014 Routine Description:
4016 The routine queries the registry to determine if this disk is visible to
4017 the BIOS. If the disk is visable to the BIOS, then the geometry information
4022 DeviceExtension - Supplies a pointer to the device information for disk.
4031 OBJECT_ATTRIBUTES objectAttributes
;
4032 UNICODE_STRING unicodeString
;
4036 PCM_INT13_DRIVE_PARAMETER driveParameters
;
4037 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor
;
4038 PKEY_VALUE_FULL_INFORMATION keyData
;
4042 ULONG numberOfDrives
;
4045 ULONG sectorsPerTrack
;
4046 ULONG tracksPerCylinder
;
4047 BOOLEAN foundEZHooker
;
4053 // Initialize the object for the key.
4056 InitializeObjectAttributes(&objectAttributes
,
4057 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
4058 OBJ_CASE_INSENSITIVE
,
4060 (PSECURITY_DESCRIPTOR
) NULL
);
4063 // Create the hardware base key.
4066 status
= ZwOpenKey(&hardwareKey
,
4071 if (!NT_SUCCESS(status
)) {
4072 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
));
4078 // Get disk BIOS geometry information.
4081 RtlInitUnicodeString(&unicodeString
, L
"Configuration Data");
4083 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
4085 if (keyData
== NULL
) {
4086 ZwClose(hardwareKey
);
4090 status
= ZwQueryValueKey(hardwareKey
,
4092 KeyValueFullInformation
,
4097 if (!NT_SUCCESS(status
)) {
4099 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4101 ExFreePool(keyData
);
4106 // Open EISA bus key.
4109 RtlInitUnicodeString(&unicodeString
, L
"EisaAdapter");
4111 InitializeObjectAttributes(&objectAttributes
,
4113 OBJ_CASE_INSENSITIVE
,
4115 (PSECURITY_DESCRIPTOR
)NULL
);
4117 status
= ZwOpenKey(&busKey
,
4121 if (!NT_SUCCESS(status
)) {
4126 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4127 if (EnumerateBusKey(DeviceExtension
,
4131 ZwClose(hardwareKey
);
4138 // Open Multifunction bus key.
4141 RtlInitUnicodeString(&unicodeString
, L
"MultifunctionAdapter");
4143 InitializeObjectAttributes(&objectAttributes
,
4145 OBJ_CASE_INSENSITIVE
,
4147 (PSECURITY_DESCRIPTOR
)NULL
);
4149 status
= ZwOpenKey(&busKey
,
4153 ZwClose(hardwareKey
);
4154 if (NT_SUCCESS(status
)) {
4156 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4157 if (EnumerateBusKey(DeviceExtension
,
4165 ExFreePool(keyData
);
4170 resourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PUCHAR
)keyData
+
4171 keyData
->DataOffset
);
4174 // Check that the data is long enough to hold a full resource descriptor,
4175 // and that the last resouce list is device-specific and long enough.
4178 if (keyData
->DataLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) ||
4179 resourceDescriptor
->PartialResourceList
.Count
== 0 ||
4180 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].Type
!=
4181 CmResourceTypeDeviceSpecific
||
4182 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0]
4183 .u
.DeviceSpecificData
.DataSize
< sizeof(ULONG
)) {
4185 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4186 ExFreePool(keyData
);
4191 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
;
4194 // Point to the BIOS data. The BIOS data is located after the first
4195 // partial Resource list which should be device specific data.
4198 buffer
= (PUCHAR
) keyData
+ keyData
->DataOffset
+
4199 sizeof(CM_FULL_RESOURCE_DESCRIPTOR
);
4202 numberOfDrives
= length
/ sizeof(CM_INT13_DRIVE_PARAMETER
);
4205 // Use the defaults if the drive number is greater than the
4206 // number of drives detected by the BIOS.
4209 if (numberOfDrives
<= diskNumber
) {
4210 ExFreePool(keyData
);
4215 // Point to the array of drive parameters.
4218 driveParameters
= (PCM_INT13_DRIVE_PARAMETER
) buffer
+ diskNumber
;
4219 cylinders
= driveParameters
->MaxCylinders
+ 1;
4220 sectorsPerTrack
= driveParameters
->SectorsPerTrack
;
4221 tracksPerCylinder
= driveParameters
->MaxHeads
+1;
4224 // Calculate the actual number of sectors.
4227 sectors
= (ULONG
)(DeviceExtension
->PartitionLength
.QuadPart
>>
4228 DeviceExtension
->SectorShift
);
4231 if (sectors
>= cylinders
* tracksPerCylinder
* sectorsPerTrack
) {
4232 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4233 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4234 sectors
, cylinders
, tracksPerCylinder
, sectorsPerTrack
));
4239 // Since the BIOS may not report the full drive, recalculate the drive
4240 // size based on the volume size and the BIOS values for tracks per
4241 // cylinder and sectors per track..
4244 length
= tracksPerCylinder
* sectorsPerTrack
;
4249 // The BIOS information is bogus.
4252 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4253 ExFreePool(keyData
);
4257 cylinders
= sectors
/ length
;
4260 // Update the actual geometry information.
4263 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= sectorsPerTrack
;
4264 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
;
4265 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)cylinders
;
4266 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= cylinders
* tracksPerCylinder
* sectorsPerTrack
*
4267 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4270 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4275 ExFreePool(keyData
);
4277 foundEZHooker
= FALSE
;
4279 if (!DeviceExtension
->DMActive
) {
4281 HalExamineMBR(DeviceExtension
->DeviceObject
,
4282 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4290 foundEZHooker
= TRUE
;
4296 if (DeviceExtension
->DMActive
|| foundEZHooker
) {
4298 while (cylinders
> 1024) {
4300 tracksPerCylinder
= tracksPerCylinder
*2;
4301 cylinders
= cylinders
/2;
4306 // int 13 values are always 1 less.
4309 tracksPerCylinder
-= 1;
4313 // DM reserves the CE cylinder
4318 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= cylinders
+ 1;
4319 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
+ 1;
4321 DeviceExtension
->PartitionLength
.QuadPart
=
4322 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
=
4323 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
*
4324 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
*
4325 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
*
4326 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
;
4328 if (DeviceExtension
->DMActive
) {
4330 DeviceExtension
->DMByteSkew
= DeviceExtension
->DMSkew
* DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4336 DeviceExtension
->DMByteSkew
= 0;
4342 } // end UpdateGeometry()
4348 UpdateRemovableGeometry (
4349 IN PDEVICE_OBJECT DeviceObject
,
4355 Routine Description:
4357 This routines updates the size and starting offset of the device. This is
4358 used when the media on the device may have changed thereby changing the
4359 size of the device. If this is the physical device then a
4360 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4364 DeviceObject - Supplies the device object whos size needs to be updated.
4366 Irp - Supplies a reference where the status can be updated.
4370 Returns the status of the opertion.
4375 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4376 PDRIVE_LAYOUT_INFORMATION partitionList
;
4378 PDISK_DATA diskData
;
4379 ULONG partitionNumber
;
4382 // Determine if the size of the partition may have changed because
4383 // the media has changed.
4386 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
4388 return(STATUS_SUCCESS
);
4393 // If this request is for partition zero then do a read drive
4394 // capacity otherwise do a I/O read partition table.
4397 diskData
= (PDISK_DATA
) (deviceExtension
+ 1);
4400 // Read the drive capcity. If that fails, give up.
4403 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
4405 if (!NT_SUCCESS(status
)) {
4410 // Read the partition table agian.
4413 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
4414 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4419 if (!NT_SUCCESS(status
)) {
4422 // Fail the request.
4428 if (diskData
->PartitionNumber
!= 0 &&
4429 diskData
->PartitionNumber
<= partitionList
->PartitionCount
) {
4431 partitionNumber
= diskData
->PartitionNumber
- 1;
4434 // Update the partition information for this parition.
4437 diskData
->PartitionType
=
4438 partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
4440 diskData
->BootIndicator
=
4441 partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
4443 deviceExtension
->StartingOffset
=
4444 partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
4446 deviceExtension
->PartitionLength
=
4447 partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
4449 diskData
->HiddenSectors
=
4450 partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
4452 deviceExtension
->SectorShift
= ((PDEVICE_EXTENSION
)
4453 deviceExtension
->PhysicalDevice
->DeviceExtension
)->SectorShift
;
4455 } else if (diskData
->PartitionNumber
!= 0) {
4458 // The paritition does not exist. Zero all the data.
4461 diskData
->PartitionType
= 0;
4462 diskData
->BootIndicator
= 0;
4463 diskData
->HiddenSectors
= 0;
4464 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)0;
4465 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)0;
4469 // Free the parition list allocate by I/O read partition table.
4472 ExFreePool(partitionList
);
4475 return(STATUS_SUCCESS
);
4481 ScsiDiskProcessError(
4482 PDEVICE_OBJECT DeviceObject
,
4483 PSCSI_REQUEST_BLOCK Srb
,
4489 Routine Description:
4491 This routine checks the type of error. If the error indicates an underrun
4492 then indicate the request should be retried.
4496 DeviceObject - Supplies a pointer to the device object.
4498 Srb - Supplies a pointer to the failing Srb.
4500 Status - Status with which the IRP will be completed.
4502 Retry - Indication of whether the request will be retried.
4511 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4513 if (*Status
== STATUS_DATA_OVERRUN
&&
4514 ( Srb
->Cdb
[0] == SCSIOP_WRITE
|| Srb
->Cdb
[0] == SCSIOP_READ
)) {
4519 // Update the error count for the device.
4522 deviceExtension
->ErrorCount
++;
4525 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
4526 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
4529 // The disk drive should never be busy this long. Reset the scsi bus
4530 // maybe this will clear the condition.
4533 ResetScsiBus(DeviceObject
);
4536 // Update the error count for the device.
4539 deviceExtension
->ErrorCount
++;
4546 PDEVICE_OBJECT DeviceObject
,
4547 PSCSI_INQUIRY_DATA LunInfo
,
4548 PIO_SCSI_CAPABILITIES PortCapabilities
4553 Routine Description:
4555 This function checks to see if an SCSI logical unit requires speical
4560 DeviceObject - Supplies the device object to be tested.
4562 InquiryData - Supplies the inquiry data returned by the device of interest.
4564 PortCapabilities - Supplies the capabilities of the device object.
4573 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4574 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
4575 BAD_CONTROLLER_INFORMATION
const *controller
;
4578 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
4580 controller
= &ScsiDiskBadControllers
[j
];
4582 if (strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
4586 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller
->InquiryString
));
4589 // Found a listed controller. Determine what must be done.
4592 if (controller
->DisableTaggedQueuing
) {
4595 // Disable tagged queuing.
4598 deviceExtension
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
4601 if (controller
->DisableSynchronousTransfers
) {
4604 // Disable synchronous data transfers.
4607 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4611 if (controller
->DisableDisconnects
) {
4614 // Disable disconnects.
4617 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
4622 // Found device so exit the loop and return.
4629 // Set the StartUnit flag appropriately.
4632 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) {
4633 deviceExtension
->DeviceFlags
|= DEV_SAFE_START_UNIT
;
4635 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
4636 if (_strnicmp((PCCHAR
)InquiryData
->VendorId
, "iomega", strlen("iomega"))) {
4637 deviceExtension
->DeviceFlags
&= ~DEV_SAFE_START_UNIT
;
4648 IN PDEVICE_OBJECT DeviceObject
4653 Routine Description:
4655 This command sends a reset bus command to the SCSI port driver.
4659 DeviceObject - The device object for the logical unit with
4668 PIO_STACK_LOCATION irpStack
;
4670 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4671 PSCSI_REQUEST_BLOCK srb
;
4672 PCOMPLETION_CONTEXT context
;
4674 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4677 // Allocate Srb from nonpaged pool.
4680 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
4681 sizeof(COMPLETION_CONTEXT
));
4684 // Save the device object in the context for use by the completion
4688 context
->DeviceObject
= DeviceObject
;
4689 srb
= &context
->Srb
;
4695 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4698 // Write length to SRB.
4701 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4704 // Set up SCSI bus address.
4707 srb
->PathId
= deviceExtension
->PathId
;
4708 srb
->TargetId
= deviceExtension
->TargetId
;
4709 srb
->Lun
= deviceExtension
->Lun
;
4711 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4714 // Build the asynchronous request to be sent to the port driver.
4715 // Since this routine is called from a DPC the IRP should always be
4719 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
4721 IoSetCompletionRoutine(irp
,
4722 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
4728 irpStack
= IoGetNextIrpStackLocation(irp
);
4730 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4732 srb
->OriginalRequest
= irp
;
4735 // Store the SRB address in next stack for port driver.
4738 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4741 // Call the port driver with the IRP.
4744 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
4748 } // end ResetScsiBus()
4753 UpdateDeviceObjects(
4754 IN PDEVICE_OBJECT PhysicalDisk
,
4760 Routine Description:
4762 This routine creates, deletes and changes device objects when
4763 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4764 the drive layout information for the user. It is possible to
4765 call this routine even in the GET_LAYOUT case because RewritePartition
4770 DeviceObject - Device object for physical disk.
4771 Irp - IO Request Packet (IRP).
4779 PDEVICE_EXTENSION physicalExtension
= PhysicalDisk
->DeviceExtension
;
4780 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
4782 ULONG partitionNumber
;
4783 ULONG partitionCount
;
4784 ULONG lastPartition
;
4785 ULONG partitionOrdinal
;
4786 PPARTITION_INFORMATION partitionEntry
;
4787 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
4788 STRING ntNameString
;
4789 UNICODE_STRING ntUnicodeString
;
4790 PDEVICE_OBJECT deviceObject
;
4791 PDEVICE_EXTENSION deviceExtension
;
4792 PDISK_DATA diskData
;
4794 ULONG numberListElements
;
4797 partitionCount
= ((partitionList
->PartitionCount
+ 3) / 4) * 4;
4800 // Zero all of the partition numbers.
4803 for (partition
= 0; partition
< partitionCount
; partition
++) {
4804 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4805 partitionEntry
->PartitionNumber
= 0;
4809 // Walk through chain of partitions for this disk to determine
4810 // which existing partitions have no match.
4813 deviceExtension
= physicalExtension
;
4814 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4819 deviceExtension
= diskData
->NextPartition
;
4822 // Check if this is the last partition in the chain.
4825 if (!deviceExtension
) {
4830 // Get the partition device extension from disk data.
4833 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4836 // Check for highest partition number this far.
4839 if (diskData
->PartitionNumber
> lastPartition
) {
4840 lastPartition
= diskData
->PartitionNumber
;
4844 // Check if this partition is not currently being used.
4847 if (!deviceExtension
->PartitionLength
.QuadPart
) {
4852 // Loop through partition information to look for match.
4856 partitionOrdinal
= 0;
4858 for (partition
= 0; partition
< partitionCount
; partition
++) {
4861 // Get partition descriptor.
4864 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4867 // Check if empty, or describes extended partiton or hasn't changed.
4870 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4871 IsContainerPartition(partitionEntry
->PartitionType
)) {
4876 // Advance partition ordinal.
4882 // Check if new partition starts where this partition starts.
4885 if (partitionEntry
->StartingOffset
.QuadPart
!=
4886 deviceExtension
->StartingOffset
.QuadPart
) {
4891 // Check if partition length is the same.
4894 if (partitionEntry
->PartitionLength
.QuadPart
==
4895 deviceExtension
->PartitionLength
.QuadPart
) {
4898 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4899 physicalExtension
->DeviceNumber
,
4900 diskData
->PartitionNumber
));
4903 // Indicate match is found and set partition number
4908 partitionEntry
->PartitionNumber
= diskData
->PartitionNumber
;
4916 // A match is found.
4919 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4922 // If this partition is marked for update then update partition type.
4925 if (partitionEntry
->RewritePartition
) {
4926 diskData
->PartitionType
= partitionEntry
->PartitionType
;
4930 // Update partitional ordinal for calls to HAL routine
4931 // IoSetPartitionInformation.
4934 diskData
->PartitionOrdinal
= partitionOrdinal
;
4937 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4938 physicalExtension
->DeviceNumber
,
4939 diskData
->PartitionOrdinal
,
4940 diskData
->PartitionNumber
));
4945 // no match was found, indicate this partition is gone.
4949 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4950 physicalExtension
->DeviceNumber
,
4951 diskData
->PartitionNumber
));
4953 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
4959 // Walk through partition loop to find new partitions and set up
4960 // device extensions to describe them. In some cases new device
4961 // objects will be created.
4964 partitionOrdinal
= 0;
4967 partition
< partitionCount
;
4971 // Get partition descriptor.
4974 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4977 // Check if empty, or describes an extended partiton.
4980 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4981 IsContainerPartition(partitionEntry
->PartitionType
)) {
4986 // Keep track of position on the disk for calls to IoSetPartitionInformation.
4992 // Check if this entry should be rewritten.
4995 if (!partitionEntry
->RewritePartition
) {
4999 if (partitionEntry
->PartitionNumber
) {
5002 // Partition is an exact match with an existing partition, but is
5003 // being written anyway.
5010 // Check first if existing device object is available by
5011 // walking partition extension list.
5014 partitionNumber
= 0;
5015 deviceExtension
= physicalExtension
;
5016 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5021 // Get next partition device extension from disk data.
5024 deviceExtension
= diskData
->NextPartition
;
5026 if (!deviceExtension
) {
5030 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5033 // A device object is free if the partition length is set to zero.
5036 if (!deviceExtension
->PartitionLength
.QuadPart
) {
5037 partitionNumber
= diskData
->PartitionNumber
;
5044 // If partition number is still zero then a new device object
5048 if (partitionNumber
== 0) {
5051 partitionNumber
= lastPartition
;
5054 // Get or create partition object and set up partition parameters.
5057 sprintf(ntNameBuffer
,
5058 "\\Device\\Harddisk%lu\\Partition%lu",
5059 physicalExtension
->DeviceNumber
,
5062 RtlInitString(&ntNameString
,
5065 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
5069 if (!NT_SUCCESS(status
)) {
5074 "UpdateDeviceObjects: Create device object %s\n",
5078 // This is a new name. Create the device object to represent it.
5081 status
= IoCreateDevice(PhysicalDisk
->DriverObject
,
5082 DEVICE_EXTENSION_SIZE
,
5089 if (!NT_SUCCESS(status
)) {
5091 "UpdateDeviceObjects: Can't create device %s\n",
5093 RtlFreeUnicodeString(&ntUnicodeString
);
5098 // Set up device object fields.
5101 deviceObject
->Flags
|= DO_DIRECT_IO
;
5102 deviceObject
->StackSize
= PhysicalDisk
->StackSize
;
5105 // Set up device extension fields.
5108 deviceExtension
= deviceObject
->DeviceExtension
;
5111 // Copy physical disk extension to partition extension.
5114 RtlMoveMemory(deviceExtension
,
5116 sizeof(DEVICE_EXTENSION
));
5119 // Initialize the new S-List.
5122 if (deviceExtension
->SrbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
5123 numberListElements
= 30;
5125 numberListElements
= 8;
5129 // Build the lookaside list for srb's for this partition based on
5130 // whether the adapter and disk can do tagged queueing.
5133 ScsiClassInitializeSrbLookasideList(deviceExtension
,
5134 numberListElements
);
5137 // Allocate spinlock for zoning for split-request completion.
5140 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
5143 // Write back partition number used in creating object name.
5146 partitionEntry
->PartitionNumber
= partitionNumber
;
5149 // Clear flags initializing bit.
5152 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
5155 // Point back at device object.
5158 deviceExtension
->DeviceObject
= deviceObject
;
5160 RtlFreeUnicodeString(&ntUnicodeString
);
5163 // Link to end of partition chain using previous disk data.
5166 diskData
->NextPartition
= deviceExtension
;
5169 // Get new disk data and zero next partition pointer.
5172 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5173 diskData
->NextPartition
= NULL
;
5178 // Set pointer to disk data area that follows device extension.
5181 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5184 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5185 physicalExtension
->DeviceNumber
,
5190 // Update partition information in partition device extension.
5193 diskData
->PartitionNumber
= partitionNumber
;
5194 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5195 diskData
->BootIndicator
= partitionEntry
->BootIndicator
;
5196 deviceExtension
->StartingOffset
= partitionEntry
->StartingOffset
;
5197 deviceExtension
->PartitionLength
= partitionEntry
->PartitionLength
;
5198 diskData
->HiddenSectors
= partitionEntry
->HiddenSectors
;
5199 diskData
->PartitionOrdinal
= partitionOrdinal
;
5202 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5203 diskData
->PartitionOrdinal
,
5204 diskData
->PartitionNumber
));
5207 // Update partition number passed in to indicate the
5208 // device name for this partition.
5211 partitionEntry
->PartitionNumber
= partitionNumber
;
5214 } // end UpdateDeviceObjects()
5217 // This function is supposed only to support NTFS tools
5218 // from M. Russinovich. This is kind of huge hack and is
5219 // totally undocumented :-).
5222 NtfsRussinovichism(PDEVICE_OBJECT DeviceObject
,
5226 return STATUS_NOT_IMPLEMENTED
;
5230 // Hack: this function is not supposed to be implemented
5231 // Even though it's required to enable some M. Russinovich
5232 // to directly request disks so that they can dump NTFS data
5233 // without going through the driver.
5234 // We don't expect doing more from here, hence the limited
5235 // implementation and support.
5239 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject
,
5242 PIO_STACK_LOCATION Stack
;
5245 DPRINT1("ScsiDiskFileSystemControl(%p, %p)\n", DeviceObject
, Irp
);
5247 Stack
= IoGetCurrentIrpStackLocation(Irp
);
5249 switch (Stack
->MinorFunction
)
5251 case IRP_MN_USER_FS_REQUEST
:
5252 Status
= NtfsRussinovichism(DeviceObject
, Irp
);
5256 DPRINT("MinorFunction %d\n", Stack
->MinorFunction
);
5257 Status
= STATUS_INVALID_DEVICE_REQUEST
;
5261 Irp
->IoStatus
.Status
= Status
;
5262 Irp
->IoStatus
.Information
= 0;
5264 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);