xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision f7e62c142ced153e9400b519bdd66062dd6bbf0e)
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"
20*f7e62c14SMyung Bae #include "utils/asset_utils.hpp"
213ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
22c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp"
230ec8b83dSEd Tanous 
24d7857201SEd Tanous #include <asm-generic/errno.h>
25d7857201SEd Tanous 
26d7857201SEd Tanous #include <boost/beast/http/field.hpp>
27d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
28ef4c65b7SEd Tanous #include <boost/url/format.hpp>
29d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
30f5c9f8bdSJason M. Bills 
31d7857201SEd Tanous #include <array>
32d7857201SEd Tanous #include <charconv>
33d7857201SEd Tanous #include <cstddef>
34d7857201SEd Tanous #include <cstdint>
35d7857201SEd Tanous #include <format>
36d7857201SEd Tanous #include <functional>
378c1d0549SMyung Bae #include <limits>
38d7857201SEd Tanous #include <memory>
39d7857201SEd Tanous #include <optional>
40d7857201SEd Tanous #include <string>
41d7857201SEd Tanous #include <string_view>
42d7857201SEd Tanous #include <system_error>
43d7857201SEd Tanous #include <utility>
44d7857201SEd Tanous #include <variant>
458c1d0549SMyung Bae 
46f5c9f8bdSJason M. Bills namespace redfish
47f5c9f8bdSJason M. Bills {
48f5c9f8bdSJason M. Bills 
4989492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
5094c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
5194c3a10bSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
52a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = {
53a5409991SLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeSlot"};
54f5c9f8bdSJason M. Bills 
554ff0f1f4SEd Tanous inline void handlePCIeDevicePath(
56543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
57ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
58543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
59543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
60543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
61543f9a75SLakshmi Yadlapati 
62543f9a75SLakshmi Yadlapati {
63543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
64543f9a75SLakshmi Yadlapati     {
65543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
66543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
67543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
68543f9a75SLakshmi Yadlapati         {
69543f9a75SLakshmi Yadlapati             continue;
70543f9a75SLakshmi Yadlapati         }
71543f9a75SLakshmi Yadlapati 
72543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
733a58c5a8SKonstantin Aladyshev             pcieDevicePath, pcieDeviceInterface,
74ac106bf6SEd Tanous             [pcieDevicePath, asyncResp,
75543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
76543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
77543f9a75SLakshmi Yadlapati                 if (ec || object.empty())
78543f9a75SLakshmi Yadlapati                 {
7962598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error {}", ec);
80ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
81543f9a75SLakshmi Yadlapati                     return;
82543f9a75SLakshmi Yadlapati                 }
83543f9a75SLakshmi Yadlapati                 callback(pcieDevicePath, object.begin()->first);
84543f9a75SLakshmi Yadlapati             });
85543f9a75SLakshmi Yadlapati         return;
86543f9a75SLakshmi Yadlapati     }
87543f9a75SLakshmi Yadlapati 
8862598e31SEd Tanous     BMCWEB_LOG_WARNING("PCIe Device not found");
89ac106bf6SEd Tanous     messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
90543f9a75SLakshmi Yadlapati }
91543f9a75SLakshmi Yadlapati 
924ff0f1f4SEd Tanous inline void getValidPCIeDevicePath(
93543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
94ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
95543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
96543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
97543f9a75SLakshmi Yadlapati {
98543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
9994c3a10bSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
100ac106bf6SEd Tanous         [pcieDeviceId, asyncResp,
101543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
102543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
103543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
104543f9a75SLakshmi Yadlapati             if (ec)
105543f9a75SLakshmi Yadlapati             {
10662598e31SEd Tanous                 BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
107ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
108543f9a75SLakshmi Yadlapati                 return;
109543f9a75SLakshmi Yadlapati             }
110ac106bf6SEd Tanous             handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
111ac106bf6SEd Tanous                                  callback);
112543f9a75SLakshmi Yadlapati             return;
113543f9a75SLakshmi Yadlapati         });
114543f9a75SLakshmi Yadlapati }
115543f9a75SLakshmi Yadlapati 
1164ff0f1f4SEd Tanous inline void handlePCIeDeviceCollectionGet(
117b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
118ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
119b38fa2abSLakshmi Yadlapati     const std::string& systemName)
120b38fa2abSLakshmi Yadlapati {
121ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
122b38fa2abSLakshmi Yadlapati     {
123b38fa2abSLakshmi Yadlapati         return;
124b38fa2abSLakshmi Yadlapati     }
12525b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
1267f3e84a1SEd Tanous     {
1277f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
1287f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1297f3e84a1SEd Tanous                                    systemName);
1307f3e84a1SEd Tanous         return;
1317f3e84a1SEd Tanous     }
132253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
133b38fa2abSLakshmi Yadlapati     {
134ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
135ac106bf6SEd Tanous                                    systemName);
136b38fa2abSLakshmi Yadlapati         return;
137b38fa2abSLakshmi Yadlapati     }
138543f9a75SLakshmi Yadlapati 
139ac106bf6SEd Tanous     asyncResp->res.addHeader(boost::beast::http::field::link,
140b38fa2abSLakshmi Yadlapati                              "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
141b38fa2abSLakshmi Yadlapati                              "PCIeDeviceCollection.json>; rel=describedby");
142ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
143b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
144253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = std::format(
145253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME);
146ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
147ac106bf6SEd Tanous     asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
148b38fa2abSLakshmi Yadlapati 
14970c4d545SLakshmi Yadlapati     pcie_util::getPCIeDeviceList(asyncResp,
15070c4d545SLakshmi Yadlapati                                  nlohmann::json::json_pointer("/Members"));
151b38fa2abSLakshmi Yadlapati }
152b38fa2abSLakshmi Yadlapati 
1537e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
154adbe192aSJason M. Bills {
155adbe192aSJason M. Bills     /**
156adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
157adbe192aSJason M. Bills      */
15822d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
159ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1607e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
161b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
162f5c9f8bdSJason M. Bills }
163f5c9f8bdSJason M. Bills 
164a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties(
165a5409991SLakshmi Yadlapati     crow::Response& res, const boost::system::error_code& ec,
166a5409991SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieSlotProperties)
167a5409991SLakshmi Yadlapati {
168a5409991SLakshmi Yadlapati     if (ec)
169a5409991SLakshmi Yadlapati     {
17062598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}",
17162598e31SEd Tanous                          ec.value());
172a5409991SLakshmi Yadlapati         messages::internalError(res);
173a5409991SLakshmi Yadlapati         return;
174a5409991SLakshmi Yadlapati     }
175a5409991SLakshmi Yadlapati     std::string generation;
176a5409991SLakshmi Yadlapati     size_t lanes = 0;
177a5409991SLakshmi Yadlapati     std::string slotType;
178a5409991SLakshmi Yadlapati 
179a5409991SLakshmi Yadlapati     bool success = sdbusplus::unpackPropertiesNoThrow(
180a5409991SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation",
181a5409991SLakshmi Yadlapati         generation, "Lanes", lanes, "SlotType", slotType);
182a5409991SLakshmi Yadlapati 
183a5409991SLakshmi Yadlapati     if (!success)
184a5409991SLakshmi Yadlapati     {
185a5409991SLakshmi Yadlapati         messages::internalError(res);
186a5409991SLakshmi Yadlapati         return;
187a5409991SLakshmi Yadlapati     }
188a5409991SLakshmi Yadlapati 
189a5409991SLakshmi Yadlapati     std::optional<pcie_device::PCIeTypes> pcieType =
190a5409991SLakshmi Yadlapati         pcie_util::redfishPcieGenerationFromDbus(generation);
191a5409991SLakshmi Yadlapati     if (!pcieType)
192a5409991SLakshmi Yadlapati     {
19362598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation);
194a5409991SLakshmi Yadlapati     }
195a5409991SLakshmi Yadlapati     else
196a5409991SLakshmi Yadlapati     {
197a5409991SLakshmi Yadlapati         if (*pcieType == pcie_device::PCIeTypes::Invalid)
198a5409991SLakshmi Yadlapati         {
19962598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation);
200a5409991SLakshmi Yadlapati             messages::internalError(res);
201a5409991SLakshmi Yadlapati             return;
202a5409991SLakshmi Yadlapati         }
203a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["PCIeType"] = *pcieType;
204a5409991SLakshmi Yadlapati     }
205a5409991SLakshmi Yadlapati 
20682f80326SKonstantin Aladyshev     if (lanes != 0)
20782f80326SKonstantin Aladyshev     {
208a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["Lanes"] = lanes;
20982f80326SKonstantin Aladyshev     }
210a5409991SLakshmi Yadlapati 
211a5409991SLakshmi Yadlapati     std::optional<pcie_slots::SlotTypes> redfishSlotType =
212a5409991SLakshmi Yadlapati         pcie_util::dbusSlotTypeToRf(slotType);
213a5409991SLakshmi Yadlapati     if (!redfishSlotType)
214a5409991SLakshmi Yadlapati     {
21562598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType);
216a5409991SLakshmi Yadlapati     }
217a5409991SLakshmi Yadlapati     else
218a5409991SLakshmi Yadlapati     {
219a5409991SLakshmi Yadlapati         if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
220a5409991SLakshmi Yadlapati         {
22162598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType);
222a5409991SLakshmi Yadlapati             messages::internalError(res);
223a5409991SLakshmi Yadlapati             return;
224a5409991SLakshmi Yadlapati         }
225a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["SlotType"] = *redfishSlotType;
226a5409991SLakshmi Yadlapati     }
227a5409991SLakshmi Yadlapati }
228a5409991SLakshmi Yadlapati 
229a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath(
230a5409991SLakshmi Yadlapati     const std::string& pcieDevicePath,
231a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
232a5409991SLakshmi Yadlapati     std::function<void(const std::string& pcieDeviceSlot)>&& callback)
233a5409991SLakshmi Yadlapati {
234a5409991SLakshmi Yadlapati     std::string associationPath = pcieDevicePath + "/contained_by";
235a5409991SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
236a5409991SLakshmi Yadlapati         associationPath, sdbusplus::message::object_path(inventoryPath), 0,
237a5409991SLakshmi Yadlapati         pcieSlotInterface,
2388cb2c024SEd Tanous         [callback = std::move(callback), asyncResp, pcieDevicePath](
239a5409991SLakshmi Yadlapati             const boost::system::error_code& ec,
240a5409991SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& endpoints) {
241a5409991SLakshmi Yadlapati             if (ec)
242a5409991SLakshmi Yadlapati             {
243a5409991SLakshmi Yadlapati                 if (ec.value() == EBADR)
244a5409991SLakshmi Yadlapati                 {
245a5409991SLakshmi Yadlapati                     // Missing association is not an error
246a5409991SLakshmi Yadlapati                     return;
247a5409991SLakshmi Yadlapati                 }
24862598e31SEd Tanous                 BMCWEB_LOG_ERROR(
24962598e31SEd Tanous                     "DBUS response error for getAssociatedSubTreePaths {}",
25062598e31SEd Tanous                     ec.value());
251a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
252a5409991SLakshmi Yadlapati                 return;
253a5409991SLakshmi Yadlapati             }
254a5409991SLakshmi Yadlapati             if (endpoints.size() > 1)
255a5409991SLakshmi Yadlapati             {
25662598e31SEd Tanous                 BMCWEB_LOG_ERROR(
257a6bd55b0SGunnar Mills                     "PCIeDevice {} is associated with more than one PCIeSlot: {}",
258a6bd55b0SGunnar Mills                     pcieDevicePath, endpoints.size());
25967f0b9c0SMyung Bae                 for (const std::string& slotPath : endpoints)
26067f0b9c0SMyung Bae                 {
26167f0b9c0SMyung Bae                     BMCWEB_LOG_ERROR("Invalid PCIeSlotPath: {}", slotPath);
26267f0b9c0SMyung Bae                 }
263a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
264a5409991SLakshmi Yadlapati                 return;
265a5409991SLakshmi Yadlapati             }
266a5409991SLakshmi Yadlapati             if (endpoints.empty())
267a5409991SLakshmi Yadlapati             {
268bd79bce8SPatrick Williams                 // If the device doesn't have an association, return without
269bd79bce8SPatrick Williams                 // PCIe Slot properties
27062598e31SEd Tanous                 BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot");
271a5409991SLakshmi Yadlapati                 return;
272a5409991SLakshmi Yadlapati             }
273a5409991SLakshmi Yadlapati             callback(endpoints[0]);
274a5409991SLakshmi Yadlapati         });
275a5409991SLakshmi Yadlapati }
276a5409991SLakshmi Yadlapati 
277bd79bce8SPatrick Williams inline void afterGetDbusObject(
278bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
279bd79bce8SPatrick Williams     const std::string& pcieDeviceSlot, const boost::system::error_code& ec,
280a5409991SLakshmi Yadlapati     const dbus::utility::MapperGetObject& object)
281a5409991SLakshmi Yadlapati {
282a5409991SLakshmi Yadlapati     if (ec || object.empty())
283a5409991SLakshmi Yadlapati     {
28462598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}",
28562598e31SEd Tanous                          ec.value());
286a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
287a5409991SLakshmi Yadlapati         return;
288a5409991SLakshmi Yadlapati     }
289deae6a78SEd Tanous     dbus::utility::getAllProperties(
290deae6a78SEd Tanous         object.begin()->first, pcieDeviceSlot,
291a5409991SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
292a5409991SLakshmi Yadlapati         [asyncResp](
293a5409991SLakshmi Yadlapati             const boost::system::error_code& ec2,
294a5409991SLakshmi Yadlapati             const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
295a5409991SLakshmi Yadlapati             addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
296a5409991SLakshmi Yadlapati         });
297a5409991SLakshmi Yadlapati }
298a5409991SLakshmi Yadlapati 
299a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath(
300a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
301a5409991SLakshmi Yadlapati     const std::string& pcieDeviceSlot)
302a5409991SLakshmi Yadlapati {
303a5409991SLakshmi Yadlapati     dbus::utility::getDbusObject(
304a5409991SLakshmi Yadlapati         pcieDeviceSlot, pcieSlotInterface,
305a5409991SLakshmi Yadlapati         [asyncResp,
306a5409991SLakshmi Yadlapati          pcieDeviceSlot](const boost::system::error_code& ec,
307a5409991SLakshmi Yadlapati                          const dbus::utility::MapperGetObject& object) {
308a5409991SLakshmi Yadlapati             afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
309a5409991SLakshmi Yadlapati         });
310a5409991SLakshmi Yadlapati }
311a5409991SLakshmi Yadlapati 
312bd79bce8SPatrick Williams inline void getPCIeDeviceHealth(
313bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
314bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
315e164f1b6SLakshmi Yadlapati {
316deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
317deae6a78SEd Tanous         service, pcieDevicePath,
318e164f1b6SLakshmi Yadlapati         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
319e164f1b6SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, const bool value) {
320e164f1b6SLakshmi Yadlapati             if (ec)
321e164f1b6SLakshmi Yadlapati             {
322e164f1b6SLakshmi Yadlapati                 if (ec.value() != EBADR)
323e164f1b6SLakshmi Yadlapati                 {
32462598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
32562598e31SEd Tanous                                      ec.value());
326e164f1b6SLakshmi Yadlapati                     messages::internalError(asyncResp->res);
327e164f1b6SLakshmi Yadlapati                 }
328e164f1b6SLakshmi Yadlapati                 return;
329e164f1b6SLakshmi Yadlapati             }
330e164f1b6SLakshmi Yadlapati 
331e164f1b6SLakshmi Yadlapati             if (!value)
332e164f1b6SLakshmi Yadlapati             {
333539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
334539d8c6bSEd Tanous                     resource::Health::Critical;
335e164f1b6SLakshmi Yadlapati             }
336e164f1b6SLakshmi Yadlapati         });
337e164f1b6SLakshmi Yadlapati }
338e164f1b6SLakshmi Yadlapati 
339bd79bce8SPatrick Williams inline void getPCIeDeviceState(
340bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
341bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
342c6bb3285SLakshmi Yadlapati {
343deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
344deae6a78SEd Tanous         service, pcieDevicePath, "xyz.openbmc_project.Inventory.Item",
345deae6a78SEd Tanous         "Present",
346a5409991SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, bool value) {
347c6bb3285SLakshmi Yadlapati             if (ec)
348c6bb3285SLakshmi Yadlapati             {
349c6bb3285SLakshmi Yadlapati                 if (ec.value() != EBADR)
350c6bb3285SLakshmi Yadlapati                 {
35162598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State");
352ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
353c6bb3285SLakshmi Yadlapati                 }
354c6bb3285SLakshmi Yadlapati                 return;
355c6bb3285SLakshmi Yadlapati             }
356c6bb3285SLakshmi Yadlapati 
357c6bb3285SLakshmi Yadlapati             if (!value)
358c6bb3285SLakshmi Yadlapati             {
359539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
360539d8c6bSEd Tanous                     resource::State::Absent;
361c6bb3285SLakshmi Yadlapati             }
362c6bb3285SLakshmi Yadlapati         });
363c6bb3285SLakshmi Yadlapati }
364c6bb3285SLakshmi Yadlapati 
365543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
366a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
367a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId,
368543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
369f5c9f8bdSJason M. Bills {
370d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
371814bf20aSKonstantin Aladyshev     const std::string* generationSupported = nullptr;
3729bb0a7feSKonstantin Aladyshev     const size_t* lanesInUse = nullptr;
373814bf20aSKonstantin Aladyshev     const size_t* maxLanes = nullptr;
374d1bde9e5SKrzysztof Grobelny 
375d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
376609ba4c9SEd Tanous         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse",
377609ba4c9SEd Tanous         generationInUse, "GenerationSupported", generationSupported,
378609ba4c9SEd Tanous         "LanesInUse", lanesInUse, "MaxLanes", maxLanes);
379d1bde9e5SKrzysztof Grobelny 
380d1bde9e5SKrzysztof Grobelny     if (!success)
381d1bde9e5SKrzysztof Grobelny     {
382a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
383d1bde9e5SKrzysztof Grobelny         return;
384d1bde9e5SKrzysztof Grobelny     }
385d1bde9e5SKrzysztof Grobelny 
386d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
387d1bde9e5SKrzysztof Grobelny     {
3880ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
389c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
390543f9a75SLakshmi Yadlapati 
391d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
392d1bde9e5SKrzysztof Grobelny         {
39362598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
39462598e31SEd Tanous                                *generationInUse);
395cf3b484eSLakshmi Yadlapati         }
396cf3b484eSLakshmi Yadlapati         else
397cf3b484eSLakshmi Yadlapati         {
398cf3b484eSLakshmi Yadlapati             if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
399cf3b484eSLakshmi Yadlapati             {
40062598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
40162598e31SEd Tanous                                  *generationInUse);
402a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
403d1bde9e5SKrzysztof Grobelny                 return;
404d1bde9e5SKrzysztof Grobelny             }
405a5409991SLakshmi Yadlapati             asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
406d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
407d1bde9e5SKrzysztof Grobelny         }
408a9f68bb5STony Lee     }
409d1bde9e5SKrzysztof Grobelny 
410814bf20aSKonstantin Aladyshev     if (generationSupported != nullptr)
411814bf20aSKonstantin Aladyshev     {
412814bf20aSKonstantin Aladyshev         std::optional<pcie_device::PCIeTypes> redfishGenerationSupported =
413814bf20aSKonstantin Aladyshev             pcie_util::redfishPcieGenerationFromDbus(*generationSupported);
414814bf20aSKonstantin Aladyshev 
415814bf20aSKonstantin Aladyshev         if (!redfishGenerationSupported)
416814bf20aSKonstantin Aladyshev         {
41762598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
41862598e31SEd Tanous                                *generationSupported);
419814bf20aSKonstantin Aladyshev         }
420814bf20aSKonstantin Aladyshev         else
421814bf20aSKonstantin Aladyshev         {
422814bf20aSKonstantin Aladyshev             if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid)
423814bf20aSKonstantin Aladyshev             {
42462598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
42562598e31SEd Tanous                                  *generationSupported);
426814bf20aSKonstantin Aladyshev                 messages::internalError(asyncResp->res);
427814bf20aSKonstantin Aladyshev                 return;
428814bf20aSKonstantin Aladyshev             }
429814bf20aSKonstantin Aladyshev             asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] =
430814bf20aSKonstantin Aladyshev                 *redfishGenerationSupported;
431814bf20aSKonstantin Aladyshev         }
432814bf20aSKonstantin Aladyshev     }
433814bf20aSKonstantin Aladyshev 
4348c1d0549SMyung Bae     if (lanesInUse != nullptr)
435543f9a75SLakshmi Yadlapati     {
4368c1d0549SMyung Bae         if (*lanesInUse == std::numeric_limits<size_t>::max())
4378c1d0549SMyung Bae         {
4388c1d0549SMyung Bae             // The default value of LanesInUse is "maxint", and the field will
4398c1d0549SMyung Bae             // be null if it is a default value.
4408c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr;
4418c1d0549SMyung Bae         }
4428c1d0549SMyung Bae         else
4438c1d0549SMyung Bae         {
4448c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] =
4458c1d0549SMyung Bae                 *lanesInUse;
4468c1d0549SMyung Bae         }
447543f9a75SLakshmi Yadlapati     }
448814bf20aSKonstantin Aladyshev     // The default value of MaxLanes is 0, and the field will be
449814bf20aSKonstantin Aladyshev     // left as off if it is a default value.
450814bf20aSKonstantin Aladyshev     if (maxLanes != nullptr && *maxLanes != 0)
451814bf20aSKonstantin Aladyshev     {
452814bf20aSKonstantin Aladyshev         asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes;
453814bf20aSKonstantin Aladyshev     }
454543f9a75SLakshmi Yadlapati 
455a5409991SLakshmi Yadlapati     asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
456a5409991SLakshmi Yadlapati         boost::urls::format(
457253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
458253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
459d1bde9e5SKrzysztof Grobelny }
460d1bde9e5SKrzysztof Grobelny 
461543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
462ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
463543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
464543f9a75SLakshmi Yadlapati     const std::function<void(
465543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
466d1bde9e5SKrzysztof Grobelny {
467deae6a78SEd Tanous     dbus::utility::getAllProperties(
468deae6a78SEd Tanous         service, pcieDevicePath,
469543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
470ac106bf6SEd Tanous         [asyncResp,
471543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
472543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
473543f9a75SLakshmi Yadlapati             if (ec)
474543f9a75SLakshmi Yadlapati             {
475543f9a75SLakshmi Yadlapati                 if (ec.value() != EBADR)
476543f9a75SLakshmi Yadlapati                 {
47762598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties");
478ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
479543f9a75SLakshmi Yadlapati                 }
480543f9a75SLakshmi Yadlapati                 return;
481543f9a75SLakshmi Yadlapati             }
482543f9a75SLakshmi Yadlapati             callback(pcieDevProperties);
483543f9a75SLakshmi Yadlapati         });
484d1bde9e5SKrzysztof Grobelny }
485d1bde9e5SKrzysztof Grobelny 
486543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
487ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
488543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
489543f9a75SLakshmi Yadlapati {
490ac106bf6SEd Tanous     asyncResp->res.addHeader(
491543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
492543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
493ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
494253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
495253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
496253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
497ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
498ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
499539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
500539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
501543f9a75SLakshmi Yadlapati }
5021476687dSEd Tanous 
503a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath(
504a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
505a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId, const std::string& pcieDevicePath,
506a5409991SLakshmi Yadlapati     const std::string& service)
507a5409991SLakshmi Yadlapati {
508a5409991SLakshmi Yadlapati     addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
509*f7e62c14SMyung Bae     asset_utils::getAssetInfo(asyncResp, service, pcieDevicePath,
510*f7e62c14SMyung Bae                               ""_json_pointer, true);
511a5409991SLakshmi Yadlapati     getPCIeDeviceState(asyncResp, pcieDevicePath, service);
512a5409991SLakshmi Yadlapati     getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
513a5409991SLakshmi Yadlapati     getPCIeDeviceProperties(
514a5409991SLakshmi Yadlapati         asyncResp, pcieDevicePath, service,
515a5409991SLakshmi Yadlapati         std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
516a5409991SLakshmi Yadlapati     getPCIeDeviceSlotPath(
517a5409991SLakshmi Yadlapati         pcieDevicePath, asyncResp,
518a5409991SLakshmi Yadlapati         std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
519a5409991SLakshmi Yadlapati }
520a5409991SLakshmi Yadlapati 
521bd79bce8SPatrick Williams inline void handlePCIeDeviceGet(
522bd79bce8SPatrick Williams     App& app, const crow::Request& req,
523ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
524bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId)
525543f9a75SLakshmi Yadlapati {
526ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
527543f9a75SLakshmi Yadlapati     {
528543f9a75SLakshmi Yadlapati         return;
529543f9a75SLakshmi Yadlapati     }
53025b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5317f3e84a1SEd Tanous     {
5327f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
5337f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5347f3e84a1SEd Tanous                                    systemName);
5357f3e84a1SEd Tanous         return;
5367f3e84a1SEd Tanous     }
537253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
538543f9a75SLakshmi Yadlapati     {
539ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
540ac106bf6SEd Tanous                                    systemName);
541543f9a75SLakshmi Yadlapati         return;
542543f9a75SLakshmi Yadlapati     }
543543f9a75SLakshmi Yadlapati 
544543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
545ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
546a5409991SLakshmi Yadlapati         std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
547543f9a75SLakshmi Yadlapati }
548543f9a75SLakshmi Yadlapati 
549543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
550543f9a75SLakshmi Yadlapati {
551543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
552543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
553543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
554543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
555dede6a98SJason M. Bills }
556dede6a98SJason M. Bills 
55735ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
55835ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
55935ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
56035ad613dSLakshmi Yadlapati {
56135ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
56235ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
56335ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
56435ad613dSLakshmi Yadlapati 
56535ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
56635ad613dSLakshmi Yadlapati     {
56735ad613dSLakshmi Yadlapati         // Check if this function exists by
56835ad613dSLakshmi Yadlapati         // looking for a device ID
569bd79bce8SPatrick Williams         std::string devIDProperty =
570bd79bce8SPatrick Williams             "Function" + std::to_string(functionNum) + "DeviceId";
57135ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
57235ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
57335ad613dSLakshmi Yadlapati         {
57435ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
57535ad613dSLakshmi Yadlapati             {
57635ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
57735ad613dSLakshmi Yadlapati                 break;
57835ad613dSLakshmi Yadlapati             }
57935ad613dSLakshmi Yadlapati         }
58035ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
58135ad613dSLakshmi Yadlapati         {
58235ad613dSLakshmi Yadlapati             continue;
58335ad613dSLakshmi Yadlapati         }
58435ad613dSLakshmi Yadlapati 
58535ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
586ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
587253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
588253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
589253f11b8SEd Tanous             std::to_string(functionNum));
590b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
59135ad613dSLakshmi Yadlapati     }
59235ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
59335ad613dSLakshmi Yadlapati }
59435ad613dSLakshmi Yadlapati 
59535ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
59635ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
597ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5987f3e84a1SEd Tanous     const std::string& systemName, const std::string& pcieDeviceId)
59935ad613dSLakshmi Yadlapati {
600ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
60135ad613dSLakshmi Yadlapati     {
60235ad613dSLakshmi Yadlapati         return;
60335ad613dSLakshmi Yadlapati     }
60425b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
6057f3e84a1SEd Tanous     {
6067f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
6077f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6087f3e84a1SEd Tanous                                    systemName);
6097f3e84a1SEd Tanous         return;
6107f3e84a1SEd Tanous     }
61135ad613dSLakshmi Yadlapati 
61235ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
613ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
614ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
61535ad613dSLakshmi Yadlapati                                   const std::string& service) {
616ac106bf6SEd Tanous             asyncResp->res.addHeader(
61735ad613dSLakshmi Yadlapati                 boost::beast::http::field::link,
61835ad613dSLakshmi Yadlapati                 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
619ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
62035ad613dSLakshmi Yadlapati                 "#PCIeFunctionCollection.PCIeFunctionCollection";
621ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
622253f11b8SEd Tanous                 "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
623253f11b8SEd Tanous                 BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
624ac106bf6SEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
625ac106bf6SEd Tanous             asyncResp->res.jsonValue["Description"] =
62635ad613dSLakshmi Yadlapati                 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
62735ad613dSLakshmi Yadlapati             getPCIeDeviceProperties(
628ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
629ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId](
63035ad613dSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
631ac106bf6SEd Tanous                     addPCIeFunctionList(asyncResp->res, pcieDeviceId,
632ac106bf6SEd Tanous                                         pcieDevProperties);
63335ad613dSLakshmi Yadlapati                 });
63435ad613dSLakshmi Yadlapati         });
63535ad613dSLakshmi Yadlapati }
63635ad613dSLakshmi Yadlapati 
6377e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
6387e860f15SJohn Edward Broadbent {
639dede6a98SJason M. Bills     /**
640dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
641dede6a98SJason M. Bills      */
6427e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
6437f3e84a1SEd Tanous                  "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
644ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
645002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
64635ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
6477e860f15SJohn Edward Broadbent }
6487e860f15SJohn Edward Broadbent 
649727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
650e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
651727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
652f5c9f8bdSJason M. Bills {
653e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
654b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
655f5c9f8bdSJason M. Bills     {
656b9d36b47SEd Tanous         const std::string* strProperty =
657b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
658dc8cfa66SEd Tanous         if (strProperty == nullptr)
659dc8cfa66SEd Tanous         {
660dc8cfa66SEd Tanous             continue;
661dc8cfa66SEd Tanous         }
662b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
663f5c9f8bdSJason M. Bills         {
664727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
665f5c9f8bdSJason M. Bills         }
666b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
667f5c9f8bdSJason M. Bills         {
668727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
669f5c9f8bdSJason M. Bills         }
670727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
671727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
672727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
673b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
674f5c9f8bdSJason M. Bills         {
675727a046cSLakshmi Yadlapati             if (!strProperty->empty())
676727a046cSLakshmi Yadlapati             {
677727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
678727a046cSLakshmi Yadlapati             }
679f5c9f8bdSJason M. Bills         }
680b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
681f5c9f8bdSJason M. Bills         {
682727a046cSLakshmi Yadlapati             if (!strProperty->empty())
683727a046cSLakshmi Yadlapati             {
684727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
685727a046cSLakshmi Yadlapati             }
686f5c9f8bdSJason M. Bills         }
687b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
688f5c9f8bdSJason M. Bills         {
689727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
690f5c9f8bdSJason M. Bills         }
691b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
692f5c9f8bdSJason M. Bills         {
693727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
694f5c9f8bdSJason M. Bills         }
695b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
696b9d36b47SEd Tanous         {
697727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
698b9d36b47SEd Tanous         }
699002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
700f5c9f8bdSJason M. Bills         {
701727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
702b9d36b47SEd Tanous         }
703f5c9f8bdSJason M. Bills     }
704727a046cSLakshmi Yadlapati }
705727a046cSLakshmi Yadlapati 
706727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
707727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
708e14742caSEd Tanous                                             uint64_t pcieFunctionId)
709727a046cSLakshmi Yadlapati {
710727a046cSLakshmi Yadlapati     resp.addHeader(
711727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
712727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
713727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
714ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
715253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
716253f11b8SEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
717253f11b8SEd Tanous         std::to_string(pcieFunctionId));
718727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
719e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
720e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
721253f11b8SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
722253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
723253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
724727a046cSLakshmi Yadlapati }
725727a046cSLakshmi Yadlapati 
726bd79bce8SPatrick Williams inline void handlePCIeFunctionGet(
727bd79bce8SPatrick Williams     App& app, const crow::Request& req,
728ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
729bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId,
730e14742caSEd Tanous     const std::string& pcieFunctionIdStr)
731727a046cSLakshmi Yadlapati {
732ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
733727a046cSLakshmi Yadlapati     {
734727a046cSLakshmi Yadlapati         return;
735727a046cSLakshmi Yadlapati     }
73625b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
7377f3e84a1SEd Tanous     {
7387f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
7397f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
7407f3e84a1SEd Tanous                                    systemName);
7417f3e84a1SEd Tanous         return;
7427f3e84a1SEd Tanous     }
743253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
7447f3e84a1SEd Tanous     {
7457f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
7467f3e84a1SEd Tanous                                    systemName);
7477f3e84a1SEd Tanous         return;
7487f3e84a1SEd Tanous     }
749dc8cfa66SEd Tanous     std::string_view pcieFunctionIdView = pcieFunctionIdStr;
7507f3e84a1SEd Tanous 
751e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
752e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
753dc8cfa66SEd Tanous         pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId);
754dc8cfa66SEd Tanous     if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end())
755e14742caSEd Tanous     {
756ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
757e14742caSEd Tanous                                    pcieFunctionIdStr);
758e14742caSEd Tanous         return;
759e14742caSEd Tanous     }
760727a046cSLakshmi Yadlapati 
761bd79bce8SPatrick Williams     getValidPCIeDevicePath(
762bd79bce8SPatrick Williams         pcieDeviceId, asyncResp,
763bd79bce8SPatrick Williams         [asyncResp, pcieDeviceId, pcieFunctionId](
764bd79bce8SPatrick Williams             const std::string& pcieDevicePath, const std::string& service) {
765727a046cSLakshmi Yadlapati             getPCIeDeviceProperties(
766ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
767ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId, pcieFunctionId](
768727a046cSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
769bd79bce8SPatrick Williams                     addPCIeFunctionCommonProperties(
770bd79bce8SPatrick Williams                         asyncResp->res, pcieDeviceId, pcieFunctionId);
771ac106bf6SEd Tanous                     addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
772727a046cSLakshmi Yadlapati                                               pcieDevProperties);
7737e860f15SJohn Edward Broadbent                 });
774727a046cSLakshmi Yadlapati         });
775727a046cSLakshmi Yadlapati }
776727a046cSLakshmi Yadlapati 
777727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
778727a046cSLakshmi Yadlapati {
779727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
7807f3e84a1SEd Tanous         app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
781727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
782727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
783727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
784f5c9f8bdSJason M. Bills }
785f5c9f8bdSJason M. Bills 
786f5c9f8bdSJason M. Bills } // namespace redfish
787