blob: a715acd0166b2de71cb3e9ff63493d209801ce1b [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080019#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070021#include "generated/enums/pcie_device.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080022#include "query.hpp"
23#include "registries/privilege_registry.hpp"
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -060024#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080025#include "utils/dbus_utils.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070026
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080027#include <boost/system/linux_error.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020028#include <sdbusplus/asio/property.hpp>
29#include <sdbusplus/unpack_properties.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080030
31namespace redfish
32{
33
Gunnar Mills1214b7e2020-06-04 10:11:30 -050034static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
35static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
36static constexpr char const* pcieDeviceInterface =
Lakshmi Yadlapatib8f38ea2023-03-30 08:23:48 -050037 "xyz.openbmc_project.Inventory.Item.PCIeDevice";
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080038
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060039static inline void handlePCIeDevicePath(
40 const std::string& pcieDeviceId,
41 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
42 const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
43 const std::function<void(const std::string& pcieDevicePath,
44 const std::string& service)>& callback)
45
46{
47 for (const std::string& pcieDevicePath : pcieDevicePaths)
48 {
49 std::string pciecDeviceName =
50 sdbusplus::message::object_path(pcieDevicePath).filename();
51 if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
52 {
53 continue;
54 }
55
56 dbus::utility::getDbusObject(
57 pcieDevicePath, {},
58 [pcieDevicePath, aResp,
59 callback](const boost::system::error_code& ec,
60 const dbus::utility::MapperGetObject& object) {
61 if (ec || object.empty())
62 {
63 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
64 messages::internalError(aResp->res);
65 return;
66 }
67 callback(pcieDevicePath, object.begin()->first);
68 });
69 return;
70 }
71
72 BMCWEB_LOG_WARNING << "PCIe Device not found";
73 messages::resourceNotFound(aResp->res, "PCIeDevice", pcieDeviceId);
74}
75
76static inline void getValidPCIeDevicePath(
77 const std::string& pcieDeviceId,
78 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
79 const std::function<void(const std::string& pcieDevicePath,
80 const std::string& service)>& callback)
81{
82 constexpr std::array<std::string_view, 1> interfaces{
83 "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
84
85 dbus::utility::getSubTreePaths(
86 "/xyz/openbmc_project/inventory", 0, interfaces,
87 [pcieDeviceId, aResp,
88 callback](const boost::system::error_code& ec,
89 const dbus::utility::MapperGetSubTreePathsResponse&
90 pcieDevicePaths) {
91 if (ec)
92 {
93 BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
94 messages::internalError(aResp->res);
95 return;
96 }
97 handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback);
98 return;
99 });
100}
101
Ed Tanousb5a76932020-09-29 16:16:58 -0700102static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +0800103 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -0700104 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800105{
George Liu7a1dbc42022-12-07 16:03:22 +0800106 dbus::utility::getSubTreePaths(
107 pciePath, 1, {},
108 [asyncResp, name](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800109 const dbus::utility::MapperGetSubTreePathsResponse&
110 pcieDevicePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700111 if (ec)
112 {
113 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
114 << ec.message();
115 // Not an error, system just doesn't have PCIe info
116 return;
117 }
118 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
119 pcieDeviceList = nlohmann::json::array();
120 for (const std::string& pcieDevicePath : pcieDevicePaths)
121 {
122 size_t devStart = pcieDevicePath.rfind('/');
123 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800124 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700125 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800126 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800127
Ed Tanous002d39b2022-05-31 08:59:27 -0700128 std::string devName = pcieDevicePath.substr(devStart + 1);
129 if (devName.empty())
130 {
131 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800132 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700133 nlohmann::json::object_t pcieDevice;
Willy Tueddfc432022-09-26 16:46:38 +0000134 pcieDevice["@odata.id"] = crow::utility::urlFromPieces(
135 "redfish", "v1", "Systems", "system", "PCIeDevices", devName);
Ed Tanous002d39b2022-05-31 08:59:27 -0700136 pcieDeviceList.push_back(std::move(pcieDevice));
137 }
138 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
George Liu7a1dbc42022-12-07 16:03:22 +0800139 });
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800140}
141
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600142static inline void handlePCIeDeviceCollectionGet(
143 crow::App& app, const crow::Request& req,
144 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
145 const std::string& systemName)
146{
147 if (!redfish::setUpRedfishRoute(app, req, aResp))
148 {
149 return;
150 }
151 if (systemName != "system")
152 {
153 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
154 return;
155 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600156
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600157 aResp->res.addHeader(boost::beast::http::field::link,
158 "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
159 "PCIeDeviceCollection.json>; rel=describedby");
160 aResp->res.jsonValue["@odata.type"] =
161 "#PCIeDeviceCollection.PCIeDeviceCollection";
162 aResp->res.jsonValue["@odata.id"] =
163 "/redfish/v1/Systems/system/PCIeDevices";
164 aResp->res.jsonValue["Name"] = "PCIe Device Collection";
165 aResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
166 aResp->res.jsonValue["Members"] = nlohmann::json::array();
167 aResp->res.jsonValue["Members@odata.count"] = 0;
168
169 constexpr std::array<std::string_view, 1> interfaces{
170 "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
171 collection_util::getCollectionMembers(
172 aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
173 interfaces);
174}
175
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700176inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -0700177{
Jason M. Billsadbe1922019-10-14 15:44:35 -0700178 /**
179 * Functions triggers appropriate requests on DBus
180 */
Ed Tanous22d268c2022-05-19 09:39:07 -0700181 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -0700182 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700183 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600184 std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700185}
186
Ed Tanous0ec8b832022-03-14 14:56:47 -0700187inline std::optional<pcie_device::PCIeTypes>
Spencer Ku62cd45a2021-11-22 16:41:25 +0800188 redfishPcieGenerationFromDbus(const std::string& generationInUse)
189{
190 if (generationInUse ==
191 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
192 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700193 return pcie_device::PCIeTypes::Gen1;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800194 }
195 if (generationInUse ==
196 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
197 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700198 return pcie_device::PCIeTypes::Gen2;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800199 }
200 if (generationInUse ==
201 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
202 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700203 return pcie_device::PCIeTypes::Gen3;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800204 }
205 if (generationInUse ==
206 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
207 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700208 return pcie_device::PCIeTypes::Gen4;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800209 }
210 if (generationInUse ==
211 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
212 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700213 return pcie_device::PCIeTypes::Gen5;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800214 }
Ed Tanouse825cbc2022-06-17 11:39:22 -0700215 if (generationInUse.empty() ||
216 generationInUse ==
217 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800218 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700219 return pcie_device::PCIeTypes::Invalid;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800220 }
221
222 // The value is not unknown or Gen1-5, need return an internal error.
223 return std::nullopt;
224}
225
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600226inline void getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
227 const std::string& pcieDevicePath,
228 const std::string& service)
229{
230 sdbusplus::asio::getAllProperties(
231 *crow::connections::systemBus, service, pcieDevicePath,
232 "xyz.openbmc_project.Inventory.Decorator.Asset",
233 [pcieDevicePath,
234 aResp{aResp}](const boost::system::error_code& ec,
235 const dbus::utility::DBusPropertiesMap& assetList) {
236 if (ec)
237 {
238 if (ec.value() != EBADR)
239 {
240 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
241 << ec.value();
242 messages::internalError(aResp->res);
243 }
244 return;
245 }
246
247 const std::string* manufacturer = nullptr;
248 const std::string* model = nullptr;
249 const std::string* partNumber = nullptr;
250 const std::string* serialNumber = nullptr;
251 const std::string* sparePartNumber = nullptr;
252
253 const bool success = sdbusplus::unpackPropertiesNoThrow(
254 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
255 manufacturer, "Model", model, "PartNumber", partNumber,
256 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
257
258 if (!success)
259 {
260 messages::internalError(aResp->res);
261 return;
262 }
263
264 if (manufacturer != nullptr)
265 {
266 aResp->res.jsonValue["Manufacturer"] = *manufacturer;
267 }
268 if (model != nullptr)
269 {
270 aResp->res.jsonValue["Model"] = *model;
271 }
272
273 if (partNumber != nullptr)
274 {
275 aResp->res.jsonValue["PartNumber"] = *partNumber;
276 }
277
278 if (serialNumber != nullptr)
279 {
280 aResp->res.jsonValue["SerialNumber"] = *serialNumber;
281 }
282
283 if (sparePartNumber != nullptr && !sparePartNumber->empty())
284 {
285 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
286 }
287 });
288}
289
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600290inline void addPCIeDeviceProperties(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600291 crow::Response& resp, const std::string& pcieDeviceId,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600292 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
293{
294 const std::string* manufacturer = nullptr;
295 const std::string* deviceType = nullptr;
296 const std::string* generationInUse = nullptr;
297 const int64_t* lanesInUse = nullptr;
298
299 const bool success = sdbusplus::unpackPropertiesNoThrow(
300 dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
301 deviceType, "GenerationInUse", generationInUse, "LanesInUse",
302 lanesInUse, "Manufacturer", manufacturer);
303
304 if (!success)
305 {
306 messages::internalError(resp);
307 return;
308 }
309
310 if (deviceType != nullptr && !deviceType->empty())
311 {
312 resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
313 }
314
315 if (generationInUse != nullptr)
316 {
317 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
318 redfishPcieGenerationFromDbus(*generationInUse);
319
320 if (!redfishGenerationInUse)
321 {
322 messages::internalError(resp);
323 return;
324 }
325 if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
326 {
327 resp.jsonValue["PCIeInterface"]["PCIeType"] =
328 *redfishGenerationInUse;
329 }
330 }
331
332 // The default value of LanesInUse is 0, and the field will be
333 // left as off if it is a default value.
334 if (lanesInUse != nullptr && *lanesInUse != 0)
335 {
336 resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
337 }
338
339 if (manufacturer != nullptr)
340 {
341 resp.jsonValue["PCIeInterface"]["Manufacturer"] = *manufacturer;
342 }
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600343
344 resp.jsonValue["PCIeFunctions"]["@odata.id"] = crow::utility::urlFromPieces(
345 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
346 "PCIeFunctions");
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600347}
348
349inline void getPCIeDeviceProperties(
350 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
351 const std::string& pcieDevicePath, const std::string& service,
352 const std::function<void(
353 const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
354{
355 sdbusplus::asio::getAllProperties(
356 *crow::connections::systemBus, service, pcieDevicePath,
357 "xyz.openbmc_project.Inventory.Item.PCIeDevice",
358 [aResp,
359 callback](const boost::system::error_code& ec,
360 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
361 if (ec)
362 {
363 if (ec.value() != EBADR)
364 {
365 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
366 messages::internalError(aResp->res);
367 }
368 return;
369 }
370 callback(pcieDevProperties);
371 });
372}
373
374inline void addPCIeDeviceCommonProperties(
375 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
376 const std::string& pcieDeviceId)
377{
378 aResp->res.addHeader(
379 boost::beast::http::field::link,
380 "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
381 aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
382 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
383 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId);
384 aResp->res.jsonValue["Name"] = "PCIe Device";
385 aResp->res.jsonValue["Id"] = pcieDeviceId;
386}
387
388inline void handlePCIeDeviceGet(App& app, const crow::Request& req,
389 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
390 const std::string& systemName,
391 const std::string& pcieDeviceId)
392{
393 if (!redfish::setUpRedfishRoute(app, req, aResp))
394 {
395 return;
396 }
397 if (systemName != "system")
398 {
399 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
400 return;
401 }
402
403 getValidPCIeDevicePath(
404 pcieDeviceId, aResp,
405 [aResp, pcieDeviceId](const std::string& pcieDevicePath,
406 const std::string& service) {
407 addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600408 getPCIeDeviceAsset(aResp, pcieDevicePath, service);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600409 getPCIeDeviceProperties(
410 aResp, pcieDevicePath, service,
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600411 [aResp, pcieDeviceId](
412 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
413 addPCIeDeviceProperties(aResp->res, pcieDeviceId,
414 pcieDevProperties);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600415 });
416 });
417}
418
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700419inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800420{
Ed Tanous22d268c2022-05-19 09:39:07 -0700421 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700422 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700423 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600424 std::bind_front(handlePCIeDeviceGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700425}
426
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600427inline void addPCIeFunctionList(
428 crow::Response& res, const std::string& pcieDeviceId,
429 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
430{
431 nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
432 pcieFunctionList = nlohmann::json::array();
433 static constexpr const int maxPciFunctionNum = 8;
434
435 for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
436 {
437 // Check if this function exists by
438 // looking for a device ID
439 std::string devIDProperty =
440 "Function" + std::to_string(functionNum) + "DeviceId";
441 const std::string* property = nullptr;
442 for (const auto& propEntry : pcieDevProperties)
443 {
444 if (propEntry.first == devIDProperty)
445 {
446 property = std::get_if<std::string>(&propEntry.second);
447 break;
448 }
449 }
450 if (property == nullptr || property->empty())
451 {
452 continue;
453 }
454
455 nlohmann::json::object_t pcieFunction;
456 pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
457 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
458 "PCIeFunctions", std::to_string(functionNum));
459 pcieFunctionList.push_back(std::move(pcieFunction));
460 }
461 res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
462}
463
464inline void handlePCIeFunctionCollectionGet(
465 App& app, const crow::Request& req,
466 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
467 const std::string& pcieDeviceId)
468{
469 if (!redfish::setUpRedfishRoute(app, req, aResp))
470 {
471 return;
472 }
473
474 getValidPCIeDevicePath(
475 pcieDeviceId, aResp,
476 [aResp, pcieDeviceId](const std::string& pcieDevicePath,
477 const std::string& service) {
478 aResp->res.addHeader(
479 boost::beast::http::field::link,
480 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
481 aResp->res.jsonValue["@odata.type"] =
482 "#PCIeFunctionCollection.PCIeFunctionCollection";
483 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
484 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
485 "PCIeFunctions");
486 aResp->res.jsonValue["Name"] = "PCIe Function Collection";
487 aResp->res.jsonValue["Description"] =
488 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
489 getPCIeDeviceProperties(
490 aResp, pcieDevicePath, service,
491 [aResp, pcieDeviceId](
492 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
493 addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties);
494 });
495 });
496}
497
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700498inline void requestRoutesSystemPCIeFunctionCollection(App& app)
499{
500 /**
501 * Functions triggers appropriate requests on DBus
502 */
503 BMCWEB_ROUTE(app,
504 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700505 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700506 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600507 std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700508}
509
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600510inline bool validatePCIeFunctionId(
511 const std::string& pcieFunctionId,
512 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
513{
514 std::string functionName = "Function" + pcieFunctionId;
515 std::string devIDProperty = functionName + "DeviceId";
516
517 const std::string* devIdProperty = nullptr;
518 for (const auto& property : pcieDevProperties)
519 {
520 if (property.first == devIDProperty)
521 {
522 devIdProperty = std::get_if<std::string>(&property.second);
523 break;
524 }
525 }
526 return (devIdProperty != nullptr && !devIdProperty->empty());
527}
528
529inline void addPCIeFunctionProperties(
530 crow::Response& resp, const std::string& pcieFunctionId,
531 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
532{
533 std::string functionName = "Function" + pcieFunctionId;
534 if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties))
535 {
536 messages::resourceNotFound(resp, "PCIeFunction", pcieFunctionId);
537 return;
538 }
539 for (const auto& property : pcieDevProperties)
540 {
541 const std::string* strProperty =
542 std::get_if<std::string>(&property.second);
543
544 if (property.first == functionName + "DeviceId")
545 {
546 resp.jsonValue["DeviceId"] = *strProperty;
547 }
548 if (property.first == functionName + "VendorId")
549 {
550 resp.jsonValue["VendorId"] = *strProperty;
551 }
552 // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
553 // property strings should be mapped correctly to ensure these
554 // strings are Redfish enum values. For now just check for empty.
555 if (property.first == functionName + "FunctionType")
556 {
557 if (!strProperty->empty())
558 {
559 resp.jsonValue["FunctionType"] = *strProperty;
560 }
561 }
562 if (property.first == functionName + "DeviceClass")
563 {
564 if (!strProperty->empty())
565 {
566 resp.jsonValue["DeviceClass"] = *strProperty;
567 }
568 }
569 if (property.first == functionName + "ClassCode")
570 {
571 resp.jsonValue["ClassCode"] = *strProperty;
572 }
573 if (property.first == functionName + "RevisionId")
574 {
575 resp.jsonValue["RevisionId"] = *strProperty;
576 }
577 if (property.first == functionName + "SubsystemId")
578 {
579 resp.jsonValue["SubsystemId"] = *strProperty;
580 }
581 if (property.first == functionName + "SubsystemVendorId")
582 {
583 resp.jsonValue["SubsystemVendorId"] = *strProperty;
584 }
585 }
586}
587
588inline void addPCIeFunctionCommonProperties(crow::Response& resp,
589 const std::string& pcieDeviceId,
590 const std::string& pcieFunctionId)
591{
592 resp.addHeader(
593 boost::beast::http::field::link,
594 "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
595 resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
596 resp.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
597 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
598 "PCIeFunctions", pcieFunctionId);
599 resp.jsonValue["Name"] = "PCIe Function";
600 resp.jsonValue["Id"] = pcieFunctionId;
601 resp.jsonValue["FunctionId"] = std::stoi(pcieFunctionId);
602 resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
603 crow::utility::urlFromPieces("redfish", "v1", "Systems", "system",
604 "PCIeDevices", pcieDeviceId);
605}
606
607inline void
608 handlePCIeFunctionGet(App& app, const crow::Request& req,
609 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
610 const std::string& pcieDeviceId,
611 const std::string& pcieFunctionId)
612{
613 if (!redfish::setUpRedfishRoute(app, req, aResp))
614 {
615 return;
616 }
617
618 getValidPCIeDevicePath(
619 pcieDeviceId, aResp,
620 [aResp, pcieDeviceId, pcieFunctionId](const std::string& pcieDevicePath,
621 const std::string& service) {
622 getPCIeDeviceProperties(
623 aResp, pcieDevicePath, service,
624 [aResp, pcieDeviceId, pcieFunctionId](
625 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
626 addPCIeFunctionCommonProperties(aResp->res, pcieDeviceId,
627 pcieFunctionId);
628 addPCIeFunctionProperties(aResp->res, pcieFunctionId,
629 pcieDevProperties);
630 });
631 });
632}
633
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700634inline void requestRoutesSystemPCIeFunction(App& app)
635{
636 BMCWEB_ROUTE(
637 app,
638 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700639 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700640 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600641 std::bind_front(handlePCIeFunctionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700642}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800643
644} // namespace redfish