/drivers/storage/class/disk_new/geometry.c
C | 1470 lines | 737 code | 299 blank | 434 comment | 119 complexity | 8ed474e23ff67223c7516f617072ee70 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-3.0, CC-BY-SA-3.0, AGPL-3.0, GPL-3.0, CPL-1.0
- /*++
- Copyright (C) Microsoft Corporation, 1991 - 1999
- Module Name:
- geometry.c
- Abstract:
- SCSI disk class driver - this module contains all the code for generating
- disk geometries.
- Environment:
- kernel mode only
- Notes:
- Revision History:
- --*/
- #include "disk.h"
- #include "ntddstor.h"
- #if defined (_X86_)
- DISK_GEOMETRY_SOURCE
- DiskUpdateGeometry(
- IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension
- );
- NTSTATUS
- DiskUpdateRemovableGeometry (
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
- );
- VOID
- DiskScanBusDetectInfo(
- IN PDRIVER_OBJECT DriverObject,
- IN HANDLE BusKey
- );
- NTSTATUS
- DiskSaveBusDetectInfo(
- IN PDRIVER_OBJECT DriverObject,
- IN HANDLE TargetKey,
- IN ULONG DiskNumber
- );
- NTSTATUS
- DiskSaveGeometryDetectInfo(
- IN PDRIVER_OBJECT DriverObject,
- IN HANDLE HardwareKey
- );
- NTSTATUS
- DiskGetPortGeometry(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- OUT PDISK_GEOMETRY Geometry
- );
- typedef struct _DISK_DETECT_INFO {
- BOOLEAN Initialized;
- ULONG Style;
- ULONG Signature;
- ULONG MbrCheckSum;
- PDEVICE_OBJECT Device;
- CM_INT13_DRIVE_PARAMETER DriveParameters;
- } DISK_DETECT_INFO, *PDISK_DETECT_INFO;
- //
- // Information about the disk geometries collected and saved into the registry
- // by NTDETECT.COM or the system firmware.
- //
- PDISK_DETECT_INFO DetectInfoList = NULL;
- ULONG DetectInfoCount = 0;
- ULONG DetectInfoUsedCount = 0;
- #ifdef ALLOC_PRAGMA
- #pragma alloc_text(INIT, DiskSaveDetectInfo)
- #pragma alloc_text(INIT, DiskScanBusDetectInfo)
- #pragma alloc_text(INIT, DiskSaveBusDetectInfo)
- #pragma alloc_text(INIT, DiskSaveGeometryDetectInfo)
- #pragma alloc_text(PAGE, DiskUpdateGeometry)
- #pragma alloc_text(PAGE, DiskUpdateRemovableGeometry)
- #pragma alloc_text(PAGE, DiskGetPortGeometry)
- #pragma alloc_text(PAGE, DiskGetDetectInfo)
- #pragma alloc_text(PAGE, DiskReadSignature)
- #endif
- NTSTATUS
- DiskSaveDetectInfo(
- PDRIVER_OBJECT DriverObject
- )
- /*++
- Routine Description:
- This routine saves away the firmware information about the disks which has
- been saved in the registry. It generates a list (DetectInfoList) which
- contains the disk geometries, signatures & checksums of all drives which
- were examined by NtDetect. This list is later used to assign geometries
- to disks as they are initialized.
- Arguments:
- DriverObject - the driver being initialized. This is used to get to the
- hardware database.
-
- Return Value:
- status.
-
- --*/
-
- {
- OBJECT_ATTRIBUTES objectAttributes;
- HANDLE hardwareKey;
- UNICODE_STRING unicodeString;
- HANDLE busKey;
- NTSTATUS status;
- PAGED_CODE();
- InitializeObjectAttributes(
- &objectAttributes,
- DriverObject->HardwareDatabase,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
- //
- // Create the hardware base key.
- //
- status = ZwOpenKey(&hardwareKey, KEY_READ, &objectAttributes);
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskSaveDetectInfo: Cannot open hardware data. "
- "Name: %wZ\n",
- DriverObject->HardwareDatabase));
- return status;
- }
- status = DiskSaveGeometryDetectInfo(DriverObject, hardwareKey);
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskSaveDetectInfo: Can't query configuration data "
- "(%#08lx)\n",
- status));
- ZwClose(hardwareKey);
- return status;
- }
- //
- // Open EISA bus key.
- //
- RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
- InitializeObjectAttributes(&objectAttributes,
- &unicodeString,
- OBJ_CASE_INSENSITIVE,
- hardwareKey,
- NULL);
- status = ZwOpenKey(&busKey,
- KEY_READ,
- &objectAttributes);
- if(NT_SUCCESS(status)) {
- DebugPrint((1, "DiskSaveDetectInfo: Opened EisaAdapter key\n"));
- DiskScanBusDetectInfo(DriverObject, busKey);
- ZwClose(busKey);
- }
- //
- // Open MultiFunction bus key.
- //
- RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
- InitializeObjectAttributes(&objectAttributes,
- &unicodeString,
- OBJ_CASE_INSENSITIVE,
- hardwareKey,
- NULL);
- status = ZwOpenKey(&busKey,
- KEY_READ,
- &objectAttributes);
- if(NT_SUCCESS(status)) {
- DebugPrint((1, "DiskSaveDetectInfo: Opened MultifunctionAdapter key\n"));
- DiskScanBusDetectInfo(DriverObject, busKey);
- ZwClose(busKey);
- }
- ZwClose(hardwareKey);
- return STATUS_SUCCESS;
- }
- VOID
- DiskCleanupDetectInfo(
- IN PDRIVER_OBJECT DriverObject
- )
- /*++
- Routine Description:
-
- This routine will cleanup the data structure built by DiskSaveDetectInfo.
-
- Arguments:
- DriverObject - a pointer to the kernel object for this driver.
-
- Return Value:
- none
-
- --*/
- {
- if(DetectInfoList != NULL) {
- ExFreePool(DetectInfoList);
- DetectInfoList = NULL;
- }
- return;
- }
- NTSTATUS
- DiskSaveGeometryDetectInfo(
- IN PDRIVER_OBJECT DriverObject,
- IN HANDLE HardwareKey
- )
- {
- UNICODE_STRING unicodeString;
- PKEY_VALUE_FULL_INFORMATION keyData;
- ULONG length;
- PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor;
- PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
- PCM_INT13_DRIVE_PARAMETER driveParameters;
- ULONG numberOfDrives;
- ULONG i;
- NTSTATUS status;
- PAGED_CODE();
- //
- // Get disk BIOS geometry information.
- //
- RtlInitUnicodeString(&unicodeString, L"Configuration Data");
- keyData = ExAllocatePoolWithTag(PagedPool,
- VALUE_BUFFER_SIZE,
- DISK_TAG_UPDATE_GEOM);
-
- if(keyData == NULL) {
- DebugPrint((1, "DiskSaveGeometryDetectInfo: Can't allocate config "
- "data buffer\n"));
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- status = ZwQueryValueKey(HardwareKey,
- &unicodeString,
- KeyValueFullInformation,
- keyData,
- VALUE_BUFFER_SIZE,
- &length);
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskSaveGeometryDetectInfo: Can't query configuration "
- "data (%#08lx)\n",
- status));
- ExFreePool(keyData);
- return status;
- }
- //
- // Extract the resource list out of the key data.
- //
- fullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
- (((PUCHAR) keyData) + keyData->DataOffset);
- partialDescriptor =
- fullDescriptor->PartialResourceList.PartialDescriptors;
- length = partialDescriptor->u.DeviceSpecificData.DataSize;
- if((keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) ||
- (fullDescriptor->PartialResourceList.Count == 0) ||
- (partialDescriptor->Type != CmResourceTypeDeviceSpecific) ||
- (length < sizeof(ULONG))) {
- DebugPrint((1, "DiskSaveGeometryDetectInfo: BIOS header data too small "
- "or invalid\n"));
- ExFreePool(keyData);
- return STATUS_INVALID_PARAMETER;
- }
- //
- // Point to the BIOS data. THe BIOS data is located after the first
- // partial Resource list which should be device specific data.
- //
- {
- PUCHAR buffer = (PUCHAR) keyData;
- buffer += keyData->DataOffset;
- buffer += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
- driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer;
- }
- numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
- //
- // Allocate our detect info list now that we know how many entries there
- // are going to be. No other routine allocates detect info and this is
- // done out of DriverEntry so we don't need to synchronize it's creation.
- //
- length = sizeof(DISK_DETECT_INFO) * numberOfDrives;
- DetectInfoList = ExAllocatePoolWithTag(PagedPool,
- length,
- DISK_TAG_UPDATE_GEOM);
- if(DetectInfoList == NULL) {
- DebugPrint((1, "DiskSaveGeometryDetectInfo: Couldn't allocate %x bytes "
- "for DetectInfoList\n",
- length));
- ExFreePool(keyData);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- DetectInfoCount = numberOfDrives;
- RtlZeroMemory(DetectInfoList, length);
- //
- // Copy the information out of the key data and into the list we've
- // allocated.
- //
- for(i = 0; i < numberOfDrives; i++) {
- DetectInfoList[i].DriveParameters = driveParameters[i];
- }
- ExFreePool(keyData);
- return STATUS_SUCCESS;
- }
- VOID
- DiskScanBusDetectInfo(
- IN PDRIVER_OBJECT DriverObject,
- IN HANDLE BusKey
- )
- /*++
- Routine Description:
- The routine queries the registry to determine which disks are visible to
- the BIOS. If a disk is visable to the BIOS then the geometry information
- is updated with the disk's signature and MBR checksum.
- Arguments:
- DriverObject - the object for this driver.
- BusKey - handle to the bus key to be enumerated.
- Return Value:
- status
-
- --*/
- {
- ULONG busNumber;
- NTSTATUS status;
- for(busNumber = 0; ; busNumber++) {
- WCHAR buffer[32];
- UNICODE_STRING unicodeString;
- OBJECT_ATTRIBUTES objectAttributes;
- HANDLE spareKey;
- HANDLE adapterKey;
- ULONG adapterNumber;
- DebugPrint((1, "DiskScanBusDetectInfo: Scanning bus %d\n", busNumber));
- //
- // Open controller name key.
- //
- swprintf(buffer, L"%d", busNumber);
- RtlInitUnicodeString(&unicodeString, buffer);
- InitializeObjectAttributes(&objectAttributes,
- &unicodeString,
- OBJ_CASE_INSENSITIVE,
- BusKey,
- NULL);
- status = ZwOpenKey(&spareKey, KEY_READ, &objectAttributes);
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskScanBusDetectInfo: Error %#08lx opening bus "
- "key %#x\n",
- status, busNumber));
- break;
- }
- //
- // Open up a controller ordinal key.
- //
- RtlInitUnicodeString(&unicodeString, L"DiskController");
- InitializeObjectAttributes(&objectAttributes,
- &unicodeString,
- OBJ_CASE_INSENSITIVE,
- spareKey,
- NULL);
- status = ZwOpenKey(&adapterKey, KEY_READ, &objectAttributes);
- ZwClose(spareKey);
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskScanBusDetectInfo: Error %#08lx opening "
- "DiskController key\n",
- status));
- continue;
- }
- for(adapterNumber = 0; ; adapterNumber++) {
- HANDLE diskKey;
- ULONG diskNumber;
-
- //
- // Open disk key.
- //
- DebugPrint((1, "DiskScanBusDetectInfo: Scanning disk key "
- "%d\\DiskController\\%d\\DiskPeripheral\n",
- busNumber, adapterNumber));
- swprintf(buffer, L"%d\\DiskPeripheral", adapterNumber);
- RtlInitUnicodeString(&unicodeString, buffer);
- InitializeObjectAttributes(&objectAttributes,
- &unicodeString,
- OBJ_CASE_INSENSITIVE,
- adapterKey,
- NULL);
- status = ZwOpenKey(&diskKey, KEY_READ, &objectAttributes);
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskScanBusDetectInfo: Error %#08lx opening "
- "disk key\n",
- status));
- break;
- }
- for(diskNumber = 0; ; diskNumber++) {
- HANDLE targetKey;
- DebugPrint((1, "DiskScanBusDetectInfo: Scanning target key "
- "%d\\DiskController\\%d\\DiskPeripheral\\%d\n",
- busNumber, adapterNumber, diskNumber));
- swprintf(buffer, L"%d", diskNumber);
- RtlInitUnicodeString(&unicodeString, buffer);
- InitializeObjectAttributes(&objectAttributes,
- &unicodeString,
- OBJ_CASE_INSENSITIVE,
- diskKey,
- NULL);
- status = ZwOpenKey(&targetKey, KEY_READ, &objectAttributes);
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskScanBusDetectInfo: Error %#08lx "
- "opening target key\n",
- status));
- break;
- }
- status = DiskSaveBusDetectInfo(DriverObject,
- targetKey,
- diskNumber);
- ZwClose(targetKey);
- }
- ZwClose(diskKey);
- }
- ZwClose(adapterKey);
- }
- return;
- }
- NTSTATUS
- DiskSaveBusDetectInfo(
- IN PDRIVER_OBJECT DriverObject,
- IN HANDLE TargetKey,
- IN ULONG DiskNumber
- )
- /*++
- Routine Description:
- This routine will transfer the firmware/ntdetect reported information
- in the specified target key into the appropriate entry in the
- DetectInfoList.
- Arguments:
- DriverObject - the object for this driver.
-
- TargetKey - the key for the disk being saved.
- DiskNumber - the ordinal of the entry in the DiskPeripheral tree for this
- entry
- Return Value:
- status
- --*/
- {
- PDISK_DETECT_INFO diskInfo;
- UNICODE_STRING unicodeString;
- PKEY_VALUE_FULL_INFORMATION keyData;
- ULONG length;
- NTSTATUS status;
- PAGED_CODE();
- diskInfo = &(DetectInfoList[DiskNumber]);
- if(diskInfo->Initialized) {
- ASSERT(FALSE);
- DebugPrint((1, "DiskSaveBusDetectInfo: disk entry %#x already has a "
- "signature of %#08lx and mbr checksum of %#08lx\n",
- DiskNumber,
- diskInfo->Signature,
- diskInfo->MbrCheckSum));
- return STATUS_UNSUCCESSFUL;
- }
- RtlInitUnicodeString(&unicodeString, L"Identifier");
- keyData = ExAllocatePoolWithTag(PagedPool,
- VALUE_BUFFER_SIZE,
- DISK_TAG_UPDATE_GEOM);
- if(keyData == NULL) {
- DebugPrint((1, "DiskSaveBusDetectInfo: Couldn't allocate space for "
- "registry data\n"));
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- //
- // Get disk peripheral identifier.
- //
- status = ZwQueryValueKey(TargetKey,
- &unicodeString,
- KeyValueFullInformation,
- keyData,
- VALUE_BUFFER_SIZE,
- &length);
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskSaveBusDetectInfo: Error %#08lx getting "
- "Identifier\n",
- status));
- ExFreePool(keyData);
- return status;
- } else if (keyData->DataLength < 9*sizeof(WCHAR)) {
- //
- // the data is too short to use (we subtract 9 chars in normal path)
- //
- DebugPrint((1, "DiskSaveBusDetectInfo: Saved data was invalid, "
- "not enough data in registry!\n"));
- ExFreePool(keyData);
- return STATUS_UNSUCCESSFUL;
-
- } else {
- UNICODE_STRING identifier;
- ULONG value;
- //
- // Complete unicode string.
- //
-
- identifier.Buffer = (PWSTR) ((PUCHAR)keyData + keyData->DataOffset);
- identifier.Length = (USHORT) keyData->DataLength;
- identifier.MaximumLength = (USHORT) keyData->DataLength;
-
- //
- // Get the first value out of the identifier - this will be the MBR
- // checksum.
- //
-
- status = RtlUnicodeStringToInteger(&identifier, 16, &value);
-
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskSaveBusDetectInfo: Error %#08lx converting "
- "identifier %wZ into MBR xsum\n",
- status,
- &identifier));
- ExFreePool(keyData);
- return status;
- }
-
- diskInfo->MbrCheckSum = value;
-
- //
- // Shift the string over to get the disk signature
- //
-
- identifier.Buffer += 9;
- identifier.Length -= 9 * sizeof(WCHAR);
- identifier.MaximumLength -= 9 * sizeof(WCHAR);
-
- status = RtlUnicodeStringToInteger(&identifier, 16, &value);
-
- if(!NT_SUCCESS(status)) {
- DebugPrint((1, "DiskSaveBusDetectInfo: Error %#08lx converting "
- "identifier %wZ into disk signature\n",
- status,
- &identifier));
- ExFreePool(keyData);
- value = 0;
- }
- diskInfo->Signature = value;
- }
- //
- // Here is where we would save away the extended int13 data.
- //
- //
- // Mark this entry as initialized so we can make sure not to do it again.
- //
- diskInfo->Initialized = TRUE;
- return STATUS_SUCCESS;
- }
- DISK_GEOMETRY_SOURCE
- DiskUpdateGeometry(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
- )
- /*++
- Routine Description:
- This routine checks the DetectInfoList saved away during disk driver init
- to see if any geometry information was reported for this drive. If the
- geometry data exists (determined by matching non-zero signatures or
- non-zero MBR checksums) then it will be saved in the RealGeometry member
- of the disk data block.
- ClassReadDriveCapacity MUST be called after calling this routine to update
- the cylinder count based on the size of the disk and the presence of any
- disk management software.
- Arguments:
- DeviceExtension - Supplies a pointer to the device information for disk.
- Return Value:
- Inidicates whether the "RealGeometry" in the data block is now valid.
- --*/
- {
- PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
- ULONG i;
- PDISK_DETECT_INFO diskInfo;
- BOOLEAN found = FALSE;
- NTSTATUS status;
- PAGED_CODE();
- ASSERT(FdoExtension->CommonExtension.IsFdo);
- ASSERT((FdoExtension->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0);
- //
- // If we've already set a non-default geometry for this drive then there's
- // no need to try and update again.
- //
- if(diskData->GeometrySource != DiskGeometryUnknown) {
- return diskData->GeometrySource;
- }
- //
- // Scan through the saved detect info to see if we can find a match
- // for this device.
- //
- for(i = 0; i < DetectInfoCount; i++) {
- ASSERT(DetectInfoList != NULL);
- diskInfo = &(DetectInfoList[i]);
- if((diskData->Mbr.Signature != 0) &&
- (diskData->Mbr.Signature == diskInfo->Signature)) {
- DebugPrint((1, "DiskUpdateGeometry: found match for signature "
- "%#08lx\n",
- diskData->Mbr.Signature));
- found = TRUE;
- break;
- } else if((diskData->Mbr.Signature == 0) &&
- (diskData->Mbr.MbrCheckSum != 0) &&
- (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) {
- DebugPrint((1, "DiskUpdateGeometry: found match for xsum %#08lx\n",
- diskData->Mbr.MbrCheckSum));
- found = TRUE;
- break;
- }
- }
- if(found) {
- ULONG cylinders;
- ULONG sectorsPerTrack;
- ULONG tracksPerCylinder;
- ULONG sectors;
- ULONG length;
- //
- // Point to the array of drive parameters.
- //
-
- cylinders = diskInfo->DriveParameters.MaxCylinders + 1;
- sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
- tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1;
- //
- // Since the BIOS may not report the full drive, recalculate the drive
- // size based on the volume size and the BIOS values for tracks per
- // cylinder and sectors per track..
- //
-
- length = tracksPerCylinder * sectorsPerTrack;
-
- if (length == 0) {
-
- //
- // The BIOS information is bogus.
- //
-
- DebugPrint((1, "DiskUpdateGeometry: H (%d) or S(%d) is zero\n",
- tracksPerCylinder, sectorsPerTrack));
- return FALSE;
- }
-
- //
- // since we are copying the structure RealGeometry here, we should
- // really initialize all the fields, especially since a zero'd
- // BytesPerSector field would cause a trap in xHalReadPartitionTable()
- //
- diskData->RealGeometry = FdoExtension->DiskGeometry;
-
- //
- // Save the geometry information away in the disk data block and
- // set the bit indicating that we found a valid one.
- //
- diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack;
- diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder;
- diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders;
- DebugPrint((1, "DiskUpdateGeometry: BIOS spt %#x, #heads %#x, "
- "#cylinders %#x\n",
- sectorsPerTrack, tracksPerCylinder, cylinders));
- diskData->GeometrySource = DiskGeometryFromBios;
- diskInfo->Device = FdoExtension->DeviceObject;
- } else {
-
- DebugPrint((1, "DiskUpdateGeometry: no match found for signature %#08lx\n", diskData->Mbr.Signature));
- }
- if(diskData->GeometrySource == DiskGeometryUnknown) {
- //
- // We couldn't find a geometry from the BIOS. Check with the port
- // driver and see if it can provide one.
- //
- status = DiskGetPortGeometry(FdoExtension, &(diskData->RealGeometry));
- if(NT_SUCCESS(status)) {
- //
- // Check the geometry to make sure it's valid.
- //
- if((diskData->RealGeometry.TracksPerCylinder *
- diskData->RealGeometry.SectorsPerTrack) != 0) {
- diskData->GeometrySource = DiskGeometryFromPort;
- DebugPrint((1, "DiskUpdateGeometry: using Port geometry for disk %#p\n", FdoExtension));
-
- if (diskData->RealGeometry.BytesPerSector == 0) {
-
- DebugPrint((0, "DiskDriverReinit: Port driver failed to "
- "set BytesPerSector in the RealGeometry\n"));
- diskData->RealGeometry.BytesPerSector =
- FdoExtension->DiskGeometry.BytesPerSector;
- if (diskData->RealGeometry.BytesPerSector == 0) {
- ASSERT(!"BytesPerSector is still zero!");
- }
- }
- }
- }
- }
- //
- // If we came up with a "real" geometry for this drive then set it in the
- // device extension.
- //
- if(diskData->GeometrySource != DiskGeometryUnknown) {
- FdoExtension->DiskGeometry = diskData->RealGeometry;
- //
- // Increment the count of used geometry entries.
- //
- InterlockedIncrement(&DetectInfoUsedCount);
- }
- return diskData->GeometrySource;
- }
- NTSTATUS
- DiskUpdateRemovableGeometry (
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
- )
- /*++
- Routine Description:
- This routine updates the geometry of the disk. It will query the port
- driver to see if it can provide any geometry info. If not it will use
- the current head & sector count.
-
- Based on these values & the capacity of the drive as reported by
- ClassReadDriveCapacity it will determine a new cylinder count for the
- device.
- Arguments:
- Fdo - Supplies the functional device object whos size needs to be updated.
- Return Value:
- Returns the status of the opertion.
- --*/
- {
- PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
- PDISK_DATA diskData = commonExtension->DriverData;
- PDISK_GEOMETRY geometry = &(diskData->RealGeometry);
- NTSTATUS status;
- PAGED_CODE();
- ASSERT_FDO(commonExtension->DeviceObject);
- if (FdoExtension->DeviceDescriptor) {
- ASSERT(FdoExtension->DeviceDescriptor->RemovableMedia);
- }
- ASSERT(TEST_FLAG(FdoExtension->DeviceObject->Characteristics,
- FILE_REMOVABLE_MEDIA));
- //
- // Attempt to determine the disk geometry. First we'll check with the
- // port driver to see what it suggests for a value.
- //
- status = DiskGetPortGeometry(FdoExtension, geometry);
- if(NT_SUCCESS(status) &&
- ((geometry->TracksPerCylinder * geometry->SectorsPerTrack) != 0)) {
- FdoExtension->DiskGeometry = (*geometry);
- }
- return status;
- }
- NTSTATUS
- DiskGetPortGeometry(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- OUT PDISK_GEOMETRY Geometry
- )
- /*++
- Routine Description:
- This routine will query the port driver for disk geometry. Some port
- drivers (in particular IDEPORT) may be able to provide geometry for the
- device.
-
- Arguments:
- FdoExtension - the device object for the disk.
-
- Geometry - a structure to save the geometry information into (if any is
- available)
-
- Return Value:
-
- STATUS_SUCCESS if geometry information can be provided or
- error status indicating why it can't.
-
- --*/
- {
- PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
- PIRP irp;
- PIO_STACK_LOCATION irpStack;
- KEVENT event;
- NTSTATUS status;
- PAGED_CODE();
- //
- // Build an irp to send IOCTL_DISK_GET_DRIVE_GEOMETRY to the lower driver.
- //
- irp = IoAllocateIrp(commonExtension->LowerDeviceObject->StackSize, FALSE);
- if(irp == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- irpStack = IoGetNextIrpStackLocation(irp);
- irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
- irpStack->Parameters.DeviceIoControl.IoControlCode =
- IOCTL_DISK_GET_DRIVE_GEOMETRY;
- irpStack->Parameters.DeviceIoControl.OutputBufferLength =
- sizeof(DISK_GEOMETRY);
- irp->AssociatedIrp.SystemBuffer = Geometry;
- KeInitializeEvent(&event, SynchronizationEvent, FALSE);
- IoSetCompletionRoutine(irp,
- (PIO_COMPLETION_ROUTINE)ClassSignalCompletion,
- &event,
- TRUE,
- TRUE,
- TRUE);
- status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
- KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
- ASSERT((status == STATUS_PENDING) || (status == irp->IoStatus.Status));
- status = irp->IoStatus.Status;
- IoFreeIrp(irp);
- return status;
- }
- NTSTATUS
- DiskReadDriveCapacity(
- IN PDEVICE_OBJECT Fdo
- )
- /*++
- Routine Description:
- This routine is used by disk.sys as a wrapper for the classpnp API
- ClassReadDriveCapacity. It will perform some additional operations to
- attempt to determine drive geometry before it calls the classpnp version
- of the routine.
-
- For fixed disks this involves calling DiskUpdateGeometry which will check
- various sources (the BIOS, the port driver) for geometry information.
-
- Arguments:
- Fdo - a pointer to the device object to be checked.
- Return Value:
- status of ClassReadDriveCapacity.
-
- --*/
- {
- PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
- PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
- DISK_GEOMETRY_SOURCE diskGeometrySource = DiskGeometryUnknown;
- NTSTATUS status;
- ASSERT_FDO(Fdo);
- if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
- DiskUpdateRemovableGeometry(fdoExtension);
- } else {
- diskGeometrySource = DiskUpdateGeometry(fdoExtension);
- }
- status = ClassReadDriveCapacity(Fdo);
- return status;
- }
- VOID
- DiskDriverReinitialization(
- IN PDRIVER_OBJECT DriverObject,
- IN PVOID Nothing,
- IN ULONG Count
- )
- /*++
- Routine Description:
- This routine will scan through the current list of disks and attempt to
- match them to any remaining geometry information. This will only be done
- on the first call to the routine.
- Note: This routine assumes that the system will not be adding or removing
- devices during this phase of the init process. This is very likely
- a bad assumption but it greatly simplifies the code.
- Arguments:
- DriverObject - a pointer to the object for the disk driver.
-
- Nothing - unused
-
- Count - an indication of how many times this routine has been called.
-
- Return Value:
- none
- --*/
- {
- PDEVICE_OBJECT deviceObject;
- PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
- PDISK_DATA diskData;
- ULONG unmatchedDiskCount;
- PDEVICE_OBJECT unmatchedDisk = NULL;
- ULONG i;
- PDISK_DETECT_INFO diskInfo = NULL;
- if(Count != 1) {
- DebugPrint((1, "DiskDriverReinitialization: ignoring call %d\n",
- Count));
- return;
- }
- //
- // Check to see how many entries in the detect info list have been matched.
- // If there's only one remaining we'll see if we can find a disk to go with
- // it.
- //
- if(DetectInfoCount == 0) {
- DebugPrint((1, "DiskDriverReinitialization: no detect info saved\n"));
- return;
- }
- if((DetectInfoCount - DetectInfoUsedCount) != 1) {
- DebugPrint((1, "DiskDriverReinitialization: %d of %d geometry entries "
- "used - will not attempt match\n"));
- return;
- }
- //
- // Scan through the list of disks and see if any of them are missing
- // geometry information. If there is only one such disk we'll try to
- // match it to the unmatched geometry.
- //
-
-
- //
- // ISSUE-2000/5/24-henrygab - figure out if there's a way to keep
- // removals from happening while doing this.
- //
- for(deviceObject = DriverObject->DeviceObject, unmatchedDiskCount = 0;
- deviceObject != NULL;
- deviceObject = deviceObject->NextDevice) {
- //
- // Make sure this is a disk and not a partition.
- //
- fdoExtension = deviceObject->DeviceExtension;
- if(fdoExtension->CommonExtension.IsFdo == FALSE) {
- DebugPrint((1, "DiskDriverReinit: DO %#p is not an FDO\n",
- deviceObject));
- continue;
- }
- //
- // If the geometry for this one is already known then skip it.
- //
- diskData = fdoExtension->CommonExtension.DriverData;
- if(diskData->GeometrySource != DiskGeometryUnknown) {
- DebugPrint((1, "DiskDriverReinit: FDO %#p has a geometry\n",
- deviceObject));
- continue;
- }
- DebugPrint((1, "DiskDriverReinit: FDO %#p has no geometry\n",
- deviceObject));
- //
- // Mark this one as using the default. It's past the time when disk
- // might blunder across the geometry info. If we set the geometry
- // from the bios we'll reset this field down below.
- //
- diskData->GeometrySource = DiskGeometryFromDefault;
- //
- // As long as we've only got one unmatched disk we're fine.
- //
- unmatchedDiskCount++;
- if(unmatchedDiskCount > 1) {
- ASSERT(unmatchedDisk != NULL);
- DebugPrint((1, "DiskDriverReinit: FDO %#p also has no geometry\n",
- unmatchedDisk));
- unmatchedDisk = NULL;
- break;
- }
- unmatchedDisk = deviceObject;
- }
- //
- // If there's more or less than one ungeometried disk then we can't do
- // anything about the geometry.
- //
- if(unmatchedDiskCount != 1) {
- DebugPrint((1, "DiskDriverReinit: Unable to match geometry\n"));
- return;
- }
- fdoExtension = unmatchedDisk->DeviceExtension;
- diskData = fdoExtension->CommonExtension.DriverData;
- DebugPrint((1, "DiskDriverReinit: Found possible match\n"));
- //
- // Find the geometry which wasn't assigned.
- //
- for(i = 0; i < DetectInfoCount; i++) {
- if(DetectInfoList[i].Device == NULL) {
- diskInfo = &(DetectInfoList[i]);
- break;
- }
- }
- ASSERT(diskInfo != NULL);
- {
- //
- // Save the geometry information away in the disk data block and
- // set the bit indicating that we found a valid one.
- //
- ULONG cylinders;
- ULONG sectorsPerTrack;
- ULONG tracksPerCylinder;
- ULONG sectors;
- ULONG length;
- //
- // Point to the array of drive parameters.
- //
-
- cylinders = diskInfo->DriveParameters.MaxCylinders + 1;
- sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
- tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1;
- //
- // Since the BIOS may not report the full drive, recalculate the drive
- // size based on the volume size and the BIOS values for tracks per
- // cylinder and sectors per track..
- //
-
- length = tracksPerCylinder * sectorsPerTrack;
-
- if (length == 0) {
-
- //
- // The BIOS information is bogus.
- //
-
- DebugPrint((1, "DiskDriverReinit: H (%d) or S(%d) is zero\n",
- tracksPerCylinder, sectorsPerTrack));
- return;
- }
-
- //
- // since we are copying the structure RealGeometry here, we should
- // really initialize all the fields, especially since a zero'd
- // BytesPerSector field would cause a trap in xHalReadPartitionTable()
- //
-
- diskData->RealGeometry = fdoExtension->DiskGeometry;
-
- //
- // Save the geometry information away in the disk data block and
- // set the bit indicating that we found a valid one.
- //
-
- diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack;
- diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder;
- diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders;
- DebugPrint((1, "DiskDriverReinit: BIOS spt %#x, #heads %#x, "
- "#cylinders %#x\n",
- sectorsPerTrack, tracksPerCylinder, cylinders));
- diskData->GeometrySource = DiskGeometryGuessedFromBios;
- diskInfo->Device = unmatchedDisk;
- //
- // Now copy the geometry over to the fdo extension and call
- // classpnp to redetermine the disk size and cylinder count.
- //
- fdoExtension->DiskGeometry = diskData->RealGeometry;
-
- //
- // BUGBUG - why not call DiskReadDriveCapacity()?
- //
- ClassReadDriveCapacity(unmatchedDisk);
- if (diskData->RealGeometry.BytesPerSector == 0) {
- //
- // if the BytesPerSector field is set to zero for a disk
- // listed in the bios, then the system will bugcheck in
- // xHalReadPartitionTable(). assert here since it is
- // easier to determine what is happening this way.
- //
- ASSERT(!"RealGeometry not set to non-zero bps\n");
- }
- }
- return;
- }
- NTSTATUS
- DiskGetDetectInfo(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- OUT PDISK_DETECTION_INFO DetectInfo
- )
- /*++
- Routine Description:
- Get the Int13 information from the BIOS DetectInfoList.
- Arguments:
- FdoExtension - Supplies a pointer to the FDO extension that we want to
- obtain the detect information for.
- DetectInfo - A buffer where the detect information will be copied to.
- Return Value:
- NTSTATUS code.
- --*/
- {
- ULONG i;
- BOOLEAN found;
- PDISK_DETECT_INFO diskInfo = NULL;
- PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
- PAGED_CODE ();
- ASSERT(FdoExtension->CommonExtension.IsFdo);
- //
- // Fail for non-fixed drives.
- //
-
- if (TEST_FLAG (FdoExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
- return STATUS_NOT_SUPPORTED;
- }
- //
- // There is no GPT detection info, so fail this.
- //
-
- if (diskData->PartitionStyle == PARTITION_STYLE_GPT) {
- return STATUS_NOT_SUPPORTED;
- }
- for(i = 0; i < DetectInfoCount; i++) {
-
- ASSERT(DetectInfoList != NULL);
- diskInfo = &(DetectInfoList[i]);
- if((diskData->Mbr.Signature != 0) &&
- (diskData->Mbr.Signature == diskInfo->Signature)) {
- DebugPrint((1, "DiskGetDetectInfo: found match for signature "
- "%#08lx\n",
- diskData->Mbr.Signature));
- found = TRUE;
- break;
- } else if((diskData->Mbr.Signature == 0) &&
- (diskData->Mbr.MbrCheckSum != 0) &&
- (diskData->Mbr.MbrCheckSum == diskInfo->MbrCheckSum)) {
- DebugPrint((1, "DiskGetDetectInfo: found match for xsum %#08lx\n",
- diskData->Mbr.MbrCheckSum));
- found = TRUE;
- break;
- }
- }
- if ( found ) {
- DetectInfo->DetectionType = DetectInt13;
- DetectInfo->Int13.DriveSelect = diskInfo->DriveParameters.DriveSelect;
- DetectInfo->Int13.MaxCylinders = diskInfo->DriveParameters.MaxCylinders;
- DetectInfo->Int13.SectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
- DetectInfo->Int13.MaxHeads = diskInfo->DriveParameters.MaxHeads;
- DetectInfo->Int13.NumberDrives = diskInfo->DriveParameters.NumberDrives;
- RtlZeroMemory (&DetectInfo->ExInt13, sizeof (DetectInfo->ExInt13));
- }
- return (found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
- }
- NTSTATUS
- DiskReadSignature(
- IN PDEVICE_OBJECT Fdo
- )
- /*++
- Routine Description:
- Read the disks signature from the drive. The signature can be either
- a MBR signature or a GPT/EFI signature.
- The low-level signature reading is done by IoReadDiskSignature().
- Arguments:
- Fdo - Pointer to the FDO of a disk to read the signature for.
-
- Return Value:
- NTSTATUS code.
- --*/
- {
- NTSTATUS Status;
- PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
- PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
- DISK_SIGNATURE Signature;
- PAGED_CODE ();
-
- Status = IoReadDiskSignature (Fdo,
- fdoExtension->DiskGeometry.BytesPerSector,
- &Signature);
- if (!NT_SUCCESS (Status)) {
- return Status;
- }
-
- if (Signature.PartitionStyle == PARTITION_STYLE_GPT) {
- diskData->PartitionStyle = PARTITION_STYLE_GPT;
- diskData->Efi.DiskId = Signature.Gpt.DiskId;
- } else if (Signature.PartitionStyle == PARTITION_STYLE_MBR) {
- diskData->PartitionStyle = PARTITION_STYLE_MBR;
- diskData->Mbr.Signature = Signature.Mbr.Signature;
- diskData->Mbr.MbrCheckSum = Signature.Mbr.CheckSum;
- } else {
- ASSERT (FALSE);
- Status = STATUS_UNSUCCESSFUL;
- }
- return Status;
- }
- #endif // defined(_X86_)