static ClRcT clAmsMgmtSGMigrateMPlusN(ClAmsSGRedundancyModelT model,
                                      ClAmsEntityT *sgName,
                                      const ClCharT *prefix,
                                      ClUint32T numActiveSUs,
                                      ClUint32T numStandbySUs,
                                      ClAmsMgmtMigrateListT *migrateList)
{
    ClUint32T i;
    ClRcT rc = CL_OK;
    ClAmsEntityBufferT siBuffer = {0};
    ClAmsEntityBufferT suBuffer = {0};
    ClAmsEntityBufferT nodeBuffer = {0};
    ClInt32T extraSIs = 0;
    ClInt32T extraSUs = 0;
    ClInt32T extraNodes = 0;
    ClAmsEntityT *nodeList = NULL;
    ClAmsEntityT *nodes = NULL;
    ClAmsEntityT *sus = NULL;
    ClAmsEntityT *comps = NULL;
    ClAmsEntityT *sis =  NULL;
    ClAmsEntityT *csis = NULL;
    ClInt32T numNodes = 0;
    ClAmsEntityConfigT *pSURefComp = NULL;
    ClAmsEntityConfigT *pSGRefSI = NULL;
    ClAmsEntityConfigT *pSIRefCSI = NULL;
    ClAmsEntityConfigT *pSGConfig = NULL;
    ClAmsSGConfigT sgConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
    ClUint32T numSupportedCSITypes = 0;
    SaNameT *pNumSupportedCSITypes = NULL;
    ClAmsMgmtCCBHandleT ccbHandle = 0;
    ClAmsMgmtMigrateListT *unlockList = NULL;

    rc = clAmsMgmtEntityGetConfig(gHandle, sgName, &pSGConfig);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "SG [%.*s] config get returned [%#x]",
                   sgName->name.length-1, sgName->name.value, rc);
        goto out;
    }

    memcpy(&sgConfig, pSGConfig, sizeof(sgConfig));
    clHeapFree(pSGConfig);

    /*
     * If scaling down actives, ensure that those many service units are locked.
     */
    if(numActiveSUs < sgConfig.numPrefActiveSUs)
    {
        ClInt32T numShrinkSUs = sgConfig.numPrefActiveSUs - numActiveSUs;
        ClAmsEntityBufferT suList = {0};
        ClInt32T numOutOfServiceSUs = 0;
        rc = clAmsMgmtGetSGSUList(gHandle, sgName, &suList);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "SG [%.*s] su list returned [%#x]",
                       sgName->name.length-1, sgName->name.value, rc);
            goto out;
        }
        for(i = 0; i < suList.count; ++i)
        {
            ClAmsSUConfigT *pSUConfig = NULL;
            rc = clAmsMgmtEntityGetConfig(gHandle, suList.entity+i,
                                          (ClAmsEntityConfigT**)&pSUConfig);
            if(rc != CL_OK)
            {
                clHeapFree(suList.entity);
                clLogError("AMS", "MIGRATE", "SU [%.*s] get config returned [%#x]",
                           suList.entity[i].name.length-1, suList.entity[i].name.value, rc);
                goto out;
            }
            if(pSUConfig->adminState == CL_AMS_ADMIN_STATE_LOCKED_A
               ||
               pSUConfig->adminState == CL_AMS_ADMIN_STATE_LOCKED_I)
            {
                ++numOutOfServiceSUs;
            }
            clHeapFree(pSUConfig);
        }
        clHeapFree(suList.entity);
        if(numOutOfServiceSUs < numShrinkSUs)
        {
            clLogError("AMS", "MIGRATE", "Expected a minimum of [%d] SUs to be out of service to satisfy SG. "
                       "redundancy model shrink. Got [%d] out of service", numShrinkSUs,
                       numOutOfServiceSUs);
            rc = CL_AMS_RC(CL_AMS_ERR_INVALID_ENTITY_STATE);
            goto out;
        }
    }

    rc = clAmsMgmtSGRedundancyModelEstimate(model, sgName, numActiveSUs, numStandbySUs,
                                            &extraSIs, &extraSUs, &extraNodes);

    if(rc != CL_OK)
    {
        goto out;
    }
    
    rc = clAmsMgmtCCBInitialize(gHandle, &ccbHandle);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS ccb initialize returned [%#x]", rc);
        goto out;
    }

    /* 
     * Add the existing SI CSI list to the supported list.
     */
    rc = clAmsMgmtGetSGSIList(gHandle, sgName, &siBuffer);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS sg si list returned [%#x]", rc);
        goto out;
    }

    if(siBuffer.count)
    {
        rc = clAmsMgmtEntityGetConfig(gHandle, siBuffer.entity,
                                      &pSGRefSI);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS reference si get config returned [%#x]",
                       rc);
            goto out_free;
        }
    }

    for(i = 0; i < siBuffer.count; ++i)
    {
        ClUint32T j; 
        ClAmsEntityBufferT csiBuffer = {CL_AMS_ENTITY_TYPE_ENTITY};
        ClAmsSIConfigT siConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
        ClUint64T mask = 0;
        memcpy(&siConfig.entity, siBuffer.entity+i, 
               sizeof(siConfig.entity));
        mask |= SI_CONFIG_NUM_STANDBY_ASSIGNMENTS;
        siConfig.numStandbyAssignments = numStandbySUs;
        if(numActiveSUs > 1)
            siConfig.numStandbyAssignments = (numStandbySUs+1)&~1;
        siConfig.numStandbyAssignments = CL_MAX(1, siConfig.numStandbyAssignments/
                                                (numActiveSUs?numActiveSUs:1));
        /*
         * Update the num standby assignments.
         */
        rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &siConfig.entity, mask);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "SI [%.*s] num standby set returned [%#x]",
                       siConfig.entity.name.length-1, siConfig.entity.name.value, rc);
        }

        rc = clAmsMgmtGetSICSIList(gHandle, siBuffer.entity+i,
                                   &csiBuffer);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS get si csi list returned [%#x]", rc);
            goto out_free;
        }
        pNumSupportedCSITypes = (SaNameT*) clHeapRealloc(pNumSupportedCSITypes, (numSupportedCSITypes+csiBuffer.count)*sizeof(SaNameT));
        for(j = 0; j < csiBuffer.count ; ++j)
        {
            ClAmsEntityConfigT *entityConfig = NULL;
            ClAmsCSIConfigT csiConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            ClUint32T k;

            rc = clAmsMgmtEntityGetConfig(gHandle, csiBuffer.entity+j, &entityConfig);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS csi get config returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&csiConfig, entityConfig, sizeof(csiConfig));
            if(!pSIRefCSI)
            {
                pSIRefCSI = entityConfig;
            }
            else
            {
                clHeapFree(entityConfig);
            }
            /*
             * Search for this csi type in the list to see if its 
             * already present
             */
            for(k = 0; k < numSupportedCSITypes; ++k)
            {
                if(!memcmp(pNumSupportedCSITypes[k].value,
                           csiConfig.type.value,
                           pNumSupportedCSITypes[k].length))
                    break;
            }

            if(k == numSupportedCSITypes)
            {
                memcpy(pNumSupportedCSITypes+numSupportedCSITypes,
                       &csiConfig.type, sizeof(csiConfig.type));
                ++numSupportedCSITypes;
            }
        }

        clHeapFree(csiBuffer.entity);
    }
    
    if(extraSIs)
    {
        sis = (ClAmsEntityT*) clHeapCalloc(extraSIs, sizeof(ClAmsEntityT));
        CL_ASSERT(sis != NULL);
        csis = (ClAmsEntityT*) clHeapCalloc(extraSIs, sizeof(ClAmsEntityT));
        for(i = siBuffer.count; i < siBuffer.count + extraSIs; ++i)
        {
            ClAmsEntityT si ={CL_AMS_ENTITY_TYPE_ENTITY};
            ClAmsEntityT csi = {CL_AMS_ENTITY_TYPE_ENTITY};
            ClUint64T bitMask = 0;
            ClAmsSIConfigT siConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            ClAmsCSIConfigT csiConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            si.type = CL_AMS_ENTITY_TYPE_SI;
            snprintf((ClCharT*)si.name.value, sizeof(si.name.value)-1, "%s_%.*s_SI%d", prefix,
                     sgName->name.length-1, (const ClCharT*)sgName->name.value, i);
            clLogNotice("AMS", "MIGRATE", "Creating SI [%s]", si.name.value);
            si.name.length = strlen((const ClCharT*)si.name.value)+1;
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &si);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS entity create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&sis[i-siBuffer.count], &si, sizeof(si));
            
            rc = clAmsMgmtCCBSetSGSIList(ccbHandle, sgName, &si);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS set sg silist returned [%#x]", rc);
                goto out_free;
            }

            if(pSGRefSI)
            {
                /*
                 * Set config to the base SI.
                 */
                bitMask = CL_AMS_CONFIG_ATTR_ALL;
                memcpy(&siConfig, pSGRefSI, sizeof(siConfig));
                memcpy(&siConfig.entity, &si, sizeof(siConfig.entity));
                siConfig.numStandbyAssignments = numStandbySUs;
                if(numActiveSUs > 1 )
                    siConfig.numStandbyAssignments = (numStandbySUs+1)&~1;
                siConfig.numStandbyAssignments = CL_MAX(1,siConfig.numStandbyAssignments/
                                                        (numActiveSUs?numActiveSUs:1));
                siConfig.numCSIs = 1;
                siConfig.adminState = CL_AMS_ADMIN_STATE_LOCKED_A;
                rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &siConfig.entity, bitMask);
                if(rc != CL_OK)
                {
                    clLogError("AMS", "MIGRATE", "AMS entity set config returned [%#x]", rc);
                    goto out_free;
                }
            }

            csi.type = CL_AMS_ENTITY_TYPE_CSI;
            snprintf((ClCharT*)csi.name.value, sizeof(csi.name.value),
                     "%s_CSI%d", (const ClCharT*)si.name.value, i-siBuffer.count);
            csi.name.length = strlen((const ClCharT*)csi.name.value)+1;
            clLogNotice("AMS", "MIGRATE", "Creating CSI [%s]", csi.name.value);
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &csi);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS csi create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&csis[i-siBuffer.count], &csi, sizeof(csi));
            rc = clAmsMgmtCCBSetSICSIList(ccbHandle, &si, &csi);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "SET si csi list returned [%#x]", rc);
                goto out_free;
            }
            
            if(pSIRefCSI)
            {
                /*
                 * Load the config. for the base csi type.
                 */
                memcpy(&csiConfig, pSIRefCSI, sizeof(csiConfig));
                memcpy(&csiConfig.entity, &csi, sizeof(csiConfig.entity));
                csiConfig.isProxyCSI = CL_FALSE;
                memcpy(&csiConfig.type, &csiConfig.entity.name, sizeof(csiConfig.type));
                bitMask = CL_AMS_CONFIG_ATTR_ALL;
                rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &csiConfig.entity, bitMask);
                if(rc != CL_OK)
                {
                    clLogError("AMS", "MIGRATE", "AMS ref csi set config returned [%#x]", rc);
                    goto out_free;
                }
            }
            /*
             * Add this to the supported list.
             */
            pNumSupportedCSITypes = (SaNameT*) clHeapRealloc(pNumSupportedCSITypes, (numSupportedCSITypes+1)*sizeof(SaNameT));
            CL_ASSERT(pNumSupportedCSITypes != NULL);
            memcpy(pNumSupportedCSITypes+numSupportedCSITypes, &csi.name, sizeof(SaNameT));
            ++numSupportedCSITypes;
        }
    }

    if(extraNodes)
    {
        nodes = (ClAmsEntityT*) clHeapCalloc(extraNodes, sizeof(ClAmsEntityT));
        CL_ASSERT(nodes != NULL);

        rc = clAmsMgmtGetNodeList(gHandle, &nodeBuffer);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS get node list returned [%#x]", rc);
            goto out_free;
        }
        for(i = nodeBuffer.count ; i < nodeBuffer.count + extraNodes; ++i)
        {
            ClAmsEntityT node = {CL_AMS_ENTITY_TYPE_ENTITY};
            node.type = CL_AMS_ENTITY_TYPE_NODE;
            snprintf((ClCharT*) node.name.value, sizeof(node.name.value), "%s_Node%d", prefix, i);
            node.name.length = strlen((const ClCharT*) node.name.value) + 1;
            clLogNotice("AMS", "MIGRATE", "Creating node [%s]", node.name.value);
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &node);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS ccb create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&nodes[i-nodeBuffer.count], &node, sizeof(node));
        }
    }

    rc = clAmsMgmtGetSGSUList(gHandle, sgName, &suBuffer);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "Get SG su list returned [%#x]", rc);
        goto out_free;
    }

    for(i = 0 ; i < suBuffer.count; ++i)
    {
        ClUint32T j;
        ClAmsEntityBufferT compBuffer=
            {
                0
            }
        ;
        rc = clAmsMgmtGetSUCompList(gHandle, &suBuffer.entity[i],
                                    &compBuffer);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "Get SU comp list returned [%#x]", rc);
            goto out_free;
        }
        /*
         * Get the first component properties.
         */
        if(!pSURefComp)
        {
            rc = clAmsMgmtEntityGetConfig(gHandle, compBuffer.entity,
                                          &pSURefComp);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS base comp get config returned [%#x]",
                           rc);
                goto out_free;
            }
        }

        /*
         * Update all config. with supported csi types.
         * and correct comp config whereever appropriate
         */
        for(j = 0; j < compBuffer.count; ++j)
        {
            ClAmsEntityConfigT *entityConfig =NULL;
            ClAmsCompConfigT compConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            ClUint64T bitMask = 0;
            ClUint32T k ;
            rc = clAmsMgmtEntityGetConfig(gHandle, compBuffer.entity+j,
                                          &entityConfig);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS comp get config returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&compConfig, entityConfig, sizeof(compConfig));
            clHeapFree(entityConfig);
            /*
             * update supported CSI type incase of SI additions.
             */
            if(extraSIs)
            {
                bitMask |= COMP_CONFIG_SUPPORTED_CSI_TYPE;
                compConfig.pSupportedCSITypes = (SaNameT*) clHeapRealloc(compConfig.pSupportedCSITypes, (compConfig.numSupportedCSITypes + extraSIs)* sizeof(SaNameT));
                CL_ASSERT(compConfig.pSupportedCSITypes);
                for(k = compConfig.numSupportedCSITypes; k < compConfig.numSupportedCSITypes + extraSIs; ++k)
                {
                    memcpy(compConfig.pSupportedCSITypes+k, &csis[k-compConfig.numSupportedCSITypes].name, sizeof(SaNameT));
                }
                compConfig.numSupportedCSITypes += extraSIs;
            }
            bitMask |= COMP_CONFIG_NUM_MAX_STANDBY_CSIS;
            /*
             * take active to standby ratio
             */
            compConfig.numMaxStandbyCSIs = numActiveSUs;
            if(numStandbySUs > 1 )
                compConfig.numMaxStandbyCSIs = (numActiveSUs+1)&~1;
            compConfig.numMaxStandbyCSIs = CL_MAX(1, compConfig.numMaxStandbyCSIs/
                                                  (numStandbySUs?numStandbySUs:1));
            rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,
                                             &compConfig.entity,
                                             bitMask);
            clHeapFree(compConfig.pSupportedCSITypes);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS entity set config returned [%#x]", rc);
                goto out_free;
            }
        }
        clHeapFree(compBuffer.entity);
    }

    if(extraSUs)
    {
        sus = (ClAmsEntityT*) clHeapCalloc(extraSUs, sizeof(ClAmsEntityT));
        CL_ASSERT(sus != NULL);
        comps = (ClAmsEntityT*) clHeapCalloc(extraSUs, sizeof(ClAmsEntityT));
        CL_ASSERT(comps != NULL);
        nodeList = (ClAmsEntityT*) clHeapCalloc(extraSUs + extraNodes, sizeof(ClAmsEntityT));
        CL_ASSERT(nodeList != NULL);

        rc = clAmsMgmtGetSUFreeNodes(sgName, prefix, extraSUs, extraNodes, nodeList, &numNodes);

        for(i = suBuffer.count; i < suBuffer.count + extraSUs; ++i)
        {
            ClAmsEntityT su = {CL_AMS_ENTITY_TYPE_ENTITY};
            ClAmsEntityT comp = {CL_AMS_ENTITY_TYPE_ENTITY};
            ClAmsSUConfigT suConfig = 
                {
                    {
                       CL_AMS_ENTITY_TYPE_ENTITY
                    }
                }
            ;
            ClAmsCompConfigT compConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            ClUint64T bitMask = 0;

            su.type = CL_AMS_ENTITY_TYPE_SU;
            snprintf((ClCharT*)su.name.value, sizeof(su.name.value),
                     "%s_%s_SU%d", prefix, (const ClCharT*)nodeList[i-suBuffer.count].name.value, i);

            su.name.length = strlen((const ClCharT*)su.name.value)+1;
            clLogNotice("AMS", "MIGRATE", "Creating SU [%s]", su.name.value);
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &su);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "SU create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&sus[i-suBuffer.count], &su, sizeof(su));
            /*
             * Assign this SU under the parent node and SG
             */
            rc = clAmsMgmtCCBSetNodeSUList(ccbHandle, &nodeList[i-suBuffer.count], &su);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "Node su list set returned [%#x]", rc);
                goto out_free;
            }

            /*
             * Give the parent SG. for this SU
             */
            rc = clAmsMgmtCCBSetSGSUList(ccbHandle, sgName, &su);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "Set SG su list returned [%#x]", rc);
                goto out_free;
            }
            bitMask = SU_CONFIG_NUM_COMPONENTS;
            memcpy(&suConfig.entity, &su, sizeof(suConfig.entity));
            suConfig.numComponents = 1;
            rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &suConfig.entity, bitMask);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "SU set config returned [%#x]", rc);
                goto out_free;
            }
            
            comp.type = CL_AMS_ENTITY_TYPE_COMP;
            snprintf((ClCharT*) comp.name.value, sizeof(comp.name.value), "%s_Comp%d", su.name.value, i - suBuffer.count);
            comp.name.length = strlen((const ClCharT*) comp.name.value) + 1;
            clLogNotice("AMS", "MIGRATE", "Creating component [%s]",
                        comp.name.value);
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &comp);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "Comp create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&comps[i-suBuffer.count], &comp, sizeof(comp));
            rc = clAmsMgmtCCBSetSUCompList(ccbHandle, &su, 
                                           &comp);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS set su comp list returned [%#x]", rc);
                goto out_free;
            }
            
            if(pSURefComp)
            {
                /*
                 * At this stage, we have created the hierarchy. 
                 * Set the comp property to the base component type and
                 * add the num supported CSI types to be part of every component
                 * added to the SU.
                 */

                bitMask = CL_AMS_CONFIG_ATTR_ALL;
                memcpy(&compConfig, pSURefComp, sizeof(compConfig));
                memcpy(&compConfig.entity, &comp, sizeof(compConfig.entity));
                compConfig.numSupportedCSITypes = numSupportedCSITypes;
                compConfig.pSupportedCSITypes = pNumSupportedCSITypes;
                memcpy(&compConfig.parentSU.entity, &su, sizeof(compConfig.parentSU.entity));
                
                /*
                 * Distribute the standbys based on the active/standby ratio.
                 */
                compConfig.numMaxStandbyCSIs = numActiveSUs;
                if(numStandbySUs > 1 )
                    compConfig.numMaxStandbyCSIs = (numActiveSUs+1)&~1;
                compConfig.numMaxStandbyCSIs = CL_MAX(1, compConfig.numMaxStandbyCSIs/
                                                      (numStandbySUs?numStandbySUs:1));
                rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &compConfig.entity,
                                                 bitMask);
                if(rc != CL_OK)
                {
                    clLogError("AMS", "MIGRATE", "AMS set config returned [%#x]", rc);
                    goto out_free;
                }
            }
        }
    }

    /*
     * At this stage, we are all set to commit. after updating SG config.
     */
    {
        ClUint64T bitMask = 0;
        bitMask |= SG_CONFIG_REDUNDANCY_MODEL;
        sgConfig.redundancyModel = model;
        sgConfig.numPrefActiveSUs = numActiveSUs;
        bitMask |= SG_CONFIG_NUM_PREF_ACTIVE_SUS;
        sgConfig.numPrefStandbySUs = numStandbySUs;
        bitMask |= SG_CONFIG_NUM_PREF_STANDBY_SUS;
        if(sgConfig.numPrefInserviceSUs < numActiveSUs + numStandbySUs)
        {
            sgConfig.numPrefInserviceSUs = numActiveSUs + numStandbySUs;
            bitMask |= SG_CONFIG_NUM_PREF_INSERVICE_SUS;
        }
        sgConfig.numPrefAssignedSUs = numActiveSUs + numStandbySUs;
        bitMask |= SG_CONFIG_NUM_PREF_ASSIGNED_SUS;
        /*
         * Active standby ratio.
         */
        sgConfig.maxStandbySIsPerSU = numActiveSUs;
        if(numStandbySUs > 1 )
            sgConfig.maxStandbySIsPerSU = (numActiveSUs+1)&~1;
        sgConfig.maxStandbySIsPerSU = CL_MAX(1,sgConfig.maxStandbySIsPerSU/
                                             (numStandbySUs?numStandbySUs:1));
        bitMask |= SG_CONFIG_MAX_STANDBY_SIS_PER_SU;
        rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &sgConfig.entity, bitMask);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS sg set config returned [%#x]", rc);
            goto out_free;
        }
    }

    rc = clAmsMgmtCCBCommit(ccbHandle);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS database commit returned [%#x]", rc);
    }

    /*
     * Okay, the commit is successful. Now unlock all added entities
     * except SU so that other attributes could be updated before unlocking
     * Do that in a separate thread as there could be pending invocations.
     */
    unlockList = (ClAmsMgmtMigrateListT*) clHeapCalloc(1, sizeof(*unlockList));
    CL_ASSERT(unlockList != NULL);
    unlockList->si.count = extraSIs;
    unlockList->node.count = extraNodes;
    unlockList->su.count = extraSUs;
                                                
    unlockList->si.entity = (ClAmsEntityT*) clHeapCalloc(extraSIs, sizeof(*sis));
    unlockList->node.entity = (ClAmsEntityT*) clHeapCalloc(extraNodes, sizeof(*nodes));
    unlockList->su.entity = (ClAmsEntityT*) clHeapCalloc(extraSUs, sizeof(*sus));

    CL_ASSERT(unlockList->si.entity && unlockList->node.entity && unlockList->su.entity);

    memcpy(unlockList->si.entity, sis, sizeof(*sis)*extraSIs);
    memcpy(unlockList->node.entity, nodes, sizeof(*nodes)*extraNodes);
    memcpy(unlockList->su.entity, sus, sizeof(*sus) * extraSUs);

    clOsalTaskCreateDetached("MIGRATE-UNLOCK-THREAD", CL_OSAL_SCHED_OTHER, 0, 0, 
                             clAmsMgmtMigrateListUnlock, (void*)unlockList);

    /*
     * Return the newly created info. in the migrated list.
     */
    if(migrateList)
    {
        if(extraSIs)
        {
            migrateList->si.count = extraSIs;
            migrateList->si.entity = sis;
            migrateList->csi.count = extraSIs;
            migrateList->csi.entity = csis;
            sis = csis = NULL;
        }

        if(extraNodes)
        {
            migrateList->node.count = extraNodes;
            migrateList->node.entity = nodes;
            nodes = NULL;
        }

        if(extraSUs)
        {
            migrateList->su.count = extraSUs;
            migrateList->su.entity = sus;
            migrateList->comp.count = extraSUs;
            migrateList->comp.entity = comps;
            sus = comps = NULL;
        }
    }

    out_free:

    clAmsMgmtCCBFinalize(ccbHandle);

    if(siBuffer.entity) clHeapFree(siBuffer.entity);
    if(nodeBuffer.entity) clHeapFree(nodeBuffer.entity);
    if(suBuffer.entity) clHeapFree(suBuffer.entity);
    if(nodeList) clHeapFree(nodeList);
    if(nodes) clHeapFree(nodes);
    if(sus) clHeapFree(sus);
    if(comps) clHeapFree(comps);
    if(sis) clHeapFree(sis);
    if(csis) clHeapFree(csis);
    if(pSGRefSI) clHeapFree(pSGRefSI);
    if(pSIRefCSI) clHeapFree(pSIRefCSI);
    if(pSURefComp) clHeapFree(pSURefComp);
    if(pNumSupportedCSITypes) clHeapFree(pNumSupportedCSITypes);

    out:
    return rc;
}
/*
 * Create objects for the static AMF entities.
 */
