reactos/drivers/storage/class/disk/disk.h

1293 lines
32 KiB
C

/*++
Copyright (C) Microsoft Corporation, 1991 - 2010
Module Name:
disk.c
Abstract:
SCSI disk class driver
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include "ntddk.h"
#include "scsi.h"
#include <wmidata.h>
#include "classpnp.h"
#include <wmistr.h>
#include "ntstrsafe.h"
//
// Set component ID for DbgPrintEx calls
//
#ifndef DEBUG_COMP_ID
#define DEBUG_COMP_ID DPFLTR_DISK_ID
#endif
//
// Include header file and setup GUID for tracing
//
#include <storswtr.h>
#define WPP_GUID_DISK (945186BF, 3DD6, 4f3f, 9C8E, 9EDD3FC9D558)
#ifndef WPP_CONTROL_GUIDS
#define WPP_CONTROL_GUIDS WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_DISK)
#endif
#ifdef ExAllocatePool
#undef ExAllocatePool
#define ExAllocatePool #NT_ASSERT(FALSE)
#endif
#define DISK_TAG_GENERAL ' DcS' // "ScD " - generic tag
#define DISK_TAG_SMART 'aDcS' // "ScDa" - SMART allocations
#define DISK_TAG_INFO_EXCEPTION 'ADcS' // "ScDA" - Info Exceptions
#define DISK_TAG_DISABLE_CACHE 'CDcS' // "ScDC" - disable cache paths
#define DISK_TAG_CCONTEXT 'cDcS' // "ScDc" - disk allocated completion context
#define DISK_TAG_DISK_GEOM 'GDcS' // "ScDG" - disk geometry buffer
#define DISK_TAG_UPDATE_GEOM 'gDcS' // "ScDg" - update disk geometry paths
#define DISK_TAG_SENSE_INFO 'IDcS' // "ScDI" - sense info buffers
#define DISK_TAG_PNP_ID 'iDcS' // "ScDp" - pnp ids
#define DISK_TAG_MODE_DATA 'MDcS' // "ScDM" - mode data buffer
#define DISK_CACHE_MBR_CHECK 'mDcS' // "ScDM" - mbr checksum code
#define DISK_TAG_NAME 'NDcS' // "ScDN" - disk name code
#define DISK_TAG_READ_CAP 'PDcS' // "ScDP" - read capacity buffer
#define DISK_TAG_PART_LIST 'pDcS' // "ScDp" - disk partition lists
#define DISK_TAG_SRB 'SDcS' // "ScDS" - srb allocation
#define DISK_TAG_START 'sDcS' // "ScDs" - start device paths
#define DISK_TAG_UPDATE_CAP 'UDcS' // "ScDU" - update capacity path
#define DISK_TAG_WI_CONTEXT 'WDcS' // "ScDW" - work-item context
#ifdef __REACTOS__
#undef MdlMappingNoExecute
#define MdlMappingNoExecute 0
#define NonPagedPoolNx NonPagedPool
#define NonPagedPoolNxCacheAligned NonPagedPoolCacheAligned
#undef POOL_NX_ALLOCATION
#define POOL_NX_ALLOCATION 0
#endif
#if defined(_X86_) || defined(_AMD64_)
//
// Disk device data
//
typedef enum _DISK_GEOMETRY_SOURCE {
DiskGeometryUnknown,
DiskGeometryFromBios,
DiskGeometryFromPort,
DiskGeometryFromNec98,
DiskGeometryGuessedFromBios,
DiskGeometryFromDefault,
DiskGeometryFromNT4
} DISK_GEOMETRY_SOURCE, *PDISK_GEOMETRY_SOURCE;
#endif
//
// Context for requests that can be combined and sent down
//
typedef struct _DISK_GROUP_CONTEXT
{
//
// Queue of requests whose representative is currently outstanding at the port driver
//
LIST_ENTRY CurrList;
//
// The representative for the above queue
//
PIRP CurrIrp;
//
// Queue of requests whose representative is waiting to go down
//
LIST_ENTRY NextList;
//
// The representative for the above queue
//
PIRP NextIrp;
//
// The srb associated with this group
//
#if (NTDDI_VERSION >= NTDDI_WIN8)
union {
SCSI_REQUEST_BLOCK Srb;
STORAGE_REQUEST_BLOCK SrbEx;
UCHAR SrbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE];
} Srb;
#else
SCSI_REQUEST_BLOCK Srb;
#endif
//
// The spinlock that will synchronize access to this context
//
KSPIN_LOCK Spinlock;
//
// This event will allow for the requests to be sent down synchronously
//
KEVENT Event;
#if DBG
//
// This counter maintains the number of requests currently tagged
// to the request that is waiting to go down
//
ULONG DbgTagCount;
//
// This counter maintains the number of requests that were avoided
//
ULONG DbgSavCount;
//
// This counter maintains the total number of times that we combined
// requests and the respective number of requests that were tagged
//
ULONG DbgRefCount[64];
#endif
} DISK_GROUP_CONTEXT, *PDISK_GROUP_CONTEXT;
//
// Write cache setting as defined by the user
//
typedef enum _DISK_USER_WRITE_CACHE_SETTING
{
DiskWriteCacheDisable = 0,
DiskWriteCacheEnable = 1,
DiskWriteCacheDefault = -1
} DISK_USER_WRITE_CACHE_SETTING, *PDISK_USER_WRITE_CACHE_SETTING;
typedef struct _DISK_DATA {
//
// This field is the ordinal of a partition as it appears on a disk.
//
ULONG PartitionOrdinal;
//
// How has this disk been partitioned? Either EFI or MBR.
//
PARTITION_STYLE PartitionStyle;
union {
struct {
//
// Disk signature (from MBR)
//
ULONG Signature;
//
// MBR checksum
//
ULONG MbrCheckSum;
//
// Number of hidden sectors for BPB.
//
ULONG HiddenSectors;
//
// 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;
} Mbr;
struct {
//
// The DiskGUID field from the EFI partition header.
//
GUID DiskId;
//
// Partition type of this device object.
//
GUID PartitionType;
//
// Unique partition identifier for this partition.
//
GUID PartitionId;
//
// EFI partition attributes for this partition.
//
ULONG64 Attributes;
//
// EFI partition name of this partition.
//
WCHAR PartitionName[36];
} Efi;
#ifdef _MSC_VER
#pragma warning(suppress: 4201) //this is intended to be an unnamed union
#endif
};
struct {
//
// This flag is set when the well known name is created (through
// DiskCreateSymbolicLinks) and cleared when destroying it
// (by calling DiskDeleteSymbolicLinks).
//
unsigned int WellKnownNameCreated : 1;
//
// This flag is set when the PhysicalDriveN link is created (through
// DiskCreateSymbolicLinks) and is cleared when destroying it (through
// DiskDeleteSymbolicLinks)
//
unsigned int PhysicalDriveLinkCreated : 1;
} LinkStatus;
//
// ReadyStatus - STATUS_SUCCESS indicates that the drive is ready for
// use. Any error status is to be returned as an explaination for why
// a request is failed.
//
// This was done solely for the zero-length partition case of having no
// media in a removable disk drive. When that occurs, and a read is sent
// to the zero-length non-partition-zero PDO that was created, we had to
// be able to fail the request with a reasonable value. This may not have
// been the best way to do this, but it works.
//
NTSTATUS ReadyStatus;
//
// SCSI address used for SMART operations.
//
SCSI_ADDRESS ScsiAddress;
//
// What type of failure prediction mechanism is available
//
FAILURE_PREDICTION_METHOD FailurePredictionCapability;
BOOLEAN AllowFPPerfHit;
//
// Indicates that the SCSI Informational Exceptions mode page is supported.
// Note that this only indicates *support* and does not necessarily
// indicate that Informational Exception reporting via sense code is
// actually enabled.
//
BOOLEAN ScsiInfoExceptionsSupported;
//
// Indicates if failure prediction is actually enabled (via whatever)
// method is applicable as indicated by FailurePredictionCapability.
//
BOOLEAN FailurePredictionEnabled;
#if defined(_X86_) || defined(_AMD64_)
//
// This flag indiciates that a non-default geometry for this drive has
// already been determined by the disk driver. This field is ignored
// for removable media drives.
//
DISK_GEOMETRY_SOURCE GeometrySource;
//
// If GeometryDetermined is TRUE this will contain the geometry which was
// reported by the firmware or by the BIOS. For removable media drives
// this will contain the last geometry used when media was present.
//
DISK_GEOMETRY RealGeometry;
#endif
//
// This mutex prevents more than one IOCTL_DISK_VERIFY from being
// sent down to the disk. This greatly reduces the possibility of
// a Denial-of-Service attack
//
KMUTEX VerifyMutex;
//
// This allows for parallel flush requests to be combined into one so as to
// reduce the number of outstanding requests that are sent down to the disk
//
DISK_GROUP_CONTEXT FlushContext;
//
// The user-specified disk write cache setting
//
DISK_USER_WRITE_CACHE_SETTING WriteCacheOverride;
} DISK_DATA, *PDISK_DATA;
//
// Define a general structure of identfing disk controllers with bad
// hardware.
//
#define HackDisableTaggedQueuing (0x01)
#define HackDisableSynchronousTransfers (0x02)
#define HackDisableSpinDown (0x04)
#define HackDisableWriteCache (0x08)
#define HackCauseNotReportableHack (0x10)
#define HackRequiresStartUnitCommand (0x20)
#define DiskDeviceParameterSubkey L"Disk"
#define DiskDeviceUserWriteCacheSetting L"UserWriteCacheSetting"
#define DiskDeviceCacheIsPowerProtected L"CacheIsPowerProtected"
#define FUNCTIONAL_EXTENSION_SIZE sizeof(FUNCTIONAL_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
#define MAX_MEDIA_TYPES 4
typedef struct _DISK_MEDIA_TYPES_LIST {
PCCHAR VendorId;
PCCHAR ProductId;
PCCHAR Revision;
const ULONG NumberOfTypes;
const ULONG NumberOfSides;
const STORAGE_MEDIA_TYPE MediaTypes[MAX_MEDIA_TYPES];
} DISK_MEDIA_TYPES_LIST, *PDISK_MEDIA_TYPES_LIST;
//
// WMI reregistration structures used for reregister work item
//
typedef struct
{
SINGLE_LIST_ENTRY Next;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
} DISKREREGREQUEST, *PDISKREREGREQUEST;
#define MAX_SECTORS_PER_VERIFY 0x100
//
// This is based off 100ns units
//
#define ONE_MILLI_SECOND ((ULONGLONG)10 * 1000)
//
// Context for the work-item
//
typedef struct _DISK_VERIFY_WORKITEM_CONTEXT
{
PIRP Irp;
PSCSI_REQUEST_BLOCK Srb;
PIO_WORKITEM WorkItem;
} DISK_VERIFY_WORKITEM_CONTEXT, *PDISK_VERIFY_WORKITEM_CONTEXT;
//
// Poll for Failure Prediction every hour
//
#define DISK_DEFAULT_FAILURE_POLLING_PERIOD 1 * 60 * 60
#define CHECK_IRQL() \
if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { \
NT_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); \
return STATUS_INVALID_LEVEL; \
}
//
// Static global lookup tables.
//
extern CLASSPNP_SCAN_FOR_SPECIAL_INFO DiskBadControllers[];
extern const DISK_MEDIA_TYPES_LIST DiskMediaTypes[];
extern const DISK_MEDIA_TYPES_LIST DiskMediaTypesExclude[];
#if defined(__REACTOS__) && defined(_MSC_VER)
# pragma section("PAGECONS", read)
# pragma section("PAGEDATA", read,write)
#endif
//
// Macros
//
//
// Routine prototypes.
//
DRIVER_INITIALIZE DriverEntry;
VOID
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskUnload(
IN PDRIVER_OBJECT DriverObject
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskInitFdo(
IN PDEVICE_OBJECT Fdo
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskStartFdo(
IN PDEVICE_OBJECT Fdo
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskStopDevice(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Type
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskRemoveDevice(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Type
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskReadWriteVerification(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
VOID
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoProcessError(
PDEVICE_OBJECT DeviceObject,
PSCSI_REQUEST_BLOCK Srb,
NTSTATUS *Status,
BOOLEAN *Retry
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskShutdownFlush(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskGetCacheInformation(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
IN PDISK_CACHE_INFORMATION CacheInfo
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskSetCacheInformation(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
IN PDISK_CACHE_INFORMATION CacheInfo
);
VOID
DiskLogCacheInformation(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
IN PDISK_CACHE_INFORMATION CacheInfo,
IN NTSTATUS Status
);
NTSTATUS
DiskIoctlGetCacheSetting(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
DiskIoctlSetCacheSetting(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
IO_WORKITEM_ROUTINE DisableWriteCache;
IO_WORKITEM_ROUTINE DiskIoctlVerifyThread;
VOID
DiskFlushDispatch(
IN PDEVICE_OBJECT Fdo,
IN PDISK_GROUP_CONTEXT FlushContext
);
IO_COMPLETION_ROUTINE DiskFlushComplete;
NTSTATUS
DiskModeSelect(
IN PDEVICE_OBJECT DeviceObject,
_In_reads_bytes_(Length) PCHAR ModeSelectBuffer,
IN ULONG Length,
IN BOOLEAN SavePage
);
//
// We need to validate that the self test subcommand is valid and
// appropriate. Right now we allow subcommands 0, 1 and 2 which are non
// captive mode tests. Once we figure out a way to know if it is safe to
// run a captive test then we can allow captive mode tests. Also if the
// atapi 5 spec is ever updated to denote that bit 7 is the captive
// mode bit, we can allow any request that does not have bit 7 set. Until
// that is done we want to be sure
//
#define DiskIsValidSmartSelfTest(Subcommand) \
( ((Subcommand) == SMART_OFFLINE_ROUTINE_OFFLINE) || \
((Subcommand) == SMART_SHORT_SELFTEST_OFFLINE) || \
((Subcommand) == SMART_EXTENDED_SELFTEST_OFFLINE) )
NTSTATUS
DiskPerformSmartCommand(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
IN ULONG SrbControlCode,
IN UCHAR Command,
IN UCHAR Feature,
IN UCHAR SectorCount,
IN UCHAR SectorNumber,
IN OUT PSRB_IO_CONTROL SrbControl,
OUT PULONG BufferSize
);
NTSTATUS
DiskGetInfoExceptionInformation(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
OUT PMODE_INFO_EXCEPTIONS ReturnPageData
);
NTSTATUS
DiskSetInfoExceptionInformation(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
IN PMODE_INFO_EXCEPTIONS PageData
);
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
NTSTATUS
DiskGetModePage(
_In_ PDEVICE_OBJECT Fdo,
_In_ UCHAR PageMode,
_In_ UCHAR PageControl,
_In_ PMODE_PARAMETER_HEADER ModeData,
_Inout_ PULONG ModeDataSize,
_Out_ PVOID* PageData
);
NTSTATUS
DiskEnableInfoExceptions(
_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
_In_ BOOLEAN Enable
);
#endif // (NTDDI_VERSION >= NTDDI_WINBLUE)
NTSTATUS
DiskDetectFailurePrediction(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
PFAILURE_PREDICTION_METHOD FailurePredictCapability,
BOOLEAN ScsiAddressAvailable
);
NTSTATUS
DiskCreateFdo(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT LowerDeviceObject,
IN PULONG DeviceCount,
IN BOOLEAN DasdAccessOnly
);
VOID
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskSetSpecialHacks(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
IN ULONG_PTR Data
);
VOID
ResetBus(
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
DiskGenerateDeviceName(
IN ULONG DeviceNumber,
OUT PCCHAR *RawName
);
VOID
DiskCreateSymbolicLinks(
IN PDEVICE_OBJECT DeviceObject
);
VOID
DiskDeleteSymbolicLinks(
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoQueryWmiRegInfo(
IN PDEVICE_OBJECT DeviceObject,
OUT ULONG *RegFlags,
OUT PUNICODE_STRING InstanceName
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoQueryWmiRegInfoEx(
IN PDEVICE_OBJECT DeviceObject,
OUT ULONG *RegFlags,
OUT PUNICODE_STRING InstanceName,
OUT PUNICODE_STRING MofName
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoQueryWmiDataBlock(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG BufferAvail,
OUT PUCHAR Buffer
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoSetWmiDataBlock(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG BufferSize,
IN PUCHAR Buffer
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoSetWmiDataItem(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG DataItemId,
IN ULONG BufferSize,
IN PUCHAR Buffer
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskFdoExecuteWmiMethod(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG MethodId,
IN ULONG InBufferSize,
IN ULONG OutBufferSize,
IN PUCHAR Buffer
);
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskWmiFunctionControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN CLASSENABLEDISABLEFUNCTION Function,
IN BOOLEAN Enable
);
NTSTATUS
DiskReadFailurePredictStatus(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus
);
NTSTATUS
DiskReadFailurePredictData(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData
);
NTSTATUS
DiskEnableDisableFailurePrediction(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
BOOLEAN Enable
);
NTSTATUS
DiskEnableDisableFailurePredictPolling(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
BOOLEAN Enable,
ULONG PollTimeInSeconds
);
NTSTATUS DiskInitializeReregistration(
VOID
);
extern GUIDREGINFO DiskWmiFdoGuidList[];
#if defined(_X86_) || defined(_AMD64_)
NTSTATUS
DiskReadDriveCapacity(
IN PDEVICE_OBJECT Fdo
);
#else
#define DiskReadDriveCapacity(Fdo) ClassReadDriveCapacity(Fdo)
#endif
#if defined(_X86_) || defined(_AMD64_)
NTSTATUS
DiskSaveDetectInfo(
PDRIVER_OBJECT DriverObject
);
VOID
DiskCleanupDetectInfo(
IN PDRIVER_OBJECT DriverObject
);
VOID
DiskDriverReinitialization (
IN PDRIVER_OBJECT DriverObject,
IN PVOID Nothing,
IN ULONG Count
);
#endif
#if defined(_X86_) || defined(_AMD64_)
NTSTATUS
DiskGetDetectInfo(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
OUT PDISK_DETECTION_INFO DetectInfo
);
NTSTATUS
DiskReadSignature(
IN PDEVICE_OBJECT Fdo
);
BOOLEAN
DiskIsNT4Geometry(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
);
#else
#define DiskGetDetectInfo(FdoExtension, DetectInfo) (STATUS_UNSUCCESSFUL)
#endif
#define DiskHashGuid(Guid) (((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0] ^ ((PULONG) &Guid)[0])
NTSTATUS
DiskDetermineMediaTypes(
IN PDEVICE_OBJECT Fdo,
IN PIRP Irp,
IN UCHAR MediumType,
IN UCHAR DensityCode,
IN BOOLEAN MediaPresent,
IN BOOLEAN IsWritable
);
NTSTATUS
DiskIoctlGetLengthInfo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
DiskIoctlGetDriveGeometry(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlGetDriveGeometryEx(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
DiskIoctlGetCacheInformation(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlSetCacheInformation(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlGetMediaTypesEx(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlPredictFailure(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlEnableFailurePrediction(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlVerify(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlReassignBlocks(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlReassignBlocksEx(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlIsWritable(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlSetVerify(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlClearVerify(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlUpdateDriveSize(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlGetVolumeDiskExtents(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlSmartGetVersion(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlSmartReceiveDriveData(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS
DiskIoctlSmartSendDriveCommand(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
FORCEINLINE // __REACTOS__
PCDB
GetSrbScsiData(
_In_ PSTORAGE_REQUEST_BLOCK SrbEx,
_In_opt_ PUCHAR CdbLength8,
_In_opt_ PULONG CdbLength32,
_In_opt_ PUCHAR ScsiStatus,
_In_opt_ PVOID *SenseInfoBuffer,
_In_opt_ PUCHAR SenseInfoBufferLength
)
/*++
Routine Description:
Helper function to retrieve SCSI related fields from an extended SRB. If SRB is
not a SRB_FUNCTION_EXECUTE_SCSI or not an extended SRB, default values will be returned.
Arguments:
SrbEx - Pointer to extended SRB.
CdbLength8 - Pointer to buffer to hold CdbLength field value for
SRBEX_DATA_SCSI_CDB16 or SRBEX_DATA_SCSI_CDB32
CdbLength32 - Pointer to buffer to hold CdbLength field value for
SRBEX_DATA_SCSI_CDB_VAR
ScsiStatus - Pointer to buffer to hold ScsiStatus field value.
SenseInfoBuffer - Pointer to buffer to hold SenseInfoBuffer value.
SenseInfoBufferLength - Pointer to buffer to hold SenseInfoBufferLength value.
Return Value:
Pointer to Cdb field or NULL if SRB is not a SRB_FUNCTION_EXECUTE_SCSI.
--*/
{
PCDB Cdb = NULL;
ULONG i;
PSRBEX_DATA SrbExData = NULL;
BOOLEAN FoundEntry = FALSE;
if ((SrbEx->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) &&
(SrbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)) {
NT_ASSERT(SrbEx->NumSrbExData > 0);
for (i = 0; i < SrbEx->NumSrbExData; i++) {
// Skip any invalid offsets
if ((SrbEx->SrbExDataOffset[i] < sizeof(STORAGE_REQUEST_BLOCK)) ||
(SrbEx->SrbExDataOffset[i] > SrbEx->SrbLength)){
// Catch any invalid offsets
NT_ASSERT(FALSE);
continue;
}
SrbExData = (PSRBEX_DATA)((PUCHAR)SrbEx + SrbEx->SrbExDataOffset[i]);
switch (SrbExData->Type) {
case SrbExDataTypeScsiCdb16:
if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB16) <= SrbEx->SrbLength) {
FoundEntry = TRUE;
if (CdbLength8) {
*CdbLength8 = ((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength;
}
if (((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength > 0) {
Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB16) SrbExData)->Cdb;
}
if (ScsiStatus) {
*ScsiStatus =
((PSRBEX_DATA_SCSI_CDB16) SrbExData)->ScsiStatus;
}
if (SenseInfoBuffer) {
*SenseInfoBuffer =
((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBuffer;
}
if (SenseInfoBufferLength) {
*SenseInfoBufferLength =
((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBufferLength;
}
} else {
// Catch invalid offset
NT_ASSERT(FALSE);
}
break;
case SrbExDataTypeScsiCdb32:
if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB32) <= SrbEx->SrbLength) {
FoundEntry = TRUE;
if (CdbLength8) {
*CdbLength8 = ((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength;
}
if (((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength > 0) {
Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB32) SrbExData)->Cdb;
}
if (ScsiStatus) {
*ScsiStatus =
((PSRBEX_DATA_SCSI_CDB32) SrbExData)->ScsiStatus;
}
if (SenseInfoBuffer) {
*SenseInfoBuffer =
((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBuffer;
}
if (SenseInfoBufferLength) {
*SenseInfoBufferLength =
((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBufferLength;
}
} else {
// Catch invalid offset
NT_ASSERT(FALSE);
}
break;
case SrbExDataTypeScsiCdbVar:
if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB_VAR) <= SrbEx->SrbLength) {
FoundEntry = TRUE;
if (CdbLength32) {
*CdbLength32 = ((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength;
}
if (((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength > 0) {
Cdb = (PCDB)((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->Cdb;
}
if (ScsiStatus) {
*ScsiStatus =
((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->ScsiStatus;
}
if (SenseInfoBuffer) {
*SenseInfoBuffer =
((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBuffer;
}
if (SenseInfoBufferLength) {
*SenseInfoBufferLength =
((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBufferLength;
}
} else {
// Catch invalid offset
NT_ASSERT(FALSE);
}
break;
}
if (FoundEntry) {
break;
}
}
} else {
if (CdbLength8) {
*CdbLength8 = 0;
}
if (CdbLength32) {
*CdbLength32 = 0;
}
if (ScsiStatus) {
*ScsiStatus = 0;
}
if (SenseInfoBuffer) {
*SenseInfoBuffer = NULL;
}
if (SenseInfoBufferLength) {
*SenseInfoBufferLength = 0;
}
}
return Cdb;
}
FORCEINLINE // __REACTOS__
VOID
SetSrbScsiData(
_In_ PSTORAGE_REQUEST_BLOCK SrbEx,
_In_ UCHAR CdbLength8,
_In_ ULONG CdbLength32,
_In_ UCHAR ScsiStatus,
_In_opt_ PVOID SenseInfoBuffer,
_In_ UCHAR SenseInfoBufferLength
)
/*++
Routine Description:
Helper function to set SCSI related fields from an extended SRB. If SRB is
not a SRB_FUNCTION_EXECUTE_SCSI or not an extended SRB, no modifications will
be made
Arguments:
SrbEx - Pointer to extended SRB.
CdbLength8 - CdbLength field value for SRBEX_DATA_SCSI_CDB16
or SRBEX_DATA_SCSI_CDB32
CdbLength32 - CdbLength field value for SRBEX_DATA_SCSI_CDB_VAR
ScsiStatus - ScsiStatus field value.
SenseInfoBuffer - SenseInfoBuffer value.
SenseInfoBufferLength - SenseInfoBufferLength value.
Return Value:
None
--*/
{
ULONG i;
PSRBEX_DATA SrbExData = NULL;
BOOLEAN FoundEntry = FALSE;
if ((SrbEx->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) &&
(SrbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI)) {
NT_ASSERT(SrbEx->NumSrbExData > 0);
for (i = 0; i < SrbEx->NumSrbExData; i++) {
// Skip any invalid offsets
if ((SrbEx->SrbExDataOffset[i] < sizeof(STORAGE_REQUEST_BLOCK)) ||
(SrbEx->SrbExDataOffset[i] > SrbEx->SrbLength)){
// Catch any invalid offsets
NT_ASSERT(FALSE);
continue;
}
SrbExData = (PSRBEX_DATA)((PUCHAR)SrbEx + SrbEx->SrbExDataOffset[i]);
switch (SrbExData->Type) {
case SrbExDataTypeScsiCdb16:
if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB16) <= SrbEx->SrbLength) {
FoundEntry = TRUE;
((PSRBEX_DATA_SCSI_CDB16) SrbExData)->CdbLength = CdbLength8;
((PSRBEX_DATA_SCSI_CDB16) SrbExData)->ScsiStatus = ScsiStatus;
((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBuffer = SenseInfoBuffer;
((PSRBEX_DATA_SCSI_CDB16) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength;
} else {
// Catch invalid offset
NT_ASSERT(FALSE);
}
break;
case SrbExDataTypeScsiCdb32:
if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB32) <= SrbEx->SrbLength) {
FoundEntry = TRUE;
((PSRBEX_DATA_SCSI_CDB32) SrbExData)->CdbLength = CdbLength8;
((PSRBEX_DATA_SCSI_CDB32) SrbExData)->ScsiStatus = ScsiStatus;
((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBuffer = SenseInfoBuffer;
((PSRBEX_DATA_SCSI_CDB32) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength;
} else {
// Catch invalid offset
NT_ASSERT(FALSE);
}
break;
case SrbExDataTypeScsiCdbVar:
if (SrbEx->SrbExDataOffset[i] + sizeof(SRBEX_DATA_SCSI_CDB_VAR) <= SrbEx->SrbLength) {
FoundEntry = TRUE;
((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->CdbLength = CdbLength32;
((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->ScsiStatus = ScsiStatus;
((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBuffer = SenseInfoBuffer;
((PSRBEX_DATA_SCSI_CDB_VAR) SrbExData)->SenseInfoBufferLength = SenseInfoBufferLength;
} else {
// Catch invalid offset
NT_ASSERT(FALSE);
}
break;
}
if (FoundEntry) {
break;
}
}
}
return;
}