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