Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions viostor/viostor.inx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ ErrorControl = %SERVICE_ERROR_NORMAL%
ServiceBinary = %INX_PLATFORM_DRIVERS_DIR%\viostor.sys
LoadOrderGroup = SCSI miniport
AddReg = pnpsafe_pci_addreg
AddReg = bus_reset_addreg

[scsi_inst.HW]
AddReg = pnpsafe_pci_addreg_msix
Expand All @@ -93,6 +94,9 @@ HKR, "Parameters\PnpInterface", "5", %REG_DWORD%, 0x00000001
HKR, "Parameters", "BusType", %REG_DWORD%, 0x00000001
HKR, "Parameters", DmaRemappingCompatible,0x00010001,0

[bus_reset_addreg]
HKR, "Parameters\Device", "VirtioActionOnReset", %REG_DWORD%, 0x00000001

[pnpsafe_pci_addreg_msix]
HKR, "Interrupt Management",, 0x00000010
HKR, "Interrupt Management\MessageSignaledInterruptProperties",, 0x00000010
Expand Down
260 changes: 258 additions & 2 deletions viostor/virtio_stor.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,229 @@ VOID WppCleanupRoutine(PVOID arg1)
}
#endif

USHORT CopyBufferToAnsiString(void *_pDest, const void *_pSrc, const char delimiter, size_t _maxlength)
{
PCHAR dst = (PCHAR)_pDest;
PCHAR src = (PCHAR)_pSrc;
USHORT _length = _maxlength;

while (_length && (*src != delimiter))
{
*dst++ = *src++;
--_length;
};
*dst = '\0';
return _length;
}

BOOLEAN VioStorReadRegistryParameter(IN PVOID DeviceExtension, IN PUCHAR ValueName, IN LONG offset)
{
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->slot_number - 1;
ULONG value_as_ulong;

/* Get a clean buffer to store the registry value... */
pBuffer = StorPortAllocateRegistryBuffer(DeviceExtension, &pBufferLength);
if (pBuffer == NULL)
{
RhelDbgPrint(TRACE_LEVEL_WARNING, " StorPortAllocateRegistryBuffer failed to allocate buffer\n");
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.
*
* Please refer to PR #1216 for more details.
*
* FIXME NOTE END
*/
pHwAddress->Type = STOR_ADDRESS_TYPE_BTL8;
pHwAddress->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
RhelDbgPrint(TRACE_REGISTRY,
" Checking whether the HBA system port number and HBA specific registry are available for reading... "
"\n");
spgspn_rc = StorPortGetSystemPortNumber(DeviceExtension, pHwAddress);
if (spgspn_rc = STOR_STATUS_INVALID_DEVICE_STATE)
{
RhelDbgPrint(TRACE_REGISTRY,
" WARNING : !!!...HBA Port not ready yet...!!! Returns : 0x%x (STOR_STATUS_INVALID_DEVICE_STATE) "
"\n",
spgspn_rc);
/*
* 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
* 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;
RhelDbgPrint(TRACE_REGISTRY,
" Using alternate per HBA registry read technique [\\Parameters\\Device\\Value_(ddd)]. \n");

/* 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];
}

PUCHAR ValueNamePerHba = (UCHAR *)&valname_as_str;
bReadResult = StorPortRegistryRead(DeviceExtension,
ValueNamePerHba,
1,
MINIPORT_REG_DWORD,
pBuffer,
&pBufferLength);
}
else
{
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");
/* 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);
/* 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);
}

if ((bReadResult == FALSE) || (pBufferLength == 0))
{
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");
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);
/* 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);
}
/* Give me the DWORD Registry Value as a ULONG from the pointer.
* Used in TRACING.
*/
memcpy(&value_as_ulong, pBuffer, sizeof(ULONG));

if ((bReadResult == FALSE) || (pBufferLength == 0))
{
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);
StorPortFreeRegistryBuffer(DeviceExtension, pBuffer);
return FALSE;
}
else
{
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);

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

StorPortFreeRegistryBuffer(DeviceExtension, pBuffer);

return TRUE;
}
}

