On checkstop request dump and transition host

After checkstop analyses completes attention handler will request a dump
and the transition the host. The type of dump requested is dependent on
the results of the isolator.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I1116be8f8d045a4916d3321f461c22345fecf274
diff --git a/analyzer/analyzer_main.cpp b/analyzer/analyzer_main.cpp
index 68babfe..c8de857 100644
--- a/analyzer/analyzer_main.cpp
+++ b/analyzer/analyzer_main.cpp
@@ -4,6 +4,7 @@
 
 #include <analyzer/ras-data/ras-data-parser.hpp>
 #include <analyzer/service_data.hpp>
+#include <attn/attn_dump.hpp>
 #include <hei_main.hpp>
 #include <phosphor-logging/log.hpp>
 #include <util/pdbg.hpp>
@@ -32,9 +33,10 @@
  * @brief Will create and submit a PEL using the given data.
  * @param i_isoData   The data gathered during isolation (for FFDC).
  * @param i_servData  Data regarding service actions gathered during analysis.
+ * @return Tuple of BMC log id, platform log id
  */
-void createPel(const libhei::IsolationData& i_isoData,
-               const ServiceData& i_servData);
+std::tuple<uint32_t, uint32_t> createPel(const libhei::IsolationData& i_isoData,
+                                         const ServiceData& i_servData);
 
 //------------------------------------------------------------------------------
 
@@ -120,7 +122,7 @@
 
 //------------------------------------------------------------------------------
 
-bool analyzeHardware()
+bool analyzeHardware(attn::DumpParameters& o_dumpParameters)
 {
     bool attnFound = false;
 
@@ -166,7 +168,12 @@
         rasData.getResolution(rootCause)->resolve(servData);
 
         // Create and commit a PEL.
-        createPel(isoData, servData);
+        uint32_t logId = std::get<1>(createPel(isoData, servData));
+
+        // Populate dump parameters
+        o_dumpParameters.logId    = logId;
+        o_dumpParameters.unitId   = 0;
+        o_dumpParameters.dumpType = attn::DumpType::Hardware;
     }
 
     // All done, clean up the isolator.
