示例#1
0
int32_t mssIplUeIsolation( TargetHandle_t i_mba, const CenRank & i_rank,
                           CenDqBitmap & o_bitmap )
{
    #define PRDF_FUNC "[PlatServices::mssIplUeIsolation] "

    int32_t o_rc = SUCCESS;

    uint8_t data[PORT_SLCT_PER_MBA][DIMM_DQ_RANK_BITMAP_SIZE];

    errlHndl_t errl = NULL;
    PRD_FAPI_TO_ERRL( errl, mss_IPL_UE_isolation, getFapiTarget(i_mba),
                      i_rank.getMaster(), data );
    if ( NULL != errl )
    {
        PRDF_ERR( PRDF_FUNC"mss_IPL_UE_isolation() failed: MBA=0x%08x "
                  "rank=%d", getHuid(i_mba), i_rank.getMaster() );
        PRDF_COMMIT_ERRL( errl, ERRL_ACTION_REPORT );
        o_rc = FAIL;
    }
    else
    {
        o_bitmap = CenDqBitmap ( i_mba, i_rank, data );
    }

    return o_rc;

    #undef PRDF_FUNC
}
示例#2
0
int32_t CenSymbol::getSymbol( const CenRank & i_rank, WiringType i_wiringType,
                              uint8_t i_dimmDq, uint8_t i_portSlct,
                              uint8_t & o_symbol )
{
    #define PRDF_FUNC "[CenSymbol::getSymbol] "

    int32_t o_rc = SUCCESS;

    do
    {
        if ( DQS_PER_DIMM <= i_dimmDq )
        {
            PRDF_ERR( PRDF_FUNC"i_dimmDq is invalid" );
            o_rc = FAIL; break;
        }

        if ( PORT_SLCT_PER_MBA <= i_portSlct )
        {
            PRDF_ERR( PRDF_FUNC"i_portSlct is invalid" );
            o_rc = FAIL; break;
        }

        // Get the Centaur DQ.
        uint8_t cenDq = i_dimmDq;

        // TODO: RTC 67376 Add wiring type support for IS DIMMs to convert from
        //       i_dimmDq to cenDq.

        o_symbol = cenDq2Symbol( cenDq, i_portSlct );

    } while(0);

    if ( SUCCESS != o_rc )
    {
        PRDF_ERR( PRDF_FUNC"Failed: i_rank=M%dS%d i_wiringType=%d i_dimmDq=%d "
                  "i_portSlct=%d", i_rank.getMaster(), i_rank.getSlave(),
                  i_wiringType, i_dimmDq, i_portSlct );
    }

    return o_rc;

    #undef PRDF_FUNC
}
示例#3
0
int32_t CenMbaTdCtlr::handleTdEvent( STEP_CODE_DATA_STRUCT & io_sc,
                                     const CenRank & i_rank,
                                     const CenMbaTdCtlrCommon::TdType i_event,
                                     bool i_banTps )
{
    #define PRDF_FUNC "[CenMbaTdCtlr::handleTdEvent] "

    // This is a no-op in Hostboot because we can't support Targeted Diagnostics
    // at this time. Instead, print a trace statement indicating the intended
    // request. Note that any VCM request will eventually be found during the
    // initialization of the runtime TD controller.
    PRDF_INF( PRDF_FUNC"TD request found during Hostboot: iv_mbaChip=0x%08x "
              "i_rank=M%dS%d i_event=%d i_banTps=%c", iv_mbaChip->GetId(),
              i_rank.getMaster(), i_rank.getSlave(), i_event,
              i_banTps ? 'T' : 'F' );

    return SUCCESS;

    #undef PRDF_FUNC
}
示例#4
0
int32_t TdRankList::setInterruptedRank( const CenRank & i_rank )
{
    #define PRDF_FUNC "[TdRankList::setInterruptedRank] "

    int32_t o_rc = SUCCESS;

    ListItr it = findRank( i_rank );
    if ( iv_list.end() == it )
    {
        PRDF_ERR( PRDF_FUNC "findRank() failed: i_rank=%d", i_rank.getMaster() );
        o_rc = FAIL;
    }
    else
    {
        iv_curRank = it;
    }

    return o_rc;

    #undef PRDF_FUNC
}
示例#5
0
int32_t TdRankList::setRankStatus( const CenRank & i_rank, bool i_isGood )
{
    #define PRDF_FUNC "[TdRankList::setRankStatus] "

    int32_t o_rc = SUCCESS;

    ListItr it = findRank( i_rank );
    if ( iv_list.end() == it )
    {
        PRDF_ERR( PRDF_FUNC "findRank() failed: i_rank=%d i_isGood=%c",
                  i_rank.getMaster(), i_isGood ? 'T' : 'F' );
        o_rc = FAIL;
    }
    else
    {
        it->isGood = i_isGood;
    }

    return o_rc;

    #undef PRDF_FUNC
}
示例#6
0
TargetHandleList getConnectedDimms( TargetHandle_t i_mba,
                                    const CenRank & i_rank )
{
    #define PRDF_FUNC "[CalloutUtil::getConnectedDimms] "

    TargetHandleList o_list;

    if ( TYPE_MBA != getTargetType(i_mba) )
    {
        PRDF_ERR( PRDF_FUNC "Invalid target type: HUID=0x%08x", getHuid(i_mba) );
    }
    else
    {
        TargetHandleList dimmList = getConnected( i_mba, TYPE_DIMM );
        for ( TargetHandleList::iterator dimmIt = dimmList.begin();
              dimmIt != dimmList.end(); dimmIt++)
        {
            uint8_t dimmSlct;
            int32_t l_rc = getMbaDimm( *dimmIt, dimmSlct );
            if ( SUCCESS != l_rc )
            {
                PRDF_ERR( PRDF_FUNC "getMbaDimm(0x%08x) failed",
                          getHuid(*dimmIt) );
                continue;
            }

            if ( dimmSlct == i_rank.getDimmSlct() )
            {
                o_list.push_back( *dimmIt );
            }
        }
    }

    return o_list;

    #undef PRDF_FUNC
}
示例#7
0
int32_t CenMbaIplCeStats::collectStats( const CenRank & i_stopRank )
{
    #define PRDF_FUNC "[CenMbaIplCeStats::collectStats] "
    int32_t o_rc = SUCCESS;
    do
    {
        MemUtils::MaintSymbols symData; CenSymbol junk;
        o_rc = MemUtils::collectCeStats( iv_mbaChip, i_stopRank, symData, junk);
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC"MemUtils::collectCeStats() failed. MBA:0X%08X",
                      getHuid( iv_mbaChip->GetChipHandle() ) );
            break;
        }

        // if size of stats collected is zero, it may mean some symbol
        // has gone beyond maximum value. But this is only valid for DD1
        // and has a very low probability. So ignoring this case.

        for ( uint32_t i = 0; i < symData.size(); i++ )
        {
            uint8_t dimmSlct = i_stopRank.getDimmSlct();
            uint8_t dram = symData[i].symbol.getDram();
            uint8_t portSlct = symData[i].symbol.getPortSlct();

            // Check if analysis is banned.
            HalfRankKey banKey = { i_stopRank, portSlct };

            // Check if the rank has already been banned. Note that [] will
            // create an entry if one does not exist, so used find() instead to
            // check for existence in the map.
            if ( iv_bannedAnalysis.end() != iv_bannedAnalysis.find(banKey) )
                continue;

            // Update iv_ceSymbols with the new symbol data.
            SymbolKey symkey = { symData[i].symbol };
            iv_ceSymbols.push_back (symkey );

            // Increment the soft CEs per DRAM.
            DramKey dramKey = { i_stopRank, dram, portSlct };
            iv_dramMap[dramKey] += symData[i].count;

            // Increment the soft CEs per half rank.
            HalfRankKey rankKey = { i_stopRank, portSlct };
            iv_rankMap[rankKey] += symData[i].count;

            // In case of dimm select, rank select does not matter
            CenRank dimmRank( dimmSlct << DIMM_SLCT_PER_MBA );
            // Increment the soft CEs per half dimm select.
            HalfRankKey dsKey = { dimmRank, portSlct };
            iv_dsMap[dsKey] += symData[i].count;
        }

    } while (0);

    // We have to clear all stats before giving control back to MDIA..
    // This is done by setting up MBSTRQ[53] bit
    // We are doing cleanup in TdController code,
    // So not clearing up stats here.
    return o_rc;

    #undef PRDF_FUNC
}
示例#8
0
int32_t collectCeStats( ExtensibleChip * i_mbaChip, const CenRank & i_rank,
                        MaintSymbols & o_maintStats, CenSymbol & o_chipMark,
                        uint8_t i_thr )
{
    #define PRDF_FUNC "[MemUtils::collectCeStats] "

    int32_t o_rc = SUCCESS;

    o_chipMark = CenSymbol(); // Initially invalid.

    do
    {
        if ( 0 == i_thr ) // Must be non-zero
        {
            PRDF_ERR( PRDF_FUNC "i_thr %d is invalid", i_thr );
            o_rc = FAIL; break;
        }

        TargetHandle_t mbaTrgt = i_mbaChip->GetChipHandle();
        CenMbaDataBundle * mbadb = getMbaDataBundle( i_mbaChip );
        ExtensibleChip * membufChip = mbadb->getMembChip();
        if ( NULL == membufChip )
        {
            PRDF_ERR( PRDF_FUNC "getMembChip() failed" );
            o_rc = FAIL; break;
        }

        uint8_t mbaPos = getTargetPosition( mbaTrgt );
        if ( MAX_MBA_PER_MEMBUF <= mbaPos )
        {
            PRDF_ERR( PRDF_FUNC "mbaPos %d is invalid", mbaPos );
            o_rc = FAIL; break;
        }

        const bool isX4 = isDramWidthX4(mbaTrgt);

        // Get the current spares on this rank.
        CenSymbol sp0, sp1, ecc;
        o_rc = mssGetSteerMux( mbaTrgt, i_rank, sp0, sp1, ecc );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "mssGetSteerMux() failed." );
            break;
        }

        // Use this map to keep track of the total counts per DRAM.
        DramCountMap dramCounts;

        const char * reg_str = NULL;
        SCAN_COMM_REGISTER_CLASS * reg = NULL;

        for ( uint8_t regIdx = 0; regIdx < CE_REGS_PER_MBA; regIdx++ )
        {
            reg_str = mbsCeStatReg[mbaPos][regIdx];
            reg     = membufChip->getRegister( reg_str );

            o_rc = reg->Read();
            if ( SUCCESS != o_rc )
            {
                PRDF_ERR( PRDF_FUNC "Read() failed on %s", reg_str );
                break;
            }

            uint8_t baseSymbol = SYMBOLS_PER_CE_REG * regIdx;

            for ( uint8_t i = 0; i < SYMBOLS_PER_CE_REG; i++ )
            {
                uint8_t count = reg->GetBitFieldJustified( (i*8), 8 );

                if ( 0 == count ) continue; // nothing to do

                uint8_t sym  = baseSymbol + i;
                uint8_t dram = symbol2Dram( sym, isX4 );

                // Keep track of the total DRAM counts.
                dramCounts[dram].totalCount += count;

                // Add any symbols that have exceeded threshold to the list.
                if ( i_thr <= count )
                {
                    // Keep track of the total number of symbols per DRAM that
                    // have exceeded threshold.
                    dramCounts[dram].symbolCount++;

                    SymbolData symData;
                    symData.symbol = CenSymbol::fromSymbol( mbaTrgt, i_rank,
                                            sym, CEN_SYMBOL::BOTH_SYMBOL_DQS );
                    if ( !symData.symbol.isValid() )
                    {
                        PRDF_ERR( PRDF_FUNC "CenSymbol() failed: symbol=%d",
                                  sym );
                        o_rc = FAIL;
                        break;
                    }
                    else
                    {
                        // Check if this symbol is on any of the spares.
                        if ( ( sp0.isValid() &&
                               (sp0.getDram() == symData.symbol.getDram()) ) ||
                             ( sp1.isValid() &&
                               (sp1.getDram() == symData.symbol.getDram()) ) )
                        {
                            symData.symbol.setDramSpared();
                        }
                        if ( ecc.isValid() &&
                             (ecc.getDram() == symData.symbol.getDram()) )
                        {
                            symData.symbol.setEccSpared();
                        }

                        // Add the symbol to the list.
                        symData.count = count;
                        o_maintStats.push_back( symData );
                    }
                }
            }
            if ( SUCCESS != o_rc ) break;
        }
        if ( SUCCESS != o_rc ) break;

        if ( o_maintStats.empty() ) break; // no need to continue

        // Sort the list of symbols.
        std::sort( o_maintStats.begin(), o_maintStats.end(), sortSymDataCount );

        // Get the DRAM with the highest count.
        uint32_t highestDram  = 0;
        uint32_t highestCount = 0;
        const uint32_t symbolTH = isX4 ? 1 : 2;
        for ( DramCountMap::iterator it = dramCounts.begin();
              it != dramCounts.end(); ++it )
        {
            if ( (symbolTH     <= it->second.symbolCount) &&
                 (highestCount <  it->second.totalCount ) )
            {
                highestDram  = it->first;
                highestCount = it->second.totalCount;
            }
        }

        if ( 0 != highestCount )
        {
            uint8_t sym = dram2Symbol( highestDram, isX4 );
            o_chipMark  = CenSymbol::fromSymbol( mbaTrgt, i_rank, sym );

            // Check if this symbol is on any of the spares.
            if ( ( sp0.isValid() && (sp0.getDram() == o_chipMark.getDram()) ) ||
                 ( sp1.isValid() && (sp1.getDram() == o_chipMark.getDram()) ) )
            {
                o_chipMark.setDramSpared();
            }
            if ( ecc.isValid() && (ecc.getDram() == o_chipMark.getDram()) )
            {
                o_chipMark.setEccSpared();
            }
        }

    } while(0);

    if ( SUCCESS != o_rc )
    {
        PRDF_ERR( PRDF_FUNC "Failed: i_mbaChip=0x%08x i_rank=m%ds%d i_thr=%d",
                  i_mbaChip->GetId(), i_rank.getMaster(), i_rank.getSlave(),
                  i_thr );
    }

    return o_rc;

    #undef PRDF_FUNC
}
int32_t getMnfgMemCeTh( ExtensibleChip * i_mbaChip, const CenRank & i_rank,
                        uint16_t & o_cePerDram, uint16_t & o_cePerHalfRank,
                        uint16_t & o_cePerDimm )
{
    #define PRDF_FUNC "[getMnfgMemCeTh] "

    int32_t o_rc = SUCCESS;

    do
    {
        // Get base threshold ( 2GB ).
        uint8_t baseTh = getMnfgCeTh();

        // A base threhold of 0 indicates there should be no thresholding.
        if ( 0 == baseTh )
        {
            o_cePerDram = o_cePerHalfRank = o_cePerDimm =
                                    MfgThreshold::INFINITE_LIMIT_THR;
            break;
        }

        // Get DRAM size
        uint8_t size = 0;
        o_rc = MemUtils::getDramSize( i_mbaChip, size );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "MemUtils::getDramSize() failed" );
            break;
        }

        // Get number of ranks per DIMM select.
        uint8_t rankCount = getRanksPerDimm( i_mbaChip->GetChipHandle(),
                                             i_rank.getDimmSlct() );
        if ( 0 == rankCount )
        {
            PRDF_ERR( PRDF_FUNC "PlatServices::getRanksPerDimm() failed" );
            o_rc = FAIL; break;
        }

        // Get number of allowed CEs.
        uint8_t baseAllowed = baseTh - 1;

        // Calculate CEs per DRAM.
        //   The DRAM size is in MBAXCR[6:7], where 0 = 2Gb, 1 = 4Gb, 2 = 8Gb,
        //   and 3 = 16 Gb. So the allowed CEs per DRAM can be calculated with
        //   the following:
        //         perDram = base * 2^(MBAXCR[6:7]+1) * (9/16)
        //     or, perDram = (base << MBAXCR[6:7]+1)  * (9/16)
        uint32_t computeBase = (baseAllowed << (size+1)) * 9;
        o_cePerDram = (computeBase + 8) / 16;

        // Calculate CEs per DIMM.
        o_cePerDimm = ((computeBase * (2 + rankCount)) + 8) / 16;

        // Calculate CEs per half-rank.
        // Same as perDimm where rankCount is 1;
        o_cePerHalfRank = ((computeBase * (2 + 1)) + 8) / 16;

    } while (0);

    return o_rc;

    #undef PRDF_FUNC
}
示例#10
0
/**
 * @brief  MBSECCFIR[19] - Fetch UE.
 * @param  i_membChip A Centaur chip.
 * @param  i_sc       The step code data struct.
 * @param  i_mbaPos   The MBA position.
 * @return SUCCESS
 */
