Add support for Get TI Info chipop

Use the Get TI Info chipop to determine if a special attention was
due to a TI or a breakpoint.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I256dcf1171c27e851032353226c174307105cd0a
diff --git a/attn/attention.cpp b/attn/attention.cpp
index 0806ef2..3fd3f83 100644
--- a/attn/attention.cpp
+++ b/attn/attention.cpp
@@ -30,6 +30,12 @@
     return iv_handler(this);
 }
 
+/* @brief Get attention handler target */
+pdbg_target* Attention::getTarget() const
+{
+    return iv_target;
+}
+
 /** @brief less than operator, for heap creation */
 bool Attention::operator<(const Attention& right) const
 {
diff --git a/attn/attention.hpp b/attn/attention.hpp
index a4d3461..69f9fcf 100644
--- a/attn/attention.hpp
+++ b/attn/attention.hpp
@@ -52,6 +52,9 @@
     /* @brief Call attention handler function */
     int handle();
 
+    /* @brief Get attention handler target */
+    pdbg_target* getTarget() const;
+
     /** @brief Copy constructor. */
     Attention(const Attention&) = default;
 
diff --git a/attn/attn_handler.cpp b/attn/attn_handler.cpp
index 945156d..6ea2fdc 100644
--- a/attn/attn_handler.cpp
+++ b/attn/attn_handler.cpp
@@ -1,3 +1,5 @@
+#include <libpdbg.h>
+
 #include <analyzer/analyzer_main.hpp>
 #include <attention.hpp>
 #include <attn_config.hpp>
@@ -62,7 +64,6 @@
     pdbg_target* target;
     pdbg_for_each_class_target("fsi", target)
     {
-        trace<level::INFO>("iterating targets");
         if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
         {
             proc = pdbg_target_index(target); // get processor number
@@ -173,22 +174,11 @@
     if (false == (i_attention->getConfig()->getFlag(enVital)))
     {
         trace<level::INFO>("vital handling disabled");
+        rc = RC_NOT_HANDLED;
     }
     else
     {
-        // TODO need vital attention handling
-
-        // FIXME TEMP CODE - begin
-        if (0)
-        {
-            eventVital();
-        }
-        else
-        {
-            trace<level::INFO>("vital NOT handled"); // enabled but not handled
-            rc = RC_NOT_HANDLED;
-        }
-        // FIXME TEMP CODE -end
+        eventVital();
     }
 
     return rc;
@@ -248,24 +238,41 @@
 {
     int rc = RC_SUCCESS; // assume special attention handled
 
-    trace<level::INFO>("special attention handler started");
+    // The TI infor chipop will give us a pointer to the TI info data
+    uint8_t* tiInfo           = nullptr; // ptr to TI info data
+    uint32_t tiInfoLen        = 0;       // length of TI info data
+    pdbg_target* tiInfoTarget = i_attention->getTarget(); // get TI info target
 
-    // TODO
-    // Until the special attention chipop is availabe we will treat the special
-    // attention as a TI. If TI handling is disabled we will treat the special
-    // attention as a breakpopint.
+    // Get length and location of TI info data
+    sbe_mpipl_get_ti_info(tiInfoTarget, &tiInfo, &tiInfoLen);
 
-    // TI attention gets priority over breakpoints, if enabled then handle
-    if (true == (i_attention->getConfig()->getFlag(enTerminate)))
+    // Note: If we want to support running this application on architectures
+    // of different endian-ness we need to handler that here. The TI data
+    // will always be written in big-endian order.
+
+    // If TI area exists and is marked valid we can assume TI occurred
+    if ((nullptr != tiInfo) && (0 != tiInfo[0]))
     {
-        trace<level::INFO>("TI (terminate immediately)");
+        TiDataArea* tiDataArea = (TiDataArea*)tiInfo;
 
-        // Call TI special attention handler
-        tiHandler();
+        // trace a few known TI data area values
+        std::stringstream ss; // log message stream
+        ss << "TI data command = " << tiDataArea->command;
+        trace<level::INFO>(ss.str().c_str());
+        ss << "TI data SRC format = " << tiDataArea->srcFormat;
+        trace<level::INFO>(ss.str().c_str());
+        ss << "TI data hb_terminate_type = " << tiDataArea->hbTerminateType;
+        trace<level::INFO>(ss.str().c_str());
 
-        // generate log event
-        eventTerminate();
+        if (true == (i_attention->getConfig()->getFlag(enTerminate)))
+        {
+            trace<level::INFO>("TI (terminate immediately)");
+
+            // Call TI special attention handler
+            rc = tiHandler(tiDataArea);
+        }
     }
+    // TI area not valid, assume breakpoint
     else
     {
         if (true == (i_attention->getConfig()->getFlag(enBreakpoints)))
@@ -277,9 +284,15 @@
         }
     }
 
+    // release TI data buffer
+    if (nullptr != tiInfo)
+    {
+        free(tiInfo);
+    }
+
     if (RC_SUCCESS != rc)
     {
-        trace<level::INFO>("Special attn handling disabled");
+        trace<level::INFO>("Special attn not handled");
     }
 
     return rc;
diff --git a/attn/ti_handler.cpp b/attn/ti_handler.cpp
index 4801f2c..f1354aa 100644
--- a/attn/ti_handler.cpp
+++ b/attn/ti_handler.cpp
@@ -1,27 +1,36 @@
+#include <attn_handler.hpp>
 #include <attn_logging.hpp>
 #include <sdbusplus/bus.hpp>
+#include <ti_handler.hpp>
 
 namespace attn
 {
 
 /** @brief Start host diagnostic mode systemd unit */
-void tiHandler()
+int tiHandler(TiDataArea* i_tiDataArea)
 {
-    // trace message
-    trace<level::INFO>("start host diagnostic mode service");
+    int rc = RC_NOT_HANDLED; // assume TI not handled
 
-    // Use the systemd service manager object interface to call the start unit
-    // method with the obmc-host-diagnostic-mode target.
-    auto bus    = sdbusplus::bus::new_system();
-    auto method = bus.new_method_call(
-        "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
-        "org.freedesktop.systemd1.Manager", "StartUnit");
+    if (0xa1 == i_tiDataArea->command)
+    {
+        // trace message
+        trace<level::INFO>("start host diagnostic mode service");
 
-    method.append("obmc-host-diagnostic-mode@0.target"); // unit to activate
-    method.append("replace"); // mode = replace conflicting queued jobs
-    bus.call_noreply(method); // start the service
+        // Use the systemd service manager object interface to call the start
+        // unit method with the obmc-host-diagnostic-mode target.
+        auto bus    = sdbusplus::bus::new_system();
+        auto method = bus.new_method_call(
+            "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
+            "org.freedesktop.systemd1.Manager", "StartUnit");
 
-    return;
+        method.append("obmc-host-diagnostic-mode@0.target"); // unit to activate
+        method.append("replace"); // mode = replace conflicting queued jobs
+        bus.call_noreply(method); // start the service
+
+        rc = RC_SUCCESS;
+    }
+
+    return rc;
 }
 
 } // namespace attn
diff --git a/attn/ti_handler.hpp b/attn/ti_handler.hpp
index d3b83cd..bc28f71 100644
--- a/attn/ti_handler.hpp
+++ b/attn/ti_handler.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <stdint.h>
+
 /**
  * @brief TI special attention handler
  *
@@ -8,6 +10,47 @@
 namespace attn
 {
 
-void tiHandler();
+// TI data area definition
+#pragma pack(push)
+#pragma pack(1)
+struct TiDataArea
+{
+    uint8_t tiAreaValid;       // 0x00, common (non-zero == valid)
+    uint8_t command;           // 0x01, phyp/opal = 0xA1
+    uint16_t numDataBytes;     // 0x02, phyp/opal
+    uint8_t reserved1;         // 0x04, reserved
+    uint8_t hbTerminateType;   // 0x05, hostboot only
+    uint16_t hardwareDumpType; // 0x06, phyp/opal
+    uint8_t srcFormat;         // 0x08, phyp/opal = 0x02
+    uint8_t srcFlags;          // 0x09, phyp/opal
+    uint8_t numAsciiWords;     // 0x0a, phyp/opal
+    uint8_t numHexWords;       // 0x0b, phyp/opal
+    uint8_t hbDumpFlag;        // 0x0c, hostboot only
+    uint8_t source;            // 0x0d, hostboot only
+    uint16_t lenSrc;           // 0x0e, phyp/opal
+    uint32_t srcWord12HbWord0; // 0x10, common
+    uint32_t srcWord13HbWord2; // 0x14, common (Word1 intentionally skipped)
+    uint32_t srcWord14HbWord3; // 0x18, common
+    uint32_t srcWord15HbWord4; // 0x1c, common
+    uint32_t srcWord16HbWord5; // 0x20, common
+    uint32_t srcWord17HbWord6; // 0x24, common
+    uint32_t srcWord18HbWord7; // 0x28, common
+    uint32_t srcWord19HbWord8; // 0x2c, common
+    uint32_t asciiData0;       // 0x30, phyp/opal, hostboot error_data
+    uint32_t asciiData1;       // 0x34, phyp/opal, hostboot EID
+    uint32_t asciiData2;       // 0x38, phyp/opal
+    uint32_t asciiData3;       // 0x3c, phyp/opal
+    uint32_t asciiData4;       // 0x40, phyp/opal
+    uint32_t asciiData5;       // 0x44, phyp/opal
+    uint32_t asciiData6;       // 0x48, phyp/opal
+    uint32_t asciiData7;       // 0x4c, phyp/opal
+    uint8_t location;          // 0x50, phyp/opal
+    uint8_t codeSection;       // 0x51, phyp/opal
+    uint8_t additionalSize;    // 0x52, phyp/opal
+    uint8_t andData;           // 0x53, phyp/opal
+};
+#pragma pack(pop)
+
+int tiHandler(TiDataArea* i_tiDataArea);
 
 } // namespace attn