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 // HACK: How can we end here with null sector size?!
1521 if (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
== 0) {
1522 DPRINT1("Hack! Received invalid sector size\n");
1523 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1527 // Verify parameters of this request.
1528 // Check that ending sector is within partition and
1529 // that number of bytes to transfer is a multiple of
1533 startingOffset
.QuadPart
= (currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
1536 if ((startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) ||
1537 (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1))) {
1540 // This error maybe caused by the fact that the drive is not ready.
1543 if (((PDISK_DATA
)(deviceExtension
+ 1))->DriveNotReady
) {
1546 // Flag this as a user errror so that a popup is generated.
1549 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
1550 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1555 // Note fastfat depends on this parameter to determine when to
1556 // remount do to a sector size change.
1559 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1562 if (startingOffset
.QuadPart
> deviceExtension
->PartitionLength
.QuadPart
) {
1563 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset
.QuadPart
, deviceExtension
->PartitionLength
.QuadPart
);
1566 if (transferByteCount
& (deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
- 1)) {
1567 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount
, deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
1570 if (Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_READY
) {
1571 DPRINT1("Failing due to device not ready!\n");
1574 return STATUS_INVALID_PARAMETER
;
1577 return STATUS_SUCCESS
;
1579 } // end ScsiDiskReadWrite()
1584 ScsiDiskDeviceControl(
1585 PDEVICE_OBJECT DeviceObject
,
1591 Routine Description:
1593 I/O system entry for device controls to SCSI disks.
1597 DeviceObject - Pointer to driver object created by system.
1607 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1608 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1609 PDISK_DATA diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
1610 PSCSI_REQUEST_BLOCK srb
;
1612 PMODE_PARAMETER_HEADER modeData
;
1617 IO_STATUS_BLOCK ioStatus
;
1621 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
1625 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1626 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1627 return(STATUS_INSUFFICIENT_RESOURCES
);
1631 // Write zeros to Srb.
1634 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1636 cdb
= (PCDB
)srb
->Cdb
;
1638 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1640 case SMART_GET_VERSION
: {
1643 PSRB_IO_CONTROL srbControl
;
1644 PGETVERSIONINPARAMS versionParams
;
1646 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1647 sizeof(GETVERSIONINPARAMS
)) {
1648 status
= STATUS_INVALID_PARAMETER
;
1653 // Create notification event object to be used to signal the
1654 // request completion.
1657 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1659 srbControl
= ExAllocatePool(NonPagedPool
,
1660 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
));
1663 status
= STATUS_INSUFFICIENT_RESOURCES
;
1668 // fill in srbControl fields
1671 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1672 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1673 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1674 srbControl
->Length
= sizeof(GETVERSIONINPARAMS
);
1675 srbControl
->ControlCode
= IOCTL_SCSI_MINIPORT_SMART_VERSION
;
1678 // Point to the 'buffer' portion of the SRB_CONTROL
1681 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1684 // Ensure correct target is set in the cmd parameters.
1687 versionParams
= (PGETVERSIONINPARAMS
)buffer
;
1688 versionParams
->bIDEDeviceMap
= deviceExtension
->TargetId
;
1691 // Copy the IOCTL parameters to the srb control buffer area.
1694 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(GETVERSIONINPARAMS
));
1697 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1698 deviceExtension
->PortDeviceObject
,
1700 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1702 sizeof(SRB_IO_CONTROL
) + sizeof(GETVERSIONINPARAMS
),
1708 status
= STATUS_INSUFFICIENT_RESOURCES
;
1713 // Call the port driver with the request and wait for it to complete.
1716 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1718 if (status
== STATUS_PENDING
) {
1719 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1720 status
= ioStatus
.Status
;
1724 // If successful, copy the data received into the output buffer.
1725 // This should only fail in the event that the IDE driver is older than this driver.
1728 if (NT_SUCCESS(status
)) {
1730 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1732 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, sizeof(GETVERSIONINPARAMS
));
1733 Irp
->IoStatus
.Information
= sizeof(GETVERSIONINPARAMS
);
1736 ExFreePool(srbControl
);
1740 case SMART_RCV_DRIVE_DATA
: {
1742 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1743 ULONG controlCode
= 0;
1744 PSRB_IO_CONTROL srbControl
;
1747 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1748 (sizeof(SENDCMDINPARAMS
) - 1)) {
1749 status
= STATUS_INVALID_PARAMETER
;
1752 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1753 (sizeof(SENDCMDOUTPARAMS
) + 512 - 1)) {
1754 status
= STATUS_INVALID_PARAMETER
;
1759 // Create notification event object to be used to signal the
1760 // request completion.
1763 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1765 if (cmdInParameters
->irDriveRegs
.bCommandReg
== ID_CMD
) {
1767 length
= IDENTIFY_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1768 controlCode
= IOCTL_SCSI_MINIPORT_IDENTIFY
;
1770 } else if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1771 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1772 case READ_ATTRIBUTES
:
1773 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
;
1774 length
= READ_ATTRIBUTE_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1776 case READ_THRESHOLDS
:
1777 controlCode
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
;
1778 length
= READ_THRESHOLD_BUFFER_SIZE
+ sizeof(SENDCMDOUTPARAMS
);
1781 status
= STATUS_INVALID_PARAMETER
;
1786 status
= STATUS_INVALID_PARAMETER
;
1789 if (controlCode
== 0) {
1790 status
= STATUS_INVALID_PARAMETER
;
1794 srbControl
= ExAllocatePool(NonPagedPool
,
1795 sizeof(SRB_IO_CONTROL
) + length
);
1798 status
= STATUS_INSUFFICIENT_RESOURCES
;
1803 // fill in srbControl fields
1806 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1807 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1808 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1809 srbControl
->Length
= length
;
1810 srbControl
->ControlCode
= controlCode
;
1813 // Point to the 'buffer' portion of the SRB_CONTROL
1816 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1819 // Ensure correct target is set in the cmd parameters.
1822 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1825 // Copy the IOCTL parameters to the srb control buffer area.
1828 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1830 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
1831 deviceExtension
->PortDeviceObject
,
1833 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
1835 sizeof(SRB_IO_CONTROL
) + length
,
1841 status
= STATUS_INSUFFICIENT_RESOURCES
;
1846 // Call the port driver with the request and wait for it to complete.
1849 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
1851 if (status
== STATUS_PENDING
) {
1852 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1853 status
= ioStatus
.Status
;
1857 // If successful, copy the data received into the output buffer
1860 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1862 if (NT_SUCCESS(status
)) {
1864 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
- 1);
1865 Irp
->IoStatus
.Information
= length
- 1;
1869 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, (sizeof(SENDCMDOUTPARAMS
) - 1));
1870 Irp
->IoStatus
.Information
= sizeof(SENDCMDOUTPARAMS
) - 1;
1874 ExFreePool(srbControl
);
1879 case SMART_SEND_DRIVE_COMMAND
: {
1881 PSENDCMDINPARAMS cmdInParameters
= ((PSENDCMDINPARAMS
)Irp
->AssociatedIrp
.SystemBuffer
);
1882 PSRB_IO_CONTROL srbControl
;
1883 ULONG controlCode
= 0;
1886 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1887 (sizeof(SENDCMDINPARAMS
) - 1)) {
1888 status
= STATUS_INVALID_PARAMETER
;
1891 } else if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1892 (sizeof(SENDCMDOUTPARAMS
) - 1)) {
1893 status
= STATUS_INVALID_PARAMETER
;
1898 // Create notification event object to be used to signal the
1899 // request completion.
1902 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1906 if (cmdInParameters
->irDriveRegs
.bCommandReg
== SMART_CMD
) {
1907 switch (cmdInParameters
->irDriveRegs
.bFeaturesReg
) {
1910 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
;
1914 controlCode
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
;
1917 case RETURN_SMART_STATUS
:
1920 // Ensure bBuffer is at least 2 bytes (to hold the values of
1921 // cylinderLow and cylinderHigh).
1924 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1925 (sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
))) {
1927 status
= STATUS_INVALID_PARAMETER
;
1931 controlCode
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
;
1932 length
= sizeof(IDEREGS
);
1935 case ENABLE_DISABLE_AUTOSAVE
:
1936 controlCode
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
;
1939 case SAVE_ATTRIBUTE_VALUES
:
1940 controlCode
= IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
;
1943 case EXECUTE_OFFLINE_DIAGS
:
1944 controlCode
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
;
1948 status
= STATUS_INVALID_PARAMETER
;
1953 status
= STATUS_INVALID_PARAMETER
;
1956 if (controlCode
== 0) {
1957 status
= STATUS_INVALID_PARAMETER
;
1961 length
+= (sizeof(SENDCMDOUTPARAMS
) > sizeof(SENDCMDINPARAMS
)) ? sizeof(SENDCMDOUTPARAMS
) : sizeof(SENDCMDINPARAMS
);
1962 srbControl
= ExAllocatePool(NonPagedPool
,
1963 sizeof(SRB_IO_CONTROL
) + length
);
1966 status
= STATUS_INSUFFICIENT_RESOURCES
;
1971 // fill in srbControl fields
1974 srbControl
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
1975 RtlMoveMemory (srbControl
->Signature
, "SCSIDISK", 8);
1976 srbControl
->Timeout
= deviceExtension
->TimeOutValue
;
1977 srbControl
->Length
= length
;
1980 // Point to the 'buffer' portion of the SRB_CONTROL
1983 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
1986 // Ensure correct target is set in the cmd parameters.
1989 cmdInParameters
->bDriveNumber
= deviceExtension
->TargetId
;
1992 // Copy the IOCTL parameters to the srb control buffer area.
1995 RtlMoveMemory((PVOID
)buffer
, Irp
->AssociatedIrp
.SystemBuffer
, sizeof(SENDCMDINPARAMS
) - 1);
1997 srbControl
->ControlCode
= controlCode
;
1999 irp2
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT
,
2000 deviceExtension
->PortDeviceObject
,
2002 sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1,
2004 sizeof(SRB_IO_CONTROL
) + length
,
2010 status
= STATUS_INSUFFICIENT_RESOURCES
;
2015 // Call the port driver with the request and wait for it to complete.
2018 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp2
);
2020 if (status
== STATUS_PENDING
) {
2021 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2022 status
= ioStatus
.Status
;
2026 // Copy the data received into the output buffer. Since the status buffer
2027 // contains error information also, always perform this copy. IO will will
2028 // either pass this back to the app, or zero it, in case of error.
2031 buffer
= (ULONG_PTR
)srbControl
+ srbControl
->HeaderLength
;
2034 // Update the return buffer size based on the sub-command.
2037 if (cmdInParameters
->irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) {
2038 length
= sizeof(SENDCMDOUTPARAMS
) - 1 + sizeof(IDEREGS
);
2040 length
= sizeof(SENDCMDOUTPARAMS
) - 1;
2043 RtlMoveMemory ( Irp
->AssociatedIrp
.SystemBuffer
, (PVOID
)buffer
, length
);
2044 Irp
->IoStatus
.Information
= length
;
2046 ExFreePool(srbControl
);
2051 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2052 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2055 PDEVICE_EXTENSION physicalDeviceExtension
;
2056 PDISK_DATA physicalDiskData
;
2057 BOOLEAN removable
= FALSE
;
2058 BOOLEAN listInitialized
= FALSE
;
2060 if ((irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
&&
2061 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2062 sizeof(DISK_GEOMETRY
)) ||
2063 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
&&
2064 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2065 sizeof(DISK_GEOMETRY_EX
))) {
2067 status
= STATUS_INFO_LENGTH_MISMATCH
;
2071 status
= STATUS_SUCCESS
;
2073 physicalDeviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2074 physicalDiskData
= (PDISK_DATA
)(physicalDeviceExtension
+ 1);
2076 removable
= (BOOLEAN
)DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
;
2077 listInitialized
= (physicalDiskData
->PartitionListState
== Initialized
);
2079 if (removable
|| (!listInitialized
))
2082 // Issue ReadCapacity to update device extension
2083 // with information for current media.
2086 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
2092 if (!NT_SUCCESS(status
)) {
2095 // Note the drive is not ready.
2098 diskData
->DriveNotReady
= TRUE
;
2104 // Note the drive is now ready.
2107 diskData
->DriveNotReady
= FALSE
;
2109 } else if (NT_SUCCESS(status
)) {
2111 // ReadDriveCapacity was allright, create Partition Objects
2113 if (physicalDiskData
->PartitionListState
== NotInitialized
) {
2114 status
= CreatePartitionDeviceObjects(deviceExtension
->PhysicalDevice
, NULL
);
2118 if (NT_SUCCESS(status
)) {
2121 // Copy drive geometry information from device extension.
2124 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2125 deviceExtension
->DiskGeometry
,
2126 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2127 sizeof(DISK_GEOMETRY
) :
2128 sizeof(DISK_GEOMETRY_EX
));
2130 status
= STATUS_SUCCESS
;
2131 Irp
->IoStatus
.Information
=
2132 (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_GET_DRIVE_GEOMETRY
) ?
2133 sizeof(DISK_GEOMETRY
) :
2134 sizeof(DISK_GEOMETRY_EX
);
2141 case IOCTL_DISK_VERIFY
:
2145 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2146 LARGE_INTEGER byteOffset
;
2151 // Validate buffer length.
2154 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2155 sizeof(VERIFY_INFORMATION
)) {
2157 status
= STATUS_INFO_LENGTH_MISMATCH
;
2165 srb
->CdbLength
= 10;
2167 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2170 // Add disk offset to starting sector.
2173 byteOffset
.QuadPart
= deviceExtension
->StartingOffset
.QuadPart
+
2174 verifyInfo
->StartingOffset
.QuadPart
;
2177 // Convert byte offset to sector offset.
2180 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> deviceExtension
->SectorShift
);
2183 // Convert ULONG byte count to USHORT sector count.
2186 sectorCount
= (USHORT
)(verifyInfo
->Length
>> deviceExtension
->SectorShift
);
2189 // Move little endian values into CDB in big endian format.
2192 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2193 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2194 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2195 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2197 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2198 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2201 // The verify command is used by the NT FORMAT utility and
2202 // requests are sent down for 5% of the volume size. The
2203 // request timeout value is calculated based on the number of
2204 // sectors verified.
2207 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2208 deviceExtension
->TimeOutValue
;
2210 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
2221 case IOCTL_DISK_GET_PARTITION_INFO
:
2224 // Return the information about the partition specified by the device
2225 // object. Note that no information is ever returned about the size
2226 // or partition type of the physical disk, as this doesn't make any
2230 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2231 sizeof(PARTITION_INFORMATION
)) {
2233 status
= STATUS_INFO_LENGTH_MISMATCH
;
2236 #if 0 // HACK: ReactOS partition numbers must be wrong
2237 else if (diskData
->PartitionNumber
== 0) {
2240 // Paritition zero is not a partition so this is not a
2241 // reasonable request.
2244 status
= STATUS_INVALID_DEVICE_REQUEST
;
2250 PPARTITION_INFORMATION outputBuffer
;
2253 // Update the geometry in case it has changed.
2256 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2258 if (!NT_SUCCESS(status
)) {
2261 // Note the drive is not ready.
2264 diskData
->DriveNotReady
= TRUE
;
2269 // Note the drive is now ready.
2272 diskData
->DriveNotReady
= FALSE
;
2273 // HACK: ReactOS partition numbers must be wrong (>0 part)
2274 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2276 status
= STATUS_INVALID_DEVICE_REQUEST
;
2281 (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2283 outputBuffer
->PartitionType
= diskData
->PartitionType
;
2284 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2285 outputBuffer
->PartitionLength
.QuadPart
= (diskData
->PartitionNumber
) ?
2286 deviceExtension
->PartitionLength
.QuadPart
: 2305843009213693951LL; // HACK
2287 outputBuffer
->HiddenSectors
= diskData
->HiddenSectors
;
2288 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2289 outputBuffer
->BootIndicator
= diskData
->BootIndicator
;
2290 outputBuffer
->RewritePartition
= FALSE
;
2291 outputBuffer
->RecognizedPartition
=
2292 IsRecognizedPartition(diskData
->PartitionType
);
2294 status
= STATUS_SUCCESS
;
2295 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
2300 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2303 // Return the information about the partition specified by the device
2304 // object. Note that no information is ever returned about the size
2305 // or partition type of the physical disk, as this doesn't make any
2309 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2310 sizeof(PARTITION_INFORMATION_EX
)) {
2312 status
= STATUS_INFO_LENGTH_MISMATCH
;
2315 else if (diskData
->PartitionNumber
== 0) {
2318 // Paritition zero is not a partition so this is not a
2319 // reasonable request.
2322 status
= STATUS_INVALID_DEVICE_REQUEST
;
2327 PPARTITION_INFORMATION_EX outputBuffer
;
2330 // Update the geometry in case it has changed.
2333 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2335 if (!NT_SUCCESS(status
)) {
2338 // Note the drive is not ready.
2341 diskData
->DriveNotReady
= TRUE
;
2346 // Note the drive is now ready.
2349 diskData
->DriveNotReady
= FALSE
;
2351 if (diskData
->PartitionType
== 0 && (diskData
->PartitionNumber
> 0)) {
2353 status
= STATUS_INVALID_DEVICE_REQUEST
;
2358 (PPARTITION_INFORMATION_EX
)Irp
->AssociatedIrp
.SystemBuffer
;
2361 // FIXME: hack of the year, assume that partition is MBR
2362 // Thing that can obviously be wrong...
2365 outputBuffer
->PartitionStyle
= PARTITION_STYLE_MBR
;
2366 outputBuffer
->Mbr
.PartitionType
= diskData
->PartitionType
;
2367 outputBuffer
->StartingOffset
= deviceExtension
->StartingOffset
;
2368 outputBuffer
->PartitionLength
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2369 outputBuffer
->Mbr
.HiddenSectors
= diskData
->HiddenSectors
;
2370 outputBuffer
->PartitionNumber
= diskData
->PartitionNumber
;
2371 outputBuffer
->Mbr
.BootIndicator
= diskData
->BootIndicator
;
2372 outputBuffer
->RewritePartition
= FALSE
;
2373 outputBuffer
->Mbr
.RecognizedPartition
=
2374 IsRecognizedPartition(diskData
->PartitionType
);
2376 status
= STATUS_SUCCESS
;
2377 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
2382 case IOCTL_DISK_SET_PARTITION_INFO
:
2384 if (diskData
->PartitionNumber
== 0) {
2386 status
= STATUS_UNSUCCESSFUL
;
2390 PSET_PARTITION_INFORMATION inputBuffer
=
2391 (PSET_PARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
2394 // Validate buffer length.
2397 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2398 sizeof(SET_PARTITION_INFORMATION
)) {
2400 status
= STATUS_INFO_LENGTH_MISMATCH
;
2405 // The HAL routines IoGet- and IoSetPartitionInformation were
2406 // developed before support of dynamic partitioning and therefore
2407 // don't distinguish between partition ordinal (that is the order
2408 // of a partition on a disk) and the partition number. (The
2409 // partition number is assigned to a partition to identify it to
2410 // the system.) Use partition ordinals for these legacy calls.
2413 status
= IoSetPartitionInformation(
2414 deviceExtension
->PhysicalDevice
,
2415 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2416 diskData
->PartitionOrdinal
,
2417 inputBuffer
->PartitionType
);
2419 if (NT_SUCCESS(status
)) {
2421 diskData
->PartitionType
= inputBuffer
->PartitionType
;
2427 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2430 // Return the partition layout for the physical drive. Note that
2431 // the layout is returned for the actual physical drive, regardless
2432 // of which partition was specified for the request.
2435 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2436 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2437 status
= STATUS_INFO_LENGTH_MISMATCH
;
2441 PDRIVE_LAYOUT_INFORMATION partitionList
;
2442 PDEVICE_EXTENSION physicalExtension
= deviceExtension
;
2443 PPARTITION_INFORMATION partitionEntry
;
2444 PDISK_DATA diskData
;
2449 // Read partition information.
2452 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
2453 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2457 if (!NT_SUCCESS(status
)) {
2462 // The disk layout has been returned in the partitionList
2463 // buffer. Determine its size and, if the data will fit
2464 // into the intermediatery buffer, return it.
2467 tempSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,PartitionEntry
[0]);
2468 tempSize
+= partitionList
->PartitionCount
*
2469 sizeof(PARTITION_INFORMATION
);
2472 irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
2474 status
= STATUS_BUFFER_TOO_SMALL
;
2475 ExFreePool(partitionList
);
2480 // Walk partition list to associate partition numbers with
2481 // partition entries.
2484 for (i
= 0; i
< partitionList
->PartitionCount
; i
++) {
2487 // Walk partition chain anchored at physical disk extension.
2490 deviceExtension
= physicalExtension
;
2491 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2495 deviceExtension
= diskData
->NextPartition
;
2498 // Check if this is the last partition in the chain.
2501 if (!deviceExtension
) {
2506 // Get the partition device extension from disk data.
2509 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
2512 // Check if this partition is not currently being used.
2515 if (!deviceExtension
->PartitionLength
.QuadPart
) {
2519 partitionEntry
= &partitionList
->PartitionEntry
[i
];
2522 // Check if empty, or describes extended partiton or hasn't changed.
2525 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2526 IsContainerPartition(partitionEntry
->PartitionType
)) {
2531 // Check if new partition starts where this partition starts.
2534 if (partitionEntry
->StartingOffset
.QuadPart
!=
2535 deviceExtension
->StartingOffset
.QuadPart
) {
2540 // Check if partition length is the same.
2543 if (partitionEntry
->PartitionLength
.QuadPart
==
2544 deviceExtension
->PartitionLength
.QuadPart
) {
2547 // Partitions match. Update partition number.
2550 partitionEntry
->PartitionNumber
=
2551 diskData
->PartitionNumber
;
2559 // Copy partition information to system buffer.
2562 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
2565 status
= STATUS_SUCCESS
;
2566 Irp
->IoStatus
.Information
= tempSize
;
2569 // Finally, free the buffer allocated by reading the
2573 ExFreePool(partitionList
);
2578 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
2583 // Update the disk with new partition information.
2586 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
2589 // Validate buffer length.
2592 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2593 sizeof(DRIVE_LAYOUT_INFORMATION
)) {
2595 status
= STATUS_INFO_LENGTH_MISMATCH
;
2599 length
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2600 (partitionList
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
);
2603 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2606 status
= STATUS_BUFFER_TOO_SMALL
;
2611 // Verify that device object is for physical disk.
2614 if (deviceExtension
->PhysicalDevice
->DeviceExtension
!= deviceExtension
) {
2615 status
= STATUS_INVALID_PARAMETER
;
2620 // Walk through partition table comparing partitions to
2621 // existing partitions to create, delete and change
2622 // device objects as necessary.
2625 UpdateDeviceObjects(DeviceObject
,
2629 // Write changes to disk.
2632 status
= IoWritePartitionTable(
2633 deviceExtension
->DeviceObject
,
2634 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
2635 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
,
2636 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
,
2641 // Update IRP with bytes returned.
2644 if (NT_SUCCESS(status
)) {
2645 Irp
->IoStatus
.Information
= length
;
2650 case IOCTL_DISK_REASSIGN_BLOCKS
:
2653 // Map defective blocks to new location on disk.
2658 PREASSIGN_BLOCKS badBlocks
= Irp
->AssociatedIrp
.SystemBuffer
;
2664 // Validate buffer length.
2667 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2668 sizeof(REASSIGN_BLOCKS
)) {
2670 status
= STATUS_INFO_LENGTH_MISMATCH
;
2674 bufferSize
= sizeof(REASSIGN_BLOCKS
) +
2675 (badBlocks
->Count
- 1) * sizeof(ULONG
);
2677 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
2680 status
= STATUS_INFO_LENGTH_MISMATCH
;
2685 // Build the data buffer to be transferred in the input buffer.
2686 // The format of the data to the device is:
2690 // x * 4 btyes Block Address
2692 // All values are big endian.
2695 badBlocks
->Reserved
= 0;
2696 blockCount
= badBlocks
->Count
;
2699 // Convert # of entries to # of bytes.
2703 badBlocks
->Count
= (USHORT
) ((blockCount
>> 8) & 0XFF);
2704 badBlocks
->Count
|= (USHORT
) ((blockCount
<< 8) & 0XFF00);
2707 // Convert back to number of entries.
2712 for (; blockCount
> 0; blockCount
--) {
2714 blockNumber
= badBlocks
->BlockNumber
[blockCount
-1];
2716 REVERSE_BYTES((PFOUR_BYTE
) &badBlocks
->BlockNumber
[blockCount
-1],
2717 (PFOUR_BYTE
) &blockNumber
);
2722 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_REASSIGN_BLOCKS
;
2725 // Set timeout value.
2728 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
2730 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
2736 Irp
->IoStatus
.Status
= status
;
2737 Irp
->IoStatus
.Information
= 0;
2739 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2744 case IOCTL_DISK_IS_WRITABLE
:
2747 // Determine if the device is writable.
2750 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
2752 if (modeData
== NULL
) {
2753 status
= STATUS_INSUFFICIENT_RESOURCES
;
2757 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
2759 length
= ScsiClassModeSense(DeviceObject
,
2762 MODE_SENSE_RETURN_ALL
);
2764 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2767 // Retry the request in case of a check condition.
2770 length
= ScsiClassModeSense(DeviceObject
,
2773 MODE_SENSE_RETURN_ALL
);
2775 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
2776 status
= STATUS_IO_DEVICE_ERROR
;
2777 ExFreePool(modeData
);
2782 if (modeData
->DeviceSpecificParameter
& MODE_DSP_WRITE_PROTECT
) {
2783 status
= STATUS_MEDIA_WRITE_PROTECTED
;
2785 status
= STATUS_SUCCESS
;
2788 ExFreePool(modeData
);
2791 case IOCTL_DISK_INTERNAL_SET_VERIFY
:
2794 // If the caller is kernel mode, set the verify bit.
2797 if (Irp
->RequestorMode
== KernelMode
) {
2798 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2800 status
= STATUS_SUCCESS
;
2803 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY
:
2806 // If the caller is kernel mode, clear the verify bit.
2809 if (Irp
->RequestorMode
== KernelMode
) {
2810 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
2812 status
= STATUS_SUCCESS
;
2815 case IOCTL_DISK_FIND_NEW_DEVICES
:
2818 // Search for devices that have been powered on since the last
2819 // device search or system initialization.
2822 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2823 status
= DriverEntry(DeviceObject
->DriverObject
,
2826 Irp
->IoStatus
.Status
= status
;
2828 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2831 case IOCTL_DISK_MEDIA_REMOVAL
:
2834 // If the disk is not removable then don't allow this command.
2837 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
2838 status
= STATUS_INVALID_DEVICE_REQUEST
;
2843 // Fall through and let the class driver process the request.
2846 case IOCTL_DISK_GET_LENGTH_INFO
:
2849 // Validate buffer length.
2852 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2853 sizeof(GET_LENGTH_INFORMATION
)) {
2854 status
= STATUS_BUFFER_TOO_SMALL
;
2858 PGET_LENGTH_INFORMATION lengthInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
2861 // Update the geometry in case it has changed.
2864 status
= UpdateRemovableGeometry (DeviceObject
, Irp
);
2866 if (!NT_SUCCESS(status
)) {
2869 // Note the drive is not ready.
2872 diskData
->DriveNotReady
= TRUE
;
2877 // Note the drive is now ready.
2880 diskData
->DriveNotReady
= FALSE
;
2883 // Output data, and return
2886 lengthInformation
->Length
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
2887 status
= STATUS_SUCCESS
;
2888 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2896 // Free the Srb, since it is not needed.
2902 // Pass the request to the common device control routine.
2905 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
2909 } // end switch( ...
2911 Irp
->IoStatus
.Status
= status
;
2913 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2915 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2918 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2922 } // end ScsiDiskDeviceControl()
2926 ScsiDiskShutdownFlush (
2927 IN PDEVICE_OBJECT DeviceObject
,
2933 Routine Description:
2935 This routine is called for a shutdown and flush IRPs. These are sent by the
2936 system before it actually shuts down or when the file system does a flush.
2937 A synchronize cache command is sent to the device if it is write caching.
2938 If the device is removable an unlock command will be sent. This routine
2939 will sent a shutdown or flush Srb to the port driver.
2943 DriverObject - Pointer to device object to being shutdown by system.
2954 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2955 PIO_STACK_LOCATION irpStack
;
2956 PSCSI_REQUEST_BLOCK srb
;
2961 // Allocate SCSI request block.
2964 srb
= ExAllocatePool(NonPagedPool
, sizeof(SCSI_REQUEST_BLOCK
));
2969 // Set the status and complete the request.
2972 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2973 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2974 return(STATUS_INSUFFICIENT_RESOURCES
);
2977 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
2980 // Write length to SRB.
2983 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2986 // Set SCSI bus address.
2989 srb
->PathId
= deviceExtension
->PathId
;
2990 srb
->TargetId
= deviceExtension
->TargetId
;
2991 srb
->Lun
= deviceExtension
->Lun
;
2994 // Set timeout value and mark the request as not being a tagged request.
2997 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
* 4;
2998 srb
->QueueTag
= SP_UNTAGGED
;
2999 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3000 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3003 // If the write cache is enabled then send a synchronize cache request.
3006 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3008 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3009 srb
->CdbLength
= 10;
3011 srb
->Cdb
[0] = SCSIOP_SYNCHRONIZE_CACHE
;
3013 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3019 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status
));
3023 // Unlock the device if it is removable and this is a shutdown.
3026 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3028 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
3029 irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
3032 cdb
= (PVOID
) srb
->Cdb
;
3033 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3034 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
3037 // Set timeout value.
3040 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3041 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3047 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status
));
3053 // Save a few parameters in the current stack location.
3056 srb
->Function
= irpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
?
3057 SRB_FUNCTION_SHUTDOWN
: SRB_FUNCTION_FLUSH
;
3060 // Set the retry count to zero.
3063 irpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
3066 // Set up IoCompletion routine address.
3069 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3072 // Get next stack location and
3073 // set major function code.
3076 irpStack
= IoGetNextIrpStackLocation(Irp
);
3078 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3081 // Set up SRB for execute scsi request.
3082 // Save SRB address in next stack for port driver.
3085 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3088 // Set up Irp Address.
3091 srb
->OriginalRequest
= Irp
;
3094 // Call the port driver to process the request.
3097 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3099 } // end ScsiDiskShutdown()
3105 PDEVICE_OBJECT DeviceObject
3109 Routine Description:
3111 The routine performs the necessary functions to determine if a device is
3112 really a floppy rather than a harddisk. This is done by a mode sense
3113 command. First, a check is made to see if the medimum type is set. Second
3114 a check is made for the flexible parameters mode page. Also a check is
3115 made to see if the write cache is enabled.
3119 DeviceObject - Supplies the device object to be tested.
3123 Return TRUE if the indicated device is a floppy.
3127 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3134 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3136 if (modeData
== NULL
) {
3140 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3142 length
= ScsiClassModeSense(DeviceObject
,
3145 MODE_SENSE_RETURN_ALL
);
3147 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3150 // Retry the request in case of a check condition.
3153 length
= ScsiClassModeSense(DeviceObject
,
3156 MODE_SENSE_RETURN_ALL
);
3158 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3160 ExFreePool(modeData
);
3167 // If the length is greater than length indicated by the mode data reset
3168 // the data to the mode data.
3171 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3172 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3176 // Look for the flexible disk mode page.
3179 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_FLEXIBILE
, TRUE
);
3181 if (pageData
!= NULL
) {
3183 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3184 ExFreePool(modeData
);
3189 // Check to see if the write cache is enabled.
3192 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3195 // Assume that write cache is disabled or not supported.
3198 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3201 // Check if valid caching page exists.
3204 if (pageData
!= NULL
) {
3207 // Check if write cache is disabled.
3210 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3213 "SCSIDISK: Disk write cache enabled\n"));
3216 // Check if forced unit access (FUA) is supported.
3219 if (((PMODE_PARAMETER_HEADER
)modeData
)->DeviceSpecificParameter
& MODE_DSP_FUA_SUPPORTED
) {
3221 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3226 "SCSIDISK: Disk does not support FUA or DPO\n"));
3236 ExFreePool(modeData
);
3239 } // end IsFloppyDevice()
3245 IN PDEVICE_OBJECT DeviceObject
,
3246 IN PCHAR ModeSelectBuffer
,
3253 Routine Description:
3255 This routine sends a mode select command.
3259 DeviceObject - Supplies the device object associated with this request.
3261 ModeSelectBuffer - Supplies a buffer containing the page data.
3263 Length - Supplies the length in bytes of the mode select buffer.
3265 SavePage - Indicates that parameters should be written to disk.
3269 Length of the transferred data is returned.
3273 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3275 SCSI_REQUEST_BLOCK srb
;
3280 PMODE_PARAMETER_BLOCK blockDescriptor
;
3284 length2
= Length
+ sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
3287 // Allocate buffer for mode select header, block descriptor, and mode page.
3290 buffer
= (ULONG_PTR
)ExAllocatePool(NonPagedPoolCacheAligned
,length2
);
3292 RtlZeroMemory((PVOID
)buffer
, length2
);
3295 // Set length in header to size of mode page.
3298 ((PMODE_PARAMETER_HEADER
)buffer
)->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
3300 blockDescriptor
= (PMODE_PARAMETER_BLOCK
)(buffer
+ 1);
3306 blockDescriptor
->BlockLength
[1]=0x02;
3309 // Copy mode page to buffer.
3312 RtlCopyMemory((PVOID
)(buffer
+ 3), ModeSelectBuffer
, Length
);
3318 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3321 // Build the MODE SELECT CDB.
3325 cdb
= (PCDB
)srb
.Cdb
;
3328 // Set timeout value from device extension.
3331 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
* 2;
3333 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3334 cdb
->MODE_SELECT
.SPBit
= SavePage
;
3335 cdb
->MODE_SELECT
.PFBit
= 1;
3336 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)(length2
);
3340 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3347 if (status
== STATUS_VERIFY_REQUIRED
) {
3350 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3363 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3364 status
= STATUS_SUCCESS
;
3367 ExFreePool((PVOID
)buffer
);
3369 if (NT_SUCCESS(status
)) {
3375 } // end SciDiskModeSelect()
3381 IN PDEVICE_OBJECT DeviceObject
,
3382 IN PSCSI_INQUIRY_DATA LunInfo
3386 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3387 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
3388 BAD_CONTROLLER_INFORMATION
const *controller
;
3393 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
3395 controller
= &ScsiDiskBadControllers
[j
];
3397 if (!controller
->DisableWriteCache
|| strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
3401 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller
->InquiryString
));
3403 modeData
= ExAllocatePool(NonPagedPoolCacheAligned
, MODE_DATA_SIZE
);
3405 if (modeData
== NULL
) {
3408 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3412 RtlZeroMemory(modeData
, MODE_DATA_SIZE
);
3414 length
= ScsiClassModeSense(DeviceObject
,
3417 MODE_SENSE_RETURN_ALL
);
3419 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3422 // Retry the request in case of a check condition.
3425 length
= ScsiClassModeSense(DeviceObject
,
3428 MODE_SENSE_RETURN_ALL
);
3430 if (length
< sizeof(MODE_PARAMETER_HEADER
)) {
3434 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3436 ExFreePool(modeData
);
3443 // If the length is greater than length indicated by the mode data reset
3444 // the data to the mode data.
3447 if (length
> (ULONG
) ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1) {
3448 length
= ((PMODE_PARAMETER_HEADER
) modeData
)->ModeDataLength
+ 1;
3452 // Check to see if the write cache is enabled.
3455 pageData
= ScsiClassFindModePage( modeData
, length
, MODE_PAGE_CACHING
, TRUE
);
3458 // Assume that write cache is disabled or not supported.
3461 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3464 // Check if valid caching page exists.
3467 if (pageData
!= NULL
) {
3469 BOOLEAN savePage
= FALSE
;
3471 savePage
= (BOOLEAN
)(((PMODE_CACHING_PAGE
)pageData
)->PageSavable
);
3474 // Check if write cache is disabled.
3477 if (((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
) {
3479 PIO_ERROR_LOG_PACKET errorLogEntry
;
3484 // Disable write cache and ensure necessary fields are zeroed.
3487 ((PMODE_CACHING_PAGE
)pageData
)->WriteCacheEnable
= FALSE
;
3488 ((PMODE_CACHING_PAGE
)pageData
)->Reserved
= 0;
3489 ((PMODE_CACHING_PAGE
)pageData
)->PageSavable
= 0;
3490 ((PMODE_CACHING_PAGE
)pageData
)->Reserved2
= 0;
3493 // Extract length from caching page.
3496 length
= ((PMODE_CACHING_PAGE
)pageData
)->PageLength
;
3499 // Compensate for page code and page length.
3505 // Issue mode select to set the parameter.
3508 if (ScsiDiskModeSelect(DeviceObject
,
3514 "SCSIDISK: Disk write cache disabled\n"));
3516 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3517 errorCode
= IO_WRITE_CACHE_DISABLED
;
3520 if (ScsiDiskModeSelect(DeviceObject
,
3526 "SCSIDISK: Disk write cache disabled\n"));
3529 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
3530 errorCode
= IO_WRITE_CACHE_DISABLED
;
3535 "SCSIDISK: Mode select to disable write cache failed\n"));
3537 deviceExtension
->DeviceFlags
|= DEV_WRITE_CACHE
;
3538 errorCode
= IO_WRITE_CACHE_ENABLED
;
3543 // Log the appropriate informational or error entry.
3546 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3548 sizeof(IO_ERROR_LOG_PACKET
) + 3
3551 if (errorLogEntry
!= NULL
) {
3553 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3554 errorLogEntry
->ErrorCode
= errorCode
;
3555 errorLogEntry
->SequenceNumber
= 0;
3556 errorLogEntry
->MajorFunctionCode
= IRP_MJ_SCSI
;
3557 errorLogEntry
->IoControlCode
= 0;
3558 errorLogEntry
->RetryCount
= 0;
3559 errorLogEntry
->UniqueErrorValue
= 0x1;
3560 errorLogEntry
->DumpDataSize
= 3 * sizeof(ULONG
);
3561 errorLogEntry
->DumpData
[0] = LunInfo
->PathId
;
3562 errorLogEntry
->DumpData
[1] = LunInfo
->TargetId
;
3563 errorLogEntry
->DumpData
[2] = LunInfo
->Lun
;
3566 // Write the error log packet.
3569 IoWriteErrorLogEntry(errorLogEntry
);
3575 // Found device so exit the loop and return.
3587 CalculateMbrCheckSum(
3588 IN PDEVICE_EXTENSION DeviceExtension
,
3594 Routine Description:
3596 Read MBR and calculate checksum.
3600 DeviceExtension - Supplies a pointer to the device information for disk.
3601 Checksum - Memory location to return MBR checksum.
3605 Returns TRUE if checksum is valid.
3609 LARGE_INTEGER sectorZero
;
3611 IO_STATUS_BLOCK ioStatus
;
3619 sectorZero
.QuadPart
= (LONGLONG
) 0;
3622 // Create notification event object to be used to signal the inquiry
3623 // request completion.
3626 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
3632 sectorSize
= DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
3635 // Make sure sector size is at least 512 bytes.
3638 if (sectorSize
< 512) {
3643 // Allocate buffer for sector read.
3646 mbr
= ExAllocatePool(NonPagedPoolCacheAligned
, sectorSize
);
3653 // Build IRP to read MBR.
3656 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
3657 DeviceExtension
->DeviceObject
,
3670 // Pass request to port driver and wait for request to complete.
3673 status
= IoCallDriver(DeviceExtension
->DeviceObject
,
3676 if (status
== STATUS_PENDING
) {
3677 KeWaitForSingleObject(&event
,
3682 status
= ioStatus
.Status
;
3685 if (!NT_SUCCESS(status
)) {
3691 // Calculate MBR checksum.
3696 for (i
= 0; i
< 128; i
++) {
3697 *Checksum
+= mbr
[i
];
3700 *Checksum
= ~*Checksum
+ 1;
3710 IN PDEVICE_EXTENSION DeviceExtension
,
3717 Routine Description:
3719 The routine queries the registry to determine if this disk is visible to
3720 the BIOS. If the disk is visable to the BIOS, then the geometry information
3725 DeviceExtension - Supplies a pointer to the device information for disk.
3726 Signature - Unique identifier recorded in MBR.
3727 BusKey - Handle of bus key.
3728 DiskNumber - Returns ordinal of disk as BIOS sees it.
3732 TRUE is disk signature matched.
3736 PDISK_DATA diskData
= (PDISK_DATA
)(DeviceExtension
+ 1);
3737 BOOLEAN diskFound
= FALSE
;
3738 OBJECT_ATTRIBUTES objectAttributes
;
3739 UNICODE_STRING unicodeString
;
3740 UNICODE_STRING identifier
;
3742 ULONG adapterNumber
;
3750 STRING anotherString
;
3753 PKEY_VALUE_FULL_INFORMATION keyData
;
3757 for (busNumber
= 0; ; busNumber
++) {
3760 // Open controller name key.
3763 sprintf((PCHAR
)buffer
,
3767 RtlInitString(&string
,
3770 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3774 if (!NT_SUCCESS(status
)){
3778 InitializeObjectAttributes(&objectAttributes
,
3780 OBJ_CASE_INSENSITIVE
,
3782 (PSECURITY_DESCRIPTOR
)NULL
);
3784 status
= ZwOpenKey(&spareKey
,
3788 RtlFreeUnicodeString(&unicodeString
);
3790 if (!NT_SUCCESS(status
)) {
3795 // Open up controller ordinal key.
3798 RtlInitUnicodeString(&unicodeString
, L
"DiskController");
3799 InitializeObjectAttributes(&objectAttributes
,
3801 OBJ_CASE_INSENSITIVE
,
3803 (PSECURITY_DESCRIPTOR
)NULL
);
3805 status
= ZwOpenKey(&adapterKey
,
3810 // This could fail even with additional adapters of this type
3814 if (!NT_SUCCESS(status
)) {
3818 for (adapterNumber
= 0; ; adapterNumber
++) {
3824 sprintf((PCHAR
)buffer
,
3825 "%lu\\DiskPeripheral",
3828 RtlInitString(&string
,
3831 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3835 if (!NT_SUCCESS(status
)){
3839 InitializeObjectAttributes(&objectAttributes
,
3841 OBJ_CASE_INSENSITIVE
,
3843 (PSECURITY_DESCRIPTOR
)NULL
);
3845 status
= ZwOpenKey(&diskKey
,
3849 RtlFreeUnicodeString(&unicodeString
);
3851 if (!NT_SUCCESS(status
)) {
3855 for (diskNumber
= 0; ; diskNumber
++) {
3857 sprintf((PCHAR
)buffer
,
3861 RtlInitString(&string
,
3864 status
= RtlAnsiStringToUnicodeString(&unicodeString
,
3868 if (!NT_SUCCESS(status
)){
3872 InitializeObjectAttributes(&objectAttributes
,
3874 OBJ_CASE_INSENSITIVE
,
3876 (PSECURITY_DESCRIPTOR
)NULL
);
3878 status
= ZwOpenKey(&targetKey
,
3882 RtlFreeUnicodeString(&unicodeString
);
3884 if (!NT_SUCCESS(status
)) {
3889 // Allocate buffer for registry query.
3892 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
3894 if (keyData
== NULL
) {
3900 // Get disk peripheral identifier.
3903 RtlInitUnicodeString(&unicodeString
, L
"Identifier");
3904 status
= ZwQueryValueKey(targetKey
,
3906 KeyValueFullInformation
,
3913 if (!NT_SUCCESS(status
)) {
3918 // Complete unicode string.
3922 (PWSTR
)((PUCHAR
)keyData
+ keyData
->DataOffset
);
3923 identifier
.Length
= (USHORT
)keyData
->DataLength
;
3924 identifier
.MaximumLength
= (USHORT
)keyData
->DataLength
;
3927 // Convert unicode identifier to ansi string.
3931 RtlUnicodeStringToAnsiString(&anotherString
,
3935 if (!NT_SUCCESS(status
)) {
3940 // If checksum is zero, then the MBR is valid and
3941 // the signature is meaningful.
3944 if (diskData
->MbrCheckSum
) {
3947 // Convert checksum to ansi string.
3950 sprintf((PCHAR
)buffer
, "%08lx", diskData
->MbrCheckSum
);
3955 // Convert signature to ansi string.
3958 sprintf((PCHAR
)buffer
, "%08lx", diskData
->Signature
);
3961 // Make string point at signature. Can't use scan
3962 // functions because they are not exported for driver use.
3965 anotherString
.Buffer
+=9;
3969 // Convert to ansi string.
3972 RtlInitString(&string
,
3977 // Make string lengths equal.
3980 anotherString
.Length
= string
.Length
;
3983 // Check if strings match.
3986 if (RtlCompareString(&string
,
3991 *DiskNumber
= diskNumber
;
3994 ExFreePool(keyData
);
3997 // Readjust indentifier string if necessary.
4000 if (!diskData
->MbrCheckSum
) {
4001 anotherString
.Buffer
-=9;
4004 RtlFreeAnsiString(&anotherString
);
4014 ZwClose(adapterKey
);
4020 } // end EnumerateBusKey()
4026 IN PDEVICE_EXTENSION DeviceExtension
4030 Routine Description:
4032 The routine queries the registry to determine if this disk is visible to
4033 the BIOS. If the disk is visable to the BIOS, then the geometry information
4038 DeviceExtension - Supplies a pointer to the device information for disk.
4047 OBJECT_ATTRIBUTES objectAttributes
;
4048 UNICODE_STRING unicodeString
;
4052 PCM_INT13_DRIVE_PARAMETER driveParameters
;
4053 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor
;
4054 PKEY_VALUE_FULL_INFORMATION keyData
;
4058 ULONG numberOfDrives
;
4061 ULONG sectorsPerTrack
;
4062 ULONG tracksPerCylinder
;
4063 BOOLEAN foundEZHooker
;
4069 // Initialize the object for the key.
4072 InitializeObjectAttributes(&objectAttributes
,
4073 DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
,
4074 OBJ_CASE_INSENSITIVE
,
4076 (PSECURITY_DESCRIPTOR
) NULL
);
4079 // Create the hardware base key.
4082 status
= ZwOpenKey(&hardwareKey
,
4087 if (!NT_SUCCESS(status
)) {
4088 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension
->DeviceObject
->DriverObject
->HardwareDatabase
));
4094 // Get disk BIOS geometry information.
4097 RtlInitUnicodeString(&unicodeString
, L
"Configuration Data");
4099 keyData
= ExAllocatePool(PagedPool
, VALUE_BUFFER_SIZE
);
4101 if (keyData
== NULL
) {
4102 ZwClose(hardwareKey
);
4106 status
= ZwQueryValueKey(hardwareKey
,
4108 KeyValueFullInformation
,
4113 if (!NT_SUCCESS(status
)) {
4115 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4117 ExFreePool(keyData
);
4122 // Open EISA bus key.
4125 RtlInitUnicodeString(&unicodeString
, L
"EisaAdapter");
4127 InitializeObjectAttributes(&objectAttributes
,
4129 OBJ_CASE_INSENSITIVE
,
4131 (PSECURITY_DESCRIPTOR
)NULL
);
4133 status
= ZwOpenKey(&busKey
,
4137 if (!NT_SUCCESS(status
)) {
4142 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4143 if (EnumerateBusKey(DeviceExtension
,
4147 ZwClose(hardwareKey
);
4154 // Open Multifunction bus key.
4157 RtlInitUnicodeString(&unicodeString
, L
"MultifunctionAdapter");
4159 InitializeObjectAttributes(&objectAttributes
,
4161 OBJ_CASE_INSENSITIVE
,
4163 (PSECURITY_DESCRIPTOR
)NULL
);
4165 status
= ZwOpenKey(&busKey
,
4169 ZwClose(hardwareKey
);
4170 if (NT_SUCCESS(status
)) {
4172 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4173 if (EnumerateBusKey(DeviceExtension
,
4181 ExFreePool(keyData
);
4186 resourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PUCHAR
)keyData
+
4187 keyData
->DataOffset
);
4190 // Check that the data is long enough to hold a full resource descriptor,
4191 // and that the last resouce list is device-specific and long enough.
4194 if (keyData
->DataLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
) ||
4195 resourceDescriptor
->PartialResourceList
.Count
== 0 ||
4196 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].Type
!=
4197 CmResourceTypeDeviceSpecific
||
4198 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0]
4199 .u
.DeviceSpecificData
.DataSize
< sizeof(ULONG
)) {
4201 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4202 ExFreePool(keyData
);
4207 resourceDescriptor
->PartialResourceList
.PartialDescriptors
[0].u
.DeviceSpecificData
.DataSize
;
4210 // Point to the BIOS data. The BIOS data is located after the first
4211 // partial Resource list which should be device specific data.
4214 buffer
= (PUCHAR
) keyData
+ keyData
->DataOffset
+
4215 sizeof(CM_FULL_RESOURCE_DESCRIPTOR
);
4218 numberOfDrives
= length
/ sizeof(CM_INT13_DRIVE_PARAMETER
);
4221 // Use the defaults if the drive number is greater than the
4222 // number of drives detected by the BIOS.
4225 if (numberOfDrives
<= diskNumber
) {
4226 ExFreePool(keyData
);
4231 // Point to the array of drive parameters.
4234 driveParameters
= (PCM_INT13_DRIVE_PARAMETER
) buffer
+ diskNumber
;
4235 cylinders
= driveParameters
->MaxCylinders
+ 1;
4236 sectorsPerTrack
= driveParameters
->SectorsPerTrack
;
4237 tracksPerCylinder
= driveParameters
->MaxHeads
+1;
4240 // Calculate the actual number of sectors.
4243 sectors
= (ULONG
)(DeviceExtension
->PartitionLength
.QuadPart
>>
4244 DeviceExtension
->SectorShift
);
4247 if (sectors
>= cylinders
* tracksPerCylinder
* sectorsPerTrack
) {
4248 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4249 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4250 sectors
, cylinders
, tracksPerCylinder
, sectorsPerTrack
));
4255 // Since the BIOS may not report the full drive, recalculate the drive
4256 // size based on the volume size and the BIOS values for tracks per
4257 // cylinder and sectors per track..
4260 length
= tracksPerCylinder
* sectorsPerTrack
;
4265 // The BIOS information is bogus.
4268 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4269 ExFreePool(keyData
);
4273 cylinders
= sectors
/ length
;
4276 // Update the actual geometry information.
4279 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= sectorsPerTrack
;
4280 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
;
4281 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)cylinders
;
4282 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= cylinders
* tracksPerCylinder
* sectorsPerTrack
*
4283 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4286 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4291 ExFreePool(keyData
);
4293 foundEZHooker
= FALSE
;
4295 if (!DeviceExtension
->DMActive
) {
4297 HalExamineMBR(DeviceExtension
->DeviceObject
,
4298 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4306 foundEZHooker
= TRUE
;
4312 if (DeviceExtension
->DMActive
|| foundEZHooker
) {
4314 while (cylinders
> 1024) {
4316 tracksPerCylinder
= tracksPerCylinder
*2;
4317 cylinders
= cylinders
/2;
4322 // int 13 values are always 1 less.
4325 tracksPerCylinder
-= 1;
4329 // DM reserves the CE cylinder
4334 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= cylinders
+ 1;
4335 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= tracksPerCylinder
+ 1;
4337 DeviceExtension
->PartitionLength
.QuadPart
=
4338 DeviceExtension
->DiskGeometry
->DiskSize
.QuadPart
=
4339 DeviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
*
4340 DeviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
*
4341 DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
*
4342 DeviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
;
4344 if (DeviceExtension
->DMActive
) {
4346 DeviceExtension
->DMByteSkew
= DeviceExtension
->DMSkew
* DeviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
;
4352 DeviceExtension
->DMByteSkew
= 0;
4358 } // end UpdateGeometry()
4364 UpdateRemovableGeometry (
4365 IN PDEVICE_OBJECT DeviceObject
,
4371 Routine Description:
4373 This routines updates the size and starting offset of the device. This is
4374 used when the media on the device may have changed thereby changing the
4375 size of the device. If this is the physical device then a
4376 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4380 DeviceObject - Supplies the device object whos size needs to be updated.
4382 Irp - Supplies a reference where the status can be updated.
4386 Returns the status of the opertion.
4391 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4392 PDRIVE_LAYOUT_INFORMATION partitionList
;
4394 PDISK_DATA diskData
;
4395 ULONG partitionNumber
;
4398 // Determine if the size of the partition may have changed because
4399 // the media has changed.
4402 if (!(DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)) {
4404 return(STATUS_SUCCESS
);
4409 // If this request is for partition zero then do a read drive
4410 // capacity otherwise do a I/O read partition table.
4413 diskData
= (PDISK_DATA
) (deviceExtension
+ 1);
4416 // Read the drive capcity. If that fails, give up.
4419 status
= ScsiClassReadDriveCapacity(deviceExtension
->PhysicalDevice
);
4421 if (!NT_SUCCESS(status
)) {
4426 // Read the partition table agian.
4429 status
= IoReadPartitionTable(deviceExtension
->PhysicalDevice
,
4430 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
,
4435 if (!NT_SUCCESS(status
)) {
4438 // Fail the request.
4444 if (diskData
->PartitionNumber
!= 0 &&
4445 diskData
->PartitionNumber
<= partitionList
->PartitionCount
) {
4447 partitionNumber
= diskData
->PartitionNumber
- 1;
4450 // Update the partition information for this parition.
4453 diskData
->PartitionType
=
4454 partitionList
->PartitionEntry
[partitionNumber
].PartitionType
;
4456 diskData
->BootIndicator
=
4457 partitionList
->PartitionEntry
[partitionNumber
].BootIndicator
;
4459 deviceExtension
->StartingOffset
=
4460 partitionList
->PartitionEntry
[partitionNumber
].StartingOffset
;
4462 deviceExtension
->PartitionLength
=
4463 partitionList
->PartitionEntry
[partitionNumber
].PartitionLength
;
4465 diskData
->HiddenSectors
=
4466 partitionList
->PartitionEntry
[partitionNumber
].HiddenSectors
;
4468 deviceExtension
->SectorShift
= ((PDEVICE_EXTENSION
)
4469 deviceExtension
->PhysicalDevice
->DeviceExtension
)->SectorShift
;
4471 } else if (diskData
->PartitionNumber
!= 0) {
4474 // The paritition does not exist. Zero all the data.
4477 diskData
->PartitionType
= 0;
4478 diskData
->BootIndicator
= 0;
4479 diskData
->HiddenSectors
= 0;
4480 deviceExtension
->StartingOffset
.QuadPart
= (LONGLONG
)0;
4481 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)0;
4485 // Free the parition list allocate by I/O read partition table.
4488 ExFreePool(partitionList
);
4491 return(STATUS_SUCCESS
);
4497 ScsiDiskProcessError(
4498 PDEVICE_OBJECT DeviceObject
,
4499 PSCSI_REQUEST_BLOCK Srb
,
4505 Routine Description:
4507 This routine checks the type of error. If the error indicates an underrun
4508 then indicate the request should be retried.
4512 DeviceObject - Supplies a pointer to the device object.
4514 Srb - Supplies a pointer to the failing Srb.
4516 Status - Status with which the IRP will be completed.
4518 Retry - Indication of whether the request will be retried.
4527 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4529 if (*Status
== STATUS_DATA_OVERRUN
&&
4530 ( Srb
->Cdb
[0] == SCSIOP_WRITE
|| Srb
->Cdb
[0] == SCSIOP_READ
)) {
4535 // Update the error count for the device.
4538 deviceExtension
->ErrorCount
++;
4541 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_ERROR
&&
4542 Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
4545 // The disk drive should never be busy this long. Reset the scsi bus
4546 // maybe this will clear the condition.
4549 ResetScsiBus(DeviceObject
);
4552 // Update the error count for the device.
4555 deviceExtension
->ErrorCount
++;
4562 PDEVICE_OBJECT DeviceObject
,
4563 PSCSI_INQUIRY_DATA LunInfo
,
4564 PIO_SCSI_CAPABILITIES PortCapabilities
4569 Routine Description:
4571 This function checks to see if an SCSI logical unit requires speical
4576 DeviceObject - Supplies the device object to be tested.
4578 InquiryData - Supplies the inquiry data returned by the device of interest.
4580 PortCapabilities - Supplies the capabilities of the device object.
4589 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4590 PINQUIRYDATA InquiryData
= (PINQUIRYDATA
)LunInfo
->InquiryData
;
4591 BAD_CONTROLLER_INFORMATION
const *controller
;
4594 for (j
= 0; j
< NUMBER_OF_BAD_CONTROLLERS
; j
++) {
4596 controller
= &ScsiDiskBadControllers
[j
];
4598 if (strncmp(controller
->InquiryString
, (PCCHAR
)InquiryData
->VendorId
, strlen(controller
->InquiryString
))) {
4602 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller
->InquiryString
));
4605 // Found a listed controller. Determine what must be done.
4608 if (controller
->DisableTaggedQueuing
) {
4611 // Disable tagged queuing.
4614 deviceExtension
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
4617 if (controller
->DisableSynchronousTransfers
) {
4620 // Disable synchronous data transfers.
4623 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
4627 if (controller
->DisableDisconnects
) {
4630 // Disable disconnects.
4633 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
4638 // Found device so exit the loop and return.
4645 // Set the StartUnit flag appropriately.
4648 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) {
4649 deviceExtension
->DeviceFlags
|= DEV_SAFE_START_UNIT
;
4651 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
4652 if (_strnicmp((PCCHAR
)InquiryData
->VendorId
, "iomega", strlen("iomega"))) {
4653 deviceExtension
->DeviceFlags
&= ~DEV_SAFE_START_UNIT
;
4664 IN PDEVICE_OBJECT DeviceObject
4669 Routine Description:
4671 This command sends a reset bus command to the SCSI port driver.
4675 DeviceObject - The device object for the logical unit with
4684 PIO_STACK_LOCATION irpStack
;
4686 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4687 PSCSI_REQUEST_BLOCK srb
;
4688 PCOMPLETION_CONTEXT context
;
4690 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4693 // Allocate Srb from nonpaged pool.
4696 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
4697 sizeof(COMPLETION_CONTEXT
));
4700 // Save the device object in the context for use by the completion
4704 context
->DeviceObject
= DeviceObject
;
4705 srb
= &context
->Srb
;
4711 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4714 // Write length to SRB.
4717 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4720 // Set up SCSI bus address.
4723 srb
->PathId
= deviceExtension
->PathId
;
4724 srb
->TargetId
= deviceExtension
->TargetId
;
4725 srb
->Lun
= deviceExtension
->Lun
;
4727 srb
->Function
= SRB_FUNCTION_RESET_BUS
;
4730 // Build the asynchronous request to be sent to the port driver.
4731 // Since this routine is called from a DPC the IRP should always be
4735 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
4737 IoSetCompletionRoutine(irp
,
4738 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
4744 irpStack
= IoGetNextIrpStackLocation(irp
);
4746 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4748 srb
->OriginalRequest
= irp
;
4751 // Store the SRB address in next stack for port driver.
4754 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4757 // Call the port driver with the IRP.
4760 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
4764 } // end ResetScsiBus()
4769 UpdateDeviceObjects(
4770 IN PDEVICE_OBJECT PhysicalDisk
,
4776 Routine Description:
4778 This routine creates, deletes and changes device objects when
4779 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4780 the drive layout information for the user. It is possible to
4781 call this routine even in the GET_LAYOUT case because RewritePartition
4786 DeviceObject - Device object for physical disk.
4787 Irp - IO Request Packet (IRP).
4795 PDEVICE_EXTENSION physicalExtension
= PhysicalDisk
->DeviceExtension
;
4796 PDRIVE_LAYOUT_INFORMATION partitionList
= Irp
->AssociatedIrp
.SystemBuffer
;
4798 ULONG partitionNumber
;
4799 ULONG partitionCount
;
4800 ULONG lastPartition
;
4801 ULONG partitionOrdinal
;
4802 PPARTITION_INFORMATION partitionEntry
;
4803 CCHAR ntNameBuffer
[MAXIMUM_FILENAME_LENGTH
];
4804 STRING ntNameString
;
4805 UNICODE_STRING ntUnicodeString
;
4806 PDEVICE_OBJECT deviceObject
;
4807 PDEVICE_EXTENSION deviceExtension
;
4808 PDISK_DATA diskData
;
4810 ULONG numberListElements
;
4813 partitionCount
= ((partitionList
->PartitionCount
+ 3) / 4) * 4;
4816 // Zero all of the partition numbers.
4819 for (partition
= 0; partition
< partitionCount
; partition
++) {
4820 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4821 partitionEntry
->PartitionNumber
= 0;
4825 // Walk through chain of partitions for this disk to determine
4826 // which existing partitions have no match.
4829 deviceExtension
= physicalExtension
;
4830 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4835 deviceExtension
= diskData
->NextPartition
;
4838 // Check if this is the last partition in the chain.
4841 if (!deviceExtension
) {
4846 // Get the partition device extension from disk data.
4849 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4852 // Check for highest partition number this far.
4855 if (diskData
->PartitionNumber
> lastPartition
) {
4856 lastPartition
= diskData
->PartitionNumber
;
4860 // Check if this partition is not currently being used.
4863 if (!deviceExtension
->PartitionLength
.QuadPart
) {
4868 // Loop through partition information to look for match.
4872 partitionOrdinal
= 0;
4874 for (partition
= 0; partition
< partitionCount
; partition
++) {
4877 // Get partition descriptor.
4880 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4883 // Check if empty, or describes extended partiton or hasn't changed.
4886 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4887 IsContainerPartition(partitionEntry
->PartitionType
)) {
4892 // Advance partition ordinal.
4898 // Check if new partition starts where this partition starts.
4901 if (partitionEntry
->StartingOffset
.QuadPart
!=
4902 deviceExtension
->StartingOffset
.QuadPart
) {
4907 // Check if partition length is the same.
4910 if (partitionEntry
->PartitionLength
.QuadPart
==
4911 deviceExtension
->PartitionLength
.QuadPart
) {
4914 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4915 physicalExtension
->DeviceNumber
,
4916 diskData
->PartitionNumber
));
4919 // Indicate match is found and set partition number
4924 partitionEntry
->PartitionNumber
= diskData
->PartitionNumber
;
4932 // A match is found.
4935 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
4938 // If this partition is marked for update then update partition type.
4941 if (partitionEntry
->RewritePartition
) {
4942 diskData
->PartitionType
= partitionEntry
->PartitionType
;
4946 // Update partitional ordinal for calls to HAL routine
4947 // IoSetPartitionInformation.
4950 diskData
->PartitionOrdinal
= partitionOrdinal
;
4953 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4954 physicalExtension
->DeviceNumber
,
4955 diskData
->PartitionOrdinal
,
4956 diskData
->PartitionNumber
));
4961 // no match was found, indicate this partition is gone.
4965 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4966 physicalExtension
->DeviceNumber
,
4967 diskData
->PartitionNumber
));
4969 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
4975 // Walk through partition loop to find new partitions and set up
4976 // device extensions to describe them. In some cases new device
4977 // objects will be created.
4980 partitionOrdinal
= 0;
4983 partition
< partitionCount
;
4987 // Get partition descriptor.
4990 partitionEntry
= &partitionList
->PartitionEntry
[partition
];
4993 // Check if empty, or describes an extended partiton.
4996 if (partitionEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
4997 IsContainerPartition(partitionEntry
->PartitionType
)) {
5002 // Keep track of position on the disk for calls to IoSetPartitionInformation.
5008 // Check if this entry should be rewritten.
5011 if (!partitionEntry
->RewritePartition
) {
5015 if (partitionEntry
->PartitionNumber
) {
5018 // Partition is an exact match with an existing partition, but is
5019 // being written anyway.
5026 // Check first if existing device object is available by
5027 // walking partition extension list.
5030 partitionNumber
= 0;
5031 deviceExtension
= physicalExtension
;
5032 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5037 // Get next partition device extension from disk data.
5040 deviceExtension
= diskData
->NextPartition
;
5042 if (!deviceExtension
) {
5046 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5049 // A device object is free if the partition length is set to zero.
5052 if (!deviceExtension
->PartitionLength
.QuadPart
) {
5053 partitionNumber
= diskData
->PartitionNumber
;
5060 // If partition number is still zero then a new device object
5064 if (partitionNumber
== 0) {
5067 partitionNumber
= lastPartition
;
5070 // Get or create partition object and set up partition parameters.
5073 sprintf(ntNameBuffer
,
5074 "\\Device\\Harddisk%lu\\Partition%lu",
5075 physicalExtension
->DeviceNumber
,
5078 RtlInitString(&ntNameString
,
5081 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
5085 if (!NT_SUCCESS(status
)) {
5090 "UpdateDeviceObjects: Create device object %s\n",
5094 // This is a new name. Create the device object to represent it.
5097 status
= IoCreateDevice(PhysicalDisk
->DriverObject
,
5098 DEVICE_EXTENSION_SIZE
,
5105 if (!NT_SUCCESS(status
)) {
5107 "UpdateDeviceObjects: Can't create device %s\n",
5109 RtlFreeUnicodeString(&ntUnicodeString
);
5114 // Set up device object fields.
5117 deviceObject
->Flags
|= DO_DIRECT_IO
;
5118 deviceObject
->StackSize
= PhysicalDisk
->StackSize
;
5121 // Set up device extension fields.
5124 deviceExtension
= deviceObject
->DeviceExtension
;
5127 // Copy physical disk extension to partition extension.
5130 RtlMoveMemory(deviceExtension
,
5132 sizeof(DEVICE_EXTENSION
));
5135 // Initialize the new S-List.
5138 if (deviceExtension
->SrbFlags
& SRB_FLAGS_QUEUE_ACTION_ENABLE
) {
5139 numberListElements
= 30;
5141 numberListElements
= 8;
5145 // Build the lookaside list for srb's for this partition based on
5146 // whether the adapter and disk can do tagged queueing.
5149 ScsiClassInitializeSrbLookasideList(deviceExtension
,
5150 numberListElements
);
5153 // Allocate spinlock for zoning for split-request completion.
5156 KeInitializeSpinLock(&deviceExtension
->SplitRequestSpinLock
);
5159 // Write back partition number used in creating object name.
5162 partitionEntry
->PartitionNumber
= partitionNumber
;
5165 // Clear flags initializing bit.
5168 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
5171 // Point back at device object.
5174 deviceExtension
->DeviceObject
= deviceObject
;
5176 RtlFreeUnicodeString(&ntUnicodeString
);
5179 // Link to end of partition chain using previous disk data.
5182 diskData
->NextPartition
= deviceExtension
;
5185 // Get new disk data and zero next partition pointer.
5188 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5189 diskData
->NextPartition
= NULL
;
5194 // Set pointer to disk data area that follows device extension.
5197 diskData
= (PDISK_DATA
)(deviceExtension
+ 1);
5200 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5201 physicalExtension
->DeviceNumber
,
5206 // Update partition information in partition device extension.
5209 diskData
->PartitionNumber
= partitionNumber
;
5210 diskData
->PartitionType
= partitionEntry
->PartitionType
;
5211 diskData
->BootIndicator
= partitionEntry
->BootIndicator
;
5212 deviceExtension
->StartingOffset
= partitionEntry
->StartingOffset
;
5213 deviceExtension
->PartitionLength
= partitionEntry
->PartitionLength
;
5214 diskData
->HiddenSectors
= partitionEntry
->HiddenSectors
;
5215 diskData
->PartitionOrdinal
= partitionOrdinal
;
5218 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5219 diskData
->PartitionOrdinal
,
5220 diskData
->PartitionNumber
));
5223 // Update partition number passed in to indicate the
5224 // device name for this partition.
5227 partitionEntry
->PartitionNumber
= partitionNumber
;
5230 } // end UpdateDeviceObjects()