/*++ BUILD Version: 0009    // Increment this if a change has global effects
Copyright (c) 1987-1993  Microsoft Corporation

Module Name:

    midatlas.c

Abstract:

    This module defines the data structure used in mapping MIDS to the corresponding requests/
    contexts associated with them.

Author:

    Balan Sethu Raman (SethuR) 26-Aug-95    Created

Notes:

--*/

#include "precomp.h"
#pragma hdrstop
#include "midatlsp.h"

VOID
RxInitializeMidMapFreeList (
    struct _MID_MAP_ *pMidMap
    );

VOID
RxUninitializeMidMap (
    struct _MID_MAP_    *pMidMap,
    PCONTEXT_DESTRUCTOR pContextDestructor
    );



#ifdef  ALLOC_PRAGMA
#pragma alloc_text(PAGE, RxInitializeMidMapFreeList)
#pragma alloc_text(PAGE, RxCreateMidAtlas)
#pragma alloc_text(PAGE, RxUninitializeMidMap)
#pragma alloc_text(PAGE, RxDestroyMidAtlas)
#endif

#define ENTRY_TYPE_FREE_MID_LIST  (0x1)
#define ENTRY_TYPE_VALID_CONTEXT  (0x2)
#define ENTRY_TYPE_MID_MAP        (0x3)

#define ENTRY_TYPE_MASK           (0x3)

#define MID_MAP_FLAGS_CAN_BE_EXPANDED (0x1)
#define MID_MAP_FLAGS_FREE_POOL       (0x2)


//INLINE ULONG _GetEntryType(PVOID pEntry)

#define _GetEntryType(pEntry)                               \
        ((ULONG)((ULONG_PTR)(pEntry)) & ENTRY_TYPE_MASK)

//INLINE PVOID _GetEntryPointer(PVOID pEntry)

#define _GetEntryPointer(pEntry)                            \
        ((PVOID)((ULONG_PTR)(pEntry) & ~ENTRY_TYPE_MASK))

#define _MakeEntry(pContext,EntryType)                      \
        (PVOID)((ULONG_PTR)(pContext) | (EntryType))

//INLINE PMID_MAP _GetFirstMidMap()
/*++

Routine Description:

    This first MID_MAP instance in the list

Return Value:

    a valid PMID_MAP, NULL if none exists.

Notes:

    This routine assumes that the necessary concurrency control action has been taken

--*/

#define _GetFirstMidMap(pListHead)                        \
               (IsListEmpty(pListHead)                    \
                ? NULL                                    \
                : (PMID_MAP)                              \
                  (CONTAINING_RECORD((pListHead)->Flink,  \
                                     MID_MAP,             \
                                     MidMapList)))

//INLINE PSMBCEDB_SERVER_ENTRY GetNextMidMap(PLIST_ENTRY pListHead, PMID_MAP pMidMap)
/*++

Routine Description:

    This routine returns the next MID_MAP in the list

Arguments:

    pListHead    - the list of MID_MAP's

    pMidMap      - the current instance

Return Value:

    a valid PMID_MAP, NULL if none exists.

Notes:

    This routine assumes that the necessary concurrency control action has been taken

--*/

#define _GetNextMidMap(pListHead,pMidMap)                      \
           (((pMidMap)->MidMapList.Flink == pListHead)         \
            ? NULL                                             \
            : (PMID_MAP)                                       \
              (CONTAINING_RECORD((pMidMap)->MidMapList.Flink,  \
                                 MID_MAP,                      \
                                 MidMapList)))


//INLINE VOID _AddMidMap(
//            PLIST_ENTRY pListHead,
//            PMID_MAP    pMidMap)
/*++

Routine Description:

    This routine adds a MID_MAP instance to a list

Arguments:

    pListHead  - the list of MID_MAP's

    pMidMap    - the MID_MAP to be added

--*/

