2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/disk/disk.c
5 * PURPOSE: Disk class driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
15 #include <include/class2.h>
21 #define IO_WRITE_CACHE_ENABLED ((NTSTATUS)0x80040020L)
22 #define IO_WRITE_CACHE_DISABLED ((NTSTATUS)0x80040022L)
28 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
35 } PARTITION_LIST_STATE
;
41 typedef struct _DISK_DATA
{
47 PDEVICE_EXTENSION NextPartition
;
50 // Disk signature (from MBR)
62 // Number of hidden sectors for BPB.
68 // Partition number of this device object
70 // This field is set during driver initialization or when the partition
71 // is created to identify a parition to the system.
74 ULONG PartitionNumber
;
77 // This field is the ordinal of a partition as it appears on a disk.
80 ULONG PartitionOrdinal
;
83 // Partition type of this device object
85 // This field is set by:
87 // 1) Initially set according to the partition list entry partition
88 // type returned by IoReadPartitionTable.
90 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
91 // I/O control function when IoSetPartitionInformation function
92 // successfully updates the partition type on the disk.
98 // Boot indicator - indicates whether this partition is a bootable (active)
99 // partition for this device
101 // This field is set according to the partition list entry boot indicator
102 // returned by IoReadPartitionTable.
105 BOOLEAN BootIndicator
;
108 // DriveNotReady - inidicates that the this device is currenly not ready
109 // because there is no media in the device.
112 BOOLEAN DriveNotReady
;
115 // State of PartitionList initialization
118 PARTITION_LIST_STATE PartitionListState
;
120 } DISK_DATA
, *PDISK_DATA
;
123 // Define a general structure of identfing disk controllers with bad
127 typedef struct _BAD_CONTROLLER_INFORMATION
{
129 BOOLEAN DisableTaggedQueuing
;
130 BOOLEAN DisableSynchronousTransfers
;
131 BOOLEAN DisableDisconnects
;
132 BOOLEAN DisableWriteCache
;
133 }BAD_CONTROLLER_INFORMATION
, *PBAD_CONTROLLER_INFORMATION
;
135 BAD_CONTROLLER_INFORMATION
const ScsiDiskBadControllers
[] = {
136 { "TOSHIBA MK538FB 60", TRUE
, FALSE
, FALSE
, FALSE
},
137 { "CONNER CP3500", FALSE
, TRUE
, FALSE
, FALSE
},
138 { "OLIVETTICP3500", FALSE
, TRUE
, FALSE
, FALSE
},
139 { "SyQuest SQ5110 CHC", TRUE
, TRUE
, FALSE
, FALSE
},
140 { "SEAGATE ST41601N 0102", FALSE
, TRUE
, FALSE
, FALSE
},
141 { "SEAGATE ST3655N", FALSE
, FALSE
, FALSE
, TRUE
},
142 { "SEAGATE ST3390N", FALSE
, FALSE
, FALSE
, TRUE
},
143 { "SEAGATE ST12550N", FALSE
, FALSE
, FALSE
, TRUE
},
144 { "SEAGATE ST32430N", FALSE
, FALSE
, FALSE
, TRUE
},
145 { "SEAGATE ST31230N", FALSE
, FALSE
, FALSE
, TRUE
},
146 { "SEAGATE ST15230N", FALSE
, FALSE
, FALSE
, TRUE
},
147 { "FUJITSU M2652S-512", TRUE
, FALSE
, FALSE
, FALSE
},
148 { "MAXTOR MXT-540SL I1.2", TRUE
, FALSE
, FALSE
, FALSE
},
149 { "COMPAQ PD-1", FALSE
, TRUE
, FALSE
, FALSE
}
153 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
154 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
156 #define MODE_DATA_SIZE 192
157 #define VALUE_BUFFER_SIZE 2048
158 #define SCSI_DISK_TIMEOUT 10
159 #define PARTITION0_LIST_SIZE 4
165 IN PDRIVER_OBJECT DriverObject
,
166 IN PUNICODE_STRING RegistryPath
171 ScsiDiskDeviceVerification(
172 IN PINQUIRYDATA InquiryData
178 IN PDRIVER_OBJECT DriveObject
,
179 IN PUNICODE_STRING RegistryPath
,
180 IN PCLASS_INIT_DATA InitializationData
,
181 IN PDEVICE_OBJECT PortDeviceObject
,
187 ScsiDiskCreateClose (
188 IN PDEVICE_OBJECT DeviceObject
,
194 ScsiDiskReadWriteVerification(
195 IN PDEVICE_OBJECT DeviceObject
,
201 ScsiDiskDeviceControl(
202 IN PDEVICE_OBJECT DeviceObject
,
208 ScsiDiskProcessError(
209 PDEVICE_OBJECT DeviceObject
,
210 PSCSI_REQUEST_BLOCK Srb
,
217 ScsiDiskShutdownFlush(
218 IN PDEVICE_OBJECT DeviceObject
,
225 IN PDEVICE_OBJECT DeviceObject
,
226 IN PSCSI_INQUIRY_DATA LunInfo
232 IN PDEVICE_OBJECT DeviceObject
,
233 IN PCHAR ModeSelectBuffer
,
241 IN PDEVICE_OBJECT DeviceObject
246 CalculateMbrCheckSum(
247 IN PDEVICE_EXTENSION DeviceExtension
,
254 IN PDEVICE_EXTENSION DeviceExtension
,
262 IN PDEVICE_EXTENSION DeviceExtension
267 UpdateRemovableGeometry (
268 IN PDEVICE_OBJECT DeviceObject
,
274 CreateDiskDeviceObject(
275 IN PDRIVER_OBJECT DriverObject
,
276 IN PUNICODE_STRING RegistryPath
,
277 IN PDEVICE_OBJECT PortDeviceObject
,
279 IN PULONG DeviceCount
,
280 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
281 IN PSCSI_INQUIRY_DATA LunInfo
,
282 IN PCLASS_INIT_DATA InitData
287 CreatePartitionDeviceObjects(
288 IN PDEVICE_OBJECT PhysicalDeviceObject
,
289 IN PUNICODE_STRING RegistryPath
295 IN PDEVICE_OBJECT DeviceObject
,
302 PDEVICE_OBJECT DeviceObject
,
303 PSCSI_INQUIRY_DATA LunInfo
,
304 PIO_SCSI_CAPABILITIES PortCapabilities
310 IN PDEVICE_OBJECT DeviceObject
315 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject
,
319 #pragma alloc_text(PAGE, DriverEntry)
320 #pragma alloc_text(PAGE, FindScsiDisks)
321 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
322 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
323 #pragma alloc_text(PAGE, EnumerateBusKey)
324 #pragma alloc_text(PAGE, UpdateGeometry)
325 #pragma alloc_text(PAGE, IsFloppyDevice)
326 #pragma alloc_text(PAGE, ScanForSpecial)
327 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
328 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
335 IN PDRIVER_OBJECT DriverObject
,
336 IN PUNICODE_STRING RegistryPath
343 This routine initializes the SCSI hard disk class driver.
347 DriverObject - Pointer to driver object created by system.
349 RegistryPath - Pointer to the name of the services node for this driver.
353 The function value is the final status from the initialization operation.
358 CLASS_INIT_DATA InitializationData
;
364 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
370 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
371 InitializationData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
373 InitializationData
.DeviceType
= FILE_DEVICE_DISK
;
374 InitializationData
.DeviceCharacteristics
= 0;
380 InitializationData
.ClassError
= ScsiDiskProcessError
;
381 InitializationData
.ClassReadWriteVerification
= ScsiDiskReadWriteVerification
;
382 InitializationData
.ClassFindDevices
= FindScsiDisks
;
383 InitializationData
.ClassFindDeviceCallBack
= ScsiDiskDeviceVerification
;
384 InitializationData
.ClassDeviceControl
= ScsiDiskDeviceControl
;
385 InitializationData
.ClassShutdownFlush
= ScsiDiskShutdownFlush
;
386 InitializationData
.ClassCreateClose
= NULL
;
389 // Call the class init routine
392 return ScsiClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
394 } // end DriverEntry()
400 ScsiDiskDeviceVerification(
401 IN PINQUIRYDATA InquiryData
408 This routine checks InquiryData for the correct device type and qualifier.
412 InquiryData - Pointer to the inquiry data for the device in question.
416 True is returned if the correct device type is found.
421 if (((InquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
422 (InquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
423 InquiryData
->DeviceTypeQualifier
== 0) {
436 IN PDRIVER_OBJECT DriverObject
,
437 IN PUNICODE_STRING RegistryPath
,
438 IN PCLASS_INIT_DATA InitializationData
,
439 IN PDEVICE_OBJECT PortDeviceObject
,
447 This routine gets a port drivers capabilities, obtains the
448 inquiry data, searches the SCSI bus for the port driver and creates
449 the device objects for the disks found.
453 DriverObject - Pointer to driver object created by system.
455 PortDeviceObject - Device object use to send requests to port driver.
457 PortNumber - Number for port driver. Used to pass on to
458 CreateDiskDeviceObjects() and create device objects.
462 True is returned if one disk was found and successfully created.
467 PIO_SCSI_CAPABILITIES portCapabilities
;
469 PCONFIGURATION_INFORMATION configurationInformation
;
471 PSCSI_INQUIRY_DATA lunInfo
;
472 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
473 PINQUIRYDATA inquiryData
;
477 BOOLEAN foundOne
= FALSE
;
482 // Call port driver to get adapter capabilities.
485 status
= ScsiClassGetCapabilities(PortDeviceObject
, &portCapabilities
);
487 if (!NT_SUCCESS(status
)) {
488 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
493 // Call port driver to get inquiry information to find disks.
496 status
= ScsiClassGetInquiryData(PortDeviceObject
, (PSCSI_ADAPTER_BUS_INFO
*) &buffer
);
498 if (!NT_SUCCESS(status
)) {
499 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
504 // Do a quick scan of the devices on this adapter to determine how many
505 // disks are on this adapter. This is used to determine the number of
506 // SRB zone elements to allocate.
510 adapterInfo
= (PVOID
) buffer
;
512 adapterDisk
= ScsiClassFindUnclaimedDevices(InitializationData
, adapterInfo
);
515 // Allocate a zone of SRB for disks on this adapter.
518 if (adapterDisk
== 0) {
521 // No free disks were found.
528 // Get the number of disks already initialized.
531 configurationInformation
= IoGetConfigurationInformation();
532 diskCount
= &configurationInformation
->DiskCount
;
535 // For each SCSI bus this adapter supports ...
538 for (scsiBus
=0; scsiBus
< (ULONG
)adapterInfo
->NumberOfBuses
; scsiBus
++) {
541 // Get the SCSI bus scan data for this bus.
544 lunInfo
= (PVOID
) (buffer
+ adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
);
547 // Search list for unclaimed disk devices.
550 while (adapterInfo
->BusData
[scsiBus
].InquiryDataOffset
) {
552 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
554 if (((inquiryData
->DeviceType
== DIRECT_ACCESS_DEVICE
) ||
555 (inquiryData
->DeviceType
== OPTICAL_DEVICE
)) &&
556 inquiryData
->DeviceTypeQualifier
== 0 &&
557 (!lunInfo
->DeviceClaimed
)) {
560 "FindScsiDevices: Vendor string is %.24s\n",
561 inquiryData
->VendorId
));
564 // Create device objects for disk
567 status
= CreateDiskDeviceObject(DriverObject
,
576 if (NT_SUCCESS(status
)) {
579 // Increment system disk device count.
592 if (lunInfo
->NextInquiryDataOffset
== 0) {
596 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
602 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
609 } // end FindScsiDisks()
614 CreateDiskDeviceObject(
615 IN PDRIVER_OBJECT DriverObject
,
616 IN PUNICODE_STRING RegistryPath
,
617 IN PDEVICE_OBJECT PortDeviceObject
,
619 IN PULONG DeviceCount
,
620 IN PIO_SCSI_CAPABILITIES PortCapabilities
,
621 IN PSCSI_INQUIRY_DATA LunInfo
,
622 IN PCLASS_INIT_DATA InitData
629 This routine creates an object for the physical device and then searches
630 the device for partitions and creates an object for each partition.
634 DriverObject - Pointer to driver object created by system.
636 PortDeviceObject - Miniport device object.
638 PortNumber - port number. Used in creating disk objects.
640 DeviceCount - Number of previously installed devices.
642 PortCapabilities - Capabilities of this SCSI port.
644 LunInfo - LUN specific information.
652 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
654 UNICODE_STRING ntUnicodeString
;
655 OBJECT_ATTRIBUTES objectAttributes
;
658 PDEVICE_OBJECT deviceObject
= NULL
;
659 //PDEVICE_OBJECT physicalDevice;
660 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
661 PDEVICE_EXTENSION deviceExtension
= NULL
;
662 //PDEVICE_EXTENSION physicalDeviceExtension;
663 UCHAR pathId
= LunInfo
->PathId
;
664 UCHAR targetId
= LunInfo
->TargetId
;
665 UCHAR lun
= LunInfo
->Lun
;
666 //BOOLEAN writeCache;
667 PVOID senseData
= NULL
;
670 BOOLEAN srbListInitialized
= FALSE
;
676 // Set up an object directory to contain the objects for this
677 // device and all its partitions.
680 sprintf(ntNameBuffer
,
681 "\\Device\\Harddisk%lu",
684 RtlInitString(&ntNameString
,
687 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
691 if (!NT_SUCCESS(status
)) {
695 InitializeObjectAttributes(&objectAttributes
,
697 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
701 status
= ZwCreateDirectoryObject(&handle
,
702 DIRECTORY_ALL_ACCESS
,
705 RtlFreeUnicodeString(&ntUnicodeString
);
707 if (!NT_SUCCESS(status
)) {
710 "CreateDiskDeviceObjects: Could not create directory %s\n",
720 status
= ScsiClassClaimDevice(PortDeviceObject
,
725 if (!NT_SUCCESS(status
)) {
726 ZwMakeTemporaryObject(handle
);
732 // Create a device object for this device. Each physical disk will
733 // have at least one device object. The required device object
734 // describes the entire device. Its directory path is
735 // \Device\HarddiskN\Partition0, where N = device number.
738 sprintf(ntNameBuffer
,
739 "\\Device\\Harddisk%lu\\Partition0",
743 status
= ScsiClassCreateDeviceObject(DriverObject
,
749 if (!NT_SUCCESS(status
)) {
752 "CreateDiskDeviceObjects: Can not create device object %s\n",
755 goto CreateDiskDeviceObjectsExit
;
759 // Indicate that IRPs should include MDLs for data transfers.
762 deviceObject
->Flags
|= DO_DIRECT_IO
;
765 // Check if this is during initialization. If not indicate that
766 // system initialization already took place and this disk is ready
771 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
775 // Check for removable media support.
778 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->RemovableMedia
) {
779 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
783 // Set up required stack size in device object.
786 deviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
788 deviceExtension
= deviceObject
->DeviceExtension
;
791 // Allocate spinlock for split request completion.
794 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
797 // Initialize lock count to zero. The lock count is used to
798 // disable the ejection mechanism on devices that support
799 // removable media. Only the lock count in the physical
800 // device extension is used.
803 deviceExtension
->LockCount
= 0;
806 // Save system disk number.
809 deviceExtension
->DeviceNumber
= *DeviceCount
;
812 // Copy port device object pointer to the device extension.
815 deviceExtension
->PortDeviceObject
= PortDeviceObject
;
818 // Set the alignment requirements for the device based on the
819 // host adapter requirements
822 if (PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
823 deviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
827 // This is the physical device object.
830 //physicalDevice = deviceObject;
831 //physicalDeviceExtension = deviceExtension;
834 // Save address of port driver capabilities.
837 deviceExtension
->PortCapabilities
= PortCapabilities
;
840 // Build the lookaside list for srb's for the physical disk. Should only
844 ScsiClassInitializeSrbLookasideList(deviceExtension
,
845 PARTITION0_LIST_SIZE
);
847 srbListInitialized
= TRUE
;
850 // Initialize the srb flags.
853 if (((PINQUIRYDATA
)LunInfo
->InquiryData
)->CommandQueue
&&
854 PortCapabilities
->TaggedQueuing
) {
856 deviceExtension
->SrbFlags
= SRB_FLAGS_QUEUE_ACTION_ENABLE
;
860 deviceExtension
->SrbFlags
= 0;
865 // Allow queued requests if this is not removable media.
868 if (!(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
870 deviceExtension
->SrbFlags
|= SRB_FLAGS_NO_QUEUE_FREEZE
;
875 // Look for controller that require special flags.
878 ScanForSpecial(deviceObject
,
882 //srbFlags = deviceExtension->SrbFlags;
885 // Allocate buffer for drive geometry.
888 diskGeometry
= ExAllocatePool(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
));
890 if (diskGeometry
== NULL
) {
893 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
894 status
= STATUS_INSUFFICIENT_RESOURCES
;
895 goto CreateDiskDeviceObjectsExit
;
898 deviceExtension
->DiskGeometry
= diskGeometry
;
901 // Allocate request sense buffer.
904 senseData
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
906 if (senseData
== NULL
) {
909 // The buffer can not be allocated.
913 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
915 status
= STATUS_INSUFFICIENT_RESOURCES
;
916 goto CreateDiskDeviceObjectsExit
;
920 // Set the sense data pointer in the device extension.
923 deviceExtension
->SenseData
= senseData
;
926 // Physical device object will describe the entire
927 // device, starting at byte offset 0.
930 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)(0);
933 // TargetId/LUN describes a device location on the SCSI bus.
934 // This information comes from the inquiry buffer.
937 deviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
938 deviceExtension
->PathId
= pathId
;
939 deviceExtension
->TargetId
= targetId
;
940 deviceExtension
->Lun
= lun
;
943 // Set timeout value in seconds.
946 timeOut
= ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
948 deviceExtension
->TimeOutValue
= timeOut
;
950 deviceExtension
->TimeOutValue
= SCSI_DISK_TIMEOUT
;
954 // Back pointer to device object.
957 deviceExtension
->DeviceObject
= deviceObject
;
960 // If this is a removable device, then make sure it is not a floppy.
961 // Perform a mode sense command to determine the media type. Note
962 // IsFloppyDevice also checks for write cache enabled.
965 if (IsFloppyDevice(deviceObject
) && deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
966 (((PINQUIRYDATA
)LunInfo
->InquiryData
)->DeviceType
== DIRECT_ACCESS_DEVICE
)) {
968 status
= STATUS_NO_SUCH_DEVICE
;
969 goto CreateDiskDeviceObjectsExit
;
972 DisableWriteCache(deviceObject
,LunInfo
);
974 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
977 // NOTE: At this point one device object has been successfully created.
978 // from here on out return success.
982 // Do READ CAPACITY. This SCSI command
983 // returns the number of bytes on a device.
984 // Device extension is updated with device size.
987 status
= ScsiClassReadDriveCapacity(deviceObject
);
990 // If the read capcity failed then just return, unless this is a
991 // removable disk where a device object partition needs to be created.
994 if (!NT_SUCCESS(status
) &&
995 !(deviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
998 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
1001 return(STATUS_SUCCESS
);
1006 // Make sure the volume verification bit is off so that
1007 // IoReadPartitionTable will work.
1010 deviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
1013 status
= CreatePartitionDeviceObjects(deviceObject
, RegistryPath
);
1015 if (NT_SUCCESS(status
))
1016 return STATUS_SUCCESS
;
1019 CreateDiskDeviceObjectsExit
:
1022 // Release the device since an error occurred.
1025 ScsiClassClaimDevice(PortDeviceObject
,
1030 if (diskGeometry
!= NULL
) {
1031 ExFreePool(diskGeometry
);
1034 if (senseData
!= NULL
) {
1035 ExFreePool(senseData
);
1038 if (deviceObject
!= NULL
) {
1040 if (srbListInitialized
) {
1041 ExDeleteNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
1044 IoDeleteDevice(deviceObject
);
1048 // Delete directory and return.
1051 if (!NT_SUCCESS(status
)) {
1052 ZwMakeTemporaryObject(handle
);
1059 } // end CreateDiskDeviceObjects()
1064 CreatePartitionDeviceObjects(
1065 IN PDEVICE_OBJECT PhysicalDeviceObject
,
1066 IN PUNICODE_STRING RegistryPath
1069 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
1070 ULONG partitionNumber
= 0;
1072 PDEVICE_OBJECT deviceObject
= NULL
;
1073 PDISK_GEOMETRY_EX diskGeometry
= NULL
;
1074 PDRIVE_LAYOUT_INFORMATION partitionList
= NULL
;
1075 PDEVICE_EXTENSION deviceExtension
;
1076 PDEVICE_EXTENSION physicalDeviceExtension
;
1077 PCLASS_INIT_DATA initData
= NULL
;
1078 PDISK_DATA diskData
;
1079 PDISK_DATA physicalDiskData
;
1080 ULONG bytesPerSector
;
1083 ULONG dmByteSkew
= 0;
1085 BOOLEAN dmActive
= FALSE
;
1086 ULONG numberListElements
= 0;
1090 // Get physical device geometry information for partition table reads.
1093 physicalDeviceExtension
= PhysicalDeviceObject
->DeviceExtension
;
1094 diskGeometry
= physicalDeviceExtension
->DiskGeometry
;
1095 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
;
1098 // Make sure sector size is not zero.
1101 if (bytesPerSector
== 0) {
1104 // Default sector size for disk is 512.
1107 bytesPerSector
= diskGeometry
->Geometry
.BytesPerSector
= 512;
1110 sectorShift
= physicalDeviceExtension
->SectorShift
;
1113 // Set pointer to disk data area that follows device extension.
1116 diskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1117 diskData
->PartitionListState
= Initializing
;
1120 // Determine is DM Driver is loaded on an IDE drive that is
1121 // under control of Atapi - this could be either a crashdump or
1122 // an Atapi device is sharing the controller with an IDE disk.
1125 HalExamineMBR(PhysicalDeviceObject
,
1126 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1133 // Update the device extension, so that the call to IoReadPartitionTable
1134 // will get the correct information. Any I/O to this disk will have
1135 // to be skewed by *dmSkew sectors aka DMByteSkew.
1138 physicalDeviceExtension
->DMSkew
= *dmSkew
;
1139 physicalDeviceExtension
->DMActive
= TRUE
;
1140 physicalDeviceExtension
->DMByteSkew
= physicalDeviceExtension
->DMSkew
* bytesPerSector
;
1143 // Save away the infomation that we need, since this deviceExtension will soon be
1148 dmByteSkew
= physicalDeviceExtension
->DMByteSkew
;
1153 // Create objects for all the partitions on the device.
1156 status
= IoReadPartitionTable(PhysicalDeviceObject
,
1157 physicalDeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
1159 (PVOID
)&partitionList
);
1162 // If the I/O read partition table failed and this is a removable device,
1163 // then fix up the partition list to make it look like there is one
1164 // zero length partition.
1166 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status
);
1167 if ((!NT_SUCCESS(status
) || partitionList
->PartitionCount
== 0) &&
1168 PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1170 if (!NT_SUCCESS(status
)) {
1173 // Remember this disk is not ready.
1176 diskData
->DriveNotReady
= TRUE
;
1181 // Free the partition list allocated by IoReadPartitionTable.
1184 ExFreePool(partitionList
);
1188 // Allocate and zero a partition list.
1191 partitionList
= ExAllocatePool(NonPagedPool
, sizeof(*partitionList
));
1194 if (partitionList
!= NULL
) {
1196 RtlZeroMemory( partitionList
, sizeof( *partitionList
));
1199 // Set the partition count to one and the status to success
1200 // so one device object will be created. Set the partition type
1201 // to a bogus value.
1204 partitionList
->PartitionCount
= 1;
1206 status
= STATUS_SUCCESS
;
1210 if (NT_SUCCESS(status
)) {
1213 // Record disk signature.
1216 diskData
->Signature
= partitionList
->Signature
;
1219 // If disk signature is zero, then calculate the MBR checksum.
1222 if (!diskData
->Signature
) {
1224 if (!CalculateMbrCheckSum(physicalDeviceExtension
,
1225 &diskData
->MbrCheckSum
)) {
1228 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1229 physicalDeviceExtension
->DeviceNumber
));
1233 "SCSIDISK: MBR checksum for disk %x is %x\n",
1234 physicalDeviceExtension
->DeviceNumber
,
1235 diskData
->MbrCheckSum
));
1240 // Check the registry and determine if the BIOS knew about this drive. If
1241 // it did then update the geometry with the BIOS information.
1244 UpdateGeometry(physicalDeviceExtension
);
1246 srbFlags
= physicalDeviceExtension
->SrbFlags
;
1248 initData
= ExAllocatePool(NonPagedPool
, sizeof(CLASS_INIT_DATA
));
1252 "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n"));
1254 status
= STATUS_INSUFFICIENT_RESOURCES
;
1255 goto CreatePartitionDeviceObjectsExit
;
1258 RtlZeroMemory(initData
, sizeof(CLASS_INIT_DATA
));
1260 initData
->InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
1261 initData
->DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
1262 initData
->DeviceType
= FILE_DEVICE_DISK
;
1263 initData
->DeviceCharacteristics
= PhysicalDeviceObject
->Characteristics
;
1264 initData
->ClassError
= physicalDeviceExtension
->ClassError
;
1265 initData
->ClassReadWriteVerification
= physicalDeviceExtension
->ClassReadWriteVerification
;
1266 initData
->ClassFindDevices
= physicalDeviceExtension
->ClassFindDevices
;
1267 initData
->ClassDeviceControl
= physicalDeviceExtension
->ClassDeviceControl
;
1268 initData
->ClassShutdownFlush
= physicalDeviceExtension
->ClassShutdownFlush
;
1269 initData
->ClassCreateClose
= physicalDeviceExtension
->ClassCreateClose
;
1270 initData
->ClassStartIo
= physicalDeviceExtension
->ClassStartIo
;
1273 // Create device objects for the device partitions (if any).
1274 // PartitionCount includes physical device partition 0,
1275 // so only one partition means no objects to create.
1279 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1280 partitionList
->PartitionCount
));
1282 for (partitionNumber
= 0; partitionNumber
<
1283 partitionList
->PartitionCount
; partitionNumber
++) {
1286 // Create partition object and set up partition parameters.
1289 sprintf(ntNameBuffer
,
1290 "\\Device\\Harddisk%lu\\Partition%lu",
1291 physicalDeviceExtension
->DeviceNumber
,
1292 partitionNumber
+ 1);
1295 "CreateDiskDeviceObjects: Create device object %s\n",
1298 status
= ScsiClassCreateDeviceObject(PhysicalDeviceObject
->DriverObject
,
1300 PhysicalDeviceObject
,
1304 if (!NT_SUCCESS(status
)) {
1306 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer
));
1312 // Set up device object fields.
1315 deviceObject
->Flags
|= DO_DIRECT_IO
;
1318 // Check if this is during initialization. If not indicate that
1319 // system initialization already took place and this disk is ready
1323 if (!RegistryPath
) {
1324 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1327 deviceObject
->StackSize
= (CCHAR
)physicalDeviceExtension
->PortDeviceObject
->StackSize
+ 1;
1330 // Set up device extension fields.
1333 deviceExtension
= deviceObject
->DeviceExtension
;
1338 // Restore any saved DM values.
1341 deviceExtension
->DMByteSkew
= dmByteSkew
;
1342 deviceExtension
->DMSkew
= *dmSkew
;
1343 deviceExtension
->DMActive
= TRUE
;
1348 // Link new device extension to previous disk data
1349 // to support dynamic partitioning.
1352 diskData
->NextPartition
= deviceExtension
;
1355 // Get pointer to new disk data.
1358 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1361 // Set next partition pointer to NULL in case this is the
1365 diskData
->NextPartition
= NULL
;
1368 // Allocate spinlock for zoning for split-request completion.
1371 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
1374 // Copy port device object pointer to device extension.
1377 deviceExtension
->PortDeviceObject
= physicalDeviceExtension
->PortDeviceObject
;
1380 // Set the alignment requirements for the device based on the
1381 // host adapter requirements
1384 if (physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
1385 deviceObject
->AlignmentRequirement
= physicalDeviceExtension
->PortDeviceObject
->AlignmentRequirement
;
1389 if (srbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
1390 numberListElements
= 30;
1392 numberListElements
= 8;
1396 // Build the lookaside list for srb's for this partition based on
1397 // whether the adapter and disk can do tagged queueing.
1400 ScsiClassInitializeSrbLookasideList(deviceExtension
,
1401 numberListElements
);
1403 deviceExtension
->SrbFlags
= srbFlags
;
1406 // Set the sense-data pointer in the device extension.
1409 deviceExtension
->SenseData
= physicalDeviceExtension
->SenseData
;
1410 deviceExtension
->PortCapabilities
= physicalDeviceExtension
->PortCapabilities
;
1411 deviceExtension
->DiskGeometry
= diskGeometry
;
1412 diskData
->PartitionOrdinal
= diskData
->PartitionNumber
= partitionNumber
+ 1;
1413 diskData
->PartitionType
= partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
1414 diskData
->BootIndicator
= partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
1416 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1417 diskData
->PartitionType
));
1419 deviceExtension
->StartingOffset
= partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
1420 deviceExtension
->PartitionLength
= partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
1421 diskData
->HiddenSectors
= partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
1422 deviceExtension
->PortNumber
= physicalDeviceExtension
->PortNumber
;
1423 deviceExtension
->PathId
= physicalDeviceExtension
->PathId
;
1424 deviceExtension
->TargetId
= physicalDeviceExtension
->TargetId
;
1425 deviceExtension
->Lun
= physicalDeviceExtension
->Lun
;
1428 // Check for removable media support.
1431 if (PhysicalDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1432 deviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
1436 // Set timeout value in seconds.
1439 deviceExtension
->TimeOutValue
= physicalDeviceExtension
->TimeOutValue
;
1440 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= bytesPerSector
;
1441 deviceExtension
->SectorShift
= sectorShift
;
1442 deviceExtension
->DeviceObject
= deviceObject
;
1443 deviceExtension
->DeviceFlags
|= physicalDeviceExtension
->DeviceFlags
;
1445 } // end for (partitionNumber) ...
1448 // Free the buffer allocated by reading the
1452 ExFreePool(partitionList
);
1460 CreatePartitionDeviceObjectsExit
:
1462 if (partitionList
) {
1463 ExFreePool(partitionList
);
1466 ExFreePool(initData
);
1478 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
1479 physicalDiskData
->PartitionListState
= Initialized
;
1481 return(STATUS_SUCCESS
);
1484 } // end CreatePartitionDeviceObjects()
1489 ScsiDiskReadWriteVerification(
1490 IN PDEVICE_OBJECT DeviceObject
,
1496 Routine Description:
1498 I/O System entry for read and write requests to SCSI disks.
1502 DeviceObject - Pointer to driver object created by system.
1512 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1513 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1514 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1515 LARGE_INTEGER startingOffset
;
1518 // Verify parameters of this request.
1519 // Check that ending sector is within partition and
1520 // that number of bytes to transfer is a multiple of
1524 startingOffset
.QuadPart
= (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
1527 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
1528 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
1531 // This error maybe caused by the fact that the drive is not ready.
1534 if (((PDISK_DATA
)(deviceExtension
+ 1))->DriveNotReady
) {
1537 // Flag this as a user errror so that a popup is generated.
1540 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
1541 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1546 // Note fastfat depends on this parameter to determine when to
1547 // remount do to a sector size change.
1550 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1553 DPRINT1("STATUS_INVALID_PARAMETER\n");
1554 return STATUS_INVALID_PARAMETER
;
1557 return STATUS_SUCCESS
;
1559 } // end ScsiDiskReadWrite()
1564 ScsiDiskDeviceControl(
1565 PDEVICE_OBJECT DeviceObject
,
1571 Routine Description:
1573 I/O system entry for device controls to SCSI disks.
1577 DeviceObject - Pointer to driver object created by system.
1587 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1588 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1589 PDISK_DATA diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1590 PSCSI_REQUEST_BLOCK srb
;
1592 PMODE_PARAMETER_HEADER modeData
;
1597 IO_STATUS_BLOCK ioStatus
;
1601 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
1605 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1606 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1607 return(STATUS_INSUFFICIENT_RESOURCES
);
1611 // Write zeros to Srb.
1614 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1616 cdb
= (PCDB
)srb
->Cdb
;
1618 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1620 case SMART_GET_VERSION
: {
1623 PSRB_IO_CONTROL srbControl
;
1624 PGETVERSIONINPARAMS versionParams
;
1626 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1627 sizeof(GETVERSIONINPARAMS
)) {
1628 status
= STATUS_INVALID_PARAMETER
;
1633 // Create notification event object to be used to signal the
1634 // request completion.
1637 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1639 srbControl
= ExAllocatePool(NonPagedPool
,
1640 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
));
1643 status
= STATUS_INSUFFICIENT_RESOURCES
;
1648 // fill in srbControl fields
1651 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1652 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1653 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1654 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1655 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1658 // Point to the 'buffer' portion of the SRB_CONTROL
1661 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1664 // Ensure correct target is set in the cmd parameters.
1667 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1668 versionParams
->bIDEDeviceMap
= deviceExtension
->TargetId
;
1671 // Copy the IOCTL parameters to the srb control buffer area.
1674 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(GETVERSIONINPARAMS
));
1677 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1678 deviceExtension
->PortDeviceObject
,
1680 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1682 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1688 status
= STATUS_INSUFFICIENT_RESOURCES
;
1693 // Call the port driver with the request and wait for it to complete.
1696 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1698 if (status
== STATUS_PENDING
) {
1699 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1700 status
= ioStatus
.Status
;
1704 // If successful, copy the data received into the output buffer.
1705 // This should only fail in the event that the IDE driver is older than this driver.
1708 if (NT_SUCCESS(status
)) {
1710 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1712 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, sizeof(GETVERSIONINPARAMS
));
1713 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1716 ExFreePool(srbControl
);
1720 case SMART_RCV_DRIVE_DATA
: {
1722 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1723 ULONG controlCode
= 0;
1724 PSRB_IO_CONTROL srbControl
;
1727 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1728 (sizeof(SENDCMDINPARAMS
) - 1)) {
1729 status
= STATUS_INVALID_PARAMETER
;
1732 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1733 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1734 status
= STATUS_INVALID_PARAMETER
;
1739 // Create notification event object to be used to signal the
1740 // request completion.
1743 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1745 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1747 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1748 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1750 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1751 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1752 case READ_ATTRIBUTES
:
1753 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1754 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1756 case READ_THRESHOLDS
:
1757 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1758 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1761 status
= STATUS_INVALID_PARAMETER
;
1766 status
= STATUS_INVALID_PARAMETER
;
1769 if (controlCode
== 0) {
1770 status
= STATUS_INVALID_PARAMETER
;
1774 srbControl
= ExAllocatePool(NonPagedPool
,
1775 sizeof(SRB_IO_CONTROL
) + length
);
1778 status
= STATUS_INSUFFICIENT_RESOURCES
;
1783 // fill in srbControl fields
1786 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1787 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1788 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1789 srbControl
->Length
= length
;
1790 srbControl
->ControlCode
= controlCode
;
1793 // Point to the 'buffer' portion of the SRB_CONTROL
1796 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1799 // Ensure correct target is set in the cmd parameters.
1802 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1805 // Copy the IOCTL parameters to the srb control buffer area.
1808 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1810 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1811 deviceExtension
->PortDeviceObject
,
1813 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1815 sizeof(SRB_IO_CONTROL
) + length
,
1821 status
= STATUS_INSUFFICIENT_RESOURCES
;
1826 // Call the port driver with the request and wait for it to complete.
1829 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1831 if (status
== STATUS_PENDING
) {
1832 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1833 status
= ioStatus
.Status
;
1837 // If successful, copy the data received into the output buffer
1840 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1842 if (NT_SUCCESS(status
)) {
1844 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
- 1);
1845 Irp
->IoStatus
.Information
= length
- 1;
1849 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1850 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1854 ExFreePool(srbControl
);
1859 case SMART_SEND_DRIVE_COMMAND
: {
1861 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1862 PSRB_IO_CONTROL srbControl
;
1863 ULONG controlCode
= 0;
1866 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1867 (sizeof(SENDCMDINPARAMS
) - 1)) {
1868 status
= STATUS_INVALID_PARAMETER
;
1871 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1872 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1873 status
= STATUS_INVALID_PARAMETER
;
1878 // Create notification event object to be used to signal the
1879 // request completion.
1882 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1886 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1887 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1890 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1894 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1897 case RETURN_SMART_STATUS
:
1900 // Ensure bBuffer is at least 2 bytes (to hold the values of
1901 // cylinderLow and cylinderHigh).
1904 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1905 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1907 status
= STATUS_INVALID_PARAMETER
;
1911 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1912 length
= sizeof(IDEREGS
);
1915 case ENABLE_DISABLE_AUTOSAVE
:
1916 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1919 case SAVE_ATTRIBUTE_VALUES
:
1920 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1923 case EXECUTE_OFFLINE_DIAGS
:
1924 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1928 status
= STATUS_INVALID_PARAMETER
;
1933 status
= STATUS_INVALID_PARAMETER
;
1936 if (controlCode
== 0) {
1937 status
= STATUS_INVALID_PARAMETER
;
1941 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1942 srbControl
= ExAllocatePool(NonPagedPool
,
1943 sizeof(SRB_IO_CONTROL
) + length
);
1946 status
= STATUS_INSUFFICIENT_RESOURCES
;
1951 // fill in srbControl fields
1954 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1955 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1956 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1957 srbControl
->Length
= length
;
1960 // Point to the 'buffer' portion of the SRB_CONTROL
1963 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1966 // Ensure correct target is set in the cmd parameters.
1969 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1972 // Copy the IOCTL parameters to the srb control buffer area.
1975 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1977 srbControl
->ControlCode
= controlCode
;
1979 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1980 deviceExtension
->PortDeviceObject
,
1982 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1984 sizeof(SRB_IO_CONTROL
) + length
,
1990 status
= STATUS_INSUFFICIENT_RESOURCES
;
1995 // Call the port driver with the request and wait for it to complete.
1998 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2000 if (status
== STATUS_PENDING
) {
2001 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2002 status
= ioStatus
.Status
;
2006 // Copy the data received into the output buffer. Since the status buffer
2007 // contains error information also, always perform this copy. IO will will
2008 // either pass this back to the app, or zero it, in case of error.
2011 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2014 // Update the return buffer size based on the sub-command.
2017 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
2018 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
2020 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
2023 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
);
2024 Irp
->IoStatus
.Information
= length
;
2026 ExFreePool(srbControl
);
2031 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2032 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2035 PDEVICE_EXTENSION physicalDeviceExtension
;
2036 PDISK_DATA physicalDiskData
;
2037 BOOLEAN removable
= FALSE
;
2038 BOOLEAN listInitialized
= FALSE
;
2040 if ((irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
&&
2041 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2042 sizeof(DISK_GEOMETRY
)) ||
2043 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
&&
2044 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2045 sizeof(DISK_GEOMETRY_EX
))) {
2047 status
= STATUS_INFO_LENGTH_MISMATCH
;
2051 status
= STATUS_SUCCESS
;
2053 physicalDeviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2054 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
2056 removable
= (BOOLEAN
)DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
;
2057 listInitialized
= (physicalDiskData
->PartitionListState
== Initialized
);
2059 if (removable
|| (!listInitialized
))
2062 // Issue ReadCapacity to update device extension
2063 // with information for current media.
2066 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
2072 if (!NT_SUCCESS(status
)) {
2075 // Note the drive is not ready.
2078 diskData
->DriveNotReady
= TRUE
;
2084 // Note the drive is now ready.
2087 diskData
->DriveNotReady
= FALSE
;
2089 } else if (NT_SUCCESS(status
)) {
2091 // ReadDriveCapacity was allright, create Partition Objects
2093 if (physicalDiskData
->PartitionListState
== NotInitialized
) {
2094 status
= CreatePartitionDeviceObjects(deviceExtension
->PhysicalDevice
, NULL
);
2098 if (NT_SUCCESS(status
)) {
2101 // Copy drive geometry information from device extension.
2104 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2105 deviceExtension
->DiskGeometry
,
2106 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2107 sizeof(DISK_GEOMETRY
) :
2108 sizeof(DISK_GEOMETRY_EX
));
2110 status
= STATUS_SUCCESS
;
2111 Irp
->IoStatus
.Information
=
2112 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2113 sizeof(DISK_GEOMETRY
) :
2114 sizeof(DISK_GEOMETRY_EX
);
2121 case IOCTL_DISK_VERIFY
:
2125 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2126 LARGE_INTEGER byteOffset
;
2131 // Validate buffer length.
2134 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2135 sizeof(VERIFY_INFORMATION
)) {
2137 status
= STATUS_INFO_LENGTH_MISMATCH
;
2145 srb
->CdbLength
= 10;
2147 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2150 // Add disk offset to starting sector.
2153 byteOffset
.QuadPart
= deviceExtension
->StartingOffset
.QuadPart
+
2154 verifyInfo
->StartingOffset
.QuadPart
;
2157 // Convert byte offset to sector offset.
2160 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2163 // Convert ULONG byte count to USHORT sector count.
2166 sectorCount
= (USHORT
)(verifyInfo
->Length
>> deviceExtension
->SectorShift
);
2169 // Move little endian values into CDB in big endian format.
2172 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2173 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2174 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2175 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2177 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2178 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2181 // The verify command is used by the NT FORMAT utility and
2182 // requests are sent down for 5% of the volume size. The
2183 // request timeout value is calculated based on the number of
2184 // sectors verified.
2187 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2188 deviceExtension
->TimeOutValue
;
2190 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
2201 case IOCTL_DISK_GET_PARTITION_INFO
:
2204 // Return the information about the partition specified by the device
2205 // object. Note that no information is ever returned about the size
2206 // or partition type of the physical disk, as this doesn't make any
2210 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2211 sizeof(PARTITION_INFORMATION
)) {
2213 status
= STATUS_INFO_LENGTH_MISMATCH
;
2216 #if 0 // HACK: ReactOS partition numbers must be wrong
2217 else if (diskData
->PartitionNumber
== 0) {
2220 // Paritition zero is not a partition so this is not a
2221 // reasonable request.
2224 status
= STATUS_INVALID_DEVICE_REQUEST
;
2230 PPARTITION_INFORMATION outputBuffer
;
2233 // Update the geometry in case it has changed.
2236 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2238 if (!NT_SUCCESS(status
)) {
2241 // Note the drive is not ready.
2244 diskData
->DriveNotReady
= TRUE
;
2249 // Note the drive is now ready.
2252 diskData
->DriveNotReady
= FALSE
;
2253 // HACK: ReactOS partition numbers must be wrong (>0 part)
2254 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2256 status
= STATUS_INVALID_DEVICE_REQUEST
;
2261 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2263 outputBuffer
->PartitionType
= diskData
->PartitionType
;
2264 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2265 outputBuffer
->PartitionLength
.QuadPart
= (diskData
->PartitionNumber
) ?
2266 deviceExtension
->PartitionLength
.QuadPart
: 2305843009213693951LL; // HACK
2267 outputBuffer
->HiddenSectors
= diskData
->HiddenSectors
;
2268 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2269 outputBuffer
->BootIndicator
= diskData
->BootIndicator
;
2270 outputBuffer
->RewritePartition
= FALSE
;
2271 outputBuffer
->RecognizedPartition
=
2272 IsRecognizedPartition(diskData
->PartitionType
);
2274 status
= STATUS_SUCCESS
;
2275 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2280 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2283 // Return the information about the partition specified by the device
2284 // object. Note that no information is ever returned about the size
2285 // or partition type of the physical disk, as this doesn't make any
2289 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2290 sizeof(PARTITION_INFORMATION_EX
)) {
2292 status
= STATUS_INFO_LENGTH_MISMATCH
;
2295 else if (diskData
->PartitionNumber
== 0) {
2298 // Paritition zero is not a partition so this is not a
2299 // reasonable request.
2302 status
= STATUS_INVALID_DEVICE_REQUEST
;
2307 PPARTITION_INFORMATION_EX outputBuffer
;
2310 // Update the geometry in case it has changed.
2313 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2315 if (!NT_SUCCESS(status
)) {
2318 // Note the drive is not ready.
2321 diskData
->DriveNotReady
= TRUE
;
2326 // Note the drive is now ready.
2329 diskData
->DriveNotReady
= FALSE
;
2331 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2333 status
= STATUS_INVALID_DEVICE_REQUEST
;
2338 (PPARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
2341 // FIXME: hack of the year, assume that partition is MBR
2342 // Thing that can obviously be wrong...
2345 outputBuffer
->PartitionStyle
= PARTITION_STYLE_MBR
;
2346 outputBuffer
->Mbr
.PartitionType
= diskData
->PartitionType
;
2347 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2348 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2349 outputBuffer
->Mbr
.HiddenSectors
= diskData
->HiddenSectors
;
2350 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2351 outputBuffer
->Mbr
.BootIndicator
= diskData
->BootIndicator
;
2352 outputBuffer
->RewritePartition
= FALSE
;
2353 outputBuffer
->Mbr
.RecognizedPartition
=
2354 IsRecognizedPartition(diskData
->PartitionType
);
2356 status
= STATUS_SUCCESS
;
2357 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
2362 case IOCTL_DISK_SET_PARTITION_INFO
:
2364 if (diskData
->PartitionNumber
== 0) {
2366 status
= STATUS_UNSUCCESSFUL
;
2370 PSET_PARTITION_INFORMATION inputBuffer
=
2371 (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2374 // Validate buffer length.
2377 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2378 sizeof(SET_PARTITION_INFORMATION
)) {
2380 status
= STATUS_INFO_LENGTH_MISMATCH
;
2385 // The HAL routines IoGet- and IoSetPartitionInformation were
2386 // developed before support of dynamic partitioning and therefore
2387 // don't distinguish between partition ordinal (that is the order
2388 // of a partition on a disk) and the partition number. (The
2389 // partition number is assigned to a partition to identify it to
2390 // the system.) Use partition ordinals for these legacy calls.
2393 status
= IoSetPartitionInformation(
2394 deviceExtension
->PhysicalDevice
,
2395 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2396 diskData
->PartitionOrdinal
,
2397 inputBuffer
->PartitionType
);
2399 if (NT_SUCCESS(status
)) {
2401 diskData
->PartitionType
= inputBuffer
->PartitionType
;
2407 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2410 // Return the partition layout for the physical drive. Note that
2411 // the layout is returned for the actual physical drive, regardless
2412 // of which partition was specified for the request.
2415 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2416 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2417 status
= STATUS_INFO_LENGTH_MISMATCH
;
2421 PDRIVE_LAYOUT_INFORMATION partitionList
;
2422 PDEVICE_EXTENSION physicalExtension
= deviceExtension
;
2423 PPARTITION_INFORMATION partitionEntry
;
2424 PDISK_DATA diskData
;
2429 // Read partition information.
2432 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
2433 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2437 if (!NT_SUCCESS(status
)) {
2442 // The disk layout has been returned in the partitionList
2443 // buffer. Determine its size and, if the data will fit
2444 // into the intermediatery buffer, return it.
2447 tempSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,PartitionEntry
[0]);
2448 tempSize
+= partitionList
->PartitionCount
*
2449 sizeof(PARTITION_INFORMATION
);
2452 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
2454 status
= STATUS_BUFFER_TOO_SMALL
;
2455 ExFreePool(partitionList
);
2460 // Walk partition list to associate partition numbers with
2461 // partition entries.
2464 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
2467 // Walk partition chain anchored at physical disk extension.
2470 deviceExtension
= physicalExtension
;
2471 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2475 deviceExtension
= diskData
->NextPartition
;
2478 // Check if this is the last partition in the chain.
2481 if (!deviceExtension
) {
2486 // Get the partition device extension from disk data.
2489 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2492 // Check if this partition is not currently being used.
2495 if (!deviceExtension
->PartitionLength
.QuadPart
) {
2499 partitionEntry
= &partitionList
->PartitionEntry
[i
];
2502 // Check if empty, or describes extended partiton or hasn't changed.
2505 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2506 IsContainerPartition(partitionEntry
->PartitionType
)) {
2511 // Check if new partition starts where this partition starts.
2514 if (partitionEntry
->StartingOffset
.QuadPart
!=
2515 deviceExtension
->StartingOffset
.QuadPart
) {
2520 // Check if partition length is the same.
2523 if (partitionEntry
->PartitionLength
.QuadPart
==
2524 deviceExtension
->PartitionLength
.QuadPart
) {
2527 // Partitions match. Update partition number.
2530 partitionEntry
->PartitionNumber
=
2531 diskData
->PartitionNumber
;
2539 // Copy partition information to system buffer.
2542 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2545 status
= STATUS_SUCCESS
;
2546 Irp
->IoStatus
.Information
= tempSize
;
2549 // Finally, free the buffer allocated by reading the
2553 ExFreePool(partitionList
);
2558 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
2563 // Update the disk with new partition information.
2566 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
2569 // Validate buffer length.
2572 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2573 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2575 status
= STATUS_INFO_LENGTH_MISMATCH
;
2579 length
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2580 (partitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
);
2583 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2586 status
= STATUS_BUFFER_TOO_SMALL
;
2591 // Verify that device object is for physical disk.
2594 if (deviceExtension
->PhysicalDevice
->DeviceExtension
!= deviceExtension
) {
2595 status
= STATUS_INVALID_PARAMETER
;
2600 // Walk through partition table comparing partitions to
2601 // existing partitions to create, delete and change
2602 // device objects as necessary.
2605 UpdateDeviceObjects(DeviceObject
,
2609 // Write changes to disk.
2612 status
= IoWritePartitionTable(
2613 deviceExtension
->DeviceObject
,
2614 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2615 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
,
2616 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
,
2621 // Update IRP with bytes returned.
2624 if (NT_SUCCESS(status
)) {
2625 Irp
->IoStatus
.Information
= length
;
2630 case IOCTL_DISK_REASSIGN_BLOCKS
:
2633 // Map defective blocks to new location on disk.
2638 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2644 // Validate buffer length.
2647 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2648 sizeof(REASSIGN_BLOCKS
)) {
2650 status
= STATUS_INFO_LENGTH_MISMATCH
;
2654 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2655 (badBlocks
->Count
- 1) * sizeof(ULONG
);
2657 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2660 status
= STATUS_INFO_LENGTH_MISMATCH
;
2665 // Build the data buffer to be transferred in the input buffer.
2666 // The format of the data to the device is:
2670 // x * 4 btyes Block Address
2672 // All values are big endian.
2675 badBlocks
->Reserved
= 0;
2676 blockCount
= badBlocks
->Count
;
2679 // Convert # of entries to # of bytes.
2683 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2684 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2687 // Convert back to number of entries.
2692 for (; blockCount
> 0; blockCount
--) {
2694 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2696 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2697 (PFOUR_BYTE
) &blockNumber
);
2702 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2705 // Set timeout value.
2708 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2710 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2716 Irp
->IoStatus
.Status
= status
;
2717 Irp
->IoStatus
.Information
= 0;
2719 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2724 case IOCTL_DISK_IS_WRITABLE
:
2727 // Determine if the device is writable.
2730 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
2732 if (modeData
== NULL
) {
2733 status
= STATUS_INSUFFICIENT_RESOURCES
;
2737 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
2739 length
= ScsiClassModeSense(DeviceObject
,
2742 MODE_SENSE_RETURN_ALL
);
2744 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2747 // Retry the request in case of a check condition.
2750 length
= ScsiClassModeSense(DeviceObject
,
2753 MODE_SENSE_RETURN_ALL
);
2755 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2756 status
= STATUS_IO_DEVICE_ERROR
;
2757 ExFreePool(modeData
);
2762 if (modeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
) {
2763 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2765 status
= STATUS_SUCCESS
;
2768 ExFreePool(modeData
);
2771 case IOCTL_DISK_INTERNAL_SET_VERIFY
:
2774 // If the caller is kernel mode, set the verify bit.
2777 if (Irp
->RequestorMode
== KernelMode
) {
2778 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2780 status
= STATUS_SUCCESS
;
2783 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
:
2786 // If the caller is kernel mode, clear the verify bit.
2789 if (Irp
->RequestorMode
== KernelMode
) {
2790 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
2792 status
= STATUS_SUCCESS
;
2795 case IOCTL_DISK_FIND_NEW_DEVICES
:
2798 // Search for devices that have been powered on since the last
2799 // device search or system initialization.
2802 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2803 status
= DriverEntry(DeviceObject
->DriverObject
,
2806 Irp
->IoStatus
.Status
= status
;
2808 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2811 case IOCTL_DISK_MEDIA_REMOVAL
:
2814 // If the disk is not removable then don't allow this command.
2817 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
2818 status
= STATUS_INVALID_DEVICE_REQUEST
;
2823 // Fall through and let the class driver process the request.
2826 case IOCTL_DISK_GET_LENGTH_INFO
:
2829 // Validate buffer length.
2832 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2833 sizeof(GET_LENGTH_INFORMATION
)) {
2834 status
= STATUS_BUFFER_TOO_SMALL
;
2838 PGET_LENGTH_INFORMATION lengthInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
2841 // Update the geometry in case it has changed.
2844 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2846 if (!NT_SUCCESS(status
)) {
2849 // Note the drive is not ready.
2852 diskData
->DriveNotReady
= TRUE
;
2857 // Note the drive is now ready.
2860 diskData
->DriveNotReady
= FALSE
;
2863 // Output data, and return
2866 lengthInformation
->Length
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2867 status
= STATUS_SUCCESS
;
2868 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2876 // Free the Srb, since it is not needed.
2882 // Pass the request to the common device control routine.
2885 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
2889 } // end switch( ...
2891 Irp
->IoStatus
.Status
= status
;
2893 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2895 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2898 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2902 } // end ScsiDiskDeviceControl()
2906 ScsiDiskShutdownFlush (
2907 IN PDEVICE_OBJECT DeviceObject
,
2913 Routine Description:
2915 This routine is called for a shutdown and flush IRPs. These are sent by the
2916 system before it actually shuts down or when the file system does a flush.
2917 A synchronize cache command is sent to the device if it is write caching.
2918 If the device is removable an unlock command will be sent. This routine
2919 will sent a shutdown or flush Srb to the port driver.
2923 DriverObject - Pointer to device object to being shutdown by system.
2934 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2935 PIO_STACK_LOCATION irpStack
;
2936 PSCSI_REQUEST_BLOCK srb
;
2941 // Allocate SCSI request block.
2944 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
2949 // Set the status and complete the request.
2952 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2953 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2954 return(STATUS_INSUFFICIENT_RESOURCES
);
2957 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
2960 // Write length to SRB.
2963 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2966 // Set SCSI bus address.
2969 srb
->PathId
= deviceExtension
->PathId
;
2970 srb
->TargetId
= deviceExtension
->TargetId
;
2971 srb
->Lun
= deviceExtension
->Lun
;
2974 // Set timeout value and mark the request as not being a tagged request.
2977 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 4;
2978 srb
->QueueTag
= SP_UNTAGGED
;
2979 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
2980 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
2983 // If the write cache is enabled then send a synchronize cache request.
2986 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2988 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2989 srb
->CdbLength
= 10;
2991 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
2993 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2999 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status
));
3003 // Unlock the device if it is removable and this is a shutdown.
3006 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3008 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
3009 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
3012 cdb
= (PVOID
) srb
->Cdb
;
3013 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3014 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3017 // Set timeout value.
3020 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3021 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3027 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3033 // Save a few parameters in the current stack location.
3036 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3037 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3040 // Set the retry count to zero.
3043 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3046 // Set up IoCompletion routine address.
3049 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3052 // Get next stack location and
3053 // set major function code.
3056 irpStack
= IoGetNextIrpStackLocation(Irp
);
3058 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3061 // Set up SRB for execute scsi request.
3062 // Save SRB address in next stack for port driver.
3065 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3068 // Set up Irp Address.
3071 srb
->OriginalRequest
= Irp
;
3074 // Call the port driver to process the request.
3077 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3079 } // end ScsiDiskShutdown()
3085 PDEVICE_OBJECT DeviceObject
3089 Routine Description:
3091 The routine performs the necessary functions to determine if a device is
3092 really a floppy rather than a harddisk. This is done by a mode sense
3093 command. First, a check is made to see if the medimum type is set. Second
3094 a check is made for the flexible parameters mode page. Also a check is
3095 made to see if the write cache is enabled.
3099 DeviceObject - Supplies the device object to be tested.
3103 Return TRUE if the indicated device is a floppy.
3107 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3114 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3116 if (modeData
== NULL
) {
3120 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3122 length
= ScsiClassModeSense(DeviceObject
,
3125 MODE_SENSE_RETURN_ALL
);
3127 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3130 // Retry the request in case of a check condition.
3133 length
= ScsiClassModeSense(DeviceObject
,
3136 MODE_SENSE_RETURN_ALL
);
3138 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3140 ExFreePool(modeData
);
3147 // If the length is greater than length indicated by the mode data reset
3148 // the data to the mode data.
3151 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3152 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3156 // Look for the flexible disk mode page.
3159 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_FLEXIBILE
, TRUE
);
3161 if (pageData
!= NULL
) {
3163 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3164 ExFreePool(modeData
);
3169 // Check to see if the write cache is enabled.
3172 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3175 // Assume that write cache is disabled or not supported.
3178 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3181 // Check if valid caching page exists.
3184 if (pageData
!= NULL
) {
3187 // Check if write cache is disabled.
3190 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3193 "SCSIDISK: Disk write cache enabled\n"));
3196 // Check if forced unit access (FUA) is supported.
3199 if (((PMODE_PARAMETER_HEADER
)modeData
)->DeviceSpecificParameter
& MODE_DSP_FUA_SUPPORTED
) {
3201 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3206 "SCSIDISK: Disk does not support FUA or DPO\n"));
3216 ExFreePool(modeData
);
3219 } // end IsFloppyDevice()
3225 IN PDEVICE_OBJECT DeviceObject
,
3226 IN PCHAR ModeSelectBuffer
,
3233 Routine Description:
3235 This routine sends a mode select command.
3239 DeviceObject - Supplies the device object associated with this request.
3241 ModeSelectBuffer - Supplies a buffer containing the page data.
3243 Length - Supplies the length in bytes of the mode select buffer.
3245 SavePage - Indicates that parameters should be written to disk.
3249 Length of the transferred data is returned.
3253 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3255 SCSI_REQUEST_BLOCK srb
;
3260 PMODE_PARAMETER_BLOCK blockDescriptor
;
3264 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3267 // Allocate buffer for mode select header, block descriptor, and mode page.
3270 buffer
= (ULONG_PTR
)ExAllocatePool(NonPagedPoolCacheAligned
,length2
);
3272 RtlZeroMemory((PVOID
)buffer
, length2
);
3275 // Set length in header to size of mode page.
3278 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3280 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3286 blockDescriptor
->BlockLength
[1]=0x02;
3289 // Copy mode page to buffer.
3292 RtlCopyMemory((PVOID
)(buffer
+ 3), ModeSelectBuffer
, Length
);
3298 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3301 // Build the MODE SELECT CDB.
3305 cdb
= (PCDB
)srb
.Cdb
;
3308 // Set timeout value from device extension.
3311 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
3313 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3314 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3315 cdb
->MODE_SELECT
.PFBit
= 1;
3316 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3320 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3327 if (status
== STATUS_VERIFY_REQUIRED
) {
3330 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3343 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3344 status
= STATUS_SUCCESS
;
3347 ExFreePool((PVOID
)buffer
);
3349 if (NT_SUCCESS(status
)) {
3355 } // end SciDiskModeSelect()
3361 IN PDEVICE_OBJECT DeviceObject
,
3362 IN PSCSI_INQUIRY_DATA LunInfo
3366 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3367 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3368 BAD_CONTROLLER_INFORMATION
const *controller
;
3373 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
3375 controller
= &ScsiDiskBadControllers
[j
];
3377 if (!controller
->DisableWriteCache
|| strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
3381 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller
->InquiryString
));
3383 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3385 if (modeData
== NULL
) {
3388 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3392 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3394 length
= ScsiClassModeSense(DeviceObject
,
3397 MODE_SENSE_RETURN_ALL
);
3399 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3402 // Retry the request in case of a check condition.
3405 length
= ScsiClassModeSense(DeviceObject
,
3408 MODE_SENSE_RETURN_ALL
);
3410 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3414 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3416 ExFreePool(modeData
);
3423 // If the length is greater than length indicated by the mode data reset
3424 // the data to the mode data.
3427 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3428 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3432 // Check to see if the write cache is enabled.
3435 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3438 // Assume that write cache is disabled or not supported.
3441 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3444 // Check if valid caching page exists.
3447 if (pageData
!= NULL
) {
3449 BOOLEAN savePage
= FALSE
;
3451 savePage
= (BOOLEAN
)(((PMODE_CACHING_PAGE
)pageData
)->PageSavable
);
3454 // Check if write cache is disabled.
3457 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3459 PIO_ERROR_LOG_PACKET errorLogEntry
;
3464 // Disable write cache and ensure necessary fields are zeroed.
3467 ((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
= FALSE
;
3468 ((PMODE_CACHING_PAGE
)pageData
)->Reserved
= 0;
3469 ((PMODE_CACHING_PAGE
)pageData
)->PageSavable
= 0;
3470 ((PMODE_CACHING_PAGE
)pageData
)->Reserved2
= 0;
3473 // Extract length from caching page.
3476 length
= ((PMODE_CACHING_PAGE
)pageData
)->PageLength
;
3479 // Compensate for page code and page length.
3485 // Issue mode select to set the parameter.
3488 if (ScsiDiskModeSelect(DeviceObject
,
3494 "SCSIDISK: Disk write cache disabled\n"));
3496 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3497 errorCode
= IO_WRITE_CACHE_DISABLED
;
3500 if (ScsiDiskModeSelect(DeviceObject
,
3506 "SCSIDISK: Disk write cache disabled\n"));
3509 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3510 errorCode
= IO_WRITE_CACHE_DISABLED
;
3515 "SCSIDISK: Mode select to disable write cache failed\n"));
3517 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3518 errorCode
= IO_WRITE_CACHE_ENABLED
;
3523 // Log the appropriate informational or error entry.
3526 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3528 sizeof(IO_ERROR_LOG_PACKET
) + 3
3531 if (errorLogEntry
!= NULL
) {
3533 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3534 errorLogEntry
->ErrorCode
= errorCode
;
3535 errorLogEntry
->SequenceNumber
= 0;
3536 errorLogEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
3537 errorLogEntry
->IoControlCode
= 0;
3538 errorLogEntry
->RetryCount
= 0;
3539 errorLogEntry
->UniqueErrorValue
= 0x1;
3540 errorLogEntry
->DumpDataSize
= 3 * sizeof(ULONG
);
3541 errorLogEntry
->DumpData
[0] = LunInfo
->PathId
;
3542 errorLogEntry
->DumpData
[1] = LunInfo
->TargetId
;
3543 errorLogEntry
->DumpData
[2] = LunInfo
->Lun
;
3546 // Write the error log packet.
3549 IoWriteErrorLogEntry(errorLogEntry
);
3555 // Found device so exit the loop and return.
3567 CalculateMbrCheckSum(
3568 IN PDEVICE_EXTENSION DeviceExtension
,
3574 Routine Description:
3576 Read MBR and calculate checksum.
3580 DeviceExtension - Supplies a pointer to the device information for disk.
3581 Checksum - Memory location to return MBR checksum.
3585 Returns TRUE if checksum is valid.
3589 LARGE_INTEGER sectorZero
;
3591 IO_STATUS_BLOCK ioStatus
;
3599 sectorZero
.QuadPart
= (LONGLONG
) 0;
3602 // Create notification event object to be used to signal the inquiry
3603 // request completion.
3606 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
3612 sectorSize
= DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
3615 // Make sure sector size is at least 512 bytes.
3618 if (sectorSize
< 512) {
3623 // Allocate buffer for sector read.
3626 mbr
= ExAllocatePool(NonPagedPoolCacheAligned
, sectorSize
);
3633 // Build IRP to read MBR.
3636 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
3637 DeviceExtension
->DeviceObject
,
3650 // Pass request to port driver and wait for request to complete.
3653 status
= IoCallDriver(DeviceExtension
->DeviceObject
,
3656 if (status
== STATUS_PENDING
) {
3657 KeWaitForSingleObject(&event
,
3662 status
= ioStatus
.Status
;
3665 if (!NT_SUCCESS(status
)) {
3671 // Calculate MBR checksum.
3676 for (i
= 0; i
< 128; i
++) {
3677 *Checksum
+= mbr
[i
];
3680 *Checksum
= ~*Checksum
+ 1;
3690 IN PDEVICE_EXTENSION DeviceExtension
,
3697 Routine Description:
3699 The routine queries the registry to determine if this disk is visible to
3700 the BIOS. If the disk is visable to the BIOS, then the geometry information
3705 DeviceExtension - Supplies a pointer to the device information for disk.
3706 Signature - Unique identifier recorded in MBR.
3707 BusKey - Handle of bus key.
3708 DiskNumber - Returns ordinal of disk as BIOS sees it.
3712 TRUE is disk signature matched.
3716 PDISK_DATA diskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
3717 BOOLEAN diskFound
= FALSE
;
3718 OBJECT_ATTRIBUTES objectAttributes
;
3719 UNICODE_STRING unicodeString
;
3720 UNICODE_STRING identifier
;
3722 ULONG adapterNumber
;
3730 STRING anotherString
;
3733 PKEY_VALUE_FULL_INFORMATION keyData
;
3737 for (busNumber
= 0; ; busNumber
++) {
3740 // Open controller name key.
3743 sprintf((PCHAR
)buffer
,
3747 RtlInitString(&string
,
3750 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3754 if (!NT_SUCCESS(status
)){
3758 InitializeObjectAttributes(&objectAttributes
,
3760 OBJ_CASE_INSENSITIVE
,
3762 (PSECURITY_DESCRIPTOR
)NULL
);
3764 status
= ZwOpenKey(&spareKey
,
3768 RtlFreeUnicodeString(&unicodeString
);
3770 if (!NT_SUCCESS(status
)) {
3775 // Open up controller ordinal key.
3778 RtlInitUnicodeString(&unicodeString
, L
"DiskController");
3779 InitializeObjectAttributes(&objectAttributes
,
3781 OBJ_CASE_INSENSITIVE
,
3783 (PSECURITY_DESCRIPTOR
)NULL
);
3785 status
= ZwOpenKey(&adapterKey
,
3790 // This could fail even with additional adapters of this type
3794 if (!NT_SUCCESS(status
)) {
3798 for (adapterNumber
= 0; ; adapterNumber
++) {
3804 sprintf((PCHAR
)buffer
,
3805 "%lu\\DiskPeripheral",
3808 RtlInitString(&string
,
3811 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3815 if (!NT_SUCCESS(status
)){
3819 InitializeObjectAttributes(&objectAttributes
,
3821 OBJ_CASE_INSENSITIVE
,
3823 (PSECURITY_DESCRIPTOR
)NULL
);
3825 status
= ZwOpenKey(&diskKey
,
3829 RtlFreeUnicodeString(&unicodeString
);
3831 if (!NT_SUCCESS(status
)) {
3835 for (diskNumber
= 0; ; diskNumber
++) {
3837 sprintf((PCHAR
)buffer
,
3841 RtlInitString(&string
,
3844 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3848 if (!NT_SUCCESS(status
)){
3852 InitializeObjectAttributes(&objectAttributes
,
3854 OBJ_CASE_INSENSITIVE
,
3856 (PSECURITY_DESCRIPTOR
)NULL
);
3858 status
= ZwOpenKey(&targetKey
,
3862 RtlFreeUnicodeString(&unicodeString
);
3864 if (!NT_SUCCESS(status
)) {
3869 // Allocate buffer for registry query.
3872 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
3874 if (keyData
== NULL
) {
3880 // Get disk peripheral identifier.
3883 RtlInitUnicodeString(&unicodeString
, L
"Identifier");
3884 status
= ZwQueryValueKey(targetKey
,
3886 KeyValueFullInformation
,
3893 if (!NT_SUCCESS(status
)) {
3898 // Complete unicode string.
3902 (PWSTR
)((PUCHAR
)keyData
+ keyData
->DataOffset
);
3903 identifier
.Length
= (USHORT
)keyData
->DataLength
;
3904 identifier
.MaximumLength
= (USHORT
)keyData
->DataLength
;
3907 // Convert unicode identifier to ansi string.
3911 RtlUnicodeStringToAnsiString(&anotherString
,
3915 if (!NT_SUCCESS(status
)) {
3920 // If checksum is zero, then the MBR is valid and
3921 // the signature is meaningful.
3924 if (diskData
->MbrCheckSum
) {
3927 // Convert checksum to ansi string.
3930 sprintf((PCHAR
)buffer
, "%08lx", diskData
->MbrCheckSum
);
3935 // Convert signature to ansi string.
3938 sprintf((PCHAR
)buffer
, "%08lx", diskData
->Signature
);
3941 // Make string point at signature. Can't use scan
3942 // functions because they are not exported for driver use.
3945 anotherString
.Buffer
+=9;
3949 // Convert to ansi string.
3952 RtlInitString(&string
,
3957 // Make string lengths equal.
3960 anotherString
.Length
= string
.Length
;
3963 // Check if strings match.
3966 if (RtlCompareString(&string
,
3971 *DiskNumber
= diskNumber
;
3974 ExFreePool(keyData
);
3977 // Readjust indentifier string if necessary.
3980 if (!diskData
->MbrCheckSum
) {
3981 anotherString
.Buffer
-=9;
3984 RtlFreeAnsiString(&anotherString
);
3994 ZwClose(adapterKey
);
4000 } // end EnumerateBusKey()
4006 IN PDEVICE_EXTENSION DeviceExtension
4010 Routine Description:
4012 The routine queries the registry to determine if this disk is visible to
4013 the BIOS. If the disk is visable to the BIOS, then the geometry information
4018 DeviceExtension - Supplies a pointer to the device information for disk.
4027 OBJECT_ATTRIBUTES objectAttributes
;
4028 UNICODE_STRING unicodeString
;
4032 PCM_INT13_DRIVE_PARAMETER driveParameters
;
4033 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor
;
4034 PKEY_VALUE_FULL_INFORMATION keyData
;
4038 ULONG numberOfDrives
;
4041 ULONG sectorsPerTrack
;
4042 ULONG tracksPerCylinder
;
4043 BOOLEAN foundEZHooker
;
4049 // Initialize the object for the key.
4052 InitializeObjectAttributes(&objectAttributes
,
4053 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
4054 OBJ_CASE_INSENSITIVE
,
4056 (PSECURITY_DESCRIPTOR
) NULL
);
4059 // Create the hardware base key.
4062 status
= ZwOpenKey(&hardwareKey
,
4067 if (!NT_SUCCESS(status
)) {
4068 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
));
4074 // Get disk BIOS geometry information.
4077 RtlInitUnicodeString(&unicodeString
, L
"Configuration Data");
4079 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
4081 if (keyData
== NULL
) {
4082 ZwClose(hardwareKey
);
4086 status
= ZwQueryValueKey(hardwareKey
,
4088 KeyValueFullInformation
,
4093 if (!NT_SUCCESS(status
)) {
4095 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4097 ExFreePool(keyData
);
4102 // Open EISA bus key.
4105 RtlInitUnicodeString(&unicodeString
, L
"EisaAdapter");
4107 InitializeObjectAttributes(&objectAttributes
,
4109 OBJ_CASE_INSENSITIVE
,
4111 (PSECURITY_DESCRIPTOR
)NULL
);
4113 status
= ZwOpenKey(&busKey
,
4117 if (!NT_SUCCESS(status
)) {
4122 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4123 if (EnumerateBusKey(DeviceExtension
,
4127 ZwClose(hardwareKey
);
4134 // Open Multifunction bus key.
4137 RtlInitUnicodeString(&unicodeString
, L
"MultifunctionAdapter");
4139 InitializeObjectAttributes(&objectAttributes
,
4141 OBJ_CASE_INSENSITIVE
,
4143 (PSECURITY_DESCRIPTOR
)NULL
);
4145 status
= ZwOpenKey(&busKey
,
4149 ZwClose(hardwareKey
);
4150 if (NT_SUCCESS(status
)) {
4152 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4153 if (EnumerateBusKey(DeviceExtension
,
4161 ExFreePool(keyData
);
4166 resourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PUCHAR
)keyData
+
4167 keyData
->DataOffset
);
4170 // Check that the data is long enough to hold a full resource descriptor,
4171 // and that the last resouce list is device-specific and long enough.
4174 if (keyData
->DataLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) ||
4175 resourceDescriptor
->PartialResourceList
.Count
== 0 ||
4176 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].Type
!=
4177 CmResourceTypeDeviceSpecific
||
4178 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0]
4179 .u
.DeviceSpecificData
.DataSize
< sizeof(ULONG
)) {
4181 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4182 ExFreePool(keyData
);
4187 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
;
4190 // Point to the BIOS data. The BIOS data is located after the first
4191 // partial Resource list which should be device specific data.
4194 buffer
= (PUCHAR
) keyData
+ keyData
->DataOffset
+
4195 sizeof(CM_FULL_RESOURCE_DESCRIPTOR
);
4198 numberOfDrives
= length
/ sizeof(CM_INT13_DRIVE_PARAMETER
);
4201 // Use the defaults if the drive number is greater than the
4202 // number of drives detected by the BIOS.
4205 if (numberOfDrives
<= diskNumber
) {
4206 ExFreePool(keyData
);
4211 // Point to the array of drive parameters.
4214 driveParameters
= (PCM_INT13_DRIVE_PARAMETER
) buffer
+ diskNumber
;
4215 cylinders
= driveParameters
->MaxCylinders
+ 1;
4216 sectorsPerTrack
= driveParameters
->SectorsPerTrack
;
4217 tracksPerCylinder
= driveParameters
->MaxHeads
+1;
4220 // Calculate the actual number of sectors.
4223 sectors
= (ULONG
)(DeviceExtension
->PartitionLength
.QuadPart
>>
4224 DeviceExtension
->SectorShift
);
4227 if (sectors
>= cylinders
* tracksPerCylinder
* sectorsPerTrack
) {
4228 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4229 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4230 sectors
, cylinders
, tracksPerCylinder
, sectorsPerTrack
));
4235 // Since the BIOS may not report the full drive, recalculate the drive
4236 // size based on the volume size and the BIOS values for tracks per
4237 // cylinder and sectors per track..
4240 length
= tracksPerCylinder
* sectorsPerTrack
;
4245 // The BIOS information is bogus.
4248 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4249 ExFreePool(keyData
);
4253 cylinders
= sectors
/ length
;
4256 // Update the actual geometry information.
4259 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= sectorsPerTrack
;
4260 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
;
4261 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)cylinders
;
4262 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= cylinders
* tracksPerCylinder
* sectorsPerTrack
*
4263 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4266 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4271 ExFreePool(keyData
);
4273 foundEZHooker
= FALSE
;
4275 if (!DeviceExtension
->DMActive
) {
4277 HalExamineMBR(DeviceExtension
->DeviceObject
,
4278 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4286 foundEZHooker
= TRUE
;
4292 if (DeviceExtension
->DMActive
|| foundEZHooker
) {
4294 while (cylinders
> 1024) {
4296 tracksPerCylinder
= tracksPerCylinder
*2;
4297 cylinders
= cylinders
/2;
4302 // int 13 values are always 1 less.
4305 tracksPerCylinder
-= 1;
4309 // DM reserves the CE cylinder
4314 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= cylinders
+ 1;
4315 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
+ 1;
4317 DeviceExtension
->PartitionLength
.QuadPart
=
4318 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
=
4319 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
*
4320 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
*
4321 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
*
4322 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
;
4324 if (DeviceExtension
->DMActive
) {
4326 DeviceExtension
->DMByteSkew
= DeviceExtension
->DMSkew
* DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4332 DeviceExtension
->DMByteSkew
= 0;
4338 } // end UpdateGeometry()
4344 UpdateRemovableGeometry (
4345 IN PDEVICE_OBJECT DeviceObject
,
4351 Routine Description:
4353 This routines updates the size and starting offset of the device. This is
4354 used when the media on the device may have changed thereby changing the
4355 size of the device. If this is the physical device then a
4356 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4360 DeviceObject - Supplies the device object whos size needs to be updated.
4362 Irp - Supplies a reference where the status can be updated.
4366 Returns the status of the opertion.
4371 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4372 PDRIVE_LAYOUT_INFORMATION partitionList
;
4374 PDISK_DATA diskData
;
4375 ULONG partitionNumber
;
4378 // Determine if the size of the partition may have changed because
4379 // the media has changed.
4382 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
4384 return(STATUS_SUCCESS
);
4389 // If this request is for partition zero then do a read drive
4390 // capacity otherwise do a I/O read partition table.
4393 diskData
= (PDISK_DATA
) (deviceExtension
+ 1);
4396 // Read the drive capcity. If that fails, give up.
4399 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
4401 if (!NT_SUCCESS(status
)) {
4406 // Read the partition table agian.
4409 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
4410 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4415 if (!NT_SUCCESS(status
)) {
4418 // Fail the request.
4424 if (diskData
->PartitionNumber
!= 0 &&
4425 diskData
->PartitionNumber
<= partitionList
->PartitionCount
) {
4427 partitionNumber
= diskData
->PartitionNumber
- 1;
4430 // Update the partition information for this parition.
4433 diskData
->PartitionType
=
4434 partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
4436 diskData
->BootIndicator
=
4437 partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
4439 deviceExtension
->StartingOffset
=
4440 partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
4442 deviceExtension
->PartitionLength
=
4443 partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
4445 diskData
->HiddenSectors
=
4446 partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
4448 deviceExtension
->SectorShift
= ((PDEVICE_EXTENSION
)
4449 deviceExtension
->PhysicalDevice
->DeviceExtension
)->SectorShift
;
4451 } else if (diskData
->PartitionNumber
!= 0) {
4454 // The paritition does not exist. Zero all the data.
4457 diskData
->PartitionType
= 0;
4458 diskData
->BootIndicator
= 0;
4459 diskData
->HiddenSectors
= 0;
4460 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)0;
4461 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)0;
4465 // Free the parition list allocate by I/O read partition table.
4468 ExFreePool(partitionList
);
4471 return(STATUS_SUCCESS
);
4477 ScsiDiskProcessError(
4478 PDEVICE_OBJECT DeviceObject
,
4479 PSCSI_REQUEST_BLOCK Srb
,
4485 Routine Description:
4487 This routine checks the type of error. If the error indicates an underrun
4488 then indicate the request should be retried.
4492 DeviceObject - Supplies a pointer to the device object.
4494 Srb - Supplies a pointer to the failing Srb.
4496 Status - Status with which the IRP will be completed.
4498 Retry - Indication of whether the request will be retried.
4507 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4509 if (*Status
== STATUS_DATA_OVERRUN
&&
4510 ( Srb
->Cdb
[0] == SCSIOP_WRITE
|| Srb
->Cdb
[0] == SCSIOP_READ
)) {
4515 // Update the error count for the device.
4518 deviceExtension
->ErrorCount
++;
4521 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
4522 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
4525 // The disk drive should never be busy this long. Reset the scsi bus
4526 // maybe this will clear the condition.
4529 ResetScsiBus(DeviceObject
);
4532 // Update the error count for the device.
4535 deviceExtension
->ErrorCount
++;
4542 PDEVICE_OBJECT DeviceObject
,
4543 PSCSI_INQUIRY_DATA LunInfo
,
4544 PIO_SCSI_CAPABILITIES PortCapabilities
4549 Routine Description:
4551 This function checks to see if an SCSI logical unit requires speical
4556 DeviceObject - Supplies the device object to be tested.
4558 InquiryData - Supplies the inquiry data returned by the device of interest.
4560 PortCapabilities - Supplies the capabilities of the device object.
4569 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4570 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
4571 BAD_CONTROLLER_INFORMATION
const *controller
;
4574 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
4576 controller
= &ScsiDiskBadControllers
[j
];
4578 if (strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
4582 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller
->InquiryString
));
4585 // Found a listed controller. Determine what must be done.
4588 if (controller
->DisableTaggedQueuing
) {
4591 // Disable tagged queuing.
4594 deviceExtension
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
4597 if (controller
->DisableSynchronousTransfers
) {
4600 // Disable synchronous data transfers.
4603 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4607 if (controller
->DisableDisconnects
) {
4610 // Disable disconnects.
4613 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
4618 // Found device so exit the loop and return.
4625 // Set the StartUnit flag appropriately.
4628 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) {
4629 deviceExtension
->DeviceFlags
|= DEV_SAFE_START_UNIT
;
4631 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
4632 if (_strnicmp((PCCHAR
)InquiryData
->VendorId
, "iomega", strlen("iomega"))) {
4633 deviceExtension
->DeviceFlags
&= ~DEV_SAFE_START_UNIT
;
4644 IN PDEVICE_OBJECT DeviceObject
4649 Routine Description:
4651 This command sends a reset bus command to the SCSI port driver.
4655 DeviceObject - The device object for the logical unit with
4664 PIO_STACK_LOCATION irpStack
;
4666 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4667 PSCSI_REQUEST_BLOCK srb
;
4668 PCOMPLETION_CONTEXT context
;
4670 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4673 // Allocate Srb from nonpaged pool.
4676 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
4677 sizeof(COMPLETION_CONTEXT
));
4680 // Save the device object in the context for use by the completion
4684 context
->DeviceObject
= DeviceObject
;
4685 srb
= &context
->Srb
;
4691 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4694 // Write length to SRB.
4697 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4700 // Set up SCSI bus address.
4703 srb
->PathId
= deviceExtension
->PathId
;
4704 srb
->TargetId
= deviceExtension
->TargetId
;
4705 srb
->Lun
= deviceExtension
->Lun
;
4707 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4710 // Build the asynchronous request to be sent to the port driver.
4711 // Since this routine is called from a DPC the IRP should always be
4715 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
4717 IoSetCompletionRoutine(irp
,
4718 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
4724 irpStack
= IoGetNextIrpStackLocation(irp
);
4726 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4728 srb
->OriginalRequest
= irp
;
4731 // Store the SRB address in next stack for port driver.
4734 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4737 // Call the port driver with the IRP.
4740 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
4744 } // end ResetScsiBus()
4749 UpdateDeviceObjects(
4750 IN PDEVICE_OBJECT PhysicalDisk
,
4756 Routine Description:
4758 This routine creates, deletes and changes device objects when
4759 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4760 the drive layout information for the user. It is possible to
4761 call this routine even in the GET_LAYOUT case because RewritePartition
4766 DeviceObject - Device object for physical disk.
4767 Irp - IO Request Packet (IRP).
4775 PDEVICE_EXTENSION physicalExtension
= PhysicalDisk
->DeviceExtension
;
4776 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
4778 ULONG partitionNumber
;
4779 ULONG partitionCount
;
4780 ULONG lastPartition
;
4781 ULONG partitionOrdinal
;
4782 PPARTITION_INFORMATION partitionEntry
;
4783 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
4784 STRING ntNameString
;
4785 UNICODE_STRING ntUnicodeString
;
4786 PDEVICE_OBJECT deviceObject
;
4787 PDEVICE_EXTENSION deviceExtension
;
4788 PDISK_DATA diskData
;
4790 ULONG numberListElements
;
4793 partitionCount
= ((partitionList
->PartitionCount
+ 3) / 4) * 4;
4796 // Zero all of the partition numbers.
4799 for (partition
= 0; partition
< partitionCount
; partition
++) {
4800 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4801 partitionEntry
->PartitionNumber
= 0;
4805 // Walk through chain of partitions for this disk to determine
4806 // which existing partitions have no match.
4809 deviceExtension
= physicalExtension
;
4810 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4815 deviceExtension
= diskData
->NextPartition
;
4818 // Check if this is the last partition in the chain.
4821 if (!deviceExtension
) {
4826 // Get the partition device extension from disk data.
4829 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4832 // Check for highest partition number this far.
4835 if (diskData
->PartitionNumber
> lastPartition
) {
4836 lastPartition
= diskData
->PartitionNumber
;
4840 // Check if this partition is not currently being used.
4843 if (!deviceExtension
->PartitionLength
.QuadPart
) {
4848 // Loop through partition information to look for match.
4852 partitionOrdinal
= 0;
4854 for (partition
= 0; partition
< partitionCount
; partition
++) {
4857 // Get partition descriptor.
4860 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4863 // Check if empty, or describes extended partiton or hasn't changed.
4866 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4867 IsContainerPartition(partitionEntry
->PartitionType
)) {
4872 // Advance partition ordinal.
4878 // Check if new partition starts where this partition starts.
4881 if (partitionEntry
->StartingOffset
.QuadPart
!=
4882 deviceExtension
->StartingOffset
.QuadPart
) {
4887 // Check if partition length is the same.
4890 if (partitionEntry
->PartitionLength
.QuadPart
==
4891 deviceExtension
->PartitionLength
.QuadPart
) {
4894 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4895 physicalExtension
->DeviceNumber
,
4896 diskData
->PartitionNumber
));
4899 // Indicate match is found and set partition number
4904 partitionEntry
->PartitionNumber
= diskData
->PartitionNumber
;
4912 // A match is found.
4915 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4918 // If this partition is marked for update then update partition type.
4921 if (partitionEntry
->RewritePartition
) {
4922 diskData
->PartitionType
= partitionEntry
->PartitionType
;
4926 // Update partitional ordinal for calls to HAL routine
4927 // IoSetPartitionInformation.
4930 diskData
->PartitionOrdinal
= partitionOrdinal
;
4933 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4934 physicalExtension
->DeviceNumber
,
4935 diskData
->PartitionOrdinal
,
4936 diskData
->PartitionNumber
));
4941 // no match was found, indicate this partition is gone.
4945 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4946 physicalExtension
->DeviceNumber
,
4947 diskData
->PartitionNumber
));
4949 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
4955 // Walk through partition loop to find new partitions and set up
4956 // device extensions to describe them. In some cases new device
4957 // objects will be created.
4960 partitionOrdinal
= 0;
4963 partition
< partitionCount
;
4967 // Get partition descriptor.
4970 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4973 // Check if empty, or describes an extended partiton.
4976 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4977 IsContainerPartition(partitionEntry
->PartitionType
)) {
4982 // Keep track of position on the disk for calls to IoSetPartitionInformation.
4988 // Check if this entry should be rewritten.
4991 if (!partitionEntry
->RewritePartition
) {
4995 if (partitionEntry
->PartitionNumber
) {
4998 // Partition is an exact match with an existing partition, but is
4999 // being written anyway.
5006 // Check first if existing device object is available by
5007 // walking partition extension list.
5010 partitionNumber
= 0;
5011 deviceExtension
= physicalExtension
;
5012 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5017 // Get next partition device extension from disk data.
5020 deviceExtension
= diskData
->NextPartition
;
5022 if (!deviceExtension
) {
5026 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5029 // A device object is free if the partition length is set to zero.
5032 if (!deviceExtension
->PartitionLength
.QuadPart
) {
5033 partitionNumber
= diskData
->PartitionNumber
;
5040 // If partition number is still zero then a new device object
5044 if (partitionNumber
== 0) {
5047 partitionNumber
= lastPartition
;
5050 // Get or create partition object and set up partition parameters.
5053 sprintf(ntNameBuffer
,
5054 "\\Device\\Harddisk%lu\\Partition%lu",
5055 physicalExtension
->DeviceNumber
,
5058 RtlInitString(&ntNameString
,
5061 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
5065 if (!NT_SUCCESS(status
)) {
5070 "UpdateDeviceObjects: Create device object %s\n",
5074 // This is a new name. Create the device object to represent it.
5077 status
= IoCreateDevice(PhysicalDisk
->DriverObject
,
5078 DEVICE_EXTENSION_SIZE
,
5085 if (!NT_SUCCESS(status
)) {
5087 "UpdateDeviceObjects: Can't create device %s\n",
5089 RtlFreeUnicodeString(&ntUnicodeString
);
5094 // Set up device object fields.
5097 deviceObject
->Flags
|= DO_DIRECT_IO
;
5098 deviceObject
->StackSize
= PhysicalDisk
->StackSize
;
5101 // Set up device extension fields.
5104 deviceExtension
= deviceObject
->DeviceExtension
;
5107 // Copy physical disk extension to partition extension.
5110 RtlMoveMemory(deviceExtension
,
5112 sizeof(DEVICE_EXTENSION
));
5115 // Initialize the new S-List.
5118 if (deviceExtension
->SrbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
5119 numberListElements
= 30;
5121 numberListElements
= 8;
5125 // Build the lookaside list for srb's for this partition based on
5126 // whether the adapter and disk can do tagged queueing.
5129 ScsiClassInitializeSrbLookasideList(deviceExtension
,
5130 numberListElements
);
5133 // Allocate spinlock for zoning for split-request completion.
5136 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
5139 // Write back partition number used in creating object name.
5142 partitionEntry
->PartitionNumber
= partitionNumber
;
5145 // Clear flags initializing bit.
5148 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
5151 // Point back at device object.
5154 deviceExtension
->DeviceObject
= deviceObject
;
5156 RtlFreeUnicodeString(&ntUnicodeString
);
5159 // Link to end of partition chain using previous disk data.
5162 diskData
->NextPartition
= deviceExtension
;
5165 // Get new disk data and zero next partition pointer.
5168 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5169 diskData
->NextPartition
= NULL
;
5174 // Set pointer to disk data area that follows device extension.
5177 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5180 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5181 physicalExtension
->DeviceNumber
,
5186 // Update partition information in partition device extension.
5189 diskData
->PartitionNumber
= partitionNumber
;
5190 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5191 diskData
->BootIndicator
= partitionEntry
->BootIndicator
;
5192 deviceExtension
->StartingOffset
= partitionEntry
->StartingOffset
;
5193 deviceExtension
->PartitionLength
= partitionEntry
->PartitionLength
;
5194 diskData
->HiddenSectors
= partitionEntry
->HiddenSectors
;
5195 diskData
->PartitionOrdinal
= partitionOrdinal
;
5198 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5199 diskData
->PartitionOrdinal
,
5200 diskData
->PartitionNumber
));
5203 // Update partition number passed in to indicate the
5204 // device name for this partition.
5207 partitionEntry
->PartitionNumber
= partitionNumber
;
5210 } // end UpdateDeviceObjects()