summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZane Shelley <zshelle@us.ibm.com>2013-04-27 22:12:56 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2013-06-11 09:11:25 -0500
commit25a05966a93786736212b4f35aa84929423a48e4 (patch)
tree3be7d985ec3938b43671ff01e93ff8db5eae9de1
parentbb2e9e1adac63e8b12c881b546b757f8d8de5697 (diff)
downloadtalos-hostboot-25a05966a93786736212b4f35aa84929423a48e4.tar.gz
talos-hostboot-25a05966a93786736212b4f35aa84929423a48e4.zip
PRD: TD controller for MDIA
Change-Id: I6453a1fef37cbd7f9d3c105af8349688ad62c0c2 RTC: 22866 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/4248 Tested-by: Jenkins Server Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com> Reviewed-by: Zane Shelley <zshelle@us.ibm.com> Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/4935
-rw-r--r--src/usr/diag/mdia/mdiasm.C8
-rwxr-xr-xsrc/usr/diag/prdf/common/framework/rule/prdrpp6
-rwxr-xr-xsrc/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C84
-rwxr-xr-xsrc/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H37
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/pegasus/Mba.rule24
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule32
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C20
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H20
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H6
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C36
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H8
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C76
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H11
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H48
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C104
-rw-r--r--src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H212
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C40
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H15
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C3
-rwxr-xr-xsrc/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H3
-rwxr-xr-xsrc/usr/diag/prdf/common/prd_pegasus.mk10
-rw-r--r--src/usr/diag/prdf/framework/service/prdfPlatServices.C36
-rw-r--r--src/usr/diag/prdf/framework/service/prdfPlatServices.H12
-rw-r--r--src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H6
-rw-r--r--src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C1342
-rw-r--r--src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H174
-rw-r--r--src/usr/diag/prdf/test/prdfTest_Mba.H22
27 files changed, 2252 insertions, 143 deletions
diff --git a/src/usr/diag/mdia/mdiasm.C b/src/usr/diag/mdia/mdiasm.C
index 512a20265..893fffcda 100644
--- a/src/usr/diag/mdia/mdiasm.C
+++ b/src/usr/diag/mdia/mdiasm.C
@@ -585,8 +585,12 @@ errlHndl_t StateMachine::doMaintCommand(WorkFlowProperties & i_wfp)
uint64_t timeout = 60000000000;
errlHndl_t err = NULL;
- uint64_t stopCondition = mss_MaintCmd::STOP_ON_END_ADDRESS
- | mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION;
+ uint64_t stopCondition =
+ mss_MaintCmd::STOP_END_OF_RANK |
+ mss_MaintCmd::STOP_ON_MPE |
+ mss_MaintCmd::STOP_ON_UE |
+ mss_MaintCmd::STOP_ON_END_ADDRESS |
+ mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION;
uint64_t workItem;
bool restart;
diff --git a/src/usr/diag/prdf/common/framework/rule/prdrpp b/src/usr/diag/prdf/common/framework/rule/prdrpp
index 058e5f4b5..fab66e381 100755
--- a/src/usr/diag/prdf/common/framework/rule/prdrpp
+++ b/src/usr/diag/prdf/common/framework/rule/prdrpp
@@ -50,11 +50,15 @@ sub read_file
open_file($include);
print ".end_included\n";
}
+ elsif ( $line =~ m{/\*[^\*].*\*/} )
+ {
+ # Skip C-style (/* */) comments. This is needed to avoid prologs
+ # added to the extra signature .H files.
+ }
else
{
print $line;
}
-
}
}
diff --git a/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C b/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C
index 20a4cdea8..0d77d3aaa 100755
--- a/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C
+++ b/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C
@@ -60,6 +60,14 @@ namespace PlatServices
{
//##############################################################################
+//## Forward references
+//##############################################################################
+
+int32_t getMemAddrRange( TargetHandle_t i_mba, uint8_t i_rank,
+ ecmdDataBufferBase & o_startAddr,
+ ecmdDataBufferBase & o_endAddr );
+
+//##############################################################################
//## Utility Functions (for this file only)
//##############################################################################
@@ -289,22 +297,25 @@ int32_t setBadDqBitmap( TargetHandle_t i_mba, const CenRank & i_rank,
int32_t o_rc = SUCCESS;
- const uint8_t (&data)[PORT_SLCT_PER_MBA][DIMM_DQ_RANK_BITMAP_SIZE]
+ if ( !areDramRepairsDisabled() )
+ {
+ const uint8_t (&data)[PORT_SLCT_PER_MBA][DIMM_DQ_RANK_BITMAP_SIZE]
= i_bitmap.getData();
- for ( int32_t ps = 0; ps < PORT_SLCT_PER_MBA; ps++ )
- {
- errlHndl_t errl = NULL;
- PRD_FAPI_TO_ERRL( errl, dimmSetBadDqBitmap, getFapiTarget(i_mba),
- ps, i_rank.getDimmSlct(), i_rank.getRankSlct(),
- data[ps] );
- if ( NULL != errl )
+ for ( int32_t ps = 0; ps < PORT_SLCT_PER_MBA; ps++ )
{
- PRDF_ERR( PRDF_FUNC"dimmSetBadDqBitmap() failed: MBA=0x%08x "
- "ps=%d ds=%d rs=%d", getHuid(i_mba), ps,
- i_rank.getDimmSlct(), i_rank.getRankSlct() );
- PRDF_COMMIT_ERRL( errl, ERRL_ACTION_REPORT );
- o_rc = FAIL;
+ errlHndl_t errl = NULL;
+ PRD_FAPI_TO_ERRL( errl, dimmSetBadDqBitmap, getFapiTarget(i_mba),
+ ps, i_rank.getDimmSlct(), i_rank.getRankSlct(),
+ data[ps] );
+ if ( NULL != errl )
+ {
+ PRDF_ERR( PRDF_FUNC"dimmSetBadDqBitmap() failed: MBA=0x%08x "
+ "ps=%d ds=%d rs=%d", getHuid(i_mba), ps,
+ i_rank.getDimmSlct(), i_rank.getRankSlct() );
+ PRDF_COMMIT_ERRL( errl, ERRL_ACTION_REPORT );
+ o_rc = FAIL;
+ }
}
}
@@ -445,6 +456,48 @@ int32_t mssSetSteerMux( TargetHandle_t i_mba, const CenRank & i_rank,
//------------------------------------------------------------------------------
+int32_t getMemAddrRange( TargetHandle_t i_mba, CenAddr & o_startAddr,
+ CenAddr & o_endAddr )
+{
+ ecmdDataBufferBase startAddr(64), endAddr(64);
+ int32_t o_rc = getMemAddrRange( i_mba, MSS_ALL_RANKS, startAddr, endAddr );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( "[PlatServices::getMemAddrRange] failed: i_mba=0x%08x",
+ getHuid(i_mba) );
+ }
+ else
+ {
+ o_startAddr = CenAddr::fromMaintStartAddr( startAddr.getDoubleWord(0) );
+ o_endAddr = CenAddr::fromMaintEndAddr( endAddr.getDoubleWord(0) );
+ }
+
+ return o_rc;
+}
+
+//------------------------------------------------------------------------------
+
+int32_t getMemAddrRange( TargetHandle_t i_mba, const CenRank & i_rank,
+ CenAddr & o_startAddr, CenAddr & o_endAddr )
+{
+ ecmdDataBufferBase startAddr(64), endAddr(64);
+ int32_t o_rc = getMemAddrRange(i_mba, i_rank.flatten(), startAddr, endAddr);
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( "[PlatServices::getMemAddrRange] failed: i_mba=0x%08x "
+ "i_rank=%d", getHuid(i_mba), i_rank.flatten() );
+ }
+ else
+ {
+ o_startAddr = CenAddr::fromMaintStartAddr( startAddr.getDoubleWord(0) );
+ o_endAddr = CenAddr::fromMaintEndAddr( endAddr.getDoubleWord(0) );
+ }
+
+ return o_rc;
+}
+
+//------------------------------------------------------------------------------
+
/* TODO - Get the memory buffer raw card type (i.e. R/C A). This is needed for
the DRAM site locations for buffered DIMMs. Should be able to get this
from an attribute but doesn't look like this is available yet.
@@ -673,8 +726,9 @@ mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType,
//------------------------------------------------------------------------------
mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType,
- TargetHandle_t i_mba, uint32_t i_stopCond,
- bool i_isFastSpeed, const CenRank & i_rank )
+ TargetHandle_t i_mba,
+ const CenRank & i_rank, uint32_t i_stopCond,
+ bool i_isFastSpeed )
{
mss_MaintCmdWrapper * o_cmd = NULL;
diff --git a/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H b/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H
index 24d975b38..51fb8c1b9 100755
--- a/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H
+++ b/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H
@@ -55,6 +55,7 @@
namespace PRDF
{
+class CenAddr;
class CenDqBitmap;
class CenMark;
class CenRank;
@@ -208,6 +209,7 @@ int32_t getBadDqBitmap( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank,
* @param i_mbaTarget A MBA target.
* @param i_rank Target rank.
* @param i_bitmap DQ bitmap container.
+ * @note This is a no-op if DRAM Repairs are disabled in manufacturing.
* @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
*/
int32_t setBadDqBitmap( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank,
@@ -271,6 +273,28 @@ int32_t mssSetSteerMux( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank,
const CenSymbol & i_symbol, bool i_x4EccSpare );
/**
+ * @brief Returns the start and end maintenance address of the given MBA.
+ * @param i_mba Target MBA.
+ * @param o_startAddr The return start address.
+ * @param o_endAddr The return end address.
+ * @return Non-SUCCESS in internal function fails, SUCCESS otherwise.
+ */
+int32_t getMemAddrRange( TARGETING::TargetHandle_t i_mba, CenAddr & o_startAddr,
+ CenAddr & o_endAddr );
+
+/**
+ * @brief Returns the start and end maintenance address of the given rank.
+ * @param i_mba Target MBA.
+ * @param i_rank Target rank.
+ * @param o_startAddr The return start address.
+ * @param o_endAddr The return end address.
+ * @return Non-SUCCESS in internal function fails, SUCCESS otherwise.
+ */
+int32_t getMemAddrRange( TARGETING::TargetHandle_t i_mba,
+ const CenRank & i_rank, CenAddr & o_startAddr,
+ CenAddr & o_endAddr );
+
+/**
* @brief Returns the memory buffer raw card type (i.e. R/C A).
* @param i_memTarget A memory buffer, MBA, or DIMM.
* @return
@@ -362,7 +386,7 @@ class mss_MaintCmdWrapper
* @param i_cmdType Maintenance command type which we want to create.
* @param i_mba An MBA target.
* @param i_stopCond Bit mask for conditions in which to stop command.
- * @param i_isFastSpeed false = slow (12 H), true = fast.
+ * @param i_isFastSpeed false = slow (12 H), true = fast (default).
* @return A mss_MaintCmdWrapper object, NULL if an internal function failed.
* @note This function allocates memory on heap for mss_MaintCmdWrapper
* object. It is the caller's responsibilty to delete this object.
@@ -370,16 +394,17 @@ class mss_MaintCmdWrapper
*/
mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType,
TARGETING::TargetHandle_t i_mba,
- uint32_t i_stopCond, bool i_isFastSpeed );
+ uint32_t i_stopCond,
+ bool i_isFastSpeed = true );
/**
* @brief Create a maintenance command object that will run on all memory
* behind the given rank.
* @param i_cmdType Maintenance command type which we want to create.
+ * @param i_rank The target rank.
* @param i_mba An MBA target.
* @param i_stopCond Bit mask for conditions in which to stop command.
- * @param i_isFastSpeed false = slow (12 H), true = fast.
- * @param i_rank The target rank.
+ * @param i_isFastSpeed false = slow (12 H), true = fast (default).
* @return A mss_MaintCmdWrapper object, NULL if an internal function failed.
* @note This function allocates memory on heap for mss_MaintCmdWrapper
* object. It is the caller's responsibilty to delete this object.
@@ -387,8 +412,8 @@ mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType,
*/
mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType,
TARGETING::TargetHandle_t i_mba,
- uint32_t i_stopCond, bool i_isFastSpeed,
- const CenRank & i_rank );
+ const CenRank & i_rank, uint32_t i_stopCond,
+ bool i_isFastSpeed = true );
} // end namespace PlatServices
diff --git a/src/usr/diag/prdf/common/plat/pegasus/Mba.rule b/src/usr/diag/prdf/common/plat/pegasus/Mba.rule
index d09d63997..438f483be 100755
--- a/src/usr/diag/prdf/common/plat/pegasus/Mba.rule
+++ b/src/usr/diag/prdf/common/plat/pegasus/Mba.rule
@@ -44,6 +44,8 @@ chip Mba
dump DUMP_CONTENT_HWSUPERNOVA;
scomlen 64;
+.include "prdfCenMbaExtraSig.H";
+
#############################################################################
# #
# ###### #
@@ -120,6 +122,13 @@ chip Mba
capture group FirRegs;
};
+ register MBADDRPHYFIR_AND
+ {
+ name "DPHY01.PHY01_DDRPHY_FIR_REG_AND";
+ scomaddr 0x800200910301143F;
+ capture group never;
+ };
+
register MBADDRPHYFIR_MASK
{
name "DPHY01.PHY01_DDRPHY_FIR_MASK_REG";
@@ -190,11 +199,17 @@ chip Mba
name "MBU.MBA01.MBA_MCBIST.SCOMFIR.MBSPAQ";
scomaddr 0x03010611;
reset (&, 0x03010612);
- #FIXME : There is no OR register for mask. Is it right to use mask register value
mask (|, 0x03010614);
capture group FirRegs;
};
+ register MBASPA_AND
+ {
+ name "MBU.MBA01.MBA_MCBIST.SCOMFIR.MBSPAQ_AND";
+ scomaddr 0x03010612;
+ capture group never;
+ };
+
register MBASPA_MASK
{
name "MBU.MBA01.MBA_MCBIST.SCOMFIR.MBSPAMSKQ";
@@ -221,7 +236,6 @@ chip Mba
capture group CerrRegs;
};
-
register DDRPHY_APB_FIR_ERR0_P0
{
name "DPHY01.DDRPHY_APB_FIR_ERR0_P0";
@@ -796,5 +810,9 @@ group gMbaSpa attntype SPECIAL filter singlebit
################################################################################
/** Analyze maintenance command complete */
-actionclass analyzeMaintCmdComplete { funccall("MaintCmdComplete"); };
+actionclass analyzeMaintCmdComplete
+{
+ funccall("MaintCmdComplete"); # Must be called last so return code can be
+ # passed on to rule code.
+};
diff --git a/src/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule b/src/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule
index 668f49be3..7bf027415 100755
--- a/src/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule
+++ b/src/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule
@@ -228,6 +228,13 @@
capture group FirRegs;
};
+ register MBSECC01FIR_AND
+ {
+ name "MBU.MBS.ECC01.MBECCFIR_AND";
+ scomaddr 0x02011441;
+ capture group never;
+ };
+
register MBSECC01FIR_MASK
{
name "MBU.MBS.ECC01.MBECCFIR_MASK";
@@ -269,6 +276,13 @@
capture group FirRegs;
};
+ register MBSECC23FIR_AND
+ {
+ name "MBU.MBS.ECC23.MBECCFIR_AND";
+ scomaddr 0x02011481;
+ capture group never;
+ };
+
register MBSECC23FIR_MASK
{
name "MBU.MBS.ECC23.MBECCFIR_MASK";
@@ -599,3 +613,21 @@
capture group default;
};
+ ############################################################################
+ # NEST Chiplet memory scrub/read threshold register
+ ############################################################################
+
+ register MBSTR_0
+ {
+ name "MBU.MBS.MCBISTS01.SCOMFIR.MBSTRQ";
+ scomaddr 0x02011655;
+ capture group default;
+ };
+
+ register MBSTR_1
+ {
+ name "MBU.MBS.MCBISTS23.SCOMFIR.MBSTRQ";
+ scomaddr 0x02011755;
+ capture group default;
+ };
+
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C
index 39917a826..a7ca03cb7 100644
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C
@@ -27,6 +27,7 @@
#include <iipServiceDataCollector.h>
#include <prdfCenAddress.H>
+#include <prdfCenMarkstore.H>
#include <prdfPlatServices.H>
#include <prdfTrace.H>
@@ -49,6 +50,25 @@ void defaultError( STEP_CODE_DATA_STRUCT & i_sc )
//------------------------------------------------------------------------------
+void calloutMark( TargetHandle_t i_mba, const CenRank & i_rank,
+ const CenMark & i_mark, STEP_CODE_DATA_STRUCT & io_sc,
+ PRDpriority i_priority )
+{
+ if ( i_mark.getCM().isValid() )
+ {
+ MemoryMru memmru ( i_mba, i_rank, i_mark.getCM() );
+ io_sc.service_data->SetCallout( memmru, i_priority );
+ }
+
+ if ( i_mark.getSM().isValid() )
+ {
+ MemoryMru memmru ( i_mba, i_rank, i_mark.getSM() );
+ io_sc.service_data->SetCallout( memmru, i_priority );
+ }
+}
+
+//------------------------------------------------------------------------------
+
TargetHandleList getConnectedDimms( TargetHandle_t i_mba,
const CenRank & i_rank )
{
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H
index ff4f97baf..0bf1a6863 100644
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H
@@ -24,15 +24,18 @@
#ifndef prdfCalloutUtil_H
#define prdfCalloutUtil_H
-#include <prdfPlatServices.H>
-
/** @file prdfCalloutUtil.H
* @brief Utility functions for common, non-trivial callouts.
*/
+#include <prdfPlatServices.H>
+
+#include <prdfCallouts.H>
+
namespace PRDF
{
+class CenMark;
class CenRank;
struct STEP_CODE_DATA_STRUCT;
@@ -48,6 +51,19 @@ namespace CalloutUtil
void defaultError( STEP_CODE_DATA_STRUCT & i_sc );
/**
+ * @brief Will add a MemoryMru to the callout list for the chip mark and symbol
+ * mark, if they exist.
+ * @param i_mba Target MBA.
+ * @param i_rank Target rank.
+ * @param i_mark Target mark.
+ * @param io_sc The step code data struct.
+ * @param i_priority Callout priority (default MRU_MED).
+ */
+void calloutMark( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank,
+ const CenMark & i_mark, STEP_CODE_DATA_STRUCT & io_sc,
+ PRDpriority i_priority = MRU_MED );
+
+/**
* @param i_mba The target MBA.
* @param i_rank The target rank.
* @return A list of DIMMs connected to the MBA and rank.
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H
index 8d31d928b..4360da5b2 100644
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H
@@ -48,6 +48,12 @@ enum
SYMBOLS_PER_BYTE = 4,
DQS_PER_SYMBOL = 2,
DQS_PER_BYTE = SYMBOLS_PER_BYTE * DQS_PER_SYMBOL,
+
+ SYMBOLS_PER_X8DRAM = 4,
+ SYMBOLS_PER_X4DRAM = 2,
+
+ X8DRAMS_PER_RANK = SYMBOLS_PER_RANK / SYMBOLS_PER_X8DRAM,
+ X4DRAMS_PER_RANK = SYMBOLS_PER_RANK / SYMBOLS_PER_X4DRAM,
};
} // end namespace PRDF
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C
index 8b0e920d8..48ea97c00 100644
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C
@@ -228,6 +228,42 @@ int32_t CenDqBitmap::setEccSpare( uint8_t i_pins )
//------------------------------------------------------------------------------
+int32_t CenDqBitmap::isDramSpareAvailable( uint8_t i_portSlct,
+ bool & o_available )
+{
+ #define PRDF_FUNC "[CenDqBitmap::isDramSpareAvailable] "
+
+ int32_t o_rc = SUCCESS;
+
+ o_available = false;
+
+ do
+ {
+ if ( PORT_SLCT_PER_MBA <= i_portSlct )
+ {
+ PRDF_ERR( PRDF_FUNC"Invalid parameter: i_portSlct=%d", i_portSlct );
+ o_rc = FAIL; break;
+ }
+
+ if ( isDramWidthX4(iv_mba) )
+ {
+ // TODO: RTC 68096 Need to add x4 ECC support.
+ }
+ else
+ {
+ o_available =
+ ( 0 == iv_data[i_portSlct][DIMM_DQ_RANK_BITMAP_SIZE-1] );
+ }
+
+ } while (0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
void CenDqBitmap::getCaptureData( CaptureData & o_cd ) const
{
uint8_t rank = iv_rank.flatten();
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H
index 834c3bb01..4762caecd 100644
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H
@@ -114,6 +114,14 @@ class CenDqBitmap
int32_t setEccSpare( uint8_t i_pins );
/**
+ * @brief Queries for DRAM spare status.
+ * @param i_portSlct The target port.
+ * @param o_available TRUE if the spare is available, FALSE if it is used.
+ * @return Non-SUCCESS if an internal function failed, SUCCESS otherwise.
+ */
+ int32_t isDramSpareAvailable( uint8_t i_portSlct, bool & o_available );
+
+ /**
* @brief Adds the bitmaps for both ports to the capture data.
* @param o_cd Capture data struct.
*/
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C
index 0d03876ab..c73efc43f 100755
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C
@@ -22,19 +22,22 @@
/* IBM_PROLOG_END_TAG */
/** @file prdfCenMba.C
- * @brief Contains all the plugin code for the PRD Centaur MBA
+ * @brief Contains all common plugin code for the Centaur MBA
*/
+// Framework includes
#include <iipServiceDataCollector.h>
-#include <prdfCalloutUtil.H>
#include <prdfExtensibleChip.H>
#include <prdfPlatServices.H>
#include <prdfPluginMap.H>
-#include <prdfCenAddress.H>
+// Pegasus includes
+#include <prdfCalloutUtil.H>
#include <prdfCenMbaCaptureData.H>
#include <prdfCenMbaDataBundle.H>
+using namespace TARGETING;
+
namespace PRDF
{
@@ -78,71 +81,32 @@ int32_t MaintCmdComplete( ExtensibleChip * i_mbaChip,
{
#define PRDF_FUNC "[Mba::MaintCmdComplete] "
- using namespace TARGETING;
-
int32_t l_rc = SUCCESS;
- TargetHandle_t mbaTarget = i_mbaChip->GetChipHandle();
-
- do
- {
- #ifdef __HOSTBOOT_MODULE
-
- if ( isInMdiaMode() )
- {
- // Immediately inform mdia that the command
- // has finished.
-
- l_rc = mdiaSendEventMsg( mbaTarget, MDIA::RESET_TIMER );
-
- if(l_rc)
- {
- PRDF_ERR( PRDF_FUNC"PlatServices::mdiaSendEventMsg() failed" );
- // keep going
- }
-
- // Determine for mdia whether or not the command
- // finished at the end of the last rank or if
- // the command will need to be restarted.
- // Tuck this away until PostAnalysis.
-
- CenAddr startAddr, endAddr;
- l_rc = getCenMaintStartAddr( i_mbaChip, startAddr );
- l_rc |= getCenMaintEndAddr( i_mbaChip, endAddr );
- if ( SUCCESS != l_rc )
- {
- PRDF_ERR( PRDF_FUNC"cenGetMbaAddr() failed" );
- break;
- }
-
- CenMbaDataBundle * mbadb = getMbaDataBundle( i_mbaChip );
- mbadb->iv_sendCmdCompleteMsg = true;
- mbadb->iv_cmdCompleteMsgData =
- startAddr == endAddr ? MDIA::COMMAND_COMPLETE
- : MDIA::COMMAND_STOPPED;
-
- // Do not commit error log for a successful command complete.
- if ( MDIA::COMMAND_COMPLETE == mbadb->iv_cmdCompleteMsgData )
- i_sc.service_data->DontCommitErrorLog();
- }
-
- #endif // __HOSTBOOT_MODULE
-
- // Get DRAM repairs capture data
- CenMbaCaptureData::addDramRepairsData( mbaTarget, i_sc );
- } while (0);
+ TargetHandle_t mbaTarget = i_mbaChip->GetChipHandle();
+ CenMbaDataBundle * mbadb = getMbaDataBundle( i_mbaChip );
+ // Tell the TD controller that a maintenance command complete occurred.
+ l_rc = mbadb->iv_tdCtlr.handleCmdCompleteEvent( i_sc );
if ( SUCCESS != l_rc )
{
- PRDF_ERR( PRDF_FUNC"failed on MBA 0x%08x", getHuid(mbaTarget) );
+ PRDF_ERR( PRDF_FUNC"Failed: i_mbaChip=0x%08x", getHuid(mbaTarget) );
CalloutUtil::defaultError( i_sc );
}
- return l_rc;
+ // Gather capture data even if something failed above.
+ // NOTE: There is no need to capture if the maintenance command complete was
+ // successful with no errors because the error log will not be
+ // committed.
+ if ( !i_sc.service_data->IsDontCommitErrl() )
+ CenMbaCaptureData::addDramRepairsData( mbaTarget, i_sc );
+
+ return PRD_NO_CLEAR_FIR_BITS; // FIR bits are cleared by this plugin
#undef PRDF_FUNC
}
PRDF_PLUGIN_DEFINE( Mba, MaintCmdComplete );
} // end namespace Mba
+
} // end namespace PRDF
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H
index a239ad48d..fe2eb5c4c 100644
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H
@@ -28,11 +28,15 @@
* @brief Contains the common data bundle for a Centaur MBA object.
*/
+// Framework includes
#include <iipSystem.h>
#include <prdfExtensibleChip.H>
#include <prdfGlobal.H>
#include <prdfPlatServices.H>
+// Pegasus includes
+#include <prdfCenMbaTdCtlr.H>
+
namespace PRDF
{
@@ -48,7 +52,7 @@ class CenMbaDataBundleCommon : public DataBundle
* @param i_mbaChip The MBA chip.
*/
explicit CenMbaDataBundleCommon( ExtensibleChip * i_mbaChip ) :
- iv_mbaChip(i_mbaChip), iv_membChip(NULL)
+ iv_mbaChip(i_mbaChip), iv_membChip(NULL), iv_tdCtlr(i_mbaChip)
{}
/**
@@ -83,6 +87,11 @@ class CenMbaDataBundleCommon : public DataBundle
ExtensibleChip * iv_mbaChip; ///< This MBA chip
ExtensibleChip * iv_membChip; ///< The connected MEMBUF chip
+
+ public: // instance variables
+
+ CenMbaTdCtlr iv_tdCtlr; ///< Targeted Diagnostics Controller
+
};
} // end namespace PRDF
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H
new file mode 100644
index 000000000..3fa49f259
--- /dev/null
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H
@@ -0,0 +1,48 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2013 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __prdfCenMbaExtraSig_H
+#define __prdfCenMbaExtraSig_H
+
+#include <prdrSignatures.H>
+
+PRDR_ERROR_SIGNATURE(MaintCmdComplete_ERROR, 0xeeee0000, "",
+ "ERROR: maint cmd complete analysis failed" );
+
+PRDR_ERROR_SIGNATURE(StartVcmPhase1, 0xffff0000, "", "Starting VCM phase 1");
+PRDR_ERROR_SIGNATURE(StartVcmPhase2, 0xffff0001, "", "Starting VCM phase 2");
+PRDR_ERROR_SIGNATURE(StartDsdPhase1, 0xffff0002, "", "Starting DSD phase 1");
+PRDR_ERROR_SIGNATURE(StartDsdPhase2, 0xffff0003, "", "Starting DSD phase 2");
+
+PRDR_ERROR_SIGNATURE(MaintUE, 0xffff0010, "", "Maintenance UE");
+
+PRDR_ERROR_SIGNATURE(VcmVerified, 0xffff0020, "", "VCM: verified");
+PRDR_ERROR_SIGNATURE(VcmFalseAlarm, 0xffff0021, "", "VCM: false alarm");
+PRDR_ERROR_SIGNATURE(VcmBadSpare, 0xffff0022, "", "VCM: bad DRAM spare");
+PRDR_ERROR_SIGNATURE(VcmMarksUnavail, 0xffff0023, "",
+ "VCM: No more marks available");
+
+PRDR_ERROR_SIGNATURE(DsdDramSpared, 0xffff0030, "", "DSD: DRAM spared");
+PRDR_ERROR_SIGNATURE(DsdBadSpare, 0xffff0031, "", "DSD: DRAM spare is bad");
+
+#endif // __prdfCenMbaExtraSig_H
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C
new file mode 100644
index 000000000..1e7a0ed7c
--- /dev/null
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C
@@ -0,0 +1,104 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2013 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include <prdfCenMbaTdCtlr_common.H>
+
+using namespace TARGETING;
+
+namespace PRDF
+{
+
+using namespace PlatServices;
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlrCommon::cleanupPrevCmd()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlrCommon::cleanupPrevCmd] "
+
+ int32_t o_rc = SUCCESS;
+
+ // Clean up the current maintenance command. This must be done whenever
+ // maintenance command will no longer be executed.
+ if ( NULL != iv_mssCmd )
+ {
+ o_rc = iv_mssCmd->cleanupCmd();
+ if ( SUCCESS != o_rc )
+ PRDF_ERR( PRDF_FUNC"cleanupCmd() failed" );
+
+ delete iv_mssCmd; iv_mssCmd = NULL;
+ }
+
+ // Clear the command complete attention. This must be done before starting
+ // the next maintenance command.
+ SCAN_COMM_REGISTER_CLASS * firand = iv_mbaChip->getRegister("MBASPA_AND");
+ firand->setAllBits();
+
+ firand->ClearBit(0); // Maintenance command complete
+ firand->ClearBit(8); // Maintenance command complete (DD1.0 workaround)
+
+ int32_t l_rc = firand->Write();
+ if ( SUCCESS != l_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"Write() failed on MBASPA_AND" );
+ o_rc = FAIL;
+ }
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlrCommon::chipMarkCleanup()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlrCommon::chipMarkCleanup] "
+
+ int32_t o_rc = SUCCESS;
+
+ do
+ {
+ SCAN_COMM_REGISTER_CLASS * ddrPhyAndFir =
+ iv_mbaChip->getRegister( "MBADDRPHYFIR_AND" );
+ ddrPhyAndFir->setAllBits();
+
+ ddrPhyAndFir->ClearBit(50); // Calibration Error RE 0
+ ddrPhyAndFir->ClearBit(58); // Calibration Error RE 1
+
+ o_rc = ddrPhyAndFir->Write();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"Write() failed on MBADDRPHYFIR_AND" );
+ break;
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+} // end namespace PRDF
+
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H
new file mode 100644
index 000000000..5107dc7f5
--- /dev/null
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H
@@ -0,0 +1,212 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2013 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/** @file prdfCenMbaTdCtlr_common.H
+ * @brief The common implementation of the MBA TD Controller.
+ */
+
+#ifndef __prdfCenMbaTdCtlr_common_H
+#define __prdfCenMbaTdCtlr_common_H
+
+// Framework includes
+#include <iipServiceDataCollector.h>
+#include <prdf_types.h>
+#include <prdfPlatServices.H>
+
+// Pegasus includes
+#include <prdfCenAddress.H>
+#include <prdfCenConst.H>
+#include <prdfCenMarkstore.H>
+#include <prdfCenMbaExtraSig.H>
+
+namespace PRDF
+{
+
+class ExtensibleChip;
+
+/**
+ * @brief A state machine for memory targeted diagnostics.
+ */
+class CenMbaTdCtlrCommon
+{
+ public: // functions
+
+ /**
+ * @brief Constructor
+ *
+ * This constructor will be called in the MBA data bundle code. Therefore,
+ * no register reads/writes can be done in this constructor. Anything needed
+ * to initialize the instance variables that requires register reads/writes
+ * or is non-trivial should be done in initialize().
+ *
+ * @param i_mbaChip An MBA chip.
+ */
+ explicit CenMbaTdCtlrCommon( ExtensibleChip * i_mbaChip ) :
+ iv_mbaChip(i_mbaChip), iv_initialized(false), iv_rank(), iv_mark(),
+ iv_mssCmd(NULL)
+ {}
+
+ /** @brief Destructor */
+ ~CenMbaTdCtlrCommon()
+ {
+ delete iv_mssCmd; iv_mssCmd = NULL;
+ }
+
+ /**
+ * @brief Determines and executes the next course of action after a
+ * maintenance command complete attention.
+ * @note Initializes the TD controller, if needed.
+ * @param io_sc The step code data struct.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t handleCmdCompleteEvent( STEP_CODE_DATA_STRUCT & io_sc ) = 0;
+
+ protected: // functions
+
+ /**
+ * @brief Initializes the TD controller and sets appropriate information
+ * in the hardware, if needed.
+ *
+ * Since the TD controller constructor will only be called in the MBA data
+ * bundle, register reads/writes can NOT be done in the constructor.
+ * Instead, anything needed to initialize the instance variables that
+ * requires register reads/writes or is non-trivial should be done in
+ * this function.
+ *
+ * @note Should be called at the beginning of every public function to
+ * ensure the TD controller is initialized.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t initialize() = 0;
+
+ /**
+ * @brief Analyzes a non-TD command complete event.
+ *
+ * A maintenance command has completed but no TD are in progress. This
+ * function will check for any ECC errors, unverified chip marks from a
+ * reset/reload, etc. and starts any TD procedures, if necessary.
+ *
+ * @param io_sc The step code data struct.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t analyzeCmdComplete( STEP_CODE_DATA_STRUCT & io_sc ) = 0;
+
+ /**
+ * @brief Analyzes VCM Phase 1 results and moves state machine.
+ * @param io_sc The step code data struct.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t analyzeVcmPhase1( STEP_CODE_DATA_STRUCT & io_sc ) = 0;
+
+ /**
+ * @brief Analyzes VCM Phase 2 results and moves state machine.
+ * @param io_sc The step code data struct.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t analyzeVcmPhase2( STEP_CODE_DATA_STRUCT & io_sc ) = 0;
+
+ /**
+ * @brief Analyzes DSD Phase 1 results and moves state machine.
+ * @param io_sc The step code data struct.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t analyzeDsdPhase1( STEP_CODE_DATA_STRUCT & io_sc ) = 0;
+
+ /**
+ * @brief Analyzes DSD Phase 2 results and moves state machine.
+ * @param io_sc The step code data struct.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t analyzeDsdPhase2( STEP_CODE_DATA_STRUCT & io_sc ) = 0;
+
+ /**
+ * @brief Starts VCM Phase 1.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t startVcmPhase1() = 0;
+
+ /**
+ * @brief Starts VCM Phase 2.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t startVcmPhase2() = 0;
+
+ /**
+ * @brief Starts DSD Phase 1.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t startDsdPhase1() = 0;
+
+ /**
+ * @brief Starts DSD Phase 2.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t startDsdPhase2() = 0;
+
+ /**
+ * @return TRUE if currently running a targeted diagnositics procedure,
+ * FALSE otherwise.
+ */
+ virtual bool isInTdMode() = 0;
+
+ /**
+ * @brief Calls the cleanupCmd() function of the command that had just
+ * completed.
+ * @note This function will clear the maintenance command complete
+ * attention. So for FSP attentions, the SDC needs to be synched
+ * before calling this function just in case there is a
+ * reset/reload.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t cleanupPrevCmd();
+
+ /**
+ * @brief Clears FIR bits that may have been a side-effect of a chip mark
+ * placed by hardware.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ virtual int32_t chipMarkCleanup();
+
+ protected: // instance variables
+
+ /** The memory controller chip that this TD controller acts on. */
+ ExtensibleChip * iv_mbaChip;
+
+ /** Indicates if TD controller is initialized. */
+ bool iv_initialized;
+
+ /** The current rank that is being targeted for diagnostics. */
+ CenRank iv_rank;
+
+ /** The current mark that is being targeted for diagnostics. */
+ CenMark iv_mark;
+
+ /** Current maintenance command */
+ PlatServices::mss_MaintCmdWrapper * iv_mssCmd;
+
+}; // CenMbaTdCtlrCommon
+
+} // end namespace PRDF
+
+#endif // __prdfCenMbaTdCtlr_common_H
+
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C
index 38edaea21..57eaf1322 100755
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C
@@ -60,29 +60,17 @@ CenSymbol CenSymbol::fromSymbol( TargetHandle_t i_mba, const CenRank & i_rank,
break;
}
- if ( SYMBOLS_PER_RANK <= i_symbol )
- {
- PRDF_ERR( PRDF_FUNC"i_symbol is invalid" );
- break;
- }
-
if ( BOTH_SYMBOL_DQS < i_pins )
{
PRDF_ERR( PRDF_FUNC"i_pins is invalid" );
break;
}
- o_symbol = CenSymbol ( i_mba, i_rank, wiringType, i_symbol, i_pins );
+ o_symbol = CenSymbol ( i_mba, i_rank, wiringType, i_symbol, i_pins,
+ isDramWidthX4(i_mba) );
} while (0);
- if ( !o_symbol.isValid() )
- {
- PRDF_ERR( PRDF_FUNC"Failed: i_mba=0x%08x i_rank=%d i_symbol=%d "
- "i_pins=%d", getHuid(i_mba), i_rank.flatten(), i_symbol,
- i_pins );
- }
-
return o_symbol;
#undef PRDF_FUNC
@@ -124,17 +112,11 @@ CenSymbol CenSymbol::fromDimmDq( TargetHandle_t i_mba, const CenRank & i_rank,
uint8_t pins = (0 == (i_dimmDq & ODD_SYMBOL_DQ)) ? EVEN_SYMBOL_DQ :
ODD_SYMBOL_DQ;
- o_symbol = CenSymbol ( i_mba, i_rank, wiringType, symbol, pins );
+ o_symbol = CenSymbol ( i_mba, i_rank, wiringType, symbol, pins,
+ isDramWidthX4(i_mba) );
} while (0);
- if ( !o_symbol.isValid() )
- {
- PRDF_ERR( PRDF_FUNC"Failed: i_mba=0x%08x i_rank=%d i_dimmDq=%d "
- "i_portSlct=%d", getHuid(i_mba), i_rank.flatten(), i_dimmDq,
- i_portSlct );
- }
-
return o_symbol;
#undef PRDF_FUNC
@@ -205,6 +187,20 @@ uint8_t CenSymbol::symbol2PortSlct( uint8_t i_symbol )
//------------------------------------------------------------------------------
+uint8_t CenSymbol::symbol2Dram( uint8_t i_symbol, bool isX4Dram )
+{
+ uint8_t dram = isX4Dram ? X4DRAMS_PER_RANK : X8DRAMS_PER_RANK;
+
+ if ( SYMBOLS_PER_RANK > i_symbol )
+ {
+ dram = i_symbol / (isX4Dram ? SYMBOLS_PER_X4DRAM : SYMBOLS_PER_X8DRAM);
+ }
+
+ return dram;
+}
+
+//------------------------------------------------------------------------------
+
int32_t CenSymbol::getSymbol( const CenRank & i_rank, WiringType i_wiringType,
uint8_t i_dimmDq, uint8_t i_portSlct,
uint8_t & o_symbol )
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H
index 0bfc86dfd..a43700e87 100755
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H
@@ -81,9 +81,10 @@ class CenSymbol
* @brief Constructor from components
*/
CenSymbol( TARGETING::TargetHandle_t i_mba, CenRank i_rank,
- WiringType i_wiringType, uint8_t i_symbol, uint8_t i_pins ) :
+ WiringType i_wiringType, uint8_t i_symbol, uint8_t i_pins,
+ bool i_x4Dram ) :
iv_mbaTarget(i_mba), iv_rank(i_rank), iv_wiringType(i_wiringType),
- iv_symbol(i_symbol), iv_pins(i_pins)
+ iv_symbol(i_symbol), iv_pins(i_pins), iv_x4Dram(i_x4Dram)
{}
public: // functions
@@ -148,6 +149,12 @@ class CenSymbol
/** @return The port select for this symbol. */
uint8_t getPortSlct() const { return symbol2PortSlct( iv_symbol ); }
+ /** @return The DRAM index for this symbol. */
+ uint8_t getDram() const { return symbol2Dram( iv_symbol, iv_x4Dram ); }
+
+ /** @return TRUE this symbol is on a x4 DRAM, FALSE otherwise. */
+ bool isX4Dram() const { return iv_x4Dram; }
+
/** @return The symbol of the given Centaur DQ and port select. */
static uint8_t cenDq2Symbol( uint8_t i_CenDq, uint8_t i_ps );
@@ -157,6 +164,9 @@ class CenSymbol
/** @return The port select for given symbol. */
static uint8_t symbol2PortSlct( uint8_t i_symbol );
+ /** @return The DRAM index for the given symbol. */
+ static uint8_t symbol2Dram( uint8_t i_symbol, bool isX4Dram );
+
/**
* @brief Overrides the '<' operator.
* @param i_symbol The symbol to compare with.
@@ -199,6 +209,7 @@ class CenSymbol
WiringType iv_wiringType; ///< This symbol's wiring type.
uint8_t iv_symbol; ///< This symbol's numerical value.
uint8_t iv_pins; ///< See enum DqMask.
+ bool iv_x4Dram; ///< TRUE x4 DRAM, FALSE x8 DRAM.
};
} // end namespace PRDF
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C b/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C
index 177a64d91..6c4e7a736 100755
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C
@@ -203,8 +203,7 @@ MemoryMru::MemoryMru( TARGETING::TargetHandle_t i_mbaTarget,
iv_memMruMeld.s.rank = iv_rank.flatten();
iv_memMruMeld.s.symbol = iv_symbol.getSymbol();
iv_memMruMeld.s.pins = iv_symbol.getPins();
- //TODO: RTC 68096 Add support for DRAM spare
- iv_memMruMeld.s.dramSpared = 0;
+ iv_memMruMeld.s.dramSpared = 0; // manually set by setDramSpared()
iv_memMruMeld.s.wiringType = iv_symbol.getWiringType();
// If the code gets to this point the MemoryMru is valid.
diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H b/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H
index a1cb63ab0..448649385 100755
--- a/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H
+++ b/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H
@@ -71,6 +71,9 @@ class MemoryMru
MemoryMru( TARGETING::TargetHandle_t i_mbaTarget, const CenRank & i_rank,
MemoryMruData::Callout i_specialCallout );
+ /** @brief Indicates that the symbol actually resides on the DRAM spare. */
+ void setDramSpared() { iv_memMruMeld.s.dramSpared = 1; }
+
public: // functions
/** @return The 32-bit representation of this MemoryMru. */
diff --git a/src/usr/diag/prdf/common/prd_pegasus.mk b/src/usr/diag/prdf/common/prd_pegasus.mk
index ade450c4b..6279d7afd 100755
--- a/src/usr/diag/prdf/common/prd_pegasus.mk
+++ b/src/usr/diag/prdf/common/prd_pegasus.mk
@@ -41,10 +41,12 @@ prd_pegasus_specific = \
prdfCalloutUtil.o \
prdfCenAddress.o \
prdfCenDqBitmap.o \
+ prdfCenMbaCaptureData.o \
+ prdfCenMbaTdCtlr.o \
+ prdfCenMbaTdCtlr_common.o \
prdfCenSymbol.o \
+ prdfLaneRepair.o \
prdfLineDelete.o \
- prdfPegasusConfigurator.o \
- prdfCenMbaCaptureData.o \
prdfMemoryMru.o \
- prdfRegisterData.o \
- prdfLaneRepair.o
+ prdfPegasusConfigurator.o \
+ prdfRegisterData.o
diff --git a/src/usr/diag/prdf/framework/service/prdfPlatServices.C b/src/usr/diag/prdf/framework/service/prdfPlatServices.C
index c6477ca85..81564e53a 100644
--- a/src/usr/diag/prdf/framework/service/prdfPlatServices.C
+++ b/src/usr/diag/prdf/framework/service/prdfPlatServices.C
@@ -36,6 +36,9 @@
#include <prdfTrace.H>
#include <prdfAssert.h>
+#include <prdfCenAddress.H>
+#include <prdfCenDqBitmap.H>
+
#include <diag/mdia/mdia.H>
#include <diag/mdia/mdiamevent.H>
#include <errno.h>
@@ -44,8 +47,6 @@
using namespace TARGETING;
-//------------------------------------------------------------------------------
-
namespace PRDF
{
@@ -200,6 +201,37 @@ int32_t mssRestoreDramRepairs( TargetHandle_t i_mbaTarget,
return o_rc;
}
+//------------------------------------------------------------------------------
+
+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.flatten(), data );
+ if ( NULL != errl )
+ {
+ PRDF_ERR( PRDF_FUNC"mss_IPL_UE_isolation() failed: MBA=0x%08x "
+ "rank=%d", getHuid(i_mba), i_rank.flatten() );
+ 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
+}
+
} // end namespace PlatServices
} // end namespace PRDF
diff --git a/src/usr/diag/prdf/framework/service/prdfPlatServices.H b/src/usr/diag/prdf/framework/service/prdfPlatServices.H
index 8395d8619..41e489152 100644
--- a/src/usr/diag/prdf/framework/service/prdfPlatServices.H
+++ b/src/usr/diag/prdf/framework/service/prdfPlatServices.H
@@ -86,6 +86,18 @@ int32_t mssRestoreDramRepairs( TARGETING::TargetHandle_t i_mbaTarget,
uint8_t & o_repairedRankMask,
uint8_t & o_badDimmMask );
+/**
+ * @brief Invokes the mss_IPL_UE_isolation hardware procedure.
+ * This function will identify the bits that caused the UE.
+ * @param i_mba Target MBA.
+ * @param i_rank Target rank.
+ * @param o_bitmap DQ bitmap container.
+ * @return Non-SUCCESS in internal function fails, SUCCESS otherwise.
+ */
+int32_t mssIplUeIsolation( TARGETING::TargetHandle_t i_mba,
+ const CenRank & i_rank,
+ CenDqBitmap & o_bitmap );
+
} // end namespace PlatServices
} // end namespace PRDF
diff --git a/src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H
index ffa254849..c6dcf5ccc 100644
--- a/src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H
+++ b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H
@@ -38,7 +38,7 @@ namespace PRDF
{
/**
- * @brief The P7 Centaur MBA data bundle.
+ * @brief Centaur MBA data bundle.
*/
class CenMbaDataBundle : public CenMbaDataBundleCommon
{
@@ -56,9 +56,7 @@ class CenMbaDataBundle : public CenMbaDataBundleCommon
/**
* @brief Destructor.
*/
- ~CenMbaDataBundle()
- {
- }
+ ~CenMbaDataBundle() {}
private: // functions
diff --git a/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C
new file mode 100644
index 000000000..40f7b51a4
--- /dev/null
+++ b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C
@@ -0,0 +1,1342 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2013 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include <prdfCenMbaTdCtlr.H>
+
+// Framework includes
+#include <iipconst.h>
+#include <iipServiceDataCollector.h>
+#include <prdfExtensibleChip.H>
+#include <prdfGlobal.H>
+#include <prdfPlatServices.H>
+#include <prdfRegisterCache.H>
+#include <prdfTrace.H>
+
+// Pegasus includes
+#include <prdfCalloutUtil.H>
+#include <prdfCenAddress.H>
+#include <prdfCenConst.H>
+#include <prdfCenDqBitmap.H>
+#include <prdfCenMbaDataBundle.H>
+#include <prdfCenSymbol.H>
+
+// TODO: RTC 68096 Currently we are only supporting x8 DRAM. Once support for x4
+// DRAM is available, it will have impact on DRAM spare.
+
+using namespace TARGETING;
+
+namespace PRDF
+{
+
+using namespace PlatServices;
+
+enum EccErrorMask
+{
+ NO_ERROR = 0, ///< No ECC errors found
+ UE = 0x80, ///< UE
+ MPE = 0x40, ///< Chip mark placed
+ RCE = 0x20, ///< Retry CE
+ MCE = 0x10, ///< CE on chip mark
+};
+
+//------------------------------------------------------------------------------
+// Class Variables
+//------------------------------------------------------------------------------
+
+CenMbaTdCtlr::CMD_COMPLETE_FUNCS CenMbaTdCtlr::cv_cmdCompleteFuncs[] =
+{
+ &CenMbaTdCtlr::analyzeCmdComplete, // NO_OP
+ &CenMbaTdCtlr::analyzeVcmPhase1, // VCM_PHASE_1
+ &CenMbaTdCtlr::analyzeVcmPhase2, // VCM_PHASE_2
+ &CenMbaTdCtlr::analyzeDsdPhase1, // DSD_PHASE_1
+ &CenMbaTdCtlr::analyzeDsdPhase2, // DSD_PHASE_2
+};
+
+//------------------------------------------------------------------------------
+// Public Functions
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::handleCmdCompleteEvent( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::handleCmdCompleteEvent] "
+
+ int32_t o_rc = SUCCESS;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( !isInMdiaMode() )
+ {
+ PRDF_ERR( PRDF_FUNC"A hostboot maintenance command complete "
+ "attention occurred while MDIA was not running." );
+ o_rc = FAIL;
+ break;
+ }
+
+ o_rc = initialize();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"initialize() failed" );
+ break;
+ }
+
+ // Immediately inform MDIA that the command has finished.
+ o_rc = mdiaSendEventMsg( mba, MDIA::RESET_TIMER );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"mdiaSendEventMsg(RESET_TIMER) failed" );
+ break;
+ }
+
+ o_rc = (this->*cv_cmdCompleteFuncs[iv_tdState])( io_sc );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"Failed to continue analysis" );
+ break;
+ }
+
+ // Do some cleanup if the TD procedure is complete.
+ if ( !isInTdMode() )
+ {
+ o_rc = exitTdSequence();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"exitTdSequence() failed" );
+ break;
+ }
+ }
+
+ } while(0);
+
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"iv_mbaChip:0x%08x iv_initialized:%c iv_tdState:%d "
+ "iv_rank:%d iv_mark:%2d %2d", getHuid(mba),
+ iv_initialized ? 'T' : 'F', iv_tdState, iv_rank.flatten(),
+ iv_mark.getCM().getSymbol(), iv_mark.getSM().getSymbol() );
+
+ int32_t l_rc = cleanupPrevCmd(); // Just in case.
+ if ( SUCCESS != l_rc )
+ PRDF_ERR( PRDF_FUNC"cleanupPrevCmd() failed" );
+
+ l_rc = mdiaSendEventMsg( mba, MDIA::SKIP_MBA );
+ if ( SUCCESS != l_rc )
+ PRDF_ERR( PRDF_FUNC"mdiaSendEventMsg(SKIP_MBA) failed" );
+
+ io_sc.service_data->SetErrorSig( PRDFSIG_MaintCmdComplete_ERROR );
+ io_sc.service_data->SetServiceCall();
+
+ // There may have been a code bug, callout 2nd level support.
+ io_sc.service_data->SetCallout( NextLevelSupport_ENUM, MRU_HIGH );
+
+ // Callout the mark. If nothing was added to the callout list (no valid
+ // marks), callout the MBA.
+ CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc );
+ if ( 1 == io_sc.service_data->GetMruList().size() )
+ io_sc.service_data->SetCallout( mba );
+
+ // Just in case it was a legitimate maintenance command complete (error
+ // log not committed) but something else failed.
+ io_sc.service_data->ClearFlag(ServiceDataCollector::DONT_COMMIT_ERRL);
+ }
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+// Private Functions
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::initialize()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::initialize] "
+
+ int32_t o_rc = SUCCESS;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( iv_initialized ) break; // nothing to do
+
+ // Check for valid MBA.
+ if ( TYPE_MBA != getTargetType(mba) )
+ {
+ PRDF_ERR( PRDF_FUNC"iv_mbaChip is not TYPE_MBA" );
+ o_rc = FAIL; break;
+ }
+
+ iv_initialized = true;
+
+ } while (0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::analyzeCmdComplete( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::analyzeCmdComplete] "
+
+ int32_t o_rc = SUCCESS;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( NO_OP != iv_tdState )
+ {
+ PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" );
+ o_rc = FAIL; break;
+ }
+
+ // Get the rank on which maintenance command stopped
+ CenAddr addr;
+ o_rc = getCenMaintStartAddr( iv_mbaChip, addr );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"cenGetMaintAddr() failed" );
+ break;
+ }
+ iv_rank = CenRank( addr.getRank() );
+
+ // Get error condition which caused command to stop
+ uint8_t eccErrorMask = NO_ERROR;
+ o_rc = checkEccErrors( eccErrorMask );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" );
+ break;
+ }
+
+ if ( eccErrorMask & UE )
+ {
+ // Handle UE. Highest priority
+ o_rc = handleUE( io_sc );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"handleUE() failed" );
+ break;
+ }
+ }
+ else if ( eccErrorMask & MPE )
+ {
+ // Get the current marks in hardware.
+ o_rc = mssGetMarkStore( mba, iv_rank, iv_mark );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"mssGetMarkStore() failed");
+ break;
+ }
+
+ if ( !iv_mark.getCM().isValid() )
+ {
+ PRDF_ERR( PRDF_FUNC"No valid chip mark to verify");
+ o_rc = FAIL; break;
+ }
+
+ io_sc.service_data->SetErrorSig( PRDFSIG_StartVcmPhase1 );
+
+ CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc );
+
+ // Start VCM procedure
+ o_rc = startVcmPhase1();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"startVcmPhase1() failed" );
+ break;
+ }
+ }
+ else
+ {
+ // If maint cmd completed with no error, don't commit error log.
+ io_sc.service_data->DontCommitErrorLog();
+ }
+
+ } while (0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::analyzeVcmPhase1( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::analyzeVcmPhase1] "
+
+ int32_t o_rc = SUCCESS;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( VCM_PHASE_1 != iv_tdState )
+ {
+ PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" );
+ o_rc = FAIL; break;
+ }
+
+ // Get error condition which caused command to stop
+ uint8_t eccErrorMask = NO_ERROR;
+ o_rc = checkEccErrors( eccErrorMask );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" );
+ break;
+ }
+
+ if ( (eccErrorMask & UE) || (eccErrorMask & RCE) )
+ {
+ // Handle UE. Highest priority
+ o_rc = handleUE( io_sc );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"handleUE() failed" );
+ break;
+ }
+ }
+ else
+ {
+ io_sc.service_data->SetErrorSig( PRDFSIG_StartVcmPhase2 );
+
+ CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc );
+
+ // Start VCM Phase 2
+ o_rc = startVcmPhase2();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"startVcmPhase2() failed" );
+ break;
+ }
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::analyzeVcmPhase2( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::analyzeVcmPhase2] "
+
+ int32_t o_rc = SUCCESS;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( VCM_PHASE_2 != iv_tdState )
+ {
+ PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" );
+ o_rc = FAIL; break;
+ }
+
+ // Get error condition which caused command to stop
+ uint8_t eccErrorMask = NO_ERROR;
+ o_rc = checkEccErrors( eccErrorMask );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" );
+ break;
+ }
+
+ if ( eccErrorMask & UE )
+ {
+ // Handle UE. Highest priority
+ o_rc = handleUE( io_sc );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"handleUE() failed" );
+ break;
+ }
+ }
+ else 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
+ {
+ // Chip mark verification failed.
+
+ iv_tdState = NO_OP; // Abort the TD procedure.
+
+ io_sc.service_data->SetErrorSig( PRDFSIG_VcmFalseAlarm );
+
+ CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc );
+
+ // In the field, this error log will be recoverable for now, but we
+ // may have to add thresholding later if they become a problem. In
+ // manufacturing, this error log will be predictive.
+
+ if ( areDramRepairsDisabled() )
+ io_sc.service_data->SetServiceCall();
+
+ // Remove chip mark from hardware.
+ iv_mark.clearCM();
+ bool junk;
+ o_rc = mssSetMarkStore( mba, iv_rank, iv_mark, junk );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"mssSetMarkStore() failed" );
+ break;
+ }
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::analyzeDsdPhase1( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::analyzeDsdPhase1] "
+
+ int32_t o_rc = SUCCESS;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( DSD_PHASE_1 != iv_tdState )
+ {
+ PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" );
+ o_rc = FAIL; break;
+ }
+
+ // Get error condition which caused command to stop
+ uint8_t eccErrorMask = NO_ERROR;
+ o_rc = checkEccErrors( eccErrorMask );
+ if ( SUCCESS != o_rc)
+ {
+ PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" );
+ break;
+ }
+
+ if ( ( eccErrorMask & UE) || ( eccErrorMask & RCE ) )
+ {
+ // Handle UE. Highest priority
+ o_rc = handleUE( io_sc );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"handleUE() failed" );
+ break;
+ }
+ }
+ else
+ {
+ io_sc.service_data->SetErrorSig( PRDFSIG_StartDsdPhase2 );
+
+ CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc );
+
+ // Start DSD Phase 2
+ startDsdPhase2();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"startDsdPhase2() failed" );
+ break;
+ }
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::analyzeDsdPhase2( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::analyzeDsdPhase2] "
+
+ int32_t o_rc = SUCCESS;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( DSD_PHASE_2 != iv_tdState )
+ {
+ PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" );
+ o_rc = FAIL; break;
+ }
+
+ // Get error condition which caused command to stop
+ uint8_t eccErrorMask = NO_ERROR;
+ o_rc = checkEccErrors( eccErrorMask );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" );
+ break;
+ }
+
+ if ( eccErrorMask & UE)
+ {
+ // Handle UE. Highest priority
+ o_rc = handleUE( io_sc );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"handleUE() failed" );
+ break;
+ }
+ }
+ else if ( eccErrorMask & MCE )
+ {
+ // The spare is bad.
+
+ // Do callouts and VPD updates.
+ o_rc = handleMCE_DSD2( io_sc );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"handleMCE_DSD2() failed" );
+ break;
+ }
+ }
+ else
+ {
+ // The chip mark has successfully been steered to the spare.
+
+ io_sc.service_data->SetErrorSig( PRDFSIG_DsdDramSpared );
+
+ CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc );
+
+ // Remove chip mark from hardware.
+ iv_mark.clearCM();
+ bool junk;
+ o_rc = mssSetMarkStore( mba, iv_rank, iv_mark, junk );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"mssSetMarkStore() failed" );
+ break;
+ }
+ }
+
+ iv_tdState = NO_OP; // The TD procedure is complete.
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::startVcmPhase1()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::startVcmPhase1] "
+
+ int32_t o_rc = SUCCESS;
+
+ iv_tdState = VCM_PHASE_1;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ o_rc = prepareNextCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" );
+ break;
+ }
+
+ // Start phase 1.
+ uint32_t stopCond = ( mss_MaintCmd::STOP_END_OF_RANK |
+ mss_MaintCmd::STOP_ON_END_ADDRESS |
+ mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION );
+
+ iv_mssCmd = createMssCmd( mss_MaintCmdWrapper::TIMEBASE_STEER_CLEANUP,
+ mba, iv_rank, stopCond );
+ if ( NULL == iv_mssCmd )
+ {
+ PRDF_ERR( PRDF_FUNC"createMssCmd() failed");
+ o_rc = FAIL; break;
+ }
+
+ o_rc = iv_mssCmd->setupAndExecuteCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setupAndExecuteCmd() failed" );
+ break;
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::startVcmPhase2()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::startVcmPhase2] "
+
+ int32_t o_rc = SUCCESS;
+
+ iv_tdState = VCM_PHASE_2;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ o_rc = prepareNextCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" );
+ break;
+ }
+
+ // Start phase 2.
+ uint32_t stopCond = ( mss_MaintCmd::STOP_END_OF_RANK |
+ mss_MaintCmd::STOP_ON_END_ADDRESS |
+ mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION );
+
+ iv_mssCmd = createMssCmd( mss_MaintCmdWrapper::SUPERFAST_READ,
+ mba, iv_rank, stopCond );
+ if ( NULL == iv_mssCmd )
+ {
+ PRDF_ERR( PRDF_FUNC"createMssCmd() failed");
+ o_rc = FAIL; break;
+ }
+
+ o_rc = iv_mssCmd->setupAndExecuteCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setupAndExecuteCmd() failed" );
+ break;
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::startDsdPhase1()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::startDsdPhase1] "
+
+ int32_t o_rc = SUCCESS;
+
+ iv_tdState = DSD_PHASE_1;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ o_rc = prepareNextCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" );
+ break;
+ }
+
+ // Set the steer mux
+ o_rc = mssSetSteerMux( mba, iv_rank, iv_mark.getCM(), false );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"mssSetSteerMux() failed" );
+ break;
+ }
+
+ // Start phase 1.
+ uint32_t stopCond = ( mss_MaintCmd::STOP_END_OF_RANK |
+ mss_MaintCmd::STOP_ON_END_ADDRESS |
+ mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION );
+
+ iv_mssCmd = createMssCmd( mss_MaintCmdWrapper::TIMEBASE_STEER_CLEANUP,
+ mba, iv_rank, stopCond );
+ if ( NULL == iv_mssCmd )
+ {
+ PRDF_ERR( PRDF_FUNC"createMssCmd() failed");
+ o_rc = FAIL; break;
+ }
+
+ o_rc = iv_mssCmd->setupAndExecuteCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setupAndExecuteCmd() failed" );
+ break;
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::startDsdPhase2()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::startDsdPhase2] "
+
+ int32_t o_rc = SUCCESS;
+
+ iv_tdState = DSD_PHASE_2;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ o_rc = prepareNextCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" );
+ break;
+ }
+
+ // Start phase 2.
+ uint32_t stopCond = ( mss_MaintCmd::STOP_END_OF_RANK |
+ mss_MaintCmd::STOP_ON_END_ADDRESS |
+ mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION );
+
+ iv_mssCmd = createMssCmd( mss_MaintCmdWrapper::SUPERFAST_READ,
+ mba, iv_rank, stopCond );
+ if ( NULL == iv_mssCmd )
+ {
+ PRDF_ERR( PRDF_FUNC"createMssCmd() failed");
+ o_rc = FAIL; break;
+ }
+
+ o_rc = iv_mssCmd->setupAndExecuteCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setupAndExecuteCmd() failed" );
+ break;
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+bool CenMbaTdCtlr::isInTdMode()
+{
+ return ( (NO_OP != iv_tdState) && (MAX_TD_STATE > iv_tdState) );
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::checkEccErrors( uint8_t & o_eccErrorMask )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::checkEccErrors] "
+
+ int32_t o_rc = SUCCESS;
+
+ o_eccErrorMask = NO_ERROR;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ CenMbaDataBundle * mbadb = getMbaDataBundle( iv_mbaChip );
+ ExtensibleChip * membChip = mbadb->getMembChip();
+ if ( NULL == membChip )
+ {
+ PRDF_ERR( PRDF_FUNC"getMembChip() failed: MBA=0x%08x",
+ getHuid(mba) );
+ o_rc = FAIL; break;
+ }
+
+ const char * reg_str = ( 0 == getTargetPosition(mba) )
+ ? "MBSECC01FIR" : "MBSECC23FIR";
+ SCAN_COMM_REGISTER_CLASS * mbsEccFir = membChip->getRegister( reg_str );
+
+ o_rc = mbsEccFir->Read();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"Read() failed on %s", reg_str );
+ break;
+ }
+
+ if ( mbsEccFir->IsBitSet(20 + iv_rank.flatten()) )
+ {
+ o_eccErrorMask |= MPE;
+
+ // Clean up side-effect FIRs that may be set due to the chip mark.
+ o_rc = chipMarkCleanup();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"chipMarkCleanup() failed" );
+ break;
+ }
+ }
+
+ if ( mbsEccFir->IsBitSet(38) ) o_eccErrorMask |= MCE;
+ if ( mbsEccFir->IsBitSet(41) ) o_eccErrorMask |= UE;
+ if ( mbsEccFir->IsBitSet(42) ) o_eccErrorMask |= RCE;
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::handleUE( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::handleUE] "
+
+ using namespace CalloutUtil;
+
+ int32_t o_rc = SUCCESS;
+
+ iv_tdState = NO_OP; // Abort the TD procedure.
+
+ io_sc.service_data->SetErrorSig( PRDFSIG_MaintUE );
+ io_sc.service_data->SetServiceCall();
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ // Clean up the maintenance command. This is needed just in case the UE
+ // isolation procedure is modified to use maintenance commands.
+ o_rc = cleanupPrevCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"cleanupPrevCmd() failed" );
+ break;
+ }
+
+ // Look for all failing bits on this rank.
+ CenDqBitmap bitmap;
+ o_rc = mssIplUeIsolation( mba, iv_rank, bitmap );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"mssIplUeIsolation() failed" );
+ break;
+ }
+
+ // Add UE data to capture data.
+ bitmap.getCaptureData( io_sc.service_data->GetCaptureData() );
+
+ // Callout the failing DIMMs.
+ TargetHandleList callouts;
+ for ( int32_t ps = 0; ps < PORT_SLCT_PER_MBA; ps++ )
+ {
+ bool badDqs = false;
+ o_rc = bitmap.badDqs( ps, badDqs );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"badDqs(%d) failed", ps );
+ break;
+ }
+
+ if ( !badDqs ) continue; // nothing to do.
+
+ TargetHandleList dimms = getConnectedDimms( mba, iv_rank, ps );
+ if ( 0 == dimms.size() )
+ {
+ PRDF_ERR( PRDF_FUNC"getConnectedDimms(%d) failed", ps );
+ o_rc = FAIL; break;
+ }
+
+ callouts.insert( callouts.end(), dimms.begin(), dimms.end() );
+ }
+ if ( SUCCESS != o_rc ) break;
+
+ if ( 0 == callouts.size() )
+ {
+ // It is possible the scrub counters have rolled over to zero due to
+ // a known DD1.0 hardware bug. In this case, the best we can do is
+ // callout both DIMMs, because at minimum we know there was a UE, we
+ // just don't know where.
+ // NOTE: If this condition happens because of a DD2.0+ bug, the
+ // mssIplUeIsolation procedure will callout the Centaur.
+ callouts = getConnectedDimms( mba, iv_rank );
+ if ( 0 == callouts.size() )
+ {
+ PRDF_ERR( PRDF_FUNC"getConnectedDimms() failed" );
+ o_rc = FAIL; break;
+ }
+ }
+
+ // Callout all DIMMs in the list.
+ for ( TargetHandleList::iterator i = callouts.begin();
+ i != callouts.end(); i++ )
+ {
+ io_sc.service_data->SetCallout( *i, MRU_HIGH );
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::handleMCE_VCM2( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::handleMCE_VCM2] "
+
+ int32_t o_rc = SUCCESS;
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( VCM_PHASE_2 != iv_tdState )
+ {
+ PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" );
+ o_rc = FAIL; break;
+ }
+
+ io_sc.service_data->SetErrorSig( PRDFSIG_VcmVerified );
+
+ CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc );
+
+ if ( areDramRepairsDisabled() )
+ {
+ iv_tdState = NO_OP; // The TD procedure is complete.
+
+ io_sc.service_data->SetServiceCall();
+
+ break; // nothing else to do.
+ }
+
+ bool startDsdProcedure = false;
+
+ // Read VPD.
+ CenDqBitmap bitmap;
+ o_rc = getBadDqBitmap( mba, 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.
+ // NOTE: If this chip mark was placed on the spare, the original failing
+ // DRAM will have already been set in VPD so this will be
+ // redundant but it simplifies the rest of the logic below.
+ o_rc = bitmap.setDram( iv_mark.getCM().getSymbol() );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setDram() failed" );
+ break;
+ }
+
+ // RAS callout policies can be determined by the DIMM type. We can
+ // assume IS DIMMs are on low end systems and Centaur DIMMs are on
+ // mid/high end systems.
+ bool isCenDimm = false;
+ o_rc = isMembufOnDimm( mba, isCenDimm );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"isMembufOnDimm() failed" );
+ break;
+ }
+
+ if ( isCenDimm ) // Medium/high end systems
+ {
+ uint8_t ps = iv_mark.getCM().getPortSlct();
+
+ // It is possible that a Centaur DIMM does not have spare DRAMs.
+ // Check the VPD for available spares. Note that a x4 DIMM may have
+ // one or two spare DRAMs so check for availability on both.
+ // TODO: RTC 68096 Add support for x4 DRAMs.
+ bool dramSparePossible = false;
+ o_rc = bitmap.isDramSpareAvailable( ps, dramSparePossible );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"isDramSpareAvailable() failed" );
+ break;
+ }
+
+ if ( dramSparePossible )
+ {
+ // Verify the spare is not already used.
+ CenSymbol sp0, sp1, ecc;
+ // TODO: RTC 68096 need to support ECC spare.
+ o_rc = mssGetSteerMux( mba, iv_rank, sp0, sp1, ecc );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"mssGetSteerMux() failed" );
+ break;
+ }
+
+ if ( ((0 == ps) && !sp0.isValid()) ||
+ ((1 == ps) && !sp1.isValid()) )
+ {
+ // A spare DRAM is available.
+ startDsdProcedure = true;
+ }
+ else if ( iv_mark.getCM().getDram() ==
+ (0 == ps ? sp0.getDram() : sp1.getDram()) )
+ {
+ io_sc.service_data->SetErrorSig( PRDFSIG_VcmBadSpare );
+
+ // The chip mark was on the spare DRAM and it is bad, so
+ // call it out and set it in VPD.
+
+ MemoryMru memmru ( mba, iv_rank, iv_mark.getCM() );
+ memmru.setDramSpared();
+ io_sc.service_data->SetCallout( memmru );
+ io_sc.service_data->SetServiceCall();
+
+ o_rc = bitmap.setDramSpare( ps );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setDramSpare() failed" );
+ break;
+ }
+ }
+ else
+ {
+ // Chip mark and DRAM spare are both used.
+ io_sc.service_data->SetErrorSig( PRDFSIG_VcmMarksUnavail );
+ io_sc.service_data->SetServiceCall();
+ }
+ }
+ else
+ {
+ // Chip mark is in place and sparing is not possible.
+ io_sc.service_data->SetErrorSig( PRDFSIG_VcmMarksUnavail );
+ io_sc.service_data->SetServiceCall();
+ }
+ }
+ else // Low end systems
+ {
+ // 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() )
+ {
+ io_sc.service_data->SetErrorSig( PRDFSIG_VcmMarksUnavail );
+ io_sc.service_data->SetServiceCall();
+ }
+ }
+
+ // Write VPD.
+ o_rc = setBadDqBitmap( mba, iv_rank, bitmap );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setBadDqBitmap() failed" );
+ break;
+ }
+
+ // Start DSD Phase 1, if possible.
+ if ( startDsdProcedure )
+ {
+ io_sc.service_data->SetErrorSig( PRDFSIG_StartDsdPhase1 );
+
+ o_rc = startDsdPhase1();
+ 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 CenMbaTdCtlr::handleMCE_DSD2( STEP_CODE_DATA_STRUCT & io_sc )
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::handleMCE_DSD2] "
+
+ int32_t o_rc = SUCCESS;
+
+ io_sc.service_data->SetErrorSig( PRDFSIG_DsdBadSpare );
+ io_sc.service_data->SetServiceCall();
+
+ TargetHandle_t mba = iv_mbaChip->GetChipHandle();
+
+ do
+ {
+ if ( DSD_PHASE_2 != iv_tdState )
+ {
+ PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" );
+ o_rc = FAIL; break;
+ }
+
+ // Callout mark and spare DRAM.
+ CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc );
+
+ MemoryMru memmru ( mba, iv_rank, iv_mark.getCM() );
+ memmru.setDramSpared();
+ io_sc.service_data->SetCallout( memmru );
+
+ // The spare DRAM is bad, so set it in VPD. At this point, the chip mark
+ // should have already been set in the VPD because it was recently
+ // verified.
+
+ CenDqBitmap bitmap;
+ o_rc = getBadDqBitmap( mba, iv_rank, bitmap );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"getBadDqBitmap() failed" );
+ break;
+ }
+
+ o_rc = bitmap.setDramSpare( iv_mark.getCM().getPortSlct() );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setDramSpare() failed" );
+ break;
+ }
+
+ o_rc = setBadDqBitmap( mba, iv_rank, bitmap );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"setBadDqBitmap() failed" );
+ break;
+ }
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::exitTdSequence()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::exitTdSequence] "
+
+ int32_t o_rc = SUCCESS;
+
+ do
+ {
+ // Clean up the previous command
+ // PRD is not starting another command but MDIA might be so clear the
+ // counters and FIRs as well.
+ o_rc = prepareNextCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" );
+ break;
+ }
+
+ // Inform MDIA about command complete
+ // Note that we only want to send the command complete message if
+ // everything above is successful because a bad return code will result
+ // in a SKIP_MBA message sent. There is no need to send redundant
+ // messages.
+ o_rc = signalMdiaCmdComplete();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"signalMdiaCmdComplete() failed" );
+ break;
+ }
+
+ // Clear out the mark, just in case. This is so we don't accidentally
+ // callout this mark on another rank in an error patch scenario.
+ iv_mark = CenMark();
+
+ } while (0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::prepareNextCmd()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::prepareNextCmd] "
+
+ int32_t o_rc = SUCCESS;
+
+ do
+ {
+ CenMbaDataBundle * mbadb = getMbaDataBundle( iv_mbaChip );
+ ExtensibleChip * membChip = mbadb->getMembChip();
+ if ( NULL == membChip )
+ {
+ PRDF_ERR( PRDF_FUNC"getMembChip() failed" );
+ o_rc = FAIL; break;
+ }
+
+ uint32_t mbaPos = getTargetPosition( iv_mbaChip->GetChipHandle() );
+
+ //----------------------------------------------------------------------
+ // Clean up previous command
+ //----------------------------------------------------------------------
+
+ o_rc = cleanupPrevCmd();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"cleanupPrevCmd() failed" );
+ break;
+ }
+
+ //----------------------------------------------------------------------
+ // Clear ECC counters
+ //----------------------------------------------------------------------
+
+ const char * reg_str = ( 0 == mbaPos ) ? "MBSTR_0" : "MBSTR_1";
+ SCAN_COMM_REGISTER_CLASS * mbstr = membChip->getRegister( reg_str );
+ o_rc = mbstr->Read();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"Read() failed on %s", reg_str );
+ break;
+ }
+
+ mbstr->SetBit(53); // Setting this bit clears all counters.
+
+ o_rc = mbstr->Write();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"Write() failed on %s", reg_str );
+ break;
+ }
+
+ // Hardware automatically clears bit 53, so flush this register out of
+ // the register cache to avoid clearing the counters again with a write
+ // from the out-of-date cached copy.
+ RegDataCache & cache = RegDataCache::getCachedRegisters();
+ cache.flush( membChip, mbstr );
+
+ //----------------------------------------------------------------------
+ // Clear ECC FIRs
+ //----------------------------------------------------------------------
+
+ reg_str = ( 0 == mbaPos ) ? "MBSECC01FIR_AND" : "MBSECC23FIR_AND";
+ SCAN_COMM_REGISTER_CLASS * firand = membChip->getRegister( reg_str );
+ firand->setAllBits();
+
+ // Clear MPE bit for this rank.
+ firand->ClearBit( 20 + iv_rank.flatten() );
+
+ // Clear NCE, SCE, MCE, RCE, SUE, UE bits (36-41)
+ firand->SetBitFieldJustified( 36, 6, 0 );
+
+ o_rc = firand->Write();
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"Write() failed on %s", reg_str );
+ break;
+ }
+
+ } while (0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+//------------------------------------------------------------------------------
+
+int32_t CenMbaTdCtlr::signalMdiaCmdComplete()
+{
+ #define PRDF_FUNC "[CenMbaTdCtlr::signalMdiaCmdComplete] "
+
+ int32_t o_rc = SUCCESS;
+
+ do
+ {
+ // Determine for MDIA whether or not the command finished at the end of
+ // the last rank or if the command will need to be restarted.
+
+ // Get the last address of the last rank in memory.
+ CenAddr junk, allEndAddr;
+ o_rc = getMemAddrRange( iv_mbaChip->GetChipHandle(), junk, allEndAddr );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"getMemAddrRange() failed" );
+ break;
+ }
+
+ // Get the address currently in the MBMEA.
+ CenAddr curEndAddr;
+ o_rc = getCenMaintEndAddr( iv_mbaChip, curEndAddr );
+ if ( SUCCESS != o_rc )
+ {
+ PRDF_ERR( PRDF_FUNC"cenGetMaintAddr() failed" );
+ break;
+ }
+
+ // The actual message will need to be sent in post analysis after the
+ // FIR bits have been cleared.
+ CenMbaDataBundle * mbadb = getMbaDataBundle( iv_mbaChip );
+ mbadb->iv_sendCmdCompleteMsg = true;
+ mbadb->iv_cmdCompleteMsgData =
+ (allEndAddr == curEndAddr) ? MDIA::COMMAND_COMPLETE
+ : MDIA::COMMAND_STOPPED;
+
+ } while(0);
+
+ return o_rc;
+
+ #undef PRDF_FUNC
+}
+
+} // end namespace PRDF
+
diff --git a/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H
new file mode 100644
index 000000000..807211e30
--- /dev/null
+++ b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H
@@ -0,0 +1,174 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2013 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/** @file prdfCenMbaTdCtlr.H
+ * @brief The Hostboot implementation of the MBA TD Controller.
+ */
+
+#ifndef __prdfCenMbaTdCtlr_H
+#define __prdfCenMbaTdCtlr_H
+
+#include <prdfCenMbaTdCtlr_common.H>
+
+namespace PRDF
+{
+
+/**
+ * @brief A state machine for memory targeted diagnostics during Hostboot MDIA.
+ */
+class CenMbaTdCtlr : public CenMbaTdCtlrCommon
+{
+ private: // constants, enums
+
+ /**
+ * @brief Lists all possible states of TD controller
+ * @note These enums are used as array indexes to cv_cmdCompleteFuncs and
+ * the last entry will be used to get the size of the array.
+ */
+ enum TdState
+ {
+ NO_OP = 0, ///< No TD procedures in place.
+ VCM_PHASE_1, ///< Verify Chip Mark phase 1.
+ VCM_PHASE_2, ///< Verify Chip Mark phase 2.
+ DSD_PHASE_1, ///< DRAM Spare Deploy phase 1.
+ DSD_PHASE_2, ///< DRAM Spare Deploy phase 2.
+ MAX_TD_STATE ///< The maximum number of TD states.
+ };
+
+ // Function pointers for maintenance command complete events.
+ typedef int32_t (CenMbaTdCtlr::*CMD_COMPLETE_FUNCS)
+ ( STEP_CODE_DATA_STRUCT & io_sc );
+
+ public: // functions
+
+ /**
+ * @brief Constructor
+ *
+ * This contructor will be called in the MBA data bundle code. Therefore,
+ * no register reads/writes can be done in this constructor. Anything needed
+ * to initialize the instance variables that requires register reads/writes
+ * or is non-trivial should be done in initialize().
+ *
+ * @param i_mbaChip An MBA chip.
+ */
+ explicit CenMbaTdCtlr( ExtensibleChip * i_mbaChip ) :
+ CenMbaTdCtlrCommon(i_mbaChip), iv_tdState(NO_OP)
+ {}
+
+ public: // Overloaded functions
+
+ int32_t handleCmdCompleteEvent( STEP_CODE_DATA_STRUCT & io_sc );
+
+ private: // Overloaded functions
+
+ int32_t initialize();
+
+ int32_t analyzeCmdComplete( STEP_CODE_DATA_STRUCT & io_sc );
+ int32_t analyzeVcmPhase1( STEP_CODE_DATA_STRUCT & io_sc );
+ int32_t analyzeVcmPhase2( STEP_CODE_DATA_STRUCT & io_sc );
+ int32_t analyzeDsdPhase1( STEP_CODE_DATA_STRUCT & io_sc );
+ int32_t analyzeDsdPhase2( STEP_CODE_DATA_STRUCT & io_sc );
+
+ int32_t startVcmPhase1();
+ int32_t startVcmPhase2();
+ int32_t startDsdPhase1();
+ int32_t startDsdPhase2();
+
+ bool isInTdMode();
+
+ private: // functions
+
+ /**
+ * @brief Checks if ECC errors have occurred during a maintenance command.
+ * @param o_eccErrorMask Bitwise mask indicating which ECC errors have
+ * occurred.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ int32_t checkEccErrors( uint8_t & o_eccErrorMask );
+
+ /**
+ * @brief Handle UEs during TD analysis.
+ * @param io_sc Service data collector.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ int32_t handleUE( STEP_CODE_DATA_STRUCT & io_sc );
+
+ /**
+ * @brief Handle MCE event during VCM Phase 2
+ * @param io_sc Service data collector.
+ * @note This will update bad bits information in VPD, set callouts, and
+ * start the DRAM sparing procedure, if possible.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ int32_t handleMCE_VCM2( STEP_CODE_DATA_STRUCT & io_sc );
+
+ /**
+ * @brief Handle MCE event during DSD Phase 2
+ * @param io_sc Service data collector.
+ * @note This will update bad bits information in VPD and set callouts.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ int32_t handleMCE_DSD2( STEP_CODE_DATA_STRUCT & io_sc );
+
+ /**
+ * @brief Handle cleanup when TD sequence is complete and TD state machine
+ * will reset.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ int32_t exitTdSequence();
+
+ /**
+ * @brief Preforms cleanup tasks that need to be done before starting the
+ * next maintenance command (i.e. clear scrub counter).
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ int32_t prepareNextCmd();
+
+ /**
+ * @brief Sends a message to MDIA that a maintenance command has completed.
+ * @note If for some reason PRD needed to do some targeted diagnotics and
+ * on a rank that was not the last rank behind the MBA, this
+ * function will need to send a message to MDIA indicating that the
+ * command stopped and MDIA will need to restart the pattern testing
+ * from the next address to the end of memory.
+ * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise.
+ */
+ int32_t signalMdiaCmdComplete();
+
+ private: // instance variables
+
+ /** The targeted diagnostics state variable (see enum TdState). */
+ TdState iv_tdState;
+
+ /** Array of functions pointers for TD controller states. This is used to
+ * determine the next course of action after a maintenance command complete
+ * attention.
+ */
+ static CMD_COMPLETE_FUNCS cv_cmdCompleteFuncs[MAX_TD_STATE];
+
+}; // CenMbaTdCtlr
+
+} // end namespace PRDF
+
+#endif // __prdfCenMbaTdCtlr_H
+
diff --git a/src/usr/diag/prdf/test/prdfTest_Mba.H b/src/usr/diag/prdf/test/prdfTest_Mba.H
index eae23077a..7730e88da 100644
--- a/src/usr/diag/prdf/test/prdfTest_Mba.H
+++ b/src/usr/diag/prdf/test/prdfTest_Mba.H
@@ -62,9 +62,8 @@ class MBAFIR:public CxxTest::TestSuite
}
}
- void TestCheckstop(void)
+ void DISABLED_TestCheckstop(void)
{
- /*
PRDS_BEGIN("MBAFIR01 Checkstop attention");
PRDS_ERROR_ENTRY("NODE{0}:MEMBUF{4}", PRDF::CHECK_STOP);
PRDS_EXPECTED_SIGNATURE("NODE{0}:MEMBUF{4}:MBS{0}:MBA{0}", 0x43f10002);
@@ -82,26 +81,7 @@ class MBAFIR:public CxxTest::TestSuite
{
TS_FAIL("Expected Signature Failed MBAFIR01 Checkstop attention");
}
- */
}
- void TestSpecialAttention(void)
- {
- PRDS_BEGIN("MBAFIR01 Special attention");
- PRDS_ERROR_ENTRY("NODE{0}:MEMBUF{4}", PRDF::SPECIAL);
- PRDS_EXPECTED_SIGNATURE("NODE{0}:MEMBUF{4}:MBS{0}:MBA{0}", 0x9e8b0000);
- // PRDS_EXPECTED_CALLOUT(NONE);
- // GLOBAL_RE_FIR
- PRDS_SCR_WRITE("NODE{0}:MEMBUF{4}", 0x570F001A, 0x1000000000000000);
- // MEM_CHIPLET_CS_FIR[0] Attention from MBAFIR01
- PRDS_SCR_WRITE("NODE{0}:MEMBUF{4}", 0x03040004, 0x8000000000000000);
- // set MBAFIR01[0]
- PRDS_SCR_WRITE("NODE{0}:MEMBUF{4}:MBS{0}:MBA{0}", 0x03010611, 0x8000000000000000);
- PRDS_START_SIM();
- if(!(PRDS_END()))
- {
- TS_FAIL("Expected Signature Failed MBAFIR01 Special attention");
- }
- }
};
#endif
OpenPOWER on IntegriCloud