int32_t AnalyzeFetchUe( ExtensibleChip * i_membChip,
                        STEP_CODE_DATA_STRUCT & i_sc, uint32_t i_mbaPos )
{
    #define PRDF_FUNC "[AnalyzeFetchUe] "

    int32_t l_rc = SUCCESS;

    ExtensibleChip * mbaChip = NULL;

    do
    {
        // All memory UEs should be customer viewable. Normally, this would be
        // done by setting the threshold to 1, but we do not want to mask UEs
        // on the first occurrence.
        i_sc.service_data->SetServiceCall();

        CenMembufDataBundle * membdb = getMembufDataBundle( i_membChip );
        mbaChip = membdb->getMbaChip( i_mbaPos );
        if ( NULL == mbaChip )
        {
            PRDF_ERR( PRDF_FUNC"getMbaChip() returned NULL" );
            l_rc = FAIL; break;
        }

        CenAddr addr;
        l_rc = getCenReadAddr( i_membChip, i_mbaPos, READ_UE_ADDR, addr );
        if ( SUCCESS != l_rc )
        {
            PRDF_ERR( PRDF_FUNC"getCenReadAddr() failed" );
            break;
        }
        CenRank rank = addr.getRank();

        // Add address to UE table.
        CenMbaDataBundle * mbadb = getMbaDataBundle( mbaChip );
        mbadb->iv_ueTable.addEntry( UE_TABLE::FETCH_UE, addr );

        // Callout the rank.
        MemoryMru memmru ( mbaChip->GetChipHandle(), rank,
                           MemoryMruData::CALLOUT_RANK );
        i_sc.service_data->SetCallout( memmru );

        // Add a TPS request to the TD queue and ban any further TPS requests
        // for this rank.
        l_rc = mbadb->iv_tdCtlr.handleTdEvent( i_sc, rank,
                                               CenMbaTdCtlrCommon::TPS_EVENT,
                                               true );
        if ( SUCCESS != l_rc )
        {
            PRDF_ERR( PRDF_FUNC"handleTdEvent() failed: rank=m%ds%d",
                      rank.getMaster(), rank.getSlave() );
            // We are not adding break here as we still want to do lmbGard
            // If you want to add any code after this which depends on result
            // of handleTdEvent result, add the code judicially.
        }

        #ifndef __HOSTBOOT_MODULE
        // Send lmb gard message to PHYP.
        int32_t lmbRc =  DEALLOC::lmbGard( mbaChip, addr );
        if ( SUCCESS != lmbRc )
        {
            PRDF_ERR( PRDF_FUNC"lmbGard() failed" );
            l_rc = lmbRc; break;
        }
        #endif

    } while (0);

    // Add ECC capture data for FFDC.
    if ( NULL != mbaChip )
        CenMbaCaptureData::addMemEccData( mbaChip, i_sc );

    if ( SUCCESS != l_rc )
    {
        PRDF_ERR( PRDF_FUNC"Failed: i_membChip=0x%08x i_mbaPos=%d",
                  i_membChip->GetId(), i_mbaPos );
        CalloutUtil::defaultError( i_sc );
    }

    return SUCCESS; // Intentionally return SUCCESS for this plugin

    #undef PRDF_FUNC
}
示例#11
0
/**
 * @brief  MBSECCFIR[16] - Fetch New CE (NCE).
 * @param  i_membChip A Centaur chip.
 * @param  i_sc       The step code data struct.
 * @param  i_mbaPos   The MBA position.
 * @return SUCCESS
 */