#define _AddMidMap(pListHead,pMidMap)                                       \
        {                                                                   \
           PMID_MAP pPredecessor;                                           \
           pPredecessor = _GetFirstMidMap(pListHead);                       \
           while (pPredecessor != NULL) {                                   \
              if (pPredecessor->Level < pMidMap->Level) {                   \
                 pPredecessor = _GetNextMidMap(pListHead,pPredecessor);     \
              } else {                                                      \
                 pPredecessor = (PMID_MAP)                                  \
                                CONTAINING_RECORD(                          \
                                     pPredecessor->MidMapList.Blink,        \
                                     MID_MAP,                               \
                                     MidMapList);                           \
                 break;                                                     \
              }                                                             \
           }                                                                \
                                                                            \
           if (pPredecessor == NULL) {                                      \
              InsertTailList(pListHead,&((pMidMap)->MidMapList));         \
           } else {                                                         \
              (pMidMap)->MidMapList.Flink = pPredecessor->MidMapList.Flink; \
              pPredecessor->MidMapList.Flink = &(pMidMap)->MidMapList;      \
                                                                            \
              (pMidMap)->MidMapList.Blink = &pPredecessor->MidMapList;      \
              (pMidMap)->MidMapList.Flink->Blink = &(pMidMap)->MidMapList;  \
           }                                                                \
        }


//INLINE VOID _RemoveMidMap(PMID_MAP pMidMap)
/*++

Routine Description:

    This routine removes a MID_MAP instance from the list

Arguments:

    pMidMap - the MID_MAP instance to be removed

--*/

#define _RemoveMidMap(pMidMap)   \
            RemoveEntryList(&(pMidMap)->MidMapList)



VOID
RxInitializeMidMapFreeList(PMID_MAP pMidMap)
/*++

Routine Description:

   This routine initializes a MID_MAP data structure.

Arguments:

    pMidMap  - the MID_MAP instance to be initialized.

Notes:

--*/
{
   USHORT i;

   PVOID  *pEntryValue     = (PVOID *)&pMidMap->Entries[1];
   PVOID  *pEntriesPointer = (PVOID *)&pMidMap->Entries;

   PAGED_CODE();

   //DbgPrint("RxInitializeMidMapFreeList .. Entry\n");

   if (pMidMap->MaximumNumberOfMids > 0) {
       pMidMap->pFreeMidListHead = pMidMap->Entries;
       for (i = 1; i <= pMidMap->MaximumNumberOfMids - 1;i++,pEntryValue++) {
          *pEntriesPointer++ = _MakeEntry(pEntryValue,ENTRY_TYPE_FREE_MID_LIST);
       }

       *pEntriesPointer = _MakeEntry(NULL,ENTRY_TYPE_FREE_MID_LIST);
   }

   //DbgPrint("RxInitializeMidMapFreeList .. Exit\n");
}


PRX_MID_ATLAS
RxCreateMidAtlas(
   USHORT MaximumNumberOfMids,
   USHORT MidsAllocatedAtStart)
