OpenPOWER: Do not allow system dump when already in progress

if a system dump is in progress or already available in host
memory reject any further dump requests.

Test:
Initiate system dump when another dump in progress

Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
Change-Id: I4598912b0761669859f84a43ab4c60f47664b1e6
diff --git a/dump-extensions/openpower-dumps/dump_manager_system.cpp b/dump-extensions/openpower-dumps/dump_manager_system.cpp
index 23d1994..93200c2 100644
--- a/dump-extensions/openpower-dumps/dump_manager_system.cpp
+++ b/dump-extensions/openpower-dumps/dump_manager_system.cpp
@@ -4,6 +4,7 @@
 
 #include "dump_utils.hpp"
 #include "op_dump_consts.hpp"
+#include "op_dump_util.hpp"
 #include "system_dump_entry.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
@@ -126,6 +127,14 @@
             "System dump accepts not more than 2 additional parameters");
     }
 
+    if (openpower::dump::util::isSystemDumpInProgress())
+    {
+        log<level::ERR>(
+            fmt::format("Another dump in progress or available to offload")
+                .c_str());
+        elog<sdbusplus::xyz::openbmc_project::Common::Error::Unavailable>();
+    }
+
     using NotAllowed =
         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
     using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
diff --git a/dump-extensions/openpower-dumps/op_dump_util.cpp b/dump-extensions/openpower-dumps/op_dump_util.cpp
index 88d41ab..2c6fb5e 100644
--- a/dump-extensions/openpower-dumps/op_dump_util.cpp
+++ b/dump-extensions/openpower-dumps/op_dump_util.cpp
@@ -1,5 +1,6 @@
 #include "op_dump_util.hpp"
 
+#include "dump_utils.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 #include "xyz/openbmc_project/Dump/Create/error.hpp"
 
@@ -70,6 +71,69 @@
     return std::filesystem::exists(MP_REBOOT_FILE);
 }
 
+bool isSystemDumpInProgress()
+{
+    using BiosBaseTableItem = std::pair<
+        std::string,
+        std::tuple<std::string, bool, std::string, std::string, std::string,
+                   std::variant<int64_t, std::string>,
+                   std::variant<int64_t, std::string>,
+                   std::vector<std::tuple<
+                       std::string, std::variant<int64_t, std::string>>>>>;
+    using BiosBaseTable = std::vector<BiosBaseTableItem>;
+
+    try
+    {
+        std::string dumpInProgress{};
+        auto bus = sdbusplus::bus::new_default();
+
+        auto retVal =
+            phosphor::dump::readDBusProperty<std::variant<BiosBaseTable>>(
+                bus, "xyz.openbmc_project.BIOSConfigManager",
+                "/xyz/openbmc_project/bios_config/manager",
+                "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable");
+        const auto baseBiosTable = std::get_if<BiosBaseTable>(&retVal);
+        if (baseBiosTable == nullptr)
+        {
+            log<level::ERR>(
+                "Util failed to read BIOSconfig property BaseBIOSTable");
+            return false;
+        }
+        for (const auto& item : *baseBiosTable)
+        {
+            const auto attributeName = std::get<0>(item);
+            auto attrValue = std::get<5>(std::get<1>(item));
+            auto val = std::get_if<std::string>(&attrValue);
+            if (val != nullptr && attributeName == "pvm_sys_dump_active")
+            {
+                dumpInProgress = *val;
+                break;
+            }
+        }
+        if (dumpInProgress.empty())
+        {
+            log<level::ERR>(
+                "Util failed to read pvm_hmc_managed property value");
+            return false;
+        }
+        if (dumpInProgress == "Enabled")
+        {
+            log<level::INFO>("A system dump is already in progress");
+            return true;
+        }
+    }
+    catch (const std::exception& ex)
+    {
+        log<level::ERR>(
+            fmt::format("Failed to read pvm_sys_dump_active ({})", ex.what())
+                .c_str());
+        return false;
+    }
+
+    log<level::INFO>("Another system dump is not in progress");
+    return false;
+}
+
 } // namespace util
 } // namespace dump
 } // namespace openpower
diff --git a/dump-extensions/openpower-dumps/op_dump_util.hpp b/dump-extensions/openpower-dumps/op_dump_util.hpp
index 3de441a..ad7e135 100644
--- a/dump-extensions/openpower-dumps/op_dump_util.hpp
+++ b/dump-extensions/openpower-dumps/op_dump_util.hpp
@@ -24,6 +24,12 @@
  */
 bool isInMpReboot();
 
+/** @brief Check whether a system is in progress or
+ *  available to offload.
+ *  @return true - A dump is in progress or available to offload
+ *          false - No dump in progress
+ */
+bool isSystemDumpInProgress();
 } // namespace util
 } // namespace dump
 } // namespace openpower
diff --git a/dump_utils.hpp b/dump_utils.hpp
index 82fff10..93e8878 100644
--- a/dump_utils.hpp
+++ b/dump_utils.hpp
@@ -3,11 +3,13 @@
 #include "dump_manager.hpp"
 
 #include <fmt/core.h>
+#include <fmt/format.h>
 #include <systemd/sd-event.h>
 #include <unistd.h>
 
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/log.hpp>
 #include <sdbusplus/bus.hpp>
 #include <xyz/openbmc_project/Common/error.hpp>
 #include <xyz/openbmc_project/Dump/Create/server.hpp>
@@ -202,5 +204,44 @@
  */
 bool isHostQuiesced();
 
+/**
+ * @brief Read property value from the specified object and interface
+ * @param[in] bus D-Bus handle
+ * @param[in] service service which has implemented the interface
+ * @param[in] object object having has implemented the interface
+ * @param[in] intf interface having the property
+ * @param[in] prop name of the property to read
+ * @return property value
+ */
+template <typename T>
+T readDBusProperty(sdbusplus::bus::bus& bus, const std::string& service,
+                   const std::string& object, const std::string& intf,
+                   const std::string& prop)
+{
+    using ::phosphor::logging::level;
+    using ::phosphor::logging::log;
+    T retVal{};
+    try
+    {
+        auto properties =
+            bus.new_method_call(service.c_str(), object.c_str(),
+                                "org.freedesktop.DBus.Properties", "Get");
+        properties.append(intf);
+        properties.append(prop);
+        auto result = bus.call(properties);
+        result.read(retVal);
+    }
+    catch (const std::exception& ex)
+    {
+        log<level::ERR>(
+            fmt::format("Failed to get the property ({}) interface ({}) "
+                        "object path ({}) error ({}) ",
+                        prop.c_str(), intf.c_str(), object.c_str(), ex.what())
+                .c_str());
+        throw;
+    }
+    return retVal;
+}
+
 } // namespace dump
 } // namespace phosphor