Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vioscsi] New ProcessQueue() routine #1214

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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 vioscsi/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ SynchronizedKickEventRoutine(IN PVOID DeviceExtension, IN PVOID Context);

VOID VioScsiCompleteDpcRoutine(IN PSTOR_DPC Dpc, IN PVOID Context, IN PVOID SystemArgument1, IN PVOID SystemArgument2);

BOOLEAN
FORCEINLINE
ProcessQueue(IN PVOID DeviceExtension, IN ULONG MessageId, IN PVOID InlineFuncName);

VOID ProcessBuffer(IN PVOID DeviceExtension, IN ULONG MessageId, IN STOR_SPINLOCK LockMode);

VOID
Expand Down
310 changes: 156 additions & 154 deletions vioscsi/vioscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ PreProcessRequest(IN PVOID DeviceExtension, IN PSRB_TYPE Srb);

VOID FORCEINLINE PostProcessRequest(IN PVOID DeviceExtension, IN PSRB_TYPE Srb);

VOID FORCEINLINE DispatchQueue(IN PVOID DeviceExtension, IN ULONG MessageId);
BOOLEAN
FORCEINLINE
DispatchQueue(IN PVOID DeviceExtension, IN ULONG MessageId, IN PVOID InlineFuncName);

BOOLEAN
VioScsiInterrupt(IN PVOID DeviceExtension);
Expand Down Expand Up @@ -937,163 +939,29 @@ VOID HandleResponse(IN PVOID DeviceExtension, IN PVirtIOSCSICmd cmd)
BOOLEAN
VioScsiInterrupt(IN PVOID DeviceExtension)
{
PVirtIOSCSICmd cmd = NULL;
PVirtIOSCSIEventNode evtNode = NULL;
unsigned int len = 0;
PADAPTER_EXTENSION adaptExt = NULL;
BOOLEAN isInterruptServiced = FALSE;
PSRB_TYPE Srb = NULL;
ULONG intReason = 0;

adaptExt = (PADAPTER_EXTENSION)DeviceExtension;

if (adaptExt->bRemoved)
{
return FALSE;
}

#if !defined(RUN_UNCHECKED)
// NOTE : SDV banned function
// RhelDbgPrint(TRACE_LEVEL_VERBOSE, " IRQL (%d)\n", KeGetCurrentIrql());
#endif

intReason = virtio_read_isr_status(&adaptExt->vdev);

if (intReason == 1 || adaptExt->dump_mode)
{
isInterruptServiced = TRUE;

if (adaptExt->tmf_infly)
{
while ((cmd = (PVirtIOSCSICmd)virtqueue_get_buf(adaptExt->vq[VIRTIO_SCSI_CONTROL_QUEUE], &len)) != NULL)
{
VirtIOSCSICtrlTMFResp *resp;
Srb = (PSRB_TYPE)cmd->srb;
ASSERT(Srb == (PSRB_TYPE)&adaptExt->tmf_cmd.Srb);
resp = &cmd->resp.tmf;
switch (resp->response)
{
case VIRTIO_SCSI_S_OK:
case VIRTIO_SCSI_S_FUNCTION_SUCCEEDED:
break;
default:
RhelDbgPrint(TRACE_LEVEL_ERROR, " unknown response %d\n", resp->response);
ASSERT(0);
break;
}
StorPortResume(DeviceExtension);
}
adaptExt->tmf_infly = FALSE;
}
while ((evtNode = (PVirtIOSCSIEventNode)virtqueue_get_buf(adaptExt->vq[VIRTIO_SCSI_EVENTS_QUEUE], &len)) !=
NULL)
{
PVirtIOSCSIEvent evt = &evtNode->event;
switch (evt->event)
{
case VIRTIO_SCSI_T_NO_EVENT:
break;
case VIRTIO_SCSI_T_TRANSPORT_RESET:
TransportReset(DeviceExtension, evt);
break;
case VIRTIO_SCSI_T_PARAM_CHANGE:
ParamChange(DeviceExtension, evt);
break;
default:
RhelDbgPrint(TRACE_LEVEL_ERROR, " Unsupport virtio scsi event %x\n", evt->event);
break;
}
SynchronizedKickEventRoutine(DeviceExtension, evtNode);
}

if (!adaptExt->dump_mode && adaptExt->dpc_ok)
{
StorPortIssueDpc(DeviceExtension,
&adaptExt->dpc[0],
ULongToPtr(QUEUE_TO_MESSAGE(VIRTIO_SCSI_REQUEST_QUEUE_0)),
ULongToPtr(QUEUE_TO_MESSAGE(VIRTIO_SCSI_REQUEST_QUEUE_0)));
}
else
{
ProcessBuffer(DeviceExtension, QUEUE_TO_MESSAGE(VIRTIO_SCSI_REQUEST_QUEUE_0), InterruptLock);
}
}

RhelDbgPrint(TRACE_LEVEL_VERBOSE, " isInterruptServiced = %d\n", isInterruptServiced);
return isInterruptServiced;
}

