blob: d0c88f46091fe5d3927c7049bf2fcc67ab7f18f8 [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>
Ed Tanousef4c65b2023-04-24 15:28:50 -070028#include <boost/url/format.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020029#include <sdbusplus/asio/property.hpp>
30#include <sdbusplus/unpack_properties.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080031
32namespace redfish
33{
34
Patrick Williams89492a12023-05-10 07:51:34 -050035static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -050036static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
37 "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{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060082 dbus::utility::getSubTreePaths(
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -050083 inventoryPath, 0, pcieDeviceInterface,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060084 [pcieDeviceId, aResp,
85 callback](const boost::system::error_code& ec,
86 const dbus::utility::MapperGetSubTreePathsResponse&
87 pcieDevicePaths) {
88 if (ec)
89 {
90 BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
91 messages::internalError(aResp->res);
92 return;
93 }
94 handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback);
95 return;
96 });
97}
98
Ed Tanousb5a76932020-09-29 16:16:58 -070099static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +0800100 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -0700101 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800102{
George Liu7a1dbc42022-12-07 16:03:22 +0800103 dbus::utility::getSubTreePaths(
Lakshmi Yadlapati38e3d672023-05-02 09:26:33 -0500104 inventoryPath, 0, pcieDeviceInterface,
George Liu7a1dbc42022-12-07 16:03:22 +0800105 [asyncResp, name](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800106 const dbus::utility::MapperGetSubTreePathsResponse&
107 pcieDevicePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700108 if (ec)
109 {
110 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
111 << ec.message();
112 // Not an error, system just doesn't have PCIe info
113 return;
114 }
115 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
116 pcieDeviceList = nlohmann::json::array();
117 for (const std::string& pcieDevicePath : pcieDevicePaths)
118 {
119 size_t devStart = pcieDevicePath.rfind('/');
120 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800121 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700122 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800123 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800124
Ed Tanous002d39b2022-05-31 08:59:27 -0700125 std::string devName = pcieDevicePath.substr(devStart + 1);
126 if (devName.empty())
127 {
128 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800129 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700130 nlohmann::json::object_t pcieDevice;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700131 pcieDevice["@odata.id"] = boost::urls::format(
132 "/redfish/v1/Systems/system/PCIeDevices/{}", devName);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500133 pcieDeviceList.emplace_back(std::move(pcieDevice));
Ed Tanous002d39b2022-05-31 08:59:27 -0700134 }
135 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
George Liu7a1dbc42022-12-07 16:03:22 +0800136 });
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800137}
138
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600139static inline void handlePCIeDeviceCollectionGet(
140 crow::App& app, const crow::Request& req,
141 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
142 const std::string& systemName)
143{
144 if (!redfish::setUpRedfishRoute(app, req, aResp))
145 {
146 return;
147 }
148 if (systemName != "system")
149 {
150 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
151 return;
152 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600153
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600154 aResp->res.addHeader(boost::beast::http::field::link,
155 "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
156 "PCIeDeviceCollection.json>; rel=describedby");
157 aResp->res.jsonValue["@odata.type"] =
158 "#PCIeDeviceCollection.PCIeDeviceCollection";
159 aResp->res.jsonValue["@odata.id"] =
160 "/redfish/v1/Systems/system/PCIeDevices";
161 aResp->res.jsonValue["Name"] = "PCIe Device Collection";
162 aResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
163 aResp->res.jsonValue["Members"] = nlohmann::json::array();
164 aResp->res.jsonValue["Members@odata.count"] = 0;
165
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600166 collection_util::getCollectionMembers(
167 aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -0500168 pcieDeviceInterface);
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600169}
170
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700171inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -0700172{
Jason M. Billsadbe1922019-10-14 15:44:35 -0700173 /**
174 * Functions triggers appropriate requests on DBus
175 */
Ed Tanous22d268c2022-05-19 09:39:07 -0700176 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -0700177 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700178 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600179 std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700180}
181
Ed Tanous0ec8b832022-03-14 14:56:47 -0700182inline std::optional<pcie_device::PCIeTypes>
Spencer Ku62cd45a2021-11-22 16:41:25 +0800183 redfishPcieGenerationFromDbus(const std::string& generationInUse)
184{
185 if (generationInUse ==
186 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
187 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700188 return pcie_device::PCIeTypes::Gen1;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800189 }
190 if (generationInUse ==
191 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
192 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700193 return pcie_device::PCIeTypes::Gen2;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800194 }
195 if (generationInUse ==
196 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
197 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700198 return pcie_device::PCIeTypes::Gen3;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800199 }
200 if (generationInUse ==
201 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
202 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700203 return pcie_device::PCIeTypes::Gen4;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800204 }
205 if (generationInUse ==
206 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
207 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700208 return pcie_device::PCIeTypes::Gen5;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800209 }
Ed Tanouse825cbc2022-06-17 11:39:22 -0700210 if (generationInUse.empty() ||
211 generationInUse ==
212 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800213 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700214 return pcie_device::PCIeTypes::Invalid;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800215 }
216
217 // The value is not unknown or Gen1-5, need return an internal error.
218 return std::nullopt;
219}
220
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500221inline void getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
222 const std::string& pcieDevicePath,
223 const std::string& service)
224{
225 sdbusplus::asio::getProperty<bool>(
226 *crow::connections::systemBus, service, pcieDevicePath,
227 "xyz.openbmc_project.Inventory.Item", "Present",
228 [aResp](const boost::system::error_code& ec, const bool value) {
229 if (ec)
230 {
231 if (ec.value() != EBADR)
232 {
233 BMCWEB_LOG_ERROR << "DBUS response error for State";
234 messages::internalError(aResp->res);
235 }
236 return;
237 }
238
239 if (!value)
240 {
241 aResp->res.jsonValue["Status"]["State"] = "Absent";
242 }
243 });
244}
245
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600246inline void getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
247 const std::string& pcieDevicePath,
248 const std::string& service)
249{
250 sdbusplus::asio::getAllProperties(
251 *crow::connections::systemBus, service, pcieDevicePath,
252 "xyz.openbmc_project.Inventory.Decorator.Asset",
253 [pcieDevicePath,
254 aResp{aResp}](const boost::system::error_code& ec,
255 const dbus::utility::DBusPropertiesMap& assetList) {
256 if (ec)
257 {
258 if (ec.value() != EBADR)
259 {
260 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
261 << ec.value();
262 messages::internalError(aResp->res);
263 }
264 return;
265 }
266
267 const std::string* manufacturer = nullptr;
268 const std::string* model = nullptr;
269 const std::string* partNumber = nullptr;
270 const std::string* serialNumber = nullptr;
271 const std::string* sparePartNumber = nullptr;
272
273 const bool success = sdbusplus::unpackPropertiesNoThrow(
274 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
275 manufacturer, "Model", model, "PartNumber", partNumber,
276 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
277
278 if (!success)
279 {
280 messages::internalError(aResp->res);
281 return;
282 }
283
284 if (manufacturer != nullptr)
285 {
286 aResp->res.jsonValue["Manufacturer"] = *manufacturer;
287 }
288 if (model != nullptr)
289 {
290 aResp->res.jsonValue["Model"] = *model;
291 }
292
293 if (partNumber != nullptr)
294 {
295 aResp->res.jsonValue["PartNumber"] = *partNumber;
296 }
297
298 if (serialNumber != nullptr)
299 {
300 aResp->res.jsonValue["SerialNumber"] = *serialNumber;
301 }
302
303 if (sparePartNumber != nullptr && !sparePartNumber->empty())
304 {
305 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
306 }
307 });
308}
309
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600310inline void addPCIeDeviceProperties(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600311 crow::Response& resp, const std::string& pcieDeviceId,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600312 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
313{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600314 const std::string* deviceType = nullptr;
315 const std::string* generationInUse = nullptr;
316 const int64_t* lanesInUse = nullptr;
317
318 const bool success = sdbusplus::unpackPropertiesNoThrow(
319 dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
320 deviceType, "GenerationInUse", generationInUse, "LanesInUse",
Lakshmi Yadlapatibad2c4a2023-04-07 09:14:37 -0500321 lanesInUse);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600322
323 if (!success)
324 {
325 messages::internalError(resp);
326 return;
327 }
328
329 if (deviceType != nullptr && !deviceType->empty())
330 {
331 resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
332 }
333
334 if (generationInUse != nullptr)
335 {
336 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
337 redfishPcieGenerationFromDbus(*generationInUse);
338
339 if (!redfishGenerationInUse)
340 {
341 messages::internalError(resp);
342 return;
343 }
344 if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
345 {
346 resp.jsonValue["PCIeInterface"]["PCIeType"] =
347 *redfishGenerationInUse;
348 }
349 }
350
351 // The default value of LanesInUse is 0, and the field will be
352 // left as off if it is a default value.
353 if (lanesInUse != nullptr && *lanesInUse != 0)
354 {
355 resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
356 }
357
Ed Tanousef4c65b2023-04-24 15:28:50 -0700358 resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format(
359 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
360 pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600361}
362
363inline void getPCIeDeviceProperties(
364 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
365 const std::string& pcieDevicePath, const std::string& service,
366 const std::function<void(
367 const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
368{
369 sdbusplus::asio::getAllProperties(
370 *crow::connections::systemBus, service, pcieDevicePath,
371 "xyz.openbmc_project.Inventory.Item.PCIeDevice",
372 [aResp,
373 callback](const boost::system::error_code& ec,
374 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
375 if (ec)
376 {
377 if (ec.value() != EBADR)
378 {
379 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
380 messages::internalError(aResp->res);
381 }
382 return;
383 }
384 callback(pcieDevProperties);
385 });
386}
387
388inline void addPCIeDeviceCommonProperties(
389 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
390 const std::string& pcieDeviceId)
391{
392 aResp->res.addHeader(
393 boost::beast::http::field::link,
394 "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
395 aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700396 aResp->res.jsonValue["@odata.id"] = boost::urls::format(
397 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600398 aResp->res.jsonValue["Name"] = "PCIe Device";
399 aResp->res.jsonValue["Id"] = pcieDeviceId;
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500400 aResp->res.jsonValue["Status"]["State"] = "Enabled";
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600401}
402
403inline void handlePCIeDeviceGet(App& app, const crow::Request& req,
404 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
405 const std::string& systemName,
406 const std::string& pcieDeviceId)
407{
408 if (!redfish::setUpRedfishRoute(app, req, aResp))
409 {
410 return;
411 }
412 if (systemName != "system")
413 {
414 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
415 return;
416 }
417
418 getValidPCIeDevicePath(
419 pcieDeviceId, aResp,
420 [aResp, pcieDeviceId](const std::string& pcieDevicePath,
421 const std::string& service) {
422 addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600423 getPCIeDeviceAsset(aResp, pcieDevicePath, service);
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500424 getPCIeDeviceState(aResp, pcieDevicePath, service);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600425 getPCIeDeviceProperties(
426 aResp, pcieDevicePath, service,
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600427 [aResp, pcieDeviceId](
428 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
429 addPCIeDeviceProperties(aResp->res, pcieDeviceId,
430 pcieDevProperties);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600431 });
432 });
433}
434
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700435inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800436{
Ed Tanous22d268c2022-05-19 09:39:07 -0700437 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700438 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700439 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600440 std::bind_front(handlePCIeDeviceGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700441}
442
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600443inline void addPCIeFunctionList(
444 crow::Response& res, const std::string& pcieDeviceId,
445 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
446{
447 nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
448 pcieFunctionList = nlohmann::json::array();
449 static constexpr const int maxPciFunctionNum = 8;
450
451 for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
452 {
453 // Check if this function exists by
454 // looking for a device ID
Patrick Williams89492a12023-05-10 07:51:34 -0500455 std::string devIDProperty = "Function" + std::to_string(functionNum) +
456 "DeviceId";
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600457 const std::string* property = nullptr;
458 for (const auto& propEntry : pcieDevProperties)
459 {
460 if (propEntry.first == devIDProperty)
461 {
462 property = std::get_if<std::string>(&propEntry.second);
463 break;
464 }
465 }
466 if (property == nullptr || property->empty())
467 {
468 continue;
469 }
470
471 nlohmann::json::object_t pcieFunction;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700472 pcieFunction["@odata.id"] = boost::urls::format(
473 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
474 pcieDeviceId, std::to_string(functionNum));
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500475 pcieFunctionList.emplace_back(std::move(pcieFunction));
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600476 }
477 res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
478}
479
480inline void handlePCIeFunctionCollectionGet(
481 App& app, const crow::Request& req,
482 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
483 const std::string& pcieDeviceId)
484{
485 if (!redfish::setUpRedfishRoute(app, req, aResp))
486 {
487 return;
488 }
489
490 getValidPCIeDevicePath(
491 pcieDeviceId, aResp,
492 [aResp, pcieDeviceId](const std::string& pcieDevicePath,
493 const std::string& service) {
494 aResp->res.addHeader(
495 boost::beast::http::field::link,
496 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
497 aResp->res.jsonValue["@odata.type"] =
498 "#PCIeFunctionCollection.PCIeFunctionCollection";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700499 aResp->res.jsonValue["@odata.id"] = boost::urls::format(
500 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
501 pcieDeviceId);
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600502 aResp->res.jsonValue["Name"] = "PCIe Function Collection";
503 aResp->res.jsonValue["Description"] =
504 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
505 getPCIeDeviceProperties(
506 aResp, pcieDevicePath, service,
507 [aResp, pcieDeviceId](
508 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
509 addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties);
510 });
511 });
512}
513
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700514inline void requestRoutesSystemPCIeFunctionCollection(App& app)
515{
516 /**
517 * Functions triggers appropriate requests on DBus
518 */
519 BMCWEB_ROUTE(app,
520 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700521 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700522 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600523 std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700524}
525
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600526inline bool validatePCIeFunctionId(
527 const std::string& pcieFunctionId,
528 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
529{
530 std::string functionName = "Function" + pcieFunctionId;
531 std::string devIDProperty = functionName + "DeviceId";
532
533 const std::string* devIdProperty = nullptr;
534 for (const auto& property : pcieDevProperties)
535 {
536 if (property.first == devIDProperty)
537 {
538 devIdProperty = std::get_if<std::string>(&property.second);
539 break;
540 }
541 }
542 return (devIdProperty != nullptr && !devIdProperty->empty());
543}
544
545inline void addPCIeFunctionProperties(
546 crow::Response& resp, const std::string& pcieFunctionId,
547 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
548{
549 std::string functionName = "Function" + pcieFunctionId;
550 if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties))
551 {
552 messages::resourceNotFound(resp, "PCIeFunction", pcieFunctionId);
553 return;
554 }
555 for (const auto& property : pcieDevProperties)
556 {
557 const std::string* strProperty =
558 std::get_if<std::string>(&property.second);
559
560 if (property.first == functionName + "DeviceId")
561 {
562 resp.jsonValue["DeviceId"] = *strProperty;
563 }
564 if (property.first == functionName + "VendorId")
565 {
566 resp.jsonValue["VendorId"] = *strProperty;
567 }
568 // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
569 // property strings should be mapped correctly to ensure these
570 // strings are Redfish enum values. For now just check for empty.
571 if (property.first == functionName + "FunctionType")
572 {
573 if (!strProperty->empty())
574 {
575 resp.jsonValue["FunctionType"] = *strProperty;
576 }
577 }
578 if (property.first == functionName + "DeviceClass")
579 {
580 if (!strProperty->empty())
581 {
582 resp.jsonValue["DeviceClass"] = *strProperty;
583 }
584 }
585 if (property.first == functionName + "ClassCode")
586 {
587 resp.jsonValue["ClassCode"] = *strProperty;
588 }
589 if (property.first == functionName + "RevisionId")
590 {
591 resp.jsonValue["RevisionId"] = *strProperty;
592 }
593 if (property.first == functionName + "SubsystemId")
594 {
595 resp.jsonValue["SubsystemId"] = *strProperty;
596 }
597 if (property.first == functionName + "SubsystemVendorId")
598 {
599 resp.jsonValue["SubsystemVendorId"] = *strProperty;
600 }
601 }
602}
603
604inline void addPCIeFunctionCommonProperties(crow::Response& resp,
605 const std::string& pcieDeviceId,
606 const std::string& pcieFunctionId)
607{
608 resp.addHeader(
609 boost::beast::http::field::link,
610 "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
611 resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700612 resp.jsonValue["@odata.id"] = boost::urls::format(
613 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
614 pcieDeviceId, pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600615 resp.jsonValue["Name"] = "PCIe Function";
616 resp.jsonValue["Id"] = pcieFunctionId;
617 resp.jsonValue["FunctionId"] = std::stoi(pcieFunctionId);
Ed Tanousef4c65b2023-04-24 15:28:50 -0700618 resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
619 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600620}
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