blob: 740e393bf40a6d566c4d866c393395e0d4ab120f [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 Tanous45ca1b82022-03-25 13:07:27 -070022#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070023#include <registries/privilege_registry.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080024
25namespace redfish
26{
27
Gunnar Mills1214b7e2020-06-04 10:11:30 -050028static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
29static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
30static constexpr char const* pcieDeviceInterface =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080031 "xyz.openbmc_project.PCIe.Device";
32
Ed Tanousb5a76932020-09-29 16:16:58 -070033static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080034 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -070035 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080036{
Ed Tanousb9d36b42022-02-26 21:42:46 -080037 auto getPCIeMapCallback =
38 [asyncResp, name](const boost::system::error_code ec,
39 const dbus::utility::MapperGetSubTreePathsResponse&
40 pcieDevicePaths) {
41 if (ec)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080042 {
Ed Tanousb9d36b42022-02-26 21:42:46 -080043 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
44 << ec.message();
45 // Not an error, system just doesn't have PCIe info
46 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080047 }
Ed Tanousb9d36b42022-02-26 21:42:46 -080048 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
49 pcieDeviceList = nlohmann::json::array();
50 for (const std::string& pcieDevicePath : pcieDevicePaths)
51 {
52 size_t devStart = pcieDevicePath.rfind('/');
53 if (devStart == std::string::npos)
54 {
55 continue;
56 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080057
Ed Tanousb9d36b42022-02-26 21:42:46 -080058 std::string devName = pcieDevicePath.substr(devStart + 1);
59 if (devName.empty())
60 {
61 continue;
62 }
Ed Tanous14766872022-03-15 10:44:42 -070063 nlohmann::json::object_t pcieDevice;
64 pcieDevice["@odata.id"] =
65 "/redfish/v1/Systems/system/PCIeDevices/" + devName;
66 pcieDeviceList.push_back(std::move(pcieDevice));
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080067 }
Ed Tanousb9d36b42022-02-26 21:42:46 -080068 asyncResp->res.jsonValue[name + "@odata.count"] =
69 pcieDeviceList.size();
70 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080071 crow::connections::systemBus->async_method_call(
72 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
73 "/xyz/openbmc_project/object_mapper",
74 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
75 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
76}
77
John Edward Broadbent7e860f12021-04-08 15:57:16 -070078inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -070079{
Jason M. Billsadbe1922019-10-14 15:44:35 -070080 /**
81 * Functions triggers appropriate requests on DBus
82 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -070083 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -070084 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070085 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -070086 [&app](const crow::Request& req,
87 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
88 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
89 {
90 return;
91 }
Ed Tanous14766872022-03-15 10:44:42 -070092
93 asyncResp->res.jsonValue["@odata.type"] =
94 "#PCIeDeviceCollection.PCIeDeviceCollection";
95 asyncResp->res.jsonValue["@odata.id"] =
96 "/redfish/v1/Systems/system/PCIeDevices";
97 asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
98 asyncResp->res.jsonValue["Description"] =
99 "Collection of PCIe Devices";
100 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
101 asyncResp->res.jsonValue["Members@odata.count"] = 0;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700102 getPCIeDeviceList(asyncResp, "Members");
103 });
104}
105
Spencer Ku62cd45a2021-11-22 16:41:25 +0800106inline std::optional<std::string>
107 redfishPcieGenerationFromDbus(const std::string& generationInUse)
108{
109 if (generationInUse ==
110 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
111 {
112 return "Gen1";
113 }
114 if (generationInUse ==
115 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
116 {
117 return "Gen2";
118 }
119 if (generationInUse ==
120 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
121 {
122 return "Gen3";
123 }
124 if (generationInUse ==
125 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
126 {
127 return "Gen4";
128 }
129 if (generationInUse ==
130 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
131 {
132 return "Gen5";
133 }
134 if (generationInUse.empty() ||
135 generationInUse ==
136 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
137 {
138 return "";
139 }
140
141 // The value is not unknown or Gen1-5, need return an internal error.
142 return std::nullopt;
143}
144
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700145inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800146{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700147 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700148 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700149 .methods(
150 boost::beast::http::verb::
151 get)([&app](const crow::Request& req,
152 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
153 const std::string& device) {
154 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700155 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700156 return;
157 }
158 auto getPCIeDeviceCallback =
159 [asyncResp, device](
160 const boost::system::error_code ec,
161 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
162 if (ec)
163 {
164 BMCWEB_LOG_DEBUG
165 << "failed to get PCIe Device properties ec: "
166 << ec.value() << ": " << ec.message();
167 if (ec.value() ==
168 boost::system::linux_error::bad_request_descriptor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700169 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700170 messages::resourceNotFound(asyncResp->res,
171 "PCIeDevice", device);
172 }
173 else
174 {
175 messages::internalError(asyncResp->res);
176 }
177 return;
178 }
179
Ed Tanous14766872022-03-15 10:44:42 -0700180 asyncResp->res.jsonValue["@odata.type"] =
181 "#PCIeDevice.v1_4_0.PCIeDevice";
182 asyncResp->res.jsonValue["@odata.id"] =
183 "/redfish/v1/Systems/system/PCIeDevices/" + device;
184 asyncResp->res.jsonValue["Name"] = "PCIe Device";
185 asyncResp->res.jsonValue["Id"] = device;
186
187 asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
188 "/redfish/v1/Systems/system/PCIeDevices/" + device +
189 "/PCIeFunctions";
Ed Tanous45ca1b82022-03-25 13:07:27 -0700190 for (const auto& property : pcieDevProperties)
191 {
192 const std::string* propertyString =
193 std::get_if<std::string>(&property.second);
194 if (property.first == "Manufacturer")
195 {
196 if (propertyString == nullptr)
Ed Tanous168e20c2021-12-13 14:39:53 -0800197 {
198 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700199 return;
Ed Tanous168e20c2021-12-13 14:39:53 -0800200 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700201 asyncResp->res.jsonValue["Manufacturer"] =
202 *propertyString;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800203 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700204 if (property.first == "DeviceType")
Ed Tanousb9d36b42022-02-26 21:42:46 -0800205 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700206 if (propertyString == nullptr)
Ed Tanousb9d36b42022-02-26 21:42:46 -0800207 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700208 messages::internalError(asyncResp->res);
209 return;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800210 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700211 asyncResp->res.jsonValue["DeviceType"] =
212 *propertyString;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800213 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700214 if (property.first == "GenerationInUse")
215 {
216 if (propertyString == nullptr)
217 {
218 messages::internalError(asyncResp->res);
219 return;
220 }
221 std::optional<std::string> generationInUse =
222 redfishPcieGenerationFromDbus(*propertyString);
223 if (!generationInUse)
224 {
225 messages::internalError(asyncResp->res);
226 return;
227 }
228 if (generationInUse->empty())
229 {
230 // unknown, no need to handle
231 return;
232 }
233 asyncResp->res
234 .jsonValue["PCIeInterface"]["PCIeType"] =
235 *generationInUse;
236 }
237 }
238 };
239 std::string escapedPath = std::string(pciePath) + "/" + device;
240 dbus::utility::escapePathForDbus(escapedPath);
241 crow::connections::systemBus->async_method_call(
242 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
243 "org.freedesktop.DBus.Properties", "GetAll",
244 pcieDeviceInterface);
245 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700246}
247
248inline void requestRoutesSystemPCIeFunctionCollection(App& app)
249{
250 /**
251 * Functions triggers appropriate requests on DBus
252 */
253 BMCWEB_ROUTE(app,
254 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700255 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700256 .methods(
257 boost::beast::http::verb::
258 get)([&app](const crow::Request& req,
259 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
260 const std::string& device) {
261 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700262 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700263 return;
264 }
Ed Tanous14766872022-03-15 10:44:42 -0700265
266 asyncResp->res.jsonValue["@odata.type"] =
267 "#PCIeFunctionCollection.PCIeFunctionCollection";
268 asyncResp->res.jsonValue["@odata.id"] =
269 "/redfish/v1/Systems/system/PCIeDevices/" + device +
270 "/PCIeFunctions";
271 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
272 asyncResp->res.jsonValue["Description"] =
273 "Collection of PCIe Functions for PCIe Device " + device;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700274
Ed Tanous45ca1b82022-03-25 13:07:27 -0700275 auto getPCIeDeviceCallback =
276 [asyncResp, device](
277 const boost::system::error_code ec,
278 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
279 if (ec)
280 {
281 BMCWEB_LOG_DEBUG
282 << "failed to get PCIe Device properties ec: "
283 << ec.value() << ": " << ec.message();
284 if (ec.value() ==
285 boost::system::linux_error::bad_request_descriptor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700286 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700287 messages::resourceNotFound(asyncResp->res,
288 "PCIeDevice", device);
289 }
290 else
291 {
292 messages::internalError(asyncResp->res);
293 }
294 return;
295 }
296
297 nlohmann::json& pcieFunctionList =
298 asyncResp->res.jsonValue["Members"];
299 pcieFunctionList = nlohmann::json::array();
300 static constexpr const int maxPciFunctionNum = 8;
301 for (int functionNum = 0; functionNum < maxPciFunctionNum;
302 functionNum++)
303 {
304 // Check if this function exists by looking for a
305 // device ID
306 std::string devIDProperty =
307 "Function" + std::to_string(functionNum) +
308 "DeviceId";
309 const std::string* property = nullptr;
310 for (const auto& propEntry : pcieDevProperties)
311 {
312 if (propEntry.first == devIDProperty)
Ed Tanousb9d36b42022-02-26 21:42:46 -0800313 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700314 property =
315 std::get_if<std::string>(&propEntry.second);
Ed Tanousb9d36b42022-02-26 21:42:46 -0800316 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700317 }
318 if (property == nullptr || !property->empty())
319 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800320 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700321 }
Ed Tanous14766872022-03-15 10:44:42 -0700322 nlohmann::json::object_t pcieFunction;
323 pcieFunction["@odata.id"] =
324 "/redfish/v1/Systems/system/PCIeDevices/" + device +
325 "/PCIeFunctions/" + std::to_string(functionNum);
326 pcieFunctionList.push_back(std::move(pcieFunction));
Ed Tanous45ca1b82022-03-25 13:07:27 -0700327 }
328 asyncResp->res.jsonValue["Members@odata.count"] =
329 pcieFunctionList.size();
330 };
331 std::string escapedPath = std::string(pciePath) + "/" + device;
332 dbus::utility::escapePathForDbus(escapedPath);
333 crow::connections::systemBus->async_method_call(
334 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
335 "org.freedesktop.DBus.Properties", "GetAll",
336 pcieDeviceInterface);
337 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700338}
339
340inline void requestRoutesSystemPCIeFunction(App& app)
341{
342 BMCWEB_ROUTE(
343 app,
344 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700345 .privileges(redfish::privileges::getPCIeFunction)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700346 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700347 boost::beast::http::verb::
348 get)([&app](const crow::Request& req,
349 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
350 const std::string& device,
351 const std::string& function) {
352 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
353 {
354 return;
355 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800356 auto getPCIeDeviceCallback =
357 [asyncResp, device, function](
358 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800359 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanous168e20c2021-12-13 14:39:53 -0800360 if (ec)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800361 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800362 BMCWEB_LOG_DEBUG
363 << "failed to get PCIe Device properties ec: "
364 << ec.value() << ": " << ec.message();
365 if (ec.value() ==
366 boost::system::linux_error::bad_request_descriptor)
367 {
368 messages::resourceNotFound(asyncResp->res,
369 "PCIeDevice", device);
370 }
371 else
372 {
373 messages::internalError(asyncResp->res);
374 }
375 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800376 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800377
Ed Tanous14766872022-03-15 10:44:42 -0700378 // Check if this function exists by looking for a device
379 // ID
Ed Tanousb9d36b42022-02-26 21:42:46 -0800380 std::string functionName = "Function" + function;
381 std::string devIDProperty = functionName + "DeviceId";
382
383 const std::string* devIdProperty = nullptr;
384 for (const auto& property : pcieDevProperties)
385 {
386 if (property.first == devIDProperty)
387 {
388 devIdProperty =
389 std::get_if<std::string>(&property.second);
390 continue;
391 }
392 }
393 if (devIdProperty == nullptr || !devIdProperty->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800394 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800395 messages::resourceNotFound(asyncResp->res,
396 "PCIeFunction", function);
397 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800398 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800399
Ed Tanous14766872022-03-15 10:44:42 -0700400 asyncResp->res.jsonValue["@odata.type"] =
401 "#PCIeFunction.v1_2_0.PCIeFunction";
402 asyncResp->res.jsonValue["@odata.id"] =
403 "/redfish/v1/Systems/system/PCIeDevices/" + device +
404 "/PCIeFunctions/" + function;
405 asyncResp->res.jsonValue["Name"] = "PCIe Function";
406 asyncResp->res.jsonValue["Id"] = function;
407 asyncResp->res.jsonValue["FunctionId"] =
408 std::stoi(function);
409 asyncResp->res
410 .jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
411 "/redfish/v1/Systems/system/PCIeDevices/" + device;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700412
Ed Tanousb9d36b42022-02-26 21:42:46 -0800413 for (const auto& property : pcieDevProperties)
Ed Tanous168e20c2021-12-13 14:39:53 -0800414 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800415 const std::string* strProperty =
416 std::get_if<std::string>(&property.second);
417 if (property.first == functionName + "DeviceId")
418 {
419 asyncResp->res.jsonValue["DeviceId"] = *strProperty;
420 }
421 if (property.first == functionName + "VendorId")
422 {
423 asyncResp->res.jsonValue["VendorId"] = *strProperty;
424 }
425 if (property.first == functionName + "FunctionType")
426 {
427 asyncResp->res.jsonValue["FunctionType"] =
428 *strProperty;
429 }
430 if (property.first == functionName + "DeviceClass")
431 {
432 asyncResp->res.jsonValue["DeviceClass"] =
433 *strProperty;
434 }
435 if (property.first == functionName + "ClassCode")
436 {
437 asyncResp->res.jsonValue["ClassCode"] =
438 *strProperty;
439 }
440 if (property.first == functionName + "RevisionId")
441 {
442 asyncResp->res.jsonValue["RevisionId"] =
443 *strProperty;
444 }
445 if (property.first == functionName + "SubsystemId")
446 {
447 asyncResp->res.jsonValue["SubsystemId"] =
448 *strProperty;
449 }
450 if (property.first ==
451 functionName + "SubsystemVendorId")
452 {
453 asyncResp->res.jsonValue["SubsystemVendorId"] =
454 *strProperty;
455 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800456 }
457 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700458 std::string escapedPath = std::string(pciePath) + "/" + device;
459 dbus::utility::escapePathForDbus(escapedPath);
460 crow::connections::systemBus->async_method_call(
461 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
462 "org.freedesktop.DBus.Properties", "GetAll",
463 pcieDeviceInterface);
464 });
465}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800466
467} // namespace redfish