/*++

Routine Description:

   This routine allocates a new instance of MID_ATLAS data structure.

Arguments:

    MaximumNumberOfMids  - the maximum number of MIDS in the atlas.

    MidsAllocatedAtStart - the number of MIDS allocated at start

Notes:

--*/
{
    PRX_MID_ATLAS pMidAtlas;
    PMID_MAP   pMidMap;
    ULONG      AtlasSize;
    USHORT     MidsAllocatedRoundedToPowerOf2;
    USHORT     MaximumMidsRoundedToPowerOf2;
    UCHAR      MidFieldWidth,MaximumMidFieldWidth;

    PAGED_CODE();

    // Round off the Mids allocated at Start to a power of two
    MaximumMidsRoundedToPowerOf2 = 0x100;
    MaximumMidFieldWidth = 8;

    if (MaximumMidsRoundedToPowerOf2 != MaximumNumberOfMids) {
        if (MaximumNumberOfMids > MaximumMidsRoundedToPowerOf2) {
            while (MaximumNumberOfMids > MaximumMidsRoundedToPowerOf2) {
                MaximumMidsRoundedToPowerOf2 = MaximumMidsRoundedToPowerOf2 << 1;
                MaximumMidFieldWidth++;
            }
        } else {
            while (MaximumNumberOfMids < MaximumMidsRoundedToPowerOf2) {
                MaximumMidsRoundedToPowerOf2 = MaximumMidsRoundedToPowerOf2 >> 1;
                MaximumMidFieldWidth--;
            }

            MaximumMidFieldWidth++;
            MaximumMidsRoundedToPowerOf2 = MaximumMidsRoundedToPowerOf2 << 1;
        }
    }

    MidsAllocatedRoundedToPowerOf2 = 0x100;
    MidFieldWidth = 8;

    if (MidsAllocatedRoundedToPowerOf2 != MidsAllocatedAtStart) {
        if (MidsAllocatedAtStart > MidsAllocatedRoundedToPowerOf2) {
            while (MidsAllocatedAtStart > MidsAllocatedRoundedToPowerOf2) {
                MidsAllocatedRoundedToPowerOf2 = MidsAllocatedRoundedToPowerOf2 << 1;
                MidFieldWidth++;
            }
        } else {
            while (MidsAllocatedAtStart < MidsAllocatedRoundedToPowerOf2) {
                MidsAllocatedRoundedToPowerOf2 = MidsAllocatedRoundedToPowerOf2 >> 1;
                MidFieldWidth--;
            }

            MidFieldWidth++;
            MidsAllocatedRoundedToPowerOf2 = MidsAllocatedRoundedToPowerOf2 << 1;
        }
    }

    AtlasSize = sizeof(RX_MID_ATLAS) +
                FIELD_OFFSET(MID_MAP,Entries);

    if (MaximumNumberOfMids == MidsAllocatedAtStart) {
        AtlasSize += (sizeof(PVOID) * MidsAllocatedAtStart);
    } else {
        AtlasSize += (sizeof(PVOID) * MidsAllocatedRoundedToPowerOf2);
    }

    pMidAtlas = (PRX_MID_ATLAS)RxAllocatePoolWithTag(
                              NonPagedPool,
                              AtlasSize,
                              RXCE_MIDATLAS_POOLTAG);
    if (pMidAtlas != NULL) {
        pMidMap = (PMID_MAP)(pMidAtlas + 1);

        pMidMap->Flags                 = 0;
        pMidAtlas->MaximumNumberOfMids = MaximumNumberOfMids;
        pMidAtlas->MidsAllocated       = MidsAllocatedAtStart;
        pMidAtlas->NumberOfMidsInUse = 0;
        pMidAtlas->NumberOfMidsDiscarded = 0;
        pMidAtlas->MaximumMidFieldWidth = MaximumMidFieldWidth;

        pMidMap->MaximumNumberOfMids = MidsAllocatedAtStart;
        pMidMap->NumberOfMidsInUse   = 0;
        pMidMap->BaseMid             = 0;
        pMidMap->IndexMask           = MidsAllocatedRoundedToPowerOf2 - 1;
        pMidMap->IndexAlignmentCount = 0;
        pMidMap->IndexFieldWidth     = MidFieldWidth;
        pMidMap->Level               = 1;

        InitializeListHead(&pMidAtlas->MidMapFreeList);
        InitializeListHead(&pMidAtlas->MidMapExpansionList);
        RxInitializeMidMapFreeList(pMidMap);

        _AddMidMap(&pMidAtlas->MidMapFreeList,pMidMap);
        pMidAtlas->pRootMidMap = pMidMap;

        if (MaximumNumberOfMids > MidsAllocatedAtStart) {
            // Round off the maximum number of MIDS to determine the level and the
            // size of the quantum ( allocation increments)

            pMidMap->Flags |= MID_MAP_FLAGS_CAN_BE_EXPANDED;

            pMidAtlas->MidQuantum           = 32;
            pMidAtlas->MidQuantumFieldWidth = 5;
            MaximumMidsRoundedToPowerOf2 = MaximumMidsRoundedToPowerOf2 >> (pMidMap->IndexAlignmentCount + 5);

            if (MaximumMidsRoundedToPowerOf2 > 0) {
                pMidAtlas->NumberOfLevels = 3;
            } else {
                pMidAtlas->NumberOfLevels = 2;
            }
        } else {
            pMidAtlas->MidQuantum     = 0;
            pMidAtlas->NumberOfLevels = 1;
            pMidMap->Flags &= ~MID_MAP_FLAGS_CAN_BE_EXPANDED;
        }
    }

    //DbgPrint("RxAllocatMidAtlas .. Exit (pMidAtlas) %lx\n",pMidAtlas);
    return pMidAtlas;
}

