3663 lines
98 KiB
C
3663 lines
98 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
abiosdsk.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This driver services disk devices through the standard
|
|||
|
ABIOS disk compatibility interface.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Current Author
|
|||
|
Bob Rinne (bobri) 10-Jul-1992
|
|||
|
Initial Author
|
|||
|
Mike Glass (mglass) 1-Aug-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
kernel mode only
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
10-Jul-1992 bobri - Added page buffer to account for changes in memory
|
|||
|
management.
|
|||
|
2-Sep-1992 bobri - Added verify support.
|
|||
|
1-Mar-1993 jhavens - Added AdapterObject support to remove internal
|
|||
|
buffering and get larger I/Os
|
|||
|
13-Nov-1993 mglass - Added routine UpdateDeviceObjects to support dynamic
|
|||
|
disk repartitioning.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ntddk.h"
|
|||
|
#include "stdarg.h"
|
|||
|
#include "stdio.h"
|
|||
|
|
|||
|
|
|||
|
#if defined(i386)
|
|||
|
|
|||
|
#include "ntdddisk.h"
|
|||
|
#include "abiosdev.h"
|
|||
|
|
|||
|
#ifdef POOL_TAGGING
|
|||
|
#ifdef ExAllocatePool
|
|||
|
#undef ExAllocatePool
|
|||
|
#endif
|
|||
|
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'sobA')
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Abios support routine definitions.
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
KeI386AbiosCall(
|
|||
|
IN USHORT LogicalId,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUCHAR RequestBlock,
|
|||
|
IN USHORT EntryPoint
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
KeI386FlatToGdtSelector(
|
|||
|
IN ULONG SelectorBase,
|
|||
|
IN USHORT Length,
|
|||
|
IN USHORT Selector
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
KeI386ReleaseLid(
|
|||
|
IN USHORT LogicalId,
|
|||
|
IN PDRIVER_OBJECT DriverObject
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
KeI386GetLid(
|
|||
|
IN USHORT DeviceId,
|
|||
|
IN USHORT RelativeLid,
|
|||
|
IN BOOLEAN SharedLid,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
OUT PUSHORT LogicalId
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
KeI386AllocateGdtSelectors(
|
|||
|
OUT PUSHORT SelectorArray,
|
|||
|
IN USHORT NumberOfSelectors
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
KeI386ReleaseGdtSelectors(
|
|||
|
OUT PUSHORT SelectorArray,
|
|||
|
IN USHORT NumberOfSelectors
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
//
|
|||
|
// ABIOS debug level global variable
|
|||
|
//
|
|||
|
|
|||
|
ULONG AbiosDebug = 0;
|
|||
|
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
//
|
|||
|
// Controller extension
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _CONTROLLER_EXTENSION {
|
|||
|
|
|||
|
//
|
|||
|
// Back pointer to controller object
|
|||
|
//
|
|||
|
|
|||
|
PCONTROLLER_OBJECT ControllerObject;
|
|||
|
|
|||
|
//
|
|||
|
// Pointer to Adapter object for DMA and synchronization.
|
|||
|
//
|
|||
|
|
|||
|
PADAPTER_OBJECT DmaAdapterObject;
|
|||
|
|
|||
|
//
|
|||
|
// The map register base for the adapter object.
|
|||
|
//
|
|||
|
|
|||
|
PVOID MapRegisterBase;
|
|||
|
|
|||
|
//
|
|||
|
// The maximum number of pages that the transfer can span.
|
|||
|
//
|
|||
|
|
|||
|
ULONG MaximumNumberOfPages;
|
|||
|
|
|||
|
//
|
|||
|
// Request timeout value
|
|||
|
//
|
|||
|
|
|||
|
LARGE_INTEGER TimeoutValue;
|
|||
|
|
|||
|
//
|
|||
|
// Current request
|
|||
|
//
|
|||
|
|
|||
|
PIRP IrpAddress;
|
|||
|
|
|||
|
//
|
|||
|
// Number of map registers allocated.
|
|||
|
//
|
|||
|
|
|||
|
ULONG NumberOfMapRegisters;
|
|||
|
|
|||
|
//
|
|||
|
// Pointer to driver object used in ABIOS calls as identifier of
|
|||
|
// ownership of LID
|
|||
|
//
|
|||
|
|
|||
|
PDRIVER_OBJECT DriverObject;
|
|||
|
PKINTERRUPT InterruptObject;
|
|||
|
ULONG Irq;
|
|||
|
|
|||
|
//
|
|||
|
// DMA arbitration level from ABIOS
|
|||
|
//
|
|||
|
|
|||
|
UCHAR ArbitrationLevel;
|
|||
|
|
|||
|
//
|
|||
|
// Attempting reset of device.
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN PerformingReset;
|
|||
|
|
|||
|
//
|
|||
|
// Data Selector: selector to frame data.
|
|||
|
//
|
|||
|
|
|||
|
USHORT DataSelector;
|
|||
|
|
|||
|
//
|
|||
|
// Number of retries left.
|
|||
|
//
|
|||
|
|
|||
|
USHORT RetryCount;
|
|||
|
|
|||
|
//
|
|||
|
// Number of disks on this controller
|
|||
|
//
|
|||
|
|
|||
|
USHORT UnitCount;
|
|||
|
|
|||
|
//
|
|||
|
// ABIOS indentifier
|
|||
|
//
|
|||
|
|
|||
|
USHORT LogicalId;
|
|||
|
|
|||
|
//
|
|||
|
// ABIOS request block size and pointer.
|
|||
|
//
|
|||
|
|
|||
|
USHORT RequestBlockLength;
|
|||
|
PABIOS_REQUEST_BLOCK RequestBlock;
|
|||
|
PABIOS_REQUEST_BLOCK RetryRequestBlock;
|
|||
|
|
|||
|
//
|
|||
|
// 16:16 Selector points to ABIOS request block.
|
|||
|
//
|
|||
|
|
|||
|
PUCHAR Selector;
|
|||
|
|
|||
|
//
|
|||
|
// Current device object
|
|||
|
//
|
|||
|
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// Total sectors for this IRP
|
|||
|
//
|
|||
|
|
|||
|
ULONG TotalSectors;
|
|||
|
|
|||
|
//
|
|||
|
// Remaining sectors in this request
|
|||
|
//
|
|||
|
|
|||
|
ULONG RemainingSectors;
|
|||
|
|
|||
|
//
|
|||
|
// Sectors this transfer
|
|||
|
//
|
|||
|
|
|||
|
ULONG TransferSectors;
|
|||
|
|
|||
|
//
|
|||
|
// Starting sector on disk
|
|||
|
//
|
|||
|
|
|||
|
ULONG StartingSector;
|
|||
|
|
|||
|
//
|
|||
|
// Virtual address of data buffer.
|
|||
|
//
|
|||
|
|
|||
|
PVOID VirtualAddress;
|
|||
|
|
|||
|
//
|
|||
|
// System address for PIO devices.
|
|||
|
//
|
|||
|
|
|||
|
PVOID SystemAddress;
|
|||
|
|
|||
|
//
|
|||
|
// Physical Address of data buffer.
|
|||
|
//
|
|||
|
|
|||
|
ULONG PhysicalAddress;
|
|||
|
|
|||
|
//
|
|||
|
// Number of bytes transferred
|
|||
|
//
|
|||
|
|
|||
|
ULONG BytesTransferred;
|
|||
|
|
|||
|
KDPC CompletionDpc;
|
|||
|
KTIMER Timer;
|
|||
|
KDPC TimerDpc;
|
|||
|
|
|||
|
} CONTROLLER_EXTENSION, *PCONTROLLER_EXTENSION;
|
|||
|
|
|||
|
#define CONTROLLER_EXTENSION_SIZE sizeof(CONTROLLER_EXTENSION)
|
|||
|
|
|||
|
//
|
|||
|
// Device Extension
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _DEVICE_EXTENSION {
|
|||
|
|
|||
|
//
|
|||
|
// Back pointer to device object
|
|||
|
//
|
|||
|
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// Pointer to controller extension
|
|||
|
//
|
|||
|
|
|||
|
PCONTROLLER_EXTENSION ControllerExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Pointer to physical disk extension.
|
|||
|
//
|
|||
|
|
|||
|
struct _DEVICE_EXTENSION *PhysicalDevice;
|
|||
|
|
|||
|
//
|
|||
|
// Unit number on controller
|
|||
|
//
|
|||
|
|
|||
|
USHORT Unit;
|
|||
|
|
|||
|
//
|
|||
|
// Ordinal of partition represented by this device object
|
|||
|
//
|
|||
|
|
|||
|
USHORT PartitionNumber;
|
|||
|
|
|||
|
//
|
|||
|
// Partition type of this device object
|
|||
|
//
|
|||
|
// This field is set by:
|
|||
|
//
|
|||
|
// 1) Initially set according to the partition list entry partition
|
|||
|
// type returned by IoReadPartitionTable.
|
|||
|
//
|
|||
|
// 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
|
|||
|
// I/O control function when IoSetPartitionInformation function
|
|||
|
// successfully updates the partition type on the disk.
|
|||
|
//
|
|||
|
|
|||
|
UCHAR PartitionType;
|
|||
|
|
|||
|
//
|
|||
|
// Boot indicator - indicates whether this partition is a bootable (active)
|
|||
|
// partition for this device
|
|||
|
//
|
|||
|
// This field is set according to the partition list entry boot indicator
|
|||
|
// returned by IoReadPartitionTable.
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN BootIndicator;
|
|||
|
|
|||
|
//
|
|||
|
// Log2 of sector size
|
|||
|
//
|
|||
|
|
|||
|
UCHAR SectorShift;
|
|||
|
|
|||
|
//
|
|||
|
// PAGE_SIZE / Sector size
|
|||
|
//
|
|||
|
|
|||
|
UCHAR SectorsInPage;
|
|||
|
|
|||
|
//
|
|||
|
// Maximum number of sectors that can be transfered
|
|||
|
// in single request block
|
|||
|
//
|
|||
|
|
|||
|
USHORT MaximumNumberBlocks;
|
|||
|
|
|||
|
//
|
|||
|
// ABIOS suggested number of software retries
|
|||
|
//
|
|||
|
|
|||
|
USHORT SoftwareRetries;
|
|||
|
|
|||
|
//
|
|||
|
// System disk number
|
|||
|
//
|
|||
|
|
|||
|
ULONG DiskNumber;
|
|||
|
|
|||
|
//
|
|||
|
// Link to next partition for dynamic partitioning support
|
|||
|
//
|
|||
|
|
|||
|
struct _DEVICE_EXTENSION *NextPartition;
|
|||
|
|
|||
|
//
|
|||
|
// Drive parameters returned in IO device control.
|
|||
|
//
|
|||
|
|
|||
|
DISK_GEOMETRY DiskGeometry;
|
|||
|
|
|||
|
//
|
|||
|
// Number of hidden sectors for BPB.
|
|||
|
//
|
|||
|
|
|||
|
ULONG HiddenSectors;
|
|||
|
|
|||
|
//
|
|||
|
// Length of partition in bytes
|
|||
|
//
|
|||
|
|
|||
|
LARGE_INTEGER PartitionLength;
|
|||
|
|
|||
|
//
|
|||
|
// Number of bytes before start of partition
|
|||
|
//
|
|||
|
|
|||
|
LARGE_INTEGER StartingOffset;
|
|||
|
|
|||
|
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
|||
|
|
|||
|
#define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION)
|
|||
|
|
|||
|
#define BYTES_PER_SECTOR 512
|
|||
|
#define SECTOR_SHIFT 9
|
|||
|
|
|||
|
#define NUMBER_MCA_ADAPTERS 2
|
|||
|
|
|||
|
#define HIGHEST_MEMORY_ADDRESS (16 * 1024 * 1024)
|
|||
|
|
|||
|
ULONG AbiosDiskErrorLogSequence = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Set debug macro.
|
|||
|
//
|
|||
|
|
|||
|
#if DBG
|
|||
|
#define DebugPrint(x) AbiosDebugPrint x
|
|||
|
#else
|
|||
|
#define DebugPrint(x)
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Function declarations
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PVOID DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosProcessLogicalId(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN USHORT LogicalId,
|
|||
|
IN PCONFIGURATION_INFORMATION ConfigurationInformation,
|
|||
|
IN USHORT Selector
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosProcessDisk(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PCONTROLLER_OBJECT ControllerObject,
|
|||
|
IN PCONFIGURATION_INFORMATION ConfigurationInformation,
|
|||
|
IN USHORT LogicalId,
|
|||
|
IN USHORT Unit
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosDiskCreate(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosDiskReadWrite(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosDiskStartIo(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
AbiosDiskControllerPioAllocated(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID MapRegisterBase,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
AbiosDiskControllerForDmaAllocated(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID MapRegisterBase,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
AbiosDiskAdapterAllocated(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID MapRegisterBase,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosBuildRequest(
|
|||
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AbiosDiskSynchronizedIoStart(
|
|||
|
IN PVOID DeviceObject
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AbiosDiskInterrupt(
|
|||
|
IN PKINTERRUPT InterruptObject,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosDiskCompletionDpc(
|
|||
|
IN PKDPC Dpc,
|
|||
|
IN PVOID DeferredContext,
|
|||
|
IN PVOID SystemArgument1,
|
|||
|
IN PVOID SystemArgument2
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosDiskTimeoutDpc(
|
|||
|
IN PKDPC Dpc,
|
|||
|
IN PVOID DeferredContext,
|
|||
|
IN PVOID SystemArgument1,
|
|||
|
IN PVOID SystemArgument2
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AbiosCheckReturnCode(
|
|||
|
IN PVOID DeviceObject
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosInterpretReturnCode(
|
|||
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|||
|
IN PABIOS_REQUEST_BLOCK RequestBlock
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosDiskDeviceControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosDiskLogError(
|
|||
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|||
|
IN ULONG UniqueErrorValue,
|
|||
|
IN NTSTATUS FinalStatus,
|
|||
|
IN NTSTATUS SpecificIoStatus
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
UpdateDeviceObjects(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Define code that may be discarded after boot.
|
|||
|
//
|
|||
|
|
|||
|
#pragma alloc_text(INIT, DriverEntry)
|
|||
|
#pragma alloc_text(INIT, AbiosProcessDisk)
|
|||
|
#pragma alloc_text(INIT, AbiosProcessLogicalId)
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize ABIOS driver.
|
|||
|
This return is the system initialization entry point when
|
|||
|
the driver is linked into the kernel.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - for the ABIOS driver.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
USHORT relativeLid = 1;
|
|||
|
NTSTATUS returnStatus = STATUS_NO_SUCH_DEVICE;
|
|||
|
USHORT logicalId;
|
|||
|
PCONFIGURATION_INFORMATION configurationInformation;
|
|||
|
USHORT selectorArray[NUMBER_MCA_ADAPTERS];
|
|||
|
NTSTATUS status;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Get the configuration information for this driver.
|
|||
|
//
|
|||
|
|
|||
|
configurationInformation = IoGetConfigurationInformation();
|
|||
|
|
|||
|
//
|
|||
|
// Set up the device driver entry points.
|
|||
|
//
|
|||
|
|
|||
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = AbiosDiskCreate;
|
|||
|
DriverObject->DriverStartIo = AbiosDiskStartIo;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_READ] = AbiosDiskReadWrite;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = AbiosDiskReadWrite;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AbiosDiskDeviceControl;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate 16:16 selectors for request blocks.
|
|||
|
// NOTE: This call is the first ABIOS call and determines
|
|||
|
// the presence of ABIOS. If it fails then the driver fails
|
|||
|
// to initialize and returns the status of this call.
|
|||
|
//
|
|||
|
|
|||
|
status = KeI386AllocateGdtSelectors(selectorArray, NUMBER_MCA_ADAPTERS);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((1,
|
|||
|
"AbiosDiskInitialize: KeI386AllocateGdtSelectors failed\n"));
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find MCA adapters.
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i < NUMBER_MCA_ADAPTERS; i++) {
|
|||
|
|
|||
|
status = KeI386GetLid(ABIOS_DEVICE_DISK,
|
|||
|
relativeLid,
|
|||
|
FALSE,
|
|||
|
DriverObject,
|
|||
|
&logicalId);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Process this disk.
|
|||
|
//
|
|||
|
|
|||
|
status = AbiosProcessLogicalId(DriverObject,
|
|||
|
logicalId,
|
|||
|
configurationInformation,
|
|||
|
selectorArray[relativeLid-1]);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((1,"AbiosDiskInitialize: LID initialization failed\n"));
|
|||
|
} else {
|
|||
|
returnStatus = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Increment relative LID;
|
|||
|
//
|
|||
|
|
|||
|
relativeLid++;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(returnStatus) &&
|
|||
|
status == STATUS_ABIOS_NOT_PRESENT) {
|
|||
|
|
|||
|
KeI386ReleaseGdtSelectors(selectorArray, NUMBER_MCA_ADAPTERS);
|
|||
|
}
|
|||
|
|
|||
|
return returnStatus;
|
|||
|
} // end DriverEntry()
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosProcessLogicalId(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN USHORT LogicalId,
|
|||
|
IN PCONFIGURATION_INFORMATION ConfigurationInformation,
|
|||
|
IN USHORT Selector
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Create controller object to represent this logical id.
|
|||
|
Then allocate ABIOS request block and create GDT selector
|
|||
|
entry to point to it. Issue 'Get Logical ID Parameters' to
|
|||
|
find the number of disk devices and IRQ information.
|
|||
|
Using this information set up the interrupt, DPC and timer.
|
|||
|
Then for each disk call AbiosProcessDisk to create device
|
|||
|
objects and initialize device extension to describe the
|
|||
|
disk.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - for the ABIOS Driver.
|
|||
|
LogicalId - the logical id for ABIOS indicating what to process.
|
|||
|
ConfigurationInformation - pointer to the system configuration structure.
|
|||
|
Selector - selector allocated to frame the ABIOS request block.
|
|||
|
This routine will allocate the space and initialize
|
|||
|
this selector entry in the GDT.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG disksOnLid = 0;
|
|||
|
PABIOS_REQUEST_BLOCK requestBlock;
|
|||
|
PABIOS_LID_PARAMETERS lidParameters;
|
|||
|
PCONTROLLER_OBJECT controllerObject;
|
|||
|
DEVICE_DESCRIPTION deviceDescription;
|
|||
|
PCONTROLLER_EXTENSION controllerExtension;
|
|||
|
KIRQL irql;
|
|||
|
NTSTATUS status;
|
|||
|
USHORT unit;
|
|||
|
KAFFINITY affinity;
|
|||
|
ULONG vector;
|
|||
|
PABIOS_DISK_READ_DEVICE_PARMS diskParameters;
|
|||
|
|
|||
|
//
|
|||
|
// Create controller object for this logical unit.
|
|||
|
//
|
|||
|
|
|||
|
controllerObject = IoCreateController(sizeof(CONTROLLER_EXTENSION));
|
|||
|
|
|||
|
if (controllerObject == NULL) {
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
controllerExtension = (PCONTROLLER_EXTENSION)(controllerObject + 1);
|
|||
|
controllerExtension->ControllerObject = controllerObject;
|
|||
|
|
|||
|
//
|
|||
|
// Store driver object in controller extension to be
|
|||
|
// used as driver unique identifier to claim ABIOS LIDs.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->DriverObject = DriverObject;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate ABIOS request block for this device.
|
|||
|
//
|
|||
|
|
|||
|
requestBlock = controllerExtension->RequestBlock =
|
|||
|
ExAllocatePool(NonPagedPool,
|
|||
|
2 * REQUEST_BLOCK_LENGTH);
|
|||
|
|
|||
|
if (!requestBlock) {
|
|||
|
IoDeleteController(controllerObject);
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
controllerExtension->RetryRequestBlock =
|
|||
|
(PABIOS_REQUEST_BLOCK)((PUCHAR)requestBlock + REQUEST_BLOCK_LENGTH);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize request block to zero.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(requestBlock, REQUEST_BLOCK_LENGTH);
|
|||
|
RtlZeroMemory(controllerExtension->RetryRequestBlock, REQUEST_BLOCK_LENGTH);
|
|||
|
|
|||
|
//
|
|||
|
// Fill in static fields.
|
|||
|
//
|
|||
|
|
|||
|
requestBlock->Length = REQUEST_BLOCK_LENGTH;
|
|||
|
requestBlock->LogicalId = LogicalId;
|
|||
|
requestBlock->Unit = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Create GDT selector for request block.
|
|||
|
//
|
|||
|
|
|||
|
KeI386FlatToGdtSelector((ULONG)requestBlock,
|
|||
|
REQUEST_BLOCK_LENGTH,
|
|||
|
Selector);
|
|||
|
|
|||
|
//
|
|||
|
// Create 16:0 virtual address of request block.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->Selector = (PUCHAR)(Selector<<16);
|
|||
|
|
|||
|
//
|
|||
|
// Issue Return Logical ID Parameters function.
|
|||
|
//
|
|||
|
|
|||
|
requestBlock->Length = 0x0020;
|
|||
|
requestBlock->Function = ABIOS_FUNCTION_GET_LID_PARMS;
|
|||
|
|
|||
|
status = KeI386AbiosCall(LogicalId,
|
|||
|
DriverObject,
|
|||
|
(PUCHAR)(Selector<<16),
|
|||
|
ABIOS_START_ROUTINE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
ExFreePool(requestBlock);
|
|||
|
IoDeleteController(controllerObject);
|
|||
|
DebugPrint((1,"AbiosProcessLogicalId: KeI386ABiosCall Failed\n"));
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Cast requestBlock to return parameters.
|
|||
|
//
|
|||
|
|
|||
|
lidParameters = (PABIOS_LID_PARAMETERS)requestBlock;
|
|||
|
|
|||
|
if ((lidParameters->LidFlags & ABIOS_DATA_TRANSFER_DATA_MASK) == ABIOS_DATA_LOGICAL) {
|
|||
|
|
|||
|
//
|
|||
|
// Create GDT selector for data pointers.
|
|||
|
//
|
|||
|
|
|||
|
status = KeI386AllocateGdtSelectors(&controllerExtension->DataSelector, 1);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
ExFreePool(requestBlock);
|
|||
|
IoDeleteController(controllerObject);
|
|||
|
DebugPrint((1, "AbiosProcessLogicalId: Failed data selector\n"));
|
|||
|
return status;
|
|||
|
}
|
|||
|
} else {
|
|||
|
controllerExtension->DataSelector = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Copy results to controller extension.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->LogicalId = LogicalId;
|
|||
|
controllerExtension->Irq = lidParameters->Irq;
|
|||
|
controllerExtension->UnitCount = lidParameters->UnitCount;
|
|||
|
controllerExtension->ArbitrationLevel = lidParameters->ArbitrationLevel;
|
|||
|
|
|||
|
DebugPrint((2,
|
|||
|
"AbiosProcessLogicalId: Irq is %d\n",
|
|||
|
lidParameters->Irq));
|
|||
|
DebugPrint((2,
|
|||
|
"AbiosProcessLogicalId: Unit count is %d\n",
|
|||
|
lidParameters->UnitCount));
|
|||
|
|
|||
|
|
|||
|
DebugPrint((2,
|
|||
|
"AbiosProcessLogicalId: Use physical data addresses\n"));
|
|||
|
|
|||
|
controllerExtension->PerformingReset = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Assume request block length is less than or equal
|
|||
|
// to the size of the request block allocated.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(lidParameters->RequestBlockLength <= REQUEST_BLOCK_LENGTH);
|
|||
|
|
|||
|
controllerExtension->RequestBlockLength = lidParameters->RequestBlockLength;
|
|||
|
|
|||
|
//
|
|||
|
// Check the drives attached to this LogicalId to verify that ABIOS
|
|||
|
// support is needed.
|
|||
|
//
|
|||
|
|
|||
|
disksOnLid = controllerExtension->UnitCount;
|
|||
|
diskParameters = (PABIOS_DISK_READ_DEVICE_PARMS) requestBlock;
|
|||
|
for (unit = 0; unit < controllerExtension->UnitCount; unit++) {
|
|||
|
|
|||
|
//
|
|||
|
// Issue ABIOS Read Device Parameters.
|
|||
|
//
|
|||
|
|
|||
|
requestBlock->Length = controllerExtension->RequestBlockLength;
|
|||
|
requestBlock->LogicalId = controllerExtension->LogicalId;
|
|||
|
requestBlock->Unit = unit;
|
|||
|
requestBlock->Function = ABIOS_FUNCTION_READ_DEVICE_PARMS;
|
|||
|
|
|||
|
status = KeI386AbiosCall(controllerExtension->LogicalId,
|
|||
|
DriverObject,
|
|||
|
controllerExtension->Selector,
|
|||
|
ABIOS_START_ROUTINE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((1,"AbiosProcessLogicalId: Can't read device parameters\n"));
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check to see it the disk device is a SCSI.
|
|||
|
//
|
|||
|
|
|||
|
if (diskParameters->DeviceControlFlags & DISK_READ_PARMS_SCSI_DEVICE) {
|
|||
|
|
|||
|
DebugPrint((2, "AbiosProcessLogicalId: This is a SCSI device\n"));
|
|||
|
disksOnLid--;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if this device supports SCBs.
|
|||
|
//
|
|||
|
|
|||
|
if (diskParameters->DeviceControlFlags & DISK_READ_PARMS_SUPPORTS_SCB) {
|
|||
|
DebugPrint((2, "AbiosProcessLogicalId: This device supports SCBs\n"));
|
|||
|
disksOnLid--;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!disksOnLid) {
|
|||
|
|
|||
|
//
|
|||
|
// There are no devices requiring ABIOS support.
|
|||
|
//
|
|||
|
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize completion DPC routine.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeDpc(&controllerExtension->CompletionDpc,
|
|||
|
AbiosDiskCompletionDpc,
|
|||
|
controllerExtension);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize timer.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeTimer(&controllerExtension->Timer);
|
|||
|
|
|||
|
KeInitializeDpc(&controllerExtension->TimerDpc,
|
|||
|
AbiosDiskTimeoutDpc,
|
|||
|
controllerExtension);
|
|||
|
|
|||
|
//
|
|||
|
// Call HAL to get system interrupt parameters.
|
|||
|
//
|
|||
|
|
|||
|
vector = HalGetInterruptVector(MicroChannel, // InterfaceType
|
|||
|
0, // BusNumber
|
|||
|
controllerExtension->Irq,
|
|||
|
0, // BusInterruptVector
|
|||
|
&irql,
|
|||
|
&affinity);
|
|||
|
|
|||
|
//
|
|||
|
// Allocate and connect interrupt objects for this device to all of the
|
|||
|
// processors on which this device can interrupt.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->DmaAdapterObject = NULL;
|
|||
|
status = IoConnectInterrupt(&controllerExtension->InterruptObject,
|
|||
|
AbiosDiskInterrupt,
|
|||
|
controllerExtension,
|
|||
|
(PKSPIN_LOCK)NULL,
|
|||
|
vector,
|
|||
|
irql,
|
|||
|
irql,
|
|||
|
LevelSensitive,
|
|||
|
TRUE,
|
|||
|
affinity,
|
|||
|
FALSE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugPrint((1,"AbiosProcessLogicalId: Can't connect to Interrupt %d\n",
|
|||
|
controllerExtension->Irq));
|
|||
|
|
|||
|
IoDeleteController(controllerObject);
|
|||
|
ExFreePool(requestBlock);
|
|||
|
(VOID)KeI386ReleaseLid(LogicalId, DriverObject);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate an adapter for this controller.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
|
|||
|
deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
|
|||
|
deviceDescription.InterfaceType = MicroChannel;
|
|||
|
deviceDescription.BusNumber = 0;
|
|||
|
deviceDescription.ScatterGather = FALSE;
|
|||
|
deviceDescription.Master = TRUE;
|
|||
|
deviceDescription.Dma32BitAddresses = FALSE;
|
|||
|
deviceDescription.AutoInitialize = FALSE;
|
|||
|
deviceDescription.MaximumLength = MM_MAXIMUM_DISK_IO_SIZE + PAGE_SIZE;
|
|||
|
|
|||
|
controllerExtension->DmaAdapterObject = HalGetAdapter(
|
|||
|
&deviceDescription,
|
|||
|
&controllerExtension->MaximumNumberOfPages
|
|||
|
);
|
|||
|
|
|||
|
if (controllerExtension->DmaAdapterObject == NULL) {
|
|||
|
|
|||
|
DebugPrint((1,"AbiosProcessLogicalId: Can't get DMA adapter object\n"));
|
|||
|
|
|||
|
ExFreePool(controllerExtension);
|
|||
|
ExFreePool(requestBlock);
|
|||
|
(VOID)KeI386ReleaseLid(LogicalId, DriverObject);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize request timeout value.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->TimeoutValue.LowPart = (ULONG)
|
|||
|
-(10 * 1000 * 1000 * ABIOS_DISK_TIMEOUT);
|
|||
|
controllerExtension->TimeoutValue.HighPart = -1;
|
|||
|
|
|||
|
//
|
|||
|
// Process each disk on controller.
|
|||
|
//
|
|||
|
|
|||
|
for (unit = 0; unit < controllerExtension->UnitCount; unit++) {
|
|||
|
|
|||
|
status = AbiosProcessDisk(DriverObject,
|
|||
|
controllerObject,
|
|||
|
ConfigurationInformation,
|
|||
|
LogicalId,
|
|||
|
unit);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Increment system disk count.
|
|||
|
//
|
|||
|
|
|||
|
ConfigurationInformation->DiskCount++;
|
|||
|
disksOnLid++;
|
|||
|
} else {
|
|||
|
DebugPrint((1,
|
|||
|
"AbiosProcessLogicalId: Disk %d failed to initialize\n",
|
|||
|
unit));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no disks initialized then fail.
|
|||
|
//
|
|||
|
|
|||
|
if (disksOnLid) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Clean up structures no longer needed.
|
|||
|
//
|
|||
|
|
|||
|
IoDisconnectInterrupt(controllerExtension->InterruptObject);
|
|||
|
ExFreePool(requestBlock);
|
|||
|
|
|||
|
IoDeleteController(controllerObject);
|
|||
|
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
} // end AbiosProcessLogicalId()
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosProcessDisk(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PCONTROLLER_OBJECT ControllerObject,
|
|||
|
IN PCONFIGURATION_INFORMATION ConfigurationInformation,
|
|||
|
IN USHORT LogicalId,
|
|||
|
IN USHORT Unit
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given a logical id and a unit number for ABIOS, this routine will
|
|||
|
process the disk and create all device objects for the partitions
|
|||
|
contained on the disk.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - the system driver object for ABIOSDISK.
|
|||
|
ControllerObject - the controller object created for this ABIOS controller.
|
|||
|
ConfigurationInformation - pointer to the system configuration structure.
|
|||
|
LogicalId - the logical id for ABIOS indicating what to process.
|
|||
|
Unit - the ABIOS unit number for the disk to process.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR ntNameBuffer[256];
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
HANDLE handle;
|
|||
|
STRING ntNameString;
|
|||
|
UNICODE_STRING ntUnicodeString;
|
|||
|
NTSTATUS status;
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
PDEVICE_EXTENSION deviceExtension;
|
|||
|
PDEVICE_EXTENSION physicalDevice;
|
|||
|
PDRIVE_LAYOUT_INFORMATION partitionList;
|
|||
|
USHORT partitionNumber;
|
|||
|
PCONTROLLER_EXTENSION controllerExtension =
|
|||
|
ControllerObject->ControllerExtension;
|
|||
|
PABIOS_REQUEST_BLOCK requestBlock = controllerExtension->RequestBlock;
|
|||
|
PULONG diskCount = &ConfigurationInformation->DiskCount;
|
|||
|
PABIOS_DISK_READ_DEVICE_PARMS diskParameters =
|
|||
|
(PABIOS_DISK_READ_DEVICE_PARMS)requestBlock;
|
|||
|
|
|||
|
//
|
|||
|
// Issue ABIOS Read Device Parameters.
|
|||
|
//
|
|||
|
|
|||
|
requestBlock->Length = controllerExtension->RequestBlockLength;
|
|||
|
requestBlock->LogicalId = controllerExtension->LogicalId;
|
|||
|
requestBlock->Unit = Unit;
|
|||
|
requestBlock->Function = ABIOS_FUNCTION_READ_DEVICE_PARMS;
|
|||
|
|
|||
|
status = KeI386AbiosCall(controllerExtension->LogicalId,
|
|||
|
DriverObject,
|
|||
|
controllerExtension->Selector,
|
|||
|
ABIOS_START_ROUTINE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((1,"AbiosProcessDisk: Can't read device parameters\n"));
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check to see it the disk device is a SCSI.
|
|||
|
//
|
|||
|
|
|||
|
if (diskParameters->DeviceControlFlags & DISK_READ_PARMS_SCSI_DEVICE) {
|
|||
|
|
|||
|
DebugPrint((2, "AbiosProcessDisk: This is a SCSI device\n"));
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if this device supports SCBs.
|
|||
|
//
|
|||
|
|
|||
|
if (diskParameters->DeviceControlFlags & DISK_READ_PARMS_SUPPORTS_SCB) {
|
|||
|
DebugPrint((2, "AbiosProcessDisk: This device supports SCBs\n"));
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
if (diskParameters->DeviceControlFlags & DISK_READ_PARMS_ST506) {
|
|||
|
DebugPrint((2,
|
|||
|
"AbiosProcessDisk: This device supports the ST506 interface\n"));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up an object directory to contain the objects for this
|
|||
|
// device and all its partitions.
|
|||
|
//
|
|||
|
|
|||
|
sprintf(ntNameBuffer,
|
|||
|
"\\Device\\Harddisk%d",
|
|||
|
*diskCount);
|
|||
|
RtlInitString(&ntNameString,
|
|||
|
ntNameBuffer);
|
|||
|
(VOID)RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
|||
|
&ntNameString,
|
|||
|
TRUE);
|
|||
|
InitializeObjectAttributes(&objectAttributes,
|
|||
|
&ntUnicodeString,
|
|||
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
status = ZwCreateDirectoryObject(&handle,
|
|||
|
DIRECTORY_ALL_ACCESS,
|
|||
|
&objectAttributes);
|
|||
|
|
|||
|
RtlFreeUnicodeString(&ntUnicodeString);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((1,"Could not create directory %s\n",
|
|||
|
ntNameBuffer));
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Create device object for this device. Each device will
|
|||
|
// have at least one device object. The required device object
|
|||
|
// describes the entire device. Its directory path is
|
|||
|
// \Device\HarddiskN/Partition0, where N = device number.
|
|||
|
//
|
|||
|
|
|||
|
sprintf(ntNameBuffer,
|
|||
|
"\\Device\\Harddisk%d\\Partition0",
|
|||
|
*diskCount);
|
|||
|
RtlInitString(&ntNameString,
|
|||
|
ntNameBuffer);
|
|||
|
status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
|||
|
&ntNameString,
|
|||
|
TRUE);
|
|||
|
ASSERT(NT_SUCCESS(status));
|
|||
|
|
|||
|
//
|
|||
|
// Create physical device object.
|
|||
|
//
|
|||
|
|
|||
|
status = IoCreateDevice(DriverObject,
|
|||
|
DEVICE_EXTENSION_SIZE,
|
|||
|
&ntUnicodeString,
|
|||
|
FILE_DEVICE_DISK,
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
&deviceObject);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugPrint((1,"CreateDeviceObjects: Can not create device %s\n",
|
|||
|
ntNameBuffer));
|
|||
|
|
|||
|
//
|
|||
|
// Delete directory by making it tempory and closing the
|
|||
|
// only reference to the directory and return.
|
|||
|
//
|
|||
|
|
|||
|
ZwMakeTemporaryObject(handle);
|
|||
|
ZwClose(handle);
|
|||
|
RtlFreeUnicodeString(&ntUnicodeString);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// A device object was created. Close the handle to the directory.
|
|||
|
//
|
|||
|
|
|||
|
ZwClose(handle);
|
|||
|
|
|||
|
RtlFreeUnicodeString(&ntUnicodeString);
|
|||
|
|
|||
|
//
|
|||
|
// initialize the new deviceObject.
|
|||
|
//
|
|||
|
|
|||
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|||
|
deviceObject->AlignmentRequirement = BYTES_PER_SECTOR - 1;
|
|||
|
deviceObject->StackSize = 1;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the device extension
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension = deviceObject->DeviceExtension;
|
|||
|
deviceExtension->DeviceObject = deviceObject;
|
|||
|
deviceExtension = deviceObject->DeviceExtension;
|
|||
|
deviceExtension->ControllerExtension = controllerExtension;
|
|||
|
deviceExtension->Unit = Unit;
|
|||
|
deviceExtension->DiskNumber = *diskCount;
|
|||
|
deviceExtension->NextPartition = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Physical device object will describe the entire
|
|||
|
// device, starting at byte offset 0.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension->StartingOffset.QuadPart = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Copy results of ABIOS Read Device Parameter call.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(diskParameters->SectorSize == 2);
|
|||
|
|
|||
|
//
|
|||
|
// ABIOS only handles sectors sizes of 512.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension->DiskGeometry.BytesPerSector = BYTES_PER_SECTOR;
|
|||
|
|
|||
|
ASSERT(diskParameters->SectorSize == 2);
|
|||
|
|
|||
|
deviceExtension->DiskGeometry.SectorsPerTrack =
|
|||
|
diskParameters->SectorsPerTrack;
|
|||
|
deviceExtension->DiskGeometry.MediaType = FixedMedia;
|
|||
|
|
|||
|
deviceExtension->SectorShift = SECTOR_SHIFT;
|
|||
|
deviceExtension->SectorsInPage = PAGE_SIZE >> SECTOR_SHIFT;
|
|||
|
deviceExtension->DiskGeometry.TracksPerCylinder =
|
|||
|
diskParameters->NumberHeads;
|
|||
|
deviceExtension->DiskGeometry.Cylinders.QuadPart =
|
|||
|
diskParameters->NumberCylinders;
|
|||
|
|
|||
|
if (diskParameters->SoftwareRetryCount <= 1) {
|
|||
|
|
|||
|
//
|
|||
|
// Don't accept a single retry. This code will retry up to 2 times
|
|||
|
// without a reset, then attempt a reset/retry.
|
|||
|
//
|
|||
|
deviceExtension->SoftwareRetries = 3;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This could be less than the default or much greater.
|
|||
|
// Accept what the controller suggests.
|
|||
|
//
|
|||
|
deviceExtension->SoftwareRetries = diskParameters->SoftwareRetryCount;
|
|||
|
}
|
|||
|
deviceExtension->MaximumNumberBlocks = diskParameters->MaximumNumberBlocks;
|
|||
|
|
|||
|
//
|
|||
|
// Limit the number of map registers to the maximum number of blocks so
|
|||
|
// that extra mapped registers are never allocated.
|
|||
|
//
|
|||
|
|
|||
|
if ((ULONG)(deviceExtension->MaximumNumberBlocks / deviceExtension->SectorsInPage) <
|
|||
|
controllerExtension->MaximumNumberOfPages) {
|
|||
|
|
|||
|
controllerExtension->MaximumNumberOfPages = 1 +
|
|||
|
deviceExtension->MaximumNumberBlocks / deviceExtension->SectorsInPage;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Calculate size of physical disk. This is set to the maximum
|
|||
|
// signed long value to encompass all disks.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension->PartitionLength.LowPart = (ULONG) -1;
|
|||
|
deviceExtension->PartitionLength.HighPart = 0x7fffffff;
|
|||
|
|
|||
|
//
|
|||
|
// Set physical device pointer to this device extension.
|
|||
|
//
|
|||
|
|
|||
|
physicalDevice = deviceExtension->PhysicalDevice = deviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Create objects for all the partitions on the device.
|
|||
|
//
|
|||
|
|
|||
|
status = IoReadPartitionTable(deviceObject,
|
|||
|
deviceExtension->DiskGeometry.BytesPerSector,
|
|||
|
TRUE,
|
|||
|
(PVOID)&partitionList);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugPrint((2,
|
|||
|
"AbiosProcessDisk: Number of partitions is %d\n",
|
|||
|
partitionList->PartitionCount));
|
|||
|
|
|||
|
//
|
|||
|
// Create device objects for the device partitions (if any).
|
|||
|
// PartitionCount includes physical device partition 0,
|
|||
|
// so only one partition means no objects to create.
|
|||
|
//
|
|||
|
|
|||
|
for (partitionNumber = 0; partitionNumber <
|
|||
|
partitionList->PartitionCount; partitionNumber++) {
|
|||
|
|
|||
|
//
|
|||
|
// Create partition object and set up partition parameters.
|
|||
|
//
|
|||
|
|
|||
|
sprintf(ntNameBuffer,
|
|||
|
"\\Device\\Harddisk%d\\Partition%d",
|
|||
|
*diskCount,
|
|||
|
partitionNumber + 1);
|
|||
|
RtlInitString(&ntNameString,
|
|||
|
ntNameBuffer);
|
|||
|
status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
|||
|
&ntNameString,
|
|||
|
TRUE);
|
|||
|
ASSERT(NT_SUCCESS(status));
|
|||
|
|
|||
|
status = IoCreateDevice(DriverObject,
|
|||
|
DEVICE_EXTENSION_SIZE,
|
|||
|
&ntUnicodeString,
|
|||
|
FILE_DEVICE_DISK,
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
&deviceObject);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"CreateDeviceObjects: Can't create device object for %s, %x\n",
|
|||
|
ntNameBuffer,
|
|||
|
status));
|
|||
|
RtlFreeUnicodeString(&ntUnicodeString);
|
|||
|
return status;
|
|||
|
|
|||
|
} else {
|
|||
|
DebugPrint((2,
|
|||
|
"AbiosProcessDisk: created device object for %s\n",
|
|||
|
ntNameBuffer));
|
|||
|
}
|
|||
|
|
|||
|
RtlFreeUnicodeString(&ntUnicodeString);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize device object.
|
|||
|
//
|
|||
|
|
|||
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|||
|
deviceObject->AlignmentRequirement = BYTES_PER_SECTOR - 1;
|
|||
|
deviceObject->StackSize = 1;
|
|||
|
|
|||
|
//
|
|||
|
// Link partition extensions to support dynamic partitioning.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension->NextPartition = deviceObject->DeviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// initialize device extension.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension = deviceObject->DeviceExtension;
|
|||
|
deviceExtension->PhysicalDevice = physicalDevice;
|
|||
|
deviceExtension->ControllerExtension = controllerExtension;
|
|||
|
deviceExtension->PartitionNumber = partitionNumber + 1;
|
|||
|
deviceExtension->PartitionType =
|
|||
|
partitionList->PartitionEntry[partitionNumber].PartitionType;
|
|||
|
deviceExtension->BootIndicator =
|
|||
|
partitionList->PartitionEntry[partitionNumber].BootIndicator;
|
|||
|
deviceExtension->StartingOffset =
|
|||
|
partitionList->PartitionEntry[partitionNumber].StartingOffset;
|
|||
|
deviceExtension->PartitionLength =
|
|||
|
partitionList->PartitionEntry[partitionNumber].PartitionLength;
|
|||
|
deviceExtension->HiddenSectors =
|
|||
|
partitionList->PartitionEntry[partitionNumber].HiddenSectors;
|
|||
|
deviceExtension->DiskGeometry.BytesPerSector = BYTES_PER_SECTOR;
|
|||
|
deviceExtension->DiskGeometry.MediaType = FixedMedia;
|
|||
|
deviceExtension->SectorShift = SECTOR_SHIFT;
|
|||
|
deviceExtension->DiskNumber = *diskCount;
|
|||
|
deviceExtension->NextPartition = NULL;
|
|||
|
|
|||
|
deviceExtension->DeviceObject = deviceObject;
|
|||
|
|
|||
|
} // end for partitionNumber ...
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugPrint((1,"CreateDeviceObjects: IoReadPartitionTable failed\n"));
|
|||
|
|
|||
|
} // end if...else
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
} // end AbiosProcessDisk()
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosDiskCreate(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine serves create commands. It does no more than
|
|||
|
establish the drivers existance by returning status success.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - representing the device being opened.
|
|||
|
IRP - the open/create request IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
DebugPrint((3,"AbiosDiskCreate: Enter routine\n"));
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|||
|
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // end AbiosDiskCreate()
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosDiskReadWrite(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the driver entry point for read and write requests
|
|||
|
to ABIOS disks. IRP parameters are verified and relative
|
|||
|
block address is calculated for request to be queued. If
|
|||
|
queue is empty, request is started via a call to AbiosDiskStartIo.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - representing the device being referenced.
|
|||
|
IRP - the read/write request IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
ULONG transferByteCount = irpStack->Parameters.Read.Length;
|
|||
|
LARGE_INTEGER startingOffset = irpStack->Parameters.Read.ByteOffset;
|
|||
|
ULONG sectorOffset;
|
|||
|
|
|||
|
//
|
|||
|
// Verify parameters of this request.
|
|||
|
// Check that ending sector is within partition and
|
|||
|
// that number of bytes to transfer is a multiple of
|
|||
|
// the sector size.
|
|||
|
//
|
|||
|
|
|||
|
if (((deviceExtension->PartitionLength.QuadPart - startingOffset.QuadPart) <
|
|||
|
transferByteCount) ||
|
|||
|
(transferByteCount % deviceExtension->DiskGeometry.BytesPerSector)) {
|
|||
|
|
|||
|
DebugPrint((1,"AbiosDiskReadWrite: Invalid I/O parameters\n"));
|
|||
|
|
|||
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Zero out information field in status block.
|
|||
|
// Bytes transferred will be returned here.
|
|||
|
//
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Mark IRP with status pending.
|
|||
|
//
|
|||
|
|
|||
|
IoMarkIrpPending(Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Add partition byte offset to make start byte relative to
|
|||
|
// beginning of disk.
|
|||
|
//
|
|||
|
|
|||
|
irpStack->Parameters.Read.ByteOffset.QuadPart = startingOffset.QuadPart +
|
|||
|
deviceExtension->StartingOffset.QuadPart;
|
|||
|
|
|||
|
//
|
|||
|
// Calculate sector offset for queue sort.
|
|||
|
//
|
|||
|
|
|||
|
sectorOffset = (ULONG) (irpStack->Parameters.Read.ByteOffset.QuadPart >>
|
|||
|
deviceExtension->SectorShift);
|
|||
|
|
|||
|
//
|
|||
|
// Queue or start IRP.
|
|||
|
//
|
|||
|
|
|||
|
IoStartPacket(deviceExtension->PhysicalDevice->DeviceObject,
|
|||
|
Irp,
|
|||
|
§orOffset,
|
|||
|
NULL);
|
|||
|
return STATUS_PENDING;
|
|||
|
} // end AbiosDiskReadWrite()
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosDiskStartIo(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Start io packet via a routine called when the controller object
|
|||
|
can be allocated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the device being referenced.
|
|||
|
Irp - represents the request to be started.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PCONTROLLER_EXTENSION controllerExtension =
|
|||
|
deviceExtension->ControllerExtension;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(Irp);
|
|||
|
|
|||
|
if (controllerExtension->DataSelector) {
|
|||
|
IoAllocateController(controllerExtension->ControllerObject,
|
|||
|
DeviceObject,
|
|||
|
(PDRIVER_CONTROL)AbiosDiskControllerPioAllocated,
|
|||
|
NULL);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate controller object.
|
|||
|
//
|
|||
|
|
|||
|
IoAllocateController(controllerExtension->ControllerObject,
|
|||
|
DeviceObject,
|
|||
|
(PDRIVER_CONTROL)AbiosDiskControllerForDmaAllocated,
|
|||
|
NULL);
|
|||
|
|
|||
|
return;
|
|||
|
} // end AbiosDiskStartIo()
|
|||
|
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
AbiosDiskControllerForDmaAllocated(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID MapRegisterBase,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Calls IoAllocateAdapterChannel to get map registers.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the device being referenced.
|
|||
|
Irp - the i/o request.
|
|||
|
MapRegisterBase - not used.
|
|||
|
Context - not used.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PCONTROLLER_EXTENSION controllerExtension =
|
|||
|
deviceExtension->ControllerExtension;
|
|||
|
ULONG numberOfPages;
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the number of pages required by the transfer.
|
|||
|
//
|
|||
|
|
|||
|
if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
|
|||
|
|
|||
|
//
|
|||
|
// Assumed to be a VERIFY request.
|
|||
|
//
|
|||
|
|
|||
|
numberOfPages = 0;
|
|||
|
} else {
|
|||
|
|
|||
|
numberOfPages = BYTES_TO_PAGES(Irp->MdlAddress->ByteOffset +
|
|||
|
irpStack->Parameters.Read.Length);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Limit the number of pages to that allowed by the adapter object.
|
|||
|
//
|
|||
|
|
|||
|
if (controllerExtension->MaximumNumberOfPages < numberOfPages) {
|
|||
|
numberOfPages = controllerExtension->MaximumNumberOfPages;
|
|||
|
}
|
|||
|
|
|||
|
controllerExtension->NumberOfMapRegisters = numberOfPages;
|
|||
|
|
|||
|
IoAllocateAdapterChannel(controllerExtension->DmaAdapterObject,
|
|||
|
DeviceObject,
|
|||
|
numberOfPages,
|
|||
|
AbiosDiskAdapterAllocated,
|
|||
|
NULL );
|
|||
|
//
|
|||
|
// Keep the controller object.
|
|||
|
//
|
|||
|
|
|||
|
return KeepObject;
|
|||
|
} // AbiosDiskControllerForDmaAllocated()
|
|||
|
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
AbiosDiskAdapterAllocated(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID MapRegisterBase,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Build ABIOS request block and call synchronized routine to call ABIOS.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the device being referenced.
|
|||
|
Irp - the i/o request.
|
|||
|
MapRegisterBase - the used for IoMapTransfer
|
|||
|
Context - unused.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PCONTROLLER_EXTENSION controllerExtension =
|
|||
|
deviceExtension->ControllerExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Debug: check if controller object really free.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(!controllerExtension->IrpAddress);
|
|||
|
|
|||
|
//
|
|||
|
// Move IRP address and device object to controller extension.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->IrpAddress = Irp;
|
|||
|
controllerExtension->DeviceObject = DeviceObject;
|
|||
|
controllerExtension->MapRegisterBase = MapRegisterBase;
|
|||
|
|
|||
|
//
|
|||
|
// Calculate first sector and count. Partition byte offset already
|
|||
|
// added in to first sector.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->StartingSector = (ULONG)
|
|||
|
(irpStack->Parameters.Read.ByteOffset.QuadPart >>
|
|||
|
deviceExtension->SectorShift);
|
|||
|
controllerExtension->RemainingSectors = controllerExtension->TotalSectors =
|
|||
|
irpStack->Parameters.Read.Length >>
|
|||
|
deviceExtension->SectorShift;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize transferred value and retries.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->BytesTransferred = 0;
|
|||
|
controllerExtension->RetryCount = deviceExtension->SoftwareRetries;
|
|||
|
|
|||
|
if (irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
|
|||
|
|
|||
|
//
|
|||
|
// Determine virtual memory address for this transfer.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->VirtualAddress =
|
|||
|
MmGetMdlVirtualAddress(Irp->MdlAddress);
|
|||
|
} else {
|
|||
|
controllerExtension->VirtualAddress = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build ABIOS request block.
|
|||
|
//
|
|||
|
|
|||
|
AbiosBuildRequest(deviceExtension, Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Start timing request.
|
|||
|
//
|
|||
|
|
|||
|
KeSetTimer(&controllerExtension->Timer,
|
|||
|
controllerExtension->TimeoutValue,
|
|||
|
&controllerExtension->TimerDpc);
|
|||
|
|
|||
|
//
|
|||
|
// Call synchronized routine to submit request block.
|
|||
|
//
|
|||
|
|
|||
|
KeSynchronizeExecution(
|
|||
|
deviceExtension->ControllerExtension->InterruptObject,
|
|||
|
AbiosDiskSynchronizedIoStart,
|
|||
|
DeviceObject);
|
|||
|
|
|||
|
//
|
|||
|
// Free the DMA adapter object but keep the map registers.
|
|||
|
//
|
|||
|
|
|||
|
return DeallocateObjectKeepRegisters;
|
|||
|
} // end AbiosDiskAdapterAllocated()
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
AbiosDiskControllerPioAllocated(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID MapRegisterBase,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Build ABIOS request block and call synchronized routine to call ABIOS.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the device being referenced.
|
|||
|
Irp - the i/o request.
|
|||
|
MapRegisterBase - the used for IoMapTransfer
|
|||
|
Context - unused.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
IO_ALLOCATION_ACTION
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PCONTROLLER_EXTENSION controllerExtension =
|
|||
|
deviceExtension->ControllerExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Move IRP address and device object to controller extension.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->IrpAddress = Irp;
|
|||
|
controllerExtension->DeviceObject = DeviceObject;
|
|||
|
controllerExtension->MapRegisterBase = MapRegisterBase;
|
|||
|
|
|||
|
//
|
|||
|
// Calculate first sector and count. Partition byte offset already
|
|||
|
// added in to first sector.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->StartingSector = (ULONG)
|
|||
|
(irpStack->Parameters.Read.ByteOffset.QuadPart >>
|
|||
|
deviceExtension->SectorShift);
|
|||
|
controllerExtension->RemainingSectors = controllerExtension->TotalSectors =
|
|||
|
irpStack->Parameters.Read.Length >>
|
|||
|
deviceExtension->SectorShift;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize transferred value and retries.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->BytesTransferred = 0;
|
|||
|
controllerExtension->RetryCount = deviceExtension->SoftwareRetries;
|
|||
|
|
|||
|
if (irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
|
|||
|
|
|||
|
//
|
|||
|
// Determine virtual memory address for this transfer and set up
|
|||
|
// the system address for the PIO.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->VirtualAddress =
|
|||
|
MmGetMdlVirtualAddress(Irp->MdlAddress);
|
|||
|
controllerExtension->SystemAddress =
|
|||
|
MmGetSystemAddressForMdl(Irp->MdlAddress);
|
|||
|
} else {
|
|||
|
controllerExtension->VirtualAddress = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build ABIOS request block.
|
|||
|
//
|
|||
|
|
|||
|
AbiosBuildRequest(deviceExtension, Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Start timing request.
|
|||
|
//
|
|||
|
|
|||
|
KeSetTimer(&controllerExtension->Timer,
|
|||
|
controllerExtension->TimeoutValue,
|
|||
|
&controllerExtension->TimerDpc);
|
|||
|
|
|||
|
//
|
|||
|
// Call synchronized routine to submit request block.
|
|||
|
//
|
|||
|
|
|||
|
KeSynchronizeExecution(
|
|||
|
deviceExtension->ControllerExtension->InterruptObject,
|
|||
|
AbiosDiskSynchronizedIoStart,
|
|||
|
DeviceObject);
|
|||
|
return KeepObject;
|
|||
|
} // AbiosDiskControllerPioAllocated()
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosBuildRequest(
|
|||
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Build ABIOS request block for read, write or verify. The request block is
|
|||
|
located via the controller extension in the device extension.
|
|||
|
In the case of verify, the parameters for the offset and length of the
|
|||
|
verify have been stored in a "Read" parameter block of the Irp stack.
|
|||
|
Note: Read and Write parameter blocks are identical.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceExtension - The device for the read or write.
|
|||
|
Irp - The IRP containing the VERIFY request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCONTROLLER_EXTENSION controllerExtension =
|
|||
|
DeviceExtension->ControllerExtension;
|
|||
|
PABIOS_REQUEST_BLOCK requestBlock = controllerExtension->RequestBlock;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
ULONG length;
|
|||
|
|
|||
|
//
|
|||
|
// Determine if sectors requested are greater than maximum
|
|||
|
// sector count for a single ABIOS request.
|
|||
|
//
|
|||
|
|
|||
|
if (controllerExtension->RemainingSectors >
|
|||
|
DeviceExtension->MaximumNumberBlocks) {
|
|||
|
|
|||
|
//
|
|||
|
// Set up sector count to maximum number of
|
|||
|
// sectors that can be transferred.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->TransferSectors =
|
|||
|
DeviceExtension->MaximumNumberBlocks;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
controllerExtension->TransferSectors =
|
|||
|
controllerExtension->RemainingSectors;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Zero out request block.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(requestBlock, controllerExtension->RequestBlockLength);
|
|||
|
|
|||
|
|
|||
|
if (irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
|
|||
|
|
|||
|
//
|
|||
|
// Determine ABIOS command.
|
|||
|
//
|
|||
|
|
|||
|
if (irpStack->MajorFunction == IRP_MJ_READ) {
|
|||
|
requestBlock->Function = ABIOS_FUNCTION_READ;
|
|||
|
} else {
|
|||
|
requestBlock->Function = ABIOS_FUNCTION_WRITE;
|
|||
|
}
|
|||
|
|
|||
|
if (controllerExtension->DataSelector) {
|
|||
|
|
|||
|
//
|
|||
|
// Limit the transfer to 64K
|
|||
|
//
|
|||
|
|
|||
|
if (controllerExtension->TransferSectors > ((64 * 1024) / BYTES_PER_SECTOR)) {
|
|||
|
controllerExtension->TransferSectors = ((64 * 1024) / BYTES_PER_SECTOR);
|
|||
|
length = (64 * 1024) >> DeviceExtension->SectorShift;
|
|||
|
} else {
|
|||
|
length = controllerExtension->TransferSectors >>
|
|||
|
DeviceExtension->SectorShift;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up the data selector to frame the data buffer.
|
|||
|
//
|
|||
|
|
|||
|
KeI386FlatToGdtSelector((ULONG)controllerExtension->SystemAddress,
|
|||
|
(USHORT)(64 * 1024),
|
|||
|
controllerExtension->DataSelector);
|
|||
|
requestBlock->DataSelector = controllerExtension->DataSelector;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Limit the request to the number of map registers available.
|
|||
|
//
|
|||
|
|
|||
|
length = controllerExtension->MaximumNumberOfPages << PAGE_SHIFT;
|
|||
|
length -= (ULONG) controllerExtension->VirtualAddress & (PAGE_SIZE - 1);
|
|||
|
|
|||
|
//
|
|||
|
// Truncate to sectors.
|
|||
|
//
|
|||
|
|
|||
|
length = length >> DeviceExtension->SectorShift;
|
|||
|
|
|||
|
//
|
|||
|
// Shorten the transfer if necessary.
|
|||
|
//
|
|||
|
|
|||
|
if (length < controllerExtension->TransferSectors ) {
|
|||
|
controllerExtension->TransferSectors = length;
|
|||
|
} else {
|
|||
|
length = controllerExtension->TransferSectors;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert length from sectors to bytes.
|
|||
|
//
|
|||
|
|
|||
|
length <<= DeviceExtension->SectorShift;
|
|||
|
|
|||
|
//
|
|||
|
// Map the transfer for the adapter.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->PhysicalAddress =
|
|||
|
IoMapTransfer(controllerExtension->DmaAdapterObject,
|
|||
|
Irp->MdlAddress,
|
|||
|
controllerExtension->MapRegisterBase,
|
|||
|
controllerExtension->VirtualAddress,
|
|||
|
&length,
|
|||
|
(BOOLEAN)
|
|||
|
(irpStack->MajorFunction == IRP_MJ_READ ? FALSE : TRUE)
|
|||
|
).LowPart;
|
|||
|
}
|
|||
|
} else {
|
|||
|
requestBlock->Function = ABIOS_FUNCTION_VERIFY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Construct the request block.
|
|||
|
//
|
|||
|
|
|||
|
requestBlock->PhysicalAddress = controllerExtension->PhysicalAddress;
|
|||
|
requestBlock->Length = controllerExtension->RequestBlockLength;
|
|||
|
requestBlock->LogicalId = controllerExtension->LogicalId;
|
|||
|
requestBlock->Unit = DeviceExtension->Unit;
|
|||
|
requestBlock->BlockCount = (USHORT) controllerExtension->TransferSectors;
|
|||
|
requestBlock->RelativeBlockAddress = controllerExtension->StartingSector;
|
|||
|
requestBlock->CachingByte = 0;
|
|||
|
|
|||
|
DebugPrint((4,
|
|||
|
"AbiosBuildRequest: %s sector %d to 0x%x for %d\n",
|
|||
|
(requestBlock->Function == ABIOS_FUNCTION_READ) ?
|
|||
|
"Read" : "Write",
|
|||
|
requestBlock->RelativeBlockAddress,
|
|||
|
requestBlock->PhysicalAddress,
|
|||
|
requestBlock->BlockCount));
|
|||
|
} // end AbiosBuildRequest()
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AbiosDiskSynchronizedIoStart(
|
|||
|
IN PVOID DeviceObject
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called from AbiosDiskStartIo and is synchronized
|
|||
|
with the interrupt service routine. The ABIOS request block is
|
|||
|
complete and ready to be submitted to the ABIOS.
|
|||
|
It is also called from AbiosDiskTickHandler when a request times
|
|||
|
out and AbiosDiskCompletionDpc. In these cases, it is to retry a
|
|||
|
request.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - representing the device to start.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension =
|
|||
|
((PDEVICE_OBJECT) DeviceObject)->DeviceExtension;
|
|||
|
PCONTROLLER_EXTENSION controllerExtension =
|
|||
|
deviceExtension->ControllerExtension;
|
|||
|
PABIOS_REQUEST_BLOCK requestBlock = controllerExtension->RequestBlock;
|
|||
|
PIRP irp = controllerExtension->IrpAddress;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize return code to not valid.
|
|||
|
//
|
|||
|
|
|||
|
requestBlock->ReturnCode = ABIOS_RC_NOT_VALID;
|
|||
|
|
|||
|
if (requestBlock->Function != ABIOS_FUNCTION_RESET_DEVICE) {
|
|||
|
|
|||
|
//
|
|||
|
// Save a copy of the request block for potential retries.
|
|||
|
//
|
|||
|
|
|||
|
RtlMoveMemory(controllerExtension->RetryRequestBlock,
|
|||
|
requestBlock,
|
|||
|
REQUEST_BLOCK_LENGTH);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call ABIOS to submit request block.
|
|||
|
//
|
|||
|
|
|||
|
status = KeI386AbiosCall(controllerExtension->LogicalId,
|
|||
|
controllerExtension->DriverObject,
|
|||
|
controllerExtension->Selector,
|
|||
|
ABIOS_START_ROUTINE);
|
|||
|
|
|||
|
if ((!NT_SUCCESS(status)) || (requestBlock->ReturnCode & 0x8000)) {
|
|||
|
|
|||
|
DebugPrint((1,"AbiosDiskSynchronizedIoStart: ABIOS call failed:\n"));
|
|||
|
DebugPrint((1,"\tStatus %lx; ABIOS return code %lx\n",
|
|||
|
status,
|
|||
|
requestBlock->ReturnCode));
|
|||
|
|
|||
|
//
|
|||
|
// Do not complete request. Let it time out and be completed from
|
|||
|
// the timer DPC. Can't complete request or cancel timer at raised
|
|||
|
// IRQL.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
(VOID)AbiosCheckReturnCode((PVOID)DeviceObject);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
} // end AbiosDiskSynchronizedIoStart()
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AbiosDiskInterrupt(
|
|||
|
IN PKINTERRUPT InterruptObject,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the interrupt service routine (ISR) for the ABIOS disk. It is
|
|||
|
called by the interrupt manager to handle a disk device interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
InterruptObject - not used.
|
|||
|
Context - pointer to the ControllerExtension that interrupted.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the interrupt is a device this driver services.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCONTROLLER_EXTENSION controllerExtension = Context;
|
|||
|
PABIOS_REQUEST_BLOCK requestBlock = controllerExtension->RequestBlock;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(InterruptObject);
|
|||
|
|
|||
|
//
|
|||
|
// Issue ABIOS call to verify interrupt and clear device
|
|||
|
// interrupt.
|
|||
|
//
|
|||
|
|
|||
|
status = KeI386AbiosCall(controllerExtension->LogicalId,
|
|||
|
controllerExtension->DriverObject,
|
|||
|
controllerExtension->Selector,
|
|||
|
ABIOS_INTERRUPT_ROUTINE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugPrint((1,"AbiosDiskInterrupt: Abios call failed\n"));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (!controllerExtension->DmaAdapterObject) {
|
|||
|
|
|||
|
//
|
|||
|
// Interrupt occurred during initialization.
|
|||
|
//
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return AbiosCheckReturnCode((PVOID)controllerExtension->DeviceObject);
|
|||
|
} // end AbiosDiskInterrupt()
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosDiskCompletionDpc(
|
|||
|
IN PKDPC Dpc,
|
|||
|
IN PVOID DeferredContext,
|
|||
|
IN PVOID SystemArgument1,
|
|||
|
IN PVOID SystemArgument2
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to complete processing after an interrupt.
|
|||
|
It will check the ABIOS status and determine if the request failed
|
|||
|
or needs to be restarted. On success it checks the parameters for
|
|||
|
the request to see if additional processing is required to complete
|
|||
|
the actual Irp.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Dpc - not used.
|
|||
|
DeferredContext - a pointer to the controller extension.
|
|||
|
SystemArgument1 - not used.
|
|||
|
SystemArgument2 - not used.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCONTROLLER_EXTENSION controllerExtension = DeferredContext;
|
|||
|
PDEVICE_OBJECT deviceObject = controllerExtension->DeviceObject;
|
|||
|
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
|
|||
|
PIRP irp = controllerExtension->IrpAddress;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(irp);
|
|||
|
PABIOS_REQUEST_BLOCK requestBlock = controllerExtension->RequestBlock;
|
|||
|
BOOLEAN doingDma = controllerExtension->DataSelector ? FALSE : TRUE;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(Dpc);
|
|||
|
UNREFERENCED_PARAMETER(SystemArgument1);
|
|||
|
UNREFERENCED_PARAMETER(SystemArgument2);
|
|||
|
|
|||
|
//
|
|||
|
// Cancel request timer.
|
|||
|
//
|
|||
|
|
|||
|
KeCancelTimer(&controllerExtension->Timer);
|
|||
|
|
|||
|
//
|
|||
|
// Check for resetting controller.
|
|||
|
//
|
|||
|
|
|||
|
if (controllerExtension->PerformingReset == TRUE) {
|
|||
|
controllerExtension->PerformingReset = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// This is a reset/retry. Copy the saved request back into the
|
|||
|
// request block and try again.
|
|||
|
//
|
|||
|
|
|||
|
RtlMoveMemory(requestBlock,
|
|||
|
controllerExtension->RetryRequestBlock,
|
|||
|
REQUEST_BLOCK_LENGTH);
|
|||
|
KeSetTimer(&controllerExtension->Timer,
|
|||
|
controllerExtension->TimeoutValue,
|
|||
|
&controllerExtension->TimerDpc);
|
|||
|
KeSynchronizeExecution(
|
|||
|
controllerExtension->InterruptObject,
|
|||
|
AbiosDiskSynchronizedIoStart,
|
|||
|
deviceObject);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check for failed request.
|
|||
|
//
|
|||
|
|
|||
|
if (requestBlock->ReturnCode & ABIOS_RC_UNSUCCESSFUL) {
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"AbiosDiskCompletionDpc: %s request failed - return code %lx\n"
|
|||
|
"\trequest block %lx disk block %lx ttw %d\n",
|
|||
|
(irpStack->MajorFunction == IRP_MJ_WRITE) ? "Write" : "Read",
|
|||
|
requestBlock->ReturnCode,
|
|||
|
requestBlock,
|
|||
|
requestBlock->RelativeBlockAddress,
|
|||
|
requestBlock->WaitTime));
|
|||
|
//
|
|||
|
// Check if transfer should be retried.
|
|||
|
//
|
|||
|
|
|||
|
if ((requestBlock->ReturnCode & ABIOS_RC_RETRYABLE) &&
|
|||
|
(controllerExtension->RetryCount)) {
|
|||
|
|
|||
|
controllerExtension->RetryCount--;
|
|||
|
|
|||
|
if (controllerExtension->RetryCount >= 1) {
|
|||
|
|
|||
|
//
|
|||
|
// For all retries except for the last one (where RetryCount
|
|||
|
// will be == 0), do not reset the controller.
|
|||
|
//
|
|||
|
|
|||
|
RtlMoveMemory(requestBlock,
|
|||
|
controllerExtension->RetryRequestBlock,
|
|||
|
REQUEST_BLOCK_LENGTH);
|
|||
|
KeSetTimer(&controllerExtension->Timer,
|
|||
|
controllerExtension->TimeoutValue,
|
|||
|
&controllerExtension->TimerDpc);
|
|||
|
KeSynchronizeExecution(
|
|||
|
controllerExtension->InterruptObject,
|
|||
|
AbiosDiskSynchronizedIoStart,
|
|||
|
deviceObject);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reset and retry this request.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"AbiosDiskCompletionDpc: Retries left %d request block %lx\n",
|
|||
|
controllerExtension->RetryCount,
|
|||
|
requestBlock));
|
|||
|
|
|||
|
//
|
|||
|
// Reset the device.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(requestBlock,
|
|||
|
REQUEST_BLOCK_LENGTH);
|
|||
|
requestBlock->Length = REQUEST_BLOCK_LENGTH;
|
|||
|
requestBlock->Function = ABIOS_FUNCTION_RESET_DEVICE;
|
|||
|
requestBlock->LogicalId = controllerExtension->LogicalId;
|
|||
|
requestBlock->Unit = deviceExtension->Unit;
|
|||
|
|
|||
|
controllerExtension->PerformingReset = TRUE;
|
|||
|
|
|||
|
AbiosDiskLogError(deviceExtension,
|
|||
|
requestBlock->ReturnCode,
|
|||
|
STATUS_SUCCESS,
|
|||
|
IO_ERR_NOT_READY);
|
|||
|
|
|||
|
//
|
|||
|
// Start timing request.
|
|||
|
//
|
|||
|
|
|||
|
KeSetTimer(&controllerExtension->Timer,
|
|||
|
controllerExtension->TimeoutValue,
|
|||
|
&controllerExtension->TimerDpc);
|
|||
|
|
|||
|
//
|
|||
|
// Call synchronized routine to submit request block.
|
|||
|
//
|
|||
|
|
|||
|
KeSynchronizeExecution(
|
|||
|
controllerExtension->InterruptObject,
|
|||
|
AbiosDiskSynchronizedIoStart,
|
|||
|
deviceObject);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check return code of completing request block.
|
|||
|
//
|
|||
|
|
|||
|
status = AbiosInterpretReturnCode(deviceExtension, requestBlock);
|
|||
|
|
|||
|
//
|
|||
|
// Flush the DMA adapter channel.
|
|||
|
//
|
|||
|
|
|||
|
if ((irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) && (doingDma)) {
|
|||
|
|
|||
|
IoFlushAdapterBuffers( controllerExtension->DmaAdapterObject,
|
|||
|
irp->MdlAddress,
|
|||
|
controllerExtension->MapRegisterBase,
|
|||
|
controllerExtension->VirtualAddress,
|
|||
|
0,
|
|||
|
(BOOLEAN)
|
|||
|
(irpStack->MajorFunction == IRP_MJ_READ ? FALSE : TRUE));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else if (requestBlock->Function == ABIOS_FUNCTION_RESET_DEVICE) {
|
|||
|
|
|||
|
//
|
|||
|
// Request timed out; Retries exhausted.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"AbiosDiskCompletionDpc: %s reset failed - return code %lx\n"
|
|||
|
"\trequest block %lx disk block %lx ttw %d\n",
|
|||
|
(irpStack->MajorFunction == IRP_MJ_WRITE) ? "Write" : "Read",
|
|||
|
requestBlock->ReturnCode,
|
|||
|
requestBlock,
|
|||
|
requestBlock->RelativeBlockAddress,
|
|||
|
requestBlock->WaitTime));
|
|||
|
AbiosDiskLogError(deviceExtension,
|
|||
|
2,
|
|||
|
STATUS_IO_TIMEOUT,
|
|||
|
IO_ERR_TIMEOUT);
|
|||
|
status = STATUS_IO_TIMEOUT;
|
|||
|
|
|||
|
//
|
|||
|
// Flush the DMA adapter channel.
|
|||
|
//
|
|||
|
|
|||
|
if ((irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) && (doingDma)) {
|
|||
|
|
|||
|
IoFlushAdapterBuffers(controllerExtension->DmaAdapterObject,
|
|||
|
irp->MdlAddress,
|
|||
|
controllerExtension->MapRegisterBase,
|
|||
|
controllerExtension->VirtualAddress,
|
|||
|
0,
|
|||
|
(BOOLEAN)
|
|||
|
(irpStack->MajorFunction == IRP_MJ_READ ? FALSE : TRUE));
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This code will operate for both read and write as well as
|
|||
|
// verify. When doing verify, bytesTransferred is really the
|
|||
|
// count of bytes verified.
|
|||
|
//
|
|||
|
|
|||
|
ULONG bytesTransferred = requestBlock->BlockCount * BYTES_PER_SECTOR;
|
|||
|
|
|||
|
//
|
|||
|
// Check for successful retry.
|
|||
|
//
|
|||
|
|
|||
|
if (controllerExtension->RetryCount != deviceExtension->SoftwareRetries) {
|
|||
|
DebugPrint((0,
|
|||
|
"AbiosDiskCompletionDpc: %s retry succeeded return code %lx\n"
|
|||
|
"\trequest block %lx disk block %lx ttw %d\n",
|
|||
|
(irpStack->MajorFunction == IRP_MJ_WRITE) ? "Write" : "Read",
|
|||
|
requestBlock->ReturnCode,
|
|||
|
requestBlock,
|
|||
|
requestBlock->RelativeBlockAddress,
|
|||
|
requestBlock->WaitTime));
|
|||
|
AbiosDiskLogError(deviceExtension,
|
|||
|
requestBlock->ReturnCode,
|
|||
|
STATUS_SUCCESS,
|
|||
|
IO_ERR_RETRY_SUCCEEDED);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Flush the DMA adapter channel.
|
|||
|
//
|
|||
|
|
|||
|
if ((irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) && (doingDma)) {
|
|||
|
|
|||
|
IoFlushAdapterBuffers(controllerExtension->DmaAdapterObject,
|
|||
|
irp->MdlAddress,
|
|||
|
controllerExtension->MapRegisterBase,
|
|||
|
controllerExtension->VirtualAddress,
|
|||
|
bytesTransferred,
|
|||
|
(BOOLEAN)
|
|||
|
(irpStack->MajorFunction == IRP_MJ_READ ? FALSE : TRUE));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Increment bytes transferred.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->BytesTransferred += bytesTransferred;
|
|||
|
controllerExtension->RemainingSectors -= requestBlock->BlockCount;
|
|||
|
|
|||
|
//
|
|||
|
// Check if more sectors to transfer.
|
|||
|
//
|
|||
|
|
|||
|
if (controllerExtension->RemainingSectors) {
|
|||
|
|
|||
|
DebugPrint((2,
|
|||
|
"AbiosDiskCompletionDpc: " // no comma
|
|||
|
"Blocks transferred %lx Sectors remaining %lx\n",
|
|||
|
requestBlock->BlockCount,
|
|||
|
controllerExtension->RemainingSectors));
|
|||
|
|
|||
|
//
|
|||
|
// Calculate values for the next operation.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->StartingSector +=
|
|||
|
controllerExtension->TransferSectors;
|
|||
|
|
|||
|
//
|
|||
|
// The value of the virtual address may be zero if this is a
|
|||
|
// verify request. Updating this value has no negative effects.
|
|||
|
// so it is updated even in the verify case.
|
|||
|
//
|
|||
|
|
|||
|
*((PULONG)&controllerExtension->VirtualAddress) += bytesTransferred;
|
|||
|
if (!doingDma) {
|
|||
|
*((PULONG)&controllerExtension->SystemAddress) += bytesTransferred;
|
|||
|
}
|
|||
|
controllerExtension->RetryCount = deviceExtension->SoftwareRetries;
|
|||
|
|
|||
|
//
|
|||
|
// Build ABIOS request block and submit the request
|
|||
|
//
|
|||
|
|
|||
|
AbiosBuildRequest(deviceExtension, irp);
|
|||
|
KeSynchronizeExecution(controllerExtension->InterruptObject,
|
|||
|
AbiosDiskSynchronizedIoStart,
|
|||
|
deviceObject);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the map registers.
|
|||
|
//
|
|||
|
|
|||
|
if ((irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) && (doingDma)) {
|
|||
|
|
|||
|
IoFreeMapRegisters(controllerExtension->DmaAdapterObject,
|
|||
|
controllerExtension->MapRegisterBase,
|
|||
|
controllerExtension->NumberOfMapRegisters);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update blocks transferred in IRP.
|
|||
|
//
|
|||
|
|
|||
|
irp->IoStatus.Information += controllerExtension->BytesTransferred;
|
|||
|
|
|||
|
//
|
|||
|
// Complete IRP.
|
|||
|
//
|
|||
|
|
|||
|
irp->IoStatus.Status = status;
|
|||
|
|
|||
|
if (IoIsErrorUserInduced(irp->IoStatus.Status)) {
|
|||
|
IoSetHardErrorOrVerifyDevice(irp, deviceObject);
|
|||
|
}
|
|||
|
|
|||
|
IoCompleteRequest(irp, IO_DISK_INCREMENT);
|
|||
|
|
|||
|
//
|
|||
|
// Set IRP pointer in controllerExtension to NULL and
|
|||
|
// release controller.
|
|||
|
//
|
|||
|
|
|||
|
controllerExtension->IrpAddress = NULL;
|
|||
|
IoFreeController(controllerExtension->ControllerObject);
|
|||
|
|
|||
|
//
|
|||
|
// Start next packet.
|
|||
|
//
|
|||
|
|
|||
|
IoStartNextPacket(deviceObject, FALSE);
|
|||
|
return;
|
|||
|
} // end AbiosDiskCompletionDpc()
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AbiosCheckReturnCode(
|
|||
|
IN PVOID DeviceObject
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Check ABIOS request block completion code. Based on this code this routine
|
|||
|
may stall execution or schedule a Dpc.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - pointer to the device object representing the device
|
|||
|
returning the error code.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if interrupt serviced
|
|||
|
(Not check if called from request submission routine)
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension =
|
|||
|
((PDEVICE_OBJECT) DeviceObject)->DeviceExtension;
|
|||
|
PCONTROLLER_EXTENSION controllerExtension =
|
|||
|
deviceExtension->ControllerExtension;
|
|||
|
PABIOS_REQUEST_BLOCK requestBlock = controllerExtension->RequestBlock;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Check if request block is complete.
|
|||
|
//
|
|||
|
|
|||
|
switch (requestBlock->ReturnCode) {
|
|||
|
|
|||
|
case ABIOS_RC_NOT_VALID:
|
|||
|
|
|||
|
//
|
|||
|
// Request pending. Wait for interrupt.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
|
|||
|
case ABIOS_RC_STAGE_INTERRUPT:
|
|||
|
|
|||
|
//
|
|||
|
// Do nothing else for this interrupt.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
|
|||
|
case ABIOS_RC_STAGE_TIME:
|
|||
|
|
|||
|
//
|
|||
|
// Delay and call the abios interrupt routine again.
|
|||
|
//
|
|||
|
|
|||
|
KeStallExecutionProcessor(requestBlock->WaitTime);
|
|||
|
break;
|
|||
|
|
|||
|
case ABIOS_RC_NOT_MY_INTERRUPT:
|
|||
|
|
|||
|
DebugPrint((2,"AbiosCheckReturnCode: Spurious interrupt\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Treat this interrupt as spurious.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
DebugPrint((3, "AbiosCheckReturnCode: Command complete\n"));
|
|||
|
|
|||
|
if (controllerExtension->IrpAddress) {
|
|||
|
|
|||
|
//
|
|||
|
// Queue DPC to complete or restart this request block.
|
|||
|
//
|
|||
|
|
|||
|
KeInsertQueueDpc(&controllerExtension->CompletionDpc,
|
|||
|
controllerExtension->IrpAddress,
|
|||
|
controllerExtension);
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
} // end switch()
|
|||
|
|
|||
|
status = KeI386AbiosCall(controllerExtension->LogicalId,
|
|||
|
controllerExtension->DriverObject,
|
|||
|
controllerExtension->Selector,
|
|||
|
ABIOS_INTERRUPT_ROUTINE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugPrint((1,"AbiosCheckReturnCode: Abios call failed\n"));
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
} while (TRUE);
|
|||
|
} // end AbiosCheckReturnCode()
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosInterpretReturnCode(
|
|||
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|||
|
IN PABIOS_REQUEST_BLOCK RequestBlock
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Map ABIOS return code to NT status. If an error occurred this routine
|
|||
|
will make the appropriate mapping to an error log event and call the
|
|||
|
routine to submit the error log entry. The NT status returned can
|
|||
|
be used as the IoStatus returned to the upper layer drivers.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceExtension - represents the device for the error.
|
|||
|
RequestBlock - the ABIOS request block containing the error value.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
USHORT returnClass;
|
|||
|
USHORT returnCode;
|
|||
|
NTSTATUS status;
|
|||
|
NTSTATUS ioStatus;
|
|||
|
|
|||
|
returnCode = RequestBlock->ReturnCode;
|
|||
|
returnClass = returnCode & ABIOS_RC_CLASS_MASK;
|
|||
|
|
|||
|
if (returnClass | ABIOS_RC_UNSUCCESSFUL) {
|
|||
|
|
|||
|
switch (returnClass) {
|
|||
|
case ABIOS_RC_UNSUCCESSFUL:
|
|||
|
if (returnCode == ABIOS_RC_DEVICE_IN_USE) {
|
|||
|
ioStatus = IO_ERR_NOT_READY;
|
|||
|
status = STATUS_DEVICE_BUSY;
|
|||
|
} else {
|
|||
|
ioStatus = IO_ERR_CONTROLLER_ERROR;
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
switch (returnCode & ABIOS_RC_CODE_MASK) {
|
|||
|
|
|||
|
case ABIOS_RC_RESET_FAILED:
|
|||
|
ioStatus = IO_ERR_CONTROLLER_ERROR;
|
|||
|
status = STATUS_DISK_RESET_FAILED;
|
|||
|
break;
|
|||
|
|
|||
|
case ABIOS_RC_ADDRESS_MARK_NOT_FOUND:
|
|||
|
ioStatus = IO_ERR_SEEK_ERROR;
|
|||
|
status = STATUS_DATA_ERROR;
|
|||
|
break;
|
|||
|
|
|||
|
case ABIOS_RC_BAD_SECTOR:
|
|||
|
case ABIOS_RC_BAD_TRACK:
|
|||
|
case ABIOS_RC_BAD_SECTOR_FORMAT:
|
|||
|
case ABIOS_RC_WRITE_FAULT:
|
|||
|
ioStatus = IO_ERR_BAD_BLOCK;
|
|||
|
status = STATUS_DATA_ERROR;
|
|||
|
break;
|
|||
|
|
|||
|
case ABIOS_RC_CRC_ERROR:
|
|||
|
ioStatus = IO_ERR_BAD_BLOCK;
|
|||
|
status = STATUS_CRC_ERROR;
|
|||
|
break;
|
|||
|
|
|||
|
case ABIOS_RC_BAD_CONTROLLER:
|
|||
|
ioStatus = IO_ERR_CONTROLLER_ERROR;
|
|||
|
status = STATUS_ADAPTER_HARDWARE_ERROR;
|
|||
|
break;
|
|||
|
|
|||
|
case ABIOS_RC_EQUIPMENT_CHECK:
|
|||
|
case ABIOS_RC_DEVICE_DID_NOT_RESPOND:
|
|||
|
ioStatus = IO_ERR_CONTROLLER_ERROR;
|
|||
|
status = STATUS_IO_DEVICE_ERROR;
|
|||
|
break;
|
|||
|
|
|||
|
case ABIOS_RC_DEVICE_IN_USE:
|
|||
|
ioStatus = IO_ERR_NOT_READY;
|
|||
|
status = STATUS_DEVICE_NOT_READY;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ioStatus = IO_ERR_CONTROLLER_ERROR;
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
} else {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
AbiosDiskLogError(DeviceExtension,
|
|||
|
(ULONG) returnCode,
|
|||
|
status,
|
|||
|
ioStatus);
|
|||
|
}
|
|||
|
return status;
|
|||
|
} // end AbiosInterpretReturnCode()
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosDiskTimeoutDpc(
|
|||
|
IN PKDPC Dpc,
|
|||
|
IN PVOID DeferredContext,
|
|||
|
IN PVOID SystemArgument1,
|
|||
|
IN PVOID SystemArgument2
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when the ABIOS disk request timer expires.
|
|||
|
The routine notifies ABIOS that a timeout has occurred.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Dpc - not used.
|
|||
|
DeferredContext - address of controller extension
|
|||
|
SystemArgument1 - not used.
|
|||
|
SystemArgument2 - not used.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PCONTROLLER_EXTENSION controllerExtension = DeferredContext;
|
|||
|
PIRP irp = controllerExtension->IrpAddress;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(irp);
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(Dpc);
|
|||
|
UNREFERENCED_PARAMETER(SystemArgument1);
|
|||
|
UNREFERENCED_PARAMETER(SystemArgument2);
|
|||
|
|
|||
|
DebugPrint((0,
|
|||
|
"AbiosDiskTimeoutDpc: Request (%x) to %x timed out\n",
|
|||
|
irp,
|
|||
|
controllerExtension));
|
|||
|
|
|||
|
ASSERT(controllerExtension->PerformingReset == FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Notifiy ABIOS that request timed out.
|
|||
|
//
|
|||
|
|
|||
|
status = KeI386AbiosCall(controllerExtension->LogicalId,
|
|||
|
controllerExtension->DriverObject,
|
|||
|
controllerExtension->Selector,
|
|||
|
ABIOS_TIMEOUT_ROUTINE);
|
|||
|
|
|||
|
//
|
|||
|
// Let normal return code processing handle the error condition.
|
|||
|
//
|
|||
|
|
|||
|
AbiosCheckReturnCode(controllerExtension->DeviceObject);
|
|||
|
return;
|
|||
|
} // end AbiosDiskTimeoutDpc()
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AbiosDiskDeviceControl(
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by the I/O subsystem to perform device specific
|
|||
|
control functions. Most of these functions are satisfied immediately
|
|||
|
within this routine. Others (such as VERIFY) will require additional
|
|||
|
processing.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the object for the device control.
|
|||
|
Irp - the device control request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
ULONG sectorOffset;
|
|||
|
PVERIFY_INFORMATION verifyInfo;
|
|||
|
|
|||
|
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|||
|
|
|||
|
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
|
|||
|
|
|||
|
DebugPrint((3,"AbiosDeviceIoControl: Get drive geometry\n"));
|
|||
|
|
|||
|
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
|
|||
|
&deviceExtension->DiskGeometry,
|
|||
|
sizeof(DISK_GEOMETRY));
|
|||
|
|
|||
|
Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_CHECK_VERIFY:
|
|||
|
|
|||
|
//
|
|||
|
// This driver does not handle device that
|
|||
|
// support removable media.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((3, "AbiosDeviceIoControl: Check verify\n"));
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_VERIFY:
|
|||
|
|
|||
|
//
|
|||
|
// Set up the Irp for processing.
|
|||
|
//
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
IoMarkIrpPending(Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Doctor up the Irp to put the verify information into the
|
|||
|
// stack parameter block.
|
|||
|
//
|
|||
|
|
|||
|
verifyInfo = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
irpStack->Parameters.Read.Length = verifyInfo->Length;
|
|||
|
irpStack->Parameters.Read.ByteOffset.QuadPart =
|
|||
|
verifyInfo->StartingOffset.QuadPart + deviceExtension->StartingOffset.QuadPart;
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the key and queue or start IRP.
|
|||
|
//
|
|||
|
|
|||
|
sectorOffset = (ULONG) (irpStack->Parameters.Read.ByteOffset.QuadPart >>
|
|||
|
deviceExtension->SectorShift);
|
|||
|
IoStartPacket(deviceExtension->PhysicalDevice->DeviceObject,
|
|||
|
Irp,
|
|||
|
§orOffset,
|
|||
|
NULL);
|
|||
|
return STATUS_PENDING;
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case IOCTL_DISK_GET_PARTITION_INFO:
|
|||
|
|
|||
|
//
|
|||
|
// Return the information about the partition specified by the
|
|||
|
// device object. Note that no information is ever returned about
|
|||
|
// the size or partition type of the physical disk.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((3,"AbiosDeviceIoControl: Get partition info\n"));
|
|||
|
|
|||
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|||
|
sizeof(PARTITION_INFORMATION)) {
|
|||
|
|
|||
|
DebugPrint((3, "AbiosDeviceControl: Buffer length %lx\n",
|
|||
|
irpStack->Parameters.DeviceIoControl.OutputBufferLength));
|
|||
|
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
|
|||
|
} else if ((deviceExtension->PartitionType == 0) ||
|
|||
|
(deviceExtension->PartitionNumber == 0)) {
|
|||
|
|
|||
|
DebugPrint((3, "AbiosDeviceControl: PartitionType %d\n",
|
|||
|
deviceExtension->PartitionType));
|
|||
|
|
|||
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
PPARTITION_INFORMATION outputBuffer;
|
|||
|
|
|||
|
outputBuffer =
|
|||
|
(PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|||
|
outputBuffer->PartitionType = deviceExtension->PartitionType;
|
|||
|
outputBuffer->StartingOffset = deviceExtension->StartingOffset;
|
|||
|
outputBuffer->PartitionLength= deviceExtension->PartitionLength;
|
|||
|
outputBuffer->HiddenSectors = deviceExtension->HiddenSectors;
|
|||
|
outputBuffer->PartitionNumber = deviceExtension->PartitionNumber;
|
|||
|
|
|||
|
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_SET_PARTITION_INFO:
|
|||
|
|
|||
|
DebugPrint((3,"AbiosDeviceIoControl: Set partition info\n"));
|
|||
|
|
|||
|
if (deviceExtension->PartitionNumber == 0) {
|
|||
|
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
PSET_PARTITION_INFORMATION inputBuffer =
|
|||
|
(PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
status = IoSetPartitionInformation(
|
|||
|
deviceExtension->PhysicalDevice->DeviceObject,
|
|||
|
deviceExtension->DiskGeometry.BytesPerSector,
|
|||
|
(ULONG) deviceExtension->PartitionNumber,
|
|||
|
inputBuffer->PartitionType);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
deviceExtension->PartitionType = inputBuffer->PartitionType;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_GET_DRIVE_LAYOUT:
|
|||
|
|
|||
|
//
|
|||
|
// Return the partition layout for the physical drive. Note that
|
|||
|
// the layout is returned for the actual physical drive, regardless
|
|||
|
// of which partition was specified for the request.
|
|||
|
//
|
|||
|
|
|||
|
if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|||
|
sizeof( DRIVE_LAYOUT_INFORMATION ) ) {
|
|||
|
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
PDRIVE_LAYOUT_INFORMATION partitionList;
|
|||
|
|
|||
|
status = IoReadPartitionTable(deviceExtension->DeviceObject,
|
|||
|
deviceExtension->DiskGeometry.BytesPerSector,
|
|||
|
FALSE,
|
|||
|
&partitionList);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
ULONG tempSize;
|
|||
|
|
|||
|
//
|
|||
|
// The disk layout has been returned in the partitionList
|
|||
|
// buffer. Determine its size and, if the data will fit
|
|||
|
// into the intermediary buffer, return it.
|
|||
|
//
|
|||
|
|
|||
|
tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
|
|||
|
PartitionEntry[0]);
|
|||
|
tempSize += partitionList->PartitionCount *
|
|||
|
sizeof(PARTITION_INFORMATION);
|
|||
|
|
|||
|
if (tempSize >
|
|||
|
irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
|
|||
|
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
} else {
|
|||
|
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
|
|||
|
partitionList,
|
|||
|
tempSize );
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Information = tempSize;
|
|||
|
UpdateDeviceObjects(DeviceObject,
|
|||
|
Irp);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the buffer allocated by reading the partition
|
|||
|
// table and update the partition numbers for the user.
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(partitionList);
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_SET_DRIVE_LAYOUT:
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Update the disk with new partition information.
|
|||
|
//
|
|||
|
|
|||
|
PDRIVE_LAYOUT_INFORMATION partitionList =
|
|||
|
Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Call routine to create, delete and change device objects to
|
|||
|
// reflect new disk layout.
|
|||
|
//
|
|||
|
|
|||
|
UpdateDeviceObjects(DeviceObject,
|
|||
|
Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Write new layout to disk.
|
|||
|
//
|
|||
|
|
|||
|
status = IoWritePartitionTable(
|
|||
|
deviceExtension->DeviceObject,
|
|||
|
deviceExtension->DiskGeometry.BytesPerSector,
|
|||
|
deviceExtension->DiskGeometry.SectorsPerTrack,
|
|||
|
deviceExtension->DiskGeometry.TracksPerCylinder,
|
|||
|
partitionList);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
Irp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case IOCTL_DISK_INTERNAL_SET_VERIFY:
|
|||
|
|
|||
|
//
|
|||
|
// If the caller is kernel mode, set the verify bit.
|
|||
|
//
|
|||
|
|
|||
|
if (Irp->RequestorMode == KernelMode) {
|
|||
|
DeviceObject->Flags |= DO_VERIFY_VOLUME;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
|
|||
|
|
|||
|
//
|
|||
|
// If the caller is kernel mode, clear the verify bit.
|
|||
|
//
|
|||
|
|
|||
|
if (Irp->RequestorMode == KernelMode) {
|
|||
|
DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
DebugPrint((3,
|
|||
|
"AbiosIoDeviceControl: Unsupported device IOCTL\n"));
|
|||
|
|
|||
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
} // end AbiosDiskDeviceControl()
|
|||
|
|
|||
|
|
|||
|
#if DBG
|
|||
|
VOID
|
|||
|
AbiosDebugPrint(
|
|||
|
ULONG DebugPrintLevel,
|
|||
|
PCCHAR DebugMessage,
|
|||
|
...
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Debug print for ABIOS driver
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Debug print level between 0 and 3, with 3 being the most verbose.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
va_list ap;
|
|||
|
|
|||
|
va_start( ap, DebugMessage );
|
|||
|
|
|||
|
if (DebugPrintLevel <= AbiosDebug) {
|
|||
|
|
|||
|
char buffer[128];
|
|||
|
|
|||
|
vsprintf(buffer, DebugMessage, ap);
|
|||
|
DbgPrint(buffer);
|
|||
|
}
|
|||
|
|
|||
|
va_end(ap);
|
|||
|
} // end DebugPrint(
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AbiosDiskLogError(
|
|||
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|||
|
IN ULONG UniqueErrorValue,
|
|||
|
IN NTSTATUS FinalStatus,
|
|||
|
IN NTSTATUS SpecificIoStatus
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine performs error logging for the Abios disk driver.
|
|||
|
This consists of allocating an error log packet and if this is
|
|||
|
successful, filling in the details provided as parameters.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceExtension - Extension representing failing device.
|
|||
|
UniqueErrorValue - Values defined to uniquely identify error location.
|
|||
|
FinalStatus - Status returned for failure.
|
|||
|
SpecificIoStatus - IO error status value.
|
|||
|
Irp - If there is an irp this is the pointer to it.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_ERROR_LOG_PACKET errorLogPacket;
|
|||
|
|
|||
|
errorLogPacket = IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
|
|||
|
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET)));
|
|||
|
if (errorLogPacket != NULL) {
|
|||
|
|
|||
|
errorLogPacket->SequenceNumber = AbiosDiskErrorLogSequence++;
|
|||
|
errorLogPacket->ErrorCode = SpecificIoStatus;
|
|||
|
errorLogPacket->FinalStatus = FinalStatus;
|
|||
|
errorLogPacket->UniqueErrorValue = UniqueErrorValue;
|
|||
|
errorLogPacket->DumpDataSize = 0;
|
|||
|
IoWriteErrorLogEntry(errorLogPacket);
|
|||
|
}
|
|||
|
} // end AbiosDiskLogError()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
UpdateDeviceObjects(
|
|||
|
IN PDEVICE_OBJECT PhysicalDisk,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine creates, deletes and changes device objects when
|
|||
|
the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates the
|
|||
|
partition numbers in the drive layout structure. It is possible to
|
|||
|
call this routine even on a GET_LAYOUT case because RewritePartition
|
|||
|
is set to FALSE.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Device object for physical disk.
|
|||
|
Irp - IO Request Packet (IRP).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension;
|
|||
|
PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
ULONG partition;
|
|||
|
ULONG partitionNumber;
|
|||
|
ULONG partitionCount;
|
|||
|
ULONG lastPartition;
|
|||
|
PPARTITION_INFORMATION partitionEntry;
|
|||
|
CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
|
|||
|
STRING ntNameString;
|
|||
|
UNICODE_STRING ntUnicodeString;
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
PDEVICE_EXTENSION deviceExtension;
|
|||
|
PDEVICE_EXTENSION lastExtension;
|
|||
|
NTSTATUS status;
|
|||
|
BOOLEAN found;
|
|||
|
|
|||
|
partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4;
|
|||
|
|
|||
|
//
|
|||
|
// LastExtension is used to link new partitions onto the partition
|
|||
|
// chain anchored at the physical extension. Preset this variable
|
|||
|
// to the physical extension in case no partitions exist on this disk
|
|||
|
// before this set drive layout.
|
|||
|
//
|
|||
|
|
|||
|
lastExtension = physicalExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Zero all of the partition numbers.
|
|||
|
//
|
|||
|
|
|||
|
for (partition = 0; partition < partitionCount; partition++) {
|
|||
|
partitionEntry = &partitionList->PartitionEntry[partition];
|
|||
|
partitionEntry->PartitionNumber = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Walk through chain of partitions for this disk to determine
|
|||
|
// which existing partitions have no match.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension = physicalExtension;
|
|||
|
lastPartition = 0;
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
deviceExtension = deviceExtension->NextPartition;
|
|||
|
|
|||
|
//
|
|||
|
// Check if this is the last partition in the chain.
|
|||
|
//
|
|||
|
|
|||
|
if (!deviceExtension) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check for highest partition number this far.
|
|||
|
//
|
|||
|
|
|||
|
if (deviceExtension->PartitionNumber > lastPartition) {
|
|||
|
lastPartition = deviceExtension->PartitionNumber;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if this partition is not currently being used.
|
|||
|
//
|
|||
|
|
|||
|
if (!deviceExtension->PartitionLength.QuadPart) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Loop through partition information to look for match.
|
|||
|
//
|
|||
|
|
|||
|
found = FALSE;
|
|||
|
for (partition = 0;
|
|||
|
partition < partitionCount;
|
|||
|
partition++) {
|
|||
|
|
|||
|
//
|
|||
|
// Get partition descriptor.
|
|||
|
//
|
|||
|
|
|||
|
partitionEntry = &partitionList->PartitionEntry[partition];
|
|||
|
|
|||
|
//
|
|||
|
// Check if empty, or describes extended partiton or hasn't changed.
|
|||
|
//
|
|||
|
|
|||
|
if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
|
|||
|
IsContainerPartition(partitionEntry->PartitionType)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if new partition starts where this partition starts.
|
|||
|
//
|
|||
|
|
|||
|
if (partitionEntry->StartingOffset.QuadPart != deviceExtension->StartingOffset.QuadPart) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if partition length is the same.
|
|||
|
//
|
|||
|
|
|||
|
if (partitionEntry->PartitionLength.QuadPart == deviceExtension->PartitionLength.QuadPart) {
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
|
|||
|
physicalExtension->DiskNumber,
|
|||
|
deviceExtension->PartitionNumber));
|
|||
|
|
|||
|
//
|
|||
|
// Indicate match is found and set partition number
|
|||
|
// in user buffer.
|
|||
|
//
|
|||
|
|
|||
|
found = TRUE;
|
|||
|
partitionEntry->PartitionNumber = deviceExtension->PartitionNumber;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (found) {
|
|||
|
|
|||
|
//
|
|||
|
// A match is found. If this partition is marked for update,
|
|||
|
// check for a partition type change.
|
|||
|
//
|
|||
|
|
|||
|
if (partitionEntry->RewritePartition) {
|
|||
|
deviceExtension->PartitionType = partitionEntry->PartitionType;
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// no match was found, indicate this partition is gone.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
|
|||
|
physicalExtension->DiskNumber,
|
|||
|
deviceExtension->PartitionNumber));
|
|||
|
|
|||
|
deviceExtension->PartitionLength.QuadPart = 0;
|
|||
|
}
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// Walk through partition loop to find new partitions and set up
|
|||
|
// device extensions to describe them. In some cases new device
|
|||
|
// objects will be created.
|
|||
|
//
|
|||
|
|
|||
|
for (partition = 0;
|
|||
|
partition < partitionCount;
|
|||
|
partition++) {
|
|||
|
|
|||
|
//
|
|||
|
// Get partition descriptor.
|
|||
|
//
|
|||
|
|
|||
|
partitionEntry = &partitionList->PartitionEntry[partition];
|
|||
|
|
|||
|
//
|
|||
|
// Check if empty, or describes extended partiton or hasn't changed.
|
|||
|
//
|
|||
|
|
|||
|
if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
|
|||
|
IsContainerPartition(partitionEntry->PartitionType) ||
|
|||
|
!partitionEntry->RewritePartition) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (partitionEntry->PartitionNumber) {
|
|||
|
|
|||
|
//
|
|||
|
// Partition is being rewritten, but already exists as a device object
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check first if existing device object is available by
|
|||
|
// walking partition extension list.
|
|||
|
//
|
|||
|
|
|||
|
partitionNumber = 0;
|
|||
|
deviceExtension = physicalExtension;
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Get next partition device extension from disk data.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension = deviceExtension->NextPartition;
|
|||
|
|
|||
|
if (!deviceExtension) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// A device object is free if the partition length is set to zero.
|
|||
|
//
|
|||
|
|
|||
|
if (!deviceExtension->PartitionLength.QuadPart) {
|
|||
|
partitionNumber = deviceExtension->PartitionNumber;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
lastExtension = deviceExtension;
|
|||
|
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// If partition number is still zero then a new device object
|
|||
|
// must be created.
|
|||
|
//
|
|||
|
|
|||
|
if (partitionNumber == 0) {
|
|||
|
|
|||
|
lastPartition++;
|
|||
|
partitionNumber = lastPartition;
|
|||
|
|
|||
|
//
|
|||
|
// Get or create partition object and set up partition parameters.
|
|||
|
//
|
|||
|
|
|||
|
sprintf(ntNameBuffer,
|
|||
|
"\\Device\\Harddisk%d\\Partition%d",
|
|||
|
physicalExtension->DiskNumber,
|
|||
|
partitionNumber);
|
|||
|
|
|||
|
RtlInitString(&ntNameString,
|
|||
|
ntNameBuffer);
|
|||
|
|
|||
|
status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
|||
|
&ntNameString,
|
|||
|
TRUE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"UpdateDeviceObjects: Create device object %s\n",
|
|||
|
ntNameBuffer));
|
|||
|
|
|||
|
//
|
|||
|
// This is a new name. Create the device object to represent it.
|
|||
|
//
|
|||
|
|
|||
|
status = IoCreateDevice(PhysicalDisk->DriverObject,
|
|||
|
DEVICE_EXTENSION_SIZE,
|
|||
|
&ntUnicodeString,
|
|||
|
FILE_DEVICE_DISK,
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
&deviceObject);
|
|||
|
RtlFreeUnicodeString(&ntUnicodeString);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((1,
|
|||
|
"UpdateDeviceObjects: Can't create device %s\n",
|
|||
|
ntNameBuffer));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up device object fields.
|
|||
|
//
|
|||
|
|
|||
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|||
|
deviceObject->StackSize = PhysicalDisk->StackSize;
|
|||
|
|
|||
|
//
|
|||
|
// Set up device extension fields.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension = deviceObject->DeviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Copy physical disk extension to partition extension.
|
|||
|
//
|
|||
|
|
|||
|
RtlMoveMemory(deviceExtension,
|
|||
|
physicalExtension,
|
|||
|
sizeof(DEVICE_EXTENSION));
|
|||
|
|
|||
|
//
|
|||
|
// Clear flags initializing bit.
|
|||
|
//
|
|||
|
|
|||
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|||
|
|
|||
|
//
|
|||
|
// Point back at device object.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension->DeviceObject = deviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// Link to end of partition chain using previous disk data.
|
|||
|
//
|
|||
|
|
|||
|
lastExtension->NextPartition = deviceExtension;
|
|||
|
deviceExtension->NextPartition = NULL;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
|
|||
|
physicalExtension->DiskNumber,
|
|||
|
partitionNumber));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update partition information in partition device extension.
|
|||
|
//
|
|||
|
|
|||
|
deviceExtension->PartitionNumber = (USHORT)partitionNumber;
|
|||
|
deviceExtension->PartitionType = partitionEntry->PartitionType;
|
|||
|
deviceExtension->BootIndicator = partitionEntry->BootIndicator;
|
|||
|
deviceExtension->StartingOffset = partitionEntry->StartingOffset;
|
|||
|
deviceExtension->PartitionLength = partitionEntry->PartitionLength;
|
|||
|
deviceExtension->HiddenSectors = partitionEntry->HiddenSectors;
|
|||
|
|
|||
|
//
|
|||
|
// Update partition number passed in to indicate the
|
|||
|
// device name for this partition.
|
|||
|
//
|
|||
|
|
|||
|
partitionEntry->PartitionNumber = partitionNumber;
|
|||
|
}
|
|||
|
} // end UpdateDeviceObjects()
|
|||
|
|
|||
|
#else // defined(i386)
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the main entry point for this driver. This routine exists so
|
|||
|
that this driver can be built for non-x86 platforms and still be loaded
|
|||
|
as a driver into the system, since it must be loaded by the OS loader
|
|||
|
during the initial boot phase. It simply returns a status that indicates
|
|||
|
that it did not successfully initialize, and will therefore allows the
|
|||
|
system to boot.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Supplies a pointer to the driver object that represents
|
|||
|
the loaded instantiation of this driver in memory.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The final return status is always an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Simply return an error and get out of here.
|
|||
|
//
|
|||
|
|
|||
|
return STATUS_DEVICE_DOES_NOT_EXIST;
|
|||
|
}
|
|||
|
#endif // defined(i386)
|