Do not collect VPD unless required
This commit adds some checks before we attempt VPD collection
on udev events. The following conditions are added:
-- Check if the FRU is marked concurrently maintainable or pluggable at
standby. If either is true, proceed.
-- Check if the BMC is at a NotReady state - if yes, proceeed.
-- Check if the FRU has never been colelcted before (Present is false) -
if yes, proceed.
In all other scenarios, the collection is skipped. This helps eliminate
cases where grabbing the SPI mux causes a whole bunch of parsers to run,
and an immediate power on leads to I2C arbitration loss errors.
Signed-off-by: Santosh Puranik <santosh.puranik@in.ibm.com>
Change-Id: I8f92014e1fc0becf5f7c56019a31bb2e46c6ccf0
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index 613f4af..ba03318 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -77,6 +77,109 @@
}
/**
+ * @brief Returns the BMC state
+ */
+static auto getBMCState()
+{
+ std::string bmcState;
+ try
+ {
+ auto bus = sdbusplus::bus::new_default();
+ auto properties = bus.new_method_call(
+ "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0",
+ "org.freedesktop.DBus.Properties", "Get");
+ properties.append("xyz.openbmc_project.State.BMC");
+ properties.append("CurrentBMCState");
+ auto result = bus.call(properties);
+ std::variant<std::string> val;
+ result.read(val);
+ if (auto pVal = std::get_if<std::string>(&val))
+ {
+ bmcState = *pVal;
+ }
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ // Ignore any error
+ std::cerr << "Failed to get BMC state: " << e.what() << "\n";
+ }
+ return bmcState;
+}
+
+/**
+ * @brief Check if the FRU is in the cache
+ *
+ * Checks if the FRU associated with the supplied D-Bus object path is already
+ * on D-Bus. This can be used to test if a VPD collection is required for this
+ * FRU. It uses the "xyz.openbmc_project.Inventory.Item, Present" property to
+ * determine the presence of a FRU in the cache.
+ *
+ * @param objectPath - The D-Bus object path without the PIM prefix.
+ * @return true if the object exists on D-Bus, false otherwise.
+ */
+static auto isFruInVpdCache(const std::string& objectPath)
+{
+ try
+ {
+ auto bus = sdbusplus::bus::new_default();
+ auto invPath = std::string{pimPath} + objectPath;
+ auto props = bus.new_method_call(
+ "xyz.openbmc_project.Inventory.Manager", invPath.c_str(),
+ "org.freedesktop.DBus.Properties", "Get");
+ props.append("xyz.openbmc_project.Inventory.Item");
+ props.append("Present");
+ auto result = bus.call(props);
+ std::variant<bool> present;
+ result.read(present);
+ if (auto pVal = std::get_if<bool>(&present))
+ {
+ return *pVal;
+ }
+ return false;
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ std::cout << "FRU: " << objectPath << " not in D-Bus\n";
+ // Assume not present in case of an error
+ return false;
+ }
+}
+
+/**
+ * @brief Check if VPD recollection is needed for the given EEPROM
+ *
+ * Not all FRUs can be swapped at BMC ready state. This function does the
+ * following:
+ * -- Check if the FRU is marked as "pluggableAtStandby" OR
+ * "concurrentlyMaintainable". If so, return true.
+ * -- Check if we are at BMC NotReady state. If we are, then return true.
+ * -- Else check if the FRU is not present in the VPD cache (to cover for VPD
+ * force collection). If not found in the cache, return true.
+ * -- Else return false.
+ *
+ * @param js - JSON Object.
+ * @param filePath - The EEPROM file.
+ * @return true if collection should be attempted, false otherwise.
+ */
+static auto needsRecollection(const nlohmann::json& js, const string& filePath)
+{
+ if (js["frus"][filePath].at(0).value("pluggableAtStandby", false) ||
+ js["frus"][filePath].at(0).value("concurrentlyMaintainable", false))
+ {
+ return true;
+ }
+ if (getBMCState() == "xyz.openbmc_project.State.BMC.BMCState.NotReady")
+ {
+ return true;
+ }
+ if (!isFruInVpdCache(js["frus"][filePath].at(0).value("inventoryPath", "")))
+ {
+ return true;
+ }
+ return false;
+}
+
+/**
* @brief Expands location codes
*/
static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap,
@@ -1419,6 +1522,13 @@
}
}
+ // Check if this VPD should be recollected at all
+ if (!needsRecollection(js, file))
+ {
+ cout << "Skip VPD recollection for: " << file << endl;
+ return 0;
+ }
+
try
{
vpdVector = getVpdDataInVector(js, file);