Attn: On TI with recoverable errors call analyzer

While servicing a TI attention handler will check if recoverable
error attentions are present and if so it will call the analyzer.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I60f0d32932f678ddee894d9424b16409e60bdbd4
diff --git a/attn/attn_common.cpp b/attn/attn_common.cpp
index 0b9061d..d387b4f 100644
--- a/attn/attn_common.cpp
+++ b/attn/attn_common.cpp
@@ -1,6 +1,7 @@
 #include <libpdbg.h>
 
 #include <attn/attn_common.hpp>
+#include <attn/attn_handler.hpp>
 #include <attn/attn_logging.hpp>
 #include <sdbusplus/bus.hpp>
 #include <util/pdbg.hpp>
@@ -89,4 +90,71 @@
 
 } // end addHbStatusRegs
 
+/** @brief Check for recoverable errors present */
+bool recoverableErrors()
+{
+    bool recoverableErrors = false; // assume no recoverable attentions
+
+    pdbg_target* target;
+    pdbg_for_each_class_target("proc", target)
+    {
+        if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
+        {
+            auto proc = pdbg_target_index(target); // get processor number
+
+            // Use PIB target to determine if a processor is enabled
+            char path[16];
+            sprintf(path, "/proc%d/pib", proc);
+            pdbg_target* pibTarget = pdbg_target_from_path(nullptr, path);
+
+            // sanity check
+            if (nullptr == pibTarget)
+            {
+                trace<level::INFO>("pib path or target not found");
+                continue;
+            }
+
+            // check if pib target is enabled - indicates proc is enabled
+            if (PDBG_TARGET_ENABLED == pdbg_target_probe(pibTarget))
+            {
+                // The processor FSI target is required for CFAM read
+                sprintf(path, "/proc%d/fsi", proc);
+                pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path);
+
+                // sanity check
+                if (nullptr == fsiTarget)
+                {
+                    trace<level::INFO>("fsi path or target not found");
+                    continue;
+                }
+
+                uint32_t isr_val = 0xffffffff; // invalid isr value
+
+                // get active attentions on processor
+                if (RC_SUCCESS != fsi_read(fsiTarget, 0x1007, &isr_val))
+                {
+                    // log cfam read error
+                    trace<level::ERROR>("Error! cfam read 0x1007 FAILED");
+                    eventAttentionFail((int)AttnSection::attnHandler |
+                                       ATTN_PDBG_CFAM);
+                }
+                // check for invalid/stale value
+                else if (0xffffffff == isr_val)
+                {
+                    trace<level::ERROR>("Error! cfam read 0x1007 INVALID");
+                    continue;
+                }
+                // check recoverable error status bit
+                else if (0 != (isr_val & RECOVERABLE_ATTN))
+                {
+                    recoverableErrors = true;
+                    break;
+                }
+            } // fsi target enabled
+        }     // pib target enabled
+    }         // next processor
+
+    return recoverableErrors;
+}
+
 } // namespace attn
diff --git a/attn/attn_common.hpp b/attn/attn_common.hpp
index 6f4428d..938af36 100644
--- a/attn/attn_common.hpp
+++ b/attn/attn_common.hpp
@@ -45,4 +45,11 @@
  */
 void addHbStatusRegs();
 
+/**
+ * @brief Check for recoverable errors present
+ *
+ * @return true if any recoverable errors are present, else false
+ */
+bool recoverableErrors();
+
 } // namespace attn
diff --git a/attn/attn_dump.hpp b/attn/attn_dump.hpp
index 04c51e7..d7cdfac 100644
--- a/attn/attn_dump.hpp
+++ b/attn/attn_dump.hpp
@@ -1,4 +1,5 @@
 #pragma once
