17691cc2fSChicago Duan #pragma once
27691cc2fSChicago Duan 
37691cc2fSChicago Duan #include "error_messages.hpp"
4*0ec8b83dSEd Tanous #include "generated/enums/pcie_slot.hpp"
57691cc2fSChicago Duan #include "utility.hpp"
67691cc2fSChicago Duan 
77691cc2fSChicago Duan #include <app.hpp>
87691cc2fSChicago Duan #include <pcie.hpp>
97691cc2fSChicago Duan #include <registries/privilege_registry.hpp>
10d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
11d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
12d1bde9e5SKrzysztof Grobelny #include <utils/dbus_utils.hpp>
137691cc2fSChicago Duan #include <utils/json_utils.hpp>
147691cc2fSChicago Duan 
157691cc2fSChicago Duan namespace redfish
167691cc2fSChicago Duan {
177691cc2fSChicago Duan 
18*0ec8b83dSEd Tanous inline pcie_slot::SlotTypes dbusSlotTypeToRf(const std::string& slotType)
197691cc2fSChicago Duan {
207691cc2fSChicago Duan     if (slotType ==
217691cc2fSChicago Duan         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.FullLength")
227691cc2fSChicago Duan     {
23*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::FullLength;
247691cc2fSChicago Duan     }
257691cc2fSChicago Duan     if (slotType ==
267691cc2fSChicago Duan         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.HalfLength")
277691cc2fSChicago Duan     {
28*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::HalfLength;
297691cc2fSChicago Duan     }
307691cc2fSChicago Duan     if (slotType ==
317691cc2fSChicago Duan         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.LowProfile")
327691cc2fSChicago Duan     {
33*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::LowProfile;
347691cc2fSChicago Duan     }
357691cc2fSChicago Duan     if (slotType ==
367691cc2fSChicago Duan         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.Mini")
377691cc2fSChicago Duan     {
38*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::Mini;
397691cc2fSChicago Duan     }
407691cc2fSChicago Duan     if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.M_2")
417691cc2fSChicago Duan     {
42*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::M2;
437691cc2fSChicago Duan     }
447691cc2fSChicago Duan     if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OEM")
457691cc2fSChicago Duan     {
46*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::OEM;
477691cc2fSChicago Duan     }
487691cc2fSChicago Duan     if (slotType ==
497691cc2fSChicago Duan         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OCP3Small")
507691cc2fSChicago Duan     {
51*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::OCP3Small;
527691cc2fSChicago Duan     }
537691cc2fSChicago Duan     if (slotType ==
547691cc2fSChicago Duan         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OCP3Large")
557691cc2fSChicago Duan     {
56*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::OCP3Large;
577691cc2fSChicago Duan     }
587691cc2fSChicago Duan     if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.U_2")
597691cc2fSChicago Duan     {
60*0ec8b83dSEd Tanous         return pcie_slot::SlotTypes::U2;
617691cc2fSChicago Duan     }
627691cc2fSChicago Duan 
637691cc2fSChicago Duan     // Unknown or others
64*0ec8b83dSEd Tanous     return pcie_slot::SlotTypes::Invalid;
657691cc2fSChicago Duan }
667691cc2fSChicago Duan 
677691cc2fSChicago Duan inline void
687691cc2fSChicago Duan     onPcieSlotGetAllDone(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
697691cc2fSChicago Duan                          const boost::system::error_code ec,
707691cc2fSChicago Duan                          const dbus::utility::DBusPropertiesMap& propertiesList)
717691cc2fSChicago Duan {
727691cc2fSChicago Duan     if (ec)
737691cc2fSChicago Duan     {
747691cc2fSChicago Duan         BMCWEB_LOG_ERROR << "Can't get PCIeSlot properties!";
757691cc2fSChicago Duan         messages::internalError(asyncResp->res);
767691cc2fSChicago Duan         return;
777691cc2fSChicago Duan     }
787691cc2fSChicago Duan 
797691cc2fSChicago Duan     nlohmann::json& slots = asyncResp->res.jsonValue["Slots"];
807691cc2fSChicago Duan 
817691cc2fSChicago Duan     nlohmann::json::array_t* slotsPtr =
827691cc2fSChicago Duan         slots.get_ptr<nlohmann::json::array_t*>();
837691cc2fSChicago Duan     if (slotsPtr == nullptr)
847691cc2fSChicago Duan     {
857691cc2fSChicago Duan         BMCWEB_LOG_ERROR << "Slots key isn't an array???";
867691cc2fSChicago Duan         messages::internalError(asyncResp->res);
877691cc2fSChicago Duan         return;
887691cc2fSChicago Duan     }
897691cc2fSChicago Duan 
907691cc2fSChicago Duan     nlohmann::json::object_t slot;
917691cc2fSChicago Duan 
92d1bde9e5SKrzysztof Grobelny     const std::string* generation = nullptr;
93d1bde9e5SKrzysztof Grobelny     const size_t* lanes = nullptr;
94d1bde9e5SKrzysztof Grobelny     const std::string* slotType = nullptr;
95d1bde9e5SKrzysztof Grobelny     const bool* hotPluggable = nullptr;
967691cc2fSChicago Duan 
97d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
98d1bde9e5SKrzysztof Grobelny         dbus_utils::UnpackErrorPrinter(), propertiesList, "Generation",
99d1bde9e5SKrzysztof Grobelny         generation, "Lanes", lanes, "SlotType", slotType, "HotPluggable",
100d1bde9e5SKrzysztof Grobelny         hotPluggable);
101d1bde9e5SKrzysztof Grobelny 
102d1bde9e5SKrzysztof Grobelny     if (!success)
1037691cc2fSChicago Duan     {
1047691cc2fSChicago Duan         messages::internalError(asyncResp->res);
1057691cc2fSChicago Duan         return;
1067691cc2fSChicago Duan     }
107d1bde9e5SKrzysztof Grobelny 
108d1bde9e5SKrzysztof Grobelny     if (generation != nullptr)
109d1bde9e5SKrzysztof Grobelny     {
110*0ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> pcieType =
111d1bde9e5SKrzysztof Grobelny             redfishPcieGenerationFromDbus(*generation);
1127691cc2fSChicago Duan         if (!pcieType)
1137691cc2fSChicago Duan         {
1147691cc2fSChicago Duan             messages::internalError(asyncResp->res);
1157691cc2fSChicago Duan             return;
1167691cc2fSChicago Duan         }
1177691cc2fSChicago Duan         slot["PCIeType"] = !pcieType;
1187691cc2fSChicago Duan     }
119d1bde9e5SKrzysztof Grobelny 
120d1bde9e5SKrzysztof Grobelny     if (lanes != nullptr)
1217691cc2fSChicago Duan     {
122d1bde9e5SKrzysztof Grobelny 
123d1bde9e5SKrzysztof Grobelny         slot["Lanes"] = *lanes;
1247691cc2fSChicago Duan     }
125d1bde9e5SKrzysztof Grobelny 
126d1bde9e5SKrzysztof Grobelny     if (slotType != nullptr)
1277691cc2fSChicago Duan     {
128d1bde9e5SKrzysztof Grobelny         std::string redfishSlotType = dbusSlotTypeToRf(*slotType);
1297691cc2fSChicago Duan         if (!slotType.empty())
1307691cc2fSChicago Duan         {
1317691cc2fSChicago Duan             messages::internalError(asyncResp->res);
1327691cc2fSChicago Duan             return;
1337691cc2fSChicago Duan         }
134d1bde9e5SKrzysztof Grobelny         slot["SlotType"] = redfishSlotType;
1357691cc2fSChicago Duan     }
136d1bde9e5SKrzysztof Grobelny 
137d1bde9e5SKrzysztof Grobelny     if (hotPluggable != nullptr)
1387691cc2fSChicago Duan     {
139d1bde9e5SKrzysztof Grobelny         slot["HotPluggable"] = *hotPluggable;
1407691cc2fSChicago Duan     }
141d1bde9e5SKrzysztof Grobelny 
1427691cc2fSChicago Duan     slots.emplace_back(std::move(slot));
1437691cc2fSChicago Duan }
1447691cc2fSChicago Duan 
1457691cc2fSChicago Duan inline void onMapperAssociationDone(
1467691cc2fSChicago Duan     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1477691cc2fSChicago Duan     const std::string& chassisID, const std::string& pcieSlotPath,
1487691cc2fSChicago Duan     const std::string& connectionName, const boost::system::error_code ec,
1497691cc2fSChicago Duan     const std::variant<std::vector<std::string>>& endpoints)
1507691cc2fSChicago Duan {
1517691cc2fSChicago Duan     if (ec)
1527691cc2fSChicago Duan     {
1537691cc2fSChicago Duan         if (ec.value() == EBADR)
1547691cc2fSChicago Duan         {
1557691cc2fSChicago Duan             // This PCIeSlot have no chassis association.
1567691cc2fSChicago Duan             return;
1577691cc2fSChicago Duan         }
1587691cc2fSChicago Duan         BMCWEB_LOG_ERROR << "DBUS response error";
1597691cc2fSChicago Duan         messages::internalError(asyncResp->res);
1607691cc2fSChicago Duan         return;
1617691cc2fSChicago Duan     }
1627691cc2fSChicago Duan 
1637691cc2fSChicago Duan     const std::vector<std::string>* pcieSlotChassis =
1647691cc2fSChicago Duan         std::get_if<std::vector<std::string>>(&(endpoints));
1657691cc2fSChicago Duan 
1667691cc2fSChicago Duan     if (pcieSlotChassis == nullptr)
1677691cc2fSChicago Duan     {
1687691cc2fSChicago Duan         BMCWEB_LOG_ERROR << "Error getting PCIe Slot association!";
1697691cc2fSChicago Duan         messages::internalError(asyncResp->res);
1707691cc2fSChicago Duan         return;
1717691cc2fSChicago Duan     }
1727691cc2fSChicago Duan 
1737691cc2fSChicago Duan     if (pcieSlotChassis->size() != 1)
1747691cc2fSChicago Duan     {
1757691cc2fSChicago Duan         BMCWEB_LOG_ERROR << "PCIe Slot association error! ";
1767691cc2fSChicago Duan         messages::internalError(asyncResp->res);
1777691cc2fSChicago Duan         return;
1787691cc2fSChicago Duan     }
1797691cc2fSChicago Duan 
1807691cc2fSChicago Duan     sdbusplus::message::object_path path((*pcieSlotChassis)[0]);
1817691cc2fSChicago Duan     std::string chassisName = path.filename();
1827691cc2fSChicago Duan     if (chassisName != chassisID)
1837691cc2fSChicago Duan     {
1847691cc2fSChicago Duan         // The pcie slot doesn't belong to the chassisID
1857691cc2fSChicago Duan         return;
1867691cc2fSChicago Duan     }
1877691cc2fSChicago Duan 
188d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
189d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, connectionName, pcieSlotPath,
190d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
1917691cc2fSChicago Duan         [asyncResp](const boost::system::error_code ec,
1927691cc2fSChicago Duan                     const dbus::utility::DBusPropertiesMap& propertiesList) {
1937691cc2fSChicago Duan         onPcieSlotGetAllDone(asyncResp, ec, propertiesList);
194d1bde9e5SKrzysztof Grobelny         });
1957691cc2fSChicago Duan }
1967691cc2fSChicago Duan 
1977691cc2fSChicago Duan inline void
1987691cc2fSChicago Duan     onMapperSubtreeDone(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1997691cc2fSChicago Duan                         const std::string& chassisID,
2007691cc2fSChicago Duan                         const boost::system::error_code ec,
2017691cc2fSChicago Duan                         const dbus::utility::MapperGetSubTreeResponse& subtree)
2027691cc2fSChicago Duan {
2037691cc2fSChicago Duan     if (ec)
2047691cc2fSChicago Duan     {
2057691cc2fSChicago Duan         BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
2067691cc2fSChicago Duan         messages::internalError(asyncResp->res);
2077691cc2fSChicago Duan         return;
2087691cc2fSChicago Duan     }
2097691cc2fSChicago Duan     if (subtree.empty())
2107691cc2fSChicago Duan     {
211d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "Chassis", chassisID);
2127691cc2fSChicago Duan         return;
2137691cc2fSChicago Duan     }
2147691cc2fSChicago Duan 
2157691cc2fSChicago Duan     BMCWEB_LOG_DEBUG << "Get properties for PCIeSlots associated to chassis = "
2167691cc2fSChicago Duan                      << chassisID;
2177691cc2fSChicago Duan 
2187691cc2fSChicago Duan     asyncResp->res.jsonValue["@odata.type"] = "#PCIeSlots.v1_4_1.PCIeSlots";
2197691cc2fSChicago Duan     asyncResp->res.jsonValue["Name"] = "PCIe Slot Information";
2207691cc2fSChicago Duan     asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
2217691cc2fSChicago Duan         "redfish", "v1", "Chassis", chassisID, "PCIeSlots");
2227691cc2fSChicago Duan     asyncResp->res.jsonValue["Id"] = "1";
2237691cc2fSChicago Duan     asyncResp->res.jsonValue["Slots"] = nlohmann::json::array();
2247691cc2fSChicago Duan 
2257691cc2fSChicago Duan     for (const auto& pathServicePair : subtree)
2267691cc2fSChicago Duan     {
2277691cc2fSChicago Duan         const std::string& pcieSlotPath = pathServicePair.first;
2287691cc2fSChicago Duan         for (const auto& connectionInterfacePair : pathServicePair.second)
2297691cc2fSChicago Duan         {
2307691cc2fSChicago Duan             const std::string& connectionName = connectionInterfacePair.first;
2317691cc2fSChicago Duan             sdbusplus::message::object_path pcieSlotAssociationPath(
2327691cc2fSChicago Duan                 pcieSlotPath);
2337691cc2fSChicago Duan             pcieSlotAssociationPath /= "chassis";
2347691cc2fSChicago Duan 
2357691cc2fSChicago Duan             // The association of this PCIeSlot is used to determine whether
2367691cc2fSChicago Duan             // it belongs to this ChassisID
2377691cc2fSChicago Duan             crow::connections::systemBus->async_method_call(
2387691cc2fSChicago Duan                 [asyncResp, chassisID, pcieSlotPath, connectionName](
2397691cc2fSChicago Duan                     const boost::system::error_code ec,
2407691cc2fSChicago Duan                     const std::variant<std::vector<std::string>>& endpoints) {
2417691cc2fSChicago Duan                 onMapperAssociationDone(asyncResp, chassisID, pcieSlotPath,
2427691cc2fSChicago Duan                                         connectionName, ec, endpoints);
2437691cc2fSChicago Duan                 },
2447691cc2fSChicago Duan                 "xyz.openbmc_project.ObjectMapper",
2457691cc2fSChicago Duan                 std::string{pcieSlotAssociationPath},
2467691cc2fSChicago Duan                 "org.freedesktop.DBus.Properties", "Get",
2477691cc2fSChicago Duan                 "xyz.openbmc_project.Association", "endpoints");
2487691cc2fSChicago Duan         }
2497691cc2fSChicago Duan     }
2507691cc2fSChicago Duan }
2517691cc2fSChicago Duan 
2527691cc2fSChicago Duan inline void handlePCIeSlotCollectionGet(
2537691cc2fSChicago Duan     crow::App& app, const crow::Request& req,
2547691cc2fSChicago Duan     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2557691cc2fSChicago Duan     const std::string& chassisID)
2567691cc2fSChicago Duan {
2572aacf856SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2587691cc2fSChicago Duan     {
2597691cc2fSChicago Duan         return;
2607691cc2fSChicago Duan     }
2617691cc2fSChicago Duan 
2627691cc2fSChicago Duan     crow::connections::systemBus->async_method_call(
2637691cc2fSChicago Duan         [asyncResp,
2647691cc2fSChicago Duan          chassisID](const boost::system::error_code ec,
2657691cc2fSChicago Duan                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
2667691cc2fSChicago Duan         onMapperSubtreeDone(asyncResp, chassisID, ec, subtree);
2677691cc2fSChicago Duan         },
2687691cc2fSChicago Duan         "xyz.openbmc_project.ObjectMapper",
2697691cc2fSChicago Duan         "/xyz/openbmc_project/object_mapper",
2707691cc2fSChicago Duan         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
2717691cc2fSChicago Duan         "/xyz/openbmc_project/inventory", int32_t(0),
2727691cc2fSChicago Duan         std::array<const char*, 1>{
2737691cc2fSChicago Duan             "xyz.openbmc_project.Inventory.Item.PCIeSlot"});
2747691cc2fSChicago Duan }
2757691cc2fSChicago Duan 
2767691cc2fSChicago Duan inline void requestRoutesPCIeSlots(App& app)
2777691cc2fSChicago Duan {
2787691cc2fSChicago Duan     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PCIeSlots/")
2797691cc2fSChicago Duan         .privileges(redfish::privileges::getPCIeSlots)
2807691cc2fSChicago Duan         .methods(boost::beast::http::verb::get)(
2817691cc2fSChicago Duan             std::bind_front(handlePCIeSlotCollectionGet, std::ref(app)));
2827691cc2fSChicago Duan }
2837691cc2fSChicago Duan 
2847691cc2fSChicago Duan } // namespace redfish
285