summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/openpower-pels/host_notifier.cpp101
-rw-r--r--extensions/openpower-pels/host_notifier.hpp18
-rw-r--r--test/openpower-pels/host_notifier_test.cpp32
3 files changed, 149 insertions, 2 deletions
diff --git a/extensions/openpower-pels/host_notifier.cpp b/extensions/openpower-pels/host_notifier.cpp
index f9e0418..8fe6955 100644
--- a/extensions/openpower-pels/host_notifier.cpp
+++ b/extensions/openpower-pels/host_notifier.cpp
@@ -21,6 +21,7 @@ namespace openpower::pels
{
const auto subscriptionName = "PELHostNotifier";
+const size_t maxRetryAttempts = 15;
using namespace phosphor::logging;
@@ -110,6 +111,41 @@ bool HostNotifier::enqueueRequired(uint32_t id) const
return required;
}
+bool HostNotifier::notifyRequired(uint32_t id) const
+{
+ bool notify = true;
+ Repository::LogID i{Repository::LogID::Pel{id}};
+
+ if (auto attributes = _repo.getPELAttributes(i); attributes)
+ {
+ // If already acked by the host, don't send again.
+ // (A safety check as it shouldn't get to this point.)
+ auto a = attributes.value().get();
+ if (a.hostState == TransmissionState::acked)
+ {
+ notify = false;
+ }
+ else if (a.actionFlags.test(hiddenFlagBit))
+ {
+ // If hidden and acked (or will be) acked by the HMC,
+ // also don't send it. (HMC management can come and
+ // go at any time)
+ if ((a.hmcState == TransmissionState::acked) ||
+ _dataIface.isHMCManaged())
+ {
+ notify = false;
+ }
+ }
+ }
+ else
+ {
+ // Must have been deleted since put on the queue.
+ notify = false;
+ }
+
+ return notify;
+}
+
void HostNotifier::newLogCallback(const PEL& pel)
{
if (!enqueueRequired(pel.id()))
@@ -124,6 +160,71 @@ void HostNotifier::newLogCallback(const PEL& pel)
void HostNotifier::doNewLogNotify()
{
+ if (!_dataIface.isHostUp() || _retryTimer.isEnabled())
+ {
+ return;
+ }
+
+ if (_retryCount >= maxRetryAttempts)
+ {
+ // Give up until a new log comes in.
+ if (_retryCount == maxRetryAttempts)
+ {
+ // If this were to really happen, the PLDM interface
+ // would be down and isolating that shouldn't left to
+ // a logging daemon, so just trace. Also, this will start
+ // trying again when the next new log comes in.
+ log<level::ERR>(
+ "PEL Host notifier hit max retry attempts. Giving up for now.",
+ entry("PEL_ID=0x%X", _pelQueue.front()));
+ }
+ return;
+ }
+
+ bool doNotify = false;
+ uint32_t id = 0;
+
+ // Find the PEL to send
+ while (!doNotify && !_pelQueue.empty())
+ {
+ id = _pelQueue.front();
+ _pelQueue.pop_front();
+
+ if (notifyRequired(id))
+ {
+ doNotify = true;
+ }
+ }
+
+ if (doNotify)
+ {
+ // Get the size using the repo attributes
+ Repository::LogID i{Repository::LogID::Pel{id}};
+ if (auto attributes = _repo.getPELAttributes(i); attributes)
+ {
+ auto size = static_cast<size_t>(
+ std::filesystem::file_size((*attributes).get().path));
+ auto rc = _hostIface->sendNewLogCmd(id, size);
+
+ if (rc == CmdStatus::success)
+ {
+ _inProgressPEL = id;
+ }
+ else
+ {
+ // It failed. Retry
+ log<level::ERR>("PLDM send failed", entry("PEL_ID=0x%X", id));
+ _pelQueue.push_front(id);
+ _inProgressPEL = 0;
+ _retryTimer.restartOnce(_hostIface->getSendRetryDelay());
+ }
+ }
+ else
+ {
+ log<level::ERR>("PEL ID not in repository. Cannot notify host",
+ entry("PEL_ID=0x%X", id));
+ }
+ }
}
void HostNotifier::hostStateChange(bool hostUp)
diff --git a/extensions/openpower-pels/host_notifier.hpp b/extensions/openpower-pels/host_notifier.hpp
index 1bb7538..127eb03 100644
--- a/extensions/openpower-pels/host_notifier.hpp
+++ b/extensions/openpower-pels/host_notifier.hpp
@@ -67,6 +67,20 @@ class HostNotifier
*/
bool enqueueRequired(uint32_t id) const;
+ /**
+ * @brief If the host still needs to be notified of the PEL
+ * at the time of the notification.
+ *
+ * Only returns false if:
+ * - Already acked by the host
+ * - It's hidden, and the HMC already got or will get it.
+ *
+ * @param[in] id - The PEL ID
+ *
+ * @return bool - If the notify is required
+ */
+ bool notifyRequired(uint32_t id) const;
+
private:
/**
* @brief This function gets called by the Repository class
@@ -88,8 +102,8 @@ class HostNotifier
bool addPELToQueue(const PEL& pel);
/**
- * @brief Takes the PEL off the front of the queue and issues
- * the PLDM send.
+ * @brief Takes the first PEL from the queue that needs to be
+ * sent, and issues the send if conditions are right.
*/
void doNewLogNotify();
diff --git a/test/openpower-pels/host_notifier_test.cpp b/test/openpower-pels/host_notifier_test.cpp
index 2f2e1f0..3608539 100644
--- a/test/openpower-pels/host_notifier_test.cpp
+++ b/test/openpower-pels/host_notifier_test.cpp
@@ -131,15 +131,18 @@ TEST_F(HostNotifierTest, TestPolicyAckedPEL)
// This is required
EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
+ EXPECT_TRUE(notifier.notifyRequired(pel->id()));
// Not in the repo
EXPECT_FALSE(notifier.enqueueRequired(42));
+ EXPECT_FALSE(notifier.notifyRequired(42));
// Now set this PEL to host acked
repo.setPELHostTransState(pel->id(), TransmissionState::acked);
// Since it's acked, doesn't need to be enqueued or transmitted
EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
+ EXPECT_FALSE(notifier.notifyRequired(pel->id()));
}
// Test the 'don't report' PEL flag
@@ -189,6 +192,9 @@ TEST_F(HostNotifierTest, TestPolicyHiddenNoHMC)
// Still need to enqueue this
EXPECT_TRUE(notifier.enqueueRequired(pel->id()));
+
+ // Still need to send it
+ EXPECT_TRUE(notifier.notifyRequired(pel->id()));
}
// Don't need to enqueue a hidden log already acked by the HMC
@@ -220,6 +226,32 @@ TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCAcked)
EXPECT_FALSE(notifier.enqueueRequired(pel->id()));
}
+// Test that changing the HMC manage status affects
+// the policy with hidden log notification.
+TEST_F(HostNotifierTest, TestPolicyHiddenWithHMCManaged)
+{
+ Repository repo{repoPath};
+ MockDataInterface dataIface;
+
+ std::unique_ptr<HostInterface> hostIface =
+ std::make_unique<MockHostInterface>(event, dataIface);
+
+ HostNotifier notifier{repo, dataIface, std::move(hostIface)};
+
+ // hiddenFlagBit
+ auto pel = makePEL(0x4000);
+
+ repo.add(pel);
+
+ // The first time, the HMC managed is false
+ EXPECT_TRUE(notifier.notifyRequired(pel->id()));
+
+ dataIface.setHMCManaged(true);
+
+ // This time, HMC managed is true so no need to notify
+ EXPECT_FALSE(notifier.notifyRequired(pel->id()));
+}
+
// Test that PELs are enqueued on startup
TEST_F(HostNotifierTest, TestStartup)
{
OpenPOWER on IntegriCloud