From 67499d6a3e8747725083398348f655dedc86b552 Mon Sep 17 00:00:00 2001 From: Caleb Palmer Date: Fri, 27 Apr 2018 14:20:47 -0500 Subject: PRD: Runtime VCM support for Centaur Change-Id: I0dc0361b4d258961e23ff43098261a47feb52834 RTC: 191847 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/58458 Tested-by: Jenkins Server Reviewed-by: Benjamin J. Weisenbeck Reviewed-by: Brian J. Stegmiller Reviewed-by: Zane C. Shelley Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/59235 Tested-by: Jenkins OP Build CI Tested-by: Jenkins OP HW Tested-by: FSP CI Jenkins --- .../diag/prdf/common/plat/cen/prdfCenMbaExtraSig.H | 4 + .../prdf/common/plat/mem/prdfCenMbaDataBundle.H | 16 ++ .../common/plat/pegasus/prdfCenMbaTdCtlr_common.C | 194 ----------------- .../prdf/common/plat/pegasus/prdfCenMbaTdCtlr_rt.C | 240 --------------------- src/usr/diag/prdf/plat/mem/prdfMemTdQueue.H | 5 + src/usr/diag/prdf/plat/mem/prdfMemVcm_rt.C | 170 ++++++++++++++- 6 files changed, 185 insertions(+), 444 deletions(-) diff --git a/src/usr/diag/prdf/common/plat/cen/prdfCenMbaExtraSig.H b/src/usr/diag/prdf/common/plat/cen/prdfCenMbaExtraSig.H index f094dccb8..7464ba1c6 100644 --- a/src/usr/diag/prdf/common/plat/cen/prdfCenMbaExtraSig.H +++ b/src/usr/diag/prdf/common/plat/cen/prdfCenMbaExtraSig.H @@ -32,6 +32,10 @@ PRDR_ERROR_SIGNATURE(CmdComplete_ERROR, 0xeeee0000, "", "ERROR: command complete analysis failed" ); +PRDR_ERROR_SIGNATURE(VcmResume, 0xbbbb0000, "", "VCM: Resuming procedure"); +PRDR_ERROR_SIGNATURE(TpsResume, 0xbbbb0001, "", "TPS: Resuming procedure"); +PRDR_ERROR_SIGNATURE(DsdResume, 0xbbbb0003, "", "DSD: Resuming procedure"); + PRDR_ERROR_SIGNATURE(MaintNCE_CTE, 0xbbbb0016, "", "Maint SOFT/INTER CTE"); PRDR_ERROR_SIGNATURE(VcmBadSpare, 0xbbbb0022, "", "VCM: bad DRAM spare"); diff --git a/src/usr/diag/prdf/common/plat/mem/prdfCenMbaDataBundle.H b/src/usr/diag/prdf/common/plat/mem/prdfCenMbaDataBundle.H index 88d502620..024a08ec3 100644 --- a/src/usr/diag/prdf/common/plat/mem/prdfCenMbaDataBundle.H +++ b/src/usr/diag/prdf/common/plat/mem/prdfCenMbaDataBundle.H @@ -74,6 +74,7 @@ class MbaDataBundle : public DataBundle #ifdef __HOSTBOOT_RUNTIME + delete iv_vcmFalseAlarmCounter; delete iv_tpsFalseAlarmCounter; #else // IPL only @@ -105,6 +106,18 @@ class MbaDataBundle : public DataBundle #ifdef __HOSTBOOT_RUNTIME + /** @return The VCM false alarm counter. */ + VcmFalseAlarm * getVcmFalseAlarmCounter() + { + if ( nullptr == iv_vcmFalseAlarmCounter ) + { + iv_vcmFalseAlarmCounter = new VcmFalseAlarm( + TimeBasedThreshold { 4, ThresholdResolution::ONE_DAY } ); + } + + return iv_vcmFalseAlarmCounter; + } + /** @return The TPS false alarm counter. */ TpsFalseAlarm * getTpsFalseAlarmCounter() { @@ -146,6 +159,9 @@ class MbaDataBundle : public DataBundle #ifdef __HOSTBOOT_RUNTIME + /** VCM false alarm counter. */ + VcmFalseAlarm * iv_vcmFalseAlarmCounter = nullptr; + /** TPS false alarm counter. */ TpsFalseAlarm * iv_tpsFalseAlarmCounter = nullptr; diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C index 8e81936e1..04a336e8d 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C @@ -43,200 +43,6 @@ using namespace PlatServices; //------------------------------------------------------------------------------ -int32_t CenMbaTdCtlrCommon::handleMCE_VCM2( STEP_CODE_DATA_STRUCT & io_sc ) -{ - #define PRDF_FUNC "[CenMbaTdCtlrCommon::handleMCE_VCM2] " - - using namespace fapi; // For spare config macros. - - int32_t o_rc = SUCCESS; - - iv_isEccSteer = false; - - do - { - if ( VCM_PHASE_2 != iv_tdState ) - { - PRDF_ERR( PRDF_FUNC "Invalid state machine configuration" ); - o_rc = FAIL; break; - } - - setTdSignature( io_sc, PRDFSIG_VcmVerified ); - - if ( areDramRepairsDisabled() ) - { - iv_tdState = NO_OP; // The TD procedure is complete. - - io_sc.service_data->setServiceCall(); - - break; // nothing else to do. - } - - // If there is a symbol mark on the same DRAM as the newly verified chip - // mark, remove the symbol mark. - const uint8_t cmDram = iv_mark.getCM().getDram(); - if ( cmDram == iv_mark.getSM().getDram() ) - { - iv_mark.clearSM(); - bool blocked; // Won't be blocked because chip mark is in place. - o_rc = mssSetMarkStore( iv_mbaTrgt, iv_rank, iv_mark, blocked ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "mssSetMarkStore() failed" ); - break; - } - } - - bool startDsdProcedure = false; - - // Read VPD. - CenDqBitmap bitmap; - o_rc = getBadDqBitmap( iv_mbaTrgt, iv_rank, bitmap ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "getBadDqBitmap() failed" ); - break; - } - - // The chip mark is considered verified, so set it in VPD. - o_rc = bitmap.setDram( iv_mark.getCM() ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "setDram() failed" ); - break; - } - - uint8_t ps = iv_mark.getCM().getPortSlct(); - uint8_t spareConfig = ENUM_ATTR_VPD_DIMM_SPARE_NO_SPARE; - o_rc = getDimmSpareConfig( iv_mbaTrgt, iv_rank, ps, - spareConfig ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "getDimmSpareConfig() failed" ); - break; - } - - // Check if DRAM spare is present. Also, ECC spares are available on all - // x4 DIMMS. - if ( ( ENUM_ATTR_VPD_DIMM_SPARE_NO_SPARE != spareConfig ) || iv_x4Dimm ) - { - // Get the current spares in hardware. - CenSymbol sp0, sp1, ecc; - o_rc = mssGetSteerMux( iv_mbaTrgt, iv_rank, sp0, sp1, ecc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "mssGetSteerMux() failed" ); - break; - } - - // If the verified chip mark is on a spare then the spare is bad and - // hardware can not steer it to another DRAM even if one is - // available (e.g. ECC spare). In this this case, make error log - // predictive (remember that the chip mark has already been added to - // the callout list. - if ( ( cmDram == (0 == ps ? sp0.getDram() : sp1.getDram()) ) || - ( cmDram == ecc.getDram() ) ) - { - setTdSignature( io_sc, PRDFSIG_VcmBadSpare ); - io_sc.service_data->setServiceCall(); - } - else - { - // Certain DIMMs may have had spares intentially made - // unavailable by the manufacturer. Check the VPD for available - // spares. Note that a x4 DIMM has DRAM spares and ECC spares, - // so check for availability on both. - bool dramSparePossible = false; - bool eccSparePossible = false; - o_rc = bitmap.isSpareAvailable( ps, dramSparePossible, - eccSparePossible ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "isDramSpareAvailable() failed" ); - break; - } - - if ( dramSparePossible && - (0 == ps ? !sp0.isValid() : !sp1.isValid()) ) - { - // A spare DRAM is available. - startDsdProcedure = true; - } - else if ( eccSparePossible && !ecc.isValid() ) - { - startDsdProcedure = true; - iv_isEccSteer = true; - } - else - { - // Chip mark is in place and sparing is not possible. - setTdSignature( io_sc, PRDFSIG_VcmCmAndSpare ); - io_sc.service_data->setServiceCall(); - - // The mark has already been added to the callout list. - // Callout the used spares, if they exists. - if ( sp0.isValid() ) - { - MemoryMru memmru ( iv_mbaTrgt, iv_rank, sp0 ); - io_sc.service_data->SetCallout( memmru ); - } - if ( sp1.isValid() ) - { - MemoryMru memmru ( iv_mbaTrgt, iv_rank, sp1 ); - io_sc.service_data->SetCallout( memmru ); - } - if ( ecc.isValid() ) - { - MemoryMru memmru ( iv_mbaTrgt, iv_rank, ecc ); - io_sc.service_data->SetCallout( memmru ); - } - } - } - } - else // DRAM spare not supported. - { - // Not able to do dram sparing. If there is a symbol mark, there are - // no repairs available so call it out and set the error log to - // predictive. - if ( iv_mark.getSM().isValid() ) - { - setTdSignature( io_sc, PRDFSIG_VcmCmAndSm ); - io_sc.service_data->setServiceCall(); - } - } - - // Write VPD. - o_rc = setBadDqBitmap( iv_mbaTrgt, iv_rank, bitmap ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "setBadDqBitmap() failed" ); - break; - } - - // Start DSD Phase 1, if possible. - if ( startDsdProcedure ) - { - o_rc = startDsdPhase1( io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "startDsdPhase1() failed" ); - break; - } - } - else - { - iv_tdState = NO_OP; // The TD procedure is complete. - } - - } while(0); - - return o_rc; - - #undef PRDF_FUNC -} - -//------------------------------------------------------------------------------ - int32_t CenMbaTdCtlrCommon::handleMCE_DSD2( STEP_CODE_DATA_STRUCT & io_sc ) { #define PRDF_FUNC "[CenMbaTdCtlrCommon::handleMCE_DSD2] " diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_rt.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_rt.C index f3ee6884f..a2bc9ca83 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_rt.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_rt.C @@ -76,246 +76,6 @@ CenMbaTdCtlr::FUNCS CenMbaTdCtlr::cv_cmdCompleteFuncs[] = // Private Functions //------------------------------------------------------------------------------ -int32_t CenMbaTdCtlr::analyzeVcmPhase1( STEP_CODE_DATA_STRUCT & io_sc, - const CenAddr & i_stopAddr, - const CenAddr & i_endAddr ) -{ - #define PRDF_FUNC "[CenMbaTdCtlr::analyzeVcmPhase1] " - - int32_t o_rc = SUCCESS; - - do - { - if ( VCM_PHASE_1 != iv_tdState ) - { - PRDF_ERR( PRDF_FUNC "Invalid state machine configuration" ); - o_rc = FAIL; break; - } - - // Add the mark to the callout list. - CalloutUtil::calloutMark( iv_mbaTrgt, iv_rank, iv_mark, io_sc ); - - // Check for any ECC errors that occurred during the procedure. - uint16_t eccErrorMask = NO_ERROR; - o_rc = checkEccErrors( eccErrorMask, io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "checkEccErrors() failed" ); - break; - } - - if ( eccErrorMask & UE ) - { - o_rc = handleUe_Td( io_sc, i_stopAddr ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "handleUe_Td() failed" ); - break; - } - - // Abort the procedure. - iv_tdState = NO_OP; - break; - } - - if ( eccErrorMask & RETRY_CTE ) - { - o_rc = handleRceEte_Td( io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "handleRceEte_Td() failed" ); - break; - } - } - - // If the scrub stopped on the last address of the rank, start the next - // TD procedure. Otherwise, resume background scrubbing. This is needed - // for attentions like retry CTEs where, due to a hardware issue, must - // report the attention immediately and cannot wait for the scrub to get - // to the end of the rank. - - if ( i_endAddr == i_stopAddr ) - { - // Start VCM Phase 2 - o_rc = startVcmPhase2( io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "startVcmPhase2() failed" ); - break; - } - } - else - { - // Restart the scrub on the next address. - o_rc = resumeScrub( io_sc, eccErrorMask ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "resumeScrub() failed" ); - break; - } - } - - } while(0); - - // If this TD procedure was aborted, execute TD complete sequence. - if ( (iv_tdState == NO_OP) && (SUCCESS == o_rc) ) - { - o_rc = handleTdComplete( io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "handleTdComplete() failed" ); - } - } - - return o_rc; - - #undef PRDF_FUNC -} - -//------------------------------------------------------------------------------ - -int32_t CenMbaTdCtlr::analyzeVcmPhase2( STEP_CODE_DATA_STRUCT & io_sc, - const CenAddr & i_stopAddr, - const CenAddr & i_endAddr ) -{ - #define PRDF_FUNC "[CenMbaTdCtlr::analyzeVcmPhase2] " - - int32_t o_rc = SUCCESS; - - do - { - if ( VCM_PHASE_2 != iv_tdState ) - { - PRDF_ERR( PRDF_FUNC "Invalid state machine configuration" ); - o_rc = FAIL; break; - } - - // Add the mark to the callout list. - CalloutUtil::calloutMark( iv_mbaTrgt, iv_rank, iv_mark, io_sc ); - - // Check for any ECC errors that occurred during the procedure. - uint16_t eccErrorMask = NO_ERROR; - o_rc = checkEccErrors( eccErrorMask, io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "checkEccErrors() failed" ); - break; - } - - if ( eccErrorMask & UE ) - { - o_rc = handleUe_Td( io_sc, i_stopAddr ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "handleUe_Td() failed" ); - break; - } - - // Abort the procedure. - iv_tdState = NO_OP; - break; - } - - if ( eccErrorMask & RETRY_CTE ) - { - o_rc = handleRceEte_Td( io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "handleRceEte_Td() failed" ); - break; - } - } - - if ( eccErrorMask & MCE ) - { - // Chip mark is verified. - // Do callouts, VPD updates, and start DRAM sparing, if possible. - o_rc = handleMCE_VCM2( io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "handleMCE_VCM2() failed" ); - break; - } - } - else if ( i_endAddr == i_stopAddr ) - { - // Chip mark verification failed. - setTdSignature( io_sc, PRDFSIG_VcmFalseAlarm ); - - // In manufacturing, this error log will be predictive. - if ( areDramRepairsDisabled() ) - { - io_sc.service_data->setServiceCall(); - iv_tdState = NO_OP; // Move on to the next TD procedure. - break; - } - - // Increment the false alarm count and threshold. if needed. - if ( iv_vcmRankData.incFalseAlarm(iv_rank, io_sc) ) - { - io_sc.service_data->AddSignatureList( iv_mbaTrgt, - PRDFSIG_VcmFalseAlarmExceeded ); - - // Treat the chip mark as verified. - o_rc = handleMCE_VCM2( io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "handleMCE_VCM2() failed" ); - } - } - else - { - // Remove chip mark from hardware. - iv_mark.clearCM(); - - // There is small time window where hardware places a chip mark - // immediately after it is removed, but before the HWP procedure - // can query the FIR registers. In this case, we will simply - // allow the write to be 'blocked' and handle the new chip mark - // in a separate attention. - bool allowWriteBlocked = true; - bool blocked; // Currently ignored. - o_rc = mssSetMarkStore( iv_mbaTrgt, iv_rank, iv_mark, blocked, - allowWriteBlocked ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "mssSetMarkStore() failed" ); - break; - } - - iv_tdState = NO_OP; // Move on to the next TD procedure. - } - } - else - { - // Restart the scrub on the next address. - o_rc = resumeScrub( io_sc, eccErrorMask ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "resumeScrub() failed" ); - break; - } - } - - } while(0); - - // If this TD procedure was aborted, execute TD complete sequence. - if ( (iv_tdState == NO_OP) && (SUCCESS == o_rc) ) - { - o_rc = handleTdComplete( io_sc ); - if ( SUCCESS != o_rc ) - { - PRDF_ERR( PRDF_FUNC "handleTdComplete() failed" ); - } - } - - return o_rc; - - #undef PRDF_FUNC -} - -//------------------------------------------------------------------------------ - int32_t CenMbaTdCtlr::analyzeDsdPhase1( STEP_CODE_DATA_STRUCT & io_sc, const CenAddr & i_stopAddr, const CenAddr & i_endAddr ) diff --git a/src/usr/diag/prdf/plat/mem/prdfMemTdQueue.H b/src/usr/diag/prdf/plat/mem/prdfMemTdQueue.H index 5e4d32454..56254abe3 100755 --- a/src/usr/diag/prdf/plat/mem/prdfMemTdQueue.H +++ b/src/usr/diag/prdf/plat/mem/prdfMemTdQueue.H @@ -150,6 +150,11 @@ class TdEntry // used for displaying FFDC in the TD controller. const MemRank iv_rank; ///< The rank in which this event occurred. + #ifdef __HOSTBOOT_RUNTIME + /** True if the current TD command can be resumed, false otherwise. Resume + * only supported for MBA at this time. */ + bool iv_canResumeScrub = false; + #endif }; //------------------------------------------------------------------------------ diff --git a/src/usr/diag/prdf/plat/mem/prdfMemVcm_rt.C b/src/usr/diag/prdf/plat/mem/prdfMemVcm_rt.C index b7cb13653..122c54367 100644 --- a/src/usr/diag/prdf/plat/mem/prdfMemVcm_rt.C +++ b/src/usr/diag/prdf/plat/mem/prdfMemVcm_rt.C @@ -29,6 +29,8 @@ #include #include #include +#include +#include using namespace TARGETING; @@ -55,9 +57,7 @@ VcmFalseAlarm * __getFalseAlarmCounter( ExtensibleChip * i_chip ) template<> VcmFalseAlarm * __getFalseAlarmCounter( ExtensibleChip * i_chip ) { - // TODO: RTC 157888 - //return getMbaDataBundle(i_chip)->getVcmFalseAlarmCounter(); - return nullptr; + return getMbaDataBundle(i_chip)->getVcmFalseAlarmCounter(); } //############################################################################## @@ -232,12 +232,26 @@ uint32_t VcmEvent::startCmd() if ( TD_PHASE_2 == iv_phase ) stopCond |= mss_MaintCmd::STOP_ON_MCE; - // Start the time based scrub procedure on this master rank. - o_rc = startTdScrub( iv_chip, iv_rank, MASTER_RANK, stopCond ); - if ( SUCCESS != o_rc ) + if ( iv_canResumeScrub ) { - PRDF_ERR( PRDF_FUNC "startTdScrub(0x%08x,0x%2x) failed", - iv_chip->getHuid(), getKey() ); + // Resume the command from the next address to the end of this master + // rank. + o_rc = resumeTdScrub( iv_chip, MASTER_RANK, stopCond ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "resumeTdScrub(0x%08x) failed", + iv_chip->getHuid() ); + } + } + else + { + // Start the time based scrub procedure on this master rank. + o_rc = startTdScrub( iv_chip, iv_rank, MASTER_RANK, stopCond); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "startTdScrub(0x%08x,0x%2x) failed", + iv_chip->getHuid(), getKey() ); + } } return o_rc; @@ -247,6 +261,48 @@ uint32_t VcmEvent::startCmd() //------------------------------------------------------------------------------ +template<> +uint32_t VcmEvent::startNextPhase( STEP_CODE_DATA_STRUCT & io_sc ) +{ + uint32_t signature = 0; + + if ( iv_canResumeScrub ) + { + signature = PRDFSIG_VcmResume; + + PRDF_TRAC( "[VcmEvent] Resuming VCM Phase %d: 0x%08x,0x%02x", + iv_phase, iv_chip->getHuid(), getKey() ); + } + else + { + switch ( iv_phase ) + { + case TD_PHASE_0: + iv_phase = TD_PHASE_1; + signature = PRDFSIG_StartVcmPhase1; + break; + + case TD_PHASE_1: + iv_phase = TD_PHASE_2; + signature = PRDFSIG_StartVcmPhase2; + break; + + default: PRDF_ASSERT( false ); // invalid phase + } + + PRDF_TRAC( "[VcmEvent] Starting VCM Phase %d: 0x%08x,0x%02x", + iv_phase, iv_chip->getHuid(), getKey() ); + } + + io_sc.service_data->AddSignatureList( iv_chip->getTrgt(), signature ); + + return startCmd(); + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + template<> uint32_t VcmEvent::checkEcc( const uint32_t & i_eccAttns, STEP_CODE_DATA_STRUCT & io_sc, @@ -277,10 +333,8 @@ uint32_t VcmEvent::checkEcc( const uint32_t & i_eccAttns, break; } - /* TODO: RTC 157888 o_rc = MemEcc::handleMemUe( iv_chip, addr, UE_TABLE::SCRUB_UE, io_sc ); - */ if ( SUCCESS != o_rc ) { PRDF_ERR( PRDF_FUNC "handleMemUe(0x%08x,0x%02x) failed", @@ -313,6 +367,102 @@ uint32_t VcmEvent::checkEcc( const uint32_t & i_eccAttns, #undef PRDF_FUNC } +//------------------------------------------------------------------------------ + +template<> +uint32_t VcmEvent::analyzePhase( STEP_CODE_DATA_STRUCT & io_sc, + bool & o_done ) +{ + #define PRDF_FUNC "[VcmEvent::analyzePhase] " + + uint32_t o_rc = SUCCESS; + + do + { + if ( TD_PHASE_0 == iv_phase ) break; // Nothing to analyze yet. + + // Look for any ECC errors that occurred during the command. + uint32_t eccAttns; + o_rc = checkEccFirs( iv_chip, eccAttns ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "checkEccFirs(0x%08x) failed", + iv_chip->getHuid() ); + break; + } + + // Analyze the ECC errors, if needed. + o_rc = checkEcc( eccAttns, io_sc, o_done ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "checkEcc() failed on 0x%08x", + iv_chip->getHuid() ); + break; + } + + if ( o_done ) break; // abort the procedure. + + // Determine if the command stopped on the last address. + bool lastAddr = false; + o_rc = didCmdStopOnLastAddr( iv_chip, MASTER_RANK, lastAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "didCmdStopOnLastAddr(0x%08x) failed", + iv_chip->getHuid() ); + break; + } + + // It is important to initialize iv_canResumeScrub here, so that we will + // know to resume the current phase in startNextPhase() instead of + // starting phase. + iv_canResumeScrub = !lastAddr; + + if ( TD_PHASE_2 == iv_phase ) + { + if ( eccAttns & MAINT_MCE ) + { + // The chip mark has been verified. + o_rc = verified( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "verified() failed on 0x%08x", + iv_chip->getHuid() ); + break; + } + + // Procedure is complete. + o_done = true; + } + else if ( !iv_canResumeScrub ) + { + // The chip mark is not verified and the command has reached the + // end of the rank. So this is a false alarm. + o_rc = falseAlarm( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "falseAlarm() failed on 0x%08x", + iv_chip->getHuid() ); + break; + } + + // Procedure is complete. + o_done = true; + } + } + + } while (0); + + if ( (SUCCESS == o_rc) && o_done ) + { + // Clear the ECC FFDC for this master rank. + MemDbUtils::resetEccFfdc( iv_chip, iv_rank, MASTER_RANK ); + } + + return o_rc; + + #undef PRDF_FUNC +} + //############################################################################## // // Generic template functions -- cgit v1.2.1