summaryrefslogtreecommitdiff
path: root/storage/class/disk/src/geometry.c
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-04-29 09:48:49 -0700
committerDave Wilson <[email protected]>2015-04-29 10:47:29 -0700
commitd40232638faaab19de557e70a3ee938da7a35295 (patch)
tree14e61c973745949af186b7940e3a53d25322f5de /storage/class/disk/src/geometry.c
parent02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff)
samples update for //build
Diffstat (limited to 'storage/class/disk/src/geometry.c')
-rw-r--r--storage/class/disk/src/geometry.c1672
1 files changed, 1672 insertions, 0 deletions
diff --git a/storage/class/disk/src/geometry.c b/storage/class/disk/src/geometry.c
new file mode 100644
index 00000000..911a33a4
--- /dev/null
+++ b/storage/class/disk/src/geometry.c
@@ -0,0 +1,1672 @@
+/*++
+
+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"
+
+#ifdef DEBUG_USE_WPP
+#include "geometry.tmh"
+#endif
+
+#if defined(_X86_) || defined(_AMD64_)
+
+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;
+LONG DetectInfoUsedCount = 0;
+
+#define GET_STARTING_SECTOR(p) ( \
+ (ULONG) (p->StartingSectorLsb0) + \
+ (ULONG) (p->StartingSectorLsb1 << 8 ) + \
+ (ULONG) (p->StartingSectorMsb0 << 16) + \
+ (ULONG) (p->StartingSectorMsb1 << 24) )
+
+#define GET_ENDING_S_OF_CHS(p) ( \
+ (UCHAR) (p->EndingCylinderLsb & 0x3F) )
+
+//
+// Definitions from hal.h
+//
+
+//
+// Boot record disk partition table entry structure format
+//
+
+typedef struct _PARTITION_DESCRIPTOR
+{
+ UCHAR ActiveFlag;
+ UCHAR StartingTrack;
+ UCHAR StartingCylinderLsb;
+ UCHAR StartingCylinderMsb;
+ UCHAR PartitionType;
+ UCHAR EndingTrack;
+ UCHAR EndingCylinderLsb;
+ UCHAR EndingCylinderMsb;
+ UCHAR StartingSectorLsb0;
+ UCHAR StartingSectorLsb1;
+ UCHAR StartingSectorMsb0;
+ UCHAR StartingSectorMsb1;
+ UCHAR PartitionLengthLsb0;
+ UCHAR PartitionLengthLsb1;
+ UCHAR PartitionLengthMsb0;
+ UCHAR PartitionLengthMsb1;
+
+} PARTITION_DESCRIPTOR, *PPARTITION_DESCRIPTOR;
+
+//
+// Number of partition table entries
+//
+
+#define NUM_PARTITION_TABLE_ENTRIES 4
+
+//
+// Partition table record and boot signature offsets in 16-bit words
+//
+
+#define PARTITION_TABLE_OFFSET ( 0x1be / 2)
+#define BOOT_SIGNATURE_OFFSET ((0x200 / 2) - 1)
+
+//
+// Boot record signature value
+//
+
+#define BOOT_RECORD_SIGNATURE (0xaa55)
+
+
+#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, DiskIsNT4Geometry)
+#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 = {0};
+ HANDLE hardwareKey;
+
+ UNICODE_STRING unicodeString;
+ HANDLE busKey;
+
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ DriverObject->HardwareDatabase,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+
+ //
+ // Create the hardware base key.
+ //
+
+ status = ZwOpenKey(&hardwareKey, KEY_READ, &objectAttributes);
+
+ if(!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Cannot open hardware data. "
+ "Name: %wZ\n",
+ DriverObject->HardwareDatabase));
+ return status;
+ }
+
+ status = DiskSaveGeometryDetectInfo(DriverObject, hardwareKey);
+
+ if(!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "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 | OBJ_KERNEL_HANDLE,
+ hardwareKey,
+ NULL);
+
+ status = ZwOpenKey(&busKey,
+ KEY_READ,
+ &objectAttributes);
+
+ if(NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskSaveDetectInfo: Opened EisaAdapter key\n"));
+ DiskScanBusDetectInfo(DriverObject, busKey);
+ ZwClose(busKey);
+ }
+
+ //
+ // Open MultiFunction bus key.
+ //
+
+ RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ hardwareKey,
+ NULL);
+
+ status = ZwOpenKey(&busKey,
+ KEY_READ,
+ &objectAttributes);
+
+ if(NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "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
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(DriverObject);
+ FREE_POOL(DetectInfoList);
+ 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();
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ //
+ // Get disk BIOS geometry information.
+ //
+
+ RtlInitUnicodeString(&unicodeString, L"Configuration Data");
+
+ keyData = ExAllocatePoolWithTag(PagedPool,
+ VALUE_BUFFER_SIZE,
+ DISK_TAG_UPDATE_GEOM);
+
+ if(keyData == NULL) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "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)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Can't query configuration "
+ "data (%#08lx)\n",
+ status));
+ FREE_POOL(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))) {
+
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: BIOS header data too small "
+ "or invalid\n"));
+ FREE_POOL(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) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveGeometryDetectInfo: Couldn't allocate %x bytes "
+ "for DetectInfoList\n",
+ length));
+
+ FREE_POOL(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++) {
+#pragma warning(suppress: 6386) // PREFast bug means it doesn't correctly remember the size of DetectInfoList
+ DetectInfoList[i].DriveParameters = driveParameters[i];
+ }
+
+ FREE_POOL(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] = { 0 };
+ UNICODE_STRING unicodeString;
+
+ OBJECT_ATTRIBUTES objectAttributes = {0};
+
+ HANDLE spareKey;
+ HANDLE adapterKey;
+
+ ULONG adapterNumber;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning bus %d\n", busNumber));
+
+ //
+ // Open controller name key.
+ //
+
+ status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", busNumber);
+ if (!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status));
+ break;
+ }
+
+ RtlInitUnicodeString(&unicodeString, buffer);
+
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ BusKey,
+ NULL);
+
+ status = ZwOpenKey(&spareKey, KEY_READ, &objectAttributes);
+
+ if(!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "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 | OBJ_KERNEL_HANDLE,
+ spareKey,
+ NULL);
+
+ status = ZwOpenKey(&adapterKey, KEY_READ, &objectAttributes);
+ ZwClose(spareKey);
+
+ if(!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening "
+ "DiskController key\n",
+ status));
+ continue;
+ }
+
+ for(adapterNumber = 0; ; adapterNumber++) {
+
+ HANDLE diskKey;
+ ULONG diskNumber;
+
+ //
+ // Open disk key.
+ //
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning disk key "
+ "%d\\DiskController\\%d\\DiskPeripheral\n",
+ busNumber, adapterNumber));
+
+ status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d\\DiskPeripheral", adapterNumber);
+ if (!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status));
+ break;
+ }
+
+ RtlInitUnicodeString(&unicodeString, buffer);
+
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ adapterKey,
+ NULL);
+
+ status = ZwOpenKey(&diskKey, KEY_READ, &objectAttributes);
+
+ if(!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx opening "
+ "disk key\n",
+ status));
+ break;
+ }
+
+ for(diskNumber = 0; ; diskNumber++) {
+
+ HANDLE targetKey;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Scanning target key "
+ "%d\\DiskController\\%d\\DiskPeripheral\\%d\n",
+ busNumber, adapterNumber, diskNumber));
+
+ status = RtlStringCchPrintfW(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, L"%d", diskNumber);
+ if (!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Format symbolic link failed with error: 0x%X\n", status));
+ break;
+ }
+
+ RtlInitUnicodeString(&unicodeString, buffer);
+
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ diskKey,
+ NULL);
+
+ status = ZwOpenKey(&targetKey, KEY_READ, &objectAttributes);
+
+ if(!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskScanBusDetectInfo: Error %#08lx "
+ "opening target key\n",
+ status));
+ break;
+ }
+
+ 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();
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ if (DiskNumber >= DetectInfoCount)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ diskInfo = &(DetectInfoList[DiskNumber]);
+
+ if(diskInfo->Initialized) {
+
+ NT_ASSERT(FALSE);
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "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) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "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)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx getting "
+ "Identifier\n",
+ status));
+ FREE_POOL(keyData);
+ return status;
+
+ } else if (keyData->DataLength < 9*sizeof(WCHAR)) {
+
+ //
+ // the data is too short to use (we subtract 9 chars in normal path)
+ //
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Saved data was invalid, "
+ "not enough data in registry!\n"));
+ FREE_POOL(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)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx converting "
+ "identifier %wZ into MBR xsum\n",
+ status,
+ &identifier));
+ FREE_POOL(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)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskSaveBusDetectInfo: Error %#08lx converting "
+ "identifier %wZ into disk signature\n",
+ status,
+ &identifier));
+ 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;
+
+ FREE_POOL(keyData);
+
+ 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 = NULL;
+
+ BOOLEAN found = FALSE;
+
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+
+ NT_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++) {
+
+ NT_ASSERT(DetectInfoList != NULL);
+
+ diskInfo = &(DetectInfoList[i]);
+
+ if((diskData->Mbr.Signature != 0) &&
+ (diskData->Mbr.Signature == diskInfo->Signature)) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "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)) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: found match for xsum %#08lx\n",
+ diskData->Mbr.MbrCheckSum));
+ found = TRUE;
+ break;
+ }
+ }
+
+ if(found) {
+
+ ULONG cylinders;
+ ULONG sectorsPerTrack;
+ ULONG tracksPerCylinder;
+
+ 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.
+ //
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: H (%d) or S(%d) is zero\n",
+ tracksPerCylinder, sectorsPerTrack));
+ return DiskGeometryUnknown;
+ }
+
+ //
+ // 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;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: BIOS spt %#x, #heads %#x, "
+ "#cylinders %#x\n",
+ sectorsPerTrack, tracksPerCylinder, cylinders));
+
+ diskData->GeometrySource = DiskGeometryFromBios;
+ diskInfo->Device = FdoExtension->DeviceObject;
+
+ //
+ // Increment the count of used geometry entries.
+ //
+
+ InterlockedIncrement(&DetectInfoUsedCount);
+
+ } else {
+
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "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;
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskUpdateGeometry: using Port geometry for disk %#p\n", FdoExtension));
+
+ if (diskData->RealGeometry.BytesPerSector == 0) {
+
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskDriverReinit: Port driver failed to "
+ "set BytesPerSector in the RealGeometry\n"));
+ diskData->RealGeometry.BytesPerSector =
+ FdoExtension->DiskGeometry.BytesPerSector;
+ if (diskData->RealGeometry.BytesPerSector == 0) {
+ NT_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;
+ }
+
+ 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();
+
+ if (FdoExtension->DeviceDescriptor) {
+ NT_ASSERT(FdoExtension->DeviceDescriptor->RemovableMedia);
+ }
+ NT_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,
+ ClassSignalCompletion,
+ &event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
+ if (status == STATUS_PENDING) {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ status = irp->IoStatus.Status;
+ }
+
+ IoFreeIrp(irp);
+
+ return status;
+}
+
+
+BOOLEAN
+DiskIsNT4Geometry(
+ IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ )
+
+/*++
+
+Routine Description:
+
+ The default geometry that was used in partitioning disks under Windows NT 4.0 was
+
+ Sectors per Track = 0x20 = 32
+ Tracks per Cylinder = 0x40 = 64
+
+ This was changed in Windows 2000 to
+
+ Sectors per Track = 0x3F = 63
+ Tracks per Cylinder = 0xFF = 255
+
+ If neither the BIOS nor the port driver can report the correct geometry, we will
+ default to the new numbers on such disks. Now LVM uses the geometry when creating
+ logical volumes and dynamic disks. So reporting an incorrect geometry will cause
+ the entire extended partition / dynamic disk to be destroyed
+
+ In this routine, we will look at the Master Boot Record. In 90% of the cases, the
+ first entry corresponds to a partition that starts on the first track. If this is
+ so, we shall retrieve the logical block address associated with it and calculate
+ the correct geometry. Now, all partitions start on a cylinder boundary. So, for
+ the remaining 10% we will look at the ending CHS number to determine the geometry
+
+--*/
+
+{
+ PUSHORT readBuffer = NULL;
+ BOOLEAN bFoundNT4 = FALSE;
+
+ PAGED_CODE();
+
+ readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, FdoExtension->DiskGeometry.BytesPerSector, DISK_TAG_UPDATE_GEOM);
+
+ if (readBuffer)
+ {
+ KEVENT event;
+ LARGE_INTEGER diskOffset;
+ IO_STATUS_BLOCK ioStatus = { 0 };
+ PIRP irp;
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ //
+ // Read the Master Boot Record at disk offset 0
+ //
+
+ diskOffset.QuadPart = 0;
+
+ irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, FdoExtension->DeviceObject, readBuffer, FdoExtension->DiskGeometry.BytesPerSector, &diskOffset, &event, &ioStatus);
+
+ if (irp)
+ {
+ PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp);
+ NTSTATUS status;
+
+ irpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
+
+ status = IoCallDriver(FdoExtension->DeviceObject, irp);
+
+ if (status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ status = ioStatus.Status;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // Match the boot record signature
+ //
+
+ if (readBuffer[BOOT_SIGNATURE_OFFSET] == BOOT_RECORD_SIGNATURE)
+ {
+ PPARTITION_DESCRIPTOR partitionTableEntry = (PPARTITION_DESCRIPTOR)&readBuffer[PARTITION_TABLE_OFFSET];
+ ULONG uCount = 0;
+
+ //
+ // Walk the entries looking for a clue as to what the geometry might be
+ //
+
+ for (uCount = 0; uCount < NUM_PARTITION_TABLE_ENTRIES; uCount++)
+ {
+ //
+ // We are only concerned if there might be a logical volume or if this disk is part of a dynamic set
+ //
+
+ if (IsContainerPartition(partitionTableEntry->PartitionType) || partitionTableEntry->PartitionType == PARTITION_LDM)
+ {
+ //
+ // In 90% of the cases, the first entry corresponds to a partition that starts on the first track
+ //
+
+ if (partitionTableEntry->StartingTrack == 1 && GET_STARTING_SECTOR(partitionTableEntry) == 0x20)
+ {
+ bFoundNT4 = TRUE;
+ break;
+ }
+
+ //
+ // In almost every case, the ending CHS number is on a cylinder boundary
+ //
+
+ if (partitionTableEntry->EndingTrack == 0x3F && GET_ENDING_S_OF_CHS(partitionTableEntry) == 0x20)
+ {
+ bFoundNT4 = TRUE;
+ break;
+ }
+ }
+
+ partitionTableEntry++;
+ }
+ }
+ else
+ {
+ //
+ // The Master Boot Record is invalid
+ //
+ }
+ }
+ }
+
+ FREE_POOL(readBuffer);
+ }
+
+ return bFoundNT4;
+}
+
+
+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;
+ NTSTATUS status;
+
+ if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
+ DiskUpdateRemovableGeometry(fdoExtension);
+ } else {
+ 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;
+
+ UNREFERENCED_PARAMETER(Nothing);
+
+ if(Count != 1) {
+ TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "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) {
+ TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: no detect info saved\n"));
+ return;
+ }
+
+ if((DetectInfoCount - DetectInfoUsedCount) != 1) {
+ TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "DiskDriverReinitialization: %d of %d geometry entries "
+ "used - will not attempt match\n", DetectInfoUsedCount, DetectInfoCount));
+ 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;
+#pragma prefast(suppress:28175, "Need to access the opaque field to scan through the list of disks")
+ deviceObject = deviceObject->NextDevice) {
+
+ fdoExtension = deviceObject->DeviceExtension;
+
+ if (!fdoExtension->CommonExtension.IsFdo) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: %#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) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskDriverReinit: FDO %#p has a geometry\n",
+ deviceObject));
+ continue;
+ }
+
+ TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "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) {
+ NT_ASSERT(unmatchedDisk != NULL);
+ TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "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) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "DiskDriverReinit: Unable to match geometry\n"));
+ return;
+
+ }
+
+ fdoExtension = unmatchedDisk->DeviceExtension;
+ diskData = fdoExtension->CommonExtension.DriverData;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "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;
+ }
+ }
+
+ if (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 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.
+ //
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "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;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "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;
+
+ (VOID)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.
+ //
+
+ NT_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 = FALSE;
+ PDISK_DETECT_INFO diskInfo = NULL;
+ PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
+
+ PAGED_CODE ();
+
+ //
+ // 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++) {
+
+
+ NT_ASSERT(DetectInfoList != NULL);
+
+ diskInfo = &(DetectInfoList[i]);
+
+ if((diskData->Mbr.Signature != 0) &&
+ (diskData->Mbr.Signature == diskInfo->Signature)) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "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)) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "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 = { 0 };
+
+ 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 {
+ NT_ASSERT (FALSE);
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ return Status;
+}
+
+#endif // defined(_X86_) || defined(_AMD64_)
+