VOID
RxUninitializeMidMap(
         PMID_MAP            pMidMap,
         PCONTEXT_DESTRUCTOR pContextDestructor)
/*++

Routine Description:

   This routine uninitializes a MID_MAP data structure.

Arguments:

    pMidMap            -- the MID_MAP instance to be uninitialized.

    pContextDestructor -- the context destructor
Notes:

--*/
{
   USHORT i;
   ULONG  EntryType;

   PAGED_CODE();

   //DbgPrint("RxUninitializeMidMap .. Entry No.Of MIDS in Use %ld\n",pMidMap->NumberOfMidsInUse);
   RxLog(("_UninitMidMap .. num= %ld\n",pMidMap->NumberOfMidsInUse));
   RxWmiLog(LOG,
            RxUninitializeMidMap,
            LOGXSHORT(pMidMap->NumberOfMidsInUse));

   for (i = 0; i < pMidMap->MaximumNumberOfMids; i++) {
      PMID_MAP pChildMidMap;

      EntryType = _GetEntryType(pMidMap->Entries[i]);
      switch (EntryType) {
      case ENTRY_TYPE_MID_MAP :
         {
            pChildMidMap = (PMID_MAP)_GetEntryPointer(pMidMap->Entries[i]);
            RxUninitializeMidMap(pChildMidMap,pContextDestructor);
         }
         break;
      case ENTRY_TYPE_VALID_CONTEXT :
         {
            if (pContextDestructor != NULL) {
               PVOID pContext;

               pContext = _GetEntryPointer(pMidMap->Entries[i]);

               (pContextDestructor)(pContext);
            }
         }
         break;
      default:
         break;
      }
   }

   if (pMidMap->Flags & MID_MAP_FLAGS_FREE_POOL) {
      RxFreePool(pMidMap);
   }

   //DbgPrint("RxUninitializeMidMap .. Exit\n");
}

VOID
RxDestroyMidAtlas(
   PRX_MID_ATLAS          pMidAtlas,
   PCONTEXT_DESTRUCTOR pContextDestructor)
/*++

Routine Description:

   This routine frees a MID_ATLAS instance. As a side effect it invokes the
   passed in context destructor on every valid context in the MID_ATLAS

Arguments:

    pMidAtlas           - the MID_ATLAS instance to be freed.

    PCONTEXT_DESTRUCTOR - the associated context destructor

Notes:

--*/
{
   PAGED_CODE();

   //DbgPrint("RxFreeMidAtlas .. Entry\n");
   RxUninitializeMidMap(pMidAtlas->pRootMidMap,pContextDestructor);

   RxFreePool(pMidAtlas);
   //DbgPrint("RxFreeMidAtlas .. Exit\n");
}

PVOID
RxMapMidToContext(
      PRX_MID_ATLAS pMidAtlas,
      USHORT     Mid)
