mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
462 lines
15 KiB
C
462 lines
15 KiB
C
/*
|
|
* PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
* PURPOSE: Registry operations
|
|
* COPYRIGHT: Eric Kohl (eric.kohl@reactos.org)
|
|
* Aleksey Bragin (aleksey@reactos.org)
|
|
* 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
|
|
*/
|
|
|
|
#include "scsiport.h"
|
|
#include "scsitypes.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
VOID
|
|
SpiInitOpenKeys(
|
|
_Inout_ PCONFIGURATION_INFO ConfigInfo,
|
|
_In_ PSCSI_PORT_DRIVER_EXTENSION DriverExtension)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING KeyName;
|
|
NTSTATUS Status;
|
|
HANDLE parametersKey;
|
|
|
|
DriverExtension->IsLegacyDriver = TRUE;
|
|
|
|
/* Open the service key */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&DriverExtension->RegistryPath,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = ZwOpenKey(&ConfigInfo->ServiceKey, KEY_READ, &ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n",
|
|
DriverExtension->RegistryPath, Status);
|
|
ConfigInfo->ServiceKey = NULL;
|
|
}
|
|
|
|
/* If we could open driver's service key, then proceed to the Parameters key */
|
|
if (ConfigInfo->ServiceKey != NULL)
|
|
{
|
|
RtlInitUnicodeString(&KeyName, L"Parameters");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
ConfigInfo->ServiceKey,
|
|
NULL);
|
|
|
|
/* Try to open it */
|
|
Status = ZwOpenKey(&ConfigInfo->DeviceKey, KEY_READ, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Yes, Parameters key exist, and it must be used instead of
|
|
the Service key */
|
|
ZwClose(ConfigInfo->ServiceKey);
|
|
ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
|
|
ConfigInfo->DeviceKey = NULL;
|
|
}
|
|
}
|
|
|
|
if (ConfigInfo->ServiceKey != NULL)
|
|
{
|
|
/* Open the Device key */
|
|
RtlInitUnicodeString(&KeyName, L"Device");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
ConfigInfo->ServiceKey,
|
|
NULL);
|
|
|
|
/* We don't check for failure here - not needed */
|
|
ZwOpenKey(&ConfigInfo->DeviceKey, KEY_READ, &ObjectAttributes);
|
|
|
|
// Detect the driver PnP capabilities via its Parameters\PnpInterface key
|
|
// for example: HKLM\SYSTEM\CurrentControlSet\Services\UNIATA\Parameters\PnpInterface
|
|
|
|
RtlInitUnicodeString(&KeyName, L"PnpInterface");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
ConfigInfo->ServiceKey,
|
|
NULL);
|
|
|
|
Status = ZwOpenKey(¶metersKey, KEY_READ, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
// if the key exists, it's enough for us for now
|
|
// (the proper check should iterate over INTERFACE_TYPE values)
|
|
DriverExtension->IsLegacyDriver = FALSE;
|
|
ZwClose(parametersKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
* NAME INTERNAL
|
|
* SpiBuildDeviceMap
|
|
*
|
|
* DESCRIPTION
|
|
* Builds the registry device map of all device which are attached
|
|
* to the given SCSI HBA port. The device map is located at:
|
|
* \Registry\Machine\DeviceMap\Scsi
|
|
*
|
|
* RUN LEVEL
|
|
* PASSIVE_LEVEL
|
|
*
|
|
* ARGUMENTS
|
|
* DeviceExtension
|
|
* ...
|
|
*
|
|
* RegistryPath
|
|
* Name of registry driver service key.
|
|
*
|
|
* RETURNS
|
|
* NTSTATUS
|
|
*/
|
|
|
|
NTSTATUS
|
|
RegistryInitAdapterKey(
|
|
_Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
WCHAR NameBuffer[64];
|
|
HANDLE ScsiKey;
|
|
HANDLE ScsiPortKey = NULL;
|
|
HANDLE ScsiBusKey = NULL;
|
|
HANDLE ScsiInitiatorKey = NULL;
|
|
ULONG BusNumber;
|
|
ULONG UlongData;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("SpiBuildDeviceMap() called\n");
|
|
|
|
if (DeviceExtension == NULL)
|
|
{
|
|
DPRINT1("Invalid parameter\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Open or create the 'Scsi' subkey */
|
|
RtlInitUnicodeString(&KeyName,
|
|
L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
|
|
0,
|
|
NULL);
|
|
Status = ZwCreateKey(&ScsiKey,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Create new 'Scsi Port X' subkey */
|
|
DPRINT("Scsi Port %lu\n", DeviceExtension->PortNumber);
|
|
|
|
swprintf(NameBuffer,
|
|
L"Scsi Port %lu",
|
|
DeviceExtension->PortNumber);
|
|
RtlInitUnicodeString(&KeyName, NameBuffer);
|
|
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_KERNEL_HANDLE, ScsiKey, NULL);
|
|
Status = ZwCreateKey(&ScsiPortKey,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
ZwClose(ScsiKey);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* Create port-specific values
|
|
*/
|
|
|
|
/* Set 'DMA Enabled' (REG_DWORD) value */
|
|
UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
|
|
DPRINT(" DMA Enabled = %s\n", UlongData ? "TRUE" : "FALSE");
|
|
RtlInitUnicodeString(&ValueName, L"DMA Enabled");
|
|
Status = ZwSetValueKey(ScsiPortKey,
|
|
&ValueName,
|
|
0,
|
|
REG_DWORD,
|
|
&UlongData,
|
|
sizeof(UlongData));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
|
|
ZwClose(ScsiPortKey);
|
|
return Status;
|
|
}
|
|
|
|
/* Set 'Driver' (REG_SZ) value */
|
|
PUNICODE_STRING driverNameU = &DeviceExtension->Common.DeviceObject->DriverObject
|
|
->DriverExtension->ServiceKeyName;
|
|
|
|
PWCHAR driverName = ExAllocatePoolWithTag(PagedPool,
|
|
driverNameU->Length + sizeof(UNICODE_NULL),
|
|
TAG_SCSIPORT);
|
|
if (!driverName)
|
|
{
|
|
DPRINT("Failed to allocate driverName!\n");
|
|
ZwClose(ScsiPortKey);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(driverName, driverNameU->Buffer, driverNameU->Length);
|
|
driverName[driverNameU->Length / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
RtlInitUnicodeString(&ValueName, L"Driver");
|
|
Status = ZwSetValueKey(ScsiPortKey,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
driverName,
|
|
driverNameU->Length + sizeof(UNICODE_NULL));
|
|
|
|
ExFreePoolWithTag(driverName, TAG_SCSIPORT);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
|
|
ZwClose(ScsiPortKey);
|
|
return Status;
|
|
}
|
|
|
|
/* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
|
|
UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
|
|
DPRINT(" Interrupt = %lu\n", UlongData);
|
|
RtlInitUnicodeString(&ValueName, L"Interrupt");
|
|
Status = ZwSetValueKey(ScsiPortKey,
|
|
&ValueName,
|
|
0,
|
|
REG_DWORD,
|
|
&UlongData,
|
|
sizeof(UlongData));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
|
|
ZwClose(ScsiPortKey);
|
|
return Status;
|
|
}
|
|
|
|
/* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
|
|
UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
|
|
DPRINT(" IOAddress = %lx\n", UlongData);
|
|
RtlInitUnicodeString(&ValueName, L"IOAddress");
|
|
Status = ZwSetValueKey(ScsiPortKey,
|
|
&ValueName,
|
|
0,
|
|
REG_DWORD,
|
|
&UlongData,
|
|
sizeof(UlongData));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
|
|
ZwClose(ScsiPortKey);
|
|
return Status;
|
|
}
|
|
|
|
/* Enumerate buses */
|
|
for (BusNumber = 0; BusNumber < DeviceExtension->NumberOfBuses; BusNumber++)
|
|
{
|
|
/* Create 'Scsi Bus X' key */
|
|
DPRINT(" Scsi Bus %lu\n", BusNumber);
|
|
swprintf(NameBuffer,
|
|
L"Scsi Bus %lu",
|
|
BusNumber);
|
|
RtlInitUnicodeString(&KeyName, NameBuffer);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_KERNEL_HANDLE,
|
|
ScsiPortKey,
|
|
NULL);
|
|
Status = ZwCreateKey(&ScsiBusKey,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
|
|
goto ByeBye;
|
|
}
|
|
|
|
/* Create 'Initiator Id X' key */
|
|
DPRINT(" Initiator Id %lu\n",
|
|
DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
|
|
swprintf(NameBuffer,
|
|
L"Initiator Id %lu",
|
|
(ULONG)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
|
|
RtlInitUnicodeString(&KeyName, NameBuffer);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_KERNEL_HANDLE,
|
|
ScsiBusKey,
|
|
NULL);
|
|
Status = ZwCreateKey(&ScsiInitiatorKey,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
|
|
goto ByeBye;
|
|
}
|
|
|
|
/* FIXME: Are there any initiator values (??) */
|
|
|
|
ZwClose(ScsiInitiatorKey);
|
|
ScsiInitiatorKey = NULL;
|
|
|
|
DeviceExtension->Buses[BusNumber].RegistryMapKey = ScsiBusKey;
|
|
ScsiBusKey = NULL;
|
|
}
|
|
|
|
ByeBye:
|
|
if (ScsiInitiatorKey != NULL)
|
|
ZwClose(ScsiInitiatorKey);
|
|
|
|
if (ScsiBusKey != NULL)
|
|
ZwClose(ScsiBusKey);
|
|
|
|
if (ScsiPortKey != NULL)
|
|
ZwClose(ScsiPortKey);
|
|
|
|
DPRINT("SpiBuildDeviceMap() done\n");
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RegistryInitLunKey(
|
|
_Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension)
|
|
{
|
|
WCHAR nameBuffer[64];
|
|
UNICODE_STRING keyName;
|
|
UNICODE_STRING valueName;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
HANDLE targetKey;
|
|
NTSTATUS status;
|
|
|
|
// get the LUN's bus key
|
|
PSCSI_PORT_DEVICE_EXTENSION portExt = LunExtension->Common.LowerDevice->DeviceExtension;
|
|
HANDLE busKey = portExt->Buses[LunExtension->PathId].RegistryMapKey;
|
|
|
|
// create/open 'Target Id X' key
|
|
swprintf(nameBuffer, L"Target Id %lu", LunExtension->TargetId);
|
|
RtlInitUnicodeString(&keyName, nameBuffer);
|
|
InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_KERNEL_HANDLE, busKey, NULL);
|
|
status = ZwCreateKey(&targetKey,
|
|
KEY_ALL_ACCESS,
|
|
&objectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DPRINT("ZwCreateKey() failed (Status %lx)\n", status);
|
|
return status;
|
|
}
|
|
|
|
// Create 'Logical Unit Id X' key
|
|
swprintf(nameBuffer, L"Logical Unit Id %lu", LunExtension->Lun);
|
|
RtlInitUnicodeString(&keyName, nameBuffer);
|
|
InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_KERNEL_HANDLE, targetKey, NULL);
|
|
status = ZwCreateKey(&LunExtension->RegistryMapKey,
|
|
KEY_ALL_ACCESS,
|
|
&objectAttributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DPRINT("ZwCreateKey() failed (Status %lx)\n", status);
|
|
goto ByeBye;
|
|
}
|
|
|
|
// Set 'Identifier' (REG_SZ) value
|
|
swprintf(nameBuffer,
|
|
L"%.8S%.16S%.4S",
|
|
LunExtension->InquiryData.VendorId,
|
|
LunExtension->InquiryData.ProductId,
|
|
LunExtension->InquiryData.ProductRevisionLevel);
|
|
RtlInitUnicodeString(&valueName, L"Identifier");
|
|
status = ZwSetValueKey(LunExtension->RegistryMapKey,
|
|
&valueName,
|
|
0,
|
|
REG_SZ,
|
|
nameBuffer,
|
|
(wcslen(nameBuffer) + 1) * sizeof(WCHAR));
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", status);
|
|
goto ByeBye;
|
|
}
|
|
|
|
// Set 'Type' (REG_SZ) value
|
|
PWCHAR typeName = (PWCHAR)GetPeripheralTypeW(&LunExtension->InquiryData);
|
|
DPRINT(" Type = '%S'\n", typeName);
|
|
RtlInitUnicodeString(&valueName, L"Type");
|
|
status = ZwSetValueKey(LunExtension->RegistryMapKey,
|
|
&valueName,
|
|
0,
|
|
REG_SZ,
|
|
typeName,
|
|
(wcslen(typeName) + 1) * sizeof(WCHAR));
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", status);
|
|
goto ByeBye;
|
|
}
|
|
|
|
// Set 'InquiryData' (REG_BINARY) value
|
|
RtlInitUnicodeString(&valueName, L"InquiryData");
|
|
status = ZwSetValueKey(LunExtension->RegistryMapKey,
|
|
&valueName,
|
|
0,
|
|
REG_BINARY,
|
|
&LunExtension->InquiryData,
|
|
INQUIRYDATABUFFERSIZE);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DPRINT("ZwSetValueKey('InquiryData') failed (Status %lx)\n", status);
|
|
goto ByeBye;
|
|
}
|
|
|
|
ByeBye:
|
|
ZwClose(targetKey);
|
|
// TODO: maybe we will need it in future
|
|
ZwClose(LunExtension->RegistryMapKey);
|
|
|
|
return status;
|
|
}
|