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