From 54632a9bb2dda405bc1b2d7a2b3d2c13eca925a5 Mon Sep 17 00:00:00 2001 From: James Feist Date: Fri, 27 Sep 2019 15:15:14 -0700 Subject: Add rebuilding to hsbp manager Interface is pushed here: https://gerrit.openbmc-project.xyz/c/openbmc/phosphor-dbus-interfaces/+/25671 Tested: available on dbus Change-Id: I79a73bb0e62951b09f4eb8bf0594aa39916b5dd9 Signed-off-by: James Feist --- hsbp-manager/src/hsbp_manager.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/hsbp-manager/src/hsbp_manager.cpp b/hsbp-manager/src/hsbp_manager.cpp index e02b76a..9dd4dbd 100644 --- a/hsbp-manager/src/hsbp_manager.cpp +++ b/hsbp-manager/src/hsbp_manager.cpp @@ -49,7 +49,8 @@ static std::string zeroPad(const uint8_t val) struct Drive { - Drive(size_t driveIndex, bool isPresent, bool isOperational, bool nvme) : + Drive(size_t driveIndex, bool isPresent, bool isOperational, bool nvme, + bool rebuilding) : isNvme(nvme) { constexpr const char* basePath = @@ -61,19 +62,25 @@ struct Drive "Drive " + std::to_string(driveIndex)); itemIface->initialize(); operationalIface = objServer.add_interface( - basePath + std::to_string(driveIndex), + itemIface->get_object_path(), "xyz.openbmc_project.State.Decorator.OperationalStatus"); operationalIface->register_property("Functional", isOperational); operationalIface->initialize(); + rebuildingIface = objServer.add_interface( + itemIface->get_object_path(), "xyz.openbmc_project.State.Drive"); + rebuildingIface->register_property("Rebuilding", rebuilding); + rebuildingIface->initialize(); } ~Drive() { objServer.remove_interface(itemIface); objServer.remove_interface(operationalIface); + objServer.remove_interface(rebuildingIface); } std::shared_ptr itemIface; std::shared_ptr operationalIface; + std::shared_ptr rebuildingIface; bool isNvme; }; @@ -155,17 +162,20 @@ struct Backplane uint8_t curPresence = 0; uint8_t curIFDET = 0; uint8_t curFailed = 0; + uint8_t curRebuild = 0; getPresence(curPresence); getIFDET(curIFDET); getFailed(curFailed); + getRebuild(curRebuild); if (curPresence != presence || curIFDET != ifdet || - curFailed != failed) + curFailed != failed || curRebuild != rebuilding) { presence = curPresence; ifdet = curIFDET; failed = curFailed; + rebuilding = curRebuild; updateDrives(); } runTimer(); @@ -180,10 +190,12 @@ struct Backplane bool isNvme = nvme & (1 << ii); bool isPresent = isNvme || (presence & (1 << ii)); bool isFailed = !isPresent || failed & (1 << ii); + bool isRebuilding = !isPresent && (rebuilding & (1 << ii)); // +1 to convert from 0 based to 1 based size_t driveIndex = (backplaneIndex * maxDrives) + ii + 1; - drives.emplace_back(driveIndex, isPresent, !isFailed, isNvme); + drives.emplace_back(driveIndex, isPresent, !isFailed, isNvme, + isRebuilding); } } @@ -195,12 +207,14 @@ struct Backplane { bool isNvme = nvme & (1 << ii); bool isPresent = isNvme || (presence & (1 << ii)); - bool isFailed = !isPresent || failed & (1 << ii); + bool isFailed = !isPresent || (failed & (1 << ii)); + bool isRebuilding = isPresent && (rebuilding & (1 << ii)); Drive& drive = drives[ii]; drive.isNvme = isNvme; drive.itemIface->set_property("Present", isPresent); drive.operationalIface->set_property("Functional", !isFailed); + drive.rebuildingIface->set_property("Rebuilding", isRebuilding); } } @@ -351,6 +365,7 @@ struct Backplane uint8_t presence = 0; uint8_t ifdet = 0; uint8_t failed = 0; + uint8_t rebuilding = 0; int file = -1; -- cgit v1.2.3 From 05cbe7a49a614b554413f8ebbda4306f603112f6 Mon Sep 17 00:00:00 2001 From: James Feist Date: Wed, 2 Oct 2019 09:09:16 -0700 Subject: 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 --- hsbp-manager/CMakeLists.txt | 1 + hsbp-manager/include/utils.hpp | 1 + hsbp-manager/src/hsbp_manager.cpp | 249 +++++++++++++++++++++++++++++++++++++- 3 files changed, 250 insertions(+), 1 deletion(-) 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::string, int64_t, uint64_t, double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>; +using Association = std::tuple; 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 #include +#include #include #include #include @@ -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 associations; + associations.emplace_back("inventory", "drive", path); + associationIface->register_property("Associations", associations); + associationIface->initialize(); } std::shared_ptr itemIface; std::shared_ptr operationalIface; std::shared_ptr rebuildingIface; + std::shared_ptr 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(io)) + timer(std::make_shared(io)), + muxes(std::make_shared>()) { } void run() @@ -375,10 +402,206 @@ struct Backplane std::shared_ptr versionIface; std::vector drives; + std::shared_ptr> muxes; }; std::unordered_map 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>& 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( + std::get(findBus->second)); + size_t driveIndex = static_cast( + std::get(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(std::stoi(busStr)); + size_t addr = + static_cast(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{driveType}); +} + +void populateMuxes(std::shared_ptr> muxes, + std::string& rootPath) +{ + const static std::array 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> callback = + std::make_shared>( + []() { 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& 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>& 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( + std::get(findBus->second)); + size_t address = static_cast( + std::get(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(); } -- cgit v1.2.3