blob: 778768f0925644b9fabf9fdccecd1f3171a4e9ae [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>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02009#include <sdbusplus/asio/property.hpp>
10#include <sdbusplus/unpack_properties.hpp>
11#include <utils/dbus_utils.hpp>
Chicago Duan7691cc22021-01-25 19:52:35 +080012#include <utils/json_utils.hpp>
13
14namespace redfish
15{
16
17inline 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
66inline 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
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020091 const std::string* generation = nullptr;
92 const size_t* lanes = nullptr;
93 const std::string* slotType = nullptr;
94 const bool* hotPluggable = nullptr;
Chicago Duan7691cc22021-01-25 19:52:35 +080095
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020096 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;
Chicago Duan7691cc22021-01-25 19:52:35 +0800105 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200106
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
Chicago Duan7691cc22021-01-25 19:52:35 +0800141 slots.emplace_back(std::move(slot));
142}
143
144inline 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
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200187 sdbusplus::asio::getAllProperties(
188 *crow::connections::systemBus, connectionName, pcieSlotPath,
189 "xyz.openbmc_project.Inventory.Item.PCIeSlot",
Chicago Duan7691cc22021-01-25 19:52:35 +0800190 [asyncResp](const boost::system::error_code ec,
191 const dbus::utility::DBusPropertiesMap& propertiesList) {
192 onPcieSlotGetAllDone(asyncResp, ec, propertiesList);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200193 });
Chicago Duan7691cc22021-01-25 19:52:35 +0800194}
195
196inline 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 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800210 messages::resourceNotFound(asyncResp->res, "Chassis", chassisID);
Chicago Duan7691cc22021-01-25 19:52:35 +0800211 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
251inline void handlePCIeSlotCollectionGet(
252 crow::App& app, const crow::Request& req,
253 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
254 const std::string& chassisID)
255{
Ed Tanous2aacf852022-06-17 08:07:54 -0700256 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Chicago Duan7691cc22021-01-25 19:52:35 +0800257 {
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
275inline 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