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
16 #include <include/class2.h>
27 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
34 } PARTITION_LIST_STATE
;
40 typedef struct _DISK_DATA
{
46 PDEVICE_EXTENSION NextPartition
;
49 // Disk signature (from MBR)
61 // Number of hidden sectors for BPB.
67 // Partition number of this device object
69 // This field is set during driver initialization or when the partition
70 // is created to identify a partition to the system.
73 ULONG PartitionNumber
;
76 // This field is the ordinal of a partition as it appears on a disk.
79 ULONG PartitionOrdinal
;
82 // Partition type of this device object
84 // This field is set by:
86 // 1) Initially set according to the partition list entry partition
87 // type returned by IoReadPartitionTable.
89 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
90 // I/O control function when IoSetPartitionInformation function
91 // successfully updates the partition type on the disk.
97 // Boot indicator - indicates whether this partition is a bootable (active)
98 // partition for this device
100 // This field is set according to the partition list entry boot indicator
101 // returned by IoReadPartitionTable.
104 BOOLEAN BootIndicator
;
107 // DriveNotReady - indicates that the this device is currently not ready
108 // because there is no media in the device.
111 BOOLEAN DriveNotReady
;
114 // State of PartitionList initialization
117 PARTITION_LIST_STATE PartitionListState
;
121 // HACK so that we can use NT5+ NTOS functions with this NT4 driver
122 // for removable devices and avoid an infinite recursive loop between
123 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
125 ULONG UpdateRemovableGeometryCount
;
128 } DISK_DATA
, *PDISK_DATA
;
131 // Define a general structure of identifying disk controllers with bad
135 typedef struct _BAD_CONTROLLER_INFORMATION
{
137 BOOLEAN DisableTaggedQueuing
;
138 BOOLEAN DisableSynchronousTransfers
;
139 BOOLEAN DisableDisconnects
;
140 BOOLEAN DisableWriteCache
;
141 }BAD_CONTROLLER_INFORMATION
, *PBAD_CONTROLLER_INFORMATION
;
143 BAD_CONTROLLER_INFORMATION
const ScsiDiskBadControllers
[] = {
144 { "TOSHIBA MK538FB 60", TRUE
, FALSE
, FALSE
, FALSE
},
145 { "CONNER CP3500", FALSE
, TRUE
, FALSE
, FALSE
},
146 { "OLIVETTICP3500", FALSE
, TRUE
, FALSE
, FALSE
},
147 { "SyQuest SQ5110 CHC", TRUE
, TRUE
, FALSE
, FALSE
},
148 { "SEAGATE ST41601N 0102", FALSE
, TRUE
, FALSE
, FALSE
},
149 { "SEAGATE ST3655N", FALSE
, FALSE
, FALSE
, TRUE
},
150 { "SEAGATE ST3390N", FALSE
, FALSE
, FALSE
, TRUE
},
151 { "SEAGATE ST12550N", FALSE
, FALSE
, FALSE
, TRUE
},
152 { "SEAGATE ST32430N", FALSE
, FALSE
, FALSE
, TRUE
},
153 { "SEAGATE ST31230N", FALSE
, FALSE
, FALSE
, TRUE
},
154 { "SEAGATE ST15230N", FALSE
, FALSE
, FALSE
, TRUE
},
155 { "FUJITSU M2652S-512", TRUE
, FALSE
, FALSE
, FALSE
},
156 { "MAXTOR MXT-540SL I1.2", TRUE
, FALSE
, FALSE
, FALSE
},
157 { "COMPAQ PD-1", FALSE
, TRUE
, FALSE
, FALSE
}
161 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
162 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
164 #define MODE_DATA_SIZE 192
165 #define VALUE_BUFFER_SIZE 2048
166 #define SCSI_DISK_TIMEOUT 10
167 #define PARTITION0_LIST_SIZE 4
173 IN PDRIVER_OBJECT DriverObject
,
174 IN PUNICODE_STRING RegistryPath
179 ScsiDiskDeviceVerification(
180 IN PINQUIRYDATA InquiryData
186 IN PDRIVER_OBJECT DriveObject
,
187 IN PUNICODE_STRING RegistryPath
,
188 IN PCLASS_INIT_DATA InitializationData
,
189 IN PDEVICE_OBJECT PortDeviceObject
,
195 ScsiDiskCreateClose (
196 IN PDEVICE_OBJECT DeviceObject
,
202 ScsiDiskReadWriteVerification(
203 IN PDEVICE_OBJECT DeviceObject
,
209 ScsiDiskDeviceControl(
210 IN PDEVICE_OBJECT DeviceObject
,
216 ScsiDiskProcessError(
217 PDEVICE_OBJECT DeviceObject
,
218 PSCSI_REQUEST_BLOCK Srb
,
225 ScsiDiskShutdownFlush(
226 IN PDEVICE_OBJECT DeviceObject
,
233 IN PDEVICE_OBJECT DeviceObject
,
234 IN PSCSI_INQUIRY_DATA LunInfo
240 IN PDEVICE_OBJECT DeviceObject
,
241 IN PCHAR ModeSelectBuffer
,
249 IN PDEVICE_OBJECT DeviceObject
254 CalculateMbrCheckSum(
255 IN PDEVICE_EXTENSION DeviceExtension
,
262 IN PDEVICE_EXTENSION DeviceExtension
,
270 IN PDEVICE_EXTENSION DeviceExtension
275 UpdateRemovableGeometry (
276 IN PDEVICE_OBJECT DeviceObject
,
282 CreateDiskDeviceObject(
283 IN PDRIVER_OBJECT DriverObject
,
284 IN PUNICODE_STRING RegistryPath
,
285 IN PDEVICE_OBJECT PortDeviceObject
,
287 IN PULONG DeviceCount
,
288 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
289 IN PSCSI_INQUIRY_DATA LunInfo
,
290 IN PCLASS_INIT_DATA InitData
295 CreatePartitionDeviceObjects(
296 IN PDEVICE_OBJECT PhysicalDeviceObject
,
297 IN PUNICODE_STRING RegistryPath
303 IN PDEVICE_OBJECT DeviceObject
,
310 PDEVICE_OBJECT DeviceObject
,
311 PSCSI_INQUIRY_DATA LunInfo
,
312 PIO_SCSI_CAPABILITIES PortCapabilities
318 IN PDEVICE_OBJECT DeviceObject
323 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject
,
327 #pragma alloc_text(PAGE, DriverEntry)
328 #pragma alloc_text(PAGE, FindScsiDisks)
329 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
330 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
331 #pragma alloc_text(PAGE, EnumerateBusKey)
332 #pragma alloc_text(PAGE, UpdateGeometry)
333 #pragma alloc_text(PAGE, IsFloppyDevice)
334 #pragma alloc_text(PAGE, ScanForSpecial)
335 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
336 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
343 IN PDRIVER_OBJECT DriverObject
,
344 IN PUNICODE_STRING RegistryPath
351 This routine initializes the SCSI hard disk class driver.
355 DriverObject - Pointer to driver object created by system.
357 RegistryPath - Pointer to the name of the services node for this driver.
361 The function value is the final status from the initialization operation.
366 CLASS_INIT_DATA InitializationData
;
372 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
378 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
379 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
381 InitializationData
.DeviceType
= FILE_DEVICE_DISK
;
382 InitializationData
.DeviceCharacteristics
= 0;
388 InitializationData
.ClassError
= ScsiDiskProcessError
;
389 InitializationData
.ClassReadWriteVerification
= ScsiDiskReadWriteVerification
;
390 InitializationData
.ClassFindDevices
= FindScsiDisks
;
391 InitializationData
.ClassFindDeviceCallBack
= ScsiDiskDeviceVerification
;
392 InitializationData
.ClassDeviceControl
= ScsiDiskDeviceControl
;
393 InitializationData
.ClassShutdownFlush
= ScsiDiskShutdownFlush
;
394 InitializationData
.ClassCreateClose
= NULL
;
397 // Call the class init routine
400 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
402 } // end DriverEntry()
408 ScsiDiskDeviceVerification(
409 IN PINQUIRYDATA InquiryData
416 This routine checks InquiryData for the correct device type and qualifier.
420 InquiryData - Pointer to the inquiry data for the device in question.
424 True is returned if the correct device type is found.
429 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
430 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
431 InquiryData
->DeviceTypeQualifier
== 0) {
444 IN PDRIVER_OBJECT DriverObject
,
445 IN PUNICODE_STRING RegistryPath
,
446 IN PCLASS_INIT_DATA InitializationData
,
447 IN PDEVICE_OBJECT PortDeviceObject
,
455 This routine gets a port drivers capabilities, obtains the
456 inquiry data, searches the SCSI bus for the port driver and creates
457 the device objects for the disks found.
461 DriverObject - Pointer to driver object created by system.
463 PortDeviceObject - Device object use to send requests to port driver.
465 PortNumber - Number for port driver. Used to pass on to
466 CreateDiskDeviceObjects() and create device objects.
470 True is returned if one disk was found and successfully created.
475 PIO_SCSI_CAPABILITIES portCapabilities
;
477 PCONFIGURATION_INFORMATION configurationInformation
;
479 PSCSI_INQUIRY_DATA lunInfo
;
480 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
481 PINQUIRYDATA inquiryData
;
485 BOOLEAN foundOne
= FALSE
;
490 // Call port driver to get adapter capabilities.
493 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
495 if (!NT_SUCCESS(status
)) {
496 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
501 // Call port driver to get inquiry information to find disks.
504 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
506 if (!NT_SUCCESS(status
)) {
507 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
512 // Do a quick scan of the devices on this adapter to determine how many
513 // disks are on this adapter. This is used to determine the number of
514 // SRB zone elements to allocate.
517 adapterInfo
= (PVOID
) buffer
;
519 adapterDisk
= ScsiClassFindUnclaimedDevices(InitializationData
, adapterInfo
);
522 // Allocate a zone of SRB for disks on this adapter.
525 if (adapterDisk
== 0) {
528 // No free disks were found.
535 // Get the number of disks already initialized.
538 configurationInformation
= IoGetConfigurationInformation();
539 diskCount
= &configurationInformation
->DiskCount
;
542 // For each SCSI bus this adapter supports ...
545 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
548 // Get the SCSI bus scan data for this bus.
551 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
554 // Search list for unclaimed disk devices.
557 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
559 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
561 if (((inquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
562 (inquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
563 inquiryData
->DeviceTypeQualifier
== 0 &&
564 (!lunInfo
->DeviceClaimed
)) {
567 "FindScsiDevices: Vendor string is %.24s\n",
568 inquiryData
->VendorId
));
571 // Create device objects for disk
574 status
= CreateDiskDeviceObject(DriverObject
,
583 if (NT_SUCCESS(status
)) {
586 // Increment system disk device count.
599 if (lunInfo
->NextInquiryDataOffset
== 0) {
603 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
609 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
616 } // end FindScsiDisks()
621 CreateDiskDeviceObject(
622 IN PDRIVER_OBJECT DriverObject
,
623 IN PUNICODE_STRING RegistryPath
,
624 IN PDEVICE_OBJECT PortDeviceObject
,
626 IN PULONG DeviceCount
,
627 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
628 IN PSCSI_INQUIRY_DATA LunInfo
,
629 IN PCLASS_INIT_DATA InitData
636 This routine creates an object for the physical device and then searches
637 the device for partitions and creates an object for each partition.
641 DriverObject - Pointer to driver object created by system.
643 PortDeviceObject - Miniport device object.
645 PortNumber - port number. Used in creating disk objects.
647 DeviceCount - Number of previously installed devices.
649 PortCapabilities - Capabilities of this SCSI port.
651 LunInfo - LUN specific information.
659 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
661 UNICODE_STRING ntUnicodeString
;
662 OBJECT_ATTRIBUTES objectAttributes
;
665 PDEVICE_OBJECT deviceObject
= NULL
;
666 //PDEVICE_OBJECT physicalDevice;
667 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
668 PDEVICE_EXTENSION deviceExtension
= NULL
;
669 //PDEVICE_EXTENSION physicalDeviceExtension;
670 UCHAR pathId
= LunInfo
->PathId
;
671 UCHAR targetId
= LunInfo
->TargetId
;
672 UCHAR lun
= LunInfo
->Lun
;
673 //BOOLEAN writeCache;
674 PVOID senseData
= NULL
;
677 BOOLEAN srbListInitialized
= FALSE
;
683 // Set up an object directory to contain the objects for this
684 // device and all its partitions.
687 sprintf(ntNameBuffer
,
688 "\\Device\\Harddisk%lu",
691 RtlInitString(&ntNameString
,
694 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
698 if (!NT_SUCCESS(status
)) {
702 InitializeObjectAttributes(&objectAttributes
,
704 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
708 status
= ZwCreateDirectoryObject(&handle
,
709 DIRECTORY_ALL_ACCESS
,
712 RtlFreeUnicodeString(&ntUnicodeString
);
714 if (!NT_SUCCESS(status
)) {
717 "CreateDiskDeviceObjects: Could not create directory %s\n",
727 status
= ScsiClassClaimDevice(PortDeviceObject
,
732 if (!NT_SUCCESS(status
)) {
733 ZwMakeTemporaryObject(handle
);
739 // Create a device object for this device. Each physical disk will
740 // have at least one device object. The required device object
741 // describes the entire device. Its directory path is
742 // \Device\HarddiskN\Partition0, where N = device number.
745 sprintf(ntNameBuffer
,
746 "\\Device\\Harddisk%lu\\Partition0",
750 status
= ScsiClassCreateDeviceObject(DriverObject
,
756 if (!NT_SUCCESS(status
)) {
759 "CreateDiskDeviceObjects: Can not create device object %s\n",
762 goto CreateDiskDeviceObjectsExit
;
766 // Indicate that IRPs should include MDLs for data transfers.
769 deviceObject
->Flags
|= DO_DIRECT_IO
;
772 // Check if this is during initialization. If not indicate that
773 // system initialization already took place and this disk is ready
778 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
782 // Check for removable media support.
785 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->RemovableMedia
) {
786 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
790 // Set up required stack size in device object.
793 deviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
795 deviceExtension
= deviceObject
->DeviceExtension
;
798 // Allocate spinlock for split request completion.
801 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
804 // Initialize lock count to zero. The lock count is used to
805 // disable the ejection mechanism on devices that support
806 // removable media. Only the lock count in the physical
807 // device extension is used.
810 deviceExtension
->LockCount
= 0;
813 // Save system disk number.
816 deviceExtension
->DeviceNumber
= *DeviceCount
;
819 // Copy port device object pointer to the device extension.
822 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
825 // Set the alignment requirements for the device based on the
826 // host adapter requirements
829 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
830 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
834 // This is the physical device object.
837 //physicalDevice = deviceObject;
838 //physicalDeviceExtension = deviceExtension;
841 // Save address of port driver capabilities.
844 deviceExtension
->PortCapabilities
= PortCapabilities
;
847 // Build the lookaside list for srb's for the physical disk. Should only
851 ScsiClassInitializeSrbLookasideList(deviceExtension
,
852 PARTITION0_LIST_SIZE
);
854 srbListInitialized
= TRUE
;
857 // Initialize the srb flags.
860 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->CommandQueue
&&
861 PortCapabilities
->TaggedQueuing
) {
863 deviceExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
867 deviceExtension
->SrbFlags
= 0;
872 // Allow queued requests if this is not removable media.
875 if (!(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
877 deviceExtension
->SrbFlags
|= SRB_FLAGS_NO_QUEUE_FREEZE
;
882 // Look for controller that require special flags.
885 ScanForSpecial(deviceObject
,
889 //srbFlags = deviceExtension->SrbFlags;
892 // Allocate buffer for drive geometry.
895 diskGeometry
= ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
897 if (diskGeometry
== NULL
) {
900 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
901 status
= STATUS_INSUFFICIENT_RESOURCES
;
902 goto CreateDiskDeviceObjectsExit
;
905 deviceExtension
->DiskGeometry
= diskGeometry
;
908 // Allocate request sense buffer.
911 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
913 if (senseData
== NULL
) {
916 // The buffer can not be allocated.
920 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
922 status
= STATUS_INSUFFICIENT_RESOURCES
;
923 goto CreateDiskDeviceObjectsExit
;
927 // Set the sense data pointer in the device extension.
930 deviceExtension
->SenseData
= senseData
;
933 // Physical device object will describe the entire
934 // device, starting at byte offset 0.
937 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)(0);
940 // TargetId/LUN describes a device location on the SCSI bus.
941 // This information comes from the inquiry buffer.
944 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
945 deviceExtension
->PathId
= pathId
;
946 deviceExtension
->TargetId
= targetId
;
947 deviceExtension
->Lun
= lun
;
950 // Set timeout value in seconds.
953 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
955 deviceExtension
->TimeOutValue
= timeOut
;
957 deviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
961 // Back pointer to device object.
964 deviceExtension
->DeviceObject
= deviceObject
;
967 // If this is a removable device, then make sure it is not a floppy.
968 // Perform a mode sense command to determine the media type. Note
969 // IsFloppyDevice also checks for write cache enabled.
972 if (IsFloppyDevice(deviceObject
) && deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
973 (((PINQUIRYDATA
)LunInfo
->InquiryData
)->DeviceType
== DIRECT_ACCESS_DEVICE
)) {
975 status
= STATUS_NO_SUCH_DEVICE
;
976 goto CreateDiskDeviceObjectsExit
;
979 DisableWriteCache(deviceObject
,LunInfo
);
981 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
984 // NOTE: At this point one device object has been successfully created.
985 // from here on out return success.
989 // Do READ CAPACITY. This SCSI command
990 // returns the number of bytes on a device.
991 // Device extension is updated with device size.
994 status
= ScsiClassReadDriveCapacity(deviceObject
);
997 // If the read capacity failed then just return, unless this is a
998 // removable disk where a device object partition needs to be created.
1001 if (!NT_SUCCESS(status
) &&
1002 !(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
1005 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
1008 return(STATUS_SUCCESS
);
1013 // Make sure the volume verification bit is off so that
1014 // IoReadPartitionTable will work.
1017 deviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
1020 status
= CreatePartitionDeviceObjects(deviceObject
, RegistryPath
);
1022 if (NT_SUCCESS(status
))
1023 return STATUS_SUCCESS
;
1026 CreateDiskDeviceObjectsExit
:
1029 // Release the device since an error occurred.
1032 ScsiClassClaimDevice(PortDeviceObject
,
1037 if (diskGeometry
!= NULL
) {
1038 ExFreePool(diskGeometry
);
1041 if (senseData
!= NULL
) {
1042 ExFreePool(senseData
);
1045 if (deviceObject
!= NULL
) {
1047 if (srbListInitialized
) {
1048 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1051 IoDeleteDevice(deviceObject
);
1055 // Delete directory and return.
1058 if (!NT_SUCCESS(status
)) {
1059 ZwMakeTemporaryObject(handle
);
1066 } // end CreateDiskDeviceObjects()
1071 CreatePartitionDeviceObjects(
1072 IN PDEVICE_OBJECT PhysicalDeviceObject
,
1073 IN PUNICODE_STRING RegistryPath
1076 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
1077 ULONG partitionNumber
= 0;
1079 PDEVICE_OBJECT deviceObject
= NULL
;
1080 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
1081 PDRIVE_LAYOUT_INFORMATION partitionList
= NULL
;
1082 PDEVICE_EXTENSION deviceExtension
;
1083 PDEVICE_EXTENSION physicalDeviceExtension
;
1084 PCLASS_INIT_DATA initData
= NULL
;
1085 PDISK_DATA diskData
;
1086 PDISK_DATA physicalDiskData
;
1087 ULONG bytesPerSector
;
1090 ULONG dmByteSkew
= 0;
1092 BOOLEAN dmActive
= FALSE
;
1093 ULONG numberListElements
= 0;
1097 // Get physical device geometry information for partition table reads.
1100 physicalDeviceExtension
= PhysicalDeviceObject
->DeviceExtension
;
1101 diskGeometry
= physicalDeviceExtension
->DiskGeometry
;
1102 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
;
1105 // Make sure sector size is not zero.
1108 if (bytesPerSector
== 0) {
1111 // Default sector size for disk is 512.
1114 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
= 512;
1117 sectorShift
= physicalDeviceExtension
->SectorShift
;
1120 // Set pointer to disk data area that follows device extension.
1123 diskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1124 diskData
->PartitionListState
= Initializing
;
1127 // Determine is DM Driver is loaded on an IDE drive that is
1128 // under control of Atapi - this could be either a crashdump or
1129 // an Atapi device is sharing the controller with an IDE disk.
1132 HalExamineMBR(PhysicalDeviceObject
,
1133 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1140 // Update the device extension, so that the call to IoReadPartitionTable
1141 // will get the correct information. Any I/O to this disk will have
1142 // to be skewed by *dmSkew sectors aka DMByteSkew.
1145 physicalDeviceExtension
->DMSkew
= *dmSkew
;
1146 physicalDeviceExtension
->DMActive
= TRUE
;
1147 physicalDeviceExtension
->DMByteSkew
= physicalDeviceExtension
->DMSkew
* bytesPerSector
;
1150 // Save away the information that we need, since this deviceExtension will soon be
1155 dmByteSkew
= physicalDeviceExtension
->DMByteSkew
;
1161 // HACK so that we can use NT5+ NTOS functions with this NT4 driver
1162 // for removable devices and avoid an infinite recursive loop between
1163 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
1165 diskData
->UpdateRemovableGeometryCount
= 0;
1169 // Create objects for all the partitions on the device.
1172 status
= IoReadPartitionTable(PhysicalDeviceObject
,
1173 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1175 (PVOID
)&partitionList
);
1178 // If the I/O read partition table failed and this is a removable device,
1179 // then fix up the partition list to make it look like there is one
1180 // zero length partition.
1182 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status
);
1183 if ((!NT_SUCCESS(status
) || partitionList
->PartitionCount
== 0) &&
1184 PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1186 if (!NT_SUCCESS(status
)) {
1189 // Remember this disk is not ready.
1192 diskData
->DriveNotReady
= TRUE
;
1197 // Free the partition list allocated by IoReadPartitionTable.
1200 ExFreePool(partitionList
);
1204 // Allocate and zero a partition list.
1207 partitionList
= ExAllocatePool(NonPagedPool
, sizeof(*partitionList
));
1210 if (partitionList
!= NULL
) {
1212 RtlZeroMemory( partitionList
, sizeof( *partitionList
));
1215 // Set the partition count to one and the status to success
1216 // so one device object will be created. Set the partition type
1217 // to a bogus value.
1220 partitionList
->PartitionCount
= 1;
1222 status
= STATUS_SUCCESS
;
1226 if (NT_SUCCESS(status
)) {
1229 // Record disk signature.
1232 diskData
->Signature
= partitionList
->Signature
;
1235 // If disk signature is zero, then calculate the MBR checksum.
1238 if (!diskData
->Signature
) {
1240 if (!CalculateMbrCheckSum(physicalDeviceExtension
,
1241 &diskData
->MbrCheckSum
)) {
1244 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1245 physicalDeviceExtension
->DeviceNumber
));
1249 "SCSIDISK: MBR checksum for disk %x is %x\n",
1250 physicalDeviceExtension
->DeviceNumber
,
1251 diskData
->MbrCheckSum
));
1256 // Check the registry and determine if the BIOS knew about this drive. If
1257 // it did then update the geometry with the BIOS information.
1260 UpdateGeometry(physicalDeviceExtension
);
1262 srbFlags
= physicalDeviceExtension
->SrbFlags
;
1264 initData
= ExAllocatePool(NonPagedPool
, sizeof(CLASS_INIT_DATA
));
1268 "Disk.CreatePartitionDeviceObjects - Allocation of initData failed\n"));
1270 status
= STATUS_INSUFFICIENT_RESOURCES
;
1271 goto CreatePartitionDeviceObjectsExit
;
1274 RtlZeroMemory(initData
, sizeof(CLASS_INIT_DATA
));
1276 initData
->InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
1277 initData
->DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
1278 initData
->DeviceType
= FILE_DEVICE_DISK
;
1279 initData
->DeviceCharacteristics
= PhysicalDeviceObject
->Characteristics
;
1280 initData
->ClassError
= physicalDeviceExtension
->ClassError
;
1281 initData
->ClassReadWriteVerification
= physicalDeviceExtension
->ClassReadWriteVerification
;
1282 initData
->ClassFindDevices
= physicalDeviceExtension
->ClassFindDevices
;
1283 initData
->ClassDeviceControl
= physicalDeviceExtension
->ClassDeviceControl
;
1284 initData
->ClassShutdownFlush
= physicalDeviceExtension
->ClassShutdownFlush
;
1285 initData
->ClassCreateClose
= physicalDeviceExtension
->ClassCreateClose
;
1286 initData
->ClassStartIo
= physicalDeviceExtension
->ClassStartIo
;
1289 // Create device objects for the device partitions (if any).
1290 // PartitionCount includes physical device partition 0,
1291 // so only one partition means no objects to create.
1295 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1296 partitionList
->PartitionCount
));
1298 for (partitionNumber
= 0; partitionNumber
<
1299 partitionList
->PartitionCount
; partitionNumber
++) {
1302 // Create partition object and set up partition parameters.
1305 sprintf(ntNameBuffer
,
1306 "\\Device\\Harddisk%lu\\Partition%lu",
1307 physicalDeviceExtension
->DeviceNumber
,
1308 partitionNumber
+ 1);
1311 "CreateDiskDeviceObjects: Create device object %s\n",
1314 status
= ScsiClassCreateDeviceObject(PhysicalDeviceObject
->DriverObject
,
1316 PhysicalDeviceObject
,
1320 if (!NT_SUCCESS(status
)) {
1322 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer
));
1328 // Set up device object fields.
1331 deviceObject
->Flags
|= DO_DIRECT_IO
;
1334 // Check if this is during initialization. If not indicate that
1335 // system initialization already took place and this disk is ready
1339 if (!RegistryPath
) {
1340 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1343 deviceObject
->StackSize
= (CCHAR
)physicalDeviceExtension
->PortDeviceObject
->StackSize
+ 1;
1346 // Set up device extension fields.
1349 deviceExtension
= deviceObject
->DeviceExtension
;
1354 // Restore any saved DM values.
1357 deviceExtension
->DMByteSkew
= dmByteSkew
;
1358 deviceExtension
->DMSkew
= *dmSkew
;
1359 deviceExtension
->DMActive
= TRUE
;
1364 // Link new device extension to previous disk data
1365 // to support dynamic partitioning.
1368 diskData
->NextPartition
= deviceExtension
;
1371 // Get pointer to new disk data.
1374 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1377 // Set next partition pointer to NULL in case this is the
1381 diskData
->NextPartition
= NULL
;
1384 // Allocate spinlock for zoning for split-request completion.
1387 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
1390 // Copy port device object pointer to device extension.
1393 deviceExtension
->PortDeviceObject
= physicalDeviceExtension
->PortDeviceObject
;
1396 // Set the alignment requirements for the device based on the
1397 // host adapter requirements
1400 if (physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
1401 deviceObject
->AlignmentRequirement
= physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
;
1405 if (srbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
1406 numberListElements
= 30;
1408 numberListElements
= 8;
1412 // Build the lookaside list for srb's for this partition based on
1413 // whether the adapter and disk can do tagged queueing.
1416 ScsiClassInitializeSrbLookasideList(deviceExtension
,
1417 numberListElements
);
1419 deviceExtension
->SrbFlags
= srbFlags
;
1422 // Set the sense-data pointer in the device extension.
1425 deviceExtension
->SenseData
= physicalDeviceExtension
->SenseData
;
1426 deviceExtension
->PortCapabilities
= physicalDeviceExtension
->PortCapabilities
;
1427 deviceExtension
->DiskGeometry
= diskGeometry
;
1428 diskData
->PartitionOrdinal
= diskData
->PartitionNumber
= partitionNumber
+ 1;
1429 diskData
->PartitionType
= partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
1430 diskData
->BootIndicator
= partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
1432 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1433 diskData
->PartitionType
));
1435 deviceExtension
->StartingOffset
= partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
1436 deviceExtension
->PartitionLength
= partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
1437 diskData
->HiddenSectors
= partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
1438 deviceExtension
->PortNumber
= physicalDeviceExtension
->PortNumber
;
1439 deviceExtension
->PathId
= physicalDeviceExtension
->PathId
;
1440 deviceExtension
->TargetId
= physicalDeviceExtension
->TargetId
;
1441 deviceExtension
->Lun
= physicalDeviceExtension
->Lun
;
1444 // Check for removable media support.
1447 if (PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1448 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
1452 // Set timeout value in seconds.
1455 deviceExtension
->TimeOutValue
= physicalDeviceExtension
->TimeOutValue
;
1456 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bytesPerSector
;
1457 deviceExtension
->SectorShift
= sectorShift
;
1458 deviceExtension
->DeviceObject
= deviceObject
;
1459 deviceExtension
->DeviceFlags
|= physicalDeviceExtension
->DeviceFlags
;
1461 } // end for (partitionNumber) ...
1464 // Free the buffer allocated by reading the
1468 ExFreePool(partitionList
);
1476 CreatePartitionDeviceObjectsExit
:
1478 if (partitionList
) {
1479 ExFreePool(partitionList
);
1482 ExFreePool(initData
);
1494 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1495 physicalDiskData
->PartitionListState
= Initialized
;
1497 return(STATUS_SUCCESS
);
1500 } // end CreatePartitionDeviceObjects()
1505 ScsiDiskReadWriteVerification(
1506 IN PDEVICE_OBJECT DeviceObject
,
1512 Routine Description:
1514 I/O System entry for read and write requests to SCSI disks.
1518 DeviceObject - Pointer to driver object created by system.
1528 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1529 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1530 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1531 LARGE_INTEGER startingOffset
;
1534 // HACK: How can we end here with null sector size?!
1537 if (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
== 0) {
1538 DPRINT1("Hack! Received invalid sector size\n");
1539 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1543 // Verify parameters of this request.
1544 // Check that ending sector is within partition and
1545 // that number of bytes to transfer is a multiple of
1549 startingOffset
.QuadPart
= (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
1552 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
1553 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
1556 // This error maybe caused by the fact that the drive is not ready.
1559 if (((PDISK_DATA
)(deviceExtension
+ 1))->DriveNotReady
) {
1562 // Flag this as a user error so that a popup is generated.
1565 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
1566 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1571 // Note fastfat depends on this parameter to determine when to
1572 // remount do to a sector size change.
1575 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1578 if (startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) {
1579 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset
.QuadPart
, deviceExtension
->PartitionLength
.QuadPart
);
1582 if (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1)) {
1583 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount
, deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
1586 if (Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_READY
) {
1587 DPRINT1("Failing due to device not ready!\n");
1590 return STATUS_INVALID_PARAMETER
;
1593 return STATUS_SUCCESS
;
1595 } // end ScsiDiskReadWrite()
1600 ScsiDiskDeviceControl(
1601 PDEVICE_OBJECT DeviceObject
,
1607 Routine Description:
1609 I/O system entry for device controls to SCSI disks.
1613 DeviceObject - Pointer to driver object created by system.
1623 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1624 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1625 PDISK_DATA diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1626 PSCSI_REQUEST_BLOCK srb
;
1628 PMODE_PARAMETER_HEADER modeData
;
1633 IO_STATUS_BLOCK ioStatus
;
1637 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
1641 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1642 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1643 return(STATUS_INSUFFICIENT_RESOURCES
);
1647 // Write zeros to Srb.
1650 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1652 cdb
= (PCDB
)srb
->Cdb
;
1654 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1656 case SMART_GET_VERSION
: {
1659 PSRB_IO_CONTROL srbControl
;
1660 PGETVERSIONINPARAMS versionParams
;
1662 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1663 sizeof(GETVERSIONINPARAMS
)) {
1664 status
= STATUS_INVALID_PARAMETER
;
1669 // Create notification event object to be used to signal the
1670 // request completion.
1673 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1675 srbControl
= ExAllocatePool(NonPagedPool
,
1676 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
));
1679 status
= STATUS_INSUFFICIENT_RESOURCES
;
1684 // fill in srbControl fields
1687 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1688 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1689 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1690 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1691 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1694 // Point to the 'buffer' portion of the SRB_CONTROL
1697 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1700 // Ensure correct target is set in the cmd parameters.
1703 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1704 versionParams
->bIDEDeviceMap
= deviceExtension
->TargetId
;
1707 // Copy the IOCTL parameters to the srb control buffer area.
1710 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(GETVERSIONINPARAMS
));
1713 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1714 deviceExtension
->PortDeviceObject
,
1716 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1718 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1724 status
= STATUS_INSUFFICIENT_RESOURCES
;
1729 // Call the port driver with the request and wait for it to complete.
1732 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1734 if (status
== STATUS_PENDING
) {
1735 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1736 status
= ioStatus
.Status
;
1740 // If successful, copy the data received into the output buffer.
1741 // This should only fail in the event that the IDE driver is older than this driver.
1744 if (NT_SUCCESS(status
)) {
1746 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1748 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, sizeof(GETVERSIONINPARAMS
));
1749 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1752 ExFreePool(srbControl
);
1756 case SMART_RCV_DRIVE_DATA
: {
1758 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1759 ULONG controlCode
= 0;
1760 PSRB_IO_CONTROL srbControl
;
1763 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1764 (sizeof(SENDCMDINPARAMS
) - 1)) {
1765 status
= STATUS_INVALID_PARAMETER
;
1768 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1769 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1770 status
= STATUS_INVALID_PARAMETER
;
1775 // Create notification event object to be used to signal the
1776 // request completion.
1779 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1781 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1783 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1784 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1786 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1787 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1788 case READ_ATTRIBUTES
:
1789 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1790 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1792 case READ_THRESHOLDS
:
1793 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1794 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1797 status
= STATUS_INVALID_PARAMETER
;
1802 status
= STATUS_INVALID_PARAMETER
;
1805 if (controlCode
== 0) {
1806 status
= STATUS_INVALID_PARAMETER
;
1810 srbControl
= ExAllocatePool(NonPagedPool
,
1811 sizeof(SRB_IO_CONTROL
) + length
);
1814 status
= STATUS_INSUFFICIENT_RESOURCES
;
1819 // fill in srbControl fields
1822 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1823 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1824 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1825 srbControl
->Length
= length
;
1826 srbControl
->ControlCode
= controlCode
;
1829 // Point to the 'buffer' portion of the SRB_CONTROL
1832 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1835 // Ensure correct target is set in the cmd parameters.
1838 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1841 // Copy the IOCTL parameters to the srb control buffer area.
1844 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1846 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1847 deviceExtension
->PortDeviceObject
,
1849 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1851 sizeof(SRB_IO_CONTROL
) + length
,
1857 status
= STATUS_INSUFFICIENT_RESOURCES
;
1862 // Call the port driver with the request and wait for it to complete.
1865 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1867 if (status
== STATUS_PENDING
) {
1868 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1869 status
= ioStatus
.Status
;
1873 // If successful, copy the data received into the output buffer
1876 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1878 if (NT_SUCCESS(status
)) {
1880 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
- 1);
1881 Irp
->IoStatus
.Information
= length
- 1;
1885 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1886 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1890 ExFreePool(srbControl
);
1895 case SMART_SEND_DRIVE_COMMAND
: {
1897 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1898 PSRB_IO_CONTROL srbControl
;
1899 ULONG controlCode
= 0;
1902 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1903 (sizeof(SENDCMDINPARAMS
) - 1)) {
1904 status
= STATUS_INVALID_PARAMETER
;
1907 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1908 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1909 status
= STATUS_INVALID_PARAMETER
;
1914 // Create notification event object to be used to signal the
1915 // request completion.
1918 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1922 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1923 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1926 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1930 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1933 case RETURN_SMART_STATUS
:
1936 // Ensure bBuffer is at least 2 bytes (to hold the values of
1937 // cylinderLow and cylinderHigh).
1940 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1941 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1943 status
= STATUS_INVALID_PARAMETER
;
1947 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1948 length
= sizeof(IDEREGS
);
1951 case ENABLE_DISABLE_AUTOSAVE
:
1952 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1955 case SAVE_ATTRIBUTE_VALUES
:
1956 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1959 case EXECUTE_OFFLINE_DIAGS
:
1960 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1964 status
= STATUS_INVALID_PARAMETER
;
1969 status
= STATUS_INVALID_PARAMETER
;
1972 if (controlCode
== 0) {
1973 status
= STATUS_INVALID_PARAMETER
;
1977 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1978 srbControl
= ExAllocatePool(NonPagedPool
,
1979 sizeof(SRB_IO_CONTROL
) + length
);
1982 status
= STATUS_INSUFFICIENT_RESOURCES
;
1987 // fill in srbControl fields
1990 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1991 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1992 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1993 srbControl
->Length
= length
;
1996 // Point to the 'buffer' portion of the SRB_CONTROL
1999 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2002 // Ensure correct target is set in the cmd parameters.
2005 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
2008 // Copy the IOCTL parameters to the srb control buffer area.
2011 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
2013 srbControl
->ControlCode
= controlCode
;
2015 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
2016 deviceExtension
->PortDeviceObject
,
2018 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
2020 sizeof(SRB_IO_CONTROL
) + length
,
2026 status
= STATUS_INSUFFICIENT_RESOURCES
;
2031 // Call the port driver with the request and wait for it to complete.
2034 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2036 if (status
== STATUS_PENDING
) {
2037 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2038 status
= ioStatus
.Status
;
2042 // Copy the data received into the output buffer. Since the status buffer
2043 // contains error information also, always perform this copy. IO will will
2044 // either pass this back to the app, or zero it, in case of error.
2047 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2050 // Update the return buffer size based on the sub-command.
2053 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
2054 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
2056 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
2059 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
);
2060 Irp
->IoStatus
.Information
= length
;
2062 ExFreePool(srbControl
);
2067 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2068 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2071 PDEVICE_EXTENSION physicalDeviceExtension
;
2072 PDISK_DATA physicalDiskData
;
2073 BOOLEAN removable
= FALSE
;
2074 BOOLEAN listInitialized
= FALSE
;
2077 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) {
2078 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
)) {
2079 status
= STATUS_BUFFER_TOO_SMALL
;
2083 copyLength
= sizeof(DISK_GEOMETRY
);
2085 ASSERT(irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
);
2086 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
)) {
2087 status
= STATUS_BUFFER_TOO_SMALL
;
2091 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= sizeof(DISK_GEOMETRY_EX
)) {
2092 copyLength
= sizeof(DISK_GEOMETRY_EX
);
2094 copyLength
= FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
);
2098 status
= STATUS_SUCCESS
;
2100 physicalDeviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2101 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
2103 removable
= (BOOLEAN
)DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
;
2104 listInitialized
= (physicalDiskData
->PartitionListState
== Initialized
);
2106 if (removable
|| (!listInitialized
))
2109 // Issue ReadCapacity to update device extension
2110 // with information for current media.
2113 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
2119 if (!NT_SUCCESS(status
)) {
2122 // Note the drive is not ready.
2125 diskData
->DriveNotReady
= TRUE
;
2131 // Note the drive is now ready.
2134 diskData
->DriveNotReady
= FALSE
;
2136 } else if (NT_SUCCESS(status
)) {
2138 // ReadDriveCapacity was alright, create Partition Objects
2140 if (physicalDiskData
->PartitionListState
== NotInitialized
) {
2141 status
= CreatePartitionDeviceObjects(deviceExtension
->PhysicalDevice
, NULL
);
2145 if (NT_SUCCESS(status
)) {
2148 // Copy drive geometry information from device extension.
2151 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2152 deviceExtension
->DiskGeometry
,
2155 status
= STATUS_SUCCESS
;
2156 Irp
->IoStatus
.Information
= copyLength
;
2163 case IOCTL_DISK_VERIFY
:
2167 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2168 LARGE_INTEGER byteOffset
;
2173 // Validate buffer length.
2176 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2177 sizeof(VERIFY_INFORMATION
)) {
2179 status
= STATUS_INFO_LENGTH_MISMATCH
;
2187 srb
->CdbLength
= 10;
2189 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2192 // Add disk offset to starting sector.
2195 byteOffset
.QuadPart
= deviceExtension
->StartingOffset
.QuadPart
+
2196 verifyInfo
->StartingOffset
.QuadPart
;
2199 // Convert byte offset to sector offset.
2202 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2205 // Convert ULONG byte count to USHORT sector count.
2208 sectorCount
= (USHORT
)(verifyInfo
->Length
>> deviceExtension
->SectorShift
);
2211 // Move little endian values into CDB in big endian format.
2214 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2215 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2216 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2217 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2219 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2220 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2223 // The verify command is used by the NT FORMAT utility and
2224 // requests are sent down for 5% of the volume size. The
2225 // request timeout value is calculated based on the number of
2226 // sectors verified.
2229 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2230 deviceExtension
->TimeOutValue
;
2232 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
2243 case IOCTL_DISK_GET_PARTITION_INFO
:
2246 // Return the information about the partition specified by the device
2247 // object. Note that no information is ever returned about the size
2248 // or partition type of the physical disk, as this doesn't make any
2252 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2253 sizeof(PARTITION_INFORMATION
)) {
2255 status
= STATUS_INFO_LENGTH_MISMATCH
;
2260 // Update the geometry in case it has changed.
2263 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2265 if (!NT_SUCCESS(status
)) {
2268 // Note the drive is not ready.
2271 diskData
->DriveNotReady
= TRUE
;
2276 // Note the drive is now ready.
2279 diskData
->DriveNotReady
= FALSE
;
2282 // Handle the case were we query the whole disk
2285 if (diskData
->PartitionNumber
== 0) {
2287 PPARTITION_INFORMATION outputBuffer
;
2290 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2292 outputBuffer
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2293 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2294 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2295 outputBuffer
->HiddenSectors
= 0;
2296 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2297 outputBuffer
->BootIndicator
= FALSE
;
2298 outputBuffer
->RewritePartition
= FALSE
;
2299 outputBuffer
->RecognizedPartition
= FALSE
;
2301 status
= STATUS_SUCCESS
;
2302 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2306 PPARTITION_INFORMATION outputBuffer
;
2309 // We query a single partition here
2310 // FIXME: this can only work for MBR-based disks, check for this!
2314 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2316 outputBuffer
->PartitionType
= diskData
->PartitionType
;
2317 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2318 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2319 outputBuffer
->HiddenSectors
= diskData
->HiddenSectors
;
2320 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2321 outputBuffer
->BootIndicator
= diskData
->BootIndicator
;
2322 outputBuffer
->RewritePartition
= FALSE
;
2323 outputBuffer
->RecognizedPartition
=
2324 IsRecognizedPartition(diskData
->PartitionType
);
2326 status
= STATUS_SUCCESS
;
2327 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2332 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2335 // Return the information about the partition specified by the device
2336 // object. Note that no information is ever returned about the size
2337 // or partition type of the physical disk, as this doesn't make any
2341 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2342 sizeof(PARTITION_INFORMATION_EX
)) {
2344 status
= STATUS_INFO_LENGTH_MISMATCH
;
2347 #if 0 // HACK: ReactOS partition numbers must be wrong
2348 else if (diskData
->PartitionNumber
== 0) {
2351 // Partition zero is not a partition so this is not a
2352 // reasonable request.
2355 status
= STATUS_INVALID_DEVICE_REQUEST
;
2361 PPARTITION_INFORMATION_EX outputBuffer
;
2363 if (diskData
->PartitionNumber
== 0) {
2364 DPRINT1("HACK: Handling partition 0 request!\n");
2369 // Update the geometry in case it has changed.
2372 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2374 if (!NT_SUCCESS(status
)) {
2377 // Note the drive is not ready.
2380 diskData
->DriveNotReady
= TRUE
;
2385 // Note the drive is now ready.
2388 diskData
->DriveNotReady
= FALSE
;
2390 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2392 status
= STATUS_INVALID_DEVICE_REQUEST
;
2397 (PPARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
2400 // FIXME: hack of the year, assume that partition is MBR
2401 // Thing that can obviously be wrong...
2404 outputBuffer
->PartitionStyle
= PARTITION_STYLE_MBR
;
2405 outputBuffer
->Mbr
.PartitionType
= diskData
->PartitionType
;
2406 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2407 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2408 outputBuffer
->Mbr
.HiddenSectors
= diskData
->HiddenSectors
;
2409 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2410 outputBuffer
->Mbr
.BootIndicator
= diskData
->BootIndicator
;
2411 outputBuffer
->RewritePartition
= FALSE
;
2412 outputBuffer
->Mbr
.RecognizedPartition
=
2413 IsRecognizedPartition(diskData
->PartitionType
);
2415 status
= STATUS_SUCCESS
;
2416 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
2421 case IOCTL_DISK_SET_PARTITION_INFO
:
2423 if (diskData
->PartitionNumber
== 0) {
2425 status
= STATUS_UNSUCCESSFUL
;
2429 PSET_PARTITION_INFORMATION inputBuffer
=
2430 (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2433 // Validate buffer length.
2436 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2437 sizeof(SET_PARTITION_INFORMATION
)) {
2439 status
= STATUS_INFO_LENGTH_MISMATCH
;
2444 // The HAL routines IoGet- and IoSetPartitionInformation were
2445 // developed before support of dynamic partitioning and therefore
2446 // don't distinguish between partition ordinal (that is the order
2447 // of a partition on a disk) and the partition number. (The
2448 // partition number is assigned to a partition to identify it to
2449 // the system.) Use partition ordinals for these legacy calls.
2452 status
= IoSetPartitionInformation(
2453 deviceExtension
->PhysicalDevice
,
2454 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2455 diskData
->PartitionOrdinal
,
2456 inputBuffer
->PartitionType
);
2458 if (NT_SUCCESS(status
)) {
2460 diskData
->PartitionType
= inputBuffer
->PartitionType
;
2466 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2469 // Return the partition layout for the physical drive. Note that
2470 // the layout is returned for the actual physical drive, regardless
2471 // of which partition was specified for the request.
2474 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2475 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2476 status
= STATUS_INFO_LENGTH_MISMATCH
;
2480 PDRIVE_LAYOUT_INFORMATION partitionList
;
2481 PDEVICE_EXTENSION physicalExtension
= deviceExtension
;
2482 PPARTITION_INFORMATION partitionEntry
;
2483 PDISK_DATA diskData
;
2488 // Read partition information.
2491 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
2492 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2496 if (!NT_SUCCESS(status
)) {
2501 // The disk layout has been returned in the partitionList
2502 // buffer. Determine its size and, if the data will fit
2503 // into the intermediary buffer, return it.
2506 tempSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,PartitionEntry
[0]);
2507 tempSize
+= partitionList
->PartitionCount
*
2508 sizeof(PARTITION_INFORMATION
);
2511 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
2513 status
= STATUS_BUFFER_TOO_SMALL
;
2514 ExFreePool(partitionList
);
2519 // Walk partition list to associate partition numbers with
2520 // partition entries.
2523 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
2526 // Walk partition chain anchored at physical disk extension.
2529 deviceExtension
= physicalExtension
;
2530 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2534 deviceExtension
= diskData
->NextPartition
;
2537 // Check if this is the last partition in the chain.
2540 if (!deviceExtension
) {
2545 // Get the partition device extension from disk data.
2548 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2551 // Check if this partition is not currently being used.
2554 if (!deviceExtension
->PartitionLength
.QuadPart
) {
2558 partitionEntry
= &partitionList
->PartitionEntry
[i
];
2561 // Check if empty, or describes extended partition or hasn't changed.
2564 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2565 IsContainerPartition(partitionEntry
->PartitionType
)) {
2570 // Check if new partition starts where this partition starts.
2573 if (partitionEntry
->StartingOffset
.QuadPart
!=
2574 deviceExtension
->StartingOffset
.QuadPart
) {
2579 // Check if partition length is the same.
2582 if (partitionEntry
->PartitionLength
.QuadPart
==
2583 deviceExtension
->PartitionLength
.QuadPart
) {
2586 // Partitions match. Update partition number.
2589 partitionEntry
->PartitionNumber
=
2590 diskData
->PartitionNumber
;
2598 // Copy partition information to system buffer.
2601 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2604 status
= STATUS_SUCCESS
;
2605 Irp
->IoStatus
.Information
= tempSize
;
2608 // Finally, free the buffer allocated by reading the
2612 ExFreePool(partitionList
);
2617 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
2622 // Update the disk with new partition information.
2625 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
2628 // Validate buffer length.
2631 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2632 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2634 status
= STATUS_INFO_LENGTH_MISMATCH
;
2638 length
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2639 (partitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
);
2642 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2645 status
= STATUS_BUFFER_TOO_SMALL
;
2650 // Verify that device object is for physical disk.
2653 if (deviceExtension
->PhysicalDevice
->DeviceExtension
!= deviceExtension
) {
2654 status
= STATUS_INVALID_PARAMETER
;
2659 // Walk through partition table comparing partitions to
2660 // existing partitions to create, delete and change
2661 // device objects as necessary.
2664 UpdateDeviceObjects(DeviceObject
,
2668 // Write changes to disk.
2671 status
= IoWritePartitionTable(
2672 deviceExtension
->DeviceObject
,
2673 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2674 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
,
2675 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
,
2680 // Update IRP with bytes returned.
2683 if (NT_SUCCESS(status
)) {
2684 Irp
->IoStatus
.Information
= length
;
2689 case IOCTL_DISK_REASSIGN_BLOCKS
:
2692 // Map defective blocks to new location on disk.
2697 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2703 // Validate buffer length.
2706 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2707 sizeof(REASSIGN_BLOCKS
)) {
2709 status
= STATUS_INFO_LENGTH_MISMATCH
;
2713 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2714 (badBlocks
->Count
- 1) * sizeof(ULONG
);
2716 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2719 status
= STATUS_INFO_LENGTH_MISMATCH
;
2724 // Build the data buffer to be transferred in the input buffer.
2725 // The format of the data to the device is:
2729 // x * 4 btyes Block Address
2731 // All values are big endian.
2734 badBlocks
->Reserved
= 0;
2735 blockCount
= badBlocks
->Count
;
2738 // Convert # of entries to # of bytes.
2742 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2743 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2746 // Convert back to number of entries.
2751 for (; blockCount
> 0; blockCount
--) {
2753 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2755 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2756 (PFOUR_BYTE
) &blockNumber
);
2761 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2764 // Set timeout value.
2767 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2769 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2775 Irp
->IoStatus
.Status
= status
;
2776 Irp
->IoStatus
.Information
= 0;
2778 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2783 case IOCTL_DISK_IS_WRITABLE
:
2786 // Determine if the device is writable.
2789 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
2791 if (modeData
== NULL
) {
2792 status
= STATUS_INSUFFICIENT_RESOURCES
;
2796 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
2798 length
= ScsiClassModeSense(DeviceObject
,
2801 MODE_SENSE_RETURN_ALL
);
2803 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2806 // Retry the request in case of a check condition.
2809 length
= ScsiClassModeSense(DeviceObject
,
2812 MODE_SENSE_RETURN_ALL
);
2814 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2815 status
= STATUS_IO_DEVICE_ERROR
;
2816 ExFreePool(modeData
);
2821 if (modeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
) {
2822 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2824 status
= STATUS_SUCCESS
;
2827 ExFreePool(modeData
);
2830 case IOCTL_DISK_INTERNAL_SET_VERIFY
:
2833 // If the caller is kernel mode, set the verify bit.
2836 if (Irp
->RequestorMode
== KernelMode
) {
2837 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2839 status
= STATUS_SUCCESS
;
2842 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
:
2845 // If the caller is kernel mode, clear the verify bit.
2848 if (Irp
->RequestorMode
== KernelMode
) {
2849 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
2851 status
= STATUS_SUCCESS
;
2854 case IOCTL_DISK_FIND_NEW_DEVICES
:
2857 // Search for devices that have been powered on since the last
2858 // device search or system initialization.
2861 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2862 status
= DriverEntry(DeviceObject
->DriverObject
,
2865 Irp
->IoStatus
.Status
= status
;
2867 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2870 case IOCTL_DISK_MEDIA_REMOVAL
:
2873 // If the disk is not removable then don't allow this command.
2876 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
2877 status
= STATUS_INVALID_DEVICE_REQUEST
;
2882 // Fall through and let the class driver process the request.
2885 case IOCTL_DISK_GET_LENGTH_INFO
:
2888 // Validate buffer length.
2891 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2892 sizeof(GET_LENGTH_INFORMATION
)) {
2893 status
= STATUS_BUFFER_TOO_SMALL
;
2897 PGET_LENGTH_INFORMATION lengthInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
2900 // Update the geometry in case it has changed.
2903 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2905 if (!NT_SUCCESS(status
)) {
2908 // Note the drive is not ready.
2911 diskData
->DriveNotReady
= TRUE
;
2916 // Note the drive is now ready.
2919 diskData
->DriveNotReady
= FALSE
;
2922 // Output data, and return
2925 lengthInformation
->Length
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2926 status
= STATUS_SUCCESS
;
2927 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2935 // Free the Srb, since it is not needed.
2941 // Pass the request to the common device control routine.
2944 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
2948 } // end switch( ...
2950 Irp
->IoStatus
.Status
= status
;
2952 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2954 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2957 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2961 } // end ScsiDiskDeviceControl()
2965 ScsiDiskShutdownFlush (
2966 IN PDEVICE_OBJECT DeviceObject
,
2972 Routine Description:
2974 This routine is called for a shutdown and flush IRPs. These are sent by the
2975 system before it actually shuts down or when the file system does a flush.
2976 A synchronize cache command is sent to the device if it is write caching.
2977 If the device is removable an unlock command will be sent. This routine
2978 will sent a shutdown or flush Srb to the port driver.
2982 DriverObject - Pointer to device object to being shutdown by system.
2993 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2994 PIO_STACK_LOCATION irpStack
;
2995 PSCSI_REQUEST_BLOCK srb
;
3000 // Allocate SCSI request block.
3003 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
3008 // Set the status and complete the request.
3011 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3012 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3013 return(STATUS_INSUFFICIENT_RESOURCES
);
3016 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3019 // Write length to SRB.
3022 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3025 // Set SCSI bus address.
3028 srb
->PathId
= deviceExtension
->PathId
;
3029 srb
->TargetId
= deviceExtension
->TargetId
;
3030 srb
->Lun
= deviceExtension
->Lun
;
3033 // Set timeout value and mark the request as not being a tagged request.
3036 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 4;
3037 srb
->QueueTag
= SP_UNTAGGED
;
3038 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3039 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3042 // If the write cache is enabled then send a synchronize cache request.
3045 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3047 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3048 srb
->CdbLength
= 10;
3050 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
3052 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3058 DebugPrint((1, "ScsiDiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status
));
3062 // Unlock the device if it is removable and this is a shutdown.
3065 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3067 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
3068 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
3071 cdb
= (PVOID
) srb
->Cdb
;
3072 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3073 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3076 // Set timeout value.
3079 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3080 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3086 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3092 // Save a few parameters in the current stack location.
3095 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3096 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3099 // Set the retry count to zero.
3102 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3105 // Set up IoCompletion routine address.
3108 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3111 // Get next stack location and
3112 // set major function code.
3115 irpStack
= IoGetNextIrpStackLocation(Irp
);
3117 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3120 // Set up SRB for execute scsi request.
3121 // Save SRB address in next stack for port driver.
3124 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3127 // Set up Irp Address.
3130 srb
->OriginalRequest
= Irp
;
3133 // Call the port driver to process the request.
3136 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3138 } // end ScsiDiskShutdown()
3144 PDEVICE_OBJECT DeviceObject
3148 Routine Description:
3150 The routine performs the necessary functions to determine if a device is
3151 really a floppy rather than a harddisk. This is done by a mode sense
3152 command. First, a check is made to see if the media type is set. Second
3153 a check is made for the flexible parameters mode page. Also a check is
3154 made to see if the write cache is enabled.
3158 DeviceObject - Supplies the device object to be tested.
3162 Return TRUE if the indicated device is a floppy.
3166 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3173 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3175 if (modeData
== NULL
) {
3179 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3181 length
= ScsiClassModeSense(DeviceObject
,
3184 MODE_SENSE_RETURN_ALL
);
3186 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3189 // Retry the request in case of a check condition.
3192 length
= ScsiClassModeSense(DeviceObject
,
3195 MODE_SENSE_RETURN_ALL
);
3197 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3199 ExFreePool(modeData
);
3206 // If the length is greater than length indicated by the mode data reset
3207 // the data to the mode data.
3210 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3211 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3215 // Look for the flexible disk mode page.
3218 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_FLEXIBILE
, TRUE
);
3220 if (pageData
!= NULL
) {
3222 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3223 ExFreePool(modeData
);
3228 // Check to see if the write cache is enabled.
3231 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3234 // Assume that write cache is disabled or not supported.
3237 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3240 // Check if valid caching page exists.
3243 if (pageData
!= NULL
) {
3246 // Check if write cache is disabled.
3249 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3252 "SCSIDISK: Disk write cache enabled\n"));
3255 // Check if forced unit access (FUA) is supported.
3258 if (((PMODE_PARAMETER_HEADER
)modeData
)->DeviceSpecificParameter
& MODE_DSP_FUA_SUPPORTED
) {
3260 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3265 "SCSIDISK: Disk does not support FUA or DPO\n"));
3275 ExFreePool(modeData
);
3278 } // end IsFloppyDevice()
3284 IN PDEVICE_OBJECT DeviceObject
,
3285 IN PCHAR ModeSelectBuffer
,
3292 Routine Description:
3294 This routine sends a mode select command.
3298 DeviceObject - Supplies the device object associated with this request.
3300 ModeSelectBuffer - Supplies a buffer containing the page data.
3302 Length - Supplies the length in bytes of the mode select buffer.
3304 SavePage - Indicates that parameters should be written to disk.
3308 Length of the transferred data is returned.
3312 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3314 SCSI_REQUEST_BLOCK srb
;
3319 PMODE_PARAMETER_BLOCK blockDescriptor
;
3323 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3326 // Allocate buffer for mode select header, block descriptor, and mode page.
3329 buffer
= (ULONG_PTR
)ExAllocatePool(NonPagedPoolCacheAligned
,length2
);
3331 RtlZeroMemory((PVOID
)buffer
, length2
);
3334 // Set length in header to size of mode page.
3337 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3339 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3345 blockDescriptor
->BlockLength
[1]=0x02;
3348 // Copy mode page to buffer.
3351 RtlCopyMemory((PVOID
)(buffer
+ 3), ModeSelectBuffer
, Length
);
3357 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3360 // Build the MODE SELECT CDB.
3364 cdb
= (PCDB
)srb
.Cdb
;
3367 // Set timeout value from device extension.
3370 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
3372 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3373 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3374 cdb
->MODE_SELECT
.PFBit
= 1;
3375 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3379 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3386 if (status
== STATUS_VERIFY_REQUIRED
) {
3389 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3402 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3403 status
= STATUS_SUCCESS
;
3406 ExFreePool((PVOID
)buffer
);
3408 if (NT_SUCCESS(status
)) {
3414 } // end SciDiskModeSelect()
3420 IN PDEVICE_OBJECT DeviceObject
,
3421 IN PSCSI_INQUIRY_DATA LunInfo
3425 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3426 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3427 BAD_CONTROLLER_INFORMATION
const *controller
;
3432 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
3434 controller
= &ScsiDiskBadControllers
[j
];
3436 if (!controller
->DisableWriteCache
|| strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
3440 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller
->InquiryString
));
3442 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3444 if (modeData
== NULL
) {
3447 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3451 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3453 length
= ScsiClassModeSense(DeviceObject
,
3456 MODE_SENSE_RETURN_ALL
);
3458 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3461 // Retry the request in case of a check condition.
3464 length
= ScsiClassModeSense(DeviceObject
,
3467 MODE_SENSE_RETURN_ALL
);
3469 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3473 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3475 ExFreePool(modeData
);
3482 // If the length is greater than length indicated by the mode data reset
3483 // the data to the mode data.
3486 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3487 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3491 // Check to see if the write cache is enabled.
3494 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3497 // Assume that write cache is disabled or not supported.
3500 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3503 // Check if valid caching page exists.
3506 if (pageData
!= NULL
) {
3508 BOOLEAN savePage
= FALSE
;
3510 savePage
= (BOOLEAN
)(((PMODE_CACHING_PAGE
)pageData
)->PageSavable
);
3513 // Check if write cache is disabled.
3516 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3518 PIO_ERROR_LOG_PACKET errorLogEntry
;
3523 // Disable write cache and ensure necessary fields are zeroed.
3526 ((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
= FALSE
;
3527 ((PMODE_CACHING_PAGE
)pageData
)->Reserved
= 0;
3528 ((PMODE_CACHING_PAGE
)pageData
)->PageSavable
= 0;
3529 ((PMODE_CACHING_PAGE
)pageData
)->Reserved2
= 0;
3532 // Extract length from caching page.
3535 length
= ((PMODE_CACHING_PAGE
)pageData
)->PageLength
;
3538 // Compensate for page code and page length.
3544 // Issue mode select to set the parameter.
3547 if (ScsiDiskModeSelect(DeviceObject
,
3553 "SCSIDISK: Disk write cache disabled\n"));
3555 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3556 errorCode
= IO_WRITE_CACHE_DISABLED
;
3559 if (ScsiDiskModeSelect(DeviceObject
,
3565 "SCSIDISK: Disk write cache disabled\n"));
3568 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3569 errorCode
= IO_WRITE_CACHE_DISABLED
;
3574 "SCSIDISK: Mode select to disable write cache failed\n"));
3576 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3577 errorCode
= IO_WRITE_CACHE_ENABLED
;
3582 // Log the appropriate informational or error entry.
3585 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3587 sizeof(IO_ERROR_LOG_PACKET
) + 3
3590 if (errorLogEntry
!= NULL
) {
3592 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3593 errorLogEntry
->ErrorCode
= errorCode
;
3594 errorLogEntry
->SequenceNumber
= 0;
3595 errorLogEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
3596 errorLogEntry
->IoControlCode
= 0;
3597 errorLogEntry
->RetryCount
= 0;
3598 errorLogEntry
->UniqueErrorValue
= 0x1;
3599 errorLogEntry
->DumpDataSize
= 3 * sizeof(ULONG
);
3600 errorLogEntry
->DumpData
[0] = LunInfo
->PathId
;
3601 errorLogEntry
->DumpData
[1] = LunInfo
->TargetId
;
3602 errorLogEntry
->DumpData
[2] = LunInfo
->Lun
;
3605 // Write the error log packet.
3608 IoWriteErrorLogEntry(errorLogEntry
);
3614 // Found device so exit the loop and return.
3626 CalculateMbrCheckSum(
3627 IN PDEVICE_EXTENSION DeviceExtension
,
3633 Routine Description:
3635 Read MBR and calculate checksum.
3639 DeviceExtension - Supplies a pointer to the device information for disk.
3640 Checksum - Memory location to return MBR checksum.
3644 Returns TRUE if checksum is valid.
3648 LARGE_INTEGER sectorZero
;
3650 IO_STATUS_BLOCK ioStatus
;
3658 sectorZero
.QuadPart
= (LONGLONG
) 0;
3661 // Create notification event object to be used to signal the inquiry
3662 // request completion.
3665 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
3671 sectorSize
= DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
3674 // Make sure sector size is at least 512 bytes.
3677 if (sectorSize
< 512) {
3682 // Allocate buffer for sector read.
3685 mbr
= ExAllocatePool(NonPagedPoolCacheAligned
, sectorSize
);
3692 // Build IRP to read MBR.
3695 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
3696 DeviceExtension
->DeviceObject
,
3709 // Pass request to port driver and wait for request to complete.
3712 status
= IoCallDriver(DeviceExtension
->DeviceObject
,
3715 if (status
== STATUS_PENDING
) {
3716 KeWaitForSingleObject(&event
,
3721 status
= ioStatus
.Status
;
3724 if (!NT_SUCCESS(status
)) {
3730 // Calculate MBR checksum.
3735 for (i
= 0; i
< 128; i
++) {
3736 *Checksum
+= mbr
[i
];
3739 *Checksum
= ~*Checksum
+ 1;
3749 IN PDEVICE_EXTENSION DeviceExtension
,
3756 Routine Description:
3758 The routine queries the registry to determine if this disk is visible to
3759 the BIOS. If the disk is visible to the BIOS, then the geometry information
3764 DeviceExtension - Supplies a pointer to the device information for disk.
3765 Signature - Unique identifier recorded in MBR.
3766 BusKey - Handle of bus key.
3767 DiskNumber - Returns ordinal of disk as BIOS sees it.
3771 TRUE is disk signature matched.
3775 PDISK_DATA diskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
3776 BOOLEAN diskFound
= FALSE
;
3777 OBJECT_ATTRIBUTES objectAttributes
;
3778 UNICODE_STRING unicodeString
;
3779 UNICODE_STRING identifier
;
3781 ULONG adapterNumber
;
3789 STRING anotherString
;
3792 PKEY_VALUE_FULL_INFORMATION keyData
;
3796 for (busNumber
= 0; ; busNumber
++) {
3799 // Open controller name key.
3802 sprintf((PCHAR
)buffer
,
3806 RtlInitString(&string
,
3809 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3813 if (!NT_SUCCESS(status
)){
3817 InitializeObjectAttributes(&objectAttributes
,
3819 OBJ_CASE_INSENSITIVE
,
3821 (PSECURITY_DESCRIPTOR
)NULL
);
3823 status
= ZwOpenKey(&spareKey
,
3827 RtlFreeUnicodeString(&unicodeString
);
3829 if (!NT_SUCCESS(status
)) {
3834 // Open up controller ordinal key.
3837 RtlInitUnicodeString(&unicodeString
, L
"DiskController");
3838 InitializeObjectAttributes(&objectAttributes
,
3840 OBJ_CASE_INSENSITIVE
,
3842 (PSECURITY_DESCRIPTOR
)NULL
);
3844 status
= ZwOpenKey(&adapterKey
,
3849 // This could fail even with additional adapters of this type
3853 if (!NT_SUCCESS(status
)) {
3857 for (adapterNumber
= 0; ; adapterNumber
++) {
3863 sprintf((PCHAR
)buffer
,
3864 "%lu\\DiskPeripheral",
3867 RtlInitString(&string
,
3870 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3874 if (!NT_SUCCESS(status
)){
3878 InitializeObjectAttributes(&objectAttributes
,
3880 OBJ_CASE_INSENSITIVE
,
3882 (PSECURITY_DESCRIPTOR
)NULL
);
3884 status
= ZwOpenKey(&diskKey
,
3888 RtlFreeUnicodeString(&unicodeString
);
3890 if (!NT_SUCCESS(status
)) {
3894 for (diskNumber
= 0; ; diskNumber
++) {
3896 sprintf((PCHAR
)buffer
,
3900 RtlInitString(&string
,
3903 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3907 if (!NT_SUCCESS(status
)){
3911 InitializeObjectAttributes(&objectAttributes
,
3913 OBJ_CASE_INSENSITIVE
,
3915 (PSECURITY_DESCRIPTOR
)NULL
);
3917 status
= ZwOpenKey(&targetKey
,
3921 RtlFreeUnicodeString(&unicodeString
);
3923 if (!NT_SUCCESS(status
)) {
3928 // Allocate buffer for registry query.
3931 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
3933 if (keyData
== NULL
) {
3939 // Get disk peripheral identifier.
3942 RtlInitUnicodeString(&unicodeString
, L
"Identifier");
3943 status
= ZwQueryValueKey(targetKey
,
3945 KeyValueFullInformation
,
3952 if (!NT_SUCCESS(status
)) {
3953 ExFreePool(keyData
);
3957 if (keyData
->DataLength
< 9*sizeof(WCHAR
)) {
3959 // the data is too short to use (we subtract 9 chars in normal path)
3961 DebugPrint((1, "EnumerateBusKey: Saved data was invalid, "
3962 "not enough data in registry!\n"));
3963 ExFreePool(keyData
);
3968 // Complete unicode string.
3972 (PWSTR
)((PUCHAR
)keyData
+ keyData
->DataOffset
);
3973 identifier
.Length
= (USHORT
)keyData
->DataLength
;
3974 identifier
.MaximumLength
= (USHORT
)keyData
->DataLength
;
3977 // Convert unicode identifier to ansi string.
3981 RtlUnicodeStringToAnsiString(&anotherString
,
3985 if (!NT_SUCCESS(status
)) {
3986 ExFreePool(keyData
);
3991 // If checksum is zero, then the MBR is valid and
3992 // the signature is meaningful.
3995 if (diskData
->MbrCheckSum
) {
3998 // Convert checksum to ansi string.
4001 sprintf((PCHAR
)buffer
, "%08lx", diskData
->MbrCheckSum
);
4006 // Convert signature to ansi string.
4009 sprintf((PCHAR
)buffer
, "%08lx", diskData
->Signature
);
4012 // Make string point at signature. Can't use scan
4013 // functions because they are not exported for driver use.
4016 anotherString
.Buffer
+=9;
4020 // Convert to ansi string.
4023 RtlInitString(&string
,
4028 // Make string lengths equal.
4031 anotherString
.Length
= string
.Length
;
4034 // Check if strings match.
4037 if (RtlCompareString(&string
,
4042 *DiskNumber
= diskNumber
;
4045 ExFreePool(keyData
);
4048 // Readjust identifier string if necessary.
4051 if (!diskData
->MbrCheckSum
) {
4052 anotherString
.Buffer
-=9;
4055 RtlFreeAnsiString(&anotherString
);
4065 ZwClose(adapterKey
);
4071 } // end EnumerateBusKey()
4077 IN PDEVICE_EXTENSION DeviceExtension
4081 Routine Description:
4083 The routine queries the registry to determine if this disk is visible to
4084 the BIOS. If the disk is visible to the BIOS, then the geometry information
4089 DeviceExtension - Supplies a pointer to the device information for disk.
4098 OBJECT_ATTRIBUTES objectAttributes
;
4099 UNICODE_STRING unicodeString
;
4103 PCM_INT13_DRIVE_PARAMETER driveParameters
;
4104 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor
;
4105 PKEY_VALUE_FULL_INFORMATION keyData
;
4109 ULONG numberOfDrives
;
4112 ULONG sectorsPerTrack
;
4113 ULONG tracksPerCylinder
;
4114 BOOLEAN foundEZHooker
;
4120 // Initialize the object for the key.
4123 InitializeObjectAttributes(&objectAttributes
,
4124 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
4125 OBJ_CASE_INSENSITIVE
,
4127 (PSECURITY_DESCRIPTOR
) NULL
);
4130 // Create the hardware base key.
4133 status
= ZwOpenKey(&hardwareKey
,
4138 if (!NT_SUCCESS(status
)) {
4139 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
));
4145 // Get disk BIOS geometry information.
4148 RtlInitUnicodeString(&unicodeString
, L
"Configuration Data");
4150 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
4152 if (keyData
== NULL
) {
4153 ZwClose(hardwareKey
);
4157 status
= ZwQueryValueKey(hardwareKey
,
4159 KeyValueFullInformation
,
4164 if (!NT_SUCCESS(status
)) {
4166 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4168 ZwClose(hardwareKey
);
4169 ExFreePool(keyData
);
4174 // Open EISA bus key.
4177 RtlInitUnicodeString(&unicodeString
, L
"EisaAdapter");
4179 InitializeObjectAttributes(&objectAttributes
,
4181 OBJ_CASE_INSENSITIVE
,
4183 (PSECURITY_DESCRIPTOR
)NULL
);
4185 status
= ZwOpenKey(&busKey
,
4189 if (!NT_SUCCESS(status
)) {
4194 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4195 if (EnumerateBusKey(DeviceExtension
,
4199 ZwClose(hardwareKey
);
4206 // Open Multifunction bus key.
4209 RtlInitUnicodeString(&unicodeString
, L
"MultifunctionAdapter");
4211 InitializeObjectAttributes(&objectAttributes
,
4213 OBJ_CASE_INSENSITIVE
,
4215 (PSECURITY_DESCRIPTOR
)NULL
);
4217 status
= ZwOpenKey(&busKey
,
4221 ZwClose(hardwareKey
);
4222 if (NT_SUCCESS(status
)) {
4224 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4225 if (EnumerateBusKey(DeviceExtension
,
4233 ExFreePool(keyData
);
4238 resourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PUCHAR
)keyData
+
4239 keyData
->DataOffset
);
4242 // Check that the data is long enough to hold a full resource descriptor,
4243 // and that the last resource list is device-specific and long enough.
4246 if (keyData
->DataLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) ||
4247 resourceDescriptor
->PartialResourceList
.Count
== 0 ||
4248 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].Type
!=
4249 CmResourceTypeDeviceSpecific
||
4250 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0]
4251 .u
.DeviceSpecificData
.DataSize
< sizeof(ULONG
)) {
4253 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4254 ExFreePool(keyData
);
4259 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
;
4262 // Point to the BIOS data. The BIOS data is located after the first
4263 // partial Resource list which should be device specific data.
4266 buffer
= (PUCHAR
) keyData
+ keyData
->DataOffset
+
4267 sizeof(CM_FULL_RESOURCE_DESCRIPTOR
);
4270 numberOfDrives
= length
/ sizeof(CM_INT13_DRIVE_PARAMETER
);
4273 // Use the defaults if the drive number is greater than the
4274 // number of drives detected by the BIOS.
4277 if (numberOfDrives
<= diskNumber
) {
4278 ExFreePool(keyData
);
4283 // Point to the array of drive parameters.
4286 driveParameters
= (PCM_INT13_DRIVE_PARAMETER
) buffer
+ diskNumber
;
4287 cylinders
= driveParameters
->MaxCylinders
+ 1;
4288 sectorsPerTrack
= driveParameters
->SectorsPerTrack
;
4289 tracksPerCylinder
= driveParameters
->MaxHeads
+1;
4292 // Calculate the actual number of sectors.
4295 sectors
= (ULONG
)(DeviceExtension
->PartitionLength
.QuadPart
>>
4296 DeviceExtension
->SectorShift
);
4299 if (sectors
>= cylinders
* tracksPerCylinder
* sectorsPerTrack
) {
4300 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4301 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4302 sectors
, cylinders
, tracksPerCylinder
, sectorsPerTrack
));
4307 // Since the BIOS may not report the full drive, recalculate the drive
4308 // size based on the volume size and the BIOS values for tracks per
4309 // cylinder and sectors per track..
4312 length
= tracksPerCylinder
* sectorsPerTrack
;
4317 // The BIOS information is bogus.
4320 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4321 ExFreePool(keyData
);
4325 cylinders
= sectors
/ length
;
4328 // Update the actual geometry information.
4331 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= sectorsPerTrack
;
4332 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
;
4333 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)cylinders
;
4334 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= (LONGLONG
)cylinders
* tracksPerCylinder
* sectorsPerTrack
*
4335 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4338 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4343 ExFreePool(keyData
);
4345 foundEZHooker
= FALSE
;
4347 if (!DeviceExtension
->DMActive
) {
4349 HalExamineMBR(DeviceExtension
->DeviceObject
,
4350 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4358 foundEZHooker
= TRUE
;
4364 if (DeviceExtension
->DMActive
|| foundEZHooker
) {
4366 while (cylinders
> 1024) {
4368 tracksPerCylinder
= tracksPerCylinder
*2;
4369 cylinders
= cylinders
/2;
4374 // int 13 values are always 1 less.
4377 tracksPerCylinder
-= 1;
4381 // DM reserves the CE cylinder
4386 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= cylinders
+ 1;
4387 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
+ 1;
4389 DeviceExtension
->PartitionLength
.QuadPart
=
4390 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
=
4391 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
*
4392 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
*
4393 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
*
4394 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
;
4396 if (DeviceExtension
->DMActive
) {
4398 DeviceExtension
->DMByteSkew
= DeviceExtension
->DMSkew
* DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4404 DeviceExtension
->DMByteSkew
= 0;
4410 } // end UpdateGeometry()
4416 UpdateRemovableGeometry (
4417 IN PDEVICE_OBJECT DeviceObject
,
4423 Routine Description:
4425 This routines updates the size and starting offset of the device. This is
4426 used when the media on the device may have changed thereby changing the
4427 size of the device. If this is the physical device then a
4428 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4432 DeviceObject - Supplies the device object whos size needs to be updated.
4434 Irp - Supplies a reference where the status can be updated.
4438 Returns the status of the operation.
4443 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4444 PDRIVE_LAYOUT_INFORMATION partitionList
;
4446 PDISK_DATA diskData
;
4447 ULONG partitionNumber
;
4450 // Determine if the size of the partition may have changed because
4451 // the media has changed.
4454 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
4456 return(STATUS_SUCCESS
);
4461 // If this request is for partition zero then do a read drive
4462 // capacity otherwise do a I/O read partition table.
4465 diskData
= (PDISK_DATA
) (deviceExtension
+ 1);
4468 // Read the drive capacity. If that fails, give up.
4471 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
4473 if (!NT_SUCCESS(status
)) {
4479 // HACK so that we can use NT5+ NTOS functions with this NT4 driver
4480 // for removable devices and avoid an infinite recursive loop between
4481 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
4483 // Check whether the update-count is greater or equal than one
4484 // (and increase it) and if so, reset it and return success.
4485 if (diskData
->UpdateRemovableGeometryCount
++ >= 1)
4487 diskData
->UpdateRemovableGeometryCount
= 0;
4488 return(STATUS_SUCCESS
);
4493 // Read the partition table again.
4496 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
4497 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4503 // HACK so that we can use NT5+ NTOS functions with this NT4 driver
4504 // for removable devices and avoid an infinite recursive loop between
4505 // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
4507 // Inconditionally reset the update-count.
4508 diskData
->UpdateRemovableGeometryCount
= 0;
4511 if (!NT_SUCCESS(status
)) {
4514 // Fail the request.
4520 if (diskData
->PartitionNumber
!= 0 &&
4521 diskData
->PartitionNumber
<= partitionList
->PartitionCount
) {
4523 partitionNumber
= diskData
->PartitionNumber
- 1;
4526 // Update the partition information for this partition.
4529 diskData
->PartitionType
=
4530 partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
4532 diskData
->BootIndicator
=
4533 partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
4535 deviceExtension
->StartingOffset
=
4536 partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
4538 deviceExtension
->PartitionLength
=
4539 partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
4541 diskData
->HiddenSectors
=
4542 partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
4544 deviceExtension
->SectorShift
= ((PDEVICE_EXTENSION
)
4545 deviceExtension
->PhysicalDevice
->DeviceExtension
)->SectorShift
;
4547 } else if (diskData
->PartitionNumber
!= 0) {
4550 // The partition does not exist. Zero all the data.
4553 diskData
->PartitionType
= 0;
4554 diskData
->BootIndicator
= 0;
4555 diskData
->HiddenSectors
= 0;
4556 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)0;
4557 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)0;
4561 // Free the partition list allocate by I/O read partition table.
4564 ExFreePool(partitionList
);
4567 return(STATUS_SUCCESS
);
4573 ScsiDiskProcessError(
4574 PDEVICE_OBJECT DeviceObject
,
4575 PSCSI_REQUEST_BLOCK Srb
,
4581 Routine Description:
4583 This routine checks the type of error. If the error indicates an underrun
4584 then indicate the request should be retried.
4588 DeviceObject - Supplies a pointer to the device object.
4590 Srb - Supplies a pointer to the failing Srb.
4592 Status - Status with which the IRP will be completed.
4594 Retry - Indication of whether the request will be retried.
4603 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4605 if (*Status
== STATUS_DATA_OVERRUN
&&
4606 ( Srb
->Cdb
[0] == SCSIOP_WRITE
|| Srb
->Cdb
[0] == SCSIOP_READ
)) {
4611 // Update the error count for the device.
4614 deviceExtension
->ErrorCount
++;
4617 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
4618 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
4621 // The disk drive should never be busy this long. Reset the scsi bus
4622 // maybe this will clear the condition.
4625 ResetScsiBus(DeviceObject
);
4628 // Update the error count for the device.
4631 deviceExtension
->ErrorCount
++;
4638 PDEVICE_OBJECT DeviceObject
,
4639 PSCSI_INQUIRY_DATA LunInfo
,
4640 PIO_SCSI_CAPABILITIES PortCapabilities
4645 Routine Description:
4647 This function checks to see if an SCSI logical unit requires special
4652 DeviceObject - Supplies the device object to be tested.
4654 InquiryData - Supplies the inquiry data returned by the device of interest.
4656 PortCapabilities - Supplies the capabilities of the device object.
4665 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4666 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
4667 BAD_CONTROLLER_INFORMATION
const *controller
;
4670 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
4672 controller
= &ScsiDiskBadControllers
[j
];
4674 if (strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
4678 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller
->InquiryString
));
4681 // Found a listed controller. Determine what must be done.
4684 if (controller
->DisableTaggedQueuing
) {
4687 // Disable tagged queuing.
4690 deviceExtension
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
4693 if (controller
->DisableSynchronousTransfers
) {
4696 // Disable synchronous data transfers.
4699 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4703 if (controller
->DisableDisconnects
) {
4706 // Disable disconnects.
4709 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
4714 // Found device so exit the loop and return.
4721 // Set the StartUnit flag appropriately.
4724 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) {
4725 deviceExtension
->DeviceFlags
|= DEV_SAFE_START_UNIT
;
4727 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
4728 if (_strnicmp((PCCHAR
)InquiryData
->VendorId
, "iomega", strlen("iomega"))) {
4729 deviceExtension
->DeviceFlags
&= ~DEV_SAFE_START_UNIT
;
4740 IN PDEVICE_OBJECT DeviceObject
4745 Routine Description:
4747 This command sends a reset bus command to the SCSI port driver.
4751 DeviceObject - The device object for the logical unit with
4760 PIO_STACK_LOCATION irpStack
;
4762 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4763 PSCSI_REQUEST_BLOCK srb
;
4764 PCOMPLETION_CONTEXT context
;
4766 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4769 // Allocate Srb from nonpaged pool.
4772 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
4773 sizeof(COMPLETION_CONTEXT
));
4776 // Save the device object in the context for use by the completion
4780 context
->DeviceObject
= DeviceObject
;
4781 srb
= &context
->Srb
;
4787 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4790 // Write length to SRB.
4793 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4796 // Set up SCSI bus address.
4799 srb
->PathId
= deviceExtension
->PathId
;
4800 srb
->TargetId
= deviceExtension
->TargetId
;
4801 srb
->Lun
= deviceExtension
->Lun
;
4803 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4806 // Build the asynchronous request to be sent to the port driver.
4807 // Since this routine is called from a DPC the IRP should always be
4811 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
4813 IoSetCompletionRoutine(irp
,
4814 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
4820 irpStack
= IoGetNextIrpStackLocation(irp
);
4822 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4824 srb
->OriginalRequest
= irp
;
4827 // Store the SRB address in next stack for port driver.
4830 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4833 // Call the port driver with the IRP.
4836 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
4840 } // end ResetScsiBus()
4845 UpdateDeviceObjects(
4846 IN PDEVICE_OBJECT PhysicalDisk
,
4852 Routine Description:
4854 This routine creates, deletes and changes device objects when
4855 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4856 the drive layout information for the user. It is possible to
4857 call this routine even in the GET_LAYOUT case because RewritePartition
4862 DeviceObject - Device object for physical disk.
4863 Irp - IO Request Packet (IRP).
4871 PDEVICE_EXTENSION physicalExtension
= PhysicalDisk
->DeviceExtension
;
4872 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
4874 ULONG partitionNumber
;
4875 ULONG partitionCount
;
4876 ULONG lastPartition
;
4877 ULONG partitionOrdinal
;
4878 PPARTITION_INFORMATION partitionEntry
;
4879 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
4880 STRING ntNameString
;
4881 UNICODE_STRING ntUnicodeString
;
4882 PDEVICE_OBJECT deviceObject
;
4883 PDEVICE_EXTENSION deviceExtension
;
4884 PDISK_DATA diskData
;
4886 ULONG numberListElements
;
4889 partitionCount
= ((partitionList
->PartitionCount
+ 3) / 4) * 4;
4892 // Zero all of the partition numbers.
4895 for (partition
= 0; partition
< partitionCount
; partition
++) {
4896 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4897 partitionEntry
->PartitionNumber
= 0;
4901 // Walk through chain of partitions for this disk to determine
4902 // which existing partitions have no match.
4905 deviceExtension
= physicalExtension
;
4906 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4911 deviceExtension
= diskData
->NextPartition
;
4914 // Check if this is the last partition in the chain.
4917 if (!deviceExtension
) {
4922 // Get the partition device extension from disk data.
4925 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4928 // Check for highest partition number this far.
4931 if (diskData
->PartitionNumber
> lastPartition
) {
4932 lastPartition
= diskData
->PartitionNumber
;
4936 // Check if this partition is not currently being used.
4939 if (!deviceExtension
->PartitionLength
.QuadPart
) {
4944 // Loop through partition information to look for match.
4948 partitionOrdinal
= 0;
4950 for (partition
= 0; partition
< partitionCount
; partition
++) {
4953 // Get partition descriptor.
4956 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4959 // Check if empty, or describes extended partition or hasn't changed.
4962 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4963 IsContainerPartition(partitionEntry
->PartitionType
)) {
4968 // Advance partition ordinal.
4974 // Check if new partition starts where this partition starts.
4977 if (partitionEntry
->StartingOffset
.QuadPart
!=
4978 deviceExtension
->StartingOffset
.QuadPart
) {
4983 // Check if partition length is the same.
4986 if (partitionEntry
->PartitionLength
.QuadPart
==
4987 deviceExtension
->PartitionLength
.QuadPart
) {
4990 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4991 physicalExtension
->DeviceNumber
,
4992 diskData
->PartitionNumber
));
4995 // Indicate match is found and set partition number
5000 partitionEntry
->PartitionNumber
= diskData
->PartitionNumber
;
5008 // A match is found.
5011 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5014 // If this partition is marked for update then update partition type.
5017 if (partitionEntry
->RewritePartition
) {
5018 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5022 // Update partitional ordinal for calls to HAL routine
5023 // IoSetPartitionInformation.
5026 diskData
->PartitionOrdinal
= partitionOrdinal
;
5029 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
5030 physicalExtension
->DeviceNumber
,
5031 diskData
->PartitionOrdinal
,
5032 diskData
->PartitionNumber
));
5037 // no match was found, indicate this partition is gone.
5041 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
5042 physicalExtension
->DeviceNumber
,
5043 diskData
->PartitionNumber
));
5045 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
5051 // Walk through partition loop to find new partitions and set up
5052 // device extensions to describe them. In some cases new device
5053 // objects will be created.
5056 partitionOrdinal
= 0;
5059 partition
< partitionCount
;
5063 // Get partition descriptor.
5066 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
5069 // Check if empty, or describes an extended partition.
5072 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
5073 IsContainerPartition(partitionEntry
->PartitionType
)) {
5078 // Keep track of position on the disk for calls to IoSetPartitionInformation.
5084 // Check if this entry should be rewritten.
5087 if (!partitionEntry
->RewritePartition
) {
5091 if (partitionEntry
->PartitionNumber
) {
5094 // Partition is an exact match with an existing partition, but is
5095 // being written anyway.
5102 // Check first if existing device object is available by
5103 // walking partition extension list.
5106 partitionNumber
= 0;
5107 deviceExtension
= physicalExtension
;
5108 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5113 // Get next partition device extension from disk data.
5116 deviceExtension
= diskData
->NextPartition
;
5118 if (!deviceExtension
) {
5122 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5125 // A device object is free if the partition length is set to zero.
5128 if (!deviceExtension
->PartitionLength
.QuadPart
) {
5129 partitionNumber
= diskData
->PartitionNumber
;
5136 // If partition number is still zero then a new device object
5140 if (partitionNumber
== 0) {
5143 partitionNumber
= lastPartition
;
5146 // Get or create partition object and set up partition parameters.
5149 sprintf(ntNameBuffer
,
5150 "\\Device\\Harddisk%lu\\Partition%lu",
5151 physicalExtension
->DeviceNumber
,
5154 RtlInitString(&ntNameString
,
5157 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
5161 if (!NT_SUCCESS(status
)) {
5166 "UpdateDeviceObjects: Create device object %s\n",
5170 // This is a new name. Create the device object to represent it.
5173 status
= IoCreateDevice(PhysicalDisk
->DriverObject
,
5174 DEVICE_EXTENSION_SIZE
,
5181 if (!NT_SUCCESS(status
)) {
5183 "UpdateDeviceObjects: Can't create device %s\n",
5185 RtlFreeUnicodeString(&ntUnicodeString
);
5190 // Set up device object fields.
5193 deviceObject
->Flags
|= DO_DIRECT_IO
;
5194 deviceObject
->StackSize
= PhysicalDisk
->StackSize
;
5197 // Set up device extension fields.
5200 deviceExtension
= deviceObject
->DeviceExtension
;
5203 // Copy physical disk extension to partition extension.
5206 RtlMoveMemory(deviceExtension
,
5208 sizeof(DEVICE_EXTENSION
));
5211 // Initialize the new S-List.
5214 if (deviceExtension
->SrbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
5215 numberListElements
= 30;
5217 numberListElements
= 8;
5221 // Build the lookaside list for srb's for this partition based on
5222 // whether the adapter and disk can do tagged queueing.
5225 ScsiClassInitializeSrbLookasideList(deviceExtension
,
5226 numberListElements
);
5229 // Allocate spinlock for zoning for split-request completion.
5232 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
5235 // Write back partition number used in creating object name.
5238 partitionEntry
->PartitionNumber
= partitionNumber
;
5241 // Clear flags initializing bit.
5244 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
5247 // Point back at device object.
5250 deviceExtension
->DeviceObject
= deviceObject
;
5252 RtlFreeUnicodeString(&ntUnicodeString
);
5255 // Link to end of partition chain using previous disk data.
5258 diskData
->NextPartition
= deviceExtension
;
5261 // Get new disk data and zero next partition pointer.
5264 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5265 diskData
->NextPartition
= NULL
;
5270 // Set pointer to disk data area that follows device extension.
5273 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5276 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5277 physicalExtension
->DeviceNumber
,
5282 // Update partition information in partition device extension.
5285 diskData
->PartitionNumber
= partitionNumber
;
5286 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5287 diskData
->BootIndicator
= partitionEntry
->BootIndicator
;
5288 deviceExtension
->StartingOffset
= partitionEntry
->StartingOffset
;
5289 deviceExtension
->PartitionLength
= partitionEntry
->PartitionLength
;
5290 diskData
->HiddenSectors
= partitionEntry
->HiddenSectors
;
5291 diskData
->PartitionOrdinal
= partitionOrdinal
;
5294 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5295 diskData
->PartitionOrdinal
,
5296 diskData
->PartitionNumber
));
5299 // Update partition number passed in to indicate the
5300 // device name for this partition.
5303 partitionEntry
->PartitionNumber
= partitionNumber
;
5306 } // end UpdateDeviceObjects()