Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

306 lines
8.7 KiB

#include "mpio.h"
NTSTATUS
MPIOInitiateFailOver(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID FailingPath,
IN ULONG ErrorMask
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
PDSM_ENTRY dsm = &diskExtension->DsmInfo;
PREAL_DEV_INFO targetInfo;
PVOID newPath = NULL;
NTSTATUS status;
WCHAR buffer[64];
MPDebugPrint((0,
"InitiateFailOver: Invalidating %x\n",
FailingPath));
//
// Initiate the fail-over.
//
status = dsm->InvalidatePath(dsm->DsmContext,
ErrorMask,
FailingPath,
&newPath);
MPDebugPrint((0,
"InitiateFailOver: New Path (%x)\n",
newPath));
//
// TODO - Put in real Path identiifiers.
//
swprintf(buffer,L"Path (%x) Failed Over to (%x)", FailingPath, newPath);
MPIOFireEvent(DeviceObject,
L"MPIO WrkerThrd",
buffer,
MPIO_WARNING);
//
// If successful, go into DEGRADED
//
if ((status == STATUS_SUCCESS) && newPath) {
//
// Ensure that newPath actually is found in one of the TargetInfo
// structures that make up this mpdisk.
//
targetInfo = MPIOGetTargetInfo(diskExtension,
newPath,
NULL);
if (targetInfo == NULL) {
MPDebugPrint((0,
"MPIOInitiateFailOver: No match for path (%x)\n",
newPath));
DbgBreakPoint();
return STATUS_NO_SUCH_DEVICE;
}
ASSERT(newPath == targetInfo->PathId);
//
// Verify that this path/device combo. is ready.
//
status = dsm->PathVerify(dsm->DsmContext,
targetInfo->DsmID,
targetInfo->PathId);
if (!NT_SUCCESS(status)) {
MPDebugPrint((0,
"MPIOInitiateFailOver: PathVerify failed (%x)\n",
status));
//
// Log.
//
return status;
}
//
// Ensure the new path is active.
// Invalidate path should have done everything to assure that
// the new device(s) are ready.
//
targetInfo->PathActive = dsm->IsPathActive(dsm->DsmContext,
newPath);
ASSERT(targetInfo->PathActive);
//
// Set CurrentPath to this new one.
//
diskExtension->CurrentPath = newPath;
//
// Update all that are using this path, that it has changed.
//
MPIOSetNewPath(diskExtension->ControlObject,
newPath);
} else {
if (newPath == NULL) {
MPDebugPrint((0,
"MPIOInitiateFailOver: DSM returned NULL path\n"));
}
if (status != STATUS_SUCCESS) {
//
// LOG
//
MPDebugPrint((0,
"MPIOInitiateFailOver: DSM returned (%x)\n",
status));
}
//
// Set the path to NULL. The callback will key off this and the bad status.
//
diskExtension->CurrentPath = NULL;
DbgBreakPoint();
}
return status;
}
VOID
MPIORecoveryThread(
IN PVOID Context
)
/*++
Routine Description:
This routine is the thread proc that is started upon creation of an mpdisk.
When signaled, it will initiate the fail-over, insure that the new path is
ready, then call-back the mpdisk to indicate success or failure of the operation.
Arguments:
Context - Info needed to handle the fail-over.
Return Value:
None.
--*/
{
PMPIO_THREAD_CONTEXT context = Context;
PDEVICE_OBJECT deviceObject = context->DeviceObject;
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
PKEVENT event = context->Event;
PVOID failingPath;
MPIO_CALLBACK RequestComplete;
PMPIO_REQUEST_INFO requestInfo;
PLIST_ENTRY entry;
NTSTATUS status;
ULONG i;
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
while (TRUE) {
//
// Wait on the event.
//
KeWaitForSingleObject(event,
Executive,
KernelMode,
FALSE,
NULL);
KeClearEvent(event);
//
// Yank the packet.
//
entry = ExInterlockedRemoveHeadList(&diskExtension->WorkList,
&diskExtension->WorkListLock);
ASSERT(entry);
//
// Get the actual work item.
//
requestInfo = CONTAINING_RECORD(entry, MPIO_REQUEST_INFO, ListEntry);
//
// Get the call-back proc.
//
RequestComplete = requestInfo->RequestComplete;
//
// Determine the operation.
//
if (requestInfo->Operation == INITIATE_FAILOVER) {
//
// Get the device that indicated the failure.
//
failingPath = requestInfo->OperationSpecificInfo;
//
// Asking for a fail-over. Call the handler.
//
status = MPIOInitiateFailOver(deviceObject,
failingPath,
requestInfo->ErrorMask);
} else if (requestInfo->Operation == SHUTDOWN) {
//
// Being signaled to die.
//
ExFreePool(requestInfo);
goto terminateThread;
} else if (requestInfo->Operation == FORCE_RESCAN) {
PFLTR_ENTRY fltrEntry;
fltrEntry = (PFLTR_ENTRY)(requestInfo->OperationSpecificInfo);
MPIOForceRescan(fltrEntry->FilterObject);
//
// Indicate that the rescan is complete.
//
fltrEntry->Flags &= ~FLTR_FLAGS_RESCANNING;
} else if (requestInfo->Operation == PATH_REMOVAL) {
PDSM_ENTRY dsm = &diskExtension->DsmInfo;
MPDebugPrint((0,
"RecoveryThread: Removing Path (%x)\n",
requestInfo->OperationSpecificInfo));
//
// Call the dsm to clean up. All of the devices have been
// removed, and any pending actions have been completed, so
// it's safe to do this now.
//
dsm->RemovePath(dsm->DsmContext,
requestInfo->OperationSpecificInfo);
} else if (requestInfo->Operation == DEVICE_REMOVAL) {
PMPIO_DEVICE_REMOVAL deviceRemoval = requestInfo->OperationSpecificInfo;
MPDebugPrint((0,
"RecoveryThread: Removing Device (%x) DsmID (%x)\n",
deviceRemoval->TargetInfo,
deviceRemoval->TargetInfo->DsmID));
//
// Invoke the remove routine.
//
status = MPIORemoveDeviceAsync(deviceRemoval->DeviceObject,
deviceRemoval->TargetInfo);
//
// Free this allocation.
//
ExFreePool(deviceRemoval);
} else {
MPDebugPrint((0,
"MPIORecoveryThread: Invalid operation (%x) in (%x)\n",
requestInfo->Operation,
requestInfo));
ASSERT(FALSE);
}
if (RequestComplete) {
//
// Invoke the call-back routine to indicate
// completion.
//
RequestComplete(deviceObject,
requestInfo->Operation,
status);
if (requestInfo->Operation == INITIATE_FAILOVER) {
//
// Force a rescan on the disks adapters.
//
for (i = 0; i < diskExtension->TargetInfoCount; i++ ) {
MPIOForceRescan(diskExtension->TargetInfo[i].DevFilter);
}
}
}
//
// Dispose of the work item.
//
ExFreePool(requestInfo);
}
terminateThread:
PsTerminateSystemThread(STATUS_SUCCESS);
}