blob: 1872c021310d51d0b2928f54b1e18c3222b11852 [file] [log] [blame]
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#pragma once
18
John Edward Broadbent7e860f12021-04-08 15:57:16 -070019#include <app.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080020#include <boost/system/linux_error.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070021#include <registries/privilege_registry.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080022
23namespace redfish
24{
25
Gunnar Mills1214b7e2020-06-04 10:11:30 -050026static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
27static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
28static constexpr char const* pcieDeviceInterface =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080029 "xyz.openbmc_project.PCIe.Device";
30
Ed Tanousb5a76932020-09-29 16:16:58 -070031static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080032 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -070033 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080034{
Jason M. Billsadbe1922019-10-14 15:44:35 -070035 auto getPCIeMapCallback = [asyncResp, name](
36 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050037 std::vector<std::string>& pcieDevicePaths) {
Jason M. Billsadbe1922019-10-14 15:44:35 -070038 if (ec)
39 {
40 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
41 << ec.message();
42 // Not an error, system just doesn't have PCIe info
43 return;
44 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
Jason M. Billsadbe1922019-10-14 15:44:35 -070046 pcieDeviceList = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -050047 for (const std::string& pcieDevicePath : pcieDevicePaths)
Jason M. Billsadbe1922019-10-14 15:44:35 -070048 {
Ed Tanous3174e4d2020-10-07 11:41:22 -070049 size_t devStart = pcieDevicePath.rfind('/');
Jason M. Billsadbe1922019-10-14 15:44:35 -070050 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080051 {
Jason M. Billsadbe1922019-10-14 15:44:35 -070052 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080053 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080054
Jason M. Billsadbe1922019-10-14 15:44:35 -070055 std::string devName = pcieDevicePath.substr(devStart + 1);
56 if (devName.empty())
57 {
58 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080059 }
Jason M. Billsadbe1922019-10-14 15:44:35 -070060 pcieDeviceList.push_back(
61 {{"@odata.id",
62 "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
63 }
64 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
65 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080066 crow::connections::systemBus->async_method_call(
67 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
68 "/xyz/openbmc_project/object_mapper",
69 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
70 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
71}
72
John Edward Broadbent7e860f12021-04-08 15:57:16 -070073inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -070074{
Jason M. Billsadbe1922019-10-14 15:44:35 -070075 /**
76 * Functions triggers appropriate requests on DBus
77 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -070078 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -070079 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070080 .methods(boost::beast::http::verb::get)(
81 [](const crow::Request&,
82 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Jason M. Billsadbe1922019-10-14 15:44:35 -070083
John Edward Broadbent7e860f12021-04-08 15:57:16 -070084 {
85 asyncResp->res.jsonValue = {
86 {"@odata.type",
87 "#PCIeDeviceCollection.PCIeDeviceCollection"},
88 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices"},
89 {"Name", "PCIe Device Collection"},
90 {"Description", "Collection of PCIe Devices"},
91 {"Members", nlohmann::json::array()},
92 {"Members@odata.count", 0}};
93 getPCIeDeviceList(asyncResp, "Members");
94 });
95}
96
Spencer Ku62cd45a2021-11-22 16:41:25 +080097inline std::optional<std::string>
98 redfishPcieGenerationFromDbus(const std::string& generationInUse)
99{
100 if (generationInUse ==
101 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
102 {
103 return "Gen1";
104 }
105 if (generationInUse ==
106 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
107 {
108 return "Gen2";
109 }
110 if (generationInUse ==
111 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
112 {
113 return "Gen3";
114 }
115 if (generationInUse ==
116 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
117 {
118 return "Gen4";
119 }
120 if (generationInUse ==
121 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
122 {
123 return "Gen5";
124 }
125 if (generationInUse.empty() ||
126 generationInUse ==
127 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
128 {
129 return "";
130 }
131
132 // The value is not unknown or Gen1-5, need return an internal error.
133 return std::nullopt;
134}
135
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700136inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800137{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700138 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700139 .privileges(redfish::privileges::getPCIeDevice)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700140 .methods(boost::beast::http::verb::get)(
141 [](const crow::Request&,
142 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
143 const std::string& device)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800144
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700145 {
146 auto getPCIeDeviceCallback = [asyncResp, device](
147 const boost::system::error_code
148 ec,
149 boost::container::flat_map<
150 std::string,
151 std::variant<std::string>>&
152 pcieDevProperties) {
153 if (ec)
154 {
155 BMCWEB_LOG_DEBUG
156 << "failed to get PCIe Device properties ec: "
157 << ec.value() << ": " << ec.message();
158 if (ec.value() ==
159 boost::system::linux_error::bad_request_descriptor)
160 {
161 messages::resourceNotFound(asyncResp->res,
162 "PCIeDevice", device);
163 }
164 else
165 {
166 messages::internalError(asyncResp->res);
167 }
168 return;
169 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800170
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700171 asyncResp->res.jsonValue = {
172 {"@odata.type", "#PCIeDevice.v1_4_0.PCIeDevice"},
173 {"@odata.id",
174 "/redfish/v1/Systems/system/PCIeDevices/" + device},
175 {"Name", "PCIe Device"},
176 {"Id", device}};
177
178 if (std::string* property = std::get_if<std::string>(
179 &pcieDevProperties["Manufacturer"]);
180 property)
181 {
182 asyncResp->res.jsonValue["Manufacturer"] = *property;
183 }
184
185 if (std::string* property = std::get_if<std::string>(
186 &pcieDevProperties["DeviceType"]);
187 property)
188 {
189 asyncResp->res.jsonValue["DeviceType"] = *property;
190 }
191
Spencer Ku62cd45a2021-11-22 16:41:25 +0800192 if (std::string* property = std::get_if<std::string>(
193 &pcieDevProperties["GenerationInUse"]);
194 property)
195 {
196 std::optional<std::string> generationInUse =
197 redfishPcieGenerationFromDbus(*property);
198 if (!generationInUse)
199 {
200 messages::internalError(asyncResp->res);
201 return;
202 }
203 if (*generationInUse == "")
204 {
205 // unknown, no need to handle
206 return;
207 }
208 asyncResp->res.jsonValue["PCIeInterface"]["PcieType"] =
209 *generationInUse;
210 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700211 asyncResp->res.jsonValue["PCIeFunctions"] = {
212 {"@odata.id",
213 "/redfish/v1/Systems/system/PCIeDevices/" + device +
214 "/PCIeFunctions"}};
215 };
216 std::string escapedPath = std::string(pciePath) + "/" + device;
217 dbus::utility::escapePathForDbus(escapedPath);
218 crow::connections::systemBus->async_method_call(
219 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
220 "org.freedesktop.DBus.Properties", "GetAll",
221 pcieDeviceInterface);
222 });
223}
224
225inline void requestRoutesSystemPCIeFunctionCollection(App& app)
226{
227 /**
228 * Functions triggers appropriate requests on DBus
229 */
230 BMCWEB_ROUTE(app,
231 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700232 .privileges(redfish::privileges::getPCIeFunctionCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700233 .methods(boost::beast::http::verb::get)(
234 [](const crow::Request&,
235 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
236 const std::string& device)
237
238 {
239 asyncResp->res.jsonValue = {
240 {"@odata.type",
241 "#PCIeFunctionCollection.PCIeFunctionCollection"},
242 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
243 device + "/PCIeFunctions"},
244 {"Name", "PCIe Function Collection"},
245 {"Description",
246 "Collection of PCIe Functions for PCIe Device " + device}};
247
248 auto getPCIeDeviceCallback = [asyncResp, device](
249 const boost::system::error_code
250 ec,
251 boost::container::flat_map<
252 std::string,
253 std::variant<std::string>>&
254 pcieDevProperties) {
255 if (ec)
256 {
257 BMCWEB_LOG_DEBUG
258 << "failed to get PCIe Device properties ec: "
259 << ec.value() << ": " << ec.message();
260 if (ec.value() ==
261 boost::system::linux_error::bad_request_descriptor)
262 {
263 messages::resourceNotFound(asyncResp->res,
264 "PCIeDevice", device);
265 }
266 else
267 {
268 messages::internalError(asyncResp->res);
269 }
270 return;
271 }
272
273 nlohmann::json& pcieFunctionList =
274 asyncResp->res.jsonValue["Members"];
275 pcieFunctionList = nlohmann::json::array();
276 static constexpr const int maxPciFunctionNum = 8;
277 for (int functionNum = 0; functionNum < maxPciFunctionNum;
278 functionNum++)
279 {
280 // Check if this function exists by looking for a device
281 // ID
282 std::string devIDProperty =
283 "Function" + std::to_string(functionNum) +
284 "DeviceId";
285 std::string* property = std::get_if<std::string>(
286 &pcieDevProperties[devIDProperty]);
287 if (property && !property->empty())
288 {
289 pcieFunctionList.push_back(
290 {{"@odata.id",
291 "/redfish/v1/Systems/system/PCIeDevices/" +
292 device + "/PCIeFunctions/" +
293 std::to_string(functionNum)}});
294 }
295 }
296 asyncResp->res.jsonValue["PCIeFunctions@odata.count"] =
297 pcieFunctionList.size();
298 };
299 std::string escapedPath = std::string(pciePath) + "/" + device;
300 dbus::utility::escapePathForDbus(escapedPath);
301 crow::connections::systemBus->async_method_call(
302 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
303 "org.freedesktop.DBus.Properties", "GetAll",
304 pcieDeviceInterface);
305 });
306}
307
308inline void requestRoutesSystemPCIeFunction(App& app)
309{
310 BMCWEB_ROUTE(
311 app,
312 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700313 .privileges(redfish::privileges::getPCIeFunction)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700314 .methods(
315 boost::beast::http::verb::get)([](const crow::Request&,
316 const std::shared_ptr<
317 bmcweb::AsyncResp>& asyncResp,
318 const std::string& device,
319 const std::string& function) {
320 auto getPCIeDeviceCallback = [asyncResp, device, function](
321 const boost::system::error_code ec,
322 boost::container::flat_map<
323 std::string,
324 std::variant<std::string>>&
325 pcieDevProperties) {
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800326 if (ec)
327 {
328 BMCWEB_LOG_DEBUG
329 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700330 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800331 if (ec.value() ==
332 boost::system::linux_error::bad_request_descriptor)
333 {
334 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
335 device);
336 }
337 else
338 {
339 messages::internalError(asyncResp->res);
340 }
341 return;
342 }
343
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700344 // Check if this function exists by looking for a device ID
345 std::string devIDProperty = "Function" + function + "DeviceId";
346 if (std::string* property = std::get_if<std::string>(
347 &pcieDevProperties[devIDProperty]);
348 property && property->empty())
349 {
350 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
351 function);
352 return;
353 }
354
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800355 asyncResp->res.jsonValue = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700356 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
Jason M. Billsdede6a92019-10-14 15:41:30 -0700357 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700358 device + "/PCIeFunctions/" + function},
359 {"Name", "PCIe Function"},
360 {"Id", function},
361 {"FunctionId", std::stoi(function)},
362 {"Links",
363 {{"PCIeDevice",
364 {{"@odata.id",
365 "/redfish/v1/Systems/system/PCIeDevices/" +
366 device}}}}}};
367
368 if (std::string* property = std::get_if<std::string>(
369 &pcieDevProperties["Function" + function + "DeviceId"]);
370 property)
371 {
372 asyncResp->res.jsonValue["DeviceId"] = *property;
373 }
374
375 if (std::string* property = std::get_if<std::string>(
376 &pcieDevProperties["Function" + function + "VendorId"]);
377 property)
378 {
379 asyncResp->res.jsonValue["VendorId"] = *property;
380 }
381
382 if (std::string* property = std::get_if<std::string>(
383 &pcieDevProperties["Function" + function +
384 "FunctionType"]);
385 property)
386 {
387 asyncResp->res.jsonValue["FunctionType"] = *property;
388 }
389
390 if (std::string* property = std::get_if<std::string>(
391 &pcieDevProperties["Function" + function +
392 "DeviceClass"]);
393 property)
394 {
395 asyncResp->res.jsonValue["DeviceClass"] = *property;
396 }
397
398 if (std::string* property = std::get_if<std::string>(
399 &pcieDevProperties["Function" + function +
400 "ClassCode"]);
401 property)
402 {
403 asyncResp->res.jsonValue["ClassCode"] = *property;
404 }
405
406 if (std::string* property = std::get_if<std::string>(
407 &pcieDevProperties["Function" + function +
408 "RevisionId"]);
409 property)
410 {
411 asyncResp->res.jsonValue["RevisionId"] = *property;
412 }
413
414 if (std::string* property = std::get_if<std::string>(
415 &pcieDevProperties["Function" + function +
416 "SubsystemId"]);
417 property)
418 {
419 asyncResp->res.jsonValue["SubsystemId"] = *property;
420 }
421
422 if (std::string* property = std::get_if<std::string>(
423 &pcieDevProperties["Function" + function +
424 "SubsystemVendorId"]);
425 property)
426 {
427 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
428 }
Jason M. Billsdede6a92019-10-14 15:41:30 -0700429 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700430 std::string escapedPath = std::string(pciePath) + "/" + device;
431 dbus::utility::escapePathForDbus(escapedPath);
432 crow::connections::systemBus->async_method_call(
433 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
434 "org.freedesktop.DBus.Properties", "GetAll",
435 pcieDeviceInterface);
436 });
437}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800438
439} // namespace redfish