static BOOLEAN VioScsiMSInterruptWorker(IN PVOID DeviceExtension, IN ULONG MessageID)
{
PVirtIOSCSICmd cmd;
PVirtIOSCSIEventNode evtNode;
unsigned int len;
PADAPTER_EXTENSION adaptExt;
PSRB_TYPE Srb = NULL;
ULONG intReason = 0;

adaptExt = (PADAPTER_EXTENSION)DeviceExtension;

RhelDbgPrint(TRACE_LEVEL_VERBOSE, " MessageID 0x%x\n", MessageID);

if (MessageID >= QUEUE_TO_MESSAGE(VIRTIO_SCSI_REQUEST_QUEUE_0))
if ((virtio_read_isr_status(&adaptExt->vdev) == 1) || adaptExt->dump_mode)
{
DispatchQueue(DeviceExtension, MessageID);
return TRUE;
}
if (MessageID == 0)
{
return TRUE;
return ProcessQueue(DeviceExtension,
VIRTIO_SCSI_REQUEST_QUEUE_0 + VIRTIO_SCSI_MSI_CONTROL_Q_OFFSET,
"ProcessQueue");
}
if (MessageID == QUEUE_TO_MESSAGE(VIRTIO_SCSI_CONTROL_QUEUE))
{
if (adaptExt->tmf_infly)
{
while ((cmd = (PVirtIOSCSICmd)virtqueue_get_buf(adaptExt->vq[VIRTIO_SCSI_CONTROL_QUEUE], &len)) != NULL)
{
VirtIOSCSICtrlTMFResp *resp;
Srb = (PSRB_TYPE)(cmd->srb);
ASSERT(Srb == (PSRB_TYPE)&adaptExt->tmf_cmd.Srb);
resp = &cmd->resp.tmf;
switch (resp->response)
{
case VIRTIO_SCSI_S_OK:
case VIRTIO_SCSI_S_FUNCTION_SUCCEEDED:
break;
default:
RhelDbgPrint(TRACE_LEVEL_ERROR, " Unknown response %d\n", resp->response);
ASSERT(0);
break;
}
StorPortResume(DeviceExtension);
}
adaptExt->tmf_infly = FALSE;
}
return TRUE;
}
if (MessageID == QUEUE_TO_MESSAGE(VIRTIO_SCSI_EVENTS_QUEUE))
else
{
while ((evtNode = (PVirtIOSCSIEventNode)virtqueue_get_buf(adaptExt->vq[VIRTIO_SCSI_EVENTS_QUEUE], &len)) !=
NULL)
{
PVirtIOSCSIEvent evt = &evtNode->event;
switch (evt->event)
{
case VIRTIO_SCSI_T_NO_EVENT:
break;
case VIRTIO_SCSI_T_TRANSPORT_RESET:
TransportReset(DeviceExtension, evt);
break;
case VIRTIO_SCSI_T_PARAM_CHANGE:
ParamChange(DeviceExtension, evt);
break;
default:
RhelDbgPrint(TRACE_LEVEL_ERROR, " Unsupport virtio scsi event %x\n", evt->event);
break;
}
SynchronizedKickEventRoutine(DeviceExtension, evtNode);
}
return TRUE;
return FALSE;
}
return FALSE;
}

