Files
reactos/reactos/drivers/storage/disk/disk.c
T
Hervé Poussineau eeef3f67ba Support mount manager in disk.sys
svn path=/trunk/; revision=24286
2006-09-28 16:33:12 +00:00

2611 lines
76 KiB
C

/*
* ReactOS kernel
* Copyright (C) 2001, 2002, 2003, 2004 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: services/storage/disk/disk.c
* PURPOSE: disk class driver
* PROGRAMMER: Eric Kohl
*/
/* INCLUDES *****************************************************************/
#include <ntddk.h>
#include <ntdddisk.h>
#include <scsi.h>
#include <ntddscsi.h>
#include <mountdev.h>
#include <mountmgr.h>
#include <include/class2.h>
#include <stdio.h>
#define NDEBUG
#include <debug.h>
#define VERSION "0.0.1"
#define SCSI_DISK_TIMEOUT 10 /* Default timeout: 10 seconds */
#define MODE_DATA_SIZE 192
#define MAX_PATH 260
typedef struct _DISK_DATA
{
PDEVICE_EXTENSION NextPartition;
ULONG Signature;
ULONG MbrCheckSum;
ULONG HiddenSectors;
ULONG PartitionNumber;
ULONG PartitionOrdinal;
UCHAR PartitionType;
BOOLEAN BootIndicator;
BOOLEAN DriveNotReady;
} DISK_DATA, *PDISK_DATA;
BOOLEAN STDCALL
DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath,
PCLASS_INIT_DATA InitializationData,
PDEVICE_OBJECT PortDeviceObject,
ULONG PortNumber);
BOOLEAN STDCALL
DiskClassCheckDevice(IN PINQUIRYDATA InquiryData);
NTSTATUS STDCALL
DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
static VOID
DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
IN ULONG DeviceNumber);
static NTSTATUS
DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath, /* what's this used for? */
IN PDEVICE_OBJECT PortDeviceObject,
IN ULONG PortNumber,
IN ULONG DiskNumber,
IN PIO_SCSI_CAPABILITIES Capabilities,
IN PSCSI_INQUIRY_DATA InquiryData,
IN PCLASS_INIT_DATA InitializationData);
NTSTATUS STDCALL
DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS STDCALL
DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
static BOOLEAN
ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension,
IN HANDLE BusKey,
OUT PULONG DetectedDiskNumber);
static VOID
DiskClassUpdatePartitionDeviceObjects (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
static VOID
ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension);
static BOOLEAN
ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension,
OUT PULONG Checksum);
static NTSTATUS
DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject,
IN PIRP Irp);
/* FUNCTIONS ****************************************************************/
/**********************************************************************
* NAME EXPORTED
* DriverEntry
*
* DESCRIPTION
* This function initializes the driver, locates and claims
* hardware resources, and creates various NT objects needed
* to process I/O requests.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DriverObject
* System allocated Driver Object for this driver
*
* RegistryPath
* Name of registry driver service key
*
* RETURN VALUE
* Status
*/
NTSTATUS STDCALL
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
CLASS_INIT_DATA InitData;
DPRINT("Disk Class Driver %s\n",
VERSION);
DPRINT("RegistryPath '%wZ'\n",
RegistryPath);
RtlZeroMemory(&InitData,
sizeof(CLASS_INIT_DATA));
InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA);
InitData.DeviceType = FILE_DEVICE_DISK;
InitData.DeviceCharacteristics = 0;
InitData.ClassError = NULL; // DiskClassProcessError;
InitData.ClassReadWriteVerification = DiskClassCheckReadWrite;
InitData.ClassFindDeviceCallBack = DiskClassCheckDevice;
InitData.ClassFindDevices = DiskClassFindDevices;
InitData.ClassDeviceControl = DiskClassDeviceControl;
InitData.ClassShutdownFlush = DiskClassShutdownFlush;
InitData.ClassCreateClose = NULL;
InitData.ClassStartIo = NULL;
return(ScsiClassInitialize(DriverObject,
RegistryPath,
&InitData));
}
/**********************************************************************
* NAME EXPORTED
* DiskClassFindDevices
*
* DESCRIPTION
* This function searches for device that are attached to the
* given scsi port.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DriverObject
* System allocated Driver Object for this driver
*
* RegistryPath
* Name of registry driver service key
*
* InitializationData
* Pointer to the main initialization data
*
* PortDeviceObject
* Pointer to the port Device Object
*
* PortNumber
* Port number
*
* RETURN VALUE
* TRUE: At least one disk drive was found
* FALSE: No disk drive found
*/
BOOLEAN STDCALL
DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath,
PCLASS_INIT_DATA InitializationData,
PDEVICE_OBJECT PortDeviceObject,
ULONG PortNumber)
{
PCONFIGURATION_INFORMATION ConfigInfo;
PIO_SCSI_CAPABILITIES PortCapabilities;
PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
PSCSI_INQUIRY_DATA UnitInfo;
PINQUIRYDATA InquiryData;
PCHAR Buffer;
ULONG Bus;
ULONG DeviceCount;
BOOLEAN FoundDevice = FALSE;
NTSTATUS Status;
DPRINT("DiskClassFindDevices() called.\n");
/* Get port capabilities */
Status = ScsiClassGetCapabilities(PortDeviceObject,
&PortCapabilities);
if (!NT_SUCCESS(Status))
{
DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
return(FALSE);
}
DPRINT("PortCapabilities: %p\n", PortCapabilities);
DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
/* Get inquiry data */
Status = ScsiClassGetInquiryData(PortDeviceObject,
(PSCSI_ADAPTER_BUS_INFO *)&Buffer);
if (!NT_SUCCESS(Status))
{
DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status);
return(FALSE);
}
/* Check whether there are unclaimed devices */
AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
AdapterBusInfo);
if (DeviceCount == 0)
{
DPRINT("No unclaimed devices!\n");
return(FALSE);
}
DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
ConfigInfo = IoGetConfigurationInformation();
/* Search each bus of this adapter */
for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
{
DPRINT("Searching bus %lu\n", Bus);
UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
{
InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
DPRINT("Device type %u\n", InquiryData->DeviceType);
if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
(InquiryData->DeviceType == OPTICAL_DEVICE)) &&
(InquiryData->DeviceTypeQualifier == 0) &&
(UnitInfo->DeviceClaimed == FALSE))
{
DPRINT("Vendor: '%.24s'\n",
InquiryData->VendorId);
/* Create device objects for disk */
Status = DiskClassCreateDeviceObject(DriverObject,
RegistryPath,
PortDeviceObject,
PortNumber,
ConfigInfo->DiskCount,
PortCapabilities,
UnitInfo,
InitializationData);
if (NT_SUCCESS(Status))
{
ConfigInfo->DiskCount++;
FoundDevice = TRUE;
}
}
if (UnitInfo->NextInquiryDataOffset == 0)
break;
UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
}
}
ExFreePool(Buffer);
DPRINT("DiskClassFindDevices() done\n");
return(FoundDevice);
}
static VOID
DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
IN ULONG DeviceNumber)
{
DeviceExtension->MediaChangeEvent =
IoCreateSynchronizationEvent (NULL,
&DeviceExtension->MediaChangeEventHandle);
KeClearEvent (DeviceExtension->MediaChangeEvent);
}
/**********************************************************************
* NAME EXPORTED
* DiskClassCheckDevice
*
* DESCRIPTION
* This function checks the InquiryData for the correct device
* type and qualifier.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* InquiryData
* Pointer to the inquiry data for the device in question.
*
* RETURN VALUE
* TRUE: A disk device was found.
* FALSE: Otherwise.
*/
BOOLEAN STDCALL
DiskClassCheckDevice(IN PINQUIRYDATA InquiryData)
{
return((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE ||
InquiryData->DeviceType == OPTICAL_DEVICE) &&
InquiryData->DeviceTypeQualifier == 0);
}
/**********************************************************************
* NAME EXPORTED
* DiskClassCheckReadWrite
*
* DESCRIPTION
* This function checks the given IRP for correct data.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DeviceObject
* Pointer to the device.
*
* Irp
* Irp to check.
*
* RETURN VALUE
* STATUS_SUCCESS: The IRP matches the requirements of the given device.
* Others: Failure.
*/
NTSTATUS STDCALL
DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
PDISK_DATA DiskData;
PIO_STACK_LOCATION IrpStack;
LARGE_INTEGER EndingOffset;
DPRINT("DiskClassCheckReadWrite() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
DiskData = (PDISK_DATA)(DeviceExtension + 1);
if (DiskData->DriveNotReady == TRUE)
{
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
IoSetHardErrorOrVerifyDevice(Irp,
DeviceObject);
return(STATUS_INVALID_PARAMETER);
}
IrpStack = IoGetCurrentIrpStackLocation(Irp);
EndingOffset.QuadPart = IrpStack->Parameters.Read.ByteOffset.QuadPart +
IrpStack->Parameters.Read.Length;
DPRINT("Ending %I64d, and RealEnding %I64d! PartSize %I64d\n",EndingOffset.QuadPart,
DeviceExtension->PartitionLength.QuadPart,
DeviceExtension->PartitionLength.QuadPart /
DeviceExtension->DiskGeometry->BytesPerSector);
if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
(DeviceExtension->DiskGeometry->MediaType == RemovableMedia))
{
/* Assume if removable media and if Partition length is 0, Partition not built yet! */
if (DeviceExtension->PartitionLength.QuadPart == 0)
return(STATUS_SUCCESS);
}
if (EndingOffset.QuadPart > DeviceExtension->PartitionLength.QuadPart)
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return(STATUS_INVALID_PARAMETER);
}
return(STATUS_SUCCESS);
}
/**********************************************************************
* NAME INTERNAL
* DiskClassCreateDeviceObject
*
* DESCRIPTION
* Create the raw device and any partition devices on this drive
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DriverObject
* The system created driver object
* RegistryPath
* PortDeviceObject
* PortNumber
* DiskNumber
* Capabilities
* InquiryData
* InitialzationData
*
* RETURN VALUE
* STATUS_SUCCESS: Device objects for disk and partitions were created.
* Others: Failure.
*/
static NTSTATUS
DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath,
IN PDEVICE_OBJECT PortDeviceObject,
IN ULONG PortNumber,
IN ULONG DiskNumber,
IN PIO_SCSI_CAPABILITIES Capabilities,
IN PSCSI_INQUIRY_DATA InquiryData,
IN PCLASS_INIT_DATA InitializationData)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeDeviceDirName;
WCHAR NameBuffer[80];
CHAR NameBuffer2[80];
PDEVICE_OBJECT DiskDeviceObject;
PDEVICE_OBJECT PartitionDeviceObject;
PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
PDEVICE_EXTENSION PartitionDeviceExtension; /* defined in class2.h */
PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
HANDLE Handle;
PPARTITION_INFORMATION PartitionEntry;
PDISK_DATA DiskData;
ULONG PartitionNumber;
PVOID MbrBuffer;
NTSTATUS Status;
DPRINT("DiskClassCreateDeviceObject() called\n");
/* Create the harddisk device directory */
swprintf(NameBuffer,
L"\\Device\\Harddisk%lu",
DiskNumber);
RtlInitUnicodeString(&UnicodeDeviceDirName,
NameBuffer);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeDeviceDirName,
0,
NULL,
NULL);
Status = ZwCreateDirectoryObject(&Handle,
0,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not create device dir object\n");
return(Status);
}
/* Claim the disk device */
Status = ScsiClassClaimDevice(PortDeviceObject,
InquiryData,
FALSE,
&PortDeviceObject);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not claim disk device\n");
ZwMakeTemporaryObject(Handle);
ZwClose(Handle);
return(Status);
}
/* Create disk device (Partition 0) */
sprintf(NameBuffer2,
"\\Device\\Harddisk%lu\\Partition0",
DiskNumber);
Status = ScsiClassCreateDeviceObject(DriverObject,
NameBuffer2,
NULL,
&DiskDeviceObject,
InitializationData);
if (!NT_SUCCESS(Status))
{
DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
/* Release (unclaim) the disk */
ScsiClassClaimDevice(PortDeviceObject,
InquiryData,
TRUE,
NULL);
/* Delete the harddisk device directory */
ZwMakeTemporaryObject(Handle);
ZwClose(Handle);
return(Status);
}
DiskDeviceObject->Flags |= DO_DIRECT_IO;
if (((PINQUIRYDATA)InquiryData->InquiryData)->RemovableMedia)
{
DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
}
DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
{
DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
}
DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
DiskDeviceExtension->LockCount = 0;
DiskDeviceExtension->DeviceNumber = DiskNumber;
DiskDeviceExtension->DeviceObject = DiskDeviceObject;
DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
DiskDeviceExtension->PortCapabilities = Capabilities;
DiskDeviceExtension->StartingOffset.QuadPart = 0;
DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
DiskDeviceExtension->PathId = InquiryData->PathId;
DiskDeviceExtension->TargetId = InquiryData->TargetId;
DiskDeviceExtension->Lun = InquiryData->Lun;
DiskDeviceExtension->SrbFlags = 0;
/* Enable the command queueing, if it possible */
if (Capabilities->TaggedQueuing &&
((PINQUIRYDATA)InquiryData->InquiryData)->CommandQueue)
{
DiskDeviceExtension->SrbFlags |= SRB_FLAGS_QUEUE_ACTION_ENABLE;
}
/* Get timeout value */
DiskDeviceExtension->TimeOutValue =
ScsiClassQueryTimeOutRegistryValue(RegistryPath);
if (DiskDeviceExtension->TimeOutValue == 0)
DiskDeviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
/* Initialize the lookaside list for SRBs */
ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
4);
/* zero-out disk data */
DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
RtlZeroMemory(DiskData,
sizeof(DISK_DATA));
/* Get disk geometry */
DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
sizeof(DISK_GEOMETRY));
if (DiskDeviceExtension->DiskGeometry == NULL)
{
DPRINT("Failed to allocate geometry buffer!\n");
ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
IoDeleteDevice(DiskDeviceObject);
/* Release (unclaim) the disk */
ScsiClassClaimDevice(PortDeviceObject,
InquiryData,
TRUE,
NULL);
/* Delete the harddisk device directory */
ZwMakeTemporaryObject(Handle);
ZwClose(Handle);
return(STATUS_INSUFFICIENT_RESOURCES);
}
/* Allocate sense data buffer */
DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPoolCacheAligned,
SENSE_BUFFER_SIZE);
if (DiskDeviceExtension->SenseData == NULL)
{
DPRINT("Failed to allocate sense data buffer!\n");
ExFreePool (DiskDeviceExtension->DiskGeometry);
ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
IoDeleteDevice(DiskDeviceObject);
/* Release (unclaim) the disk */
ScsiClassClaimDevice(PortDeviceObject,
InquiryData,
TRUE,
NULL);
/* Delete the harddisk device directory */
ZwMakeTemporaryObject(Handle);
ZwClose(Handle);
return(STATUS_INSUFFICIENT_RESOURCES);
}
/* Read the drive's capacity */
Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
if (!NT_SUCCESS(Status) &&
(DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
{
DPRINT("Failed to retrieve drive capacity!\n");
return(STATUS_SUCCESS);
}
else
{
/* Clear the verify flag for removable media drives. */
DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
}
DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
(DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
{
DiskClassCreateMediaChangeEvent(DiskDeviceExtension,DiskNumber);
if (DiskDeviceExtension->MediaChangeEvent != NULL)
{
DPRINT("Allocated media change event!\n");
}
}
/* Check disk for presence of a disk manager */
HalExamineMBR(DiskDeviceObject,
DiskDeviceExtension->DiskGeometry->BytesPerSector,
0x54,
&MbrBuffer);
if (MbrBuffer != NULL)
{
/* Start disk at sector 63 if the Ontrack Disk Manager was found */
DPRINT("Found 'Ontrack Disk Manager'!\n");
DiskDeviceExtension->DMSkew = 63;
DiskDeviceExtension->DMByteSkew =
63 * DiskDeviceExtension->DiskGeometry->BytesPerSector;
DiskDeviceExtension->DMActive = TRUE;
ExFreePool(MbrBuffer);
MbrBuffer = NULL;
}
if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
(DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
{
/* Allocate a partition list for a single entry. */
PartitionList = ExAllocatePool(NonPagedPool,
sizeof(DRIVE_LAYOUT_INFORMATION));
if (PartitionList != NULL)
{
RtlZeroMemory(PartitionList,
sizeof(DRIVE_LAYOUT_INFORMATION));
PartitionList->PartitionCount = 1;
DiskData->DriveNotReady = TRUE;
Status = STATUS_SUCCESS;
}
}
else
{
/* Read partition table */
Status = IoReadPartitionTable(DiskDeviceObject,
DiskDeviceExtension->DiskGeometry->BytesPerSector,
TRUE,
&PartitionList);
DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
{
if (!NT_SUCCESS(Status))
{
/* Drive is not ready. */
DPRINT("Drive not ready\n");
DiskData->DriveNotReady = TRUE;
}
else
{
ExFreePool(PartitionList);
}
/* Allocate a partition list for a single entry. */
PartitionList = ExAllocatePool(NonPagedPool,
sizeof(DRIVE_LAYOUT_INFORMATION));
if (PartitionList != NULL)
{
RtlZeroMemory(PartitionList,
sizeof(DRIVE_LAYOUT_INFORMATION));
PartitionList->PartitionCount = 1;
Status = STATUS_SUCCESS;
}
}
}
if (NT_SUCCESS(Status))
{
DPRINT("Read partition table!\n");
DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
/* Set disk signature */
DiskData->Signature = PartitionList->Signature;
/* Calculate MBR checksum if disk got no signature */
if (DiskData->Signature == 0)
{
if (!ScsiDiskCalcMbrCheckSum(DiskDeviceExtension,
&DiskData->MbrCheckSum))
{
DPRINT("MBR checksum calculation failed for disk %lu\n",
DiskDeviceExtension->DeviceNumber);
}
else
{
DPRINT("MBR checksum for disk %lu is %lx\n",
DiskDeviceExtension->DeviceNumber,
DiskData->MbrCheckSum);
}
}
else
{
DPRINT("Signature on disk %lu is %lx\n",
DiskDeviceExtension->DeviceNumber,
DiskData->Signature);
}
/* Update disk geometry if disk is visible to the BIOS */
ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension);
for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
{
PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
PartitionNumber,
PartitionEntry->PartitionNumber,
PartitionEntry->BootIndicator,
PartitionEntry->PartitionType,
PartitionEntry->StartingOffset.QuadPart /
DiskDeviceExtension->DiskGeometry->BytesPerSector,
PartitionEntry->PartitionLength.QuadPart /
DiskDeviceExtension->DiskGeometry->BytesPerSector);
/* Create partition device object */
sprintf(NameBuffer2,
"\\Device\\Harddisk%lu\\Partition%lu",
DiskNumber,
PartitionNumber + 1);
Status = ScsiClassCreateDeviceObject(DriverObject,
NameBuffer2,
DiskDeviceObject,
&PartitionDeviceObject ,
InitializationData);
DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
if (NT_SUCCESS(Status))
{
PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
PartitionDeviceExtension->SenseData = DiskDeviceExtension->SenseData;
PartitionDeviceExtension->LockCount = 0;
PartitionDeviceExtension->DeviceNumber = DiskNumber;
PartitionDeviceExtension->DeviceObject = PartitionDeviceObject;
PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
PartitionDeviceExtension->PortCapabilities = Capabilities;
PartitionDeviceExtension->StartingOffset.QuadPart =
PartitionEntry->StartingOffset.QuadPart;
PartitionDeviceExtension->PartitionLength.QuadPart =
PartitionEntry->PartitionLength.QuadPart;
PartitionDeviceExtension->DMSkew = DiskDeviceExtension->DMSkew;
PartitionDeviceExtension->DMByteSkew = DiskDeviceExtension->DMByteSkew;
PartitionDeviceExtension->DMActive = DiskDeviceExtension->DMActive;
PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
PartitionDeviceExtension->PathId = InquiryData->PathId;
PartitionDeviceExtension->TargetId = InquiryData->TargetId;
PartitionDeviceExtension->Lun = InquiryData->Lun;
PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
PartitionDeviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
/* Initialize lookaside list for SRBs */
ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension,
8);
/* Link current partition device extension to previous disk data */
DiskData->NextPartition = PartitionDeviceExtension;
/* Initialize current disk data */
DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
DiskData->NextPartition = NULL;
DiskData->PartitionType = PartitionEntry->PartitionType;
DiskData->PartitionNumber = PartitionNumber + 1;
DiskData->PartitionOrdinal = PartitionNumber + 1;
DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
DiskData->BootIndicator = PartitionEntry->BootIndicator;
DiskData->DriveNotReady = FALSE;
/* Tell mount manager that we have a new partition for him. This should be replaced
* by the registration of MOUNTDEV_MOUNTED_DEVICE_GUID interface on partition PDO.
*/
{
UNICODE_STRING MountManagerU = RTL_CONSTANT_STRING(MOUNTMGR_DEVICE_NAME);
IO_STATUS_BLOCK IoStatusBlock;
ULONG Length = strlen(NameBuffer2) * sizeof(WCHAR);
PMOUNTMGR_TARGET_NAME TargetName;
HANDLE hMountManager;
InitializeObjectAttributes(
&ObjectAttributes,
&MountManagerU,
0,
NULL,
NULL);
Status = NtOpenFile(&hMountManager, FILE_READ_ACCESS, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN);
if (!NT_SUCCESS(Status))
{
DPRINT("NtOpenFile(%wZ) failed with status 0x%08lx\n", &MountManagerU, Status);
}
else
{
TargetName = ExAllocatePool(PagedPool, FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Length + sizeof(UNICODE_NULL));
if (!TargetName)
{
DPRINT("ExAllocatePool() failed\n");
}
else
{
TargetName->DeviceNameLength = Length;
swprintf(
TargetName->DeviceName,
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskNumber,
PartitionNumber + 1);
Status = NtDeviceIoControlFile(
hMountManager,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
TargetName, FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Length,
NULL, 0);
if (NT_SUCCESS(Status))
Status = NtWaitForSingleObject(hMountManager, FALSE, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtDeviceIoControlFile() failed with status 0x%08lx\n", Status);
}
ExFreePool(TargetName);
}
NtClose(hMountManager);
}
}
}
else
{
DPRINT("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
break;
}
}
}
if (PartitionList != NULL)
ExFreePool(PartitionList);
DPRINT("DiskClassCreateDeviceObjects() done\n");
return(STATUS_SUCCESS);
}
static NTSTATUS
DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject,
IN PIRP Irp)
{
PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
PDEVICE_EXTENSION DiskDeviceExtension, DDE;
PDISK_DATA DiskData, DD;
PPARTITION_INFORMATION PartitionEntry;
ULONG PartitionNumber;
NTSTATUS Status;
DPRINT("DiskBuildPartitionTable() start\n");
DiskDeviceExtension = (PDEVICE_EXTENSION)DiskDeviceObject->DeviceExtension;
DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
DDE = (PDEVICE_EXTENSION) DiskDeviceExtension->PhysicalDevice->DeviceExtension;
DD = (PDISK_DATA)(DDE +1);
/* Clear flag for Partition0, just incase it was set. */
DD->DriveNotReady = FALSE;
Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
if (!NT_SUCCESS(Status))
{
/* Drive is not ready. */
DPRINT("Drive not ready\n");
DiskData->DriveNotReady = TRUE;
return Status;
}
/* Read partition table */
Status = IoReadPartitionTable(DiskDeviceExtension->PhysicalDevice,
DiskDeviceExtension->DiskGeometry->BytesPerSector,
TRUE,
&PartitionList);
DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
if (!NT_SUCCESS(Status))
{
/* Drive is not ready. */
DPRINT("Drive not ready\n");
DiskData->DriveNotReady = TRUE;
if (PartitionList != NULL)
ExFreePool(PartitionList);
return Status;
}
if (NT_SUCCESS(Status))
{
DPRINT("Read partition table!\n");
DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
/* Set disk signature */
DiskData->Signature = PartitionList->Signature;
DiskData->NextPartition = NULL;
if (PartitionList->PartitionCount)
{
for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
{
PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
DiskData->PartitionType = PartitionEntry->PartitionType;
DiskData->PartitionNumber = PartitionNumber + 1;
DiskData->PartitionOrdinal = PartitionNumber + 1;
DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
DiskData->BootIndicator = PartitionEntry->BootIndicator;
DiskData->DriveNotReady = FALSE;
DiskDeviceExtension->StartingOffset = PartitionEntry->StartingOffset;
DiskDeviceExtension->PartitionLength = PartitionEntry->PartitionLength;
DPRINT1("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
PartitionNumber,
DiskData->PartitionNumber,
DiskData->BootIndicator,
DiskData->PartitionType,
DiskDeviceExtension->StartingOffset.QuadPart /
DiskDeviceExtension->DiskGeometry->BytesPerSector,
DiskDeviceExtension->PartitionLength.QuadPart /
DiskDeviceExtension->DiskGeometry->BytesPerSector);
}
}
else
{
DiskData->PartitionType = 0;
DiskData->PartitionNumber = 1;
DiskData->PartitionOrdinal = 0;
DiskData->HiddenSectors = 0;
DiskData->BootIndicator = 0;
DiskData->DriveNotReady = FALSE;
DiskDeviceExtension->StartingOffset.QuadPart = 0;
DiskDeviceExtension->PartitionLength.QuadPart += DiskDeviceExtension->StartingOffset.QuadPart;
}
}
DPRINT("DiskBuildPartitionTable() done\n");
if (PartitionList != NULL)
ExFreePool(PartitionList);
return(STATUS_SUCCESS);
}
/**********************************************************************
* NAME EXPORTED
* DiskClassDeviceControl
*
* DESCRIPTION
* Answer requests for device control calls
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* Standard dispatch arguments
*
* RETURNS
* Status
*/
NTSTATUS STDCALL
DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IrpStack;
ULONG ControlCode, InputLength, OutputLength;
PDISK_DATA DiskData;
ULONG Information;
NTSTATUS Status;
KEVENT Event;
IO_STATUS_BLOCK IoSB;
PIRP LocalIrp;
PSRB_IO_CONTROL SrbIoControl;
PSENDCMDINPARAMS InParams;
DPRINT("DiskClassDeviceControl() called!\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
Information = 0;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
DiskData = (PDISK_DATA)(DeviceExtension + 1);
switch (ControlCode)
{
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
if (DeviceExtension->DiskGeometry == NULL)
{
DPRINT("No disk geometry available!\n");
DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
sizeof(DISK_GEOMETRY));
}
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
{
Status = ScsiClassReadDriveCapacity(DeviceObject);
DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status);
if (!NT_SUCCESS(Status))
{
/* Drive is not ready */
DiskData->DriveNotReady = TRUE;
break;
}
/* Drive is ready */
DiskData->DriveNotReady = FALSE;
}
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
DeviceExtension->DiskGeometry,
sizeof(DISK_GEOMETRY));
Status = STATUS_SUCCESS;
Information = sizeof(DISK_GEOMETRY);
break;
case IOCTL_DISK_GET_PARTITION_INFO:
DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
(DeviceExtension->DiskGeometry->MediaType == RemovableMedia))
{
/* Update a partition list for a single entry. */
Status = DiskBuildPartitionTable(DeviceObject,Irp);
}
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(PARTITION_INFORMATION))
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else if (DiskData->PartitionNumber == 0)
{
Status = STATUS_INVALID_DEVICE_REQUEST;
}
else
{
PPARTITION_INFORMATION PartitionInfo;
PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
PartitionInfo->PartitionType = DiskData->PartitionType;
PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
PartitionInfo->BootIndicator = DiskData->BootIndicator;
PartitionInfo->RewritePartition = FALSE;
PartitionInfo->RecognizedPartition =
IsRecognizedPartition(DiskData->PartitionType);
Status = STATUS_SUCCESS;
Information = sizeof(PARTITION_INFORMATION);
}
break;
case IOCTL_DISK_SET_PARTITION_INFO:
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SET_PARTITION_INFORMATION))
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else if (DiskData->PartitionNumber == 0)
{
Status = STATUS_INVALID_DEVICE_REQUEST;
}
else
{
PSET_PARTITION_INFORMATION PartitionInfo;
PartitionInfo = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
Status = IoSetPartitionInformation(DeviceExtension->PhysicalDevice,
DeviceExtension->DiskGeometry->BytesPerSector,
DiskData->PartitionOrdinal,
PartitionInfo->PartitionType);
if (NT_SUCCESS(Status))
{
DiskData->PartitionType = PartitionInfo->PartitionType;
}
}
break;
case IOCTL_DISK_GET_DRIVE_LAYOUT:
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(DRIVE_LAYOUT_INFORMATION))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
PDRIVE_LAYOUT_INFORMATION PartitionList;
Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
DeviceExtension->DiskGeometry->BytesPerSector,
FALSE,
&PartitionList);
if (NT_SUCCESS(Status))
{
ULONG BufferSize;
BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
PartitionEntry[0]);
BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
PartitionList,
BufferSize);
Status = STATUS_SUCCESS;
Information = BufferSize;
}
ExFreePool(PartitionList);
}
}
break;
case IOCTL_DISK_SET_DRIVE_LAYOUT:
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(DRIVE_LAYOUT_INFORMATION))
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else if (DeviceExtension->PhysicalDevice->DeviceExtension != DeviceExtension)
{
Status = STATUS_INVALID_PARAMETER;
}
else
{
PDRIVE_LAYOUT_INFORMATION PartitionList;
ULONG TableSize;
PartitionList = Irp->AssociatedIrp.SystemBuffer;
TableSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
((PartitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < TableSize)
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
/* Update partition device objects */
DiskClassUpdatePartitionDeviceObjects (DeviceObject,
Irp);
/* Write partition table */
Status = IoWritePartitionTable(DeviceExtension->PhysicalDevice,
DeviceExtension->DiskGeometry->BytesPerSector,
DeviceExtension->DiskGeometry->SectorsPerTrack,
DeviceExtension->DiskGeometry->TracksPerCylinder,
PartitionList);
}
}
break;
case IOCTL_DISK_IS_WRITABLE:
{
PMODE_PARAMETER_HEADER ModeData;
ULONG Length;
ModeData = ExAllocatePool (NonPagedPool,
MODE_DATA_SIZE);
if (ModeData == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlZeroMemory (ModeData,
MODE_DATA_SIZE);
Length = ScsiClassModeSense (DeviceObject,
(PVOID)ModeData,
MODE_DATA_SIZE,
MODE_SENSE_RETURN_ALL);
if (Length < sizeof(MODE_PARAMETER_HEADER))
{
/* FIXME: Retry */
Status = STATUS_IO_DEVICE_ERROR;
ExFreePool (ModeData);
break;
}
if (ModeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT)
{
Status = STATUS_MEDIA_WRITE_PROTECTED;
}
else
{
Status = STATUS_SUCCESS;
}
ExFreePool (ModeData);
}
break;
case IOCTL_DISK_VERIFY:
case IOCTL_DISK_FORMAT_TRACKS:
case IOCTL_DISK_PERFORMANCE:
case IOCTL_DISK_LOGGING:
case IOCTL_DISK_FORMAT_TRACKS_EX:
case IOCTL_DISK_HISTOGRAM_STRUCTURE:
case IOCTL_DISK_HISTOGRAM_DATA:
case IOCTL_DISK_HISTOGRAM_RESET:
case IOCTL_DISK_REQUEST_STRUCTURE:
case IOCTL_DISK_REQUEST_DATA:
/* If we get here, something went wrong. Inform the requestor */
DPRINT("Unhandled control code: %lx\n", ControlCode);
Status = STATUS_INVALID_DEVICE_REQUEST;
Information = 0;
break;
case SMART_GET_VERSION:
{
PGETVERSIONINPARAMS Version;
DPRINT("SMART_GET_VERSION\n");
if (OutputLength < sizeof(GETVERSIONINPARAMS))
{
Status = STATUS_BUFFER_TOO_SMALL;
Information = sizeof(GETVERSIONINPARAMS);
break;
}
SrbIoControl = ExAllocatePool(NonPagedPool, sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
if (SrbIoControl == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
Version = (PGETVERSIONINPARAMS)(SrbIoControl + 1);
memset(SrbIoControl, 0, sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
SrbIoControl->HeaderLength = sizeof(SRB_IO_CONTROL);
memcpy(SrbIoControl->Signature, "ScsiDisk", 8);
SrbIoControl->Timeout = DeviceExtension->TimeOutValue * 4;
SrbIoControl->Length = sizeof(GETVERSIONINPARAMS);
SrbIoControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
LocalIrp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
DeviceExtension->PortDeviceObject,
SrbIoControl,
sizeof(SRB_IO_CONTROL),
SrbIoControl,
sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
FALSE,
&Event,
&IoSB);
if (LocalIrp == NULL)
{
ExFreePool(SrbIoControl);
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
Status = IoCallDriver(DeviceExtension->PortDeviceObject, LocalIrp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoSB.Status;
}
if (NT_SUCCESS(Status))
{
memcpy(Irp->AssociatedIrp.SystemBuffer, Version, sizeof(GETVERSIONINPARAMS));
Information = sizeof(GETVERSIONINPARAMS);
}
ExFreePool(SrbIoControl);
break;
}
case SMART_SEND_DRIVE_COMMAND:
{
DPRINT("SMART_SEND_DRIVE_COMMAND\n");
if (InputLength < sizeof(SENDCMDINPARAMS) - 1)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
InParams = (PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer;
if (InParams->irDriveRegs.bCommandReg == SMART_CMD)
{
if (InParams->irDriveRegs.bFeaturesReg == ENABLE_DISABLE_AUTOSAVE)
{
DPRINT("IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE\n");
ControlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
Information = sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bFeaturesReg == SAVE_ATTRIBUTE_VALUES)
{
DPRINT("IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES\n");
ControlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
Information = sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bFeaturesReg == EXECUTE_OFFLINE_DIAGS)
{
DPRINT("IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS\n");
ControlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
Information = sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bFeaturesReg == SMART_WRITE_LOG)
{
DPRINT("IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG\n");
ControlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG;
if (InputLength < sizeof(SENDCMDINPARAMS) - 1 + 512 * max(1, InParams->irDriveRegs.bSectorCountReg))
{
Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
Information = sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bFeaturesReg == ENABLE_SMART)
{
DPRINT("IOCTL_SCSI_MINIPORT_ENABLE_SMART\n");
ControlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
Information = sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bFeaturesReg == DISABLE_SMART)
{
DPRINT("IOCTL_SCSI_MINIPORT_DISABLE_SMART\n");
ControlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
Information = sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS)
{
DPRINT("IOCTL_SCSI_MINIPORT_RETURN_STATUS\n");
ControlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
Information = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
}
else if (InParams->irDriveRegs.bFeaturesReg == ENABLE_DISABLE_AUTO_OFFLINE)
{
DPRINT("IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS\n");
ControlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
Information = sizeof(SENDCMDOUTPARAMS) - 1;
}
else
{
DPRINT("%x\n", InParams->irDriveRegs.bFeaturesReg);
Status = STATUS_INVALID_PARAMETER;
break;
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
break;
}
if (OutputLength < Information)
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
SrbIoControl = ExAllocatePool(NonPagedPool, sizeof(SRB_IO_CONTROL) + max(Information, sizeof(SENDCMDINPARAMS) - 1));
if (SrbIoControl == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
Information = 0;
break;
}
memset(SrbIoControl, 0, sizeof(SRB_IO_CONTROL) + max(Information, sizeof(SENDCMDINPARAMS) - 1));
SrbIoControl->HeaderLength = sizeof(SRB_IO_CONTROL);
memcpy(SrbIoControl->Signature, "SCSIDISK", 8);
SrbIoControl->Timeout = DeviceExtension->TimeOutValue * 4;
SrbIoControl->Length = Information;
SrbIoControl->ControlCode = ControlCode;
InParams = (PSENDCMDINPARAMS)(SrbIoControl + 1);
memcpy(InParams, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
InParams->bDriveNumber = DeviceExtension->TargetId;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
LocalIrp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
DeviceExtension->PortDeviceObject,
SrbIoControl,
sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
SrbIoControl,
sizeof(SRB_IO_CONTROL) + Information,
FALSE,
&Event,
&IoSB);
if (LocalIrp == NULL)
{
ExFreePool(SrbIoControl);
Information = 0;
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
Status = IoCallDriver(DeviceExtension->PortDeviceObject, LocalIrp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoSB.Status;
}
if (NT_SUCCESS(Status))
{
Information = SrbIoControl->Length;
}
else
{
Information = sizeof(SENDCMDOUTPARAMS) - 1;
}
memcpy(Irp->AssociatedIrp.SystemBuffer, InParams, Information);
ExFreePool(SrbIoControl);
break;
}
case SMART_RCV_DRIVE_DATA:
{
DPRINT("SMART_RCV_DRIVE_DATA\n");
if (InputLength < sizeof(SENDCMDINPARAMS) - 1)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
InParams = (PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer;
if (InParams->irDriveRegs.bCommandReg == ID_CMD)
{
DPRINT("IOCTL_SCSI_MINIPORT_IDENTIFY\n");
ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
Information = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bCommandReg == SMART_CMD)
{
if (InParams->irDriveRegs.bFeaturesReg == READ_ATTRIBUTES)
{
DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS\n");
ControlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
Information = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bFeaturesReg == READ_THRESHOLDS)
{
DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS\n");
ControlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
Information = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) - 1;
}
else if (InParams->irDriveRegs.bFeaturesReg == SMART_READ_LOG)
{
DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_LOG\n");
ControlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG;
Information = sizeof(SENDCMDOUTPARAMS) - 1 + 512 * max(1, InParams->irDriveRegs.bSectorCountReg);
}
else
{
DPRINT("%x\n", InParams->irDriveRegs.bFeaturesReg);
Status = STATUS_INVALID_PARAMETER;
break;
}
}
else
{
DPRINT("%x\n", InParams->irDriveRegs.bCommandReg);
Status = STATUS_INVALID_PARAMETER;
break;
}
if (OutputLength < Information)
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
SrbIoControl = ExAllocatePool(NonPagedPool, sizeof(SRB_IO_CONTROL) + Information);
if (SrbIoControl == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
Information = 0;
break;
}
memset(SrbIoControl, 0, sizeof(SRB_IO_CONTROL) + Information);
SrbIoControl->HeaderLength = sizeof(SRB_IO_CONTROL);
memcpy(SrbIoControl->Signature, "SCSIDISK", 8);
SrbIoControl->Timeout = DeviceExtension->TimeOutValue * 4;
SrbIoControl->Length = Information;
SrbIoControl->ControlCode = ControlCode;
InParams = (PSENDCMDINPARAMS)(SrbIoControl + 1);
memcpy(InParams, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
InParams->bDriveNumber = DeviceExtension->TargetId;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
LocalIrp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
DeviceExtension->PortDeviceObject,
SrbIoControl,
sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
SrbIoControl,
sizeof(SRB_IO_CONTROL) + Information,
FALSE,
&Event,
&IoSB);
if (LocalIrp == NULL)
{
ExFreePool(SrbIoControl);
Information = 0;
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
Status = IoCallDriver(DeviceExtension->PortDeviceObject, LocalIrp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoSB.Status;
}
if (NT_SUCCESS(Status))
{
#if 0
CHAR Buffer[256];
ULONG i, j;
UCHAR sum = 0;
memset(Buffer, 0, sizeof(Buffer));
for (i = 0; i < 512; i += 16)
{
for (j = 0; j < 16 && i + j < 512; j++)
{
sprintf(&Buffer[3*j], "%02x ", ((PSENDCMDOUTPARAMS)(SrbIoControl + 1))->bBuffer[i + j]);
sum += ((PSENDCMDOUTPARAMS)(SrbIoControl + 1))->bBuffer[i + j];
}
for (j = 0; j < 16 && i + j < 512; j++)
{
sprintf(&Buffer[3*16 + j], "%c", isprint(((PSENDCMDOUTPARAMS)(SrbIoControl + 1))->bBuffer[i + j]) ? ((PSENDCMDOUTPARAMS)(SrbIoControl + 1))->bBuffer[i + j] : '.');
}
DPRINT1("%04x %s\n", i, Buffer);
}
DPRINT1("Sum %02x\n", sum);
#endif
Information = SrbIoControl->Length;
}
else
{
Information = sizeof(SENDCMDOUTPARAMS) -1;
}
memcpy(Irp->AssociatedIrp.SystemBuffer, InParams, Information);
ExFreePool(SrbIoControl);
break;
}
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
{
WCHAR NameBuffer[80];
PMOUNTDEV_NAME pMountDevName;
ULONG NameLength;
DPRINT("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME))
{
Status = STATUS_BUFFER_TOO_SMALL;
Information = 0;
}
else
{
pMountDevName = (PMOUNTDEV_NAME)Irp->AssociatedIrp.SystemBuffer;
swprintf(NameBuffer,
L"\\Device\\Harddisk%lu\\Partition%lu",
DeviceExtension->DeviceNumber,
((PDISK_DATA)(DeviceExtension + 1))->PartitionNumber);
NameLength = wcslen(NameBuffer) * sizeof(WCHAR);
pMountDevName->NameLength = NameLength;
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(MOUNTDEV_NAME, Name) + NameLength)
{
Information = sizeof(MOUNTDEV_NAME);
Status = STATUS_BUFFER_OVERFLOW;
}
else
{
RtlCopyMemory(pMountDevName->Name, NameBuffer, NameLength);
Information = FIELD_OFFSET(MOUNTDEV_NAME, Name) + NameLength;
Status = STATUS_SUCCESS;
}
}
break;
}
case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
{
WCHAR NameBuffer[80];
PMOUNTDEV_UNIQUE_ID pMountDevUniqueId;
ULONG UniqueIdLength;
DPRINT("IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n");
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME))
{
Status = STATUS_BUFFER_TOO_SMALL;
Information = 0;
}
else
{
pMountDevUniqueId = (PMOUNTDEV_UNIQUE_ID)Irp->AssociatedIrp.SystemBuffer;
swprintf(NameBuffer,
L"\\Device\\Harddisk%lu\\Partition%lu",
DeviceExtension->DeviceNumber,
((PDISK_DATA)(DeviceExtension + 1))->PartitionNumber);
UniqueIdLength = wcslen(NameBuffer) * sizeof(WCHAR);
pMountDevUniqueId->UniqueIdLength = UniqueIdLength;
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + UniqueIdLength)
{
Information = sizeof(MOUNTDEV_UNIQUE_ID);
Status = STATUS_BUFFER_OVERFLOW;
}
else
{
RtlCopyMemory(pMountDevUniqueId->UniqueId, NameBuffer, UniqueIdLength);
Information = FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + UniqueIdLength;
Status = STATUS_SUCCESS;
}
}
break;
}
default:
/* Call the common device control function */
return(ScsiClassDeviceControl(DeviceObject, Irp));
}
/* Verify the device if the user caused the error */
if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
{
IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = Information;
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return(Status);
}
/**********************************************************************
* NAME EXPORTED
* DiskClassShutdownFlush
*
* DESCRIPTION
* Answer requests for shutdown and flush calls.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DeviceObject
* Pointer to the device.
*
* Irp
* Pointer to the IRP
*
* RETURN VALUE
* Status
*/
NTSTATUS STDCALL
DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IrpStack;
PSCSI_REQUEST_BLOCK Srb;
DPRINT("DiskClassShutdownFlush() called!\n");
DeviceExtension = DeviceObject->DeviceExtension;
/* Allocate SRB */
Srb = ExAllocatePool(NonPagedPool,
sizeof(SCSI_REQUEST_BLOCK));
if (Srb == NULL)
{
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_INSUFFICIENT_RESOURCES);
}
RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
/* Set timeout */
Srb->TimeOutValue = DeviceExtension->TimeOutValue * 4;
/* Flush write cache */
Srb->CdbLength = 10;
Srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
ScsiClassSendSrbSynchronous(DeviceObject,
Srb,
NULL,
0,
TRUE);
/* Get current stack location */
IrpStack = IoGetCurrentIrpStackLocation(Irp);
/* FIXME: Unlock removable media upon shutdown */
/* No retry */
IrpStack->Parameters.Others.Argument4 = (PVOID)0;
/* Send shutdown or flush request to the port driver */
Srb->CdbLength = 0;
if (IrpStack->MajorFunction == IRP_MJ_SHUTDOWN)
Srb->Function = SRB_FUNCTION_SHUTDOWN;
else
Srb->Function = SRB_FUNCTION_FLUSH;
/* Init completion routine */
IoSetCompletionRoutine(Irp,
ScsiClassIoComplete,
Srb,
TRUE,
TRUE,
TRUE);
/* Prepare next stack location for a call to the port driver */
IrpStack = IoGetNextIrpStackLocation(Irp);
IrpStack->MajorFunction = IRP_MJ_SCSI;
IrpStack->Parameters.Scsi.Srb = Srb;
Srb->OriginalRequest = Irp;
/* Call port driver */
return(IoCallDriver(DeviceExtension->PortDeviceObject, Irp));
}
/**********************************************************************
* NAME INTERNAL
* DiskClassUpdatePartitionDeviceObjects
*
* DESCRIPTION
* Deletes, modifies or creates partition device objects.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DeviceObject
* Pointer to the device.
*
* Irp
* Pointer to the IRP
*
* RETURN VALUE
* None
*/
static VOID
DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject,
IN PIRP Irp)
{
PDRIVE_LAYOUT_INFORMATION PartitionList;
PPARTITION_INFORMATION PartitionEntry;
PDEVICE_EXTENSION DeviceExtension;
PDEVICE_EXTENSION DiskDeviceExtension;
PDISK_DATA DiskData;
ULONG PartitionCount;
ULONG PartitionOrdinal;
ULONG PartitionNumber;
ULONG LastPartitionNumber;
ULONG i;
BOOLEAN Found;
WCHAR NameBuffer[MAX_PATH];
UNICODE_STRING DeviceName;
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status;
DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
/* Get partition list */
PartitionList = Irp->AssociatedIrp.SystemBuffer;
/* Round partition count up by 4 */
PartitionCount = ((PartitionList->PartitionCount + 3) / 4) * 4;
/* Remove the partition numbers from the partition list */
for (i = 0; i < PartitionCount; i++)
{
PartitionList->PartitionEntry[i].PartitionNumber = 0;
}
DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
/* Traverse on-disk partition list */
LastPartitionNumber = 0;
DeviceExtension = DiskDeviceExtension;
DiskData = (PDISK_DATA)(DeviceExtension + 1);
while (TRUE)
{
DeviceExtension = DiskData->NextPartition;
if (DeviceExtension == NULL)
break;
/* Get disk data */
DiskData = (PDISK_DATA)(DeviceExtension + 1);
/* Update last partition number */
if (DiskData->PartitionNumber > LastPartitionNumber)
LastPartitionNumber = DiskData->PartitionNumber;
/* Ignore unused on-disk partitions */
if (DeviceExtension->PartitionLength.QuadPart == 0ULL)
continue;
Found = FALSE;
PartitionOrdinal = 0;
for (i = 0; i < PartitionCount; i++)
{
/* Get current partition entry */
PartitionEntry = &PartitionList->PartitionEntry[i];
/* Ignore empty (aka unused) or extended partitions */
if (PartitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
IsContainerPartition (PartitionEntry->PartitionType))
continue;
PartitionOrdinal++;
/* Check for matching partition start offset and length */
if ((PartitionEntry->StartingOffset.QuadPart !=
DeviceExtension->StartingOffset.QuadPart) ||
(PartitionEntry->PartitionLength.QuadPart !=
DeviceExtension->PartitionLength.QuadPart))
continue;
DPRINT("Found matching partition entry for partition %lu\n",
DiskData->PartitionNumber);
/* Found matching partition */
Found = TRUE;
/* Update partition number in partition list */
PartitionEntry->PartitionNumber = DiskData->PartitionNumber;
break;
}
if (Found == TRUE)
{
/* Get disk data for current partition */
DiskData = (PDISK_DATA)(DeviceExtension + 1);
/* Update partition type if partiton will be rewritten */
if (PartitionEntry->RewritePartition == TRUE)
DiskData->PartitionType = PartitionEntry->PartitionType;
/* Assign new partiton ordinal */
DiskData->PartitionOrdinal = PartitionOrdinal;
DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
DiskData->PartitionOrdinal,
DiskData->PartitionNumber);
}
else
{
/* Delete this partition */
DeviceExtension->PartitionLength.QuadPart = 0ULL;
DPRINT("Deleting partition %lu\n",
DiskData->PartitionNumber);
}
}
/* Traverse partiton list and create new partiton devices */
PartitionOrdinal = 0;
for (i = 0; i < PartitionCount; i++)
{
/* Get current partition entry */
PartitionEntry = &PartitionList->PartitionEntry[i];
/* Ignore empty (aka unused) or extended partitions */
if (PartitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
IsContainerPartition (PartitionEntry->PartitionType))
continue;
PartitionOrdinal++;
/* Ignore unchanged partition entries */
if (PartitionEntry->RewritePartition == FALSE)
continue;
/* Check for an unused device object */
PartitionNumber = 0;
DeviceExtension = DiskDeviceExtension;
DiskData = (PDISK_DATA)(DeviceExtension + 1);
while (TRUE)
{
DeviceExtension = DiskData->NextPartition;
if (DeviceExtension == NULL)
break;
/* Get partition disk data */
DiskData = (PDISK_DATA)(DeviceExtension + 1);
/* Found a free (unused) partition (device object) */
if (DeviceExtension->PartitionLength.QuadPart == 0ULL)
{
PartitionNumber = DiskData->PartitionNumber;
break;
}
}
if (PartitionNumber == 0)
{
/* Create a new partition device object */
DPRINT("Create new partition device object\n");
/* Get new partiton number */
LastPartitionNumber++;
PartitionNumber = LastPartitionNumber;
/* Create partition device object */
swprintf(NameBuffer,
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskDeviceExtension->DeviceNumber,
PartitionNumber);
RtlInitUnicodeString(&DeviceName,
NameBuffer);
Status = IoCreateDevice(DiskDeviceObject->DriverObject,
sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA),
&DeviceName,
FILE_DEVICE_DISK,
0,
FALSE,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
DPRINT("IoCreateDevice() failed (Status %lx)\n", Status);
continue;
}
DeviceObject->Flags |= DO_DIRECT_IO;
DeviceObject->StackSize = DiskDeviceObject->StackSize;
DeviceObject->Characteristics = DiskDeviceObject->Characteristics;
DeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
/* Initialize device extension */
DeviceExtension = DeviceObject->DeviceExtension;
RtlCopyMemory(DeviceExtension,
DiskDeviceObject->DeviceExtension,
sizeof(DEVICE_EXTENSION));
DeviceExtension->DeviceObject = DeviceObject;
/* Initialize lookaside list for SRBs */
ScsiClassInitializeSrbLookasideList(DeviceExtension,
8);
/* Link current partition device extension to previous disk data */
DiskData->NextPartition = DeviceExtension;
DiskData = (PDISK_DATA)(DeviceExtension + 1);
DiskData->NextPartition = NULL;
}
else
{
/* Reuse an existing partition device object */
DPRINT("Reuse an exisiting partition device object\n");
DiskData = (PDISK_DATA)(DeviceExtension + 1);
}
/* Update partition data and device extension */
DiskData->PartitionNumber = PartitionNumber;
DiskData->PartitionOrdinal = PartitionOrdinal;
DiskData->PartitionType = PartitionEntry->PartitionType;
DiskData->BootIndicator = PartitionEntry->BootIndicator;
DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
DeviceExtension->StartingOffset = PartitionEntry->StartingOffset;
DeviceExtension->PartitionLength = PartitionEntry->PartitionLength;
/* Update partition number in the partition list */
PartitionEntry->PartitionNumber = PartitionNumber;
DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
DiskData->PartitionOrdinal,
DiskData->PartitionNumber);
}
DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
}
/**********************************************************************
* NAME INTERNAL
* ScsiDiskSearchForDisk
*
* DESCRIPTION
* Searches the hardware tree for the given disk.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DeviceExtension
* Disk device extension.
*
* BusKey
* Handle to the hardware bus key.
*
* DetectedDiskNumber
* Returned disk number.
*
* RETURN VALUE
* TRUE: Disk was found.
* FALSE: Search failed.
*/
static BOOLEAN
ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension,
IN HANDLE BusKey,
OUT PULONG DetectedDiskNumber)
{
PKEY_VALUE_FULL_INFORMATION ValueData;
OBJECT_ATTRIBUTES ObjectAttributes;
PDISK_DATA DiskData;
UNICODE_STRING IdentifierString;
UNICODE_STRING NameString;
HANDLE BusInstanceKey;
HANDLE ControllerKey;
HANDLE DiskKey;
HANDLE DiskInstanceKey;
ULONG BusNumber;
ULONG ControllerNumber;
ULONG DiskNumber;
ULONG Length;
WCHAR Buffer[32];
BOOLEAN DiskFound;
NTSTATUS Status;
DPRINT("ScsiDiskSearchForDiskData() called\n");
DiskFound = FALSE;
/* Enumerate buses */
for (BusNumber = 0; ; BusNumber++)
{
/* Open bus instance subkey */
swprintf(Buffer,
L"%lu",
BusNumber);
RtlInitUnicodeString(&NameString,
Buffer);
InitializeObjectAttributes(&ObjectAttributes,
&NameString,
OBJ_CASE_INSENSITIVE,
BusKey,
NULL);
Status = ZwOpenKey(&BusInstanceKey,
KEY_READ,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
break;
}
/* Open 'DiskController' subkey */
RtlInitUnicodeString(&NameString,
L"DiskController");
InitializeObjectAttributes(&ObjectAttributes,
&NameString,
OBJ_CASE_INSENSITIVE,
BusInstanceKey,
NULL);
Status = ZwOpenKey(&ControllerKey,
KEY_READ,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ZwClose(BusInstanceKey);
continue;
}
/* Enumerate controllers */
for (ControllerNumber = 0; ; ControllerNumber++)
{
/* Open 'DiskPeripheral' subkey */
swprintf(Buffer,
L"%lu\\DiskPeripheral",
ControllerNumber);
RtlInitUnicodeString(&NameString,
Buffer);
InitializeObjectAttributes(&ObjectAttributes,
&NameString,
OBJ_CASE_INSENSITIVE,
ControllerKey,
NULL);
Status = ZwOpenKey(&DiskKey,
KEY_READ,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
break;
}
/* Enumerate disks */
for (DiskNumber = 0; ; DiskNumber++)
{
/* Open disk instance subkey */
swprintf(Buffer,
L"%lu",
DiskNumber);
RtlInitUnicodeString(&NameString,
Buffer);
InitializeObjectAttributes(&ObjectAttributes,
&NameString,
OBJ_CASE_INSENSITIVE,
DiskKey,
NULL);
Status = ZwOpenKey(&DiskInstanceKey,
KEY_READ,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
break;
}
DPRINT("Found disk key: bus %lu controller %lu disk %lu\n",
BusNumber,
ControllerNumber,
DiskNumber);
/* Allocate data buffer */
ValueData = ExAllocatePool(PagedPool,
2048);
if (ValueData == NULL)
{
ZwClose(DiskInstanceKey);
continue;
}
/* Get the 'Identifier' value */
RtlInitUnicodeString(&NameString,
L"Identifier");
Status = ZwQueryValueKey(DiskInstanceKey,
&NameString,
KeyValueFullInformation,
ValueData,
2048,
&Length);
ZwClose(DiskInstanceKey);
if (!NT_SUCCESS(Status))
{
ExFreePool(ValueData);
continue;
}
IdentifierString.Buffer =
(PWSTR)((PUCHAR)ValueData + ValueData->DataOffset);
IdentifierString.Length = (USHORT)ValueData->DataLength - 2;
IdentifierString.MaximumLength = (USHORT)ValueData->DataLength;
DPRINT("DiskIdentifier: %wZ\n",
&IdentifierString);
DiskData = (PDISK_DATA)(DeviceExtension + 1);
if (DiskData->Signature != 0)
{
/* Comapre disk signature */
swprintf(Buffer,
L"%08lx",
DiskData->Signature);
if (!_wcsnicmp(Buffer, &IdentifierString.Buffer[9], 8))
{
DPRINT("Found disk %lu\n", DiskNumber);
DiskFound = TRUE;
*DetectedDiskNumber = DiskNumber;
}
}
else
{
/* Comapre mbr checksum */
swprintf(Buffer,
L"%08lx",
DiskData->MbrCheckSum);
if (!_wcsnicmp(Buffer, &IdentifierString.Buffer[0], 8))
{
DPRINT("Found disk %lu\n", DiskNumber);
DiskFound = TRUE;
*DetectedDiskNumber = DiskNumber;
}
}
ExFreePool(ValueData);
ZwClose(DiskInstanceKey);
if (DiskFound == TRUE)
break;
}
ZwClose(DiskKey);
}
ZwClose(ControllerKey);
ZwClose(BusInstanceKey);
}
DPRINT("ScsiDiskSearchForDisk() done\n");
return DiskFound;
}
/**********************************************************************
* NAME INTERNAL
* DiskClassUpdateFixedDiskGeometry
*
* DESCRIPTION
* Updated the geometry of a disk if the disk can be accessed
* by the BIOS.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DeviceExtension
* Disk device extension.
*
* RETURN VALUE
* None
*/
static VOID
ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension)
{
PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor;
PCM_INT13_DRIVE_PARAMETER DriveParameters;
PKEY_VALUE_FULL_INFORMATION ValueBuffer;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE SystemKey;
HANDLE BusKey;
ULONG DiskNumber = 0;
ULONG Length;
#if 0
ULONG i;
#endif
ULONG Cylinders;
ULONG Sectors;
ULONG SectorsPerTrack;
ULONG TracksPerCylinder;
NTSTATUS Status;
DPRINT("ScsiDiskUpdateFixedDiskGeometry() called\n");
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\Hardware\\Description\\System");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Open the adapter key */
Status = ZwOpenKey(&SystemKey,
KEY_READ,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
return;
}
/* Allocate value buffer */
ValueBuffer = ExAllocatePool(PagedPool,
1024);
if (ValueBuffer == NULL)
{
DPRINT("Failed to allocate value buffer\n");
ZwClose(SystemKey);
return;
}
RtlInitUnicodeString(&ValueName,
L"Configuration Data");
/* Query 'Configuration Data' value */
Status = ZwQueryValueKey(SystemKey,
&ValueName,
KeyValueFullInformation,
ValueBuffer,
1024,
&Length);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
ExFreePool(ValueBuffer);
ZwClose(SystemKey);
return;
}
/* Open the 'MultifunctionAdapter' subkey */
RtlInitUnicodeString(&KeyName,
L"MultifunctionAdapter");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
SystemKey,
NULL);
Status = ZwOpenKey(&BusKey,
KEY_READ,
&ObjectAttributes);
ZwClose(SystemKey);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
ExFreePool(ValueBuffer);
return;
}
if (!ScsiDiskSearchForDisk(DeviceExtension, BusKey, &DiskNumber))
{
DPRINT("ScsiDiskSearchForDisk() failed\n");
ZwClose(BusKey);
ExFreePool(ValueBuffer);
return;
}
ZwClose(BusKey);
ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
((PUCHAR)ValueBuffer + ValueBuffer->DataOffset);
DriveParameters = (PCM_INT13_DRIVE_PARAMETER)
((PUCHAR)ResourceDescriptor + sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
#if 0
for (i = 0; i< DriveParameters[0].NumberDrives; i++)
{
DPRINT("Drive %lu: %lu Cylinders %hu Heads %hu Sectors\n",
i,
DriveParameters[i].MaxCylinders,
DriveParameters[i].MaxHeads,
DriveParameters[i].SectorsPerTrack);
}
#endif
Cylinders = DriveParameters[DiskNumber].MaxCylinders + 1;
TracksPerCylinder = DriveParameters[DiskNumber].MaxHeads +1;
SectorsPerTrack = DriveParameters[DiskNumber].SectorsPerTrack;
DPRINT("BIOS geometry: %lu Cylinders %hu Heads %hu Sectors\n",
Cylinders,
TracksPerCylinder,
SectorsPerTrack);
Sectors = (ULONG)
(DeviceExtension->PartitionLength.QuadPart >> DeviceExtension->SectorShift);
DPRINT("Physical sectors: %lu\n",
Sectors);
Length = TracksPerCylinder * SectorsPerTrack;
if (Length == 0)
{
DPRINT("Invalid track length 0\n");
ExFreePool(ValueBuffer);
return;
}
Cylinders = Sectors / Length;
DPRINT("Logical geometry: %lu Cylinders %hu Heads %hu Sectors\n",
Cylinders,
TracksPerCylinder,
SectorsPerTrack);
/* Update the disk geometry */
DeviceExtension->DiskGeometry->SectorsPerTrack = SectorsPerTrack;
DeviceExtension->DiskGeometry->TracksPerCylinder = TracksPerCylinder;
DeviceExtension->DiskGeometry->Cylinders.QuadPart = (ULONGLONG)Cylinders;
if (DeviceExtension->DMActive)
{
DPRINT("FIXME: Update geometry with respect to the installed disk manager!\n");
/* FIXME: Update geometry for disk managers */
}
ExFreePool(ValueBuffer);
DPRINT("ScsiDiskUpdateFixedDiskGeometry() done\n");
}
/**********************************************************************
* NAME INTERNAL
* ScsiDiskCalcMbrCheckSum
*
* DESCRIPTION
* Calculates the Checksum from drives MBR.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DeviceExtension
* Disk device extension.
*
* Checksum
* Pointer to the caller supplied cecksum variable.
*
* RETURN VALUE
* TRUE: Checksum was calculated.
* FALSE: Calculation failed.
*/
static BOOLEAN
ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension,
OUT PULONG Checksum)
{
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER SectorOffset;
ULONG SectorSize;
PULONG MbrBuffer;
KEVENT Event;
PIRP Irp;
ULONG i;
ULONG Sum;
NTSTATUS Status;
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
/* Get the disk sector size */
SectorSize = DeviceExtension->DiskGeometry->BytesPerSector;
if (SectorSize < 512)
{
SectorSize = 512;
}
/* Allocate MBR buffer */
MbrBuffer = ExAllocatePool(NonPagedPool,
SectorSize);
if (MbrBuffer == NULL)
{
return FALSE;
}
/* Allocate an IRP */
SectorOffset.QuadPart = 0ULL;
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
DeviceExtension->DeviceObject,
MbrBuffer,
SectorSize,
&SectorOffset,
&Event,
&IoStatusBlock);
if (Irp == NULL)
{
ExFreePool(MbrBuffer);
return FALSE;
}
/* Call the miniport driver */
Status = IoCallDriver(DeviceExtension->DeviceObject,
Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event,
Suspended,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
if (!NT_SUCCESS(Status))
{
ExFreePool(MbrBuffer);
return FALSE;
}
/* Calculate MBR checksum */
Sum = 0;
for (i = 0; i < 128; i++)
{
Sum += MbrBuffer[i];
}
*Checksum = ~Sum + 1;
ExFreePool(MbrBuffer);
return TRUE;
}
/* EOF */