Esempio n. 1
0
NTSTATUS
NTAPI
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;
}
Esempio n. 2
0
NTSTATUS
DiskInitFdo(
    IN PDEVICE_OBJECT Fdo
    )

/*++

Routine Description:

    This routine is called to do one-time initialization of new device objects


Arguments:

    Fdo - a pointer to the functional device object for this device

Return Value:

    status

--*/

{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;

    ULONG srbFlags = 0;
    ULONG timeOut = 0;
    ULONG bytesPerSector;

    PULONG dmSkew;

    NTSTATUS status = STATUS_SUCCESS;

    PAGED_CODE();

    //
    // Build the lookaside list for srb's for the physical disk. Should only
    // need a couple.  If this fails then we don't have an emergency SRB so
    // fail the call to initialize.
    //

    ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) fdoExtension,
                                    PARTITION0_LIST_SIZE);

    if (fdoExtension->DeviceDescriptor->RemovableMedia)
    {
        SET_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA);
    }

    //
    // Initialize the srb flags.
    //

    //
    // Because all requests share a common sense buffer, it is possible
    // for the buffer to be overwritten if the port driver completes
    // multiple failed requests that require a request sense before the
    // class driver's completion routine can consume the data in the buffer.
    // To prevent this, we allow the port driver to allocate a unique sense
    // buffer each time it needs one.  We are responsible for freeing this
    // buffer.  This also allows the adapter to be configured to support
    // additional sense data beyond the minimum 18 bytes.
    //

    SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE);

    if (fdoExtension->DeviceDescriptor->CommandQueueing &&
        fdoExtension->AdapterDescriptor->CommandQueueing) {

        SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);

    }

    //
    // Look for controllers that require special flags.
    //

    ClassScanForSpecial(fdoExtension, DiskBadControllers, DiskSetSpecialHacks);

    //
    // Clear buffer for drive geometry.
    //

    RtlZeroMemory(&(fdoExtension->DiskGeometry),
                  sizeof(DISK_GEOMETRY));

    //
    // Allocate request sense buffer.
    //

    fdoExtension->SenseData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
                                                    SENSE_BUFFER_SIZE_EX,
                                                    DISK_TAG_START);

    if (fdoExtension->SenseData == NULL) {

        //
        // The buffer can not be allocated.
        //

        TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskInitFdo: Can not allocate request sense buffer\n"));

        status = STATUS_INSUFFICIENT_RESOURCES;
        return status;
    }

    //
    // Set the buffer size of SenseData
    //

    fdoExtension->SenseDataLength = SENSE_BUFFER_SIZE_EX;

    //
    // Physical device object will describe the entire
    // device, starting at byte offset 0.
    //

    fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)(0);

    //
    // Set timeout value in seconds.
    //
    if ( (fdoExtension->MiniportDescriptor != NULL) && 
         (fdoExtension->MiniportDescriptor->IoTimeoutValue > 0) ) {
        //
        // use the value set by Storport miniport driver
        //
        fdoExtension->TimeOutValue = fdoExtension->MiniportDescriptor->IoTimeoutValue;
    } else {
        //
        // get timeout value from registry
        //
        timeOut = ClassQueryTimeOutRegistryValue(Fdo);

        if (timeOut) {
            fdoExtension->TimeOutValue = timeOut;
        } else {
            fdoExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
        }
    }
    //
    // If this is a removable drive, build an entry in devicemap\scsi
    // indicating it's physicaldriveN name, set up the appropriate
    // update partitions routine and set the flags correctly.
    // note: only do this after the timeout value is set, above.
    //

    if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {

        ClassUpdateInformationInRegistry( Fdo,
                                          "PhysicalDrive",
                                          fdoExtension->DeviceNumber,
                                          NULL,
                                          0);
        //
        // Enable media change notification for removable disks
        //
        ClassInitializeMediaChangeDetection(fdoExtension,
                                            (PUCHAR)"Disk");

    } else {

        SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
        SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);

    }

    //
    // The commands we send during the init could cause the flags to change
    // in case of any error.  Save the SRB flags locally and restore it at
    // the end of this function, so that the class driver can get it.
    //

    srbFlags = fdoExtension->SrbFlags;


    //
    // Read the drive capacity.  Don't use the disk version of the routine here
    // since we don't know the disk signature yet - the disk version will
    // attempt to determine the BIOS reported geometry.
    //

    (VOID)ClassReadDriveCapacity(Fdo);

    //
    // Set up sector size fields.
    //
    // Stack variables will be used to update
    // the partition device extensions.
    //
    // The device extension field SectorShift is
    // used to calculate sectors in I/O transfers.
    //
    // The DiskGeometry structure is used to service
    // IOCTls used by the format utility.
    //

    bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;

    //
    // Make sure sector size is not zero.
    //

    if (bytesPerSector == 0) {

        //
        // Default sector size for disk is 512.
        //

        bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector = 512;
        fdoExtension->SectorShift = 9;
    }

    //
    // Determine is DM Driver is loaded on an IDE drive that is
    // under control of Atapi - this could be either a crashdump or
    // an Atapi device is sharing the controller with an IDE disk.
    //

    HalExamineMBR(fdoExtension->CommonExtension.DeviceObject,
                  fdoExtension->DiskGeometry.BytesPerSector,
                  (ULONG)0x54,
                  &dmSkew);

    if (dmSkew) {

        //
        // Update the device extension, so that the call to IoReadPartitionTable
        // will get the correct information. Any I/O to this disk will have
        // to be skewed by *dmSkew sectors aka DMByteSkew.
        //

        fdoExtension->DMSkew     = *dmSkew;
        fdoExtension->DMActive   = TRUE;
        fdoExtension->DMByteSkew = fdoExtension->DMSkew * bytesPerSector;

        FREE_POOL(dmSkew);
    }

