blob: 275421604c654b11ffc96bddf5fbe3d80613a855 [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
Patrick Williams89492a12023-05-10 07:51:34 -050034static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -050035static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
36 "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080037
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060038static inline void handlePCIeDevicePath(
39 const std::string& pcieDeviceId,
40 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
41 const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
42 const std::function<void(const std::string& pcieDevicePath,
43 const std::string& service)>& callback)
44
45{
46 for (const std::string& pcieDevicePath : pcieDevicePaths)
47 {
48 std::string pciecDeviceName =
49 sdbusplus::message::object_path(pcieDevicePath).filename();
50 if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
51 {
52 continue;
53 }
54
55 dbus::utility::getDbusObject(
56 pcieDevicePath, {},
57 [pcieDevicePath, aResp,
58 callback](const boost::system::error_code& ec,
59 const dbus::utility::MapperGetObject& object) {
60 if (ec || object.empty())
61 {
62 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
63 messages::internalError(aResp->res);
64 return;
65 }
66 callback(pcieDevicePath, object.begin()->first);
67 });
68 return;
69 }
70
71 BMCWEB_LOG_WARNING << "PCIe Device not found";
72 messages::resourceNotFound(aResp->res, "PCIeDevice", pcieDeviceId);
73}
74
75static inline void getValidPCIeDevicePath(
76 const std::string& pcieDeviceId,
77 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
78 const std::function<void(const std::string& pcieDevicePath,
79 const std::string& service)>& callback)
80{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060081 dbus::utility::getSubTreePaths(
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -050082 inventoryPath, 0, pcieDeviceInterface,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060083 [pcieDeviceId, aResp,
84 callback](const boost::system::error_code& ec,
85 const dbus::utility::MapperGetSubTreePathsResponse&
86 pcieDevicePaths) {
87 if (ec)
88 {
89 BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
90 messages::internalError(aResp->res);
91 return;
92 }
93 handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback);
94 return;
95 });
96}
97
Ed Tanousb5a76932020-09-29 16:16:58 -070098static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080099 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -0700100 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800101{
George Liu7a1dbc42022-12-07 16:03:22 +0800102 dbus::utility::getSubTreePaths(
Lakshmi Yadlapati38e3d672023-05-02 09:26:33 -0500103 inventoryPath, 0, pcieDeviceInterface,
George Liu7a1dbc42022-12-07 16:03:22 +0800104 [asyncResp, name](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800105 const dbus::utility::MapperGetSubTreePathsResponse&
106 pcieDevicePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700107 if (ec)
108 {
109 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
110 << ec.message();
111 // Not an error, system just doesn't have PCIe info
112 return;
113 }
114 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
115 pcieDeviceList = nlohmann::json::array();
116 for (const std::string& pcieDevicePath : pcieDevicePaths)
117 {
118 size_t devStart = pcieDevicePath.rfind('/');
119 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800120 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700121 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800122 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800123
Ed Tanous002d39b2022-05-31 08:59:27 -0700124 std::string devName = pcieDevicePath.substr(devStart + 1);
125 if (devName.empty())
126 {
127 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800128 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700129 nlohmann::json::object_t pcieDevice;
Willy Tueddfc432022-09-26 16:46:38 +0000130 pcieDevice["@odata.id"] = crow::utility::urlFromPieces(
131 "redfish", "v1", "Systems", "system", "PCIeDevices", devName);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500132 pcieDeviceList.emplace_back(std::move(pcieDevice));
Ed Tanous002d39b2022-05-31 08:59:27 -0700133 }
134 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
George Liu7a1dbc42022-12-07 16:03:22 +0800135 });
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800136}
137
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600138static inline void handlePCIeDeviceCollectionGet(
139 crow::App& app, const crow::Request& req,
140 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
141 const std::string& systemName)
142{
143 if (!redfish::setUpRedfishRoute(app, req, aResp))
144 {
145 return;
146 }
147 if (systemName != "system")
148 {
149 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
150 return;
151 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600152
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600153 aResp->res.addHeader(boost::beast::http::field::link,
154 "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
155 "PCIeDeviceCollection.json>; rel=describedby");
156 aResp->res.jsonValue["@odata.type"] =
157 "#PCIeDeviceCollection.PCIeDeviceCollection";
158 aResp->res.jsonValue["@odata.id"] =
159 "/redfish/v1/Systems/system/PCIeDevices";
160 aResp->res.jsonValue["Name"] = "PCIe Device Collection";
161 aResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
162 aResp->res.jsonValue["Members"] = nlohmann::json::array();
163 aResp->res.jsonValue["Members@odata.count"] = 0;
164
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600165 collection_util::getCollectionMembers(
166 aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -0500167 pcieDeviceInterface);
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600168}
169
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700170inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -0700171{
Jason M. Billsadbe1922019-10-14 15:44:35 -0700172 /**
173 * Functions triggers appropriate requests on DBus
174 */
Ed Tanous22d268c2022-05-19 09:39:07 -0700175 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -0700176 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700177 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600178 std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700179}
180
Ed Tanous0ec8b832022-03-14 14:56:47 -0700181inline std::optional<pcie_device::PCIeTypes>
Spencer Ku62cd45a2021-11-22 16:41:25 +0800182 redfishPcieGenerationFromDbus(const std::string& generationInUse)
183{
184 if (generationInUse ==
185 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
186 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700187 return pcie_device::PCIeTypes::Gen1;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800188 }
189 if (generationInUse ==
190 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
191 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700192 return pcie_device::PCIeTypes::Gen2;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800193 }
194 if (generationInUse ==
195 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
196 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700197 return pcie_device::PCIeTypes::Gen3;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800198 }
199 if (generationInUse ==
200 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
201 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700202 return pcie_device::PCIeTypes::Gen4;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800203 }
204 if (generationInUse ==
205 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
206 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700207 return pcie_device::PCIeTypes::Gen5;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800208 }
Ed Tanouse825cbc2022-06-17 11:39:22 -0700209 if (generationInUse.empty() ||
210 generationInUse ==
211 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800212 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700213 return pcie_device::PCIeTypes::Invalid;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800214 }
215
216 // The value is not unknown or Gen1-5, need return an internal error.
217 return std::nullopt;
218}
219
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500220inline void getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
221 const std::string& pcieDevicePath,
222 const std::string& service)
223{
224 sdbusplus::asio::getProperty<bool>(
225 *crow::connections::systemBus, service, pcieDevicePath,
226 "xyz.openbmc_project.Inventory.Item", "Present",
227 [aResp](const boost::system::error_code& ec, const bool value) {
228 if (ec)
229 {
230 if (ec.value() != EBADR)
231 {
232 BMCWEB_LOG_ERROR << "DBUS response error for State";
233 messages::internalError(aResp->res);
234 }
235 return;
236 }
237
238 if (!value)
239 {
240 aResp->res.jsonValue["Status"]["State"] = "Absent";
241 }
242 });
243}
244
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600245inline void getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
246 const std::string& pcieDevicePath,
247 const std::string& service)
248{
249 sdbusplus::asio::getAllProperties(
250 *crow::connections::systemBus, service, pcieDevicePath,
251 "xyz.openbmc_project.Inventory.Decorator.Asset",
252 [pcieDevicePath,
253 aResp{aResp}](const boost::system::error_code& ec,
254 const dbus::utility::DBusPropertiesMap& assetList) {
255 if (ec)
256 {
257 if (ec.value() != EBADR)
258 {
259 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
260 << ec.value();
261 messages::internalError(aResp->res);
262 }
263 return;
264 }
265
266 const std::string* manufacturer = nullptr;
267 const std::string* model = nullptr;
268 const std::string* partNumber = nullptr;
269 const std::string* serialNumber = nullptr;
270 const std::string* sparePartNumber = nullptr;
271
272 const bool success = sdbusplus::unpackPropertiesNoThrow(
273 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
274 manufacturer, "Model", model, "PartNumber", partNumber,
275 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
276
277 if (!success)
278 {
279 messages::internalError(aResp->res);
280 return;
281 }
282
283 if (manufacturer != nullptr)
284 {
285 aResp->res.jsonValue["Manufacturer"] = *manufacturer;
286 }
287 if (model != nullptr)
288 {
289 aResp->res.jsonValue["Model"] = *model;
290 }
291
292 if (partNumber != nullptr)
293 {
294 aResp->res.jsonValue["PartNumber"] = *partNumber;
295 }
296
297 if (serialNumber != nullptr)
298 {
299 aResp->res.jsonValue["SerialNumber"] = *serialNumber;
300 }
301
302 if (sparePartNumber != nullptr && !sparePartNumber->empty())
303 {
304 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
305 }
306 });
307}
308
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600309inline void addPCIeDeviceProperties(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600310 crow::Response& resp, const std::string& pcieDeviceId,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600311 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
312{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600313 const std::string* deviceType = nullptr;
314 const std::string* generationInUse = nullptr;
315 const int64_t* lanesInUse = nullptr;
316
317 const bool success = sdbusplus::unpackPropertiesNoThrow(
318 dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
319 deviceType, "GenerationInUse", generationInUse, "LanesInUse",
Lakshmi Yadlapatibad2c4a2023-04-07 09:14:37 -0500320 lanesInUse);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600321
322 if (!success)
323 {
324 messages::internalError(resp);
325 return;
326 }
327
328 if (deviceType != nullptr && !deviceType->empty())
329 {
330 resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
331 }
332
333 if (generationInUse != nullptr)
334 {
335 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
336 redfishPcieGenerationFromDbus(*generationInUse);
337
338 if (!redfishGenerationInUse)
339 {
340 messages::internalError(resp);
341 return;
342 }
343 if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
344 {
345 resp.jsonValue["PCIeInterface"]["PCIeType"] =
346 *redfishGenerationInUse;
347 }
348 }
349
350 // The default value of LanesInUse is 0, and the field will be
351 // left as off if it is a default value.
352 if (lanesInUse != nullptr && *lanesInUse != 0)
353 {
354 resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
355 }
356
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600357 resp.jsonValue["PCIeFunctions"]["@odata.id"] = crow::utility::urlFromPieces(
358 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
359 "PCIeFunctions");
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600360}
361
362inline void getPCIeDeviceProperties(
363 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
364 const std::string& pcieDevicePath, const std::string& service,
365 const std::function<void(
366 const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
367{
368 sdbusplus::asio::getAllProperties(
369 *crow::connections::systemBus, service, pcieDevicePath,
370 "xyz.openbmc_project.Inventory.Item.PCIeDevice",
371 [aResp,
372 callback](const boost::system::error_code& ec,
373 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
374 if (ec)
375 {
376 if (ec.value() != EBADR)
377 {
378 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
379 messages::internalError(aResp->res);
380 }
381 return;
382 }
383 callback(pcieDevProperties);
384 });
385}
386
387inline void addPCIeDeviceCommonProperties(
388 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
389 const std::string& pcieDeviceId)
390{
391 aResp->res.addHeader(
392 boost::beast::http::field::link,
393 "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
394 aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
395 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
396 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId);
397 aResp->res.jsonValue["Name"] = "PCIe Device";
398 aResp->res.jsonValue["Id"] = pcieDeviceId;
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500399 aResp->res.jsonValue["Status"]["State"] = "Enabled";
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600400}
401
402inline void handlePCIeDeviceGet(App& app, const crow::Request& req,
403 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
404 const std::string& systemName,
405 const std::string& pcieDeviceId)
406{
407 if (!redfish::setUpRedfishRoute(app, req, aResp))
408 {
409 return;
410 }
411 if (systemName != "system")
412 {
413 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
414 return;
415 }
416
417 getValidPCIeDevicePath(
418 pcieDeviceId, aResp,
419 [aResp, pcieDeviceId](const std::string& pcieDevicePath,
420 const std::string& service) {
421 addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600422 getPCIeDeviceAsset(aResp, pcieDevicePath, service);
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500423 getPCIeDeviceState(aResp, pcieDevicePath, service);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600424 getPCIeDeviceProperties(
425 aResp, pcieDevicePath, service,
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600426 [aResp, pcieDeviceId](
427 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
428 addPCIeDeviceProperties(aResp->res, pcieDeviceId,
429 pcieDevProperties);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600430 });
431 });
432}
433
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700434inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800435{
Ed Tanous22d268c2022-05-19 09:39:07 -0700436 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700437 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700438 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600439 std::bind_front(handlePCIeDeviceGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700440}
441
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600442inline void addPCIeFunctionList(
443 crow::Response& res, const std::string& pcieDeviceId,
444 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
445{
446 nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
447 pcieFunctionList = nlohmann::json::array();
448 static constexpr const int maxPciFunctionNum = 8;
449
450 for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
451 {
452 // Check if this function exists by
453 // looking for a device ID
Patrick Williams89492a12023-05-10 07:51:34 -0500454 std::string devIDProperty = "Function" + std::to_string(functionNum) +
455 "DeviceId";
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600456 const std::string* property = nullptr;
457 for (const auto& propEntry : pcieDevProperties)
458 {
459 if (propEntry.first == devIDProperty)
460 {
461 property = std::get_if<std::string>(&propEntry.second);
462 break;
463 }
464 }
465 if (property == nullptr || property->empty())
466 {
467 continue;
468 }
469
470 nlohmann::json::object_t pcieFunction;
471 pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
472 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
473 "PCIeFunctions", std::to_string(functionNum));
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500474 pcieFunctionList.emplace_back(std::move(pcieFunction));
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600475 }
476 res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
477}
478
479inline void handlePCIeFunctionCollectionGet(
480 App& app, const crow::Request& req,
481 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
482 const std::string& pcieDeviceId)
483{
484 if (!redfish::setUpRedfishRoute(app, req, aResp))
485 {
486 return;
487 }
488
489 getValidPCIeDevicePath(
490 pcieDeviceId, aResp,
491 [aResp, pcieDeviceId](const std::string& pcieDevicePath,
492 const std::string& service) {
493 aResp->res.addHeader(
494 boost::beast::http::field::link,
495 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
496 aResp->res.jsonValue["@odata.type"] =
497 "#PCIeFunctionCollection.PCIeFunctionCollection";
498 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
499 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
500 "PCIeFunctions");
501 aResp->res.jsonValue["Name"] = "PCIe Function Collection";
502 aResp->res.jsonValue["Description"] =
503 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
504 getPCIeDeviceProperties(
505 aResp, pcieDevicePath, service,
506 [aResp, pcieDeviceId](
507 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
508 addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties);
509 });
510 });
511}
512
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700513inline void requestRoutesSystemPCIeFunctionCollection(App& app)
514{
515 /**
516 * Functions triggers appropriate requests on DBus
517 */
518 BMCWEB_ROUTE(app,
519 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700520 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700521 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600522 std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700523}
524
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600525inline bool validatePCIeFunctionId(
526 const std::string& pcieFunctionId,
527 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
528{
529 std::string functionName = "Function" + pcieFunctionId;
530 std::string devIDProperty = functionName + "DeviceId";
531
532 const std::string* devIdProperty = nullptr;
533 for (const auto& property : pcieDevProperties)
534 {
535 if (property.first == devIDProperty)
536 {
537 devIdProperty = std::get_if<std::string>(&property.second);
538 break;
539 }
540 }
541 return (devIdProperty != nullptr && !devIdProperty->empty());
542}
543
544inline void addPCIeFunctionProperties(
545 crow::Response& resp, const std::string& pcieFunctionId,
546 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
547{
548 std::string functionName = "Function" + pcieFunctionId;
549 if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties))
550 {
551 messages::resourceNotFound(resp, "PCIeFunction", pcieFunctionId);
552 return;
553 }
554 for (const auto& property : pcieDevProperties)
555 {
556 const std::string* strProperty =
557 std::get_if<std::string>(&property.second);
558
559 if (property.first == functionName + "DeviceId")
560 {
561 resp.jsonValue["DeviceId"] = *strProperty;
562 }
563 if (property.first == functionName + "VendorId")
564 {
565 resp.jsonValue["VendorId"] = *strProperty;
566 }
567 // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
568 // property strings should be mapped correctly to ensure these
569 // strings are Redfish enum values. For now just check for empty.
570 if (property.first == functionName + "FunctionType")
571 {
572 if (!strProperty->empty())
573 {
574 resp.jsonValue["FunctionType"] = *strProperty;
575 }
576 }
577 if (property.first == functionName + "DeviceClass")
578 {
579 if (!strProperty->empty())
580 {
581 resp.jsonValue["DeviceClass"] = *strProperty;
582 }
583 }
584 if (property.first == functionName + "ClassCode")
585 {
586 resp.jsonValue["ClassCode"] = *strProperty;
587 }
588 if (property.first == functionName + "RevisionId")
589 {
590 resp.jsonValue["RevisionId"] = *strProperty;
591 }
592 if (property.first == functionName + "SubsystemId")
593 {
594 resp.jsonValue["SubsystemId"] = *strProperty;
595 }
596 if (property.first == functionName + "SubsystemVendorId")
597 {
598 resp.jsonValue["SubsystemVendorId"] = *strProperty;
599 }
600 }
601}
602
603inline void addPCIeFunctionCommonProperties(crow::Response& resp,
604 const std::string& pcieDeviceId,
605 const std::string& pcieFunctionId)
606{
607 resp.addHeader(
608 boost::beast::http::field::link,
609 "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
610 resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
611 resp.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
612 "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
613 "PCIeFunctions", pcieFunctionId);
614 resp.jsonValue["Name"] = "PCIe Function";
615 resp.jsonValue["Id"] = pcieFunctionId;
616 resp.jsonValue["FunctionId"] = std::stoi(pcieFunctionId);
617 resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
618 crow::utility::urlFromPieces("redfish", "v1", "Systems", "system",
619 "PCIeDevices", pcieDeviceId);
620}
621
622inline void
623 handlePCIeFunctionGet(App& app, const crow::Request& req,
624 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
625 const std::string& pcieDeviceId,
626 const std::string& pcieFunctionId)
627{
628 if (!redfish::setUpRedfishRoute(app, req, aResp))
629 {
630 return;
631 }
632
633 getValidPCIeDevicePath(
634 pcieDeviceId, aResp,
635 [aResp, pcieDeviceId, pcieFunctionId](const std::string& pcieDevicePath,
636 const std::string& service) {
637 getPCIeDeviceProperties(
638 aResp, pcieDevicePath, service,
639 [aResp, pcieDeviceId, pcieFunctionId](
640 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
641 addPCIeFunctionCommonProperties(aResp->res, pcieDeviceId,
642 pcieFunctionId);
643 addPCIeFunctionProperties(aResp->res, pcieFunctionId,
644 pcieDevProperties);
645 });
646 });
647}
648
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700649inline void requestRoutesSystemPCIeFunction(App& app)
650{
651 BMCWEB_ROUTE(
652 app,
653 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700654 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700655 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600656 std::bind_front(handlePCIeFunctionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700657}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800658
659} // namespace redfish