Attn: Determine TI source by host running state

In cases where the TI info is not available use the host running state
to make an educated guess as to the source of the TI.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I95c59ecad90b3aec417a64df4eac0ac5cb50dc09
diff --git a/attn/attn_dbus.cpp b/attn/attn_dbus.cpp
index 9f4bbc9..97843b8 100644
--- a/attn/attn_dbus.cpp
+++ b/attn/attn_dbus.cpp
@@ -1,4 +1,7 @@
+#include <attn_dbus.hpp>
+#include <attn_handler.hpp>
 #include <attn_logging.hpp>
+#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
 
 #include <string>
 #include <vector>
@@ -16,14 +19,16 @@
  * @param i_interface - dbus method interface
  * @param i_function - dbus interface function
  * @param o_method - method that is created
+ * @param i_extended - optional for extended methods
  * @return non-zero if error
  *
  **/
 int dbusMethod(const std::string& i_path, const std::string& i_interface,
                const std::string& i_function,
-               sdbusplus::message::message& o_method)
+               sdbusplus::message::message& o_method,
+               const std::string& i_extended = "")
 {
-    int rc = 1; // assume error
+    int rc = RC_DBUS_ERROR; // assume error
 
     try
     {
@@ -54,12 +59,23 @@
         {
             auto service = responseFindService.begin()->first;
 
-            // return the method
-            o_method =
-                bus.new_method_call(service.c_str(), i_path.c_str(),
-                                    i_interface.c_str(), i_function.c_str());
+            // Some methods (e.g. get attribute) take an extended parameter
+            if (i_extended == "")
+            {
+                // return the method
+                o_method = bus.new_method_call(service.c_str(), i_path.c_str(),
+                                               i_interface.c_str(),
+                                               i_function.c_str());
+            }
+            else
+            {
+                // return extended method
+                o_method =
+                    bus.new_method_call(service.c_str(), i_path.c_str(),
+                                        i_extended.c_str(), i_function.c_str());
+            }
 
-            rc = 0;
+            rc = RC_SUCCESS;
         }
         else
         {
@@ -112,7 +128,7 @@
             // reply will be tuple containing bmc log id, platform log id
             std::tuple<uint32_t, uint32_t> reply = {0, 0};
 
-            // parse dbus reply
+            // parse dbus response into reply
             response.read(reply);
             plid = std::get<1>(reply); // platform log id is tuple "second"
         }
@@ -205,7 +221,7 @@
             // reply will be a unix file descriptor
             sdbusplus::message::unix_fd reply;
 
-            // parse dbus reply
+            // parse dbus response into reply
             response.read(reply);
 
             fd = dup(reply); // need to copy (dup) the file descriptor
@@ -221,4 +237,66 @@
     return fd; // file descriptor or -1
 }
 
+/** @brief Get the running state of the host */
+HostRunningState hostRunningState()
+{
+    HostRunningState host = HostRunningState::Unknown;
+
+    // dbus specifics
+    constexpr auto path      = "/xyz/openbmc_project/state/host0";
+    constexpr auto interface = "xyz.openbmc_project.State.Boot.Progress";
+    constexpr auto extended  = "org.freedesktop.DBus.Properties";
+    constexpr auto function  = "Get";
+
+    sdbusplus::message::message method;
+
+    if (0 == dbusMethod(path, interface, function, method, extended))
+    {
+        try
+        {
+            // additional dbus call parameters
+            method.append(interface, "BootProgress");
+
+            // using system dbus
+            auto bus      = sdbusplus::bus::new_system();
+            auto response = bus.call(method);
+
+            // reply will be a variant
+            std::variant<std::string, bool, std::vector<uint8_t>,
+                         std::vector<std::string>>
+                reply;
+
+            // parse dbus response into reply
+            response.read(reply);
+
+            // get boot progress (string) and convert to boot stage
+            std::string bootProgress(std::get<std::string>(reply));
+
+            using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::
+                server::Progress::ProgressStages;
+
+            BootProgress stage = sdbusplus::xyz::openbmc_project::State::Boot::
+                server::Progress::convertProgressStagesFromString(bootProgress);
+
+            if ((stage == BootProgress::SystemInitComplete) ||
+                (stage == BootProgress::OSStart) ||
+                (stage == BootProgress::OSRunning))
+            {
+                host = HostRunningState::Started;
+            }
+            else
+            {
+                host = HostRunningState::NotStarted;
+            }
+        }
+        catch (const sdbusplus::exception::SdBusError& e)
+        {
+            trace<level::INFO>("hostRunningState exception");
+            std::string traceMsg = std::string(e.what(), maxTraceLen);
+            trace<level::ERROR>(traceMsg.c_str());
+        }
+    }
+
+    return host;
+}
 } // namespace attn