#if defined(_X86_) || defined(_AMD64_)

    //
    // Try to read the signature off the disk and determine the correct drive
    // geometry based on that.  This requires rereading the disk size to get
    // the cylinder count updated correctly.
    //

    if(!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {

        DiskReadSignature(Fdo);
        DiskReadDriveCapacity(Fdo);

        if (diskData->GeometrySource == DiskGeometryUnknown)
        {
            //
            // Neither the  BIOS  nor the port driver could provide us with a  reliable
            // geometry.  Before we use the default,  look to see if it was partitioned
            // under Windows NT4 [or earlier] and apply the one that was used back then
            //

            if (DiskIsNT4Geometry(fdoExtension))
            {
                diskData->RealGeometry = fdoExtension->DiskGeometry;
                diskData->RealGeometry.SectorsPerTrack   = 0x20;
                diskData->RealGeometry.TracksPerCylinder = 0x40;
                fdoExtension->DiskGeometry = diskData->RealGeometry;

                diskData->GeometrySource = DiskGeometryFromNT4;
            }
        }
    }

#endif

    DiskCreateSymbolicLinks(Fdo);

    //
    // Get the SCSI address if it's available for use with SMART ioctls.
    // SMART ioctls are used for failure prediction, so we need to get
    // the SCSI address before initializing failure prediction.
    //

    {
        PIRP irp;
        KEVENT event;
        IO_STATUS_BLOCK statusBlock = { 0 };

        KeInitializeEvent(&event, SynchronizationEvent, FALSE);

        irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS,
                                            fdoExtension->CommonExtension.LowerDeviceObject,
                                            NULL,
                                            0L,
                                            &(diskData->ScsiAddress),
                                            sizeof(SCSI_ADDRESS),
                                            FALSE,
                                            &event,
                                            &statusBlock);

        status = STATUS_UNSUCCESSFUL;

        if(irp != NULL) {

            status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);

            if(status == STATUS_PENDING) {
                KeWaitForSingleObject(&event,
                                      Executive,
                                      KernelMode,
                                      FALSE,
                                      NULL);
                status = statusBlock.Status;
            }
        }
    }

    //
    // Determine the type of disk and enable failure prediction in the hardware
    // and enable failure prediction polling.
    //

    if (*InitSafeBootMode == 0)
    {
        DiskDetectFailurePrediction(fdoExtension,
                                    &diskData->FailurePredictionCapability,
                                    NT_SUCCESS(status));

        if (diskData->FailurePredictionCapability != FailurePredictionNone)
        {
            //
            // Cool, we've got some sort of failure prediction, enable it
            // at the hardware and then enable polling for it
            //

            //
            // By default we allow performance to be degradeded if failure
            // prediction is enabled.
            //

            diskData->AllowFPPerfHit = TRUE;

            //
            // Enable polling only after Atapi and SBP2 add support for the new
            // SRB flag that indicates that the request should not reset the
            // drive spin down idle timer.
            //

            status = DiskEnableDisableFailurePredictPolling(fdoExtension,
                                          TRUE,
                                          DISK_DEFAULT_FAILURE_POLLING_PERIOD);

            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskInitFdo: Failure Prediction Poll enabled as "
                           "%d for device %p, Status = %lx\n",
                     diskData->FailurePredictionCapability,
                     Fdo,
                     status));
        }
    } else {

        //
        // In safe boot mode we do not enable failure prediction, as perhaps
        // it is the reason why normal boot does not work
        //

        diskData->FailurePredictionCapability = FailurePredictionNone;

    }

    //
    // Initialize the verify mutex
    //

    KeInitializeMutex(&diskData->VerifyMutex, MAX_SECTORS_PER_VERIFY);

    //
    // Initialize the flush group context
    //

    RtlZeroMemory(&diskData->FlushContext, sizeof(DISK_GROUP_CONTEXT));

    InitializeListHead(&diskData->FlushContext.CurrList);
    InitializeListHead(&diskData->FlushContext.NextList);

    KeInitializeSpinLock(&diskData->FlushContext.Spinlock);
    KeInitializeEvent(&diskData->FlushContext.Event, SynchronizationEvent, FALSE);


    //
    // Restore the saved value
    //
    fdoExtension->SrbFlags = srbFlags;

    return STATUS_SUCCESS;

} // end DiskInitFdo()
Esempio n. 3
0
NTSTATUS
NTAPI
DiskInitFdo(
    IN PDEVICE_OBJECT Fdo
    )