BOOLEAN
Expand All @@ -1111,15 +979,15 @@ VioScsiMSInterrupt(IN PVOID DeviceExtension, IN ULONG MessageID)
if (!adaptExt->msix_one_vector)
{
/* Each queue has its own vector, this is the fast and common case */
return VioScsiMSInterruptWorker(DeviceExtension, MessageID);
return ProcessQueue(DeviceExtension, MessageId, "ProcessQueue");
}

/* Fall back to checking all queues */
for (i = 0; i < adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0; i++)
{
if (virtqueue_has_buf(adaptExt->vq[i]))
{
isInterruptServiced |= VioScsiMSInterruptWorker(DeviceExtension, i + 1);
isInterruptServiced |= ProcessQueue(DeviceExtension, i + VIRTIO_SCSI_MSI_CONTROL_Q_OFFSET, "ProcessQueue");
}
}
return isInterruptServiced;
Expand Down Expand Up @@ -1400,25 +1268,159 @@ VioScsiBuildIo(IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb)
return TRUE;
}

VOID FORCEINLINE DispatchQueue(IN PVOID DeviceExtension, IN ULONG MessageId)
BOOLEAN
FORCEINLINE
ProcessQueue(IN PVOID DeviceExtension, IN ULONG MessageId, IN PVOID InlineFuncName)
{
#if !defined(RUN_UNCHECKED)
ENTER_INL_FN();
#endif

PVirtIOSCSICmd cmd;
PVirtIOSCSIEventNode evtNode;
unsigned int len;
PADAPTER_EXTENSION adaptExt;
PSRB_TYPE Srb = NULL;

adaptExt = (PADAPTER_EXTENSION)DeviceExtension;

#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_LEVEL_VERBOSE, " Processing VirtIO Queue : %lu \n", MESSAGE_TO_QUEUE(MessageId));
#endif

if (MessageId >= QUEUE_TO_MESSAGE(VIRTIO_SCSI_REQUEST_QUEUE_0))
{
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_LEVEL_VERBOSE, " Dispatching to Request Queue...\n");
#endif
BOOLEAN dispatch_q_status = DispatchQueue(DeviceExtension, MessageId, "DispatchQueue");
#if !defined(RUN_UNCHECKED)
EXIT_INL_FN();
#endif
return dispatch_q_status;
}
if ((MessageId == 0) && (VIRTIO_SCSI_MSI_CONTROL_Q_OFFSET != 0))
{
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_LEVEL_VERBOSE,
" MSI-X Vector 0 [MessageId = 0] is unused by HBA. Returning without further processing.\n");
EXIT_INL_FN();
#endif
return TRUE;
}
if (MessageId == QUEUE_TO_MESSAGE(VIRTIO_SCSI_CONTROL_QUEUE))
{
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_LEVEL_VERBOSE, " Processing Control Queue...\n");
#endif
if (adaptExt->tmf_infly)
{
while ((cmd = (PVirtIOSCSICmd)virtqueue_get_buf(adaptExt->vq[VIRTIO_SCSI_CONTROL_QUEUE], &len)) != NULL)
{
VirtIOSCSICtrlTMFResp *resp;
Srb = (PSRB_TYPE)(cmd->srb);
ASSERT(Srb == (PSRB_TYPE)&adaptExt->tmf_cmd.Srb);
resp = &cmd->resp.tmf;
switch (resp->response)
{
case VIRTIO_SCSI_S_OK:
case VIRTIO_SCSI_S_FUNCTION_SUCCEEDED:
break;
default:
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_LEVEL_ERROR, " Unknown ERROR response %d\n", resp->response);
#endif
ASSERT(0);
break;
}
StorPortResume(DeviceExtension);
}
adaptExt->tmf_infly = FALSE;
}
#if !defined(RUN_UNCHECKED)
EXIT_INL_FN();
#endif
return TRUE;
}
if (MessageId == QUEUE_TO_MESSAGE(VIRTIO_SCSI_EVENTS_QUEUE))
{
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_LEVEL_VERBOSE, " Processing Events Queue...\n");
#endif
while ((evtNode = (PVirtIOSCSIEventNode)virtqueue_get_buf(adaptExt->vq[VIRTIO_SCSI_EVENTS_QUEUE], &len)) !=
NULL)
{
PVirtIOSCSIEvent evt = &evtNode->event;
switch (evt->event)
{
case VIRTIO_SCSI_T_NO_EVENT:
break;
case VIRTIO_SCSI_T_TRANSPORT_RESET:
TransportReset(DeviceExtension, evt);
break;
case VIRTIO_SCSI_T_PARAM_CHANGE:
ParamChange(DeviceExtension, evt);
break;
default:
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_LEVEL_ERROR, " Unsupport virtio scsi event %x\n", evt->event);
#endif
break;
}
SynchronizedKickEventRoutine(DeviceExtension, evtNode);
}
#if !defined(RUN_UNCHECKED)
EXIT_INL_FN();
#endif
return TRUE;
}
#if !defined(RUN_UNCHECKED)
EXIT_INL_FN();
#endif
return FALSE;
}

