-
Notifications
You must be signed in to change notification settings - Fork 387
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] Fix SendSRB regression and refactor for optimum performance [viostor] Backport SendSRB improvements #1135
Changes from all commits
a719ccd
4d4bf72
2887e8b
2e033cb
976c325
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -56,21 +56,25 @@ SendSRB( | |||||
UCHAR ScsiStatus = SCSISTAT_GOOD; | ||||||
ULONG MessageID; | ||||||
int res = 0; | ||||||
BOOLEAN notify = FALSE; | ||||||
PREQUEST_LIST element; | ||||||
ULONG index; | ||||||
ENTER_FN_SRB(); | ||||||
|
||||||
if (!Srb) | ||||||
return; | ||||||
ENTER_FN_SRB(); | ||||||
|
||||||
if (!Srb) { | ||||||
EXIT_FN_SRB(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. EXIT_FN_SRB() is an alias for debuggin, right? if so, can we align/indent appropriately here? Means it easier to read There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The question here I think is: does it stay or does it go...? Another call slows the driver down. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's probably worth mentioning that we can probably add some conditional blocks like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The other option here, if everyone is ok with using it would be to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatively, we can just drop an appropriately indented Any of these work for me. What I think is most important is that there is working tracing... |
||||||
return; | ||||||
} | ||||||
|
||||||
if (adaptExt->bRemoved) { | ||||||
SRB_SET_SRB_STATUS(Srb, SRB_STATUS_NO_DEVICE); | ||||||
CompleteRequest(DeviceExtension, Srb); | ||||||
return; | ||||||
} | ||||||
|
||||||
EXIT_FN_SRB(); | ||||||
benyamin-codez marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
return; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need this extra indent? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, nor the indent for the brace at L75. |
||||||
} | ||||||
LOG_SRB_INFO(); | ||||||
|
||||||
if (adaptExt->num_queues > 1) { | ||||||
STARTIO_PERFORMANCE_PARAMETERS param; | ||||||
param.Size = sizeof(STARTIO_PERFORMANCE_PARAMETERS); | ||||||
|
@@ -82,53 +86,55 @@ ENTER_FN_SRB(); | |||||
} | ||||||
} else { | ||||||
RhelDbgPrint(TRACE_LEVEL_ERROR, " StorPortGetStartIoPerfParams failed srb 0x%p status 0x%x MessageNumber %d.\n", Srb, status, param.MessageNumber); | ||||||
// FIXME | ||||||
// Should we return on this error..? | ||||||
// Should it be TRACE_LEVEL_FATAL..? | ||||||
//is_done = TRUE; | ||||||
} | ||||||
} | ||||||
|
||||||
srbExt = SRB_EXTENSION(Srb); | ||||||
|
||||||
if (!srbExt) { | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " No SRB Extenstion for SRB 0x%p \n", Srb); | ||||||
EXIT_FN_SRB(); | ||||||
benyamin-codez marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
return; | ||||||
} | ||||||
|
||||||
MessageID = QUEUE_TO_MESSAGE(QueueNumber); | ||||||
index = QueueNumber - VIRTIO_SCSI_REQUEST_QUEUE_0; | ||||||
|
||||||
if (adaptExt->reset_in_progress) { | ||||||
RhelDbgPrint(TRACE_LEVEL_FATAL, " Reset is in progress, completing SRB 0x%p with SRB_STATUS_BUS_RESET.\n", Srb); | ||||||
RhelDbgPrint(TRACE_LEVEL_WARNING, " Reset is in progress, completing SRB 0x%p with SRB_STATUS_BUS_RESET.\n", Srb); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no problem, but why go from FATAL to WARNING here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm presuming that we have historically always wanted to see this. In WPP, I think this would be TRACE_LEVEL_NONE, but in Dbg this probably wouldn't work. However, it is actually just a warning, and should succeed following the reset. If not, this should generate an TRACE_LEVEL_ERROR or TRACE_LEVEL_FATAL event. |
||||||
SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BUS_RESET); | ||||||
CompleteRequest(DeviceExtension, Srb); | ||||||
EXIT_FN_SRB(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, there's going to be lots... 8^d |
||||||
return; | ||||||
} | ||||||
|
||||||
VioScsiVQLock(DeviceExtension, MessageID, &LockHandle, FALSE); | ||||||
VioScsiLockManager(DeviceExtension, MessageID, &LockHandle, FALSE, VIOSCSI_VQLOCKOP_LOCK); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO make the the introduction and cut-in of VioScsiLockManager a completely separate commit/PR. Then have another commit/PR that does the move-around There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have the technology. <-- I hope you get the reference... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be clear, the idea here was to permit WPP tracing of each lock/unlock function whilst optimising. The problem with optimising and WPP is that |
||||||
SET_VA_PA(); | ||||||
res = virtqueue_add_buf(adaptExt->vq[QueueNumber], | ||||||
srbExt->psgl, | ||||||
srbExt->out, srbExt->in, | ||||||
&srbExt->cmd, va, pa); | ||||||
|
||||||
if (res >= 0) { | ||||||
notify = virtqueue_kick_prepare(adaptExt->vq[QueueNumber]); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be clear, in this case, we're only //potentially// kicking the underlying device if we're successful in enqueueing work. This function also has a membarrier, which are are now doing under the lock, vs outside the lock in the previous code I certainly love it when stuff is faster, but it isn't immediately clearer to me why this code would be more performant than the existing code. Is the idea that we're changing the amount of kicks happening for the better? Would love to know your observations here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was the breaking change following the v208 package. |
||||||
element = &adaptExt->processing_srbs[index]; | ||||||
InsertTailList(&element->srb_list, &srbExt->list_entry); | ||||||
element->srb_cnt++; | ||||||
} | ||||||
VioScsiVQUnlock(DeviceExtension, MessageID, &LockHandle, FALSE); | ||||||
if ( res >= 0){ | ||||||
if (virtqueue_kick_prepare(adaptExt->vq[QueueNumber])) { | ||||||
virtqueue_notify(adaptExt->vq[QueueNumber]); | ||||||
} | ||||||
} else { | ||||||
virtqueue_notify(adaptExt->vq[QueueNumber]); | ||||||
ScsiStatus = SCSISTAT_QUEUE_FULL; | ||||||
SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BUSY); | ||||||
SRB_SET_SCSI_STATUS(Srb, ScsiStatus); | ||||||
StorPortBusy(DeviceExtension, 10); | ||||||
CompleteRequest(DeviceExtension, Srb); | ||||||
RhelDbgPrint(TRACE_LEVEL_FATAL, " Could not put an SRB into a VQ, so complete it with SRB_STATUS_BUSY. QueueNumber = %d, SRB = 0x%p, Lun = %d, TimeOut = %d.\n", QueueNumber, srbExt->Srb, SRB_LUN(Srb), Srb->TimeOutValue); | ||||||
RhelDbgPrint(TRACE_LEVEL_WARNING, " Could not put an SRB into a VQ, so complete it with SRB_STATUS_BUSY. QueueNumber = %d, SRB = 0x%p, Lun = %d, TimeOut = %d.\n", QueueNumber, srbExt->Srb, SRB_LUN(Srb), Srb->TimeOutValue); | ||||||
} | ||||||
VioScsiLockManager(DeviceExtension, MessageID, &LockHandle, FALSE, VIOSCSI_VQLOCKOP_UNLOCK); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So is the bug here that we're simply unlocking the queue too soon, such that when there is the error path here, things can get jumbled up and blow up? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe so, but probably something underlying in the virtqueue implementation too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this change doesn't just touch the error path but also the happy path (
I'm no VirtIO expert so I can't really say whether Also, it looks like until and including 7dc052d, the kvm-guest-drivers-windows/vioscsi/helper.c Line 112 in 7dc052d
and happens outside the lock starting with f1338bb (this commit is also mentioned by @benyamin-codez) kvm-guest-drivers-windows/vioscsi/helper.c Line 109 in f1338bb
Could the early unlock be the cause for the vioscsi "Reset to device \Device\RaidPortN" + IO lockups? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, under high load conditions, this could certainly be a trigger. It's probably worth pointing out that Here is the latter from void virtqueue_notify(struct virtqueue *vq)
{
vq->notification_cb(vq);
}
void virtqueue_kick(struct virtqueue *vq)
{
if (virtqueue_kick_prepare(vq)) {
virtqueue_notify(vq);
}
} However, if (_vq->vdev->event_suppression_enabled) {
return wrap_around || (bool)vring_need_event(vring_avail_event(&vq->vring), new, old);
} else {
return !(vq->vring.used->flags & VIRTQ_USED_F_NO_NOTIFY);
} ...and: /* The Host uses this in used->flags to advise the Guest: don't kick me when
* you add a buffer. It's unreliable, so it's simply an optimization. Guest
* will still kick if it's out of buffers. */
#define VIRTQ_USED_F_NO_NOTIFY 1 It also bears mentioning, that even when a notification callback is required it is completely up to the device as to what it will do. It may well just ignore the kicks... |
||||||
if (notify){ | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would we not want to kick the underlying backend in the failure case? In the QUEUE_FULL branch above, notify will be false, yea? In which case, we wont send a kick. I'd imagine we would want to kick in unilaterally, just in case it needs to be hit with a hammer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think there was a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So it appears that res will only ever (famous last words) be a 0 (SUCCESS) or a 28 (ENOSPC: No space left on device), i.e. SCSISTAT_QUEUE_FULL. The test should really be As no data was added to a buffer, does it really need any further action? You might observe in my reply to @frwbr above that a call to We could call a My thoughts were that it would just consume compute resources and time. |
||||||
virtqueue_notify(adaptExt->vq[QueueNumber]); | ||||||
} | ||||||
|
||||||
EXIT_FN_SRB(); | ||||||
} | ||||||
|
||||||
|
@@ -185,6 +191,7 @@ DeviceReset( | |||||
|
||||||
ENTER_FN(); | ||||||
if (adaptExt->dump_mode) { | ||||||
EXIT_FN(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto on my comments about indentation if we can get away with it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, let's wait to see what Vadim says. |
||||||
return TRUE; | ||||||
} | ||||||
ASSERT(adaptExt->tmf_infly == FALSE); | ||||||
|
@@ -197,7 +204,7 @@ ENTER_FN(); | |||||
cmd->req.tmf.lun[3] = 0; | ||||||
cmd->req.tmf.type = VIRTIO_SCSI_T_TMF; | ||||||
cmd->req.tmf.subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET; | ||||||
|
||||||
srbExt->psgl = srbExt->vio_sg; | ||||||
srbExt->pdesc = srbExt->desc_alias; | ||||||
sgElement = 0; | ||||||
|
@@ -212,9 +219,11 @@ ENTER_FN(); | |||||
StorPortPause(DeviceExtension, 60); | ||||||
if (!SendTMF(DeviceExtension, Srb)) { | ||||||
StorPortResume(DeviceExtension); | ||||||
EXIT_FN(); | ||||||
return FALSE; | ||||||
} | ||||||
adaptExt->tmf_infly = TRUE; | ||||||
EXIT_FN(); | ||||||
return TRUE; | ||||||
} | ||||||
|
||||||
|
@@ -384,46 +393,48 @@ ENTER_FN(); | |||||
SP_INTERNAL_ADAPTER_ERROR, | ||||||
__LINE__); | ||||||
RhelDbgPrint(TRACE_LEVEL_FATAL, " CANNOT READ PCI CONFIGURATION SPACE %d\n", pci_cfg_len); | ||||||
EXIT_FN(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this whole part should be a separate PR. Not that its bad, just seems orthogonal? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue was that in the trace I could see entry into the functions, but when leaving early, it indicated a potential problem, because the corresponding exit trace was missing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Jon, if you were actually talking about the section below, it was because it was in orphaned braces. |
||||||
return FALSE; | ||||||
} | ||||||
|
||||||
|
||||||
UCHAR CapOffset; | ||||||
PPCI_MSIX_CAPABILITY pMsixCapOffset; | ||||||
PPCI_COMMON_HEADER pPciComHeader; | ||||||
pPciComHeader = &adaptExt->pci_config; | ||||||
if ((pPciComHeader->Status & PCI_STATUS_CAPABILITIES_LIST) == 0) | ||||||
{ | ||||||
UCHAR CapOffset; | ||||||
PPCI_MSIX_CAPABILITY pMsixCapOffset; | ||||||
PPCI_COMMON_HEADER pPciComHeader; | ||||||
pPciComHeader = &adaptExt->pci_config; | ||||||
if ((pPciComHeader->Status & PCI_STATUS_CAPABILITIES_LIST) == 0) | ||||||
{ | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " NO CAPABILITIES_LIST\n"); | ||||||
} | ||||||
else | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " NO CAPABILITIES_LIST\n"); | ||||||
} else | ||||||
{ | ||||||
if ((pPciComHeader->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_DEVICE_TYPE) | ||||||
{ | ||||||
if ((pPciComHeader->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_DEVICE_TYPE) | ||||||
CapOffset = pPciComHeader->u.type0.CapabilitiesPtr; | ||||||
while (CapOffset != 0) | ||||||
{ | ||||||
CapOffset = pPciComHeader->u.type0.CapabilitiesPtr; | ||||||
while (CapOffset != 0) | ||||||
pMsixCapOffset = (PPCI_MSIX_CAPABILITY)&adaptExt->pci_config_buf[CapOffset]; | ||||||
if (pMsixCapOffset->Header.CapabilityID == PCI_CAPABILITY_ID_MSIX) | ||||||
{ | ||||||
pMsixCapOffset = (PPCI_MSIX_CAPABILITY)&adaptExt->pci_config_buf[CapOffset]; | ||||||
if (pMsixCapOffset->Header.CapabilityID == PCI_CAPABILITY_ID_MSIX) | ||||||
{ | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.TableSize = %d\n", pMsixCapOffset->MessageControl.TableSize); | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.FunctionMask = %d\n", pMsixCapOffset->MessageControl.FunctionMask); | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.MSIXEnable = %d\n", pMsixCapOffset->MessageControl.MSIXEnable); | ||||||
|
||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " MessageTable = %lu\n", pMsixCapOffset->MessageTable.TableOffset); | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " PBATable = %lu\n", pMsixCapOffset->PBATable.TableOffset); | ||||||
adaptExt->msix_enabled = (pMsixCapOffset->MessageControl.MSIXEnable == 1); | ||||||
} else | ||||||
{ | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " CapabilityID = %x, Next CapOffset = %x\n", pMsixCapOffset->Header.CapabilityID, CapOffset); | ||||||
} | ||||||
CapOffset = pMsixCapOffset->Header.Next; | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.TableSize = %d\n", pMsixCapOffset->MessageControl.TableSize); | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.FunctionMask = %d\n", pMsixCapOffset->MessageControl.FunctionMask); | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.MSIXEnable = %d\n", pMsixCapOffset->MessageControl.MSIXEnable); | ||||||
|
||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " MessageTable = %lu\n", pMsixCapOffset->MessageTable.TableOffset); | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " PBATable = %lu\n", pMsixCapOffset->PBATable.TableOffset); | ||||||
adaptExt->msix_enabled = (pMsixCapOffset->MessageControl.MSIXEnable == 1); | ||||||
} else | ||||||
{ | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " CapabilityID = %x, Next CapOffset = %x\n", pMsixCapOffset->Header.CapabilityID, CapOffset); | ||||||
} | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " msix_enabled = %d\n", adaptExt->msix_enabled); | ||||||
} else | ||||||
{ | ||||||
RhelDbgPrint(TRACE_LEVEL_FATAL, " NOT A PCI_DEVICE_TYPE\n"); | ||||||
CapOffset = pMsixCapOffset->Header.Next; | ||||||
} | ||||||
RhelDbgPrint(TRACE_LEVEL_INFORMATION, " msix_enabled = %d\n", adaptExt->msix_enabled); | ||||||
} else | ||||||
{ | ||||||
RhelDbgPrint(TRACE_LEVEL_FATAL, " NOT A PCI_DEVICE_TYPE\n"); | ||||||
// FIXME | ||||||
// Should we not return on this error..? | ||||||
//EXIT_FN(); | ||||||
//return FALSE; | ||||||
} | ||||||
} | ||||||
|
||||||
|
@@ -435,19 +446,21 @@ ENTER_FN(); | |||||
if (iBar == -1) { | ||||||
RhelDbgPrint(TRACE_LEVEL_FATAL, | ||||||
" Cannot get index for BAR %I64d\n", accessRange->RangeStart.QuadPart); | ||||||
EXIT_FN(); | ||||||
return FALSE; | ||||||
} | ||||||
adaptExt->pci_bars[iBar].BasePA = accessRange->RangeStart; | ||||||
adaptExt->pci_bars[iBar].uLength = accessRange->RangeLength; | ||||||
adaptExt->pci_bars[iBar].bPortSpace = !accessRange->RangeInMemory; | ||||||
} | ||||||
} | ||||||
|
||||||
/* initialize the virtual device */ | ||||||
if (!InitVirtIODevice(DeviceExtension)) { | ||||||
EXIT_FN(); | ||||||
return FALSE; | ||||||
} | ||||||
|
||||||
EXIT_FN(); | ||||||
return TRUE; | ||||||
} | ||||||
|
@@ -491,53 +504,78 @@ ENTER_FN(); | |||||
RtlZeroMemory((PVOID)EventNode, sizeof(VirtIOSCSIEventNode)); | ||||||
EventNode->sg.physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &EventNode->event, &fragLen); | ||||||
EventNode->sg.length = sizeof(VirtIOSCSIEvent); | ||||||
EXIT_FN(); | ||||||
return SynchronizedKickEventRoutine(DeviceExtension, (PVOID)EventNode); | ||||||
} | ||||||
|
||||||
VOID | ||||||
// | ||||||
// FORCEINLINE <<---- DO NOT FORCE INLINE | ||||||
// Wrapper for VioScsiVQLock and VioScsiVQUnlock, so they can be forced inline for optimum performance. | ||||||
// | ||||||
VioScsiLockManager( | ||||||
IN PVOID DeviceExtension, | ||||||
IN ULONG MessageID, | ||||||
IN OUT PSTOR_LOCK_HANDLE LockHandle, | ||||||
IN BOOLEAN isr, | ||||||
IN BOOLEAN LockOp | ||||||
) | ||||||
{ | ||||||
ENTER_FN(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need ENTER_/EXIT_ for this particular function? It really is just a wrapper for the lock/unlock. I wonder if it would be more efficient to just put the ENTER/EXIT for isr==TRUE only? like put it on the }. else { conditional at the bottom? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe, but I just wanted to check we left the function clean. Remember, it's for the tracing. |
||||||
if (!isr) { | ||||||
// ^^^^^^ Checking NOT isr moved here... | ||||||
switch (LockOp) { | ||||||
case VIOSCSI_VQLOCKOP_LOCK: | ||||||
VioScsiVQLock(DeviceExtension, MessageID, LockHandle, "VioScsiVQLock"); | ||||||
break; | ||||||
case VIOSCSI_VQLOCKOP_UNLOCK: | ||||||
VioScsiVQUnlock(DeviceExtension, LockHandle, "VioScsiVQUnlock"); | ||||||
break; | ||||||
default: | ||||||
break; | ||||||
} | ||||||
} | ||||||
EXIT_FN(); | ||||||
} | ||||||
|
||||||
VOID | ||||||
//FORCEINLINE | ||||||
FORCEINLINE | ||||||
VioScsiVQLock( | ||||||
IN PVOID DeviceExtension, | ||||||
IN ULONG MessageID, | ||||||
IN OUT PSTOR_LOCK_HANDLE LockHandle, | ||||||
IN BOOLEAN isr | ||||||
IN PVOID InlineFuncName | ||||||
) | ||||||
{ | ||||||
PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; | ||||||
ULONG QueueNumber = MESSAGE_TO_QUEUE(MessageID); | ||||||
ENTER_FN(); | ||||||
|
||||||
if (!isr) { | ||||||
if (adaptExt->msix_enabled) { | ||||||
// Queue numbers start at 0, message ids at 1. | ||||||
NT_ASSERT(MessageID > VIRTIO_SCSI_REQUEST_QUEUE_0); | ||||||
if (QueueNumber >= (adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0)) { | ||||||
QueueNumber %= adaptExt->num_queues; | ||||||
} | ||||||
StorPortAcquireSpinLock(DeviceExtension, DpcLock, &adaptExt->dpc[QueueNumber - VIRTIO_SCSI_REQUEST_QUEUE_0], LockHandle); | ||||||
} | ||||||
else { | ||||||
StorPortAcquireSpinLock(DeviceExtension, InterruptLock, NULL, LockHandle); | ||||||
|
||||||
ENTER_INL_FN(); | ||||||
|
||||||
if (adaptExt->msix_enabled) { | ||||||
// Queue numbers start at 0, message ids at 1. | ||||||
NT_ASSERT(MessageID > VIRTIO_SCSI_REQUEST_QUEUE_0); | ||||||
if (QueueNumber >= (adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0)) { | ||||||
QueueNumber %= adaptExt->num_queues; | ||||||
} | ||||||
StorPortAcquireSpinLock(DeviceExtension, DpcLock, &adaptExt->dpc[QueueNumber - VIRTIO_SCSI_REQUEST_QUEUE_0], LockHandle); | ||||||
} else { | ||||||
StorPortAcquireSpinLock(DeviceExtension, InterruptLock, NULL, LockHandle); | ||||||
} | ||||||
EXIT_FN(); | ||||||
EXIT_INL_FN(); | ||||||
} | ||||||
|
||||||
VOID | ||||||
//FORCEINLINE | ||||||
FORCEINLINE | ||||||
VioScsiVQUnlock( | ||||||
IN PVOID DeviceExtension, | ||||||
IN ULONG MessageID, | ||||||
IN PSTOR_LOCK_HANDLE LockHandle, | ||||||
IN BOOLEAN isr | ||||||
IN PVOID InlineFuncName | ||||||
) | ||||||
{ | ||||||
ENTER_FN(); | ||||||
if (!isr) { | ||||||
StorPortReleaseSpinLock(DeviceExtension, LockHandle); | ||||||
} | ||||||
EXIT_FN(); | ||||||
ENTER_INL_FN(); | ||||||
StorPortReleaseSpinLock(DeviceExtension, LockHandle); | ||||||
EXIT_INL_FN(); | ||||||
} | ||||||
|
||||||
VOID FirmwareRequest( | ||||||
|
@@ -560,6 +598,7 @@ ENTER_FN(); | |||||
SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH); | ||||||
RhelDbgPrint(TRACE_LEVEL_ERROR, | ||||||
" FirmwareRequest Bad Block Length %ul\n", dataLen); | ||||||
EXIT_FN(); | ||||||
return; | ||||||
} | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, do we ever hit this scenario where we are coming into SendSRB with a null Srb? Meaning, are there any callers that actually can do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seemed like a sanity check to me. It lives on, so maybe someone saw one in the past. We can add a WPP macro here to check and use a reserved flag and just look for that in the trace. It would take pretty extreme performance testing, and more to the point - fairly thorough fail condition testing. Maybe raise a new issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, it is a kind of sanity check. Static driver verifier was failing without this check.