2002-03-08 12:01:26 +00:00
|
|
|
|
/*
|
2007-04-01 19:25:38 +00:00
|
|
|
|
* PROJECT: ReactOS Storage Stack
|
|
|
|
|
* LICENSE: DDK - see license.txt in the root dir
|
|
|
|
|
* FILE: drivers/storage/disk/disk.c
|
|
|
|
|
* PURPOSE: Disk class driver
|
|
|
|
|
* PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
|
2001-07-24 10:21:15 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2005-12-01 21:37:19 +00:00
|
|
|
|
#include <ntddk.h>
|
|
|
|
|
#include <ntdddisk.h>
|
|
|
|
|
#include <scsi.h>
|
|
|
|
|
#include <ntddscsi.h>
|
2006-09-28 16:33:12 +00:00
|
|
|
|
#include <mountdev.h>
|
|
|
|
|
#include <mountmgr.h>
|
2015-06-07 11:46:34 +00:00
|
|
|
|
#include <ntiologc.h>
|
2005-07-20 02:52:52 +00:00
|
|
|
|
#include <include/class2.h>
|
2005-06-17 17:15:55 +00:00
|
|
|
|
#include <stdio.h>
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2007-12-11 21:34:04 +00:00
|
|
|
|
#define NDEBUG
|
2001-07-24 10:21:15 +00:00
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
#ifdef POOL_TAGGING
|
|
|
|
|
#ifdef ExAllocatePool
|
|
|
|
|
#undef ExAllocatePool
|
|
|
|
|
#endif
|
|
|
|
|
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
|
|
|
|
|
#endif
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
typedef enum {
|
|
|
|
|
NotInitialized,
|
|
|
|
|
Initializing,
|
|
|
|
|
Initialized
|
|
|
|
|
} PARTITION_LIST_STATE;
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Disk device data
|
|
|
|
|
//
|
2003-05-01 17:50:35 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
typedef struct _DISK_DATA {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Partition chain
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
PDEVICE_EXTENSION NextPartition;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Disk signature (from MBR)
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ULONG Signature;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// MBR checksum
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ULONG MbrCheckSum;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Number of hidden sectors for BPB.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ULONG HiddenSectors;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Partition number of this device object
|
|
|
|
|
//
|
|
|
|
|
// This field is set during driver initialization or when the partition
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// is created to identify a partition to the system.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ULONG PartitionNumber;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// This field is the ordinal of a partition as it appears on a disk.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ULONG PartitionOrdinal;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// DriveNotReady - indicates that the this device is currently not ready
|
2007-09-10 16:25:48 +00:00
|
|
|
|
// because there is no media in the device.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
BOOLEAN DriveNotReady;
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
//
|
|
|
|
|
// State of PartitionList initialization
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
PARTITION_LIST_STATE PartitionListState;
|
|
|
|
|
|
2019-01-02 19:28:21 +00:00
|
|
|
|
#ifdef __REACTOS__
|
|
|
|
|
//
|
|
|
|
|
// HACK so that we can use NT5+ NTOS functions with this NT4 driver
|
|
|
|
|
// for removable devices and avoid an infinite recursive loop between
|
|
|
|
|
// disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
|
|
|
|
|
//
|
|
|
|
|
ULONG UpdateRemovableGeometryCount;
|
|
|
|
|
#endif
|
|
|
|
|
|
2002-03-01 23:18:35 +00:00
|
|
|
|
} DISK_DATA, *PDISK_DATA;
|
2004-11-24 11:09:49 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Define a general structure of identifying disk controllers with bad
|
2007-04-01 19:25:38 +00:00
|
|
|
|
// hardware.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
typedef struct _BAD_CONTROLLER_INFORMATION {
|
|
|
|
|
PCHAR InquiryString;
|
|
|
|
|
BOOLEAN DisableTaggedQueuing;
|
|
|
|
|
BOOLEAN DisableSynchronousTransfers;
|
|
|
|
|
BOOLEAN DisableDisconnects;
|
|
|
|
|
BOOLEAN DisableWriteCache;
|
|
|
|
|
}BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION;
|
|
|
|
|
|
|
|
|
|
BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = {
|
|
|
|
|
{ "TOSHIBA MK538FB 60", TRUE, FALSE, FALSE, FALSE },
|
|
|
|
|
{ "CONNER CP3500", FALSE, TRUE, FALSE, FALSE },
|
|
|
|
|
{ "OLIVETTICP3500", FALSE, TRUE, FALSE, FALSE },
|
|
|
|
|
{ "SyQuest SQ5110 CHC", TRUE, TRUE, FALSE, FALSE },
|
|
|
|
|
{ "SEAGATE ST41601N 0102", FALSE, TRUE, FALSE, FALSE },
|
|
|
|
|
{ "SEAGATE ST3655N", FALSE, FALSE, FALSE, TRUE },
|
|
|
|
|
{ "SEAGATE ST3390N", FALSE, FALSE, FALSE, TRUE },
|
|
|
|
|
{ "SEAGATE ST12550N", FALSE, FALSE, FALSE, TRUE },
|
|
|
|
|
{ "SEAGATE ST32430N", FALSE, FALSE, FALSE, TRUE },
|
|
|
|
|
{ "SEAGATE ST31230N", FALSE, FALSE, FALSE, TRUE },
|
|
|
|
|
{ "SEAGATE ST15230N", FALSE, FALSE, FALSE, TRUE },
|
|
|
|
|
{ "FUJITSU M2652S-512", TRUE, FALSE, FALSE, FALSE },
|
|
|
|
|
{ "MAXTOR MXT-540SL I1.2", TRUE, FALSE, FALSE, FALSE },
|
|
|
|
|
{ "COMPAQ PD-1", FALSE, TRUE, FALSE, FALSE }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
|
|
|
|
|
#define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
|
|
|
|
|
|
|
|
|
|
#define MODE_DATA_SIZE 192
|
|
|
|
|
#define VALUE_BUFFER_SIZE 2048
|
|
|
|
|
#define SCSI_DISK_TIMEOUT 10
|
|
|
|
|
#define PARTITION0_LIST_SIZE 4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DriverEntry(
|
|
|
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
|
|
|
IN PUNICODE_STRING RegistryPath
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskDeviceVerification(
|
|
|
|
|
IN PINQUIRYDATA InquiryData
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
FindScsiDisks(
|
|
|
|
|
IN PDRIVER_OBJECT DriveObject,
|
|
|
|
|
IN PUNICODE_STRING RegistryPath,
|
|
|
|
|
IN PCLASS_INIT_DATA InitializationData,
|
|
|
|
|
IN PDEVICE_OBJECT PortDeviceObject,
|
|
|
|
|
IN ULONG PortNumber
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskCreateClose (
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskReadWriteVerification(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskDeviceControl(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskProcessError(
|
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
PSCSI_REQUEST_BLOCK Srb,
|
|
|
|
|
NTSTATUS *Status,
|
|
|
|
|
BOOLEAN *Retry
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskShutdownFlush(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DisableWriteCache(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PSCSI_INQUIRY_DATA LunInfo
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskModeSelect(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PCHAR ModeSelectBuffer,
|
|
|
|
|
IN ULONG Length,
|
|
|
|
|
IN BOOLEAN SavePage
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
IsFloppyDevice(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
CalculateMbrCheckSum(
|
|
|
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
|
|
|
OUT PULONG Checksum
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
EnumerateBusKey(
|
|
|
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
|
|
|
HANDLE BusKey,
|
|
|
|
|
PULONG DiskNumber
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
UpdateGeometry(
|
|
|
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
UpdateRemovableGeometry (
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
CreateDiskDeviceObject(
|
|
|
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
|
|
|
IN PUNICODE_STRING RegistryPath,
|
|
|
|
|
IN PDEVICE_OBJECT PortDeviceObject,
|
|
|
|
|
IN ULONG PortNumber,
|
|
|
|
|
IN PULONG DeviceCount,
|
|
|
|
|
IN PIO_SCSI_CAPABILITIES PortCapabilities,
|
|
|
|
|
IN PSCSI_INQUIRY_DATA LunInfo,
|
|
|
|
|
IN PCLASS_INIT_DATA InitData
|
|
|
|
|
);
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-09-10 16:25:48 +00:00
|
|
|
|
CreatePartitionDeviceObjects(
|
|
|
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
|
|
|
IN PUNICODE_STRING RegistryPath
|
|
|
|
|
);
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
UpdateDeviceObjects(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScanForSpecial(
|
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
PSCSI_INQUIRY_DATA LunInfo,
|
|
|
|
|
PIO_SCSI_CAPABILITIES PortCapabilities
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ResetScsiBus(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
|
|
|
);
|
|
|
|
|
|
2014-10-28 21:59:57 +00:00
|
|
|
|
NTSTATUS
|
|
|
|
|
NTAPI
|
|
|
|
|
ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
PIRP Irp);
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
|
#pragma alloc_text(PAGE, DriverEntry)
|
|
|
|
|
#pragma alloc_text(PAGE, FindScsiDisks)
|
|
|
|
|
#pragma alloc_text(PAGE, CreateDiskDeviceObject)
|
|
|
|
|
#pragma alloc_text(PAGE, CalculateMbrCheckSum)
|
|
|
|
|
#pragma alloc_text(PAGE, EnumerateBusKey)
|
|
|
|
|
#pragma alloc_text(PAGE, UpdateGeometry)
|
|
|
|
|
#pragma alloc_text(PAGE, IsFloppyDevice)
|
|
|
|
|
#pragma alloc_text(PAGE, ScanForSpecial)
|
|
|
|
|
#pragma alloc_text(PAGE, ScsiDiskDeviceControl)
|
|
|
|
|
#pragma alloc_text(PAGE, ScsiDiskModeSelect)
|
|
|
|
|
#endif
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DriverEntry(
|
|
|
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
|
|
|
IN PUNICODE_STRING RegistryPath
|
|
|
|
|
)
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
/*++
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
Routine Description:
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
This routine initializes the SCSI hard disk class driver.
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DriverObject - Pointer to driver object created by system.
|
|
|
|
|
|
|
|
|
|
RegistryPath - Pointer to the name of the services node for this driver.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
The function value is the final status from the initialization operation.
|
|
|
|
|
|
|
|
|
|
--*/
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2004-03-31 03:33:48 +00:00
|
|
|
|
{
|
2007-04-01 19:25:38 +00:00
|
|
|
|
CLASS_INIT_DATA InitializationData;
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Zero InitData
|
|
|
|
|
//
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Set sizes
|
|
|
|
|
//
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
|
|
|
|
|
InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
|
|
|
|
|
|
|
|
|
|
InitializationData.DeviceType = FILE_DEVICE_DISK;
|
|
|
|
|
InitializationData.DeviceCharacteristics = 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set entry points
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
InitializationData.ClassError = ScsiDiskProcessError;
|
|
|
|
|
InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification;
|
|
|
|
|
InitializationData.ClassFindDevices = FindScsiDisks;
|
|
|
|
|
InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification;
|
|
|
|
|
InitializationData.ClassDeviceControl = ScsiDiskDeviceControl;
|
|
|
|
|
InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush;
|
|
|
|
|
InitializationData.ClassCreateClose = NULL;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call the class init routine
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
|
|
|
|
|
|
|
|
|
|
} // end DriverEntry()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskDeviceVerification(
|
|
|
|
|
IN PINQUIRYDATA InquiryData
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
2002-01-27 01:25:49 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This routine checks InquiryData for the correct device type and qualifier.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
InquiryData - Pointer to the inquiry data for the device in question.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
True is returned if the correct device type is found.
|
|
|
|
|
|
|
|
|
|
--*/
|
2002-01-27 01:25:49 +00:00
|
|
|
|
{
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
|
|
|
|
|
(InquiryData->DeviceType == OPTICAL_DEVICE)) &&
|
|
|
|
|
InquiryData->DeviceTypeQualifier == 0) {
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2002-01-27 01:25:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
FindScsiDisks(
|
|
|
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
|
|
|
IN PUNICODE_STRING RegistryPath,
|
|
|
|
|
IN PCLASS_INIT_DATA InitializationData,
|
|
|
|
|
IN PDEVICE_OBJECT PortDeviceObject,
|
|
|
|
|
IN ULONG PortNumber
|
|
|
|
|
)
|
2002-01-27 01:25:49 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This routine gets a port drivers capabilities, obtains the
|
|
|
|
|
inquiry data, searches the SCSI bus for the port driver and creates
|
|
|
|
|
the device objects for the disks found.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DriverObject - Pointer to driver object created by system.
|
|
|
|
|
|
|
|
|
|
PortDeviceObject - Device object use to send requests to port driver.
|
|
|
|
|
|
|
|
|
|
PortNumber - Number for port driver. Used to pass on to
|
|
|
|
|
CreateDiskDeviceObjects() and create device objects.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
True is returned if one disk was found and successfully created.
|
|
|
|
|
|
|
|
|
|
--*/
|
2002-03-08 12:01:26 +00:00
|
|
|
|
|
2002-01-31 14:58:52 +00:00
|
|
|
|
{
|
2007-04-01 19:25:38 +00:00
|
|
|
|
PIO_SCSI_CAPABILITIES portCapabilities;
|
|
|
|
|
PULONG diskCount;
|
|
|
|
|
PCONFIGURATION_INFORMATION configurationInformation;
|
|
|
|
|
PCHAR buffer;
|
|
|
|
|
PSCSI_INQUIRY_DATA lunInfo;
|
|
|
|
|
PSCSI_ADAPTER_BUS_INFO adapterInfo;
|
|
|
|
|
PINQUIRYDATA inquiryData;
|
|
|
|
|
ULONG scsiBus;
|
|
|
|
|
ULONG adapterDisk;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
BOOLEAN foundOne = FALSE;
|
|
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call port driver to get adapter capabilities.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
|
|
|
|
|
return(FALSE);
|
|
|
|
|
}
|
2002-03-22 20:35:09 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Call port driver to get inquiry information to find disks.
|
|
|
|
|
//
|
2002-01-31 14:58:52 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
|
2002-03-22 20:35:09 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
|
|
|
|
|
return(FALSE);
|
2002-03-22 20:35:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Do a quick scan of the devices on this adapter to determine how many
|
|
|
|
|
// disks are on this adapter. This is used to determine the number of
|
|
|
|
|
// SRB zone elements to allocate.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
adapterInfo = (PVOID) buffer;
|
2005-02-27 21:17:24 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo);
|
2005-02-27 21:17:24 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Allocate a zone of SRB for disks on this adapter.
|
|
|
|
|
//
|
2005-02-01 21:21:33 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (adapterDisk == 0) {
|
2005-02-27 21:17:24 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// No free disks were found.
|
|
|
|
|
//
|
2005-02-27 21:17:24 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
return(FALSE);
|
2005-02-27 21:17:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Get the number of disks already initialized.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
configurationInformation = IoGetConfigurationInformation();
|
|
|
|
|
diskCount = &configurationInformation->DiskCount;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// For each SCSI bus this adapter supports ...
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get the SCSI bus scan data for this bus.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Search list for unclaimed disk devices.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
|
|
|
|
|
|
|
|
|
|
inquiryData = (PVOID)lunInfo->InquiryData;
|
|
|
|
|
|
|
|
|
|
if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
|
|
|
|
|
(inquiryData->DeviceType == OPTICAL_DEVICE)) &&
|
|
|
|
|
inquiryData->DeviceTypeQualifier == 0 &&
|
|
|
|
|
(!lunInfo->DeviceClaimed)) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"FindScsiDevices: Vendor string is %.24s\n",
|
|
|
|
|
inquiryData->VendorId));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Create device objects for disk
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = CreateDiskDeviceObject(DriverObject,
|
|
|
|
|
RegistryPath,
|
|
|
|
|
PortDeviceObject,
|
|
|
|
|
PortNumber,
|
|
|
|
|
diskCount,
|
|
|
|
|
portCapabilities,
|
|
|
|
|
lunInfo,
|
|
|
|
|
InitializationData);
|
|
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Increment system disk device count.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
(*diskCount)++;
|
|
|
|
|
foundOne = TRUE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get next LunInfo.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (lunInfo->NextInquiryDataOffset == 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
|
|
|
|
|
|
|
|
|
|
}
|
2005-02-01 21:21:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
|
|
|
|
|
//
|
2002-01-31 14:58:52 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ExFreePool(buffer);
|
2002-01-27 01:25:49 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
return(foundOne);
|
2002-01-27 01:25:49 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
} // end FindScsiDisks()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
CreateDiskDeviceObject(
|
|
|
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
|
|
|
IN PUNICODE_STRING RegistryPath,
|
|
|
|
|
IN PDEVICE_OBJECT PortDeviceObject,
|
|
|
|
|
IN ULONG PortNumber,
|
|
|
|
|
IN PULONG DeviceCount,
|
|
|
|
|
IN PIO_SCSI_CAPABILITIES PortCapabilities,
|
|
|
|
|
IN PSCSI_INQUIRY_DATA LunInfo,
|
|
|
|
|
IN PCLASS_INIT_DATA InitData
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This routine creates an object for the physical device and then searches
|
|
|
|
|
the device for partitions and creates an object for each partition.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DriverObject - Pointer to driver object created by system.
|
2002-01-27 01:25:49 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
PortDeviceObject - Miniport device object.
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
PortNumber - port number. Used in creating disk objects.
|
|
|
|
|
|
|
|
|
|
DeviceCount - Number of previously installed devices.
|
|
|
|
|
|
|
|
|
|
PortCapabilities - Capabilities of this SCSI port.
|
|
|
|
|
|
|
|
|
|
LunInfo - LUN specific information.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
|
|
|
|
|
|
--*/
|
2004-03-31 03:33:48 +00:00
|
|
|
|
{
|
2007-04-01 19:25:38 +00:00
|
|
|
|
CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
|
|
|
|
|
STRING ntNameString;
|
|
|
|
|
UNICODE_STRING ntUnicodeString;
|
|
|
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
|
HANDLE handle;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
2011-09-11 00:40:20 +00:00
|
|
|
|
//PDEVICE_OBJECT physicalDevice;
|
2010-10-12 20:17:55 +00:00
|
|
|
|
PDISK_GEOMETRY_EX diskGeometry = NULL;
|
2007-04-05 17:36:39 +00:00
|
|
|
|
PDEVICE_EXTENSION deviceExtension = NULL;
|
2011-09-11 00:40:20 +00:00
|
|
|
|
//PDEVICE_EXTENSION physicalDeviceExtension;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
UCHAR pathId = LunInfo->PathId;
|
|
|
|
|
UCHAR targetId = LunInfo->TargetId;
|
|
|
|
|
UCHAR lun = LunInfo->Lun;
|
2011-09-11 00:40:20 +00:00
|
|
|
|
//BOOLEAN writeCache;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
PVOID senseData = NULL;
|
2011-09-11 00:40:20 +00:00
|
|
|
|
//ULONG srbFlags;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ULONG timeOut = 0;
|
|
|
|
|
BOOLEAN srbListInitialized = FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set up an object directory to contain the objects for this
|
|
|
|
|
// device and all its partitions.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
sprintf(ntNameBuffer,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
"\\Device\\Harddisk%lu",
|
2007-04-01 19:25:38 +00:00
|
|
|
|
*DeviceCount);
|
|
|
|
|
|
|
|
|
|
RtlInitString(&ntNameString,
|
|
|
|
|
ntNameBuffer);
|
|
|
|
|
|
|
|
|
|
status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
|
|
|
|
&ntNameString,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
return(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
|
|
|
&ntUnicodeString,
|
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
status = ZwCreateDirectoryObject(&handle,
|
|
|
|
|
DIRECTORY_ALL_ACCESS,
|
|
|
|
|
&objectAttributes);
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
RtlFreeUnicodeString(&ntUnicodeString);
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (!NT_SUCCESS(status)) {
|
2004-07-15 04:04:08 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"CreateDiskDeviceObjects: Could not create directory %s\n",
|
|
|
|
|
ntNameBuffer));
|
2004-07-15 04:04:08 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
return(status);
|
2004-03-31 03:33:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Claim the device.
|
|
|
|
|
//
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
status = ScsiClassClaimDevice(PortDeviceObject,
|
|
|
|
|
LunInfo,
|
|
|
|
|
FALSE,
|
|
|
|
|
&PortDeviceObject);
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
ZwMakeTemporaryObject(handle);
|
|
|
|
|
ZwClose(handle);
|
|
|
|
|
return status;
|
2004-03-31 03:33:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Create a device object for this device. Each physical disk 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.
|
|
|
|
|
//
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
sprintf(ntNameBuffer,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
"\\Device\\Harddisk%lu\\Partition0",
|
2007-04-01 19:25:38 +00:00
|
|
|
|
*DeviceCount);
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
status = ScsiClassCreateDeviceObject(DriverObject,
|
|
|
|
|
ntNameBuffer,
|
|
|
|
|
NULL,
|
|
|
|
|
&deviceObject,
|
|
|
|
|
InitData);
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (!NT_SUCCESS(status)) {
|
2004-03-31 03:33:48 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"CreateDiskDeviceObjects: Can not create device object %s\n",
|
|
|
|
|
ntNameBuffer));
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
goto CreateDiskDeviceObjectsExit;
|
|
|
|
|
}
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Indicate that IRPs should include MDLs for data transfers.
|
|
|
|
|
//
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceObject->Flags |= DO_DIRECT_IO;
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Check if this is during initialization. If not indicate that
|
|
|
|
|
// system initialization already took place and this disk is ready
|
|
|
|
|
// to be accessed.
|
|
|
|
|
//
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (!RegistryPath) {
|
|
|
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
|
}
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Check for removable media support.
|
|
|
|
|
//
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) {
|
|
|
|
|
deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
|
|
|
|
|
}
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Set up required stack size in device object.
|
|
|
|
|
//
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
|
2006-09-28 16:33:12 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceExtension = deviceObject->DeviceExtension;
|
2006-09-28 16:33:12 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Allocate spinlock for split request completion.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Initialize lock count to zero. The lock count is used to
|
|
|
|
|
// disable the ejection mechanism on devices that support
|
|
|
|
|
// removable media. Only the lock count in the physical
|
|
|
|
|
// device extension is used.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->LockCount = 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Save system disk number.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->DeviceNumber = *DeviceCount;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy port device object pointer to the device extension.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->PortDeviceObject = PortDeviceObject;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set the alignment requirements for the device based on the
|
|
|
|
|
// host adapter requirements
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
|
|
|
|
|
deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// This is the physical device object.
|
|
|
|
|
//
|
|
|
|
|
|
2011-09-11 00:40:20 +00:00
|
|
|
|
//physicalDevice = deviceObject;
|
|
|
|
|
//physicalDeviceExtension = deviceExtension;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Save address of port driver capabilities.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->PortCapabilities = PortCapabilities;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Build the lookaside list for srb's for the physical disk. Should only
|
|
|
|
|
// need a couple.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ScsiClassInitializeSrbLookasideList(deviceExtension,
|
|
|
|
|
PARTITION0_LIST_SIZE);
|
|
|
|
|
|
|
|
|
|
srbListInitialized = TRUE;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Initialize the srb flags.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue &&
|
|
|
|
|
PortCapabilities->TaggedQueuing) {
|
|
|
|
|
|
|
|
|
|
deviceExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
deviceExtension->SrbFlags = 0;
|
2005-10-16 11:17:26 +00:00
|
|
|
|
|
2002-02-03 20:21:59 +00:00
|
|
|
|
}
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Allow queued requests if this is not removable media.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
|
|
|
|
|
|
|
|
|
|
deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
|
|
|
|
|
|
2002-07-18 18:09:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Look for controller that require special flags.
|
|
|
|
|
//
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScanForSpecial(deviceObject,
|
|
|
|
|
LunInfo,
|
|
|
|
|
PortCapabilities);
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2011-09-11 00:40:20 +00:00
|
|
|
|
//srbFlags = deviceExtension->SrbFlags;
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Allocate buffer for drive geometry.
|
|
|
|
|
//
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2010-10-12 20:17:55 +00:00
|
|
|
|
diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (diskGeometry == NULL) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
goto CreateDiskDeviceObjectsExit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deviceExtension->DiskGeometry = diskGeometry;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate request sense buffer.
|
|
|
|
|
//
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (senseData == NULL) {
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// The buffer can not be allocated.
|
|
|
|
|
//
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
|
|
|
|
|
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
goto CreateDiskDeviceObjectsExit;
|
2002-07-18 18:09:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Set the sense data pointer in the device extension.
|
|
|
|
|
//
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceExtension->SenseData = senseData;
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Physical device object will describe the entire
|
|
|
|
|
// device, starting at byte offset 0.
|
|
|
|
|
//
|
2003-05-01 17:50:35 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0);
|
2002-01-14 01:45:03 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// TargetId/LUN describes a device location on the SCSI bus.
|
|
|
|
|
// This information comes from the inquiry buffer.
|
|
|
|
|
//
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceExtension->PortNumber = (UCHAR)PortNumber;
|
|
|
|
|
deviceExtension->PathId = pathId;
|
|
|
|
|
deviceExtension->TargetId = targetId;
|
|
|
|
|
deviceExtension->Lun = lun;
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Set timeout value in seconds.
|
|
|
|
|
//
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
|
|
|
|
|
if (timeOut) {
|
|
|
|
|
deviceExtension->TimeOutValue = timeOut;
|
|
|
|
|
} else {
|
|
|
|
|
deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
|
|
|
|
|
}
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Back pointer to device object.
|
|
|
|
|
//
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceExtension->DeviceObject = deviceObject;
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// If this is a removable device, then make sure it is not a floppy.
|
|
|
|
|
// Perform a mode sense command to determine the media type. Note
|
|
|
|
|
// IsFloppyDevice also checks for write cache enabled.
|
|
|
|
|
//
|
2002-07-18 18:09:59 +00:00
|
|
|
|
|
2019-04-27 21:44:55 +00:00
|
|
|
|
#if 0
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
|
|
|
|
|
(((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) {
|
2001-07-24 10:21:15 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
|
|
|
goto CreateDiskDeviceObjectsExit;
|
|
|
|
|
}
|
2019-04-27 21:44:55 +00:00
|
|
|
|
#endif
|
2003-04-27 10:50:07 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DisableWriteCache(deviceObject,LunInfo);
|
2003-04-27 10:50:07 +00:00
|
|
|
|
|
2011-09-11 00:40:20 +00:00
|
|
|
|
//writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
|
2003-04-27 18:10:38 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// NOTE: At this point one device object has been successfully created.
|
|
|
|
|
// from here on out return success.
|
|
|
|
|
//
|
2003-04-27 18:10:38 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Do READ CAPACITY. This SCSI command
|
|
|
|
|
// returns the number of bytes on a device.
|
|
|
|
|
// Device extension is updated with device size.
|
|
|
|
|
//
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
status = ScsiClassReadDriveCapacity(deviceObject);
|
2003-04-28 11:05:34 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// If the read capacity failed then just return, unless this is a
|
2007-04-01 19:25:38 +00:00
|
|
|
|
// removable disk where a device object partition needs to be created.
|
|
|
|
|
//
|
2003-04-28 11:05:34 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
|
|
|
!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
|
2003-04-27 18:10:38 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"CreateDiskDeviceObjects: Can't read capacity for device %s\n",
|
|
|
|
|
ntNameBuffer));
|
|
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Make sure the volume verification bit is off so that
|
|
|
|
|
// IoReadPartitionTable will work.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceObject->Flags &= ~DO_VERIFY_VOLUME;
|
2003-04-27 18:10:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
status = CreatePartitionDeviceObjects(deviceObject, RegistryPath);
|
|
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status))
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CreateDiskDeviceObjectsExit:
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2007-09-10 16:25:48 +00:00
|
|
|
|
// Release the device since an error occurred.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2007-09-10 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
ScsiClassClaimDevice(PortDeviceObject,
|
|
|
|
|
LunInfo,
|
|
|
|
|
TRUE,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (diskGeometry != NULL) {
|
|
|
|
|
ExFreePool(diskGeometry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (senseData != NULL) {
|
|
|
|
|
ExFreePool(senseData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (deviceObject != NULL) {
|
|
|
|
|
|
|
|
|
|
if (srbListInitialized) {
|
|
|
|
|
ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IoDeleteDevice(deviceObject);
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2007-09-10 16:25:48 +00:00
|
|
|
|
// Delete directory and return.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2007-09-10 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
ZwMakeTemporaryObject(handle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZwClose(handle);
|
|
|
|
|
|
|
|
|
|
return(status);
|
|
|
|
|
|
|
|
|
|
} // end CreateDiskDeviceObjects()
|
|
|
|
|
|
2019-10-21 14:50:36 +00:00
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
|
NTAPI
|
|
|
|
|
ReportToMountMgr(
|
|
|
|
|
IN PDEVICE_OBJECT DiskDeviceObject
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This routine reports the creation of a disk device object to the
|
|
|
|
|
MountMgr to fake PnP.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DiskDeviceObject - Pointer to the created disk device.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
{
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
UNICODE_STRING mountMgrDevice;
|
|
|
|
|
PDEVICE_OBJECT deviceObject;
|
|
|
|
|
PFILE_OBJECT fileObject;
|
|
|
|
|
PMOUNTMGR_TARGET_NAME mountTarget;
|
|
|
|
|
ULONG diskLen;
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
|
PIRP irp;
|
|
|
|
|
KEVENT event;
|
|
|
|
|
IO_STATUS_BLOCK ioStatus;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// First, get MountMgr DeviceObject.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&mountMgrDevice, MOUNTMGR_DEVICE_NAME);
|
|
|
|
|
status = IoGetDeviceObjectPointer(&mountMgrDevice, FILE_READ_ATTRIBUTES,
|
|
|
|
|
&fileObject, &deviceObject);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"ReportToMountMgr: Can't get MountMgr pointers %lx\n",
|
|
|
|
|
status));
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deviceExtension = DiskDeviceObject->DeviceExtension;
|
|
|
|
|
diskLen = deviceExtension->DeviceName.Length;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate input buffer to report our partition device.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
mountTarget = ExAllocatePool(NonPagedPool,
|
|
|
|
|
sizeof(MOUNTMGR_TARGET_NAME) + diskLen);
|
|
|
|
|
|
|
|
|
|
if (!mountTarget) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"ReportToMountMgr: Allocation of mountTarget failed\n"));
|
|
|
|
|
|
|
|
|
|
ObDereferenceObject(fileObject);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mountTarget->DeviceNameLength = diskLen;
|
|
|
|
|
RtlCopyMemory(mountTarget->DeviceName, deviceExtension->DeviceName.Buffer, diskLen);
|
|
|
|
|
|
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Build the IRP used to communicate with the MountMgr.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
|
|
|
|
|
deviceObject,
|
|
|
|
|
mountTarget,
|
|
|
|
|
sizeof(MOUNTMGR_TARGET_NAME) + diskLen,
|
|
|
|
|
NULL,
|
|
|
|
|
0,
|
|
|
|
|
FALSE,
|
|
|
|
|
&event,
|
|
|
|
|
&ioStatus);
|
|
|
|
|
|
|
|
|
|
if (!irp) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"ReportToMountMgr: Allocation of irp failed\n"));
|
|
|
|
|
|
|
|
|
|
ExFreePool(mountTarget);
|
|
|
|
|
ObDereferenceObject(fileObject);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call the MountMgr.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoCallDriver(deviceObject, irp);
|
|
|
|
|
|
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
|
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
|
|
|
|
status = ioStatus.Status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// We're done.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
DPRINT1("Reported to the MountMgr: %lx\n", status);
|
|
|
|
|
|
|
|
|
|
ExFreePool(mountTarget);
|
|
|
|
|
ObDereferenceObject(fileObject);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-09-10 16:25:48 +00:00
|
|
|
|
CreatePartitionDeviceObjects(
|
|
|
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
|
|
|
IN PUNICODE_STRING RegistryPath
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
|
|
|
|
|
ULONG partitionNumber = 0;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
2010-10-12 20:17:55 +00:00
|
|
|
|
PDISK_GEOMETRY_EX diskGeometry = NULL;
|
2007-09-10 16:25:48 +00:00
|
|
|
|
PDRIVE_LAYOUT_INFORMATION partitionList = NULL;
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
|
PDEVICE_EXTENSION physicalDeviceExtension;
|
|
|
|
|
PCLASS_INIT_DATA initData = NULL;
|
|
|
|
|
PDISK_DATA diskData;
|
|
|
|
|
PDISK_DATA physicalDiskData;
|
|
|
|
|
ULONG bytesPerSector;
|
|
|
|
|
UCHAR sectorShift;
|
|
|
|
|
ULONG srbFlags;
|
|
|
|
|
ULONG dmByteSkew = 0;
|
|
|
|
|
PULONG dmSkew;
|
|
|
|
|
BOOLEAN dmActive = FALSE;
|
|
|
|
|
ULONG numberListElements = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get physical device geometry information for partition table reads.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension;
|
|
|
|
|
diskGeometry = physicalDeviceExtension->DiskGeometry;
|
2010-10-12 20:17:55 +00:00
|
|
|
|
bytesPerSector = diskGeometry->Geometry.BytesPerSector;
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Make sure sector size is not zero.
|
|
|
|
|
//
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (bytesPerSector == 0) {
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Default sector size for disk is 512.
|
|
|
|
|
//
|
|
|
|
|
|
2010-10-12 20:17:55 +00:00
|
|
|
|
bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512;
|
2003-04-29 18:06:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
sectorShift = physicalDeviceExtension->SectorShift;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set pointer to disk data area that follows device extension.
|
|
|
|
|
//
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
diskData = (PDISK_DATA)(physicalDeviceExtension + 1);
|
|
|
|
|
diskData->PartitionListState = Initializing;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Determine is DM Driver is loaded on an IDE drive that is
|
|
|
|
|
// under control of Atapi - this could be either a crashdump or
|
|
|
|
|
// an Atapi device is sharing the controller with an IDE disk.
|
|
|
|
|
//
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
HalExamineMBR(PhysicalDeviceObject,
|
2010-10-12 20:17:55 +00:00
|
|
|
|
physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
(ULONG)0x54,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PVOID)&dmSkew);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (dmSkew) {
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Update the device extension, so that the call to IoReadPartitionTable
|
|
|
|
|
// will get the correct information. Any I/O to this disk will have
|
|
|
|
|
// to be skewed by *dmSkew sectors aka DMByteSkew.
|
|
|
|
|
//
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
physicalDeviceExtension->DMSkew = *dmSkew;
|
|
|
|
|
physicalDeviceExtension->DMActive = TRUE;
|
|
|
|
|
physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector;
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Save away the information that we need, since this deviceExtension will soon be
|
2007-04-01 19:25:38 +00:00
|
|
|
|
// blown away.
|
|
|
|
|
//
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
dmActive = TRUE;
|
2007-09-10 16:25:48 +00:00
|
|
|
|
dmByteSkew = physicalDeviceExtension->DMByteSkew;
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
|
|
|
|
}
|
2003-04-27 18:10:38 +00:00
|
|
|
|
|
2019-01-02 19:28:21 +00:00
|
|
|
|
#ifdef __REACTOS__
|
|
|
|
|
//
|
|
|
|
|
// HACK so that we can use NT5+ NTOS functions with this NT4 driver
|
|
|
|
|
// for removable devices and avoid an infinite recursive loop between
|
|
|
|
|
// disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
|
|
|
|
|
//
|
|
|
|
|
diskData->UpdateRemovableGeometryCount = 0;
|
|
|
|
|
#endif
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Create objects for all the partitions on the device.
|
|
|
|
|
//
|
2003-04-27 18:10:38 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
status = IoReadPartitionTable(PhysicalDeviceObject,
|
2010-10-12 20:17:55 +00:00
|
|
|
|
physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
TRUE,
|
|
|
|
|
(PVOID)&partitionList);
|
2003-04-27 10:50:07 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// If the I/O read partition table failed and this is a removable device,
|
|
|
|
|
// then fix up the partition list to make it look like there is one
|
|
|
|
|
// zero length partition.
|
|
|
|
|
//
|
2007-12-11 18:31:13 +00:00
|
|
|
|
DPRINT("IoReadPartitionTable() status: 0x%08X\n", status);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
|
2007-09-10 16:25:48 +00:00
|
|
|
|
PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
|
2003-04-29 18:06:26 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Remember this disk is not ready.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->DriveNotReady = TRUE;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Free the partition list allocated by IoReadPartitionTable.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ExFreePool(partitionList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate and zero a partition list.
|
|
|
|
|
//
|
|
|
|
|
|
2014-07-19 17:48:46 +00:00
|
|
|
|
partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (partitionList != NULL) {
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory( partitionList, sizeof( *partitionList ));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set the partition count to one and the status to success
|
|
|
|
|
// so one device object will be created. Set the partition type
|
|
|
|
|
// to a bogus value.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionList->PartitionCount = 1;
|
|
|
|
|
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Record disk signature.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->Signature = partitionList->Signature;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If disk signature is zero, then calculate the MBR checksum.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!diskData->Signature) {
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
if (!CalculateMbrCheckSum(physicalDeviceExtension,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
&diskData->MbrCheckSum)) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"SCSIDISK: Can't calculate MBR checksum for disk %x\n",
|
2007-09-10 16:25:48 +00:00
|
|
|
|
physicalDeviceExtension->DeviceNumber));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
DebugPrint((2,
|
|
|
|
|
"SCSIDISK: MBR checksum for disk %x is %x\n",
|
2007-09-10 16:25:48 +00:00
|
|
|
|
physicalDeviceExtension->DeviceNumber,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
diskData->MbrCheckSum));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check the registry and determine if the BIOS knew about this drive. If
|
|
|
|
|
// it did then update the geometry with the BIOS information.
|
|
|
|
|
//
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
UpdateGeometry(physicalDeviceExtension);
|
|
|
|
|
|
|
|
|
|
srbFlags = physicalDeviceExtension->SrbFlags;
|
|
|
|
|
|
|
|
|
|
initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA));
|
|
|
|
|
if (!initData)
|
|
|
|
|
{
|
|
|
|
|
DebugPrint((1,
|
2016-11-13 15:31:39 +00:00
|
|
|
|
"Disk.CreatePartitionDeviceObjects - Allocation of initData failed\n"));
|
2007-09-10 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
goto CreatePartitionDeviceObjectsExit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA));
|
|
|
|
|
|
|
|
|
|
initData->InitializationDataSize = sizeof(CLASS_INIT_DATA);
|
|
|
|
|
initData->DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
|
|
|
|
|
initData->DeviceType = FILE_DEVICE_DISK;
|
|
|
|
|
initData->DeviceCharacteristics = PhysicalDeviceObject->Characteristics;
|
|
|
|
|
initData->ClassError = physicalDeviceExtension->ClassError;
|
|
|
|
|
initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification;
|
|
|
|
|
initData->ClassFindDevices = physicalDeviceExtension->ClassFindDevices;
|
|
|
|
|
initData->ClassDeviceControl = physicalDeviceExtension->ClassDeviceControl;
|
|
|
|
|
initData->ClassShutdownFlush = physicalDeviceExtension->ClassShutdownFlush;
|
|
|
|
|
initData->ClassCreateClose = physicalDeviceExtension->ClassCreateClose;
|
|
|
|
|
initData->ClassStartIo = physicalDeviceExtension->ClassStartIo;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Create device objects for the device partitions (if any).
|
|
|
|
|
// PartitionCount includes physical device partition 0,
|
|
|
|
|
// so only one partition means no objects to create.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
DebugPrint((2,
|
|
|
|
|
"CreateDiskDeviceObjects: Number of partitions is %d\n",
|
|
|
|
|
partitionList->PartitionCount));
|
|
|
|
|
|
|
|
|
|
for (partitionNumber = 0; partitionNumber <
|
|
|
|
|
partitionList->PartitionCount; partitionNumber++) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Create partition object and set up partition parameters.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
sprintf(ntNameBuffer,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
"\\Device\\Harddisk%lu\\Partition%lu",
|
2007-09-10 16:25:48 +00:00
|
|
|
|
physicalDeviceExtension->DeviceNumber,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
partitionNumber + 1);
|
|
|
|
|
|
|
|
|
|
DebugPrint((2,
|
|
|
|
|
"CreateDiskDeviceObjects: Create device object %s\n",
|
|
|
|
|
ntNameBuffer));
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ntNameBuffer,
|
2007-09-10 16:25:48 +00:00
|
|
|
|
PhysicalDeviceObject,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
&deviceObject,
|
2007-09-10 16:25:48 +00:00
|
|
|
|
initData);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer));
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set up device object fields.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if this is during initialization. If not indicate that
|
|
|
|
|
// system initialization already took place and this disk is ready
|
|
|
|
|
// to be accessed.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!RegistryPath) {
|
|
|
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set up device extension fields.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
|
|
|
|
|
|
|
|
if (dmActive) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Restore any saved DM values.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->DMByteSkew = dmByteSkew;
|
|
|
|
|
deviceExtension->DMSkew = *dmSkew;
|
|
|
|
|
deviceExtension->DMActive = TRUE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Link new device extension to previous disk data
|
|
|
|
|
// to support dynamic partitioning.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->NextPartition = deviceExtension;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get pointer to new disk data.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set next partition pointer to NULL in case this is the
|
|
|
|
|
// last partition.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->NextPartition = NULL;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate spinlock for zoning for split-request completion.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy port device object pointer to device extension.
|
|
|
|
|
//
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set the alignment requirements for the device based on the
|
|
|
|
|
// host adapter requirements
|
|
|
|
|
//
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
|
|
|
|
|
deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
|
|
|
|
|
numberListElements = 30;
|
|
|
|
|
} else {
|
|
|
|
|
numberListElements = 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Build the lookaside list for srb's for this partition based on
|
|
|
|
|
// whether the adapter and disk can do tagged queueing.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ScsiClassInitializeSrbLookasideList(deviceExtension,
|
|
|
|
|
numberListElements);
|
|
|
|
|
|
|
|
|
|
deviceExtension->SrbFlags = srbFlags;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set the sense-data pointer in the device extension.
|
|
|
|
|
//
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
deviceExtension->SenseData = physicalDeviceExtension->SenseData;
|
|
|
|
|
deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceExtension->DiskGeometry = diskGeometry;
|
|
|
|
|
diskData->PartitionOrdinal = diskData->PartitionNumber = partitionNumber + 1;
|
|
|
|
|
diskData->PartitionType = partitionList->PartitionEntry[partitionNumber].PartitionType;
|
|
|
|
|
diskData->BootIndicator = partitionList->PartitionEntry[partitionNumber].BootIndicator;
|
|
|
|
|
|
|
|
|
|
DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
|
|
|
|
|
diskData->PartitionType));
|
|
|
|
|
|
|
|
|
|
deviceExtension->StartingOffset = partitionList->PartitionEntry[partitionNumber].StartingOffset;
|
|
|
|
|
deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength;
|
|
|
|
|
diskData->HiddenSectors = partitionList->PartitionEntry[partitionNumber].HiddenSectors;
|
2007-09-10 16:25:48 +00:00
|
|
|
|
deviceExtension->PortNumber = physicalDeviceExtension->PortNumber;
|
|
|
|
|
deviceExtension->PathId = physicalDeviceExtension->PathId;
|
|
|
|
|
deviceExtension->TargetId = physicalDeviceExtension->TargetId;
|
|
|
|
|
deviceExtension->Lun = physicalDeviceExtension->Lun;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check for removable media support.
|
|
|
|
|
//
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set timeout value in seconds.
|
|
|
|
|
//
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue;
|
2010-10-12 20:17:55 +00:00
|
|
|
|
deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceExtension->SectorShift = sectorShift;
|
|
|
|
|
deviceExtension->DeviceObject = deviceObject;
|
|
|
|
|
deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags;
|
|
|
|
|
|
2019-10-21 14:50:36 +00:00
|
|
|
|
//
|
|
|
|
|
// Now we're done, report to the MountMgr.
|
|
|
|
|
// This is a HACK required to have the driver
|
|
|
|
|
// handle the associated DosDevices.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ReportToMountMgr(deviceObject);
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
} // end for (partitionNumber) ...
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Free the buffer allocated by reading the
|
|
|
|
|
// partition table.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ExFreePool(partitionList);
|
|
|
|
|
|
2014-07-19 17:48:46 +00:00
|
|
|
|
if (dmSkew) {
|
|
|
|
|
ExFreePool(dmSkew);
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
CreatePartitionDeviceObjectsExit:
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
if (partitionList) {
|
|
|
|
|
ExFreePool(partitionList);
|
|
|
|
|
}
|
|
|
|
|
if (initData) {
|
|
|
|
|
ExFreePool(initData);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-19 17:48:46 +00:00
|
|
|
|
if (dmSkew) {
|
|
|
|
|
ExFreePool(dmSkew);
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
return status;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
} // end if...else
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
|
|
|
|
|
physicalDiskData->PartitionListState = Initialized;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
return(STATUS_SUCCESS);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
} // end CreatePartitionDeviceObjects()
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskReadWriteVerification(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
I/O System entry for read and write requests to SCSI disks.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceObject - Pointer to driver object created by system.
|
|
|
|
|
Irp - IRP involved.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
NT Status
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
|
ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
|
|
|
|
|
LARGE_INTEGER startingOffset;
|
|
|
|
|
|
2014-11-02 23:11:22 +00:00
|
|
|
|
//
|
|
|
|
|
// HACK: How can we end here with null sector size?!
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (deviceExtension->DiskGeometry->Geometry.BytesPerSector == 0) {
|
|
|
|
|
DPRINT1("Hack! Received invalid sector size\n");
|
|
|
|
|
deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// 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.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
|
|
|
|
|
transferByteCount);
|
|
|
|
|
|
|
|
|
|
if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
|
2010-10-12 20:17:55 +00:00
|
|
|
|
(transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// This error maybe caused by the fact that the drive is not ready.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) {
|
|
|
|
|
|
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Flag this as a user error so that a popup is generated.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
|
|
|
|
|
IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Note fastfat depends on this parameter to determine when to
|
|
|
|
|
// remount do to a sector size change.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-02 23:11:22 +00:00
|
|
|
|
if (startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) {
|
|
|
|
|
DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset.QuadPart, deviceExtension->PartitionLength.QuadPart);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1)) {
|
|
|
|
|
DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount, deviceExtension->DiskGeometry->Geometry.BytesPerSector);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) {
|
|
|
|
|
DPRINT1("Failing due to device not ready!\n");
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
|
|
|
|
} // end ScsiDiskReadWrite()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskDeviceControl(
|
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
PIRP Irp
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
I/O system entry for device controls to SCSI disks.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceObject - Pointer to driver object created by system.
|
|
|
|
|
Irp - IRP involved.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
Status is returned.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
|
|
|
PCDB cdb;
|
|
|
|
|
PMODE_PARAMETER_HEADER modeData;
|
|
|
|
|
PIRP irp2;
|
|
|
|
|
ULONG length;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
KEVENT event;
|
|
|
|
|
IO_STATUS_BLOCK ioStatus;
|
|
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
|
|
srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
|
|
|
|
|
|
|
|
|
|
if (srb == NULL) {
|
|
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Write zeros to Srb.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
|
|
|
|
|
|
|
|
|
|
cdb = (PCDB)srb->Cdb;
|
|
|
|
|
|
|
|
|
|
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
|
|
|
|
|
|
case SMART_GET_VERSION: {
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
ULONG_PTR buffer;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
PSRB_IO_CONTROL srbControl;
|
|
|
|
|
PGETVERSIONINPARAMS versionParams;
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
|
|
|
sizeof(GETVERSIONINPARAMS)) {
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Create notification event object to be used to signal the
|
|
|
|
|
// request completion.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
|
|
|
|
|
|
srbControl = ExAllocatePool(NonPagedPool,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
|
|
|
|
|
|
|
|
|
|
if (!srbControl) {
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// fill in srbControl fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
|
|
|
|
|
RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
|
|
|
|
|
srbControl->Timeout = deviceExtension->TimeOutValue;
|
|
|
|
|
srbControl->Length = sizeof(GETVERSIONINPARAMS);
|
|
|
|
|
srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Point to the 'buffer' portion of the SRB_CONTROL
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Ensure correct target is set in the cmd parameters.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
versionParams = (PGETVERSIONINPARAMS)buffer;
|
|
|
|
|
versionParams->bIDEDeviceMap = deviceExtension->TargetId;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy the IOCTL parameters to the srb control buffer area.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
|
|
|
|
|
deviceExtension->PortDeviceObject,
|
|
|
|
|
srbControl,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
|
|
|
|
|
srbControl,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
|
|
|
|
|
FALSE,
|
|
|
|
|
&event,
|
|
|
|
|
&ioStatus);
|
|
|
|
|
|
|
|
|
|
if (irp2 == NULL) {
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call the port driver with the request and wait for it to complete.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
|
|
|
|
|
|
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
|
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
|
|
|
|
status = ioStatus.Status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If successful, copy the data received into the output buffer.
|
|
|
|
|
// This should only fail in the event that the IDE driver is older than this driver.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExFreePool(srbControl);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SMART_RCV_DRIVE_DATA: {
|
|
|
|
|
|
|
|
|
|
PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
|
ULONG controlCode = 0;
|
|
|
|
|
PSRB_IO_CONTROL srbControl;
|
2007-04-05 17:36:39 +00:00
|
|
|
|
ULONG_PTR buffer;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
|
|
|
(sizeof(SENDCMDINPARAMS) - 1)) {
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
} else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
|
|
|
(sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Create notification event object to be used to signal the
|
|
|
|
|
// request completion.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
|
|
|
|
|
|
if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
|
|
|
|
|
|
|
|
|
|
length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
|
|
|
|
|
|
|
|
|
|
} else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
|
|
|
|
|
switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
|
|
|
|
|
case READ_ATTRIBUTES:
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
|
|
|
|
|
length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
|
|
|
|
|
break;
|
|
|
|
|
case READ_THRESHOLDS:
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
|
|
|
|
|
length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (controlCode == 0) {
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srbControl = ExAllocatePool(NonPagedPool,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + length);
|
|
|
|
|
|
|
|
|
|
if (!srbControl) {
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// fill in srbControl fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
|
|
|
|
|
RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
|
|
|
|
|
srbControl->Timeout = deviceExtension->TimeOutValue;
|
|
|
|
|
srbControl->Length = length;
|
|
|
|
|
srbControl->ControlCode = controlCode;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Point to the 'buffer' portion of the SRB_CONTROL
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Ensure correct target is set in the cmd parameters.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
cmdInParameters->bDriveNumber = deviceExtension->TargetId;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy the IOCTL parameters to the srb control buffer area.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
|
|
|
|
|
deviceExtension->PortDeviceObject,
|
|
|
|
|
srbControl,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
|
|
|
|
|
srbControl,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + length,
|
|
|
|
|
FALSE,
|
|
|
|
|
&event,
|
|
|
|
|
&ioStatus);
|
|
|
|
|
|
|
|
|
|
if (irp2 == NULL) {
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call the port driver with the request and wait for it to complete.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
|
|
|
|
|
|
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
|
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
|
|
|
|
status = ioStatus.Status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If successful, copy the data received into the output buffer
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
Irp->IoStatus.Information = length - 1;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExFreePool(srbControl);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SMART_SEND_DRIVE_COMMAND: {
|
|
|
|
|
|
|
|
|
|
PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
|
PSRB_IO_CONTROL srbControl;
|
|
|
|
|
ULONG controlCode = 0;
|
2007-04-05 17:36:39 +00:00
|
|
|
|
ULONG_PTR buffer;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
|
|
|
(sizeof(SENDCMDINPARAMS) - 1)) {
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
} else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
|
|
|
(sizeof(SENDCMDOUTPARAMS) - 1)) {
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Create notification event object to be used to signal the
|
|
|
|
|
// request completion.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
|
|
|
|
|
|
length = 0;
|
|
|
|
|
|
|
|
|
|
if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
|
|
|
|
|
switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
|
|
|
|
|
|
|
|
|
|
case ENABLE_SMART:
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DISABLE_SMART:
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RETURN_SMART_STATUS:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Ensure bBuffer is at least 2 bytes (to hold the values of
|
|
|
|
|
// cylinderLow and cylinderHigh).
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
|
|
|
(sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
|
|
|
|
|
length = sizeof(IDEREGS);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ENABLE_DISABLE_AUTOSAVE:
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SAVE_ATTRIBUTE_VALUES:
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EXECUTE_OFFLINE_DIAGS:
|
|
|
|
|
controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
|
2010-12-28 18:20:28 +00:00
|
|
|
|
break;
|
2014-07-19 17:48:46 +00:00
|
|
|
|
|
2010-12-28 18:20:28 +00:00
|
|
|
|
default:
|
2007-04-01 19:25:38 +00:00
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (controlCode == 0) {
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-25 12:27:47 +00:00
|
|
|
|
length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
srbControl = ExAllocatePool(NonPagedPool,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + length);
|
|
|
|
|
|
|
|
|
|
if (!srbControl) {
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// fill in srbControl fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
|
|
|
|
|
RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
|
|
|
|
|
srbControl->Timeout = deviceExtension->TimeOutValue;
|
|
|
|
|
srbControl->Length = length;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Point to the 'buffer' portion of the SRB_CONTROL
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Ensure correct target is set in the cmd parameters.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
cmdInParameters->bDriveNumber = deviceExtension->TargetId;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy the IOCTL parameters to the srb control buffer area.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
srbControl->ControlCode = controlCode;
|
|
|
|
|
|
|
|
|
|
irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
|
|
|
|
|
deviceExtension->PortDeviceObject,
|
|
|
|
|
srbControl,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
|
|
|
|
|
srbControl,
|
|
|
|
|
sizeof(SRB_IO_CONTROL) + length,
|
|
|
|
|
FALSE,
|
|
|
|
|
&event,
|
|
|
|
|
&ioStatus);
|
|
|
|
|
|
|
|
|
|
if (irp2 == NULL) {
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call the port driver with the request and wait for it to complete.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
|
|
|
|
|
|
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
|
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
|
|
|
|
status = ioStatus.Status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy the data received into the output buffer. Since the status buffer
|
|
|
|
|
// contains error information also, always perform this copy. IO will will
|
|
|
|
|
// either pass this back to the app, or zero it, in case of error.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update the return buffer size based on the sub-command.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
|
|
|
|
|
length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
|
|
|
|
|
} else {
|
|
|
|
|
length = sizeof(SENDCMDOUTPARAMS) - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
Irp->IoStatus.Information = length;
|
|
|
|
|
|
|
|
|
|
ExFreePool(srbControl);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
|
2010-10-12 20:17:55 +00:00
|
|
|
|
case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
|
2007-09-10 16:25:48 +00:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
PDEVICE_EXTENSION physicalDeviceExtension;
|
|
|
|
|
PDISK_DATA physicalDiskData;
|
|
|
|
|
BOOLEAN removable = FALSE;
|
|
|
|
|
BOOLEAN listInitialized = FALSE;
|
2017-03-02 20:03:55 +00:00
|
|
|
|
ULONG copyLength;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2017-03-02 20:03:55 +00:00
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) {
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
|
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2017-03-02 20:03:55 +00:00
|
|
|
|
copyLength = sizeof(DISK_GEOMETRY);
|
|
|
|
|
} else {
|
|
|
|
|
ASSERT(irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX);
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) {
|
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(DISK_GEOMETRY_EX)) {
|
|
|
|
|
copyLength = sizeof(DISK_GEOMETRY_EX);
|
|
|
|
|
} else {
|
|
|
|
|
copyLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
|
|
|
|
|
}
|
2007-04-01 19:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
|
|
physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
|
|
|
|
|
physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA;
|
|
|
|
|
listInitialized = (physicalDiskData->PartitionListState == Initialized);
|
|
|
|
|
|
|
|
|
|
if (removable || (!listInitialized))
|
|
|
|
|
{
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// Issue ReadCapacity to update device extension
|
|
|
|
|
// with information for current media.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (removable) {
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Note the drive is not ready.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->DriveNotReady = TRUE;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Note the drive is now ready.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->DriveNotReady = FALSE;
|
2007-09-10 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
} else if (NT_SUCCESS(status)) {
|
|
|
|
|
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// ReadDriveCapacity was alright, create Partition Objects
|
2007-09-10 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
if (physicalDiskData->PartitionListState == NotInitialized) {
|
|
|
|
|
status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL);
|
|
|
|
|
}
|
2007-04-01 19:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
if (NT_SUCCESS(status)) {
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
//
|
|
|
|
|
// Copy drive geometry information from device extension.
|
|
|
|
|
//
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
|
|
|
|
|
deviceExtension->DiskGeometry,
|
2017-03-02 20:03:55 +00:00
|
|
|
|
copyLength);
|
2007-09-10 16:25:48 +00:00
|
|
|
|
|
|
|
|
|
status = STATUS_SUCCESS;
|
2017-03-02 20:03:55 +00:00
|
|
|
|
Irp->IoStatus.Information = copyLength;
|
2007-09-10 16:25:48 +00:00
|
|
|
|
}
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2007-09-10 16:25:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
case IOCTL_DISK_VERIFY:
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
LARGE_INTEGER byteOffset;
|
|
|
|
|
ULONG sectorOffset;
|
|
|
|
|
USHORT sectorCount;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Validate buffer length.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
|
|
|
sizeof(VERIFY_INFORMATION)) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Verify sectors
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->CdbLength = 10;
|
|
|
|
|
|
|
|
|
|
cdb->CDB10.OperationCode = SCSIOP_VERIFY;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Add disk offset to starting sector.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
|
|
|
|
|
verifyInfo->StartingOffset.QuadPart;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert byte offset to sector offset.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert ULONG byte count to USHORT sector count.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Move little endian values into CDB in big endian format.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3;
|
|
|
|
|
cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2;
|
|
|
|
|
cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1;
|
|
|
|
|
cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0;
|
|
|
|
|
|
|
|
|
|
cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1;
|
|
|
|
|
cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->Byte0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// The verify command is used by the NT FORMAT utility and
|
|
|
|
|
// requests are sent down for 5% of the volume size. The
|
|
|
|
|
// request timeout value is calculated based on the number of
|
|
|
|
|
// sectors verified.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
|
|
|
|
|
deviceExtension->TimeOutValue;
|
|
|
|
|
|
|
|
|
|
status = ScsiClassSendSrbAsynchronous(DeviceObject,
|
|
|
|
|
srb,
|
|
|
|
|
Irp,
|
|
|
|
|
NULL,
|
|
|
|
|
0,
|
|
|
|
|
FALSE);
|
|
|
|
|
|
|
|
|
|
return(status);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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, as this doesn't make any
|
|
|
|
|
// sense.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
|
|
|
sizeof(PARTITION_INFORMATION)) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
2017-12-24 20:54:09 +00:00
|
|
|
|
break;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
}
|
2017-12-24 20:54:09 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update the geometry in case it has changed.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = UpdateRemovableGeometry (DeviceObject, Irp);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
2017-12-24 20:54:09 +00:00
|
|
|
|
// Note the drive is not ready.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
2017-12-24 20:54:09 +00:00
|
|
|
|
diskData->DriveNotReady = TRUE;
|
|
|
|
|
break;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-24 20:54:09 +00:00
|
|
|
|
//
|
|
|
|
|
// Note the drive is now ready.
|
|
|
|
|
//
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2017-12-24 20:54:09 +00:00
|
|
|
|
diskData->DriveNotReady = FALSE;
|
2016-02-22 20:47:55 +00:00
|
|
|
|
|
2017-12-24 20:54:09 +00:00
|
|
|
|
//
|
|
|
|
|
// Handle the case were we query the whole disk
|
|
|
|
|
//
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2017-12-24 20:54:09 +00:00
|
|
|
|
if (diskData->PartitionNumber == 0) {
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2017-12-24 20:54:09 +00:00
|
|
|
|
PPARTITION_INFORMATION outputBuffer;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2017-12-24 20:54:09 +00:00
|
|
|
|
outputBuffer =
|
|
|
|
|
(PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2017-12-24 20:54:09 +00:00
|
|
|
|
outputBuffer->PartitionType = PARTITION_ENTRY_UNUSED;
|
|
|
|
|
outputBuffer->StartingOffset = deviceExtension->StartingOffset;
|
|
|
|
|
outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
|
|
|
|
|
outputBuffer->HiddenSectors = 0;
|
|
|
|
|
outputBuffer->PartitionNumber = diskData->PartitionNumber;
|
|
|
|
|
outputBuffer->BootIndicator = FALSE;
|
|
|
|
|
outputBuffer->RewritePartition = FALSE;
|
|
|
|
|
outputBuffer->RecognizedPartition = FALSE;
|
|
|
|
|
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
PPARTITION_INFORMATION outputBuffer;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
2017-12-24 20:54:09 +00:00
|
|
|
|
// We query a single partition here
|
|
|
|
|
// FIXME: this can only work for MBR-based disks, check for this!
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
outputBuffer =
|
|
|
|
|
(PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
|
|
|
|
|
outputBuffer->PartitionType = diskData->PartitionType;
|
|
|
|
|
outputBuffer->StartingOffset = deviceExtension->StartingOffset;
|
2017-12-24 20:54:09 +00:00
|
|
|
|
outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
outputBuffer->HiddenSectors = diskData->HiddenSectors;
|
|
|
|
|
outputBuffer->PartitionNumber = diskData->PartitionNumber;
|
|
|
|
|
outputBuffer->BootIndicator = diskData->BootIndicator;
|
|
|
|
|
outputBuffer->RewritePartition = FALSE;
|
|
|
|
|
outputBuffer->RecognizedPartition =
|
|
|
|
|
IsRecognizedPartition(diskData->PartitionType);
|
|
|
|
|
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2010-10-19 19:27:28 +00:00
|
|
|
|
case IOCTL_DISK_GET_PARTITION_INFO_EX:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 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, as this doesn't make any
|
|
|
|
|
// sense.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
|
|
|
sizeof(PARTITION_INFORMATION_EX)) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
|
|
|
|
|
|
}
|
2016-02-24 07:55:36 +00:00
|
|
|
|
#if 0 // HACK: ReactOS partition numbers must be wrong
|
2010-10-19 19:27:28 +00:00
|
|
|
|
else if (diskData->PartitionNumber == 0) {
|
|
|
|
|
|
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Partition zero is not a partition so this is not a
|
2010-10-19 19:27:28 +00:00
|
|
|
|
// reasonable request.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
|
|
|
|
|
|
}
|
2016-02-24 07:55:36 +00:00
|
|
|
|
#endif
|
2010-10-19 19:27:28 +00:00
|
|
|
|
else {
|
|
|
|
|
|
|
|
|
|
PPARTITION_INFORMATION_EX outputBuffer;
|
|
|
|
|
|
2016-02-24 07:55:36 +00:00
|
|
|
|
if (diskData->PartitionNumber == 0) {
|
|
|
|
|
DPRINT1("HACK: Handling partition 0 request!\n");
|
|
|
|
|
//ASSERT(FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-19 19:27:28 +00:00
|
|
|
|
//
|
|
|
|
|
// Update the geometry in case it has changed.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = UpdateRemovableGeometry (DeviceObject, Irp);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Note the drive is not ready.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->DriveNotReady = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Note the drive is now ready.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->DriveNotReady = FALSE;
|
|
|
|
|
|
|
|
|
|
if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outputBuffer =
|
|
|
|
|
(PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// FIXME: hack of the year, assume that partition is MBR
|
|
|
|
|
// Thing that can obviously be wrong...
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
|
|
|
|
|
outputBuffer->Mbr.PartitionType = diskData->PartitionType;
|
|
|
|
|
outputBuffer->StartingOffset = deviceExtension->StartingOffset;
|
|
|
|
|
outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
|
|
|
|
|
outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
|
|
|
|
|
outputBuffer->PartitionNumber = diskData->PartitionNumber;
|
|
|
|
|
outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
|
|
|
|
|
outputBuffer->RewritePartition = FALSE;
|
|
|
|
|
outputBuffer->Mbr.RecognizedPartition =
|
|
|
|
|
IsRecognizedPartition(diskData->PartitionType);
|
|
|
|
|
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
case IOCTL_DISK_SET_PARTITION_INFO:
|
|
|
|
|
|
|
|
|
|
if (diskData->PartitionNumber == 0) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
PSET_PARTITION_INFORMATION inputBuffer =
|
|
|
|
|
(PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Validate buffer length.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
|
|
|
sizeof(SET_PARTITION_INFORMATION)) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// The HAL routines IoGet- and IoSetPartitionInformation were
|
|
|
|
|
// developed before support of dynamic partitioning and therefore
|
|
|
|
|
// don't distinguish between partition ordinal (that is the order
|
|
|
|
|
// of a partition on a disk) and the partition number. (The
|
|
|
|
|
// partition number is assigned to a partition to identify it to
|
|
|
|
|
// the system.) Use partition ordinals for these legacy calls.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoSetPartitionInformation(
|
|
|
|
|
deviceExtension->PhysicalDevice,
|
2010-10-12 20:17:55 +00:00
|
|
|
|
deviceExtension->DiskGeometry->Geometry.BytesPerSector,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
diskData->PartitionOrdinal,
|
|
|
|
|
inputBuffer->PartitionType);
|
|
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
diskData->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_INFO_LENGTH_MISMATCH;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
PDRIVE_LAYOUT_INFORMATION partitionList;
|
|
|
|
|
PDEVICE_EXTENSION physicalExtension = deviceExtension;
|
|
|
|
|
PPARTITION_INFORMATION partitionEntry;
|
|
|
|
|
PDISK_DATA diskData;
|
|
|
|
|
ULONG tempSize;
|
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Read partition information.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
|
2010-10-12 20:17:55 +00:00
|
|
|
|
deviceExtension->DiskGeometry->Geometry.BytesPerSector,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
FALSE,
|
|
|
|
|
&partitionList);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// The disk layout has been returned in the partitionList
|
|
|
|
|
// buffer. Determine its size and, if the data will fit
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// into the intermediary buffer, return it.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
|
|
|
|
|
tempSize += partitionList->PartitionCount *
|
|
|
|
|
sizeof(PARTITION_INFORMATION);
|
|
|
|
|
|
|
|
|
|
if (tempSize >
|
|
|
|
|
irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
|
ExFreePool(partitionList);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Walk partition list to associate partition numbers with
|
|
|
|
|
// partition entries.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < partitionList->PartitionCount; i++) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Walk partition chain anchored at physical disk extension.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension = physicalExtension;
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
|
|
deviceExtension = diskData->NextPartition;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if this is the last partition in the chain.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!deviceExtension) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get the partition device extension from disk data.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if this partition is not currently being used.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!deviceExtension->PartitionLength.QuadPart) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
partitionEntry = &partitionList->PartitionEntry[i];
|
|
|
|
|
|
|
|
|
|
//
|
2016-02-29 01:22:02 +00:00
|
|
|
|
// Check if empty, or describes extended partition or hasn't changed.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Partitions match. Update partition number.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionEntry->PartitionNumber =
|
|
|
|
|
diskData->PartitionNumber;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy partition information to system buffer.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
|
|
|
|
|
partitionList,
|
|
|
|
|
tempSize);
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
Irp->IoStatus.Information = tempSize;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Finally, free the buffer allocated by reading the
|
|
|
|
|
// partition table.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ExFreePool(partitionList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IOCTL_DISK_SET_DRIVE_LAYOUT:
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update the disk with new partition information.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Validate buffer length.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
|
|
|
sizeof(DRIVE_LAYOUT_INFORMATION)) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length = sizeof(DRIVE_LAYOUT_INFORMATION) +
|
|
|
|
|
(partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
|
|
|
length) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Verify that device object is for physical disk.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Walk through partition table comparing partitions to
|
|
|
|
|
// existing partitions to create, delete and change
|
|
|
|
|
// device objects as necessary.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
UpdateDeviceObjects(DeviceObject,
|
|
|
|
|
Irp);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Write changes to disk.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoWritePartitionTable(
|
|
|
|
|
deviceExtension->DeviceObject,
|
2010-10-12 20:17:55 +00:00
|
|
|
|
deviceExtension->DiskGeometry->Geometry.BytesPerSector,
|
|
|
|
|
deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
|
|
|
|
|
deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
partitionList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update IRP with bytes returned.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
Irp->IoStatus.Information = length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IOCTL_DISK_REASSIGN_BLOCKS:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Map defective blocks to new location on disk.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
ULONG bufferSize;
|
|
|
|
|
ULONG blockNumber;
|
|
|
|
|
ULONG blockCount;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Validate buffer length.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
|
|
|
sizeof(REASSIGN_BLOCKS)) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bufferSize = sizeof(REASSIGN_BLOCKS) +
|
|
|
|
|
(badBlocks->Count - 1) * sizeof(ULONG);
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
|
|
|
bufferSize) {
|
|
|
|
|
|
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Build the data buffer to be transferred in the input buffer.
|
|
|
|
|
// The format of the data to the device is:
|
|
|
|
|
//
|
|
|
|
|
// 2 bytes Reserved
|
|
|
|
|
// 2 bytes Length
|
|
|
|
|
// x * 4 btyes Block Address
|
|
|
|
|
//
|
|
|
|
|
// All values are big endian.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
badBlocks->Reserved = 0;
|
|
|
|
|
blockCount = badBlocks->Count;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert # of entries to # of bytes.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
blockCount *= 4;
|
|
|
|
|
badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
|
|
|
|
|
badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert back to number of entries.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
blockCount /= 4;
|
|
|
|
|
|
|
|
|
|
for (; blockCount > 0; blockCount--) {
|
|
|
|
|
|
|
|
|
|
blockNumber = badBlocks->BlockNumber[blockCount-1];
|
|
|
|
|
|
|
|
|
|
REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
|
|
|
|
|
(PFOUR_BYTE) &blockNumber);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srb->CdbLength = 6;
|
|
|
|
|
|
|
|
|
|
cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set timeout value.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->TimeOutValue = deviceExtension->TimeOutValue;
|
|
|
|
|
|
|
|
|
|
status = ScsiClassSendSrbSynchronous(DeviceObject,
|
|
|
|
|
srb,
|
|
|
|
|
badBlocks,
|
|
|
|
|
bufferSize,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
|
ExFreePool(srb);
|
|
|
|
|
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(status);
|
|
|
|
|
|
|
|
|
|
case IOCTL_DISK_IS_WRITABLE:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Determine if the device is writable.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
|
|
|
|
|
|
|
|
|
|
if (modeData == NULL) {
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory(modeData, MODE_DATA_SIZE);
|
|
|
|
|
|
|
|
|
|
length = ScsiClassModeSense(DeviceObject,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PCHAR) modeData,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
MODE_DATA_SIZE,
|
|
|
|
|
MODE_SENSE_RETURN_ALL);
|
|
|
|
|
|
|
|
|
|
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Retry the request in case of a check condition.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
length = ScsiClassModeSense(DeviceObject,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PCHAR) modeData,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
MODE_DATA_SIZE,
|
|
|
|
|
MODE_SENSE_RETURN_ALL);
|
|
|
|
|
|
|
|
|
|
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
|
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_INTERNAL_SET_VERIFY:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If the caller is kernel mode, set the verify bit.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (Irp->RequestorMode == KernelMode) {
|
|
|
|
|
DeviceObject->Flags |= DO_VERIFY_VOLUME;
|
|
|
|
|
}
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IOCTL_DISK_FIND_NEW_DEVICES:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Search for devices that have been powered on since the last
|
|
|
|
|
// device search or system initialization.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
|
|
|
|
|
status = DriverEntry(DeviceObject->DriverObject,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
|
ExFreePool(srb);
|
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
case IOCTL_DISK_MEDIA_REMOVAL:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If the disk is not removable then don't allow this command.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
|
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Fall through and let the class driver process the request.
|
|
|
|
|
//
|
|
|
|
|
|
2010-10-31 08:13:33 +00:00
|
|
|
|
case IOCTL_DISK_GET_LENGTH_INFO:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Validate buffer length.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
|
|
|
sizeof(GET_LENGTH_INFORMATION)) {
|
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update the geometry in case it has changed.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = UpdateRemovableGeometry (DeviceObject, Irp);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Note the drive is not ready.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->DriveNotReady = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Note the drive is now ready.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->DriveNotReady = FALSE;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Output data, and return
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
default:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Free the Srb, since it is not needed.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ExFreePool(srb);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Pass the request to the common device control routine.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
return(ScsiClassDeviceControl(DeviceObject, Irp));
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
} // end switch( ...
|
|
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
|
|
|
|
|
|
|
|
|
|
IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
|
ExFreePool(srb);
|
|
|
|
|
return(status);
|
|
|
|
|
|
|
|
|
|
} // end ScsiDiskDeviceControl()
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskShutdownFlush (
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This routine is called for a shutdown and flush IRPs. These are sent by the
|
|
|
|
|
system before it actually shuts down or when the file system does a flush.
|
|
|
|
|
A synchronize cache command is sent to the device if it is write caching.
|
|
|
|
|
If the device is removable an unlock command will be sent. This routine
|
|
|
|
|
will sent a shutdown or flush Srb to the port driver.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DriverObject - Pointer to device object to being shutdown by system.
|
|
|
|
|
|
|
|
|
|
Irp - IRP involved.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
NT Status
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
PCDB cdb;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate SCSI request block.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
|
|
|
|
|
|
|
|
|
|
if (srb == NULL) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set the status and complete the request.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Write length to SRB.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set SCSI bus address.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->PathId = deviceExtension->PathId;
|
|
|
|
|
srb->TargetId = deviceExtension->TargetId;
|
|
|
|
|
srb->Lun = deviceExtension->Lun;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set timeout value and mark the request as not being a tagged request.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
|
|
|
|
|
srb->QueueTag = SP_UNTAGGED;
|
|
|
|
|
srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
|
|
|
|
|
srb->SrbFlags = deviceExtension->SrbFlags;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If the write cache is enabled then send a synchronize cache request.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
|
|
|
|
|
|
|
|
|
|
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
|
|
|
|
|
srb->CdbLength = 10;
|
|
|
|
|
|
|
|
|
|
srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
|
|
|
|
|
|
|
|
|
|
status = ScsiClassSendSrbSynchronous(DeviceObject,
|
|
|
|
|
srb,
|
|
|
|
|
NULL,
|
|
|
|
|
0,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
2016-11-13 15:31:39 +00:00
|
|
|
|
DebugPrint((1, "ScsiDiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status ));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Unlock the device if it is removable and this is a shutdown.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
|
|
|
|
|
|
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
|
|
|
|
|
irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
|
|
|
|
|
|
|
|
|
|
srb->CdbLength = 6;
|
|
|
|
|
cdb = (PVOID) srb->Cdb;
|
|
|
|
|
cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
|
|
|
|
|
cdb->MEDIA_REMOVAL.Prevent = FALSE;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set timeout value.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->TimeOutValue = deviceExtension->TimeOutValue;
|
|
|
|
|
status = ScsiClassSendSrbSynchronous(DeviceObject,
|
|
|
|
|
srb,
|
|
|
|
|
NULL,
|
|
|
|
|
0,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srb->CdbLength = 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Save a few parameters in the current stack location.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
|
|
|
|
|
SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set the retry count to zero.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
irpStack->Parameters.Others.Argument4 = (PVOID) 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set up IoCompletion routine address.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get next stack location and
|
|
|
|
|
// set major function code.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
irpStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
|
|
|
|
|
|
irpStack->MajorFunction = IRP_MJ_SCSI;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set up SRB for execute scsi request.
|
|
|
|
|
// Save SRB address in next stack for port driver.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
irpStack->Parameters.Scsi.Srb = srb;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set up Irp Address.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->OriginalRequest = Irp;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call the port driver to process the request.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
|
|
|
|
|
|
|
|
|
|
} // end ScsiDiskShutdown()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
IsFloppyDevice(
|
|
|
|
|
PDEVICE_OBJECT DeviceObject
|
|
|
|
|
)
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
The routine performs the necessary functions to determine if a device is
|
|
|
|
|
really a floppy rather than a harddisk. This is done by a mode sense
|
2016-11-13 15:31:39 +00:00
|
|
|
|
command. First, a check is made to see if the media type is set. Second
|
2007-04-01 19:25:38 +00:00
|
|
|
|
a check is made for the flexible parameters mode page. Also a check is
|
|
|
|
|
made to see if the write cache is enabled.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceObject - Supplies the device object to be tested.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
Return TRUE if the indicated device is a floppy.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
{
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PVOID modeData;
|
|
|
|
|
PUCHAR pageData;
|
|
|
|
|
ULONG length;
|
|
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
|
|
modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
|
|
|
|
|
|
|
|
|
|
if (modeData == NULL) {
|
|
|
|
|
return(FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory(modeData, MODE_DATA_SIZE);
|
|
|
|
|
|
|
|
|
|
length = ScsiClassModeSense(DeviceObject,
|
|
|
|
|
modeData,
|
|
|
|
|
MODE_DATA_SIZE,
|
|
|
|
|
MODE_SENSE_RETURN_ALL);
|
|
|
|
|
|
|
|
|
|
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Retry the request in case of a check condition.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
length = ScsiClassModeSense(DeviceObject,
|
|
|
|
|
modeData,
|
|
|
|
|
MODE_DATA_SIZE,
|
|
|
|
|
MODE_SENSE_RETURN_ALL);
|
|
|
|
|
|
|
|
|
|
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
|
|
|
|
|
|
ExFreePool(modeData);
|
|
|
|
|
return(FALSE);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If the length is greater than length indicated by the mode data reset
|
|
|
|
|
// the data to the mode data.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
|
|
|
|
|
length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Look for the flexible disk mode page.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
|
|
|
|
|
|
|
|
|
|
if (pageData != NULL) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
|
|
|
|
|
ExFreePool(modeData);
|
|
|
|
|
return(TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check to see if the write cache is enabled.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Assume that write cache is disabled or not supported.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if valid caching page exists.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (pageData != NULL) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if write cache is disabled.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"SCSIDISK: Disk write cache enabled\n"));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if forced unit access (FUA) is supported.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
|
|
|
|
|
|
|
|
|
|
deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"SCSIDISK: Disk does not support FUA or DPO\n"));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// TODO: Log this.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExFreePool(modeData);
|
|
|
|
|
return(FALSE);
|
|
|
|
|
|
|
|
|
|
} // end IsFloppyDevice()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskModeSelect(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PCHAR ModeSelectBuffer,
|
|
|
|
|
IN ULONG Length,
|
|
|
|
|
IN BOOLEAN SavePage
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This routine sends a mode select command.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceObject - Supplies the device object associated with this request.
|
|
|
|
|
|
|
|
|
|
ModeSelectBuffer - Supplies a buffer containing the page data.
|
|
|
|
|
|
|
|
|
|
Length - Supplies the length in bytes of the mode select buffer.
|
|
|
|
|
|
|
|
|
|
SavePage - Indicates that parameters should be written to disk.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
Length of the transferred data is returned.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
{
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PCDB cdb;
|
|
|
|
|
SCSI_REQUEST_BLOCK srb;
|
|
|
|
|
ULONG retries = 1;
|
|
|
|
|
ULONG length2;
|
|
|
|
|
NTSTATUS status;
|
2007-04-05 17:36:39 +00:00
|
|
|
|
ULONG_PTR buffer;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
PMODE_PARAMETER_BLOCK blockDescriptor;
|
|
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
|
|
length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate buffer for mode select header, block descriptor, and mode page.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlZeroMemory((PVOID)buffer, length2);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set length in header to size of mode page.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set size
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
blockDescriptor->BlockLength[1]=0x02;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy mode page to buffer.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Zero SRB.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Build the MODE SELECT CDB.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb.CdbLength = 6;
|
|
|
|
|
cdb = (PCDB)srb.Cdb;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set timeout value from device extension.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
|
|
|
|
|
|
|
|
|
|
cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
|
|
|
|
|
cdb->MODE_SELECT.SPBit = SavePage;
|
|
|
|
|
cdb->MODE_SELECT.PFBit = 1;
|
|
|
|
|
cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
|
|
|
|
|
|
|
|
|
|
Retry:
|
|
|
|
|
|
|
|
|
|
status = ScsiClassSendSrbSynchronous(DeviceObject,
|
|
|
|
|
&srb,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PVOID)buffer,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
length2,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (status == STATUS_VERIFY_REQUIRED) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Routine ScsiClassSendSrbSynchronous does not retry requests returned with
|
|
|
|
|
// this status.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (retries--) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Retry request.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
goto Retry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
ExFreePool((PVOID)buffer);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
return(TRUE);
|
|
|
|
|
} else {
|
|
|
|
|
return(FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // end SciDiskModeSelect()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
DisableWriteCache(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PSCSI_INQUIRY_DATA LunInfo
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
|
|
|
|
|
BAD_CONTROLLER_INFORMATION const *controller;
|
|
|
|
|
ULONG j,length;
|
|
|
|
|
PVOID modeData;
|
|
|
|
|
PUCHAR pageData;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
|
|
|
|
|
|
|
|
|
|
controller = &ScsiDiskBadControllers[j];
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
|
2007-04-01 19:25:38 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
|
|
|
|
|
|
|
|
|
|
modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
|
|
|
|
|
|
|
|
|
|
if (modeData == NULL) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory(modeData, MODE_DATA_SIZE);
|
|
|
|
|
|
|
|
|
|
length = ScsiClassModeSense(DeviceObject,
|
|
|
|
|
modeData,
|
|
|
|
|
MODE_DATA_SIZE,
|
|
|
|
|
MODE_SENSE_RETURN_ALL);
|
|
|
|
|
|
|
|
|
|
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Retry the request in case of a check condition.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
length = ScsiClassModeSense(DeviceObject,
|
|
|
|
|
modeData,
|
|
|
|
|
MODE_DATA_SIZE,
|
|
|
|
|
MODE_SENSE_RETURN_ALL);
|
|
|
|
|
|
|
|
|
|
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
|
|
|
|
|
|
|
|
|
|
ExFreePool(modeData);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If the length is greater than length indicated by the mode data reset
|
|
|
|
|
// the data to the mode data.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
|
|
|
|
|
length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check to see if the write cache is enabled.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Assume that write cache is disabled or not supported.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if valid caching page exists.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (pageData != NULL) {
|
|
|
|
|
|
|
|
|
|
BOOLEAN savePage = FALSE;
|
|
|
|
|
|
|
|
|
|
savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if write cache is disabled.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
|
|
|
|
|
|
|
|
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
|
|
|
LONG errorCode;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Disable write cache and ensure necessary fields are zeroed.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
|
|
|
|
|
((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
|
|
|
|
|
((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
|
|
|
|
|
((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Extract length from caching page.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Compensate for page code and page length.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
length += 2;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Issue mode select to set the parameter.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (ScsiDiskModeSelect(DeviceObject,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PCHAR)pageData,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
length,
|
|
|
|
|
savePage)) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"SCSIDISK: Disk write cache disabled\n"));
|
|
|
|
|
|
|
|
|
|
deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
|
|
|
|
|
errorCode = IO_WRITE_CACHE_DISABLED;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
if (ScsiDiskModeSelect(DeviceObject,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PCHAR)pageData,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
length,
|
|
|
|
|
savePage)) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"SCSIDISK: Disk write cache disabled\n"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
|
|
|
|
|
errorCode = IO_WRITE_CACHE_DISABLED;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"SCSIDISK: Mode select to disable write cache failed\n"));
|
|
|
|
|
|
|
|
|
|
deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
|
|
|
|
|
errorCode = IO_WRITE_CACHE_ENABLED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Log the appropriate informational or error entry.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
|
|
|
|
DeviceObject,
|
|
|
|
|
sizeof(IO_ERROR_LOG_PACKET) + 3
|
|
|
|
|
* sizeof(ULONG));
|
|
|
|
|
|
|
|
|
|
if (errorLogEntry != NULL) {
|
|
|
|
|
|
|
|
|
|
errorLogEntry->FinalStatus = STATUS_SUCCESS;
|
|
|
|
|
errorLogEntry->ErrorCode = errorCode;
|
|
|
|
|
errorLogEntry->SequenceNumber = 0;
|
|
|
|
|
errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
|
|
|
|
|
errorLogEntry->IoControlCode = 0;
|
|
|
|
|
errorLogEntry->RetryCount = 0;
|
|
|
|
|
errorLogEntry->UniqueErrorValue = 0x1;
|
|
|
|
|
errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
|
|
|
|
|
errorLogEntry->DumpData[0] = LunInfo->PathId;
|
|
|
|
|
errorLogEntry->DumpData[1] = LunInfo->TargetId;
|
|
|
|
|
errorLogEntry->DumpData[2] = LunInfo->Lun;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Write the error log packet.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Found device so exit the loop and return.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
CalculateMbrCheckSum(
|
|
|
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
|
|
|
OUT PULONG Checksum
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
Read MBR and calculate checksum.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceExtension - Supplies a pointer to the device information for disk.
|
|
|
|
|
Checksum - Memory location to return MBR checksum.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
Returns TRUE if checksum is valid.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
{
|
|
|
|
|
LARGE_INTEGER sectorZero;
|
|
|
|
|
PIRP irp;
|
|
|
|
|
IO_STATUS_BLOCK ioStatus;
|
|
|
|
|
KEVENT event;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
ULONG sectorSize;
|
|
|
|
|
PULONG mbr;
|
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
sectorZero.QuadPart = (LONGLONG) 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Create notification event object to be used to signal the inquiry
|
|
|
|
|
// request completion.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get sector size.
|
|
|
|
|
//
|
|
|
|
|
|
2010-10-12 20:17:55 +00:00
|
|
|
|
sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Make sure sector size is at least 512 bytes.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (sectorSize < 512) {
|
|
|
|
|
sectorSize = 512;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate buffer for sector read.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
|
|
|
|
|
|
|
|
|
|
if (!mbr) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Build IRP to read MBR.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
|
|
|
|
|
DeviceExtension->DeviceObject,
|
|
|
|
|
mbr,
|
|
|
|
|
sectorSize,
|
|
|
|
|
§orZero,
|
|
|
|
|
&event,
|
|
|
|
|
&ioStatus );
|
|
|
|
|
|
|
|
|
|
if (!irp) {
|
|
|
|
|
ExFreePool(mbr);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Pass request to port driver and wait for request to complete.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoCallDriver(DeviceExtension->DeviceObject,
|
|
|
|
|
irp);
|
|
|
|
|
|
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
|
KeWaitForSingleObject(&event,
|
|
|
|
|
Suspended,
|
|
|
|
|
KernelMode,
|
|
|
|
|
FALSE,
|
|
|
|
|
NULL);
|
|
|
|
|
status = ioStatus.Status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
ExFreePool(mbr);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Calculate MBR checksum.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
*Checksum = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 128; i++) {
|
|
|
|
|
*Checksum += mbr[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*Checksum = ~*Checksum + 1;
|
|
|
|
|
|
|
|
|
|
ExFreePool(mbr);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
EnumerateBusKey(
|
|
|
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
|
|
|
HANDLE BusKey,
|
|
|
|
|
PULONG DiskNumber
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
The routine queries the registry to determine if this disk is visible to
|
2016-11-13 15:31:39 +00:00
|
|
|
|
the BIOS. If the disk is visible to the BIOS, then the geometry information
|
2007-04-01 19:25:38 +00:00
|
|
|
|
is updated.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceExtension - Supplies a pointer to the device information for disk.
|
|
|
|
|
Signature - Unique identifier recorded in MBR.
|
|
|
|
|
BusKey - Handle of bus key.
|
|
|
|
|
DiskNumber - Returns ordinal of disk as BIOS sees it.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
TRUE is disk signature matched.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
{
|
|
|
|
|
PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1);
|
|
|
|
|
BOOLEAN diskFound = FALSE;
|
|
|
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
|
UNICODE_STRING unicodeString;
|
|
|
|
|
UNICODE_STRING identifier;
|
|
|
|
|
ULONG busNumber;
|
|
|
|
|
ULONG adapterNumber;
|
|
|
|
|
ULONG diskNumber;
|
|
|
|
|
HANDLE adapterKey;
|
|
|
|
|
HANDLE spareKey;
|
|
|
|
|
HANDLE diskKey;
|
|
|
|
|
HANDLE targetKey;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
STRING string;
|
|
|
|
|
STRING anotherString;
|
|
|
|
|
ULONG length;
|
|
|
|
|
UCHAR buffer[20];
|
|
|
|
|
PKEY_VALUE_FULL_INFORMATION keyData;
|
|
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
|
|
for (busNumber = 0; ; busNumber++) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Open controller name key.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
sprintf((PCHAR)buffer,
|
|
|
|
|
"%lu",
|
2007-04-01 19:25:38 +00:00
|
|
|
|
busNumber);
|
|
|
|
|
|
|
|
|
|
RtlInitString(&string,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PCSZ)buffer);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
status = RtlAnsiStringToUnicodeString(&unicodeString,
|
|
|
|
|
&string,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)){
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
|
|
|
&unicodeString,
|
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
|
BusKey,
|
|
|
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
|
|
|
|
|
|
status = ZwOpenKey(&spareKey,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
&objectAttributes);
|
|
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&unicodeString);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Open up controller ordinal key.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&unicodeString, L"DiskController");
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
|
|
|
&unicodeString,
|
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
|
spareKey,
|
|
|
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
|
|
|
|
|
|
status = ZwOpenKey(&adapterKey,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
&objectAttributes);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// This could fail even with additional adapters of this type
|
|
|
|
|
// to search.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (adapterNumber = 0; ; adapterNumber++) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Open disk key.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
sprintf((PCHAR)buffer,
|
|
|
|
|
"%lu\\DiskPeripheral",
|
2007-04-01 19:25:38 +00:00
|
|
|
|
adapterNumber);
|
|
|
|
|
|
|
|
|
|
RtlInitString(&string,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PCSZ)buffer);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
status = RtlAnsiStringToUnicodeString(&unicodeString,
|
|
|
|
|
&string,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)){
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
|
|
|
&unicodeString,
|
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
|
adapterKey,
|
|
|
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
|
|
|
|
|
|
status = ZwOpenKey(&diskKey,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
&objectAttributes);
|
|
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&unicodeString);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (diskNumber = 0; ; diskNumber++) {
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
sprintf((PCHAR)buffer,
|
|
|
|
|
"%lu",
|
2007-04-01 19:25:38 +00:00
|
|
|
|
diskNumber);
|
|
|
|
|
|
|
|
|
|
RtlInitString(&string,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PCSZ)buffer);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
status = RtlAnsiStringToUnicodeString(&unicodeString,
|
|
|
|
|
&string,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)){
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
|
|
|
&unicodeString,
|
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
|
diskKey,
|
|
|
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
|
|
|
|
|
|
status = ZwOpenKey(&targetKey,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
&objectAttributes);
|
|
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&unicodeString);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate buffer for registry query.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
|
|
|
|
|
|
|
|
|
|
if (keyData == NULL) {
|
|
|
|
|
ZwClose(targetKey);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get disk peripheral identifier.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&unicodeString, L"Identifier");
|
|
|
|
|
status = ZwQueryValueKey(targetKey,
|
|
|
|
|
&unicodeString,
|
|
|
|
|
KeyValueFullInformation,
|
|
|
|
|
keyData,
|
|
|
|
|
VALUE_BUFFER_SIZE,
|
|
|
|
|
&length);
|
|
|
|
|
|
|
|
|
|
ZwClose(targetKey);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
2017-05-08 21:34:07 +00:00
|
|
|
|
ExFreePool(keyData);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (keyData->DataLength < 9*sizeof(WCHAR)) {
|
|
|
|
|
//
|
|
|
|
|
// the data is too short to use (we subtract 9 chars in normal path)
|
|
|
|
|
//
|
|
|
|
|
DebugPrint((1, "EnumerateBusKey: Saved data was invalid, "
|
|
|
|
|
"not enough data in registry!\n"));
|
|
|
|
|
ExFreePool(keyData);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Complete unicode string.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
identifier.Buffer =
|
|
|
|
|
(PWSTR)((PUCHAR)keyData + keyData->DataOffset);
|
|
|
|
|
identifier.Length = (USHORT)keyData->DataLength;
|
|
|
|
|
identifier.MaximumLength = (USHORT)keyData->DataLength;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert unicode identifier to ansi string.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status =
|
|
|
|
|
RtlUnicodeStringToAnsiString(&anotherString,
|
|
|
|
|
&identifier,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
2017-05-08 21:34:07 +00:00
|
|
|
|
ExFreePool(keyData);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If checksum is zero, then the MBR is valid and
|
|
|
|
|
// the signature is meaningful.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (diskData->MbrCheckSum) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert checksum to ansi string.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert signature to ansi string.
|
|
|
|
|
//
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
sprintf((PCHAR)buffer, "%08lx", diskData->Signature);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Make string point at signature. Can't use scan
|
|
|
|
|
// functions because they are not exported for driver use.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
anotherString.Buffer+=9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert to ansi string.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlInitString(&string,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
(PCSZ)buffer);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Make string lengths equal.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
anotherString.Length = string.Length;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if strings match.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (RtlCompareString(&string,
|
|
|
|
|
&anotherString,
|
|
|
|
|
TRUE) == 0) {
|
|
|
|
|
|
|
|
|
|
diskFound = TRUE;
|
|
|
|
|
*DiskNumber = diskNumber;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExFreePool(keyData);
|
|
|
|
|
|
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Readjust identifier string if necessary.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!diskData->MbrCheckSum) {
|
|
|
|
|
anotherString.Buffer-=9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtlFreeAnsiString(&anotherString);
|
|
|
|
|
|
|
|
|
|
if (diskFound) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZwClose(diskKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZwClose(adapterKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZwClose(BusKey);
|
|
|
|
|
return diskFound;
|
|
|
|
|
|
|
|
|
|
} // end EnumerateBusKey()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
UpdateGeometry(
|
|
|
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
|
|
|
)
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
The routine queries the registry to determine if this disk is visible to
|
2016-11-13 15:31:39 +00:00
|
|
|
|
the BIOS. If the disk is visible to the BIOS, then the geometry information
|
2007-04-01 19:25:38 +00:00
|
|
|
|
is updated.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceExtension - Supplies a pointer to the device information for disk.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
|
UNICODE_STRING unicodeString;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
HANDLE hardwareKey;
|
|
|
|
|
HANDLE busKey;
|
|
|
|
|
PCM_INT13_DRIVE_PARAMETER driveParameters;
|
|
|
|
|
PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
|
|
|
|
|
PKEY_VALUE_FULL_INFORMATION keyData;
|
|
|
|
|
ULONG diskNumber;
|
|
|
|
|
PUCHAR buffer;
|
|
|
|
|
ULONG length;
|
|
|
|
|
ULONG numberOfDrives;
|
|
|
|
|
ULONG cylinders;
|
|
|
|
|
ULONG sectors;
|
|
|
|
|
ULONG sectorsPerTrack;
|
|
|
|
|
ULONG tracksPerCylinder;
|
|
|
|
|
BOOLEAN foundEZHooker;
|
|
|
|
|
PVOID tmpPtr;
|
|
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Initialize the object for the key.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
|
|
|
DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
|
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
|
NULL,
|
|
|
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Create the hardware base key.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = ZwOpenKey(&hardwareKey,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
&objectAttributes);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get disk BIOS geometry information.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&unicodeString, L"Configuration Data");
|
|
|
|
|
|
|
|
|
|
keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
|
|
|
|
|
|
|
|
|
|
if (keyData == NULL) {
|
|
|
|
|
ZwClose(hardwareKey);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = ZwQueryValueKey(hardwareKey,
|
|
|
|
|
&unicodeString,
|
|
|
|
|
KeyValueFullInformation,
|
|
|
|
|
keyData,
|
|
|
|
|
VALUE_BUFFER_SIZE,
|
|
|
|
|
&length);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
DebugPrint((1,
|
|
|
|
|
"SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
|
|
|
|
|
status));
|
2017-05-08 21:34:07 +00:00
|
|
|
|
ZwClose(hardwareKey);
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ExFreePool(keyData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Open EISA bus key.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
|
|
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
|
|
|
&unicodeString,
|
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
|
hardwareKey,
|
|
|
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
|
|
|
|
|
|
status = ZwOpenKey(&busKey,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
&objectAttributes);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
goto openMultiKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DebugPrint((3,
|
|
|
|
|
"SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
|
|
|
|
|
if (EnumerateBusKey(DeviceExtension,
|
|
|
|
|
busKey,
|
|
|
|
|
&diskNumber)) {
|
|
|
|
|
|
|
|
|
|
ZwClose(hardwareKey);
|
|
|
|
|
goto diskMatched;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
openMultiKey:
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Open Multifunction bus key.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
|
|
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
|
|
|
&unicodeString,
|
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
|
hardwareKey,
|
|
|
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
|
|
|
|
|
|
status = ZwOpenKey(&busKey,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
&objectAttributes);
|
|
|
|
|
|
|
|
|
|
ZwClose(hardwareKey);
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
DebugPrint((3,
|
|
|
|
|
"SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
|
|
|
|
|
if (EnumerateBusKey(DeviceExtension,
|
|
|
|
|
busKey,
|
|
|
|
|
&diskNumber)) {
|
|
|
|
|
|
|
|
|
|
goto diskMatched;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExFreePool(keyData);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
diskMatched:
|
|
|
|
|
|
|
|
|
|
resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData +
|
|
|
|
|
keyData->DataOffset);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check that the data is long enough to hold a full resource descriptor,
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// and that the last resource list is device-specific and long enough.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) ||
|
|
|
|
|
resourceDescriptor->PartialResourceList.Count == 0 ||
|
|
|
|
|
resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type !=
|
|
|
|
|
CmResourceTypeDeviceSpecific ||
|
|
|
|
|
resourceDescriptor->PartialResourceList.PartialDescriptors[0]
|
|
|
|
|
.u.DeviceSpecificData.DataSize < sizeof(ULONG)) {
|
|
|
|
|
|
|
|
|
|
DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
|
|
|
|
|
ExFreePool(keyData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
length =
|
|
|
|
|
resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Point to the BIOS data. The BIOS data is located after the first
|
|
|
|
|
// partial Resource list which should be device specific data.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
buffer = (PUCHAR) keyData + keyData->DataOffset +
|
|
|
|
|
sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Use the defaults if the drive number is greater than the
|
|
|
|
|
// number of drives detected by the BIOS.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (numberOfDrives <= diskNumber) {
|
|
|
|
|
ExFreePool(keyData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Point to the array of drive parameters.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber;
|
|
|
|
|
cylinders = driveParameters->MaxCylinders + 1;
|
|
|
|
|
sectorsPerTrack = driveParameters->SectorsPerTrack;
|
|
|
|
|
tracksPerCylinder = driveParameters->MaxHeads +1;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Calculate the actual number of sectors.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >>
|
|
|
|
|
DeviceExtension->SectorShift);
|
|
|
|
|
|
|
|
|
|
#if DBG
|
|
|
|
|
if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) {
|
|
|
|
|
DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
|
|
|
|
|
"SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
|
|
|
|
|
sectors, cylinders, tracksPerCylinder, sectorsPerTrack));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Since the BIOS may not report the full drive, recalculate the drive
|
|
|
|
|
// size based on the volume size and the BIOS values for tracks per
|
|
|
|
|
// cylinder and sectors per track..
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
length = tracksPerCylinder * sectorsPerTrack;
|
|
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// The BIOS information is bogus.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
|
|
|
|
|
ExFreePool(keyData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cylinders = sectors / length;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update the actual geometry information.
|
|
|
|
|
//
|
|
|
|
|
|
2010-10-12 20:17:55 +00:00
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack;
|
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder;
|
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders;
|
2016-11-03 21:38:56 +00:00
|
|
|
|
DeviceExtension->DiskGeometry->DiskSize.QuadPart = (LONGLONG)cylinders * tracksPerCylinder * sectorsPerTrack *
|
2010-10-12 20:17:55 +00:00
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
DebugPrint((3,
|
|
|
|
|
"SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
|
|
|
|
|
sectorsPerTrack,
|
|
|
|
|
tracksPerCylinder,
|
|
|
|
|
cylinders));
|
|
|
|
|
|
|
|
|
|
ExFreePool(keyData);
|
|
|
|
|
|
|
|
|
|
foundEZHooker = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!DeviceExtension->DMActive) {
|
|
|
|
|
|
|
|
|
|
HalExamineMBR(DeviceExtension->DeviceObject,
|
2010-10-12 20:17:55 +00:00
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.BytesPerSector,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
(ULONG)0x55,
|
|
|
|
|
&tmpPtr
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (tmpPtr) {
|
|
|
|
|
|
|
|
|
|
ExFreePool(tmpPtr);
|
|
|
|
|
foundEZHooker = TRUE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DeviceExtension->DMActive || foundEZHooker) {
|
|
|
|
|
|
|
|
|
|
while (cylinders > 1024) {
|
|
|
|
|
|
|
|
|
|
tracksPerCylinder = tracksPerCylinder*2;
|
|
|
|
|
cylinders = cylinders/2;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// int 13 values are always 1 less.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
tracksPerCylinder -= 1;
|
|
|
|
|
cylinders -= 1;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// DM reserves the CE cylinder
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
cylinders -= 1;
|
|
|
|
|
|
2010-10-12 20:17:55 +00:00
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1;
|
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
DeviceExtension->PartitionLength.QuadPart =
|
2010-10-12 20:17:55 +00:00
|
|
|
|
DeviceExtension->DiskGeometry->DiskSize.QuadPart =
|
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart *
|
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack *
|
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.BytesPerSector *
|
|
|
|
|
DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (DeviceExtension->DMActive) {
|
|
|
|
|
|
2010-10-12 20:17:55 +00:00
|
|
|
|
DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
DeviceExtension->DMByteSkew = 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
} // end UpdateGeometry()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
UpdateRemovableGeometry (
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
IN PIRP Irp
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This routines updates the size and starting offset of the device. This is
|
|
|
|
|
used when the media on the device may have changed thereby changing the
|
|
|
|
|
size of the device. If this is the physical device then a
|
|
|
|
|
ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceObject - Supplies the device object whos size needs to be updated.
|
|
|
|
|
|
|
|
|
|
Irp - Supplies a reference where the status can be updated.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
2016-11-13 15:31:39 +00:00
|
|
|
|
Returns the status of the operation.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PDRIVE_LAYOUT_INFORMATION partitionList;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
PDISK_DATA diskData;
|
|
|
|
|
ULONG partitionNumber;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Determine if the size of the partition may have changed because
|
|
|
|
|
// the media has changed.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
|
|
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If this request is for partition zero then do a read drive
|
|
|
|
|
// capacity otherwise do a I/O read partition table.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData = (PDISK_DATA) (deviceExtension + 1);
|
|
|
|
|
|
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Read the drive capacity. If that fails, give up.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
return(status);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 19:28:21 +00:00
|
|
|
|
#ifdef __REACTOS__
|
|
|
|
|
//
|
|
|
|
|
// HACK so that we can use NT5+ NTOS functions with this NT4 driver
|
|
|
|
|
// for removable devices and avoid an infinite recursive loop between
|
|
|
|
|
// disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
|
|
|
|
|
//
|
|
|
|
|
// Check whether the update-count is greater or equal than one
|
|
|
|
|
// (and increase it) and if so, reset it and return success.
|
|
|
|
|
if (diskData->UpdateRemovableGeometryCount++ >= 1)
|
|
|
|
|
{
|
|
|
|
|
diskData->UpdateRemovableGeometryCount = 0;
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Read the partition table again.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
|
2010-10-12 20:17:55 +00:00
|
|
|
|
deviceExtension->DiskGeometry->Geometry.BytesPerSector,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
TRUE,
|
|
|
|
|
&partitionList);
|
|
|
|
|
|
2019-01-02 19:28:21 +00:00
|
|
|
|
#ifdef __REACTOS__
|
|
|
|
|
//
|
|
|
|
|
// HACK so that we can use NT5+ NTOS functions with this NT4 driver
|
|
|
|
|
// for removable devices and avoid an infinite recursive loop between
|
|
|
|
|
// disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
|
|
|
|
|
//
|
|
|
|
|
// Inconditionally reset the update-count.
|
|
|
|
|
diskData->UpdateRemovableGeometryCount = 0;
|
|
|
|
|
#endif
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Fail the request.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
return(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (diskData->PartitionNumber != 0 &&
|
|
|
|
|
diskData->PartitionNumber <= partitionList->PartitionCount ) {
|
|
|
|
|
|
|
|
|
|
partitionNumber = diskData->PartitionNumber - 1;
|
|
|
|
|
|
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Update the partition information for this partition.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->PartitionType =
|
|
|
|
|
partitionList->PartitionEntry[partitionNumber].PartitionType;
|
|
|
|
|
|
|
|
|
|
diskData->BootIndicator =
|
|
|
|
|
partitionList->PartitionEntry[partitionNumber].BootIndicator;
|
|
|
|
|
|
|
|
|
|
deviceExtension->StartingOffset =
|
|
|
|
|
partitionList->PartitionEntry[partitionNumber].StartingOffset;
|
|
|
|
|
|
|
|
|
|
deviceExtension->PartitionLength =
|
|
|
|
|
partitionList->PartitionEntry[partitionNumber].PartitionLength;
|
|
|
|
|
|
|
|
|
|
diskData->HiddenSectors =
|
|
|
|
|
partitionList->PartitionEntry[partitionNumber].HiddenSectors;
|
|
|
|
|
|
|
|
|
|
deviceExtension->SectorShift = ((PDEVICE_EXTENSION)
|
|
|
|
|
deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift;
|
|
|
|
|
|
|
|
|
|
} else if (diskData->PartitionNumber != 0) {
|
|
|
|
|
|
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// The partition does not exist. Zero all the data.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->PartitionType = 0;
|
|
|
|
|
diskData->BootIndicator = 0;
|
|
|
|
|
diskData->HiddenSectors = 0;
|
|
|
|
|
deviceExtension->StartingOffset.QuadPart = (LONGLONG)0;
|
|
|
|
|
deviceExtension->PartitionLength.QuadPart = (LONGLONG)0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
2016-11-13 15:31:39 +00:00
|
|
|
|
// Free the partition list allocate by I/O read partition table.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ExFreePool(partitionList);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScsiDiskProcessError(
|
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
PSCSI_REQUEST_BLOCK Srb,
|
|
|
|
|
NTSTATUS *Status,
|
|
|
|
|
BOOLEAN *Retry
|
|
|
|
|
)
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This routine checks the type of error. If the error indicates an underrun
|
|
|
|
|
then indicate the request should be retried.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceObject - Supplies a pointer to the device object.
|
|
|
|
|
|
|
|
|
|
Srb - Supplies a pointer to the failing Srb.
|
|
|
|
|
|
|
|
|
|
Status - Status with which the IRP will be completed.
|
|
|
|
|
|
|
|
|
|
Retry - Indication of whether the request will be retried.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
|
|
|
|
|
if (*Status == STATUS_DATA_OVERRUN &&
|
|
|
|
|
( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) {
|
|
|
|
|
|
|
|
|
|
*Retry = TRUE;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update the error count for the device.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->ErrorCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
|
|
|
|
|
Srb->ScsiStatus == SCSISTAT_BUSY) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// The disk drive should never be busy this long. Reset the scsi bus
|
|
|
|
|
// maybe this will clear the condition.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ResetScsiBus(DeviceObject);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update the error count for the device.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->ErrorCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ScanForSpecial(
|
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
|
PSCSI_INQUIRY_DATA LunInfo,
|
|
|
|
|
PIO_SCSI_CAPABILITIES PortCapabilities
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
2016-11-13 15:31:39 +00:00
|
|
|
|
This function checks to see if an SCSI logical unit requires special
|
2007-04-01 19:25:38 +00:00
|
|
|
|
flags to be set.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceObject - Supplies the device object to be tested.
|
|
|
|
|
|
|
|
|
|
InquiryData - Supplies the inquiry data returned by the device of interest.
|
|
|
|
|
|
|
|
|
|
PortCapabilities - Supplies the capabilities of the device object.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
|
|
|
|
|
BAD_CONTROLLER_INFORMATION const *controller;
|
2007-04-05 17:36:39 +00:00
|
|
|
|
ULONG j;
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
|
|
|
|
|
|
|
|
|
|
controller = &ScsiDiskBadControllers[j];
|
|
|
|
|
|
2007-04-05 17:36:39 +00:00
|
|
|
|
if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
|
2007-04-01 19:25:38 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Found a listed controller. Determine what must be done.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (controller->DisableTaggedQueuing) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Disable tagged queuing.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (controller->DisableSynchronousTransfers) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Disable synchronous data transfers.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (controller->DisableDisconnects) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Disable disconnects.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Found device so exit the loop and return.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set the StartUnit flag appropriately.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (DeviceObject->DeviceType == FILE_DEVICE_DISK) {
|
|
|
|
|
deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT;
|
|
|
|
|
|
|
|
|
|
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
|
2007-04-05 17:36:39 +00:00
|
|
|
|
if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) {
|
2007-04-01 19:25:38 +00:00
|
|
|
|
deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
ResetScsiBus(
|
|
|
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
|
|
This command sends a reset bus command to the SCSI port driver.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
DeviceObject - The device object for the logical unit with
|
|
|
|
|
hardware problem.
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
{
|
|
|
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
|
PIRP irp;
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
|
|
|
PCOMPLETION_CONTEXT context;
|
|
|
|
|
|
|
|
|
|
DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate Srb from nonpaged pool.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
context = ExAllocatePool(NonPagedPoolMustSucceed,
|
|
|
|
|
sizeof(COMPLETION_CONTEXT));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Save the device object in the context for use by the completion
|
|
|
|
|
// routine.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
context->DeviceObject = DeviceObject;
|
|
|
|
|
srb = &context->Srb;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Zero out srb.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Write length to SRB.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set up SCSI bus address.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
srb->PathId = deviceExtension->PathId;
|
|
|
|
|
srb->TargetId = deviceExtension->TargetId;
|
|
|
|
|
srb->Lun = deviceExtension->Lun;
|
|
|
|
|
|
|
|
|
|
srb->Function = SRB_FUNCTION_RESET_BUS;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Build the asynchronous request to be sent to the port driver.
|
|
|
|
|
// Since this routine is called from a DPC the IRP should always be
|
|
|
|
|
// available.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
|
|
|
|
|
|
|
|
IoSetCompletionRoutine(irp,
|
|
|
|
|
(PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
|
|
|
|
|
context,
|
|
|
|
|
TRUE,
|
|
|
|
|
TRUE,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
irpStack = IoGetNextIrpStackLocation(irp);
|
|
|
|
|
|
|
|
|
|
irpStack->MajorFunction = IRP_MJ_SCSI;
|
|
|
|
|
|
|
|
|
|
srb->OriginalRequest = irp;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Store the SRB address in next stack for port driver.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
irpStack->Parameters.Scsi.Srb = srb;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call the port driver with the IRP.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
IoCallDriver(deviceExtension->PortDeviceObject, irp);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
} // end ResetScsiBus()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-11-30 11:16:55 +00:00
|
|
|
|
NTAPI
|
2007-04-01 19:25:38 +00:00
|
|
|
|
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 drive layout information for the user. It is possible to
|
|
|
|
|
call this routine even in the GET_LAYOUT case because RewritePartition
|
|
|
|
|
will be 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;
|
|
|
|
|
ULONG partitionOrdinal;
|
|
|
|
|
PPARTITION_INFORMATION partitionEntry;
|
|
|
|
|
CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
|
|
|
|
|
STRING ntNameString;
|
|
|
|
|
UNICODE_STRING ntUnicodeString;
|
|
|
|
|
PDEVICE_OBJECT deviceObject;
|
|
|
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
|
PDISK_DATA diskData;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
ULONG numberListElements;
|
|
|
|
|
BOOLEAN found;
|
|
|
|
|
|
|
|
|
|
partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 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;
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
lastPartition = 0;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
|
|
deviceExtension = diskData->NextPartition;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if this is the last partition in the chain.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!deviceExtension) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get the partition device extension from disk data.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check for highest partition number this far.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (diskData->PartitionNumber > lastPartition) {
|
|
|
|
|
lastPartition = diskData->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;
|
|
|
|
|
partitionOrdinal = 0;
|
|
|
|
|
|
|
|
|
|
for (partition = 0; partition < partitionCount; partition++) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get partition descriptor.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionEntry = &partitionList->PartitionEntry[partition];
|
|
|
|
|
|
|
|
|
|
//
|
2016-02-29 01:22:02 +00:00
|
|
|
|
// Check if empty, or describes extended partition or hasn't changed.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
|
|
|
|
|
IsContainerPartition(partitionEntry->PartitionType)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Advance partition ordinal.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionOrdinal++;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 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) {
|
|
|
|
|
|
2015-06-07 13:44:49 +00:00
|
|
|
|
DebugPrint((3,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
"UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
|
|
|
|
|
physicalExtension->DeviceNumber,
|
2015-06-07 13:44:49 +00:00
|
|
|
|
diskData->PartitionNumber));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Indicate match is found and set partition number
|
|
|
|
|
// in user buffer.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
found = TRUE;
|
|
|
|
|
partitionEntry->PartitionNumber = diskData->PartitionNumber;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// A match is found.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If this partition is marked for update then update partition type.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (partitionEntry->RewritePartition) {
|
|
|
|
|
diskData->PartitionType = partitionEntry->PartitionType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update partitional ordinal for calls to HAL routine
|
|
|
|
|
// IoSetPartitionInformation.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->PartitionOrdinal = partitionOrdinal;
|
|
|
|
|
|
2015-06-07 13:44:49 +00:00
|
|
|
|
DebugPrint((1,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
"UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
|
|
|
|
|
physicalExtension->DeviceNumber,
|
|
|
|
|
diskData->PartitionOrdinal,
|
2015-06-07 13:44:49 +00:00
|
|
|
|
diskData->PartitionNumber));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// no match was found, indicate this partition is gone.
|
|
|
|
|
//
|
|
|
|
|
|
2015-06-07 13:44:49 +00:00
|
|
|
|
DebugPrint((1,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
"UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
|
|
|
|
|
physicalExtension->DeviceNumber,
|
2015-06-07 13:44:49 +00:00
|
|
|
|
diskData->PartitionNumber));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
deviceExtension->PartitionLength.QuadPart = (LONGLONG) 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.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionOrdinal = 0;
|
|
|
|
|
|
|
|
|
|
for (partition = 0;
|
|
|
|
|
partition < partitionCount;
|
|
|
|
|
partition++) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get partition descriptor.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionEntry = &partitionList->PartitionEntry[partition];
|
|
|
|
|
|
|
|
|
|
//
|
2016-02-29 01:22:02 +00:00
|
|
|
|
// Check if empty, or describes an extended partition.
|
2007-04-01 19:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
|
|
|
|
|
IsContainerPartition(partitionEntry->PartitionType)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Keep track of position on the disk for calls to IoSetPartitionInformation.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionOrdinal++;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check if this entry should be rewritten.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!partitionEntry->RewritePartition) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (partitionEntry->PartitionNumber) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Partition is an exact match with an existing partition, but is
|
|
|
|
|
// being written anyway.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check first if existing device object is available by
|
|
|
|
|
// walking partition extension list.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionNumber = 0;
|
|
|
|
|
deviceExtension = physicalExtension;
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get next partition device extension from disk data.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension = diskData->NextPartition;
|
|
|
|
|
|
|
|
|
|
if (!deviceExtension) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// A device object is free if the partition length is set to zero.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!deviceExtension->PartitionLength.QuadPart) {
|
|
|
|
|
partitionNumber = diskData->PartitionNumber;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} 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,
|
2007-04-05 17:36:39 +00:00
|
|
|
|
"\\Device\\Harddisk%lu\\Partition%lu",
|
2007-04-01 19:25:38 +00:00
|
|
|
|
physicalExtension->DeviceNumber,
|
|
|
|
|
partitionNumber);
|
|
|
|
|
|
|
|
|
|
RtlInitString(&ntNameString,
|
|
|
|
|
ntNameBuffer);
|
|
|
|
|
|
|
|
|
|
status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
|
|
|
|
&ntNameString,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-07 13:44:49 +00:00
|
|
|
|
DebugPrint((3,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
"UpdateDeviceObjects: Create device object %s\n",
|
2015-06-07 13:44:49 +00:00
|
|
|
|
ntNameBuffer));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
2015-06-07 13:44:49 +00:00
|
|
|
|
DebugPrint((1,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
"UpdateDeviceObjects: Can't create device %s\n",
|
2015-06-07 13:44:49 +00:00
|
|
|
|
ntNameBuffer));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
RtlFreeUnicodeString(&ntUnicodeString);
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Initialize the new S-List.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
|
|
|
|
|
numberListElements = 30;
|
|
|
|
|
} else {
|
|
|
|
|
numberListElements = 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Build the lookaside list for srb's for this partition based on
|
|
|
|
|
// whether the adapter and disk can do tagged queueing.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ScsiClassInitializeSrbLookasideList(deviceExtension,
|
|
|
|
|
numberListElements);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Allocate spinlock for zoning for split-request completion.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Write back partition number used in creating object name.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionEntry->PartitionNumber = partitionNumber;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Clear flags initializing bit.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Point back at device object.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
deviceExtension->DeviceObject = deviceObject;
|
|
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&ntUnicodeString);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Link to end of partition chain using previous disk data.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->NextPartition = deviceExtension;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Get new disk data and zero next partition pointer.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
diskData->NextPartition = NULL;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Set pointer to disk data area that follows device extension.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData = (PDISK_DATA)(deviceExtension + 1);
|
|
|
|
|
|
2015-06-07 13:44:49 +00:00
|
|
|
|
DebugPrint((1,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
"UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
|
|
|
|
|
physicalExtension->DeviceNumber,
|
2015-06-07 13:44:49 +00:00
|
|
|
|
partitionNumber));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update partition information in partition device extension.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
diskData->PartitionNumber = partitionNumber;
|
|
|
|
|
diskData->PartitionType = partitionEntry->PartitionType;
|
|
|
|
|
diskData->BootIndicator = partitionEntry->BootIndicator;
|
|
|
|
|
deviceExtension->StartingOffset = partitionEntry->StartingOffset;
|
|
|
|
|
deviceExtension->PartitionLength = partitionEntry->PartitionLength;
|
|
|
|
|
diskData->HiddenSectors = partitionEntry->HiddenSectors;
|
|
|
|
|
diskData->PartitionOrdinal = partitionOrdinal;
|
|
|
|
|
|
2015-06-07 13:44:49 +00:00
|
|
|
|
DebugPrint((1,
|
2007-04-01 19:25:38 +00:00
|
|
|
|
"UpdateDeviceObjects: Ordinal %d is partition %d\n",
|
|
|
|
|
diskData->PartitionOrdinal,
|
2015-06-07 13:44:49 +00:00
|
|
|
|
diskData->PartitionNumber));
|
2007-04-01 19:25:38 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update partition number passed in to indicate the
|
|
|
|
|
// device name for this partition.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
partitionEntry->PartitionNumber = partitionNumber;
|
|
|
|
|
}
|
2003-04-28 11:05:34 +00:00
|
|
|
|
|
2007-04-01 19:25:38 +00:00
|
|
|
|
} // end UpdateDeviceObjects()
|
2014-10-28 21:59:57 +00:00
|
|
|
|
|