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