Skip to content

Commit

Permalink
[vioscsi] Extend VioScsiReadRegistryParameter()
Browse files Browse the repository at this point in the history
Adds capability to do per HBA registry reads.
This permits, e.g. PhysicalBreaks_001, PhysicalBreaks_002, etc. as
an alternative to \Parameters\Device(d) by instead using the
format \Parameters\Device\Valuename_123.
Includes FIXME NOTE regarding StorPortGetSystemPortNumber().
StorPortGetSystemPortNumber() should return before HBA-specific
registry reads can successfully use \Parameters\Device(d).

Coincidentally updated the following in VioScsiFindAdapter():
adaptExt->dump_mode (new tracing)
adaptExt->hba_id (new tracing and new definition)

The HBA ID that determines the "123" in Valuename_123 of the registry
path \Parameters\Device\Valuename_123 is the HBA slot number minus 1.

Signed-off-by: benyamin-codez <[email protected]>
  • Loading branch information
benyamin-codez committed Dec 7, 2024
1 parent 38c92fa commit 100af3e
Showing 1 changed file with 218 additions and 30 deletions.
248 changes: 218 additions & 30 deletions vioscsi/vioscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,41 +304,220 @@ BOOLEAN VioScsiReadRegistryParameter(
IN LONG offset
)
{
BOOLEAN Ret = FALSE;
ULONG Len = sizeof(ULONG);
UCHAR* pBuf = NULL;
PADAPTER_EXTENSION adaptExt;


adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
pBuf = StorPortAllocateRegistryBuffer(DeviceExtension, &Len);
if (pBuf == NULL) {
RhelDbgPrint(TRACE_LEVEL_FATAL, "StorPortAllocateRegistryBuffer failed to allocate buffer\n");
BOOLEAN bReadResult = FALSE;
BOOLEAN bUseAltPerHbaRegRead = FALSE;
ULONG pBufferLength = sizeof(ULONG);
UCHAR* pBuffer = NULL;
PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
ULONG spgspn_rc, i, j;
STOR_ADDRESS HwAddress = { 0 };
PSTOR_ADDRESS pHwAddress = &HwAddress;
CHAR valname_as_str[64] = { 0 };
CHAR hba_id_as_str[4] = { 0 };
USHORT shAdapterId = (USHORT)adaptExt->hba_id;
#if !defined(RUN_UNCHECKED)
ULONG value_as_ulong;
#endif

/* Get a clean buffer to store the registry value... */
pBuffer = StorPortAllocateRegistryBuffer(DeviceExtension, &pBufferLength);
if (pBuffer == NULL) {
#if !defined(RUN_UNCHECKED) || defined(RUN_MIN_CHECKED)
RhelDbgPrint(TRACE_LEVEL_WARNING, " StorPortAllocateRegistryBuffer failed to allocate buffer\n");
#endif
return FALSE;
}
memset(pBuffer, 0, sizeof(ULONG));

/* Check if we can get a System PortNumber to access the \Parameters\Device(d) subkey to get a per HBA value.
* FIXME NOTE
*
* Regarding StorPortGetSystemPortNumber():
*
* StorPort always reports STOR_STATUS_INVALID_DEVICE_STATE and does not update pHwAddress->Port.
* Calls to StorPortRegistryRead() and StorPortRegistryWrite() only read or write to \Parameters\Device-1,
* which appears to be an uninitialized value. Therefore, the alternate per HBA read technique will always be used.
*
* Various initialisation syntaxes were attempted, including partial and fully initialized STOR_ADDRESS and
* STOR_ADDR_BTL8 structs and pointers. Attempts to initialize most of the deprecated HW_INITIALIZATION_DATA
* and PORT_CONFIGURATION_INFORMATION members were also made, but of no effect with regard to this function.
* Using DeviceExtension or the adaptExt pointer as the first parameter to the function had no effect.
* Attempts to set the InitiatorBusId were successful, but of no effect with regard to this function.
* Also attempted BusType = BusTypeScsi (rather than BusTypeSas per inf default) - in both the inf and using
* StorPortSetAdapterBusType() too. Also tried many other BusTypes via StorPortSetAdapterBusType() mechanics.
* Maybe something in WMI or VPD processing...? Do we need PortAttributes.PortState = HBA_PORTSTATE_ONLINE and
* PortAttributes.PortType = HBA_PORTTYPE_SASDEVICE to be set...? Should we be initializing adaptExt->wwn,
* adaptExt->port_wwn or adaptExt->port_idx...? The wMI routines are not using the InstanceIndex and InstanceCount
* parameters to cycle through HBAs. Maybe they should...
*
* Difficult to determine what is wrong here...
* ¯\_(ツ)_/¯
*
* FIXME NOTE END
*/
pHwAddress->Type = STOR_ADDRESS_TYPE_BTL8;
pHwAddress->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_REGISTRY, " Checking whether the HBA system port number and HBA specific registry are available for reading... \n");
#endif
spgspn_rc = StorPortGetSystemPortNumber(DeviceExtension, pHwAddress);
if (spgspn_rc = STOR_STATUS_INVALID_DEVICE_STATE) {
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_REGISTRY, " WARNING : !!!...HBA Port not ready yet...!!! Returns : 0x%x (STOR_STATUS_INVALID_DEVICE_STATE) \n", spgspn_rc);
#endif
/*
* When we are unable to get a valid system PortNumber, we need to
* use an alternate per HBA registry read technique. The technique
* implemented here uses per HBA registry value names based on the
* hba_id, which is the Storport provided slot_number minus one,
* padded to hundreds, e.g. \Parameters\Device\Valuename_123.
*
* This permits up to 999 HBAs. That ought to be enough... c( O.O )ɔ
*/
bUseAltPerHbaRegRead = TRUE;
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_REGISTRY, " Using alternate per HBA registry read technique [\\Parameters\\Device\\Value_(ddd)]. \n");
#endif