int32_t AnalyzeFetchNce( ExtensibleChip * i_membChip,
                         STEP_CODE_DATA_STRUCT & i_sc, uint32_t i_mbaPos )
{
    #define PRDF_FUNC "[AnalyzeFetchNce] "

    int32_t l_rc = SUCCESS;

    ExtensibleChip * mbaChip = NULL;

    do
    {
        CenMembufDataBundle * membdb = getMembufDataBundle( i_membChip );
        mbaChip = membdb->getMbaChip( i_mbaPos );
        if ( NULL == mbaChip )
        {
            PRDF_ERR( PRDF_FUNC"getMbaChip() returned NULL" );
            l_rc = FAIL; break;
        }
        TargetHandle_t mbaTrgt = mbaChip->GetChipHandle();

        CenAddr addr;
        l_rc = getCenReadAddr( i_membChip, i_mbaPos, READ_NCE_ADDR, addr );
        if ( SUCCESS != l_rc )
        {
            PRDF_ERR( PRDF_FUNC"getCenReadAddr() failed" );
            break;
        }
        CenRank rank = addr.getRank();

        if ( 0x20 > getChipLevel(i_membChip->GetChipHandle()) )
        {
            // There is a bug in DD1.x where the value of MBSEVR cannot be
            // trusted. The workaround is too complicated for its value so
            // callout the rank instead.
            MemoryMru memmru ( mbaTrgt, rank, MemoryMruData::CALLOUT_RANK );
            i_sc.service_data->SetCallout( memmru );
        }
        else // DD2.0+
        {
            // Get the failing symbol
            const char * reg_str = (0 == i_mbaPos) ? "MBA0_MBSEVR"
                                                   : "MBA1_MBSEVR";
            SCAN_COMM_REGISTER_CLASS * reg = i_membChip->getRegister(reg_str);
            l_rc = reg->Read();
            if ( SUCCESS != l_rc )
            {
                PRDF_ERR( PRDF_FUNC"Read() failed on %s", reg_str );
                break;
            }

            uint8_t galois = reg->GetBitFieldJustified( 40, 8 );
            uint8_t mask   = reg->GetBitFieldJustified( 32, 8 );

            CenSymbol symbol = CenSymbol::fromGalois( mbaTrgt, rank, galois,
                                                      mask );
            if ( !symbol.isValid() )
            {
                PRDF_ERR( PRDF_FUNC"Failed to create symbol: galois=0x%02x "
                          "mask=0x%02x", galois, mask );
                break;
            }

            // Check if this symbol is on any of the spares.
            CenSymbol sp0, sp1, ecc;
            l_rc = mssGetSteerMux( mbaTrgt, rank, sp0, sp1, ecc );
            if ( SUCCESS != l_rc )
            {
                PRDF_ERR( PRDF_FUNC"mssGetSteerMux() failed. HUID: 0x%08x "
                        "rank: %d", getHuid(mbaTrgt), rank.getMaster() );
                break;
            }
            if ( (sp0.isValid() && (sp0.getDram() == symbol.getDram())) ||
                 (sp1.isValid() && (sp1.getDram() == symbol.getDram())) )
            {
                symbol.setDramSpared();
            }
            if ( ecc.isValid() && (ecc.getDram() == symbol.getDram()) )
            {
                symbol.setEccSpared();
            }

            // Add the DIMM to the callout list
            MemoryMru memmru ( mbaTrgt, rank, symbol );
            i_sc.service_data->SetCallout( memmru, MRU_MEDA );

            // Add to CE table
            CenMbaDataBundle * mbadb = getMbaDataBundle( mbaChip );
            uint32_t ceTableRc = mbadb->iv_ceTable.addEntry( addr, symbol );
            bool doTps = ( CenMbaCeTable::NO_TH_REACHED != ceTableRc );

            // Check MNFG thresholds, if needed.
            if ( mfgMode() )
            {
                // Get the MNFG CE thresholds.
                uint16_t dramTh, hrTh, dimmTh;
                l_rc = getMnfgMemCeTh( mbaChip, rank, dramTh, hrTh, dimmTh );
                if ( SUCCESS != l_rc )
                {
                    PRDF_ERR( PRDF_FUNC"getMnfgMemCeTh() failed: rank=m%ds%d",
                              rank.getMaster(), rank.getSlave() );
                    break;
                }

                // Get counts from CE table.
                uint32_t dramCount, hrCount, dimmCount;
                mbadb->iv_ceTable.getMnfgCounts( addr.getRank(), symbol,
                                                 dramCount, hrCount,
                                                 dimmCount );

                if ( dramTh < dramCount )
                {
                    i_sc.service_data->AddSignatureList( mbaTrgt,
                                                         PRDFSIG_MnfgDramCte );
                    i_sc.service_data->SetServiceCall();
                    doTps = true;
                }
                else if ( hrTh < hrCount )
                {
                    i_sc.service_data->AddSignatureList( mbaTrgt,
                                                         PRDFSIG_MnfgHrCte );
                    i_sc.service_data->SetServiceCall();
                    doTps = true;
                }
                else if ( dimmTh < dimmCount )
                {
                    i_sc.service_data->AddSignatureList( mbaTrgt,
                                                         PRDFSIG_MnfgDimmCte );
                    i_sc.service_data->SetServiceCall();
                    doTps = true;
                }
                else if ( 0 != (CenMbaCeTable::TABLE_FULL & ceTableRc) )
                {
                    i_sc.service_data->AddSignatureList( mbaTrgt,
                                                         PRDFSIG_MnfgTableFull);

                    // The table is full and no other threshold has been met.
                    // We are in a state where we may never hit a MNFG
                    // threshold. Callout all memory behind the MBA. Also, since
                    // the counts are all over the place, there may be a problem
                    // with the MBA. So call it out as well.
                    MemoryMru all_mm ( mbaTrgt, rank,
                                       MemoryMruData::CALLOUT_ALL_MEM );
                    i_sc.service_data->SetCallout( all_mm,  MRU_MEDA );
                    i_sc.service_data->SetCallout( mbaTrgt, MRU_MEDA );
                    i_sc.service_data->SetServiceCall();
                }
                else if ( 0 != (CenMbaCeTable::ENTRY_TH_REACHED & ceTableRc) )
                {
                    i_sc.service_data->AddSignatureList( mbaTrgt,
                                                         PRDFSIG_MnfgEntryCte );

                    // There is a single entry threshold and no other threshold
                    // has been met. This is a potential flooding issue, so make
                    // the DIMM callout predictive.
                    i_sc.service_data->SetServiceCall();
                }
            }

            // Initiate a TPS procedure, if needed.
            if ( doTps )
            {
                // If a MNFG threshold has been reached (predictive callout), we
                // will still try to start TPS just in case MNFG disables the
                // termination policy.

                // Will not be able to do TPS during hostboot. Note that we will
                // still call handleTdEvent() so we can get the trace statement
                // indicating TPS was requested during Hostboot.

                l_rc = mbadb->iv_tdCtlr.handleTdEvent( i_sc, rank,
                                                CenMbaTdCtlrCommon::TPS_EVENT );
                if ( SUCCESS != l_rc )
                {
                    PRDF_ERR( PRDF_FUNC"handleTdEvent() failed: rank=m%ds%d",
                              rank.getMaster(), rank.getSlave() );
                    break;
                }
            }
        }

    } while (0);

    // Add ECC capture data for FFDC.
    if ( NULL != mbaChip )
        CenMbaCaptureData::addMemEccData( mbaChip, i_sc );

    if ( SUCCESS != l_rc )
    {
        PRDF_ERR( PRDF_FUNC"Failed: i_membChip=0x%08x i_mbaPos=%d",
                  i_membChip->GetId(), i_mbaPos );
        CalloutUtil::defaultError( i_sc );
    }

    return SUCCESS; // Intentionally return SUCCESS for this plugin

    #undef PRDF_FUNC
}