blob: f98d6c879777dfe07373839a75b001c9d2ecffe5 [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
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -060099static inline void handlePCIeDeviceCollectionGet(
100 crow::App& app, const crow::Request& req,
101 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
102 const std::string& systemName)
103{
104 if (!redfish::setUpRedfishRoute(app, req, aResp))
105 {
106 return;
107 }
108 if (systemName != "system")
109 {
110 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
111 return;
112 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600113
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600114 aResp->res.addHeader(boost::beast::http::field::link,
115 "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
116 "PCIeDeviceCollection.json>; rel=describedby");
117 aResp->res.jsonValue["@odata.type"] =
118 "#PCIeDeviceCollection.PCIeDeviceCollection";
119 aResp->res.jsonValue["@odata.id"] =
120 "/redfish/v1/Systems/system/PCIeDevices";
121 aResp->res.jsonValue["Name"] = "PCIe Device Collection";
122 aResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
123 aResp->res.jsonValue["Members"] = nlohmann::json::array();
124 aResp->res.jsonValue["Members@odata.count"] = 0;
125
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600126 collection_util::getCollectionMembers(
127 aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -0500128 pcieDeviceInterface);
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600129}
130
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700131inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -0700132{
Jason M. Billsadbe1922019-10-14 15:44:35 -0700133 /**
134 * Functions triggers appropriate requests on DBus
135 */
Ed Tanous22d268c2022-05-19 09:39:07 -0700136 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -0700137 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700138 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600139 std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700140}
141
Ed Tanous0ec8b832022-03-14 14:56:47 -0700142inline std::optional<pcie_device::PCIeTypes>
Spencer Ku62cd45a2021-11-22 16:41:25 +0800143 redfishPcieGenerationFromDbus(const std::string& generationInUse)
144{
145 if (generationInUse ==
146 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
147 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700148 return pcie_device::PCIeTypes::Gen1;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800149 }
150 if (generationInUse ==
151 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
152 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700153 return pcie_device::PCIeTypes::Gen2;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800154 }
155 if (generationInUse ==
156 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
157 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700158 return pcie_device::PCIeTypes::Gen3;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800159 }
160 if (generationInUse ==
161 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
162 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700163 return pcie_device::PCIeTypes::Gen4;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800164 }
165 if (generationInUse ==
166 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
167 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700168 return pcie_device::PCIeTypes::Gen5;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800169 }
Ed Tanouse825cbc2022-06-17 11:39:22 -0700170 if (generationInUse.empty() ||
171 generationInUse ==
172 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800173 {
Ed Tanous0ec8b832022-03-14 14:56:47 -0700174 return pcie_device::PCIeTypes::Invalid;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800175 }
176
177 // The value is not unknown or Gen1-5, need return an internal error.
178 return std::nullopt;
179}
180
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500181inline void getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
182 const std::string& pcieDevicePath,
183 const std::string& service)
184{
185 sdbusplus::asio::getProperty<bool>(
186 *crow::connections::systemBus, service, pcieDevicePath,
187 "xyz.openbmc_project.Inventory.Item", "Present",
188 [aResp](const boost::system::error_code& ec, const bool value) {
189 if (ec)
190 {
191 if (ec.value() != EBADR)
192 {
193 BMCWEB_LOG_ERROR << "DBUS response error for State";
194 messages::internalError(aResp->res);
195 }
196 return;
197 }
198
199 if (!value)
200 {
201 aResp->res.jsonValue["Status"]["State"] = "Absent";
202 }
203 });
204}
205
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600206inline void getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
207 const std::string& pcieDevicePath,
208 const std::string& service)
209{
210 sdbusplus::asio::getAllProperties(
211 *crow::connections::systemBus, service, pcieDevicePath,
212 "xyz.openbmc_project.Inventory.Decorator.Asset",
213 [pcieDevicePath,
214 aResp{aResp}](const boost::system::error_code& ec,
215 const dbus::utility::DBusPropertiesMap& assetList) {
216 if (ec)
217 {
218 if (ec.value() != EBADR)
219 {
220 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
221 << ec.value();
222 messages::internalError(aResp->res);
223 }
224 return;
225 }
226
227 const std::string* manufacturer = nullptr;
228 const std::string* model = nullptr;
229 const std::string* partNumber = nullptr;
230 const std::string* serialNumber = nullptr;
231 const std::string* sparePartNumber = nullptr;
232
233 const bool success = sdbusplus::unpackPropertiesNoThrow(
234 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
235 manufacturer, "Model", model, "PartNumber", partNumber,
236 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
237
238 if (!success)
239 {
240 messages::internalError(aResp->res);
241 return;
242 }
243
244 if (manufacturer != nullptr)
245 {
246 aResp->res.jsonValue["Manufacturer"] = *manufacturer;
247 }
248 if (model != nullptr)
249 {
250 aResp->res.jsonValue["Model"] = *model;
251 }
252
253 if (partNumber != nullptr)
254 {
255 aResp->res.jsonValue["PartNumber"] = *partNumber;
256 }
257
258 if (serialNumber != nullptr)
259 {
260 aResp->res.jsonValue["SerialNumber"] = *serialNumber;
261 }
262
263 if (sparePartNumber != nullptr && !sparePartNumber->empty())
264 {
265 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
266 }
267 });
268}
269
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600270inline void addPCIeDeviceProperties(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600271 crow::Response& resp, const std::string& pcieDeviceId,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600272 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
273{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600274 const std::string* deviceType = nullptr;
275 const std::string* generationInUse = nullptr;
276 const int64_t* lanesInUse = nullptr;
277
278 const bool success = sdbusplus::unpackPropertiesNoThrow(
279 dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
280 deviceType, "GenerationInUse", generationInUse, "LanesInUse",
Lakshmi Yadlapatibad2c4a2023-04-07 09:14:37 -0500281 lanesInUse);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600282
283 if (!success)
284 {
285 messages::internalError(resp);
286 return;
287 }
288
289 if (deviceType != nullptr && !deviceType->empty())
290 {
291 resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
292 }
293
294 if (generationInUse != nullptr)
295 {
296 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
297 redfishPcieGenerationFromDbus(*generationInUse);
298
299 if (!redfishGenerationInUse)
300 {
301 messages::internalError(resp);
302 return;
303 }
304 if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
305 {
306 resp.jsonValue["PCIeInterface"]["PCIeType"] =
307 *redfishGenerationInUse;
308 }
309 }
310
311 // The default value of LanesInUse is 0, and the field will be
312 // left as off if it is a default value.
313 if (lanesInUse != nullptr && *lanesInUse != 0)
314 {
315 resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
316 }
317
Ed Tanousef4c65b2023-04-24 15:28:50 -0700318 resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format(
319 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
320 pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600321}
322
323inline void getPCIeDeviceProperties(
324 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
325 const std::string& pcieDevicePath, const std::string& service,
326 const std::function<void(
327 const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
328{
329 sdbusplus::asio::getAllProperties(
330 *crow::connections::systemBus, service, pcieDevicePath,
331 "xyz.openbmc_project.Inventory.Item.PCIeDevice",
332 [aResp,
333 callback](const boost::system::error_code& ec,
334 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
335 if (ec)
336 {
337 if (ec.value() != EBADR)
338 {
339 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
340 messages::internalError(aResp->res);
341 }
342 return;
343 }
344 callback(pcieDevProperties);
345 });
346}
347
348inline void addPCIeDeviceCommonProperties(
349 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
350 const std::string& pcieDeviceId)
351{
352 aResp->res.addHeader(
353 boost::beast::http::field::link,
354 "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
355 aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700356 aResp->res.jsonValue["@odata.id"] = boost::urls::format(
357 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600358 aResp->res.jsonValue["Name"] = "PCIe Device";
359 aResp->res.jsonValue["Id"] = pcieDeviceId;
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500360 aResp->res.jsonValue["Status"]["State"] = "Enabled";
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600361}
362
363inline void handlePCIeDeviceGet(App& app, const crow::Request& req,
364 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
365 const std::string& systemName,
366 const std::string& pcieDeviceId)
367{
368 if (!redfish::setUpRedfishRoute(app, req, aResp))
369 {
370 return;
371 }
372 if (systemName != "system")
373 {
374 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
375 return;
376 }
377
378 getValidPCIeDevicePath(
379 pcieDeviceId, aResp,
380 [aResp, pcieDeviceId](const std::string& pcieDevicePath,
381 const std::string& service) {
382 addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600383 getPCIeDeviceAsset(aResp, pcieDevicePath, service);
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500384 getPCIeDeviceState(aResp, pcieDevicePath, service);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600385 getPCIeDeviceProperties(
386 aResp, pcieDevicePath, service,
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600387 [aResp, pcieDeviceId](
388 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
389 addPCIeDeviceProperties(aResp->res, pcieDeviceId,
390 pcieDevProperties);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600391 });
392 });
393}
394
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700395inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800396{
Ed Tanous22d268c2022-05-19 09:39:07 -0700397 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700398 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700399 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600400 std::bind_front(handlePCIeDeviceGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700401}
402
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600403inline void addPCIeFunctionList(
404 crow::Response& res, const std::string& pcieDeviceId,
405 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
406{
407 nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
408 pcieFunctionList = nlohmann::json::array();
409 static constexpr const int maxPciFunctionNum = 8;
410
411 for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
412 {
413 // Check if this function exists by
414 // looking for a device ID
Patrick Williams89492a12023-05-10 07:51:34 -0500415 std::string devIDProperty = "Function" + std::to_string(functionNum) +
416 "DeviceId";
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600417 const std::string* property = nullptr;
418 for (const auto& propEntry : pcieDevProperties)
419 {
420 if (propEntry.first == devIDProperty)
421 {
422 property = std::get_if<std::string>(&propEntry.second);
423 break;
424 }
425 }
426 if (property == nullptr || property->empty())
427 {
428 continue;
429 }
430
431 nlohmann::json::object_t pcieFunction;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700432 pcieFunction["@odata.id"] = boost::urls::format(
433 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
434 pcieDeviceId, std::to_string(functionNum));
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500435 pcieFunctionList.emplace_back(std::move(pcieFunction));
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600436 }
437 res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
438}
439
440inline void handlePCIeFunctionCollectionGet(
441 App& app, const crow::Request& req,
442 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
443 const std::string& pcieDeviceId)
444{
445 if (!redfish::setUpRedfishRoute(app, req, aResp))
446 {
447 return;
448 }
449
450 getValidPCIeDevicePath(
451 pcieDeviceId, aResp,
452 [aResp, pcieDeviceId](const std::string& pcieDevicePath,
453 const std::string& service) {
454 aResp->res.addHeader(
455 boost::beast::http::field::link,
456 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
457 aResp->res.jsonValue["@odata.type"] =
458 "#PCIeFunctionCollection.PCIeFunctionCollection";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700459 aResp->res.jsonValue["@odata.id"] = boost::urls::format(
460 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
461 pcieDeviceId);
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600462 aResp->res.jsonValue["Name"] = "PCIe Function Collection";
463 aResp->res.jsonValue["Description"] =
464 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
465 getPCIeDeviceProperties(
466 aResp, pcieDevicePath, service,
467 [aResp, pcieDeviceId](
468 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
469 addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties);
470 });
471 });
472}
473
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700474inline void requestRoutesSystemPCIeFunctionCollection(App& app)
475{
476 /**
477 * Functions triggers appropriate requests on DBus
478 */
479 BMCWEB_ROUTE(app,
480 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700481 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700482 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600483 std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700484}
485
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600486inline bool validatePCIeFunctionId(
Myung Baed5e74b82023-05-31 11:28:02 -0500487 uint64_t pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600488 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
489{
Myung Baed5e74b82023-05-31 11:28:02 -0500490 std::string functionName = "Function" + std::to_string(pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600491 std::string devIDProperty = functionName + "DeviceId";
492
493 const std::string* devIdProperty = nullptr;
494 for (const auto& property : pcieDevProperties)
495 {
496 if (property.first == devIDProperty)
497 {
498 devIdProperty = std::get_if<std::string>(&property.second);
499 break;
500 }
501 }
502 return (devIdProperty != nullptr && !devIdProperty->empty());
503}
504
505inline void addPCIeFunctionProperties(
Ed Tanouse14742c2023-05-31 10:27:49 -0700506 crow::Response& resp, uint64_t pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600507 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
508{
Ed Tanouse14742c2023-05-31 10:27:49 -0700509 std::string functionName = "Function" + std::to_string(pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600510 for (const auto& property : pcieDevProperties)
511 {
512 const std::string* strProperty =
513 std::get_if<std::string>(&property.second);
514
515 if (property.first == functionName + "DeviceId")
516 {
517 resp.jsonValue["DeviceId"] = *strProperty;
518 }
519 if (property.first == functionName + "VendorId")
520 {
521 resp.jsonValue["VendorId"] = *strProperty;
522 }
523 // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
524 // property strings should be mapped correctly to ensure these
525 // strings are Redfish enum values. For now just check for empty.
526 if (property.first == functionName + "FunctionType")
527 {
528 if (!strProperty->empty())
529 {
530 resp.jsonValue["FunctionType"] = *strProperty;
531 }
532 }
533 if (property.first == functionName + "DeviceClass")
534 {
535 if (!strProperty->empty())
536 {
537 resp.jsonValue["DeviceClass"] = *strProperty;
538 }
539 }
540 if (property.first == functionName + "ClassCode")
541 {
542 resp.jsonValue["ClassCode"] = *strProperty;
543 }
544 if (property.first == functionName + "RevisionId")
545 {
546 resp.jsonValue["RevisionId"] = *strProperty;
547 }
548 if (property.first == functionName + "SubsystemId")
549 {
550 resp.jsonValue["SubsystemId"] = *strProperty;
551 }
552 if (property.first == functionName + "SubsystemVendorId")
553 {
554 resp.jsonValue["SubsystemVendorId"] = *strProperty;
555 }
556 }
557}
558
559inline void addPCIeFunctionCommonProperties(crow::Response& resp,
560 const std::string& pcieDeviceId,
Ed Tanouse14742c2023-05-31 10:27:49 -0700561 uint64_t pcieFunctionId)
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600562{
563 resp.addHeader(
564 boost::beast::http::field::link,
565 "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
566 resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700567 resp.jsonValue["@odata.id"] = boost::urls::format(
568 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
569 pcieDeviceId, pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600570 resp.jsonValue["Name"] = "PCIe Function";
Ed Tanouse14742c2023-05-31 10:27:49 -0700571 resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
572 resp.jsonValue["FunctionId"] = pcieFunctionId;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700573 resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
574 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600575}
576
577inline void
578 handlePCIeFunctionGet(App& app, const crow::Request& req,
579 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
580 const std::string& pcieDeviceId,
Ed Tanouse14742c2023-05-31 10:27:49 -0700581 const std::string& pcieFunctionIdStr)
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600582{
583 if (!redfish::setUpRedfishRoute(app, req, aResp))
584 {
585 return;
586 }
Ed Tanouse14742c2023-05-31 10:27:49 -0700587 uint64_t pcieFunctionId = 0;
588 std::from_chars_result result = std::from_chars(
589 &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId);
590 if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end())
591 {
592 messages::resourceNotFound(aResp->res, "PCIeFunction",
593 pcieFunctionIdStr);
594 return;
595 }
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600596
597 getValidPCIeDevicePath(
598 pcieDeviceId, aResp,
599 [aResp, pcieDeviceId, pcieFunctionId](const std::string& pcieDevicePath,
600 const std::string& service) {
601 getPCIeDeviceProperties(
602 aResp, pcieDevicePath, service,
603 [aResp, pcieDeviceId, pcieFunctionId](
604 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Myung Baed5e74b82023-05-31 11:28:02 -0500605 if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties))
606 {
607 messages::resourceNotFound(aResp->res, "PCIeFunction",
608 std::to_string(pcieFunctionId));
609 return;
610 }
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600611 addPCIeFunctionCommonProperties(aResp->res, pcieDeviceId,
612 pcieFunctionId);
613 addPCIeFunctionProperties(aResp->res, pcieFunctionId,
614 pcieDevProperties);
615 });
616 });
617}
618
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700619inline void requestRoutesSystemPCIeFunction(App& app)
620{
621 BMCWEB_ROUTE(
622 app,
623 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700624 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700625 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600626 std::bind_front(handlePCIeFunctionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700627}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800628
629} // namespace redfish