OpenPOWER: Limit User-Requested System Dumps

System dumps can be several gigabytes in size. To conserve space,
only one dump is stored at a time. When a new dump is requested,
the existing dump will be discarded while creating a new one.
In the case of system-generated dumps, which are triggered by
critical errors, it is permissible to initiate a new dump even
if an existing dump is already present in the host memory
This commit adds a restriction on initiating new user-requested system
dumps while a system dump is in progress or if one is already stored
in host memory.

New user-requested system dumps will be allowed once the existing
dump is deleted or offloaded.

This change applies only to user-requested dumps and does not impact
system generated dumps.

Test:
- Initiate system dump when another dump in progress and verified
  a Unavailable was returned
- Force a system generated system dump when one dump is present
  a Unavailable was returned

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 fad4947..949c87c 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"
 
@@ -140,6 +141,14 @@
         lg2::warning(
             "System dump accepts not more than 2 additional parameters");
     }
+    using Unavailable =
+        sdbusplus::xyz::openbmc_project::Common::Error::Unavailable;
+
+    if (openpower::dump::util::isSystemDumpInProgress(bus))
+    {
+        lg2::error("Another dump in progress or available to offload");
+        elog<Unavailable>();
+    }
 
     using NotAllowed =
         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
diff --git a/dump-extensions/openpower-dumps/op_dump_util.cpp b/dump-extensions/openpower-dumps/op_dump_util.cpp
index e8b2497..c56b902 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"
 
@@ -52,6 +53,60 @@
     return isEnabled;
 }
 
+BIOSAttrValueType readBIOSAttribute(const std::string& attrName,
+                                    sdbusplus::bus::bus& bus)
+{
+    std::tuple<std::string, BIOSAttrValueType, BIOSAttrValueType> attrVal;
+    auto method = bus.new_method_call(
+        "xyz.openbmc_project.BIOSConfigManager",
+        "/xyz/openbmc_project/bios_config/manager",
+        "xyz.openbmc_project.BIOSConfig.Manager", "GetAttribute");
+    method.append(attrName);
+    try
+    {
+        auto result = bus.call(method);
+        result.read(std::get<0>(attrVal), std::get<1>(attrVal),
+                    std::get<2>(attrVal));
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        lg2::error("Failed to read BIOS Attribute: {ATTRIBUTE_NAME}",
+                   "ATTRIBUTE_NAME", attrName);
+        throw;
+    }
+    return std::get<1>(attrVal);
+}
+
+bool isSystemDumpInProgress(sdbusplus::bus::bus& bus)
+{
+    try
+    {
+        auto dumpInProgress = std::get<std::string>(
+            readBIOSAttribute("pvm_sys_dump_active"), bus);
+        if (dumpInProgress == "Enabled")
+        {
+            lg2::info("A system dump is already in progress");
+            return true;
+        }
+    }
+    catch (const std::bad_variant_access& ex)
+    {
+        lg2::error("Failed to read pvm_sys_dump_active property value due "
+                   "to bad variant access error:{ERROR}",
+                   "ERROR", ex);
+        return false;
+    }
+    catch (const std::exception& ex)
+    {
+        lg2::error("Failed to read pvm_sys_dump_active error:{ERROR}", "ERROR",
+                   ex);
+        return false;
+    }
+
+    lg2::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 80c84a3..695fcd5 100644
--- a/dump-extensions/openpower-dumps/op_dump_util.hpp
+++ b/dump-extensions/openpower-dumps/op_dump_util.hpp
@@ -19,6 +19,28 @@
  */
 bool isOPDumpsEnabled(sdbusplus::bus::bus& bus);
 
+using BIOSAttrValueType = std::variant<int64_t, std::string>;
+
+/** @brief Read a BIOS attribute value
+ *
+ *  @param[in] attrName - Name of the BIOS attribute
+ *  @param[in] bus - D-Bus handle
+ *
+ *  @return The value of the BIOS attribute as a variant of possible types
+ *
+ *  @throws sdbusplus::exception::SdBusError if failed to read the attribute
+ */
+BIOSAttrValueType readBIOSAttribute(const std::string& attrName,
+                                    sdbusplus::bus::bus& bus);
+
+/** @brief Check whether a system is in progress or available to offload.
+ *
+ *  @param[in] bus - D-Bus handle
+ *
+ *  @return true - A dump is in progress or available to offload
+ *          false - No dump in progress
+ */
+bool isSystemDumpInProgress(sdbusplus::bus::bus& bus);
 } // namespace util
 } // namespace dump
 } // namespace openpower