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 parition 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 - inidicates that the this device is currenly 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 identfing 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.
509 adapterInfo
= (PVOID
) buffer
;
511 adapterDisk
= ScsiClassFindUnclaimedDevices(InitializationData
, adapterInfo
);
514 // Allocate a zone of SRB for disks on this adapter.
517 if (adapterDisk
== 0) {
520 // No free disks were found.
527 // Get the number of disks already initialized.
530 configurationInformation
= IoGetConfigurationInformation();
531 diskCount
= &configurationInformation
->DiskCount
;
534 // For each SCSI bus this adapter supports ...
537 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
540 // Get the SCSI bus scan data for this bus.
543 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
546 // Search list for unclaimed disk devices.
549 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
551 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
553 if (((inquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
554 (inquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
555 inquiryData
->DeviceTypeQualifier
== 0 &&
556 (!lunInfo
->DeviceClaimed
)) {
559 "FindScsiDevices: Vendor string is %.24s\n",
560 inquiryData
->VendorId
));
563 // Create device objects for disk
566 status
= CreateDiskDeviceObject(DriverObject
,
575 if (NT_SUCCESS(status
)) {
578 // Increment system disk device count.
591 if (lunInfo
->NextInquiryDataOffset
== 0) {
595 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
601 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
608 } // end FindScsiDisks()
613 CreateDiskDeviceObject(
614 IN PDRIVER_OBJECT DriverObject
,
615 IN PUNICODE_STRING RegistryPath
,
616 IN PDEVICE_OBJECT PortDeviceObject
,
618 IN PULONG DeviceCount
,
619 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
620 IN PSCSI_INQUIRY_DATA LunInfo
,
621 IN PCLASS_INIT_DATA InitData
628 This routine creates an object for the physical device and then searches
629 the device for partitions and creates an object for each partition.
633 DriverObject - Pointer to driver object created by system.
635 PortDeviceObject - Miniport device object.
637 PortNumber - port number. Used in creating disk objects.
639 DeviceCount - Number of previously installed devices.
641 PortCapabilities - Capabilities of this SCSI port.
643 LunInfo - LUN specific information.
651 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
653 UNICODE_STRING ntUnicodeString
;
654 OBJECT_ATTRIBUTES objectAttributes
;
657 PDEVICE_OBJECT deviceObject
= NULL
;
658 //PDEVICE_OBJECT physicalDevice;
659 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
660 PDEVICE_EXTENSION deviceExtension
= NULL
;
661 //PDEVICE_EXTENSION physicalDeviceExtension;
662 UCHAR pathId
= LunInfo
->PathId
;
663 UCHAR targetId
= LunInfo
->TargetId
;
664 UCHAR lun
= LunInfo
->Lun
;
665 //BOOLEAN writeCache;
666 PVOID senseData
= NULL
;
669 BOOLEAN srbListInitialized
= FALSE
;
675 // Set up an object directory to contain the objects for this
676 // device and all its partitions.
679 sprintf(ntNameBuffer
,
680 "\\Device\\Harddisk%lu",
683 RtlInitString(&ntNameString
,
686 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
690 if (!NT_SUCCESS(status
)) {
694 InitializeObjectAttributes(&objectAttributes
,
696 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
700 status
= ZwCreateDirectoryObject(&handle
,
701 DIRECTORY_ALL_ACCESS
,
704 RtlFreeUnicodeString(&ntUnicodeString
);
706 if (!NT_SUCCESS(status
)) {
709 "CreateDiskDeviceObjects: Could not create directory %s\n",
719 status
= ScsiClassClaimDevice(PortDeviceObject
,
724 if (!NT_SUCCESS(status
)) {
725 ZwMakeTemporaryObject(handle
);
731 // Create a device object for this device. Each physical disk will
732 // have at least one device object. The required device object
733 // describes the entire device. Its directory path is
734 // \Device\HarddiskN\Partition0, where N = device number.
737 sprintf(ntNameBuffer
,
738 "\\Device\\Harddisk%lu\\Partition0",
742 status
= ScsiClassCreateDeviceObject(DriverObject
,
748 if (!NT_SUCCESS(status
)) {
751 "CreateDiskDeviceObjects: Can not create device object %s\n",
754 goto CreateDiskDeviceObjectsExit
;
758 // Indicate that IRPs should include MDLs for data transfers.
761 deviceObject
->Flags
|= DO_DIRECT_IO
;
764 // Check if this is during initialization. If not indicate that
765 // system initialization already took place and this disk is ready
770 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
774 // Check for removable media support.
777 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->RemovableMedia
) {
778 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
782 // Set up required stack size in device object.
785 deviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
787 deviceExtension
= deviceObject
->DeviceExtension
;
790 // Allocate spinlock for split request completion.
793 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
796 // Initialize lock count to zero. The lock count is used to
797 // disable the ejection mechanism on devices that support
798 // removable media. Only the lock count in the physical
799 // device extension is used.
802 deviceExtension
->LockCount
= 0;
805 // Save system disk number.
808 deviceExtension
->DeviceNumber
= *DeviceCount
;
811 // Copy port device object pointer to the device extension.
814 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
817 // Set the alignment requirements for the device based on the
818 // host adapter requirements
821 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
822 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
826 // This is the physical device object.
829 //physicalDevice = deviceObject;
830 //physicalDeviceExtension = deviceExtension;
833 // Save address of port driver capabilities.
836 deviceExtension
->PortCapabilities
= PortCapabilities
;
839 // Build the lookaside list for srb's for the physical disk. Should only
843 ScsiClassInitializeSrbLookasideList(deviceExtension
,
844 PARTITION0_LIST_SIZE
);
846 srbListInitialized
= TRUE
;
849 // Initialize the srb flags.
852 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->CommandQueue
&&
853 PortCapabilities
->TaggedQueuing
) {
855 deviceExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
859 deviceExtension
->SrbFlags
= 0;
864 // Allow queued requests if this is not removable media.
867 if (!(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
869 deviceExtension
->SrbFlags
|= SRB_FLAGS_NO_QUEUE_FREEZE
;
874 // Look for controller that require special flags.
877 ScanForSpecial(deviceObject
,
881 //srbFlags = deviceExtension->SrbFlags;
884 // Allocate buffer for drive geometry.
887 diskGeometry
= ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
889 if (diskGeometry
== NULL
) {
892 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
893 status
= STATUS_INSUFFICIENT_RESOURCES
;
894 goto CreateDiskDeviceObjectsExit
;
897 deviceExtension
->DiskGeometry
= diskGeometry
;
900 // Allocate request sense buffer.
903 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
905 if (senseData
== NULL
) {
908 // The buffer can not be allocated.
912 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
914 status
= STATUS_INSUFFICIENT_RESOURCES
;
915 goto CreateDiskDeviceObjectsExit
;
919 // Set the sense data pointer in the device extension.
922 deviceExtension
->SenseData
= senseData
;
925 // Physical device object will describe the entire
926 // device, starting at byte offset 0.
929 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)(0);
932 // TargetId/LUN describes a device location on the SCSI bus.
933 // This information comes from the inquiry buffer.
936 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
937 deviceExtension
->PathId
= pathId
;
938 deviceExtension
->TargetId
= targetId
;
939 deviceExtension
->Lun
= lun
;
942 // Set timeout value in seconds.
945 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
947 deviceExtension
->TimeOutValue
= timeOut
;
949 deviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
953 // Back pointer to device object.
956 deviceExtension
->DeviceObject
= deviceObject
;
959 // If this is a removable device, then make sure it is not a floppy.
960 // Perform a mode sense command to determine the media type. Note
961 // IsFloppyDevice also checks for write cache enabled.
964 if (IsFloppyDevice(deviceObject
) && deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
965 (((PINQUIRYDATA
)LunInfo
->InquiryData
)->DeviceType
== DIRECT_ACCESS_DEVICE
)) {
967 status
= STATUS_NO_SUCH_DEVICE
;
968 goto CreateDiskDeviceObjectsExit
;
971 DisableWriteCache(deviceObject
,LunInfo
);
973 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
976 // NOTE: At this point one device object has been successfully created.
977 // from here on out return success.
981 // Do READ CAPACITY. This SCSI command
982 // returns the number of bytes on a device.
983 // Device extension is updated with device size.
986 status
= ScsiClassReadDriveCapacity(deviceObject
);
989 // If the read capcity failed then just return, unless this is a
990 // removable disk where a device object partition needs to be created.
993 if (!NT_SUCCESS(status
) &&
994 !(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
997 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
1000 return(STATUS_SUCCESS
);
1005 // Make sure the volume verification bit is off so that
1006 // IoReadPartitionTable will work.
1009 deviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
1012 status
= CreatePartitionDeviceObjects(deviceObject
, RegistryPath
);
1014 if (NT_SUCCESS(status
))
1015 return STATUS_SUCCESS
;
1018 CreateDiskDeviceObjectsExit
:
1021 // Release the device since an error occurred.
1024 ScsiClassClaimDevice(PortDeviceObject
,
1029 if (diskGeometry
!= NULL
) {
1030 ExFreePool(diskGeometry
);
1033 if (senseData
!= NULL
) {
1034 ExFreePool(senseData
);
1037 if (deviceObject
!= NULL
) {
1039 if (srbListInitialized
) {
1040 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1043 IoDeleteDevice(deviceObject
);
1047 // Delete directory and return.
1050 if (!NT_SUCCESS(status
)) {
1051 ZwMakeTemporaryObject(handle
);
1058 } // end CreateDiskDeviceObjects()
1063 CreatePartitionDeviceObjects(
1064 IN PDEVICE_OBJECT PhysicalDeviceObject
,
1065 IN PUNICODE_STRING RegistryPath
1068 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
1069 ULONG partitionNumber
= 0;
1071 PDEVICE_OBJECT deviceObject
= NULL
;
1072 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
1073 PDRIVE_LAYOUT_INFORMATION partitionList
= NULL
;
1074 PDEVICE_EXTENSION deviceExtension
;
1075 PDEVICE_EXTENSION physicalDeviceExtension
;
1076 PCLASS_INIT_DATA initData
= NULL
;
1077 PDISK_DATA diskData
;
1078 PDISK_DATA physicalDiskData
;
1079 ULONG bytesPerSector
;
1082 ULONG dmByteSkew
= 0;
1084 BOOLEAN dmActive
= FALSE
;
1085 ULONG numberListElements
= 0;
1089 // Get physical device geometry information for partition table reads.
1092 physicalDeviceExtension
= PhysicalDeviceObject
->DeviceExtension
;
1093 diskGeometry
= physicalDeviceExtension
->DiskGeometry
;
1094 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
;
1097 // Make sure sector size is not zero.
1100 if (bytesPerSector
== 0) {
1103 // Default sector size for disk is 512.
1106 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
= 512;
1109 sectorShift
= physicalDeviceExtension
->SectorShift
;
1112 // Set pointer to disk data area that follows device extension.
1115 diskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1116 diskData
->PartitionListState
= Initializing
;
1119 // Determine is DM Driver is loaded on an IDE drive that is
1120 // under control of Atapi - this could be either a crashdump or
1121 // an Atapi device is sharing the controller with an IDE disk.
1124 HalExamineMBR(PhysicalDeviceObject
,
1125 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1132 // Update the device extension, so that the call to IoReadPartitionTable
1133 // will get the correct information. Any I/O to this disk will have
1134 // to be skewed by *dmSkew sectors aka DMByteSkew.
1137 physicalDeviceExtension
->DMSkew
= *dmSkew
;
1138 physicalDeviceExtension
->DMActive
= TRUE
;
1139 physicalDeviceExtension
->DMByteSkew
= physicalDeviceExtension
->DMSkew
* bytesPerSector
;
1142 // Save away the infomation that we need, since this deviceExtension will soon be
1147 dmByteSkew
= physicalDeviceExtension
->DMByteSkew
;
1152 // Create objects for all the partitions on the device.
1155 status
= IoReadPartitionTable(PhysicalDeviceObject
,
1156 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1158 (PVOID
)&partitionList
);
1161 // If the I/O read partition table failed and this is a removable device,
1162 // then fix up the partition list to make it look like there is one
1163 // zero length partition.
1165 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status
);
1166 if ((!NT_SUCCESS(status
) || partitionList
->PartitionCount
== 0) &&
1167 PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1169 if (!NT_SUCCESS(status
)) {
1172 // Remember this disk is not ready.
1175 diskData
->DriveNotReady
= TRUE
;
1180 // Free the partition list allocated by IoReadPartitionTable.
1183 ExFreePool(partitionList
);
1187 // Allocate and zero a partition list.
1190 partitionList
= ExAllocatePool(NonPagedPool
, sizeof(*partitionList
));
1193 if (partitionList
!= NULL
) {
1195 RtlZeroMemory( partitionList
, sizeof( *partitionList
));
1198 // Set the partition count to one and the status to success
1199 // so one device object will be created. Set the partition type
1200 // to a bogus value.
1203 partitionList
->PartitionCount
= 1;
1205 status
= STATUS_SUCCESS
;
1209 if (NT_SUCCESS(status
)) {
1212 // Record disk signature.
1215 diskData
->Signature
= partitionList
->Signature
;
1218 // If disk signature is zero, then calculate the MBR checksum.
1221 if (!diskData
->Signature
) {
1223 if (!CalculateMbrCheckSum(physicalDeviceExtension
,
1224 &diskData
->MbrCheckSum
)) {
1227 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1228 physicalDeviceExtension
->DeviceNumber
));
1232 "SCSIDISK: MBR checksum for disk %x is %x\n",
1233 physicalDeviceExtension
->DeviceNumber
,
1234 diskData
->MbrCheckSum
));
1239 // Check the registry and determine if the BIOS knew about this drive. If
1240 // it did then update the geometry with the BIOS information.
1243 UpdateGeometry(physicalDeviceExtension
);
1245 srbFlags
= physicalDeviceExtension
->SrbFlags
;
1247 initData
= ExAllocatePool(NonPagedPool
, sizeof(CLASS_INIT_DATA
));
1251 "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n"));
1253 status
= STATUS_INSUFFICIENT_RESOURCES
;
1254 goto CreatePartitionDeviceObjectsExit
;
1257 RtlZeroMemory(initData
, sizeof(CLASS_INIT_DATA
));
1259 initData
->InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
1260 initData
->DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
1261 initData
->DeviceType
= FILE_DEVICE_DISK
;
1262 initData
->DeviceCharacteristics
= PhysicalDeviceObject
->Characteristics
;
1263 initData
->ClassError
= physicalDeviceExtension
->ClassError
;
1264 initData
->ClassReadWriteVerification
= physicalDeviceExtension
->ClassReadWriteVerification
;
1265 initData
->ClassFindDevices
= physicalDeviceExtension
->ClassFindDevices
;
1266 initData
->ClassDeviceControl
= physicalDeviceExtension
->ClassDeviceControl
;
1267 initData
->ClassShutdownFlush
= physicalDeviceExtension
->ClassShutdownFlush
;
1268 initData
->ClassCreateClose
= physicalDeviceExtension
->ClassCreateClose
;
1269 initData
->ClassStartIo
= physicalDeviceExtension
->ClassStartIo
;
1272 // Create device objects for the device partitions (if any).
1273 // PartitionCount includes physical device partition 0,
1274 // so only one partition means no objects to create.
1278 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1279 partitionList
->PartitionCount
));
1281 for (partitionNumber
= 0; partitionNumber
<
1282 partitionList
->PartitionCount
; partitionNumber
++) {
1285 // Create partition object and set up partition parameters.
1288 sprintf(ntNameBuffer
,
1289 "\\Device\\Harddisk%lu\\Partition%lu",
1290 physicalDeviceExtension
->DeviceNumber
,
1291 partitionNumber
+ 1);
1294 "CreateDiskDeviceObjects: Create device object %s\n",
1297 status
= ScsiClassCreateDeviceObject(PhysicalDeviceObject
->DriverObject
,
1299 PhysicalDeviceObject
,
1303 if (!NT_SUCCESS(status
)) {
1305 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer
));
1311 // Set up device object fields.
1314 deviceObject
->Flags
|= DO_DIRECT_IO
;
1317 // Check if this is during initialization. If not indicate that
1318 // system initialization already took place and this disk is ready
1322 if (!RegistryPath
) {
1323 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1326 deviceObject
->StackSize
= (CCHAR
)physicalDeviceExtension
->PortDeviceObject
->StackSize
+ 1;
1329 // Set up device extension fields.
1332 deviceExtension
= deviceObject
->DeviceExtension
;
1337 // Restore any saved DM values.
1340 deviceExtension
->DMByteSkew
= dmByteSkew
;
1341 deviceExtension
->DMSkew
= *dmSkew
;
1342 deviceExtension
->DMActive
= TRUE
;
1347 // Link new device extension to previous disk data
1348 // to support dynamic partitioning.
1351 diskData
->NextPartition
= deviceExtension
;
1354 // Get pointer to new disk data.
1357 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1360 // Set next partition pointer to NULL in case this is the
1364 diskData
->NextPartition
= NULL
;
1367 // Allocate spinlock for zoning for split-request completion.
1370 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
1373 // Copy port device object pointer to device extension.
1376 deviceExtension
->PortDeviceObject
= physicalDeviceExtension
->PortDeviceObject
;
1379 // Set the alignment requirements for the device based on the
1380 // host adapter requirements
1383 if (physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
1384 deviceObject
->AlignmentRequirement
= physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
;
1388 if (srbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
1389 numberListElements
= 30;
1391 numberListElements
= 8;
1395 // Build the lookaside list for srb's for this partition based on
1396 // whether the adapter and disk can do tagged queueing.
1399 ScsiClassInitializeSrbLookasideList(deviceExtension
,
1400 numberListElements
);
1402 deviceExtension
->SrbFlags
= srbFlags
;
1405 // Set the sense-data pointer in the device extension.
1408 deviceExtension
->SenseData
= physicalDeviceExtension
->SenseData
;
1409 deviceExtension
->PortCapabilities
= physicalDeviceExtension
->PortCapabilities
;
1410 deviceExtension
->DiskGeometry
= diskGeometry
;
1411 diskData
->PartitionOrdinal
= diskData
->PartitionNumber
= partitionNumber
+ 1;
1412 diskData
->PartitionType
= partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
1413 diskData
->BootIndicator
= partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
1415 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1416 diskData
->PartitionType
));
1418 deviceExtension
->StartingOffset
= partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
1419 deviceExtension
->PartitionLength
= partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
1420 diskData
->HiddenSectors
= partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
1421 deviceExtension
->PortNumber
= physicalDeviceExtension
->PortNumber
;
1422 deviceExtension
->PathId
= physicalDeviceExtension
->PathId
;
1423 deviceExtension
->TargetId
= physicalDeviceExtension
->TargetId
;
1424 deviceExtension
->Lun
= physicalDeviceExtension
->Lun
;
1427 // Check for removable media support.
1430 if (PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1431 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
1435 // Set timeout value in seconds.
1438 deviceExtension
->TimeOutValue
= physicalDeviceExtension
->TimeOutValue
;
1439 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bytesPerSector
;
1440 deviceExtension
->SectorShift
= sectorShift
;
1441 deviceExtension
->DeviceObject
= deviceObject
;
1442 deviceExtension
->DeviceFlags
|= physicalDeviceExtension
->DeviceFlags
;
1444 } // end for (partitionNumber) ...
1447 // Free the buffer allocated by reading the
1451 ExFreePool(partitionList
);
1459 CreatePartitionDeviceObjectsExit
:
1461 if (partitionList
) {
1462 ExFreePool(partitionList
);
1465 ExFreePool(initData
);
1477 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1478 physicalDiskData
->PartitionListState
= Initialized
;
1480 return(STATUS_SUCCESS
);
1483 } // end CreatePartitionDeviceObjects()
1488 ScsiDiskReadWriteVerification(
1489 IN PDEVICE_OBJECT DeviceObject
,
1495 Routine Description:
1497 I/O System entry for read and write requests to SCSI disks.
1501 DeviceObject - Pointer to driver object created by system.
1511 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1512 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1513 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1514 LARGE_INTEGER startingOffset
;
1517 // HACK: How can we end here with null sector size?!
1520 if (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
== 0) {
1521 DPRINT1("Hack! Received invalid sector size\n");
1522 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1526 // Verify parameters of this request.
1527 // Check that ending sector is within partition and
1528 // that number of bytes to transfer is a multiple of
1532 startingOffset
.QuadPart
= (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
1535 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
1536 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
1539 // This error maybe caused by the fact that the drive is not ready.
1542 if (((PDISK_DATA
)(deviceExtension
+ 1))->DriveNotReady
) {
1545 // Flag this as a user errror so that a popup is generated.
1548 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
1549 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1554 // Note fastfat depends on this parameter to determine when to
1555 // remount do to a sector size change.
1558 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1561 if (startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) {
1562 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset
.QuadPart
, deviceExtension
->PartitionLength
.QuadPart
);
1565 if (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1)) {
1566 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount
, deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
1569 if (Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_READY
) {
1570 DPRINT1("Failing due to device not ready!\n");
1573 return STATUS_INVALID_PARAMETER
;
1576 return STATUS_SUCCESS
;
1578 } // end ScsiDiskReadWrite()
1583 ScsiDiskDeviceControl(
1584 PDEVICE_OBJECT DeviceObject
,
1590 Routine Description:
1592 I/O system entry for device controls to SCSI disks.
1596 DeviceObject - Pointer to driver object created by system.
1606 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1607 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1608 PDISK_DATA diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1609 PSCSI_REQUEST_BLOCK srb
;
1611 PMODE_PARAMETER_HEADER modeData
;
1616 IO_STATUS_BLOCK ioStatus
;
1620 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
1624 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1625 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1626 return(STATUS_INSUFFICIENT_RESOURCES
);
1630 // Write zeros to Srb.
1633 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1635 cdb
= (PCDB
)srb
->Cdb
;
1637 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1639 case SMART_GET_VERSION
: {
1642 PSRB_IO_CONTROL srbControl
;
1643 PGETVERSIONINPARAMS versionParams
;
1645 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1646 sizeof(GETVERSIONINPARAMS
)) {
1647 status
= STATUS_INVALID_PARAMETER
;
1652 // Create notification event object to be used to signal the
1653 // request completion.
1656 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1658 srbControl
= ExAllocatePool(NonPagedPool
,
1659 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
));
1662 status
= STATUS_INSUFFICIENT_RESOURCES
;
1667 // fill in srbControl fields
1670 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1671 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1672 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1673 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1674 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1677 // Point to the 'buffer' portion of the SRB_CONTROL
1680 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1683 // Ensure correct target is set in the cmd parameters.
1686 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1687 versionParams
->bIDEDeviceMap
= deviceExtension
->TargetId
;
1690 // Copy the IOCTL parameters to the srb control buffer area.
1693 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(GETVERSIONINPARAMS
));
1696 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1697 deviceExtension
->PortDeviceObject
,
1699 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1701 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1707 status
= STATUS_INSUFFICIENT_RESOURCES
;
1712 // Call the port driver with the request and wait for it to complete.
1715 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1717 if (status
== STATUS_PENDING
) {
1718 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1719 status
= ioStatus
.Status
;
1723 // If successful, copy the data received into the output buffer.
1724 // This should only fail in the event that the IDE driver is older than this driver.
1727 if (NT_SUCCESS(status
)) {
1729 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1731 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, sizeof(GETVERSIONINPARAMS
));
1732 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1735 ExFreePool(srbControl
);
1739 case SMART_RCV_DRIVE_DATA
: {
1741 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1742 ULONG controlCode
= 0;
1743 PSRB_IO_CONTROL srbControl
;
1746 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1747 (sizeof(SENDCMDINPARAMS
) - 1)) {
1748 status
= STATUS_INVALID_PARAMETER
;
1751 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1752 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1753 status
= STATUS_INVALID_PARAMETER
;
1758 // Create notification event object to be used to signal the
1759 // request completion.
1762 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1764 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1766 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1767 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1769 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1770 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1771 case READ_ATTRIBUTES
:
1772 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1773 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1775 case READ_THRESHOLDS
:
1776 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1777 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1780 status
= STATUS_INVALID_PARAMETER
;
1785 status
= STATUS_INVALID_PARAMETER
;
1788 if (controlCode
== 0) {
1789 status
= STATUS_INVALID_PARAMETER
;
1793 srbControl
= ExAllocatePool(NonPagedPool
,
1794 sizeof(SRB_IO_CONTROL
) + length
);
1797 status
= STATUS_INSUFFICIENT_RESOURCES
;
1802 // fill in srbControl fields
1805 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1806 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1807 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1808 srbControl
->Length
= length
;
1809 srbControl
->ControlCode
= controlCode
;
1812 // Point to the 'buffer' portion of the SRB_CONTROL
1815 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1818 // Ensure correct target is set in the cmd parameters.
1821 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1824 // Copy the IOCTL parameters to the srb control buffer area.
1827 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1829 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1830 deviceExtension
->PortDeviceObject
,
1832 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1834 sizeof(SRB_IO_CONTROL
) + length
,
1840 status
= STATUS_INSUFFICIENT_RESOURCES
;
1845 // Call the port driver with the request and wait for it to complete.
1848 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1850 if (status
== STATUS_PENDING
) {
1851 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1852 status
= ioStatus
.Status
;
1856 // If successful, copy the data received into the output buffer
1859 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1861 if (NT_SUCCESS(status
)) {
1863 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
- 1);
1864 Irp
->IoStatus
.Information
= length
- 1;
1868 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1869 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1873 ExFreePool(srbControl
);
1878 case SMART_SEND_DRIVE_COMMAND
: {
1880 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1881 PSRB_IO_CONTROL srbControl
;
1882 ULONG controlCode
= 0;
1885 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1886 (sizeof(SENDCMDINPARAMS
) - 1)) {
1887 status
= STATUS_INVALID_PARAMETER
;
1890 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1891 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1892 status
= STATUS_INVALID_PARAMETER
;
1897 // Create notification event object to be used to signal the
1898 // request completion.
1901 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1905 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1906 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1909 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1913 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1916 case RETURN_SMART_STATUS
:
1919 // Ensure bBuffer is at least 2 bytes (to hold the values of
1920 // cylinderLow and cylinderHigh).
1923 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1924 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1926 status
= STATUS_INVALID_PARAMETER
;
1930 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1931 length
= sizeof(IDEREGS
);
1934 case ENABLE_DISABLE_AUTOSAVE
:
1935 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1938 case SAVE_ATTRIBUTE_VALUES
:
1939 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1942 case EXECUTE_OFFLINE_DIAGS
:
1943 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1947 status
= STATUS_INVALID_PARAMETER
;
1952 status
= STATUS_INVALID_PARAMETER
;
1955 if (controlCode
== 0) {
1956 status
= STATUS_INVALID_PARAMETER
;
1960 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1961 srbControl
= ExAllocatePool(NonPagedPool
,
1962 sizeof(SRB_IO_CONTROL
) + length
);
1965 status
= STATUS_INSUFFICIENT_RESOURCES
;
1970 // fill in srbControl fields
1973 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1974 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1975 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1976 srbControl
->Length
= length
;
1979 // Point to the 'buffer' portion of the SRB_CONTROL
1982 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1985 // Ensure correct target is set in the cmd parameters.
1988 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1991 // Copy the IOCTL parameters to the srb control buffer area.
1994 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1996 srbControl
->ControlCode
= controlCode
;
1998 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1999 deviceExtension
->PortDeviceObject
,
2001 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
2003 sizeof(SRB_IO_CONTROL
) + length
,
2009 status
= STATUS_INSUFFICIENT_RESOURCES
;
2014 // Call the port driver with the request and wait for it to complete.
2017 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2019 if (status
== STATUS_PENDING
) {
2020 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2021 status
= ioStatus
.Status
;
2025 // Copy the data received into the output buffer. Since the status buffer
2026 // contains error information also, always perform this copy. IO will will
2027 // either pass this back to the app, or zero it, in case of error.
2030 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2033 // Update the return buffer size based on the sub-command.
2036 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
2037 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
2039 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
2042 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
);
2043 Irp
->IoStatus
.Information
= length
;
2045 ExFreePool(srbControl
);
2050 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2051 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2054 PDEVICE_EXTENSION physicalDeviceExtension
;
2055 PDISK_DATA physicalDiskData
;
2056 BOOLEAN removable
= FALSE
;
2057 BOOLEAN listInitialized
= FALSE
;
2059 if ((irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
&&
2060 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2061 sizeof(DISK_GEOMETRY
)) ||
2062 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
&&
2063 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2064 sizeof(DISK_GEOMETRY_EX
))) {
2066 status
= STATUS_INFO_LENGTH_MISMATCH
;
2070 status
= STATUS_SUCCESS
;
2072 physicalDeviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2073 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
2075 removable
= (BOOLEAN
)DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
;
2076 listInitialized
= (physicalDiskData
->PartitionListState
== Initialized
);
2078 if (removable
|| (!listInitialized
))
2081 // Issue ReadCapacity to update device extension
2082 // with information for current media.
2085 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
2091 if (!NT_SUCCESS(status
)) {
2094 // Note the drive is not ready.
2097 diskData
->DriveNotReady
= TRUE
;
2103 // Note the drive is now ready.
2106 diskData
->DriveNotReady
= FALSE
;
2108 } else if (NT_SUCCESS(status
)) {
2110 // ReadDriveCapacity was allright, create Partition Objects
2112 if (physicalDiskData
->PartitionListState
== NotInitialized
) {
2113 status
= CreatePartitionDeviceObjects(deviceExtension
->PhysicalDevice
, NULL
);
2117 if (NT_SUCCESS(status
)) {
2120 // Copy drive geometry information from device extension.
2123 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2124 deviceExtension
->DiskGeometry
,
2125 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2126 sizeof(DISK_GEOMETRY
) :
2127 sizeof(DISK_GEOMETRY_EX
));
2129 status
= STATUS_SUCCESS
;
2130 Irp
->IoStatus
.Information
=
2131 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2132 sizeof(DISK_GEOMETRY
) :
2133 sizeof(DISK_GEOMETRY_EX
);
2140 case IOCTL_DISK_VERIFY
:
2144 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2145 LARGE_INTEGER byteOffset
;
2150 // Validate buffer length.
2153 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2154 sizeof(VERIFY_INFORMATION
)) {
2156 status
= STATUS_INFO_LENGTH_MISMATCH
;
2164 srb
->CdbLength
= 10;
2166 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2169 // Add disk offset to starting sector.
2172 byteOffset
.QuadPart
= deviceExtension
->StartingOffset
.QuadPart
+
2173 verifyInfo
->StartingOffset
.QuadPart
;
2176 // Convert byte offset to sector offset.
2179 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2182 // Convert ULONG byte count to USHORT sector count.
2185 sectorCount
= (USHORT
)(verifyInfo
->Length
>> deviceExtension
->SectorShift
);
2188 // Move little endian values into CDB in big endian format.
2191 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2192 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2193 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2194 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2196 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2197 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2200 // The verify command is used by the NT FORMAT utility and
2201 // requests are sent down for 5% of the volume size. The
2202 // request timeout value is calculated based on the number of
2203 // sectors verified.
2206 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2207 deviceExtension
->TimeOutValue
;
2209 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
2220 case IOCTL_DISK_GET_PARTITION_INFO
:
2223 // Return the information about the partition specified by the device
2224 // object. Note that no information is ever returned about the size
2225 // or partition type of the physical disk, as this doesn't make any
2229 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2230 sizeof(PARTITION_INFORMATION
)) {
2232 status
= STATUS_INFO_LENGTH_MISMATCH
;
2235 #if 0 // HACK: ReactOS partition numbers must be wrong
2236 else if (diskData
->PartitionNumber
== 0) {
2239 // Paritition zero is not a partition so this is not a
2240 // reasonable request.
2243 status
= STATUS_INVALID_DEVICE_REQUEST
;
2249 PPARTITION_INFORMATION outputBuffer
;
2251 if (diskData
->PartitionNumber
== 0) {
2252 DPRINT1("HACK: Handling partition 0 request!\n");
2257 // Update the geometry in case it has changed.
2260 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2262 if (!NT_SUCCESS(status
)) {
2265 // Note the drive is not ready.
2268 diskData
->DriveNotReady
= TRUE
;
2273 // Note the drive is now ready.
2276 diskData
->DriveNotReady
= FALSE
;
2279 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2281 outputBuffer
->PartitionType
= diskData
->PartitionType
;
2282 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2283 outputBuffer
->PartitionLength
.QuadPart
= (diskData
->PartitionNumber
) ?
2284 deviceExtension
->PartitionLength
.QuadPart
: 2305843009213693951LL; // HACK
2285 outputBuffer
->HiddenSectors
= diskData
->HiddenSectors
;
2286 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2287 outputBuffer
->BootIndicator
= diskData
->BootIndicator
;
2288 outputBuffer
->RewritePartition
= FALSE
;
2289 outputBuffer
->RecognizedPartition
=
2290 IsRecognizedPartition(diskData
->PartitionType
);
2292 status
= STATUS_SUCCESS
;
2293 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2298 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2301 // Return the information about the partition specified by the device
2302 // object. Note that no information is ever returned about the size
2303 // or partition type of the physical disk, as this doesn't make any
2307 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2308 sizeof(PARTITION_INFORMATION_EX
)) {
2310 status
= STATUS_INFO_LENGTH_MISMATCH
;
2313 else if (diskData
->PartitionNumber
== 0) {
2316 // Paritition zero is not a partition so this is not a
2317 // reasonable request.
2320 status
= STATUS_INVALID_DEVICE_REQUEST
;
2325 PPARTITION_INFORMATION_EX outputBuffer
;
2328 // Update the geometry in case it has changed.
2331 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2333 if (!NT_SUCCESS(status
)) {
2336 // Note the drive is not ready.
2339 diskData
->DriveNotReady
= TRUE
;
2344 // Note the drive is now ready.
2347 diskData
->DriveNotReady
= FALSE
;
2349 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2351 status
= STATUS_INVALID_DEVICE_REQUEST
;
2356 (PPARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
2359 // FIXME: hack of the year, assume that partition is MBR
2360 // Thing that can obviously be wrong...
2363 outputBuffer
->PartitionStyle
= PARTITION_STYLE_MBR
;
2364 outputBuffer
->Mbr
.PartitionType
= diskData
->PartitionType
;
2365 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2366 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2367 outputBuffer
->Mbr
.HiddenSectors
= diskData
->HiddenSectors
;
2368 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2369 outputBuffer
->Mbr
.BootIndicator
= diskData
->BootIndicator
;
2370 outputBuffer
->RewritePartition
= FALSE
;
2371 outputBuffer
->Mbr
.RecognizedPartition
=
2372 IsRecognizedPartition(diskData
->PartitionType
);
2374 status
= STATUS_SUCCESS
;
2375 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
2380 case IOCTL_DISK_SET_PARTITION_INFO
:
2382 if (diskData
->PartitionNumber
== 0) {
2384 status
= STATUS_UNSUCCESSFUL
;
2388 PSET_PARTITION_INFORMATION inputBuffer
=
2389 (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2392 // Validate buffer length.
2395 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2396 sizeof(SET_PARTITION_INFORMATION
)) {
2398 status
= STATUS_INFO_LENGTH_MISMATCH
;
2403 // The HAL routines IoGet- and IoSetPartitionInformation were
2404 // developed before support of dynamic partitioning and therefore
2405 // don't distinguish between partition ordinal (that is the order
2406 // of a partition on a disk) and the partition number. (The
2407 // partition number is assigned to a partition to identify it to
2408 // the system.) Use partition ordinals for these legacy calls.
2411 status
= IoSetPartitionInformation(
2412 deviceExtension
->PhysicalDevice
,
2413 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2414 diskData
->PartitionOrdinal
,
2415 inputBuffer
->PartitionType
);
2417 if (NT_SUCCESS(status
)) {
2419 diskData
->PartitionType
= inputBuffer
->PartitionType
;
2425 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2428 // Return the partition layout for the physical drive. Note that
2429 // the layout is returned for the actual physical drive, regardless
2430 // of which partition was specified for the request.
2433 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2434 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2435 status
= STATUS_INFO_LENGTH_MISMATCH
;
2439 PDRIVE_LAYOUT_INFORMATION partitionList
;
2440 PDEVICE_EXTENSION physicalExtension
= deviceExtension
;
2441 PPARTITION_INFORMATION partitionEntry
;
2442 PDISK_DATA diskData
;
2447 // Read partition information.
2450 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
2451 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2455 if (!NT_SUCCESS(status
)) {
2460 // The disk layout has been returned in the partitionList
2461 // buffer. Determine its size and, if the data will fit
2462 // into the intermediatery buffer, return it.
2465 tempSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,PartitionEntry
[0]);
2466 tempSize
+= partitionList
->PartitionCount
*
2467 sizeof(PARTITION_INFORMATION
);
2470 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
2472 status
= STATUS_BUFFER_TOO_SMALL
;
2473 ExFreePool(partitionList
);
2478 // Walk partition list to associate partition numbers with
2479 // partition entries.
2482 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
2485 // Walk partition chain anchored at physical disk extension.
2488 deviceExtension
= physicalExtension
;
2489 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2493 deviceExtension
= diskData
->NextPartition
;
2496 // Check if this is the last partition in the chain.
2499 if (!deviceExtension
) {
2504 // Get the partition device extension from disk data.
2507 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2510 // Check if this partition is not currently being used.
2513 if (!deviceExtension
->PartitionLength
.QuadPart
) {
2517 partitionEntry
= &partitionList
->PartitionEntry
[i
];
2520 // Check if empty, or describes extended partiton or hasn't changed.
2523 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2524 IsContainerPartition(partitionEntry
->PartitionType
)) {
2529 // Check if new partition starts where this partition starts.
2532 if (partitionEntry
->StartingOffset
.QuadPart
!=
2533 deviceExtension
->StartingOffset
.QuadPart
) {
2538 // Check if partition length is the same.
2541 if (partitionEntry
->PartitionLength
.QuadPart
==
2542 deviceExtension
->PartitionLength
.QuadPart
) {
2545 // Partitions match. Update partition number.
2548 partitionEntry
->PartitionNumber
=
2549 diskData
->PartitionNumber
;
2557 // Copy partition information to system buffer.
2560 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2563 status
= STATUS_SUCCESS
;
2564 Irp
->IoStatus
.Information
= tempSize
;
2567 // Finally, free the buffer allocated by reading the
2571 ExFreePool(partitionList
);
2576 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
2581 // Update the disk with new partition information.
2584 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
2587 // Validate buffer length.
2590 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2591 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2593 status
= STATUS_INFO_LENGTH_MISMATCH
;
2597 length
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2598 (partitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
);
2601 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2604 status
= STATUS_BUFFER_TOO_SMALL
;
2609 // Verify that device object is for physical disk.
2612 if (deviceExtension
->PhysicalDevice
->DeviceExtension
!= deviceExtension
) {
2613 status
= STATUS_INVALID_PARAMETER
;
2618 // Walk through partition table comparing partitions to
2619 // existing partitions to create, delete and change
2620 // device objects as necessary.
2623 UpdateDeviceObjects(DeviceObject
,
2627 // Write changes to disk.
2630 status
= IoWritePartitionTable(
2631 deviceExtension
->DeviceObject
,
2632 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2633 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
,
2634 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
,
2639 // Update IRP with bytes returned.
2642 if (NT_SUCCESS(status
)) {
2643 Irp
->IoStatus
.Information
= length
;
2648 case IOCTL_DISK_REASSIGN_BLOCKS
:
2651 // Map defective blocks to new location on disk.
2656 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2662 // Validate buffer length.
2665 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2666 sizeof(REASSIGN_BLOCKS
)) {
2668 status
= STATUS_INFO_LENGTH_MISMATCH
;
2672 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2673 (badBlocks
->Count
- 1) * sizeof(ULONG
);
2675 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2678 status
= STATUS_INFO_LENGTH_MISMATCH
;
2683 // Build the data buffer to be transferred in the input buffer.
2684 // The format of the data to the device is:
2688 // x * 4 btyes Block Address
2690 // All values are big endian.
2693 badBlocks
->Reserved
= 0;
2694 blockCount
= badBlocks
->Count
;
2697 // Convert # of entries to # of bytes.
2701 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2702 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2705 // Convert back to number of entries.
2710 for (; blockCount
> 0; blockCount
--) {
2712 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2714 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2715 (PFOUR_BYTE
) &blockNumber
);
2720 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2723 // Set timeout value.
2726 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2728 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2734 Irp
->IoStatus
.Status
= status
;
2735 Irp
->IoStatus
.Information
= 0;
2737 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2742 case IOCTL_DISK_IS_WRITABLE
:
2745 // Determine if the device is writable.
2748 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
2750 if (modeData
== NULL
) {
2751 status
= STATUS_INSUFFICIENT_RESOURCES
;
2755 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
2757 length
= ScsiClassModeSense(DeviceObject
,
2760 MODE_SENSE_RETURN_ALL
);
2762 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2765 // Retry the request in case of a check condition.
2768 length
= ScsiClassModeSense(DeviceObject
,
2771 MODE_SENSE_RETURN_ALL
);
2773 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2774 status
= STATUS_IO_DEVICE_ERROR
;
2775 ExFreePool(modeData
);
2780 if (modeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
) {
2781 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2783 status
= STATUS_SUCCESS
;
2786 ExFreePool(modeData
);
2789 case IOCTL_DISK_INTERNAL_SET_VERIFY
:
2792 // If the caller is kernel mode, set the verify bit.
2795 if (Irp
->RequestorMode
== KernelMode
) {
2796 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2798 status
= STATUS_SUCCESS
;
2801 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
:
2804 // If the caller is kernel mode, clear the verify bit.
2807 if (Irp
->RequestorMode
== KernelMode
) {
2808 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
2810 status
= STATUS_SUCCESS
;
2813 case IOCTL_DISK_FIND_NEW_DEVICES
:
2816 // Search for devices that have been powered on since the last
2817 // device search or system initialization.
2820 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2821 status
= DriverEntry(DeviceObject
->DriverObject
,
2824 Irp
->IoStatus
.Status
= status
;
2826 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2829 case IOCTL_DISK_MEDIA_REMOVAL
:
2832 // If the disk is not removable then don't allow this command.
2835 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
2836 status
= STATUS_INVALID_DEVICE_REQUEST
;
2841 // Fall through and let the class driver process the request.
2844 case IOCTL_DISK_GET_LENGTH_INFO
:
2847 // Validate buffer length.
2850 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2851 sizeof(GET_LENGTH_INFORMATION
)) {
2852 status
= STATUS_BUFFER_TOO_SMALL
;
2856 PGET_LENGTH_INFORMATION lengthInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
2859 // Update the geometry in case it has changed.
2862 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2864 if (!NT_SUCCESS(status
)) {
2867 // Note the drive is not ready.
2870 diskData
->DriveNotReady
= TRUE
;
2875 // Note the drive is now ready.
2878 diskData
->DriveNotReady
= FALSE
;
2881 // Output data, and return
2884 lengthInformation
->Length
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2885 status
= STATUS_SUCCESS
;
2886 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2894 // Free the Srb, since it is not needed.
2900 // Pass the request to the common device control routine.
2903 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
2907 } // end switch( ...
2909 Irp
->IoStatus
.Status
= status
;
2911 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2913 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2916 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2920 } // end ScsiDiskDeviceControl()
2924 ScsiDiskShutdownFlush (
2925 IN PDEVICE_OBJECT DeviceObject
,
2931 Routine Description:
2933 This routine is called for a shutdown and flush IRPs. These are sent by the
2934 system before it actually shuts down or when the file system does a flush.
2935 A synchronize cache command is sent to the device if it is write caching.
2936 If the device is removable an unlock command will be sent. This routine
2937 will sent a shutdown or flush Srb to the port driver.
2941 DriverObject - Pointer to device object to being shutdown by system.
2952 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2953 PIO_STACK_LOCATION irpStack
;
2954 PSCSI_REQUEST_BLOCK srb
;
2959 // Allocate SCSI request block.
2962 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
2967 // Set the status and complete the request.
2970 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2971 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2972 return(STATUS_INSUFFICIENT_RESOURCES
);
2975 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
2978 // Write length to SRB.
2981 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2984 // Set SCSI bus address.
2987 srb
->PathId
= deviceExtension
->PathId
;
2988 srb
->TargetId
= deviceExtension
->TargetId
;
2989 srb
->Lun
= deviceExtension
->Lun
;
2992 // Set timeout value and mark the request as not being a tagged request.
2995 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 4;
2996 srb
->QueueTag
= SP_UNTAGGED
;
2997 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
2998 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3001 // If the write cache is enabled then send a synchronize cache request.
3004 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3006 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3007 srb
->CdbLength
= 10;
3009 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
3011 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3017 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status
));
3021 // Unlock the device if it is removable and this is a shutdown.
3024 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3026 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
3027 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
3030 cdb
= (PVOID
) srb
->Cdb
;
3031 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3032 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3035 // Set timeout value.
3038 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3039 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3045 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3051 // Save a few parameters in the current stack location.
3054 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3055 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3058 // Set the retry count to zero.
3061 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3064 // Set up IoCompletion routine address.
3067 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3070 // Get next stack location and
3071 // set major function code.
3074 irpStack
= IoGetNextIrpStackLocation(Irp
);
3076 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3079 // Set up SRB for execute scsi request.
3080 // Save SRB address in next stack for port driver.
3083 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3086 // Set up Irp Address.
3089 srb
->OriginalRequest
= Irp
;
3092 // Call the port driver to process the request.
3095 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3097 } // end ScsiDiskShutdown()
3103 PDEVICE_OBJECT DeviceObject
3107 Routine Description:
3109 The routine performs the necessary functions to determine if a device is
3110 really a floppy rather than a harddisk. This is done by a mode sense
3111 command. First, a check is made to see if the medimum type is set. Second
3112 a check is made for the flexible parameters mode page. Also a check is
3113 made to see if the write cache is enabled.
3117 DeviceObject - Supplies the device object to be tested.
3121 Return TRUE if the indicated device is a floppy.
3125 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3132 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3134 if (modeData
== NULL
) {
3138 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3140 length
= ScsiClassModeSense(DeviceObject
,
3143 MODE_SENSE_RETURN_ALL
);
3145 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3148 // Retry the request in case of a check condition.
3151 length
= ScsiClassModeSense(DeviceObject
,
3154 MODE_SENSE_RETURN_ALL
);
3156 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3158 ExFreePool(modeData
);
3165 // If the length is greater than length indicated by the mode data reset
3166 // the data to the mode data.
3169 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3170 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3174 // Look for the flexible disk mode page.
3177 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_FLEXIBILE
, TRUE
);
3179 if (pageData
!= NULL
) {
3181 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3182 ExFreePool(modeData
);
3187 // Check to see if the write cache is enabled.
3190 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3193 // Assume that write cache is disabled or not supported.
3196 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3199 // Check if valid caching page exists.
3202 if (pageData
!= NULL
) {
3205 // Check if write cache is disabled.
3208 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3211 "SCSIDISK: Disk write cache enabled\n"));
3214 // Check if forced unit access (FUA) is supported.
3217 if (((PMODE_PARAMETER_HEADER
)modeData
)->DeviceSpecificParameter
& MODE_DSP_FUA_SUPPORTED
) {
3219 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3224 "SCSIDISK: Disk does not support FUA or DPO\n"));
3234 ExFreePool(modeData
);
3237 } // end IsFloppyDevice()
3243 IN PDEVICE_OBJECT DeviceObject
,
3244 IN PCHAR ModeSelectBuffer
,
3251 Routine Description:
3253 This routine sends a mode select command.
3257 DeviceObject - Supplies the device object associated with this request.
3259 ModeSelectBuffer - Supplies a buffer containing the page data.
3261 Length - Supplies the length in bytes of the mode select buffer.
3263 SavePage - Indicates that parameters should be written to disk.
3267 Length of the transferred data is returned.
3271 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3273 SCSI_REQUEST_BLOCK srb
;
3278 PMODE_PARAMETER_BLOCK blockDescriptor
;
3282 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3285 // Allocate buffer for mode select header, block descriptor, and mode page.
3288 buffer
= (ULONG_PTR
)ExAllocatePool(NonPagedPoolCacheAligned
,length2
);
3290 RtlZeroMemory((PVOID
)buffer
, length2
);
3293 // Set length in header to size of mode page.
3296 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3298 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3304 blockDescriptor
->BlockLength
[1]=0x02;
3307 // Copy mode page to buffer.
3310 RtlCopyMemory((PVOID
)(buffer
+ 3), ModeSelectBuffer
, Length
);
3316 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3319 // Build the MODE SELECT CDB.
3323 cdb
= (PCDB
)srb
.Cdb
;
3326 // Set timeout value from device extension.
3329 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
3331 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3332 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3333 cdb
->MODE_SELECT
.PFBit
= 1;
3334 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3338 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3345 if (status
== STATUS_VERIFY_REQUIRED
) {
3348 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3361 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3362 status
= STATUS_SUCCESS
;
3365 ExFreePool((PVOID
)buffer
);
3367 if (NT_SUCCESS(status
)) {
3373 } // end SciDiskModeSelect()
3379 IN PDEVICE_OBJECT DeviceObject
,
3380 IN PSCSI_INQUIRY_DATA LunInfo
3384 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3385 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3386 BAD_CONTROLLER_INFORMATION
const *controller
;
3391 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
3393 controller
= &ScsiDiskBadControllers
[j
];
3395 if (!controller
->DisableWriteCache
|| strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
3399 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller
->InquiryString
));
3401 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3403 if (modeData
== NULL
) {
3406 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3410 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3412 length
= ScsiClassModeSense(DeviceObject
,
3415 MODE_SENSE_RETURN_ALL
);
3417 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3420 // Retry the request in case of a check condition.
3423 length
= ScsiClassModeSense(DeviceObject
,
3426 MODE_SENSE_RETURN_ALL
);
3428 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3432 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3434 ExFreePool(modeData
);
3441 // If the length is greater than length indicated by the mode data reset
3442 // the data to the mode data.
3445 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3446 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3450 // Check to see if the write cache is enabled.
3453 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3456 // Assume that write cache is disabled or not supported.
3459 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3462 // Check if valid caching page exists.
3465 if (pageData
!= NULL
) {
3467 BOOLEAN savePage
= FALSE
;
3469 savePage
= (BOOLEAN
)(((PMODE_CACHING_PAGE
)pageData
)->PageSavable
);
3472 // Check if write cache is disabled.
3475 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3477 PIO_ERROR_LOG_PACKET errorLogEntry
;
3482 // Disable write cache and ensure necessary fields are zeroed.
3485 ((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
= FALSE
;
3486 ((PMODE_CACHING_PAGE
)pageData
)->Reserved
= 0;
3487 ((PMODE_CACHING_PAGE
)pageData
)->PageSavable
= 0;
3488 ((PMODE_CACHING_PAGE
)pageData
)->Reserved2
= 0;
3491 // Extract length from caching page.
3494 length
= ((PMODE_CACHING_PAGE
)pageData
)->PageLength
;
3497 // Compensate for page code and page length.
3503 // Issue mode select to set the parameter.
3506 if (ScsiDiskModeSelect(DeviceObject
,
3512 "SCSIDISK: Disk write cache disabled\n"));
3514 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3515 errorCode
= IO_WRITE_CACHE_DISABLED
;
3518 if (ScsiDiskModeSelect(DeviceObject
,
3524 "SCSIDISK: Disk write cache disabled\n"));
3527 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3528 errorCode
= IO_WRITE_CACHE_DISABLED
;
3533 "SCSIDISK: Mode select to disable write cache failed\n"));
3535 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3536 errorCode
= IO_WRITE_CACHE_ENABLED
;
3541 // Log the appropriate informational or error entry.
3544 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3546 sizeof(IO_ERROR_LOG_PACKET
) + 3
3549 if (errorLogEntry
!= NULL
) {
3551 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3552 errorLogEntry
->ErrorCode
= errorCode
;
3553 errorLogEntry
->SequenceNumber
= 0;
3554 errorLogEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
3555 errorLogEntry
->IoControlCode
= 0;
3556 errorLogEntry
->RetryCount
= 0;
3557 errorLogEntry
->UniqueErrorValue
= 0x1;
3558 errorLogEntry
->DumpDataSize
= 3 * sizeof(ULONG
);
3559 errorLogEntry
->DumpData
[0] = LunInfo
->PathId
;
3560 errorLogEntry
->DumpData
[1] = LunInfo
->TargetId
;
3561 errorLogEntry
->DumpData
[2] = LunInfo
->Lun
;
3564 // Write the error log packet.
3567 IoWriteErrorLogEntry(errorLogEntry
);
3573 // Found device so exit the loop and return.
3585 CalculateMbrCheckSum(
3586 IN PDEVICE_EXTENSION DeviceExtension
,
3592 Routine Description:
3594 Read MBR and calculate checksum.
3598 DeviceExtension - Supplies a pointer to the device information for disk.
3599 Checksum - Memory location to return MBR checksum.
3603 Returns TRUE if checksum is valid.
3607 LARGE_INTEGER sectorZero
;
3609 IO_STATUS_BLOCK ioStatus
;
3617 sectorZero
.QuadPart
= (LONGLONG
) 0;
3620 // Create notification event object to be used to signal the inquiry
3621 // request completion.
3624 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
3630 sectorSize
= DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
3633 // Make sure sector size is at least 512 bytes.
3636 if (sectorSize
< 512) {
3641 // Allocate buffer for sector read.
3644 mbr
= ExAllocatePool(NonPagedPoolCacheAligned
, sectorSize
);
3651 // Build IRP to read MBR.
3654 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
3655 DeviceExtension
->DeviceObject
,
3668 // Pass request to port driver and wait for request to complete.
3671 status
= IoCallDriver(DeviceExtension
->DeviceObject
,
3674 if (status
== STATUS_PENDING
) {
3675 KeWaitForSingleObject(&event
,
3680 status
= ioStatus
.Status
;
3683 if (!NT_SUCCESS(status
)) {
3689 // Calculate MBR checksum.
3694 for (i
= 0; i
< 128; i
++) {
3695 *Checksum
+= mbr
[i
];
3698 *Checksum
= ~*Checksum
+ 1;
3708 IN PDEVICE_EXTENSION DeviceExtension
,
3715 Routine Description:
3717 The routine queries the registry to determine if this disk is visible to
3718 the BIOS. If the disk is visable to the BIOS, then the geometry information
3723 DeviceExtension - Supplies a pointer to the device information for disk.
3724 Signature - Unique identifier recorded in MBR.
3725 BusKey - Handle of bus key.
3726 DiskNumber - Returns ordinal of disk as BIOS sees it.
3730 TRUE is disk signature matched.
3734 PDISK_DATA diskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
3735 BOOLEAN diskFound
= FALSE
;
3736 OBJECT_ATTRIBUTES objectAttributes
;
3737 UNICODE_STRING unicodeString
;
3738 UNICODE_STRING identifier
;
3740 ULONG adapterNumber
;
3748 STRING anotherString
;
3751 PKEY_VALUE_FULL_INFORMATION keyData
;
3755 for (busNumber
= 0; ; busNumber
++) {
3758 // Open controller name key.
3761 sprintf((PCHAR
)buffer
,
3765 RtlInitString(&string
,
3768 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3772 if (!NT_SUCCESS(status
)){
3776 InitializeObjectAttributes(&objectAttributes
,
3778 OBJ_CASE_INSENSITIVE
,
3780 (PSECURITY_DESCRIPTOR
)NULL
);
3782 status
= ZwOpenKey(&spareKey
,
3786 RtlFreeUnicodeString(&unicodeString
);
3788 if (!NT_SUCCESS(status
)) {
3793 // Open up controller ordinal key.
3796 RtlInitUnicodeString(&unicodeString
, L
"DiskController");
3797 InitializeObjectAttributes(&objectAttributes
,
3799 OBJ_CASE_INSENSITIVE
,
3801 (PSECURITY_DESCRIPTOR
)NULL
);
3803 status
= ZwOpenKey(&adapterKey
,
3808 // This could fail even with additional adapters of this type
3812 if (!NT_SUCCESS(status
)) {
3816 for (adapterNumber
= 0; ; adapterNumber
++) {
3822 sprintf((PCHAR
)buffer
,
3823 "%lu\\DiskPeripheral",
3826 RtlInitString(&string
,
3829 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3833 if (!NT_SUCCESS(status
)){
3837 InitializeObjectAttributes(&objectAttributes
,
3839 OBJ_CASE_INSENSITIVE
,
3841 (PSECURITY_DESCRIPTOR
)NULL
);
3843 status
= ZwOpenKey(&diskKey
,
3847 RtlFreeUnicodeString(&unicodeString
);
3849 if (!NT_SUCCESS(status
)) {
3853 for (diskNumber
= 0; ; diskNumber
++) {
3855 sprintf((PCHAR
)buffer
,
3859 RtlInitString(&string
,
3862 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3866 if (!NT_SUCCESS(status
)){
3870 InitializeObjectAttributes(&objectAttributes
,
3872 OBJ_CASE_INSENSITIVE
,
3874 (PSECURITY_DESCRIPTOR
)NULL
);
3876 status
= ZwOpenKey(&targetKey
,
3880 RtlFreeUnicodeString(&unicodeString
);
3882 if (!NT_SUCCESS(status
)) {
3887 // Allocate buffer for registry query.
3890 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
3892 if (keyData
== NULL
) {
3898 // Get disk peripheral identifier.
3901 RtlInitUnicodeString(&unicodeString
, L
"Identifier");
3902 status
= ZwQueryValueKey(targetKey
,
3904 KeyValueFullInformation
,
3911 if (!NT_SUCCESS(status
)) {
3916 // Complete unicode string.
3920 (PWSTR
)((PUCHAR
)keyData
+ keyData
->DataOffset
);
3921 identifier
.Length
= (USHORT
)keyData
->DataLength
;
3922 identifier
.MaximumLength
= (USHORT
)keyData
->DataLength
;
3925 // Convert unicode identifier to ansi string.
3929 RtlUnicodeStringToAnsiString(&anotherString
,
3933 if (!NT_SUCCESS(status
)) {
3938 // If checksum is zero, then the MBR is valid and
3939 // the signature is meaningful.
3942 if (diskData
->MbrCheckSum
) {
3945 // Convert checksum to ansi string.
3948 sprintf((PCHAR
)buffer
, "%08lx", diskData
->MbrCheckSum
);
3953 // Convert signature to ansi string.
3956 sprintf((PCHAR
)buffer
, "%08lx", diskData
->Signature
);
3959 // Make string point at signature. Can't use scan
3960 // functions because they are not exported for driver use.
3963 anotherString
.Buffer
+=9;
3967 // Convert to ansi string.
3970 RtlInitString(&string
,
3975 // Make string lengths equal.
3978 anotherString
.Length
= string
.Length
;
3981 // Check if strings match.
3984 if (RtlCompareString(&string
,
3989 *DiskNumber
= diskNumber
;
3992 ExFreePool(keyData
);
3995 // Readjust indentifier string if necessary.
3998 if (!diskData
->MbrCheckSum
) {
3999 anotherString
.Buffer
-=9;
4002 RtlFreeAnsiString(&anotherString
);
4012 ZwClose(adapterKey
);
4018 } // end EnumerateBusKey()
4024 IN PDEVICE_EXTENSION DeviceExtension
4028 Routine Description:
4030 The routine queries the registry to determine if this disk is visible to
4031 the BIOS. If the disk is visable to the BIOS, then the geometry information
4036 DeviceExtension - Supplies a pointer to the device information for disk.
4045 OBJECT_ATTRIBUTES objectAttributes
;
4046 UNICODE_STRING unicodeString
;
4050 PCM_INT13_DRIVE_PARAMETER driveParameters
;
4051 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor
;
4052 PKEY_VALUE_FULL_INFORMATION keyData
;
4056 ULONG numberOfDrives
;
4059 ULONG sectorsPerTrack
;
4060 ULONG tracksPerCylinder
;
4061 BOOLEAN foundEZHooker
;
4067 // Initialize the object for the key.
4070 InitializeObjectAttributes(&objectAttributes
,
4071 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
4072 OBJ_CASE_INSENSITIVE
,
4074 (PSECURITY_DESCRIPTOR
) NULL
);
4077 // Create the hardware base key.
4080 status
= ZwOpenKey(&hardwareKey
,
4085 if (!NT_SUCCESS(status
)) {
4086 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
));
4092 // Get disk BIOS geometry information.
4095 RtlInitUnicodeString(&unicodeString
, L
"Configuration Data");
4097 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
4099 if (keyData
== NULL
) {
4100 ZwClose(hardwareKey
);
4104 status
= ZwQueryValueKey(hardwareKey
,
4106 KeyValueFullInformation
,
4111 if (!NT_SUCCESS(status
)) {
4113 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4115 ExFreePool(keyData
);
4120 // Open EISA bus key.
4123 RtlInitUnicodeString(&unicodeString
, L
"EisaAdapter");
4125 InitializeObjectAttributes(&objectAttributes
,
4127 OBJ_CASE_INSENSITIVE
,
4129 (PSECURITY_DESCRIPTOR
)NULL
);
4131 status
= ZwOpenKey(&busKey
,
4135 if (!NT_SUCCESS(status
)) {
4140 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4141 if (EnumerateBusKey(DeviceExtension
,
4145 ZwClose(hardwareKey
);
4152 // Open Multifunction bus key.
4155 RtlInitUnicodeString(&unicodeString
, L
"MultifunctionAdapter");
4157 InitializeObjectAttributes(&objectAttributes
,
4159 OBJ_CASE_INSENSITIVE
,
4161 (PSECURITY_DESCRIPTOR
)NULL
);
4163 status
= ZwOpenKey(&busKey
,
4167 ZwClose(hardwareKey
);
4168 if (NT_SUCCESS(status
)) {
4170 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4171 if (EnumerateBusKey(DeviceExtension
,
4179 ExFreePool(keyData
);
4184 resourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PUCHAR
)keyData
+
4185 keyData
->DataOffset
);
4188 // Check that the data is long enough to hold a full resource descriptor,
4189 // and that the last resouce list is device-specific and long enough.
4192 if (keyData
->DataLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) ||
4193 resourceDescriptor
->PartialResourceList
.Count
== 0 ||
4194 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].Type
!=
4195 CmResourceTypeDeviceSpecific
||
4196 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0]
4197 .u
.DeviceSpecificData
.DataSize
< sizeof(ULONG
)) {
4199 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4200 ExFreePool(keyData
);
4205 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
;
4208 // Point to the BIOS data. The BIOS data is located after the first
4209 // partial Resource list which should be device specific data.
4212 buffer
= (PUCHAR
) keyData
+ keyData
->DataOffset
+
4213 sizeof(CM_FULL_RESOURCE_DESCRIPTOR
);
4216 numberOfDrives
= length
/ sizeof(CM_INT13_DRIVE_PARAMETER
);
4219 // Use the defaults if the drive number is greater than the
4220 // number of drives detected by the BIOS.
4223 if (numberOfDrives
<= diskNumber
) {
4224 ExFreePool(keyData
);
4229 // Point to the array of drive parameters.
4232 driveParameters
= (PCM_INT13_DRIVE_PARAMETER
) buffer
+ diskNumber
;
4233 cylinders
= driveParameters
->MaxCylinders
+ 1;
4234 sectorsPerTrack
= driveParameters
->SectorsPerTrack
;
4235 tracksPerCylinder
= driveParameters
->MaxHeads
+1;
4238 // Calculate the actual number of sectors.
4241 sectors
= (ULONG
)(DeviceExtension
->PartitionLength
.QuadPart
>>
4242 DeviceExtension
->SectorShift
);
4245 if (sectors
>= cylinders
* tracksPerCylinder
* sectorsPerTrack
) {
4246 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4247 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4248 sectors
, cylinders
, tracksPerCylinder
, sectorsPerTrack
));
4253 // Since the BIOS may not report the full drive, recalculate the drive
4254 // size based on the volume size and the BIOS values for tracks per
4255 // cylinder and sectors per track..
4258 length
= tracksPerCylinder
* sectorsPerTrack
;
4263 // The BIOS information is bogus.
4266 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4267 ExFreePool(keyData
);
4271 cylinders
= sectors
/ length
;
4274 // Update the actual geometry information.
4277 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= sectorsPerTrack
;
4278 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
;
4279 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)cylinders
;
4280 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= cylinders
* tracksPerCylinder
* sectorsPerTrack
*
4281 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4284 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4289 ExFreePool(keyData
);
4291 foundEZHooker
= FALSE
;
4293 if (!DeviceExtension
->DMActive
) {
4295 HalExamineMBR(DeviceExtension
->DeviceObject
,
4296 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4304 foundEZHooker
= TRUE
;
4310 if (DeviceExtension
->DMActive
|| foundEZHooker
) {
4312 while (cylinders
> 1024) {
4314 tracksPerCylinder
= tracksPerCylinder
*2;
4315 cylinders
= cylinders
/2;
4320 // int 13 values are always 1 less.
4323 tracksPerCylinder
-= 1;
4327 // DM reserves the CE cylinder
4332 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= cylinders
+ 1;
4333 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
+ 1;
4335 DeviceExtension
->PartitionLength
.QuadPart
=
4336 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
=
4337 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
*
4338 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
*
4339 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
*
4340 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
;
4342 if (DeviceExtension
->DMActive
) {
4344 DeviceExtension
->DMByteSkew
= DeviceExtension
->DMSkew
* DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4350 DeviceExtension
->DMByteSkew
= 0;
4356 } // end UpdateGeometry()
4362 UpdateRemovableGeometry (
4363 IN PDEVICE_OBJECT DeviceObject
,
4369 Routine Description:
4371 This routines updates the size and starting offset of the device. This is
4372 used when the media on the device may have changed thereby changing the
4373 size of the device. If this is the physical device then a
4374 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4378 DeviceObject - Supplies the device object whos size needs to be updated.
4380 Irp - Supplies a reference where the status can be updated.
4384 Returns the status of the opertion.
4389 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4390 PDRIVE_LAYOUT_INFORMATION partitionList
;
4392 PDISK_DATA diskData
;
4393 ULONG partitionNumber
;
4396 // Determine if the size of the partition may have changed because
4397 // the media has changed.
4400 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
4402 return(STATUS_SUCCESS
);
4407 // If this request is for partition zero then do a read drive
4408 // capacity otherwise do a I/O read partition table.
4411 diskData
= (PDISK_DATA
) (deviceExtension
+ 1);
4414 // Read the drive capcity. If that fails, give up.
4417 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
4419 if (!NT_SUCCESS(status
)) {
4424 // Read the partition table agian.
4427 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
4428 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4433 if (!NT_SUCCESS(status
)) {
4436 // Fail the request.
4442 if (diskData
->PartitionNumber
!= 0 &&
4443 diskData
->PartitionNumber
<= partitionList
->PartitionCount
) {
4445 partitionNumber
= diskData
->PartitionNumber
- 1;
4448 // Update the partition information for this parition.
4451 diskData
->PartitionType
=
4452 partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
4454 diskData
->BootIndicator
=
4455 partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
4457 deviceExtension
->StartingOffset
=
4458 partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
4460 deviceExtension
->PartitionLength
=
4461 partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
4463 diskData
->HiddenSectors
=
4464 partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
4466 deviceExtension
->SectorShift
= ((PDEVICE_EXTENSION
)
4467 deviceExtension
->PhysicalDevice
->DeviceExtension
)->SectorShift
;
4469 } else if (diskData
->PartitionNumber
!= 0) {
4472 // The paritition does not exist. Zero all the data.
4475 diskData
->PartitionType
= 0;
4476 diskData
->BootIndicator
= 0;
4477 diskData
->HiddenSectors
= 0;
4478 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)0;
4479 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)0;
4483 // Free the parition list allocate by I/O read partition table.
4486 ExFreePool(partitionList
);
4489 return(STATUS_SUCCESS
);
4495 ScsiDiskProcessError(
4496 PDEVICE_OBJECT DeviceObject
,
4497 PSCSI_REQUEST_BLOCK Srb
,
4503 Routine Description:
4505 This routine checks the type of error. If the error indicates an underrun
4506 then indicate the request should be retried.
4510 DeviceObject - Supplies a pointer to the device object.
4512 Srb - Supplies a pointer to the failing Srb.
4514 Status - Status with which the IRP will be completed.
4516 Retry - Indication of whether the request will be retried.
4525 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4527 if (*Status
== STATUS_DATA_OVERRUN
&&
4528 ( Srb
->Cdb
[0] == SCSIOP_WRITE
|| Srb
->Cdb
[0] == SCSIOP_READ
)) {
4533 // Update the error count for the device.
4536 deviceExtension
->ErrorCount
++;
4539 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
4540 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
4543 // The disk drive should never be busy this long. Reset the scsi bus
4544 // maybe this will clear the condition.
4547 ResetScsiBus(DeviceObject
);
4550 // Update the error count for the device.
4553 deviceExtension
->ErrorCount
++;
4560 PDEVICE_OBJECT DeviceObject
,
4561 PSCSI_INQUIRY_DATA LunInfo
,
4562 PIO_SCSI_CAPABILITIES PortCapabilities
4567 Routine Description:
4569 This function checks to see if an SCSI logical unit requires speical
4574 DeviceObject - Supplies the device object to be tested.
4576 InquiryData - Supplies the inquiry data returned by the device of interest.
4578 PortCapabilities - Supplies the capabilities of the device object.
4587 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4588 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
4589 BAD_CONTROLLER_INFORMATION
const *controller
;
4592 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
4594 controller
= &ScsiDiskBadControllers
[j
];
4596 if (strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
4600 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller
->InquiryString
));
4603 // Found a listed controller. Determine what must be done.
4606 if (controller
->DisableTaggedQueuing
) {
4609 // Disable tagged queuing.
4612 deviceExtension
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
4615 if (controller
->DisableSynchronousTransfers
) {
4618 // Disable synchronous data transfers.
4621 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4625 if (controller
->DisableDisconnects
) {
4628 // Disable disconnects.
4631 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
4636 // Found device so exit the loop and return.
4643 // Set the StartUnit flag appropriately.
4646 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) {
4647 deviceExtension
->DeviceFlags
|= DEV_SAFE_START_UNIT
;
4649 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
4650 if (_strnicmp((PCCHAR
)InquiryData
->VendorId
, "iomega", strlen("iomega"))) {
4651 deviceExtension
->DeviceFlags
&= ~DEV_SAFE_START_UNIT
;
4662 IN PDEVICE_OBJECT DeviceObject
4667 Routine Description:
4669 This command sends a reset bus command to the SCSI port driver.
4673 DeviceObject - The device object for the logical unit with
4682 PIO_STACK_LOCATION irpStack
;
4684 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4685 PSCSI_REQUEST_BLOCK srb
;
4686 PCOMPLETION_CONTEXT context
;
4688 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4691 // Allocate Srb from nonpaged pool.
4694 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
4695 sizeof(COMPLETION_CONTEXT
));
4698 // Save the device object in the context for use by the completion
4702 context
->DeviceObject
= DeviceObject
;
4703 srb
= &context
->Srb
;
4709 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4712 // Write length to SRB.
4715 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4718 // Set up SCSI bus address.
4721 srb
->PathId
= deviceExtension
->PathId
;
4722 srb
->TargetId
= deviceExtension
->TargetId
;
4723 srb
->Lun
= deviceExtension
->Lun
;
4725 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4728 // Build the asynchronous request to be sent to the port driver.
4729 // Since this routine is called from a DPC the IRP should always be
4733 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
4735 IoSetCompletionRoutine(irp
,
4736 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
4742 irpStack
= IoGetNextIrpStackLocation(irp
);
4744 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4746 srb
->OriginalRequest
= irp
;
4749 // Store the SRB address in next stack for port driver.
4752 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4755 // Call the port driver with the IRP.
4758 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
4762 } // end ResetScsiBus()
4767 UpdateDeviceObjects(
4768 IN PDEVICE_OBJECT PhysicalDisk
,
4774 Routine Description:
4776 This routine creates, deletes and changes device objects when
4777 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4778 the drive layout information for the user. It is possible to
4779 call this routine even in the GET_LAYOUT case because RewritePartition
4784 DeviceObject - Device object for physical disk.
4785 Irp - IO Request Packet (IRP).
4793 PDEVICE_EXTENSION physicalExtension
= PhysicalDisk
->DeviceExtension
;
4794 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
4796 ULONG partitionNumber
;
4797 ULONG partitionCount
;
4798 ULONG lastPartition
;
4799 ULONG partitionOrdinal
;
4800 PPARTITION_INFORMATION partitionEntry
;
4801 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
4802 STRING ntNameString
;
4803 UNICODE_STRING ntUnicodeString
;
4804 PDEVICE_OBJECT deviceObject
;
4805 PDEVICE_EXTENSION deviceExtension
;
4806 PDISK_DATA diskData
;
4808 ULONG numberListElements
;
4811 partitionCount
= ((partitionList
->PartitionCount
+ 3) / 4) * 4;
4814 // Zero all of the partition numbers.
4817 for (partition
= 0; partition
< partitionCount
; partition
++) {
4818 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4819 partitionEntry
->PartitionNumber
= 0;
4823 // Walk through chain of partitions for this disk to determine
4824 // which existing partitions have no match.
4827 deviceExtension
= physicalExtension
;
4828 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4833 deviceExtension
= diskData
->NextPartition
;
4836 // Check if this is the last partition in the chain.
4839 if (!deviceExtension
) {
4844 // Get the partition device extension from disk data.
4847 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4850 // Check for highest partition number this far.
4853 if (diskData
->PartitionNumber
> lastPartition
) {
4854 lastPartition
= diskData
->PartitionNumber
;
4858 // Check if this partition is not currently being used.
4861 if (!deviceExtension
->PartitionLength
.QuadPart
) {
4866 // Loop through partition information to look for match.
4870 partitionOrdinal
= 0;
4872 for (partition
= 0; partition
< partitionCount
; partition
++) {
4875 // Get partition descriptor.
4878 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4881 // Check if empty, or describes extended partiton or hasn't changed.
4884 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4885 IsContainerPartition(partitionEntry
->PartitionType
)) {
4890 // Advance partition ordinal.
4896 // Check if new partition starts where this partition starts.
4899 if (partitionEntry
->StartingOffset
.QuadPart
!=
4900 deviceExtension
->StartingOffset
.QuadPart
) {
4905 // Check if partition length is the same.
4908 if (partitionEntry
->PartitionLength
.QuadPart
==
4909 deviceExtension
->PartitionLength
.QuadPart
) {
4912 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4913 physicalExtension
->DeviceNumber
,
4914 diskData
->PartitionNumber
));
4917 // Indicate match is found and set partition number
4922 partitionEntry
->PartitionNumber
= diskData
->PartitionNumber
;
4930 // A match is found.
4933 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4936 // If this partition is marked for update then update partition type.
4939 if (partitionEntry
->RewritePartition
) {
4940 diskData
->PartitionType
= partitionEntry
->PartitionType
;
4944 // Update partitional ordinal for calls to HAL routine
4945 // IoSetPartitionInformation.
4948 diskData
->PartitionOrdinal
= partitionOrdinal
;
4951 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4952 physicalExtension
->DeviceNumber
,
4953 diskData
->PartitionOrdinal
,
4954 diskData
->PartitionNumber
));
4959 // no match was found, indicate this partition is gone.
4963 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4964 physicalExtension
->DeviceNumber
,
4965 diskData
->PartitionNumber
));
4967 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
4973 // Walk through partition loop to find new partitions and set up
4974 // device extensions to describe them. In some cases new device
4975 // objects will be created.
4978 partitionOrdinal
= 0;
4981 partition
< partitionCount
;
4985 // Get partition descriptor.
4988 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4991 // Check if empty, or describes an extended partiton.
4994 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4995 IsContainerPartition(partitionEntry
->PartitionType
)) {
5000 // Keep track of position on the disk for calls to IoSetPartitionInformation.
5006 // Check if this entry should be rewritten.
5009 if (!partitionEntry
->RewritePartition
) {
5013 if (partitionEntry
->PartitionNumber
) {
5016 // Partition is an exact match with an existing partition, but is
5017 // being written anyway.
5024 // Check first if existing device object is available by
5025 // walking partition extension list.
5028 partitionNumber
= 0;
5029 deviceExtension
= physicalExtension
;
5030 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5035 // Get next partition device extension from disk data.
5038 deviceExtension
= diskData
->NextPartition
;
5040 if (!deviceExtension
) {
5044 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5047 // A device object is free if the partition length is set to zero.
5050 if (!deviceExtension
->PartitionLength
.QuadPart
) {
5051 partitionNumber
= diskData
->PartitionNumber
;
5058 // If partition number is still zero then a new device object
5062 if (partitionNumber
== 0) {
5065 partitionNumber
= lastPartition
;
5068 // Get or create partition object and set up partition parameters.
5071 sprintf(ntNameBuffer
,
5072 "\\Device\\Harddisk%lu\\Partition%lu",
5073 physicalExtension
->DeviceNumber
,
5076 RtlInitString(&ntNameString
,
5079 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
5083 if (!NT_SUCCESS(status
)) {
5088 "UpdateDeviceObjects: Create device object %s\n",
5092 // This is a new name. Create the device object to represent it.
5095 status
= IoCreateDevice(PhysicalDisk
->DriverObject
,
5096 DEVICE_EXTENSION_SIZE
,
5103 if (!NT_SUCCESS(status
)) {
5105 "UpdateDeviceObjects: Can't create device %s\n",
5107 RtlFreeUnicodeString(&ntUnicodeString
);
5112 // Set up device object fields.
5115 deviceObject
->Flags
|= DO_DIRECT_IO
;
5116 deviceObject
->StackSize
= PhysicalDisk
->StackSize
;
5119 // Set up device extension fields.
5122 deviceExtension
= deviceObject
->DeviceExtension
;
5125 // Copy physical disk extension to partition extension.
5128 RtlMoveMemory(deviceExtension
,
5130 sizeof(DEVICE_EXTENSION
));
5133 // Initialize the new S-List.
5136 if (deviceExtension
->SrbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
5137 numberListElements
= 30;
5139 numberListElements
= 8;
5143 // Build the lookaside list for srb's for this partition based on
5144 // whether the adapter and disk can do tagged queueing.
5147 ScsiClassInitializeSrbLookasideList(deviceExtension
,
5148 numberListElements
);
5151 // Allocate spinlock for zoning for split-request completion.
5154 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
5157 // Write back partition number used in creating object name.
5160 partitionEntry
->PartitionNumber
= partitionNumber
;
5163 // Clear flags initializing bit.
5166 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
5169 // Point back at device object.
5172 deviceExtension
->DeviceObject
= deviceObject
;
5174 RtlFreeUnicodeString(&ntUnicodeString
);
5177 // Link to end of partition chain using previous disk data.
5180 diskData
->NextPartition
= deviceExtension
;
5183 // Get new disk data and zero next partition pointer.
5186 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5187 diskData
->NextPartition
= NULL
;
5192 // Set pointer to disk data area that follows device extension.
5195 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5198 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5199 physicalExtension
->DeviceNumber
,
5204 // Update partition information in partition device extension.
5207 diskData
->PartitionNumber
= partitionNumber
;
5208 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5209 diskData
->BootIndicator
= partitionEntry
->BootIndicator
;
5210 deviceExtension
->StartingOffset
= partitionEntry
->StartingOffset
;
5211 deviceExtension
->PartitionLength
= partitionEntry
->PartitionLength
;
5212 diskData
->HiddenSectors
= partitionEntry
->HiddenSectors
;
5213 diskData
->PartitionOrdinal
= partitionOrdinal
;
5216 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5217 diskData
->PartitionOrdinal
,
5218 diskData
->PartitionNumber
));
5221 // Update partition number passed in to indicate the
5222 // device name for this partition.
5225 partitionEntry
->PartitionNumber
= partitionNumber
;
5228 } // end UpdateDeviceObjects()