278 lines
7 KiB
C
278 lines
7 KiB
C
#include <mpio.h>
|
||
|
||
|
||
VOID
|
||
MPIOInitQueue(
|
||
IN PMP_QUEUE Queue,
|
||
IN ULONG QueueTag
|
||
)
|
||
{
|
||
//
|
||
// Initialize this queue's spinlock.
|
||
//
|
||
KeInitializeSpinLock(&Queue->SpinLock);
|
||
|
||
//
|
||
// Init the list entry.
|
||
//
|
||
InitializeListHead(&Queue->ListEntry);
|
||
|
||
//
|
||
// Set the number of items.
|
||
//
|
||
Queue->QueuedItems = 0;
|
||
|
||
//
|
||
// Set the queue marker.
|
||
//
|
||
Queue->QueueIndicator = QueueTag;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
MPIOInsertQueue(
|
||
IN PMP_QUEUE Queue,
|
||
IN PMPQUEUE_ENTRY QueueEntry
|
||
)
|
||
{
|
||
KIRQL irql;
|
||
|
||
KeAcquireSpinLock(&Queue->SpinLock, &irql);
|
||
|
||
//
|
||
// Insert the entry on the queue.
|
||
//
|
||
InsertTailList(&Queue->ListEntry,
|
||
&QueueEntry->ListEntry);
|
||
|
||
//
|
||
// Indicate the additonal item.
|
||
//
|
||
Queue->QueuedItems++;
|
||
|
||
KeReleaseSpinLock(&Queue->SpinLock, irql);
|
||
|
||
}
|
||
|
||
|
||
PMPQUEUE_ENTRY
|
||
MPIORemoveQueue(
|
||
IN PMP_QUEUE Queue
|
||
)
|
||
{
|
||
KIRQL irql;
|
||
PLIST_ENTRY entry;
|
||
|
||
KeAcquireSpinLock(&Queue->SpinLock, &irql);
|
||
|
||
//
|
||
// Get the next item on the list.
|
||
//
|
||
entry = RemoveHeadList(&Queue->ListEntry);
|
||
|
||
//
|
||
// Indicate one less.
|
||
//
|
||
Queue->QueuedItems--;
|
||
|
||
KeReleaseSpinLock(&Queue->SpinLock, irql);
|
||
|
||
return CONTAINING_RECORD(entry, MPQUEUE_ENTRY, ListEntry);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPIOIssueQueuedRequests(
|
||
IN PREAL_DEV_INFO TargetInfo,
|
||
IN PMP_QUEUE Queue,
|
||
IN ULONG State,
|
||
IN PULONG RequestCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine runs Queue, extracts the requests and issues them
|
||
to DeviceObject.
|
||
It is used to handle the various failure queue submissions.
|
||
It assumes that the requests are ready to submit, context values
|
||
updated, and all targetInfo,diskExtension, deviceExtension values to
|
||
be correct.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The MPDev Object to which the request is to be sent.
|
||
Queue - The failure queue to be drained.
|
||
CompletionRoutine - The appropriate completion routine to be set-up.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PMPQUEUE_ENTRY queueEntry;
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpStack;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PMPIO_CONTEXT context;
|
||
ULONG issued = 0;
|
||
ULONG initialCount = Queue->QueuedItems;
|
||
|
||
//
|
||
// See if anything is actually in the queue.
|
||
//
|
||
if (Queue->QueuedItems == 0) {
|
||
MPDebugPrint((0,
|
||
"MPIOIssueQueuedRequests: Asked to issue Zero requests\n"));
|
||
DbgBreakPoint();
|
||
*RequestCount = 0;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
MPDebugPrint((0,
|
||
"IssueQueuedRequests: Handling (%x) in State (%x)\n",
|
||
Queue,
|
||
State));
|
||
do {
|
||
|
||
//
|
||
// Get the next entry in the queue.
|
||
// This also dec's QueuedItems.
|
||
//
|
||
queueEntry = MPIORemoveQueue(Queue);
|
||
if (queueEntry) {
|
||
|
||
//
|
||
// Extract the irp, our stack location, and the
|
||
// associated context.
|
||
//
|
||
irp = queueEntry->Irp;
|
||
irpStack = IoGetCurrentIrpStackLocation(irp);
|
||
context = irpStack->Parameters.Others.Argument4;
|
||
|
||
//
|
||
// Update the state, so that the completion routine
|
||
// can figure out when this was sent.
|
||
//
|
||
context->CurrentState = State;
|
||
context->ReIssued = TRUE;
|
||
|
||
//
|
||
// Hack out the Dsm Completion info.
|
||
// Otherwise, we call them twice for this request.
|
||
// BUGBUG: Or call set completion again.
|
||
//
|
||
context->DsmCompletion.DsmCompletionRoutine = NULL;
|
||
context->DsmCompletion.DsmContext = NULL;
|
||
context->TargetInfo = TargetInfo;
|
||
|
||
InterlockedIncrement(&TargetInfo->Requests);
|
||
|
||
//
|
||
// Determine whether this contains an Srb or not.
|
||
//
|
||
if (irpStack->MajorFunction == IRP_MJ_SCSI) {
|
||
|
||
//
|
||
// Need to rebuild the Srb.
|
||
//
|
||
RtlCopyMemory(irpStack->Parameters.Scsi.Srb,
|
||
&context->Srb,
|
||
sizeof(SCSI_REQUEST_BLOCK));
|
||
|
||
|
||
}
|
||
|
||
//
|
||
// Re-do status and information.
|
||
//
|
||
irp->IoStatus.Status = 0;
|
||
irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Rebuild port's stack location.
|
||
//
|
||
IoCopyCurrentIrpStackLocationToNext(irp);
|
||
|
||
//
|
||
// Set the appropriate completion routine.
|
||
//
|
||
IoSetCompletionRoutine(irp,
|
||
MPPdoGlobalCompletion,
|
||
context,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
//
|
||
// Send it to "DeviceObject".
|
||
//
|
||
status = IoCallDriver(TargetInfo->DevFilter, irp);
|
||
|
||
issued++;
|
||
|
||
//
|
||
// Update the caller's number of requests.
|
||
// TODO: This is updating the value that is already set.
|
||
// Either remove the parameter and this count update, or
|
||
// have callers use a different variable (not the diskExtension->XXXCount);
|
||
//
|
||
InterlockedIncrement(RequestCount);
|
||
|
||
//
|
||
// Status should be pending or success.
|
||
//
|
||
if ((status != STATUS_PENDING) &&
|
||
(status != STATUS_SUCCESS)){
|
||
|
||
//
|
||
// Completion routine will handle this, but make a
|
||
// note of the failure. TODO firgure out a better way to
|
||
// do this.
|
||
//
|
||
MPDebugPrint((0,
|
||
"MPIOIssueQueuedRequests: Irp (%x) sent to (%x) - Status (%x)\n",
|
||
irp,
|
||
TargetInfo->DevFilter,
|
||
status));
|
||
//
|
||
// LOG
|
||
//
|
||
ASSERT(status == STATUS_SUCCESS);
|
||
}
|
||
|
||
//
|
||
// Free the allocaiton.
|
||
// NOTE: These queueEntries should be on a LookasideList.
|
||
//
|
||
ExFreePool(queueEntry);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Ensure that the queue is actually empty.
|
||
//
|
||
ASSERT(Queue->QueuedItems == 0);
|
||
}
|
||
|
||
//
|
||
// BUGBUG: There is no throttling mechanism here. It would be easy
|
||
// to overload the underlying adapter in some cases.
|
||
//
|
||
// NOTE: It may be better to re-categorize all the requests instead of
|
||
// just sending all to the "newPath" that the DSM indicated.
|
||
//
|
||
// Need to note this behaviour to DSM authors!
|
||
//
|
||
} while (Queue->QueuedItems);
|
||
|
||
MPDebugPrint((0,
|
||
"IssueQueuedRequests: Issued (%x) out of (%x)\n",
|
||
issued,
|
||
initialCount));
|
||
|
||
return status;
|
||
}
|
||
|