mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 15:18:33 +00:00
![Eric Kohl](/assets/img/avatar_default.png)
- 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.
383 lines
14 KiB
C
383 lines
14 KiB
C
/*
|
|
* PROJECT: ReactOS Storport Driver
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Miniport interface code
|
|
* COPYRIGHT: Copyright 2017 Eric Kohl (eric.kohl@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
static
|
|
NTSTATUS
|
|
InitializeConfiguration(
|
|
_In_ PPORT_CONFIGURATION_INFORMATION PortConfig,
|
|
_In_ PHW_INITIALIZATION_DATA InitData,
|
|
_In_ ULONG BusNumber,
|
|
_In_ ULONG SlotNumber)
|
|
{
|
|
PCONFIGURATION_INFORMATION ConfigInfo;
|
|
ULONG i;
|
|
|
|
DPRINT1("InitializeConfiguration(%p %p %lu %lu)\n",
|
|
PortConfig, InitData, BusNumber, SlotNumber);
|
|
|
|
/* Get the configurration information */
|
|
ConfigInfo = IoGetConfigurationInformation();
|
|
|
|
/* Initialize the port configuration */
|
|
RtlZeroMemory(PortConfig,
|
|
sizeof(PORT_CONFIGURATION_INFORMATION));
|
|
|
|
PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
|
|
PortConfig->SystemIoBusNumber = BusNumber;
|
|
PortConfig->SlotNumber = SlotNumber;
|
|
PortConfig->AdapterInterfaceType = InitData->AdapterInterfaceType;
|
|
|
|
PortConfig->MaximumTransferLength = -1; //SP_UNINITIALIZED_VALUE;
|
|
PortConfig->DmaChannel = -1; //SP_UNINITIALIZED_VALUE;
|
|
PortConfig->DmaPort = -1; //SP_UNINITIALIZED_VALUE;
|
|
|
|
PortConfig->InterruptMode = LevelSensitive;
|
|
|
|
PortConfig->Master = TRUE;
|
|
PortConfig->AtdiskPrimaryClaimed = ConfigInfo->AtDiskPrimaryAddressClaimed;
|
|
PortConfig->AtdiskSecondaryClaimed = ConfigInfo->AtDiskSecondaryAddressClaimed;
|
|
PortConfig->Dma32BitAddresses = TRUE;
|
|
PortConfig->DemandMode = FALSE;
|
|
PortConfig->MapBuffers = InitData->MapBuffers;
|
|
|
|
PortConfig->NeedPhysicalAddresses = TRUE;
|
|
PortConfig->TaggedQueuing = TRUE;
|
|
PortConfig->AutoRequestSense = TRUE;
|
|
PortConfig->MultipleRequestPerLu = TRUE;
|
|
PortConfig->ReceiveEvent = InitData->ReceiveEvent;
|
|
PortConfig->RealModeInitialized = FALSE;
|
|
PortConfig->BufferAccessScsiPortControlled = TRUE;
|
|
PortConfig->MaximumNumberOfTargets = 128;
|
|
|
|
PortConfig->SpecificLuExtensionSize = InitData->SpecificLuExtensionSize;
|
|
PortConfig->SrbExtensionSize = InitData->SrbExtensionSize;
|
|
PortConfig->MaximumNumberOfLogicalUnits = 1;
|
|
PortConfig->WmiDataProvider = TRUE;
|
|
|
|
PortConfig->NumberOfAccessRanges = InitData->NumberOfAccessRanges;
|
|
DPRINT1("NumberOfAccessRanges: %lu\n", PortConfig->NumberOfAccessRanges);
|
|
if (PortConfig->NumberOfAccessRanges != 0)
|
|
{
|
|
PortConfig->AccessRanges = ExAllocatePoolWithTag(NonPagedPool,
|
|
PortConfig->NumberOfAccessRanges * sizeof(ACCESS_RANGE),
|
|
TAG_ACCRESS_RANGE);
|
|
if (PortConfig->AccessRanges == NULL)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
RtlZeroMemory(PortConfig->AccessRanges,
|
|
PortConfig->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
|
|
}
|
|
|
|
for (i = 0; i < 7; i++)
|
|
PortConfig->InitiatorBusId[i] = 0xff;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
AssignResourcesToConfiguration(
|
|
_In_ PPORT_CONFIGURATION_INFORMATION PortConfiguration,
|
|
_In_ PCM_RESOURCE_LIST ResourceList,
|
|
_In_ ULONG NumberOfAccessRanges)
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
|
|
PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
|
|
PACCESS_RANGE AccessRange;
|
|
INT i, j;
|
|
ULONG RangeNumber = 0, Interrupt = 0, Dma = 0;
|
|
|
|
DPRINT1("AssignResourceToConfiguration(%p %p %lu)\n",
|
|
PortConfiguration, ResourceList, NumberOfAccessRanges);
|
|
|
|
FullDescriptor = &ResourceList->List[0];
|
|
for (i = 0; i < ResourceList->Count; i++)
|
|
{
|
|
PartialResourceList = &FullDescriptor->PartialResourceList;
|
|
|
|
for (j = 0; j < PartialResourceList->Count; j++)
|
|
{
|
|
PartialDescriptor = &PartialResourceList->PartialDescriptors[j];
|
|
|
|
switch (PartialDescriptor->Type)
|
|
{
|
|
case CmResourceTypePort:
|
|
DPRINT1("Port: 0x%I64x (0x%lx)\n",
|
|
PartialDescriptor->u.Port.Start.QuadPart,
|
|
PartialDescriptor->u.Port.Length);
|
|
if (RangeNumber < NumberOfAccessRanges)
|
|
{
|
|
AccessRange = &((*(PortConfiguration->AccessRanges))[RangeNumber]);
|
|
AccessRange->RangeStart = PartialDescriptor->u.Port.Start;
|
|
AccessRange->RangeLength = PartialDescriptor->u.Port.Length;
|
|
AccessRange->RangeInMemory = FALSE;
|
|
RangeNumber++;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
DPRINT1("Memory: 0x%I64x (0x%lx)\n",
|
|
PartialDescriptor->u.Memory.Start.QuadPart,
|
|
PartialDescriptor->u.Memory.Length);
|
|
if (RangeNumber < NumberOfAccessRanges)
|
|
{
|
|
AccessRange = &((*(PortConfiguration->AccessRanges))[RangeNumber]);
|
|
AccessRange->RangeStart = PartialDescriptor->u.Memory.Start;
|
|
AccessRange->RangeLength = PartialDescriptor->u.Memory.Length;
|
|
AccessRange->RangeInMemory = TRUE;
|
|
RangeNumber++;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
DPRINT1("Interrupt: Level %lu Vector %lu\n",
|
|
PartialDescriptor->u.Interrupt.Level,
|
|
PartialDescriptor->u.Interrupt.Vector);
|
|
if (Interrupt == 0)
|
|
{
|
|
/* Copy interrupt data */
|
|
PortConfiguration->BusInterruptLevel = PartialDescriptor->u.Interrupt.Level;
|
|
PortConfiguration->BusInterruptVector = PartialDescriptor->u.Interrupt.Vector;
|
|
|
|
/* Set interrupt mode accordingly to the resource */
|
|
if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
|
|
{
|
|
PortConfiguration->InterruptMode = Latched;
|
|
}
|
|
else if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
|
|
{
|
|
PortConfiguration->InterruptMode = LevelSensitive;
|
|
}
|
|
}
|
|
else if (Interrupt == 1)
|
|
{
|
|
/* Copy interrupt data */
|
|
PortConfiguration->BusInterruptLevel2 = PartialDescriptor->u.Interrupt.Level;
|
|
PortConfiguration->BusInterruptVector2 = PartialDescriptor->u.Interrupt.Vector;
|
|
|
|
/* Set interrupt mode accordingly to the resource */
|
|
if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
|
|
{
|
|
PortConfiguration->InterruptMode2 = Latched;
|
|
}
|
|
else if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
|
|
{
|
|
PortConfiguration->InterruptMode2 = LevelSensitive;
|
|
}
|
|
}
|
|
Interrupt++;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
DPRINT1("Dma: Channel: %lu Port: %lu\n",
|
|
PartialDescriptor->u.Dma.Channel,
|
|
PartialDescriptor->u.Dma.Port);
|
|
if (Dma == 0)
|
|
{
|
|
PortConfiguration->DmaChannel = PartialDescriptor->u.Dma.Channel;
|
|
PortConfiguration->DmaPort = PartialDescriptor->u.Dma.Port;
|
|
|
|
if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
|
|
PortConfiguration->DmaWidth = Width8Bits;
|
|
else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
|
|
(PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16))
|
|
PortConfiguration->DmaWidth = Width16Bits;
|
|
else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
|
|
PortConfiguration->DmaWidth = Width32Bits;
|
|
}
|
|
else if (Dma == 1)
|
|
{
|
|
PortConfiguration->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
|
|
PortConfiguration->DmaPort2 = PartialDescriptor->u.Dma.Port;
|
|
|
|
if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
|
|
PortConfiguration->DmaWidth2 = Width8Bits;
|
|
else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
|
|
(PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16))
|
|
PortConfiguration->DmaWidth2 = Width16Bits;
|
|
else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
|
|
PortConfiguration->DmaWidth2 = Width32Bits;
|
|
}
|
|
Dma++;
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Other: %u\n", PartialDescriptor->Type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Advance to next CM_FULL_RESOURCE_DESCRIPTOR block in memory. */
|
|
FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptor->PartialResourceList.PartialDescriptors +
|
|
FullDescriptor->PartialResourceList.Count);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MiniportInitialize(
|
|
_In_ PMINIPORT Miniport,
|
|
_In_ PFDO_DEVICE_EXTENSION DeviceExtension,
|
|
_In_ PHW_INITIALIZATION_DATA InitData)
|
|
{
|
|
PMINIPORT_DEVICE_EXTENSION MiniportExtension;
|
|
ULONG Size;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("MiniportInitialize(%p %p %p)\n",
|
|
Miniport, DeviceExtension, InitData);
|
|
|
|
Miniport->DeviceExtension = DeviceExtension;
|
|
Miniport->InitData = InitData;
|
|
|
|
/* Calculate the miniport device extension size */
|
|
Size = sizeof(MINIPORT_DEVICE_EXTENSION) +
|
|
Miniport->InitData->DeviceExtensionSize;
|
|
|
|
/* Allocate and initialize the miniport device extension */
|
|
MiniportExtension = ExAllocatePoolWithTag(NonPagedPool,
|
|
Size,
|
|
TAG_MINIPORT_DATA);
|
|
if (MiniportExtension == NULL)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
RtlZeroMemory(MiniportExtension, Size);
|
|
|
|
MiniportExtension->Miniport = Miniport;
|
|
Miniport->MiniportExtension = MiniportExtension;
|
|
|
|
/* Initialize the port configuration */
|
|
Status = InitializeConfiguration(&Miniport->PortConfig,
|
|
InitData,
|
|
DeviceExtension->BusNumber,
|
|
DeviceExtension->SlotNumber);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
/* Assign the resources to the port configuration */
|
|
AssignResourcesToConfiguration(&Miniport->PortConfig,
|
|
DeviceExtension->AllocatedResources,
|
|
InitData->NumberOfAccessRanges);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MiniportFindAdapter(
|
|
_In_ PMINIPORT Miniport)
|
|
{
|
|
BOOLEAN Reserved = FALSE;
|
|
ULONG Result;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("MiniportFindAdapter(%p)\n", Miniport);
|
|
|
|
/* Call the miniport HwFindAdapter routine */
|
|
Result = Miniport->InitData->HwFindAdapter(&Miniport->MiniportExtension->HwDeviceExtension,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Miniport->PortConfig,
|
|
&Reserved);
|
|
DPRINT1("HwFindAdapter() returned %lu\n", Result);
|
|
|
|
/* Convert the result to a status code */
|
|
switch (Result)
|
|
{
|
|
case SP_RETURN_NOT_FOUND:
|
|
DPRINT1("SP_RETURN_NOT_FOUND\n");
|
|
Status = STATUS_NOT_FOUND;
|
|
break;
|
|
|
|
case SP_RETURN_FOUND:
|
|
DPRINT1("SP_RETURN_FOUND\n");
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SP_RETURN_ERROR:
|
|
DPRINT1("SP_RETURN_ERROR\n");
|
|
Status = STATUS_ADAPTER_HARDWARE_ERROR;
|
|
break;
|
|
|
|
case SP_RETURN_BAD_CONFIG:
|
|
DPRINT1("SP_RETURN_BAD_CONFIG\n");
|
|
Status = STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Unknown result: %lu\n", Result);
|
|
Status = STATUS_INTERNAL_ERROR;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MiniportHwInitialize(
|
|
_In_ PMINIPORT Miniport)
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
DPRINT1("MiniportHwInitialize(%p)\n", Miniport);
|
|
|
|
/* Call the miniport HwInitialize routine */
|
|
Result = Miniport->InitData->HwInitialize(&Miniport->MiniportExtension->HwDeviceExtension);
|
|
DPRINT1("HwInitialize() returned %u\n", Result);
|
|
|
|
return Result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
MiniportHwInterrupt(
|
|
_In_ PMINIPORT Miniport)
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
DPRINT1("MiniportHwInterrupt(%p)\n",
|
|
Miniport);
|
|
|
|
Result = Miniport->InitData->HwInterrupt(&Miniport->MiniportExtension->HwDeviceExtension);
|
|
DPRINT1("HwInterrupt() returned %u\n", Result);
|
|
|
|
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 */
|