blob: 9dee9d34fd739f58d53271c7742712b4eabe6de1 [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 Tanous3ccb3ad2023-01-13 17:40:03 -080021#include "query.hpp"
22#include "registries/privilege_registry.hpp"
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -060023#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080024#include "utils/dbus_utils.hpp"
Lakshmi Yadlapatic49c3292023-04-19 16:42:35 -050025#include "utils/pcie_util.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,
Ed Tanousac106bf2023-06-07 09:24:59 -070041 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060042 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, {},
Ed Tanousac106bf2023-06-07 09:24:59 -070058 [pcieDevicePath, asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060059 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;
Ed Tanousac106bf2023-06-07 09:24:59 -070064 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060065 return;
66 }
67 callback(pcieDevicePath, object.begin()->first);
68 });
69 return;
70 }
71
72 BMCWEB_LOG_WARNING << "PCIe Device not found";
Ed Tanousac106bf2023-06-07 09:24:59 -070073 messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060074}
75
76static inline void getValidPCIeDevicePath(
77 const std::string& pcieDeviceId,
Ed Tanousac106bf2023-06-07 09:24:59 -070078 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060079 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,
Ed Tanousac106bf2023-06-07 09:24:59 -070084 [pcieDeviceId, asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060085 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;
Ed Tanousac106bf2023-06-07 09:24:59 -070091 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060092 return;
93 }
Ed Tanousac106bf2023-06-07 09:24:59 -070094 handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
95 callback);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060096 return;
97 });
98}
99
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600100static inline void handlePCIeDeviceCollectionGet(
101 crow::App& app, const crow::Request& req,
Ed Tanousac106bf2023-06-07 09:24:59 -0700102 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600103 const std::string& systemName)
104{
Ed Tanousac106bf2023-06-07 09:24:59 -0700105 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600106 {
107 return;
108 }
109 if (systemName != "system")
110 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700111 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
112 systemName);
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600113 return;
114 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600115
Ed Tanousac106bf2023-06-07 09:24:59 -0700116 asyncResp->res.addHeader(boost::beast::http::field::link,
117 "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
118 "PCIeDeviceCollection.json>; rel=describedby");
119 asyncResp->res.jsonValue["@odata.type"] =
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600120 "#PCIeDeviceCollection.PCIeDeviceCollection";
Ed Tanousac106bf2023-06-07 09:24:59 -0700121 asyncResp->res.jsonValue["@odata.id"] =
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600122 "/redfish/v1/Systems/system/PCIeDevices";
Ed Tanousac106bf2023-06-07 09:24:59 -0700123 asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
124 asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
125 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
126 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600127
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600128 collection_util::getCollectionMembers(
Ed Tanousac106bf2023-06-07 09:24:59 -0700129 asyncResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -0500130 pcieDeviceInterface);
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600131}
132
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700133inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -0700134{
Jason M. Billsadbe1922019-10-14 15:44:35 -0700135 /**
136 * Functions triggers appropriate requests on DBus
137 */
Ed Tanous22d268c2022-05-19 09:39:07 -0700138 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -0700139 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700140 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600141 std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700142}
143
Ed Tanousac106bf2023-06-07 09:24:59 -0700144inline void
Lakshmi Yadlapatie164f1b2023-04-12 17:01:34 -0500145 getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
146 const std::string& pcieDevicePath,
147 const std::string& service)
148{
149 sdbusplus::asio::getProperty<bool>(
150 *crow::connections::systemBus, service, pcieDevicePath,
151 "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
152 [asyncResp](const boost::system::error_code& ec, const bool value) {
153 if (ec)
154 {
155 if (ec.value() != EBADR)
156 {
157 BMCWEB_LOG_ERROR << "DBUS response error for Health "
158 << ec.value();
159 messages::internalError(asyncResp->res);
160 }
161 return;
162 }
163
164 if (!value)
165 {
166 asyncResp->res.jsonValue["Status"]["Health"] = "Critical";
167 }
168 });
169}
170
171inline void
Ed Tanousac106bf2023-06-07 09:24:59 -0700172 getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
173 const std::string& pcieDevicePath,
174 const std::string& service)
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500175{
176 sdbusplus::asio::getProperty<bool>(
177 *crow::connections::systemBus, service, pcieDevicePath,
178 "xyz.openbmc_project.Inventory.Item", "Present",
Ed Tanousac106bf2023-06-07 09:24:59 -0700179 [asyncResp](const boost::system::error_code& ec, const bool value) {
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500180 if (ec)
181 {
182 if (ec.value() != EBADR)
183 {
184 BMCWEB_LOG_ERROR << "DBUS response error for State";
Ed Tanousac106bf2023-06-07 09:24:59 -0700185 messages::internalError(asyncResp->res);
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500186 }
187 return;
188 }
189
190 if (!value)
191 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700192 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500193 }
194 });
195}
196
Ed Tanousac106bf2023-06-07 09:24:59 -0700197inline void
198 getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
199 const std::string& pcieDevicePath,
200 const std::string& service)
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600201{
202 sdbusplus::asio::getAllProperties(
203 *crow::connections::systemBus, service, pcieDevicePath,
204 "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanousac106bf2023-06-07 09:24:59 -0700205 [pcieDevicePath, asyncResp{asyncResp}](
206 const boost::system::error_code& ec,
207 const dbus::utility::DBusPropertiesMap& assetList) {
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600208 if (ec)
209 {
210 if (ec.value() != EBADR)
211 {
212 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
213 << ec.value();
Ed Tanousac106bf2023-06-07 09:24:59 -0700214 messages::internalError(asyncResp->res);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600215 }
216 return;
217 }
218
219 const std::string* manufacturer = nullptr;
220 const std::string* model = nullptr;
221 const std::string* partNumber = nullptr;
222 const std::string* serialNumber = nullptr;
223 const std::string* sparePartNumber = nullptr;
224
225 const bool success = sdbusplus::unpackPropertiesNoThrow(
226 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
227 manufacturer, "Model", model, "PartNumber", partNumber,
228 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
229
230 if (!success)
231 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700232 messages::internalError(asyncResp->res);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600233 return;
234 }
235
236 if (manufacturer != nullptr)
237 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700238 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600239 }
240 if (model != nullptr)
241 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700242 asyncResp->res.jsonValue["Model"] = *model;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600243 }
244
245 if (partNumber != nullptr)
246 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700247 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600248 }
249
250 if (serialNumber != nullptr)
251 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700252 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600253 }
254
255 if (sparePartNumber != nullptr && !sparePartNumber->empty())
256 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700257 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600258 }
259 });
260}
261
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600262inline void addPCIeDeviceProperties(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600263 crow::Response& resp, const std::string& pcieDeviceId,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600264 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
265{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600266 const std::string* deviceType = nullptr;
267 const std::string* generationInUse = nullptr;
268 const int64_t* lanesInUse = nullptr;
269
270 const bool success = sdbusplus::unpackPropertiesNoThrow(
271 dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
272 deviceType, "GenerationInUse", generationInUse, "LanesInUse",
Lakshmi Yadlapatibad2c4a2023-04-07 09:14:37 -0500273 lanesInUse);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600274
275 if (!success)
276 {
277 messages::internalError(resp);
278 return;
279 }
280
281 if (deviceType != nullptr && !deviceType->empty())
282 {
283 resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
284 }
285
286 if (generationInUse != nullptr)
287 {
288 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
Lakshmi Yadlapatic49c3292023-04-19 16:42:35 -0500289 pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600290
291 if (!redfishGenerationInUse)
292 {
293 messages::internalError(resp);
294 return;
295 }
296 if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
297 {
298 resp.jsonValue["PCIeInterface"]["PCIeType"] =
299 *redfishGenerationInUse;
300 }
301 }
302
303 // The default value of LanesInUse is 0, and the field will be
304 // left as off if it is a default value.
305 if (lanesInUse != nullptr && *lanesInUse != 0)
306 {
307 resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
308 }
309
Ed Tanousef4c65b2023-04-24 15:28:50 -0700310 resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format(
311 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
312 pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600313}
314
315inline void getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700316 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600317 const std::string& pcieDevicePath, const std::string& service,
318 const std::function<void(
319 const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
320{
321 sdbusplus::asio::getAllProperties(
322 *crow::connections::systemBus, service, pcieDevicePath,
323 "xyz.openbmc_project.Inventory.Item.PCIeDevice",
Ed Tanousac106bf2023-06-07 09:24:59 -0700324 [asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600325 callback](const boost::system::error_code& ec,
326 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
327 if (ec)
328 {
329 if (ec.value() != EBADR)
330 {
331 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
Ed Tanousac106bf2023-06-07 09:24:59 -0700332 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600333 }
334 return;
335 }
336 callback(pcieDevProperties);
337 });
338}
339
340inline void addPCIeDeviceCommonProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700341 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600342 const std::string& pcieDeviceId)
343{
Ed Tanousac106bf2023-06-07 09:24:59 -0700344 asyncResp->res.addHeader(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600345 boost::beast::http::field::link,
346 "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
Ed Tanousac106bf2023-06-07 09:24:59 -0700347 asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
348 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -0700349 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700350 asyncResp->res.jsonValue["Name"] = "PCIe Device";
351 asyncResp->res.jsonValue["Id"] = pcieDeviceId;
352 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
Lakshmi Yadlapatie164f1b2023-04-12 17:01:34 -0500353 asyncResp->res.jsonValue["Status"]["Health"] = "OK";
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600354}
355
Ed Tanousac106bf2023-06-07 09:24:59 -0700356inline void
357 handlePCIeDeviceGet(App& app, const crow::Request& req,
358 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
359 const std::string& systemName,
360 const std::string& pcieDeviceId)
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600361{
Ed Tanousac106bf2023-06-07 09:24:59 -0700362 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600363 {
364 return;
365 }
366 if (systemName != "system")
367 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700368 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
369 systemName);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600370 return;
371 }
372
373 getValidPCIeDevicePath(
Ed Tanousac106bf2023-06-07 09:24:59 -0700374 pcieDeviceId, asyncResp,
375 [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
376 const std::string& service) {
377 addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
378 getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
379 getPCIeDeviceState(asyncResp, pcieDevicePath, service);
Lakshmi Yadlapatie164f1b2023-04-12 17:01:34 -0500380 getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600381 getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700382 asyncResp, pcieDevicePath, service,
383 [asyncResp, pcieDeviceId](
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600384 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanousac106bf2023-06-07 09:24:59 -0700385 addPCIeDeviceProperties(asyncResp->res, pcieDeviceId,
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600386 pcieDevProperties);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600387 });
388 });
389}
390
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700391inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800392{
Ed Tanous22d268c2022-05-19 09:39:07 -0700393 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700394 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700395 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600396 std::bind_front(handlePCIeDeviceGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700397}
398
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600399inline void addPCIeFunctionList(
400 crow::Response& res, const std::string& pcieDeviceId,
401 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
402{
403 nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
404 pcieFunctionList = nlohmann::json::array();
405 static constexpr const int maxPciFunctionNum = 8;
406
407 for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
408 {
409 // Check if this function exists by
410 // looking for a device ID
Patrick Williams89492a12023-05-10 07:51:34 -0500411 std::string devIDProperty = "Function" + std::to_string(functionNum) +
412 "DeviceId";
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600413 const std::string* property = nullptr;
414 for (const auto& propEntry : pcieDevProperties)
415 {
416 if (propEntry.first == devIDProperty)
417 {
418 property = std::get_if<std::string>(&propEntry.second);
419 break;
420 }
421 }
422 if (property == nullptr || property->empty())
423 {
424 continue;
425 }
426
427 nlohmann::json::object_t pcieFunction;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700428 pcieFunction["@odata.id"] = boost::urls::format(
429 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
430 pcieDeviceId, std::to_string(functionNum));
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500431 pcieFunctionList.emplace_back(std::move(pcieFunction));
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600432 }
433 res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
434}
435
436inline void handlePCIeFunctionCollectionGet(
437 App& app, const crow::Request& req,
Ed Tanousac106bf2023-06-07 09:24:59 -0700438 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600439 const std::string& pcieDeviceId)
440{
Ed Tanousac106bf2023-06-07 09:24:59 -0700441 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600442 {
443 return;
444 }
445
446 getValidPCIeDevicePath(
Ed Tanousac106bf2023-06-07 09:24:59 -0700447 pcieDeviceId, asyncResp,
448 [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
449 const std::string& service) {
450 asyncResp->res.addHeader(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600451 boost::beast::http::field::link,
452 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
Ed Tanousac106bf2023-06-07 09:24:59 -0700453 asyncResp->res.jsonValue["@odata.type"] =
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600454 "#PCIeFunctionCollection.PCIeFunctionCollection";
Ed Tanousac106bf2023-06-07 09:24:59 -0700455 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -0700456 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
457 pcieDeviceId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700458 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
459 asyncResp->res.jsonValue["Description"] =
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600460 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
461 getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700462 asyncResp, pcieDevicePath, service,
463 [asyncResp, pcieDeviceId](
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600464 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanousac106bf2023-06-07 09:24:59 -0700465 addPCIeFunctionList(asyncResp->res, pcieDeviceId,
466 pcieDevProperties);
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600467 });
468 });
469}
470
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700471inline void requestRoutesSystemPCIeFunctionCollection(App& app)
472{
473 /**
474 * Functions triggers appropriate requests on DBus
475 */
476 BMCWEB_ROUTE(app,
477 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700478 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700479 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600480 std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700481}
482
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600483inline bool validatePCIeFunctionId(
Myung Baed5e74b82023-05-31 11:28:02 -0500484 uint64_t pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600485 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
486{
Myung Baed5e74b82023-05-31 11:28:02 -0500487 std::string functionName = "Function" + std::to_string(pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600488 std::string devIDProperty = functionName + "DeviceId";
489
490 const std::string* devIdProperty = nullptr;
491 for (const auto& property : pcieDevProperties)
492 {
493 if (property.first == devIDProperty)
494 {
495 devIdProperty = std::get_if<std::string>(&property.second);
496 break;
497 }
498 }
499 return (devIdProperty != nullptr && !devIdProperty->empty());
500}
501
502inline void addPCIeFunctionProperties(
Ed Tanouse14742c2023-05-31 10:27:49 -0700503 crow::Response& resp, uint64_t pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600504 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
505{
Ed Tanouse14742c2023-05-31 10:27:49 -0700506 std::string functionName = "Function" + std::to_string(pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600507 for (const auto& property : pcieDevProperties)
508 {
509 const std::string* strProperty =
510 std::get_if<std::string>(&property.second);
511
512 if (property.first == functionName + "DeviceId")
513 {
514 resp.jsonValue["DeviceId"] = *strProperty;
515 }
516 if (property.first == functionName + "VendorId")
517 {
518 resp.jsonValue["VendorId"] = *strProperty;
519 }
520 // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
521 // property strings should be mapped correctly to ensure these
522 // strings are Redfish enum values. For now just check for empty.
523 if (property.first == functionName + "FunctionType")
524 {
525 if (!strProperty->empty())
526 {
527 resp.jsonValue["FunctionType"] = *strProperty;
528 }
529 }
530 if (property.first == functionName + "DeviceClass")
531 {
532 if (!strProperty->empty())
533 {
534 resp.jsonValue["DeviceClass"] = *strProperty;
535 }
536 }
537 if (property.first == functionName + "ClassCode")
538 {
539 resp.jsonValue["ClassCode"] = *strProperty;
540 }
541 if (property.first == functionName + "RevisionId")
542 {
543 resp.jsonValue["RevisionId"] = *strProperty;
544 }
545 if (property.first == functionName + "SubsystemId")
546 {
547 resp.jsonValue["SubsystemId"] = *strProperty;
548 }
549 if (property.first == functionName + "SubsystemVendorId")
550 {
551 resp.jsonValue["SubsystemVendorId"] = *strProperty;
552 }
553 }
554}
555
556inline void addPCIeFunctionCommonProperties(crow::Response& resp,
557 const std::string& pcieDeviceId,
Ed Tanouse14742c2023-05-31 10:27:49 -0700558 uint64_t pcieFunctionId)
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600559{
560 resp.addHeader(
561 boost::beast::http::field::link,
562 "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
563 resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700564 resp.jsonValue["@odata.id"] = boost::urls::format(
565 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
566 pcieDeviceId, pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600567 resp.jsonValue["Name"] = "PCIe Function";
Ed Tanouse14742c2023-05-31 10:27:49 -0700568 resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
569 resp.jsonValue["FunctionId"] = pcieFunctionId;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700570 resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
571 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600572}
573
574inline void
575 handlePCIeFunctionGet(App& app, const crow::Request& req,
Ed Tanousac106bf2023-06-07 09:24:59 -0700576 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600577 const std::string& pcieDeviceId,
Ed Tanouse14742c2023-05-31 10:27:49 -0700578 const std::string& pcieFunctionIdStr)
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600579{
Ed Tanousac106bf2023-06-07 09:24:59 -0700580 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600581 {
582 return;
583 }
Ed Tanouse14742c2023-05-31 10:27:49 -0700584 uint64_t pcieFunctionId = 0;
585 std::from_chars_result result = std::from_chars(
586 &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId);
587 if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end())
588 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700589 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
Ed Tanouse14742c2023-05-31 10:27:49 -0700590 pcieFunctionIdStr);
591 return;
592 }
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600593
Ed Tanousac106bf2023-06-07 09:24:59 -0700594 getValidPCIeDevicePath(pcieDeviceId, asyncResp,
595 [asyncResp, pcieDeviceId,
596 pcieFunctionId](const std::string& pcieDevicePath,
597 const std::string& service) {
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600598 getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700599 asyncResp, pcieDevicePath, service,
600 [asyncResp, pcieDeviceId, pcieFunctionId](
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600601 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanousac106bf2023-06-07 09:24:59 -0700602 addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600603 pcieFunctionId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700604 addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600605 pcieDevProperties);
606 });
Ed Tanousac106bf2023-06-07 09:24:59 -0700607 });
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600608}
609
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700610inline void requestRoutesSystemPCIeFunction(App& app)
611{
612 BMCWEB_ROUTE(
613 app,
614 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700615 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700616 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600617 std::bind_front(handlePCIeFunctionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700618}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800619
620} // namespace redfish