diff --git a/attn/attn_dbus.hpp b/attn/attn_dbus.hpp
index 8f21fbe..700097f 100644
--- a/attn/attn_dbus.hpp
+++ b/attn/attn_dbus.hpp
@@ -8,6 +8,13 @@
 namespace attn
 {
 
+enum class HostRunningState
+{
+    Unknown,
+    NotStarted,
+    Started
+};
+
 /**
  * Create a PEL for the specified event type
  *
@@ -46,4 +53,14 @@
  */
 int getPel(const uint32_t i_pelId);
 
+/**
+ * Get the host running state
+ *
+ * Use host boot progress to determine if a host has been started. If host
+ * boot progress can not be determined then host state will be unknown.
+ *
+ * @return HostType == "Unknown", "Started or "NotStarted"
+ */
+HostRunningState hostRunningState();
+
 } // namespace attn
diff --git a/attn/attn_handler.cpp b/attn/attn_handler.cpp
index 693e4c8..f4454cf 100644
--- a/attn/attn_handler.cpp
+++ b/attn/attn_handler.cpp
@@ -4,6 +4,7 @@
 #include <attn/attention.hpp>
 #include <attn/attn_common.hpp>
 #include <attn/attn_config.hpp>
+#include <attn/attn_dbus.hpp>
 #include <attn/attn_handler.hpp>
 #include <attn/attn_logging.hpp>
 #include <attn/bp_handler.hpp>
@@ -257,10 +258,33 @@
             if (PDBG_TARGET_ENABLED == pdbg_target_probe(tiInfoTarget))
             {
                 sbe_mpipl_get_ti_info(tiInfoTarget, &tiInfo, &tiInfoLen);
-                if (tiInfo == nullptr)
+
+                // If TI info not available use default based on host state
+                if (nullptr == tiInfo)
                 {
-                    trace<level::INFO>("TI info data ptr is null after call");
-                    tiInfo       = (uint8_t*)defaultPhypTiInfo;
+                    trace<level::INFO>("TI info data ptr is invalid");
+
+                    HostRunningState runningState = hostRunningState();
+                    std::string stateString       = "host state unknown";
+
+                    if ((HostRunningState::Started == runningState) ||
+                        (HostRunningState::Unknown == runningState))
+                    {
+                        if (HostRunningState::Started == runningState)
+                        {
+                            stateString = "host started";
+                        }
+                        tiInfo = (uint8_t*)defaultPhypTiInfo;
+                    }
+                    else
+                    {
+                        stateString = "host not started";
+                        tiInfo      = (uint8_t*)defaultHbTiInfo;
+                    }
+
+                    // trace host state
+                    trace<level::INFO>(stateString.c_str());
+
                     tiInfoStatic = true; // using our TI info
                 }
             }
diff --git a/attn/attn_handler.hpp b/attn/attn_handler.hpp
index c969523..770f6e9 100644
--- a/attn/attn_handler.hpp
+++ b/attn/attn_handler.hpp
@@ -8,10 +8,11 @@
 /** @brief Attention handler return codes */
 enum ReturnCodes
 {
-    RC_SUCCESS = 0,
-    RC_NOT_HANDLED,
-    RC_ANALYZER_ERROR,
-    RC_CFAM_ERROR
+    RC_SUCCESS        = 0,
+    RC_NOT_HANDLED    = 1,
+    RC_ANALYZER_ERROR = 2,
+    RC_CFAM_ERROR     = 3,
+    RC_DBUS_ERROR     = 4
 };
 
 /** @brief Code seciton for error reporing */
@@ -37,8 +38,6 @@
 constexpr uint32_t CHECKSTOP_ATTN = 0x40000000;
 constexpr uint32_t SPECIAL_ATTN   = 0x20000000;
 
-// Need to add defaultHbTiInfo with SRC BC801B99 (hex)
-
 // Need to add defaultOpalTiInfo with SRC BB821410 (ascii)
 
 constexpr uint8_t defaultPhypTiInfo[0x58] = {
@@ -51,6 +50,16 @@
     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
     0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
+constexpr uint8_t defaultHbTiInfo[0x58] = {
+    0x01, 0xa1, 0x02, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x09, 0x01, 0x00, 0x00, 0x00, 0xbc, 0x80, 0x1b, 0x99, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
 /**
  * @brief The main attention handler logic
  *
diff --git a/attn/ti_handler.cpp b/attn/ti_handler.cpp
index c1e2d2e..ff66289 100644
--- a/attn/ti_handler.cpp
+++ b/attn/ti_handler.cpp
@@ -246,8 +246,8 @@
             // Translate hex src value to ascii. This results in an 8 character
             // SRC (hostboot SRC is 32 bits)
             std::stringstream src;
-            src << std::setw(8) << std::setfill('0') << std::hex
-                << be32toh(i_tiDataArea->srcWord12HbWord0);
+            src << std::setw(8) << std::setfill('0') << std::uppercase
+                << std::hex << be32toh(i_tiDataArea->srcWord12HbWord0);
             tiAdditionalData["SrcAscii"] = src.str();
 
             eventTerminate(tiAdditionalData, (char*)i_tiDataArea);