/*++

Routine Description:

   This routine maps a MID to its associated context in a MID_ATLAS.

Arguments:

    pMidAtlas  - the MID_ATLAS instance.

    Mid        - the MId to be mapped

Return value:

    the associated context, NULL if none exists

Notes:

--*/
{
   ULONG     EntryType;
   PMID_MAP  pMidMap = pMidAtlas->pRootMidMap;
   PVOID     pContext;
   ULONG     Index;

   //DbgPrint("RxMapMidToContext Mid %lx ",Mid);

   for (;;) {
      Index = (Mid & pMidMap->IndexMask) >> pMidMap->IndexAlignmentCount;

      if( Index >= pMidMap->MaximumNumberOfMids ) {
          pContext = NULL;
          break;
      }

      pContext = pMidMap->Entries[Index];
      EntryType = _GetEntryType(pContext);
      pContext = (PVOID)_GetEntryPointer(pContext);

      if (EntryType == ENTRY_TYPE_VALID_CONTEXT) {
         break;
      } else if (EntryType == ENTRY_TYPE_FREE_MID_LIST) {
         pContext = NULL;
         break;
      } else if (EntryType == ENTRY_TYPE_MID_MAP) {
         pMidMap = (PMID_MAP)pContext;
      } else {
         pContext = NULL;
         break;
      }
   }

   //DbgPrint("Context %lx \n",pContext);

   return pContext;
}

NTSTATUS
RxMapAndDissociateMidFromContext(
      PRX_MID_ATLAS pMidAtlas,
      USHORT     Mid,
      PVOID      *pContextPointer)
/*++

Routine Description:

   This routine maps a MID to its associated context in a MID_ATLAS.

Arguments:

    pMidAtlas  - the MID_ATLAS instance.

    Mid        - the MId to be mapped

Return value:

    the associated context, NULL if none exists

Notes:

--*/
{
   ULONG     EntryType;
   PMID_MAP  pMidMap = pMidAtlas->pRootMidMap;
   PVOID     pContext;
   PVOID     *pEntry;

   //DbgPrint("RxMapAndDissociateMidFromContext Mid %lx ",Mid);

   for (;;) {
      pEntry    = &pMidMap->Entries[(Mid & pMidMap->IndexMask) >> pMidMap->IndexAlignmentCount];
      pContext  = *pEntry;
      EntryType = _GetEntryType(pContext);
      pContext  = (PVOID)_GetEntryPointer(pContext);

      if (EntryType == ENTRY_TYPE_VALID_CONTEXT) {
         pMidMap->NumberOfMidsInUse--;

         if (pMidMap->pFreeMidListHead == NULL) {
            _RemoveMidMap(pMidMap);
            _AddMidMap(&pMidAtlas->MidMapFreeList,pMidMap);
         }

         *pEntry = _MakeEntry(pMidMap->pFreeMidListHead,ENTRY_TYPE_FREE_MID_LIST);
         pMidMap->pFreeMidListHead = pEntry;


         break;
      } else if (EntryType == ENTRY_TYPE_FREE_MID_LIST) {
         pContext = NULL;
         break;
      } else if (EntryType == ENTRY_TYPE_MID_MAP) {
         pMidMap = (PMID_MAP)pContext;
      }
   }

   pMidAtlas->NumberOfMidsInUse--;
   //DbgPrint("Context %lx\n",pContext);
   *pContextPointer = pContext;
   return STATUS_SUCCESS;
}

NTSTATUS
RxReassociateMid(
      PRX_MID_ATLAS pMidAtlas,
      USHORT     Mid,
      PVOID      pNewContext)
