1 #pragma once 2 3 #include "app.hpp" 4 #include "dbus_utility.hpp" 5 #include "error_messages.hpp" 6 #include "generated/enums/pcie_slots.hpp" 7 #include "query.hpp" 8 #include "registries/privilege_registry.hpp" 9 #include "utility.hpp" 10 #include "utils/dbus_utils.hpp" 11 #include "utils/json_utils.hpp" 12 #include "utils/pcie_util.hpp" 13 14 #include <boost/system/error_code.hpp> 15 #include <boost/url/format.hpp> 16 #include <sdbusplus/asio/property.hpp> 17 #include <sdbusplus/unpack_properties.hpp> 18 19 #include <array> 20 #include <string_view> 21 22 namespace redfish 23 { 24 25 inline void 26 onPcieSlotGetAllDone(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 27 const boost::system::error_code& ec, 28 const dbus::utility::DBusPropertiesMap& propertiesList) 29 { 30 if (ec) 31 { 32 BMCWEB_LOG_ERROR << "Can't get PCIeSlot properties!"; 33 messages::internalError(asyncResp->res); 34 return; 35 } 36 37 nlohmann::json& slots = asyncResp->res.jsonValue["Slots"]; 38 39 nlohmann::json::array_t* slotsPtr = 40 slots.get_ptr<nlohmann::json::array_t*>(); 41 if (slotsPtr == nullptr) 42 { 43 BMCWEB_LOG_ERROR << "Slots key isn't an array???"; 44 messages::internalError(asyncResp->res); 45 return; 46 } 47 48 nlohmann::json::object_t slot; 49 50 const std::string* generation = nullptr; 51 const size_t* lanes = nullptr; 52 const std::string* slotType = nullptr; 53 const bool* hotPluggable = nullptr; 54 55 const bool success = sdbusplus::unpackPropertiesNoThrow( 56 dbus_utils::UnpackErrorPrinter(), propertiesList, "Generation", 57 generation, "Lanes", lanes, "SlotType", slotType, "HotPluggable", 58 hotPluggable); 59 60 if (!success) 61 { 62 messages::internalError(asyncResp->res); 63 return; 64 } 65 66 if (generation != nullptr) 67 { 68 std::optional<pcie_device::PCIeTypes> pcieType = 69 pcie_util::redfishPcieGenerationFromDbus(*generation); 70 if (!pcieType) 71 { 72 messages::internalError(asyncResp->res); 73 return; 74 } 75 if (*pcieType != pcie_device::PCIeTypes::Invalid) 76 { 77 slot["PCIeType"] = *pcieType; 78 } 79 } 80 81 if (lanes != nullptr) 82 { 83 slot["Lanes"] = *lanes; 84 } 85 86 if (slotType != nullptr) 87 { 88 std::optional<pcie_slots::SlotTypes> redfishSlotType = 89 pcie_util::dbusSlotTypeToRf(*slotType); 90 if (!redfishSlotType) 91 { 92 messages::internalError(asyncResp->res); 93 return; 94 } 95 if (*redfishSlotType != pcie_slots::SlotTypes::Invalid) 96 { 97 slot["SlotType"] = *redfishSlotType; 98 } 99 } 100 101 if (hotPluggable != nullptr) 102 { 103 slot["HotPluggable"] = *hotPluggable; 104 } 105 106 slots.emplace_back(std::move(slot)); 107 } 108 109 inline void onMapperAssociationDone( 110 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 111 const std::string& chassisID, const std::string& pcieSlotPath, 112 const std::string& connectionName, const boost::system::error_code& ec, 113 const dbus::utility::MapperEndPoints& pcieSlotChassis) 114 { 115 if (ec) 116 { 117 if (ec.value() == EBADR) 118 { 119 // This PCIeSlot have no chassis association. 120 return; 121 } 122 BMCWEB_LOG_ERROR << "DBUS response error"; 123 messages::internalError(asyncResp->res); 124 return; 125 } 126 127 if (pcieSlotChassis.size() != 1) 128 { 129 BMCWEB_LOG_ERROR << "PCIe Slot association error! "; 130 messages::internalError(asyncResp->res); 131 return; 132 } 133 134 sdbusplus::message::object_path path(pcieSlotChassis[0]); 135 std::string chassisName = path.filename(); 136 if (chassisName != chassisID) 137 { 138 // The pcie slot doesn't belong to the chassisID 139 return; 140 } 141 142 sdbusplus::asio::getAllProperties( 143 *crow::connections::systemBus, connectionName, pcieSlotPath, 144 "xyz.openbmc_project.Inventory.Item.PCIeSlot", 145 [asyncResp](const boost::system::error_code& ec2, 146 const dbus::utility::DBusPropertiesMap& propertiesList) { 147 onPcieSlotGetAllDone(asyncResp, ec2, propertiesList); 148 }); 149 } 150 151 inline void 152 onMapperSubtreeDone(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 153 const std::string& chassisID, 154 const boost::system::error_code& ec, 155 const dbus::utility::MapperGetSubTreeResponse& subtree) 156 { 157 if (ec) 158 { 159 BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec; 160 messages::internalError(asyncResp->res); 161 return; 162 } 163 if (subtree.empty()) 164 { 165 messages::resourceNotFound(asyncResp->res, "Chassis", chassisID); 166 return; 167 } 168 169 BMCWEB_LOG_DEBUG << "Get properties for PCIeSlots associated to chassis = " 170 << chassisID; 171 172 asyncResp->res.jsonValue["@odata.type"] = "#PCIeSlots.v1_4_1.PCIeSlots"; 173 asyncResp->res.jsonValue["Name"] = "PCIe Slot Information"; 174 asyncResp->res.jsonValue["@odata.id"] = 175 boost::urls::format("/redfish/v1/Chassis/{}/PCIeSlots", chassisID); 176 asyncResp->res.jsonValue["Id"] = "1"; 177 asyncResp->res.jsonValue["Slots"] = nlohmann::json::array(); 178 179 for (const auto& pathServicePair : subtree) 180 { 181 const std::string& pcieSlotPath = pathServicePair.first; 182 for (const auto& connectionInterfacePair : pathServicePair.second) 183 { 184 const std::string& connectionName = connectionInterfacePair.first; 185 sdbusplus::message::object_path pcieSlotAssociationPath( 186 pcieSlotPath); 187 pcieSlotAssociationPath /= "chassis"; 188 189 // The association of this PCIeSlot is used to determine whether 190 // it belongs to this ChassisID 191 dbus::utility::getAssociationEndPoints( 192 std::string{pcieSlotAssociationPath}, 193 [asyncResp, chassisID, pcieSlotPath, connectionName]( 194 const boost::system::error_code& ec2, 195 const dbus::utility::MapperEndPoints& endpoints) { 196 onMapperAssociationDone(asyncResp, chassisID, pcieSlotPath, 197 connectionName, ec2, endpoints); 198 }); 199 } 200 } 201 } 202 203 inline void handlePCIeSlotCollectionGet( 204 crow::App& app, const crow::Request& req, 205 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 206 const std::string& chassisID) 207 { 208 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 209 { 210 return; 211 } 212 213 constexpr std::array<std::string_view, 1> interfaces = { 214 "xyz.openbmc_project.Inventory.Item.PCIeSlot"}; 215 dbus::utility::getSubTree( 216 "/xyz/openbmc_project/inventory", 0, interfaces, 217 [asyncResp, 218 chassisID](const boost::system::error_code& ec, 219 const dbus::utility::MapperGetSubTreeResponse& subtree) { 220 onMapperSubtreeDone(asyncResp, chassisID, ec, subtree); 221 }); 222 } 223 224 inline void requestRoutesPCIeSlots(App& app) 225 { 226 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PCIeSlots/") 227 .privileges(redfish::privileges::getPCIeSlots) 228 .methods(boost::beast::http::verb::get)( 229 std::bind_front(handlePCIeSlotCollectionGet, std::ref(app))); 230 } 231 232 } // namespace redfish 233