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