diff options
author | James Feist <james.feist@linux.intel.com> | 2019-10-02 19:09:16 +0300 |
---|---|---|
committer | James Feist <james.feist@linux.intel.com> | 2019-10-08 01:23:15 +0300 |
commit | 05cbe7a49a614b554413f8ebbda4306f603112f6 (patch) | |
tree | dd06c1bfec6746d521f89658a50181b7f9ab5456 | |
parent | 54632a9bb2dda405bc1b2d7a2b3d2c13eca925a5 (diff) | |
download | provingground-05cbe7a49a614b554413f8ebbda4306f603112f6.tar.xz |
Create associations for drives with inventory
This creates associations so that redfish can know which
drives map to which configuration items.
Tested:
root@intel-obmc:~# busctl introspect xyz.openbmc_project.HsbpManager /xyz/openbmc_project/inventory/item/drive/Drive_2 --no-pager
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
org.freedesktop.DBus.Peer interface - - -
.GetMachineId method - s -
.Ping method - - -
org.freedesktop.DBus.Properties interface - - -
.Get method ss v -
.GetAll method s a{sv} -
.Set method ssv - -
.PropertiesChanged signal sa{sv}as - -
xyz.openbmc_project.Association.Definitions interface - - -
.Associations property a(sss) 1 "inventory" "drive" "/xyz/openbmc_p... emits-change
xyz.openbmc_project.Inventory.Item interface - - -
.Present property b true emits-change
.PrettyName property s "Drive 2" emits-change
xyz.openbmc_project.State.Decorator.OperationalStatus interface - - -
.Functional property b true emits-change
xyz.openbmc_project.State.Drive interface - - -
.Rebuilding property b false emits-change
Also show up in mapper
Change-Id: Ia050316ac55faa89aad86567c93f9a74594e9180
Signed-off-by: James Feist <james.feist@linux.intel.com>
-rw-r--r-- | hsbp-manager/CMakeLists.txt | 1 | ||||
-rw-r--r-- | hsbp-manager/include/utils.hpp | 1 | ||||
-rw-r--r-- | hsbp-manager/src/hsbp_manager.cpp | 249 |
3 files changed, 250 insertions, 1 deletions
diff --git a/hsbp-manager/CMakeLists.txt b/hsbp-manager/CMakeLists.txt index 20560c9..eeb6f0a 100644 --- a/hsbp-manager/CMakeLists.txt +++ b/hsbp-manager/CMakeLists.txt @@ -87,6 +87,7 @@ target_link_libraries (hsbp-manager -lsystemd) target_link_libraries (hsbp-manager i2c) target_link_libraries (hsbp-manager ${Boost_LIBRARIES}) target_link_libraries (hsbp-manager sdbusplus) +target_link_libraries (hsbp-manager stdc++fs) if (NOT YOCTO) add_dependencies (hsbp-manager sdbusplus-project) diff --git a/hsbp-manager/include/utils.hpp b/hsbp-manager/include/utils.hpp index eec2cd6..8e63bfe 100644 --- a/hsbp-manager/include/utils.hpp +++ b/hsbp-manager/include/utils.hpp @@ -25,6 +25,7 @@ using GetSubTreeType = std::vector< using BasicVariantType = std::variant<std::vector<std::string>, std::string, int64_t, uint64_t, double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>; +using Association = std::tuple<std::string, std::string, std::string>; namespace mapper { diff --git a/hsbp-manager/src/hsbp_manager.cpp b/hsbp-manager/src/hsbp_manager.cpp index 9dd4dbd..56469dd 100644 --- a/hsbp-manager/src/hsbp_manager.cpp +++ b/hsbp-manager/src/hsbp_manager.cpp @@ -18,6 +18,7 @@ #include <boost/algorithm/string/replace.hpp> #include <boost/asio/steady_timer.hpp> +#include <filesystem> #include <iostream> #include <sdbusplus/asio/connection.hpp> #include <sdbusplus/asio/object_server.hpp> @@ -47,6 +48,14 @@ static std::string zeroPad(const uint8_t val) return version.str(); } +struct Mux +{ + Mux(size_t busIn, size_t addressIn) : bus(busIn), address(addressIn) + { + } + size_t bus; + size_t address; +}; struct Drive { Drive(size_t driveIndex, bool isPresent, bool isOperational, bool nvme, @@ -76,11 +85,28 @@ struct Drive objServer.remove_interface(itemIface); objServer.remove_interface(operationalIface); objServer.remove_interface(rebuildingIface); + objServer.remove_interface(associationIface); + } + + void createAssociation(const std::string& path) + { + if (associationIface != nullptr) + { + return; + } + associationIface = objServer.add_interface( + itemIface->get_object_path(), + "xyz.openbmc_project.Association.Definitions"); + std::vector<Association> associations; + associations.emplace_back("inventory", "drive", path); + associationIface->register_property("Associations", associations); + associationIface->initialize(); } std::shared_ptr<sdbusplus::asio::dbus_interface> itemIface; std::shared_ptr<sdbusplus::asio::dbus_interface> operationalIface; std::shared_ptr<sdbusplus::asio::dbus_interface> rebuildingIface; + std::shared_ptr<sdbusplus::asio::dbus_interface> associationIface; bool isNvme; }; @@ -91,7 +117,8 @@ struct Backplane const std::string& nameIn) : bus(busIn), address(addressIn), backplaneIndex(backplaneIndexIn - 1), name(nameIn), - timer(std::make_shared<boost::asio::steady_timer>(io)) + timer(std::make_shared<boost::asio::steady_timer>(io)), + muxes(std::make_shared<std::vector<Mux>>()) { } void run() @@ -375,10 +402,206 @@ struct Backplane std::shared_ptr<sdbusplus::asio::dbus_interface> versionIface; std::vector<Drive> drives; + std::shared_ptr<std::vector<Mux>> muxes; }; std::unordered_map<std::string, Backplane> backplanes; +void updateAssociations() +{ + constexpr const char* driveType = + "xyz.openbmc_project.Inventory.Item.Drive"; + + conn->async_method_call( + [](const boost::system::error_code ec, const GetSubTreeType& subtree) { + if (ec) + { + std::cerr << "Error contacting mapper " << ec.message() << "\n"; + return; + } + for (const auto& [path, objDict] : subtree) + { + if (objDict.empty()) + { + continue; + } + + const std::string& owner = objDict.begin()->first; + conn->async_method_call( + [path](const boost::system::error_code ec2, + const boost::container::flat_map< + std::string, std::variant<uint64_t>>& values) { + if (ec2) + { + std::cerr << "Error Getting Config " + << ec2.message() << " " << __FUNCTION__ + << "\n"; + return; + } + auto findBus = values.find("Bus"); + auto findIndex = values.find("Index"); + + if (findBus == values.end() || + findIndex == values.end()) + { + std::cerr << "Illegal interface at " << path + << "\n"; + return; + } + + size_t muxBus = static_cast<size_t>( + std::get<uint64_t>(findBus->second)); + size_t driveIndex = static_cast<size_t>( + std::get<uint64_t>(findIndex->second)); + std::filesystem::path muxPath = + "/sys/bus/i2c/devices/i2c-" + + std::to_string(muxBus) + "/mux_device"; + if (!std::filesystem::is_symlink(muxPath)) + { + std::cerr << path << " mux does not exist\n"; + return; + } + + // we should be getting something of the form 7-0052 for + // bus 7 addr 52 + std::string fname = + std::filesystem::read_symlink(muxPath).filename(); + auto findDash = fname.find('-'); + + if (findDash == std::string::npos || + findDash + 1 >= fname.size()) + { + std::cerr << path << " mux path invalid\n"; + return; + } + + std::string busStr = fname.substr(0, findDash); + std::string muxStr = fname.substr(findDash + 1); + + size_t bus = static_cast<size_t>(std::stoi(busStr)); + size_t addr = + static_cast<size_t>(std::stoi(muxStr, nullptr, 16)); + Backplane* parent = nullptr; + for (auto& [name, backplane] : backplanes) + { + for (const Mux& mux : *(backplane.muxes)) + { + if (bus == mux.bus && addr == mux.address) + { + parent = &backplane; + break; + } + } + } + if (parent == nullptr) + { + std::cerr << "Failed to find mux at bus " << bus + << ", addr " << addr << "\n"; + return; + } + if (parent->drives.size() <= driveIndex) + { + + std::cerr << "Illegal drive index at " << path + << " " << driveIndex << "\n"; + return; + } + Drive& drive = parent->drives[driveIndex]; + drive.createAssociation(path); + }, + owner, path, "org.freedesktop.DBus.Properties", "GetAll", + "xyz.openbmc_project.Inventory.Item.Drive"); + } + }, + mapper::busName, mapper::path, mapper::interface, mapper::subtree, "/", + 0, std::array<const char*, 1>{driveType}); +} + +void populateMuxes(std::shared_ptr<std::vector<Mux>> muxes, + std::string& rootPath) +{ + const static std::array<const std::string, 4> muxTypes = { + "xyz.openbmc_project.Configuration.PCA9543Mux", + "xyz.openbmc_project.Configuration.PCA9544Mux", + "xyz.openbmc_project.Configuration.PCA9545Mux", + "xyz.openbmc_project.Configuration.PCA9546Mux"}; + conn->async_method_call( + [muxes](const boost::system::error_code ec, + const GetSubTreeType& subtree) { + if (ec) + { + std::cerr << "Error contacting mapper " << ec.message() << "\n"; + return; + } + std::shared_ptr<std::function<void()>> callback = + std::make_shared<std::function<void()>>( + []() { updateAssociations(); }); + for (const auto& [path, objDict] : subtree) + { + if (objDict.empty() || objDict.begin()->second.empty()) + { + continue; + } + + const std::string& owner = objDict.begin()->first; + const std::vector<std::string>& interfaces = + objDict.begin()->second; + + const std::string* interface = nullptr; + for (const std::string& iface : interfaces) + { + if (std::find(muxTypes.begin(), muxTypes.end(), iface) != + muxTypes.end()) + { + interface = &iface; + break; + } + } + if (interface == nullptr) + { + std::cerr << "Cannot get mux type\n"; + continue; + } + + conn->async_method_call( + [path, muxes, callback]( + const boost::system::error_code ec2, + const boost::container::flat_map< + std::string, std::variant<uint64_t>>& values) { + if (ec2) + { + std::cerr << "Error Getting Config " + << ec2.message() << " " << __FUNCTION__ + << "\n"; + return; + } + auto findBus = values.find("Bus"); + auto findAddress = values.find("Address"); + if (findBus == values.end() || + findAddress == values.end()) + { + std::cerr << "Illegal configuration at " << path + << "\n"; + return; + } + size_t bus = static_cast<size_t>( + std::get<uint64_t>(findBus->second)); + size_t address = static_cast<size_t>( + std::get<uint64_t>(findAddress->second)); + muxes->emplace_back(bus, address); + if (callback.use_count() == 1) + { + (*callback)(); + } + }, + owner, path, "org.freedesktop.DBus.Properties", "GetAll", + *interface); + } + }, + mapper::busName, mapper::path, mapper::interface, mapper::subtree, + rootPath, 1, muxTypes); +} + void populate() { conn->async_method_call( @@ -436,10 +659,13 @@ void populate() << "\n"; return; } + std::string parentPath = + std::filesystem::path(path).parent_path(); const auto& [backplane, status] = backplanes.emplace( *name, Backplane(*bus, *address, *backplaneIndex, *name)); backplane->second.run(); + populateMuxes(backplane->second.muxes, parentPath); }, owner, path, "org.freedesktop.DBus.Properties", "GetAll", configType); @@ -476,6 +702,27 @@ int main() }); }); + sdbusplus::bus::match::match drive( + *conn, + "type='signal',member='PropertiesChanged',arg0='xyz.openbmc_project." + "Inventory.Item.Drive'", + [&callbackTimer](sdbusplus::message::message&) { + callbackTimer.expires_after(std::chrono::seconds(2)); + callbackTimer.async_wait([](const boost::system::error_code ec) { + if (ec == boost::asio::error::operation_aborted) + { + // timer was restarted + return; + } + else if (ec) + { + std::cerr << "Timer error" << ec.message() << "\n"; + return; + } + populate(); + }); + }); + io.post([]() { populate(); }); io.run(); } |