xref: /openbmc/bmcweb/redfish-core/lib/pcie.hpp (revision d78572018fc2022091ff8b8eb5a7fef2172ba3d6)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
4f5c9f8bdSJason M. Bills 
5f5c9f8bdSJason M. Bills #pragma once
6f5c9f8bdSJason M. Bills 
7*d7857201SEd Tanous #include "bmcweb_config.h"
8*d7857201SEd Tanous 
93ccb3adbSEd Tanous #include "app.hpp"
10*d7857201SEd Tanous #include "async_resp.hpp"
117a1dbc48SGeorge Liu #include "dbus_utility.hpp"
12*d7857201SEd Tanous #include "error_messages.hpp"
13*d7857201SEd Tanous #include "generated/enums/pcie_device.hpp"
14*d7857201SEd Tanous #include "generated/enums/pcie_slots.hpp"
15539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
16*d7857201SEd Tanous #include "http_request.hpp"
17*d7857201SEd Tanous #include "logging.hpp"
183ccb3adbSEd Tanous #include "query.hpp"
193ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
203ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
21c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp"
220ec8b83dSEd Tanous 
23*d7857201SEd Tanous #include <asm-generic/errno.h>
24*d7857201SEd Tanous 
25*d7857201SEd Tanous #include <boost/beast/http/field.hpp>
26*d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
27ef4c65b7SEd Tanous #include <boost/url/format.hpp>
28d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
29f5c9f8bdSJason M. Bills 
30*d7857201SEd Tanous #include <array>
31*d7857201SEd Tanous #include <charconv>
32*d7857201SEd Tanous #include <cstddef>
33*d7857201SEd Tanous #include <cstdint>
34*d7857201SEd Tanous #include <format>
35*d7857201SEd Tanous #include <functional>
368c1d0549SMyung Bae #include <limits>
37*d7857201SEd Tanous #include <memory>
38*d7857201SEd Tanous #include <optional>
39*d7857201SEd Tanous #include <string>
40*d7857201SEd Tanous #include <string_view>
41*d7857201SEd Tanous #include <system_error>
42*d7857201SEd Tanous #include <utility>
43*d7857201SEd Tanous #include <variant>
448c1d0549SMyung Bae 
45f5c9f8bdSJason M. Bills namespace redfish
46f5c9f8bdSJason M. Bills {
47f5c9f8bdSJason M. Bills 
4889492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
4994c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
5094c3a10bSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
51a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = {
52a5409991SLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeSlot"};
53f5c9f8bdSJason M. Bills 
handlePCIeDevicePath(const std::string & pcieDeviceId,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::MapperGetSubTreePathsResponse & pcieDevicePaths,const std::function<void (const std::string & pcieDevicePath,const std::string & service)> & callback)544ff0f1f4SEd Tanous inline void handlePCIeDevicePath(
55543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
56ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
57543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
58543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
59543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
60543f9a75SLakshmi Yadlapati 
61543f9a75SLakshmi Yadlapati {
62543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
63543f9a75SLakshmi Yadlapati     {
64543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
65543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
66543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
67543f9a75SLakshmi Yadlapati         {
68543f9a75SLakshmi Yadlapati             continue;
69543f9a75SLakshmi Yadlapati         }
70543f9a75SLakshmi Yadlapati 
71543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
723a58c5a8SKonstantin Aladyshev             pcieDevicePath, pcieDeviceInterface,
73ac106bf6SEd Tanous             [pcieDevicePath, asyncResp,
74543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
75543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
76543f9a75SLakshmi Yadlapati                 if (ec || object.empty())
77543f9a75SLakshmi Yadlapati                 {
7862598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error {}", ec);
79ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
80543f9a75SLakshmi Yadlapati                     return;
81543f9a75SLakshmi Yadlapati                 }
82543f9a75SLakshmi Yadlapati                 callback(pcieDevicePath, object.begin()->first);
83543f9a75SLakshmi Yadlapati             });
84543f9a75SLakshmi Yadlapati         return;
85543f9a75SLakshmi Yadlapati     }
86543f9a75SLakshmi Yadlapati 
8762598e31SEd Tanous     BMCWEB_LOG_WARNING("PCIe Device not found");
88ac106bf6SEd Tanous     messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
89543f9a75SLakshmi Yadlapati }
90543f9a75SLakshmi Yadlapati 
getValidPCIeDevicePath(const std::string & pcieDeviceId,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::function<void (const std::string & pcieDevicePath,const std::string & service)> & callback)914ff0f1f4SEd Tanous inline void getValidPCIeDevicePath(
92543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
93ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
94543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
95543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
96543f9a75SLakshmi Yadlapati {
97543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
9894c3a10bSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
99ac106bf6SEd Tanous         [pcieDeviceId, asyncResp,
100543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
101543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
102543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
103543f9a75SLakshmi Yadlapati             if (ec)
104543f9a75SLakshmi Yadlapati             {
10562598e31SEd Tanous                 BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
106ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
107543f9a75SLakshmi Yadlapati                 return;
108543f9a75SLakshmi Yadlapati             }
109ac106bf6SEd Tanous             handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
110ac106bf6SEd Tanous                                  callback);
111543f9a75SLakshmi Yadlapati             return;
112543f9a75SLakshmi Yadlapati         });
113543f9a75SLakshmi Yadlapati }
114543f9a75SLakshmi Yadlapati 
handlePCIeDeviceCollectionGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)1154ff0f1f4SEd Tanous inline void handlePCIeDeviceCollectionGet(
116b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
117ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
118b38fa2abSLakshmi Yadlapati     const std::string& systemName)
119b38fa2abSLakshmi Yadlapati {
120ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
121b38fa2abSLakshmi Yadlapati     {
122b38fa2abSLakshmi Yadlapati         return;
123b38fa2abSLakshmi Yadlapati     }
12425b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
1257f3e84a1SEd Tanous     {
1267f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
1277f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1287f3e84a1SEd Tanous                                    systemName);
1297f3e84a1SEd Tanous         return;
1307f3e84a1SEd Tanous     }
131253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
132b38fa2abSLakshmi Yadlapati     {
133ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
134ac106bf6SEd Tanous                                    systemName);
135b38fa2abSLakshmi Yadlapati         return;
136b38fa2abSLakshmi Yadlapati     }
137543f9a75SLakshmi Yadlapati 
138ac106bf6SEd Tanous     asyncResp->res.addHeader(boost::beast::http::field::link,
139b38fa2abSLakshmi Yadlapati                              "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
140b38fa2abSLakshmi Yadlapati                              "PCIeDeviceCollection.json>; rel=describedby");
141ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
142b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
143253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = std::format(
144253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME);
145ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
146ac106bf6SEd Tanous     asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
147b38fa2abSLakshmi Yadlapati 
14870c4d545SLakshmi Yadlapati     pcie_util::getPCIeDeviceList(asyncResp,
14970c4d545SLakshmi Yadlapati                                  nlohmann::json::json_pointer("/Members"));
150b38fa2abSLakshmi Yadlapati }
151b38fa2abSLakshmi Yadlapati 
requestRoutesSystemPCIeDeviceCollection(App & app)1527e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
153adbe192aSJason M. Bills {
154adbe192aSJason M. Bills     /**
155adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
156adbe192aSJason M. Bills      */
15722d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
158ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1597e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
160b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
161f5c9f8bdSJason M. Bills }
162f5c9f8bdSJason M. Bills 
addPCIeSlotProperties(crow::Response & res,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & pcieSlotProperties)163a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties(
164a5409991SLakshmi Yadlapati     crow::Response& res, const boost::system::error_code& ec,
165a5409991SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieSlotProperties)
166a5409991SLakshmi Yadlapati {
167a5409991SLakshmi Yadlapati     if (ec)
168a5409991SLakshmi Yadlapati     {
16962598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}",
17062598e31SEd Tanous                          ec.value());
171a5409991SLakshmi Yadlapati         messages::internalError(res);
172a5409991SLakshmi Yadlapati         return;
173a5409991SLakshmi Yadlapati     }
174a5409991SLakshmi Yadlapati     std::string generation;
175a5409991SLakshmi Yadlapati     size_t lanes = 0;
176a5409991SLakshmi Yadlapati     std::string slotType;
177a5409991SLakshmi Yadlapati 
178a5409991SLakshmi Yadlapati     bool success = sdbusplus::unpackPropertiesNoThrow(
179a5409991SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation",
180a5409991SLakshmi Yadlapati         generation, "Lanes", lanes, "SlotType", slotType);
181a5409991SLakshmi Yadlapati 
182a5409991SLakshmi Yadlapati     if (!success)
183a5409991SLakshmi Yadlapati     {
184a5409991SLakshmi Yadlapati         messages::internalError(res);
185a5409991SLakshmi Yadlapati         return;
186a5409991SLakshmi Yadlapati     }
187a5409991SLakshmi Yadlapati 
188a5409991SLakshmi Yadlapati     std::optional<pcie_device::PCIeTypes> pcieType =
189a5409991SLakshmi Yadlapati         pcie_util::redfishPcieGenerationFromDbus(generation);
190a5409991SLakshmi Yadlapati     if (!pcieType)
191a5409991SLakshmi Yadlapati     {
19262598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation);
193a5409991SLakshmi Yadlapati     }
194a5409991SLakshmi Yadlapati     else
195a5409991SLakshmi Yadlapati     {
196a5409991SLakshmi Yadlapati         if (*pcieType == pcie_device::PCIeTypes::Invalid)
197a5409991SLakshmi Yadlapati         {
19862598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation);
199a5409991SLakshmi Yadlapati             messages::internalError(res);
200a5409991SLakshmi Yadlapati             return;
201a5409991SLakshmi Yadlapati         }
202a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["PCIeType"] = *pcieType;
203a5409991SLakshmi Yadlapati     }
204a5409991SLakshmi Yadlapati 
20582f80326SKonstantin Aladyshev     if (lanes != 0)
20682f80326SKonstantin Aladyshev     {
207a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["Lanes"] = lanes;
20882f80326SKonstantin Aladyshev     }
209a5409991SLakshmi Yadlapati 
210a5409991SLakshmi Yadlapati     std::optional<pcie_slots::SlotTypes> redfishSlotType =
211a5409991SLakshmi Yadlapati         pcie_util::dbusSlotTypeToRf(slotType);
212a5409991SLakshmi Yadlapati     if (!redfishSlotType)
213a5409991SLakshmi Yadlapati     {
21462598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType);
215a5409991SLakshmi Yadlapati     }
216a5409991SLakshmi Yadlapati     else
217a5409991SLakshmi Yadlapati     {
218a5409991SLakshmi Yadlapati         if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
219a5409991SLakshmi Yadlapati         {
22062598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType);
221a5409991SLakshmi Yadlapati             messages::internalError(res);
222a5409991SLakshmi Yadlapati             return;
223a5409991SLakshmi Yadlapati         }
224a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["SlotType"] = *redfishSlotType;
225a5409991SLakshmi Yadlapati     }
226a5409991SLakshmi Yadlapati }
227a5409991SLakshmi Yadlapati 
getPCIeDeviceSlotPath(const std::string & pcieDevicePath,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::function<void (const std::string & pcieDeviceSlot)> && callback)228a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath(
229a5409991SLakshmi Yadlapati     const std::string& pcieDevicePath,
230a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
231a5409991SLakshmi Yadlapati     std::function<void(const std::string& pcieDeviceSlot)>&& callback)
232a5409991SLakshmi Yadlapati {
233a5409991SLakshmi Yadlapati     std::string associationPath = pcieDevicePath + "/contained_by";
234a5409991SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
235a5409991SLakshmi Yadlapati         associationPath, sdbusplus::message::object_path(inventoryPath), 0,
236a5409991SLakshmi Yadlapati         pcieSlotInterface,
2378cb2c024SEd Tanous         [callback = std::move(callback), asyncResp, pcieDevicePath](
238a5409991SLakshmi Yadlapati             const boost::system::error_code& ec,
239a5409991SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& endpoints) {
240a5409991SLakshmi Yadlapati             if (ec)
241a5409991SLakshmi Yadlapati             {
242a5409991SLakshmi Yadlapati                 if (ec.value() == EBADR)
243a5409991SLakshmi Yadlapati                 {
244a5409991SLakshmi Yadlapati                     // Missing association is not an error
245a5409991SLakshmi Yadlapati                     return;
246a5409991SLakshmi Yadlapati                 }
24762598e31SEd Tanous                 BMCWEB_LOG_ERROR(
24862598e31SEd Tanous                     "DBUS response error for getAssociatedSubTreePaths {}",
24962598e31SEd Tanous                     ec.value());
250a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
251a5409991SLakshmi Yadlapati                 return;
252a5409991SLakshmi Yadlapati             }
253a5409991SLakshmi Yadlapati             if (endpoints.size() > 1)
254a5409991SLakshmi Yadlapati             {
25562598e31SEd Tanous                 BMCWEB_LOG_ERROR(
256a6bd55b0SGunnar Mills                     "PCIeDevice {} is associated with more than one PCIeSlot: {}",
257a6bd55b0SGunnar Mills                     pcieDevicePath, endpoints.size());
258a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
259a5409991SLakshmi Yadlapati                 return;
260a5409991SLakshmi Yadlapati             }
261a5409991SLakshmi Yadlapati             if (endpoints.empty())
262a5409991SLakshmi Yadlapati             {
263bd79bce8SPatrick Williams                 // If the device doesn't have an association, return without
264bd79bce8SPatrick Williams                 // PCIe Slot properties
26562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot");
266a5409991SLakshmi Yadlapati                 return;
267a5409991SLakshmi Yadlapati             }
268a5409991SLakshmi Yadlapati             callback(endpoints[0]);
269a5409991SLakshmi Yadlapati         });
270a5409991SLakshmi Yadlapati }
271a5409991SLakshmi Yadlapati 
afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDeviceSlot,const boost::system::error_code & ec,const dbus::utility::MapperGetObject & object)272bd79bce8SPatrick Williams inline void afterGetDbusObject(
273bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
274bd79bce8SPatrick Williams     const std::string& pcieDeviceSlot, const boost::system::error_code& ec,
275a5409991SLakshmi Yadlapati     const dbus::utility::MapperGetObject& object)
276a5409991SLakshmi Yadlapati {
277a5409991SLakshmi Yadlapati     if (ec || object.empty())
278a5409991SLakshmi Yadlapati     {
27962598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}",
28062598e31SEd Tanous                          ec.value());
281a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
282a5409991SLakshmi Yadlapati         return;
283a5409991SLakshmi Yadlapati     }
284deae6a78SEd Tanous     dbus::utility::getAllProperties(
285deae6a78SEd Tanous         object.begin()->first, pcieDeviceSlot,
286a5409991SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
287a5409991SLakshmi Yadlapati         [asyncResp](
288a5409991SLakshmi Yadlapati             const boost::system::error_code& ec2,
289a5409991SLakshmi Yadlapati             const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
290a5409991SLakshmi Yadlapati             addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
291a5409991SLakshmi Yadlapati         });
292a5409991SLakshmi Yadlapati }
293a5409991SLakshmi Yadlapati 
afterGetPCIeDeviceSlotPath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDeviceSlot)294a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath(
295a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
296a5409991SLakshmi Yadlapati     const std::string& pcieDeviceSlot)
297a5409991SLakshmi Yadlapati {
298a5409991SLakshmi Yadlapati     dbus::utility::getDbusObject(
299a5409991SLakshmi Yadlapati         pcieDeviceSlot, pcieSlotInterface,
300a5409991SLakshmi Yadlapati         [asyncResp,
301a5409991SLakshmi Yadlapati          pcieDeviceSlot](const boost::system::error_code& ec,
302a5409991SLakshmi Yadlapati                          const dbus::utility::MapperGetObject& object) {
303a5409991SLakshmi Yadlapati             afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
304a5409991SLakshmi Yadlapati         });
305a5409991SLakshmi Yadlapati }
306a5409991SLakshmi Yadlapati 
getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDevicePath,const std::string & service)307bd79bce8SPatrick Williams inline void getPCIeDeviceHealth(
308bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
309bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
310e164f1b6SLakshmi Yadlapati {
311deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
312deae6a78SEd Tanous         service, pcieDevicePath,
313e164f1b6SLakshmi Yadlapati         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
314e164f1b6SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, const bool value) {
315e164f1b6SLakshmi Yadlapati             if (ec)
316e164f1b6SLakshmi Yadlapati             {
317e164f1b6SLakshmi Yadlapati                 if (ec.value() != EBADR)
318e164f1b6SLakshmi Yadlapati                 {
31962598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
32062598e31SEd Tanous                                      ec.value());
321e164f1b6SLakshmi Yadlapati                     messages::internalError(asyncResp->res);
322e164f1b6SLakshmi Yadlapati                 }
323e164f1b6SLakshmi Yadlapati                 return;
324e164f1b6SLakshmi Yadlapati             }
325e164f1b6SLakshmi Yadlapati 
326e164f1b6SLakshmi Yadlapati             if (!value)
327e164f1b6SLakshmi Yadlapati             {
328539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
329539d8c6bSEd Tanous                     resource::Health::Critical;
330e164f1b6SLakshmi Yadlapati             }
331e164f1b6SLakshmi Yadlapati         });
332e164f1b6SLakshmi Yadlapati }
333e164f1b6SLakshmi Yadlapati 
getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDevicePath,const std::string & service)334bd79bce8SPatrick Williams inline void getPCIeDeviceState(
335bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
336bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
337c6bb3285SLakshmi Yadlapati {
338deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
339deae6a78SEd Tanous         service, pcieDevicePath, "xyz.openbmc_project.Inventory.Item",
340deae6a78SEd Tanous         "Present",
341a5409991SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, bool value) {
342c6bb3285SLakshmi Yadlapati             if (ec)
343c6bb3285SLakshmi Yadlapati             {
344c6bb3285SLakshmi Yadlapati                 if (ec.value() != EBADR)
345c6bb3285SLakshmi Yadlapati                 {
34662598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State");
347ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
348c6bb3285SLakshmi Yadlapati                 }
349c6bb3285SLakshmi Yadlapati                 return;
350c6bb3285SLakshmi Yadlapati             }
351c6bb3285SLakshmi Yadlapati 
352c6bb3285SLakshmi Yadlapati             if (!value)
353c6bb3285SLakshmi Yadlapati             {
354539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
355539d8c6bSEd Tanous                     resource::State::Absent;
356c6bb3285SLakshmi Yadlapati             }
357c6bb3285SLakshmi Yadlapati         });
358c6bb3285SLakshmi Yadlapati }
359c6bb3285SLakshmi Yadlapati 
getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDevicePath,const std::string & service)360bd79bce8SPatrick Williams inline void getPCIeDeviceAsset(
361bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
362bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
363913e7732SSunnySrivastava1984 {
364deae6a78SEd Tanous     dbus::utility::getAllProperties(
365deae6a78SEd Tanous         service, pcieDevicePath,
366913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
367ac106bf6SEd Tanous         [pcieDevicePath, asyncResp{asyncResp}](
368ac106bf6SEd Tanous             const boost::system::error_code& ec,
369913e7732SSunnySrivastava1984             const dbus::utility::DBusPropertiesMap& assetList) {
370913e7732SSunnySrivastava1984             if (ec)
371913e7732SSunnySrivastava1984             {
372913e7732SSunnySrivastava1984                 if (ec.value() != EBADR)
373913e7732SSunnySrivastava1984                 {
37462598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties{}",
37562598e31SEd Tanous                                      ec.value());
376ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
377913e7732SSunnySrivastava1984                 }
378913e7732SSunnySrivastava1984                 return;
379913e7732SSunnySrivastava1984             }
380913e7732SSunnySrivastava1984 
381913e7732SSunnySrivastava1984             const std::string* manufacturer = nullptr;
382913e7732SSunnySrivastava1984             const std::string* model = nullptr;
383913e7732SSunnySrivastava1984             const std::string* partNumber = nullptr;
384913e7732SSunnySrivastava1984             const std::string* serialNumber = nullptr;
385913e7732SSunnySrivastava1984             const std::string* sparePartNumber = nullptr;
386913e7732SSunnySrivastava1984 
387913e7732SSunnySrivastava1984             const bool success = sdbusplus::unpackPropertiesNoThrow(
388913e7732SSunnySrivastava1984                 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
389913e7732SSunnySrivastava1984                 manufacturer, "Model", model, "PartNumber", partNumber,
390bd79bce8SPatrick Williams                 "SerialNumber", serialNumber, "SparePartNumber",
391bd79bce8SPatrick Williams                 sparePartNumber);
392913e7732SSunnySrivastava1984 
393913e7732SSunnySrivastava1984             if (!success)
394913e7732SSunnySrivastava1984             {
395ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
396913e7732SSunnySrivastava1984                 return;
397913e7732SSunnySrivastava1984             }
398913e7732SSunnySrivastava1984 
399913e7732SSunnySrivastava1984             if (manufacturer != nullptr)
400913e7732SSunnySrivastava1984             {
401ac106bf6SEd Tanous                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
402913e7732SSunnySrivastava1984             }
403913e7732SSunnySrivastava1984             if (model != nullptr)
404913e7732SSunnySrivastava1984             {
405ac106bf6SEd Tanous                 asyncResp->res.jsonValue["Model"] = *model;
406913e7732SSunnySrivastava1984             }
407913e7732SSunnySrivastava1984 
408913e7732SSunnySrivastava1984             if (partNumber != nullptr)
409913e7732SSunnySrivastava1984             {
410ac106bf6SEd Tanous                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
411913e7732SSunnySrivastava1984             }
412913e7732SSunnySrivastava1984 
413913e7732SSunnySrivastava1984             if (serialNumber != nullptr)
414913e7732SSunnySrivastava1984             {
415ac106bf6SEd Tanous                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
416913e7732SSunnySrivastava1984             }
417913e7732SSunnySrivastava1984 
418913e7732SSunnySrivastava1984             if (sparePartNumber != nullptr && !sparePartNumber->empty())
419913e7732SSunnySrivastava1984             {
420ac106bf6SEd Tanous                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
421913e7732SSunnySrivastava1984             }
422913e7732SSunnySrivastava1984         });
423913e7732SSunnySrivastava1984 }
424913e7732SSunnySrivastava1984 
addPCIeDeviceProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDeviceId,const dbus::utility::DBusPropertiesMap & pcieDevProperties)425543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
426a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
427a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId,
428543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
429f5c9f8bdSJason M. Bills {
430d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
431814bf20aSKonstantin Aladyshev     const std::string* generationSupported = nullptr;
4329bb0a7feSKonstantin Aladyshev     const size_t* lanesInUse = nullptr;
433814bf20aSKonstantin Aladyshev     const size_t* maxLanes = nullptr;
434d1bde9e5SKrzysztof Grobelny 
435d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
436609ba4c9SEd Tanous         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse",
437609ba4c9SEd Tanous         generationInUse, "GenerationSupported", generationSupported,
438609ba4c9SEd Tanous         "LanesInUse", lanesInUse, "MaxLanes", maxLanes);
439d1bde9e5SKrzysztof Grobelny 
440d1bde9e5SKrzysztof Grobelny     if (!success)
441d1bde9e5SKrzysztof Grobelny     {
442a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
443d1bde9e5SKrzysztof Grobelny         return;
444d1bde9e5SKrzysztof Grobelny     }
445d1bde9e5SKrzysztof Grobelny 
446d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
447d1bde9e5SKrzysztof Grobelny     {
4480ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
449c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
450543f9a75SLakshmi Yadlapati 
451d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
452d1bde9e5SKrzysztof Grobelny         {
45362598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
45462598e31SEd Tanous                                *generationInUse);
455cf3b484eSLakshmi Yadlapati         }
456cf3b484eSLakshmi Yadlapati         else
457cf3b484eSLakshmi Yadlapati         {
458cf3b484eSLakshmi Yadlapati             if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
459cf3b484eSLakshmi Yadlapati             {
46062598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
46162598e31SEd Tanous                                  *generationInUse);
462a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
463d1bde9e5SKrzysztof Grobelny                 return;
464d1bde9e5SKrzysztof Grobelny             }
465a5409991SLakshmi Yadlapati             asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
466d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
467d1bde9e5SKrzysztof Grobelny         }
468a9f68bb5STony Lee     }
469d1bde9e5SKrzysztof Grobelny 
470814bf20aSKonstantin Aladyshev     if (generationSupported != nullptr)
471814bf20aSKonstantin Aladyshev     {
472814bf20aSKonstantin Aladyshev         std::optional<pcie_device::PCIeTypes> redfishGenerationSupported =
473814bf20aSKonstantin Aladyshev             pcie_util::redfishPcieGenerationFromDbus(*generationSupported);
474814bf20aSKonstantin Aladyshev 
475814bf20aSKonstantin Aladyshev         if (!redfishGenerationSupported)
476814bf20aSKonstantin Aladyshev         {
47762598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
47862598e31SEd Tanous                                *generationSupported);
479814bf20aSKonstantin Aladyshev         }
480814bf20aSKonstantin Aladyshev         else
481814bf20aSKonstantin Aladyshev         {
482814bf20aSKonstantin Aladyshev             if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid)
483814bf20aSKonstantin Aladyshev             {
48462598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
48562598e31SEd Tanous                                  *generationSupported);
486814bf20aSKonstantin Aladyshev                 messages::internalError(asyncResp->res);
487814bf20aSKonstantin Aladyshev                 return;
488814bf20aSKonstantin Aladyshev             }
489814bf20aSKonstantin Aladyshev             asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] =
490814bf20aSKonstantin Aladyshev                 *redfishGenerationSupported;
491814bf20aSKonstantin Aladyshev         }
492814bf20aSKonstantin Aladyshev     }
493814bf20aSKonstantin Aladyshev 
4948c1d0549SMyung Bae     if (lanesInUse != nullptr)
495543f9a75SLakshmi Yadlapati     {
4968c1d0549SMyung Bae         if (*lanesInUse == std::numeric_limits<size_t>::max())
4978c1d0549SMyung Bae         {
4988c1d0549SMyung Bae             // The default value of LanesInUse is "maxint", and the field will
4998c1d0549SMyung Bae             // be null if it is a default value.
5008c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr;
5018c1d0549SMyung Bae         }
5028c1d0549SMyung Bae         else
5038c1d0549SMyung Bae         {
5048c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] =
5058c1d0549SMyung Bae                 *lanesInUse;
5068c1d0549SMyung Bae         }
507543f9a75SLakshmi Yadlapati     }
508814bf20aSKonstantin Aladyshev     // The default value of MaxLanes is 0, and the field will be
509814bf20aSKonstantin Aladyshev     // left as off if it is a default value.
510814bf20aSKonstantin Aladyshev     if (maxLanes != nullptr && *maxLanes != 0)
511814bf20aSKonstantin Aladyshev     {
512814bf20aSKonstantin Aladyshev         asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes;
513814bf20aSKonstantin Aladyshev     }
514543f9a75SLakshmi Yadlapati 
515a5409991SLakshmi Yadlapati     asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
516a5409991SLakshmi Yadlapati         boost::urls::format(
517253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
518253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
519d1bde9e5SKrzysztof Grobelny }
520d1bde9e5SKrzysztof Grobelny 
getPCIeDeviceProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDevicePath,const std::string & service,const std::function<void (const dbus::utility::DBusPropertiesMap & pcieDevProperties)> && callback)521543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
522ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
523543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
524543f9a75SLakshmi Yadlapati     const std::function<void(
525543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
526d1bde9e5SKrzysztof Grobelny {
527deae6a78SEd Tanous     dbus::utility::getAllProperties(
528deae6a78SEd Tanous         service, pcieDevicePath,
529543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
530ac106bf6SEd Tanous         [asyncResp,
531543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
532543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
533543f9a75SLakshmi Yadlapati             if (ec)
534543f9a75SLakshmi Yadlapati             {
535543f9a75SLakshmi Yadlapati                 if (ec.value() != EBADR)
536543f9a75SLakshmi Yadlapati                 {
53762598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties");
538ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
539543f9a75SLakshmi Yadlapati                 }
540543f9a75SLakshmi Yadlapati                 return;
541543f9a75SLakshmi Yadlapati             }
542543f9a75SLakshmi Yadlapati             callback(pcieDevProperties);
543543f9a75SLakshmi Yadlapati         });
544d1bde9e5SKrzysztof Grobelny }
545d1bde9e5SKrzysztof Grobelny 
addPCIeDeviceCommonProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDeviceId)546543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
547ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
548543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
549543f9a75SLakshmi Yadlapati {
550ac106bf6SEd Tanous     asyncResp->res.addHeader(
551543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
552543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
553ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
554253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
555253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
556253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
557ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
558ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
559539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
560539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
561543f9a75SLakshmi Yadlapati }
5621476687dSEd Tanous 
afterGetValidPcieDevicePath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pcieDeviceId,const std::string & pcieDevicePath,const std::string & service)563a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath(
564a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
565a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId, const std::string& pcieDevicePath,
566a5409991SLakshmi Yadlapati     const std::string& service)
567a5409991SLakshmi Yadlapati {
568a5409991SLakshmi Yadlapati     addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
569a5409991SLakshmi Yadlapati     getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
570a5409991SLakshmi Yadlapati     getPCIeDeviceState(asyncResp, pcieDevicePath, service);
571a5409991SLakshmi Yadlapati     getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
572a5409991SLakshmi Yadlapati     getPCIeDeviceProperties(
573a5409991SLakshmi Yadlapati         asyncResp, pcieDevicePath, service,
574a5409991SLakshmi Yadlapati         std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
575a5409991SLakshmi Yadlapati     getPCIeDeviceSlotPath(
576a5409991SLakshmi Yadlapati         pcieDevicePath, asyncResp,
577a5409991SLakshmi Yadlapati         std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
578a5409991SLakshmi Yadlapati }
579a5409991SLakshmi Yadlapati 
handlePCIeDeviceGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & pcieDeviceId)580bd79bce8SPatrick Williams inline void handlePCIeDeviceGet(
581bd79bce8SPatrick Williams     App& app, const crow::Request& req,
582ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
583bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId)
584543f9a75SLakshmi Yadlapati {
585ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
586543f9a75SLakshmi Yadlapati     {
587543f9a75SLakshmi Yadlapati         return;
588543f9a75SLakshmi Yadlapati     }
58925b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5907f3e84a1SEd Tanous     {
5917f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
5927f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5937f3e84a1SEd Tanous                                    systemName);
5947f3e84a1SEd Tanous         return;
5957f3e84a1SEd Tanous     }
596253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
597543f9a75SLakshmi Yadlapati     {
598ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
599ac106bf6SEd Tanous                                    systemName);
600543f9a75SLakshmi Yadlapati         return;
601543f9a75SLakshmi Yadlapati     }
602543f9a75SLakshmi Yadlapati 
603543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
604ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
605a5409991SLakshmi Yadlapati         std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
606543f9a75SLakshmi Yadlapati }
607543f9a75SLakshmi Yadlapati 
requestRoutesSystemPCIeDevice(App & app)608543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
609543f9a75SLakshmi Yadlapati {
610543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
611543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
612543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
613543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
614dede6a98SJason M. Bills }
615dede6a98SJason M. Bills 
addPCIeFunctionList(crow::Response & res,const std::string & pcieDeviceId,const dbus::utility::DBusPropertiesMap & pcieDevProperties)61635ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
61735ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
61835ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
61935ad613dSLakshmi Yadlapati {
62035ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
62135ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
62235ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
62335ad613dSLakshmi Yadlapati 
62435ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
62535ad613dSLakshmi Yadlapati     {
62635ad613dSLakshmi Yadlapati         // Check if this function exists by
62735ad613dSLakshmi Yadlapati         // looking for a device ID
628bd79bce8SPatrick Williams         std::string devIDProperty =
629bd79bce8SPatrick Williams             "Function" + std::to_string(functionNum) + "DeviceId";
63035ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
63135ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
63235ad613dSLakshmi Yadlapati         {
63335ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
63435ad613dSLakshmi Yadlapati             {
63535ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
63635ad613dSLakshmi Yadlapati                 break;
63735ad613dSLakshmi Yadlapati             }
63835ad613dSLakshmi Yadlapati         }
63935ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
64035ad613dSLakshmi Yadlapati         {
64135ad613dSLakshmi Yadlapati             continue;
64235ad613dSLakshmi Yadlapati         }
64335ad613dSLakshmi Yadlapati 
64435ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
645ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
646253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
647253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
648253f11b8SEd Tanous             std::to_string(functionNum));
649b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
65035ad613dSLakshmi Yadlapati     }
65135ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
65235ad613dSLakshmi Yadlapati }
65335ad613dSLakshmi Yadlapati 
handlePCIeFunctionCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & pcieDeviceId)65435ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
65535ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
656ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6577f3e84a1SEd Tanous     const std::string& systemName, const std::string& pcieDeviceId)
65835ad613dSLakshmi Yadlapati {
659ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
66035ad613dSLakshmi Yadlapati     {
66135ad613dSLakshmi Yadlapati         return;
66235ad613dSLakshmi Yadlapati     }
66325b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
6647f3e84a1SEd Tanous     {
6657f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
6667f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6677f3e84a1SEd Tanous                                    systemName);
6687f3e84a1SEd Tanous         return;
6697f3e84a1SEd Tanous     }
67035ad613dSLakshmi Yadlapati 
67135ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
672ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
673ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
67435ad613dSLakshmi Yadlapati                                   const std::string& service) {
675ac106bf6SEd Tanous             asyncResp->res.addHeader(
67635ad613dSLakshmi Yadlapati                 boost::beast::http::field::link,
67735ad613dSLakshmi Yadlapati                 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
678ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
67935ad613dSLakshmi Yadlapati                 "#PCIeFunctionCollection.PCIeFunctionCollection";
680ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
681253f11b8SEd Tanous                 "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
682253f11b8SEd Tanous                 BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
683ac106bf6SEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
684ac106bf6SEd Tanous             asyncResp->res.jsonValue["Description"] =
68535ad613dSLakshmi Yadlapati                 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
68635ad613dSLakshmi Yadlapati             getPCIeDeviceProperties(
687ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
688ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId](
68935ad613dSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
690ac106bf6SEd Tanous                     addPCIeFunctionList(asyncResp->res, pcieDeviceId,
691ac106bf6SEd Tanous                                         pcieDevProperties);
69235ad613dSLakshmi Yadlapati                 });
69335ad613dSLakshmi Yadlapati         });
69435ad613dSLakshmi Yadlapati }
69535ad613dSLakshmi Yadlapati 
requestRoutesSystemPCIeFunctionCollection(App & app)6967e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
6977e860f15SJohn Edward Broadbent {
698dede6a98SJason M. Bills     /**
699dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
700dede6a98SJason M. Bills      */
7017e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
7027f3e84a1SEd Tanous                  "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
703ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
704002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
70535ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
7067e860f15SJohn Edward Broadbent }
7077e860f15SJohn Edward Broadbent 
validatePCIeFunctionId(uint64_t pcieFunctionId,const dbus::utility::DBusPropertiesMap & pcieDevProperties)708727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
709d5e74b80SMyung Bae     uint64_t pcieFunctionId,
710727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
7117e860f15SJohn Edward Broadbent {
712d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
713b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
714b9d36b47SEd Tanous 
715b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
716b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
717b9d36b47SEd Tanous     {
718b9d36b47SEd Tanous         if (property.first == devIDProperty)
719b9d36b47SEd Tanous         {
720002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
721727a046cSLakshmi Yadlapati             break;
722b9d36b47SEd Tanous         }
723b9d36b47SEd Tanous     }
724727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
725727a046cSLakshmi Yadlapati }
726727a046cSLakshmi Yadlapati 
addPCIeFunctionProperties(crow::Response & resp,uint64_t pcieFunctionId,const dbus::utility::DBusPropertiesMap & pcieDevProperties)727727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
728e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
729727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
730f5c9f8bdSJason M. Bills {
731e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
732b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
733f5c9f8bdSJason M. Bills     {
734b9d36b47SEd Tanous         const std::string* strProperty =
735b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
736dc8cfa66SEd Tanous         if (strProperty == nullptr)
737dc8cfa66SEd Tanous         {
738dc8cfa66SEd Tanous             continue;
739dc8cfa66SEd Tanous         }
740b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
741f5c9f8bdSJason M. Bills         {
742727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
743f5c9f8bdSJason M. Bills         }
744b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
745f5c9f8bdSJason M. Bills         {
746727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
747f5c9f8bdSJason M. Bills         }
748727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
749727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
750727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
751b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
752f5c9f8bdSJason M. Bills         {
753727a046cSLakshmi Yadlapati             if (!strProperty->empty())
754727a046cSLakshmi Yadlapati             {
755727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
756727a046cSLakshmi Yadlapati             }
757f5c9f8bdSJason M. Bills         }
758b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
759f5c9f8bdSJason M. Bills         {
760727a046cSLakshmi Yadlapati             if (!strProperty->empty())
761727a046cSLakshmi Yadlapati             {
762727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
763727a046cSLakshmi Yadlapati             }
764f5c9f8bdSJason M. Bills         }
765b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
766f5c9f8bdSJason M. Bills         {
767727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
768f5c9f8bdSJason M. Bills         }
769b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
770f5c9f8bdSJason M. Bills         {
771727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
772f5c9f8bdSJason M. Bills         }
773b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
774b9d36b47SEd Tanous         {
775727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
776b9d36b47SEd Tanous         }
777002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
778f5c9f8bdSJason M. Bills         {
779727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
780b9d36b47SEd Tanous         }
781f5c9f8bdSJason M. Bills     }
782727a046cSLakshmi Yadlapati }
783727a046cSLakshmi Yadlapati 
addPCIeFunctionCommonProperties(crow::Response & resp,const std::string & pcieDeviceId,uint64_t pcieFunctionId)784727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
785727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
786e14742caSEd Tanous                                             uint64_t pcieFunctionId)
787727a046cSLakshmi Yadlapati {
788727a046cSLakshmi Yadlapati     resp.addHeader(
789727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
790727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
791727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
792ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
793253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
794253f11b8SEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
795253f11b8SEd Tanous         std::to_string(pcieFunctionId));
796727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
797e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
798e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
799253f11b8SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
800253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
801253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
802727a046cSLakshmi Yadlapati }
803727a046cSLakshmi Yadlapati 
handlePCIeFunctionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & pcieDeviceId,const std::string & pcieFunctionIdStr)804bd79bce8SPatrick Williams inline void handlePCIeFunctionGet(
805bd79bce8SPatrick Williams     App& app, const crow::Request& req,
806ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
807bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId,
808e14742caSEd Tanous     const std::string& pcieFunctionIdStr)
809727a046cSLakshmi Yadlapati {
810ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
811727a046cSLakshmi Yadlapati     {
812727a046cSLakshmi Yadlapati         return;
813727a046cSLakshmi Yadlapati     }
81425b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
8157f3e84a1SEd Tanous     {
8167f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
8177f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8187f3e84a1SEd Tanous                                    systemName);
8197f3e84a1SEd Tanous         return;
8207f3e84a1SEd Tanous     }
821253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
8227f3e84a1SEd Tanous     {
8237f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8247f3e84a1SEd Tanous                                    systemName);
8257f3e84a1SEd Tanous         return;
8267f3e84a1SEd Tanous     }
827dc8cfa66SEd Tanous     std::string_view pcieFunctionIdView = pcieFunctionIdStr;
8287f3e84a1SEd Tanous 
829e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
830e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
831dc8cfa66SEd Tanous         pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId);
832dc8cfa66SEd Tanous     if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end())
833e14742caSEd Tanous     {
834ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
835e14742caSEd Tanous                                    pcieFunctionIdStr);
836e14742caSEd Tanous         return;
837e14742caSEd Tanous     }
838727a046cSLakshmi Yadlapati 
839bd79bce8SPatrick Williams     getValidPCIeDevicePath(
840bd79bce8SPatrick Williams         pcieDeviceId, asyncResp,
841bd79bce8SPatrick Williams         [asyncResp, pcieDeviceId, pcieFunctionId](
842bd79bce8SPatrick Williams             const std::string& pcieDevicePath, const std::string& service) {
843727a046cSLakshmi Yadlapati             getPCIeDeviceProperties(
844ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
845ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId, pcieFunctionId](
846727a046cSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
847bd79bce8SPatrick Williams                     addPCIeFunctionCommonProperties(
848bd79bce8SPatrick Williams                         asyncResp->res, pcieDeviceId, pcieFunctionId);
849ac106bf6SEd Tanous                     addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
850727a046cSLakshmi Yadlapati                                               pcieDevProperties);
8517e860f15SJohn Edward Broadbent                 });
852727a046cSLakshmi Yadlapati         });
853727a046cSLakshmi Yadlapati }
854727a046cSLakshmi Yadlapati 
requestRoutesSystemPCIeFunction(App & app)855727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
856727a046cSLakshmi Yadlapati {
857727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
8587f3e84a1SEd Tanous         app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
859727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
860727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
861727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
862f5c9f8bdSJason M. Bills }
863f5c9f8bdSJason M. Bills 
864f5c9f8bdSJason M. Bills } // namespace redfish
865