Capture PRD scratch registers in attention handler

PRD uses some scratch registers to debug scenarios when analysis
may have been interrupted. Attention handler will capture these
registers in case the analyzer does not.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I2882afea1299e89ed5b5ad50441d9ca2eea13e96
diff --git a/attn/attn_common.cpp b/attn/attn_common.cpp
index b24da61..1ba5df4 100644
--- a/attn/attn_common.cpp
+++ b/attn/attn_common.cpp
@@ -71,6 +71,75 @@
 
 } // end addHbStatusRegs
 
+/** @brief Capture some scratch registers for PRD */
+void addPrdScratchRegs(std::vector<util::FFDCFile>& o_files)
+{
+    // Get primary processor FSI target for CFAM reads
+    pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, "/proc0/fsi");
+
+    if (nullptr == fsiTarget)
+    {
+        trace::err("error getting scratch register target");
+    }
+    else
+    {
+        uint32_t chipId      = 0;
+        uint32_t signatureId = 0;
+
+        // get scratch register 9 (CFAM)
+        if (RC_SUCCESS != fsi_read(fsiTarget, 0x2980, &chipId))
+        {
+            trace::err("error reading scratch register 9");
+            chipId = 0;
+        }
+
+        // get scratch register 10 (CFAM)
+        if (RC_SUCCESS != fsi_read(fsiTarget, 0x2981, &signatureId))
+        {
+            trace::err("error reading scratch register 10");
+            signatureId = 0;
+        }
+
+        // Add data to traces and create user data section
+        if (0 != chipId || 0 != signatureId)
+        {
+            // trace scratch register data
+            trace::inf("PRD scratch Proc0, Chip ID: %08x, Signature ID: %08x",
+                       chipId, signatureId);
+
+            // create ffdc data for user data section
+            try
+            {
+                util::FFDCFile file{util::FFDCFormat::Text};
+                int fd = file.getFileDescriptor();
+                char buffer[150];
+                int len = sprintf(buffer,
+                                  "Scratch Register Error Signature\n"
+                                  "Processor            : 0\n"
+                                  "Chip ID              : %08x\n"
+                                  "Signature ID         : %08x\n",
+                                  chipId, signatureId);
+                if (write(fd, buffer, len) < 0)
+                {
+                    trace::err("error writing scratch register user data");
+                }
+                else
+                {
+                    o_files.push_back(std::move(file));
+                }
+            }
+            catch (const std::exception& e)
+            {
+                trace::err(
+                    "exception when creating scratch register user data");
+                trace::inf(e.what());
+            }
+        }
+    }
+
+    return;
+}
+
 /** @brief Check for recoverable errors present */
 bool recoverableErrors()
 {
diff --git a/attn/attn_common.hpp b/attn/attn_common.hpp
index cefa126..feb95df 100644
--- a/attn/attn_common.hpp
+++ b/attn/attn_common.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <util/ffdc.hpp>
+
 namespace attn
 {
 
@@ -50,6 +52,18 @@
  */
 void addHbStatusRegs();
 
+/** @brief Capture some scratch registers for PRD
+ *
+ * Capture some scratch register data that PRD can use to handle
+ * cases where analysis may have been interrupted. The data will
+ * be traced and also written to the user data section of a PEL.
+ *
+ * @param[out] o_files vector of FFDC files
+ *
+ * @return nothing
+ */
+void addPrdScratchRegs(std::vector<util::FFDCFile>& o_files);
+
 /**
  * @brief Check for recoverable errors present
  *
diff --git a/attn/attn_logging.cpp b/attn/attn_logging.cpp
index c31a656..7f621df 100644
--- a/attn/attn_logging.cpp
+++ b/attn/attn_logging.cpp
@@ -86,6 +86,9 @@
     // Create trace dump file
     util::createFFDCTraceFiles(files);
 
+    // Add PRD scratch registers
+    addPrdScratchRegs(files);
+
     return files;
 }
 
@@ -275,10 +278,17 @@
 
     tiPel->setAction(static_cast<uint16_t>(actionFlags));
 
-    // The raw PEL that we used as the basis for this custom PEL contains the
-    // attention handler trace data and does not needed to be in this PEL so
-    // we remove it here.
-    tiPel->setSectionCount(tiPel->getSectionCount() - 1);
+    // The raw PEL that we used as the basis for this custom PEL contains some
+    // user data sections that do not need to be in this PEL. However we do
+    // want to include the raw TI information.
+    int ffdcCount = 0;
+    it            = i_additional.find("FFDC count");
+    if (it != i_additional.end())
+    {
+        // remove all sections except 1 (raw Ti info)
+        ffdcCount = std::stoi(it->second) - 1;
+    }
+    tiPel->setSectionCount(tiPel->getSectionCount() - ffdcCount);
 
     // Update the raw PEL with the new custom PEL data
     tiPel->raw(i_rawPel);
@@ -312,6 +322,9 @@
     bool eventValid = false; // assume no event created
     bool tiEvent    = false; // assume not a terminate event
 
+    // count user data sections so we can fixup custom PEL
+    i_additional["FFDC count"] = std::to_string(i_ffdc.size());
+
     std::string eventName;
 
     switch (i_event)