/*++
Copyright (C) 2004-2010 Microsoft Corporation
Module Name:
dsmmain.c
Abstract:
This driver is the Microsoft Device Specific Module (DSM).
It exports behaviours that mpio.sys will use to determine how to
multipath SPC-3 conforming devices.
This file contains routines that are internal to MSDSM.
Environment:
kernel mode only
Notes:
--*/
#include "precomp.h"
#ifdef DEBUG_USE_WPP
#include "dsmmain.tmh"
#endif
#pragma warning (disable:4305)
extern BOOLEAN DoAssert;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, DsmpRegisterPersistentReservationKeys)
#endif
VOID
DsmpFreeDSMResources(
_In_ IN PDSM_CONTEXT DsmContext
)
/*++
Routine Description:
This routine will free the resources allocated by the DSM. This routine
should be called when the DSM is being unloaded.
Arguements:
DsmContext - DSM context given to MPIO during initialization
Return Value:
None
--*/
{
PDSM_WMILIB_CONTEXT wmiInfo;
PVOID tempAddress = (PVOID)DsmContext;
TracePrint((TRACE_LEVEL_VERBOSE,
TRACE_FLAG_INIT,
"DsmpFreeDSMResources (DsmCtxt %p): Entering function.\n",
DsmContext));
//
// First free the buffer allocated for storing the registry path.
//
wmiInfo = &gDsmInitData.DsmWmiInfo;
if (wmiInfo->RegistryPath.Buffer) {
TracePrint((TRACE_LEVEL_INFORMATION,
TRACE_FLAG_INIT,
"DsmpFreeDSMResources (DsmCtxt %p): Freeing wmiInfo's registry buffer.\n",
DsmContext));
DsmpFreePool(wmiInfo->RegistryPath.Buffer);
}
if (DsmContext) {
PLIST_ENTRY entry;
PDSM_DEVICE_INFO deviceInfo;
PDSM_GROUP_ENTRY groupEntry;
PDSM_FAILOVER_GROUP failGroup;
PDSM_CONTROLLER_LIST_ENTRY controllerEntry;
ExDeleteNPagedLookasideList(&(DsmContext->CompletionContextList));
//
// Free up the devices (DeviceInfo) list.
//
while (!IsListEmpty(&DsmContext->DeviceList)) {
entry = DsmContext->DeviceList.Flink;
NT_ASSERT(entry);
deviceInfo = CONTAINING_RECORD(entry, DSM_DEVICE_INFO, ListEntry);
if (deviceInfo) {
DsmpRemoveDeviceFailGroup(DsmContext, deviceInfo->FailGroup, deviceInfo, TRUE);
DsmpRemoveDeviceEntry(DsmContext, deviceInfo->Group, deviceInfo);
}
}
NT_ASSERT(!DsmContext->NumberDevices &&
!DsmContext->NumberFOGroups &&
!DsmContext->NumberGroups);
//
// By now, there should be no group entries left but play it safe and
// free up the GROUP list.
//
while (!IsListEmpty(&DsmContext->GroupList)) {
entry = DsmContext->GroupList.Flink;
NT_ASSERT(entry);
groupEntry = CONTAINING_RECORD(entry, DSM_GROUP_ENTRY, ListEntry);
if (groupEntry) {
DsmpRemoveGroupEntry(DsmContext, groupEntry, TRUE);
DsmpFreePool(groupEntry);
}
}
//
// By now there should be no FOG entries left but we play it safe and
// free up the FOG list.
//
while (!IsListEmpty(&DsmContext->FailGroupList)) {
entry = RemoveHeadList(&DsmContext->FailGroupList);
if (entry) {
failGroup = CONTAINING_RECORD(entry, DSM_FAILOVER_GROUP, ListEntry);
if (failGroup) {
PDSM_FOG_DEVICELIST_ENTRY fogDeviceListEntry = NULL;
PLIST_ENTRY deviceEntry = NULL;
while (!IsListEmpty(&failGroup->FOG_DeviceList)) {
deviceEntry = RemoveHeadList(&failGroup->FOG_DeviceList);
if (deviceEntry) {
fogDeviceListEntry = CONTAINING_RECORD(deviceEntry, DSM_FOG_DEVICELIST_ENTRY, ListEntry);
if (!fogDeviceListEntry) {
continue;
}
(fogDeviceListEntry->DeviceInfo)->FailGroup = NULL;
DsmpFreePool(fogDeviceListEntry);
InterlockedDecrement((LONG volatile*)&failGroup->Count);
}
}
DsmpFreeZombieGroupList(failGroup);
DsmpFreePool(failGroup);
InterlockedDecrement((LONG volatile*)&DsmContext->NumberFOGroups);
}
}
}
//
// Free up the controller list.
//
while (!IsListEmpty(&DsmContext->ControllerList)) {
entry = RemoveHeadList(&DsmContext->ControllerList);
if (entry) {
controllerEntry = CONTAINING_RECORD(entry, DSM_CONTROLLER_LIST_ENTRY, ListEntry);
if (controllerEntry) {
DsmpFreeControllerEntry(DsmContext, controllerEntry);
InterlockedDecrement((LONG volatile*)&DsmContext->NumberControllers);
}
}
}
NT_ASSERT(!DsmContext->NumberControllers);
//
// Free up the stale FOG list.
//
while (!IsListEmpty(&DsmContext->StaleFailGroupList)) {
entry = RemoveHeadList(&DsmContext->StaleFailGroupList);
if (entry) {
failGroup = CONTAINING_RECORD(entry, DSM_FAILOVER_GROUP, ListEntry);
if (failGroup) {
InterlockedDecrement((LONG volatile*)&DsmContext->NumberStaleFOGroups);
NT_ASSERT(IsListEmpty(&failGroup->FOG_DeviceList));
DsmpFreeZombieGroupList(failGroup);
DsmpFreePool(failGroup);
}
}
}
//
// Free up the supported devices list buffer.
//
DsmpFreePool(DsmContext->SupportedDevices.Buffer);
//
// It's the responsibility of the mpio bus driver to have already
// destroyed all devices and paths. As those functions free allocations
// for the objects, the only thing needed here is to free the DsmContext.
//
TracePrint((TRACE_LEVEL_INFORMATION,
TRACE_FLAG_INIT,
"DsmpFreeDSMResources (DsmCtxt %p): Freeing the DsmContext.\n",
DsmContext));
DsmpFreePool(DsmContext);
}
TracePrint((TRACE_LEVEL_VERBOSE,
TRACE_FLAG_INIT,
"DsmpFreeDSMResources (DsmCtxt %p): Exiting function.\n",
tempAddress));
return;
}
PDSM_GROUP_ENTRY
DsmpFindDevice(
_In_ IN PDSM_CONTEXT DsmContext,
_In_ IN PDSM_DEVICE_INFO DeviceInfo,
_In_ IN BOOLEAN AcquireDSMLockExclusive
)
/*++
Routine Description:
This routine searches for a serial number match between DeviceInfo and
the rest of the devices currently being driven by this DSM.
Arguments:
DsmContext - DSM context given to MPIO during initialization
DeviceInfo - The deviceInfo containing serial number for which to search.
AcquireDSMLockExclusive - If TRUE this routine should acquire DsmContextLock Exclusively
Return Value:
The multi-path group entry in which the device resides.
--*/
{
PDSM_DEVICE_INFO deviceInfo;
PLIST_ENTRY entry;
PDSM_GROUP_ENTRY groupEntry = NULL;
ULONG i;
KIRQL irql = PASSIVE_LEVEL; // Initialize variable to prevent C4701 error
TracePrint((TRACE_LEVEL_VERBOSE,
TRACE_FLAG_PNP,
"DsmpFindDevice (DevInfo %p): Entering functio