PEL: Prevent deletion if it's associated with HWIsolation

- This ensures that PELs linked to HWIsolation records are protected
from accidental deletion.
- Shows error message of "Call failed: The service is temporarily
unavailable.", when attempting to delete such a PEL individually.
- If trying to Delete all, will skip such PELs without showing any
message.

Tested:
Sample output:
```bash
$ busctl call xyz.openbmc_project.Logging /xyz/openbmc_project/
logging xyz.openbmc_project.Collection.DeleteAll DeleteAll

$ busctl call xyz.openbmc_project.Logging /xyz/openbmc_project/
logging/entry/2 xyz.openbmc_project.Object.Delete Delete
Call failed: The service is temporarily unavailable.

```
Change-Id: I2d28de91bbb0fbc2a991e3d5e5631814d41fe044
Signed-off-by: Harsh Agarwal <Harsh.Agarwal@ibm.com>
diff --git a/extensions/openpower-pels/data_interface.cpp b/extensions/openpower-pels/data_interface.cpp
index 146b92f..1975e95 100644
--- a/extensions/openpower-pels/data_interface.cpp
+++ b/extensions/openpower-pels/data_interface.cpp
@@ -984,6 +984,42 @@
 #endif
 }
 
+DBusPathList DataInterface::getAssociatedPaths(
+    const DBusPath& associatedPath, const DBusPath& subtree, int32_t depth,
+    const DBusInterfaceList& interfaces) const
+{
+    DBusPathList paths;
+    try
+    {
+        auto method = _bus.new_method_call(
+            service_name::objectMapper, object_path::objectMapper,
+            interface::objectMapper, "GetAssociatedSubTreePaths");
+        method.append(sdbusplus::message::object_path(associatedPath),
+                      sdbusplus::message::object_path(subtree), depth,
+                      interfaces);
+
+        auto reply = _bus.call(method, dbusTimeout);
+        reply.read(paths);
+    }
+    catch (const std::exception& e)
+    {
+        std::string ifaces(
+            std::ranges::fold_left_first(
+                interfaces,
+                [](std::string ifaces, const std::string& iface) {
+                    return ifaces + ", " + iface;
+                })
+                .value_or(""));
+
+        lg2::error("Failed getting associated paths: {ERROR}. "
+                   "AssociatedPath: {ASSOIC_PATH} Subtree: {SUBTREE} "
+                   "Interfaces: {IFACES}",
+                   "ERROR", e, "ASSOIC_PATH", associatedPath, "SUBTREE",
+                   subtree, "IFACES", ifaces);
+    }
+    return paths;
+}
+
 void DataInterface::startFruPlugWatch()
 {
     // Add a watch on inventory InterfacesAdded and then find all
diff --git a/extensions/openpower-pels/data_interface.hpp b/extensions/openpower-pels/data_interface.hpp
index 713f4cd..c6cfe4e 100644
--- a/extensions/openpower-pels/data_interface.hpp
+++ b/extensions/openpower-pels/data_interface.hpp
@@ -537,6 +537,23 @@
      */
     void addDIMMLocCode(const std::string& locCode, bool isFRUDIMM);
 
+    /**
+     * @brief Finds all D-Bus Associated paths that contain any of the
+     *        interfaces passed in, by using GetAssociatedSubTreePaths.
+     *
+     * @param[in] associatedPath - The D-Bus object path
+     * @param[in] subtree - The subtree path for which the result should be
+     *                      fetched
+     * @param[in] depth - The maximum subtree depth for which results should be
+     *                    fetched
+     * @param[in] interfaces - The desired interfaces
+     *
+     * @return The D-Bus paths.
+     */
+    virtual DBusPathList getAssociatedPaths(
+        const DBusPath& associatedPath, const DBusPath& subtree, int32_t depth,
+        const DBusInterfaceList& interfaces) const = 0;
+
   protected:
     /**
      * @brief Sets the host on/off state and runs any
@@ -907,6 +924,23 @@
     std::optional<std::vector<uint8_t>>
         getDIProperty(const std::string& locationCode) const override;
 
+    /**
+     * @brief Finds all D-Bus Associated paths that contain any of the
+     *        interfaces passed in, by using GetAssociatedSubTreePaths.
+     *
+     * @param[in] associatedPath - The D-Bus object path
+     * @param[in] subtree - The subtree path for which the result should be
+     *                      fetched
+     * @param[in] depth - The maximum subtree depth for which results should be
+     *                    fetched
+     * @param[in] interfaces - The desired interfaces
+     *
+     * @return The D-Bus paths.
+     */
+    DBusPathList getAssociatedPaths(
+        const DBusPath& associatedPath, const DBusPath& subtree, int32_t depth,
+        const DBusInterfaceList& interfaces) const override;
+
   private:
     /**
      * @brief Reads the BMC firmware version string and puts it into
diff --git a/extensions/openpower-pels/entry_points.cpp b/extensions/openpower-pels/entry_points.cpp
index dd00103..aba0457 100644
--- a/extensions/openpower-pels/entry_points.cpp
+++ b/extensions/openpower-pels/entry_points.cpp
@@ -87,5 +87,12 @@
 
 REGISTER_EXTENSION_FUNCTION(pelDeleteProhibited)
 
+void getLogIDWithHwIsolation(std::vector<uint32_t>& logIDs)
+{
+    manager->getLogIDWithHwIsolation(logIDs);
+}
+
+REGISTER_EXTENSION_FUNCTION(getLogIDWithHwIsolation)
+
 } // namespace pels
 } // namespace openpower
diff --git a/extensions/openpower-pels/manager.cpp b/extensions/openpower-pels/manager.cpp
index a362e01..03254d2 100644
--- a/extensions/openpower-pels/manager.cpp
+++ b/extensions/openpower-pels/manager.cpp
@@ -301,8 +301,28 @@
     _repo.remove(id);
 }
 
-bool Manager::isDeleteProhibited(uint32_t /*obmcLogID*/)
+void Manager::getLogIDWithHwIsolation(std::vector<uint32_t>& idsWithHwIsoEntry)
 {
+    idsWithHwIsoEntry = _dataIface->getLogIDWithHwIsolation();
+}
+
+bool Manager::isDeleteProhibited(uint32_t obmcLogID)
+{
+    auto entryPath{std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID)};
+    auto entry = _pelEntries.find(entryPath);
+    if (entry != _pelEntries.end())
+    {
+        if (entry->second->guard())
+        {
+            auto hwIsolationAssocPaths = _dataIface->getAssociatedPaths(
+                entryPath += "/isolated_hw_entry", "/", 0,
+                {"xyz.openbmc_project.HardwareIsolation.Entry"});
+            if (!hwIsolationAssocPaths.empty())
+            {
+                return true;
+            }
+        }
+    }
     return false;
 }
 
diff --git a/extensions/openpower-pels/manager.hpp b/extensions/openpower-pels/manager.hpp
index 462949d..2429aec 100644
--- a/extensions/openpower-pels/manager.hpp
+++ b/extensions/openpower-pels/manager.hpp
@@ -125,6 +125,14 @@
      */
     void erase(uint32_t obmcLogID);
 
+    /**
+     * @brief Get the list of event log ids that have an associated
+     *        hardware isolation entry.
+     *
+     * @param[in] idsWithHwIsoEntry - List to store the list of log ids
+     */
+    void getLogIDWithHwIsolation(std::vector<uint32_t>& idsWithHwIsoEntry);
+
     /** @brief Says if an OpenBMC event log may not be manually deleted at this
      *         time because its corresponding PEL cannot be.
      *