xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 67f0b9c02138d97b9a3be9676c476e4bd5cd571d)
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 
7d7857201SEd Tanous #include "bmcweb_config.h"
8d7857201SEd Tanous 
93ccb3adbSEd Tanous #include "app.hpp"
10d7857201SEd Tanous #include "async_resp.hpp"
117a1dbc48SGeorge Liu #include "dbus_utility.hpp"
12d7857201SEd Tanous #include "error_messages.hpp"
13d7857201SEd Tanous #include "generated/enums/pcie_device.hpp"
14d7857201SEd Tanous #include "generated/enums/pcie_slots.hpp"
15539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
16d7857201SEd Tanous #include "http_request.hpp"
17d7857201SEd 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 
23d7857201SEd Tanous #include <asm-generic/errno.h>
24d7857201SEd Tanous 
25d7857201SEd Tanous #include <boost/beast/http/field.hpp>
26d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
27ef4c65b7SEd Tanous #include <boost/url/format.hpp>
28d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
29f5c9f8bdSJason M. Bills 
30d7857201SEd Tanous #include <array>
31d7857201SEd Tanous #include <charconv>
32d7857201SEd Tanous #include <cstddef>
33d7857201SEd Tanous #include <cstdint>
34d7857201SEd Tanous #include <format>
35d7857201SEd Tanous #include <functional>
368c1d0549SMyung Bae #include <limits>
37d7857201SEd Tanous #include <memory>
38d7857201SEd Tanous #include <optional>
39d7857201SEd Tanous #include <string>
40d7857201SEd Tanous #include <string_view>
41d7857201SEd Tanous #include <system_error>
42d7857201SEd Tanous #include <utility>
43d7857201SEd 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 
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 
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 
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 
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 
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 
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());
258*67f0b9c0SMyung Bae                 for (const std::string& slotPath : endpoints)
259*67f0b9c0SMyung Bae                 {
260*67f0b9c0SMyung Bae                     BMCWEB_LOG_ERROR("Invalid PCIeSlotPath: {}", slotPath);
261*67f0b9c0SMyung Bae                 }
262a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
263a5409991SLakshmi Yadlapati                 return;
264a5409991SLakshmi Yadlapati             }
265a5409991SLakshmi Yadlapati             if (endpoints.empty())
266a5409991SLakshmi Yadlapati             {
267bd79bce8SPatrick Williams                 // If the device doesn't have an association, return without
268bd79bce8SPatrick Williams                 // PCIe Slot properties
26962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot");
270a5409991SLakshmi Yadlapati                 return;
271a5409991SLakshmi Yadlapati             }
272a5409991SLakshmi Yadlapati             callback(endpoints[0]);
273a5409991SLakshmi Yadlapati         });
274a5409991SLakshmi Yadlapati }
275a5409991SLakshmi Yadlapati 
276bd79bce8SPatrick Williams inline void afterGetDbusObject(
277bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
278bd79bce8SPatrick Williams     const std::string& pcieDeviceSlot, const boost::system::error_code& ec,
279a5409991SLakshmi Yadlapati     const dbus::utility::MapperGetObject& object)
280a5409991SLakshmi Yadlapati {
281a5409991SLakshmi Yadlapati     if (ec || object.empty())
282a5409991SLakshmi Yadlapati     {
28362598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}",
28462598e31SEd Tanous                          ec.value());
285a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
286a5409991SLakshmi Yadlapati         return;
287a5409991SLakshmi Yadlapati     }
288deae6a78SEd Tanous     dbus::utility::getAllProperties(
289deae6a78SEd Tanous         object.begin()->first, pcieDeviceSlot,
290a5409991SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
291a5409991SLakshmi Yadlapati         [asyncResp](
292a5409991SLakshmi Yadlapati             const boost::system::error_code& ec2,
293a5409991SLakshmi Yadlapati             const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
294a5409991SLakshmi Yadlapati             addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
295a5409991SLakshmi Yadlapati         });
296a5409991SLakshmi Yadlapati }
297a5409991SLakshmi Yadlapati 
298a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath(
299a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
300a5409991SLakshmi Yadlapati     const std::string& pcieDeviceSlot)
301a5409991SLakshmi Yadlapati {
302a5409991SLakshmi Yadlapati     dbus::utility::getDbusObject(
303a5409991SLakshmi Yadlapati         pcieDeviceSlot, pcieSlotInterface,
304a5409991SLakshmi Yadlapati         [asyncResp,
305a5409991SLakshmi Yadlapati          pcieDeviceSlot](const boost::system::error_code& ec,
306a5409991SLakshmi Yadlapati                          const dbus::utility::MapperGetObject& object) {
307a5409991SLakshmi Yadlapati             afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
308a5409991SLakshmi Yadlapati         });
309a5409991SLakshmi Yadlapati }
310a5409991SLakshmi Yadlapati 
311bd79bce8SPatrick Williams inline void getPCIeDeviceHealth(
312bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
313bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
314e164f1b6SLakshmi Yadlapati {
315deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
316deae6a78SEd Tanous         service, pcieDevicePath,
317e164f1b6SLakshmi Yadlapati         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
318e164f1b6SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, const bool value) {
319e164f1b6SLakshmi Yadlapati             if (ec)
320e164f1b6SLakshmi Yadlapati             {
321e164f1b6SLakshmi Yadlapati                 if (ec.value() != EBADR)
322e164f1b6SLakshmi Yadlapati                 {
32362598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
32462598e31SEd Tanous                                      ec.value());
325e164f1b6SLakshmi Yadlapati                     messages::internalError(asyncResp->res);
326e164f1b6SLakshmi Yadlapati                 }
327e164f1b6SLakshmi Yadlapati                 return;
328e164f1b6SLakshmi Yadlapati             }
329e164f1b6SLakshmi Yadlapati 
330e164f1b6SLakshmi Yadlapati             if (!value)
331e164f1b6SLakshmi Yadlapati             {
332539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
333539d8c6bSEd Tanous                     resource::Health::Critical;
334e164f1b6SLakshmi Yadlapati             }
335e164f1b6SLakshmi Yadlapati         });
336e164f1b6SLakshmi Yadlapati }
337e164f1b6SLakshmi Yadlapati 
338bd79bce8SPatrick Williams inline void getPCIeDeviceState(
339bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
340bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
341c6bb3285SLakshmi Yadlapati {
342deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
343deae6a78SEd Tanous         service, pcieDevicePath, "xyz.openbmc_project.Inventory.Item",
344deae6a78SEd Tanous         "Present",
345a5409991SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, bool value) {
346c6bb3285SLakshmi Yadlapati             if (ec)
347c6bb3285SLakshmi Yadlapati             {
348c6bb3285SLakshmi Yadlapati                 if (ec.value() != EBADR)
349c6bb3285SLakshmi Yadlapati                 {
35062598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State");
351ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
352c6bb3285SLakshmi Yadlapati                 }
353c6bb3285SLakshmi Yadlapati                 return;
354c6bb3285SLakshmi Yadlapati             }
355c6bb3285SLakshmi Yadlapati 
356c6bb3285SLakshmi Yadlapati             if (!value)
357c6bb3285SLakshmi Yadlapati             {
358539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
359539d8c6bSEd Tanous                     resource::State::Absent;
360c6bb3285SLakshmi Yadlapati             }
361c6bb3285SLakshmi Yadlapati         });
362c6bb3285SLakshmi Yadlapati }
363c6bb3285SLakshmi Yadlapati 
364bd79bce8SPatrick Williams inline void getPCIeDeviceAsset(
365bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
366bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
367913e7732SSunnySrivastava1984 {
368deae6a78SEd Tanous     dbus::utility::getAllProperties(
369deae6a78SEd Tanous         service, pcieDevicePath,
370913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
371ac106bf6SEd Tanous         [pcieDevicePath, asyncResp{asyncResp}](
372ac106bf6SEd Tanous             const boost::system::error_code& ec,
373913e7732SSunnySrivastava1984             const dbus::utility::DBusPropertiesMap& assetList) {
374913e7732SSunnySrivastava1984             if (ec)
375913e7732SSunnySrivastava1984             {
376913e7732SSunnySrivastava1984                 if (ec.value() != EBADR)
377913e7732SSunnySrivastava1984                 {
37862598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties{}",
37962598e31SEd Tanous                                      ec.value());
380ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
381913e7732SSunnySrivastava1984                 }
382913e7732SSunnySrivastava1984                 return;
383913e7732SSunnySrivastava1984             }
384913e7732SSunnySrivastava1984 
385913e7732SSunnySrivastava1984             const std::string* manufacturer = nullptr;
386913e7732SSunnySrivastava1984             const std::string* model = nullptr;
387913e7732SSunnySrivastava1984             const std::string* partNumber = nullptr;
388913e7732SSunnySrivastava1984             const std::string* serialNumber = nullptr;
389913e7732SSunnySrivastava1984             const std::string* sparePartNumber = nullptr;
390913e7732SSunnySrivastava1984 
391913e7732SSunnySrivastava1984             const bool success = sdbusplus::unpackPropertiesNoThrow(
392913e7732SSunnySrivastava1984                 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
393913e7732SSunnySrivastava1984                 manufacturer, "Model", model, "PartNumber", partNumber,
394bd79bce8SPatrick Williams                 "SerialNumber", serialNumber, "SparePartNumber",
395bd79bce8SPatrick Williams                 sparePartNumber);
396913e7732SSunnySrivastava1984 
397913e7732SSunnySrivastava1984             if (!success)
398913e7732SSunnySrivastava1984             {
399ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
400913e7732SSunnySrivastava1984                 return;
401913e7732SSunnySrivastava1984             }
402913e7732SSunnySrivastava1984 
403913e7732SSunnySrivastava1984             if (manufacturer != nullptr)
404913e7732SSunnySrivastava1984             {
405ac106bf6SEd Tanous                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
406913e7732SSunnySrivastava1984             }
407913e7732SSunnySrivastava1984             if (model != nullptr)
408913e7732SSunnySrivastava1984             {
409ac106bf6SEd Tanous                 asyncResp->res.jsonValue["Model"] = *model;
410913e7732SSunnySrivastava1984             }
411913e7732SSunnySrivastava1984 
412913e7732SSunnySrivastava1984             if (partNumber != nullptr)
413913e7732SSunnySrivastava1984             {
414ac106bf6SEd Tanous                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
415913e7732SSunnySrivastava1984             }
416913e7732SSunnySrivastava1984 
417913e7732SSunnySrivastava1984             if (serialNumber != nullptr)
418913e7732SSunnySrivastava1984             {
419ac106bf6SEd Tanous                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
420913e7732SSunnySrivastava1984             }
421913e7732SSunnySrivastava1984 
422913e7732SSunnySrivastava1984             if (sparePartNumber != nullptr && !sparePartNumber->empty())
423913e7732SSunnySrivastava1984             {
424ac106bf6SEd Tanous                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
425913e7732SSunnySrivastava1984             }
426913e7732SSunnySrivastava1984         });
427913e7732SSunnySrivastava1984 }
428913e7732SSunnySrivastava1984 
429543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
430a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
431a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId,
432543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
433f5c9f8bdSJason M. Bills {
434d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
435814bf20aSKonstantin Aladyshev     const std::string* generationSupported = nullptr;
4369bb0a7feSKonstantin Aladyshev     const size_t* lanesInUse = nullptr;
437814bf20aSKonstantin Aladyshev     const size_t* maxLanes = nullptr;
438d1bde9e5SKrzysztof Grobelny 
439d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
440609ba4c9SEd Tanous         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse",
441609ba4c9SEd Tanous         generationInUse, "GenerationSupported", generationSupported,
442609ba4c9SEd Tanous         "LanesInUse", lanesInUse, "MaxLanes", maxLanes);
443d1bde9e5SKrzysztof Grobelny 
444d1bde9e5SKrzysztof Grobelny     if (!success)
445d1bde9e5SKrzysztof Grobelny     {
446a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
447d1bde9e5SKrzysztof Grobelny         return;
448d1bde9e5SKrzysztof Grobelny     }
449d1bde9e5SKrzysztof Grobelny 
450d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
451d1bde9e5SKrzysztof Grobelny     {
4520ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
453c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
454543f9a75SLakshmi Yadlapati 
455d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
456d1bde9e5SKrzysztof Grobelny         {
45762598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
45862598e31SEd Tanous                                *generationInUse);
459cf3b484eSLakshmi Yadlapati         }
460cf3b484eSLakshmi Yadlapati         else
461cf3b484eSLakshmi Yadlapati         {
462cf3b484eSLakshmi Yadlapati             if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
463cf3b484eSLakshmi Yadlapati             {
46462598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
46562598e31SEd Tanous                                  *generationInUse);
466a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
467d1bde9e5SKrzysztof Grobelny                 return;
468d1bde9e5SKrzysztof Grobelny             }
469a5409991SLakshmi Yadlapati             asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
470d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
471d1bde9e5SKrzysztof Grobelny         }
472a9f68bb5STony Lee     }
473d1bde9e5SKrzysztof Grobelny 
474814bf20aSKonstantin Aladyshev     if (generationSupported != nullptr)
475814bf20aSKonstantin Aladyshev     {
476814bf20aSKonstantin Aladyshev         std::optional<pcie_device::PCIeTypes> redfishGenerationSupported =
477814bf20aSKonstantin Aladyshev             pcie_util::redfishPcieGenerationFromDbus(*generationSupported);
478814bf20aSKonstantin Aladyshev 
479814bf20aSKonstantin Aladyshev         if (!redfishGenerationSupported)
480814bf20aSKonstantin Aladyshev         {
48162598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
48262598e31SEd Tanous                                *generationSupported);
483814bf20aSKonstantin Aladyshev         }
484814bf20aSKonstantin Aladyshev         else
485814bf20aSKonstantin Aladyshev         {
486814bf20aSKonstantin Aladyshev             if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid)
487814bf20aSKonstantin Aladyshev             {
48862598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
48962598e31SEd Tanous                                  *generationSupported);
490814bf20aSKonstantin Aladyshev                 messages::internalError(asyncResp->res);
491814bf20aSKonstantin Aladyshev                 return;
492814bf20aSKonstantin Aladyshev             }
493814bf20aSKonstantin Aladyshev             asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] =
494814bf20aSKonstantin Aladyshev                 *redfishGenerationSupported;
495814bf20aSKonstantin Aladyshev         }
496814bf20aSKonstantin Aladyshev     }
497814bf20aSKonstantin Aladyshev 
4988c1d0549SMyung Bae     if (lanesInUse != nullptr)
499543f9a75SLakshmi Yadlapati     {
5008c1d0549SMyung Bae         if (*lanesInUse == std::numeric_limits<size_t>::max())
5018c1d0549SMyung Bae         {
5028c1d0549SMyung Bae             // The default value of LanesInUse is "maxint", and the field will
5038c1d0549SMyung Bae             // be null if it is a default value.
5048c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr;
5058c1d0549SMyung Bae         }
5068c1d0549SMyung Bae         else
5078c1d0549SMyung Bae         {
5088c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] =
5098c1d0549SMyung Bae                 *lanesInUse;
5108c1d0549SMyung Bae         }
511543f9a75SLakshmi Yadlapati     }
512814bf20aSKonstantin Aladyshev     // The default value of MaxLanes is 0, and the field will be
513814bf20aSKonstantin Aladyshev     // left as off if it is a default value.
514814bf20aSKonstantin Aladyshev     if (maxLanes != nullptr && *maxLanes != 0)
515814bf20aSKonstantin Aladyshev     {
516814bf20aSKonstantin Aladyshev         asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes;
517814bf20aSKonstantin Aladyshev     }
518543f9a75SLakshmi Yadlapati 
519a5409991SLakshmi Yadlapati     asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
520a5409991SLakshmi Yadlapati         boost::urls::format(
521253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
522253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
523d1bde9e5SKrzysztof Grobelny }
524d1bde9e5SKrzysztof Grobelny 
525543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
526ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
527543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
528543f9a75SLakshmi Yadlapati     const std::function<void(
529543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
530d1bde9e5SKrzysztof Grobelny {
531deae6a78SEd Tanous     dbus::utility::getAllProperties(
532deae6a78SEd Tanous         service, pcieDevicePath,
533543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
534ac106bf6SEd Tanous         [asyncResp,
535543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
536543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
537543f9a75SLakshmi Yadlapati             if (ec)
538543f9a75SLakshmi Yadlapati             {
539543f9a75SLakshmi Yadlapati                 if (ec.value() != EBADR)
540543f9a75SLakshmi Yadlapati                 {
54162598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties");
542ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
543543f9a75SLakshmi Yadlapati                 }
544543f9a75SLakshmi Yadlapati                 return;
545543f9a75SLakshmi Yadlapati             }
546543f9a75SLakshmi Yadlapati             callback(pcieDevProperties);
547543f9a75SLakshmi Yadlapati         });
548d1bde9e5SKrzysztof Grobelny }
549d1bde9e5SKrzysztof Grobelny 
550543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
551ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
552543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
553543f9a75SLakshmi Yadlapati {
554ac106bf6SEd Tanous     asyncResp->res.addHeader(
555543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
556543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
557ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
558253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
559253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
560253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
561ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
562ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
563539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
564539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
565543f9a75SLakshmi Yadlapati }
5661476687dSEd Tanous 
567a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath(
568a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
569a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId, const std::string& pcieDevicePath,
570a5409991SLakshmi Yadlapati     const std::string& service)
571a5409991SLakshmi Yadlapati {
572a5409991SLakshmi Yadlapati     addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
573a5409991SLakshmi Yadlapati     getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
574a5409991SLakshmi Yadlapati     getPCIeDeviceState(asyncResp, pcieDevicePath, service);
575a5409991SLakshmi Yadlapati     getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
576a5409991SLakshmi Yadlapati     getPCIeDeviceProperties(
577a5409991SLakshmi Yadlapati         asyncResp, pcieDevicePath, service,
578a5409991SLakshmi Yadlapati         std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
579a5409991SLakshmi Yadlapati     getPCIeDeviceSlotPath(
580a5409991SLakshmi Yadlapati         pcieDevicePath, asyncResp,
581a5409991SLakshmi Yadlapati         std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
582a5409991SLakshmi Yadlapati }
583a5409991SLakshmi Yadlapati 
584bd79bce8SPatrick Williams inline void handlePCIeDeviceGet(
585bd79bce8SPatrick Williams     App& app, const crow::Request& req,
586ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
587bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId)
588543f9a75SLakshmi Yadlapati {
589ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
590543f9a75SLakshmi Yadlapati     {
591543f9a75SLakshmi Yadlapati         return;
592543f9a75SLakshmi Yadlapati     }
59325b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5947f3e84a1SEd Tanous     {
5957f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
5967f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5977f3e84a1SEd Tanous                                    systemName);
5987f3e84a1SEd Tanous         return;
5997f3e84a1SEd Tanous     }
600253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
601543f9a75SLakshmi Yadlapati     {
602ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
603ac106bf6SEd Tanous                                    systemName);
604543f9a75SLakshmi Yadlapati         return;
605543f9a75SLakshmi Yadlapati     }
606543f9a75SLakshmi Yadlapati 
607543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
608ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
609a5409991SLakshmi Yadlapati         std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
610543f9a75SLakshmi Yadlapati }
611543f9a75SLakshmi Yadlapati 
612543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
613543f9a75SLakshmi Yadlapati {
614543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
615543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
616543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
617543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
618dede6a98SJason M. Bills }
619dede6a98SJason M. Bills 
62035ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
62135ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
62235ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
62335ad613dSLakshmi Yadlapati {
62435ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
62535ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
62635ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
62735ad613dSLakshmi Yadlapati 
62835ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
62935ad613dSLakshmi Yadlapati     {
63035ad613dSLakshmi Yadlapati         // Check if this function exists by
63135ad613dSLakshmi Yadlapati         // looking for a device ID
632bd79bce8SPatrick Williams         std::string devIDProperty =
633bd79bce8SPatrick Williams             "Function" + std::to_string(functionNum) + "DeviceId";
63435ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
63535ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
63635ad613dSLakshmi Yadlapati         {
63735ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
63835ad613dSLakshmi Yadlapati             {
63935ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
64035ad613dSLakshmi Yadlapati                 break;
64135ad613dSLakshmi Yadlapati             }
64235ad613dSLakshmi Yadlapati         }
64335ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
64435ad613dSLakshmi Yadlapati         {
64535ad613dSLakshmi Yadlapati             continue;
64635ad613dSLakshmi Yadlapati         }
64735ad613dSLakshmi Yadlapati 
64835ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
649ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
650253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
651253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
652253f11b8SEd Tanous             std::to_string(functionNum));
653b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
65435ad613dSLakshmi Yadlapati     }
65535ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
65635ad613dSLakshmi Yadlapati }
65735ad613dSLakshmi Yadlapati 
65835ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
65935ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
660ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6617f3e84a1SEd Tanous     const std::string& systemName, const std::string& pcieDeviceId)
66235ad613dSLakshmi Yadlapati {
663ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
66435ad613dSLakshmi Yadlapati     {
66535ad613dSLakshmi Yadlapati         return;
66635ad613dSLakshmi Yadlapati     }
66725b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
6687f3e84a1SEd Tanous     {
6697f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
6707f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6717f3e84a1SEd Tanous                                    systemName);
6727f3e84a1SEd Tanous         return;
6737f3e84a1SEd Tanous     }
67435ad613dSLakshmi Yadlapati 
67535ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
676ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
677ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
67835ad613dSLakshmi Yadlapati                                   const std::string& service) {
679ac106bf6SEd Tanous             asyncResp->res.addHeader(
68035ad613dSLakshmi Yadlapati                 boost::beast::http::field::link,
68135ad613dSLakshmi Yadlapati                 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
682ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
68335ad613dSLakshmi Yadlapati                 "#PCIeFunctionCollection.PCIeFunctionCollection";
684ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
685253f11b8SEd Tanous                 "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
686253f11b8SEd Tanous                 BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
687ac106bf6SEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
688ac106bf6SEd Tanous             asyncResp->res.jsonValue["Description"] =
68935ad613dSLakshmi Yadlapati                 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
69035ad613dSLakshmi Yadlapati             getPCIeDeviceProperties(
691ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
692ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId](
69335ad613dSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
694ac106bf6SEd Tanous                     addPCIeFunctionList(asyncResp->res, pcieDeviceId,
695ac106bf6SEd Tanous                                         pcieDevProperties);
69635ad613dSLakshmi Yadlapati                 });
69735ad613dSLakshmi Yadlapati         });
69835ad613dSLakshmi Yadlapati }
69935ad613dSLakshmi Yadlapati 
7007e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
7017e860f15SJohn Edward Broadbent {
702dede6a98SJason M. Bills     /**
703dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
704dede6a98SJason M. Bills      */
7057e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
7067f3e84a1SEd Tanous                  "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
707ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
708002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
70935ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
7107e860f15SJohn Edward Broadbent }
7117e860f15SJohn Edward Broadbent 
712727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
713d5e74b80SMyung Bae     uint64_t pcieFunctionId,
714727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
7157e860f15SJohn Edward Broadbent {
716d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
717b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
718b9d36b47SEd Tanous 
719b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
720b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
721b9d36b47SEd Tanous     {
722b9d36b47SEd Tanous         if (property.first == devIDProperty)
723b9d36b47SEd Tanous         {
724002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
725727a046cSLakshmi Yadlapati             break;
726b9d36b47SEd Tanous         }
727b9d36b47SEd Tanous     }
728727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
729727a046cSLakshmi Yadlapati }
730727a046cSLakshmi Yadlapati 
731727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
732e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
733727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
734f5c9f8bdSJason M. Bills {
735e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
736b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
737f5c9f8bdSJason M. Bills     {
738b9d36b47SEd Tanous         const std::string* strProperty =
739b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
740dc8cfa66SEd Tanous         if (strProperty == nullptr)
741dc8cfa66SEd Tanous         {
742dc8cfa66SEd Tanous             continue;
743dc8cfa66SEd Tanous         }
744b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
745f5c9f8bdSJason M. Bills         {
746727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
747f5c9f8bdSJason M. Bills         }
748b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
749f5c9f8bdSJason M. Bills         {
750727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
751f5c9f8bdSJason M. Bills         }
752727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
753727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
754727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
755b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
756f5c9f8bdSJason M. Bills         {
757727a046cSLakshmi Yadlapati             if (!strProperty->empty())
758727a046cSLakshmi Yadlapati             {
759727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
760727a046cSLakshmi Yadlapati             }
761f5c9f8bdSJason M. Bills         }
762b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
763f5c9f8bdSJason M. Bills         {
764727a046cSLakshmi Yadlapati             if (!strProperty->empty())
765727a046cSLakshmi Yadlapati             {
766727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
767727a046cSLakshmi Yadlapati             }
768f5c9f8bdSJason M. Bills         }
769b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
770f5c9f8bdSJason M. Bills         {
771727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
772f5c9f8bdSJason M. Bills         }
773b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
774f5c9f8bdSJason M. Bills         {
775727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
776f5c9f8bdSJason M. Bills         }
777b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
778b9d36b47SEd Tanous         {
779727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
780b9d36b47SEd Tanous         }
781002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
782f5c9f8bdSJason M. Bills         {
783727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
784b9d36b47SEd Tanous         }
785f5c9f8bdSJason M. Bills     }
786727a046cSLakshmi Yadlapati }
787727a046cSLakshmi Yadlapati 
788727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
789727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
790e14742caSEd Tanous                                             uint64_t pcieFunctionId)
791727a046cSLakshmi Yadlapati {
792727a046cSLakshmi Yadlapati     resp.addHeader(
793727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
794727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
795727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
796ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
797253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
798253f11b8SEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
799253f11b8SEd Tanous         std::to_string(pcieFunctionId));
800727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
801e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
802e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
803253f11b8SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
804253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
805253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
806727a046cSLakshmi Yadlapati }
807727a046cSLakshmi Yadlapati 
808bd79bce8SPatrick Williams inline void handlePCIeFunctionGet(
809bd79bce8SPatrick Williams     App& app, const crow::Request& req,
810ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
811bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId,
812e14742caSEd Tanous     const std::string& pcieFunctionIdStr)
813727a046cSLakshmi Yadlapati {
814ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
815727a046cSLakshmi Yadlapati     {
816727a046cSLakshmi Yadlapati         return;
817727a046cSLakshmi Yadlapati     }
81825b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
8197f3e84a1SEd Tanous     {
8207f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
8217f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8227f3e84a1SEd Tanous                                    systemName);
8237f3e84a1SEd Tanous         return;
8247f3e84a1SEd Tanous     }
825253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
8267f3e84a1SEd Tanous     {
8277f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8287f3e84a1SEd Tanous                                    systemName);
8297f3e84a1SEd Tanous         return;
8307f3e84a1SEd Tanous     }
831dc8cfa66SEd Tanous     std::string_view pcieFunctionIdView = pcieFunctionIdStr;
8327f3e84a1SEd Tanous 
833e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
834e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
835dc8cfa66SEd Tanous         pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId);
836dc8cfa66SEd Tanous     if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end())
837e14742caSEd Tanous     {
838ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
839e14742caSEd Tanous                                    pcieFunctionIdStr);
840e14742caSEd Tanous         return;
841e14742caSEd Tanous     }
842727a046cSLakshmi Yadlapati 
843bd79bce8SPatrick Williams     getValidPCIeDevicePath(
844bd79bce8SPatrick Williams         pcieDeviceId, asyncResp,
845bd79bce8SPatrick Williams         [asyncResp, pcieDeviceId, pcieFunctionId](
846bd79bce8SPatrick Williams             const std::string& pcieDevicePath, const std::string& service) {
847727a046cSLakshmi Yadlapati             getPCIeDeviceProperties(
848ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
849ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId, pcieFunctionId](
850727a046cSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
851bd79bce8SPatrick Williams                     addPCIeFunctionCommonProperties(
852bd79bce8SPatrick Williams                         asyncResp->res, pcieDeviceId, pcieFunctionId);
853ac106bf6SEd Tanous                     addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
854727a046cSLakshmi Yadlapati                                               pcieDevProperties);
8557e860f15SJohn Edward Broadbent                 });
856727a046cSLakshmi Yadlapati         });
857727a046cSLakshmi Yadlapati }
858727a046cSLakshmi Yadlapati 
859727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
860727a046cSLakshmi Yadlapati {
861727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
8627f3e84a1SEd Tanous         app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
863727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
864727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
865727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
866f5c9f8bdSJason M. Bills }
867f5c9f8bdSJason M. Bills 
868f5c9f8bdSJason M. Bills } // namespace redfish
869