#pragma once #include "app.hpp" #include "dbus_utility.hpp" #include "error_messages.hpp" #include "generated/enums/pcie_slots.hpp" #include "query.hpp" #include "registries/privilege_registry.hpp" #include "utility.hpp" #include "utils/dbus_utils.hpp" #include "utils/json_utils.hpp" #include "utils/pcie_util.hpp" #include #include #include #include #include #include namespace redfish { inline void onPcieSlotGetAllDone(const std::shared_ptr& asyncResp, const boost::system::error_code& ec, const dbus::utility::DBusPropertiesMap& propertiesList) { if (ec) { BMCWEB_LOG_ERROR("Can't get PCIeSlot properties!"); messages::internalError(asyncResp->res); return; } nlohmann::json& slots = asyncResp->res.jsonValue["Slots"]; nlohmann::json::array_t* slotsPtr = slots.get_ptr(); if (slotsPtr == nullptr) { BMCWEB_LOG_ERROR("Slots key isn't an array???"); messages::internalError(asyncResp->res); return; } nlohmann::json::object_t slot; const std::string* generation = nullptr; const size_t* lanes = nullptr; const std::string* slotType = nullptr; const bool* hotPluggable = nullptr; const bool success = sdbusplus::unpackPropertiesNoThrow( dbus_utils::UnpackErrorPrinter(), propertiesList, "Generation", generation, "Lanes", lanes, "SlotType", slotType, "HotPluggable", hotPluggable); if (!success) { messages::internalError(asyncResp->res); return; } if (generation != nullptr) { std::optional pcieType = pcie_util::redfishPcieGenerationFromDbus(*generation); if (!pcieType) { BMCWEB_LOG_WARNING("Unknown PCIe Slot Generation: {}", *generation); } else { if (*pcieType == pcie_device::PCIeTypes::Invalid) { messages::internalError(asyncResp->res); return; } slot["PCIeType"] = *pcieType; } } if (lanes != nullptr && *lanes != 0) { slot["Lanes"] = *lanes; } if (slotType != nullptr) { std::optional redfishSlotType = pcie_util::dbusSlotTypeToRf(*slotType); if (!redfishSlotType) { BMCWEB_LOG_WARNING("Unknown PCIe Slot Type: {}", *slotType); } else { if (*redfishSlotType == pcie_slots::SlotTypes::Invalid) { BMCWEB_LOG_ERROR("Unknown PCIe Slot Type: {}", *slotType); messages::internalError(asyncResp->res); return; } slot["SlotType"] = *redfishSlotType; } } if (hotPluggable != nullptr) { slot["HotPluggable"] = *hotPluggable; } slots.emplace_back(std::move(slot)); } inline void onMapperAssociationDone( const std::shared_ptr& asyncResp, const std::string& chassisID, const std::string& pcieSlotPath, const std::string& connectionName, const boost::system::error_code& ec, const dbus::utility::MapperEndPoints& pcieSlotChassis) { if (ec) { if (ec.value() == EBADR) { // This PCIeSlot have no chassis association. return; } BMCWEB_LOG_ERROR("DBUS response error"); messages::internalError(asyncResp->res); return; } if (pcieSlotChassis.size() != 1) { BMCWEB_LOG_ERROR("PCIe Slot association error! "); messages::internalError(asyncResp->res); return; } sdbusplus::message::object_path path(pcieSlotChassis[0]); std::string chassisName = path.filename(); if (chassisName != chassisID) { // The pcie slot doesn't belong to the chassisID return; } sdbusplus::asio::getAllProperties( *crow::connections::systemBus, connectionName, pcieSlotPath, "xyz.openbmc_project.Inventory.Item.PCIeSlot", [asyncResp](const boost::system::error_code& ec2, const dbus::utility::DBusPropertiesMap& propertiesList) { onPcieSlotGetAllDone(asyncResp, ec2, propertiesList); }); } inline void onMapperSubtreeDone(const std::shared_ptr& asyncResp, const std::string& chassisID, const boost::system::error_code& ec, const dbus::utility::MapperGetSubTreeResponse& subtree) { if (ec) { BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec); messages::internalError(asyncResp->res); return; } if (subtree.empty()) { messages::resourceNotFound(asyncResp->res, "Chassis", chassisID); return; } BMCWEB_LOG_DEBUG("Get properties for PCIeSlots associated to chassis = {}", chassisID); asyncResp->res.jsonValue["@odata.type"] = "#PCIeSlots.v1_4_1.PCIeSlots"; asyncResp->res.jsonValue["Name"] = "PCIe Slot Information"; asyncResp->res.jsonValue["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}/PCIeSlots", chassisID); asyncResp->res.jsonValue["Id"] = "1"; asyncResp->res.jsonValue["Slots"] = nlohmann::json::array(); for (const auto& pathServicePair : subtree) { const std::string& pcieSlotPath = pathServicePair.first; for (const auto& connectionInterfacePair : pathServicePair.second) { const std::string& connectionName = connectionInterfacePair.first; sdbusplus::message::object_path pcieSlotAssociationPath( pcieSlotPath); pcieSlotAssociationPath /= "chassis"; // The association of this PCIeSlot is used to determine whether // it belongs to this ChassisID dbus::utility::getAssociationEndPoints( std::string{pcieSlotAssociationPath}, [asyncResp, chassisID, pcieSlotPath, connectionName]( const boost::system::error_code& ec2, const dbus::utility::MapperEndPoints& endpoints) { onMapperAssociationDone(asyncResp, chassisID, pcieSlotPath, connectionName, ec2, endpoints); }); } } } inline void handlePCIeSlotCollectionGet( crow::App& app, const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& chassisID) { if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { return; } constexpr std::array interfaces = { "xyz.openbmc_project.Inventory.Item.PCIeSlot"}; dbus::utility::getSubTree( "/xyz/openbmc_project/inventory", 0, interfaces, [asyncResp, chassisID](const boost::system::error_code& ec, const dbus::utility::MapperGetSubTreeResponse& subtree) { onMapperSubtreeDone(asyncResp, chassisID, ec, subtree); }); } inline void requestRoutesPCIeSlots(App& app) { BMCWEB_ROUTE(app, "/redfish/v1/Chassis//PCIeSlots/") .privileges(redfish::privileges::getPCIeSlots) .methods(boost::beast::http::verb::get)( std::bind_front(handlePCIeSlotCollectionGet, std::ref(app))); } } // namespace redfish