/* Grab the first 60 characters of the target Registry Value.
* Value name limit is 16,383 characters, so this is important.
* We leave the last 4 characters for the hba_id_as_str values.
* NULL terminator wraps things up. Also used in TRACING.
*/
CopyBufferToAnsiString(&valname_as_str, ValueName, '\0', 60);
CopyBufferToAnsiString(&hba_id_as_str, &shAdapterId, '\0', 4);

/* Convert from integer to padded ASCII numbers. */
if (shAdapterId / 100) {
j = 0;
hba_id_as_str[j] = (UCHAR)(shAdapterId / 100) + 48;
} else {
hba_id_as_str[0] = 48;
if (shAdapterId / 10) {
j = 1;
hba_id_as_str[j] = (UCHAR)(shAdapterId / 10) + 48;
} else {
hba_id_as_str[1] = 48;
j = 2;
hba_id_as_str[j] = (UCHAR)shAdapterId + 48;
}
}
if ((j < 1) && (shAdapterId / 10)) {
j = 1;
hba_id_as_str[j] = (UCHAR)(((shAdapterId - ((shAdapterId / 100) * 100)) / 10) + 48);
} else if ((j < 2) && (shAdapterId > 9)) {
j = 2;
hba_id_as_str[j] = (UCHAR)((shAdapterId - ((shAdapterId / 10) * 10)) + 48);
} else {
j = 1;
hba_id_as_str[j] = 48;
}
if ((j < 2) && (shAdapterId > 0)) {
j = 2;
hba_id_as_str[j] = (UCHAR)((shAdapterId - ((shAdapterId / 10) * 10)) + 48);
} else if (j < 2) {
j = 2;
hba_id_as_str[j] = 48;
}
/* NULL-terminate the string. */
hba_id_as_str[3] = '\0';
/* Skip the exisitng ValueName. */
for (i = 0; valname_as_str[i] != '\0'; ++i) {}
/* Append an underscore. */
valname_as_str[i] = '\x5F';
/* Append the padded HBA ID and NULL terminator. */
for (j = 0; j < 4; ++j) {
valname_as_str[i + j + 1] = hba_id_as_str[j];
}

memset(pBuf, 0, sizeof(ULONG));

Ret = StorPortRegistryRead(DeviceExtension,
ValueName,
1,
MINIPORT_REG_DWORD,
pBuf,
&Len);
PUCHAR ValueNamePerHba = (UCHAR*)&valname_as_str;
bReadResult = StorPortRegistryRead(DeviceExtension,
ValueNamePerHba,
1,
MINIPORT_REG_DWORD,
pBuffer,
&pBufferLength);

