1145 lines
30 KiB
C
1145 lines
30 KiB
C
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spdisk.h
|
|
|
|
Abstract:
|
|
|
|
Hard disk manipulation support for text setup.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 27-Aug-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
#include <ntddscsi.h>
|
|
|
|
//
|
|
// The following will be TRUE if hard disks have been determined
|
|
// successfully (ie, if SpDetermineHardDisks was successfully called).
|
|
//
|
|
BOOLEAN HardDisksDetermined = FALSE;
|
|
|
|
//
|
|
// These two globals track the hard disks attached to the computer.
|
|
//
|
|
PHARD_DISK HardDisks;
|
|
ULONG HardDiskCount;
|
|
|
|
//
|
|
// These flags get set to TRUE if we find any disks owned
|
|
// by ATDISK or ABIOSDSK.
|
|
//
|
|
BOOLEAN AtDisksExist = FALSE;
|
|
BOOLEAN AbiosDisksExist = FALSE;
|
|
|
|
//
|
|
// Structure to track scsi ports in the system and routine to initialize
|
|
// a list of them.
|
|
//
|
|
typedef struct _MY_SCSI_PORT_INFO {
|
|
|
|
//
|
|
// Port number, redundant if these are stored in an array.
|
|
//
|
|
ULONG PortNumber;
|
|
|
|
//
|
|
// Port number relative to the the first port owned by the
|
|
// adapter that owns this port.
|
|
//
|
|
// For example, if there are 2 Future Domain controllers and an Adaptec
|
|
// controller, the RelativePortNumbers would be 0, 1, and 0.
|
|
//
|
|
ULONG RelativePortNumber;
|
|
|
|
//
|
|
// Name of owning miniport driver (ie, aha154x or fd8xx).
|
|
// NULL if unknown.
|
|
//
|
|
PWSTR MiniportName;
|
|
|
|
} MY_SCSI_PORT_INFO, *PMY_SCSI_PORT_INFO;
|
|
|
|
|
|
//
|
|
// Disk format type strings
|
|
//
|
|
// TBD : Use the localized strings
|
|
//
|
|
WCHAR *DiskTags[] = { DISK_TAG_TYPE_UNKNOWN,
|
|
DISK_TAG_TYPE_PCAT,
|
|
DISK_TAG_TYPE_NEC98,
|
|
DISK_TAG_TYPE_GPT,
|
|
DISK_TAG_TYPE_RAW };
|
|
|
|
VOID
|
|
SpInitializeScsiPortList(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Count of scsi ports in the system.
|
|
//
|
|
ULONG ScsiPortCount;
|
|
PMY_SCSI_PORT_INFO ScsiPortInfo;
|
|
|
|
//
|
|
// Key in registry of device map
|
|
//
|
|
PCWSTR szRegDeviceMap = L"\\Registry\\Machine\\Hardware\\DeviceMap";
|
|
|
|
|
|
PWSTR
|
|
SpDetermineOwningDriver(
|
|
IN HANDLE Handle
|
|
);
|
|
|
|
VOID
|
|
SpGetDiskInfo(
|
|
IN ULONG DiskNumber,
|
|
IN PVOID SifHandle,
|
|
IN PWSTR OwningDriverName,
|
|
IN HANDLE Handle,
|
|
OUT PHARD_DISK Descriptor
|
|
);
|
|
|
|
BOOLEAN
|
|
SpGetScsiAddress(
|
|
IN HANDLE Handle,
|
|
OUT PSCSI_ADDRESS ScsiAddress,
|
|
OUT PWSTR *ScsiAdapterName
|
|
);
|
|
|
|
NTSTATUS
|
|
SpDetermineInt13Hookers(
|
|
IN HANDLE DiskHandle,
|
|
IN OUT PHARD_DISK Disk
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (DiskHandle && Disk) {
|
|
PVOID UnalignedBuffer = SpMemAlloc(Disk->Geometry.BytesPerSector * 2);
|
|
|
|
if (UnalignedBuffer) {
|
|
PON_DISK_MBR Mbr = ALIGN(UnalignedBuffer, Disk->Geometry.BytesPerSector);
|
|
|
|
Disk->Int13Hooker = NoHooker;
|
|
|
|
Status = SpReadWriteDiskSectors(DiskHandle,
|
|
0,
|
|
1,
|
|
Disk->Geometry.BytesPerSector,
|
|
(PVOID)Mbr,
|
|
FALSE);
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
switch (Mbr->PartitionTable[0].SystemId) {
|
|
case 0x54:
|
|
Disk->Int13Hooker = HookerOnTrackDiskManager;
|
|
break;
|
|
|
|
case 0x55:
|
|
Disk->Int13Hooker = HookerEZDrive;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
SpMemFree(UnalignedBuffer);
|
|
} else {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpDetermineHardDisks(
|
|
IN PVOID SifHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the hard disks attached to the computer and
|
|
the state they are in (ie, on-line, off-line, removed, etc).
|
|
|
|
Arguments:
|
|
|
|
SifHandle - handle to main setup information file.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - operation successful.
|
|
|
|
The global variables HardDisks and
|
|
HardDiskCount are filled in if STATUS_SUCCESS.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONFIGURATION_INFORMATION ConfigInfo;
|
|
ULONG disk;
|
|
PWSTR OwningDriverName;
|
|
ULONG remainder;
|
|
LARGE_INTEGER temp;
|
|
PARTITION_INFORMATION PartitionInfo;
|
|
|
|
CLEAR_CLIENT_SCREEN();
|
|
SpDisplayStatusText(SP_STAT_EXAMINING_DISK_CONFIG,DEFAULT_STATUS_ATTRIBUTE);
|
|
|
|
//
|
|
// Determine the number of hard disks attached to the system
|
|
// and allocate space for an array of Disk Descriptors.
|
|
//
|
|
ConfigInfo = IoGetConfigurationInformation();
|
|
HardDiskCount = ConfigInfo->DiskCount;
|
|
|
|
if ( HardDiskCount != 0 ) {
|
|
HardDisks = SpMemAlloc(HardDiskCount * sizeof(HARD_DISK));
|
|
RtlZeroMemory(HardDisks,HardDiskCount * sizeof(HARD_DISK));
|
|
}
|
|
|
|
SpInitializeScsiPortList();
|
|
|
|
//
|
|
// For each disk, fill in its device path in the nt namespace
|
|
// and get information about the device.
|
|
//
|
|
|
|
for(disk=0; disk<HardDiskCount; disk++) {
|
|
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
HANDLE Handle;
|
|
PHARD_DISK Descriptor;
|
|
FILE_FS_DEVICE_INFORMATION DeviceInfo;
|
|
|
|
Descriptor = &HardDisks[disk];
|
|
|
|
swprintf(Descriptor->DevicePath,L"\\Device\\Harddisk%u",disk);
|
|
|
|
//
|
|
// Assume off-line.
|
|
//
|
|
Descriptor->Status = DiskOffLine;
|
|
|
|
SpFormatMessage(
|
|
Descriptor->Description,
|
|
sizeof(Descriptor->Description),
|
|
SP_TEXT_UNKNOWN_DISK_0
|
|
);
|
|
|
|
//
|
|
// Open partition0 of the disk. This should succeed even if
|
|
// there is no media in the drive.
|
|
//
|
|
Status = SpOpenPartition0(Descriptor->DevicePath,&Handle,FALSE);
|
|
if(!NT_SUCCESS(Status)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Determine device characteristics (fixed/removable).
|
|
// If this fails, assume that the disk is fixed and off-line.
|
|
//
|
|
Status = ZwQueryVolumeInformationFile(
|
|
Handle,
|
|
&IoStatusBlock,
|
|
&DeviceInfo,
|
|
sizeof(DeviceInfo),
|
|
FileFsDeviceInformation
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Save device characteristic information.
|
|
//
|
|
ASSERT(DeviceInfo.DeviceType == FILE_DEVICE_DISK);
|
|
ASSERT((DeviceInfo.Characteristics & (FILE_FLOPPY_DISKETTE | FILE_REMOTE_DEVICE)) == 0);
|
|
Descriptor->Characteristics = DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA;
|
|
|
|
} else {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: unable to determine device characteristics for %ws (%lx)\n",Descriptor->DevicePath,Status));
|
|
ZwClose(Handle);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Attempt to get geometry.
|
|
// If this fails, then assume the disk is off-line.
|
|
//
|
|
Status = ZwDeviceIoControlFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
&Descriptor->Geometry,
|
|
sizeof(DISK_GEOMETRY)
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
Descriptor->CylinderCount = Descriptor->Geometry.Cylinders.QuadPart;
|
|
|
|
//
|
|
// Calculate some additional geometry information.
|
|
//
|
|
Descriptor->SectorsPerCylinder = Descriptor->Geometry.SectorsPerTrack
|
|
* Descriptor->Geometry.TracksPerCylinder;
|
|
|
|
#if defined(_IA64_)
|
|
Status = ZwDeviceIoControlFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_DISK_GET_PARTITION_INFO,
|
|
NULL,
|
|
0,
|
|
&PartitionInfo,
|
|
sizeof(PARTITION_INFORMATION)
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
Descriptor->DiskSizeSectors = (PartitionInfo.PartitionLength.QuadPart) /
|
|
(Descriptor->Geometry.BytesPerSector);
|
|
}
|
|
else {
|
|
#endif
|
|
Descriptor->DiskSizeSectors = RtlExtendedIntegerMultiply(
|
|
Descriptor->Geometry.Cylinders,
|
|
Descriptor->SectorsPerCylinder
|
|
).LowPart;
|
|
#if defined(_IA64_)
|
|
}
|
|
#endif
|
|
if (IsNEC_98) { //NEC98
|
|
//
|
|
// Used last cylinder by T&D
|
|
//
|
|
Descriptor->DiskSizeSectors -= Descriptor->SectorsPerCylinder;
|
|
} //NEC98
|
|
|
|
Descriptor->Status = DiskOnLine;
|
|
|
|
//
|
|
// Calculate the size of the disk in MB.
|
|
//
|
|
temp.QuadPart = UInt32x32To64(
|
|
Descriptor->DiskSizeSectors,
|
|
Descriptor->Geometry.BytesPerSector
|
|
);
|
|
|
|
Descriptor->DiskSizeMB = RtlExtendedLargeIntegerDivide(temp,1024*1024,&remainder).LowPart;
|
|
if(remainder >= 512) {
|
|
Descriptor->DiskSizeMB++;
|
|
}
|
|
|
|
//
|
|
// Now that we know how big the disk is, change the default disk name.
|
|
//
|
|
SpFormatMessage(
|
|
Descriptor->Description,
|
|
sizeof(Descriptor->Description),
|
|
SP_TEXT_UNKNOWN_DISK_1,
|
|
Descriptor->DiskSizeMB
|
|
);
|
|
|
|
//
|
|
// Attempt to get the disk signature.
|
|
//
|
|
Status = ZwDeviceIoControlFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
|
NULL,
|
|
0,
|
|
TemporaryBuffer,
|
|
sizeof(TemporaryBuffer)
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx =
|
|
(PDRIVE_LAYOUT_INFORMATION_EX)TemporaryBuffer;
|
|
|
|
if (DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR)
|
|
Descriptor->Signature = (( PDRIVE_LAYOUT_INFORMATION )TemporaryBuffer)->Signature;
|
|
|
|
Descriptor->DriveLayout = *DriveLayoutEx;
|
|
|
|
switch (DriveLayoutEx->PartitionStyle) {
|
|
case PARTITION_STYLE_MBR:
|
|
Descriptor->FormatType = DISK_FORMAT_TYPE_PCAT;
|
|
|
|
//
|
|
// Determine if any INT13 hookers are present
|
|
//
|
|
SpDetermineInt13Hookers(Handle, Descriptor);
|
|
|
|
#if defined(_IA64_)
|
|
//
|
|
// Make sure that this is not a raw disk
|
|
// which is being faked as MBR disk
|
|
//
|
|
if (SpPtnIsRawDiskDriveLayout(DriveLayoutEx)) {
|
|
Descriptor->FormatType = DISK_FORMAT_TYPE_RAW;
|
|
SPPT_SET_DISK_BLANK(disk, TRUE);
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
case PARTITION_STYLE_GPT:
|
|
Descriptor->FormatType = DISK_FORMAT_TYPE_GPT;
|
|
break;
|
|
|
|
case PARTITION_STYLE_RAW:
|
|
Descriptor->FormatType = DISK_FORMAT_TYPE_RAW;
|
|
SPPT_SET_DISK_BLANK(disk, TRUE);
|
|
|
|
break;
|
|
|
|
default:
|
|
Descriptor->FormatType = DISK_FORMAT_TYPE_UNKNOWN;
|
|
break;
|
|
}
|
|
} else {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: failed to get signature for %ws (%lx)\n",Descriptor->DevicePath,Status));
|
|
Descriptor->Signature = 0;
|
|
}
|
|
|
|
} else {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: failed to get geometry for %ws (%lx)\n",Descriptor->DevicePath,Status));
|
|
ZwClose(Handle);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// NEC98: force removable media to OFFLINE.
|
|
// Because NEC98 doesnot support FLEX boot, so NT cannot boot up
|
|
// from removable media.
|
|
//
|
|
if (IsNEC_98 && (Descriptor->Characteristics & FILE_REMOVABLE_MEDIA)) {
|
|
Descriptor->Status = DiskOffLine;
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: found removable disk. force offline %ws\n", Descriptor->DevicePath));
|
|
}
|
|
|
|
//
|
|
// Now go through the device object to determine the device driver
|
|
// that owns this disk.
|
|
//
|
|
if(OwningDriverName = SpDetermineOwningDriver(Handle)) {
|
|
|
|
SpGetDiskInfo(disk,SifHandle,OwningDriverName,Handle,Descriptor);
|
|
SpMemFree(OwningDriverName);
|
|
}
|
|
|
|
ZwClose(Handle);
|
|
}
|
|
|
|
HardDisksDetermined = TRUE;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpGetDiskInfo(
|
|
IN ULONG DiskNumber,
|
|
IN PVOID SifHandle,
|
|
IN PWSTR OwningDriverName,
|
|
IN HANDLE Handle,
|
|
OUT PHARD_DISK Descriptor
|
|
)
|
|
{
|
|
PWSTR FormatString;
|
|
PWSTR ScsiAdapterName;
|
|
PWSTR PcCardInfoKey;
|
|
SCSI_ADDRESS ScsiAddress;
|
|
NTSTATUS Status;
|
|
ULONG ValLength;
|
|
PKEY_VALUE_PARTIAL_INFORMATION p;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
DISK_CONTROLLER_NUMBER ControllerInfo;
|
|
|
|
PcCardInfoKey = NULL;
|
|
|
|
//
|
|
// Look up the driver in the map in txtsetup.sif.
|
|
// Note that the driver could be one we don't recognize.
|
|
//
|
|
FormatString = SpGetSectionKeyIndex(SifHandle,SIF_DISKDRIVERMAP,OwningDriverName,0);
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Assume not SCSI and thus no scsi-style ARC name.
|
|
//
|
|
Descriptor->ArcPath[0] = 0;
|
|
Descriptor->ScsiMiniportShortname[0] = 0;
|
|
#endif
|
|
|
|
if(FormatString) {
|
|
|
|
if(_wcsicmp(OwningDriverName,L"disk")) {
|
|
|
|
//
|
|
// Non-scsi.
|
|
//
|
|
SpFormatMessageText(
|
|
Descriptor->Description,
|
|
sizeof(Descriptor->Description),
|
|
FormatString,
|
|
Descriptor->DiskSizeMB
|
|
);
|
|
|
|
if(!_wcsicmp(OwningDriverName,L"atdisk")) {
|
|
|
|
AtDisksExist = TRUE;
|
|
|
|
//
|
|
// Get controller number for atdisks.
|
|
//
|
|
Status = ZwDeviceIoControlFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_DISK_CONTROLLER_NUMBER,
|
|
NULL,
|
|
0,
|
|
&ControllerInfo,
|
|
sizeof(DISK_CONTROLLER_NUMBER)
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
swprintf(
|
|
TemporaryBuffer,
|
|
L"%ws\\AtDisk\\Controller %u",
|
|
szRegDeviceMap,
|
|
ControllerInfo.ControllerNumber
|
|
);
|
|
|
|
PcCardInfoKey = SpDupStringW(TemporaryBuffer);
|
|
|
|
} else {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to get controller number (%lx)\n",Status));
|
|
}
|
|
} else if(!IsNEC_98) {
|
|
//
|
|
// Not AT disk, might be abios disk. (NEC98 does not have ABIOS disk.)
|
|
//
|
|
if(!_wcsicmp(OwningDriverName,L"abiosdsk")) {
|
|
AbiosDisksExist = TRUE;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Scsi. Get disk address info.
|
|
//
|
|
if(SpGetScsiAddress(Handle,&ScsiAddress,&ScsiAdapterName)) {
|
|
|
|
swprintf(
|
|
TemporaryBuffer,
|
|
L"%ws\\Scsi\\Scsi Port %u",
|
|
szRegDeviceMap,
|
|
ScsiAddress.PortNumber
|
|
);
|
|
|
|
PcCardInfoKey = SpDupStringW(TemporaryBuffer);
|
|
|
|
SpFormatMessageText(
|
|
Descriptor->Description,
|
|
sizeof(Descriptor->Description),
|
|
FormatString,
|
|
Descriptor->DiskSizeMB,
|
|
ScsiAddress.Lun,
|
|
ScsiAddress.TargetId,
|
|
ScsiAddress.PathId,
|
|
ScsiAdapterName
|
|
);
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Generate "secondary" arc path.
|
|
//
|
|
|
|
_snwprintf(
|
|
Descriptor->ArcPath,
|
|
sizeof(Descriptor->ArcPath)/sizeof(WCHAR),
|
|
L"scsi(%u)disk(%u)rdisk(%u)",
|
|
ScsiPortInfo[ScsiAddress.PortNumber].RelativePortNumber,
|
|
SCSI_COMBINE_BUS_TARGET(ScsiAddress.PathId, ScsiAddress.TargetId),
|
|
ScsiAddress.Lun
|
|
);
|
|
|
|
wcsncpy(
|
|
Descriptor->ScsiMiniportShortname,
|
|
ScsiAdapterName,
|
|
(sizeof(Descriptor->ScsiMiniportShortname)/sizeof(WCHAR))-1
|
|
);
|
|
#endif
|
|
|
|
SpMemFree(ScsiAdapterName);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Some drivers, like SBP2PORT (1394), don't support
|
|
// IOCTL_SCSI_GET_ADDRESS, so just display driver name.
|
|
//
|
|
|
|
SpFormatMessage(
|
|
Descriptor->Description,
|
|
sizeof (Descriptor->Description),
|
|
SP_TEXT_UNKNOWN_DISK_2,
|
|
Descriptor->DiskSizeMB,
|
|
OwningDriverName
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Determine whether the disk is pcmcia.
|
|
//
|
|
if(PcCardInfoKey) {
|
|
|
|
Status = SpGetValueKey(
|
|
NULL,
|
|
PcCardInfoKey,
|
|
L"PCCARD",
|
|
sizeof(TemporaryBuffer),
|
|
(PCHAR)TemporaryBuffer,
|
|
&ValLength
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
p = (PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer;
|
|
|
|
if((p->Type == REG_DWORD) && (p->DataLength == sizeof(ULONG)) && *(PULONG)p->Data) {
|
|
|
|
Descriptor->PCCard = TRUE;
|
|
}
|
|
}
|
|
|
|
SpMemFree(PcCardInfoKey);
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpGetScsiAddress(
|
|
IN HANDLE Handle,
|
|
OUT PSCSI_ADDRESS ScsiAddress,
|
|
OUT PWSTR *ScsiAdapterName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get scsi address information about a device. This includes
|
|
the port, bus, id, and lun, as well as the shortname of the miniport
|
|
driver that owns the device.
|
|
|
|
Arguments:
|
|
|
|
Handle - handle to open device.
|
|
|
|
ScsiAddress - receives port, bus, id, and lun for the device described by Handle.
|
|
|
|
ScsiAdapterName - receives pointer to buffer containing shortname
|
|
for miniport driver that owns the device (ie, aha154x).
|
|
The caller must free this buffer via SpMemFree().
|
|
|
|
Return Value:
|
|
|
|
TRUE - scsi address information was determined successfully.
|
|
FALSE - error determining scsi address information.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR MiniportName = NULL;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
Status = ZwDeviceIoControlFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_SCSI_GET_ADDRESS,
|
|
NULL,
|
|
0,
|
|
ScsiAddress,
|
|
sizeof(SCSI_ADDRESS)
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to get scsi address info (%lx)\n",Status));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// We can get the miniport name from the scsi port information list
|
|
// we built earlier.
|
|
//
|
|
if(ScsiAddress->PortNumber < ScsiPortCount) {
|
|
|
|
MiniportName = ScsiPortInfo[ScsiAddress->PortNumber].MiniportName;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This should not happen.
|
|
//
|
|
ASSERT(ScsiAddress->PortNumber < ScsiPortCount);
|
|
|
|
MiniportName = TemporaryBuffer;
|
|
SpFormatMessage(MiniportName,sizeof(TemporaryBuffer),SP_TEXT_UNKNOWN);
|
|
}
|
|
|
|
*ScsiAdapterName = SpDupStringW(MiniportName);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SpDetermineOwningDriver(
|
|
IN HANDLE Handle
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_HANDLE_INFORMATION HandleInfo;
|
|
PFILE_OBJECT FileObject;
|
|
ULONG ObjectNameLength;
|
|
POBJECT_NAME_INFORMATION ObjectNameInfo;
|
|
PWSTR OwningDriverName;
|
|
|
|
//
|
|
// Get the file object for the disk device.
|
|
//
|
|
Status = ObReferenceObjectByHandle(
|
|
Handle,
|
|
0L,
|
|
*IoFileObjectType,
|
|
ExGetPreviousMode(),
|
|
&FileObject,
|
|
&HandleInfo
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpDetermineOwningDriver: unable to reference object (%lx)\n",Status));
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Follow the links to the driver object and query the name.
|
|
//
|
|
ObjectNameInfo = (POBJECT_NAME_INFORMATION)TemporaryBuffer;
|
|
|
|
Status = ObQueryNameString(
|
|
FileObject->DeviceObject->DriverObject,
|
|
ObjectNameInfo,
|
|
sizeof(TemporaryBuffer),
|
|
&ObjectNameLength
|
|
);
|
|
|
|
//
|
|
// Dereference the file object now that we've got the name.
|
|
//
|
|
ObDereferenceObject(FileObject);
|
|
|
|
//
|
|
// Check the status of the name query.
|
|
//
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpDetermineOwningDriver: unable to query name string (%lx)\n",Status));
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Pull out the name of the owning driver.
|
|
//
|
|
if(OwningDriverName = wcsrchr(ObjectNameInfo->Name.Buffer,L'\\')) {
|
|
OwningDriverName++;
|
|
} else {
|
|
OwningDriverName = ObjectNameInfo->Name.Buffer;
|
|
}
|
|
|
|
return(SpDupStringW(OwningDriverName));
|
|
}
|
|
|
|
|
|
VOID
|
|
SpInitializeScsiPortList(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG port;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
HANDLE PortHandle;
|
|
ULONG RelativeNumber;
|
|
|
|
//
|
|
// Get the number of scsi ports in the system.
|
|
//
|
|
ScsiPortCount = IoGetConfigurationInformation()->ScsiPortCount;
|
|
|
|
//
|
|
// Allocate an array to hold information about each port.
|
|
//
|
|
ScsiPortInfo = SpMemAlloc(ScsiPortCount * sizeof(MY_SCSI_PORT_INFO));
|
|
RtlZeroMemory(ScsiPortInfo,ScsiPortCount * sizeof(MY_SCSI_PORT_INFO));
|
|
|
|
//
|
|
// Iterate through the ports.
|
|
//
|
|
for(port=0; port<ScsiPortCount; port++) {
|
|
|
|
ScsiPortInfo[port].PortNumber = port;
|
|
|
|
//
|
|
// Open \device\scsiport<n> so we can determine the owning miniport.
|
|
//
|
|
swprintf(TemporaryBuffer,L"\\Device\\ScsiPort%u",port);
|
|
|
|
INIT_OBJA(&ObjectAttributes,&UnicodeString,TemporaryBuffer);
|
|
|
|
Status = ZwCreateFile(
|
|
&PortHandle,
|
|
FILE_GENERIC_READ,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
ScsiPortInfo[port].MiniportName = SpDetermineOwningDriver(PortHandle);
|
|
|
|
ZwClose(PortHandle);
|
|
|
|
} else {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to open \\device\\scsiport%u (%lx)\n",port,Status));
|
|
}
|
|
|
|
//
|
|
// Determine relative port number. If this is port 0 or the current port owner
|
|
// doesn't match the previous port owner, then the relative port number is 0.
|
|
// Otherwise the relative port number is one greater than the previous relative
|
|
// port number.
|
|
//
|
|
|
|
if(port && ScsiPortInfo[port-1].MiniportName && ScsiPortInfo[port].MiniportName
|
|
&& !_wcsicmp(ScsiPortInfo[port-1].MiniportName,ScsiPortInfo[port].MiniportName)) {
|
|
RelativeNumber++;
|
|
} else {
|
|
RelativeNumber = 0;
|
|
}
|
|
|
|
ScsiPortInfo[port].RelativePortNumber = RelativeNumber;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SpOpenPartition(
|
|
IN PWSTR DiskDevicePath,
|
|
IN ULONG PartitionNumber,
|
|
OUT HANDLE *Handle,
|
|
IN BOOLEAN NeedWriteAccess
|
|
)
|
|
{
|
|
PWSTR PartitionPath;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
//
|
|
// Form the pathname of partition.
|
|
//
|
|
PartitionPath = SpMemAlloc((wcslen(DiskDevicePath) * sizeof(WCHAR)) + sizeof(L"\\partition000"));
|
|
if(PartitionPath == NULL) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
swprintf(PartitionPath,L"%ws\\partition%u",DiskDevicePath,PartitionNumber);
|
|
|
|
//
|
|
// Attempt to open partition0.
|
|
//
|
|
INIT_OBJA(&Obja,&UnicodeString,PartitionPath);
|
|
|
|
Status = ZwCreateFile(
|
|
Handle,
|
|
FILE_GENERIC_READ | (NeedWriteAccess ? FILE_GENERIC_WRITE : 0),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ws (%lx)\n",PartitionPath,Status));
|
|
}
|
|
|
|
SpMemFree(PartitionPath);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpReadWriteDiskSectors(
|
|
IN HANDLE Handle,
|
|
IN ULONGLONG SectorNumber,
|
|
IN ULONG SectorCount,
|
|
IN ULONG BytesPerSector,
|
|
IN OUT PVOID AlignedBuffer,
|
|
IN BOOLEAN Write
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads or writes one or more disk sectors.
|
|
|
|
Arguments:
|
|
|
|
Handle - supplies handle to open partition object from which
|
|
sectors are to be read or written. The handle must be
|
|
opened for synchronous I/O.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS value indicating outcome of I/O operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
LARGE_INTEGER IoOffset;
|
|
ULONG IoSize;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Calculate the large integer byte offset of the first sector
|
|
// and the size of the I/O.
|
|
//
|
|
IoOffset.QuadPart = UInt32x32To64(SectorNumber,BytesPerSector);
|
|
IoSize = SectorCount * BytesPerSector;
|
|
|
|
//
|
|
// Perform the I/O.
|
|
//
|
|
Status = (NTSTATUS)(
|
|
|
|
Write
|
|
|
|
?
|
|
ZwWriteFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
AlignedBuffer,
|
|
IoSize,
|
|
&IoOffset,
|
|
NULL
|
|
)
|
|
:
|
|
ZwReadFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
AlignedBuffer,
|
|
IoSize,
|
|
&IoOffset,
|
|
NULL
|
|
)
|
|
);
|
|
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to %s %u sectors starting at sector %u\n",Write ? "write" : "read" ,SectorCount,SectorNumber));
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
ULONG
|
|
SpArcDevicePathToDiskNumber(
|
|
IN PWSTR ArcPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given an arc device path, determine which NT disk it represents.
|
|
|
|
Arguments:
|
|
|
|
ArcPath - supplies arc path.
|
|
|
|
Return Value:
|
|
|
|
NT disk ordinal suitable for use in generating nt device paths
|
|
of the form \device\harddiskx.
|
|
|
|
-1 if cannot be determined.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR NtPath;
|
|
ULONG DiskNumber;
|
|
ULONG PrefixLength;
|
|
|
|
//
|
|
// Assume failure.
|
|
//
|
|
DiskNumber = (ULONG)(-1);
|
|
PrefixLength = wcslen(DISK_DEVICE_NAME_BASE);
|
|
|
|
//
|
|
// Convert the path to an nt path.
|
|
//
|
|
if((NtPath = SpArcToNt(ArcPath))
|
|
&& !_wcsnicmp(NtPath,DISK_DEVICE_NAME_BASE,PrefixLength))
|
|
{
|
|
DiskNumber = (ULONG)SpStringToLong(NtPath+PrefixLength,NULL,10);
|
|
SpMemFree(NtPath);
|
|
}
|
|
|
|
return(DiskNumber);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpIsRegionBeyondCylinder1024(
|
|
IN PDISK_REGION Region
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine figures out whether a disk region contains sectors
|
|
that are on cylinders beyond cylinder 1024.
|
|
|
|
Arguments:
|
|
|
|
Region - supplies the disk region for the partition to be checked.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - Returns TRUE if the region contains a sector located in cylinder
|
|
1024 or greater. Otherwise returns FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONGLONG LastSector;
|
|
ULONGLONG LastCylinder;
|
|
|
|
if (IsNEC_98) { //NEC98
|
|
//
|
|
// NEC98 has no "1024th cylinder limit".
|
|
//
|
|
return((BOOLEAN)FALSE);
|
|
} //NEC98
|
|
|
|
if (Region->DiskNumber == 0xffffffff) {
|
|
return FALSE; // Partition is a redirected drive
|
|
}
|
|
|
|
LastSector = Region->StartSector + Region->SectorCount - 1;
|
|
LastCylinder = LastSector / HardDisks[Region->DiskNumber].SectorsPerCylinder;
|
|
|
|
return ((BOOLEAN)(LastCylinder > 1023));
|
|
|
|
}
|
|
|
|
VOID
|
|
SpAppendDiskTag(
|
|
IN PHARD_DISK Disk
|
|
)
|
|
{
|
|
if (Disk) {
|
|
PWSTR TagStart = wcsrchr(Disk->Description, DISK_TAG_START_CHAR);
|
|
|
|
if (TagStart) {
|
|
if (wcscmp(TagStart, DiskTags[0]) && wcscmp(TagStart, DiskTags[1]) &&
|
|
wcscmp(TagStart, DiskTags[2]) && wcscmp(TagStart, DiskTags[3]) &&
|
|
wcscmp(TagStart, DiskTags[4])) {
|
|
|
|
//
|
|
// not the tag we were looking for
|
|
//
|
|
TagStart = Disk->Description + wcslen(Disk->Description);
|
|
}
|
|
} else {
|
|
TagStart = Disk->Description + wcslen(Disk->Description);
|
|
*TagStart = L' ';
|
|
TagStart++;
|
|
}
|
|
|
|
wcscpy(TagStart, DiskTags[Disk->FormatType]);
|
|
}
|
|
}
|