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
);
1451 CreatePartitionDeviceObjectsExit
:
1453 if (partitionList
) {
1454 ExFreePool(partitionList
);
1457 ExFreePool(initData
);
1465 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1466 physicalDiskData
->PartitionListState
= Initialized
;
1468 return(STATUS_SUCCESS
);
1471 } // end CreatePartitionDeviceObjects()
1476 ScsiDiskReadWriteVerification(
1477 IN PDEVICE_OBJECT DeviceObject
,
1483 Routine Description:
1485 I/O System entry for read and write requests to SCSI disks.
1489 DeviceObject - Pointer to driver object created by system.
1499 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1500 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1501 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1502 LARGE_INTEGER startingOffset
;
1505 // Verify parameters of this request.
1506 // Check that ending sector is within partition and
1507 // that number of bytes to transfer is a multiple of
1511 startingOffset
.QuadPart
= (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
1514 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
1515 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
1518 // This error maybe caused by the fact that the drive is not ready.
1521 if (((PDISK_DATA
)(deviceExtension
+ 1))->DriveNotReady
) {
1524 // Flag this as a user errror so that a popup is generated.
1527 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
1528 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1533 // Note fastfat depends on this parameter to determine when to
1534 // remount do to a sector size change.
1537 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1540 return STATUS_INVALID_PARAMETER
;
1543 return STATUS_SUCCESS
;
1545 } // end ScsiDiskReadWrite()
1550 ScsiDiskDeviceControl(
1551 PDEVICE_OBJECT DeviceObject
,
1557 Routine Description:
1559 I/O system entry for device controls to SCSI disks.
1563 DeviceObject - Pointer to driver object created by system.
1573 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1574 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1575 PDISK_DATA diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1576 PSCSI_REQUEST_BLOCK srb
;
1578 PMODE_PARAMETER_HEADER modeData
;
1583 IO_STATUS_BLOCK ioStatus
;
1587 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
1591 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1592 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1593 return(STATUS_INSUFFICIENT_RESOURCES
);
1597 // Write zeros to Srb.
1600 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1602 cdb
= (PCDB
)srb
->Cdb
;
1604 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1606 case SMART_GET_VERSION
: {
1609 PSRB_IO_CONTROL srbControl
;
1610 PGETVERSIONINPARAMS versionParams
;
1612 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1613 sizeof(GETVERSIONINPARAMS
)) {
1614 status
= STATUS_INVALID_PARAMETER
;
1619 // Create notification event object to be used to signal the
1620 // request completion.
1623 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1625 srbControl
= ExAllocatePool(NonPagedPool
,
1626 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
));
1629 status
= STATUS_INSUFFICIENT_RESOURCES
;
1634 // fill in srbControl fields
1637 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1638 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1639 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1640 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1641 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1644 // Point to the 'buffer' portion of the SRB_CONTROL
1647 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1650 // Ensure correct target is set in the cmd parameters.
1653 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1654 versionParams
->bIDEDeviceMap
= deviceExtension
->TargetId
;
1657 // Copy the IOCTL parameters to the srb control buffer area.
1660 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(GETVERSIONINPARAMS
));
1663 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1664 deviceExtension
->PortDeviceObject
,
1666 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1668 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1674 status
= STATUS_INSUFFICIENT_RESOURCES
;
1679 // Call the port driver with the request and wait for it to complete.
1682 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1684 if (status
== STATUS_PENDING
) {
1685 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1686 status
= ioStatus
.Status
;
1690 // If successful, copy the data received into the output buffer.
1691 // This should only fail in the event that the IDE driver is older than this driver.
1694 if (NT_SUCCESS(status
)) {
1696 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1698 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, sizeof(GETVERSIONINPARAMS
));
1699 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1702 ExFreePool(srbControl
);
1706 case SMART_RCV_DRIVE_DATA
: {
1708 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1709 ULONG controlCode
= 0;
1710 PSRB_IO_CONTROL srbControl
;
1713 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1714 (sizeof(SENDCMDINPARAMS
) - 1)) {
1715 status
= STATUS_INVALID_PARAMETER
;
1718 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1719 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1720 status
= STATUS_INVALID_PARAMETER
;
1725 // Create notification event object to be used to signal the
1726 // request completion.
1729 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1731 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1733 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1734 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1736 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1737 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1738 case READ_ATTRIBUTES
:
1739 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1740 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1742 case READ_THRESHOLDS
:
1743 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1744 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1747 status
= STATUS_INVALID_PARAMETER
;
1752 status
= STATUS_INVALID_PARAMETER
;
1755 if (controlCode
== 0) {
1756 status
= STATUS_INVALID_PARAMETER
;
1760 srbControl
= ExAllocatePool(NonPagedPool
,
1761 sizeof(SRB_IO_CONTROL
) + length
);
1764 status
= STATUS_INSUFFICIENT_RESOURCES
;
1769 // fill in srbControl fields
1772 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1773 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1774 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1775 srbControl
->Length
= length
;
1776 srbControl
->ControlCode
= controlCode
;
1779 // Point to the 'buffer' portion of the SRB_CONTROL
1782 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1785 // Ensure correct target is set in the cmd parameters.
1788 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1791 // Copy the IOCTL parameters to the srb control buffer area.
1794 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1796 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1797 deviceExtension
->PortDeviceObject
,
1799 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1801 sizeof(SRB_IO_CONTROL
) + length
,
1807 status
= STATUS_INSUFFICIENT_RESOURCES
;
1812 // Call the port driver with the request and wait for it to complete.
1815 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1817 if (status
== STATUS_PENDING
) {
1818 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1819 status
= ioStatus
.Status
;
1823 // If successful, copy the data received into the output buffer
1826 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1828 if (NT_SUCCESS(status
)) {
1830 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
- 1);
1831 Irp
->IoStatus
.Information
= length
- 1;
1835 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1836 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1840 ExFreePool(srbControl
);
1845 case SMART_SEND_DRIVE_COMMAND
: {
1847 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1848 PSRB_IO_CONTROL srbControl
;
1849 ULONG controlCode
= 0;
1852 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1853 (sizeof(SENDCMDINPARAMS
) - 1)) {
1854 status
= STATUS_INVALID_PARAMETER
;
1857 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1858 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1859 status
= STATUS_INVALID_PARAMETER
;
1864 // Create notification event object to be used to signal the
1865 // request completion.
1868 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1872 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1873 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1876 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1880 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1883 case RETURN_SMART_STATUS
:
1886 // Ensure bBuffer is at least 2 bytes (to hold the values of
1887 // cylinderLow and cylinderHigh).
1890 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1891 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1893 status
= STATUS_INVALID_PARAMETER
;
1897 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1898 length
= sizeof(IDEREGS
);
1901 case ENABLE_DISABLE_AUTOSAVE
:
1902 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1905 case SAVE_ATTRIBUTE_VALUES
:
1906 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1909 case EXECUTE_OFFLINE_DIAGS
:
1910 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1914 status
= STATUS_INVALID_PARAMETER
;
1919 status
= STATUS_INVALID_PARAMETER
;
1922 if (controlCode
== 0) {
1923 status
= STATUS_INVALID_PARAMETER
;
1927 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1928 srbControl
= ExAllocatePool(NonPagedPool
,
1929 sizeof(SRB_IO_CONTROL
) + length
);
1932 status
= STATUS_INSUFFICIENT_RESOURCES
;
1937 // fill in srbControl fields
1940 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1941 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1942 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1943 srbControl
->Length
= length
;
1946 // Point to the 'buffer' portion of the SRB_CONTROL
1949 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1952 // Ensure correct target is set in the cmd parameters.
1955 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1958 // Copy the IOCTL parameters to the srb control buffer area.
1961 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1963 srbControl
->ControlCode
= controlCode
;
1965 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1966 deviceExtension
->PortDeviceObject
,
1968 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1970 sizeof(SRB_IO_CONTROL
) + length
,
1976 status
= STATUS_INSUFFICIENT_RESOURCES
;
1981 // Call the port driver with the request and wait for it to complete.
1984 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1986 if (status
== STATUS_PENDING
) {
1987 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1988 status
= ioStatus
.Status
;
1992 // Copy the data received into the output buffer. Since the status buffer
1993 // contains error information also, always perform this copy. IO will will
1994 // either pass this back to the app, or zero it, in case of error.
1997 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2000 // Update the return buffer size based on the sub-command.
2003 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
2004 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
2006 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
2009 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
);
2010 Irp
->IoStatus
.Information
= length
;
2012 ExFreePool(srbControl
);
2017 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2018 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2021 PDEVICE_EXTENSION physicalDeviceExtension
;
2022 PDISK_DATA physicalDiskData
;
2023 BOOLEAN removable
= FALSE
;
2024 BOOLEAN listInitialized
= FALSE
;
2026 if ((irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
&&
2027 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2028 sizeof(DISK_GEOMETRY
)) ||
2029 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
&&
2030 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2031 sizeof(DISK_GEOMETRY_EX
))) {
2033 status
= STATUS_INFO_LENGTH_MISMATCH
;
2037 status
= STATUS_SUCCESS
;
2039 physicalDeviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2040 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
2042 removable
= (BOOLEAN
)DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
;
2043 listInitialized
= (physicalDiskData
->PartitionListState
== Initialized
);
2045 if (removable
|| (!listInitialized
))
2048 // Issue ReadCapacity to update device extension
2049 // with information for current media.
2052 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
2058 if (!NT_SUCCESS(status
)) {
2061 // Note the drive is not ready.
2064 diskData
->DriveNotReady
= TRUE
;
2070 // Note the drive is now ready.
2073 diskData
->DriveNotReady
= FALSE
;
2075 } else if (NT_SUCCESS(status
)) {
2077 // ReadDriveCapacity was allright, create Partition Objects
2079 if (physicalDiskData
->PartitionListState
== NotInitialized
) {
2080 status
= CreatePartitionDeviceObjects(deviceExtension
->PhysicalDevice
, NULL
);
2084 if (NT_SUCCESS(status
)) {
2087 // Copy drive geometry information from device extension.
2090 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2091 deviceExtension
->DiskGeometry
,
2092 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2093 sizeof(DISK_GEOMETRY
) :
2094 sizeof(DISK_GEOMETRY_EX
));
2096 status
= STATUS_SUCCESS
;
2097 Irp
->IoStatus
.Information
=
2098 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2099 sizeof(DISK_GEOMETRY
) :
2100 sizeof(DISK_GEOMETRY_EX
);
2107 case IOCTL_DISK_VERIFY
:
2111 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2112 LARGE_INTEGER byteOffset
;
2117 // Validate buffer length.
2120 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2121 sizeof(VERIFY_INFORMATION
)) {
2123 status
= STATUS_INFO_LENGTH_MISMATCH
;
2131 srb
->CdbLength
= 10;
2133 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2136 // Add disk offset to starting sector.
2139 byteOffset
.QuadPart
= deviceExtension
->StartingOffset
.QuadPart
+
2140 verifyInfo
->StartingOffset
.QuadPart
;
2143 // Convert byte offset to sector offset.
2146 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2149 // Convert ULONG byte count to USHORT sector count.
2152 sectorCount
= (USHORT
)(verifyInfo
->Length
>> deviceExtension
->SectorShift
);
2155 // Move little endian values into CDB in big endian format.
2158 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2159 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2160 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2161 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2163 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2164 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2167 // The verify command is used by the NT FORMAT utility and
2168 // requests are sent down for 5% of the volume size. The
2169 // request timeout value is calculated based on the number of
2170 // sectors verified.
2173 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2174 deviceExtension
->TimeOutValue
;
2176 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
2187 case IOCTL_DISK_GET_PARTITION_INFO
:
2190 // Return the information about the partition specified by the device
2191 // object. Note that no information is ever returned about the size
2192 // or partition type of the physical disk, as this doesn't make any
2196 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2197 sizeof(PARTITION_INFORMATION
)) {
2199 status
= STATUS_INFO_LENGTH_MISMATCH
;
2202 #if 0 // HACK: ReactOS partition numbers must be wrong
2203 else if (diskData
->PartitionNumber
== 0) {
2206 // Paritition zero is not a partition so this is not a
2207 // reasonable request.
2210 status
= STATUS_INVALID_DEVICE_REQUEST
;
2216 PPARTITION_INFORMATION outputBuffer
;
2219 // Update the geometry in case it has changed.
2222 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2224 if (!NT_SUCCESS(status
)) {
2227 // Note the drive is not ready.
2230 diskData
->DriveNotReady
= TRUE
;
2235 // Note the drive is now ready.
2238 diskData
->DriveNotReady
= FALSE
;
2239 // HACK: ReactOS partition numbers must be wrong (>0 part)
2240 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2242 status
= STATUS_INVALID_DEVICE_REQUEST
;
2247 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2249 outputBuffer
->PartitionType
= diskData
->PartitionType
;
2250 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2251 outputBuffer
->PartitionLength
.QuadPart
= (diskData
->PartitionNumber
) ?
2252 deviceExtension
->PartitionLength
.QuadPart
: 2305843009213693951LL; // HACK
2253 outputBuffer
->HiddenSectors
= diskData
->HiddenSectors
;
2254 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2255 outputBuffer
->BootIndicator
= diskData
->BootIndicator
;
2256 outputBuffer
->RewritePartition
= FALSE
;
2257 outputBuffer
->RecognizedPartition
=
2258 IsRecognizedPartition(diskData
->PartitionType
);
2260 status
= STATUS_SUCCESS
;
2261 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2266 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2269 // Return the information about the partition specified by the device
2270 // object. Note that no information is ever returned about the size
2271 // or partition type of the physical disk, as this doesn't make any
2275 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2276 sizeof(PARTITION_INFORMATION_EX
)) {
2278 status
= STATUS_INFO_LENGTH_MISMATCH
;
2281 else if (diskData
->PartitionNumber
== 0) {
2284 // Paritition zero is not a partition so this is not a
2285 // reasonable request.
2288 status
= STATUS_INVALID_DEVICE_REQUEST
;
2293 PPARTITION_INFORMATION_EX outputBuffer
;
2296 // Update the geometry in case it has changed.
2299 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2301 if (!NT_SUCCESS(status
)) {
2304 // Note the drive is not ready.
2307 diskData
->DriveNotReady
= TRUE
;
2312 // Note the drive is now ready.
2315 diskData
->DriveNotReady
= FALSE
;
2317 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2319 status
= STATUS_INVALID_DEVICE_REQUEST
;
2324 (PPARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
2327 // FIXME: hack of the year, assume that partition is MBR
2328 // Thing that can obviously be wrong...
2331 outputBuffer
->PartitionStyle
= PARTITION_STYLE_MBR
;
2332 outputBuffer
->Mbr
.PartitionType
= diskData
->PartitionType
;
2333 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2334 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2335 outputBuffer
->Mbr
.HiddenSectors
= diskData
->HiddenSectors
;
2336 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2337 outputBuffer
->Mbr
.BootIndicator
= diskData
->BootIndicator
;
2338 outputBuffer
->RewritePartition
= FALSE
;
2339 outputBuffer
->Mbr
.RecognizedPartition
=
2340 IsRecognizedPartition(diskData
->PartitionType
);
2342 status
= STATUS_SUCCESS
;
2343 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
2348 case IOCTL_DISK_SET_PARTITION_INFO
:
2350 if (diskData
->PartitionNumber
== 0) {
2352 status
= STATUS_UNSUCCESSFUL
;
2356 PSET_PARTITION_INFORMATION inputBuffer
=
2357 (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2360 // Validate buffer length.
2363 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2364 sizeof(SET_PARTITION_INFORMATION
)) {
2366 status
= STATUS_INFO_LENGTH_MISMATCH
;
2371 // The HAL routines IoGet- and IoSetPartitionInformation were
2372 // developed before support of dynamic partitioning and therefore
2373 // don't distinguish between partition ordinal (that is the order
2374 // of a partition on a disk) and the partition number. (The
2375 // partition number is assigned to a partition to identify it to
2376 // the system.) Use partition ordinals for these legacy calls.
2379 status
= IoSetPartitionInformation(
2380 deviceExtension
->PhysicalDevice
,
2381 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2382 diskData
->PartitionOrdinal
,
2383 inputBuffer
->PartitionType
);
2385 if (NT_SUCCESS(status
)) {
2387 diskData
->PartitionType
= inputBuffer
->PartitionType
;
2393 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2396 // Return the partition layout for the physical drive. Note that
2397 // the layout is returned for the actual physical drive, regardless
2398 // of which partition was specified for the request.
2401 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2402 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2403 status
= STATUS_INFO_LENGTH_MISMATCH
;
2407 PDRIVE_LAYOUT_INFORMATION partitionList
;
2408 PDEVICE_EXTENSION physicalExtension
= deviceExtension
;
2409 PPARTITION_INFORMATION partitionEntry
;
2410 PDISK_DATA diskData
;
2415 // Read partition information.
2418 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
2419 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2423 if (!NT_SUCCESS(status
)) {
2428 // The disk layout has been returned in the partitionList
2429 // buffer. Determine its size and, if the data will fit
2430 // into the intermediatery buffer, return it.
2433 tempSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,PartitionEntry
[0]);
2434 tempSize
+= partitionList
->PartitionCount
*
2435 sizeof(PARTITION_INFORMATION
);
2438 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
2440 status
= STATUS_BUFFER_TOO_SMALL
;
2441 ExFreePool(partitionList
);
2446 // Walk partition list to associate partition numbers with
2447 // partition entries.
2450 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
2453 // Walk partition chain anchored at physical disk extension.
2456 deviceExtension
= physicalExtension
;
2457 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2461 deviceExtension
= diskData
->NextPartition
;
2464 // Check if this is the last partition in the chain.
2467 if (!deviceExtension
) {
2472 // Get the partition device extension from disk data.
2475 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2478 // Check if this partition is not currently being used.
2481 if (!deviceExtension
->PartitionLength
.QuadPart
) {
2485 partitionEntry
= &partitionList
->PartitionEntry
[i
];
2488 // Check if empty, or describes extended partiton or hasn't changed.
2491 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2492 IsContainerPartition(partitionEntry
->PartitionType
)) {
2497 // Check if new partition starts where this partition starts.
2500 if (partitionEntry
->StartingOffset
.QuadPart
!=
2501 deviceExtension
->StartingOffset
.QuadPart
) {
2506 // Check if partition length is the same.
2509 if (partitionEntry
->PartitionLength
.QuadPart
==
2510 deviceExtension
->PartitionLength
.QuadPart
) {
2513 // Partitions match. Update partition number.
2516 partitionEntry
->PartitionNumber
=
2517 diskData
->PartitionNumber
;
2525 // Copy partition information to system buffer.
2528 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2531 status
= STATUS_SUCCESS
;
2532 Irp
->IoStatus
.Information
= tempSize
;
2535 // Finally, free the buffer allocated by reading the
2539 ExFreePool(partitionList
);
2544 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
2549 // Update the disk with new partition information.
2552 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
2555 // Validate buffer length.
2558 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2559 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2561 status
= STATUS_INFO_LENGTH_MISMATCH
;
2565 length
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2566 (partitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
);
2569 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2572 status
= STATUS_BUFFER_TOO_SMALL
;
2577 // Verify that device object is for physical disk.
2580 if (deviceExtension
->PhysicalDevice
->DeviceExtension
!= deviceExtension
) {
2581 status
= STATUS_INVALID_PARAMETER
;
2586 // Walk through partition table comparing partitions to
2587 // existing partitions to create, delete and change
2588 // device objects as necessary.
2591 UpdateDeviceObjects(DeviceObject
,
2595 // Write changes to disk.
2598 status
= IoWritePartitionTable(
2599 deviceExtension
->DeviceObject
,
2600 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2601 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
,
2602 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
,
2607 // Update IRP with bytes returned.
2610 if (NT_SUCCESS(status
)) {
2611 Irp
->IoStatus
.Information
= length
;
2616 case IOCTL_DISK_REASSIGN_BLOCKS
:
2619 // Map defective blocks to new location on disk.
2624 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2630 // Validate buffer length.
2633 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2634 sizeof(REASSIGN_BLOCKS
)) {
2636 status
= STATUS_INFO_LENGTH_MISMATCH
;
2640 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2641 (badBlocks
->Count
- 1) * sizeof(ULONG
);
2643 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2646 status
= STATUS_INFO_LENGTH_MISMATCH
;
2651 // Build the data buffer to be transferred in the input buffer.
2652 // The format of the data to the device is:
2656 // x * 4 btyes Block Address
2658 // All values are big endian.
2661 badBlocks
->Reserved
= 0;
2662 blockCount
= badBlocks
->Count
;
2665 // Convert # of entries to # of bytes.
2669 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2670 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2673 // Convert back to number of entries.
2678 for (; blockCount
> 0; blockCount
--) {
2680 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2682 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2683 (PFOUR_BYTE
) &blockNumber
);
2688 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2691 // Set timeout value.
2694 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2696 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2702 Irp
->IoStatus
.Status
= status
;
2703 Irp
->IoStatus
.Information
= 0;
2705 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2710 case IOCTL_DISK_IS_WRITABLE
:
2713 // Determine if the device is writable.
2716 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
2718 if (modeData
== NULL
) {
2719 status
= STATUS_INSUFFICIENT_RESOURCES
;
2723 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
2725 length
= ScsiClassModeSense(DeviceObject
,
2728 MODE_SENSE_RETURN_ALL
);
2730 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2733 // Retry the request in case of a check condition.
2736 length
= ScsiClassModeSense(DeviceObject
,
2739 MODE_SENSE_RETURN_ALL
);
2741 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2742 status
= STATUS_IO_DEVICE_ERROR
;
2743 ExFreePool(modeData
);
2748 if (modeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
) {
2749 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2751 status
= STATUS_SUCCESS
;
2754 ExFreePool(modeData
);
2757 case IOCTL_DISK_INTERNAL_SET_VERIFY
:
2760 // If the caller is kernel mode, set the verify bit.
2763 if (Irp
->RequestorMode
== KernelMode
) {
2764 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2766 status
= STATUS_SUCCESS
;
2769 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
:
2772 // If the caller is kernel mode, clear the verify bit.
2775 if (Irp
->RequestorMode
== KernelMode
) {
2776 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
2778 status
= STATUS_SUCCESS
;
2781 case IOCTL_DISK_FIND_NEW_DEVICES
:
2784 // Search for devices that have been powered on since the last
2785 // device search or system initialization.
2788 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2789 status
= DriverEntry(DeviceObject
->DriverObject
,
2792 Irp
->IoStatus
.Status
= status
;
2794 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2797 case IOCTL_DISK_MEDIA_REMOVAL
:
2800 // If the disk is not removable then don't allow this command.
2803 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
2804 status
= STATUS_INVALID_DEVICE_REQUEST
;
2809 // Fall through and let the class driver process the request.
2812 case IOCTL_DISK_GET_LENGTH_INFO
:
2815 // Validate buffer length.
2818 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2819 sizeof(GET_LENGTH_INFORMATION
)) {
2820 status
= STATUS_BUFFER_TOO_SMALL
;
2824 PGET_LENGTH_INFORMATION lengthInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
2827 // Update the geometry in case it has changed.
2830 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2832 if (!NT_SUCCESS(status
)) {
2835 // Note the drive is not ready.
2838 diskData
->DriveNotReady
= TRUE
;
2843 // Note the drive is now ready.
2846 diskData
->DriveNotReady
= FALSE
;
2849 // Output data, and return
2852 lengthInformation
->Length
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2853 status
= STATUS_SUCCESS
;
2854 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2862 // Free the Srb, since it is not needed.
2868 // Pass the request to the common device control routine.
2871 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
2875 } // end switch( ...
2877 Irp
->IoStatus
.Status
= status
;
2879 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2881 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2884 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2888 } // end ScsiDiskDeviceControl()
2892 ScsiDiskShutdownFlush (
2893 IN PDEVICE_OBJECT DeviceObject
,
2899 Routine Description:
2901 This routine is called for a shutdown and flush IRPs. These are sent by the
2902 system before it actually shuts down or when the file system does a flush.
2903 A synchronize cache command is sent to the device if it is write caching.
2904 If the device is removable an unlock command will be sent. This routine
2905 will sent a shutdown or flush Srb to the port driver.
2909 DriverObject - Pointer to device object to being shutdown by system.
2920 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2921 PIO_STACK_LOCATION irpStack
;
2922 PSCSI_REQUEST_BLOCK srb
;
2927 // Allocate SCSI request block.
2930 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
2935 // Set the status and complete the request.
2938 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2939 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2940 return(STATUS_INSUFFICIENT_RESOURCES
);
2943 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
2946 // Write length to SRB.
2949 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2952 // Set SCSI bus address.
2955 srb
->PathId
= deviceExtension
->PathId
;
2956 srb
->TargetId
= deviceExtension
->TargetId
;
2957 srb
->Lun
= deviceExtension
->Lun
;
2960 // Set timeout value and mark the request as not being a tagged request.
2963 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 4;
2964 srb
->QueueTag
= SP_UNTAGGED
;
2965 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
2966 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2969 // If the write cache is enabled then send a synchronize cache request.
2972 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2974 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2975 srb
->CdbLength
= 10;
2977 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
2979 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2985 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status
));
2989 // Unlock the device if it is removable and this is a shutdown.
2992 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2994 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2995 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
2998 cdb
= (PVOID
) srb
->Cdb
;
2999 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3000 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3003 // Set timeout value.
3006 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3007 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3013 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3019 // Save a few parameters in the current stack location.
3022 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3023 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3026 // Set the retry count to zero.
3029 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3032 // Set up IoCompletion routine address.
3035 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3038 // Get next stack location and
3039 // set major function code.
3042 irpStack
= IoGetNextIrpStackLocation(Irp
);
3044 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3047 // Set up SRB for execute scsi request.
3048 // Save SRB address in next stack for port driver.
3051 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3054 // Set up Irp Address.
3057 srb
->OriginalRequest
= Irp
;
3060 // Call the port driver to process the request.
3063 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3065 } // end ScsiDiskShutdown()
3071 PDEVICE_OBJECT DeviceObject
3075 Routine Description:
3077 The routine performs the necessary functions to determine if a device is
3078 really a floppy rather than a harddisk. This is done by a mode sense
3079 command. First, a check is made to see if the medimum type is set. Second
3080 a check is made for the flexible parameters mode page. Also a check is
3081 made to see if the write cache is enabled.
3085 DeviceObject - Supplies the device object to be tested.
3089 Return TRUE if the indicated device is a floppy.
3093 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3100 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3102 if (modeData
== NULL
) {
3106 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3108 length
= ScsiClassModeSense(DeviceObject
,
3111 MODE_SENSE_RETURN_ALL
);
3113 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3116 // Retry the request in case of a check condition.
3119 length
= ScsiClassModeSense(DeviceObject
,
3122 MODE_SENSE_RETURN_ALL
);
3124 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3126 ExFreePool(modeData
);
3133 // If the length is greater than length indicated by the mode data reset
3134 // the data to the mode data.
3137 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3138 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3142 // Look for the flexible disk mode page.
3145 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_FLEXIBILE
, TRUE
);
3147 if (pageData
!= NULL
) {
3149 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3150 ExFreePool(modeData
);
3155 // Check to see if the write cache is enabled.
3158 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3161 // Assume that write cache is disabled or not supported.
3164 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3167 // Check if valid caching page exists.
3170 if (pageData
!= NULL
) {
3173 // Check if write cache is disabled.
3176 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3179 "SCSIDISK: Disk write cache enabled\n"));
3182 // Check if forced unit access (FUA) is supported.
3185 if (((PMODE_PARAMETER_HEADER
)modeData
)->DeviceSpecificParameter
& MODE_DSP_FUA_SUPPORTED
) {
3187 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3192 "SCSIDISK: Disk does not support FUA or DPO\n"));
3202 ExFreePool(modeData
);
3205 } // end IsFloppyDevice()
3211 IN PDEVICE_OBJECT DeviceObject
,
3212 IN PCHAR ModeSelectBuffer
,
3219 Routine Description:
3221 This routine sends a mode select command.
3225 DeviceObject - Supplies the device object associated with this request.
3227 ModeSelectBuffer - Supplies a buffer containing the page data.
3229 Length - Supplies the length in bytes of the mode select buffer.
3231 SavePage - Indicates that parameters should be written to disk.
3235 Length of the transferred data is returned.
3239 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3241 SCSI_REQUEST_BLOCK srb
;
3246 PMODE_PARAMETER_BLOCK blockDescriptor
;
3250 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3253 // Allocate buffer for mode select header, block descriptor, and mode page.
3256 buffer
= (ULONG_PTR
)ExAllocatePool(NonPagedPoolCacheAligned
,length2
);
3258 RtlZeroMemory((PVOID
)buffer
, length2
);
3261 // Set length in header to size of mode page.
3264 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3266 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3272 blockDescriptor
->BlockLength
[1]=0x02;
3275 // Copy mode page to buffer.
3278 RtlCopyMemory((PVOID
)(buffer
+ 3), ModeSelectBuffer
, Length
);
3284 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3287 // Build the MODE SELECT CDB.
3291 cdb
= (PCDB
)srb
.Cdb
;
3294 // Set timeout value from device extension.
3297 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
3299 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3300 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3301 cdb
->MODE_SELECT
.PFBit
= 1;
3302 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3306 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3313 if (status
== STATUS_VERIFY_REQUIRED
) {
3316 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3329 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3330 status
= STATUS_SUCCESS
;
3333 ExFreePool((PVOID
)buffer
);
3335 if (NT_SUCCESS(status
)) {
3341 } // end SciDiskModeSelect()
3347 IN PDEVICE_OBJECT DeviceObject
,
3348 IN PSCSI_INQUIRY_DATA LunInfo
3352 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3353 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3354 BAD_CONTROLLER_INFORMATION
const *controller
;
3359 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
3361 controller
= &ScsiDiskBadControllers
[j
];
3363 if (!controller
->DisableWriteCache
|| strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
3367 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller
->InquiryString
));
3369 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3371 if (modeData
== NULL
) {
3374 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3378 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3380 length
= ScsiClassModeSense(DeviceObject
,
3383 MODE_SENSE_RETURN_ALL
);
3385 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3388 // Retry the request in case of a check condition.
3391 length
= ScsiClassModeSense(DeviceObject
,
3394 MODE_SENSE_RETURN_ALL
);
3396 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3400 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3402 ExFreePool(modeData
);
3409 // If the length is greater than length indicated by the mode data reset
3410 // the data to the mode data.
3413 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3414 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3418 // Check to see if the write cache is enabled.
3421 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3424 // Assume that write cache is disabled or not supported.
3427 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3430 // Check if valid caching page exists.
3433 if (pageData
!= NULL
) {
3435 BOOLEAN savePage
= FALSE
;
3437 savePage
= (BOOLEAN
)(((PMODE_CACHING_PAGE
)pageData
)->PageSavable
);
3440 // Check if write cache is disabled.
3443 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3445 PIO_ERROR_LOG_PACKET errorLogEntry
;
3450 // Disable write cache and ensure necessary fields are zeroed.
3453 ((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
= FALSE
;
3454 ((PMODE_CACHING_PAGE
)pageData
)->Reserved
= 0;
3455 ((PMODE_CACHING_PAGE
)pageData
)->PageSavable
= 0;
3456 ((PMODE_CACHING_PAGE
)pageData
)->Reserved2
= 0;
3459 // Extract length from caching page.
3462 length
= ((PMODE_CACHING_PAGE
)pageData
)->PageLength
;
3465 // Compensate for page code and page length.
3471 // Issue mode select to set the parameter.
3474 if (ScsiDiskModeSelect(DeviceObject
,
3480 "SCSIDISK: Disk write cache disabled\n"));
3482 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3483 errorCode
= IO_WRITE_CACHE_DISABLED
;
3486 if (ScsiDiskModeSelect(DeviceObject
,
3492 "SCSIDISK: Disk write cache disabled\n"));
3495 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3496 errorCode
= IO_WRITE_CACHE_DISABLED
;
3501 "SCSIDISK: Mode select to disable write cache failed\n"));
3503 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3504 errorCode
= IO_WRITE_CACHE_ENABLED
;
3509 // Log the appropriate informational or error entry.
3512 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3514 sizeof(IO_ERROR_LOG_PACKET
) + 3
3517 if (errorLogEntry
!= NULL
) {
3519 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3520 errorLogEntry
->ErrorCode
= errorCode
;
3521 errorLogEntry
->SequenceNumber
= 0;
3522 errorLogEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
3523 errorLogEntry
->IoControlCode
= 0;
3524 errorLogEntry
->RetryCount
= 0;
3525 errorLogEntry
->UniqueErrorValue
= 0x1;
3526 errorLogEntry
->DumpDataSize
= 3 * sizeof(ULONG
);
3527 errorLogEntry
->DumpData
[0] = LunInfo
->PathId
;
3528 errorLogEntry
->DumpData
[1] = LunInfo
->TargetId
;
3529 errorLogEntry
->DumpData
[2] = LunInfo
->Lun
;
3532 // Write the error log packet.
3535 IoWriteErrorLogEntry(errorLogEntry
);
3541 // Found device so exit the loop and return.
3553 CalculateMbrCheckSum(
3554 IN PDEVICE_EXTENSION DeviceExtension
,
3560 Routine Description:
3562 Read MBR and calculate checksum.
3566 DeviceExtension - Supplies a pointer to the device information for disk.
3567 Checksum - Memory location to return MBR checksum.
3571 Returns TRUE if checksum is valid.
3575 LARGE_INTEGER sectorZero
;
3577 IO_STATUS_BLOCK ioStatus
;
3585 sectorZero
.QuadPart
= (LONGLONG
) 0;
3588 // Create notification event object to be used to signal the inquiry
3589 // request completion.
3592 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
3598 sectorSize
= DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
3601 // Make sure sector size is at least 512 bytes.
3604 if (sectorSize
< 512) {
3609 // Allocate buffer for sector read.
3612 mbr
= ExAllocatePool(NonPagedPoolCacheAligned
, sectorSize
);
3619 // Build IRP to read MBR.
3622 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
3623 DeviceExtension
->DeviceObject
,
3636 // Pass request to port driver and wait for request to complete.
3639 status
= IoCallDriver(DeviceExtension
->DeviceObject
,
3642 if (status
== STATUS_PENDING
) {
3643 KeWaitForSingleObject(&event
,
3648 status
= ioStatus
.Status
;
3651 if (!NT_SUCCESS(status
)) {
3657 // Calculate MBR checksum.
3662 for (i
= 0; i
< 128; i
++) {
3663 *Checksum
+= mbr
[i
];
3666 *Checksum
= ~*Checksum
+ 1;
3676 IN PDEVICE_EXTENSION DeviceExtension
,
3683 Routine Description:
3685 The routine queries the registry to determine if this disk is visible to
3686 the BIOS. If the disk is visable to the BIOS, then the geometry information
3691 DeviceExtension - Supplies a pointer to the device information for disk.
3692 Signature - Unique identifier recorded in MBR.
3693 BusKey - Handle of bus key.
3694 DiskNumber - Returns ordinal of disk as BIOS sees it.
3698 TRUE is disk signature matched.
3702 PDISK_DATA diskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
3703 BOOLEAN diskFound
= FALSE
;
3704 OBJECT_ATTRIBUTES objectAttributes
;
3705 UNICODE_STRING unicodeString
;
3706 UNICODE_STRING identifier
;
3708 ULONG adapterNumber
;
3716 STRING anotherString
;
3719 PKEY_VALUE_FULL_INFORMATION keyData
;
3723 for (busNumber
= 0; ; busNumber
++) {
3726 // Open controller name key.
3729 sprintf((PCHAR
)buffer
,
3733 RtlInitString(&string
,
3736 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3740 if (!NT_SUCCESS(status
)){
3744 InitializeObjectAttributes(&objectAttributes
,
3746 OBJ_CASE_INSENSITIVE
,
3748 (PSECURITY_DESCRIPTOR
)NULL
);
3750 status
= ZwOpenKey(&spareKey
,
3754 RtlFreeUnicodeString(&unicodeString
);
3756 if (!NT_SUCCESS(status
)) {
3761 // Open up controller ordinal key.
3764 RtlInitUnicodeString(&unicodeString
, L
"DiskController");
3765 InitializeObjectAttributes(&objectAttributes
,
3767 OBJ_CASE_INSENSITIVE
,
3769 (PSECURITY_DESCRIPTOR
)NULL
);
3771 status
= ZwOpenKey(&adapterKey
,
3776 // This could fail even with additional adapters of this type
3780 if (!NT_SUCCESS(status
)) {
3784 for (adapterNumber
= 0; ; adapterNumber
++) {
3790 sprintf((PCHAR
)buffer
,
3791 "%lu\\DiskPeripheral",
3794 RtlInitString(&string
,
3797 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3801 if (!NT_SUCCESS(status
)){
3805 InitializeObjectAttributes(&objectAttributes
,
3807 OBJ_CASE_INSENSITIVE
,
3809 (PSECURITY_DESCRIPTOR
)NULL
);
3811 status
= ZwOpenKey(&diskKey
,
3815 RtlFreeUnicodeString(&unicodeString
);
3817 if (!NT_SUCCESS(status
)) {
3821 for (diskNumber
= 0; ; diskNumber
++) {
3823 sprintf((PCHAR
)buffer
,
3827 RtlInitString(&string
,
3830 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3834 if (!NT_SUCCESS(status
)){
3838 InitializeObjectAttributes(&objectAttributes
,
3840 OBJ_CASE_INSENSITIVE
,
3842 (PSECURITY_DESCRIPTOR
)NULL
);
3844 status
= ZwOpenKey(&targetKey
,
3848 RtlFreeUnicodeString(&unicodeString
);
3850 if (!NT_SUCCESS(status
)) {
3855 // Allocate buffer for registry query.
3858 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
3860 if (keyData
== NULL
) {
3866 // Get disk peripheral identifier.
3869 RtlInitUnicodeString(&unicodeString
, L
"Identifier");
3870 status
= ZwQueryValueKey(targetKey
,
3872 KeyValueFullInformation
,
3879 if (!NT_SUCCESS(status
)) {
3884 // Complete unicode string.
3888 (PWSTR
)((PUCHAR
)keyData
+ keyData
->DataOffset
);
3889 identifier
.Length
= (USHORT
)keyData
->DataLength
;
3890 identifier
.MaximumLength
= (USHORT
)keyData
->DataLength
;
3893 // Convert unicode identifier to ansi string.
3897 RtlUnicodeStringToAnsiString(&anotherString
,
3901 if (!NT_SUCCESS(status
)) {
3906 // If checksum is zero, then the MBR is valid and
3907 // the signature is meaningful.
3910 if (diskData
->MbrCheckSum
) {
3913 // Convert checksum to ansi string.
3916 sprintf((PCHAR
)buffer
, "%08lx", diskData
->MbrCheckSum
);
3921 // Convert signature to ansi string.
3924 sprintf((PCHAR
)buffer
, "%08lx", diskData
->Signature
);
3927 // Make string point at signature. Can't use scan
3928 // functions because they are not exported for driver use.
3931 anotherString
.Buffer
+=9;
3935 // Convert to ansi string.
3938 RtlInitString(&string
,
3943 // Make string lengths equal.
3946 anotherString
.Length
= string
.Length
;
3949 // Check if strings match.
3952 if (RtlCompareString(&string
,
3957 *DiskNumber
= diskNumber
;
3960 ExFreePool(keyData
);
3963 // Readjust indentifier string if necessary.
3966 if (!diskData
->MbrCheckSum
) {
3967 anotherString
.Buffer
-=9;
3970 RtlFreeAnsiString(&anotherString
);
3980 ZwClose(adapterKey
);
3986 } // end EnumerateBusKey()
3992 IN PDEVICE_EXTENSION DeviceExtension
3996 Routine Description:
3998 The routine queries the registry to determine if this disk is visible to
3999 the BIOS. If the disk is visable to the BIOS, then the geometry information
4004 DeviceExtension - Supplies a pointer to the device information for disk.
4013 OBJECT_ATTRIBUTES objectAttributes
;
4014 UNICODE_STRING unicodeString
;
4018 PCM_INT13_DRIVE_PARAMETER driveParameters
;
4019 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor
;
4020 PKEY_VALUE_FULL_INFORMATION keyData
;
4024 ULONG numberOfDrives
;
4027 ULONG sectorsPerTrack
;
4028 ULONG tracksPerCylinder
;
4029 BOOLEAN foundEZHooker
;
4035 // Initialize the object for the key.
4038 InitializeObjectAttributes(&objectAttributes
,
4039 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
4040 OBJ_CASE_INSENSITIVE
,
4042 (PSECURITY_DESCRIPTOR
) NULL
);
4045 // Create the hardware base key.
4048 status
= ZwOpenKey(&hardwareKey
,
4053 if (!NT_SUCCESS(status
)) {
4054 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
));
4060 // Get disk BIOS geometry information.
4063 RtlInitUnicodeString(&unicodeString
, L
"Configuration Data");
4065 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
4067 if (keyData
== NULL
) {
4068 ZwClose(hardwareKey
);
4072 status
= ZwQueryValueKey(hardwareKey
,
4074 KeyValueFullInformation
,
4079 if (!NT_SUCCESS(status
)) {
4081 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4083 ExFreePool(keyData
);
4088 // Open EISA bus key.
4091 RtlInitUnicodeString(&unicodeString
, L
"EisaAdapter");
4093 InitializeObjectAttributes(&objectAttributes
,
4095 OBJ_CASE_INSENSITIVE
,
4097 (PSECURITY_DESCRIPTOR
)NULL
);
4099 status
= ZwOpenKey(&busKey
,
4103 if (!NT_SUCCESS(status
)) {
4108 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4109 if (EnumerateBusKey(DeviceExtension
,
4113 ZwClose(hardwareKey
);
4120 // Open Multifunction bus key.
4123 RtlInitUnicodeString(&unicodeString
, L
"MultifunctionAdapter");
4125 InitializeObjectAttributes(&objectAttributes
,
4127 OBJ_CASE_INSENSITIVE
,
4129 (PSECURITY_DESCRIPTOR
)NULL
);
4131 status
= ZwOpenKey(&busKey
,
4135 ZwClose(hardwareKey
);
4136 if (NT_SUCCESS(status
)) {
4138 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4139 if (EnumerateBusKey(DeviceExtension
,
4147 ExFreePool(keyData
);
4152 resourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PUCHAR
)keyData
+
4153 keyData
->DataOffset
);
4156 // Check that the data is long enough to hold a full resource descriptor,
4157 // and that the last resouce list is device-specific and long enough.
4160 if (keyData
->DataLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) ||
4161 resourceDescriptor
->PartialResourceList
.Count
== 0 ||
4162 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].Type
!=
4163 CmResourceTypeDeviceSpecific
||
4164 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0]
4165 .u
.DeviceSpecificData
.DataSize
< sizeof(ULONG
)) {
4167 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4168 ExFreePool(keyData
);
4173 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
;
4176 // Point to the BIOS data. The BIOS data is located after the first
4177 // partial Resource list which should be device specific data.
4180 buffer
= (PUCHAR
) keyData
+ keyData
->DataOffset
+
4181 sizeof(CM_FULL_RESOURCE_DESCRIPTOR
);
4184 numberOfDrives
= length
/ sizeof(CM_INT13_DRIVE_PARAMETER
);
4187 // Use the defaults if the drive number is greater than the
4188 // number of drives detected by the BIOS.
4191 if (numberOfDrives
<= diskNumber
) {
4192 ExFreePool(keyData
);
4197 // Point to the array of drive parameters.
4200 driveParameters
= (PCM_INT13_DRIVE_PARAMETER
) buffer
+ diskNumber
;
4201 cylinders
= driveParameters
->MaxCylinders
+ 1;
4202 sectorsPerTrack
= driveParameters
->SectorsPerTrack
;
4203 tracksPerCylinder
= driveParameters
->MaxHeads
+1;
4206 // Calculate the actual number of sectors.
4209 sectors
= (ULONG
)(DeviceExtension
->PartitionLength
.QuadPart
>>
4210 DeviceExtension
->SectorShift
);
4213 if (sectors
>= cylinders
* tracksPerCylinder
* sectorsPerTrack
) {
4214 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4215 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4216 sectors
, cylinders
, tracksPerCylinder
, sectorsPerTrack
));
4221 // Since the BIOS may not report the full drive, recalculate the drive
4222 // size based on the volume size and the BIOS values for tracks per
4223 // cylinder and sectors per track..
4226 length
= tracksPerCylinder
* sectorsPerTrack
;
4231 // The BIOS information is bogus.
4234 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4235 ExFreePool(keyData
);
4239 cylinders
= sectors
/ length
;
4242 // Update the actual geometry information.
4245 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= sectorsPerTrack
;
4246 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
;
4247 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)cylinders
;
4248 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= cylinders
* tracksPerCylinder
* sectorsPerTrack
*
4249 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4252 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4257 ExFreePool(keyData
);
4259 foundEZHooker
= FALSE
;
4261 if (!DeviceExtension
->DMActive
) {
4263 HalExamineMBR(DeviceExtension
->DeviceObject
,
4264 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4272 foundEZHooker
= TRUE
;
4278 if (DeviceExtension
->DMActive
|| foundEZHooker
) {
4280 while (cylinders
> 1024) {
4282 tracksPerCylinder
= tracksPerCylinder
*2;
4283 cylinders
= cylinders
/2;
4288 // int 13 values are always 1 less.
4291 tracksPerCylinder
-= 1;
4295 // DM reserves the CE cylinder
4300 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= cylinders
+ 1;
4301 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
+ 1;
4303 DeviceExtension
->PartitionLength
.QuadPart
=
4304 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
=
4305 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
*
4306 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
*
4307 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
*
4308 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
;
4310 if (DeviceExtension
->DMActive
) {
4312 DeviceExtension
->DMByteSkew
= DeviceExtension
->DMSkew
* DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4318 DeviceExtension
->DMByteSkew
= 0;
4324 } // end UpdateGeometry()
4330 UpdateRemovableGeometry (
4331 IN PDEVICE_OBJECT DeviceObject
,
4337 Routine Description:
4339 This routines updates the size and starting offset of the device. This is
4340 used when the media on the device may have changed thereby changing the
4341 size of the device. If this is the physical device then a
4342 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4346 DeviceObject - Supplies the device object whos size needs to be updated.
4348 Irp - Supplies a reference where the status can be updated.
4352 Returns the status of the opertion.
4357 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4358 PDRIVE_LAYOUT_INFORMATION partitionList
;
4360 PDISK_DATA diskData
;
4361 ULONG partitionNumber
;
4364 // Determine if the size of the partition may have changed because
4365 // the media has changed.
4368 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
4370 return(STATUS_SUCCESS
);
4375 // If this request is for partition zero then do a read drive
4376 // capacity otherwise do a I/O read partition table.
4379 diskData
= (PDISK_DATA
) (deviceExtension
+ 1);
4382 // Read the drive capcity. If that fails, give up.
4385 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
4387 if (!NT_SUCCESS(status
)) {
4392 // Read the partition table agian.
4395 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
4396 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4401 if (!NT_SUCCESS(status
)) {
4404 // Fail the request.
4410 if (diskData
->PartitionNumber
!= 0 &&
4411 diskData
->PartitionNumber
<= partitionList
->PartitionCount
) {
4413 partitionNumber
= diskData
->PartitionNumber
- 1;
4416 // Update the partition information for this parition.
4419 diskData
->PartitionType
=
4420 partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
4422 diskData
->BootIndicator
=
4423 partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
4425 deviceExtension
->StartingOffset
=
4426 partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
4428 deviceExtension
->PartitionLength
=
4429 partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
4431 diskData
->HiddenSectors
=
4432 partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
4434 deviceExtension
->SectorShift
= ((PDEVICE_EXTENSION
)
4435 deviceExtension
->PhysicalDevice
->DeviceExtension
)->SectorShift
;
4437 } else if (diskData
->PartitionNumber
!= 0) {
4440 // The paritition does not exist. Zero all the data.
4443 diskData
->PartitionType
= 0;
4444 diskData
->BootIndicator
= 0;
4445 diskData
->HiddenSectors
= 0;
4446 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)0;
4447 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)0;
4451 // Free the parition list allocate by I/O read partition table.
4454 ExFreePool(partitionList
);
4457 return(STATUS_SUCCESS
);
4463 ScsiDiskProcessError(
4464 PDEVICE_OBJECT DeviceObject
,
4465 PSCSI_REQUEST_BLOCK Srb
,
4471 Routine Description:
4473 This routine checks the type of error. If the error indicates an underrun
4474 then indicate the request should be retried.
4478 DeviceObject - Supplies a pointer to the device object.
4480 Srb - Supplies a pointer to the failing Srb.
4482 Status - Status with which the IRP will be completed.
4484 Retry - Indication of whether the request will be retried.
4493 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4495 if (*Status
== STATUS_DATA_OVERRUN
&&
4496 ( Srb
->Cdb
[0] == SCSIOP_WRITE
|| Srb
->Cdb
[0] == SCSIOP_READ
)) {
4501 // Update the error count for the device.
4504 deviceExtension
->ErrorCount
++;
4507 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
4508 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
4511 // The disk drive should never be busy this long. Reset the scsi bus
4512 // maybe this will clear the condition.
4515 ResetScsiBus(DeviceObject
);
4518 // Update the error count for the device.
4521 deviceExtension
->ErrorCount
++;
4528 PDEVICE_OBJECT DeviceObject
,
4529 PSCSI_INQUIRY_DATA LunInfo
,
4530 PIO_SCSI_CAPABILITIES PortCapabilities
4535 Routine Description:
4537 This function checks to see if an SCSI logical unit requires speical
4542 DeviceObject - Supplies the device object to be tested.
4544 InquiryData - Supplies the inquiry data returned by the device of interest.
4546 PortCapabilities - Supplies the capabilities of the device object.
4555 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4556 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
4557 BAD_CONTROLLER_INFORMATION
const *controller
;
4560 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
4562 controller
= &ScsiDiskBadControllers
[j
];
4564 if (strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
4568 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller
->InquiryString
));
4571 // Found a listed controller. Determine what must be done.
4574 if (controller
->DisableTaggedQueuing
) {
4577 // Disable tagged queuing.
4580 deviceExtension
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
4583 if (controller
->DisableSynchronousTransfers
) {
4586 // Disable synchronous data transfers.
4589 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4593 if (controller
->DisableDisconnects
) {
4596 // Disable disconnects.
4599 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
4604 // Found device so exit the loop and return.
4611 // Set the StartUnit flag appropriately.
4614 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) {
4615 deviceExtension
->DeviceFlags
|= DEV_SAFE_START_UNIT
;
4617 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
4618 if (_strnicmp((PCCHAR
)InquiryData
->VendorId
, "iomega", strlen("iomega"))) {
4619 deviceExtension
->DeviceFlags
&= ~DEV_SAFE_START_UNIT
;
4630 IN PDEVICE_OBJECT DeviceObject
4635 Routine Description:
4637 This command sends a reset bus command to the SCSI port driver.
4641 DeviceObject - The device object for the logical unit with
4650 PIO_STACK_LOCATION irpStack
;
4652 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4653 PSCSI_REQUEST_BLOCK srb
;
4654 PCOMPLETION_CONTEXT context
;
4656 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4659 // Allocate Srb from nonpaged pool.
4662 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
4663 sizeof(COMPLETION_CONTEXT
));
4666 // Save the device object in the context for use by the completion
4670 context
->DeviceObject
= DeviceObject
;
4671 srb
= &context
->Srb
;
4677 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4680 // Write length to SRB.
4683 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4686 // Set up SCSI bus address.
4689 srb
->PathId
= deviceExtension
->PathId
;
4690 srb
->TargetId
= deviceExtension
->TargetId
;
4691 srb
->Lun
= deviceExtension
->Lun
;
4693 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4696 // Build the asynchronous request to be sent to the port driver.
4697 // Since this routine is called from a DPC the IRP should always be
4701 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
4703 IoSetCompletionRoutine(irp
,
4704 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
4710 irpStack
= IoGetNextIrpStackLocation(irp
);
4712 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4714 srb
->OriginalRequest
= irp
;
4717 // Store the SRB address in next stack for port driver.
4720 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4723 // Call the port driver with the IRP.
4726 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
4730 } // end ResetScsiBus()
4735 UpdateDeviceObjects(
4736 IN PDEVICE_OBJECT PhysicalDisk
,
4742 Routine Description:
4744 This routine creates, deletes and changes device objects when
4745 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4746 the drive layout information for the user. It is possible to
4747 call this routine even in the GET_LAYOUT case because RewritePartition
4752 DeviceObject - Device object for physical disk.
4753 Irp - IO Request Packet (IRP).
4761 PDEVICE_EXTENSION physicalExtension
= PhysicalDisk
->DeviceExtension
;
4762 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
4764 ULONG partitionNumber
;
4765 ULONG partitionCount
;
4766 ULONG lastPartition
;
4767 ULONG partitionOrdinal
;
4768 PPARTITION_INFORMATION partitionEntry
;
4769 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
4770 STRING ntNameString
;
4771 UNICODE_STRING ntUnicodeString
;
4772 PDEVICE_OBJECT deviceObject
;
4773 PDEVICE_EXTENSION deviceExtension
;
4774 PDISK_DATA diskData
;
4776 ULONG numberListElements
;
4779 partitionCount
= ((partitionList
->PartitionCount
+ 3) / 4) * 4;
4782 // Zero all of the partition numbers.
4785 for (partition
= 0; partition
< partitionCount
; partition
++) {
4786 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4787 partitionEntry
->PartitionNumber
= 0;
4791 // Walk through chain of partitions for this disk to determine
4792 // which existing partitions have no match.
4795 deviceExtension
= physicalExtension
;
4796 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4801 deviceExtension
= diskData
->NextPartition
;
4804 // Check if this is the last partition in the chain.
4807 if (!deviceExtension
) {
4812 // Get the partition device extension from disk data.
4815 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4818 // Check for highest partition number this far.
4821 if (diskData
->PartitionNumber
> lastPartition
) {
4822 lastPartition
= diskData
->PartitionNumber
;
4826 // Check if this partition is not currently being used.
4829 if (!deviceExtension
->PartitionLength
.QuadPart
) {
4834 // Loop through partition information to look for match.
4838 partitionOrdinal
= 0;
4840 for (partition
= 0; partition
< partitionCount
; partition
++) {
4843 // Get partition descriptor.
4846 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4849 // Check if empty, or describes extended partiton or hasn't changed.
4852 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4853 IsContainerPartition(partitionEntry
->PartitionType
)) {
4858 // Advance partition ordinal.
4864 // Check if new partition starts where this partition starts.
4867 if (partitionEntry
->StartingOffset
.QuadPart
!=
4868 deviceExtension
->StartingOffset
.QuadPart
) {
4873 // Check if partition length is the same.
4876 if (partitionEntry
->PartitionLength
.QuadPart
==
4877 deviceExtension
->PartitionLength
.QuadPart
) {
4880 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4881 physicalExtension
->DeviceNumber
,
4882 diskData
->PartitionNumber
));
4885 // Indicate match is found and set partition number
4890 partitionEntry
->PartitionNumber
= diskData
->PartitionNumber
;
4898 // A match is found.
4901 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4904 // If this partition is marked for update then update partition type.
4907 if (partitionEntry
->RewritePartition
) {
4908 diskData
->PartitionType
= partitionEntry
->PartitionType
;
4912 // Update partitional ordinal for calls to HAL routine
4913 // IoSetPartitionInformation.
4916 diskData
->PartitionOrdinal
= partitionOrdinal
;
4919 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4920 physicalExtension
->DeviceNumber
,
4921 diskData
->PartitionOrdinal
,
4922 diskData
->PartitionNumber
));
4927 // no match was found, indicate this partition is gone.
4931 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4932 physicalExtension
->DeviceNumber
,
4933 diskData
->PartitionNumber
));
4935 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
4941 // Walk through partition loop to find new partitions and set up
4942 // device extensions to describe them. In some cases new device
4943 // objects will be created.
4946 partitionOrdinal
= 0;
4949 partition
< partitionCount
;
4953 // Get partition descriptor.
4956 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4959 // Check if empty, or describes an extended partiton.
4962 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4963 IsContainerPartition(partitionEntry
->PartitionType
)) {
4968 // Keep track of position on the disk for calls to IoSetPartitionInformation.
4974 // Check if this entry should be rewritten.
4977 if (!partitionEntry
->RewritePartition
) {
4981 if (partitionEntry
->PartitionNumber
) {
4984 // Partition is an exact match with an existing partition, but is
4985 // being written anyway.
4992 // Check first if existing device object is available by
4993 // walking partition extension list.
4996 partitionNumber
= 0;
4997 deviceExtension
= physicalExtension
;
4998 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5003 // Get next partition device extension from disk data.
5006 deviceExtension
= diskData
->NextPartition
;
5008 if (!deviceExtension
) {
5012 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5015 // A device object is free if the partition length is set to zero.
5018 if (!deviceExtension
->PartitionLength
.QuadPart
) {
5019 partitionNumber
= diskData
->PartitionNumber
;
5026 // If partition number is still zero then a new device object
5030 if (partitionNumber
== 0) {
5033 partitionNumber
= lastPartition
;
5036 // Get or create partition object and set up partition parameters.
5039 sprintf(ntNameBuffer
,
5040 "\\Device\\Harddisk%lu\\Partition%lu",
5041 physicalExtension
->DeviceNumber
,
5044 RtlInitString(&ntNameString
,
5047 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
5051 if (!NT_SUCCESS(status
)) {
5056 "UpdateDeviceObjects: Create device object %s\n",
5060 // This is a new name. Create the device object to represent it.
5063 status
= IoCreateDevice(PhysicalDisk
->DriverObject
,
5064 DEVICE_EXTENSION_SIZE
,
5071 if (!NT_SUCCESS(status
)) {
5073 "UpdateDeviceObjects: Can't create device %s\n",
5075 RtlFreeUnicodeString(&ntUnicodeString
);
5080 // Set up device object fields.
5083 deviceObject
->Flags
|= DO_DIRECT_IO
;
5084 deviceObject
->StackSize
= PhysicalDisk
->StackSize
;
5087 // Set up device extension fields.
5090 deviceExtension
= deviceObject
->DeviceExtension
;
5093 // Copy physical disk extension to partition extension.
5096 RtlMoveMemory(deviceExtension
,
5098 sizeof(DEVICE_EXTENSION
));
5101 // Initialize the new S-List.
5104 if (deviceExtension
->SrbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
5105 numberListElements
= 30;
5107 numberListElements
= 8;
5111 // Build the lookaside list for srb's for this partition based on
5112 // whether the adapter and disk can do tagged queueing.
5115 ScsiClassInitializeSrbLookasideList(deviceExtension
,
5116 numberListElements
);
5119 // Allocate spinlock for zoning for split-request completion.
5122 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
5125 // Write back partition number used in creating object name.
5128 partitionEntry
->PartitionNumber
= partitionNumber
;
5131 // Clear flags initializing bit.
5134 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
5137 // Point back at device object.
5140 deviceExtension
->DeviceObject
= deviceObject
;
5142 RtlFreeUnicodeString(&ntUnicodeString
);
5145 // Link to end of partition chain using previous disk data.
5148 diskData
->NextPartition
= deviceExtension
;
5151 // Get new disk data and zero next partition pointer.
5154 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5155 diskData
->NextPartition
= NULL
;
5160 // Set pointer to disk data area that follows device extension.
5163 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5166 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5167 physicalExtension
->DeviceNumber
,
5172 // Update partition information in partition device extension.
5175 diskData
->PartitionNumber
= partitionNumber
;
5176 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5177 diskData
->BootIndicator
= partitionEntry
->BootIndicator
;
5178 deviceExtension
->StartingOffset
= partitionEntry
->StartingOffset
;
5179 deviceExtension
->PartitionLength
= partitionEntry
->PartitionLength
;
5180 diskData
->HiddenSectors
= partitionEntry
->HiddenSectors
;
5181 diskData
->PartitionOrdinal
= partitionOrdinal
;
5184 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5185 diskData
->PartitionOrdinal
,
5186 diskData
->PartitionNumber
));
5189 // Update partition number passed in to indicate the
5190 // device name for this partition.
5193 partitionEntry
->PartitionNumber
= partitionNumber
;
5196 } // end UpdateDeviceObjects()