if ((Ret == FALSE) || (Len == 0)) {
RhelDbgPrint(TRACE_LEVEL_FATAL, "StorPortRegistryRead returned 0x%x, Len = %d\n", Ret, Len);
StorPortFreeRegistryBuffer(DeviceExtension, pBuf);
return FALSE;
} else {
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_REGISTRY, " HBA Port : %u | Returns : 0x%x \n", pHwAddress->Port, spgspn_rc);
RhelDbgPrint(TRACE_REGISTRY, " Using StorPort-based per HBA registry read [\\Parameters\\Device(d)]. \n");
#endif
/* FIXME : THIS DOES NOT WORK. IT WILL NOT READ \Parameters\Device(d) subkeys...
* NOTE : Only MINIPORT_REG_DWORD values are supported.
*/
bReadResult = StorPortRegistryRead(DeviceExtension,
ValueName,
0,
MINIPORT_REG_DWORD,
pBuffer,
&pBufferLength);
#if !defined(RUN_UNCHECKED)
/* Grab the first 64 characters of the target Registry Value.
* Value name limit is 16,383 characters, so this is important.
* NULL terminator wraps things up. Used in TRACING.
*/
CopyBufferToAnsiString(&valname_as_str, ValueName, '\0', 64);
#endif
}

if ((bReadResult == FALSE) || (pBufferLength == 0)) {
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_REGISTRY,
" StorPortRegistryRead was unable to find a per HBA value %s. Attempting to find a global value... \n",
(bUseAltPerHbaRegRead) ? "using \\Parameters\\Device\\Value_(ddd) value names" : "at the \\Parameters\\Device(d) subkey");
#endif
bReadResult = FALSE;
pBufferLength = sizeof(ULONG);
memset(pBuffer, 0, sizeof(ULONG));

/* Do a "Global" read of the Parameters\Device subkey...
* NOTE : Only MINIPORT_REG_DWORD values are supported.
*/
bReadResult = StorPortRegistryRead(DeviceExtension,
ValueName,
1,
MINIPORT_REG_DWORD,
pBuffer,
&pBufferLength);
#if !defined(RUN_UNCHECKED)
/* Grab the first 64 characters of the target Registry Value.
* Value name limit is 16,383 characters, so this is important.
* NULL terminator wraps things up. Used in TRACING.
*/
CopyBufferToAnsiString(&valname_as_str, ValueName, '\0', 64);
#endif
}
#if !defined(RUN_UNCHECKED)
/* Give me the DWORD Registry Value as a ULONG from the pointer.
* Used in TRACING.
*/
memcpy(&value_as_ulong, pBuffer, sizeof(ULONG));
#endif

if ((bReadResult == FALSE) || (pBufferLength == 0)) {
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_REGISTRY,
" StorPortRegistryRead of %s returned NOT FOUND or EMPTY, pBufferLength = %d, Possible pBufferLength Hint = 0x%x (%lu) \n",
valname_as_str, pBufferLength, value_as_ulong, value_as_ulong);
#endif
StorPortFreeRegistryBuffer(DeviceExtension, pBuffer);
return FALSE;
} else {
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_REGISTRY,
" StorPortRegistryRead of %s returned SUCCESS, pBufferLength = %d, Value = 0x%x (%lu) \n",
valname_as_str, pBufferLength, value_as_ulong, value_as_ulong);
#endif

StorPortCopyMemory((PVOID)((UINT_PTR)adaptExt + offset),
(PVOID)pBuffer,
sizeof(ULONG));

StorPortFreeRegistryBuffer(DeviceExtension, pBuffer );

StorPortCopyMemory((PVOID)((UINT_PTR)adaptExt + offset),
(PVOID)pBuf,
sizeof(ULONG));

StorPortFreeRegistryBuffer(DeviceExtension, pBuf );

return TRUE;
return TRUE;
}
}

ULONG
Expand Down Expand Up @@ -457,7 +636,16 @@ ENTER_FN();
RtlZeroMemory(adaptExt, sizeof(ADAPTER_EXTENSION));

adaptExt->dump_mode = IsCrashDumpMode;
adaptExt->hba_id = HBA_ID;
#if !defined(RUN_UNCHECKED) || defined(RUN_MIN_CHECKED)
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " Crash dump mode : %s \n", (adaptExt->dump_mode == IsCrashDumpMode) ? "ACTIVATED" : "NOT ACTIVATED");
#endif

/* Set the hba_id to the StorPort supplied SlotNumber minus one. Used as an analogue for the system PortNumber. */
adaptExt->hba_id = (CCHAR)ConfigInfo->SlotNumber - 1;
#if !defined(RUN_UNCHECKED) || defined(RUN_MIN_CHECKED)
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " HBA ID [adaptExt->hba_id] : %I64d \n", adaptExt->hba_id);
#endif

ConfigInfo->Master = TRUE;
ConfigInfo->ScatterGather = TRUE;
ConfigInfo->DmaWidth = Width32Bits;
Expand Down

0 comments on commit 100af3e

Please sign in to comment.