xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
4f5c9f8bdSJason M. Bills 
5f5c9f8bdSJason M. Bills #pragma once
6f5c9f8bdSJason M. Bills 
73ccb3adbSEd Tanous #include "app.hpp"
87a1dbc48SGeorge Liu #include "dbus_utility.hpp"
9539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
103ccb3adbSEd Tanous #include "query.hpp"
113ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
12b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp"
133ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
14c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp"
150ec8b83dSEd Tanous 
16f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp>
17ef4c65b7SEd Tanous #include <boost/url/format.hpp>
18d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
19d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
20f5c9f8bdSJason M. Bills 
218c1d0549SMyung Bae #include <limits>
228c1d0549SMyung Bae 
23f5c9f8bdSJason M. Bills namespace redfish
24f5c9f8bdSJason M. Bills {
25f5c9f8bdSJason M. Bills 
2689492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
2794c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
2894c3a10bSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
29a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = {
30a5409991SLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeSlot"};
31f5c9f8bdSJason M. Bills 
324ff0f1f4SEd Tanous inline void handlePCIeDevicePath(
33543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
34ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
35543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
36543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
37543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
38543f9a75SLakshmi Yadlapati 
39543f9a75SLakshmi Yadlapati {
40543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
41543f9a75SLakshmi Yadlapati     {
42543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
43543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
44543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
45543f9a75SLakshmi Yadlapati         {
46543f9a75SLakshmi Yadlapati             continue;
47543f9a75SLakshmi Yadlapati         }
48543f9a75SLakshmi Yadlapati 
49543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
503a58c5a8SKonstantin Aladyshev             pcieDevicePath, pcieDeviceInterface,
51ac106bf6SEd Tanous             [pcieDevicePath, asyncResp,
52543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
53543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
54543f9a75SLakshmi Yadlapati                 if (ec || object.empty())
55543f9a75SLakshmi Yadlapati                 {
5662598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error {}", ec);
57ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
58543f9a75SLakshmi Yadlapati                     return;
59543f9a75SLakshmi Yadlapati                 }
60543f9a75SLakshmi Yadlapati                 callback(pcieDevicePath, object.begin()->first);
61543f9a75SLakshmi Yadlapati             });
62543f9a75SLakshmi Yadlapati         return;
63543f9a75SLakshmi Yadlapati     }
64543f9a75SLakshmi Yadlapati 
6562598e31SEd Tanous     BMCWEB_LOG_WARNING("PCIe Device not found");
66ac106bf6SEd Tanous     messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
67543f9a75SLakshmi Yadlapati }
68543f9a75SLakshmi Yadlapati 
694ff0f1f4SEd Tanous inline void getValidPCIeDevicePath(
70543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
71ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
72543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
73543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
74543f9a75SLakshmi Yadlapati {
75543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
7694c3a10bSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
77ac106bf6SEd Tanous         [pcieDeviceId, asyncResp,
78543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
79543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
80543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
81543f9a75SLakshmi Yadlapati             if (ec)
82543f9a75SLakshmi Yadlapati             {
8362598e31SEd Tanous                 BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
84ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
85543f9a75SLakshmi Yadlapati                 return;
86543f9a75SLakshmi Yadlapati             }
87ac106bf6SEd Tanous             handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
88ac106bf6SEd Tanous                                  callback);
89543f9a75SLakshmi Yadlapati             return;
90543f9a75SLakshmi Yadlapati         });
91543f9a75SLakshmi Yadlapati }
92543f9a75SLakshmi Yadlapati 
934ff0f1f4SEd Tanous inline void handlePCIeDeviceCollectionGet(
94b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
95ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
96b38fa2abSLakshmi Yadlapati     const std::string& systemName)
97b38fa2abSLakshmi Yadlapati {
98ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
99b38fa2abSLakshmi Yadlapati     {
100b38fa2abSLakshmi Yadlapati         return;
101b38fa2abSLakshmi Yadlapati     }
10225b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
1037f3e84a1SEd Tanous     {
1047f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
1057f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1067f3e84a1SEd Tanous                                    systemName);
1077f3e84a1SEd Tanous         return;
1087f3e84a1SEd Tanous     }
109253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
110b38fa2abSLakshmi Yadlapati     {
111ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
112ac106bf6SEd Tanous                                    systemName);
113b38fa2abSLakshmi Yadlapati         return;
114b38fa2abSLakshmi Yadlapati     }
115543f9a75SLakshmi Yadlapati 
116ac106bf6SEd Tanous     asyncResp->res.addHeader(boost::beast::http::field::link,
117b38fa2abSLakshmi Yadlapati                              "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
118b38fa2abSLakshmi Yadlapati                              "PCIeDeviceCollection.json>; rel=describedby");
119ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
120b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
121253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = std::format(
122253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME);
123ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
124ac106bf6SEd Tanous     asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
125b38fa2abSLakshmi Yadlapati 
12670c4d545SLakshmi Yadlapati     pcie_util::getPCIeDeviceList(asyncResp,
12770c4d545SLakshmi Yadlapati                                  nlohmann::json::json_pointer("/Members"));
128b38fa2abSLakshmi Yadlapati }
129b38fa2abSLakshmi Yadlapati 
1307e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
131adbe192aSJason M. Bills {
132adbe192aSJason M. Bills     /**
133adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
134adbe192aSJason M. Bills      */
13522d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
136ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1377e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
138b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
139f5c9f8bdSJason M. Bills }
140f5c9f8bdSJason M. Bills 
141a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties(
142a5409991SLakshmi Yadlapati     crow::Response& res, const boost::system::error_code& ec,
143a5409991SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieSlotProperties)
144a5409991SLakshmi Yadlapati {
145a5409991SLakshmi Yadlapati     if (ec)
146a5409991SLakshmi Yadlapati     {
14762598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}",
14862598e31SEd Tanous                          ec.value());
149a5409991SLakshmi Yadlapati         messages::internalError(res);
150a5409991SLakshmi Yadlapati         return;
151a5409991SLakshmi Yadlapati     }
152a5409991SLakshmi Yadlapati     std::string generation;
153a5409991SLakshmi Yadlapati     size_t lanes = 0;
154a5409991SLakshmi Yadlapati     std::string slotType;
155a5409991SLakshmi Yadlapati 
156a5409991SLakshmi Yadlapati     bool success = sdbusplus::unpackPropertiesNoThrow(
157a5409991SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation",
158a5409991SLakshmi Yadlapati         generation, "Lanes", lanes, "SlotType", slotType);
159a5409991SLakshmi Yadlapati 
160a5409991SLakshmi Yadlapati     if (!success)
161a5409991SLakshmi Yadlapati     {
162a5409991SLakshmi Yadlapati         messages::internalError(res);
163a5409991SLakshmi Yadlapati         return;
164a5409991SLakshmi Yadlapati     }
165a5409991SLakshmi Yadlapati 
166a5409991SLakshmi Yadlapati     std::optional<pcie_device::PCIeTypes> pcieType =
167a5409991SLakshmi Yadlapati         pcie_util::redfishPcieGenerationFromDbus(generation);
168a5409991SLakshmi Yadlapati     if (!pcieType)
169a5409991SLakshmi Yadlapati     {
17062598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation);
171a5409991SLakshmi Yadlapati     }
172a5409991SLakshmi Yadlapati     else
173a5409991SLakshmi Yadlapati     {
174a5409991SLakshmi Yadlapati         if (*pcieType == pcie_device::PCIeTypes::Invalid)
175a5409991SLakshmi Yadlapati         {
17662598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation);
177a5409991SLakshmi Yadlapati             messages::internalError(res);
178a5409991SLakshmi Yadlapati             return;
179a5409991SLakshmi Yadlapati         }
180a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["PCIeType"] = *pcieType;
181a5409991SLakshmi Yadlapati     }
182a5409991SLakshmi Yadlapati 
18382f80326SKonstantin Aladyshev     if (lanes != 0)
18482f80326SKonstantin Aladyshev     {
185a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["Lanes"] = lanes;
18682f80326SKonstantin Aladyshev     }
187a5409991SLakshmi Yadlapati 
188a5409991SLakshmi Yadlapati     std::optional<pcie_slots::SlotTypes> redfishSlotType =
189a5409991SLakshmi Yadlapati         pcie_util::dbusSlotTypeToRf(slotType);
190a5409991SLakshmi Yadlapati     if (!redfishSlotType)
191a5409991SLakshmi Yadlapati     {
19262598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType);
193a5409991SLakshmi Yadlapati     }
194a5409991SLakshmi Yadlapati     else
195a5409991SLakshmi Yadlapati     {
196a5409991SLakshmi Yadlapati         if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
197a5409991SLakshmi Yadlapati         {
19862598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType);
199a5409991SLakshmi Yadlapati             messages::internalError(res);
200a5409991SLakshmi Yadlapati             return;
201a5409991SLakshmi Yadlapati         }
202a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["SlotType"] = *redfishSlotType;
203a5409991SLakshmi Yadlapati     }
204a5409991SLakshmi Yadlapati }
205a5409991SLakshmi Yadlapati 
206a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath(
207a5409991SLakshmi Yadlapati     const std::string& pcieDevicePath,
208a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
209a5409991SLakshmi Yadlapati     std::function<void(const std::string& pcieDeviceSlot)>&& callback)
210a5409991SLakshmi Yadlapati {
211a5409991SLakshmi Yadlapati     std::string associationPath = pcieDevicePath + "/contained_by";
212a5409991SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
213a5409991SLakshmi Yadlapati         associationPath, sdbusplus::message::object_path(inventoryPath), 0,
214a5409991SLakshmi Yadlapati         pcieSlotInterface,
2158cb2c024SEd Tanous         [callback = std::move(callback), asyncResp, pcieDevicePath](
216a5409991SLakshmi Yadlapati             const boost::system::error_code& ec,
217a5409991SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& endpoints) {
218a5409991SLakshmi Yadlapati             if (ec)
219a5409991SLakshmi Yadlapati             {
220a5409991SLakshmi Yadlapati                 if (ec.value() == EBADR)
221a5409991SLakshmi Yadlapati                 {
222a5409991SLakshmi Yadlapati                     // Missing association is not an error
223a5409991SLakshmi Yadlapati                     return;
224a5409991SLakshmi Yadlapati                 }
22562598e31SEd Tanous                 BMCWEB_LOG_ERROR(
22662598e31SEd Tanous                     "DBUS response error for getAssociatedSubTreePaths {}",
22762598e31SEd Tanous                     ec.value());
228a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
229a5409991SLakshmi Yadlapati                 return;
230a5409991SLakshmi Yadlapati             }
231a5409991SLakshmi Yadlapati             if (endpoints.size() > 1)
232a5409991SLakshmi Yadlapati             {
23362598e31SEd Tanous                 BMCWEB_LOG_ERROR(
234a6bd55b0SGunnar Mills                     "PCIeDevice {} is associated with more than one PCIeSlot: {}",
235a6bd55b0SGunnar Mills                     pcieDevicePath, endpoints.size());
236a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
237a5409991SLakshmi Yadlapati                 return;
238a5409991SLakshmi Yadlapati             }
239a5409991SLakshmi Yadlapati             if (endpoints.empty())
240a5409991SLakshmi Yadlapati             {
241bd79bce8SPatrick Williams                 // If the device doesn't have an association, return without
242bd79bce8SPatrick Williams                 // PCIe Slot properties
24362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot");
244a5409991SLakshmi Yadlapati                 return;
245a5409991SLakshmi Yadlapati             }
246a5409991SLakshmi Yadlapati             callback(endpoints[0]);
247a5409991SLakshmi Yadlapati         });
248a5409991SLakshmi Yadlapati }
249a5409991SLakshmi Yadlapati 
250bd79bce8SPatrick Williams inline void afterGetDbusObject(
251bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
252bd79bce8SPatrick Williams     const std::string& pcieDeviceSlot, const boost::system::error_code& ec,
253a5409991SLakshmi Yadlapati     const dbus::utility::MapperGetObject& object)
254a5409991SLakshmi Yadlapati {
255a5409991SLakshmi Yadlapati     if (ec || object.empty())
256a5409991SLakshmi Yadlapati     {
25762598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}",
25862598e31SEd Tanous                          ec.value());
259a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
260a5409991SLakshmi Yadlapati         return;
261a5409991SLakshmi Yadlapati     }
262deae6a78SEd Tanous     dbus::utility::getAllProperties(
263deae6a78SEd Tanous         object.begin()->first, pcieDeviceSlot,
264a5409991SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
265a5409991SLakshmi Yadlapati         [asyncResp](
266a5409991SLakshmi Yadlapati             const boost::system::error_code& ec2,
267a5409991SLakshmi Yadlapati             const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
268a5409991SLakshmi Yadlapati             addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
269a5409991SLakshmi Yadlapati         });
270a5409991SLakshmi Yadlapati }
271a5409991SLakshmi Yadlapati 
272a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath(
273a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
274a5409991SLakshmi Yadlapati     const std::string& pcieDeviceSlot)
275a5409991SLakshmi Yadlapati {
276a5409991SLakshmi Yadlapati     dbus::utility::getDbusObject(
277a5409991SLakshmi Yadlapati         pcieDeviceSlot, pcieSlotInterface,
278a5409991SLakshmi Yadlapati         [asyncResp,
279a5409991SLakshmi Yadlapati          pcieDeviceSlot](const boost::system::error_code& ec,
280a5409991SLakshmi Yadlapati                          const dbus::utility::MapperGetObject& object) {
281a5409991SLakshmi Yadlapati             afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
282a5409991SLakshmi Yadlapati         });
283a5409991SLakshmi Yadlapati }
284a5409991SLakshmi Yadlapati 
285bd79bce8SPatrick Williams inline void getPCIeDeviceHealth(
286bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
287bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
288e164f1b6SLakshmi Yadlapati {
289deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
290deae6a78SEd Tanous         service, pcieDevicePath,
291e164f1b6SLakshmi Yadlapati         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
292e164f1b6SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, const bool value) {
293e164f1b6SLakshmi Yadlapati             if (ec)
294e164f1b6SLakshmi Yadlapati             {
295e164f1b6SLakshmi Yadlapati                 if (ec.value() != EBADR)
296e164f1b6SLakshmi Yadlapati                 {
29762598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
29862598e31SEd Tanous                                      ec.value());
299e164f1b6SLakshmi Yadlapati                     messages::internalError(asyncResp->res);
300e164f1b6SLakshmi Yadlapati                 }
301e164f1b6SLakshmi Yadlapati                 return;
302e164f1b6SLakshmi Yadlapati             }
303e164f1b6SLakshmi Yadlapati 
304e164f1b6SLakshmi Yadlapati             if (!value)
305e164f1b6SLakshmi Yadlapati             {
306539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
307539d8c6bSEd Tanous                     resource::Health::Critical;
308e164f1b6SLakshmi Yadlapati             }
309e164f1b6SLakshmi Yadlapati         });
310e164f1b6SLakshmi Yadlapati }
311e164f1b6SLakshmi Yadlapati 
312bd79bce8SPatrick Williams inline void getPCIeDeviceState(
313bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
314bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
315c6bb3285SLakshmi Yadlapati {
316deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
317deae6a78SEd Tanous         service, pcieDevicePath, "xyz.openbmc_project.Inventory.Item",
318deae6a78SEd Tanous         "Present",
319a5409991SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, bool value) {
320c6bb3285SLakshmi Yadlapati             if (ec)
321c6bb3285SLakshmi Yadlapati             {
322c6bb3285SLakshmi Yadlapati                 if (ec.value() != EBADR)
323c6bb3285SLakshmi Yadlapati                 {
32462598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State");
325ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
326c6bb3285SLakshmi Yadlapati                 }
327c6bb3285SLakshmi Yadlapati                 return;
328c6bb3285SLakshmi Yadlapati             }
329c6bb3285SLakshmi Yadlapati 
330c6bb3285SLakshmi Yadlapati             if (!value)
331c6bb3285SLakshmi Yadlapati             {
332539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
333539d8c6bSEd Tanous                     resource::State::Absent;
334c6bb3285SLakshmi Yadlapati             }
335c6bb3285SLakshmi Yadlapati         });
336c6bb3285SLakshmi Yadlapati }
337c6bb3285SLakshmi Yadlapati 
338bd79bce8SPatrick Williams inline void getPCIeDeviceAsset(
339bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
340bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
341913e7732SSunnySrivastava1984 {
342deae6a78SEd Tanous     dbus::utility::getAllProperties(
343deae6a78SEd Tanous         service, pcieDevicePath,
344913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
345ac106bf6SEd Tanous         [pcieDevicePath, asyncResp{asyncResp}](
346ac106bf6SEd Tanous             const boost::system::error_code& ec,
347913e7732SSunnySrivastava1984             const dbus::utility::DBusPropertiesMap& assetList) {
348913e7732SSunnySrivastava1984             if (ec)
349913e7732SSunnySrivastava1984             {
350913e7732SSunnySrivastava1984                 if (ec.value() != EBADR)
351913e7732SSunnySrivastava1984                 {
35262598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties{}",
35362598e31SEd Tanous                                      ec.value());
354ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
355913e7732SSunnySrivastava1984                 }
356913e7732SSunnySrivastava1984                 return;
357913e7732SSunnySrivastava1984             }
358913e7732SSunnySrivastava1984 
359913e7732SSunnySrivastava1984             const std::string* manufacturer = nullptr;
360913e7732SSunnySrivastava1984             const std::string* model = nullptr;
361913e7732SSunnySrivastava1984             const std::string* partNumber = nullptr;
362913e7732SSunnySrivastava1984             const std::string* serialNumber = nullptr;
363913e7732SSunnySrivastava1984             const std::string* sparePartNumber = nullptr;
364913e7732SSunnySrivastava1984 
365913e7732SSunnySrivastava1984             const bool success = sdbusplus::unpackPropertiesNoThrow(
366913e7732SSunnySrivastava1984                 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
367913e7732SSunnySrivastava1984                 manufacturer, "Model", model, "PartNumber", partNumber,
368bd79bce8SPatrick Williams                 "SerialNumber", serialNumber, "SparePartNumber",
369bd79bce8SPatrick Williams                 sparePartNumber);
370913e7732SSunnySrivastava1984 
371913e7732SSunnySrivastava1984             if (!success)
372913e7732SSunnySrivastava1984             {
373ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
374913e7732SSunnySrivastava1984                 return;
375913e7732SSunnySrivastava1984             }
376913e7732SSunnySrivastava1984 
377913e7732SSunnySrivastava1984             if (manufacturer != nullptr)
378913e7732SSunnySrivastava1984             {
379ac106bf6SEd Tanous                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
380913e7732SSunnySrivastava1984             }
381913e7732SSunnySrivastava1984             if (model != nullptr)
382913e7732SSunnySrivastava1984             {
383ac106bf6SEd Tanous                 asyncResp->res.jsonValue["Model"] = *model;
384913e7732SSunnySrivastava1984             }
385913e7732SSunnySrivastava1984 
386913e7732SSunnySrivastava1984             if (partNumber != nullptr)
387913e7732SSunnySrivastava1984             {
388ac106bf6SEd Tanous                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
389913e7732SSunnySrivastava1984             }
390913e7732SSunnySrivastava1984 
391913e7732SSunnySrivastava1984             if (serialNumber != nullptr)
392913e7732SSunnySrivastava1984             {
393ac106bf6SEd Tanous                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
394913e7732SSunnySrivastava1984             }
395913e7732SSunnySrivastava1984 
396913e7732SSunnySrivastava1984             if (sparePartNumber != nullptr && !sparePartNumber->empty())
397913e7732SSunnySrivastava1984             {
398ac106bf6SEd Tanous                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
399913e7732SSunnySrivastava1984             }
400913e7732SSunnySrivastava1984         });
401913e7732SSunnySrivastava1984 }
402913e7732SSunnySrivastava1984 
403543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
404a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
405a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId,
406543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
407f5c9f8bdSJason M. Bills {
408d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
409814bf20aSKonstantin Aladyshev     const std::string* generationSupported = nullptr;
4109bb0a7feSKonstantin Aladyshev     const size_t* lanesInUse = nullptr;
411814bf20aSKonstantin Aladyshev     const size_t* maxLanes = nullptr;
412d1bde9e5SKrzysztof Grobelny 
413d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
414609ba4c9SEd Tanous         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse",
415609ba4c9SEd Tanous         generationInUse, "GenerationSupported", generationSupported,
416609ba4c9SEd Tanous         "LanesInUse", lanesInUse, "MaxLanes", maxLanes);
417d1bde9e5SKrzysztof Grobelny 
418d1bde9e5SKrzysztof Grobelny     if (!success)
419d1bde9e5SKrzysztof Grobelny     {
420a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
421d1bde9e5SKrzysztof Grobelny         return;
422d1bde9e5SKrzysztof Grobelny     }
423d1bde9e5SKrzysztof Grobelny 
424d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
425d1bde9e5SKrzysztof Grobelny     {
4260ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
427c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
428543f9a75SLakshmi Yadlapati 
429d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
430d1bde9e5SKrzysztof Grobelny         {
43162598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
43262598e31SEd Tanous                                *generationInUse);
433cf3b484eSLakshmi Yadlapati         }
434cf3b484eSLakshmi Yadlapati         else
435cf3b484eSLakshmi Yadlapati         {
436cf3b484eSLakshmi Yadlapati             if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
437cf3b484eSLakshmi Yadlapati             {
43862598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
43962598e31SEd Tanous                                  *generationInUse);
440a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
441d1bde9e5SKrzysztof Grobelny                 return;
442d1bde9e5SKrzysztof Grobelny             }
443a5409991SLakshmi Yadlapati             asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
444d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
445d1bde9e5SKrzysztof Grobelny         }
446a9f68bb5STony Lee     }
447d1bde9e5SKrzysztof Grobelny 
448814bf20aSKonstantin Aladyshev     if (generationSupported != nullptr)
449814bf20aSKonstantin Aladyshev     {
450814bf20aSKonstantin Aladyshev         std::optional<pcie_device::PCIeTypes> redfishGenerationSupported =
451814bf20aSKonstantin Aladyshev             pcie_util::redfishPcieGenerationFromDbus(*generationSupported);
452814bf20aSKonstantin Aladyshev 
453814bf20aSKonstantin Aladyshev         if (!redfishGenerationSupported)
454814bf20aSKonstantin Aladyshev         {
45562598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
45662598e31SEd Tanous                                *generationSupported);
457814bf20aSKonstantin Aladyshev         }
458814bf20aSKonstantin Aladyshev         else
459814bf20aSKonstantin Aladyshev         {
460814bf20aSKonstantin Aladyshev             if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid)
461814bf20aSKonstantin Aladyshev             {
46262598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
46362598e31SEd Tanous                                  *generationSupported);
464814bf20aSKonstantin Aladyshev                 messages::internalError(asyncResp->res);
465814bf20aSKonstantin Aladyshev                 return;
466814bf20aSKonstantin Aladyshev             }
467814bf20aSKonstantin Aladyshev             asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] =
468814bf20aSKonstantin Aladyshev                 *redfishGenerationSupported;
469814bf20aSKonstantin Aladyshev         }
470814bf20aSKonstantin Aladyshev     }
471814bf20aSKonstantin Aladyshev 
4728c1d0549SMyung Bae     if (lanesInUse != nullptr)
473543f9a75SLakshmi Yadlapati     {
4748c1d0549SMyung Bae         if (*lanesInUse == std::numeric_limits<size_t>::max())
4758c1d0549SMyung Bae         {
4768c1d0549SMyung Bae             // The default value of LanesInUse is "maxint", and the field will
4778c1d0549SMyung Bae             // be null if it is a default value.
4788c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr;
4798c1d0549SMyung Bae         }
4808c1d0549SMyung Bae         else
4818c1d0549SMyung Bae         {
4828c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] =
4838c1d0549SMyung Bae                 *lanesInUse;
4848c1d0549SMyung Bae         }
485543f9a75SLakshmi Yadlapati     }
486814bf20aSKonstantin Aladyshev     // The default value of MaxLanes is 0, and the field will be
487814bf20aSKonstantin Aladyshev     // left as off if it is a default value.
488814bf20aSKonstantin Aladyshev     if (maxLanes != nullptr && *maxLanes != 0)
489814bf20aSKonstantin Aladyshev     {
490814bf20aSKonstantin Aladyshev         asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes;
491814bf20aSKonstantin Aladyshev     }
492543f9a75SLakshmi Yadlapati 
493a5409991SLakshmi Yadlapati     asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
494a5409991SLakshmi Yadlapati         boost::urls::format(
495253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
496253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
497d1bde9e5SKrzysztof Grobelny }
498d1bde9e5SKrzysztof Grobelny 
499543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
500ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
501543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
502543f9a75SLakshmi Yadlapati     const std::function<void(
503543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
504d1bde9e5SKrzysztof Grobelny {
505deae6a78SEd Tanous     dbus::utility::getAllProperties(
506deae6a78SEd Tanous         service, pcieDevicePath,
507543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
508ac106bf6SEd Tanous         [asyncResp,
509543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
510543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
511543f9a75SLakshmi Yadlapati             if (ec)
512543f9a75SLakshmi Yadlapati             {
513543f9a75SLakshmi Yadlapati                 if (ec.value() != EBADR)
514543f9a75SLakshmi Yadlapati                 {
51562598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties");
516ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
517543f9a75SLakshmi Yadlapati                 }
518543f9a75SLakshmi Yadlapati                 return;
519543f9a75SLakshmi Yadlapati             }
520543f9a75SLakshmi Yadlapati             callback(pcieDevProperties);
521543f9a75SLakshmi Yadlapati         });
522d1bde9e5SKrzysztof Grobelny }
523d1bde9e5SKrzysztof Grobelny 
524543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
525ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
526543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
527543f9a75SLakshmi Yadlapati {
528ac106bf6SEd Tanous     asyncResp->res.addHeader(
529543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
530543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
531ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
532253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
533253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
534253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
535ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
536ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
537539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
538539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
539543f9a75SLakshmi Yadlapati }
5401476687dSEd Tanous 
541a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath(
542a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
543a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId, const std::string& pcieDevicePath,
544a5409991SLakshmi Yadlapati     const std::string& service)
545a5409991SLakshmi Yadlapati {
546a5409991SLakshmi Yadlapati     addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
547a5409991SLakshmi Yadlapati     getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
548a5409991SLakshmi Yadlapati     getPCIeDeviceState(asyncResp, pcieDevicePath, service);
549a5409991SLakshmi Yadlapati     getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
550a5409991SLakshmi Yadlapati     getPCIeDeviceProperties(
551a5409991SLakshmi Yadlapati         asyncResp, pcieDevicePath, service,
552a5409991SLakshmi Yadlapati         std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
553a5409991SLakshmi Yadlapati     getPCIeDeviceSlotPath(
554a5409991SLakshmi Yadlapati         pcieDevicePath, asyncResp,
555a5409991SLakshmi Yadlapati         std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
556a5409991SLakshmi Yadlapati }
557a5409991SLakshmi Yadlapati 
558bd79bce8SPatrick Williams inline void handlePCIeDeviceGet(
559bd79bce8SPatrick Williams     App& app, const crow::Request& req,
560ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
561bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId)
562543f9a75SLakshmi Yadlapati {
563ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
564543f9a75SLakshmi Yadlapati     {
565543f9a75SLakshmi Yadlapati         return;
566543f9a75SLakshmi Yadlapati     }
56725b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5687f3e84a1SEd Tanous     {
5697f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
5707f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5717f3e84a1SEd Tanous                                    systemName);
5727f3e84a1SEd Tanous         return;
5737f3e84a1SEd Tanous     }
574253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
575543f9a75SLakshmi Yadlapati     {
576ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
577ac106bf6SEd Tanous                                    systemName);
578543f9a75SLakshmi Yadlapati         return;
579543f9a75SLakshmi Yadlapati     }
580543f9a75SLakshmi Yadlapati 
581543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
582ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
583a5409991SLakshmi Yadlapati         std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
584543f9a75SLakshmi Yadlapati }
585543f9a75SLakshmi Yadlapati 
586543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
587543f9a75SLakshmi Yadlapati {
588543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
589543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
590543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
591543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
592dede6a98SJason M. Bills }
593dede6a98SJason M. Bills 
59435ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
59535ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
59635ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
59735ad613dSLakshmi Yadlapati {
59835ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
59935ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
60035ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
60135ad613dSLakshmi Yadlapati 
60235ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
60335ad613dSLakshmi Yadlapati     {
60435ad613dSLakshmi Yadlapati         // Check if this function exists by
60535ad613dSLakshmi Yadlapati         // looking for a device ID
606bd79bce8SPatrick Williams         std::string devIDProperty =
607bd79bce8SPatrick Williams             "Function" + std::to_string(functionNum) + "DeviceId";
60835ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
60935ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
61035ad613dSLakshmi Yadlapati         {
61135ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
61235ad613dSLakshmi Yadlapati             {
61335ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
61435ad613dSLakshmi Yadlapati                 break;
61535ad613dSLakshmi Yadlapati             }
61635ad613dSLakshmi Yadlapati         }
61735ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
61835ad613dSLakshmi Yadlapati         {
61935ad613dSLakshmi Yadlapati             continue;
62035ad613dSLakshmi Yadlapati         }
62135ad613dSLakshmi Yadlapati 
62235ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
623ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
624253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
625253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
626253f11b8SEd Tanous             std::to_string(functionNum));
627b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
62835ad613dSLakshmi Yadlapati     }
62935ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
63035ad613dSLakshmi Yadlapati }
63135ad613dSLakshmi Yadlapati 
63235ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
63335ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
634ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6357f3e84a1SEd Tanous     const std::string& systemName, const std::string& pcieDeviceId)
63635ad613dSLakshmi Yadlapati {
637ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
63835ad613dSLakshmi Yadlapati     {
63935ad613dSLakshmi Yadlapati         return;
64035ad613dSLakshmi Yadlapati     }
64125b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
6427f3e84a1SEd Tanous     {
6437f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
6447f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6457f3e84a1SEd Tanous                                    systemName);
6467f3e84a1SEd Tanous         return;
6477f3e84a1SEd Tanous     }
64835ad613dSLakshmi Yadlapati 
64935ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
650ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
651ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
65235ad613dSLakshmi Yadlapati                                   const std::string& service) {
653ac106bf6SEd Tanous             asyncResp->res.addHeader(
65435ad613dSLakshmi Yadlapati                 boost::beast::http::field::link,
65535ad613dSLakshmi Yadlapati                 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
656ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
65735ad613dSLakshmi Yadlapati                 "#PCIeFunctionCollection.PCIeFunctionCollection";
658ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
659253f11b8SEd Tanous                 "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
660253f11b8SEd Tanous                 BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
661ac106bf6SEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
662ac106bf6SEd Tanous             asyncResp->res.jsonValue["Description"] =
66335ad613dSLakshmi Yadlapati                 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
66435ad613dSLakshmi Yadlapati             getPCIeDeviceProperties(
665ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
666ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId](
66735ad613dSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
668ac106bf6SEd Tanous                     addPCIeFunctionList(asyncResp->res, pcieDeviceId,
669ac106bf6SEd Tanous                                         pcieDevProperties);
67035ad613dSLakshmi Yadlapati                 });
67135ad613dSLakshmi Yadlapati         });
67235ad613dSLakshmi Yadlapati }
67335ad613dSLakshmi Yadlapati 
6747e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
6757e860f15SJohn Edward Broadbent {
676dede6a98SJason M. Bills     /**
677dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
678dede6a98SJason M. Bills      */
6797e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
6807f3e84a1SEd Tanous                  "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
681ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
682002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
68335ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
6847e860f15SJohn Edward Broadbent }
6857e860f15SJohn Edward Broadbent 
686727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
687d5e74b80SMyung Bae     uint64_t pcieFunctionId,
688727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
6897e860f15SJohn Edward Broadbent {
690d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
691b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
692b9d36b47SEd Tanous 
693b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
694b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
695b9d36b47SEd Tanous     {
696b9d36b47SEd Tanous         if (property.first == devIDProperty)
697b9d36b47SEd Tanous         {
698002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
699727a046cSLakshmi Yadlapati             break;
700b9d36b47SEd Tanous         }
701b9d36b47SEd Tanous     }
702727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
703727a046cSLakshmi Yadlapati }
704727a046cSLakshmi Yadlapati 
705727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
706e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
707727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
708f5c9f8bdSJason M. Bills {
709e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
710b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
711f5c9f8bdSJason M. Bills     {
712b9d36b47SEd Tanous         const std::string* strProperty =
713b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
714dc8cfa66SEd Tanous         if (strProperty == nullptr)
715dc8cfa66SEd Tanous         {
716dc8cfa66SEd Tanous             continue;
717dc8cfa66SEd Tanous         }
718b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
719f5c9f8bdSJason M. Bills         {
720727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
721f5c9f8bdSJason M. Bills         }
722b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
723f5c9f8bdSJason M. Bills         {
724727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
725f5c9f8bdSJason M. Bills         }
726727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
727727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
728727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
729b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
730f5c9f8bdSJason M. Bills         {
731727a046cSLakshmi Yadlapati             if (!strProperty->empty())
732727a046cSLakshmi Yadlapati             {
733727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
734727a046cSLakshmi Yadlapati             }
735f5c9f8bdSJason M. Bills         }
736b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
737f5c9f8bdSJason M. Bills         {
738727a046cSLakshmi Yadlapati             if (!strProperty->empty())
739727a046cSLakshmi Yadlapati             {
740727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
741727a046cSLakshmi Yadlapati             }
742f5c9f8bdSJason M. Bills         }
743b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
744f5c9f8bdSJason M. Bills         {
745727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
746f5c9f8bdSJason M. Bills         }
747b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
748f5c9f8bdSJason M. Bills         {
749727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
750f5c9f8bdSJason M. Bills         }
751b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
752b9d36b47SEd Tanous         {
753727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
754b9d36b47SEd Tanous         }
755002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
756f5c9f8bdSJason M. Bills         {
757727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
758b9d36b47SEd Tanous         }
759f5c9f8bdSJason M. Bills     }
760727a046cSLakshmi Yadlapati }
761727a046cSLakshmi Yadlapati 
762727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
763727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
764e14742caSEd Tanous                                             uint64_t pcieFunctionId)
765727a046cSLakshmi Yadlapati {
766727a046cSLakshmi Yadlapati     resp.addHeader(
767727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
768727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
769727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
770ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
771253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
772253f11b8SEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
773253f11b8SEd Tanous         std::to_string(pcieFunctionId));
774727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
775e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
776e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
777253f11b8SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
778253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
779253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
780727a046cSLakshmi Yadlapati }
781727a046cSLakshmi Yadlapati 
782bd79bce8SPatrick Williams inline void handlePCIeFunctionGet(
783bd79bce8SPatrick Williams     App& app, const crow::Request& req,
784ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
785bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId,
786e14742caSEd Tanous     const std::string& pcieFunctionIdStr)
787727a046cSLakshmi Yadlapati {
788ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
789727a046cSLakshmi Yadlapati     {
790727a046cSLakshmi Yadlapati         return;
791727a046cSLakshmi Yadlapati     }
79225b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
7937f3e84a1SEd Tanous     {
7947f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
7957f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
7967f3e84a1SEd Tanous                                    systemName);
7977f3e84a1SEd Tanous         return;
7987f3e84a1SEd Tanous     }
799253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
8007f3e84a1SEd Tanous     {
8017f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8027f3e84a1SEd Tanous                                    systemName);
8037f3e84a1SEd Tanous         return;
8047f3e84a1SEd Tanous     }
805dc8cfa66SEd Tanous     std::string_view pcieFunctionIdView = pcieFunctionIdStr;
8067f3e84a1SEd Tanous 
807e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
808e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
809dc8cfa66SEd Tanous         pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId);
810dc8cfa66SEd Tanous     if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end())
811e14742caSEd Tanous     {
812ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
813e14742caSEd Tanous                                    pcieFunctionIdStr);
814e14742caSEd Tanous         return;
815e14742caSEd Tanous     }
816727a046cSLakshmi Yadlapati 
817bd79bce8SPatrick Williams     getValidPCIeDevicePath(
818bd79bce8SPatrick Williams         pcieDeviceId, asyncResp,
819bd79bce8SPatrick Williams         [asyncResp, pcieDeviceId, pcieFunctionId](
820bd79bce8SPatrick Williams             const std::string& pcieDevicePath, const std::string& service) {
821727a046cSLakshmi Yadlapati             getPCIeDeviceProperties(
822ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
823ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId, pcieFunctionId](
824727a046cSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
825bd79bce8SPatrick Williams                     addPCIeFunctionCommonProperties(
826bd79bce8SPatrick Williams                         asyncResp->res, pcieDeviceId, pcieFunctionId);
827ac106bf6SEd Tanous                     addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
828727a046cSLakshmi Yadlapati                                               pcieDevProperties);
8297e860f15SJohn Edward Broadbent                 });
830727a046cSLakshmi Yadlapati         });
831727a046cSLakshmi Yadlapati }
832727a046cSLakshmi Yadlapati 
833727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
834727a046cSLakshmi Yadlapati {
835727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
8367f3e84a1SEd Tanous         app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
837727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
838727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
839727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
840f5c9f8bdSJason M. Bills }
841f5c9f8bdSJason M. Bills 
842f5c9f8bdSJason M. Bills } // namespace redfish
843