| #pragma once |
| |
| #include "app.hpp" |
| #include "dbus_utility.hpp" |
| #include "error_messages.hpp" |
| #include "generated/enums/pcie_slots.hpp" |
| #include "pcie.hpp" |
| #include "registries/privilege_registry.hpp" |
| #include "utility.hpp" |
| #include "utils/dbus_utils.hpp" |
| #include "utils/json_utils.hpp" |
| |
| #include <boost/system/error_code.hpp> |
| #include <boost/url/format.hpp> |
| #include <sdbusplus/asio/property.hpp> |
| #include <sdbusplus/unpack_properties.hpp> |
| |
| #include <array> |
| #include <string_view> |
| |
| namespace redfish |
| { |
| |
| inline std::optional<pcie_slots::SlotTypes> |
| dbusSlotTypeToRf(const std::string& slotType) |
| { |
| if (slotType == |
| "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.FullLength") |
| { |
| return pcie_slots::SlotTypes::FullLength; |
| } |
| if (slotType == |
| "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.HalfLength") |
| { |
| return pcie_slots::SlotTypes::HalfLength; |
| } |
| if (slotType == |
| "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.LowProfile") |
| { |
| return pcie_slots::SlotTypes::LowProfile; |
| } |
| if (slotType == |
| "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.Mini") |
| { |
| return pcie_slots::SlotTypes::Mini; |
| } |
| if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.M_2") |
| { |
| return pcie_slots::SlotTypes::M2; |
| } |
| if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OEM") |
| { |
| return pcie_slots::SlotTypes::OEM; |
| } |
| if (slotType == |
| "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OCP3Small") |
| { |
| return pcie_slots::SlotTypes::OCP3Small; |
| } |
| if (slotType == |
| "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OCP3Large") |
| { |
| return pcie_slots::SlotTypes::OCP3Large; |
| } |
| if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.U_2") |
| { |
| return pcie_slots::SlotTypes::U2; |
| } |
| if (slotType == |
| "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.Unknown") |
| { |
| return pcie_slots::SlotTypes::Invalid; |
| } |
| |
| // Unspecified slotType should return an internal error. |
| return std::nullopt; |
| } |
| |
| inline void |
| onPcieSlotGetAllDone(const std::shared_ptr<bmcweb::AsyncResp>& 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<nlohmann::json::array_t*>(); |
| 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<pcie_device::PCIeTypes> pcieType = |
| redfishPcieGenerationFromDbus(*generation); |
| if (!pcieType) |
| { |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| if (*pcieType != pcie_device::PCIeTypes::Invalid) |
| { |
| slot["PCIeType"] = *pcieType; |
| } |
| } |
| |
| if (lanes != nullptr) |
| { |
| slot["Lanes"] = *lanes; |
| } |
| |
| if (slotType != nullptr) |
| { |
| std::optional<pcie_slots::SlotTypes> redfishSlotType = |
| dbusSlotTypeToRf(*slotType); |
| if (!redfishSlotType) |
| { |
| messages::internalError(asyncResp->res); |
| return; |
| } |
| if (*redfishSlotType != pcie_slots::SlotTypes::Invalid) |
| { |
| slot["SlotType"] = *redfishSlotType; |
| } |
| } |
| |
| if (hotPluggable != nullptr) |
| { |
| slot["HotPluggable"] = *hotPluggable; |
| } |
| |
| slots.emplace_back(std::move(slot)); |
| } |
| |
| inline void onMapperAssociationDone( |
| const std::shared_ptr<bmcweb::AsyncResp>& 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<bmcweb::AsyncResp>& 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<bmcweb::AsyncResp>& asyncResp, |
| const std::string& chassisID) |
| { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) |
| { |
| return; |
| } |
| |
| constexpr std::array<std::string_view, 1> 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/<str>/PCIeSlots/") |
| .privileges(redfish::privileges::getPCIeSlots) |
| .methods(boost::beast::http::verb::get)( |
| std::bind_front(handlePCIeSlotCollectionGet, std::ref(app))); |
| } |
| |
| } // namespace redfish |