diff --git a/analyzer/analyzer_main.hpp b/analyzer/analyzer_main.hpp
index e0c9f47..5619ba3 100644
--- a/analyzer/analyzer_main.hpp
+++ b/analyzer/analyzer_main.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <attn/attn_dump.hpp>
+
 namespace analyzer
 {
 
@@ -8,6 +10,7 @@
  *         chip. Then it performs all approriate RAS actions based on the active
  *         attentions.
  *
+ * @param[out] o_dumpParameters Dump request parameters
  * @return True if an active attenion was successfully analyzed, false
  *         otherwise.
  *         For system checkstop handling:
@@ -19,7 +22,7 @@
  *            analysis could fail to find an attention and it should not be
  *            treated as a defect.
  */
-bool analyzeHardware();
+bool analyzeHardware(attn::DumpParameters& o_dumpParameters);
 
 /**
  * @brief Get error analyzer build information
diff --git a/analyzer/create_pel.cpp b/analyzer/create_pel.cpp
index e9835c5..38a7d5f 100644
--- a/analyzer/create_pel.cpp
+++ b/analyzer/create_pel.cpp
@@ -6,6 +6,7 @@
 #include <phosphor-logging/elog.hpp>
 #include <sdbusplus/bus.hpp>
 #include <util/bin_stream.hpp>
+#include <util/dbus.hpp>
 #include <util/ffdc_file.hpp>
 #include <util/pdbg.hpp>
 #include <util/trace.hpp>
@@ -263,8 +264,8 @@
 
 //------------------------------------------------------------------------------
 
-void createPel(const libhei::IsolationData& i_isoData,
-               const ServiceData& i_servData)
+std::tuple<uint32_t, uint32_t> createPel(const libhei::IsolationData& i_isoData,
+                                         const ServiceData& i_servData)
 {
     // The message registry will require additional log data to fill in keywords
     // and additional log data.
@@ -300,28 +301,58 @@
     std::vector<util::FFDCTuple> userData;
     util::transformFFDC(userDataFiles, userData);
 
-    // Get access to logging interface and method for creating log.
-    auto bus = sdbusplus::bus::new_default_system();
+    // Response will be a tuple containing bmc-log-id, pel-log-id
+    std::tuple<uint32_t, uint32_t> response = {0, 0};
 
-    // Using direct create method (for additional data).
-    auto method = bus.new_method_call(
-        "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
-        "xyz.openbmc_project.Logging.Create", "CreateWithFFDCFiles");
+    try
+    {
+        // We want to use the logging interface that returns the event log
+        // id's of the newly created logs (org.open_power.Logging.PEL) so
+        // find the service that implements this interface.
+        constexpr auto interface = "org.open_power.Logging.PEL";
+        constexpr auto path      = "/xyz/openbmc_project/logging";
+        std::string service;
 
-    // The "Create" method requires manually adding the process ID.
-    logData["_PID"] = std::to_string(getpid());
+        if (0 == util::dbus::findService(interface, path, service))
+        {
+            // Use function that returns log id's
+            constexpr auto function = "CreatePELWithFFDCFiles";
 
-    // Get the message registry entry for this failure.
-    auto message = __getMessageRegistry(isCheckstop);
+            // Get access to logging interface and method for creating log.
+            auto bus = sdbusplus::bus::new_default_system();
 
-    // Get the message severity for this failure.
-    auto severity = __getMessageSeverity(isCheckstop);
+            // Using direct create method (for additional data).
+            auto method =
+                bus.new_method_call(service.c_str(), path, interface, function);
 
-    // Add the message, with additional log and user data.
-    method.append(message, severity, logData, userData);
+            // The "Create" method requires manually adding the process ID.
+            logData["_PID"] = std::to_string(getpid());
 
-    // Log the event.
-    bus.call_noreply(method);
+            // Get the message registry entry for this failure.
+            auto message = __getMessageRegistry(isCheckstop);
+
+            // Get the message severity for this failure.
+            auto severity = __getMessageSeverity(isCheckstop);
+
+            // Add the message, with additional log and user data.
+            method.append(message, severity, logData, userData);
+
+            // Log the event.
+            auto reply = bus.call(method);
+
+            // Parse reply for response
+            reply.read(response);
+        }
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        trace::err("Exception while creating event log entry");
+        std::string exceptionString = std::string(e.what());
+        trace::err(exceptionString.c_str());
+    }
+
+    // return tuple of {bmc-log-id, pel-log-id} or {0, 0} on error
+    return response;
 }
 
 } // namespace analyzer
diff --git a/attn/attn_dump.cpp b/attn/attn_dump.cpp
new file mode 100644
index 0000000..95976be
--- /dev/null
+++ b/attn/attn_dump.cpp
@@ -0,0 +1,133 @@
+#include <attn/attn_dbus.hpp>
+#include <attn/attn_dump.hpp>
+#include <attn/attn_logging.hpp>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/exception.hpp>
+
+namespace attn
+{
+
+/**
+ *  Callback for dump request properties change signal monitor
+ *
+ * @param[in] i_msg         Dbus message from the dbus match infrastructure
+ * @param[in] i_path        The object path we are monitoring
+ * @param[out] o_inProgress Used to break out of our dbus wait loop
+ * @reutn Always non-zero indicating no error, no cascading callbacks
+ */
+uint dumpStatusChanged(sdbusplus::message::message& i_msg, std::string i_path,
+                       bool& o_inProgress)
+{
+    // reply (msg) will be a property change message
+    std::string interface;
+    std::map<std::string, std::variant<std::string, uint8_t>> property;
+    i_msg.read(interface, property);
+
+    // looking for property Status changes
+    std::string propertyType = "Status";
+    auto dumpStatus          = property.find(propertyType);
+
+    if (dumpStatus != property.end())
+    {
+        const std::string* status =
+            std::get_if<std::string>(&(dumpStatus->second));
+
+        if ((nullptr != status) && ("xyz.openbmc_project.Common.Progress."
+                                    "OperationStatus.InProgress" != *status))
+        {
+            // dump is done, trace some info and change in progress flag
+            trace<level::INFO>(i_path.c_str());
+            trace<level::INFO>((*status).c_str());
+            o_inProgress = false;
+        }
+    }
+
+    return 1; // non-negative return code for successful callback
+}
+
+/**
+ * Register a callback for dump progress status changes
+ *
+ * @param[in] i_path The object path of the dump to monitor
+ */
+void monitorDump(const std::string& i_path)
+{
+    bool inProgress = true; // callback will update this
+
+    // setup the signal match rules and callback
+    std::string matchInterface = "xyz.openbmc_project.Common.Progress";
+    auto bus                   = sdbusplus::bus::new_system();
+
+    std::unique_ptr<sdbusplus::bus::match_t> match =
+        std::make_unique<sdbusplus::bus::match_t>(
+            bus,
+            sdbusplus::bus::match::rules::propertiesChanged(
+                i_path.c_str(), matchInterface.c_str()),
+            [&](auto& msg) {
+                return dumpStatusChanged(msg, i_path, inProgress);
+            });
+
+    // wait for dump status to be completed (complete == true)
+    trace<level::INFO>("dump requested (waiting)");
+    while (true == inProgress)
+    {
+        bus.wait(0);
+        bus.process_discard();
+    }
+    trace<level::INFO>("dump completed");
+}
+
+/** Request a dump from the dump manager */
+void requestDump(const DumpParameters& i_dumpParameters)
+{
+    constexpr auto path      = "/org/openpower/dump";
+    constexpr auto interface = "xyz.openbmc_project.Dump.Create";
+    constexpr auto function  = "CreateDump";
+
+    sdbusplus::message::message method;
+
+    if (0 == dbusMethod(path, interface, function, method))
+    {
+        try
+        {
+            // dbus call arguments
+            std::map<std::string, std::variant<std::string, uint64_t>>
+                createParams;
+            createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] =
+                uint64_t(i_dumpParameters.logId);
+            if (DumpType::Hostboot == i_dumpParameters.dumpType)
+            {
+                createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
+                    "com.ibm.Dump.Create.DumpType.Hostboot";
+            }
+            else if (DumpType::Hardware == i_dumpParameters.dumpType)
+            {
+                createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
+                    "com.ibm.Dump.Create.DumpType.Hardware";
+                createParams
+                    ["com.ibm.Dump.Create.CreateParameters.FailingUnitId"] =
+                        i_dumpParameters.unitId;
+            }
+            method.append(createParams);
+
+            // using system dbus
+            auto bus      = sdbusplus::bus::new_system();
+            auto response = bus.call(method);
+
+            // reply will be type dbus::ObjectPath
+            sdbusplus::message::object_path reply;
+            response.read(reply);
+
+            // monitor dump progress
+            monitorDump(reply);
+        }
+        catch (const sdbusplus::exception::SdBusError& e)
+        {
+            trace<level::ERROR>("requestDump exception");
+            std::string traceMsg = std::string(e.what(), maxTraceLen);
+            trace<level::ERROR>(traceMsg.c_str());
+        }
+    }
+}
+
+} // namespace attn
diff --git a/attn/attn_dump.hpp b/attn/attn_dump.hpp
new file mode 100644
index 0000000..6480b15
--- /dev/null
+++ b/attn/attn_dump.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+namespace attn
+{
+
+/** @brief Dump types supported by dump request */
+enum class DumpType
+{
+    Hostboot,
+    Hardware
+};
+
+/** @brief Structure for dump request parameters */
+class DumpParameters
+{
+  public:
+    uint32_t logId;
+    uint32_t unitId;
+    DumpType dumpType;
+};
+
+/**
+ * Request a dump from the dump manager
+ *
+ * Request a dump from the dump manager and register a monitor for observing
+ * the dump progress.
+ *
+ * @param dumpParameters Parameters for the dump request
+ */
+void requestDump(const DumpParameters& dumpParameters);
+
+} // namespace attn
diff --git a/attn/attn_handler.cpp b/attn/attn_handler.cpp
index 85172ea..566b2f7 100644
--- a/attn/attn_handler.cpp
+++ b/attn/attn_handler.cpp
@@ -227,10 +227,16 @@
     {
         // Look for any attentions found in hardware. This will generate and
         // commit a PEL if any errors are found.
-        if (true != analyzer::analyzeHardware())
+        DumpParameters dumpParameters;
+        if (true != analyzer::analyzeHardware(dumpParameters))
         {
             rc = RC_ANALYZER_ERROR;
         }
+        else
+        {
+            requestDump(dumpParameters);
+            util::dbus::transitionHost(util::dbus::HostState::Quiesce);
+        }
     }
 
     return rc;
