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