BOOLEAN
FORCEINLINE
DispatchQueue(IN PVOID DeviceExtension, IN ULONG MessageId, IN PVOID InlineFuncName)
{
#if !defined(RUN_UNCHECKED)
ENTER_INL_FN();
#endif

PADAPTER_EXTENSION adaptExt;
ENTER_FN();

adaptExt = (PADAPTER_EXTENSION)DeviceExtension;

if (!adaptExt->dump_mode && adaptExt->dpc_ok)
{
NT_ASSERT(MessageId >= QUEUE_TO_MESSAGE(VIRTIO_SCSI_REQUEST_QUEUE_0));
StorPortIssueDpc(DeviceExtension,
&adaptExt->dpc[MessageId - QUEUE_TO_MESSAGE(VIRTIO_SCSI_REQUEST_QUEUE_0)],
ULongToPtr(MessageId),
ULongToPtr(MessageId));
EXIT_FN();
return;
if (StorPortIssueDpc(DeviceExtension,
&adaptExt->dpc[MessageId - QUEUE_TO_MESSAGE(VIRTIO_SCSI_REQUEST_QUEUE_0)],
ULongToPtr(MessageId),
ULongToPtr(MessageId)))
{
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_DPC, " The request to queue a DPC was successful.\n");
EXIT_INL_FN();
#endif
return TRUE;
}
else
{
#if !defined(RUN_UNCHECKED)
RhelDbgPrint(TRACE_DPC,
" The request to queue a DPC was NOT successful. It may already be queued elsewhere.\n");
EXIT_INL_FN();
#endif
return FALSE;
}
}
ProcessBuffer(DeviceExtension, MessageId, InterruptLock);
EXIT_FN();
#if !defined(RUN_UNCHECKED)
EXIT_INL_FN();
#endif
return TRUE;
}

VOID ProcessBuffer(IN PVOID DeviceExtension, IN ULONG MessageId, IN STOR_SPINLOCK LockMode)
Expand Down
5 changes: 3 additions & 2 deletions vioscsi/vioscsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ typedef struct VirtIOBufferDescriptor VIO_SG, *PVIO_SG;
#define VIRTIO_SCSI_QUEUE_LAST VIRTIO_SCSI_REQUEST_QUEUE_0 + MAX_CPU

/* MSI messages and virtqueue indices are offset by 1, MSI 0 is not used */
#define QUEUE_TO_MESSAGE(QueueId) ((QueueId) + 1)
#define MESSAGE_TO_QUEUE(MessageId) ((MessageId)-1)
#define VIRTIO_SCSI_MSI_CONTROL_Q_OFFSET 1
#define QUEUE_TO_MESSAGE(QueueId) ((QueueId) + VIRTIO_SCSI_MSI_CONTROL_Q_OFFSET)
#define MESSAGE_TO_QUEUE(MessageId) ((MessageId)-VIRTIO_SCSI_MSI_CONTROL_Q_OFFSET)

/* SCSI command request, followed by data-out */
#pragma pack(1)
Expand Down