blob: 3c083aea49eb035a139444a2dcdcba1c46dfaf28 [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 Tanous168e20c2021-12-13 14:39:53 -080021#include <dbus_utility.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070022#include <registries/privilege_registry.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080023
24namespace redfish
25{
26
Gunnar Mills1214b7e2020-06-04 10:11:30 -050027static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
28static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
29static constexpr char const* pcieDeviceInterface =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080030 "xyz.openbmc_project.PCIe.Device";
31
Ed Tanousb5a76932020-09-29 16:16:58 -070032static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080033 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -070034 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080035{
Jason M. Billsadbe1922019-10-14 15:44:35 -070036 auto getPCIeMapCallback = [asyncResp, name](
37 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050038 std::vector<std::string>& pcieDevicePaths) {
Jason M. Billsadbe1922019-10-14 15:44:35 -070039 if (ec)
40 {
41 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
42 << ec.message();
43 // Not an error, system just doesn't have PCIe info
44 return;
45 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -050046 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
Jason M. Billsadbe1922019-10-14 15:44:35 -070047 pcieDeviceList = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -050048 for (const std::string& pcieDevicePath : pcieDevicePaths)
Jason M. Billsadbe1922019-10-14 15:44:35 -070049 {
Ed Tanous3174e4d2020-10-07 11:41:22 -070050 size_t devStart = pcieDevicePath.rfind('/');
Jason M. Billsadbe1922019-10-14 15:44:35 -070051 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080052 {
Jason M. Billsadbe1922019-10-14 15:44:35 -070053 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080054 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080055
Jason M. Billsadbe1922019-10-14 15:44:35 -070056 std::string devName = pcieDevicePath.substr(devStart + 1);
57 if (devName.empty())
58 {
59 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080060 }
Jason M. Billsadbe1922019-10-14 15:44:35 -070061 pcieDeviceList.push_back(
62 {{"@odata.id",
63 "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
64 }
65 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
66 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080067 crow::connections::systemBus->async_method_call(
68 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
69 "/xyz/openbmc_project/object_mapper",
70 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
71 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
72}
73
John Edward Broadbent7e860f12021-04-08 15:57:16 -070074inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -070075{
Jason M. Billsadbe1922019-10-14 15:44:35 -070076 /**
77 * Functions triggers appropriate requests on DBus
78 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -070079 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -070080 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070081 .methods(boost::beast::http::verb::get)(
82 [](const crow::Request&,
83 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Jason M. Billsadbe1922019-10-14 15:44:35 -070084
John Edward Broadbent7e860f12021-04-08 15:57:16 -070085 {
86 asyncResp->res.jsonValue = {
87 {"@odata.type",
88 "#PCIeDeviceCollection.PCIeDeviceCollection"},
89 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices"},
90 {"Name", "PCIe Device Collection"},
91 {"Description", "Collection of PCIe Devices"},
92 {"Members", nlohmann::json::array()},
93 {"Members@odata.count", 0}};
94 getPCIeDeviceList(asyncResp, "Members");
95 });
96}
97
Spencer Ku62cd45a2021-11-22 16:41:25 +080098inline std::optional<std::string>
99 redfishPcieGenerationFromDbus(const std::string& generationInUse)
100{
101 if (generationInUse ==
102 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
103 {
104 return "Gen1";
105 }
106 if (generationInUse ==
107 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
108 {
109 return "Gen2";
110 }
111 if (generationInUse ==
112 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
113 {
114 return "Gen3";
115 }
116 if (generationInUse ==
117 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
118 {
119 return "Gen4";
120 }
121 if (generationInUse ==
122 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
123 {
124 return "Gen5";
125 }
126 if (generationInUse.empty() ||
127 generationInUse ==
128 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
129 {
130 return "";
131 }
132
133 // The value is not unknown or Gen1-5, need return an internal error.
134 return std::nullopt;
135}
136
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700137inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800138{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700139 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700140 .privileges(redfish::privileges::getPCIeDevice)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700141 .methods(boost::beast::http::verb::get)(
142 [](const crow::Request&,
143 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
144 const std::string& device)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800145
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700146 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800147 auto getPCIeDeviceCallback =
148 [asyncResp,
149 device](const boost::system::error_code ec,
150 boost::container::flat_map<
151 std::string, dbus::utility::DbusVariantType>&
152 pcieDevProperties) {
153 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700154 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800155 BMCWEB_LOG_DEBUG
156 << "failed to get PCIe Device properties ec: "
157 << ec.value() << ": " << ec.message();
158 if (ec.value() == boost::system::linux_error::
159 bad_request_descriptor)
160 {
161 messages::resourceNotFound(
162 asyncResp->res, "PCIeDevice", device);
163 }
164 else
165 {
166 messages::internalError(asyncResp->res);
167 }
Spencer Ku62cd45a2021-11-22 16:41:25 +0800168 return;
169 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800170
171 asyncResp->res.jsonValue = {
172 {"@odata.type", "#PCIeDevice.v1_4_0.PCIeDevice"},
173 {"@odata.id",
174 "/redfish/v1/Systems/system/PCIeDevices/" +
175 device},
176 {"Name", "PCIe Device"},
177 {"Id", device}};
178
179 if (std::string* property = std::get_if<std::string>(
180 &pcieDevProperties["Manufacturer"]);
181 property)
Spencer Ku62cd45a2021-11-22 16:41:25 +0800182 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800183 asyncResp->res.jsonValue["Manufacturer"] =
184 *property;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800185 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800186
187 if (std::string* property = std::get_if<std::string>(
188 &pcieDevProperties["DeviceType"]);
189 property)
190 {
191 asyncResp->res.jsonValue["DeviceType"] = *property;
192 }
193
194 if (std::string* property = std::get_if<std::string>(
195 &pcieDevProperties["Manufacturer"]);
196 property)
197 {
198 asyncResp->res.jsonValue["Manufacturer"] =
199 *property;
200 }
201
202 if (std::string* property = std::get_if<std::string>(
203 &pcieDevProperties["DeviceType"]);
204 property)
205 {
206 asyncResp->res.jsonValue["DeviceType"] = *property;
207 }
208
209 if (std::string* property = std::get_if<std::string>(
210 &pcieDevProperties["GenerationInUse"]);
211 property)
212 {
213 std::optional<std::string> generationInUse =
214 redfishPcieGenerationFromDbus(*property);
215 if (!generationInUse)
216 {
217 messages::internalError(asyncResp->res);
218 return;
219 }
Ed Tanous26f69762022-01-25 09:49:11 -0800220 if (generationInUse->empty())
Ed Tanous168e20c2021-12-13 14:39:53 -0800221 {
222 // unknown, no need to handle
223 return;
224 }
225 asyncResp->res
Anjaliintel-21213ffc72022-02-10 12:04:45 +0000226 .jsonValue["PCIeInterface"]["PCIeType"] =
Ed Tanous168e20c2021-12-13 14:39:53 -0800227 *generationInUse;
228 }
229 asyncResp->res.jsonValue["PCIeFunctions"] = {
230 {"@odata.id",
231 "/redfish/v1/Systems/system/PCIeDevices/" +
232 device + "/PCIeFunctions"}};
233 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700234 std::string escapedPath = std::string(pciePath) + "/" + device;
235 dbus::utility::escapePathForDbus(escapedPath);
236 crow::connections::systemBus->async_method_call(
237 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
238 "org.freedesktop.DBus.Properties", "GetAll",
239 pcieDeviceInterface);
240 });
241}
242
243inline void requestRoutesSystemPCIeFunctionCollection(App& app)
244{
245 /**
246 * Functions triggers appropriate requests on DBus
247 */
248 BMCWEB_ROUTE(app,
249 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700250 .privileges(redfish::privileges::getPCIeFunctionCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700251 .methods(boost::beast::http::verb::get)(
252 [](const crow::Request&,
253 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
254 const std::string& device)
255
256 {
257 asyncResp->res.jsonValue = {
258 {"@odata.type",
259 "#PCIeFunctionCollection.PCIeFunctionCollection"},
260 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
261 device + "/PCIeFunctions"},
262 {"Name", "PCIe Function Collection"},
263 {"Description",
264 "Collection of PCIe Functions for PCIe Device " + device}};
265
266 auto getPCIeDeviceCallback = [asyncResp, device](
267 const boost::system::error_code
268 ec,
269 boost::container::flat_map<
270 std::string,
Ed Tanous168e20c2021-12-13 14:39:53 -0800271 dbus::utility::
272 DbusVariantType>&
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700273 pcieDevProperties) {
274 if (ec)
275 {
276 BMCWEB_LOG_DEBUG
277 << "failed to get PCIe Device properties ec: "
278 << ec.value() << ": " << ec.message();
279 if (ec.value() ==
280 boost::system::linux_error::bad_request_descriptor)
281 {
282 messages::resourceNotFound(asyncResp->res,
283 "PCIeDevice", device);
284 }
285 else
286 {
287 messages::internalError(asyncResp->res);
288 }
289 return;
290 }
291
292 nlohmann::json& pcieFunctionList =
293 asyncResp->res.jsonValue["Members"];
294 pcieFunctionList = nlohmann::json::array();
295 static constexpr const int maxPciFunctionNum = 8;
296 for (int functionNum = 0; functionNum < maxPciFunctionNum;
297 functionNum++)
298 {
299 // Check if this function exists by looking for a device
300 // ID
301 std::string devIDProperty =
302 "Function" + std::to_string(functionNum) +
303 "DeviceId";
304 std::string* property = std::get_if<std::string>(
305 &pcieDevProperties[devIDProperty]);
Ed Tanous26f69762022-01-25 09:49:11 -0800306 if (property != nullptr && !property->empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700307 {
308 pcieFunctionList.push_back(
309 {{"@odata.id",
310 "/redfish/v1/Systems/system/PCIeDevices/" +
311 device + "/PCIeFunctions/" +
312 std::to_string(functionNum)}});
313 }
314 }
Jiaqing Zhaoa818d152022-01-19 19:52:47 +0800315 asyncResp->res.jsonValue["Members@odata.count"] =
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700316 pcieFunctionList.size();
317 };
318 std::string escapedPath = std::string(pciePath) + "/" + device;
319 dbus::utility::escapePathForDbus(escapedPath);
320 crow::connections::systemBus->async_method_call(
321 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
322 "org.freedesktop.DBus.Properties", "GetAll",
323 pcieDeviceInterface);
324 });
325}
326
327inline void requestRoutesSystemPCIeFunction(App& app)
328{
329 BMCWEB_ROUTE(
330 app,
331 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700332 .privileges(redfish::privileges::getPCIeFunction)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700333 .methods(
334 boost::beast::http::verb::get)([](const crow::Request&,
335 const std::shared_ptr<
336 bmcweb::AsyncResp>& asyncResp,
337 const std::string& device,
338 const std::string& function) {
Ed Tanous168e20c2021-12-13 14:39:53 -0800339 auto getPCIeDeviceCallback =
340 [asyncResp, device, function](
341 const boost::system::error_code ec,
342 boost::container::flat_map<std::string,
343 dbus::utility::DbusVariantType>&
344 pcieDevProperties) {
345 if (ec)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800346 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800347 BMCWEB_LOG_DEBUG
348 << "failed to get PCIe Device properties ec: "
349 << ec.value() << ": " << ec.message();
350 if (ec.value() ==
351 boost::system::linux_error::bad_request_descriptor)
352 {
353 messages::resourceNotFound(asyncResp->res,
354 "PCIeDevice", device);
355 }
356 else
357 {
358 messages::internalError(asyncResp->res);
359 }
360 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800361 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800362
363 // Check if this function exists by looking for a device ID
364 std::string devIDProperty =
365 "Function" + function + "DeviceId";
366 if (std::string* property = std::get_if<std::string>(
367 &pcieDevProperties[devIDProperty]);
Ed Tanous26f69762022-01-25 09:49:11 -0800368 property != nullptr && property->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800369 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800370 messages::resourceNotFound(asyncResp->res,
371 "PCIeFunction", function);
372 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800373 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800374
Ed Tanous168e20c2021-12-13 14:39:53 -0800375 asyncResp->res.jsonValue = {
376 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
377 {"@odata.id",
378 "/redfish/v1/Systems/system/PCIeDevices/" + device +
379 "/PCIeFunctions/" + function},
380 {"Name", "PCIe Function"},
381 {"Id", function},
382 {"FunctionId", std::stoi(function)},
383 {"Links",
384 {{"PCIeDevice",
385 {{"@odata.id",
386 "/redfish/v1/Systems/system/PCIeDevices/" +
387 device}}}}}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700388
Ed Tanous168e20c2021-12-13 14:39:53 -0800389 if (std::string* property = std::get_if<std::string>(
390 &pcieDevProperties["Function" + function +
391 "DeviceId"]);
392 property)
393 {
394 asyncResp->res.jsonValue["DeviceId"] = *property;
395 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700396
Ed Tanous168e20c2021-12-13 14:39:53 -0800397 if (std::string* property = std::get_if<std::string>(
398 &pcieDevProperties["Function" + function +
399 "VendorId"]);
400 property)
401 {
402 asyncResp->res.jsonValue["VendorId"] = *property;
403 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700404
Ed Tanous168e20c2021-12-13 14:39:53 -0800405 if (std::string* property = std::get_if<std::string>(
406 &pcieDevProperties["Function" + function +
407 "FunctionType"]);
408 property)
409 {
410 asyncResp->res.jsonValue["FunctionType"] = *property;
411 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700412
Ed Tanous168e20c2021-12-13 14:39:53 -0800413 if (std::string* property = std::get_if<std::string>(
414 &pcieDevProperties["Function" + function +
415 "DeviceClass"]);
416 property)
417 {
418 asyncResp->res.jsonValue["DeviceClass"] = *property;
419 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700420
Ed Tanous168e20c2021-12-13 14:39:53 -0800421 if (std::string* property = std::get_if<std::string>(
422 &pcieDevProperties["Function" + function +
423 "ClassCode"]);
424 property)
425 {
426 asyncResp->res.jsonValue["ClassCode"] = *property;
427 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700428
Ed Tanous168e20c2021-12-13 14:39:53 -0800429 if (std::string* property = std::get_if<std::string>(
430 &pcieDevProperties["Function" + function +
431 "RevisionId"]);
432 property)
433 {
434 asyncResp->res.jsonValue["RevisionId"] = *property;
435 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700436
Ed Tanous168e20c2021-12-13 14:39:53 -0800437 if (std::string* property = std::get_if<std::string>(
438 &pcieDevProperties["Function" + function +
439 "SubsystemId"]);
440 property)
441 {
442 asyncResp->res.jsonValue["SubsystemId"] = *property;
443 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700444
Ed Tanous168e20c2021-12-13 14:39:53 -0800445 if (std::string* property = std::get_if<std::string>(
446 &pcieDevProperties["Function" + function +
447 "SubsystemVendorId"]);
448 property)
449 {
450 asyncResp->res.jsonValue["SubsystemVendorId"] =
451 *property;
452 }
453 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700454 std::string escapedPath = std::string(pciePath) + "/" + device;
455 dbus::utility::escapePathForDbus(escapedPath);
456 crow::connections::systemBus->async_method_call(
457 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
458 "org.freedesktop.DBus.Properties", "GetAll",
459 pcieDeviceInterface);
460 });
461}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800462
463} // namespace redfish