diff --git a/attn/attn_logging.cpp b/attn/attn_logging.cpp
index d930f5d..d85a66c 100644
--- a/attn/attn_logging.cpp
+++ b/attn/attn_logging.cpp
@@ -2,9 +2,9 @@
 
 #include <attn/attn_common.hpp>
 #include <attn/attn_dbus.hpp>
+#include <attn/attn_dump.hpp>
 #include <attn/attn_logging.hpp>
 #include <attn/pel/pel_minimal.hpp>
-#include <attn/ti_handler.hpp>
 #include <phosphor-logging/log.hpp>
 
 namespace attn
@@ -415,7 +415,7 @@
                 if ("true" == i_additional["Dump"])
                 {
                     // will not return until dump is complete
-                    requestDump(pelId);
+                    requestDump(DumpParameters{pelId, 0, DumpType::Hostboot});
                 }
             }
         }
diff --git a/attn/meson.build b/attn/meson.build
index 9397274..b4d2705 100644
--- a/attn/meson.build
+++ b/attn/meson.build
@@ -36,6 +36,7 @@
     'attn_common.cpp',
     'attn_config.cpp',
     'attn_dbus.cpp',
+    'attn_dump.cpp',
     'attn_handler.cpp',
     'attn_main.cpp',
     'attn_monitor.cpp',