/*++

Routine Description:

   This routine maps a MID to its associated context in a MID_ATLAS.

Arguments:

    pMidAtlas  - the MID_ATLAS instance.

    Mid        - the MId to be mapped

    pNewContext - the new context

Return value:

    the associated context, NULL if none exists

Notes:

--*/
{
   ULONG     EntryType;
   PMID_MAP  pMidMap = pMidAtlas->pRootMidMap;
   PVOID     pContext;

   //DbgPrint("RxReassociateMid Mid %lx ",Mid);

   for (;;) {
      pContext = pMidMap->Entries[(Mid & pMidMap->IndexMask) >> pMidMap->IndexAlignmentCount];
      EntryType = _GetEntryType(pContext);
      pContext = (PVOID)_GetEntryPointer(pContext);

      if (EntryType == ENTRY_TYPE_VALID_CONTEXT) {
         pMidMap->Entries[(Mid & pMidMap->IndexMask) >> pMidMap->IndexAlignmentCount]
               = _MakeEntry(pNewContext,ENTRY_TYPE_VALID_CONTEXT);
         break;
      } else if (EntryType == ENTRY_TYPE_FREE_MID_LIST) {
         ASSERT(!"Valid MID Atlas");
         break;
      } else if (EntryType == ENTRY_TYPE_MID_MAP) {
         pMidMap = (PMID_MAP)pContext;
      }
   }

   //DbgPrint("New COntext  %lx\n",pNewContext);

   return STATUS_SUCCESS;
}

NTSTATUS
RxAssociateContextWithMid(
      PRX_MID_ATLAS     pMidAtlas,
      PVOID          pContext,
      PUSHORT        pNewMid)