/*++

Routine Description:

    This routine is called to do one-time initialization of new device objects


Arguments:

    Fdo - a pointer to the functional device object for this device

Return Value:

    status

--*/

{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;

    PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;

    //ULONG srbFlags = 0;

    ULONG timeOut = 0;

    ULONG bytesPerSector;
    //UCHAR sectorShift;

    //BOOLEAN dmActive = FALSE;
    PULONG dmSkew;
    //ULONG dmByteSkew;

    NTSTATUS status;

    PAGED_CODE();

    //
    // Build the lookaside list for srb's for the physical disk. Should only
    // need a couple.  If this fails then we don't have an emergency SRB so
    // fail the call to initialize.
    //

    ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) fdoExtension,
                                    PARTITION0_LIST_SIZE);

    //
    // Because all requests share a common sense buffer, it is possible
    // for the buffer to be overwritten if the port driver completes
    // multiple failed requests that require a request sense before the
    // class driver's completion routine can consume the data in the buffer.
    // To prevent this, we allow the port driver to allocate a unique sense
    // buffer each time it needs one.  We are responsible for freeing this
    // buffer.  This also allows the adapter to be configured to support
    // additional sense data beyond the minimum 18 bytes.
    //

    fdoExtension->SrbFlags = SRB_FLAGS_PORT_DRIVER_ALLOCSENSE;

    //
    // Initialize the srb flags.
    //

    if (fdoExtension->DeviceDescriptor->CommandQueueing &&
        fdoExtension->AdapterDescriptor->CommandQueueing) {

        fdoExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE;

    }

    if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
        SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
    }

    //
    // Look for controllers that require special flags.
    //

    ClassScanForSpecial(fdoExtension, DiskBadControllers, DiskSetSpecialHacks);

    //
    // Look into the registry to see if this device
    // requires special attention - [ like a hack ]
    //

    DiskScanRegistryForSpecial(fdoExtension);

    //srbFlags = fdoExtension->SrbFlags;

    //
    // Clear buffer for drive geometry.
    //

    RtlZeroMemory(&(fdoExtension->DiskGeometry),
                  sizeof(DISK_GEOMETRY));

    //
    // Allocate request sense buffer.
    //

    fdoExtension->SenseData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
                                                    SENSE_BUFFER_SIZE,
                                                    DISK_TAG_START);

    if (fdoExtension->SenseData == NULL) {

        //
        // The buffer can not be allocated.
        //

        DebugPrint((1, "DiskInitFdo: Can not allocate request sense buffer\n"));

        status = STATUS_INSUFFICIENT_RESOURCES;
        return status;
    }

    //
    // Physical device object will describe the entire
    // device, starting at byte offset 0.
    //

    fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)(0);

    //
    // Set timeout value in seconds.
    //

    timeOut = ClassQueryTimeOutRegistryValue(Fdo);
    if (timeOut) {
        fdoExtension->TimeOutValue = timeOut;
    } else {
        fdoExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
    }

    //
    // If this is a removable drive, build an entry in devicemap\scsi
    // indicating it's physicaldriveN name, set up the appropriate
    // update partitions routine and set the flags correctly.
    // note: only do this after the timeout value is set, above.
    //

    if (fdoExtension->DeviceDescriptor->RemovableMedia) {
        ClassUpdateInformationInRegistry( Fdo,
                                          "PhysicalDrive",
                                          fdoExtension->DeviceNumber,
                                          NULL,
                                          0);
        //
        // Enable media change notification for removable disks
        //
        ClassInitializeMediaChangeDetection(fdoExtension,
                                            "Disk");

        SET_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA);
        diskData->UpdatePartitionRoutine = DiskUpdateRemovablePartitions;

    } else {

        SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
        diskData->UpdatePartitionRoutine = DiskUpdatePartitions;

    }

    //
    // Read the drive capacity.  Don't use the disk version of the routine here
    // since we don't know the disk signature yet - the disk version will
    // attempt to determine the BIOS reported geometry.
    //

    status = ClassReadDriveCapacity(Fdo);

    //
    // If the read capcity failed then just return, unless this is a
    // removable disk where a device object partition needs to be created.
    //

    if (!NT_SUCCESS(status) &&
        !(Fdo->Characteristics & FILE_REMOVABLE_MEDIA)) {

        DebugPrint((1,
            "DiskInitFdo: Can't read capacity for device %p\n",
            Fdo));

        if (fdoExtension->DeviceDescriptor->RemovableMedia) {
            fdoExtension->DiskGeometry.MediaType = RemovableMedia;
            Fdo->Flags &= ~DO_VERIFY_VOLUME;
        } else {
            fdoExtension->DiskGeometry.MediaType = FixedMedia;
        }

        status = STATUS_SUCCESS;
    }

    //
    // Set up sector size fields.
    //
    // Stack variables will be used to update
    // the partition device extensions.
    //
    // The device extension field SectorShift is
    // used to calculate sectors in I/O transfers.
    //
    // The DiskGeometry structure is used to service
    // IOCTls used by the format utility.
    //

    bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;

    //
    // Make sure sector size is not zero.
    //

    if (bytesPerSector == 0) {

        //
        // Default sector size for disk is 512.
        //

        bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector = 512;
    }

    //sectorShift = fdoExtension->SectorShift;

    //
    // Determine is DM Driver is loaded on an IDE drive that is
    // under control of Atapi - this could be either a crashdump or
    // an Atapi device is sharing the controller with an IDE disk.
    //

    HalExamineMBR(fdoExtension->CommonExtension.DeviceObject,
                  fdoExtension->DiskGeometry.BytesPerSector,
                  (ULONG)0x54,
                  (PVOID*)&dmSkew);

    if (dmSkew) {

        //
        // Update the device extension, so that the call to IoReadPartitionTable
        // will get the correct information. Any I/O to this disk will have
        // to be skewed by *dmSkew sectors aka DMByteSkew.
        //

        fdoExtension->DMSkew = *dmSkew;
        fdoExtension->DMActive = TRUE;
        fdoExtension->DMByteSkew = fdoExtension->DMSkew * bytesPerSector;

        //
        // Save away the infomation that we need, since this deviceExtension will soon be
        // blown away.
        //

        //dmActive = TRUE;
        //dmByteSkew = fdoExtension->DMByteSkew;

    }

