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
314 #pragma alloc_text(PAGE, DriverEntry)
315 #pragma alloc_text(PAGE, FindScsiDisks)
316 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
317 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
318 #pragma alloc_text(PAGE, EnumerateBusKey)
319 #pragma alloc_text(PAGE, UpdateGeometry)
320 #pragma alloc_text(PAGE, IsFloppyDevice)
321 #pragma alloc_text(PAGE, ScanForSpecial)
322 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
323 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
330 IN PDRIVER_OBJECT DriverObject
,
331 IN PUNICODE_STRING RegistryPath
338 This routine initializes the SCSI hard disk class driver.
342 DriverObject - Pointer to driver object created by system.
344 RegistryPath - Pointer to the name of the services node for this driver.
348 The function value is the final status from the initialization operation.
353 CLASS_INIT_DATA InitializationData
;
359 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
365 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
366 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
368 InitializationData
.DeviceType
= FILE_DEVICE_DISK
;
369 InitializationData
.DeviceCharacteristics
= 0;
375 InitializationData
.ClassError
= ScsiDiskProcessError
;
376 InitializationData
.ClassReadWriteVerification
= ScsiDiskReadWriteVerification
;
377 InitializationData
.ClassFindDevices
= FindScsiDisks
;
378 InitializationData
.ClassFindDeviceCallBack
= ScsiDiskDeviceVerification
;
379 InitializationData
.ClassDeviceControl
= ScsiDiskDeviceControl
;
380 InitializationData
.ClassShutdownFlush
= ScsiDiskShutdownFlush
;
381 InitializationData
.ClassCreateClose
= NULL
;
384 // Call the class init routine
387 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
389 } // end DriverEntry()
395 ScsiDiskDeviceVerification(
396 IN PINQUIRYDATA InquiryData
403 This routine checks InquiryData for the correct device type and qualifier.
407 InquiryData - Pointer to the inquiry data for the device in question.
411 True is returned if the correct device type is found.
416 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
417 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
418 InquiryData
->DeviceTypeQualifier
== 0) {
431 IN PDRIVER_OBJECT DriverObject
,
432 IN PUNICODE_STRING RegistryPath
,
433 IN PCLASS_INIT_DATA InitializationData
,
434 IN PDEVICE_OBJECT PortDeviceObject
,
442 This routine gets a port drivers capabilities, obtains the
443 inquiry data, searches the SCSI bus for the port driver and creates
444 the device objects for the disks found.
448 DriverObject - Pointer to driver object created by system.
450 PortDeviceObject - Device object use to send requests to port driver.
452 PortNumber - Number for port driver. Used to pass on to
453 CreateDiskDeviceObjects() and create device objects.
457 True is returned if one disk was found and successfully created.
462 PIO_SCSI_CAPABILITIES portCapabilities
;
464 PCONFIGURATION_INFORMATION configurationInformation
;
466 PSCSI_INQUIRY_DATA lunInfo
;
467 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
468 PINQUIRYDATA inquiryData
;
472 BOOLEAN foundOne
= FALSE
;
477 // Call port driver to get adapter capabilities.
480 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
482 if (!NT_SUCCESS(status
)) {
483 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
488 // Call port driver to get inquiry information to find disks.
491 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
493 if (!NT_SUCCESS(status
)) {
494 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
499 // Do a quick scan of the devices on this adapter to determine how many
500 // disks are on this adapter. This is used to determine the number of
501 // SRB zone elements to allocate.
505 adapterInfo
= (PVOID
) buffer
;
507 adapterDisk
= ScsiClassFindUnclaimedDevices(InitializationData
, adapterInfo
);
510 // Allocate a zone of SRB for disks on this adapter.
513 if (adapterDisk
== 0) {
516 // No free disks were found.
523 // Get the number of disks already initialized.
526 configurationInformation
= IoGetConfigurationInformation();
527 diskCount
= &configurationInformation
->DiskCount
;
530 // For each SCSI bus this adapter supports ...
533 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
536 // Get the SCSI bus scan data for this bus.
539 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
542 // Search list for unclaimed disk devices.
545 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
547 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
549 if (((inquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
550 (inquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
551 inquiryData
->DeviceTypeQualifier
== 0 &&
552 (!lunInfo
->DeviceClaimed
)) {
555 "FindScsiDevices: Vendor string is %.24s\n",
556 inquiryData
->VendorId
));
559 // Create device objects for disk
562 status
= CreateDiskDeviceObject(DriverObject
,
571 if (NT_SUCCESS(status
)) {
574 // Increment system disk device count.
587 if (lunInfo
->NextInquiryDataOffset
== 0) {
591 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
597 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
604 } // end FindScsiDisks()
609 CreateDiskDeviceObject(
610 IN PDRIVER_OBJECT DriverObject
,
611 IN PUNICODE_STRING RegistryPath
,
612 IN PDEVICE_OBJECT PortDeviceObject
,
614 IN PULONG DeviceCount
,
615 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
616 IN PSCSI_INQUIRY_DATA LunInfo
,
617 IN PCLASS_INIT_DATA InitData
624 This routine creates an object for the physical device and then searches
625 the device for partitions and creates an object for each partition.
629 DriverObject - Pointer to driver object created by system.
631 PortDeviceObject - Miniport device object.
633 PortNumber - port number. Used in creating disk objects.
635 DeviceCount - Number of previously installed devices.
637 PortCapabilities - Capabilities of this SCSI port.
639 LunInfo - LUN specific information.
647 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
649 UNICODE_STRING ntUnicodeString
;
650 OBJECT_ATTRIBUTES objectAttributes
;
653 PDEVICE_OBJECT deviceObject
= NULL
;
654 //PDEVICE_OBJECT physicalDevice;
655 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
656 PDEVICE_EXTENSION deviceExtension
= NULL
;
657 //PDEVICE_EXTENSION physicalDeviceExtension;
658 UCHAR pathId
= LunInfo
->PathId
;
659 UCHAR targetId
= LunInfo
->TargetId
;
660 UCHAR lun
= LunInfo
->Lun
;
661 //BOOLEAN writeCache;
662 PVOID senseData
= NULL
;
665 BOOLEAN srbListInitialized
= FALSE
;
671 // Set up an object directory to contain the objects for this
672 // device and all its partitions.
675 sprintf(ntNameBuffer
,
676 "\\Device\\Harddisk%lu",
679 RtlInitString(&ntNameString
,
682 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
686 if (!NT_SUCCESS(status
)) {
690 InitializeObjectAttributes(&objectAttributes
,
692 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
696 status
= ZwCreateDirectoryObject(&handle
,
697 DIRECTORY_ALL_ACCESS
,
700 RtlFreeUnicodeString(&ntUnicodeString
);
702 if (!NT_SUCCESS(status
)) {
705 "CreateDiskDeviceObjects: Could not create directory %s\n",
715 status
= ScsiClassClaimDevice(PortDeviceObject
,
720 if (!NT_SUCCESS(status
)) {
721 ZwMakeTemporaryObject(handle
);
727 // Create a device object for this device. Each physical disk will
728 // have at least one device object. The required device object
729 // describes the entire device. Its directory path is
730 // \Device\HarddiskN\Partition0, where N = device number.
733 sprintf(ntNameBuffer
,
734 "\\Device\\Harddisk%lu\\Partition0",
738 status
= ScsiClassCreateDeviceObject(DriverObject
,
744 if (!NT_SUCCESS(status
)) {
747 "CreateDiskDeviceObjects: Can not create device object %s\n",
750 goto CreateDiskDeviceObjectsExit
;
754 // Indicate that IRPs should include MDLs for data transfers.
757 deviceObject
->Flags
|= DO_DIRECT_IO
;
760 // Check if this is during initialization. If not indicate that
761 // system initialization already took place and this disk is ready
766 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
770 // Check for removable media support.
773 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->RemovableMedia
) {
774 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
778 // Set up required stack size in device object.
781 deviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
783 deviceExtension
= deviceObject
->DeviceExtension
;
786 // Allocate spinlock for split request completion.
789 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
792 // Initialize lock count to zero. The lock count is used to
793 // disable the ejection mechanism on devices that support
794 // removable media. Only the lock count in the physical
795 // device extension is used.
798 deviceExtension
->LockCount
= 0;
801 // Save system disk number.
804 deviceExtension
->DeviceNumber
= *DeviceCount
;
807 // Copy port device object pointer to the device extension.
810 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
813 // Set the alignment requirements for the device based on the
814 // host adapter requirements
817 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
818 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
822 // This is the physical device object.
825 //physicalDevice = deviceObject;
826 //physicalDeviceExtension = deviceExtension;
829 // Save address of port driver capabilities.
832 deviceExtension
->PortCapabilities
= PortCapabilities
;
835 // Build the lookaside list for srb's for the physical disk. Should only
839 ScsiClassInitializeSrbLookasideList(deviceExtension
,
840 PARTITION0_LIST_SIZE
);
842 srbListInitialized
= TRUE
;
845 // Initialize the srb flags.
848 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->CommandQueue
&&
849 PortCapabilities
->TaggedQueuing
) {
851 deviceExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
855 deviceExtension
->SrbFlags
= 0;
860 // Allow queued requests if this is not removable media.
863 if (!(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
865 deviceExtension
->SrbFlags
|= SRB_FLAGS_NO_QUEUE_FREEZE
;
870 // Look for controller that require special flags.
873 ScanForSpecial(deviceObject
,
877 //srbFlags = deviceExtension->SrbFlags;
880 // Allocate buffer for drive geometry.
883 diskGeometry
= ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
885 if (diskGeometry
== NULL
) {
888 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
889 status
= STATUS_INSUFFICIENT_RESOURCES
;
890 goto CreateDiskDeviceObjectsExit
;
893 deviceExtension
->DiskGeometry
= diskGeometry
;
896 // Allocate request sense buffer.
899 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
901 if (senseData
== NULL
) {
904 // The buffer can not be allocated.
908 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
910 status
= STATUS_INSUFFICIENT_RESOURCES
;
911 goto CreateDiskDeviceObjectsExit
;
915 // Set the sense data pointer in the device extension.
918 deviceExtension
->SenseData
= senseData
;
921 // Physical device object will describe the entire
922 // device, starting at byte offset 0.
925 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)(0);
928 // TargetId/LUN describes a device location on the SCSI bus.
929 // This information comes from the inquiry buffer.
932 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
933 deviceExtension
->PathId
= pathId
;
934 deviceExtension
->TargetId
= targetId
;
935 deviceExtension
->Lun
= lun
;
938 // Set timeout value in seconds.
941 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
943 deviceExtension
->TimeOutValue
= timeOut
;
945 deviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
949 // Back pointer to device object.
952 deviceExtension
->DeviceObject
= deviceObject
;
955 // If this is a removable device, then make sure it is not a floppy.
956 // Perform a mode sense command to determine the media type. Note
957 // IsFloppyDevice also checks for write cache enabled.
960 if (IsFloppyDevice(deviceObject
) && deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
961 (((PINQUIRYDATA
)LunInfo
->InquiryData
)->DeviceType
== DIRECT_ACCESS_DEVICE
)) {
963 status
= STATUS_NO_SUCH_DEVICE
;
964 goto CreateDiskDeviceObjectsExit
;
967 DisableWriteCache(deviceObject
,LunInfo
);
969 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
972 // NOTE: At this point one device object has been successfully created.
973 // from here on out return success.
977 // Do READ CAPACITY. This SCSI command
978 // returns the number of bytes on a device.
979 // Device extension is updated with device size.
982 status
= ScsiClassReadDriveCapacity(deviceObject
);
985 // If the read capcity failed then just return, unless this is a
986 // removable disk where a device object partition needs to be created.
989 if (!NT_SUCCESS(status
) &&
990 !(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
993 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
996 return(STATUS_SUCCESS
);
1001 // Make sure the volume verification bit is off so that
1002 // IoReadPartitionTable will work.
1005 deviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
1008 status
= CreatePartitionDeviceObjects(deviceObject
, RegistryPath
);
1010 if (NT_SUCCESS(status
))
1011 return STATUS_SUCCESS
;
1014 CreateDiskDeviceObjectsExit
:
1017 // Release the device since an error occurred.
1020 ScsiClassClaimDevice(PortDeviceObject
,
1025 if (diskGeometry
!= NULL
) {
1026 ExFreePool(diskGeometry
);
1029 if (senseData
!= NULL
) {
1030 ExFreePool(senseData
);
1033 if (deviceObject
!= NULL
) {
1035 if (srbListInitialized
) {
1036 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1039 IoDeleteDevice(deviceObject
);
1043 // Delete directory and return.
1046 if (!NT_SUCCESS(status
)) {
1047 ZwMakeTemporaryObject(handle
);
1054 } // end CreateDiskDeviceObjects()
1059 CreatePartitionDeviceObjects(
1060 IN PDEVICE_OBJECT PhysicalDeviceObject
,
1061 IN PUNICODE_STRING RegistryPath
1064 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
1065 ULONG partitionNumber
= 0;
1067 PDEVICE_OBJECT deviceObject
= NULL
;
1068 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
1069 PDRIVE_LAYOUT_INFORMATION partitionList
= NULL
;
1070 PDEVICE_EXTENSION deviceExtension
;
1071 PDEVICE_EXTENSION physicalDeviceExtension
;
1072 PCLASS_INIT_DATA initData
= NULL
;
1073 PDISK_DATA diskData
;
1074 PDISK_DATA physicalDiskData
;
1075 ULONG bytesPerSector
;
1078 ULONG dmByteSkew
= 0;
1080 BOOLEAN dmActive
= FALSE
;
1081 ULONG numberListElements
= 0;
1085 // Get physical device geometry information for partition table reads.
1088 physicalDeviceExtension
= PhysicalDeviceObject
->DeviceExtension
;
1089 diskGeometry
= physicalDeviceExtension
->DiskGeometry
;
1090 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
;
1093 // Make sure sector size is not zero.
1096 if (bytesPerSector
== 0) {
1099 // Default sector size for disk is 512.
1102 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
= 512;
1105 sectorShift
= physicalDeviceExtension
->SectorShift
;
1108 // Set pointer to disk data area that follows device extension.
1111 diskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1112 diskData
->PartitionListState
= Initializing
;
1115 // Determine is DM Driver is loaded on an IDE drive that is
1116 // under control of Atapi - this could be either a crashdump or
1117 // an Atapi device is sharing the controller with an IDE disk.
1120 HalExamineMBR(PhysicalDeviceObject
,
1121 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1128 // Update the device extension, so that the call to IoReadPartitionTable
1129 // will get the correct information. Any I/O to this disk will have
1130 // to be skewed by *dmSkew sectors aka DMByteSkew.
1133 physicalDeviceExtension
->DMSkew
= *dmSkew
;
1134 physicalDeviceExtension
->DMActive
= TRUE
;
1135 physicalDeviceExtension
->DMByteSkew
= physicalDeviceExtension
->DMSkew
* bytesPerSector
;
1138 // Save away the infomation that we need, since this deviceExtension will soon be
1143 dmByteSkew
= physicalDeviceExtension
->DMByteSkew
;
1148 // Create objects for all the partitions on the device.
1151 status
= IoReadPartitionTable(PhysicalDeviceObject
,
1152 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1154 (PVOID
)&partitionList
);
1157 // If the I/O read partition table failed and this is a removable device,
1158 // then fix up the partition list to make it look like there is one
1159 // zero length partition.
1161 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status
);
1162 if ((!NT_SUCCESS(status
) || partitionList
->PartitionCount
== 0) &&
1163 PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1165 if (!NT_SUCCESS(status
)) {
1168 // Remember this disk is not ready.
1171 diskData
->DriveNotReady
= TRUE
;
1176 // Free the partition list allocated by IoReadPartitionTable.
1179 ExFreePool(partitionList
);
1183 // Allocate and zero a partition list.
1186 partitionList
= ExAllocatePool(NonPagedPool
, sizeof(*partitionList
));
1189 if (partitionList
!= NULL
) {
1191 RtlZeroMemory( partitionList
, sizeof( *partitionList
));
1194 // Set the partition count to one and the status to success
1195 // so one device object will be created. Set the partition type
1196 // to a bogus value.
1199 partitionList
->PartitionCount
= 1;
1201 status
= STATUS_SUCCESS
;
1205 if (NT_SUCCESS(status
)) {
1208 // Record disk signature.
1211 diskData
->Signature
= partitionList
->Signature
;
1214 // If disk signature is zero, then calculate the MBR checksum.
1217 if (!diskData
->Signature
) {
1219 if (!CalculateMbrCheckSum(physicalDeviceExtension
,
1220 &diskData
->MbrCheckSum
)) {
1223 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1224 physicalDeviceExtension
->DeviceNumber
));
1228 "SCSIDISK: MBR checksum for disk %x is %x\n",
1229 physicalDeviceExtension
->DeviceNumber
,
1230 diskData
->MbrCheckSum
));
1235 // Check the registry and determine if the BIOS knew about this drive. If
1236 // it did then update the geometry with the BIOS information.
1239 UpdateGeometry(physicalDeviceExtension
);
1241 srbFlags
= physicalDeviceExtension
->SrbFlags
;
1243 initData
= ExAllocatePool(NonPagedPool
, sizeof(CLASS_INIT_DATA
));
1247 "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n"));
1249 status
= STATUS_INSUFFICIENT_RESOURCES
;
1250 goto CreatePartitionDeviceObjectsExit
;
1253 RtlZeroMemory(initData
, sizeof(CLASS_INIT_DATA
));
1255 initData
->InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
1256 initData
->DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
1257 initData
->DeviceType
= FILE_DEVICE_DISK
;
1258 initData
->DeviceCharacteristics
= PhysicalDeviceObject
->Characteristics
;
1259 initData
->ClassError
= physicalDeviceExtension
->ClassError
;
1260 initData
->ClassReadWriteVerification
= physicalDeviceExtension
->ClassReadWriteVerification
;
1261 initData
->ClassFindDevices
= physicalDeviceExtension
->ClassFindDevices
;
1262 initData
->ClassDeviceControl
= physicalDeviceExtension
->ClassDeviceControl
;
1263 initData
->ClassShutdownFlush
= physicalDeviceExtension
->ClassShutdownFlush
;
1264 initData
->ClassCreateClose
= physicalDeviceExtension
->ClassCreateClose
;
1265 initData
->ClassStartIo
= physicalDeviceExtension
->ClassStartIo
;
1268 // Create device objects for the device partitions (if any).
1269 // PartitionCount includes physical device partition 0,
1270 // so only one partition means no objects to create.
1274 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1275 partitionList
->PartitionCount
));
1277 for (partitionNumber
= 0; partitionNumber
<
1278 partitionList
->PartitionCount
; partitionNumber
++) {
1281 // Create partition object and set up partition parameters.
1284 sprintf(ntNameBuffer
,
1285 "\\Device\\Harddisk%lu\\Partition%lu",
1286 physicalDeviceExtension
->DeviceNumber
,
1287 partitionNumber
+ 1);
1290 "CreateDiskDeviceObjects: Create device object %s\n",
1293 status
= ScsiClassCreateDeviceObject(PhysicalDeviceObject
->DriverObject
,
1295 PhysicalDeviceObject
,
1299 if (!NT_SUCCESS(status
)) {
1301 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer
));
1307 // Set up device object fields.
1310 deviceObject
->Flags
|= DO_DIRECT_IO
;
1313 // Check if this is during initialization. If not indicate that
1314 // system initialization already took place and this disk is ready
1318 if (!RegistryPath
) {
1319 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1322 deviceObject
->StackSize
= (CCHAR
)physicalDeviceExtension
->PortDeviceObject
->StackSize
+ 1;
1325 // Set up device extension fields.
1328 deviceExtension
= deviceObject
->DeviceExtension
;
1333 // Restore any saved DM values.
1336 deviceExtension
->DMByteSkew
= dmByteSkew
;
1337 deviceExtension
->DMSkew
= *dmSkew
;
1338 deviceExtension
->DMActive
= TRUE
;
1343 // Link new device extension to previous disk data
1344 // to support dynamic partitioning.
1347 diskData
->NextPartition
= deviceExtension
;
1350 // Get pointer to new disk data.
1353 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1356 // Set next partition pointer to NULL in case this is the
1360 diskData
->NextPartition
= NULL
;
1363 // Allocate spinlock for zoning for split-request completion.
1366 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
1369 // Copy port device object pointer to device extension.
1372 deviceExtension
->PortDeviceObject
= physicalDeviceExtension
->PortDeviceObject
;
1375 // Set the alignment requirements for the device based on the
1376 // host adapter requirements
1379 if (physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
1380 deviceObject
->AlignmentRequirement
= physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
;
1384 if (srbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
1385 numberListElements
= 30;
1387 numberListElements
= 8;
1391 // Build the lookaside list for srb's for this partition based on
1392 // whether the adapter and disk can do tagged queueing.
1395 ScsiClassInitializeSrbLookasideList(deviceExtension
,
1396 numberListElements
);
1398 deviceExtension
->SrbFlags
= srbFlags
;
1401 // Set the sense-data pointer in the device extension.
1404 deviceExtension
->SenseData
= physicalDeviceExtension
->SenseData
;
1405 deviceExtension
->PortCapabilities
= physicalDeviceExtension
->PortCapabilities
;
1406 deviceExtension
->DiskGeometry
= diskGeometry
;
1407 diskData
->PartitionOrdinal
= diskData
->PartitionNumber
= partitionNumber
+ 1;
1408 diskData
->PartitionType
= partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
1409 diskData
->BootIndicator
= partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
1411 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1412 diskData
->PartitionType
));
1414 deviceExtension
->StartingOffset
= partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
1415 deviceExtension
->PartitionLength
= partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
1416 diskData
->HiddenSectors
= partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
1417 deviceExtension
->PortNumber
= physicalDeviceExtension
->PortNumber
;
1418 deviceExtension
->PathId
= physicalDeviceExtension
->PathId
;
1419 deviceExtension
->TargetId
= physicalDeviceExtension
->TargetId
;
1420 deviceExtension
->Lun
= physicalDeviceExtension
->Lun
;
1423 // Check for removable media support.
1426 if (PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1427 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
1431 // Set timeout value in seconds.
1434 deviceExtension
->TimeOutValue
= physicalDeviceExtension
->TimeOutValue
;
1435 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bytesPerSector
;
1436 deviceExtension
->SectorShift
= sectorShift
;
1437 deviceExtension
->DeviceObject
= deviceObject
;
1438 deviceExtension
->DeviceFlags
|= physicalDeviceExtension
->DeviceFlags
;
1440 } // end for (partitionNumber) ...
1443 // Free the buffer allocated by reading the
1447 ExFreePool(partitionList
);
1455 CreatePartitionDeviceObjectsExit
:
1457 if (partitionList
) {
1458 ExFreePool(partitionList
);
1461 ExFreePool(initData
);
1473 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1474 physicalDiskData
->PartitionListState
= Initialized
;
1476 return(STATUS_SUCCESS
);
1479 } // end CreatePartitionDeviceObjects()
1484 ScsiDiskReadWriteVerification(
1485 IN PDEVICE_OBJECT DeviceObject
,
1491 Routine Description:
1493 I/O System entry for read and write requests to SCSI disks.
1497 DeviceObject - Pointer to driver object created by system.
1507 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1508 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1509 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1510 LARGE_INTEGER startingOffset
;
1513 // Verify parameters of this request.
1514 // Check that ending sector is within partition and
1515 // that number of bytes to transfer is a multiple of
1519 startingOffset
.QuadPart
= (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
1522 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
1523 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
1526 // This error maybe caused by the fact that the drive is not ready.
1529 if (((PDISK_DATA
)(deviceExtension
+ 1))->DriveNotReady
) {
1532 // Flag this as a user errror so that a popup is generated.
1535 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
1536 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1541 // Note fastfat depends on this parameter to determine when to
1542 // remount do to a sector size change.
1545 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1548 return STATUS_INVALID_PARAMETER
;
1551 return STATUS_SUCCESS
;
1553 } // end ScsiDiskReadWrite()
1558 ScsiDiskDeviceControl(
1559 PDEVICE_OBJECT DeviceObject
,
1565 Routine Description:
1567 I/O system entry for device controls to SCSI disks.
1571 DeviceObject - Pointer to driver object created by system.
1581 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1582 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1583 PDISK_DATA diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1584 PSCSI_REQUEST_BLOCK srb
;
1586 PMODE_PARAMETER_HEADER modeData
;
1591 IO_STATUS_BLOCK ioStatus
;
1595 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
1599 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1600 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1601 return(STATUS_INSUFFICIENT_RESOURCES
);
1605 // Write zeros to Srb.
1608 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1610 cdb
= (PCDB
)srb
->Cdb
;
1612 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1614 case SMART_GET_VERSION
: {
1617 PSRB_IO_CONTROL srbControl
;
1618 PGETVERSIONINPARAMS versionParams
;
1620 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1621 sizeof(GETVERSIONINPARAMS
)) {
1622 status
= STATUS_INVALID_PARAMETER
;
1627 // Create notification event object to be used to signal the
1628 // request completion.
1631 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1633 srbControl
= ExAllocatePool(NonPagedPool
,
1634 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
));
1637 status
= STATUS_INSUFFICIENT_RESOURCES
;
1642 // fill in srbControl fields
1645 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1646 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1647 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1648 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1649 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1652 // Point to the 'buffer' portion of the SRB_CONTROL
1655 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1658 // Ensure correct target is set in the cmd parameters.
1661 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1662 versionParams
->bIDEDeviceMap
= deviceExtension
->TargetId
;
1665 // Copy the IOCTL parameters to the srb control buffer area.
1668 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(GETVERSIONINPARAMS
));
1671 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1672 deviceExtension
->PortDeviceObject
,
1674 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1676 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1682 status
= STATUS_INSUFFICIENT_RESOURCES
;
1687 // Call the port driver with the request and wait for it to complete.
1690 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1692 if (status
== STATUS_PENDING
) {
1693 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1694 status
= ioStatus
.Status
;
1698 // If successful, copy the data received into the output buffer.
1699 // This should only fail in the event that the IDE driver is older than this driver.
1702 if (NT_SUCCESS(status
)) {
1704 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1706 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, sizeof(GETVERSIONINPARAMS
));
1707 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1710 ExFreePool(srbControl
);
1714 case SMART_RCV_DRIVE_DATA
: {
1716 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1717 ULONG controlCode
= 0;
1718 PSRB_IO_CONTROL srbControl
;
1721 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1722 (sizeof(SENDCMDINPARAMS
) - 1)) {
1723 status
= STATUS_INVALID_PARAMETER
;
1726 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1727 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1728 status
= STATUS_INVALID_PARAMETER
;
1733 // Create notification event object to be used to signal the
1734 // request completion.
1737 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1739 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1741 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1742 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1744 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1745 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1746 case READ_ATTRIBUTES
:
1747 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1748 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1750 case READ_THRESHOLDS
:
1751 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1752 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1755 status
= STATUS_INVALID_PARAMETER
;
1760 status
= STATUS_INVALID_PARAMETER
;
1763 if (controlCode
== 0) {
1764 status
= STATUS_INVALID_PARAMETER
;
1768 srbControl
= ExAllocatePool(NonPagedPool
,
1769 sizeof(SRB_IO_CONTROL
) + length
);
1772 status
= STATUS_INSUFFICIENT_RESOURCES
;
1777 // fill in srbControl fields
1780 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1781 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1782 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1783 srbControl
->Length
= length
;
1784 srbControl
->ControlCode
= controlCode
;
1787 // Point to the 'buffer' portion of the SRB_CONTROL
1790 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1793 // Ensure correct target is set in the cmd parameters.
1796 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1799 // Copy the IOCTL parameters to the srb control buffer area.
1802 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1804 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1805 deviceExtension
->PortDeviceObject
,
1807 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1809 sizeof(SRB_IO_CONTROL
) + length
,
1815 status
= STATUS_INSUFFICIENT_RESOURCES
;
1820 // Call the port driver with the request and wait for it to complete.
1823 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1825 if (status
== STATUS_PENDING
) {
1826 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1827 status
= ioStatus
.Status
;
1831 // If successful, copy the data received into the output buffer
1834 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1836 if (NT_SUCCESS(status
)) {
1838 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
- 1);
1839 Irp
->IoStatus
.Information
= length
- 1;
1843 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1844 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1848 ExFreePool(srbControl
);
1853 case SMART_SEND_DRIVE_COMMAND
: {
1855 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1856 PSRB_IO_CONTROL srbControl
;
1857 ULONG controlCode
= 0;
1860 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1861 (sizeof(SENDCMDINPARAMS
) - 1)) {
1862 status
= STATUS_INVALID_PARAMETER
;
1865 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1866 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1867 status
= STATUS_INVALID_PARAMETER
;
1872 // Create notification event object to be used to signal the
1873 // request completion.
1876 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1880 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1881 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1884 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1888 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1891 case RETURN_SMART_STATUS
:
1894 // Ensure bBuffer is at least 2 bytes (to hold the values of
1895 // cylinderLow and cylinderHigh).
1898 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1899 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1901 status
= STATUS_INVALID_PARAMETER
;
1905 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1906 length
= sizeof(IDEREGS
);
1909 case ENABLE_DISABLE_AUTOSAVE
:
1910 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1913 case SAVE_ATTRIBUTE_VALUES
:
1914 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1917 case EXECUTE_OFFLINE_DIAGS
:
1918 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1922 status
= STATUS_INVALID_PARAMETER
;
1927 status
= STATUS_INVALID_PARAMETER
;
1930 if (controlCode
== 0) {
1931 status
= STATUS_INVALID_PARAMETER
;
1935 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1936 srbControl
= ExAllocatePool(NonPagedPool
,
1937 sizeof(SRB_IO_CONTROL
) + length
);
1940 status
= STATUS_INSUFFICIENT_RESOURCES
;
1945 // fill in srbControl fields
1948 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1949 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1950 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1951 srbControl
->Length
= length
;
1954 // Point to the 'buffer' portion of the SRB_CONTROL
1957 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1960 // Ensure correct target is set in the cmd parameters.
1963 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1966 // Copy the IOCTL parameters to the srb control buffer area.
1969 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1971 srbControl
->ControlCode
= controlCode
;
1973 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1974 deviceExtension
->PortDeviceObject
,
1976 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1978 sizeof(SRB_IO_CONTROL
) + length
,
1984 status
= STATUS_INSUFFICIENT_RESOURCES
;
1989 // Call the port driver with the request and wait for it to complete.
1992 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1994 if (status
== STATUS_PENDING
) {
1995 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1996 status
= ioStatus
.Status
;
2000 // Copy the data received into the output buffer. Since the status buffer
2001 // contains error information also, always perform this copy. IO will will
2002 // either pass this back to the app, or zero it, in case of error.
2005 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2008 // Update the return buffer size based on the sub-command.
2011 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
2012 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
2014 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
2017 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
);
2018 Irp
->IoStatus
.Information
= length
;
2020 ExFreePool(srbControl
);
2025 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2026 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2029 PDEVICE_EXTENSION physicalDeviceExtension
;
2030 PDISK_DATA physicalDiskData
;
2031 BOOLEAN removable
= FALSE
;
2032 BOOLEAN listInitialized
= FALSE
;
2034 if ((irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
&&
2035 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2036 sizeof(DISK_GEOMETRY
)) ||
2037 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
&&
2038 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2039 sizeof(DISK_GEOMETRY_EX
))) {
2041 status
= STATUS_INFO_LENGTH_MISMATCH
;
2045 status
= STATUS_SUCCESS
;
2047 physicalDeviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2048 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
2050 removable
= (BOOLEAN
)DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
;
2051 listInitialized
= (physicalDiskData
->PartitionListState
== Initialized
);
2053 if (removable
|| (!listInitialized
))
2056 // Issue ReadCapacity to update device extension
2057 // with information for current media.
2060 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
2066 if (!NT_SUCCESS(status
)) {
2069 // Note the drive is not ready.
2072 diskData
->DriveNotReady
= TRUE
;
2078 // Note the drive is now ready.
2081 diskData
->DriveNotReady
= FALSE
;
2083 } else if (NT_SUCCESS(status
)) {
2085 // ReadDriveCapacity was allright, create Partition Objects
2087 if (physicalDiskData
->PartitionListState
== NotInitialized
) {
2088 status
= CreatePartitionDeviceObjects(deviceExtension
->PhysicalDevice
, NULL
);
2092 if (NT_SUCCESS(status
)) {
2095 // Copy drive geometry information from device extension.
2098 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2099 deviceExtension
->DiskGeometry
,
2100 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2101 sizeof(DISK_GEOMETRY
) :
2102 sizeof(DISK_GEOMETRY_EX
));
2104 status
= STATUS_SUCCESS
;
2105 Irp
->IoStatus
.Information
=
2106 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2107 sizeof(DISK_GEOMETRY
) :
2108 sizeof(DISK_GEOMETRY_EX
);
2115 case IOCTL_DISK_VERIFY
:
2119 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2120 LARGE_INTEGER byteOffset
;
2125 // Validate buffer length.
2128 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2129 sizeof(VERIFY_INFORMATION
)) {
2131 status
= STATUS_INFO_LENGTH_MISMATCH
;
2139 srb
->CdbLength
= 10;
2141 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2144 // Add disk offset to starting sector.
2147 byteOffset
.QuadPart
= deviceExtension
->StartingOffset
.QuadPart
+
2148 verifyInfo
->StartingOffset
.QuadPart
;
2151 // Convert byte offset to sector offset.
2154 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2157 // Convert ULONG byte count to USHORT sector count.
2160 sectorCount
= (USHORT
)(verifyInfo
->Length
>> deviceExtension
->SectorShift
);
2163 // Move little endian values into CDB in big endian format.
2166 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2167 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2168 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2169 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2171 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2172 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2175 // The verify command is used by the NT FORMAT utility and
2176 // requests are sent down for 5% of the volume size. The
2177 // request timeout value is calculated based on the number of
2178 // sectors verified.
2181 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2182 deviceExtension
->TimeOutValue
;
2184 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
2195 case IOCTL_DISK_GET_PARTITION_INFO
:
2198 // Return the information about the partition specified by the device
2199 // object. Note that no information is ever returned about the size
2200 // or partition type of the physical disk, as this doesn't make any
2204 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2205 sizeof(PARTITION_INFORMATION
)) {
2207 status
= STATUS_INFO_LENGTH_MISMATCH
;
2210 #if 0 // HACK: ReactOS partition numbers must be wrong
2211 else if (diskData
->PartitionNumber
== 0) {
2214 // Paritition zero is not a partition so this is not a
2215 // reasonable request.
2218 status
= STATUS_INVALID_DEVICE_REQUEST
;
2224 PPARTITION_INFORMATION outputBuffer
;
2227 // Update the geometry in case it has changed.
2230 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2232 if (!NT_SUCCESS(status
)) {
2235 // Note the drive is not ready.
2238 diskData
->DriveNotReady
= TRUE
;
2243 // Note the drive is now ready.
2246 diskData
->DriveNotReady
= FALSE
;
2247 // HACK: ReactOS partition numbers must be wrong (>0 part)
2248 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2250 status
= STATUS_INVALID_DEVICE_REQUEST
;
2255 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2257 outputBuffer
->PartitionType
= diskData
->PartitionType
;
2258 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2259 outputBuffer
->PartitionLength
.QuadPart
= (diskData
->PartitionNumber
) ?
2260 deviceExtension
->PartitionLength
.QuadPart
: 2305843009213693951LL; // HACK
2261 outputBuffer
->HiddenSectors
= diskData
->HiddenSectors
;
2262 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2263 outputBuffer
->BootIndicator
= diskData
->BootIndicator
;
2264 outputBuffer
->RewritePartition
= FALSE
;
2265 outputBuffer
->RecognizedPartition
=
2266 IsRecognizedPartition(diskData
->PartitionType
);
2268 status
= STATUS_SUCCESS
;
2269 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2274 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2277 // Return the information about the partition specified by the device
2278 // object. Note that no information is ever returned about the size
2279 // or partition type of the physical disk, as this doesn't make any
2283 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2284 sizeof(PARTITION_INFORMATION_EX
)) {
2286 status
= STATUS_INFO_LENGTH_MISMATCH
;
2289 else if (diskData
->PartitionNumber
== 0) {
2292 // Paritition zero is not a partition so this is not a
2293 // reasonable request.
2296 status
= STATUS_INVALID_DEVICE_REQUEST
;
2301 PPARTITION_INFORMATION_EX outputBuffer
;
2304 // Update the geometry in case it has changed.
2307 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2309 if (!NT_SUCCESS(status
)) {
2312 // Note the drive is not ready.
2315 diskData
->DriveNotReady
= TRUE
;
2320 // Note the drive is now ready.
2323 diskData
->DriveNotReady
= FALSE
;
2325 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2327 status
= STATUS_INVALID_DEVICE_REQUEST
;
2332 (PPARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
2335 // FIXME: hack of the year, assume that partition is MBR
2336 // Thing that can obviously be wrong...
2339 outputBuffer
->PartitionStyle
= PARTITION_STYLE_MBR
;
2340 outputBuffer
->Mbr
.PartitionType
= diskData
->PartitionType
;
2341 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2342 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2343 outputBuffer
->Mbr
.HiddenSectors
= diskData
->HiddenSectors
;
2344 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2345 outputBuffer
->Mbr
.BootIndicator
= diskData
->BootIndicator
;
2346 outputBuffer
->RewritePartition
= FALSE
;
2347 outputBuffer
->Mbr
.RecognizedPartition
=
2348 IsRecognizedPartition(diskData
->PartitionType
);
2350 status
= STATUS_SUCCESS
;
2351 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
2356 case IOCTL_DISK_SET_PARTITION_INFO
:
2358 if (diskData
->PartitionNumber
== 0) {
2360 status
= STATUS_UNSUCCESSFUL
;
2364 PSET_PARTITION_INFORMATION inputBuffer
=
2365 (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2368 // Validate buffer length.
2371 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2372 sizeof(SET_PARTITION_INFORMATION
)) {
2374 status
= STATUS_INFO_LENGTH_MISMATCH
;
2379 // The HAL routines IoGet- and IoSetPartitionInformation were
2380 // developed before support of dynamic partitioning and therefore
2381 // don't distinguish between partition ordinal (that is the order
2382 // of a partition on a disk) and the partition number. (The
2383 // partition number is assigned to a partition to identify it to
2384 // the system.) Use partition ordinals for these legacy calls.
2387 status
= IoSetPartitionInformation(
2388 deviceExtension
->PhysicalDevice
,
2389 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2390 diskData
->PartitionOrdinal
,
2391 inputBuffer
->PartitionType
);
2393 if (NT_SUCCESS(status
)) {
2395 diskData
->PartitionType
= inputBuffer
->PartitionType
;
2401 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2404 // Return the partition layout for the physical drive. Note that
2405 // the layout is returned for the actual physical drive, regardless
2406 // of which partition was specified for the request.
2409 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2410 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2411 status
= STATUS_INFO_LENGTH_MISMATCH
;
2415 PDRIVE_LAYOUT_INFORMATION partitionList
;
2416 PDEVICE_EXTENSION physicalExtension
= deviceExtension
;
2417 PPARTITION_INFORMATION partitionEntry
;
2418 PDISK_DATA diskData
;
2423 // Read partition information.
2426 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
2427 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2431 if (!NT_SUCCESS(status
)) {
2436 // The disk layout has been returned in the partitionList
2437 // buffer. Determine its size and, if the data will fit
2438 // into the intermediatery buffer, return it.
2441 tempSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,PartitionEntry
[0]);
2442 tempSize
+= partitionList
->PartitionCount
*
2443 sizeof(PARTITION_INFORMATION
);
2446 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
2448 status
= STATUS_BUFFER_TOO_SMALL
;
2449 ExFreePool(partitionList
);
2454 // Walk partition list to associate partition numbers with
2455 // partition entries.
2458 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
2461 // Walk partition chain anchored at physical disk extension.
2464 deviceExtension
= physicalExtension
;
2465 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2469 deviceExtension
= diskData
->NextPartition
;
2472 // Check if this is the last partition in the chain.
2475 if (!deviceExtension
) {
2480 // Get the partition device extension from disk data.
2483 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2486 // Check if this partition is not currently being used.
2489 if (!deviceExtension
->PartitionLength
.QuadPart
) {
2493 partitionEntry
= &partitionList
->PartitionEntry
[i
];
2496 // Check if empty, or describes extended partiton or hasn't changed.
2499 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2500 IsContainerPartition(partitionEntry
->PartitionType
)) {
2505 // Check if new partition starts where this partition starts.
2508 if (partitionEntry
->StartingOffset
.QuadPart
!=
2509 deviceExtension
->StartingOffset
.QuadPart
) {
2514 // Check if partition length is the same.
2517 if (partitionEntry
->PartitionLength
.QuadPart
==
2518 deviceExtension
->PartitionLength
.QuadPart
) {
2521 // Partitions match. Update partition number.
2524 partitionEntry
->PartitionNumber
=
2525 diskData
->PartitionNumber
;
2533 // Copy partition information to system buffer.
2536 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2539 status
= STATUS_SUCCESS
;
2540 Irp
->IoStatus
.Information
= tempSize
;
2543 // Finally, free the buffer allocated by reading the
2547 ExFreePool(partitionList
);
2552 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
2557 // Update the disk with new partition information.
2560 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
2563 // Validate buffer length.
2566 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2567 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2569 status
= STATUS_INFO_LENGTH_MISMATCH
;
2573 length
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2574 (partitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
);
2577 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2580 status
= STATUS_BUFFER_TOO_SMALL
;
2585 // Verify that device object is for physical disk.
2588 if (deviceExtension
->PhysicalDevice
->DeviceExtension
!= deviceExtension
) {
2589 status
= STATUS_INVALID_PARAMETER
;
2594 // Walk through partition table comparing partitions to
2595 // existing partitions to create, delete and change
2596 // device objects as necessary.
2599 UpdateDeviceObjects(DeviceObject
,
2603 // Write changes to disk.
2606 status
= IoWritePartitionTable(
2607 deviceExtension
->DeviceObject
,
2608 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2609 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
,
2610 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
,
2615 // Update IRP with bytes returned.
2618 if (NT_SUCCESS(status
)) {
2619 Irp
->IoStatus
.Information
= length
;
2624 case IOCTL_DISK_REASSIGN_BLOCKS
:
2627 // Map defective blocks to new location on disk.
2632 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2638 // Validate buffer length.
2641 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2642 sizeof(REASSIGN_BLOCKS
)) {
2644 status
= STATUS_INFO_LENGTH_MISMATCH
;
2648 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2649 (badBlocks
->Count
- 1) * sizeof(ULONG
);
2651 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2654 status
= STATUS_INFO_LENGTH_MISMATCH
;
2659 // Build the data buffer to be transferred in the input buffer.
2660 // The format of the data to the device is:
2664 // x * 4 btyes Block Address
2666 // All values are big endian.
2669 badBlocks
->Reserved
= 0;
2670 blockCount
= badBlocks
->Count
;
2673 // Convert # of entries to # of bytes.
2677 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2678 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2681 // Convert back to number of entries.
2686 for (; blockCount
> 0; blockCount
--) {
2688 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2690 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2691 (PFOUR_BYTE
) &blockNumber
);
2696 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2699 // Set timeout value.
2702 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2704 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2710 Irp
->IoStatus
.Status
= status
;
2711 Irp
->IoStatus
.Information
= 0;
2713 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2718 case IOCTL_DISK_IS_WRITABLE
:
2721 // Determine if the device is writable.
2724 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
2726 if (modeData
== NULL
) {
2727 status
= STATUS_INSUFFICIENT_RESOURCES
;
2731 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
2733 length
= ScsiClassModeSense(DeviceObject
,
2736 MODE_SENSE_RETURN_ALL
);
2738 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2741 // Retry the request in case of a check condition.
2744 length
= ScsiClassModeSense(DeviceObject
,
2747 MODE_SENSE_RETURN_ALL
);
2749 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2750 status
= STATUS_IO_DEVICE_ERROR
;
2751 ExFreePool(modeData
);
2756 if (modeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
) {
2757 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2759 status
= STATUS_SUCCESS
;
2762 ExFreePool(modeData
);
2765 case IOCTL_DISK_INTERNAL_SET_VERIFY
:
2768 // If the caller is kernel mode, set the verify bit.
2771 if (Irp
->RequestorMode
== KernelMode
) {
2772 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2774 status
= STATUS_SUCCESS
;
2777 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
:
2780 // If the caller is kernel mode, clear the verify bit.
2783 if (Irp
->RequestorMode
== KernelMode
) {
2784 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
2786 status
= STATUS_SUCCESS
;
2789 case IOCTL_DISK_FIND_NEW_DEVICES
:
2792 // Search for devices that have been powered on since the last
2793 // device search or system initialization.
2796 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2797 status
= DriverEntry(DeviceObject
->DriverObject
,
2800 Irp
->IoStatus
.Status
= status
;
2802 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2805 case IOCTL_DISK_MEDIA_REMOVAL
:
2808 // If the disk is not removable then don't allow this command.
2811 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
2812 status
= STATUS_INVALID_DEVICE_REQUEST
;
2817 // Fall through and let the class driver process the request.
2820 case IOCTL_DISK_GET_LENGTH_INFO
:
2823 // Validate buffer length.
2826 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2827 sizeof(GET_LENGTH_INFORMATION
)) {
2828 status
= STATUS_BUFFER_TOO_SMALL
;
2832 PGET_LENGTH_INFORMATION lengthInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
2835 // Update the geometry in case it has changed.
2838 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2840 if (!NT_SUCCESS(status
)) {
2843 // Note the drive is not ready.
2846 diskData
->DriveNotReady
= TRUE
;
2851 // Note the drive is now ready.
2854 diskData
->DriveNotReady
= FALSE
;
2857 // Output data, and return
2860 lengthInformation
->Length
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2861 status
= STATUS_SUCCESS
;
2862 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2870 // Free the Srb, since it is not needed.
2876 // Pass the request to the common device control routine.
2879 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
2883 } // end switch( ...
2885 Irp
->IoStatus
.Status
= status
;
2887 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2889 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2892 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2896 } // end ScsiDiskDeviceControl()
2900 ScsiDiskShutdownFlush (
2901 IN PDEVICE_OBJECT DeviceObject
,
2907 Routine Description:
2909 This routine is called for a shutdown and flush IRPs. These are sent by the
2910 system before it actually shuts down or when the file system does a flush.
2911 A synchronize cache command is sent to the device if it is write caching.
2912 If the device is removable an unlock command will be sent. This routine
2913 will sent a shutdown or flush Srb to the port driver.
2917 DriverObject - Pointer to device object to being shutdown by system.
2928 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2929 PIO_STACK_LOCATION irpStack
;
2930 PSCSI_REQUEST_BLOCK srb
;
2935 // Allocate SCSI request block.
2938 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
2943 // Set the status and complete the request.
2946 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2947 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2948 return(STATUS_INSUFFICIENT_RESOURCES
);
2951 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
2954 // Write length to SRB.
2957 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2960 // Set SCSI bus address.
2963 srb
->PathId
= deviceExtension
->PathId
;
2964 srb
->TargetId
= deviceExtension
->TargetId
;
2965 srb
->Lun
= deviceExtension
->Lun
;
2968 // Set timeout value and mark the request as not being a tagged request.
2971 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 4;
2972 srb
->QueueTag
= SP_UNTAGGED
;
2973 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
2974 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2977 // If the write cache is enabled then send a synchronize cache request.
2980 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2982 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2983 srb
->CdbLength
= 10;
2985 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
2987 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2993 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status
));
2997 // Unlock the device if it is removable and this is a shutdown.
3000 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3002 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
3003 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
3006 cdb
= (PVOID
) srb
->Cdb
;
3007 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3008 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3011 // Set timeout value.
3014 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3015 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3021 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3027 // Save a few parameters in the current stack location.
3030 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3031 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3034 // Set the retry count to zero.
3037 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3040 // Set up IoCompletion routine address.
3043 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3046 // Get next stack location and
3047 // set major function code.
3050 irpStack
= IoGetNextIrpStackLocation(Irp
);
3052 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3055 // Set up SRB for execute scsi request.
3056 // Save SRB address in next stack for port driver.
3059 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3062 // Set up Irp Address.
3065 srb
->OriginalRequest
= Irp
;
3068 // Call the port driver to process the request.
3071 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3073 } // end ScsiDiskShutdown()
3079 PDEVICE_OBJECT DeviceObject
3083 Routine Description:
3085 The routine performs the necessary functions to determine if a device is
3086 really a floppy rather than a harddisk. This is done by a mode sense
3087 command. First, a check is made to see if the medimum type is set. Second
3088 a check is made for the flexible parameters mode page. Also a check is
3089 made to see if the write cache is enabled.
3093 DeviceObject - Supplies the device object to be tested.
3097 Return TRUE if the indicated device is a floppy.
3101 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3108 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3110 if (modeData
== NULL
) {
3114 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3116 length
= ScsiClassModeSense(DeviceObject
,
3119 MODE_SENSE_RETURN_ALL
);
3121 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3124 // Retry the request in case of a check condition.
3127 length
= ScsiClassModeSense(DeviceObject
,
3130 MODE_SENSE_RETURN_ALL
);
3132 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3134 ExFreePool(modeData
);
3141 // If the length is greater than length indicated by the mode data reset
3142 // the data to the mode data.
3145 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3146 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3150 // Look for the flexible disk mode page.
3153 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_FLEXIBILE
, TRUE
);
3155 if (pageData
!= NULL
) {
3157 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3158 ExFreePool(modeData
);
3163 // Check to see if the write cache is enabled.
3166 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3169 // Assume that write cache is disabled or not supported.
3172 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3175 // Check if valid caching page exists.
3178 if (pageData
!= NULL
) {
3181 // Check if write cache is disabled.
3184 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3187 "SCSIDISK: Disk write cache enabled\n"));
3190 // Check if forced unit access (FUA) is supported.
3193 if (((PMODE_PARAMETER_HEADER
)modeData
)->DeviceSpecificParameter
& MODE_DSP_FUA_SUPPORTED
) {
3195 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3200 "SCSIDISK: Disk does not support FUA or DPO\n"));
3210 ExFreePool(modeData
);
3213 } // end IsFloppyDevice()
3219 IN PDEVICE_OBJECT DeviceObject
,
3220 IN PCHAR ModeSelectBuffer
,
3227 Routine Description:
3229 This routine sends a mode select command.
3233 DeviceObject - Supplies the device object associated with this request.
3235 ModeSelectBuffer - Supplies a buffer containing the page data.
3237 Length - Supplies the length in bytes of the mode select buffer.
3239 SavePage - Indicates that parameters should be written to disk.
3243 Length of the transferred data is returned.
3247 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3249 SCSI_REQUEST_BLOCK srb
;
3254 PMODE_PARAMETER_BLOCK blockDescriptor
;
3258 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3261 // Allocate buffer for mode select header, block descriptor, and mode page.
3264 buffer
= (ULONG_PTR
)ExAllocatePool(NonPagedPoolCacheAligned
,length2
);
3266 RtlZeroMemory((PVOID
)buffer
, length2
);
3269 // Set length in header to size of mode page.
3272 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3274 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3280 blockDescriptor
->BlockLength
[1]=0x02;
3283 // Copy mode page to buffer.
3286 RtlCopyMemory((PVOID
)(buffer
+ 3), ModeSelectBuffer
, Length
);
3292 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3295 // Build the MODE SELECT CDB.
3299 cdb
= (PCDB
)srb
.Cdb
;
3302 // Set timeout value from device extension.
3305 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
3307 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3308 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3309 cdb
->MODE_SELECT
.PFBit
= 1;
3310 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3314 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3321 if (status
== STATUS_VERIFY_REQUIRED
) {
3324 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3337 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3338 status
= STATUS_SUCCESS
;
3341 ExFreePool((PVOID
)buffer
);
3343 if (NT_SUCCESS(status
)) {
3349 } // end SciDiskModeSelect()
3355 IN PDEVICE_OBJECT DeviceObject
,
3356 IN PSCSI_INQUIRY_DATA LunInfo
3360 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3361 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3362 BAD_CONTROLLER_INFORMATION
const *controller
;
3367 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
3369 controller
= &ScsiDiskBadControllers
[j
];
3371 if (!controller
->DisableWriteCache
|| strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
3375 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller
->InquiryString
));
3377 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3379 if (modeData
== NULL
) {
3382 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3386 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3388 length
= ScsiClassModeSense(DeviceObject
,
3391 MODE_SENSE_RETURN_ALL
);
3393 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3396 // Retry the request in case of a check condition.
3399 length
= ScsiClassModeSense(DeviceObject
,
3402 MODE_SENSE_RETURN_ALL
);
3404 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3408 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3410 ExFreePool(modeData
);
3417 // If the length is greater than length indicated by the mode data reset
3418 // the data to the mode data.
3421 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3422 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3426 // Check to see if the write cache is enabled.
3429 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3432 // Assume that write cache is disabled or not supported.
3435 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3438 // Check if valid caching page exists.
3441 if (pageData
!= NULL
) {
3443 BOOLEAN savePage
= FALSE
;
3445 savePage
= (BOOLEAN
)(((PMODE_CACHING_PAGE
)pageData
)->PageSavable
);
3448 // Check if write cache is disabled.
3451 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3453 PIO_ERROR_LOG_PACKET errorLogEntry
;
3458 // Disable write cache and ensure necessary fields are zeroed.
3461 ((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
= FALSE
;
3462 ((PMODE_CACHING_PAGE
)pageData
)->Reserved
= 0;
3463 ((PMODE_CACHING_PAGE
)pageData
)->PageSavable
= 0;
3464 ((PMODE_CACHING_PAGE
)pageData
)->Reserved2
= 0;
3467 // Extract length from caching page.
3470 length
= ((PMODE_CACHING_PAGE
)pageData
)->PageLength
;
3473 // Compensate for page code and page length.
3479 // Issue mode select to set the parameter.
3482 if (ScsiDiskModeSelect(DeviceObject
,
3488 "SCSIDISK: Disk write cache disabled\n"));
3490 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3491 errorCode
= IO_WRITE_CACHE_DISABLED
;
3494 if (ScsiDiskModeSelect(DeviceObject
,
3500 "SCSIDISK: Disk write cache disabled\n"));
3503 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3504 errorCode
= IO_WRITE_CACHE_DISABLED
;
3509 "SCSIDISK: Mode select to disable write cache failed\n"));
3511 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3512 errorCode
= IO_WRITE_CACHE_ENABLED
;
3517 // Log the appropriate informational or error entry.
3520 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3522 sizeof(IO_ERROR_LOG_PACKET
) + 3
3525 if (errorLogEntry
!= NULL
) {
3527 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3528 errorLogEntry
->ErrorCode
= errorCode
;
3529 errorLogEntry
->SequenceNumber
= 0;
3530 errorLogEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
3531 errorLogEntry
->IoControlCode
= 0;
3532 errorLogEntry
->RetryCount
= 0;
3533 errorLogEntry
->UniqueErrorValue
= 0x1;
3534 errorLogEntry
->DumpDataSize
= 3 * sizeof(ULONG
);
3535 errorLogEntry
->DumpData
[0] = LunInfo
->PathId
;
3536 errorLogEntry
->DumpData
[1] = LunInfo
->TargetId
;
3537 errorLogEntry
->DumpData
[2] = LunInfo
->Lun
;
3540 // Write the error log packet.
3543 IoWriteErrorLogEntry(errorLogEntry
);
3549 // Found device so exit the loop and return.
3561 CalculateMbrCheckSum(
3562 IN PDEVICE_EXTENSION DeviceExtension
,
3568 Routine Description:
3570 Read MBR and calculate checksum.
3574 DeviceExtension - Supplies a pointer to the device information for disk.
3575 Checksum - Memory location to return MBR checksum.
3579 Returns TRUE if checksum is valid.
3583 LARGE_INTEGER sectorZero
;
3585 IO_STATUS_BLOCK ioStatus
;
3593 sectorZero
.QuadPart
= (LONGLONG
) 0;
3596 // Create notification event object to be used to signal the inquiry
3597 // request completion.
3600 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
3606 sectorSize
= DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
3609 // Make sure sector size is at least 512 bytes.
3612 if (sectorSize
< 512) {
3617 // Allocate buffer for sector read.
3620 mbr
= ExAllocatePool(NonPagedPoolCacheAligned
, sectorSize
);
3627 // Build IRP to read MBR.
3630 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
3631 DeviceExtension
->DeviceObject
,
3644 // Pass request to port driver and wait for request to complete.
3647 status
= IoCallDriver(DeviceExtension
->DeviceObject
,
3650 if (status
== STATUS_PENDING
) {
3651 KeWaitForSingleObject(&event
,
3656 status
= ioStatus
.Status
;
3659 if (!NT_SUCCESS(status
)) {
3665 // Calculate MBR checksum.
3670 for (i
= 0; i
< 128; i
++) {
3671 *Checksum
+= mbr
[i
];
3674 *Checksum
= ~*Checksum
+ 1;
3684 IN PDEVICE_EXTENSION DeviceExtension
,
3691 Routine Description:
3693 The routine queries the registry to determine if this disk is visible to
3694 the BIOS. If the disk is visable to the BIOS, then the geometry information
3699 DeviceExtension - Supplies a pointer to the device information for disk.
3700 Signature - Unique identifier recorded in MBR.
3701 BusKey - Handle of bus key.
3702 DiskNumber - Returns ordinal of disk as BIOS sees it.
3706 TRUE is disk signature matched.
3710 PDISK_DATA diskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
3711 BOOLEAN diskFound
= FALSE
;
3712 OBJECT_ATTRIBUTES objectAttributes
;
3713 UNICODE_STRING unicodeString
;
3714 UNICODE_STRING identifier
;
3716 ULONG adapterNumber
;
3724 STRING anotherString
;
3727 PKEY_VALUE_FULL_INFORMATION keyData
;
3731 for (busNumber
= 0; ; busNumber
++) {
3734 // Open controller name key.
3737 sprintf((PCHAR
)buffer
,
3741 RtlInitString(&string
,
3744 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3748 if (!NT_SUCCESS(status
)){
3752 InitializeObjectAttributes(&objectAttributes
,
3754 OBJ_CASE_INSENSITIVE
,
3756 (PSECURITY_DESCRIPTOR
)NULL
);
3758 status
= ZwOpenKey(&spareKey
,
3762 RtlFreeUnicodeString(&unicodeString
);
3764 if (!NT_SUCCESS(status
)) {
3769 // Open up controller ordinal key.
3772 RtlInitUnicodeString(&unicodeString
, L
"DiskController");
3773 InitializeObjectAttributes(&objectAttributes
,
3775 OBJ_CASE_INSENSITIVE
,
3777 (PSECURITY_DESCRIPTOR
)NULL
);
3779 status
= ZwOpenKey(&adapterKey
,
3784 // This could fail even with additional adapters of this type
3788 if (!NT_SUCCESS(status
)) {
3792 for (adapterNumber
= 0; ; adapterNumber
++) {
3798 sprintf((PCHAR
)buffer
,
3799 "%lu\\DiskPeripheral",
3802 RtlInitString(&string
,
3805 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3809 if (!NT_SUCCESS(status
)){
3813 InitializeObjectAttributes(&objectAttributes
,
3815 OBJ_CASE_INSENSITIVE
,
3817 (PSECURITY_DESCRIPTOR
)NULL
);
3819 status
= ZwOpenKey(&diskKey
,
3823 RtlFreeUnicodeString(&unicodeString
);
3825 if (!NT_SUCCESS(status
)) {
3829 for (diskNumber
= 0; ; diskNumber
++) {
3831 sprintf((PCHAR
)buffer
,
3835 RtlInitString(&string
,
3838 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3842 if (!NT_SUCCESS(status
)){
3846 InitializeObjectAttributes(&objectAttributes
,
3848 OBJ_CASE_INSENSITIVE
,
3850 (PSECURITY_DESCRIPTOR
)NULL
);
3852 status
= ZwOpenKey(&targetKey
,
3856 RtlFreeUnicodeString(&unicodeString
);
3858 if (!NT_SUCCESS(status
)) {
3863 // Allocate buffer for registry query.
3866 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
3868 if (keyData
== NULL
) {
3874 // Get disk peripheral identifier.
3877 RtlInitUnicodeString(&unicodeString
, L
"Identifier");
3878 status
= ZwQueryValueKey(targetKey
,
3880 KeyValueFullInformation
,
3887 if (!NT_SUCCESS(status
)) {
3892 // Complete unicode string.
3896 (PWSTR
)((PUCHAR
)keyData
+ keyData
->DataOffset
);
3897 identifier
.Length
= (USHORT
)keyData
->DataLength
;
3898 identifier
.MaximumLength
= (USHORT
)keyData
->DataLength
;
3901 // Convert unicode identifier to ansi string.
3905 RtlUnicodeStringToAnsiString(&anotherString
,
3909 if (!NT_SUCCESS(status
)) {
3914 // If checksum is zero, then the MBR is valid and
3915 // the signature is meaningful.
3918 if (diskData
->MbrCheckSum
) {
3921 // Convert checksum to ansi string.
3924 sprintf((PCHAR
)buffer
, "%08lx", diskData
->MbrCheckSum
);
3929 // Convert signature to ansi string.
3932 sprintf((PCHAR
)buffer
, "%08lx", diskData
->Signature
);
3935 // Make string point at signature. Can't use scan
3936 // functions because they are not exported for driver use.
3939 anotherString
.Buffer
+=9;
3943 // Convert to ansi string.
3946 RtlInitString(&string
,
3951 // Make string lengths equal.
3954 anotherString
.Length
= string
.Length
;
3957 // Check if strings match.
3960 if (RtlCompareString(&string
,
3965 *DiskNumber
= diskNumber
;
3968 ExFreePool(keyData
);
3971 // Readjust indentifier string if necessary.
3974 if (!diskData
->MbrCheckSum
) {
3975 anotherString
.Buffer
-=9;
3978 RtlFreeAnsiString(&anotherString
);
3988 ZwClose(adapterKey
);
3994 } // end EnumerateBusKey()
4000 IN PDEVICE_EXTENSION DeviceExtension
4004 Routine Description:
4006 The routine queries the registry to determine if this disk is visible to
4007 the BIOS. If the disk is visable to the BIOS, then the geometry information
4012 DeviceExtension - Supplies a pointer to the device information for disk.
4021 OBJECT_ATTRIBUTES objectAttributes
;
4022 UNICODE_STRING unicodeString
;
4026 PCM_INT13_DRIVE_PARAMETER driveParameters
;
4027 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor
;
4028 PKEY_VALUE_FULL_INFORMATION keyData
;
4032 ULONG numberOfDrives
;
4035 ULONG sectorsPerTrack
;
4036 ULONG tracksPerCylinder
;
4037 BOOLEAN foundEZHooker
;
4043 // Initialize the object for the key.
4046 InitializeObjectAttributes(&objectAttributes
,
4047 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
4048 OBJ_CASE_INSENSITIVE
,
4050 (PSECURITY_DESCRIPTOR
) NULL
);
4053 // Create the hardware base key.
4056 status
= ZwOpenKey(&hardwareKey
,
4061 if (!NT_SUCCESS(status
)) {
4062 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
));
4068 // Get disk BIOS geometry information.
4071 RtlInitUnicodeString(&unicodeString
, L
"Configuration Data");
4073 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
4075 if (keyData
== NULL
) {
4076 ZwClose(hardwareKey
);
4080 status
= ZwQueryValueKey(hardwareKey
,
4082 KeyValueFullInformation
,
4087 if (!NT_SUCCESS(status
)) {
4089 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4091 ExFreePool(keyData
);
4096 // Open EISA bus key.
4099 RtlInitUnicodeString(&unicodeString
, L
"EisaAdapter");
4101 InitializeObjectAttributes(&objectAttributes
,
4103 OBJ_CASE_INSENSITIVE
,
4105 (PSECURITY_DESCRIPTOR
)NULL
);
4107 status
= ZwOpenKey(&busKey
,
4111 if (!NT_SUCCESS(status
)) {
4116 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4117 if (EnumerateBusKey(DeviceExtension
,
4121 ZwClose(hardwareKey
);
4128 // Open Multifunction bus key.
4131 RtlInitUnicodeString(&unicodeString
, L
"MultifunctionAdapter");
4133 InitializeObjectAttributes(&objectAttributes
,
4135 OBJ_CASE_INSENSITIVE
,
4137 (PSECURITY_DESCRIPTOR
)NULL
);
4139 status
= ZwOpenKey(&busKey
,
4143 ZwClose(hardwareKey
);
4144 if (NT_SUCCESS(status
)) {
4146 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4147 if (EnumerateBusKey(DeviceExtension
,
4155 ExFreePool(keyData
);
4160 resourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PUCHAR
)keyData
+
4161 keyData
->DataOffset
);
4164 // Check that the data is long enough to hold a full resource descriptor,
4165 // and that the last resouce list is device-specific and long enough.
4168 if (keyData
->DataLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) ||
4169 resourceDescriptor
->PartialResourceList
.Count
== 0 ||
4170 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].Type
!=
4171 CmResourceTypeDeviceSpecific
||
4172 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0]
4173 .u
.DeviceSpecificData
.DataSize
< sizeof(ULONG
)) {
4175 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4176 ExFreePool(keyData
);
4181 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
;
4184 // Point to the BIOS data. The BIOS data is located after the first
4185 // partial Resource list which should be device specific data.
4188 buffer
= (PUCHAR
) keyData
+ keyData
->DataOffset
+
4189 sizeof(CM_FULL_RESOURCE_DESCRIPTOR
);
4192 numberOfDrives
= length
/ sizeof(CM_INT13_DRIVE_PARAMETER
);
4195 // Use the defaults if the drive number is greater than the
4196 // number of drives detected by the BIOS.
4199 if (numberOfDrives
<= diskNumber
) {
4200 ExFreePool(keyData
);
4205 // Point to the array of drive parameters.
4208 driveParameters
= (PCM_INT13_DRIVE_PARAMETER
) buffer
+ diskNumber
;
4209 cylinders
= driveParameters
->MaxCylinders
+ 1;
4210 sectorsPerTrack
= driveParameters
->SectorsPerTrack
;
4211 tracksPerCylinder
= driveParameters
->MaxHeads
+1;
4214 // Calculate the actual number of sectors.
4217 sectors
= (ULONG
)(DeviceExtension
->PartitionLength
.QuadPart
>>
4218 DeviceExtension
->SectorShift
);
4221 if (sectors
>= cylinders
* tracksPerCylinder
* sectorsPerTrack
) {
4222 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4223 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4224 sectors
, cylinders
, tracksPerCylinder
, sectorsPerTrack
));
4229 // Since the BIOS may not report the full drive, recalculate the drive
4230 // size based on the volume size and the BIOS values for tracks per
4231 // cylinder and sectors per track..
4234 length
= tracksPerCylinder
* sectorsPerTrack
;
4239 // The BIOS information is bogus.
4242 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4243 ExFreePool(keyData
);
4247 cylinders
= sectors
/ length
;
4250 // Update the actual geometry information.
4253 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= sectorsPerTrack
;
4254 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
;
4255 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)cylinders
;
4256 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= cylinders
* tracksPerCylinder
* sectorsPerTrack
*
4257 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4260 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4265 ExFreePool(keyData
);
4267 foundEZHooker
= FALSE
;
4269 if (!DeviceExtension
->DMActive
) {
4271 HalExamineMBR(DeviceExtension
->DeviceObject
,
4272 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4280 foundEZHooker
= TRUE
;
4286 if (DeviceExtension
->DMActive
|| foundEZHooker
) {
4288 while (cylinders
> 1024) {
4290 tracksPerCylinder
= tracksPerCylinder
*2;
4291 cylinders
= cylinders
/2;
4296 // int 13 values are always 1 less.
4299 tracksPerCylinder
-= 1;
4303 // DM reserves the CE cylinder
4308 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= cylinders
+ 1;
4309 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
+ 1;
4311 DeviceExtension
->PartitionLength
.QuadPart
=
4312 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
=
4313 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
*
4314 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
*
4315 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
*
4316 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
;
4318 if (DeviceExtension
->DMActive
) {
4320 DeviceExtension
->DMByteSkew
= DeviceExtension
->DMSkew
* DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4326 DeviceExtension
->DMByteSkew
= 0;
4332 } // end UpdateGeometry()
4338 UpdateRemovableGeometry (
4339 IN PDEVICE_OBJECT DeviceObject
,
4345 Routine Description:
4347 This routines updates the size and starting offset of the device. This is
4348 used when the media on the device may have changed thereby changing the
4349 size of the device. If this is the physical device then a
4350 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4354 DeviceObject - Supplies the device object whos size needs to be updated.
4356 Irp - Supplies a reference where the status can be updated.
4360 Returns the status of the opertion.
4365 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4366 PDRIVE_LAYOUT_INFORMATION partitionList
;
4368 PDISK_DATA diskData
;
4369 ULONG partitionNumber
;
4372 // Determine if the size of the partition may have changed because
4373 // the media has changed.
4376 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
4378 return(STATUS_SUCCESS
);
4383 // If this request is for partition zero then do a read drive
4384 // capacity otherwise do a I/O read partition table.
4387 diskData
= (PDISK_DATA
) (deviceExtension
+ 1);
4390 // Read the drive capcity. If that fails, give up.
4393 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
4395 if (!NT_SUCCESS(status
)) {
4400 // Read the partition table agian.
4403 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
4404 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4409 if (!NT_SUCCESS(status
)) {
4412 // Fail the request.
4418 if (diskData
->PartitionNumber
!= 0 &&
4419 diskData
->PartitionNumber
<= partitionList
->PartitionCount
) {
4421 partitionNumber
= diskData
->PartitionNumber
- 1;
4424 // Update the partition information for this parition.
4427 diskData
->PartitionType
=
4428 partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
4430 diskData
->BootIndicator
=
4431 partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
4433 deviceExtension
->StartingOffset
=
4434 partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
4436 deviceExtension
->PartitionLength
=
4437 partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
4439 diskData
->HiddenSectors
=
4440 partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
4442 deviceExtension
->SectorShift
= ((PDEVICE_EXTENSION
)
4443 deviceExtension
->PhysicalDevice
->DeviceExtension
)->SectorShift
;
4445 } else if (diskData
->PartitionNumber
!= 0) {
4448 // The paritition does not exist. Zero all the data.
4451 diskData
->PartitionType
= 0;
4452 diskData
->BootIndicator
= 0;
4453 diskData
->HiddenSectors
= 0;
4454 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)0;
4455 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)0;
4459 // Free the parition list allocate by I/O read partition table.
4462 ExFreePool(partitionList
);
4465 return(STATUS_SUCCESS
);
4471 ScsiDiskProcessError(
4472 PDEVICE_OBJECT DeviceObject
,
4473 PSCSI_REQUEST_BLOCK Srb
,
4479 Routine Description:
4481 This routine checks the type of error. If the error indicates an underrun
4482 then indicate the request should be retried.
4486 DeviceObject - Supplies a pointer to the device object.
4488 Srb - Supplies a pointer to the failing Srb.
4490 Status - Status with which the IRP will be completed.
4492 Retry - Indication of whether the request will be retried.
4501 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4503 if (*Status
== STATUS_DATA_OVERRUN
&&
4504 ( Srb
->Cdb
[0] == SCSIOP_WRITE
|| Srb
->Cdb
[0] == SCSIOP_READ
)) {
4509 // Update the error count for the device.
4512 deviceExtension
->ErrorCount
++;
4515 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
4516 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
4519 // The disk drive should never be busy this long. Reset the scsi bus
4520 // maybe this will clear the condition.
4523 ResetScsiBus(DeviceObject
);
4526 // Update the error count for the device.
4529 deviceExtension
->ErrorCount
++;
4536 PDEVICE_OBJECT DeviceObject
,
4537 PSCSI_INQUIRY_DATA LunInfo
,
4538 PIO_SCSI_CAPABILITIES PortCapabilities
4543 Routine Description:
4545 This function checks to see if an SCSI logical unit requires speical
4550 DeviceObject - Supplies the device object to be tested.
4552 InquiryData - Supplies the inquiry data returned by the device of interest.
4554 PortCapabilities - Supplies the capabilities of the device object.
4563 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4564 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
4565 BAD_CONTROLLER_INFORMATION
const *controller
;
4568 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
4570 controller
= &ScsiDiskBadControllers
[j
];
4572 if (strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
4576 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller
->InquiryString
));
4579 // Found a listed controller. Determine what must be done.
4582 if (controller
->DisableTaggedQueuing
) {
4585 // Disable tagged queuing.
4588 deviceExtension
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
4591 if (controller
->DisableSynchronousTransfers
) {
4594 // Disable synchronous data transfers.
4597 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4601 if (controller
->DisableDisconnects
) {
4604 // Disable disconnects.
4607 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
4612 // Found device so exit the loop and return.
4619 // Set the StartUnit flag appropriately.
4622 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) {
4623 deviceExtension
->DeviceFlags
|= DEV_SAFE_START_UNIT
;
4625 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
4626 if (_strnicmp((PCCHAR
)InquiryData
->VendorId
, "iomega", strlen("iomega"))) {
4627 deviceExtension
->DeviceFlags
&= ~DEV_SAFE_START_UNIT
;
4638 IN PDEVICE_OBJECT DeviceObject
4643 Routine Description:
4645 This command sends a reset bus command to the SCSI port driver.
4649 DeviceObject - The device object for the logical unit with
4658 PIO_STACK_LOCATION irpStack
;
4660 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4661 PSCSI_REQUEST_BLOCK srb
;
4662 PCOMPLETION_CONTEXT context
;
4664 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4667 // Allocate Srb from nonpaged pool.
4670 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
4671 sizeof(COMPLETION_CONTEXT
));
4674 // Save the device object in the context for use by the completion
4678 context
->DeviceObject
= DeviceObject
;
4679 srb
= &context
->Srb
;
4685 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4688 // Write length to SRB.
4691 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4694 // Set up SCSI bus address.
4697 srb
->PathId
= deviceExtension
->PathId
;
4698 srb
->TargetId
= deviceExtension
->TargetId
;
4699 srb
->Lun
= deviceExtension
->Lun
;
4701 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4704 // Build the asynchronous request to be sent to the port driver.
4705 // Since this routine is called from a DPC the IRP should always be
4709 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
4711 IoSetCompletionRoutine(irp
,
4712 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
4718 irpStack
= IoGetNextIrpStackLocation(irp
);
4720 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4722 srb
->OriginalRequest
= irp
;
4725 // Store the SRB address in next stack for port driver.
4728 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4731 // Call the port driver with the IRP.
4734 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
4738 } // end ResetScsiBus()
4743 UpdateDeviceObjects(
4744 IN PDEVICE_OBJECT PhysicalDisk
,
4750 Routine Description:
4752 This routine creates, deletes and changes device objects when
4753 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4754 the drive layout information for the user. It is possible to
4755 call this routine even in the GET_LAYOUT case because RewritePartition
4760 DeviceObject - Device object for physical disk.
4761 Irp - IO Request Packet (IRP).
4769 PDEVICE_EXTENSION physicalExtension
= PhysicalDisk
->DeviceExtension
;
4770 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
4772 ULONG partitionNumber
;
4773 ULONG partitionCount
;
4774 ULONG lastPartition
;
4775 ULONG partitionOrdinal
;
4776 PPARTITION_INFORMATION partitionEntry
;
4777 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
4778 STRING ntNameString
;
4779 UNICODE_STRING ntUnicodeString
;
4780 PDEVICE_OBJECT deviceObject
;
4781 PDEVICE_EXTENSION deviceExtension
;
4782 PDISK_DATA diskData
;
4784 ULONG numberListElements
;
4787 partitionCount
= ((partitionList
->PartitionCount
+ 3) / 4) * 4;
4790 // Zero all of the partition numbers.
4793 for (partition
= 0; partition
< partitionCount
; partition
++) {
4794 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4795 partitionEntry
->PartitionNumber
= 0;
4799 // Walk through chain of partitions for this disk to determine
4800 // which existing partitions have no match.
4803 deviceExtension
= physicalExtension
;
4804 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4809 deviceExtension
= diskData
->NextPartition
;
4812 // Check if this is the last partition in the chain.
4815 if (!deviceExtension
) {
4820 // Get the partition device extension from disk data.
4823 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4826 // Check for highest partition number this far.
4829 if (diskData
->PartitionNumber
> lastPartition
) {
4830 lastPartition
= diskData
->PartitionNumber
;
4834 // Check if this partition is not currently being used.
4837 if (!deviceExtension
->PartitionLength
.QuadPart
) {
4842 // Loop through partition information to look for match.
4846 partitionOrdinal
= 0;
4848 for (partition
= 0; partition
< partitionCount
; partition
++) {
4851 // Get partition descriptor.
4854 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4857 // Check if empty, or describes extended partiton or hasn't changed.
4860 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4861 IsContainerPartition(partitionEntry
->PartitionType
)) {
4866 // Advance partition ordinal.
4872 // Check if new partition starts where this partition starts.
4875 if (partitionEntry
->StartingOffset
.QuadPart
!=
4876 deviceExtension
->StartingOffset
.QuadPart
) {
4881 // Check if partition length is the same.
4884 if (partitionEntry
->PartitionLength
.QuadPart
==
4885 deviceExtension
->PartitionLength
.QuadPart
) {
4888 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4889 physicalExtension
->DeviceNumber
,
4890 diskData
->PartitionNumber
));
4893 // Indicate match is found and set partition number
4898 partitionEntry
->PartitionNumber
= diskData
->PartitionNumber
;
4906 // A match is found.
4909 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4912 // If this partition is marked for update then update partition type.
4915 if (partitionEntry
->RewritePartition
) {
4916 diskData
->PartitionType
= partitionEntry
->PartitionType
;
4920 // Update partitional ordinal for calls to HAL routine
4921 // IoSetPartitionInformation.
4924 diskData
->PartitionOrdinal
= partitionOrdinal
;
4927 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4928 physicalExtension
->DeviceNumber
,
4929 diskData
->PartitionOrdinal
,
4930 diskData
->PartitionNumber
));
4935 // no match was found, indicate this partition is gone.
4939 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4940 physicalExtension
->DeviceNumber
,
4941 diskData
->PartitionNumber
));
4943 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
4949 // Walk through partition loop to find new partitions and set up
4950 // device extensions to describe them. In some cases new device
4951 // objects will be created.
4954 partitionOrdinal
= 0;
4957 partition
< partitionCount
;
4961 // Get partition descriptor.
4964 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4967 // Check if empty, or describes an extended partiton.
4970 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4971 IsContainerPartition(partitionEntry
->PartitionType
)) {
4976 // Keep track of position on the disk for calls to IoSetPartitionInformation.
4982 // Check if this entry should be rewritten.
4985 if (!partitionEntry
->RewritePartition
) {
4989 if (partitionEntry
->PartitionNumber
) {
4992 // Partition is an exact match with an existing partition, but is
4993 // being written anyway.
5000 // Check first if existing device object is available by
5001 // walking partition extension list.
5004 partitionNumber
= 0;
5005 deviceExtension
= physicalExtension
;
5006 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5011 // Get next partition device extension from disk data.
5014 deviceExtension
= diskData
->NextPartition
;
5016 if (!deviceExtension
) {
5020 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5023 // A device object is free if the partition length is set to zero.
5026 if (!deviceExtension
->PartitionLength
.QuadPart
) {
5027 partitionNumber
= diskData
->PartitionNumber
;
5034 // If partition number is still zero then a new device object
5038 if (partitionNumber
== 0) {
5041 partitionNumber
= lastPartition
;
5044 // Get or create partition object and set up partition parameters.
5047 sprintf(ntNameBuffer
,
5048 "\\Device\\Harddisk%lu\\Partition%lu",
5049 physicalExtension
->DeviceNumber
,
5052 RtlInitString(&ntNameString
,
5055 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
5059 if (!NT_SUCCESS(status
)) {
5064 "UpdateDeviceObjects: Create device object %s\n",
5068 // This is a new name. Create the device object to represent it.
5071 status
= IoCreateDevice(PhysicalDisk
->DriverObject
,
5072 DEVICE_EXTENSION_SIZE
,
5079 if (!NT_SUCCESS(status
)) {
5081 "UpdateDeviceObjects: Can't create device %s\n",
5083 RtlFreeUnicodeString(&ntUnicodeString
);
5088 // Set up device object fields.
5091 deviceObject
->Flags
|= DO_DIRECT_IO
;
5092 deviceObject
->StackSize
= PhysicalDisk
->StackSize
;
5095 // Set up device extension fields.
5098 deviceExtension
= deviceObject
->DeviceExtension
;
5101 // Copy physical disk extension to partition extension.
5104 RtlMoveMemory(deviceExtension
,
5106 sizeof(DEVICE_EXTENSION
));
5109 // Initialize the new S-List.
5112 if (deviceExtension
->SrbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
5113 numberListElements
= 30;
5115 numberListElements
= 8;
5119 // Build the lookaside list for srb's for this partition based on
5120 // whether the adapter and disk can do tagged queueing.
5123 ScsiClassInitializeSrbLookasideList(deviceExtension
,
5124 numberListElements
);
5127 // Allocate spinlock for zoning for split-request completion.
5130 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
5133 // Write back partition number used in creating object name.
5136 partitionEntry
->PartitionNumber
= partitionNumber
;
5139 // Clear flags initializing bit.
5142 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
5145 // Point back at device object.
5148 deviceExtension
->DeviceObject
= deviceObject
;
5150 RtlFreeUnicodeString(&ntUnicodeString
);
5153 // Link to end of partition chain using previous disk data.
5156 diskData
->NextPartition
= deviceExtension
;
5159 // Get new disk data and zero next partition pointer.
5162 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5163 diskData
->NextPartition
= NULL
;
5168 // Set pointer to disk data area that follows device extension.
5171 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5174 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5175 physicalExtension
->DeviceNumber
,
5180 // Update partition information in partition device extension.
5183 diskData
->PartitionNumber
= partitionNumber
;
5184 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5185 diskData
->BootIndicator
= partitionEntry
->BootIndicator
;
5186 deviceExtension
->StartingOffset
= partitionEntry
->StartingOffset
;
5187 deviceExtension
->PartitionLength
= partitionEntry
->PartitionLength
;
5188 diskData
->HiddenSectors
= partitionEntry
->HiddenSectors
;
5189 diskData
->PartitionOrdinal
= partitionOrdinal
;
5192 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5193 diskData
->PartitionOrdinal
,
5194 diskData
->PartitionNumber
));
5197 // Update partition number passed in to indicate the
5198 // device name for this partition.
5201 partitionEntry
->PartitionNumber
= partitionNumber
;
5204 } // end UpdateDeviceObjects()