+#include <cstdint>
 
 namespace attn
 {
diff --git a/attn/attn_handler.hpp b/attn/attn_handler.hpp
index 41ed409..90e60d5 100644
--- a/attn/attn_handler.hpp
+++ b/attn/attn_handler.hpp
@@ -6,9 +6,10 @@
 {
 
 /** @brief Attention global status bits */
-constexpr uint32_t SBE_ATTN       = 0x00000002;
-constexpr uint32_t CHECKSTOP_ATTN = 0x40000000;
-constexpr uint32_t SPECIAL_ATTN   = 0x20000000;
+constexpr uint32_t SBE_ATTN         = 0x00000002;
+constexpr uint32_t CHECKSTOP_ATTN   = 0x40000000;
+constexpr uint32_t SPECIAL_ATTN     = 0x20000000;
+constexpr uint32_t RECOVERABLE_ATTN = 0x10000000;
 
 // Need to add defaultOpalTiInfo with SRC BB821410 (ascii)
 
diff --git a/attn/attn_logging.cpp b/attn/attn_logging.cpp
index 55c782b..3fb0572 100644
--- a/attn/attn_logging.cpp
+++ b/attn/attn_logging.cpp
@@ -1,5 +1,6 @@
 #include <unistd.h>
 
+#include <analyzer/analyzer_main.hpp>
 #include <attn/attn_common.hpp>
 #include <attn/attn_dbus.hpp>
 #include <attn/attn_dump.hpp>
@@ -195,7 +196,7 @@
  * here contains data to be committed to the PEL and it can also be used to
  * create the PEL as it contains needed information.
  *
- * @param   i_buffer - buffer containing a raw PEL
+ * @param   i_rawPel - buffer containing a raw PEL
  * @param   i_additional - additional data to be added to the new PEL
  */
 void createPelCustom(std::vector<uint8_t>& i_rawPel,
@@ -211,6 +212,19 @@
     uint8_t subsystem = std::stoi(i_additional["Subsystem"]);
     tiPel->setSubsystem(subsystem);
 
+    // If recoverable attentions are active we will call the analyzer and
+    // then link the custom pel to analyzer pel.
+    std::map<std::string, std::string>::iterator it;
+    it = i_additional.find("recoverables");
+    if (it != i_additional.end() && "true" == it->second)
+    {
+        DumpParameters dumpParameters;
+        if (analyzer::analyzeHardware(dumpParameters))
+        {
+            tiPel->setPlid(dumpParameters.logId);
+        }
+    }
+
     if (static_cast<uint8_t>(pel::SubsystemID::hypervisor) == subsystem)
     {
         // populate hypervisor SRC words
@@ -382,7 +396,7 @@
 
         // If this is a TI event we will create an additional PEL that is
         // specific to the subsystem that generated the TI.
-        if ((true == tiEvent) && (0 != pelId))
+        if ((0 != pelId) && (true == tiEvent))
         {
             // get file descriptor and size of information PEL
             int pelFd = getPel(pelId);
diff --git a/attn/pel/pel_minimal.cpp b/attn/pel/pel_minimal.cpp
index 11f589f..e245671 100644
--- a/attn/pel/pel_minimal.cpp
+++ b/attn/pel/pel_minimal.cpp
@@ -104,5 +104,10 @@
     _eh->setSymptomId(symptomId);
 }
 
+void PelMinimal::setPlid(uint32_t plid)
+{
+    _ph->setPlid(plid);
+}
+
 } // namespace pel
 } // namespace attn
diff --git a/attn/pel/pel_minimal.hpp b/attn/pel/pel_minimal.hpp
index ad07ab3..fb2da90 100644
--- a/attn/pel/pel_minimal.hpp
+++ b/attn/pel/pel_minimal.hpp
@@ -121,6 +121,11 @@
      */
     void setSymptomId(const std::string& symptomId);
 
+    /**
+     * @brief Update the PLID
+     */
+    void setPlid(uint32_t plid);
+
   private:
     /**
      * @brief Maximum PEL size
diff --git a/attn/pel/private_header.cpp b/attn/pel/private_header.cpp
index a610594..c724317 100644
--- a/attn/pel/private_header.cpp
+++ b/attn/pel/private_header.cpp
@@ -34,5 +34,10 @@
     _sectionCount = sectionCount;
 }
 
+void PrivateHeader::setPlid(uint32_t plid)
+{
+    _plid = plid;
+}
+
 } // namespace pel
 } // namespace attn
diff --git a/attn/pel/private_header.hpp b/attn/pel/private_header.hpp
index 6d447ee..d6739c7 100644
--- a/attn/pel/private_header.hpp
+++ b/attn/pel/private_header.hpp
@@ -104,6 +104,13 @@
      */
     void setSectionCount(uint8_t sectionCount);
 
+    /**
+     * @brief Set the plid in this PEL
+     *
+     * @param[in] plid - platform log ID
+     */
+    void setPlid(uint32_t plid);
+
   private:
     /**
      * @brief The creation time timestamp
diff --git a/attn/ti_handler.cpp b/attn/ti_handler.cpp
index 5e9f7a4..6d28458 100644
--- a/attn/ti_handler.cpp
+++ b/attn/ti_handler.cpp
@@ -74,6 +74,9 @@
     // gather additional data for PEL
     std::map<std::string, std::string> tiAdditionalData;
 
+    // make note of recoverable errors present
+    tiAdditionalData["recoverables"] = recoverableErrors() ? "true" : "false";
+
     if (nullptr != i_tiDataArea)
     {
         parsePhypOpalTiInfo(tiAdditionalData, i_tiDataArea);
@@ -166,6 +169,10 @@
             // gather additional data for PEL
             std::map<std::string, std::string> tiAdditionalData;
 
+            // make note of recoverable errors present
+            tiAdditionalData["recoverables"] =
+                recoverableErrors() ? "true" : "false";
+
             parseHbTiInfo(tiAdditionalData, i_tiDataArea);
 
             tiAdditionalData["Subsystem"] = std::to_string(