Implement VPD recollection
This commit implements functionality to recollect VPD for a hardware
by triggering VPD parser for that hardware in case there is a
replacement.
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
Change-Id: Ia0d377b554299faac3b46a4dc8dd96f964f07bd2
diff --git a/examples/inventory.json b/examples/inventory.json
index b5592cc..0101f21 100644
--- a/examples/inventory.json
+++ b/examples/inventory.json
@@ -26,6 +26,10 @@
},
"/sys/devices/path/to/bmc/eeprom": {
"inventoryPath": "/bus/path/for/bmcfru",
+ "isReplacable": true,
+ "driverType": "at24",
+ "devAddress": "8-0051",
+ "busType": "i2c",
"extraInterfaces": {
"xyz.openbmc_project.Inventory.Item.Bmc": null
}
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index ca1dd4d..fed83ad 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -280,48 +280,6 @@
return vpdVector;
}
-/* It does nothing. Just an empty function to return null
- * at the end of variadic template args
- */
-static string getCommand()
-{
- return "";
-}
-
-/* This function to arrange all arguments to make command
- */
-template <typename T, typename... Types>
-static string getCommand(T arg1, Types... args)
-{
- string cmd = " " + arg1 + getCommand(args...);
-
- return cmd;
-}
-
-/* This API takes arguments and run that command
- * returns output of that command
- */
-template <typename T, typename... Types>
-static vector<string> executeCmd(T&& path, Types... args)
-{
- vector<string> stdOutput;
- array<char, 128> buffer;
-
- string cmd = path + getCommand(args...);
-
- unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
- if (!pipe)
- {
- throw runtime_error("popen() failed!");
- }
- while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
- {
- stdOutput.emplace_back(buffer.data());
- }
-
- return stdOutput;
-}
-
/** This API will be called at the end of VPD collection to perform any post
* actions.
*
@@ -1031,6 +989,7 @@
variant<KeywordVpdMap, Store> parseResult;
parseResult = parser->parse();
+
if (auto pVal = get_if<Store>(&parseResult))
{
populateDbus(pVal->getVpdMap(), js, file);
diff --git a/ibm_vpd_utils.hpp b/ibm_vpd_utils.hpp
index 9b48021..9aaebee 100644
--- a/ibm_vpd_utils.hpp
+++ b/ibm_vpd_utils.hpp
@@ -113,5 +113,54 @@
*/
constants::vpdType vpdTypeCheck(const Binary& vector);
+/*
+ * @brief This method does nothing. Just an empty function to return null
+ * at the end of variadic template args
+ */
+inline string getCommand()
+{
+ return "";
+}
+
+/**
+ * @brief This function to arrange all arguments to make commandy
+ * @param[in] arguments to create the command
+ * @return cmd - command string
+ */
+template <typename T, typename... Types>
+inline string getCommand(T arg1, Types... args)
+{
+ string cmd = " " + arg1 + getCommand(args...);
+
+ return cmd;
+}
+
+/**
+ * @brief This API takes arguments, creates a shell command line and executes
+ * them.
+ * @param[in] arguments for command
+ * @returns output of that command
+ */
+template <typename T, typename... Types>
+inline vector<string> executeCmd(T&& path, Types... args)
+{
+ vector<string> stdOutput;
+ array<char, 128> buffer;
+
+ string cmd = path + getCommand(args...);
+
+ unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
+ if (!pipe)
+ {
+ throw runtime_error("popen() failed!");
+ }
+ while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
+ {
+ stdOutput.emplace_back(buffer.data());
+ }
+
+ return stdOutput;
+}
+
} // namespace vpd
} // namespace openpower
diff --git a/types.hpp b/types.hpp
index c297bf5..8c5c6e1 100644
--- a/types.hpp
+++ b/types.hpp
@@ -54,6 +54,7 @@
using MapperResponse =
std::map<Path, std::map<Service, std::vector<Interface>>>;
using RestoredEeproms = std::tuple<Path, std::string, Keyword, Binary>;
+using ReplaceableFrus = std::vector<VPDfilepath>;
} // namespace inventory
} // namespace vpd
diff --git a/vpd-manager/manager.cpp b/vpd-manager/manager.cpp
index feb6115..42b1bbd 100644
--- a/vpd-manager/manager.cpp
+++ b/vpd-manager/manager.cpp
@@ -6,11 +6,18 @@
#include "ibm_vpd_utils.hpp"
#include "ipz_parser.hpp"
#include "reader_impl.hpp"
+#include "vpd_exceptions.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
using namespace openpower::vpd::constants;
using namespace openpower::vpd::inventory;
using namespace openpower::vpd::manager::editor;
using namespace openpower::vpd::manager::reader;
+using namespace std;
+using namespace openpower::vpd::parser;
+using namespace openpower::vpd::exceptions;
+using namespace phosphor::logging;
namespace openpower
{
@@ -90,6 +97,11 @@
itemEEPROM["inventoryPath"]
.get_ref<const nlohmann::json::string_t&>());
}
+
+ if (itemEEPROM.value("isReplaceable", false))
+ {
+ replaceableFrus.emplace_back(itemFRUS.key());
+ }
}
}
}
@@ -156,6 +168,80 @@
fruLocationCode);
}
+void Manager::performVPDRecollection()
+{
+ // get list of FRUs replaceable at standby
+ for (const auto& item : replaceableFrus)
+ {
+ const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
+ const nlohmann::json& singleFru = groupEEPROM[0];
+
+ const string& inventoryPath =
+ singleFru["inventoryPath"]
+ .get_ref<const nlohmann::json::string_t&>();
+
+ if ((singleFru.find("devAddress") == singleFru.end()) ||
+ (singleFru.find("driverType") == singleFru.end()) ||
+ (singleFru.find("busType") == singleFru.end()))
+ {
+ // The FRUs is marked for replacement but missing mandatory
+ // fields for recollection. Skip to another replaceable fru.
+ log<level::ERR>(
+ "Recollection Failed as mandatory field missing in Json",
+ entry("ERROR=%s",
+ ("Recollection failed for " + inventoryPath).c_str()));
+ continue;
+ }
+
+ string str = "echo ";
+ string deviceAddress = singleFru["devAddress"];
+ const string& driverType = singleFru["driverType"];
+ const string& busType = singleFru["busType"];
+
+ // devTreeStatus flag is present in json as false to mention
+ // that the EEPROM is not mentioned in device tree. If this flag
+ // is absent consider the value to be true, i.e EEPROM is
+ // mentioned in device tree
+ if (!singleFru.value("devTreeStatus", true))
+ {
+ auto pos = deviceAddress.find('-');
+ if (pos != string::npos)
+ {
+ string busNum = deviceAddress.substr(0, pos);
+ deviceAddress =
+ "0x" + deviceAddress.substr(pos + 1, string::npos);
+
+ string deleteDevice = str + deviceAddress + " > /sys/bus/" +
+ busType + "/devices/" + busType + "-" +
+ busNum + "/delete_device";
+ executeCmd(deleteDevice);
+
+ string addDevice = str + driverType + " " + deviceAddress +
+ " > /sys/bus/" + busType + "/devices/" +
+ busType + "-" + busNum + "/new_device";
+ executeCmd(addDevice);
+ }
+ else
+ {
+ log<level::ERR>(
+ "Wrong format of device address in Json",
+ entry(
+ "ERROR=%s",
+ ("Recollection failed for " + inventoryPath).c_str()));
+ continue;
+ }
+ }
+ else
+ {
+ string cmd = str + deviceAddress + " > /sys/bus/" + busType +
+ "/drivers/" + driverType;
+
+ executeCmd(cmd + "/unbind");
+ executeCmd(cmd + "/bind");
+ }
+ }
+}
+
} // namespace manager
} // namespace vpd
} // namespace openpower
diff --git a/vpd-manager/manager.hpp b/vpd-manager/manager.hpp
index 6846c6e..41d3ad7 100644
--- a/vpd-manager/manager.hpp
+++ b/vpd-manager/manager.hpp
@@ -118,6 +118,12 @@
/** @brief Start processing DBus messages. */
void run();
+ /** @brief Api to perform VPD recollection.
+ * This api will trigger parser to perform VPD recollection for FRUs that
+ * can be replaced at standby.
+ */
+ void performVPDRecollection();
+
private:
/** @brief process the given JSON file
*/
@@ -138,6 +144,9 @@
// map to hold the mapping of location code and inventory path
inventory::LocationCodeMap fruLocationCode;
+
+ // map to hold FRUs which can be replaced at standby
+ inventory::ReplaceableFrus replaceableFrus;
};
} // namespace manager
diff --git a/vpd-manager/server.cpp b/vpd-manager/server.cpp
index 8291ecd..7ca72f6 100644
--- a/vpd-manager/server.cpp
+++ b/vpd-manager/server.cpp
@@ -4,10 +4,10 @@
#include <map>
#include <sdbusplus/exception.hpp>
#include <sdbusplus/sdbus.hpp>
+#include <sdbusplus/sdbuspp_support/server.hpp>
#include <sdbusplus/server.hpp>
#include <string>
#include <tuple>
-#include <variant>
#include <xyz/openbmc_project/Common/error.hpp>
namespace sdbusplus
@@ -30,55 +30,36 @@
int Manager::_callback_WriteKeyword(sd_bus_message* msg, void* context,
sd_bus_error* error)
{
+ auto o = static_cast<Manager*>(context);
+
try
{
- auto m = message::message(msg);
-#if 1
- {
- auto tbus = m.get_bus();
- sdbusplus::server::transaction::Transaction t(tbus, m);
- sdbusplus::server::transaction::set_id(
- std::hash<sdbusplus::server::transaction::Transaction>{}(t));
- }
-#endif
-
- sdbusplus::message::object_path path{};
- std::string record{};
- std::string keyword{};
- std::vector<uint8_t> value{};
-
- m.read(path, record, keyword, value);
-
- auto o = static_cast<Manager*>(context);
- o->writeKeyword(path, record, keyword, value);
-
- auto reply = m.new_method_return();
- // No data to append on reply.
-
- reply.method_return();
- }
- catch (sdbusplus::internal_exception_t& e)
- {
- return sd_bus_error_set(error, e.name(), e.description());
+ return sdbusplus::sdbuspp::method_callback(
+ msg, o->_intf, error,
+ std::function([=](sdbusplus::message::object_path&& path,
+ std::string&& record, std::string&& keyword,
+ std::vector<uint8_t>&& value) {
+ return o->writeKeyword(path, record, keyword, value);
+ }));
}
catch (sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::PathNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::RecordNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::KeywordNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
- return true;
+ return 0;
}
namespace details
@@ -97,49 +78,32 @@
void* context,
sd_bus_error* error)
{
+ auto o = static_cast<Manager*>(context);
+
try
{
- auto m = message::message(msg);
-#if 1
- {
- auto tbus = m.get_bus();
- sdbusplus::server::transaction::Transaction t(tbus, m);
- sdbusplus::server::transaction::set_id(
- std::hash<sdbusplus::server::transaction::Transaction>{}(t));
- }
-#endif
-
- std::string locationCode{};
- uint16_t nodeNumber{};
-
- m.read(locationCode, nodeNumber);
-
- auto o = static_cast<Manager*>(context);
- auto r = o->getFRUsByUnexpandedLocationCode(locationCode, nodeNumber);
-
- auto reply = m.new_method_return();
- reply.append(std::move(r));
-
- reply.method_return();
- }
- catch (sdbusplus::internal_exception_t& e)
- {
- return sd_bus_error_set(error, e.name(), e.description());
+ return sdbusplus::sdbuspp::method_callback(
+ msg, o->_intf, error,
+ std::function(
+ [=](std::string&& locationCode, uint16_t&& nodeNumber) {
+ return o->getFRUsByUnexpandedLocationCode(locationCode,
+ nodeNumber);
+ }));
}
catch (sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::LocationNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::NodeNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
- return true;
+ return 0;
}
namespace details
@@ -158,48 +122,30 @@
void* context,
sd_bus_error* error)
{
+ auto o = static_cast<Manager*>(context);
+
try
{
- auto m = message::message(msg);
-#if 1
- {
- auto tbus = m.get_bus();
- sdbusplus::server::transaction::Transaction t(tbus, m);
- sdbusplus::server::transaction::set_id(
- std::hash<sdbusplus::server::transaction::Transaction>{}(t));
- }
-#endif
-
- std::string locationCode{};
-
- m.read(locationCode);
-
- auto o = static_cast<Manager*>(context);
- auto r = o->getFRUsByExpandedLocationCode(locationCode);
-
- auto reply = m.new_method_return();
- reply.append(std::move(r));
-
- reply.method_return();
- }
- catch (sdbusplus::internal_exception_t& e)
- {
- return sd_bus_error_set(error, e.name(), e.description());
+ return sdbusplus::sdbuspp::method_callback(
+ msg, o->_intf, error,
+ std::function([=](std::string&& locationCode) {
+ return o->getFRUsByExpandedLocationCode(locationCode);
+ }));
}
catch (sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::LocationNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::NodeNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
- return true;
+ return 0;
}
namespace details
@@ -218,49 +164,31 @@
void* context,
sd_bus_error* error)
{
+ auto o = static_cast<Manager*>(context);
+
try
{
- auto m = message::message(msg);
-#if 1
- {
- auto tbus = m.get_bus();
- sdbusplus::server::transaction::Transaction t(tbus, m);
- sdbusplus::server::transaction::set_id(
- std::hash<sdbusplus::server::transaction::Transaction>{}(t));
- }
-#endif
-
- std::string locationCode{};
- uint16_t nodeNumber{};
-
- m.read(locationCode, nodeNumber);
-
- auto o = static_cast<Manager*>(context);
- auto r = o->getExpandedLocationCode(locationCode, nodeNumber);
-
- auto reply = m.new_method_return();
- reply.append(std::move(r));
-
- reply.method_return();
- }
- catch (sdbusplus::internal_exception_t& e)
- {
- return sd_bus_error_set(error, e.name(), e.description());
+ return sdbusplus::sdbuspp::method_callback(
+ msg, o->_intf, error,
+ std::function(
+ [=](std::string&& locationCode, uint16_t&& nodeNumber) {
+ return o->getExpandedLocationCode(locationCode, nodeNumber);
+ }));
}
catch (sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::LocationNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
catch (sdbusplus::com::ibm::VPD::Error::NodeNotFound& e)
{
- return sd_bus_error_set(error, e.name(), e.description());
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
}
- return true;
+ return 0;
}
namespace details
@@ -274,6 +202,37 @@
} // namespace Manager
} // namespace details
+int Manager::_callback_PerformVPDRecollection(sd_bus_message* msg,
+ void* context,
+ sd_bus_error* error)
+{
+ auto o = static_cast<Manager*>(context);
+
+ try
+ {
+ return sdbusplus::sdbuspp::method_callback(
+ msg, o->_intf, error,
+ std::function([=]() { return o->performVPDRecollection(); }));
+ }
+ catch (sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument& e)
+ {
+ return o->_intf->sd_bus_error_set(error, e.name(), e.description());
+ }
+
+ return 0;
+}
+
+namespace details
+{
+namespace Manager
+{
+static const auto _param_PerformVPDRecollection =
+ utility::tuple_to_array(std::make_tuple('\0'));
+static const auto _return_PerformVPDRecollection =
+ utility::tuple_to_array(std::make_tuple('\0'));
+} // namespace Manager
+} // namespace details
+
const vtable::vtable_t Manager::_vtable[] = {
vtable::start(),
@@ -297,6 +256,11 @@
details::Manager::_param_GetExpandedLocationCode.data(),
details::Manager::_return_GetExpandedLocationCode.data(),
_callback_GetExpandedLocationCode),
+
+ vtable::method("PerformVPDRecollection",
+ details::Manager::_param_PerformVPDRecollection.data(),
+ details::Manager::_return_PerformVPDRecollection.data(),
+ _callback_PerformVPDRecollection),
vtable::end()};
} // namespace server