summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonald Washburn <dwashbur@us.ibm.com>2017-08-17 10:28:05 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2017-11-01 17:06:39 -0400
commit5e731ccc76d458e752e465471e27a40dd6011e5b (patch)
tree33792894597adf1c3073d3ed522bc6ab253ea4d1
parent89c19d7e3a5b6f2781636ca5373672f38d8f0a13 (diff)
downloadtalos-hostboot-5e731ccc76d458e752e465471e27a40dd6011e5b.tar.gz
talos-hostboot-5e731ccc76d458e752e465471e27a40dd6011e5b.zip
Work around for SCOM DMI bug on Cumulus.
Work-around for HW415185. On a cumulus system reads from the first 6 DMI SCOM registers need to be read twice to obtain correct values. It is desired to implement a workaround in the SCOM driver that will force a retry for any reads from these registers until a hardware fix is in place. *Implemented a framework for executing post operation actions following a scom device operation. Currently the only post operation action defined is the retry request operation. The purpose of the framework is to remove workaround logic from the device operation code and place it in easily removable individual source files as work-arounds are expected to be temporary in nature. *Move existing retry request for IBSCOM retries to a new class IbScomRetry. *Created the PostOpRetryCheck base class for the workaround framework. *Created a top-level composite pattern class used for invoking request logic - PostOpChecks. *Created a workaround class - DmiSomWorkaround for querying DMI retry requests. *Modified the doScomOp method to invoke the framework to test for retries. Removed retry recursion. *Created Unit Tests. *Created integration test. RTC: 177025 Change-Id: If4a1ecc57dd5978e5d1717a42c63cdc1698f4563 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/45104 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Prachi Gupta <pragupta@us.ibm.com> Reviewed-by: Corey V. Swenson <cswenson@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
-rw-r--r--src/usr/scom/DmiScomWorkaround.C295
-rw-r--r--src/usr/scom/DmiScomWorkaround.H152
-rw-r--r--src/usr/scom/ibscom_retry.C79
-rw-r--r--src/usr/scom/ibscom_retry.H100
-rw-r--r--src/usr/scom/makefile4
-rw-r--r--src/usr/scom/postopchecks.C132
-rw-r--r--src/usr/scom/postopchecks.H215
-rw-r--r--src/usr/scom/scom.C207
-rw-r--r--src/usr/scom/scom.mk3
-rw-r--r--src/usr/scom/test/DmiScomWorkaround_for_test.H133
-rw-r--r--src/usr/scom/test/DmiScomWorkaround_test.H632
-rw-r--r--src/usr/scom/test/ibscom_retry_test.H281
-rw-r--r--src/usr/scom/test/makefile13
-rw-r--r--src/usr/scom/test/postopchecks_test.H670
-rw-r--r--src/usr/scom/test/retryWorkaroundTestData.C188
-rw-r--r--src/usr/scom/test/retryWorkaroundTestData.H35
16 files changed, 3056 insertions, 83 deletions
diff --git a/src/usr/scom/DmiScomWorkaround.C b/src/usr/scom/DmiScomWorkaround.C
new file mode 100644
index 000000000..589df7c1d
--- /dev/null
+++ b/src/usr/scom/DmiScomWorkaround.C
@@ -0,0 +1,295 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/DmiScomWorkaround.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "DmiScomWorkaround.H"
+
+#include <devicefw/driverif.H>
+#include <targeting/common/targetservice.H>
+#include <targeting/common/utilFilter.H>
+#include <trace/interface.H>
+#include <util/misc.H>
+
+#include <algorithm>
+
+extern trace_desc_t* g_trac_scom;
+
+#define SCOM_DMI_WA_TRACD(printf_string,args...) \
+ TRACDCOMP(g_trac_scom,"DmiScomWorkaround::" printf_string,##args)
+
+namespace SCOM
+{
+
+uint64_t DmiScomWorkaround::cv_model_cumulus = 0;
+
+//---------------------------------------------------------------------------
+bool DmiScomWorkaround::requestRetry(errlHndl_t i_errl,
+ uint32_t i_retryCount,
+ DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* i_buffer,
+ size_t i_buflen,
+ int64_t i_accessType,
+ uint64_t i_addr
+ ) const
+{
+ constexpr uint64_t MODEL_UNINITIALIZED=0x00;
+ constexpr uint64_t MODEL_IS_CUMULUS=0x01;
+ constexpr uint64_t MODEL_IS_NOT_CUMULUS=0x02;
+
+ bool l_retval{false};
+
+ do
+ {
+ uint64_t l_model_cumulus = __sync_fetch_and_add(&cv_model_cumulus, 0);
+
+ // useCachedProcModel is a dependency injection seam that
+ // allows us to obtain the processor model with every call
+ // to support unit testing with mocked targets. In non-test
+ // code useCachedProcModel always returns true and the
+ // Processor model is cached for performance optimization.
+ if(useCachedProcModel())
+ {
+ //If the model is not cumulus then the workaround is not applicable
+ if(MODEL_IS_NOT_CUMULUS ==
+ (MODEL_IS_NOT_CUMULUS & l_model_cumulus))
+ {
+ break;
+ }
+ }
+
+ //The workaround is only valid for READ operations
+ if(DeviceFW::READ != i_opType)
+ {
+ break;
+ }
+
+ //we only need one retry at most.
+ if(i_retryCount > 0)
+ {
+ break;
+ }
+
+ if(nullptr == i_target)
+ {
+ break;
+ }
+
+ //Get the target type. We are only concerned with processor
+ //targets.
+ TARGETING::ATTR_TYPE_type l_type = TARGETING::TYPE_NA;
+ if(not getTargetType(i_target, l_type))
+ {
+ break;
+ }
+
+ if(TARGETING::TYPE_PROC != l_type)
+ {
+ break;
+ }
+
+ //The workaround is only applicable to CUMULUS models.
+ //If the model has not yet been determined, then discover
+ //the model in order to avoid future processing when running on a
+ //non-cumulus model. This code block is run only until the
+ //processor model is discovered, after which the check at the
+ //beginning of the method tests for the correct model.
+ if(MODEL_UNINITIALIZED == l_model_cumulus || !useCachedProcModel())
+ {
+ TARGETING::ATTR_MODEL_type l_model;
+ if(getTargetModel(i_target, l_model))
+ {
+ const char* model_name = "Unknown";
+
+ if(TARGETING::MODEL_CUMULUS != l_model)
+ {
+ if(useCachedProcModel())
+ {
+ //Cache model for a quick check at the start
+ //of the routine.
+ __sync_fetch_and_or(&cv_model_cumulus,
+ MODEL_IS_NOT_CUMULUS);
+ }
+
+ if(TARGETING::MODEL_NIMBUS == l_model)
+ {
+ model_name = "NIMBUS";
+ }
+
+ SCOM_DMI_WA_TRACD("requestRetry: "
+ "%s System Detected!",
+ model_name
+ );
+
+ break;
+ }
+ else
+ {
+ if(useCachedProcModel())
+ {
+ //Cache model for a quick check at the start
+ //of the routine.
+ __sync_fetch_and_or(&cv_model_cumulus,
+ MODEL_IS_CUMULUS);
+ }
+
+ model_name = "CUMULUS";
+
+ SCOM_DMI_WA_TRACD("requestRetry: "
+ "%s System Detected!",
+ model_name
+ );
+ }
+ }
+ }
+
+ //we'll check the EC Level every time in case
+ //a system is encountered with different EC Levels
+ uint8_t l_ecLevel{};
+ if(getTargetECLevel(i_target, l_ecLevel))
+ {
+ if(0x0 != l_ecLevel && 0x10 != l_ecLevel)
+ {
+ break;
+ }
+ }
+
+ // Match Address Formats 0x050108[23ab][3-a]
+ // 0x030108[23ab][3-a]
+ //
+ // Step 1: Check that the prefix matches 0x050108XX or 0x030108XX
+ // Step 2: Check that the last nibble of the address in [0x3,0xa]
+ // Step 3: Check that the 3rd bit of nibble 2 is not set and the
+ // 2nd bit is set.
+ // 2 - 0010
+ // 3 - 0011
+ // a - 1010
+ // b - 1011
+ if(
+ (((0xFFFFFF00 & i_addr) == 0x05010800) ||
+ ((0xFFFFFF00 & i_addr) == 0x03010800)) &&
+ (((0x0000000F & i_addr) >= 0x00000003) &&
+ ((0x0000000F & i_addr) <= 0x0000000a)) &&
+ (((0x00000040 | 0x00000020) & i_addr) == 0x00000020)
+ )
+ {
+ l_retval = true;
+ }
+ }
+ while(0);
+
+ if(l_retval)
+ {
+ incRetryCount();
+ }
+
+ return l_retval;
+}
+
+//----------------------------------------------------------------------------
+std::shared_ptr<const PostOpRetryCheck> DmiScomWorkaround::theInstance()
+{
+ static std::shared_ptr<const PostOpRetryCheck>
+ ls_instance(new DmiScomWorkaround);
+
+ return ls_instance;
+}
+
+//----------------------------------------------------------------------------
+bool DmiScomWorkaround::getTargetType(TARGETING::Target* i_target,
+ TARGETING::TYPE& o_type) const
+{
+ bool l_retval{false};
+
+ if(nullptr != i_target)
+ {
+ if(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target)
+ {
+ o_type = TARGETING::TYPE_PROC;
+ l_retval = true;
+ }
+ else if(i_target->tryGetAttr<TARGETING::ATTR_TYPE>(o_type))
+ {
+ l_retval = true;
+ }
+ }
+
+ return l_retval;
+}
+
+//----------------------------------------------------------------------------
+bool DmiScomWorkaround::getTargetModel(TARGETING::Target* i_target,
+ TARGETING::MODEL& o_model) const
+{
+ bool l_retval{false};
+ TARGETING::MODEL l_model = TARGETING::MODEL_NA;
+ TARGETING::TYPE l_type = TARGETING::TYPE_NA;
+
+ if(nullptr != i_target &&
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL != i_target)
+ {
+ if(getTargetType(i_target, l_type))
+ {
+ if(TARGETING::TYPE_PROC == l_type)
+ {
+ if(i_target->tryGetAttr<TARGETING::ATTR_MODEL>(l_model))
+ {
+ o_model = l_model;
+ l_retval = true;
+ }
+ }
+ }
+ }
+
+ return l_retval;
+}
+
+//---------------------------------------------------------------------------
+bool DmiScomWorkaround::getTargetECLevel(TARGETING::Target* i_target,
+ uint8_t& o_ecLevel) const
+{
+ bool l_retval{false};
+ uint8_t l_ecLevel{0};
+
+ if(nullptr != i_target &&
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL != i_target)
+ {
+ TARGETING::TYPE l_type = TARGETING::TYPE_NA;
+
+ if(getTargetType(i_target, l_type))
+ {
+ if(TARGETING::TYPE_PROC == l_type)
+ {
+ if(i_target->tryGetAttr<TARGETING::ATTR_EC>(l_ecLevel))
+ {
+ o_ecLevel = l_ecLevel;
+ l_retval = true;
+ }
+ }
+ }
+ }
+
+ return l_retval;
+}
+
+} //End Namespace
diff --git a/src/usr/scom/DmiScomWorkaround.H b/src/usr/scom/DmiScomWorkaround.H
new file mode 100644
index 000000000..7c7428985
--- /dev/null
+++ b/src/usr/scom/DmiScomWorkaround.H
@@ -0,0 +1,152 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/DmiScomWorkaround.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SCOM_DMI_SCOM_WORKAROUND_H
+#define __SCOM_DMI_SCOM_WORKAROUND_H
+
+#include "postopchecks.H"
+#include <targeting/common/target.H>
+
+#include <memory>
+
+namespace SCOM
+{
+
+/**
+ * @brief Workaround for SCOM Bug. The workaround
+ * requires a retry of read operations for certain sets
+ * of DMI SCOM registers.
+ */
+class DmiScomWorkaround: public PostOpRetryCheck
+{
+
+public:
+ //only one instance is allowed.
+ DmiScomWorkaround(const DmiScomWorkaround&)=delete;
+ DmiScomWorkaround(DmiScomWorkaround&&)=delete;
+ DmiScomWorkaround& operator=(const DmiScomWorkaround&)=delete;
+ DmiScomWorkaround& operator=(DmiScomWorkaround&&)=delete;
+
+ virtual ~DmiScomWorkaround() = default;
+
+ /**
+ * @brief Determine if a retry is needed given a device
+ * operation and previous results.
+ *
+ * @param[in] i_errl. The error associated with the previous
+ * scom operation. Not Used for this workaround.
+ * @param[in] i_retryCount. How many retries were made prior
+ * to this call. This workaround will only
+ * support 1 retry.
+ * @param[in] i_opType. The scom operation being attempted.
+ * This workaround is only applicable
+ * for read operations.
+ * @param[in] i_target. The target of the scom operation.
+ * The workaround is valid only for
+ * PROC and DMI targets.
+ * @param[in] i_buffer. The buffer for the scom operation.
+ * Not used for this workaround.
+ * @param[in] i_buflen. The length of the buffer for the scom
+ * operation. Not used for this workaround.
+ * @param[in] i_accessType. The access type for the scom operation.
+ * Not used for this workaround.
+ * @param[in] i_addr. The address for the scom operation. The address
+ * is used to determine if we need to retry a SCOM
+ * read.
+ *
+ * @return True if a retry should be attempted, False otherwise.
+ */
+ bool requestRetry(errlHndl_t i_errl,
+ uint32_t i_retryCount,
+ DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* i_buffer,
+ size_t i_buflen,
+ int64_t i_accessType,
+ uint64_t i_addr
+ ) const override;
+
+ /**
+ * @brief Access the single instance of this class.
+ */
+ static std::shared_ptr<const PostOpRetryCheck> theInstance();
+
+protected:
+ DmiScomWorkaround()=default;
+
+ //Unit Test Method Injection Seams.
+
+ /**
+ * @brief Obtain the type of the passed in target.
+ *
+ * @param[in] i_target. The target whose type we are trying to determine.
+ * @param[out] o_type. The type of i_target.
+ *
+ * @return True if successful, False otherwise.
+ */
+ virtual bool getTargetType(TARGETING::Target* i_target,
+ TARGETING::TYPE& o_type) const;
+
+ /**
+ * @brief Obtain the processor model if the passed in target is a
+ * PROC target.
+ *
+ * @param[in] i_target. The target from which we would like to determine
+ * the processor model.
+ * @param[out] o_model. The processor model if successful.
+ *
+ * @return True if successful, False otherwise.
+ */
+ virtual bool getTargetModel(TARGETING::Target* i_target,
+ TARGETING::MODEL& o_model) const;
+
+ /**
+ * @brief Obtain the processor EC Level if the passed in target is a
+ * PROC target.
+ *
+ * @param[in] i_target. The target from which we would like to determine
+ * the processor model.
+ * @param[out] o_ecLevel. The processor model if successful.
+ *
+ * @return True if successful, False otherwise.
+ */
+ virtual bool getTargetECLevel(TARGETING::Target* i_target,
+ uint8_t& o_ecLevel) const;
+
+ /**
+ * @brief - Allows us to create tests where the model is obtained
+ * for every call. The proc model should not be cached for
+ * unit tests in order to allow mocked targets of various
+ * models. In non-test code this method always returns true.
+ */
+ virtual bool useCachedProcModel() const {return true;}
+
+private:
+
+ static uint64_t cv_model_cumulus;
+};
+
+}
+
+#endif
diff --git a/src/usr/scom/ibscom_retry.C b/src/usr/scom/ibscom_retry.C
new file mode 100644
index 000000000..2bf54714f
--- /dev/null
+++ b/src/usr/scom/ibscom_retry.C
@@ -0,0 +1,79 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/ibscom_retry.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "ibscom_retry.H"
+#include <ibscom/ibscomreasoncodes.H>
+
+namespace SCOM
+{
+
+//----------------------------------------------------------------------------
+std::shared_ptr<const PostOpRetryCheck> IbscomRetry::theInstance()
+{
+ static std::shared_ptr<const PostOpRetryCheck>
+ ls_instance(new IbscomRetry);
+
+ return ls_instance;
+}
+
+//---------------------------------------------------------------------------
+bool IbscomRetry::requestRetry(errlHndl_t i_errl,
+ uint32_t i_retryCount,
+ DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* i_buffer,
+ size_t i_buflen,
+ int64_t i_accessType,
+ uint64_t i_addr
+ ) const
+{
+ bool l_retval{false};
+
+ do
+ {
+ if(i_retryCount > 0)
+ {
+ break;
+ }
+ else if(nullptr == i_errl)
+ {
+ break;
+ }
+
+ if(IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR == i_errl->reasonCode())
+ {
+ l_retval = true;
+ }
+ }
+ while(0);
+
+ if(l_retval)
+ {
+ incRetryCount();
+ }
+
+ return l_retval;
+}
+
+} //End Namespace
diff --git a/src/usr/scom/ibscom_retry.H b/src/usr/scom/ibscom_retry.H
new file mode 100644
index 000000000..e18155c19
--- /dev/null
+++ b/src/usr/scom/ibscom_retry.H
@@ -0,0 +1,100 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/ibscom_retry.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SCOM_IBSCOM_RETRY_H
+#define __SCOM_IBSCOM_RETRY_H
+
+#include "postopchecks.H"
+#include <memory>
+
+namespace SCOM
+{
+
+/**
+ * @brief Class to enable checking if a retry is required
+ * based upon the error reason code. If a scom
+ * operation returns an errlHndl_t with reason
+ * code set to IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR, then
+ * one retry will be requested.
+ */
+class IbscomRetry: public PostOpRetryCheck
+{
+public:
+ IbscomRetry(const IbscomRetry&)=delete;
+ IbscomRetry(IbscomRetry&&)=delete;
+ IbscomRetry& operator=(const IbscomRetry&)=delete;
+ IbscomRetry& operator=(IbscomRetry&&)=delete;
+
+ virtual ~IbscomRetry()=default;
+
+ /**
+ * @brief Determine if a retry is needed given a device
+ * operation and previous results.
+ *
+ * @param[in] i_errl. The error associated with the previous
+ * scom operation. A workaround will be requested
+ * if the error code is
+ * IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR.
+ * @param[in] i_retryCount. How many retries were made prior
+ * to this call. This workaround will only
+ * support 1 retry.
+ * @param[in] i_opType. The scom operation being attempted.
+ * This workaround does not use this value.
+ * @param[in] i_target. The target of the scom operation.
+ * This workaround does not use this value.
+ * @param[in] i_buffer. The buffer for the scom operation.
+ * This workaround does not use this value.
+ * @param[in] i_buflen. The length of the buffer for the scom
+ * operation. This workaround does not use
+ * this value.
+ * @param[in] i_accessType. The access type for the scom operation.
+ * Not used for this workaround.
+ * @param[in] i_addr. The address for the scom operation. The address
+ * is used to determine if we need to retry a SCOM
+ * read.
+ *
+ * @return True if a retry should be attempted, False otherwise.
+ */
+ bool requestRetry(errlHndl_t i_errl,
+ uint32_t i_retryCount,
+ DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* i_buffer,
+ size_t i_buflen,
+ int64_t i_accessType,
+ uint64_t i_addr
+ ) const override;
+
+ /**
+ * @brief Access the single instance of this class.
+ */
+ static std::shared_ptr<const PostOpRetryCheck> theInstance();
+
+protected:
+ IbscomRetry()=default;
+};
+
+} //End Namespace
+
+#endif
diff --git a/src/usr/scom/makefile b/src/usr/scom/makefile
index 3bb314d41..8ca16f829 100644
--- a/src/usr/scom/makefile
+++ b/src/usr/scom/makefile
@@ -5,7 +5,9 @@
#
# OpenPOWER HostBoot Project
#
-# COPYRIGHT International Business Machines Corp. 2011,2014
+# Contributors Listed Below - COPYRIGHT 2011,2017
+# [+] International Business Machines Corp.
+#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/src/usr/scom/postopchecks.C b/src/usr/scom/postopchecks.C
new file mode 100644
index 000000000..fc7e79daf
--- /dev/null
+++ b/src/usr/scom/postopchecks.C
@@ -0,0 +1,132 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/postopchecks.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "postopchecks.H"
+
+//=========================
+// Workarounds
+// Each workaround needs to be added to the composite
+// PostOpChecks instance.
+#include "DmiScomWorkaround.H"
+#include "ibscom_retry.H"
+//=========================
+
+namespace SCOM
+{
+
+//--------------------------------------------------------------------------
+PostOpChecks::PostOpChecks(
+ std::initializer_list<std::shared_ptr<const PostOpRetryCheck>> i_retrychecks):
+ iv_retryChecks{i_retrychecks}
+{
+}
+
+//------------------------------------------------------------------------
+const PostOpChecks* PostOpChecks::theInstance()
+{
+ static const PostOpChecks* ls_instance =
+ new PostOpChecks{
+ IbscomRetry::theInstance(),
+ DmiScomWorkaround::theInstance()
+ };
+
+ return ls_instance;
+}
+
+//---------------------------------------------------------------------------
+bool PostOpChecks::requestRetry(errlHndl_t i_errl,
+ uint32_t i_retryCount,
+ DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* i_buffer,
+ size_t i_buflen,
+ int64_t i_accessType,
+ uint64_t i_addr
+ ) const
+{
+ bool l_retval{false};
+ size_t l_workaroundCount = iv_retryChecks.size();
+
+ for(size_t i = 0; i < l_workaroundCount; ++i)
+ {
+ const std::shared_ptr<const PostOpRetryCheck>&
+ l_currentCheck = iv_retryChecks[i];
+ if(l_currentCheck)
+ {
+ l_retval = l_currentCheck->requestRetry(i_errl,
+ i_retryCount,
+ i_opType,
+ i_target,
+ i_buffer,
+ i_buflen,
+ i_accessType,
+ i_addr
+ );
+ if(l_retval)
+ {
+ break;
+ }
+
+ }
+ }
+
+ return l_retval;
+}
+
+//-----------------------------------------------------------------
+uint64_t PostOpChecks::getRetryCount() const
+{
+ uint64_t l_retval{};
+ const size_t l_workaroundCount = iv_retryChecks.size();
+
+ for(size_t i = 0; i < l_workaroundCount; ++i)
+ {
+ const std::shared_ptr<const PostOpRetryCheck>&
+ l_currentCheck = iv_retryChecks[i];
+ if(l_currentCheck)
+ {
+ l_retval += l_currentCheck->getRetryCount();
+ }
+ }
+
+ return l_retval;
+}
+
+//--------------------------------------------------------------------
+void PostOpChecks::resetRetryCount() const
+{
+ const size_t l_workaroundCount = iv_retryChecks.size();
+
+ for(size_t i = 0; i < l_workaroundCount; ++i)
+ {
+ const std::shared_ptr<const PostOpRetryCheck>&
+ l_currentCheck = iv_retryChecks[i];
+ if(l_currentCheck)
+ {
+ l_currentCheck->resetRetryCount();
+ }
+ }
+}
+
+} // End Namespace
diff --git a/src/usr/scom/postopchecks.H b/src/usr/scom/postopchecks.H
new file mode 100644
index 000000000..22a1db15e
--- /dev/null
+++ b/src/usr/scom/postopchecks.H
@@ -0,0 +1,215 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/postopchecks.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SCOM_POST_OP_CHECKS_H
+#define __SCOM_POST_OP_CHECKS_H
+
+#include <devicefw/driverif.H>
+#include <errl/errlentry.H>
+#include <targeting/common/target.H>
+
+#include <initializer_list>
+#include <memory>
+#include <vector>
+
+namespace SCOM
+{
+/**
+ * @brief Base class for post device operation.
+ *
+ * This base class and derived classes are intended to facilitate
+ * refactoring of workarounds, temporary or otherwise from the
+ * main flow of a device operation. This permits workarounds to be
+ * easily added and removed without polluting the device operation
+ * code and facilitates unit testing.
+ *
+ * To Add a workaround: Derive a class from PostOpRetryCheck and
+ * place it in separate source and header files. Then add a
+ * reference to a global instance of the class to the PostOpChecks
+ * global instance constructor. The requestRetry function should
+ * be fast and re-entrant.
+ *
+ * To Remove a workaround: Delete the workaround source files and
+ * remove any references to the global instances from the PostOpChecks
+ * constructor.
+ *
+ */
+class PostOpRetryCheck
+{
+public:
+ //Only a single instance is allowed.
+ PostOpRetryCheck(const PostOpRetryCheck&)=delete;
+ PostOpRetryCheck(PostOpRetryCheck&&)=delete;
+ PostOpRetryCheck& operator=(const PostOpRetryCheck&)=delete;
+ PostOpRetryCheck& operator=(PostOpRetryCheck&&)=delete;
+
+ /**
+ * @brief Determine if a retry is needed given a device
+ * operation and previous results.
+ *
+ * @param[in] i_errl. The error associated with the previous
+ * scom operation.
+ * @param[in] i_retryCount. How many retries were made prior
+ * to this call.
+ * @param[in] i_opType. The scom operation being attempted.
+ * @param[in] i_target. The target of the scom operation.
+ * @param[in] i_buffer. The buffer for the scom operation.
+ * @param[in] i_buflen. The length of the buffer for the scom
+ * operation.
+ *
+ * @param[in] i_accessType. The access type for the scom operation.
+ * @param[in] i_addr. The address for the scom operation.
+ *
+ * @return True if a retry should be attempted, False otherwise.
+ */
+ virtual bool requestRetry(errlHndl_t i_errl,
+ uint32_t i_retryCount,
+ DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* i_buffer,
+ size_t i_buflen,
+ int64_t i_accessType,
+ uint64_t i_addr
+ ) const = 0;
+
+ virtual ~PostOpRetryCheck() = default;
+
+ //Integration Testing Support
+
+ /**
+ * @brief Accessor for the iv_retryCount member. The method is virtual
+ * to allow the PostOpChecks container class to implement this method
+ * by adding the count of it's contained objects.
+ *
+ * @return The number of retries requested by this component.
+ */
+ virtual uint64_t getRetryCount() const
+ {return __sync_fetch_and_add(&iv_retryCount,0);}
+
+ /**
+ * @brief Reset the iv_retryCount member to zero.
+ */
+ virtual void resetRetryCount() const
+ {__sync_fetch_and_and(&iv_retryCount,0);}
+
+protected:
+ PostOpRetryCheck()=default;
+
+ /**
+ * @brief Increment the retry count for this object.
+ */
+ void incRetryCount() const {__sync_fetch_and_add(&iv_retryCount, 1);}
+
+private:
+ mutable uint64_t iv_retryCount{0}; /**< The number of retries requested by
+ this instance.*/
+};
+
+
+/**
+ * @brief composite pattern for invoking PostOpRetryCheck
+ * methods upon a group of contained objects.
+ */
+class PostOpChecks: public PostOpRetryCheck
+{
+public:
+ //Only a single instance is allowed.
+ PostOpChecks(const PostOpChecks&)=delete;
+ PostOpChecks(PostOpChecks&&)=delete;
+ PostOpChecks& operator=(const PostOpChecks&)=delete;
+ PostOpChecks& operator=(PostOpChecks&&)=delete;
+
+ virtual ~PostOpChecks() = default;
+
+ /**
+ * @brief Determine if a retry is needed given a device
+ * operation and previous results. This class will implement
+ * the composite pattern and invoke the same virtual function
+ * on contained interfaces until a retry request is encountered
+ * or until all children have been queried.
+ *
+ * @param[in] i_errl. The error associated with the previous
+ * scom operation.
+ * @param[in] i_retryCount. How many retries were made prior
+ * to this call.
+ * @param[in] i_opType. The scom operation being attempted.
+ * @param[in] i_target. The target of the scom operation.
+ * @param[in] i_buffer. The buffer for the scom operation.
+ * @param[in] i_buflen. The length of the buffer for the scom
+ * operation.
+ *
+ * @param[in] i_accessType. The access type for the scom operation.
+ * @param[in] i_addr. The address for the scom operation.
+ *
+ * @return True if a retry should be attempted, False otherwise.
+ */
+ bool requestRetry(errlHndl_t i_errl,
+ uint32_t i_retryCount,
+ DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* i_buffer,
+ size_t i_buflen,
+ int64_t i_accessType,
+ uint64_t i_addr
+ ) const override;
+
+ //Integration Test support
+
+ /**
+ * @brief Accessor for the iv_retryCount member.
+ *
+ * @return The number of retries requested by all children of
+ * this component.
+ */
+ uint64_t getRetryCount() const override;
+
+ /**
+ * @brief Reset the retry count member of all children to zero.
+ */
+ void resetRetryCount() const override;
+
+ /**
+ * @brief Access the single instance of this class.
+ */
+ static const PostOpChecks* theInstance();
+
+protected:
+
+ /**
+ * @brief CTOR.
+ *
+ * @param[in] i_retrychecks. A list of PostOpRetryCheck interfaces that
+ * will be queried for retries.
+ *
+ */
+ PostOpChecks(
+ std::initializer_list<std::shared_ptr<const PostOpRetryCheck>> i_retry);
+
+private:
+ const std::vector<std::shared_ptr<const PostOpRetryCheck>> iv_retryChecks;
+};
+
+}
+
+#endif
diff --git a/src/usr/scom/scom.C b/src/usr/scom/scom.C
index cf65dba85..e6d1a9135 100644
--- a/src/usr/scom/scom.C
+++ b/src/usr/scom/scom.C
@@ -37,6 +37,7 @@
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
#include "scom.H"
+#include "postopchecks.H"
#include <scom/scomreasoncodes.H>
#include <scom/errlud_pib.H>
#include <ibscom/ibscomreasoncodes.H>
@@ -769,9 +770,11 @@ errlHndl_t doScomOp(DeviceFW::OperationType i_opType,
int64_t i_accessType,
uint64_t i_addr)
{
-
errlHndl_t l_err = NULL;
+ uint32_t l_remainingAttempts{2};
+ uint32_t l_retryCount{0};
+
// P9 has a bug in the multicast logic that causes it to return a
// 'chiplet offline' error if there are any chiplets in the multicast
// group that are offline. If the scom is performed via the PIB
@@ -780,99 +783,141 @@ errlHndl_t doScomOp(DeviceFW::OperationType i_opType,
// get returned will be all FFs.
bool l_multicastBugError = false;
- do{
- TARGETING::ScomSwitches scomSetting;
- scomSetting.useXscom = true; //Default to Xscom supported.
- if(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL != i_target)
- {
- scomSetting =
- i_target->getAttr<TARGETING::ATTR_SCOM_SWITCHES>();
+ do
+ {
+ //number of max remaining attempts after the current attempt.
+ --l_remainingAttempts;
- if( TARGETING::TYPE_PROC
- == i_target->getAttr<TARGETING::ATTR_TYPE>() )
+ do{
+ TARGETING::ScomSwitches scomSetting;
+ scomSetting.useXscom = true; //Default to Xscom supported.
+ if(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL != i_target)
{
- l_multicastBugError = true;
+ scomSetting =
+ i_target->getAttr<TARGETING::ATTR_SCOM_SWITCHES>();
+
+ if( TARGETING::TYPE_PROC
+ == i_target->getAttr<TARGETING::ATTR_TYPE>() )
+ {
+ l_multicastBugError = true;
+ }
}
- }
- //Always XSCOM the Master Sentinel
- if((TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target) ||
- (scomSetting.useXscom))
- { //do XSCOM
- // xscom uses ADU so we'll do a workaround instead of ignoring
- // the error code
- l_multicastBugError = false;
-
- //Check to see if we need to do the multicast bug workaround
- // and do it, returns true if the workaround was performed
- // which means we skip the regular call
- bool l_didWorkaround = false;
- l_err = doMulticastWorkaround(i_opType,
- i_target,
- io_buffer,
- io_buflen,
- i_addr,
- l_didWorkaround);
- if( !l_didWorkaround && !l_err )
- {
+ //Always XSCOM the Master Sentinel
+ if((TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target) ||
+ (scomSetting.useXscom))
+ { //do XSCOM
+ // xscom uses ADU so we'll do a workaround instead of ignoring
+ // the error code
+ l_multicastBugError = false;
+
+ //Check to see if we need to do the multicast bug workaround
+ // and do it, returns true if the workaround was performed
+ // which means we skip the regular call
+ bool l_didWorkaround = false;
+ l_err = doMulticastWorkaround(i_opType,
+ i_target,
+ io_buffer,
+ io_buflen,
+ i_addr,
+ l_didWorkaround);
+ if( !l_didWorkaround && !l_err )
+ {
+ l_err = deviceOp(i_opType,
+ i_target,
+ io_buffer,
+ io_buflen,
+ DEVICE_XSCOM_ADDRESS(i_addr));
+ }
+ else if( l_didWorkaround && !l_err )
+ {
+ //Since this is a pre-workaround, don't
+ //test for a retry if successful.
+ l_remainingAttempts = 0;
+ }
+ break;
+ }
+ else if(scomSetting.useSbeScom)
+ { //do SBESCOM
l_err = deviceOp(i_opType,
i_target,
io_buffer,
io_buflen,
- DEVICE_XSCOM_ADDRESS(i_addr));
+ DEVICE_SBEFIFOSCOM_ADDRESS(i_addr));
+ if( l_err ) { break; }
}
- break;
- }
- else if(scomSetting.useSbeScom)
- { //do SBESCOM
- l_err = deviceOp(i_opType,
- i_target,
- io_buffer,
- io_buflen,
- DEVICE_SBEFIFOSCOM_ADDRESS(i_addr));
- if( l_err ) { break; }
- }
- else if(scomSetting.useInbandScom)
- { //do IBSCOM
- l_err = deviceOp(i_opType,
- i_target,
- io_buffer,
- io_buflen,
- DEVICE_IBSCOM_ADDRESS(i_addr));
- if( l_err ) { break; }
- }
- else if(scomSetting.useFsiScom)
- { //do FSISCOM
- l_err = deviceOp(i_opType,
- i_target,
- io_buffer,
- io_buflen,
- DEVICE_FSISCOM_ADDRESS(i_addr));
- if( l_err ) { break; }
- }
- else
+ else if(scomSetting.useInbandScom)
+ { //do IBSCOM
+ l_err = deviceOp(i_opType,
+ i_target,
+ io_buffer,
+ io_buflen,
+ DEVICE_IBSCOM_ADDRESS(i_addr));
+ if( l_err ) { break; }
+ }
+ else if(scomSetting.useFsiScom)
+ { //do FSISCOM
+ l_err = deviceOp(i_opType,
+ i_target,
+ io_buffer,
+ io_buflen,
+ DEVICE_FSISCOM_ADDRESS(i_addr));
+ if( l_err ) { break; }
+ }
+ else
+ {
+ assert(0,"SCOM::scomPerformOp> ATTR_SCOM_SWITCHES does not "
+ "indicate Xscom, SBESCOM, Ibscom, or FSISCOM is "
+ "supported. i_target=0x%.8x", get_huid(i_target));
+ l_remainingAttempts = 0;
+ break;
+ }
+
+ }while(0);
+
+ //Check if any retry workaround's are needed.
+ if(l_remainingAttempts > 0)
{
- assert(0,"SCOM::scomPerformOp> ATTR_SCOM_SWITCHES does not indicate Xscom, SBESCOM, Ibscom, or FSISCOM is supported. i_target=0x%.8x", get_huid(i_target));
- break;
- }
+ bool l_doRetry{false};
+ const PostOpChecks* l_postOpPtr = PostOpChecks::theInstance();
+ if(nullptr != l_postOpPtr)
+ {
+ l_doRetry = l_postOpPtr->requestRetry(
+ l_err,
+ l_retryCount,
+ i_opType,
+ i_target,
+ io_buffer,
+ io_buflen,
+ i_accessType,
+ i_addr
+ );
+ }
- }while(0);
+ if(l_doRetry)
+ {
+ delete l_err;
+ l_err = nullptr;
- //Look for special retry codes
- if( l_err
- && (0xFFFFFFFF != i_accessType)
- && (l_err->reasonCode() == IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR) )
- {
- delete l_err;
- l_err = nullptr;
- TRACFCOMP(g_trac_scom, "Forcing retry of Scom to %.16X on %.8X", i_addr,
- (TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target ?
- 0xFFFFFFFF : TARGETING::get_huid(i_target)));
- // use the unused i_accessType parameter to avoid an infinite recursion
- int64_t accessType_flag = 0xFFFFFFFF;
- l_err = doScomOp( i_opType, i_target, io_buffer,
- io_buflen, accessType_flag, i_addr );
+ TRACFCOMP(g_trac_scom,
+ "Forcing retry of Scom to 0x%016X on 0x%08X",
+ i_addr,
+ (TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target ?
+ 0xFFFFFFFF : TARGETING::get_huid(i_target)));
+
+ }
+ else
+ {
+ //no retries are needed.
+ l_remainingAttempts = 0;
+ break;
+ }
+ }
+
+ //keep track of attempts.
+ ++l_retryCount;
}
+ while(l_remainingAttempts > 0);
if( l_err && p9_scom_addr(i_addr).is_multicast() && l_multicastBugError )
diff --git a/src/usr/scom/scom.mk b/src/usr/scom/scom.mk
index 94854eba0..dcd349855 100644
--- a/src/usr/scom/scom.mk
+++ b/src/usr/scom/scom.mk
@@ -33,6 +33,9 @@ EXTRAINCDIR += ${ROOTPATH}/src/import/hwpf/fapi2/include/
OBJS += scom.o
OBJS += scomtrans.o
OBJS += errlud_pib.o
+OBJS += postopchecks.o
+OBJS += DmiScomWorkaround.o
+OBJS += ibscom_retry.o
# Objects From Import Directory
OBJS += p9_scominfo.o
diff --git a/src/usr/scom/test/DmiScomWorkaround_for_test.H b/src/usr/scom/test/DmiScomWorkaround_for_test.H
new file mode 100644
index 000000000..f7f81b68f
--- /dev/null
+++ b/src/usr/scom/test/DmiScomWorkaround_for_test.H
@@ -0,0 +1,133 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/test/DmiScomWorkaround_for_test.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SCOM_DMI_SCOM_WORKAROUND_FOR_TEST_H
+#define __SCOM_DMI_SCOM_WORKAROUND_FOR_TEST_H
+
+#include "../DmiScomWorkaround.H"
+
+using namespace SCOM;
+using namespace ERRORLOG;
+
+// Derived class to implement mocked target dependency injection for
+// Unit Testing of the DmiScomWorkaround class.
+class DmiScomWorkaround_for_test : public DmiScomWorkaround
+{
+public:
+
+ //---------------------------------------------------------------------
+ DmiScomWorkaround_for_test()=default;
+
+ //-----------------------------------------------------------------------
+ // getTargetType implemented using mocked target.
+ bool getTargetType(TARGETING::Target* i_target,
+ TARGETING::TYPE& o_type) const
+ override
+ {
+ //Encodings for mock targets
+ // 0x4000000000000000 DMI Target
+ // 0x8000000000000000 PROC Target
+ // 0x0200000000000000 NIMBUS
+ // 0x0100000000000000 CUMULUS
+ // 0x00000000000000XX EC Level
+
+ constexpr uint64_t typeMask{0xC000000000000000};
+ constexpr uint64_t procType{0x8000000000000000};
+ constexpr uint64_t dmiType{0x4000000000000000};
+
+ bool l_retval{false};
+ uint64_t l_targetAddr = reinterpret_cast<uint64_t>(i_target);
+
+ const uint64_t typeAddr = l_targetAddr & typeMask;
+ if(procType == typeAddr)
+ {
+ o_type = TARGETING::TYPE_PROC;
+ l_retval = true;
+ }
+ else if(dmiType == typeAddr)
+ {
+ o_type = TARGETING::TYPE_DMI;
+ l_retval = true;
+ }
+
+ return l_retval;
+ }
+
+ //------------------------------------------------------------------------
+ // getTargetModel implemented using mocked target.
+ bool getTargetModel(TARGETING::Target* i_target,
+ TARGETING::MODEL& o_model) const
+ override
+ {
+ //Encodings for mock targets
+ // 0x4000000000000000 DMI Target
+ // 0x8000000000000000 PROC Target
+ // 0x0200000000000000 NIMBUS
+ // 0x0100000000000000 CUMULUS
+ // 0x00000000000000XX EC Level
+
+ constexpr uint64_t modelMask{0x0300000000000000};
+ constexpr uint64_t cumulusModel{0x0100000000000000};
+ constexpr uint64_t nimbusModel{0x0200000000000000};
+
+ bool l_retval{false};
+ uint64_t l_targetAddr = reinterpret_cast<uint64_t>(i_target);
+
+ const uint64_t modelAddr = l_targetAddr & modelMask;
+ if(cumulusModel == modelAddr)
+ {
+ o_model = TARGETING::MODEL_CUMULUS;
+ l_retval = true;
+ }
+ else if(nimbusModel == modelAddr)
+ {
+ o_model = TARGETING::MODEL_NIMBUS;
+ l_retval = true;
+ }
+
+ return l_retval;
+ }
+
+ //-----------------------------------------------------------------------
+ bool getTargetECLevel(TARGETING::Target* i_target,
+ uint8_t& o_ecLevel) const
+ {
+ constexpr uint64_t ECLevelMask{0x00000000000000FF};
+
+ uint64_t l_targetAddr = reinterpret_cast<uint64_t>(i_target);
+
+ const uint64_t l_ecLevel = l_targetAddr & ECLevelMask;
+ o_ecLevel = static_cast<uint8_t>(l_ecLevel);
+
+ return true;
+ }
+
+ //------------------------------------------------------------------------
+ // We don't want to cache the processor model for unit tests
+ // in order to allow mocking targets with different models.
+ bool useCachedProcModel() const override {return false;}
+
+};
+
+#endif
diff --git a/src/usr/scom/test/DmiScomWorkaround_test.H b/src/usr/scom/test/DmiScomWorkaround_test.H
new file mode 100644
index 000000000..50b5d4cf4
--- /dev/null
+++ b/src/usr/scom/test/DmiScomWorkaround_test.H
@@ -0,0 +1,632 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/test/DmiScomWorkaround_test.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SCOM_DMI_SCOM_WORKAROUND_TEST_H
+#define __SCOM_DMI_SCOM_WORKAROUND_TEST_H
+
+#include "DmiScomWorkaround_for_test.H"
+#include "retryWorkaroundTestData.H"
+
+#include <cxxtest/TestSuite.H>
+#include <errl/errlreasoncodes.H>
+#include <targeting/common/target.H>
+#include <trace/interface.H>
+
+#include <vector>
+
+// Tracing is disabled by default.
+// To turn on tracing, build the tests as shown below:
+// TRACE_SCOM_UNIT_TEST=1 make -j32
+#ifdef TRACE_SCOM_UNIT_TEST
+extern trace_desc_t* g_trac_scom;
+#define SCOM_DMI_WORKAROUND_TRACF(printf_string,args...) \
+ TRACFCOMP(g_trac_scom,"DMI_WRKAROUND_TEST::" printf_string,##args)
+#else
+#define SCOM_DMI_WORKAROUND_TRACF(printf_string,args...)
+#endif
+
+//Package the TS_FAIL macro with TRACFCOMP error reporting.
+//The TS_FAIL macro output seems to be separated from
+//TRACFCOMP output. This can be confusing when adding
+//trace statements to the tests while debugging. The failure
+//message from the SCOM_DMI_WORKAROUND_TRACF macro will
+//appear inline and in the proper context to other trace
+//statements which may be added during debugging.
+#define FAIL_DMIWKRD_TEST(printf_string,args...) \
+ SCOM_DMI_WORKAROUND_TRACF(printf_string, ##args); \
+ TS_FAIL("DMI_WRKAROUND_TEST::" printf_string, ##args)
+
+using namespace SCOM;
+using namespace ERRORLOG;
+
+class DMI_WRKAROUND_TEST: public CxxTest::TestSuite
+{
+public:
+
+ //-------------------------------------------------------------------
+ // The DmiScomWorkaround will request a
+ // retry based upon the following conditions
+ //
+ // requestRetry parameters retry Conditions
+ // 1) errlHndl_t - Not used.
+ // 2) uint32_t i_retryCount - Must be 0.
+ // 3) DeviceFW::OperationType - Must be a read operation.
+ // 4) TARGETING::Target* i_target - Must be a PROC or DMI target
+ // 5) void* i_buffer - Not Used
+ // 6) size_t i_buflen - Not Used
+ // 7) int64_t i_accessType - Not Used
+ // 8) uint64_t i_addr - Address must be in a list of addresses
+ // defined in DmiScomWorkaround. There is
+ // a list for each DMI 0-7, and a list for
+ // DMI SCOM addresses accessed by a PROC
+ // target.
+
+
+ //-----------------------------------------------------------------------
+ // Test Cumulus Proc Target with addresses that do not require retries.
+ // All requestRetry calls should return false.
+ void test_cumulus_proc_with_no_retry_addr()
+ {
+ bool l_result{true};
+ populateMockTargets();
+
+ do
+ {
+ std::shared_ptr<const PostOpRetryCheck>
+ l_workaround(new DmiScomWorkaround_for_test);
+
+
+ if(not l_workaround)
+ {
+ FAIL_DMIWKRD_TEST("test_cumulus_proc_with_no_retry_addr: "
+ "Unable to create a "
+ "DmiScomWorkaround_for_test "
+ "object."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ //iterate through the list of addresses that do not
+ //require retries.
+ for(uint64_t addr: g_always_no_retry_addrs)
+ {
+ bool l_rc{false};
+
+ l_rc = l_workaround->requestRetry(nullptr,
+ 0,
+ DeviceFW::READ,
+ iv_cumulus_proc_target,
+ nullptr,
+ 0,
+ 0,
+ addr
+ );
+ if(l_rc)
+ {
+ FAIL_DMIWKRD_TEST("test_cumulus_proc_with_no_retry_addr: "
+ "requestRetry unexpectedly "
+ "returned true for a cumulus proc "
+ "target and address 0x%016X", addr
+ );
+
+ l_result = false;
+ break;
+ }
+ }
+ }
+ while(0);
+
+ if(l_result)
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_cumulus_proc_with_no_retry_addr: "
+ "Test Passed!");
+ }
+ else
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_cumulus_proc_with_no_retry_addr: "
+ "Test Failed!");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ // Test Nimbus Proc Target with addresses that do not require retries.
+ // All requestRetry calls should return false as the workaround is not
+ // required on Nimbus systems.
+ void test_nimbus_proc_with_no_retry_addr()
+ {
+ bool l_result{true};
+ populateMockTargets();
+
+ do
+ {
+ std::shared_ptr<const PostOpRetryCheck>
+ l_workaround(new DmiScomWorkaround_for_test);
+
+ if(not l_workaround)
+ {
+ FAIL_DMIWKRD_TEST("test_nimbus_proc_with_no_retry_addr: "
+ "Unable to create a "
+ "DmiScomWorkaround_for_test "
+ "object."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ //iterate through the list of addresses that do not
+ //require retries.
+ for(uint64_t addr: g_always_no_retry_addrs)
+ {
+ bool l_rc{false};
+
+ l_rc = l_workaround->requestRetry(nullptr,
+ 0,
+ DeviceFW::READ,
+ iv_nimbus_proc_target,
+ nullptr,
+ 0,
+ 0,
+ addr
+ );
+ if(l_rc)
+ {
+ FAIL_DMIWKRD_TEST("test_nimbus_proc_with_no_retry_addr: "
+ "requestRetry unexpectedly "
+ "returned true for a nimbus "
+ "proc target and address "
+ "0x%016X",
+ addr
+ );
+
+ l_result = false;
+ break;
+ }
+ }
+ }
+ while(0);
+
+ if(l_result)
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_nimbus_proc_with_no_retry_addr: "
+ "Test Passed!");
+ }
+ else
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_nimbus_proc_with_no_retry_addr: "
+ "Test Failed!");
+ }
+ }
+
+ //---------------------------------------------------------------------
+ // Test Cumulus Proc Target with addresses that require retries.
+ // All requestRetry calls should return true.
+ void test_cumulus_proc_with_retry_addr()
+ {
+ bool l_result{true};
+ populateMockTargets();
+
+ uint8_t l_ecLevel{};
+ TARGETING::Target* l_target{};
+
+ do
+ {
+ std::shared_ptr<const PostOpRetryCheck>
+ l_workaround(new DmiScomWorkaround_for_test);
+
+
+ if(not l_workaround)
+ {
+ FAIL_DMIWKRD_TEST("test_cumulus_proc_with_retry_addr: "
+ "Unable to create a "
+ "DmiScomWorkaround_for_test "
+ "object"
+ );
+
+ l_result = false;
+ break;
+ }
+
+ //Do Tests with default EC Level = 0x10
+ getTargetECLevel(iv_cumulus_proc_target, l_ecLevel);
+
+ l_result = do_proc_test(l_workaround,
+ iv_cumulus_proc_target,
+ "cumulus",
+ true, //expected result of retryRequest
+ l_ecLevel
+ );
+
+ //Do Tests with EC Level = 0x00
+ l_target = setTargetEcLevel(iv_cumulus_proc_target,
+ 0x00
+ );
+
+ l_result = do_proc_test(l_workaround,
+ l_target,
+ "cumulus",
+ true, //expected result of retryRequest
+ 0x00
+ );
+
+ //Do Tests with EC Level = 0x11
+ l_target = setTargetEcLevel(iv_cumulus_proc_target,
+ 0x11
+ );
+
+ l_result = do_proc_test(l_workaround,
+ l_target,
+ "cumulus",
+ false, //expected result of retryRequest
+ 0x11
+ );
+
+ }
+ while(0);
+
+ if(l_result)
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_cumulus_proc_with_retry_addr: "
+ "Test Passed!");
+ }
+ else
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_cumulus_proc_with_retry_addr: "
+ "Test Failed!");
+ }
+ }
+
+ //---------------------------------------------------------------------
+ // Test NIMBUS Proc Target with addresses that require retries.
+ // All requestRetry calls should return false since the workaround
+ // is not required on NIMBUS systems.
+ void test_nimbus_proc_with_retry_addr()
+ {
+ bool l_result{true};
+ populateMockTargets();
+ uint8_t l_ecLevel{};
+
+ do
+ {
+ std::shared_ptr<const PostOpRetryCheck>
+ l_workaround(new DmiScomWorkaround_for_test);
+
+
+ if(not l_workaround)
+ {
+ FAIL_DMIWKRD_TEST("test_nimbus_proc_with_retry_addr: "
+ "Unable to create a "
+ "DmiScomWorkaround_for_test "
+ "object."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ getTargetECLevel(iv_cumulus_proc_target, l_ecLevel);
+ l_result = do_proc_test(l_workaround,
+ iv_nimbus_proc_target,
+ "nimbus",
+ false, //expected result of retryRequest
+ l_ecLevel
+ );
+ }
+ while(0);
+
+ if(l_result)
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_nimbus_proc_with_retry_addr: "
+ "Test Passed!");
+ }
+ else
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_nimbus_proc_with_retry_addr: "
+ "Test Failed!");
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // The above tests were based upon addresses and targets. This test
+ // uses the other relevant parameters to the requestRetry method.
+ void test_other_args_for_false()
+ {
+ bool l_result{true};
+ bool l_rc{false};
+
+ do
+ {
+ std::shared_ptr<const PostOpRetryCheck>
+ l_workaround(new DmiScomWorkaround_for_test);
+
+
+ if(not l_workaround)
+ {
+ FAIL_DMIWKRD_TEST("test_other_args_for_false: "
+ "Unable to create a "
+ "DmiScomWorkaround_for_test "
+ "object."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ std::shared_ptr<ErrlEntry> l_errl;
+ l_errl.reset(new ErrlEntry(ERRL_SEV_INFORMATIONAL,
+ ERRL_TEST_MOD_ID,
+ ERRL_TEST_REASON_CODE,
+ 0,
+ 0,
+ false
+ )
+ );
+
+ if(not l_errl)
+ {
+ FAIL_DMIWKRD_TEST("test_other_args_for_false: "
+ "Unable to create ErrlEntry object."
+ );
+
+ l_result=false;
+ break;
+ }
+
+ //TEST 1
+ //
+ //CUMULUS Proc Target.
+ //ErrorEntry Valid.
+ //Address requires retry for CUMULUS dmi/proc targets.
+ //
+ //Expected Result: TRUE
+ //
+ //Ensures that the result is not effected by a valid
+ //errHndl_t parameter.
+
+ // requestRetry parameters retry Conditions
+ // 1) errlHndl_t - Not NULL.
+ // 2) uint32_t i_retryCount - 0.
+ // 3) DeviceFW::OperationType - READ
+ // 4) TARGETING::Target* i_target - PROC
+ // 8) uint64_t i_addr - In Retry List.
+ l_rc = l_workaround->requestRetry(l_errl.get(),
+ 0,
+ DeviceFW::READ,
+ iv_cumulus_proc_target,
+ nullptr,
+ 0,
+ 0,
+ g_always_retry_addrs.front()
+ );
+
+ if(not l_rc)
+ {
+ FAIL_DMIWKRD_TEST("test_other_args_for_false: "
+ "requestRetry unexpectedly returned "
+ "false when called with a non-null "
+ "ErrlEntry pointer"
+ );
+
+ l_result=false;
+ break;
+ }
+
+ //TEST 2
+ //
+ //CUMULUS Proc Target
+ //Address requires retry for CUMULUS dmi/proc targets.
+ //Retry Count non-zero indicating a multiple
+ //retry request.
+ //
+ //Expected Result: FALSE
+ //
+ //Ensures that the result is false for a multiple retry request.
+
+ // requestRetry parameters retry Conditions
+ // 1) errlHndl_t - NULL.
+ // 2) uint32_t i_retryCount - 1. <---- causes false return.
+ // 3) DeviceFW::OperationType - READ
+ // 4) TARGETING::Target* i_target - PROC
+ // 8) uint64_t i_addr - In Retry List.
+ l_rc = l_workaround->requestRetry(nullptr,
+ 1,
+ DeviceFW::READ,
+ iv_cumulus_proc_target,
+ nullptr,
+ 0,
+ 0,
+ g_always_retry_addrs.front()
+ );
+
+ if(l_rc)
+ {
+ FAIL_DMIWKRD_TEST("test_other_args_for_false: "
+ "requestRetry unexpectedly returned "
+ "true when called with a retry count "
+ "of 1."
+ );
+
+ l_result=false;
+ break;
+ }
+
+ //TEST 3
+ //Address requires retry for CUMULUS dmi/proc targets.
+ //CUMULUS Proc Target
+ //
+ //Operation was a WRITE. Workaround only enabled for READ.
+ //
+ //Expected Result: FALSE
+ //
+ //Ensures that the result is false for a write operation.
+ //
+ // requestRetry parameters retry Conditions
+ // 1) errlHndl_t - NULL.
+ // 2) uint32_t i_retryCount - 0.
+ // 3) DeviceFW::OperationType - WRITE <---- causes false return.
+ // 4) TARGETING::Target* i_target - PROC
+ // 8) uint64_t i_addr - In Retry List.
+ //
+ l_rc = l_workaround->requestRetry(nullptr,
+ 0,
+ DeviceFW::WRITE,
+ iv_cumulus_proc_target,
+ nullptr,
+ 0,
+ 0,
+ g_always_retry_addrs.front()
+ );
+
+ if(l_rc)
+ {
+ FAIL_DMIWKRD_TEST("test_other_args_for_false: "
+ "requestRetry unexpectedly returned "
+ "true when called with a "
+ "Write command. "
+ );
+
+ l_result=false;
+ break;
+ }
+ }
+ while(0);
+
+ if(l_result)
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_other_args_for_false: "
+ "Test Passed!");
+ }
+ else
+ {
+ SCOM_DMI_WORKAROUND_TRACF("test_other_args_for_false: "
+ "Test Failed!");
+ }
+ }
+
+private:
+
+ TARGETING::Target* iv_nimbus_proc_target{};
+ TARGETING::Target* iv_cumulus_proc_target{};
+ TARGETING::Target* iv_proc_target{};
+
+ void populateMockTargets()
+ {
+ //Encodings for mock targets
+ // 0x4000000000000000 DMI Target
+ // 0x8000000000000000 PROC Target
+ // 0x0200000000000000 NIMBUS
+ // 0x0100000000000000 CUMULUS
+ // 0x00000000000000XX Chip Unit
+
+ uint64_t addr = 0x8200000000000010;
+ iv_nimbus_proc_target = reinterpret_cast<TARGETING::Target*>(addr);
+
+ addr = 0x8100000000000010;
+ iv_cumulus_proc_target = reinterpret_cast<TARGETING::Target*>(addr);
+
+ addr = 0x8000000000000010;
+ iv_proc_target = reinterpret_cast<TARGETING::Target*>(addr);
+ }
+
+ //------------------------------------------------------------------------
+ bool do_proc_test(std::shared_ptr<const PostOpRetryCheck>& i_workaround,
+ TARGETING::Target* i_target,
+ const char* i_model,
+ const bool i_expected,
+ const uint8_t i_eclevel
+ )
+ {
+ bool l_result{true};
+ bool l_rc{false};
+ const char* l_oppositeExpString = i_expected?"false":"true";
+
+ do
+ {
+ //iterate through the complete list of retry addresses
+ for(uint64_t addr: g_always_retry_addrs)
+ {
+
+ l_rc = i_workaround->requestRetry(nullptr,
+ 0,
+ DeviceFW::READ,
+ i_target,
+ nullptr,
+ 0,
+ 0,
+ addr
+ );
+ if(i_expected != l_rc)
+ {
+ FAIL_DMIWKRD_TEST("test_%s_proc_with_retry_addr: "
+ "requestRetry unexpectedly "
+ "returned %s for a %s proc "
+ "target with EC Level 0x%0X "
+ "and address 0x%016llX",
+ i_model,
+ l_oppositeExpString,
+ i_model,
+ i_eclevel,
+ addr
+ );
+
+ l_result = false;
+ break;
+ }
+ }
+ }
+ while(0);
+
+ return l_result;
+ }
+
+ //----------------------------------------------------------------------
+ TARGETING::Target* setTargetEcLevel(TARGETING::Target* i_target,
+ uint8_t i_ecLevel
+ )
+ {
+ constexpr uint64_t ECLevelMask{0x00000000000000FF};
+
+ uint64_t l_targetAddr = reinterpret_cast<uint64_t>(i_target);
+ l_targetAddr &= ~ECLevelMask;
+ l_targetAddr |= (ECLevelMask & i_ecLevel);
+
+ return reinterpret_cast<TARGETING::Target*>(l_targetAddr);
+ }
+
+ //-----------------------------------------------------------------------
+ void getTargetECLevel(TARGETING::Target* i_target,
+ uint8_t& o_ecLevel) const
+ {
+ constexpr uint64_t ECLevelMask{0x00000000000000FF};
+
+ uint64_t l_targetAddr = reinterpret_cast<uint64_t>(i_target);
+
+ const uint64_t l_ecLevel = l_targetAddr & ECLevelMask;
+ o_ecLevel = static_cast<uint8_t>(l_ecLevel);
+ }
+};
+
+#endif
diff --git a/src/usr/scom/test/ibscom_retry_test.H b/src/usr/scom/test/ibscom_retry_test.H
new file mode 100644
index 000000000..e265c305f
--- /dev/null
+++ b/src/usr/scom/test/ibscom_retry_test.H
@@ -0,0 +1,281 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/test/ibscom_retry_test.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SCOM_IBSCOM_RETRY_TEST
+#define __SCOM_IBSCOM_RETRY_TEST
+
+#include "../ibscom_retry.H"
+#include <ibscom/ibscomreasoncodes.H>
+#include <errl/errlreasoncodes.H>
+
+#include <cxxtest/TestSuite.H>
+#include <trace/interface.H>
+
+// Tracing is disabled by default.
+// To turn on tracing, build the tests as shown below:
+// TRACE_SCOM_UNIT_TEST=1 make -j32
+#ifdef TRACE_SCOM_UNIT_TEST
+extern trace_desc_t* g_trac_scom;
+#define SCOM_IBSCOM_TRACF(printf_string,args...) \
+ TRACFCOMP(g_trac_scom,"IbScomRetryTest::" printf_string,##args)
+#else
+#define SCOM_IBSCOM_TRACF(printf_string,args...)
+#endif
+
+//Package the TS_FAIL macro with TRACFCOMP error reporting.
+//The TS_FAIL macro output seems to be separated from
+//TRACFCOMP output. This can be confusing when adding
+//trace statements to the tests while debugging. The failure
+//message from the SCOM_IBSCOM_TRACF macro will
+//appear inline and in the proper context to other trace
+//statements which may be added during debugging.
+#define FAIL_IBSCOM_TEST(printf_string,args...) \
+ SCOM_IBSCOM_TRACF(printf_string, ##args); \
+ TS_FAIL("IbScomRetryTest::" printf_string, ##args)
+
+using namespace SCOM;
+using namespace ERRORLOG;
+
+class IbScomRetryTest: public CxxTest::TestSuite
+{
+public:
+
+ //--------------------------------------------
+ // The IbscomRetry workaround will request a
+ // retry if an error occurred with a result code
+ // of IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR.
+ //
+ // requestRetry parameters retry Conditions
+ // 1) errlHndl_t - Not Null and Reason Code is
+ // IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR
+ // 2) uint32_t i_retryCount - Must be 0.
+ // 3) DeviceFW::OperationType - Not Used
+ // 4) TARGETING::Target* i_target - Not Used
+ // 5) void* i_buffer - Not Used
+ // 6) size_t i_buflen - Not Used
+ // 7) int64_t i_accessType - Not Used
+ // 8) uint64_t i_addr - Not Used
+ //
+ void test_lbscom_retry()
+ {
+ bool l_result{true};
+
+ do
+ {
+ //Get the single IbscomRetry instance.
+ std::shared_ptr<const PostOpRetryCheck> l_wrkaround =
+ IbscomRetry::theInstance();
+
+ if(not l_wrkaround)
+ {
+ FAIL_IBSCOM_TEST("test_lbscom_retry: "
+ "IbscomRetry::theInstance returned a "
+ "nullptr!"
+ );
+
+ l_result = false;
+ break;
+ }
+
+ uint16_t l_reasonCodeForTrue{IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR};
+ uint16_t l_reasonCodeForFalse{
+ static_cast<uint16_t>(l_reasonCodeForTrue + 1)};
+
+ uint32_t l_retryCount{0};
+ std::shared_ptr<ErrlEntry> l_errl;
+
+ // Test 1
+ // Use a successful error entry (nullptr).
+ //
+ // 1) errlHndl_t - NULL <--- causes false result
+ //
+ // 2) uint32_t i_retryCount - 0.
+ //
+ // Expected return: FALSE.
+ //
+ bool l_retval = l_wrkaround->requestRetry(l_errl.get(),
+ l_retryCount,
+ DeviceFW::READ,
+ nullptr,
+ nullptr,
+ 0,
+ 0,
+ 0
+ );
+ if(l_retval)
+ {
+ FAIL_IBSCOM_TEST("test_lbscom_retry: "
+ "requestRetry unexpectedly returned true "
+ "for a nullptr errlHndl_t."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ l_errl.reset(new ErrlEntry(ERRL_SEV_INFORMATIONAL,
+ ERRL_TEST_MOD_ID,
+ l_reasonCodeForTrue,
+ 0,
+ 0,
+ false
+ )
+ );
+
+ // Test 2
+ // A non-nullptr error with reason code
+ // IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR and
+ // Retry Count equal to 0.
+ //
+ // 1) errlHndl_t - Not Null and Reason Code is
+ // IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR
+ // 2) uint32_t i_retryCount - 0.
+ //
+ // Expected result: TRUE
+ //
+ l_retval = l_wrkaround->requestRetry(l_errl.get(),
+ l_retryCount,
+ DeviceFW::READ,
+ nullptr,
+ nullptr,
+ 0,
+ 0,
+ 0
+ );
+
+ if(not l_retval)
+ {
+ FAIL_IBSCOM_TEST("test_lbscom_retry: "
+ "requestRetry unexpectedly returned false "
+ "for reson code "
+ "IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR and retry "
+ "attempts %d.",
+ l_retryCount
+ );
+
+ l_result = false;
+ break;
+ }
+
+ // Test 3
+ // A non-nullptr error with reason code
+ // IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR and
+ // Retry Count equal to 1.
+ //
+ // 1) errlHndl_t - Not Null and Reason Code is
+ // IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR
+ // 2) uint32_t i_retryCount - 1 <--- Causes False Result
+ //
+ // Expected result: FALSE
+ //
+ ++l_retryCount;
+ l_retval = l_wrkaround->requestRetry(l_errl.get(),
+ l_retryCount,
+ DeviceFW::READ,
+ nullptr,
+ nullptr,
+ 0,
+ 0,
+ 0
+ );
+
+
+ if(l_retval)
+ {
+ FAIL_IBSCOM_TEST("test_lbscom_retry: "
+ "requestRetry unexpectedly returned true "
+ "for reson code "
+ "IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR and retry "
+ "attempts %d. The requestRetry should not "
+ "request more than one retry.",
+ l_retryCount
+ );
+
+ l_result = false;
+ break;
+ }
+
+ l_retryCount = 0;
+ l_errl.reset(new ErrlEntry(ERRL_SEV_INFORMATIONAL,
+ ERRL_TEST_MOD_ID,
+ l_reasonCodeForFalse,
+ 0,
+ 0,
+ false
+ )
+ );
+
+ // Test 4
+ // A non-nullptr error with reason code NOT
+ // IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR and
+ // Retry Count equal to 0.
+ //
+ // 1) errlHndl_t - Not Null and Reason Code is NOT <-- Causes False
+ // IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR
+ // 2) uint32_t i_retryCount - 0.
+ //
+ // Expected result: FALSE
+ //
+ l_retval = l_wrkaround->requestRetry(l_errl.get(),
+ l_retryCount,
+ DeviceFW::READ,
+ nullptr,
+ nullptr,
+ 0,
+ 0,
+ 0
+ );
+
+ if(l_retval)
+ {
+ FAIL_IBSCOM_TEST("test_lbscom_retry: "
+ "requestRetry unexpectedly returned true "
+ "for reson code NOT equal to "
+ "IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR. "
+ "A retry should only happen if the reason "
+ "code for the passed in error is equal to "
+ "IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ }
+ while(0);
+
+ if(l_result)
+ {
+ SCOM_IBSCOM_TRACF("IbScomRetryTest: Test Passed!");
+ }
+ else
+ {
+ SCOM_IBSCOM_TRACF("IbScomRetryTest: Test Failed!");
+ }
+ }
+};
+
+
+
+#endif
diff --git a/src/usr/scom/test/makefile b/src/usr/scom/test/makefile
index ce5b7777e..171d56e0b 100644
--- a/src/usr/scom/test/makefile
+++ b/src/usr/scom/test/makefile
@@ -5,7 +5,9 @@
#
# OpenPOWER HostBoot Project
#
-# COPYRIGHT International Business Machines Corp. 2011,2014
+# Contributors Listed Below - COPYRIGHT 2011,2017
+# [+] International Business Machines Corp.
+#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -25,4 +27,13 @@ ROOTPATH = ../../../..
MODULE = testscom
TESTS = *.H
+OBJS+=retryWorkaroundTestData.o
+
+#To enable tracing of SCOM Unit Tests
+# TRACE_SCOM_UNIT_TEST=1 make -j32
+ifdef TRACE_SCOM_UNIT_TEST
+CXXFLAGS+=-DTRACE_SCOM_UNIT_TEST
+$(info Tracing Enabled For SCOM Unit Tests)
+endif
+
include ${ROOTPATH}/config.mk
diff --git a/src/usr/scom/test/postopchecks_test.H b/src/usr/scom/test/postopchecks_test.H
new file mode 100644
index 000000000..13c93a8ca
--- /dev/null
+++ b/src/usr/scom/test/postopchecks_test.H
@@ -0,0 +1,670 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/test/postopchecks_test.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SCOM_POSTOPCHECKS_TEST_H
+#define __SCOM_POSTOPCHECKS_TEST_H
+
+#include "../DmiScomWorkaround.H"
+#include "../ibscom_retry.H"
+#include "../postopchecks.H"
+
+#include "retryWorkaroundTestData.H"
+
+#include <devicefw/userif.H>
+#include <errl/errlreasoncodes.H>
+#include <ibscom/ibscomreasoncodes.H>
+#include <targeting/common/utilFilter.H>
+#include <trace/interface.H>
+
+#include <cxxtest/TestSuite.H>
+
+//To enable tracing of SCOM Unit Tests
+// TRACE_SCOM_UNIT_TEST=1 make -j32
+#ifdef TRACE_SCOM_UNIT_TEST
+extern trace_desc_t* g_trac_scom;
+#define __TRACE_USE_ONLY__
+#define SCOM_POSTOP_TRACF(printf_string,args...) \
+ TRACFCOMP(g_trac_scom,"PostOPChecks_TEST::" printf_string,##args)
+#else
+#define __TRACE_USE_ONLY__ __attribute__((unused))
+#define SCOM_POSTOP_TRACF(printf_string,args...)
+#endif
+
+//Package the TS_FAIL macro with TRACFCOMP error reporting.
+//The TS_FAIL macro output seems to be separated from
+//TRACFCOMP output. This can be confusing when adding
+//trace statements to the tests while debugging. The failure
+//message from the SCOM_POSTOP_TRACF macro will
+//appear inline and in the proper context to other trace
+//statements which may be added during debugging.
+#define FAIL_POSTOP_TEST(printf_string,args...) \
+ SCOM_POSTOP_TRACF(printf_string, ##args); \
+ TS_FAIL("PostOPChecks_TEST::" printf_string, ##args)
+
+using namespace SCOM;
+using namespace ERRORLOG;
+
+// PostOpChecks_for_test used for unit testing
+// PostOpChecks. PostOpChecks_for_test allows us to
+// insert test workarounds instead of the singleton which
+// uses non-test workarounds.
+class PostOpChecks_for_test: public PostOpChecks
+{
+public:
+ PostOpChecks_for_test(
+ std::initializer_list<std::shared_ptr<const PostOpRetryCheck>>
+ i_retrychecks): PostOpChecks(i_retrychecks){}
+
+ virtual ~PostOpChecks_for_test() = default;
+};
+
+//Create a publicly constructable version of IbscomRetry for testing.
+class IbscomRetry_for_test: public IbscomRetry
+{
+public:
+ IbscomRetry_for_test() = default;
+ virtual ~IbscomRetry_for_test() = default;
+};
+
+class PostOPChecks_TEST: public CxxTest::TestSuite
+{
+public:
+
+ //-----------------------------------------
+ // Test the PostOPChecks composite.
+ void test_postOpRetry()
+ {
+ bool l_result{true};
+ bool l_rc{};
+
+ do
+ {
+ //Create a testable instance of IbscomRetry.
+ std::shared_ptr<const PostOpRetryCheck>
+ l_IbscomPtr{new IbscomRetry_for_test};
+
+ if(not l_IbscomPtr)
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "IbscomRetry::theInstance returned a "
+ "nullptr!"
+ );
+
+
+ l_result = false;
+ break;
+ }
+
+ //Create a DmiScomWorkaround_for_test object
+ std::shared_ptr<const PostOpRetryCheck>
+ l_dmiptr(new DmiScomWorkaround_for_test);
+
+
+ if(not l_dmiptr)
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "Unable to create a "
+ "DmiScomWorkaround_for_test "
+ "object."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ //Create PostOpChecks_for_test object
+ std::shared_ptr<const PostOpRetryCheck>
+ l_postopcheck(new PostOpChecks_for_test{
+ l_IbscomPtr,
+ l_dmiptr
+ });
+
+ if(not l_postopcheck)
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "Unable to create a "
+ "PostOpChecks_for_test "
+ "object."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ //initialize and check retry counts. Retry counts are used
+ //to determine which workaround requested a retry.
+ uint64_t l_total_retry_count{};
+ uint64_t l_ibscom_retry_count{};
+ uint64_t l_dmi_retry_count{};
+ uint64_t l_no_retry_addr{0x22334455}; //Address that does not
+ //need a retry.
+ uint16_t l_reasonCodeForTrue{IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR};
+ uint32_t l_retryCount{0};
+
+ l_postopcheck->resetRetryCount();
+ l_total_retry_count = l_postopcheck->getRetryCount();
+ l_ibscom_retry_count = l_IbscomPtr->getRetryCount();
+ l_dmi_retry_count = l_dmiptr->getRetryCount();
+
+ l_rc = checkExpectedRetryCounts("Pre Test",
+ l_total_retry_count,
+ l_ibscom_retry_count,
+ l_dmi_retry_count,
+ 0,
+ 0,
+ 0
+ );
+
+ if(not l_rc)
+ {
+ l_result = false;
+ break;
+ }
+
+ //Setup errlHndl_t pointer
+ std::shared_ptr<ErrlEntry> l_errl;
+ l_errl.reset(new ErrlEntry(ERRL_SEV_INFORMATIONAL,
+ ERRL_TEST_MOD_ID,
+ l_reasonCodeForTrue,
+ 0,
+ 0,
+ false
+ )
+ );
+
+ if(not l_errl)
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "Unable to create a ErrlEntry object."
+ );
+
+ l_result = false;
+ break;
+ }
+
+ //Test 1
+ //
+ // Ensure that the PostOpRetry composite returns false when
+ // its contained children return false.
+ //
+ // No Errl pointer - IBSCOM will not request retry.
+ // Address not in the list of addresses that require a DMI retry.
+ // - DmiWorkaround will not request retry.
+ //
+ //Expected Result: FALSE
+ //
+ l_rc = l_postopcheck->requestRetry(nullptr,
+ l_retryCount,
+ DeviceFW::READ,
+ iv_cumulus_proc_target,
+ nullptr,
+ 0,
+ 0,
+ l_no_retry_addr
+ );
+
+ if(l_rc)
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "requestRetry unexpectedly returned true "
+ "for a cumulus proc target, null "
+ "errlHndl_t pointer and address 0x%016X",
+ l_no_retry_addr
+ );
+
+ l_result = false;
+ break;
+ }
+
+ l_total_retry_count = l_postopcheck->getRetryCount();
+ l_ibscom_retry_count = l_IbscomPtr->getRetryCount();
+ l_dmi_retry_count = l_dmiptr->getRetryCount();
+
+ l_rc = checkExpectedRetryCounts("Test 1",
+ l_total_retry_count,
+ l_ibscom_retry_count,
+ l_dmi_retry_count,
+ 0,
+ 0,
+ 0
+ );
+
+ if(not l_rc)
+ {
+ l_result = false;
+ break;
+ }
+
+ //=============================================
+ // IBSCOM Retry test(s)
+ //=============================================
+
+ //Test 2
+ //
+ // Ensure that the PostOpRetry composite returns true when the
+ // contained IbscomRetry instance requests a retry and that
+ // the retry counts for both the children and composite are as
+ // expected.
+ //
+ // Errl pointer should trigger IBSCOM Retry.
+ // Address not in the list of addresses that require a DMI retry.
+ // - DmiWorkaround will not request retry.
+ //
+ //Expected Result: TRUE.
+ //
+ l_rc = l_postopcheck->requestRetry(l_errl.get(),
+ l_retryCount,
+ DeviceFW::READ,
+ iv_cumulus_proc_target,
+ nullptr,
+ 0,
+ 0,
+ l_no_retry_addr
+ );
+
+ if(not l_rc)
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "requestRetry unexpectedly returned false "
+ "for a cumulus proc target, valid "
+ "errlHndl_t pointer and address 0x%016X",
+ l_no_retry_addr
+ );
+
+ l_result = false;
+ break;
+ }
+
+ l_total_retry_count = l_postopcheck->getRetryCount();
+ l_ibscom_retry_count = l_IbscomPtr->getRetryCount();
+ l_dmi_retry_count = l_dmiptr->getRetryCount();
+
+ l_rc = checkExpectedRetryCounts("Test 2",
+ l_total_retry_count,
+ l_ibscom_retry_count,
+ l_dmi_retry_count,
+ 1, //total expected
+ 1, //ibscom expected
+ 0 //dmi retry expected
+ );
+
+ if(not l_rc)
+ {
+ l_result = false;
+ break;
+ }
+
+ //=============================================
+ // DMI Retry test(s)
+ //============================================
+
+ //Test 3
+ //
+ // Ensure that the PostOpRetry composite returns true when the
+ // contained DmiScomWorkaround instance requests a retry and that
+ // the retry counts for both the children and composite are as
+ // expected.
+ //
+ // Errl pointer is NULL and should not trigger a IBSCOM Retry.
+ // Address is in the list of addresses that require a DMI retry.
+ // - DmiWorkaround will request a retry.
+ // Expected Result: TRUE.
+ //
+ l_rc = l_postopcheck->requestRetry(nullptr,
+ l_retryCount,
+ DeviceFW::READ,
+ iv_cumulus_proc_target,
+ nullptr,
+ 0,
+ 0,
+ g_always_retry_addrs.front()
+ );
+ if(not l_rc)
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "requestRetry unexpectedly returned false "
+ "for a cumulus proc target, null "
+ "errlHndl_t pointer and address 0x%016X",
+ g_always_retry_addrs.front()
+ );
+
+ l_result = false;
+ break;
+ }
+
+ l_total_retry_count = l_postopcheck->getRetryCount();
+ l_ibscom_retry_count = l_IbscomPtr->getRetryCount();
+ l_dmi_retry_count = l_dmiptr->getRetryCount();
+
+ l_rc = checkExpectedRetryCounts("Test 3",
+ l_total_retry_count,
+ l_ibscom_retry_count,
+ l_dmi_retry_count,
+ 2, //total expected
+ 1, //ibscom expected
+ 1 //dmi retry expected
+ );
+ if(not l_rc)
+ {
+ l_result = false;
+ break;
+ }
+ }
+ while(0);
+
+ if(l_result)
+ {
+ SCOM_POSTOP_TRACF("test_postOpRetry: Test Passed!");
+ }
+ else
+ {
+ SCOM_POSTOP_TRACF("test_postOpRetry: Test Failed!");
+ }
+ }
+
+ //-----------------------------------------------------------
+ // Integration test for Scom workarounds
+ void test_scom_workaround_integration_test()
+ {
+ populateRealTargets();
+ bool l_result{true};
+
+ do
+ {
+ //integration test valid on CUMULUS system only
+ if(TARGETING::MODEL_CUMULUS != iv_model)
+ {
+ __TRACE_USE_ONLY__ const char* model_name = "";
+ if(TARGETING::MODEL_NIMBUS == iv_model)
+ {
+ model_name = "NIMBUS";
+ }
+
+ SCOM_POSTOP_TRACF("test_integration_test: "
+ "Not a Cumulus system. "
+ "Model: %s, "
+ "Aborting integration test.",
+ model_name
+ );
+
+ break;
+ }
+ else if(0x00 != iv_ecLevel && 0x10 != iv_ecLevel)
+ {
+ SCOM_POSTOP_TRACF("test_integration_test: "
+ "EC Level not valid for Test"
+ "EC Level: 0x%0x, "
+ "Aborting integration test.",
+ iv_ecLevel
+ );
+ break;
+ }
+ else
+ {
+ SCOM_POSTOP_TRACF("test_scom_workaround_integration_test: "
+ "CUMULUS System Detected."
+ );
+ }
+
+ //Ensure that we have a real target for testing.
+ if(nullptr == iv_proc_target)
+ {
+ FAIL_POSTOP_TEST("test_scom_workaround_integration_test: "
+ "No Targets for test were found!"
+ );
+
+ l_result = false;
+ break;
+ }
+
+ const PostOpChecks* l_postopptr = PostOpChecks::theInstance();
+ if(nullptr == l_postopptr)
+ {
+ FAIL_POSTOP_TEST("test_scom_workaround_integration_test: "
+ "PostOpChecks::theInstance "
+ "returned a nullptr!"
+ );
+
+ l_result = false;
+ break;
+ }
+
+ l_postopptr->resetRetryCount();
+
+ //STEP 1
+ //
+ //Test Workarounds on Proc Targets
+ //
+ //Integration Test of Proc target and all
+ //retry addresses.
+ //
+ //TEST strategy. Iterate through all retry addresses and
+ //perform a deviceRead on that address. The retry count
+ //for the DmiScomWorkaround should increment for each retry.
+ //
+ if(iv_proc_target)
+ {
+ uint64_t l_retryCount{0};
+ uint64_t l_expected_retryCount{0};
+
+ //iterate over all retry addresses
+ for(uint64_t l_addr: g_always_retry_addrs)
+ {
+ uint64_t l_buffer{0};
+ size_t l_bufsize = sizeof(uint64_t);
+ l_expected_retryCount = l_postopptr->getRetryCount();
+ errlHndl_t l_errl = DeviceFW::deviceRead(
+ iv_proc_target,
+ &l_buffer,
+ l_bufsize,
+ DEVICE_SCOM_ADDRESS(l_addr)
+ );
+ if(l_errl)
+ {
+ delete l_errl;
+ l_errl = nullptr;
+ SCOM_POSTOP_TRACF(
+ "test_scom_workaround_integration_test: "
+ "Failed to read address "
+ "0x%016llX for processor target.",
+ l_addr
+ );
+ }
+ else
+ {
+ //read succeeded, check that a retry occurred.
+ ++l_expected_retryCount;
+ l_retryCount = l_postopptr->getRetryCount();
+
+ //Because tests are run concurrently we cannot
+ //use equality to check the retry count. A test
+ //running in another thread may have read a
+ //register that requires a retry and thus bump
+ //the retry count up in addition to this test.
+ if(l_expected_retryCount > l_retryCount)
+ {
+ FAIL_POSTOP_TEST(
+ "test_scom_workaround_integration_test: "
+ "retry count not as expected. "
+ "Expected %d, Actual %d. "
+ "Target - Proc. Addr: 0x%016llX",
+ l_expected_retryCount,
+ l_retryCount,
+ l_addr
+ );
+
+ l_result = false;
+ break;
+ }
+ }
+ }
+
+ if(not l_result)
+ {
+ break;
+ }
+ }
+ }
+ while(0);
+
+ if(l_result)
+ {
+ SCOM_POSTOP_TRACF("test_scom_workaround_integration_test: "
+ "Test Passed!");
+ }
+ else
+ {
+ SCOM_POSTOP_TRACF("test_scom_workaround_integration_test: "
+ "Test Failed!");
+ }
+ }
+
+private:
+
+ //Mock target, cumulus proc target.
+ const uint64_t iv_proc_addr{0x8100000000000010};
+
+ TARGETING::Target*
+ iv_cumulus_proc_target{reinterpret_cast<TARGETING::Target*>(iv_proc_addr)};
+
+ //Real Target
+ TARGETING::Target* iv_proc_target{};
+
+ TARGETING::MODEL iv_model{TARGETING::MODEL_NA};
+ uint8_t iv_ecLevel{0xFF};
+
+ //-------------------------------------------------------------------------
+ bool checkExpectedRetryCounts(
+ const char* i_test,
+ uint64_t i_total,
+ uint64_t i_ibscom,
+ uint64_t i_dmi,
+ uint64_t i_expected_total,
+ uint64_t i_expected_ibscom,
+ uint64_t i_expected_dmi,
+ bool i_exactMatch = true
+ )
+ {
+ bool l_result{true};
+
+ do
+ {
+ // For integration tests an exact match is not desirable
+ // because tests are run concurrently and retry counts
+ // may be influenced by tests running on other threads.
+ // For Unit Tests we use dedicated derived test classes
+ // whose retry count is unaffected by other tests.
+ if((i_exactMatch && (i_expected_total != i_total)) ||
+ (!i_exactMatch && (i_expected_total > i_total))
+ )
+ {
+
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "Unexpected retry count for l_postopcheck. "
+ "Test: %s, Actual %d. Expected %d",
+ i_test,
+ i_total,
+ i_expected_total
+ );
+
+ l_result = false;
+ break;
+ }
+ else if((i_exactMatch && (i_expected_ibscom != i_ibscom)) ||
+ (!i_exactMatch && (i_expected_ibscom > i_ibscom))
+ )
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "Unexpected retry count for l_IbscomPtr. "
+ "Test: %s, Actual %d. Expected %d",
+ i_test,
+ i_ibscom,
+ i_expected_ibscom
+ );
+
+ l_result = false;
+ break;
+ }
+ else if((i_exactMatch && (i_expected_dmi != i_dmi)) ||
+ (!i_exactMatch && (i_expected_dmi > i_dmi))
+ )
+ {
+ FAIL_POSTOP_TEST("test_postOpRetry: "
+ "Unexpected retry count for l_dmiptr. "
+ "Test: %s, Actual %d. Expected %d",
+ i_test,
+ i_dmi,
+ i_expected_dmi
+ );
+
+ l_result = false;
+ break;
+ }
+ }
+ while(0);
+
+ return l_result;
+ }
+
+ //------------------------------------------------------
+ void populateRealTargets()
+ {
+ do
+ {
+ iv_ecLevel = 0xFF;
+ iv_model = TARGETING::MODEL_NA;
+ iv_proc_target = nullptr;
+
+ uint8_t l_ecLevel{};
+
+ TARGETING::TargetHandleList l_targetList;
+ TARGETING::getAllChips(l_targetList, TARGETING::TYPE_PROC, false);
+
+ for(int i=0; l_targetList.size(); ++i)
+ {
+ TARGETING::Target* l_target = l_targetList[i];
+ if(nullptr != l_target &&
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL != l_target)
+ {
+ iv_proc_target = l_target;
+ break;
+ }
+ }
+
+ if(nullptr != iv_proc_target)
+ {
+ if(iv_proc_target->tryGetAttr<TARGETING::ATTR_EC>(l_ecLevel))
+ {
+ iv_ecLevel = l_ecLevel;
+ }
+
+ iv_proc_target->tryGetAttr<TARGETING::ATTR_MODEL>(iv_model);
+ }
+ }
+ while(0);
+ }
+
+};
+
+#endif
diff --git a/src/usr/scom/test/retryWorkaroundTestData.C b/src/usr/scom/test/retryWorkaroundTestData.C
new file mode 100644
index 000000000..ef8462d8d
--- /dev/null
+++ b/src/usr/scom/test/retryWorkaroundTestData.C
@@ -0,0 +1,188 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/test/retryWorkaroundTestData.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "retryWorkaroundTestData.H"
+
+// A set of addresses that never require a SCOM DMI retry
+std::vector<uint64_t> g_always_no_retry_addrs = {
+ 0x1319821,
+ 0x1319822,
+ 0x1319921,
+ 0x1319922,
+ 0x1319a21,
+ 0x1319a22,
+ 0x1319b21,
+ 0x1319b22,
+
+ 0xF319821,
+ 0xF319822,
+ 0xF319921,
+ 0xF319922,
+ 0xF319a21,
+ 0xF319a22,
+ 0xF319b21,
+ 0xF319b22,
+
+ 0x40108a3,
+ 0x40108a4,
+ 0x40108a5,
+ 0x40108a6,
+ 0x40108a7,
+ 0x40108a8,
+ 0x40108a9,
+ 0x40108aa,
+
+ 0x3010820,
+ 0x3010821,
+ 0x3010822,
+ 0x301082b,
+ 0x301082c,
+ 0x301082d,
+ 0x301082e,
+ 0x301082f,
+
+ 0x3010830,
+ 0x3010831,
+ 0x3010832,
+ 0x301083b,
+ 0x301083c,
+ 0x301083d,
+ 0x301083e,
+ 0x301083f,
+
+ 0x30108a0,
+ 0x30108a1,
+ 0x30108a2,
+ 0x30108ab,
+ 0x30108ac,
+ 0x30108ad,
+ 0x30108ae,
+ 0x30108af,
+
+ 0x30108b0,
+ 0x30108b1,
+ 0x30108b2,
+ 0x30108bb,
+ 0x30108bc,
+ 0x30108bd,
+ 0x30108be,
+ 0x30108bf,
+
+ 0x3010803,
+ 0x3010813,
+ 0x3010843,
+ 0x3010853,
+ 0x3010863,
+ 0x3010873,
+ 0x3010883,
+ 0x3010893,
+ 0x30108c3,
+ 0x30108d3,
+ 0x30108e3,
+ 0x30108f3,
+ };
+
+//All of the following addresses require retries
+std::vector<uint64_t> g_always_retry_addrs =
+ {
+ //dmi-4
+ 0x3010823,
+ 0x3010824,
+ 0x3010825,
+ 0x3010826,
+ 0x3010827,
+ 0x3010828,
+ 0x3010829,
+ 0x301082a,
+
+ //dmi-5
+ 0x3010833,
+ 0x3010834,
+ 0x3010835,
+ 0x3010836,
+ 0x3010837,
+ 0x3010838,
+ 0x3010839,
+ 0x301083a,
+
+ //dmi-6
+ 0x30108a3,
+ 0x30108a4,
+ 0x30108a5,
+ 0x30108a6,
+ 0x30108a7,
+ 0x30108a8,
+ 0x30108a9,
+ 0x30108aa,
+
+ //dmi-7
+ 0x30108b3,
+ 0x30108b4,
+ 0x30108b5,
+ 0x30108b6,
+ 0x30108b7,
+ 0x30108b8,
+ 0x30108b9,
+ 0x30108ba,
+
+ //dmi-0
+ 0x5010823,
+ 0x5010824,
+ 0x5010825,
+ 0x5010826,
+ 0x5010827,
+ 0x5010828,
+ 0x5010829,
+ 0x501082a,
+
+ //dmi-1
+ 0x5010833,
+ 0x5010834,
+ 0x5010835,
+ 0x5010836,
+ 0x5010837,
+ 0x5010838,
+ 0x5010839,
+ 0x501083a,
+
+ //dmi-2
+ 0x50108a3,
+ 0x50108a4,
+ 0x50108a5,
+ 0x50108a6,
+ 0x50108a7,
+ 0x50108a8,
+ 0x50108a9,
+ 0x50108aa,
+
+ //dmi-3
+ 0x50108b3,
+ 0x50108b4,
+ 0x50108b5,
+ 0x50108b6,
+ 0x50108b7,
+ 0x50108b8,
+ 0x50108b9,
+ 0x50108ba
+ };
diff --git a/src/usr/scom/test/retryWorkaroundTestData.H b/src/usr/scom/test/retryWorkaroundTestData.H
new file mode 100644
index 000000000..211471a62
--- /dev/null
+++ b/src/usr/scom/test/retryWorkaroundTestData.H
@@ -0,0 +1,35 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/scom/test/retryWorkaroundTestData.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SCOM_RETRY_WORKAROUND_TEST_DATA
+#define __SCOM_RETRY_WORKAROUND_TEST_DATA
+
+#include <stdint.h>
+#include <vector>
+
+extern std::vector<uint64_t> g_always_no_retry_addrs;
+extern std::vector<uint64_t> g_always_retry_addrs;
+
+#endif
OpenPOWER on IntegriCloud