diff --git a/attn/ti_handler.cpp b/attn/ti_handler.cpp
index de692ac..54345a6 100644
--- a/attn/ti_handler.cpp
+++ b/attn/ti_handler.cpp
@@ -392,116 +392,4 @@
     }
 }
 
-/**
- *  Callback for dump request properties change signal monitor
- *
- * @param[in] i_msg         Dbus message from the dbus match infrastructure
- * @param[in] i_path        The object path we are monitoring
- * @param[out] o_inProgress Used to break out of our dbus wait loop
- * @reutn Always non-zero indicating no error, no cascading callbacks
- */
-uint dumpStatusChanged(sdbusplus::message::message& i_msg, std::string i_path,
-                       bool& o_inProgress)
-{
-    // reply (msg) will be a property change message
-    std::string interface;
-    std::map<std::string, std::variant<std::string, uint8_t>> property;
-    i_msg.read(interface, property);
-
-    // looking for property Status changes
-    std::string propertyType = "Status";
-    auto dumpStatus          = property.find(propertyType);
-
-    if (dumpStatus != property.end())
-    {
-        const std::string* status =
-            std::get_if<std::string>(&(dumpStatus->second));
-
-        if ((nullptr != status) && ("xyz.openbmc_project.Common.Progress."
-                                    "OperationStatus.InProgress" != *status))
-        {
-            // dump is done, trace some info and change in progress flag
-            trace<level::INFO>(i_path.c_str());
-            trace<level::INFO>((*status).c_str());
-            o_inProgress = false;
-        }
-    }
-
-    return 1; // non-negative return code for successful callback
-}
-
-/**
- * Register a callback for dump progress status changes
- *
- * @param[in] i_path The object path of the dump to monitor
- */
-void monitorDump(const std::string& i_path)
-{
-    bool inProgress = true; // callback will update this
-
-    // setup the signal match rules and callback
-    std::string matchInterface = "xyz.openbmc_project.Common.Progress";
-    auto bus                   = sdbusplus::bus::new_system();
-
-    std::unique_ptr<sdbusplus::bus::match_t> match =
-        std::make_unique<sdbusplus::bus::match_t>(
-            bus,
-            sdbusplus::bus::match::rules::propertiesChanged(
-                i_path.c_str(), matchInterface.c_str()),
-            [&](auto& msg) {
-                return dumpStatusChanged(msg, i_path, inProgress);
-            });
-
-    // wait for dump status to be completed (complete == true)
-    trace<level::INFO>("hbdump requested");
-    while (true == inProgress)
-    {
-        bus.wait(0);
-        bus.process_discard();
-    }
-    trace<level::INFO>("hbdump completed");
-}
-
-/** Request a dump from the dump manager */
-void requestDump(const uint32_t logId)
-{
-    constexpr auto path      = "/org/openpower/dump";
-    constexpr auto interface = "xyz.openbmc_project.Dump.Create";
-    constexpr auto function  = "CreateDump";
-
-    sdbusplus::message::message method;
-
-    if (0 == dbusMethod(path, interface, function, method))
-    {
-        try
-        {
-            // dbus call arguments
-            std::map<std::string, std::variant<std::string, uint64_t>>
-                createParams;
-            createParams["com.ibm.Dump.Create.CreateParameters.DumpType"] =
-                "com.ibm.Dump.Create.DumpType.Hostboot";
-            createParams["com.ibm.Dump.Create.CreateParameters.ErrorLogId"] =
-                uint64_t(logId);
-            method.append(createParams);
-
-            // using system dbus
-            auto bus      = sdbusplus::bus::new_system();
-            auto response = bus.call(method);
-
-            // reply will be type dbus::ObjectPath
-            sdbusplus::message::object_path reply;
-            response.read(reply);
-
-            // monitor dump progress
-            monitorDump(reply);
-        }
-        catch (const sdbusplus::exception::SdBusError& e)
-        {
-            trace<level::ERROR>("requestDump exception");
-            std::string traceMsg = std::string(e.what(), maxTraceLen);
-            trace<level::ERROR>(traceMsg.c_str());
-        }
-    }
-}
-
 } // namespace attn