/*++

Routine Description:

   This routine initializes a MID_MAP data structure.

Arguments:

    pMidMap  - the MID_MAP instance to be initialized.

Return Value:

    STATUS_SUCCESS if successful, otherwise one of the following errors

         STATUS_INSUFFICIENT_RESOURCES
         STATUS_UNSUCCESSFUL  -- no mid could be associated

Notes:

--*/
{
   NTSTATUS Status;
   PMID_MAP pMidMap;
   PVOID    *pContextPointer;

   //DbgPrint("RxAssociateContextWithMid Context %lx ",pContext);

   // Scan the list of MID_MAP's which have free entries in them.
   if ((pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapFreeList)) != NULL) {
      ASSERT(pMidMap->pFreeMidListHead != _MakeEntry(NULL,ENTRY_TYPE_FREE_MID_LIST));

      pMidMap->NumberOfMidsInUse++;
      pContextPointer           = pMidMap->pFreeMidListHead;
      pMidMap->pFreeMidListHead = _GetEntryPointer(*(pMidMap->pFreeMidListHead));
      *pContextPointer          = _MakeEntry(pContext,ENTRY_TYPE_VALID_CONTEXT);
      *pNewMid                  = ((USHORT)
                                   (pContextPointer - (PVOID *)&pMidMap->Entries)
                                    << pMidMap->IndexAlignmentCount) |
                                    pMidMap->BaseMid;

      // Check if the MID_MAP needs to be removed from the list of MID_MAP's with
      // free entries
      if (pMidMap->pFreeMidListHead ==  NULL) {
         _RemoveMidMap(pMidMap);

         // Check if it can be added to the expansion list.
         if (pMidAtlas->NumberOfLevels > pMidMap->Level) {
            _AddMidMap(&pMidAtlas->MidMapExpansionList,pMidMap);
         }
      }

      Status = STATUS_SUCCESS;
   } else if ((pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapExpansionList)) != NULL) {
      PMID_MAP pNewMidMap;

      USHORT   i;
      ULONG    NewMidMapSize;

      // Locate the index in the mid map for the new mid map
      pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapExpansionList);
      while (pMidMap != NULL) {
         for (i = 0; i < pMidMap->MaximumNumberOfMids; i++) {
            if (_GetEntryType(pMidMap->Entries[i]) != ENTRY_TYPE_MID_MAP) {
               break;
            }
         }

         if (i < pMidMap->MaximumNumberOfMids) {
            break;
         } else {
            pMidMap->Flags &= ~MID_MAP_FLAGS_CAN_BE_EXPANDED;
            _RemoveMidMap(pMidMap);
            pMidMap = _GetNextMidMap(&pMidAtlas->MidMapExpansionList,pMidMap);
         }
      }

      if (pMidMap != NULL) {
         USHORT NumberOfEntriesInMap = pMidAtlas->MaximumNumberOfMids -
                                       pMidAtlas->NumberOfMidsInUse;

         if (NumberOfEntriesInMap > pMidAtlas->MidQuantum) {
            NumberOfEntriesInMap = pMidAtlas->MidQuantum;
         }
         else if( NumberOfEntriesInMap == 1 )
         {
             // The MID_MAP design does not allow for maps of length 1.  Extend to 2
             NumberOfEntriesInMap++;
         }

         if (NumberOfEntriesInMap > 0) {
             NewMidMapSize = FIELD_OFFSET(MID_MAP,Entries) +
                             NumberOfEntriesInMap * sizeof(PVOID);
             pNewMidMap = (PMID_MAP)RxAllocatePoolWithTag(
                                        NonPagedPool,
                                        NewMidMapSize,
                                        RXCE_MIDATLAS_POOLTAG);

             if (pNewMidMap != NULL) {
                 pNewMidMap->Flags = MID_MAP_FLAGS_FREE_POOL;
                 pNewMidMap->MaximumNumberOfMids = NumberOfEntriesInMap;
                 pNewMidMap->NumberOfMidsInUse   = 0;
                 pNewMidMap->BaseMid             = (pMidMap->BaseMid |
                                                    i << pMidMap->IndexAlignmentCount);
                 pNewMidMap->IndexAlignmentCount = pMidMap->IndexAlignmentCount +
                                                   pMidMap->IndexFieldWidth;

                 pNewMidMap->IndexMask           = (pMidAtlas->MidQuantum - 1) << pNewMidMap->IndexAlignmentCount;
                 pNewMidMap->IndexFieldWidth     = pMidAtlas->MidQuantumFieldWidth;

                 RxInitializeMidMapFreeList(pNewMidMap);

                 //
                 // After the RxInitializeMidMapFreeList call above the
                 // pFreeMidListHead points to Entries[0]. We will be storing
                 // the value pMidMap->Entries[i] at this location so we need
                 // to make pFreeMidListHead point to Entries[1].
                 //
                 pNewMidMap->pFreeMidListHead = _GetEntryPointer(*(pNewMidMap->pFreeMidListHead));

                 //
                 // Set up the mid map appropriately.
                 //
                 pNewMidMap->NumberOfMidsInUse = 1;
                 pNewMidMap->Entries[0] = pMidMap->Entries[i];
                 pNewMidMap->Level = pMidMap->Level + 1;

                 //
                 // The new MinMap is stored at the pMidMap->Entries[i] location.
                 //
                 pMidMap->Entries[i] = _MakeEntry(pNewMidMap,ENTRY_TYPE_MID_MAP);

                 //
                 // Update the free list and the expansion list respectively.
                 //
                 _AddMidMap(&pMidAtlas->MidMapFreeList,pNewMidMap);

                 pNewMidMap->NumberOfMidsInUse++;
                 pContextPointer = pNewMidMap->pFreeMidListHead;
                 pNewMidMap->pFreeMidListHead = _GetEntryPointer(*(pNewMidMap->pFreeMidListHead));
                 *pContextPointer = _MakeEntry(pContext,ENTRY_TYPE_VALID_CONTEXT);
                 *pNewMid = ((USHORT)
                             (pContextPointer - (PVOID *)&pNewMidMap->Entries)
                             << pNewMidMap->IndexAlignmentCount) |
                             pNewMidMap->BaseMid;

                 Status = STATUS_SUCCESS;
             } else {
                Status = STATUS_INSUFFICIENT_RESOURCES;
             }
         } else {
             Status = STATUS_UNSUCCESSFUL;
         }
      } else {
         Status = STATUS_UNSUCCESSFUL;
      }
   } else {
      Status = STATUS_UNSUCCESSFUL;
   }

   if (Status == (STATUS_SUCCESS)) {
      pMidAtlas->NumberOfMidsInUse++;
   }

   //DbgPrint("Mid %lx\n",*pNewMid);

   return Status;
}

