blob: 0cc570ca8dc59e4dc8bd5ae08167ac6994b12b4c [file] [log] [blame]
Chicago Duan7691cc22021-01-25 19:52:35 +08001#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
11namespace redfish
12{
13
14inline 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
63inline 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
151inline 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
203inline 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
258inline void handlePCIeSlotCollectionGet(
259 crow::App& app, const crow::Request& req,
260 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
261 const std::string& chassisID)
262{
Ed Tanous2aacf852022-06-17 08:07:54 -0700263 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Chicago Duan7691cc22021-01-25 19:52:35 +0800264 {
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
282inline 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