diff --git a/attn/ti_handler.hpp b/attn/ti_handler.hpp
index 9472c2c..e659c50 100644
--- a/attn/ti_handler.hpp
+++ b/attn/ti_handler.hpp
@@ -124,14 +124,4 @@
 void parseHbTiInfo(std::map<std::string, std::string>& i_map,
                    TiDataArea* i_tiDataArea);
 
-/**
- * Request a dump from the dump manager
- *
- * Request a dump from the dump manager and register a monitor for observing
- * the dump progress.
- *
- * @param logId The id of the event log associated with this dump request
- */
-void requestDump(const uint32_t logId);
-
 } // namespace attn
diff --git a/main_nl.cpp b/main_nl.cpp
index 3510e8a..16baa36 100644
--- a/main_nl.cpp
+++ b/main_nl.cpp
@@ -3,6 +3,7 @@
 #include <analyzer/analyzer_main.hpp>
 #include <attn/attention.hpp>
 #include <attn/attn_config.hpp>
+#include <attn/attn_dump.hpp>
 #include <attn/attn_handler.hpp>
 #include <attn/attn_main.hpp>
 #include <buildinfo.hpp>
@@ -47,7 +48,8 @@
         // Either analyze (application mode) or daemon mode
         if (true == getCliOption(argv, argv + argc, "--analyze"))
         {
-            rc = analyzer::analyzeHardware(); // analyze hardware
+            attn::DumpParameters dumpParameters;
+            rc = analyzer::analyzeHardware(dumpParameters); // analyze hardware
         }
         // daemon mode
         else