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
;
119 } DISK_DATA
, *PDISK_DATA
;
122 // Define a general structure of identifying disk controllers with bad
126 typedef struct _BAD_CONTROLLER_INFORMATION
{
128 BOOLEAN DisableTaggedQueuing
;
129 BOOLEAN DisableSynchronousTransfers
;
130 BOOLEAN DisableDisconnects
;
131 BOOLEAN DisableWriteCache
;
132 }BAD_CONTROLLER_INFORMATION
, *PBAD_CONTROLLER_INFORMATION
;
134 BAD_CONTROLLER_INFORMATION
const ScsiDiskBadControllers
[] = {
135 { "TOSHIBA MK538FB 60", TRUE
, FALSE
, FALSE
, FALSE
},
136 { "CONNER CP3500", FALSE
, TRUE
, FALSE
, FALSE
},
137 { "OLIVETTICP3500", FALSE
, TRUE
, FALSE
, FALSE
},
138 { "SyQuest SQ5110 CHC", TRUE
, TRUE
, FALSE
, FALSE
},
139 { "SEAGATE ST41601N 0102", FALSE
, TRUE
, FALSE
, FALSE
},
140 { "SEAGATE ST3655N", FALSE
, FALSE
, FALSE
, TRUE
},
141 { "SEAGATE ST3390N", FALSE
, FALSE
, FALSE
, TRUE
},
142 { "SEAGATE ST12550N", FALSE
, FALSE
, FALSE
, TRUE
},
143 { "SEAGATE ST32430N", FALSE
, FALSE
, FALSE
, TRUE
},
144 { "SEAGATE ST31230N", FALSE
, FALSE
, FALSE
, TRUE
},
145 { "SEAGATE ST15230N", FALSE
, FALSE
, FALSE
, TRUE
},
146 { "FUJITSU M2652S-512", TRUE
, FALSE
, FALSE
, FALSE
},
147 { "MAXTOR MXT-540SL I1.2", TRUE
, FALSE
, FALSE
, FALSE
},
148 { "COMPAQ PD-1", FALSE
, TRUE
, FALSE
, FALSE
}
152 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
153 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
155 #define MODE_DATA_SIZE 192
156 #define VALUE_BUFFER_SIZE 2048
157 #define SCSI_DISK_TIMEOUT 10
158 #define PARTITION0_LIST_SIZE 4
164 IN PDRIVER_OBJECT DriverObject
,
165 IN PUNICODE_STRING RegistryPath
170 ScsiDiskDeviceVerification(
171 IN PINQUIRYDATA InquiryData
177 IN PDRIVER_OBJECT DriveObject
,
178 IN PUNICODE_STRING RegistryPath
,
179 IN PCLASS_INIT_DATA InitializationData
,
180 IN PDEVICE_OBJECT PortDeviceObject
,
186 ScsiDiskCreateClose (
187 IN PDEVICE_OBJECT DeviceObject
,
193 ScsiDiskReadWriteVerification(
194 IN PDEVICE_OBJECT DeviceObject
,
200 ScsiDiskDeviceControl(
201 IN PDEVICE_OBJECT DeviceObject
,
207 ScsiDiskProcessError(
208 PDEVICE_OBJECT DeviceObject
,
209 PSCSI_REQUEST_BLOCK Srb
,
216 ScsiDiskShutdownFlush(
217 IN PDEVICE_OBJECT DeviceObject
,
224 IN PDEVICE_OBJECT DeviceObject
,
225 IN PSCSI_INQUIRY_DATA LunInfo
231 IN PDEVICE_OBJECT DeviceObject
,
232 IN PCHAR ModeSelectBuffer
,
240 IN PDEVICE_OBJECT DeviceObject
245 CalculateMbrCheckSum(
246 IN PDEVICE_EXTENSION DeviceExtension
,
253 IN PDEVICE_EXTENSION DeviceExtension
,
261 IN PDEVICE_EXTENSION DeviceExtension
266 UpdateRemovableGeometry (
267 IN PDEVICE_OBJECT DeviceObject
,
273 CreateDiskDeviceObject(
274 IN PDRIVER_OBJECT DriverObject
,
275 IN PUNICODE_STRING RegistryPath
,
276 IN PDEVICE_OBJECT PortDeviceObject
,
278 IN PULONG DeviceCount
,
279 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
280 IN PSCSI_INQUIRY_DATA LunInfo
,
281 IN PCLASS_INIT_DATA InitData
286 CreatePartitionDeviceObjects(
287 IN PDEVICE_OBJECT PhysicalDeviceObject
,
288 IN PUNICODE_STRING RegistryPath
294 IN PDEVICE_OBJECT DeviceObject
,
301 PDEVICE_OBJECT DeviceObject
,
302 PSCSI_INQUIRY_DATA LunInfo
,
303 PIO_SCSI_CAPABILITIES PortCapabilities
309 IN PDEVICE_OBJECT DeviceObject
314 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject
,
318 #pragma alloc_text(PAGE, DriverEntry)
319 #pragma alloc_text(PAGE, FindScsiDisks)
320 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
321 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
322 #pragma alloc_text(PAGE, EnumerateBusKey)
323 #pragma alloc_text(PAGE, UpdateGeometry)
324 #pragma alloc_text(PAGE, IsFloppyDevice)
325 #pragma alloc_text(PAGE, ScanForSpecial)
326 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
327 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
334 IN PDRIVER_OBJECT DriverObject
,
335 IN PUNICODE_STRING RegistryPath
342 This routine initializes the SCSI hard disk class driver.
346 DriverObject - Pointer to driver object created by system.
348 RegistryPath - Pointer to the name of the services node for this driver.
352 The function value is the final status from the initialization operation.
357 CLASS_INIT_DATA InitializationData
;
363 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
369 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
370 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
372 InitializationData
.DeviceType
= FILE_DEVICE_DISK
;
373 InitializationData
.DeviceCharacteristics
= 0;
379 InitializationData
.ClassError
= ScsiDiskProcessError
;
380 InitializationData
.ClassReadWriteVerification
= ScsiDiskReadWriteVerification
;
381 InitializationData
.ClassFindDevices
= FindScsiDisks
;
382 InitializationData
.ClassFindDeviceCallBack
= ScsiDiskDeviceVerification
;
383 InitializationData
.ClassDeviceControl
= ScsiDiskDeviceControl
;
384 InitializationData
.ClassShutdownFlush
= ScsiDiskShutdownFlush
;
385 InitializationData
.ClassCreateClose
= NULL
;
388 // Call the class init routine
391 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
393 } // end DriverEntry()
399 ScsiDiskDeviceVerification(
400 IN PINQUIRYDATA InquiryData
407 This routine checks InquiryData for the correct device type and qualifier.
411 InquiryData - Pointer to the inquiry data for the device in question.
415 True is returned if the correct device type is found.
420 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
421 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
422 InquiryData
->DeviceTypeQualifier
== 0) {
435 IN PDRIVER_OBJECT DriverObject
,
436 IN PUNICODE_STRING RegistryPath
,
437 IN PCLASS_INIT_DATA InitializationData
,
438 IN PDEVICE_OBJECT PortDeviceObject
,
446 This routine gets a port drivers capabilities, obtains the
447 inquiry data, searches the SCSI bus for the port driver and creates
448 the device objects for the disks found.
452 DriverObject - Pointer to driver object created by system.
454 PortDeviceObject - Device object use to send requests to port driver.
456 PortNumber - Number for port driver. Used to pass on to
457 CreateDiskDeviceObjects() and create device objects.
461 True is returned if one disk was found and successfully created.
466 PIO_SCSI_CAPABILITIES portCapabilities
;
468 PCONFIGURATION_INFORMATION configurationInformation
;
470 PSCSI_INQUIRY_DATA lunInfo
;
471 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
472 PINQUIRYDATA inquiryData
;
476 BOOLEAN foundOne
= FALSE
;
481 // Call port driver to get adapter capabilities.
484 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
486 if (!NT_SUCCESS(status
)) {
487 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
492 // Call port driver to get inquiry information to find disks.
495 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
497 if (!NT_SUCCESS(status
)) {
498 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
503 // Do a quick scan of the devices on this adapter to determine how many
504 // disks are on this adapter. This is used to determine the number of
505 // SRB zone elements to allocate.
508 adapterInfo
= (PVOID
) buffer
;
510 adapterDisk
= ScsiClassFindUnclaimedDevices(InitializationData
, adapterInfo
);
513 // Allocate a zone of SRB for disks on this adapter.
516 if (adapterDisk
== 0) {
519 // No free disks were found.
526 // Get the number of disks already initialized.
529 configurationInformation
= IoGetConfigurationInformation();
530 diskCount
= &configurationInformation
->DiskCount
;
533 // For each SCSI bus this adapter supports ...
536 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
539 // Get the SCSI bus scan data for this bus.
542 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
545 // Search list for unclaimed disk devices.
548 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
550 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
552 if (((inquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
553 (inquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
554 inquiryData
->DeviceTypeQualifier
== 0 &&
555 (!lunInfo
->DeviceClaimed
)) {
558 "FindScsiDevices: Vendor string is %.24s\n",
559 inquiryData
->VendorId
));
562 // Create device objects for disk
565 status
= CreateDiskDeviceObject(DriverObject
,
574 if (NT_SUCCESS(status
)) {
577 // Increment system disk device count.
590 if (lunInfo
->NextInquiryDataOffset
== 0) {
594 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
600 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
607 } // end FindScsiDisks()
612 CreateDiskDeviceObject(
613 IN PDRIVER_OBJECT DriverObject
,
614 IN PUNICODE_STRING RegistryPath
,
615 IN PDEVICE_OBJECT PortDeviceObject
,
617 IN PULONG DeviceCount
,
618 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
619 IN PSCSI_INQUIRY_DATA LunInfo
,
620 IN PCLASS_INIT_DATA InitData
627 This routine creates an object for the physical device and then searches
628 the device for partitions and creates an object for each partition.
632 DriverObject - Pointer to driver object created by system.
634 PortDeviceObject - Miniport device object.
636 PortNumber - port number. Used in creating disk objects.
638 DeviceCount - Number of previously installed devices.
640 PortCapabilities - Capabilities of this SCSI port.
642 LunInfo - LUN specific information.
650 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
652 UNICODE_STRING ntUnicodeString
;
653 OBJECT_ATTRIBUTES objectAttributes
;
656 PDEVICE_OBJECT deviceObject
= NULL
;
657 //PDEVICE_OBJECT physicalDevice;
658 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
659 PDEVICE_EXTENSION deviceExtension
= NULL
;
660 //PDEVICE_EXTENSION physicalDeviceExtension;
661 UCHAR pathId
= LunInfo
->PathId
;
662 UCHAR targetId
= LunInfo
->TargetId
;
663 UCHAR lun
= LunInfo
->Lun
;
664 //BOOLEAN writeCache;
665 PVOID senseData
= NULL
;
668 BOOLEAN srbListInitialized
= FALSE
;
674 // Set up an object directory to contain the objects for this
675 // device and all its partitions.
678 sprintf(ntNameBuffer
,
679 "\\Device\\Harddisk%lu",
682 RtlInitString(&ntNameString
,
685 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
689 if (!NT_SUCCESS(status
)) {
693 InitializeObjectAttributes(&objectAttributes
,
695 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
699 status
= ZwCreateDirectoryObject(&handle
,
700 DIRECTORY_ALL_ACCESS
,
703 RtlFreeUnicodeString(&ntUnicodeString
);
705 if (!NT_SUCCESS(status
)) {
708 "CreateDiskDeviceObjects: Could not create directory %s\n",
718 status
= ScsiClassClaimDevice(PortDeviceObject
,
723 if (!NT_SUCCESS(status
)) {
724 ZwMakeTemporaryObject(handle
);
730 // Create a device object for this device. Each physical disk will
731 // have at least one device object. The required device object
732 // describes the entire device. Its directory path is
733 // \Device\HarddiskN\Partition0, where N = device number.
736 sprintf(ntNameBuffer
,
737 "\\Device\\Harddisk%lu\\Partition0",
741 status
= ScsiClassCreateDeviceObject(DriverObject
,
747 if (!NT_SUCCESS(status
)) {
750 "CreateDiskDeviceObjects: Can not create device object %s\n",
753 goto CreateDiskDeviceObjectsExit
;
757 // Indicate that IRPs should include MDLs for data transfers.
760 deviceObject
->Flags
|= DO_DIRECT_IO
;
763 // Check if this is during initialization. If not indicate that
764 // system initialization already took place and this disk is ready
769 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
773 // Check for removable media support.
776 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->RemovableMedia
) {
777 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
781 // Set up required stack size in device object.
784 deviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
786 deviceExtension
= deviceObject
->DeviceExtension
;
789 // Allocate spinlock for split request completion.
792 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
795 // Initialize lock count to zero. The lock count is used to
796 // disable the ejection mechanism on devices that support
797 // removable media. Only the lock count in the physical
798 // device extension is used.
801 deviceExtension
->LockCount
= 0;
804 // Save system disk number.
807 deviceExtension
->DeviceNumber
= *DeviceCount
;
810 // Copy port device object pointer to the device extension.
813 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
816 // Set the alignment requirements for the device based on the
817 // host adapter requirements
820 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
821 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
825 // This is the physical device object.
828 //physicalDevice = deviceObject;
829 //physicalDeviceExtension = deviceExtension;
832 // Save address of port driver capabilities.
835 deviceExtension
->PortCapabilities
= PortCapabilities
;
838 // Build the lookaside list for srb's for the physical disk. Should only
842 ScsiClassInitializeSrbLookasideList(deviceExtension
,
843 PARTITION0_LIST_SIZE
);
845 srbListInitialized
= TRUE
;
848 // Initialize the srb flags.
851 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->CommandQueue
&&
852 PortCapabilities
->TaggedQueuing
) {
854 deviceExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
858 deviceExtension
->SrbFlags
= 0;
863 // Allow queued requests if this is not removable media.
866 if (!(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
868 deviceExtension
->SrbFlags
|= SRB_FLAGS_NO_QUEUE_FREEZE
;
873 // Look for controller that require special flags.
876 ScanForSpecial(deviceObject
,
880 //srbFlags = deviceExtension->SrbFlags;
883 // Allocate buffer for drive geometry.
886 diskGeometry
= ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
888 if (diskGeometry
== NULL
) {
891 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
892 status
= STATUS_INSUFFICIENT_RESOURCES
;
893 goto CreateDiskDeviceObjectsExit
;
896 deviceExtension
->DiskGeometry
= diskGeometry
;
899 // Allocate request sense buffer.
902 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
904 if (senseData
== NULL
) {
907 // The buffer can not be allocated.
911 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
913 status
= STATUS_INSUFFICIENT_RESOURCES
;
914 goto CreateDiskDeviceObjectsExit
;
918 // Set the sense data pointer in the device extension.
921 deviceExtension
->SenseData
= senseData
;
924 // Physical device object will describe the entire
925 // device, starting at byte offset 0.
928 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)(0);
931 // TargetId/LUN describes a device location on the SCSI bus.
932 // This information comes from the inquiry buffer.
935 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
936 deviceExtension
->PathId
= pathId
;
937 deviceExtension
->TargetId
= targetId
;
938 deviceExtension
->Lun
= lun
;
941 // Set timeout value in seconds.
944 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
946 deviceExtension
->TimeOutValue
= timeOut
;
948 deviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
952 // Back pointer to device object.
955 deviceExtension
->DeviceObject
= deviceObject
;
958 // If this is a removable device, then make sure it is not a floppy.
959 // Perform a mode sense command to determine the media type. Note
960 // IsFloppyDevice also checks for write cache enabled.
963 if (IsFloppyDevice(deviceObject
) && deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
964 (((PINQUIRYDATA
)LunInfo
->InquiryData
)->DeviceType
== DIRECT_ACCESS_DEVICE
)) {
966 status
= STATUS_NO_SUCH_DEVICE
;
967 goto CreateDiskDeviceObjectsExit
;
970 DisableWriteCache(deviceObject
,LunInfo
);
972 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
975 // NOTE: At this point one device object has been successfully created.
976 // from here on out return success.
980 // Do READ CAPACITY. This SCSI command
981 // returns the number of bytes on a device.
982 // Device extension is updated with device size.
985 status
= ScsiClassReadDriveCapacity(deviceObject
);
988 // If the read capacity failed then just return, unless this is a
989 // removable disk where a device object partition needs to be created.
992 if (!NT_SUCCESS(status
) &&
993 !(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
996 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
999 return(STATUS_SUCCESS
);
1004 // Make sure the volume verification bit is off so that
1005 // IoReadPartitionTable will work.
1008 deviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
1011 status
= CreatePartitionDeviceObjects(deviceObject
, RegistryPath
);
1013 if (NT_SUCCESS(status
))
1014 return STATUS_SUCCESS
;
1017 CreateDiskDeviceObjectsExit
:
1020 // Release the device since an error occurred.
1023 ScsiClassClaimDevice(PortDeviceObject
,
1028 if (diskGeometry
!= NULL
) {
1029 ExFreePool(diskGeometry
);
1032 if (senseData
!= NULL
) {
1033 ExFreePool(senseData
);
1036 if (deviceObject
!= NULL
) {
1038 if (srbListInitialized
) {
1039 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1042 IoDeleteDevice(deviceObject
);
1046 // Delete directory and return.
1049 if (!NT_SUCCESS(status
)) {
1050 ZwMakeTemporaryObject(handle
);
1057 } // end CreateDiskDeviceObjects()
1062 CreatePartitionDeviceObjects(
1063 IN PDEVICE_OBJECT PhysicalDeviceObject
,
1064 IN PUNICODE_STRING RegistryPath
1067 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
1068 ULONG partitionNumber
= 0;
1070 PDEVICE_OBJECT deviceObject
= NULL
;
1071 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
1072 PDRIVE_LAYOUT_INFORMATION partitionList
= NULL
;
1073 PDEVICE_EXTENSION deviceExtension
;
1074 PDEVICE_EXTENSION physicalDeviceExtension
;
1075 PCLASS_INIT_DATA initData
= NULL
;
1076 PDISK_DATA diskData
;
1077 PDISK_DATA physicalDiskData
;
1078 ULONG bytesPerSector
;
1081 ULONG dmByteSkew
= 0;
1083 BOOLEAN dmActive
= FALSE
;
1084 ULONG numberListElements
= 0;
1088 // Get physical device geometry information for partition table reads.
1091 physicalDeviceExtension
= PhysicalDeviceObject
->DeviceExtension
;
1092 diskGeometry
= physicalDeviceExtension
->DiskGeometry
;
1093 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
;
1096 // Make sure sector size is not zero.
1099 if (bytesPerSector
== 0) {
1102 // Default sector size for disk is 512.
1105 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
= 512;
1108 sectorShift
= physicalDeviceExtension
->SectorShift
;
1111 // Set pointer to disk data area that follows device extension.
1114 diskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1115 diskData
->PartitionListState
= Initializing
;
1118 // Determine is DM Driver is loaded on an IDE drive that is
1119 // under control of Atapi - this could be either a crashdump or
1120 // an Atapi device is sharing the controller with an IDE disk.
1123 HalExamineMBR(PhysicalDeviceObject
,
1124 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1131 // Update the device extension, so that the call to IoReadPartitionTable
1132 // will get the correct information. Any I/O to this disk will have
1133 // to be skewed by *dmSkew sectors aka DMByteSkew.
1136 physicalDeviceExtension
->DMSkew
= *dmSkew
;
1137 physicalDeviceExtension
->DMActive
= TRUE
;
1138 physicalDeviceExtension
->DMByteSkew
= physicalDeviceExtension
->DMSkew
* bytesPerSector
;
1141 // Save away the information that we need, since this deviceExtension will soon be
1146 dmByteSkew
= physicalDeviceExtension
->DMByteSkew
;
1151 // Create objects for all the partitions on the device.
1154 status
= IoReadPartitionTable(PhysicalDeviceObject
,
1155 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1157 (PVOID
)&partitionList
);
1160 // If the I/O read partition table failed and this is a removable device,
1161 // then fix up the partition list to make it look like there is one
1162 // zero length partition.
1164 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status
);
1165 if ((!NT_SUCCESS(status
) || partitionList
->PartitionCount
== 0) &&
1166 PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1168 if (!NT_SUCCESS(status
)) {
1171 // Remember this disk is not ready.
1174 diskData
->DriveNotReady
= TRUE
;
1179 // Free the partition list allocated by IoReadPartitionTable.
1182 ExFreePool(partitionList
);
1186 // Allocate and zero a partition list.
1189 partitionList
= ExAllocatePool(NonPagedPool
, sizeof(*partitionList
));
1192 if (partitionList
!= NULL
) {
1194 RtlZeroMemory( partitionList
, sizeof( *partitionList
));
1197 // Set the partition count to one and the status to success
1198 // so one device object will be created. Set the partition type
1199 // to a bogus value.
1202 partitionList
->PartitionCount
= 1;
1204 status
= STATUS_SUCCESS
;
1208 if (NT_SUCCESS(status
)) {
1211 // Record disk signature.
1214 diskData
->Signature
= partitionList
->Signature
;
1217 // If disk signature is zero, then calculate the MBR checksum.
1220 if (!diskData
->Signature
) {
1222 if (!CalculateMbrCheckSum(physicalDeviceExtension
,
1223 &diskData
->MbrCheckSum
)) {
1226 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1227 physicalDeviceExtension
->DeviceNumber
));
1231 "SCSIDISK: MBR checksum for disk %x is %x\n",
1232 physicalDeviceExtension
->DeviceNumber
,
1233 diskData
->MbrCheckSum
));
1238 // Check the registry and determine if the BIOS knew about this drive. If
1239 // it did then update the geometry with the BIOS information.
1242 UpdateGeometry(physicalDeviceExtension
);
1244 srbFlags
= physicalDeviceExtension
->SrbFlags
;
1246 initData
= ExAllocatePool(NonPagedPool
, sizeof(CLASS_INIT_DATA
));
1250 "Disk.CreatePartitionDeviceObjects - Allocation of initData failed\n"));
1252 status
= STATUS_INSUFFICIENT_RESOURCES
;
1253 goto CreatePartitionDeviceObjectsExit
;
1256 RtlZeroMemory(initData
, sizeof(CLASS_INIT_DATA
));
1258 initData
->InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
1259 initData
->DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
1260 initData
->DeviceType
= FILE_DEVICE_DISK
;
1261 initData
->DeviceCharacteristics
= PhysicalDeviceObject
->Characteristics
;
1262 initData
->ClassError
= physicalDeviceExtension
->ClassError
;
1263 initData
->ClassReadWriteVerification
= physicalDeviceExtension
->ClassReadWriteVerification
;
1264 initData
->ClassFindDevices
= physicalDeviceExtension
->ClassFindDevices
;
1265 initData
->ClassDeviceControl
= physicalDeviceExtension
->ClassDeviceControl
;
1266 initData
->ClassShutdownFlush
= physicalDeviceExtension
->ClassShutdownFlush
;
1267 initData
->ClassCreateClose
= physicalDeviceExtension
->ClassCreateClose
;
1268 initData
->ClassStartIo
= physicalDeviceExtension
->ClassStartIo
;
1271 // Create device objects for the device partitions (if any).
1272 // PartitionCount includes physical device partition 0,
1273 // so only one partition means no objects to create.
1277 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1278 partitionList
->PartitionCount
));
1280 for (partitionNumber
= 0; partitionNumber
<
1281 partitionList
->PartitionCount
; partitionNumber
++) {
1284 // Create partition object and set up partition parameters.
1287 sprintf(ntNameBuffer
,
1288 "\\Device\\Harddisk%lu\\Partition%lu",
1289 physicalDeviceExtension
->DeviceNumber
,
1290 partitionNumber
+ 1);
1293 "CreateDiskDeviceObjects: Create device object %s\n",
1296 status
= ScsiClassCreateDeviceObject(PhysicalDeviceObject
->DriverObject
,
1298 PhysicalDeviceObject
,
1302 if (!NT_SUCCESS(status
)) {
1304 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer
));
1310 // Set up device object fields.
1313 deviceObject
->Flags
|= DO_DIRECT_IO
;
1316 // Check if this is during initialization. If not indicate that
1317 // system initialization already took place and this disk is ready
1321 if (!RegistryPath
) {
1322 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1325 deviceObject
->StackSize
= (CCHAR
)physicalDeviceExtension
->PortDeviceObject
->StackSize
+ 1;
1328 // Set up device extension fields.
1331 deviceExtension
= deviceObject
->DeviceExtension
;
1336 // Restore any saved DM values.
1339 deviceExtension
->DMByteSkew
= dmByteSkew
;
1340 deviceExtension
->DMSkew
= *dmSkew
;
1341 deviceExtension
->DMActive
= TRUE
;
1346 // Link new device extension to previous disk data
1347 // to support dynamic partitioning.
1350 diskData
->NextPartition
= deviceExtension
;
1353 // Get pointer to new disk data.
1356 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1359 // Set next partition pointer to NULL in case this is the
1363 diskData
->NextPartition
= NULL
;
1366 // Allocate spinlock for zoning for split-request completion.
1369 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
1372 // Copy port device object pointer to device extension.
1375 deviceExtension
->PortDeviceObject
= physicalDeviceExtension
->PortDeviceObject
;
1378 // Set the alignment requirements for the device based on the
1379 // host adapter requirements
1382 if (physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
1383 deviceObject
->AlignmentRequirement
= physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
;
1387 if (srbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
1388 numberListElements
= 30;
1390 numberListElements
= 8;
1394 // Build the lookaside list for srb's for this partition based on
1395 // whether the adapter and disk can do tagged queueing.
1398 ScsiClassInitializeSrbLookasideList(deviceExtension
,
1399 numberListElements
);
1401 deviceExtension
->SrbFlags
= srbFlags
;
1404 // Set the sense-data pointer in the device extension.
1407 deviceExtension
->SenseData
= physicalDeviceExtension
->SenseData
;
1408 deviceExtension
->PortCapabilities
= physicalDeviceExtension
->PortCapabilities
;
1409 deviceExtension
->DiskGeometry
= diskGeometry
;
1410 diskData
->PartitionOrdinal
= diskData
->PartitionNumber
= partitionNumber
+ 1;
1411 diskData
->PartitionType
= partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
1412 diskData
->BootIndicator
= partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
1414 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1415 diskData
->PartitionType
));
1417 deviceExtension
->StartingOffset
= partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
1418 deviceExtension
->PartitionLength
= partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
1419 diskData
->HiddenSectors
= partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
1420 deviceExtension
->PortNumber
= physicalDeviceExtension
->PortNumber
;
1421 deviceExtension
->PathId
= physicalDeviceExtension
->PathId
;
1422 deviceExtension
->TargetId
= physicalDeviceExtension
->TargetId
;
1423 deviceExtension
->Lun
= physicalDeviceExtension
->Lun
;
1426 // Check for removable media support.
1429 if (PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1430 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
1434 // Set timeout value in seconds.
1437 deviceExtension
->TimeOutValue
= physicalDeviceExtension
->TimeOutValue
;
1438 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bytesPerSector
;
1439 deviceExtension
->SectorShift
= sectorShift
;
1440 deviceExtension
->DeviceObject
= deviceObject
;
1441 deviceExtension
->DeviceFlags
|= physicalDeviceExtension
->DeviceFlags
;
1443 } // end for (partitionNumber) ...
1446 // Free the buffer allocated by reading the
1450 ExFreePool(partitionList
);
1458 CreatePartitionDeviceObjectsExit
:
1460 if (partitionList
) {
1461 ExFreePool(partitionList
);
1464 ExFreePool(initData
);
1476 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1477 physicalDiskData
->PartitionListState
= Initialized
;
1479 return(STATUS_SUCCESS
);
1482 } // end CreatePartitionDeviceObjects()
1487 ScsiDiskReadWriteVerification(
1488 IN PDEVICE_OBJECT DeviceObject
,
1494 Routine Description:
1496 I/O System entry for read and write requests to SCSI disks.
1500 DeviceObject - Pointer to driver object created by system.
1510 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1511 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1512 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1513 LARGE_INTEGER startingOffset
;
1516 // HACK: How can we end here with null sector size?!
1519 if (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
== 0) {
1520 DPRINT1("Hack! Received invalid sector size\n");
1521 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1525 // Verify parameters of this request.
1526 // Check that ending sector is within partition and
1527 // that number of bytes to transfer is a multiple of
1531 startingOffset
.QuadPart
= (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
1534 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
1535 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
1538 // This error maybe caused by the fact that the drive is not ready.
1541 if (((PDISK_DATA
)(deviceExtension
+ 1))->DriveNotReady
) {
1544 // Flag this as a user error so that a popup is generated.
1547 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
1548 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1553 // Note fastfat depends on this parameter to determine when to
1554 // remount do to a sector size change.
1557 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1560 if (startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) {
1561 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset
.QuadPart
, deviceExtension
->PartitionLength
.QuadPart
);
1564 if (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1)) {
1565 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount
, deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
1568 if (Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_READY
) {
1569 DPRINT1("Failing due to device not ready!\n");
1572 return STATUS_INVALID_PARAMETER
;
1575 return STATUS_SUCCESS
;
1577 } // end ScsiDiskReadWrite()
1582 ScsiDiskDeviceControl(
1583 PDEVICE_OBJECT DeviceObject
,
1589 Routine Description:
1591 I/O system entry for device controls to SCSI disks.
1595 DeviceObject - Pointer to driver object created by system.
1605 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1606 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1607 PDISK_DATA diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1608 PSCSI_REQUEST_BLOCK srb
;
1610 PMODE_PARAMETER_HEADER modeData
;
1615 IO_STATUS_BLOCK ioStatus
;
1619 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
1623 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1624 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1625 return(STATUS_INSUFFICIENT_RESOURCES
);
1629 // Write zeros to Srb.
1632 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1634 cdb
= (PCDB
)srb
->Cdb
;
1636 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1638 case SMART_GET_VERSION
: {
1641 PSRB_IO_CONTROL srbControl
;
1642 PGETVERSIONINPARAMS versionParams
;
1644 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1645 sizeof(GETVERSIONINPARAMS
)) {
1646 status
= STATUS_INVALID_PARAMETER
;
1651 // Create notification event object to be used to signal the
1652 // request completion.
1655 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1657 srbControl
= ExAllocatePool(NonPagedPool
,
1658 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
));
1661 status
= STATUS_INSUFFICIENT_RESOURCES
;
1666 // fill in srbControl fields
1669 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1670 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1671 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1672 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1673 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1676 // Point to the 'buffer' portion of the SRB_CONTROL
1679 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1682 // Ensure correct target is set in the cmd parameters.
1685 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1686 versionParams
->bIDEDeviceMap
= deviceExtension
->TargetId
;
1689 // Copy the IOCTL parameters to the srb control buffer area.
1692 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(GETVERSIONINPARAMS
));
1695 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1696 deviceExtension
->PortDeviceObject
,
1698 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1700 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1706 status
= STATUS_INSUFFICIENT_RESOURCES
;
1711 // Call the port driver with the request and wait for it to complete.
1714 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1716 if (status
== STATUS_PENDING
) {
1717 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1718 status
= ioStatus
.Status
;
1722 // If successful, copy the data received into the output buffer.
1723 // This should only fail in the event that the IDE driver is older than this driver.
1726 if (NT_SUCCESS(status
)) {
1728 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1730 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, sizeof(GETVERSIONINPARAMS
));
1731 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1734 ExFreePool(srbControl
);
1738 case SMART_RCV_DRIVE_DATA
: {
1740 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1741 ULONG controlCode
= 0;
1742 PSRB_IO_CONTROL srbControl
;
1745 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1746 (sizeof(SENDCMDINPARAMS
) - 1)) {
1747 status
= STATUS_INVALID_PARAMETER
;
1750 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1751 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1752 status
= STATUS_INVALID_PARAMETER
;
1757 // Create notification event object to be used to signal the
1758 // request completion.
1761 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1763 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1765 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1766 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1768 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1769 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1770 case READ_ATTRIBUTES
:
1771 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1772 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1774 case READ_THRESHOLDS
:
1775 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1776 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1779 status
= STATUS_INVALID_PARAMETER
;
1784 status
= STATUS_INVALID_PARAMETER
;
1787 if (controlCode
== 0) {
1788 status
= STATUS_INVALID_PARAMETER
;
1792 srbControl
= ExAllocatePool(NonPagedPool
,
1793 sizeof(SRB_IO_CONTROL
) + length
);
1796 status
= STATUS_INSUFFICIENT_RESOURCES
;
1801 // fill in srbControl fields
1804 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1805 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1806 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1807 srbControl
->Length
= length
;
1808 srbControl
->ControlCode
= controlCode
;
1811 // Point to the 'buffer' portion of the SRB_CONTROL
1814 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1817 // Ensure correct target is set in the cmd parameters.
1820 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1823 // Copy the IOCTL parameters to the srb control buffer area.
1826 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1828 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1829 deviceExtension
->PortDeviceObject
,
1831 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1833 sizeof(SRB_IO_CONTROL
) + length
,
1839 status
= STATUS_INSUFFICIENT_RESOURCES
;
1844 // Call the port driver with the request and wait for it to complete.
1847 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1849 if (status
== STATUS_PENDING
) {
1850 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1851 status
= ioStatus
.Status
;
1855 // If successful, copy the data received into the output buffer
1858 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1860 if (NT_SUCCESS(status
)) {
1862 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
- 1);
1863 Irp
->IoStatus
.Information
= length
- 1;
1867 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1868 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1872 ExFreePool(srbControl
);
1877 case SMART_SEND_DRIVE_COMMAND
: {
1879 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1880 PSRB_IO_CONTROL srbControl
;
1881 ULONG controlCode
= 0;
1884 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1885 (sizeof(SENDCMDINPARAMS
) - 1)) {
1886 status
= STATUS_INVALID_PARAMETER
;
1889 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1890 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1891 status
= STATUS_INVALID_PARAMETER
;
1896 // Create notification event object to be used to signal the
1897 // request completion.
1900 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1904 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1905 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1908 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1912 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1915 case RETURN_SMART_STATUS
:
1918 // Ensure bBuffer is at least 2 bytes (to hold the values of
1919 // cylinderLow and cylinderHigh).
1922 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1923 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1925 status
= STATUS_INVALID_PARAMETER
;
1929 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1930 length
= sizeof(IDEREGS
);
1933 case ENABLE_DISABLE_AUTOSAVE
:
1934 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1937 case SAVE_ATTRIBUTE_VALUES
:
1938 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1941 case EXECUTE_OFFLINE_DIAGS
:
1942 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1946 status
= STATUS_INVALID_PARAMETER
;
1951 status
= STATUS_INVALID_PARAMETER
;
1954 if (controlCode
== 0) {
1955 status
= STATUS_INVALID_PARAMETER
;
1959 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1960 srbControl
= ExAllocatePool(NonPagedPool
,
1961 sizeof(SRB_IO_CONTROL
) + length
);
1964 status
= STATUS_INSUFFICIENT_RESOURCES
;
1969 // fill in srbControl fields
1972 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1973 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1974 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1975 srbControl
->Length
= length
;
1978 // Point to the 'buffer' portion of the SRB_CONTROL
1981 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1984 // Ensure correct target is set in the cmd parameters.
1987 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1990 // Copy the IOCTL parameters to the srb control buffer area.
1993 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1995 srbControl
->ControlCode
= controlCode
;
1997 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1998 deviceExtension
->PortDeviceObject
,
2000 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
2002 sizeof(SRB_IO_CONTROL
) + length
,
2008 status
= STATUS_INSUFFICIENT_RESOURCES
;
2013 // Call the port driver with the request and wait for it to complete.
2016 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2018 if (status
== STATUS_PENDING
) {
2019 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2020 status
= ioStatus
.Status
;
2024 // Copy the data received into the output buffer. Since the status buffer
2025 // contains error information also, always perform this copy. IO will will
2026 // either pass this back to the app, or zero it, in case of error.
2029 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2032 // Update the return buffer size based on the sub-command.
2035 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
2036 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
2038 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
2041 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
);
2042 Irp
->IoStatus
.Information
= length
;
2044 ExFreePool(srbControl
);
2049 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2050 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2053 PDEVICE_EXTENSION physicalDeviceExtension
;
2054 PDISK_DATA physicalDiskData
;
2055 BOOLEAN removable
= FALSE
;
2056 BOOLEAN listInitialized
= FALSE
;
2058 if ((irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
&&
2059 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2060 sizeof(DISK_GEOMETRY
)) ||
2061 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
&&
2062 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2063 sizeof(DISK_GEOMETRY_EX
))) {
2065 status
= STATUS_INFO_LENGTH_MISMATCH
;
2069 status
= STATUS_SUCCESS
;
2071 physicalDeviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2072 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
2074 removable
= (BOOLEAN
)DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
;
2075 listInitialized
= (physicalDiskData
->PartitionListState
== Initialized
);
2077 if (removable
|| (!listInitialized
))
2080 // Issue ReadCapacity to update device extension
2081 // with information for current media.
2084 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
2090 if (!NT_SUCCESS(status
)) {
2093 // Note the drive is not ready.
2096 diskData
->DriveNotReady
= TRUE
;
2102 // Note the drive is now ready.
2105 diskData
->DriveNotReady
= FALSE
;
2107 } else if (NT_SUCCESS(status
)) {
2109 // ReadDriveCapacity was alright, create Partition Objects
2111 if (physicalDiskData
->PartitionListState
== NotInitialized
) {
2112 status
= CreatePartitionDeviceObjects(deviceExtension
->PhysicalDevice
, NULL
);
2116 if (NT_SUCCESS(status
)) {
2119 // Copy drive geometry information from device extension.
2122 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2123 deviceExtension
->DiskGeometry
,
2124 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2125 sizeof(DISK_GEOMETRY
) :
2126 sizeof(DISK_GEOMETRY_EX
));
2128 status
= STATUS_SUCCESS
;
2129 Irp
->IoStatus
.Information
=
2130 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2131 sizeof(DISK_GEOMETRY
) :
2132 sizeof(DISK_GEOMETRY_EX
);
2139 case IOCTL_DISK_VERIFY
:
2143 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2144 LARGE_INTEGER byteOffset
;
2149 // Validate buffer length.
2152 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2153 sizeof(VERIFY_INFORMATION
)) {
2155 status
= STATUS_INFO_LENGTH_MISMATCH
;
2163 srb
->CdbLength
= 10;
2165 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2168 // Add disk offset to starting sector.
2171 byteOffset
.QuadPart
= deviceExtension
->StartingOffset
.QuadPart
+
2172 verifyInfo
->StartingOffset
.QuadPart
;
2175 // Convert byte offset to sector offset.
2178 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2181 // Convert ULONG byte count to USHORT sector count.
2184 sectorCount
= (USHORT
)(verifyInfo
->Length
>> deviceExtension
->SectorShift
);
2187 // Move little endian values into CDB in big endian format.
2190 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2191 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2192 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2193 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2195 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2196 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2199 // The verify command is used by the NT FORMAT utility and
2200 // requests are sent down for 5% of the volume size. The
2201 // request timeout value is calculated based on the number of
2202 // sectors verified.
2205 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2206 deviceExtension
->TimeOutValue
;
2208 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
2219 case IOCTL_DISK_GET_PARTITION_INFO
:
2222 // Return the information about the partition specified by the device
2223 // object. Note that no information is ever returned about the size
2224 // or partition type of the physical disk, as this doesn't make any
2228 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2229 sizeof(PARTITION_INFORMATION
)) {
2231 status
= STATUS_INFO_LENGTH_MISMATCH
;
2234 #if 0 // HACK: ReactOS partition numbers must be wrong
2235 else if (diskData
->PartitionNumber
== 0) {
2238 // Partition zero is not a partition so this is not a
2239 // reasonable request.
2242 status
= STATUS_INVALID_DEVICE_REQUEST
;
2248 PPARTITION_INFORMATION outputBuffer
;
2250 if (diskData
->PartitionNumber
== 0) {
2251 DPRINT1("HACK: Handling partition 0 request!\n");
2256 // Update the geometry in case it has changed.
2259 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2261 if (!NT_SUCCESS(status
)) {
2264 // Note the drive is not ready.
2267 diskData
->DriveNotReady
= TRUE
;
2272 // Note the drive is now ready.
2275 diskData
->DriveNotReady
= FALSE
;
2278 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2280 outputBuffer
->PartitionType
= diskData
->PartitionType
;
2281 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2282 outputBuffer
->PartitionLength
.QuadPart
= (diskData
->PartitionNumber
) ?
2283 deviceExtension
->PartitionLength
.QuadPart
: 2305843009213693951LL; // HACK
2284 outputBuffer
->HiddenSectors
= diskData
->HiddenSectors
;
2285 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2286 outputBuffer
->BootIndicator
= diskData
->BootIndicator
;
2287 outputBuffer
->RewritePartition
= FALSE
;
2288 outputBuffer
->RecognizedPartition
=
2289 IsRecognizedPartition(diskData
->PartitionType
);
2291 status
= STATUS_SUCCESS
;
2292 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2297 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2300 // Return the information about the partition specified by the device
2301 // object. Note that no information is ever returned about the size
2302 // or partition type of the physical disk, as this doesn't make any
2306 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2307 sizeof(PARTITION_INFORMATION_EX
)) {
2309 status
= STATUS_INFO_LENGTH_MISMATCH
;
2312 #if 0 // HACK: ReactOS partition numbers must be wrong
2313 else if (diskData
->PartitionNumber
== 0) {
2316 // Partition zero is not a partition so this is not a
2317 // reasonable request.
2320 status
= STATUS_INVALID_DEVICE_REQUEST
;
2326 PPARTITION_INFORMATION_EX outputBuffer
;
2328 if (diskData
->PartitionNumber
== 0) {
2329 DPRINT1("HACK: Handling partition 0 request!\n");
2334 // Update the geometry in case it has changed.
2337 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2339 if (!NT_SUCCESS(status
)) {
2342 // Note the drive is not ready.
2345 diskData
->DriveNotReady
= TRUE
;
2350 // Note the drive is now ready.
2353 diskData
->DriveNotReady
= FALSE
;
2355 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2357 status
= STATUS_INVALID_DEVICE_REQUEST
;
2362 (PPARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
2365 // FIXME: hack of the year, assume that partition is MBR
2366 // Thing that can obviously be wrong...
2369 outputBuffer
->PartitionStyle
= PARTITION_STYLE_MBR
;
2370 outputBuffer
->Mbr
.PartitionType
= diskData
->PartitionType
;
2371 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2372 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2373 outputBuffer
->Mbr
.HiddenSectors
= diskData
->HiddenSectors
;
2374 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2375 outputBuffer
->Mbr
.BootIndicator
= diskData
->BootIndicator
;
2376 outputBuffer
->RewritePartition
= FALSE
;
2377 outputBuffer
->Mbr
.RecognizedPartition
=
2378 IsRecognizedPartition(diskData
->PartitionType
);
2380 status
= STATUS_SUCCESS
;
2381 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
2386 case IOCTL_DISK_SET_PARTITION_INFO
:
2388 if (diskData
->PartitionNumber
== 0) {
2390 status
= STATUS_UNSUCCESSFUL
;
2394 PSET_PARTITION_INFORMATION inputBuffer
=
2395 (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2398 // Validate buffer length.
2401 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2402 sizeof(SET_PARTITION_INFORMATION
)) {
2404 status
= STATUS_INFO_LENGTH_MISMATCH
;
2409 // The HAL routines IoGet- and IoSetPartitionInformation were
2410 // developed before support of dynamic partitioning and therefore
2411 // don't distinguish between partition ordinal (that is the order
2412 // of a partition on a disk) and the partition number. (The
2413 // partition number is assigned to a partition to identify it to
2414 // the system.) Use partition ordinals for these legacy calls.
2417 status
= IoSetPartitionInformation(
2418 deviceExtension
->PhysicalDevice
,
2419 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2420 diskData
->PartitionOrdinal
,
2421 inputBuffer
->PartitionType
);
2423 if (NT_SUCCESS(status
)) {
2425 diskData
->PartitionType
= inputBuffer
->PartitionType
;
2431 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2434 // Return the partition layout for the physical drive. Note that
2435 // the layout is returned for the actual physical drive, regardless
2436 // of which partition was specified for the request.
2439 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2440 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2441 status
= STATUS_INFO_LENGTH_MISMATCH
;
2445 PDRIVE_LAYOUT_INFORMATION partitionList
;
2446 PDEVICE_EXTENSION physicalExtension
= deviceExtension
;
2447 PPARTITION_INFORMATION partitionEntry
;
2448 PDISK_DATA diskData
;
2453 // Read partition information.
2456 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
2457 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2461 if (!NT_SUCCESS(status
)) {
2466 // The disk layout has been returned in the partitionList
2467 // buffer. Determine its size and, if the data will fit
2468 // into the intermediary buffer, return it.
2471 tempSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,PartitionEntry
[0]);
2472 tempSize
+= partitionList
->PartitionCount
*
2473 sizeof(PARTITION_INFORMATION
);
2476 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
2478 status
= STATUS_BUFFER_TOO_SMALL
;
2479 ExFreePool(partitionList
);
2484 // Walk partition list to associate partition numbers with
2485 // partition entries.
2488 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
2491 // Walk partition chain anchored at physical disk extension.
2494 deviceExtension
= physicalExtension
;
2495 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2499 deviceExtension
= diskData
->NextPartition
;
2502 // Check if this is the last partition in the chain.
2505 if (!deviceExtension
) {
2510 // Get the partition device extension from disk data.
2513 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2516 // Check if this partition is not currently being used.
2519 if (!deviceExtension
->PartitionLength
.QuadPart
) {
2523 partitionEntry
= &partitionList
->PartitionEntry
[i
];
2526 // Check if empty, or describes extended partition or hasn't changed.
2529 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2530 IsContainerPartition(partitionEntry
->PartitionType
)) {
2535 // Check if new partition starts where this partition starts.
2538 if (partitionEntry
->StartingOffset
.QuadPart
!=
2539 deviceExtension
->StartingOffset
.QuadPart
) {
2544 // Check if partition length is the same.
2547 if (partitionEntry
->PartitionLength
.QuadPart
==
2548 deviceExtension
->PartitionLength
.QuadPart
) {
2551 // Partitions match. Update partition number.
2554 partitionEntry
->PartitionNumber
=
2555 diskData
->PartitionNumber
;
2563 // Copy partition information to system buffer.
2566 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2569 status
= STATUS_SUCCESS
;
2570 Irp
->IoStatus
.Information
= tempSize
;
2573 // Finally, free the buffer allocated by reading the
2577 ExFreePool(partitionList
);
2582 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
2587 // Update the disk with new partition information.
2590 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
2593 // Validate buffer length.
2596 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2597 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2599 status
= STATUS_INFO_LENGTH_MISMATCH
;
2603 length
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2604 (partitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
);
2607 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2610 status
= STATUS_BUFFER_TOO_SMALL
;
2615 // Verify that device object is for physical disk.
2618 if (deviceExtension
->PhysicalDevice
->DeviceExtension
!= deviceExtension
) {
2619 status
= STATUS_INVALID_PARAMETER
;
2624 // Walk through partition table comparing partitions to
2625 // existing partitions to create, delete and change
2626 // device objects as necessary.
2629 UpdateDeviceObjects(DeviceObject
,
2633 // Write changes to disk.
2636 status
= IoWritePartitionTable(
2637 deviceExtension
->DeviceObject
,
2638 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2639 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
,
2640 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
,
2645 // Update IRP with bytes returned.
2648 if (NT_SUCCESS(status
)) {
2649 Irp
->IoStatus
.Information
= length
;
2654 case IOCTL_DISK_REASSIGN_BLOCKS
:
2657 // Map defective blocks to new location on disk.
2662 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2668 // Validate buffer length.
2671 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2672 sizeof(REASSIGN_BLOCKS
)) {
2674 status
= STATUS_INFO_LENGTH_MISMATCH
;
2678 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2679 (badBlocks
->Count
- 1) * sizeof(ULONG
);
2681 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2684 status
= STATUS_INFO_LENGTH_MISMATCH
;
2689 // Build the data buffer to be transferred in the input buffer.
2690 // The format of the data to the device is:
2694 // x * 4 btyes Block Address
2696 // All values are big endian.
2699 badBlocks
->Reserved
= 0;
2700 blockCount
= badBlocks
->Count
;
2703 // Convert # of entries to # of bytes.
2707 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2708 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2711 // Convert back to number of entries.
2716 for (; blockCount
> 0; blockCount
--) {
2718 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2720 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2721 (PFOUR_BYTE
) &blockNumber
);
2726 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2729 // Set timeout value.
2732 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2734 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2740 Irp
->IoStatus
.Status
= status
;
2741 Irp
->IoStatus
.Information
= 0;
2743 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2748 case IOCTL_DISK_IS_WRITABLE
:
2751 // Determine if the device is writable.
2754 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
2756 if (modeData
== NULL
) {
2757 status
= STATUS_INSUFFICIENT_RESOURCES
;
2761 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
2763 length
= ScsiClassModeSense(DeviceObject
,
2766 MODE_SENSE_RETURN_ALL
);
2768 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2771 // Retry the request in case of a check condition.
2774 length
= ScsiClassModeSense(DeviceObject
,
2777 MODE_SENSE_RETURN_ALL
);
2779 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2780 status
= STATUS_IO_DEVICE_ERROR
;
2781 ExFreePool(modeData
);
2786 if (modeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
) {
2787 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2789 status
= STATUS_SUCCESS
;
2792 ExFreePool(modeData
);
2795 case IOCTL_DISK_INTERNAL_SET_VERIFY
:
2798 // If the caller is kernel mode, set the verify bit.
2801 if (Irp
->RequestorMode
== KernelMode
) {
2802 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2804 status
= STATUS_SUCCESS
;
2807 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
:
2810 // If the caller is kernel mode, clear the verify bit.
2813 if (Irp
->RequestorMode
== KernelMode
) {
2814 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
2816 status
= STATUS_SUCCESS
;
2819 case IOCTL_DISK_FIND_NEW_DEVICES
:
2822 // Search for devices that have been powered on since the last
2823 // device search or system initialization.
2826 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2827 status
= DriverEntry(DeviceObject
->DriverObject
,
2830 Irp
->IoStatus
.Status
= status
;
2832 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2835 case IOCTL_DISK_MEDIA_REMOVAL
:
2838 // If the disk is not removable then don't allow this command.
2841 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
2842 status
= STATUS_INVALID_DEVICE_REQUEST
;
2847 // Fall through and let the class driver process the request.
2850 case IOCTL_DISK_GET_LENGTH_INFO
:
2853 // Validate buffer length.
2856 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2857 sizeof(GET_LENGTH_INFORMATION
)) {
2858 status
= STATUS_BUFFER_TOO_SMALL
;
2862 PGET_LENGTH_INFORMATION lengthInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
2865 // Update the geometry in case it has changed.
2868 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2870 if (!NT_SUCCESS(status
)) {
2873 // Note the drive is not ready.
2876 diskData
->DriveNotReady
= TRUE
;
2881 // Note the drive is now ready.
2884 diskData
->DriveNotReady
= FALSE
;
2887 // Output data, and return
2890 lengthInformation
->Length
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2891 status
= STATUS_SUCCESS
;
2892 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2900 // Free the Srb, since it is not needed.
2906 // Pass the request to the common device control routine.
2909 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
2913 } // end switch( ...
2915 Irp
->IoStatus
.Status
= status
;
2917 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2919 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2922 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2926 } // end ScsiDiskDeviceControl()
2930 ScsiDiskShutdownFlush (
2931 IN PDEVICE_OBJECT DeviceObject
,
2937 Routine Description:
2939 This routine is called for a shutdown and flush IRPs. These are sent by the
2940 system before it actually shuts down or when the file system does a flush.
2941 A synchronize cache command is sent to the device if it is write caching.
2942 If the device is removable an unlock command will be sent. This routine
2943 will sent a shutdown or flush Srb to the port driver.
2947 DriverObject - Pointer to device object to being shutdown by system.
2958 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2959 PIO_STACK_LOCATION irpStack
;
2960 PSCSI_REQUEST_BLOCK srb
;
2965 // Allocate SCSI request block.
2968 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
2973 // Set the status and complete the request.
2976 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2977 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2978 return(STATUS_INSUFFICIENT_RESOURCES
);
2981 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
2984 // Write length to SRB.
2987 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2990 // Set SCSI bus address.
2993 srb
->PathId
= deviceExtension
->PathId
;
2994 srb
->TargetId
= deviceExtension
->TargetId
;
2995 srb
->Lun
= deviceExtension
->Lun
;
2998 // Set timeout value and mark the request as not being a tagged request.
3001 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 4;
3002 srb
->QueueTag
= SP_UNTAGGED
;
3003 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3004 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3007 // If the write cache is enabled then send a synchronize cache request.
3010 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3012 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3013 srb
->CdbLength
= 10;
3015 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
3017 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3023 DebugPrint((1, "ScsiDiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status
));
3027 // Unlock the device if it is removable and this is a shutdown.
3030 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3032 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
3033 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
3036 cdb
= (PVOID
) srb
->Cdb
;
3037 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3038 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3041 // Set timeout value.
3044 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3045 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3051 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3057 // Save a few parameters in the current stack location.
3060 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3061 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3064 // Set the retry count to zero.
3067 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3070 // Set up IoCompletion routine address.
3073 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3076 // Get next stack location and
3077 // set major function code.
3080 irpStack
= IoGetNextIrpStackLocation(Irp
);
3082 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3085 // Set up SRB for execute scsi request.
3086 // Save SRB address in next stack for port driver.
3089 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3092 // Set up Irp Address.
3095 srb
->OriginalRequest
= Irp
;
3098 // Call the port driver to process the request.
3101 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3103 } // end ScsiDiskShutdown()
3109 PDEVICE_OBJECT DeviceObject
3113 Routine Description:
3115 The routine performs the necessary functions to determine if a device is
3116 really a floppy rather than a harddisk. This is done by a mode sense
3117 command. First, a check is made to see if the media type is set. Second
3118 a check is made for the flexible parameters mode page. Also a check is
3119 made to see if the write cache is enabled.
3123 DeviceObject - Supplies the device object to be tested.
3127 Return TRUE if the indicated device is a floppy.
3131 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3138 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3140 if (modeData
== NULL
) {
3144 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3146 length
= ScsiClassModeSense(DeviceObject
,
3149 MODE_SENSE_RETURN_ALL
);
3151 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3154 // Retry the request in case of a check condition.
3157 length
= ScsiClassModeSense(DeviceObject
,
3160 MODE_SENSE_RETURN_ALL
);
3162 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3164 ExFreePool(modeData
);
3171 // If the length is greater than length indicated by the mode data reset
3172 // the data to the mode data.
3175 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3176 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3180 // Look for the flexible disk mode page.
3183 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_FLEXIBILE
, TRUE
);
3185 if (pageData
!= NULL
) {
3187 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3188 ExFreePool(modeData
);
3193 // Check to see if the write cache is enabled.
3196 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3199 // Assume that write cache is disabled or not supported.
3202 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3205 // Check if valid caching page exists.
3208 if (pageData
!= NULL
) {
3211 // Check if write cache is disabled.
3214 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3217 "SCSIDISK: Disk write cache enabled\n"));
3220 // Check if forced unit access (FUA) is supported.
3223 if (((PMODE_PARAMETER_HEADER
)modeData
)->DeviceSpecificParameter
& MODE_DSP_FUA_SUPPORTED
) {
3225 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3230 "SCSIDISK: Disk does not support FUA or DPO\n"));
3240 ExFreePool(modeData
);
3243 } // end IsFloppyDevice()
3249 IN PDEVICE_OBJECT DeviceObject
,
3250 IN PCHAR ModeSelectBuffer
,
3257 Routine Description:
3259 This routine sends a mode select command.
3263 DeviceObject - Supplies the device object associated with this request.
3265 ModeSelectBuffer - Supplies a buffer containing the page data.
3267 Length - Supplies the length in bytes of the mode select buffer.
3269 SavePage - Indicates that parameters should be written to disk.
3273 Length of the transferred data is returned.
3277 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3279 SCSI_REQUEST_BLOCK srb
;
3284 PMODE_PARAMETER_BLOCK blockDescriptor
;
3288 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3291 // Allocate buffer for mode select header, block descriptor, and mode page.
3294 buffer
= (ULONG_PTR
)ExAllocatePool(NonPagedPoolCacheAligned
,length2
);
3296 RtlZeroMemory((PVOID
)buffer
, length2
);
3299 // Set length in header to size of mode page.
3302 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3304 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3310 blockDescriptor
->BlockLength
[1]=0x02;
3313 // Copy mode page to buffer.
3316 RtlCopyMemory((PVOID
)(buffer
+ 3), ModeSelectBuffer
, Length
);
3322 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3325 // Build the MODE SELECT CDB.
3329 cdb
= (PCDB
)srb
.Cdb
;
3332 // Set timeout value from device extension.
3335 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
3337 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3338 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3339 cdb
->MODE_SELECT
.PFBit
= 1;
3340 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3344 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3351 if (status
== STATUS_VERIFY_REQUIRED
) {
3354 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3367 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3368 status
= STATUS_SUCCESS
;
3371 ExFreePool((PVOID
)buffer
);
3373 if (NT_SUCCESS(status
)) {
3379 } // end SciDiskModeSelect()
3385 IN PDEVICE_OBJECT DeviceObject
,
3386 IN PSCSI_INQUIRY_DATA LunInfo
3390 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3391 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3392 BAD_CONTROLLER_INFORMATION
const *controller
;
3397 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
3399 controller
= &ScsiDiskBadControllers
[j
];
3401 if (!controller
->DisableWriteCache
|| strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
3405 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller
->InquiryString
));
3407 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3409 if (modeData
== NULL
) {
3412 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3416 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3418 length
= ScsiClassModeSense(DeviceObject
,
3421 MODE_SENSE_RETURN_ALL
);
3423 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3426 // Retry the request in case of a check condition.
3429 length
= ScsiClassModeSense(DeviceObject
,
3432 MODE_SENSE_RETURN_ALL
);
3434 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3438 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3440 ExFreePool(modeData
);
3447 // If the length is greater than length indicated by the mode data reset
3448 // the data to the mode data.
3451 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3452 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3456 // Check to see if the write cache is enabled.
3459 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3462 // Assume that write cache is disabled or not supported.
3465 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3468 // Check if valid caching page exists.
3471 if (pageData
!= NULL
) {
3473 BOOLEAN savePage
= FALSE
;
3475 savePage
= (BOOLEAN
)(((PMODE_CACHING_PAGE
)pageData
)->PageSavable
);
3478 // Check if write cache is disabled.
3481 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3483 PIO_ERROR_LOG_PACKET errorLogEntry
;
3488 // Disable write cache and ensure necessary fields are zeroed.
3491 ((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
= FALSE
;
3492 ((PMODE_CACHING_PAGE
)pageData
)->Reserved
= 0;
3493 ((PMODE_CACHING_PAGE
)pageData
)->PageSavable
= 0;
3494 ((PMODE_CACHING_PAGE
)pageData
)->Reserved2
= 0;
3497 // Extract length from caching page.
3500 length
= ((PMODE_CACHING_PAGE
)pageData
)->PageLength
;
3503 // Compensate for page code and page length.
3509 // Issue mode select to set the parameter.
3512 if (ScsiDiskModeSelect(DeviceObject
,
3518 "SCSIDISK: Disk write cache disabled\n"));
3520 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3521 errorCode
= IO_WRITE_CACHE_DISABLED
;
3524 if (ScsiDiskModeSelect(DeviceObject
,
3530 "SCSIDISK: Disk write cache disabled\n"));
3533 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3534 errorCode
= IO_WRITE_CACHE_DISABLED
;
3539 "SCSIDISK: Mode select to disable write cache failed\n"));
3541 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3542 errorCode
= IO_WRITE_CACHE_ENABLED
;
3547 // Log the appropriate informational or error entry.
3550 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3552 sizeof(IO_ERROR_LOG_PACKET
) + 3
3555 if (errorLogEntry
!= NULL
) {
3557 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3558 errorLogEntry
->ErrorCode
= errorCode
;
3559 errorLogEntry
->SequenceNumber
= 0;
3560 errorLogEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
3561 errorLogEntry
->IoControlCode
= 0;
3562 errorLogEntry
->RetryCount
= 0;
3563 errorLogEntry
->UniqueErrorValue
= 0x1;
3564 errorLogEntry
->DumpDataSize
= 3 * sizeof(ULONG
);
3565 errorLogEntry
->DumpData
[0] = LunInfo
->PathId
;
3566 errorLogEntry
->DumpData
[1] = LunInfo
->TargetId
;
3567 errorLogEntry
->DumpData
[2] = LunInfo
->Lun
;
3570 // Write the error log packet.
3573 IoWriteErrorLogEntry(errorLogEntry
);
3579 // Found device so exit the loop and return.
3591 CalculateMbrCheckSum(
3592 IN PDEVICE_EXTENSION DeviceExtension
,
3598 Routine Description:
3600 Read MBR and calculate checksum.
3604 DeviceExtension - Supplies a pointer to the device information for disk.
3605 Checksum - Memory location to return MBR checksum.
3609 Returns TRUE if checksum is valid.
3613 LARGE_INTEGER sectorZero
;
3615 IO_STATUS_BLOCK ioStatus
;
3623 sectorZero
.QuadPart
= (LONGLONG
) 0;
3626 // Create notification event object to be used to signal the inquiry
3627 // request completion.
3630 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
3636 sectorSize
= DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
3639 // Make sure sector size is at least 512 bytes.
3642 if (sectorSize
< 512) {
3647 // Allocate buffer for sector read.
3650 mbr
= ExAllocatePool(NonPagedPoolCacheAligned
, sectorSize
);
3657 // Build IRP to read MBR.
3660 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
3661 DeviceExtension
->DeviceObject
,
3674 // Pass request to port driver and wait for request to complete.
3677 status
= IoCallDriver(DeviceExtension
->DeviceObject
,
3680 if (status
== STATUS_PENDING
) {
3681 KeWaitForSingleObject(&event
,
3686 status
= ioStatus
.Status
;
3689 if (!NT_SUCCESS(status
)) {
3695 // Calculate MBR checksum.
3700 for (i
= 0; i
< 128; i
++) {
3701 *Checksum
+= mbr
[i
];
3704 *Checksum
= ~*Checksum
+ 1;
3714 IN PDEVICE_EXTENSION DeviceExtension
,
3721 Routine Description:
3723 The routine queries the registry to determine if this disk is visible to
3724 the BIOS. If the disk is visible to the BIOS, then the geometry information
3729 DeviceExtension - Supplies a pointer to the device information for disk.
3730 Signature - Unique identifier recorded in MBR.
3731 BusKey - Handle of bus key.
3732 DiskNumber - Returns ordinal of disk as BIOS sees it.
3736 TRUE is disk signature matched.
3740 PDISK_DATA diskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
3741 BOOLEAN diskFound
= FALSE
;
3742 OBJECT_ATTRIBUTES objectAttributes
;
3743 UNICODE_STRING unicodeString
;
3744 UNICODE_STRING identifier
;
3746 ULONG adapterNumber
;
3754 STRING anotherString
;
3757 PKEY_VALUE_FULL_INFORMATION keyData
;
3761 for (busNumber
= 0; ; busNumber
++) {
3764 // Open controller name key.
3767 sprintf((PCHAR
)buffer
,
3771 RtlInitString(&string
,
3774 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3778 if (!NT_SUCCESS(status
)){
3782 InitializeObjectAttributes(&objectAttributes
,
3784 OBJ_CASE_INSENSITIVE
,
3786 (PSECURITY_DESCRIPTOR
)NULL
);
3788 status
= ZwOpenKey(&spareKey
,
3792 RtlFreeUnicodeString(&unicodeString
);
3794 if (!NT_SUCCESS(status
)) {
3799 // Open up controller ordinal key.
3802 RtlInitUnicodeString(&unicodeString
, L
"DiskController");
3803 InitializeObjectAttributes(&objectAttributes
,
3805 OBJ_CASE_INSENSITIVE
,
3807 (PSECURITY_DESCRIPTOR
)NULL
);
3809 status
= ZwOpenKey(&adapterKey
,
3814 // This could fail even with additional adapters of this type
3818 if (!NT_SUCCESS(status
)) {
3822 for (adapterNumber
= 0; ; adapterNumber
++) {
3828 sprintf((PCHAR
)buffer
,
3829 "%lu\\DiskPeripheral",
3832 RtlInitString(&string
,
3835 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3839 if (!NT_SUCCESS(status
)){
3843 InitializeObjectAttributes(&objectAttributes
,
3845 OBJ_CASE_INSENSITIVE
,
3847 (PSECURITY_DESCRIPTOR
)NULL
);
3849 status
= ZwOpenKey(&diskKey
,
3853 RtlFreeUnicodeString(&unicodeString
);
3855 if (!NT_SUCCESS(status
)) {
3859 for (diskNumber
= 0; ; diskNumber
++) {
3861 sprintf((PCHAR
)buffer
,
3865 RtlInitString(&string
,
3868 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3872 if (!NT_SUCCESS(status
)){
3876 InitializeObjectAttributes(&objectAttributes
,
3878 OBJ_CASE_INSENSITIVE
,
3880 (PSECURITY_DESCRIPTOR
)NULL
);
3882 status
= ZwOpenKey(&targetKey
,
3886 RtlFreeUnicodeString(&unicodeString
);
3888 if (!NT_SUCCESS(status
)) {
3893 // Allocate buffer for registry query.
3896 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
3898 if (keyData
== NULL
) {
3904 // Get disk peripheral identifier.
3907 RtlInitUnicodeString(&unicodeString
, L
"Identifier");
3908 status
= ZwQueryValueKey(targetKey
,
3910 KeyValueFullInformation
,
3917 if (!NT_SUCCESS(status
)) {
3922 // Complete unicode string.
3926 (PWSTR
)((PUCHAR
)keyData
+ keyData
->DataOffset
);
3927 identifier
.Length
= (USHORT
)keyData
->DataLength
;
3928 identifier
.MaximumLength
= (USHORT
)keyData
->DataLength
;
3931 // Convert unicode identifier to ansi string.
3935 RtlUnicodeStringToAnsiString(&anotherString
,
3939 if (!NT_SUCCESS(status
)) {
3944 // If checksum is zero, then the MBR is valid and
3945 // the signature is meaningful.
3948 if (diskData
->MbrCheckSum
) {
3951 // Convert checksum to ansi string.
3954 sprintf((PCHAR
)buffer
, "%08lx", diskData
->MbrCheckSum
);
3959 // Convert signature to ansi string.
3962 sprintf((PCHAR
)buffer
, "%08lx", diskData
->Signature
);
3965 // Make string point at signature. Can't use scan
3966 // functions because they are not exported for driver use.
3969 anotherString
.Buffer
+=9;
3973 // Convert to ansi string.
3976 RtlInitString(&string
,
3981 // Make string lengths equal.
3984 anotherString
.Length
= string
.Length
;
3987 // Check if strings match.
3990 if (RtlCompareString(&string
,
3995 *DiskNumber
= diskNumber
;
3998 ExFreePool(keyData
);
4001 // Readjust identifier string if necessary.
4004 if (!diskData
->MbrCheckSum
) {
4005 anotherString
.Buffer
-=9;
4008 RtlFreeAnsiString(&anotherString
);
4018 ZwClose(adapterKey
);
4024 } // end EnumerateBusKey()
4030 IN PDEVICE_EXTENSION DeviceExtension
4034 Routine Description:
4036 The routine queries the registry to determine if this disk is visible to
4037 the BIOS. If the disk is visible to the BIOS, then the geometry information
4042 DeviceExtension - Supplies a pointer to the device information for disk.
4051 OBJECT_ATTRIBUTES objectAttributes
;
4052 UNICODE_STRING unicodeString
;
4056 PCM_INT13_DRIVE_PARAMETER driveParameters
;
4057 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor
;
4058 PKEY_VALUE_FULL_INFORMATION keyData
;
4062 ULONG numberOfDrives
;
4065 ULONG sectorsPerTrack
;
4066 ULONG tracksPerCylinder
;
4067 BOOLEAN foundEZHooker
;
4073 // Initialize the object for the key.
4076 InitializeObjectAttributes(&objectAttributes
,
4077 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
4078 OBJ_CASE_INSENSITIVE
,
4080 (PSECURITY_DESCRIPTOR
) NULL
);
4083 // Create the hardware base key.
4086 status
= ZwOpenKey(&hardwareKey
,
4091 if (!NT_SUCCESS(status
)) {
4092 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
));
4098 // Get disk BIOS geometry information.
4101 RtlInitUnicodeString(&unicodeString
, L
"Configuration Data");
4103 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
4105 if (keyData
== NULL
) {
4106 ZwClose(hardwareKey
);
4110 status
= ZwQueryValueKey(hardwareKey
,
4112 KeyValueFullInformation
,
4117 if (!NT_SUCCESS(status
)) {
4119 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4121 ExFreePool(keyData
);
4126 // Open EISA bus key.
4129 RtlInitUnicodeString(&unicodeString
, L
"EisaAdapter");
4131 InitializeObjectAttributes(&objectAttributes
,
4133 OBJ_CASE_INSENSITIVE
,
4135 (PSECURITY_DESCRIPTOR
)NULL
);
4137 status
= ZwOpenKey(&busKey
,
4141 if (!NT_SUCCESS(status
)) {
4146 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4147 if (EnumerateBusKey(DeviceExtension
,
4151 ZwClose(hardwareKey
);
4158 // Open Multifunction bus key.
4161 RtlInitUnicodeString(&unicodeString
, L
"MultifunctionAdapter");
4163 InitializeObjectAttributes(&objectAttributes
,
4165 OBJ_CASE_INSENSITIVE
,
4167 (PSECURITY_DESCRIPTOR
)NULL
);
4169 status
= ZwOpenKey(&busKey
,
4173 ZwClose(hardwareKey
);
4174 if (NT_SUCCESS(status
)) {
4176 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4177 if (EnumerateBusKey(DeviceExtension
,
4185 ExFreePool(keyData
);
4190 resourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PUCHAR
)keyData
+
4191 keyData
->DataOffset
);
4194 // Check that the data is long enough to hold a full resource descriptor,
4195 // and that the last resource list is device-specific and long enough.
4198 if (keyData
->DataLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) ||
4199 resourceDescriptor
->PartialResourceList
.Count
== 0 ||
4200 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].Type
!=
4201 CmResourceTypeDeviceSpecific
||
4202 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0]
4203 .u
.DeviceSpecificData
.DataSize
< sizeof(ULONG
)) {
4205 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4206 ExFreePool(keyData
);
4211 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
;
4214 // Point to the BIOS data. The BIOS data is located after the first
4215 // partial Resource list which should be device specific data.
4218 buffer
= (PUCHAR
) keyData
+ keyData
->DataOffset
+
4219 sizeof(CM_FULL_RESOURCE_DESCRIPTOR
);
4222 numberOfDrives
= length
/ sizeof(CM_INT13_DRIVE_PARAMETER
);
4225 // Use the defaults if the drive number is greater than the
4226 // number of drives detected by the BIOS.
4229 if (numberOfDrives
<= diskNumber
) {
4230 ExFreePool(keyData
);
4235 // Point to the array of drive parameters.
4238 driveParameters
= (PCM_INT13_DRIVE_PARAMETER
) buffer
+ diskNumber
;
4239 cylinders
= driveParameters
->MaxCylinders
+ 1;
4240 sectorsPerTrack
= driveParameters
->SectorsPerTrack
;
4241 tracksPerCylinder
= driveParameters
->MaxHeads
+1;
4244 // Calculate the actual number of sectors.
4247 sectors
= (ULONG
)(DeviceExtension
->PartitionLength
.QuadPart
>>
4248 DeviceExtension
->SectorShift
);
4251 if (sectors
>= cylinders
* tracksPerCylinder
* sectorsPerTrack
) {
4252 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4253 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4254 sectors
, cylinders
, tracksPerCylinder
, sectorsPerTrack
));
4259 // Since the BIOS may not report the full drive, recalculate the drive
4260 // size based on the volume size and the BIOS values for tracks per
4261 // cylinder and sectors per track..
4264 length
= tracksPerCylinder
* sectorsPerTrack
;
4269 // The BIOS information is bogus.
4272 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4273 ExFreePool(keyData
);
4277 cylinders
= sectors
/ length
;
4280 // Update the actual geometry information.
4283 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= sectorsPerTrack
;
4284 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
;
4285 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)cylinders
;
4286 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= (LONGLONG
)cylinders
* tracksPerCylinder
* sectorsPerTrack
*
4287 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4290 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4295 ExFreePool(keyData
);
4297 foundEZHooker
= FALSE
;
4299 if (!DeviceExtension
->DMActive
) {
4301 HalExamineMBR(DeviceExtension
->DeviceObject
,
4302 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4310 foundEZHooker
= TRUE
;
4316 if (DeviceExtension
->DMActive
|| foundEZHooker
) {
4318 while (cylinders
> 1024) {
4320 tracksPerCylinder
= tracksPerCylinder
*2;
4321 cylinders
= cylinders
/2;
4326 // int 13 values are always 1 less.
4329 tracksPerCylinder
-= 1;
4333 // DM reserves the CE cylinder
4338 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= cylinders
+ 1;
4339 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
+ 1;
4341 DeviceExtension
->PartitionLength
.QuadPart
=
4342 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
=
4343 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
*
4344 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
*
4345 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
*
4346 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
;
4348 if (DeviceExtension
->DMActive
) {
4350 DeviceExtension
->DMByteSkew
= DeviceExtension
->DMSkew
* DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4356 DeviceExtension
->DMByteSkew
= 0;
4362 } // end UpdateGeometry()
4368 UpdateRemovableGeometry (
4369 IN PDEVICE_OBJECT DeviceObject
,
4375 Routine Description:
4377 This routines updates the size and starting offset of the device. This is
4378 used when the media on the device may have changed thereby changing the
4379 size of the device. If this is the physical device then a
4380 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4384 DeviceObject - Supplies the device object whos size needs to be updated.
4386 Irp - Supplies a reference where the status can be updated.
4390 Returns the status of the operation.
4395 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4396 PDRIVE_LAYOUT_INFORMATION partitionList
;
4398 PDISK_DATA diskData
;
4399 ULONG partitionNumber
;
4402 // Determine if the size of the partition may have changed because
4403 // the media has changed.
4406 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
4408 return(STATUS_SUCCESS
);
4413 // If this request is for partition zero then do a read drive
4414 // capacity otherwise do a I/O read partition table.
4417 diskData
= (PDISK_DATA
) (deviceExtension
+ 1);
4420 // Read the drive capacity. If that fails, give up.
4423 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
4425 if (!NT_SUCCESS(status
)) {
4430 // Read the partition table again.
4433 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
4434 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4439 if (!NT_SUCCESS(status
)) {
4442 // Fail the request.
4448 if (diskData
->PartitionNumber
!= 0 &&
4449 diskData
->PartitionNumber
<= partitionList
->PartitionCount
) {
4451 partitionNumber
= diskData
->PartitionNumber
- 1;
4454 // Update the partition information for this partition.
4457 diskData
->PartitionType
=
4458 partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
4460 diskData
->BootIndicator
=
4461 partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
4463 deviceExtension
->StartingOffset
=
4464 partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
4466 deviceExtension
->PartitionLength
=
4467 partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
4469 diskData
->HiddenSectors
=
4470 partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
4472 deviceExtension
->SectorShift
= ((PDEVICE_EXTENSION
)
4473 deviceExtension
->PhysicalDevice
->DeviceExtension
)->SectorShift
;
4475 } else if (diskData
->PartitionNumber
!= 0) {
4478 // The partition does not exist. Zero all the data.
4481 diskData
->PartitionType
= 0;
4482 diskData
->BootIndicator
= 0;
4483 diskData
->HiddenSectors
= 0;
4484 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)0;
4485 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)0;
4489 // Free the partition list allocate by I/O read partition table.
4492 ExFreePool(partitionList
);
4495 return(STATUS_SUCCESS
);
4501 ScsiDiskProcessError(
4502 PDEVICE_OBJECT DeviceObject
,
4503 PSCSI_REQUEST_BLOCK Srb
,
4509 Routine Description:
4511 This routine checks the type of error. If the error indicates an underrun
4512 then indicate the request should be retried.
4516 DeviceObject - Supplies a pointer to the device object.
4518 Srb - Supplies a pointer to the failing Srb.
4520 Status - Status with which the IRP will be completed.
4522 Retry - Indication of whether the request will be retried.
4531 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4533 if (*Status
== STATUS_DATA_OVERRUN
&&
4534 ( Srb
->Cdb
[0] == SCSIOP_WRITE
|| Srb
->Cdb
[0] == SCSIOP_READ
)) {
4539 // Update the error count for the device.
4542 deviceExtension
->ErrorCount
++;
4545 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
4546 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
4549 // The disk drive should never be busy this long. Reset the scsi bus
4550 // maybe this will clear the condition.
4553 ResetScsiBus(DeviceObject
);
4556 // Update the error count for the device.
4559 deviceExtension
->ErrorCount
++;
4566 PDEVICE_OBJECT DeviceObject
,
4567 PSCSI_INQUIRY_DATA LunInfo
,
4568 PIO_SCSI_CAPABILITIES PortCapabilities
4573 Routine Description:
4575 This function checks to see if an SCSI logical unit requires special
4580 DeviceObject - Supplies the device object to be tested.
4582 InquiryData - Supplies the inquiry data returned by the device of interest.
4584 PortCapabilities - Supplies the capabilities of the device object.
4593 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4594 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
4595 BAD_CONTROLLER_INFORMATION
const *controller
;
4598 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
4600 controller
= &ScsiDiskBadControllers
[j
];
4602 if (strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
4606 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller
->InquiryString
));
4609 // Found a listed controller. Determine what must be done.
4612 if (controller
->DisableTaggedQueuing
) {
4615 // Disable tagged queuing.
4618 deviceExtension
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
4621 if (controller
->DisableSynchronousTransfers
) {
4624 // Disable synchronous data transfers.
4627 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4631 if (controller
->DisableDisconnects
) {
4634 // Disable disconnects.
4637 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
4642 // Found device so exit the loop and return.
4649 // Set the StartUnit flag appropriately.
4652 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) {
4653 deviceExtension
->DeviceFlags
|= DEV_SAFE_START_UNIT
;
4655 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
4656 if (_strnicmp((PCCHAR
)InquiryData
->VendorId
, "iomega", strlen("iomega"))) {
4657 deviceExtension
->DeviceFlags
&= ~DEV_SAFE_START_UNIT
;
4668 IN PDEVICE_OBJECT DeviceObject
4673 Routine Description:
4675 This command sends a reset bus command to the SCSI port driver.
4679 DeviceObject - The device object for the logical unit with
4688 PIO_STACK_LOCATION irpStack
;
4690 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4691 PSCSI_REQUEST_BLOCK srb
;
4692 PCOMPLETION_CONTEXT context
;
4694 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4697 // Allocate Srb from nonpaged pool.
4700 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
4701 sizeof(COMPLETION_CONTEXT
));
4704 // Save the device object in the context for use by the completion
4708 context
->DeviceObject
= DeviceObject
;
4709 srb
= &context
->Srb
;
4715 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4718 // Write length to SRB.
4721 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4724 // Set up SCSI bus address.
4727 srb
->PathId
= deviceExtension
->PathId
;
4728 srb
->TargetId
= deviceExtension
->TargetId
;
4729 srb
->Lun
= deviceExtension
->Lun
;
4731 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4734 // Build the asynchronous request to be sent to the port driver.
4735 // Since this routine is called from a DPC the IRP should always be
4739 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
4741 IoSetCompletionRoutine(irp
,
4742 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
4748 irpStack
= IoGetNextIrpStackLocation(irp
);
4750 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4752 srb
->OriginalRequest
= irp
;
4755 // Store the SRB address in next stack for port driver.
4758 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4761 // Call the port driver with the IRP.
4764 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
4768 } // end ResetScsiBus()
4773 UpdateDeviceObjects(
4774 IN PDEVICE_OBJECT PhysicalDisk
,
4780 Routine Description:
4782 This routine creates, deletes and changes device objects when
4783 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4784 the drive layout information for the user. It is possible to
4785 call this routine even in the GET_LAYOUT case because RewritePartition
4790 DeviceObject - Device object for physical disk.
4791 Irp - IO Request Packet (IRP).
4799 PDEVICE_EXTENSION physicalExtension
= PhysicalDisk
->DeviceExtension
;
4800 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
4802 ULONG partitionNumber
;
4803 ULONG partitionCount
;
4804 ULONG lastPartition
;
4805 ULONG partitionOrdinal
;
4806 PPARTITION_INFORMATION partitionEntry
;
4807 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
4808 STRING ntNameString
;
4809 UNICODE_STRING ntUnicodeString
;
4810 PDEVICE_OBJECT deviceObject
;
4811 PDEVICE_EXTENSION deviceExtension
;
4812 PDISK_DATA diskData
;
4814 ULONG numberListElements
;
4817 partitionCount
= ((partitionList
->PartitionCount
+ 3) / 4) * 4;
4820 // Zero all of the partition numbers.
4823 for (partition
= 0; partition
< partitionCount
; partition
++) {
4824 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4825 partitionEntry
->PartitionNumber
= 0;
4829 // Walk through chain of partitions for this disk to determine
4830 // which existing partitions have no match.
4833 deviceExtension
= physicalExtension
;
4834 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4839 deviceExtension
= diskData
->NextPartition
;
4842 // Check if this is the last partition in the chain.
4845 if (!deviceExtension
) {
4850 // Get the partition device extension from disk data.
4853 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4856 // Check for highest partition number this far.
4859 if (diskData
->PartitionNumber
> lastPartition
) {
4860 lastPartition
= diskData
->PartitionNumber
;
4864 // Check if this partition is not currently being used.
4867 if (!deviceExtension
->PartitionLength
.QuadPart
) {
4872 // Loop through partition information to look for match.
4876 partitionOrdinal
= 0;
4878 for (partition
= 0; partition
< partitionCount
; partition
++) {
4881 // Get partition descriptor.
4884 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4887 // Check if empty, or describes extended partition or hasn't changed.
4890 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4891 IsContainerPartition(partitionEntry
->PartitionType
)) {
4896 // Advance partition ordinal.
4902 // Check if new partition starts where this partition starts.
4905 if (partitionEntry
->StartingOffset
.QuadPart
!=
4906 deviceExtension
->StartingOffset
.QuadPart
) {
4911 // Check if partition length is the same.
4914 if (partitionEntry
->PartitionLength
.QuadPart
==
4915 deviceExtension
->PartitionLength
.QuadPart
) {
4918 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4919 physicalExtension
->DeviceNumber
,
4920 diskData
->PartitionNumber
));
4923 // Indicate match is found and set partition number
4928 partitionEntry
->PartitionNumber
= diskData
->PartitionNumber
;
4936 // A match is found.
4939 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4942 // If this partition is marked for update then update partition type.
4945 if (partitionEntry
->RewritePartition
) {
4946 diskData
->PartitionType
= partitionEntry
->PartitionType
;
4950 // Update partitional ordinal for calls to HAL routine
4951 // IoSetPartitionInformation.
4954 diskData
->PartitionOrdinal
= partitionOrdinal
;
4957 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4958 physicalExtension
->DeviceNumber
,
4959 diskData
->PartitionOrdinal
,
4960 diskData
->PartitionNumber
));
4965 // no match was found, indicate this partition is gone.
4969 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4970 physicalExtension
->DeviceNumber
,
4971 diskData
->PartitionNumber
));
4973 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
4979 // Walk through partition loop to find new partitions and set up
4980 // device extensions to describe them. In some cases new device
4981 // objects will be created.
4984 partitionOrdinal
= 0;
4987 partition
< partitionCount
;
4991 // Get partition descriptor.
4994 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4997 // Check if empty, or describes an extended partition.
5000 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
5001 IsContainerPartition(partitionEntry
->PartitionType
)) {
5006 // Keep track of position on the disk for calls to IoSetPartitionInformation.
5012 // Check if this entry should be rewritten.
5015 if (!partitionEntry
->RewritePartition
) {
5019 if (partitionEntry
->PartitionNumber
) {
5022 // Partition is an exact match with an existing partition, but is
5023 // being written anyway.
5030 // Check first if existing device object is available by
5031 // walking partition extension list.
5034 partitionNumber
= 0;
5035 deviceExtension
= physicalExtension
;
5036 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5041 // Get next partition device extension from disk data.
5044 deviceExtension
= diskData
->NextPartition
;
5046 if (!deviceExtension
) {
5050 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5053 // A device object is free if the partition length is set to zero.
5056 if (!deviceExtension
->PartitionLength
.QuadPart
) {
5057 partitionNumber
= diskData
->PartitionNumber
;
5064 // If partition number is still zero then a new device object
5068 if (partitionNumber
== 0) {
5071 partitionNumber
= lastPartition
;
5074 // Get or create partition object and set up partition parameters.
5077 sprintf(ntNameBuffer
,
5078 "\\Device\\Harddisk%lu\\Partition%lu",
5079 physicalExtension
->DeviceNumber
,
5082 RtlInitString(&ntNameString
,
5085 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
5089 if (!NT_SUCCESS(status
)) {
5094 "UpdateDeviceObjects: Create device object %s\n",
5098 // This is a new name. Create the device object to represent it.
5101 status
= IoCreateDevice(PhysicalDisk
->DriverObject
,
5102 DEVICE_EXTENSION_SIZE
,
5109 if (!NT_SUCCESS(status
)) {
5111 "UpdateDeviceObjects: Can't create device %s\n",
5113 RtlFreeUnicodeString(&ntUnicodeString
);
5118 // Set up device object fields.
5121 deviceObject
->Flags
|= DO_DIRECT_IO
;
5122 deviceObject
->StackSize
= PhysicalDisk
->StackSize
;
5125 // Set up device extension fields.
5128 deviceExtension
= deviceObject
->DeviceExtension
;
5131 // Copy physical disk extension to partition extension.
5134 RtlMoveMemory(deviceExtension
,
5136 sizeof(DEVICE_EXTENSION
));
5139 // Initialize the new S-List.
5142 if (deviceExtension
->SrbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
5143 numberListElements
= 30;
5145 numberListElements
= 8;
5149 // Build the lookaside list for srb's for this partition based on
5150 // whether the adapter and disk can do tagged queueing.
5153 ScsiClassInitializeSrbLookasideList(deviceExtension
,
5154 numberListElements
);
5157 // Allocate spinlock for zoning for split-request completion.
5160 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
5163 // Write back partition number used in creating object name.
5166 partitionEntry
->PartitionNumber
= partitionNumber
;
5169 // Clear flags initializing bit.
5172 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
5175 // Point back at device object.
5178 deviceExtension
->DeviceObject
= deviceObject
;
5180 RtlFreeUnicodeString(&ntUnicodeString
);
5183 // Link to end of partition chain using previous disk data.
5186 diskData
->NextPartition
= deviceExtension
;
5189 // Get new disk data and zero next partition pointer.
5192 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5193 diskData
->NextPartition
= NULL
;
5198 // Set pointer to disk data area that follows device extension.
5201 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5204 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5205 physicalExtension
->DeviceNumber
,
5210 // Update partition information in partition device extension.
5213 diskData
->PartitionNumber
= partitionNumber
;
5214 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5215 diskData
->BootIndicator
= partitionEntry
->BootIndicator
;
5216 deviceExtension
->StartingOffset
= partitionEntry
->StartingOffset
;
5217 deviceExtension
->PartitionLength
= partitionEntry
->PartitionLength
;
5218 diskData
->HiddenSectors
= partitionEntry
->HiddenSectors
;
5219 diskData
->PartitionOrdinal
= partitionOrdinal
;
5222 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5223 diskData
->PartitionOrdinal
,
5224 diskData
->PartitionNumber
));
5227 // Update partition number passed in to indicate the
5228 // device name for this partition.
5231 partitionEntry
->PartitionNumber
= partitionNumber
;
5234 } // end UpdateDeviceObjects()