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