#if defined(_X86_)
    //
    // Try to read the signature off the disk and determine the correct drive
    // geometry based on that.  This requires rereading the disk size to get
    // the cylinder count updated correctly.
    //

    if(fdoExtension->DeviceDescriptor->RemovableMedia == FALSE) {
        DiskReadSignature(Fdo);
        DiskReadDriveCapacity(Fdo);
    }
#endif

    //
    // Register interfaces for this device
    //
    {
        UNICODE_STRING interfaceName;

        RtlInitUnicodeString(&interfaceName, NULL);

        status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
                                           (LPGUID) &DiskClassGuid,
                                           NULL,
                                           &interfaceName);

        if(NT_SUCCESS(status)) {

            diskData->DiskInterfaceString = interfaceName;
            status = IoSetDeviceInterfaceState(&interfaceName, TRUE);

        } else {
            interfaceName.Buffer = NULL;
        }

        if(!NT_SUCCESS(status)) {

            DebugPrint((1, "DiskInitFdo: Unable to register or set disk DCA "
                           "for fdo %p [%lx]\n", Fdo, status));

            RtlFreeUnicodeString(&interfaceName);
            RtlInitUnicodeString(&(diskData->DiskInterfaceString), NULL);
        }
    }

    DiskCreateSymbolicLinks(Fdo);

    //
    // Determine the type of disk and enable failure preiction in the hardware
    // and enable failure prediction polling.
    //

    if (InitSafeBootMode == 0)
    {
        DiskDetectFailurePrediction(fdoExtension,
                                  &diskData->FailurePredictionCapability);

        if (diskData->FailurePredictionCapability != FailurePredictionNone)
        {
            //
            // Cool, we've got some sort of failure prediction, enable it
            // at the hardware and then enable polling for it
            //

            //
            // By default we allow performance to be degradeded if failure
            // prediction is enabled.
            //
            // TODO: Make a registry entry ?
            //

            diskData->AllowFPPerfHit = TRUE;

            //
            // Enable polling only after Atapi and SBP2 add support for the new
            // SRB flag that indicates that the request should not reset the
            // drive spin down idle timer.
            //

            status = DiskEnableDisableFailurePredictPolling(fdoExtension,
                                          TRUE,
                                          DISK_DEFAULT_FAILURE_POLLING_PERIOD);

            DebugPrint((3, "DiskInitFdo: Failure Prediction Poll enabled as "
                           "%d for device %p\n",
                     diskData->FailurePredictionCapability,
                     Fdo));
        }
    } else {

        //
        // In safe boot mode we do not enable failure prediction, as perhaps
        // it is the reason why normal boot does not work
        //

        diskData->FailurePredictionCapability = FailurePredictionNone;

    }

    //
    // Initialize the verify mutex
    //

    KeInitializeMutex(&diskData->VerifyMutex, MAX_SECTORS_PER_VERIFY);

    return(STATUS_SUCCESS);

} // end DiskInitFdo()
Esempio n. 4
0
VOID
NTAPI
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;
}