[STORPORT] Enumerate attached devices

- Implement AcquireSpinlock, ReleaseSpinlock and GetExtendedFunctionTable notifications.
- Implement a bus scan routine, borrowed from scsiport.

Storport and storahci are now able to detect a disk device attached to a Virtual Box AHCI controller.
This commit is contained in:
Eric Kohl 2018-05-24 11:39:01 +02:00
parent 8c726ae0d2
commit f7c01906e7
8 changed files with 581 additions and 22 deletions

View file

@ -243,6 +243,289 @@ PortFdoStartDevice(
}
static NTSTATUS
SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject,
ULONG Bus, ULONG Target, ULONG Lun)
{
// IO_STATUS_BLOCK IoStatusBlock;
// PIO_STACK_LOCATION IrpStack;
// KEVENT Event;
// KIRQL Irql;
// PIRP Irp;
NTSTATUS Status;
PINQUIRYDATA InquiryBuffer;
PUCHAR /*PSENSE_DATA*/ SenseBuffer;
// BOOLEAN KeepTrying = TRUE;
// ULONG RetryCount = 0;
SCSI_REQUEST_BLOCK Srb;
PCDB Cdb;
// PSCSI_PORT_LUN_EXTENSION LunExtension;
// PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PFDO_DEVICE_EXTENSION DeviceExtension;
PVOID SrbExtension = NULL;
BOOLEAN ret;
DPRINT1("SpiSendInquiry() called\n");
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_INQUIRY_DATA);
if (InquiryBuffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, SENSE_BUFFER_SIZE, TAG_SENSE_DATA);
if (SenseBuffer == NULL)
{
ExFreePoolWithTag(InquiryBuffer, TAG_INQUIRY_DATA);
return STATUS_INSUFFICIENT_RESOURCES;
}
if (DeviceExtension->Miniport.PortConfig.SrbExtensionSize != 0)
{
SrbExtension = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->Miniport.PortConfig.SrbExtensionSize, TAG_SENSE_DATA);
if (SrbExtension == NULL)
{
ExFreePoolWithTag(SenseBuffer, TAG_SENSE_DATA);
ExFreePoolWithTag(InquiryBuffer, TAG_INQUIRY_DATA);
return STATUS_INSUFFICIENT_RESOURCES;
}
}
// while (KeepTrying)
{
/* Initialize event for waiting */
// KeInitializeEvent(&Event,
// NotificationEvent,
// FALSE);
/* Create an IRP */
// Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
// DeviceObject,
// NULL,
// 0,
// InquiryBuffer,
// INQUIRYDATABUFFERSIZE,
// TRUE,
// &Event,
// &IoStatusBlock);
// if (Irp == NULL)
// {
// DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
/* Quit the loop */
// Status = STATUS_INSUFFICIENT_RESOURCES;
// KeepTrying = FALSE;
// continue;
// }
/* Prepare SRB */
RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
// Srb.OriginalRequest = Irp;
Srb.PathId = Bus;
Srb.TargetId = Target;
Srb.Lun = Lun;
Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
Srb.TimeOutValue = 4;
Srb.CdbLength = 6;
Srb.SenseInfoBuffer = SenseBuffer;
Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
Srb.DataBuffer = InquiryBuffer;
Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
Srb.SrbExtension = SrbExtension;
/* Attach Srb to the Irp */
// IrpStack = IoGetNextIrpStackLocation(Irp);
// IrpStack->Parameters.Scsi.Srb = &Srb;
/* Fill in CDB */
Cdb = (PCDB)Srb.Cdb;
Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
Cdb->CDB6INQUIRY.LogicalUnitNumber = Lun;
Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
/* Call the driver */
ret = MiniportStartIo(&DeviceExtension->Miniport,
&Srb);
DPRINT1("MiniportStartIo returned %u\n", ret);
// Status = IoCallDriver(DeviceObject, Irp);
/* Wait for it to complete */
// if (Status == STATUS_PENDING)
// {
// DPRINT1("SpiSendInquiry(): Waiting for the driver to process request...\n");
// KeWaitForSingleObject(&Event,
// Executive,
// KernelMode,
// FALSE,
// NULL);
// Status = IoStatusBlock.Status;
// }
// DPRINT1("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
{
/* All fine, copy data over */
// RtlCopyMemory(LunInfo->InquiryData,
// InquiryBuffer,
// INQUIRYDATABUFFERSIZE);
/* Quit the loop */
Status = STATUS_SUCCESS;
// KeepTrying = FALSE;
// continue;
}
DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
#if 0
/* Check if the queue is frozen */
if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
{
/* Something weird happened, deal with it (unfreeze the queue) */
KeepTrying = FALSE;
DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
LunExtension = SpiGetLunExtension(DeviceExtension,
LunInfo->PathId,
LunInfo->TargetId,
LunInfo->Lun);
/* Clear frozen flag */
LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
/* Acquire the spinlock */
KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
/* Process the request */
SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
/* SpiGetNextRequestFromLun() releases the spinlock,
so we just lower irql back to what it was before */
KeLowerIrql(Irql);
}
/* Check if data overrun happened */
if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
{
DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
/* Nothing dramatic, just copy data, but limiting the size */
RtlCopyMemory(LunInfo->InquiryData,
InquiryBuffer,
(Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
/* Quit the loop */
Status = STATUS_SUCCESS;
KeepTrying = FALSE;
}
else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
{
/* LUN is not valid, but some device responds there.
Mark it as invalid anyway */
/* Quit the loop */
Status = STATUS_INVALID_DEVICE_REQUEST;
KeepTrying = FALSE;
}
else
{
/* Retry a couple of times if no timeout happened */
if ((RetryCount < 2) &&
(SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
(SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
{
RetryCount++;
KeepTrying = TRUE;
}
else
{
/* That's all, quit the loop */
KeepTrying = FALSE;
/* Set status according to SRB status */
if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
{
Status = STATUS_INVALID_DEVICE_REQUEST;
}
else
{
Status = STATUS_IO_DEVICE_ERROR;
}
}
}
#endif
}
/* Free buffers */
if (SrbExtension != NULL)
ExFreePoolWithTag(SrbExtension, TAG_SENSE_DATA);
ExFreePoolWithTag(SenseBuffer, TAG_SENSE_DATA);
ExFreePoolWithTag(InquiryBuffer, TAG_INQUIRY_DATA);
DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
return Status;
}
static
NTSTATUS
PortFdoScanBus(
_In_ PFDO_DEVICE_EXTENSION DeviceExtension)
{
ULONG Bus, Target, Lun;
NTSTATUS Status;
DPRINT1("PortFdoScanBus(%p)\n",
DeviceExtension);
DPRINT1("NumberOfBuses: %lu\n", DeviceExtension->Miniport.PortConfig.NumberOfBuses);
DPRINT1("MaximumNumberOfTargets: %lu\n", DeviceExtension->Miniport.PortConfig.MaximumNumberOfTargets);
DPRINT1("MaximumNumberOfLogicalUnits: %lu\n", DeviceExtension->Miniport.PortConfig.MaximumNumberOfLogicalUnits);
/* Scan all buses */
for (Bus = 0; Bus < DeviceExtension->Miniport.PortConfig.NumberOfBuses; Bus++)
{
DPRINT1("Scanning bus %ld\n", Bus);
/* Scan all targets */
for (Target = 0; Target < DeviceExtension->Miniport.PortConfig.MaximumNumberOfTargets; Target++)
{
DPRINT1(" Scanning target %ld:%ld\n", Bus, Target);
/* Scan all logical units */
for (Lun = 0; Lun < DeviceExtension->Miniport.PortConfig.MaximumNumberOfLogicalUnits; Lun++)
{
DPRINT1(" Scanning logical unit %ld:%ld:%ld\n", Bus, Target, Lun);
Status = SpiSendInquiry(DeviceExtension->Device, Bus, Target, Lun);
DPRINT1("SpiSendInquiry returned 0x%08lx\n", Status);
}
}
}
DPRINT1("Done!\n");
return STATUS_SUCCESS;
}
static
NTSTATUS
PortFdoQueryBusRelations(
@ -254,6 +537,8 @@ PortFdoQueryBusRelations(
DPRINT1("PortFdoQueryBusRelations(%p %p)\n",
DeviceExtension, Information);
Status = PortFdoScanBus(DeviceExtension);
*Information = 0;
return Status;
@ -282,6 +567,35 @@ PortFdoFilterRequirements(
}
NTSTATUS
NTAPI
PortFdoScsi(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
// PIO_STACK_LOCATION Stack;
ULONG_PTR Information = 0;
NTSTATUS Status = STATUS_NOT_SUPPORTED;
DPRINT1("PortFdoScsi(%p %p)\n",
DeviceObject, Irp);
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension);
ASSERT(DeviceExtension->ExtensionType == FdoExtension);
// Stack = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
NTAPI
PortFdoPnp(

View file

@ -362,4 +362,21 @@ MiniportHwInterrupt(
return Result;
}
BOOLEAN
MiniportStartIo(
_In_ PMINIPORT Miniport,
_In_ PSCSI_REQUEST_BLOCK Srb)
{
BOOLEAN Result;
DPRINT1("MiniportHwStartIo(%p %p)\n",
Miniport, Srb);
Result = Miniport->InitData->HwStartIo(&Miniport->MiniportExtension->HwDeviceExtension, Srb);
DPRINT1("HwStartIo() returned %u\n", Result);
return Result;
}
/* EOF */

View file

@ -370,17 +370,4 @@ AllocateAddressMapping(
return STATUS_SUCCESS;
}
#if defined(_M_AMD64)
/* KeQuerySystemTime is an inline function,
so we cannot forward the export to ntoskrnl */
STORPORT_API
VOID
NTAPI
StorPortQuerySystemTime(
_Out_ PLARGE_INTEGER CurrentTime)
{
KeQuerySystemTime(CurrentTime);
}
#endif /* defined(_M_AMD64) */
/* EOF */

View file

@ -15,6 +15,21 @@
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
PortPdoScsi(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp)
{
DPRINT1("PortPdoScsi()\n");
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PortPdoPnp(

View file

@ -29,6 +29,8 @@
#define TAG_ACCRESS_RANGE 'RAtS'
#define TAG_RESOURCE_LIST 'LRtS'
#define TAG_ADDRESS_MAPPING 'MAtS'
#define TAG_INQUIRY_DATA 'QItS'
#define TAG_SENSE_DATA 'NStS'
typedef enum
{
@ -119,6 +121,12 @@ typedef struct _PDO_DEVICE_EXTENSION
/* fdo.c */
NTSTATUS
NTAPI
PortFdoScsi(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp);
NTSTATUS
NTAPI
PortFdoPnp(
@ -146,6 +154,11 @@ BOOLEAN
MiniportHwInterrupt(
_In_ PMINIPORT Miniport);
BOOLEAN
MiniportStartIo(
_In_ PMINIPORT Miniport,
_In_ PSCSI_REQUEST_BLOCK Srb);
/* misc.c */
NTSTATUS
@ -206,6 +219,12 @@ AllocateAddressMapping(
/* pdo.c */
NTSTATUS
NTAPI
PortPdoScsi(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp);
NTSTATUS
NTAPI
PortPdoPnp(

View file

@ -100,6 +100,69 @@ PortGetDriverInitData(
}
static
VOID
PortAcquireSpinLock(
PFDO_DEVICE_EXTENSION DeviceExtension,
STOR_SPINLOCK SpinLock,
PVOID LockContext,
PSTOR_LOCK_HANDLE LockHandle)
{
DPRINT1("PortAcquireSpinLock(%p %lu %p %p)\n",
DeviceExtension, SpinLock, LockContext, LockHandle);
LockHandle->Lock = SpinLock;
switch (SpinLock)
{
case DpcLock: /* 1, */
DPRINT1("DpcLock\n");
break;
case StartIoLock: /* 2 */
DPRINT1("StartIoLock\n");
break;
case InterruptLock: /* 3 */
DPRINT1("InterruptLock\n");
if (DeviceExtension->Interrupt == NULL)
LockHandle->Context.OldIrql = 0;
else
LockHandle->Context.OldIrql = KeAcquireInterruptSpinLock(DeviceExtension->Interrupt);
break;
}
}
static
VOID
PortReleaseSpinLock(
PFDO_DEVICE_EXTENSION DeviceExtension,
PSTOR_LOCK_HANDLE LockHandle)
{
DPRINT1("PortReleaseSpinLock(%p %p)\n",
DeviceExtension, LockHandle);
switch (LockHandle->Lock)
{
case DpcLock: /* 1, */
DPRINT1("DpcLock\n");
break;
case StartIoLock: /* 2 */
DPRINT1("StartIoLock\n");
break;
case InterruptLock: /* 3 */
DPRINT1("InterruptLock\n");
if (DeviceExtension->Interrupt != NULL)
KeReleaseInterruptSpinLock(DeviceExtension->Interrupt,
LockHandle->Context.OldIrql);
break;
}
}
static
NTSTATUS
NTAPI
@ -280,13 +343,30 @@ PortDispatchScsi(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
DPRINT1("PortDispatchScsi(%p %p)\n",
DeviceObject, Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
DPRINT1("ExtensionType: %u\n", DeviceExtension->ExtensionType);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
switch (DeviceExtension->ExtensionType)
{
case FdoExtension:
return PortFdoScsi(DeviceObject,
Irp);
case PdoExtension:
return PortPdoScsi(DeviceObject,
Irp);
default:
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
@ -742,10 +822,13 @@ StorPortGetPhysicalAddress(
// FIXME
UNIMPLEMENTED;
*Length = 0;
PhysicalAddress.QuadPart = (LONGLONG)0;
PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
*Length = 1;
// UNIMPLEMENTED;
// *Length = 0;
// PhysicalAddress.QuadPart = (LONGLONG)0;
return PhysicalAddress;
}
@ -1012,11 +1095,16 @@ StorPortNotification(
PMINIPORT_DEVICE_EXTENSION MiniportExtension = NULL;
PFDO_DEVICE_EXTENSION DeviceExtension = NULL;
PHW_PASSIVE_INITIALIZE_ROUTINE HwPassiveInitRoutine;
PSTORPORT_EXTENDED_FUNCTIONS *ppExtendedFunctions;
PBOOLEAN Result;
PSTOR_DPC Dpc;
PHW_DPC_ROUTINE HwDpcRoutine;
va_list ap;
STOR_SPINLOCK SpinLock;
PVOID LockContext;
PSTOR_LOCK_HANDLE LockHandle;
DPRINT1("StorPortNotification(%x %p)\n",
NotificationType, HwDeviceExtension);
@ -1036,6 +1124,13 @@ StorPortNotification(
switch (NotificationType)
{
case GetExtendedFunctionTable:
DPRINT1("GetExtendedFunctionTable\n");
ppExtendedFunctions = (PSTORPORT_EXTENDED_FUNCTIONS*)va_arg(ap, PSTORPORT_EXTENDED_FUNCTIONS*);
if (ppExtendedFunctions != NULL)
*ppExtendedFunctions = NULL; /* FIXME */
break;
case EnablePassiveInitialization:
DPRINT1("EnablePassiveInitialization\n");
HwPassiveInitRoutine = (PHW_PASSIVE_INITIALIZE_ROUTINE)va_arg(ap, PHW_PASSIVE_INITIALIZE_ROUTINE);
@ -1065,6 +1160,28 @@ StorPortNotification(
KeInitializeSpinLock(&Dpc->Lock);
break;
case AcquireSpinLock:
DPRINT1("AcquireSpinLock\n");
SpinLock = (STOR_SPINLOCK)va_arg(ap, STOR_SPINLOCK);
DPRINT1("SpinLock %lu\n", SpinLock);
LockContext = (PVOID)va_arg(ap, PVOID);
DPRINT1("LockContext %p\n", LockContext);
LockHandle = (PSTOR_LOCK_HANDLE)va_arg(ap, PSTOR_LOCK_HANDLE);
DPRINT1("LockHandle %p\n", LockHandle);
PortAcquireSpinLock(DeviceExtension,
SpinLock,
LockContext,
LockHandle);
break;
case ReleaseSpinLock:
DPRINT1("ReleaseSpinLock\n");
LockHandle = (PSTOR_LOCK_HANDLE)va_arg(ap, PSTOR_LOCK_HANDLE);
DPRINT1("LockHandle %p\n", LockHandle);
PortReleaseSpinLock(DeviceExtension,
LockHandle);
break;
default:
DPRINT1("Unsupported Notification %lx\n", NotificationType);
break;
@ -1109,6 +1226,25 @@ StorPortPauseDevice(
}
#if defined(_M_AMD64)
/*
* @implemented
*/
/* KeQuerySystemTime is an inline function,
so we cannot forward the export to ntoskrnl */
STORPORT_API
VOID
NTAPI
StorPortQuerySystemTime(
_Out_ PLARGE_INTEGER CurrentTime)
{
DPRINT1("StorPortQuerySystemTime(%p)\n", CurrentTime);
KeQuerySystemTime(CurrentTime);
}
#endif /* defined(_M_AMD64) */
/*
* @unimplemented
*/

View file

@ -24,10 +24,10 @@
@ stdcall StorPortLogError(ptr ptr long long long long long)
@ stdcall StorPortMoveMemory(ptr ptr long)
@ cdecl StorPortNotification()
@ stdcall -arch=i386 StorPortQuerySystemTime(ptr) NTOSKRNL.KeQuerySystemTime
@ stdcall -arch=amd64 StorPortQuerySystemTime(ptr)
@ stdcall StorPortPause(ptr long)
@ stdcall StorPortPauseDevice(ptr long long long long)
@ stdcall -arch=i386 StorPortQuerySystemTime(ptr) NTOSKRNL.KeQuerySystemTime
@ stdcall -arch=amd64 StorPortQuerySystemTime(ptr)
@ stdcall StorPortReadPortBufferUchar(ptr ptr ptr long)
@ stdcall StorPortReadPortBufferUlong(ptr ptr ptr long)
@ stdcall StorPortReadPortBufferUshort(ptr ptr ptr long)

View file

@ -57,7 +57,14 @@ extern "C" {
#define CDB10GENERIC_LENGTH 10
#define CDB12GENERIC_LENGTH 12
#define INQUIRYDATABUFFERSIZE 36
#define INQUIRYDATABUFFERSIZE 36
#define SENSE_BUFFER_SIZE 18
#define MAX_SENSE_BUFFER_SIZE 255
#define FILE_DEVICE_SCSI 0x0000001b
#define IOCTL_SCSI_EXECUTE_IN ((FILE_DEVICE_SCSI << 16) + 0x0011)
#define IOCTL_SCSI_EXECUTE_OUT ((FILE_DEVICE_SCSI << 16) + 0x0012)
#define IOCTL_SCSI_EXECUTE_NONE ((FILE_DEVICE_SCSI << 16) + 0x0013)
#define MODE_PAGE_VENDOR_SPECIFIC 0x00
#define MODE_PAGE_ERROR_RECOVERY 0x01
@ -563,6 +570,12 @@ typedef enum _STOR_EVENT_ASSOCIATION_ENUM
StorEventInvalidAssociation
} STOR_EVENT_ASSOCIATION_ENUM;
typedef enum _GETSGSTATUS
{
SG_ALLOCATED = 0,
SG_BUFFER_TOO_SMALL
} GETSGSTATUS, *PGETSGSTATUS;
typedef struct _SCSI_REQUEST_BLOCK
{
USHORT Length;
@ -2182,6 +2195,64 @@ VOID
_In_ PSTOR_SCATTER_GATHER_LIST ScatterGather,
_In_ PVOID Context);
typedef
BOOLEAN
(NTAPI *PStorPortGetMessageInterruptInformation)(
_In_ PVOID HwDeviceExtension,
_In_ ULONG MessageId,
_Out_ PMESSAGE_INTERRUPT_INFORMATION InterruptInfo);
typedef
VOID
(NTAPI *PStorPortPutScatterGatherList)(
_In_ PVOID HwDeviceExtension,
_In_ PSTOR_SCATTER_GATHER_LIST ScatterGatherList,
_In_ BOOLEAN WriteToDevice);
typedef
GETSGSTATUS
(NTAPI *PStorPortBuildScatterGatherList)(
_In_ PVOID HwDeviceExtension,
_In_ PVOID Mdl,
_In_ PVOID CurrentVa,
_In_ ULONG Length,
_In_ PpostScaterGatherExecute ExecutionRoutine,
_In_ PVOID Context,
_In_ BOOLEAN WriteToDevice,
_Inout_ PVOID ScatterGatherBuffer,
_In_ ULONG ScatterGatherBufferLength);
typedef
VOID
(NTAPI *PStorPortFreePool)(
_In_ PVOID PMemory,
_In_ PVOID HwDeviceExtension,
_In_opt_ PVOID PMdl);
typedef
PVOID
(NTAPI *PStorPortAllocatePool)(
_In_ ULONG NumberOfBytes,
_In_ ULONG Tag,
_In_ PVOID HwDeviceExtension,
_Out_ PVOID *PMdl);
typedef
PVOID
(NTAPI *PStorPortGetSystemAddress)(
_In_ PSCSI_REQUEST_BLOCK Srb);
typedef struct _STORPORT_EXTENDED_FUNCTIONS
{
ULONG Version;
PStorPortGetMessageInterruptInformation GetMessageInterruptInformation;
PStorPortPutScatterGatherList PutScatterGatherList;
PStorPortBuildScatterGatherList BuildScatterGatherList;
PStorPortFreePool FreePool;
PStorPortAllocatePool AllocatePool;
PStorPortGetSystemAddress GetSystemAddress;
} STORPORT_EXTENDED_FUNCTIONS, *PSTORPORT_EXTENDED_FUNCTIONS;
typedef struct _HW_INITIALIZATION_DATA
{
ULONG HwInitializationDataSize;