blob: 327e79e4590c24a87d8740baf3b86c2379822ab0 [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>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020024#include <sdbusplus/asio/property.hpp>
25#include <sdbusplus/unpack_properties.hpp>
26#include <utils/dbus_utils.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080027
28namespace redfish
29{
30
Gunnar Mills1214b7e2020-06-04 10:11:30 -050031static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
32static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
33static constexpr char const* pcieDeviceInterface =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080034 "xyz.openbmc_project.PCIe.Device";
35
Ed Tanousb5a76932020-09-29 16:16:58 -070036static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080037 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -070038 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080039{
Ed Tanousb9d36b42022-02-26 21:42:46 -080040 auto getPCIeMapCallback =
41 [asyncResp, name](const boost::system::error_code ec,
42 const dbus::utility::MapperGetSubTreePathsResponse&
43 pcieDevicePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -070044 if (ec)
45 {
46 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
47 << ec.message();
48 // Not an error, system just doesn't have PCIe info
49 return;
50 }
51 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
52 pcieDeviceList = nlohmann::json::array();
53 for (const std::string& pcieDevicePath : pcieDevicePaths)
54 {
55 size_t devStart = pcieDevicePath.rfind('/');
56 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080057 {
Ed Tanous002d39b2022-05-31 08:59:27 -070058 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080059 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080060
Ed Tanous002d39b2022-05-31 08:59:27 -070061 std::string devName = pcieDevicePath.substr(devStart + 1);
62 if (devName.empty())
63 {
64 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080065 }
Ed Tanous002d39b2022-05-31 08:59:27 -070066 nlohmann::json::object_t pcieDevice;
67 pcieDevice["@odata.id"] =
68 "/redfish/v1/Systems/system/PCIeDevices/" + devName;
69 pcieDeviceList.push_back(std::move(pcieDevice));
70 }
71 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
72 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080073 crow::connections::systemBus->async_method_call(
74 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
75 "/xyz/openbmc_project/object_mapper",
76 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
77 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
78}
79
John Edward Broadbent7e860f12021-04-08 15:57:16 -070080inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -070081{
Jason M. Billsadbe1922019-10-14 15:44:35 -070082 /**
83 * Functions triggers appropriate requests on DBus
84 */
Ed Tanous22d268c2022-05-19 09:39:07 -070085 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -070086 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070087 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -070088 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -070089 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
90 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +000091 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070092 {
93 return;
94 }
Ed Tanous22d268c2022-05-19 09:39:07 -070095 if (systemName != "system")
96 {
97 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
98 systemName);
99 return;
100 }
Ed Tanous14766872022-03-15 10:44:42 -0700101
Ed Tanous002d39b2022-05-31 08:59:27 -0700102 asyncResp->res.jsonValue["@odata.type"] =
103 "#PCIeDeviceCollection.PCIeDeviceCollection";
104 asyncResp->res.jsonValue["@odata.id"] =
105 "/redfish/v1/Systems/system/PCIeDevices";
106 asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
107 asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
108 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
109 asyncResp->res.jsonValue["Members@odata.count"] = 0;
110 getPCIeDeviceList(asyncResp, "Members");
111 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700112}
113
Spencer Ku62cd45a2021-11-22 16:41:25 +0800114inline std::optional<std::string>
115 redfishPcieGenerationFromDbus(const std::string& generationInUse)
116{
117 if (generationInUse ==
118 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
119 {
120 return "Gen1";
121 }
122 if (generationInUse ==
123 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
124 {
125 return "Gen2";
126 }
127 if (generationInUse ==
128 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
129 {
130 return "Gen3";
131 }
132 if (generationInUse ==
133 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
134 {
135 return "Gen4";
136 }
137 if (generationInUse ==
138 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
139 {
140 return "Gen5";
141 }
Ed Tanouse825cbc2022-06-17 11:39:22 -0700142 if (generationInUse.empty() ||
143 generationInUse ==
144 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800145 {
146 return "";
147 }
148
149 // The value is not unknown or Gen1-5, need return an internal error.
150 return std::nullopt;
151}
152
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700153inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800154{
Ed Tanous22d268c2022-05-19 09:39:07 -0700155 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700156 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700157 .methods(boost::beast::http::verb::get)(
158 [&app](const crow::Request& req,
159 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -0700160 const std::string& systemName, const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000161 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 {
163 return;
164 }
Ed Tanous22d268c2022-05-19 09:39:07 -0700165 if (systemName != "system")
166 {
167 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
168 systemName);
169 return;
170 }
171
Ed Tanous002d39b2022-05-31 08:59:27 -0700172 auto getPCIeDeviceCallback =
173 [asyncResp, device](
174 const boost::system::error_code ec,
175 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
176 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700177 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 BMCWEB_LOG_DEBUG
179 << "failed to get PCIe Device properties ec: " << ec.value()
180 << ": " << ec.message();
181 if (ec.value() ==
182 boost::system::linux_error::bad_request_descriptor)
183 {
184 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
185 device);
186 }
187 else
188 {
189 messages::internalError(asyncResp->res);
190 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700191 return;
192 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700193
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200194 const std::string* manufacturer = nullptr;
195 const std::string* deviceType = nullptr;
196 const std::string* generationInUse = nullptr;
197
198 const bool success = sdbusplus::unpackPropertiesNoThrow(
199 dbus_utils::UnpackErrorPrinter(), pcieDevProperties,
200 "Manufacturer", manufacturer, "DeviceType", deviceType,
201 "GenerationInUse", generationInUse);
202
203 if (!success)
204 {
205 messages::internalError(asyncResp->res);
206 return;
207 }
208
209 if (generationInUse != nullptr)
210 {
211 std::optional<std::string> redfishGenerationInUse =
212 redfishPcieGenerationFromDbus(*generationInUse);
213 if (!redfishGenerationInUse)
214 {
215 messages::internalError(asyncResp->res);
216 return;
217 }
218 if (redfishGenerationInUse->empty())
219 {
220 // unknown, no need to handle
221 return;
222 }
223 asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
224 *redfishGenerationInUse;
225 }
226
227 if (manufacturer != nullptr)
228 {
229 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
230 }
231
232 if (deviceType != nullptr)
233 {
234 asyncResp->res.jsonValue["DeviceType"] = *deviceType;
235 }
236
Ed Tanous002d39b2022-05-31 08:59:27 -0700237 asyncResp->res.jsonValue["@odata.type"] =
238 "#PCIeDevice.v1_4_0.PCIeDevice";
239 asyncResp->res.jsonValue["@odata.id"] =
240 "/redfish/v1/Systems/system/PCIeDevices/" + device;
241 asyncResp->res.jsonValue["Name"] = "PCIe Device";
242 asyncResp->res.jsonValue["Id"] = device;
243
244 asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
245 "/redfish/v1/Systems/system/PCIeDevices/" + device +
246 "/PCIeFunctions";
Ed Tanous002d39b2022-05-31 08:59:27 -0700247 };
248 std::string escapedPath = std::string(pciePath) + "/" + device;
249 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200250 sdbusplus::asio::getAllProperties(
251 *crow::connections::systemBus, pcieService, escapedPath,
252 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
Ed Tanous45ca1b82022-03-25 13:07:27 -0700253 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700254}
255
256inline void requestRoutesSystemPCIeFunctionCollection(App& app)
257{
258 /**
259 * Functions triggers appropriate requests on DBus
260 */
261 BMCWEB_ROUTE(app,
262 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700263 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700264 .methods(boost::beast::http::verb::get)(
265 [&app](const crow::Request& req,
266 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
267 const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000268 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700269 {
270 return;
271 }
272
273 asyncResp->res.jsonValue["@odata.type"] =
274 "#PCIeFunctionCollection.PCIeFunctionCollection";
275 asyncResp->res.jsonValue["@odata.id"] =
276 "/redfish/v1/Systems/system/PCIeDevices/" + device +
277 "/PCIeFunctions";
278 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
279 asyncResp->res.jsonValue["Description"] =
280 "Collection of PCIe Functions for PCIe Device " + device;
281
282 auto getPCIeDeviceCallback =
283 [asyncResp, device](
284 const boost::system::error_code ec,
285 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
286 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700287 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700288 BMCWEB_LOG_DEBUG
289 << "failed to get PCIe Device properties ec: " << ec.value()
290 << ": " << ec.message();
291 if (ec.value() ==
292 boost::system::linux_error::bad_request_descriptor)
293 {
294 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
295 device);
296 }
297 else
298 {
299 messages::internalError(asyncResp->res);
300 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700301 return;
302 }
Ed Tanous14766872022-03-15 10:44:42 -0700303
Ed Tanous002d39b2022-05-31 08:59:27 -0700304 nlohmann::json& pcieFunctionList =
305 asyncResp->res.jsonValue["Members"];
306 pcieFunctionList = nlohmann::json::array();
307 static constexpr const int maxPciFunctionNum = 8;
308 for (int functionNum = 0; functionNum < maxPciFunctionNum;
309 functionNum++)
310 {
311 // Check if this function exists by looking for a
312 // device ID
313 std::string devIDProperty =
314 "Function" + std::to_string(functionNum) + "DeviceId";
315 const std::string* property = nullptr;
316 for (const auto& propEntry : pcieDevProperties)
317 {
318 if (propEntry.first == devIDProperty)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700319 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700320 property = std::get_if<std::string>(&propEntry.second);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700321 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 }
Nan Zhoufb0ecc32022-10-17 19:17:36 +0000323 if (property == nullptr || property->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -0700324 {
Nan Zhoue28ce0e2022-10-13 22:28:36 +0000325 continue;
Ed Tanous002d39b2022-05-31 08:59:27 -0700326 }
327 nlohmann::json::object_t pcieFunction;
328 pcieFunction["@odata.id"] =
329 "/redfish/v1/Systems/system/PCIeDevices/" + device +
330 "/PCIeFunctions/" + std::to_string(functionNum);
331 pcieFunctionList.push_back(std::move(pcieFunction));
332 }
333 asyncResp->res.jsonValue["Members@odata.count"] =
334 pcieFunctionList.size();
335 };
336 std::string escapedPath = std::string(pciePath) + "/" + device;
337 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200338 sdbusplus::asio::getAllProperties(
339 *crow::connections::systemBus, pcieService, escapedPath,
340 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
Ed Tanous45ca1b82022-03-25 13:07:27 -0700341 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700342}
343
344inline void requestRoutesSystemPCIeFunction(App& app)
345{
346 BMCWEB_ROUTE(
347 app,
348 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700349 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700350 .methods(boost::beast::http::verb::get)(
351 [&app](const crow::Request& req,
352 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
353 const std::string& device, const std::string& function) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000354 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700355 {
356 return;
357 }
358 auto getPCIeDeviceCallback =
359 [asyncResp, device, function](
360 const boost::system::error_code ec,
361 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
362 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700363 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700364 BMCWEB_LOG_DEBUG
365 << "failed to get PCIe Device properties ec: " << ec.value()
366 << ": " << ec.message();
367 if (ec.value() ==
368 boost::system::linux_error::bad_request_descriptor)
369 {
370 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
371 device);
372 }
373 else
374 {
375 messages::internalError(asyncResp->res);
376 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700377 return;
378 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800379
Ed Tanous002d39b2022-05-31 08:59:27 -0700380 // Check if this function exists by looking for a device
381 // ID
382 std::string functionName = "Function" + function;
383 std::string devIDProperty = functionName + "DeviceId";
Ed Tanousb9d36b42022-02-26 21:42:46 -0800384
Ed Tanous002d39b2022-05-31 08:59:27 -0700385 const std::string* devIdProperty = nullptr;
386 for (const auto& property : pcieDevProperties)
387 {
388 if (property.first == devIDProperty)
389 {
390 devIdProperty = std::get_if<std::string>(&property.second);
391 continue;
392 }
393 }
394 if (devIdProperty == nullptr || !devIdProperty->empty())
395 {
396 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
397 function);
398 return;
399 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800400
Ed Tanous002d39b2022-05-31 08:59:27 -0700401 asyncResp->res.jsonValue["@odata.type"] =
402 "#PCIeFunction.v1_2_0.PCIeFunction";
403 asyncResp->res.jsonValue["@odata.id"] =
404 "/redfish/v1/Systems/system/PCIeDevices/" + device +
405 "/PCIeFunctions/" + function;
406 asyncResp->res.jsonValue["Name"] = "PCIe Function";
407 asyncResp->res.jsonValue["Id"] = function;
408 asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
409 asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
410 "/redfish/v1/Systems/system/PCIeDevices/" + device;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700411
Ed Tanous002d39b2022-05-31 08:59:27 -0700412 for (const auto& property : pcieDevProperties)
413 {
414 const std::string* strProperty =
415 std::get_if<std::string>(&property.second);
416 if (property.first == functionName + "DeviceId")
417 {
418 asyncResp->res.jsonValue["DeviceId"] = *strProperty;
419 }
420 if (property.first == functionName + "VendorId")
421 {
422 asyncResp->res.jsonValue["VendorId"] = *strProperty;
423 }
424 if (property.first == functionName + "FunctionType")
425 {
426 asyncResp->res.jsonValue["FunctionType"] = *strProperty;
427 }
428 if (property.first == functionName + "DeviceClass")
429 {
430 asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
431 }
432 if (property.first == functionName + "ClassCode")
433 {
434 asyncResp->res.jsonValue["ClassCode"] = *strProperty;
435 }
436 if (property.first == functionName + "RevisionId")
437 {
438 asyncResp->res.jsonValue["RevisionId"] = *strProperty;
439 }
440 if (property.first == functionName + "SubsystemId")
441 {
442 asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
443 }
444 if (property.first == functionName + "SubsystemVendorId")
445 {
446 asyncResp->res.jsonValue["SubsystemVendorId"] =
447 *strProperty;
448 }
449 }
450 };
451 std::string escapedPath = std::string(pciePath) + "/" + device;
452 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200453 sdbusplus::asio::getAllProperties(
454 *crow::connections::systemBus, pcieService, escapedPath,
455 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700456 });
457}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800458
459} // namespace redfish