ClRcT corAmfTreeInitialize(void)
{
    ClRcT rc = CL_OK;

    if(gClAmfMibLoaded)
    {
        rc = corAmfMibTreeInitialize();
    }
    else
    {
        ClVersionT version = {'B', 0x1 , 0x1};
        ClCorMOIdT moId;
        ClAmsEntityBufferT nodeList = {0};
        ClAmsEntityBufferT suList = {0};
        ClAmsEntityBufferT compList = {0};
        ClAmsEntityBufferT sgList = {0};
        ClAmsEntityBufferT siList = {0};
        ClAmsEntityBufferT csiList = {0};
        ClCorClassTypeT classIds[CL_AMS_ENTITY_TYPE_MAX+2] = {0};
        ClCorMOClassPathT sgClassPath;
        ClInt32T i;

        rc = corAmfEntityInitialize();
        if(rc != CL_OK) goto out;

        rc = clAmsMgmtInitialize(&mgmtHandle,  NULL, &version);
        if(rc != CL_OK)
        {
            clLogError("COR", "AMF", "Mgmt initialize returned [%#x]", rc);
            goto out;
        }

        if( (rc = clAmsMgmtGetNodeList(mgmtHandle, &nodeList)) != CL_OK)
        {
            clLogError("COR", "AMF", "Node list returned [%#x]", rc);
            goto out;
        }

        /*
         * Create object heirarchy for nodes/sus/comps. 
         */
        for(i = 0; i < nodeList.count; ++i)
        {
            ClInt32T j;
            ClCorMOClassPathT nodeClassPath;

            rc = clCorMoIdInitialize(&moId);
            CL_ASSERT(rc == CL_OK);

            rc = clCorNodeNameToMoIdGet(nodeList.entity[i].name, &moId);
            if(rc != CL_OK)
            {
                clLogError("COR", "AMF", "Node name to moid get for [%s] failed with [%#x]",
                           nodeList.entity[i].name.value, rc);
                goto out;
            }

            rc = clCorMoClassPathInitialize(&nodeClassPath);
            CL_ASSERT(rc == CL_OK);
        
            rc = clCorMoIdToMoClassPathGet(&moId, &nodeClassPath);
            CL_ASSERT(rc == CL_OK);

            /*
             * Now get nodes su list.
             */
            rc = clAmsMgmtGetNodeSUList(mgmtHandle, &nodeList.entity[i], &suList);
            if(rc != CL_OK)
            {
                clLogError("COR", "AMF", "Node [%s] su list returned [%#x]", 
                           nodeList.entity[i].name.value, rc);
                goto out;
            }

            if(!classIds[CL_AMS_ENTITY_TYPE_SU])
            {
                rc = corAmfEntityClassGet(CL_AMS_ENTITY_TYPE_SU, classIds+CL_AMS_ENTITY_TYPE_SU);
                if(rc != CL_OK)
                {
                    clLogError("COR", "AMF", "Class for entity SU not found");
                    goto out;
                }
            }
        
            if(!classIds[CL_AMS_ENTITY_TYPE_COMP])
            {
                rc = corAmfEntityClassGet(CL_AMS_ENTITY_TYPE_COMP, classIds+CL_AMS_ENTITY_TYPE_COMP);
                if(rc != CL_OK)
                {
                    clLogError("COR", "AMF", "Class for entity comp not found");
                    goto out;
                }
            }

            rc = clCorMoClassPathAppend(&nodeClassPath, classIds[CL_AMS_ENTITY_TYPE_SU]);
            CL_ASSERT(rc == CL_OK);

            rc = corAmfMoClassCreate("AMFSu", &nodeClassPath, NULL);
            if(rc != CL_OK)
            {
                if(CL_GET_ERROR_CODE(rc) != CL_COR_MO_TREE_ERR_FAILED_TO_ADD_NODE)
                    goto out;
            }

            if(CL_GET_ERROR_CODE(rc) != CL_COR_MO_TREE_ERR_FAILED_TO_ADD_NODE)
            {
                rc = clCorMoClassPathAppend(&nodeClassPath, classIds[CL_AMS_ENTITY_TYPE_COMP]);
                CL_ASSERT(rc == CL_OK);
            
                rc = corAmfMoClassCreate("AMFComp", &nodeClassPath, NULL);
                if(rc != CL_OK) goto out;
            }
            else
            {
                rc = CL_OK;
            }

            for(j = 0; j < suList.count; ++j)
            {
                ClInt32T k;
                ClCorMOIdT suMoId;

                memcpy(&suMoId, &moId, sizeof(suMoId));
                rc = clCorMoIdAppend(&suMoId, classIds[CL_AMS_ENTITY_TYPE_SU], j);
                CL_ASSERT(rc == CL_OK);

                rc = corAmfObjectCreate(0, &suList.entity[j], &suMoId);
                if(rc != CL_OK) goto out;

                rc = clAmsMgmtGetSUCompList(mgmtHandle, &suList.entity[j], &compList);
                if(rc != CL_OK)
                {
                    goto out;
                }
            
                for(k = 0; k < compList.count; ++k)
                {
                    ClCorMOIdT compMoId;
   
                    memcpy(&compMoId, &suMoId, sizeof(compMoId));
                    rc = clCorMoIdAppend(&compMoId, classIds[CL_AMS_ENTITY_TYPE_COMP], k);
                    CL_ASSERT(rc == CL_OK);

                    rc = corAmfObjectCreate(0, &compList.entity[k], &compMoId);
                    if(rc != CL_OK) goto out;
                }
                clHeapFree(compList.entity);
                compList.entity = NULL;
            }
            clHeapFree(suList.entity);
            suList.entity = NULL;
        }

        /*
         * Configure object heirarchy for SGs.
         */
        rc = clAmsMgmtGetSGList(mgmtHandle, &sgList);
        if(rc != CL_OK)
        {
            clLogError("COR", "AMF", "SG list returned [%#x]", rc);
            goto out;
        }

        rc = corAmfEntityClassGet(CL_AMS_ENTITY_TYPE_SG, &classIds[CL_AMS_ENTITY_TYPE_SG]);
        if(rc != CL_OK)
        {
            clLogError("COR", "AMF", "SG entity class not found");
            goto out;
        }

        rc = corAmfEntityClassGet(CL_AMS_ENTITY_TYPE_SG, &classIds[CL_AMS_ENTITY_TYPE_SI]);
        if(rc != CL_OK)
        {
            clLogError("COR", "AMF", "SI entity class not found");
            goto out;
        }

        rc = corAmfEntityClassGet(CL_AMS_ENTITY_TYPE_SG, &classIds[CL_AMS_ENTITY_TYPE_CSI]);
        if(rc != CL_OK)
        {
            clLogError("COR", "AMF", "CSI entity class not found");
            goto out;
        }

        rc = clCorMoClassPathInitialize(&sgClassPath);
        CL_ASSERT(rc == CL_OK);
        rc = clCorMoClassPathAppend(&sgClassPath, classIds[CL_AMS_ENTITY_TYPE_SG]);
        CL_ASSERT(rc == CL_OK);

        rc = corAmfMoClassCreate("AMFSg", &sgClassPath, NULL);
        if(rc != CL_OK) goto out;
       
        rc = clCorMoClassPathAppend(&sgClassPath, classIds[CL_AMS_ENTITY_TYPE_SI]);
        CL_ASSERT(rc == CL_OK);
            
        rc = corAmfMoClassCreate("AMFSi", &sgClassPath, NULL);
        if(rc != CL_OK) goto out;

        rc = clCorMoClassPathAppend(&sgClassPath, classIds[CL_AMS_ENTITY_TYPE_CSI]);
        CL_ASSERT(rc == CL_OK);

        rc = corAmfMoClassCreate("AMFCsi", &sgClassPath, NULL);
        if(rc != CL_OK) goto out;

        for(i = 0; i < sgList.count; ++i)
        {
            ClInt32T j;

            rc = clCorMoIdInitialize(&moId);
            CL_ASSERT(rc == CL_OK);
            rc = clCorMoIdAppend(&moId, classIds[CL_AMS_ENTITY_TYPE_SG], i);
            CL_ASSERT(rc == CL_OK);

            rc = corAmfObjectCreate(0, &sgList.entity[i], &moId);
            if(rc != CL_OK) goto out;

            rc = clAmsMgmtGetSGSIList(mgmtHandle, &sgList.entity[i], &siList);
            if(rc != CL_OK)
            {
                clLogError("COR", "AMF", "SI list get for SG [%s] returned [%#x]",
                           sgList.entity[i].name.value, rc);
                goto out;
            }
        
            for(j = 0; j < siList.count; ++j)
            {
                ClInt32T k;
                ClCorMOIdT siMoId;

                memcpy(&siMoId, &moId, sizeof(siMoId));
                rc = clCorMoIdAppend(&siMoId, classIds[CL_AMS_ENTITY_TYPE_SI], j);
                CL_ASSERT(rc == CL_OK);

                rc = corAmfObjectCreate(0, &siList.entity[j], &siMoId);
                if(rc != CL_OK) goto out;

                rc = clAmsMgmtGetSICSIList(mgmtHandle, &siList.entity[j], &csiList);
                if(rc != CL_OK)
                {
                    clLogError("COR", "AMF", "CSI list for SI [%s] returned [%#x]",
                               siList.entity[j].name.value, rc);
                    goto out;
                }

                for(k = 0; k < csiList.count; ++k)
                {
                    ClCorMOIdT csiMoId;
                    memcpy(&csiMoId, &siMoId, sizeof(csiMoId));
                    rc = clCorMoIdAppend(&csiMoId, classIds[CL_AMS_ENTITY_TYPE_CSI], k);
                    CL_ASSERT(rc == CL_OK);
                    rc = corAmfObjectCreate(0, &csiList.entity[k], &csiMoId);
                    if(rc != CL_OK) goto out;
                }
                clHeapFree(csiList.entity);
                csiList.entity = NULL;
            }
            clHeapFree(siList.entity);
            siList.entity = NULL;
        }

        /*
         * We are here when the objects are all created. Do a commit
         */
        rc = corAmfObjectCommit();
        if(rc != CL_OK)
        {
            clLogError("COR", "AMF", "Object commit returned [%#x]", rc);
            goto out;
        }

        clLogNotice("COR", "AMF", "COR AMF tree successfully initialized");

        out:
        if(nodeList.entity) 
            clHeapFree(nodeList.entity);
        if(suList.entity)   
            clHeapFree(suList.entity);
        if(compList.entity) 
            clHeapFree(compList.entity);
        if(sgList.entity)   
            clHeapFree(sgList.entity);
        if(siList.entity)   
            clHeapFree(siList.entity);
        if(csiList.entity) 
            clHeapFree(csiList.entity);
    }
    return rc;
}
static ClRcT clAmsCompRecovery(ClAmsEntityT *pEntity,
                               ClAmsThresholdT *pThreshold)
{
    ClAmsEntityConfigT *pEntityConfig = NULL;
    ClAmsCompConfigT *pCompConfig = NULL;
    ClRcT rc = CL_OK;

    if(pEntity->type == CL_AMS_ENTITY_TYPE_SU)
    {
        ClAmsEntityBufferT compBuffer = {0};
        rc = clAmsMgmtGetSUCompList(gClAmsEntityTriggerMgmtHandle,
                                    pEntity, &compBuffer);
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY",
                       "SU [%.*s] get comp list returned [%#x]",
                       pEntity->name.length-1, pEntity->name.value, rc);
            goto out;
        }
        if(!compBuffer.count)
        {
            clLogNotice("TRIGGER", "RECOVERY",
                        "SU doesnt have components. Locking SU");
            rc = clAmsMgmtEntityLockAssignment(gClAmsEntityTriggerMgmtHandle,
                                               pEntity);
            if(compBuffer.entity) clHeapFree(compBuffer.entity);
            goto out_free;
        }
        /*
         * Now overwrite the entity with first comp.
         */
        memcpy(pEntity, &compBuffer.entity[0], sizeof(*pEntity));
        clHeapFree(compBuffer.entity);
    }

    clLogNotice("TRIGGER", "RECOVERY",
                "Getting comp config for [%.*s]",
                pEntity->name.length-1, pEntity->name.value);

    rc = clAmsMgmtEntityGetConfig(gClAmsEntityTriggerMgmtHandle,
                                  pEntity, &pEntityConfig);

    if(rc != CL_OK)
    {
        clLogError("TRIGGER", "RECOVERY", 
                   "Entity get config returned [%#x]", rc);
        goto out;
    }
    pCompConfig = (ClAmsCompConfigT*)pEntityConfig;

    if(pThreshold->recoveryReset == CL_TRUE)
    {
        if(pThreshold->recovery == CL_AMS_ENTITY_RECOVERY_FAILOVER)
        {
            /*
             *Try repairing.
             */
            rc = clAmsMgmtEntityRepaired(gClAmsEntityTriggerMgmtHandle,
                                         &pCompConfig->parentSU.entity);
            if(rc != CL_OK)
            {
                clLogError("TRIGGER", "RECOVERY", 
                           "Repair didn't work. Trying lock assignment first");
                rc = clAmsMgmtEntityLockAssignment(gClAmsEntityTriggerMgmtHandle,
                                                   &pCompConfig->parentSU.entity);
                if(rc != CL_OK)
                {
                    clLogError("TRIGGER", "RECOVERY",
                               "Lockassignment didn't work. Trying unlock as a last resort");
                }
            }
        }
        
        clLogNotice("TRIGGER", "RECOVERY",
                    "Recoverying SU [%.*s] through unlock",
                    pCompConfig->parentSU.entity.name.length-1,
                    pCompConfig->parentSU.entity.name.value);

        rc = clAmsMgmtEntityUnlock(gClAmsEntityTriggerMgmtHandle,
                                   &pCompConfig->parentSU.entity);
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY RESET",
                       "Unlock for entity [%.*s] returned [%#x]",
                       pCompConfig->parentSU.entity.name.length-1,
                       pCompConfig->parentSU.entity.name.value, rc);
        }

        goto out_free;
    }

    switch(pThreshold->recovery)
    {
    case CL_AMS_ENTITY_RECOVERY_RESTART:

        clLogNotice("TRIGGER", "RECOVERY",
                    "Restarting comp [%.*s] as part of [%s] recovery",
                    pEntity->name.length-1, pEntity->name.value,
                    CL_METRIC_STR(pThreshold->metric.id));

        rc = clAmsMgmtEntityRestart(gClAmsEntityTriggerMgmtHandle,
                                    pEntity);
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY",
                       "Comp restart returned with [%#x]", rc);
            goto out_free;
        }
        break;

    case CL_AMS_ENTITY_RECOVERY_FAILOVER:
        /*
         * We trigger a fault to AMS with a recommended recovery.
         */
        clAmsTriggerFault(pEntity, CL_AMS_RECOVERY_COMP_FAILOVER);
        break;

    case CL_AMS_ENTITY_RECOVERY_LOCK:
        /*
         * Graceful lock of the SU
         */
        clLogNotice("TRIGGER", "RECOVERY",
                    "Locking work for parent SU [%.*s] as part of [%s] recovery",
                    pCompConfig->parentSU.entity.name.length-1,
                    pCompConfig->parentSU.entity.name.value,
                    CL_METRIC_STR(pThreshold->metric.id));

        rc = clAmsMgmtEntityLockAssignment(gClAmsEntityTriggerMgmtHandle,
                                           &pCompConfig->parentSU.entity);
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY", 
                       "SU work switchover returned [%#x]", rc);
            goto out_free;
        }
        break;

    default:
        break;
    }

    out_free:
    if(pCompConfig->pSupportedCSITypes)
        clHeapFree(pCompConfig->pSupportedCSITypes);
    
    clHeapFree(pCompConfig);

    out:
    return rc;
}