ULONG
DriverEntry(IN PVOID DriverObject, IN PVOID RegistryPath)
{
Expand Down Expand Up @@ -264,6 +487,11 @@ VirtIoFindAdapter(IN PVOID DeviceExtension,
adaptExt->slot_number = ConfigInfo->SlotNumber;
adaptExt->dump_mode = IsCrashDumpMode;

adaptExt->action_on_reset = VirtioResetCompleteRequests;
VioStorReadRegistryParameter(DeviceExtension,
REGISTRY_ACTION_ON_RESET,
FIELD_OFFSET(ADAPTER_EXTENSION, action_on_reset));

ConfigInfo->Master = TRUE;
ConfigInfo->ScatterGather = TRUE;
ConfigInfo->DmaWidth = Width32Bits;
Expand Down Expand Up @@ -980,7 +1208,21 @@ VirtIoStartIo(IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb)
case SRB_FUNCTION_RESET_DEVICE:
case SRB_FUNCTION_RESET_LOGICAL_UNIT:
{
CompletePendingRequests(DeviceExtension);
switch (adaptExt->action_on_reset)
{
case VirtioResetCompleteRequests:
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " Completing all pending SRBs\n");
CompletePendingRequests(DeviceExtension);
break;
case VirtioResetDoNothing:
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " Doing nothing with all pending SRBs\n");
break;
case VirtioResetBugCheck:
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " Let's bugcheck due to this reset event\n");
KeBugCheckEx(0xDEADDEAD, (ULONG_PTR)Srb, SRB_PATH_ID(Srb), SRB_TARGET_ID(Srb), SRB_LUN(Srb));
break;
}

CompleteRequestWithStatus(DeviceExtension, (PSRB_TYPE)Srb, SRB_STATUS_SUCCESS);
#ifdef DBG
RhelDbgPrint(TRACE_LEVEL_INFORMATION,
Expand Down Expand Up @@ -1202,7 +1444,21 @@ VirtIoResetBus(IN PVOID DeviceExtension, IN ULONG PathId)
PADAPTER_EXTENSION adaptExt;
adaptExt = (PADAPTER_EXTENSION)DeviceExtension;

CompletePendingRequests(DeviceExtension);
switch (adaptExt->action_on_reset)
{
case VirtioResetCompleteRequests:
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " Completing all pending SRBs\n");
CompletePendingRequests(DeviceExtension);
break;
case VirtioResetDoNothing:
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " Doing nothing with all pending SRBs\n");
break;
case VirtioResetBugCheck:
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " Let's bugcheck due to this reset event\n");
KeBugCheckEx(0xDEADDEAD, (ULONG_PTR)DeviceExtension, PathId, (ULONG_PTR)-1, (ULONG_PTR)-1);
break;
}

return TRUE;
}

Expand Down
11 changes: 10 additions & 1 deletion viostor/virtio_stor.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,18 @@ typedef struct _REQUEST_LIST
ULONG srb_cnt;
} REQUEST_LIST, *PREQUEST_LIST;

#define REGISTRY_ACTION_ON_RESET "VirtioActionOnReset"

typedef enum ACTION_ON_RESET
{
VirtioResetCompleteRequests,
VirtioResetDoNothing,
VirtioResetBugCheck = 0xDEADDEAD,
} ACTION_ON_RESET;

typedef struct _ADAPTER_EXTENSION
{
VirtIODevice vdev;

PVOID pageAllocationVa;
ULONG pageAllocationSize;
ULONG pageOffset;
Expand Down Expand Up @@ -256,6 +264,7 @@ typedef struct _ADAPTER_EXTENSION
REQUEST_LIST processing_srbs[MAX_CPU];
BOOLEAN reset_in_progress;
ULONGLONG fw_ver;
ACTION_ON_RESET action_on_reset;
ULONG_PTR last_srb_id;
#ifdef DBG
LONG srb_cnt;
Expand Down
1 change: 1 addition & 0 deletions viostor/virtio_stor_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ extern int nViostorDebugLevel;
WPP_DEFINE_BIT(TRACE_LEVEL_WARNING) /* bit 3 = 0x00000008 */ \
WPP_DEFINE_BIT(TRACE_LEVEL_INFORMATION) /* bit 4 = 0x00000010 */ \
WPP_DEFINE_BIT(TRACE_LEVEL_VERBOSE) /* bit 5 = 0x00000020 */ \
WPP_DEFINE_BIT(TRACE_REGISTRY) /* bit 6 = 0x00000040 */ \
)

#define WPP_Flags_LEVEL_LOGGER(Flags, level) \
Expand Down