xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 539d8c6bc399e516d39bcaa18262cf206f4c1035)
1f5c9f8bdSJason M. Bills /*
2f5c9f8bdSJason M. Bills // Copyright (c) 2018 Intel Corporation
3f5c9f8bdSJason M. Bills //
4f5c9f8bdSJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License");
5f5c9f8bdSJason M. Bills // you may not use this file except in compliance with the License.
6f5c9f8bdSJason M. Bills // You may obtain a copy of the License at
7f5c9f8bdSJason M. Bills //
8f5c9f8bdSJason M. Bills //      http://www.apache.org/licenses/LICENSE-2.0
9f5c9f8bdSJason M. Bills //
10f5c9f8bdSJason M. Bills // Unless required by applicable law or agreed to in writing, software
11f5c9f8bdSJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS,
12f5c9f8bdSJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f5c9f8bdSJason M. Bills // See the License for the specific language governing permissions and
14f5c9f8bdSJason M. Bills // limitations under the License.
15f5c9f8bdSJason M. Bills */
16f5c9f8bdSJason M. Bills 
17f5c9f8bdSJason M. Bills #pragma once
18f5c9f8bdSJason M. Bills 
193ccb3adbSEd Tanous #include "app.hpp"
207a1dbc48SGeorge Liu #include "dbus_utility.hpp"
21*539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
223ccb3adbSEd Tanous #include "query.hpp"
233ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
24b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp"
253ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
26c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp"
270ec8b83dSEd Tanous 
28f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp>
29ef4c65b7SEd Tanous #include <boost/url/format.hpp>
30d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
31d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
32f5c9f8bdSJason M. Bills 
338c1d0549SMyung Bae #include <limits>
348c1d0549SMyung Bae 
35f5c9f8bdSJason M. Bills namespace redfish
36f5c9f8bdSJason M. Bills {
37f5c9f8bdSJason M. Bills 
3889492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
3994c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
4094c3a10bSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
41a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = {
42a5409991SLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeSlot"};
43f5c9f8bdSJason M. Bills 
44543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath(
45543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
46ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
47543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
48543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
49543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
50543f9a75SLakshmi Yadlapati 
51543f9a75SLakshmi Yadlapati {
52543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
53543f9a75SLakshmi Yadlapati     {
54543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
55543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
56543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
57543f9a75SLakshmi Yadlapati         {
58543f9a75SLakshmi Yadlapati             continue;
59543f9a75SLakshmi Yadlapati         }
60543f9a75SLakshmi Yadlapati 
61543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
62543f9a75SLakshmi Yadlapati             pcieDevicePath, {},
63ac106bf6SEd Tanous             [pcieDevicePath, asyncResp,
64543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
65543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
66543f9a75SLakshmi Yadlapati             if (ec || object.empty())
67543f9a75SLakshmi Yadlapati             {
6862598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
69ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
70543f9a75SLakshmi Yadlapati                 return;
71543f9a75SLakshmi Yadlapati             }
72543f9a75SLakshmi Yadlapati             callback(pcieDevicePath, object.begin()->first);
73543f9a75SLakshmi Yadlapati         });
74543f9a75SLakshmi Yadlapati         return;
75543f9a75SLakshmi Yadlapati     }
76543f9a75SLakshmi Yadlapati 
7762598e31SEd Tanous     BMCWEB_LOG_WARNING("PCIe Device not found");
78ac106bf6SEd Tanous     messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
79543f9a75SLakshmi Yadlapati }
80543f9a75SLakshmi Yadlapati 
81543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath(
82543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
83ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
84543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
85543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
86543f9a75SLakshmi Yadlapati {
87543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
8894c3a10bSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
89ac106bf6SEd Tanous         [pcieDeviceId, asyncResp,
90543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
91543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
92543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
93543f9a75SLakshmi Yadlapati         if (ec)
94543f9a75SLakshmi Yadlapati         {
9562598e31SEd Tanous             BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
96ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
97543f9a75SLakshmi Yadlapati             return;
98543f9a75SLakshmi Yadlapati         }
99ac106bf6SEd Tanous         handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
100ac106bf6SEd Tanous                              callback);
101543f9a75SLakshmi Yadlapati         return;
102543f9a75SLakshmi Yadlapati     });
103543f9a75SLakshmi Yadlapati }
104543f9a75SLakshmi Yadlapati 
105b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet(
106b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
107ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
108b38fa2abSLakshmi Yadlapati     const std::string& systemName)
109b38fa2abSLakshmi Yadlapati {
110ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
111b38fa2abSLakshmi Yadlapati     {
112b38fa2abSLakshmi Yadlapati         return;
113b38fa2abSLakshmi Yadlapati     }
11425b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
1157f3e84a1SEd Tanous     {
1167f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
1177f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1187f3e84a1SEd Tanous                                    systemName);
1197f3e84a1SEd Tanous         return;
1207f3e84a1SEd Tanous     }
121253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
122b38fa2abSLakshmi Yadlapati     {
123ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
124ac106bf6SEd Tanous                                    systemName);
125b38fa2abSLakshmi Yadlapati         return;
126b38fa2abSLakshmi Yadlapati     }
127543f9a75SLakshmi Yadlapati 
128ac106bf6SEd Tanous     asyncResp->res.addHeader(boost::beast::http::field::link,
129b38fa2abSLakshmi Yadlapati                              "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
130b38fa2abSLakshmi Yadlapati                              "PCIeDeviceCollection.json>; rel=describedby");
131ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
132b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
133253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = std::format(
134253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME);
135ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
136ac106bf6SEd Tanous     asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
137b38fa2abSLakshmi Yadlapati 
13870c4d545SLakshmi Yadlapati     pcie_util::getPCIeDeviceList(asyncResp,
13970c4d545SLakshmi Yadlapati                                  nlohmann::json::json_pointer("/Members"));
140b38fa2abSLakshmi Yadlapati }
141b38fa2abSLakshmi Yadlapati 
1427e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
143adbe192aSJason M. Bills {
144adbe192aSJason M. Bills     /**
145adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
146adbe192aSJason M. Bills      */
14722d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
148ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1497e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
150b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
151f5c9f8bdSJason M. Bills }
152f5c9f8bdSJason M. Bills 
153a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties(
154a5409991SLakshmi Yadlapati     crow::Response& res, const boost::system::error_code& ec,
155a5409991SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieSlotProperties)
156a5409991SLakshmi Yadlapati {
157a5409991SLakshmi Yadlapati     if (ec)
158a5409991SLakshmi Yadlapati     {
15962598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}",
16062598e31SEd Tanous                          ec.value());
161a5409991SLakshmi Yadlapati         messages::internalError(res);
162a5409991SLakshmi Yadlapati         return;
163a5409991SLakshmi Yadlapati     }
164a5409991SLakshmi Yadlapati     std::string generation;
165a5409991SLakshmi Yadlapati     size_t lanes = 0;
166a5409991SLakshmi Yadlapati     std::string slotType;
167a5409991SLakshmi Yadlapati 
168a5409991SLakshmi Yadlapati     bool success = sdbusplus::unpackPropertiesNoThrow(
169a5409991SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation",
170a5409991SLakshmi Yadlapati         generation, "Lanes", lanes, "SlotType", slotType);
171a5409991SLakshmi Yadlapati 
172a5409991SLakshmi Yadlapati     if (!success)
173a5409991SLakshmi Yadlapati     {
174a5409991SLakshmi Yadlapati         messages::internalError(res);
175a5409991SLakshmi Yadlapati         return;
176a5409991SLakshmi Yadlapati     }
177a5409991SLakshmi Yadlapati 
178a5409991SLakshmi Yadlapati     std::optional<pcie_device::PCIeTypes> pcieType =
179a5409991SLakshmi Yadlapati         pcie_util::redfishPcieGenerationFromDbus(generation);
180a5409991SLakshmi Yadlapati     if (!pcieType)
181a5409991SLakshmi Yadlapati     {
18262598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation);
183a5409991SLakshmi Yadlapati     }
184a5409991SLakshmi Yadlapati     else
185a5409991SLakshmi Yadlapati     {
186a5409991SLakshmi Yadlapati         if (*pcieType == pcie_device::PCIeTypes::Invalid)
187a5409991SLakshmi Yadlapati         {
18862598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation);
189a5409991SLakshmi Yadlapati             messages::internalError(res);
190a5409991SLakshmi Yadlapati             return;
191a5409991SLakshmi Yadlapati         }
192a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["PCIeType"] = *pcieType;
193a5409991SLakshmi Yadlapati     }
194a5409991SLakshmi Yadlapati 
19582f80326SKonstantin Aladyshev     if (lanes != 0)
19682f80326SKonstantin Aladyshev     {
197a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["Lanes"] = lanes;
19882f80326SKonstantin Aladyshev     }
199a5409991SLakshmi Yadlapati 
200a5409991SLakshmi Yadlapati     std::optional<pcie_slots::SlotTypes> redfishSlotType =
201a5409991SLakshmi Yadlapati         pcie_util::dbusSlotTypeToRf(slotType);
202a5409991SLakshmi Yadlapati     if (!redfishSlotType)
203a5409991SLakshmi Yadlapati     {
20462598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType);
205a5409991SLakshmi Yadlapati     }
206a5409991SLakshmi Yadlapati     else
207a5409991SLakshmi Yadlapati     {
208a5409991SLakshmi Yadlapati         if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
209a5409991SLakshmi Yadlapati         {
21062598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType);
211a5409991SLakshmi Yadlapati             messages::internalError(res);
212a5409991SLakshmi Yadlapati             return;
213a5409991SLakshmi Yadlapati         }
214a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["SlotType"] = *redfishSlotType;
215a5409991SLakshmi Yadlapati     }
216a5409991SLakshmi Yadlapati }
217a5409991SLakshmi Yadlapati 
218a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath(
219a5409991SLakshmi Yadlapati     const std::string& pcieDevicePath,
220a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
221a5409991SLakshmi Yadlapati     std::function<void(const std::string& pcieDeviceSlot)>&& callback)
222a5409991SLakshmi Yadlapati {
223a5409991SLakshmi Yadlapati     std::string associationPath = pcieDevicePath + "/contained_by";
224a5409991SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
225a5409991SLakshmi Yadlapati         associationPath, sdbusplus::message::object_path(inventoryPath), 0,
226a5409991SLakshmi Yadlapati         pcieSlotInterface,
2278cb2c024SEd Tanous         [callback = std::move(callback), asyncResp, pcieDevicePath](
228a5409991SLakshmi Yadlapati             const boost::system::error_code& ec,
229a5409991SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& endpoints) {
230a5409991SLakshmi Yadlapati         if (ec)
231a5409991SLakshmi Yadlapati         {
232a5409991SLakshmi Yadlapati             if (ec.value() == EBADR)
233a5409991SLakshmi Yadlapati             {
234a5409991SLakshmi Yadlapati                 // Missing association is not an error
235a5409991SLakshmi Yadlapati                 return;
236a5409991SLakshmi Yadlapati             }
23762598e31SEd Tanous             BMCWEB_LOG_ERROR(
23862598e31SEd Tanous                 "DBUS response error for getAssociatedSubTreePaths {}",
23962598e31SEd Tanous                 ec.value());
240a5409991SLakshmi Yadlapati             messages::internalError(asyncResp->res);
241a5409991SLakshmi Yadlapati             return;
242a5409991SLakshmi Yadlapati         }
243a5409991SLakshmi Yadlapati         if (endpoints.size() > 1)
244a5409991SLakshmi Yadlapati         {
24562598e31SEd Tanous             BMCWEB_LOG_ERROR(
24662598e31SEd Tanous                 "PCIeDevice is associated with more than one PCIeSlot: {}",
24762598e31SEd Tanous                 endpoints.size());
248a5409991SLakshmi Yadlapati             messages::internalError(asyncResp->res);
249a5409991SLakshmi Yadlapati             return;
250a5409991SLakshmi Yadlapati         }
251a5409991SLakshmi Yadlapati         if (endpoints.empty())
252a5409991SLakshmi Yadlapati         {
253a5409991SLakshmi Yadlapati             // If the device doesn't have an association, return without PCIe
254a5409991SLakshmi Yadlapati             // Slot properties
25562598e31SEd Tanous             BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot");
256a5409991SLakshmi Yadlapati             return;
257a5409991SLakshmi Yadlapati         }
258a5409991SLakshmi Yadlapati         callback(endpoints[0]);
259a5409991SLakshmi Yadlapati     });
260a5409991SLakshmi Yadlapati }
261a5409991SLakshmi Yadlapati 
262a5409991SLakshmi Yadlapati inline void
263a5409991SLakshmi Yadlapati     afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
264a5409991SLakshmi Yadlapati                        const std::string& pcieDeviceSlot,
265a5409991SLakshmi Yadlapati                        const boost::system::error_code& ec,
266a5409991SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object)
267a5409991SLakshmi Yadlapati {
268a5409991SLakshmi Yadlapati     if (ec || object.empty())
269a5409991SLakshmi Yadlapati     {
27062598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}",
27162598e31SEd Tanous                          ec.value());
272a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
273a5409991SLakshmi Yadlapati         return;
274a5409991SLakshmi Yadlapati     }
275a5409991SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
276a5409991SLakshmi Yadlapati         *crow::connections::systemBus, object.begin()->first, pcieDeviceSlot,
277a5409991SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
278a5409991SLakshmi Yadlapati         [asyncResp](
279a5409991SLakshmi Yadlapati             const boost::system::error_code& ec2,
280a5409991SLakshmi Yadlapati             const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
281a5409991SLakshmi Yadlapati         addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
282a5409991SLakshmi Yadlapati     });
283a5409991SLakshmi Yadlapati }
284a5409991SLakshmi Yadlapati 
285a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath(
286a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
287a5409991SLakshmi Yadlapati     const std::string& pcieDeviceSlot)
288a5409991SLakshmi Yadlapati {
289a5409991SLakshmi Yadlapati     dbus::utility::getDbusObject(
290a5409991SLakshmi Yadlapati         pcieDeviceSlot, pcieSlotInterface,
291a5409991SLakshmi Yadlapati         [asyncResp,
292a5409991SLakshmi Yadlapati          pcieDeviceSlot](const boost::system::error_code& ec,
293a5409991SLakshmi Yadlapati                          const dbus::utility::MapperGetObject& object) {
294a5409991SLakshmi Yadlapati         afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
295a5409991SLakshmi Yadlapati     });
296a5409991SLakshmi Yadlapati }
297a5409991SLakshmi Yadlapati 
298ac106bf6SEd Tanous inline void
299e164f1b6SLakshmi Yadlapati     getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
300e164f1b6SLakshmi Yadlapati                         const std::string& pcieDevicePath,
301e164f1b6SLakshmi Yadlapati                         const std::string& service)
302e164f1b6SLakshmi Yadlapati {
303e164f1b6SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
304e164f1b6SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
305e164f1b6SLakshmi Yadlapati         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
306e164f1b6SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, const bool value) {
307e164f1b6SLakshmi Yadlapati         if (ec)
308e164f1b6SLakshmi Yadlapati         {
309e164f1b6SLakshmi Yadlapati             if (ec.value() != EBADR)
310e164f1b6SLakshmi Yadlapati             {
31162598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Health {}",
31262598e31SEd Tanous                                  ec.value());
313e164f1b6SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
314e164f1b6SLakshmi Yadlapati             }
315e164f1b6SLakshmi Yadlapati             return;
316e164f1b6SLakshmi Yadlapati         }
317e164f1b6SLakshmi Yadlapati 
318e164f1b6SLakshmi Yadlapati         if (!value)
319e164f1b6SLakshmi Yadlapati         {
320*539d8c6bSEd Tanous             asyncResp->res.jsonValue["Status"]["Health"] =
321*539d8c6bSEd Tanous                 resource::Health::Critical;
322e164f1b6SLakshmi Yadlapati         }
323e164f1b6SLakshmi Yadlapati     });
324e164f1b6SLakshmi Yadlapati }
325e164f1b6SLakshmi Yadlapati 
326e164f1b6SLakshmi Yadlapati inline void
327ac106bf6SEd Tanous     getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
328c6bb3285SLakshmi Yadlapati                        const std::string& pcieDevicePath,
329c6bb3285SLakshmi Yadlapati                        const std::string& service)
330c6bb3285SLakshmi Yadlapati {
331c6bb3285SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
332c6bb3285SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
333c6bb3285SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item", "Present",
334a5409991SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, bool value) {
335c6bb3285SLakshmi Yadlapati         if (ec)
336c6bb3285SLakshmi Yadlapati         {
337c6bb3285SLakshmi Yadlapati             if (ec.value() != EBADR)
338c6bb3285SLakshmi Yadlapati             {
33962598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for State");
340ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
341c6bb3285SLakshmi Yadlapati             }
342c6bb3285SLakshmi Yadlapati             return;
343c6bb3285SLakshmi Yadlapati         }
344c6bb3285SLakshmi Yadlapati 
345c6bb3285SLakshmi Yadlapati         if (!value)
346c6bb3285SLakshmi Yadlapati         {
347*539d8c6bSEd Tanous             asyncResp->res.jsonValue["Status"]["State"] =
348*539d8c6bSEd Tanous                 resource::State::Absent;
349c6bb3285SLakshmi Yadlapati         }
350c6bb3285SLakshmi Yadlapati     });
351c6bb3285SLakshmi Yadlapati }
352c6bb3285SLakshmi Yadlapati 
353ac106bf6SEd Tanous inline void
354ac106bf6SEd Tanous     getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
355913e7732SSunnySrivastava1984                        const std::string& pcieDevicePath,
356913e7732SSunnySrivastava1984                        const std::string& service)
357913e7732SSunnySrivastava1984 {
358913e7732SSunnySrivastava1984     sdbusplus::asio::getAllProperties(
359913e7732SSunnySrivastava1984         *crow::connections::systemBus, service, pcieDevicePath,
360913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
361ac106bf6SEd Tanous         [pcieDevicePath, asyncResp{asyncResp}](
362ac106bf6SEd Tanous             const boost::system::error_code& ec,
363913e7732SSunnySrivastava1984             const dbus::utility::DBusPropertiesMap& assetList) {
364913e7732SSunnySrivastava1984         if (ec)
365913e7732SSunnySrivastava1984         {
366913e7732SSunnySrivastava1984             if (ec.value() != EBADR)
367913e7732SSunnySrivastava1984             {
36862598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Properties{}",
36962598e31SEd Tanous                                  ec.value());
370ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
371913e7732SSunnySrivastava1984             }
372913e7732SSunnySrivastava1984             return;
373913e7732SSunnySrivastava1984         }
374913e7732SSunnySrivastava1984 
375913e7732SSunnySrivastava1984         const std::string* manufacturer = nullptr;
376913e7732SSunnySrivastava1984         const std::string* model = nullptr;
377913e7732SSunnySrivastava1984         const std::string* partNumber = nullptr;
378913e7732SSunnySrivastava1984         const std::string* serialNumber = nullptr;
379913e7732SSunnySrivastava1984         const std::string* sparePartNumber = nullptr;
380913e7732SSunnySrivastava1984 
381913e7732SSunnySrivastava1984         const bool success = sdbusplus::unpackPropertiesNoThrow(
382913e7732SSunnySrivastava1984             dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
383913e7732SSunnySrivastava1984             manufacturer, "Model", model, "PartNumber", partNumber,
384913e7732SSunnySrivastava1984             "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
385913e7732SSunnySrivastava1984 
386913e7732SSunnySrivastava1984         if (!success)
387913e7732SSunnySrivastava1984         {
388ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
389913e7732SSunnySrivastava1984             return;
390913e7732SSunnySrivastava1984         }
391913e7732SSunnySrivastava1984 
392913e7732SSunnySrivastava1984         if (manufacturer != nullptr)
393913e7732SSunnySrivastava1984         {
394ac106bf6SEd Tanous             asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
395913e7732SSunnySrivastava1984         }
396913e7732SSunnySrivastava1984         if (model != nullptr)
397913e7732SSunnySrivastava1984         {
398ac106bf6SEd Tanous             asyncResp->res.jsonValue["Model"] = *model;
399913e7732SSunnySrivastava1984         }
400913e7732SSunnySrivastava1984 
401913e7732SSunnySrivastava1984         if (partNumber != nullptr)
402913e7732SSunnySrivastava1984         {
403ac106bf6SEd Tanous             asyncResp->res.jsonValue["PartNumber"] = *partNumber;
404913e7732SSunnySrivastava1984         }
405913e7732SSunnySrivastava1984 
406913e7732SSunnySrivastava1984         if (serialNumber != nullptr)
407913e7732SSunnySrivastava1984         {
408ac106bf6SEd Tanous             asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
409913e7732SSunnySrivastava1984         }
410913e7732SSunnySrivastava1984 
411913e7732SSunnySrivastava1984         if (sparePartNumber != nullptr && !sparePartNumber->empty())
412913e7732SSunnySrivastava1984         {
413ac106bf6SEd Tanous             asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
414913e7732SSunnySrivastava1984         }
415913e7732SSunnySrivastava1984     });
416913e7732SSunnySrivastava1984 }
417913e7732SSunnySrivastava1984 
418543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
419a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
420a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId,
421543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
422f5c9f8bdSJason M. Bills {
423d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
424814bf20aSKonstantin Aladyshev     const std::string* generationSupported = nullptr;
4259bb0a7feSKonstantin Aladyshev     const size_t* lanesInUse = nullptr;
426814bf20aSKonstantin Aladyshev     const size_t* maxLanes = nullptr;
427d1bde9e5SKrzysztof Grobelny 
428d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
429609ba4c9SEd Tanous         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse",
430609ba4c9SEd Tanous         generationInUse, "GenerationSupported", generationSupported,
431609ba4c9SEd Tanous         "LanesInUse", lanesInUse, "MaxLanes", maxLanes);
432d1bde9e5SKrzysztof Grobelny 
433d1bde9e5SKrzysztof Grobelny     if (!success)
434d1bde9e5SKrzysztof Grobelny     {
435a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
436d1bde9e5SKrzysztof Grobelny         return;
437d1bde9e5SKrzysztof Grobelny     }
438d1bde9e5SKrzysztof Grobelny 
439d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
440d1bde9e5SKrzysztof Grobelny     {
4410ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
442c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
443543f9a75SLakshmi Yadlapati 
444d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
445d1bde9e5SKrzysztof Grobelny         {
44662598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
44762598e31SEd Tanous                                *generationInUse);
448cf3b484eSLakshmi Yadlapati         }
449cf3b484eSLakshmi Yadlapati         else
450cf3b484eSLakshmi Yadlapati         {
451cf3b484eSLakshmi Yadlapati             if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
452cf3b484eSLakshmi Yadlapati             {
45362598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
45462598e31SEd Tanous                                  *generationInUse);
455a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
456d1bde9e5SKrzysztof Grobelny                 return;
457d1bde9e5SKrzysztof Grobelny             }
458a5409991SLakshmi Yadlapati             asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
459d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
460d1bde9e5SKrzysztof Grobelny         }
461a9f68bb5STony Lee     }
462d1bde9e5SKrzysztof Grobelny 
463814bf20aSKonstantin Aladyshev     if (generationSupported != nullptr)
464814bf20aSKonstantin Aladyshev     {
465814bf20aSKonstantin Aladyshev         std::optional<pcie_device::PCIeTypes> redfishGenerationSupported =
466814bf20aSKonstantin Aladyshev             pcie_util::redfishPcieGenerationFromDbus(*generationSupported);
467814bf20aSKonstantin Aladyshev 
468814bf20aSKonstantin Aladyshev         if (!redfishGenerationSupported)
469814bf20aSKonstantin Aladyshev         {
47062598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
47162598e31SEd Tanous                                *generationSupported);
472814bf20aSKonstantin Aladyshev         }
473814bf20aSKonstantin Aladyshev         else
474814bf20aSKonstantin Aladyshev         {
475814bf20aSKonstantin Aladyshev             if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid)
476814bf20aSKonstantin Aladyshev             {
47762598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
47862598e31SEd Tanous                                  *generationSupported);
479814bf20aSKonstantin Aladyshev                 messages::internalError(asyncResp->res);
480814bf20aSKonstantin Aladyshev                 return;
481814bf20aSKonstantin Aladyshev             }
482814bf20aSKonstantin Aladyshev             asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] =
483814bf20aSKonstantin Aladyshev                 *redfishGenerationSupported;
484814bf20aSKonstantin Aladyshev         }
485814bf20aSKonstantin Aladyshev     }
486814bf20aSKonstantin Aladyshev 
4878c1d0549SMyung Bae     if (lanesInUse != nullptr)
488543f9a75SLakshmi Yadlapati     {
4898c1d0549SMyung Bae         if (*lanesInUse == std::numeric_limits<size_t>::max())
4908c1d0549SMyung Bae         {
4918c1d0549SMyung Bae             // The default value of LanesInUse is "maxint", and the field will
4928c1d0549SMyung Bae             // be null if it is a default value.
4938c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr;
4948c1d0549SMyung Bae         }
4958c1d0549SMyung Bae         else
4968c1d0549SMyung Bae         {
4978c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] =
4988c1d0549SMyung Bae                 *lanesInUse;
4998c1d0549SMyung Bae         }
500543f9a75SLakshmi Yadlapati     }
501814bf20aSKonstantin Aladyshev     // The default value of MaxLanes is 0, and the field will be
502814bf20aSKonstantin Aladyshev     // left as off if it is a default value.
503814bf20aSKonstantin Aladyshev     if (maxLanes != nullptr && *maxLanes != 0)
504814bf20aSKonstantin Aladyshev     {
505814bf20aSKonstantin Aladyshev         asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes;
506814bf20aSKonstantin Aladyshev     }
507543f9a75SLakshmi Yadlapati 
508a5409991SLakshmi Yadlapati     asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
509a5409991SLakshmi Yadlapati         boost::urls::format(
510253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
511253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
512d1bde9e5SKrzysztof Grobelny }
513d1bde9e5SKrzysztof Grobelny 
514543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
515ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
516543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
517543f9a75SLakshmi Yadlapati     const std::function<void(
518543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
519d1bde9e5SKrzysztof Grobelny {
520543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
521543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
522543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
523ac106bf6SEd Tanous         [asyncResp,
524543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
525543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
526543f9a75SLakshmi Yadlapati         if (ec)
527543f9a75SLakshmi Yadlapati         {
528543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
529543f9a75SLakshmi Yadlapati             {
53062598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Properties");
531ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
532543f9a75SLakshmi Yadlapati             }
533543f9a75SLakshmi Yadlapati             return;
534543f9a75SLakshmi Yadlapati         }
535543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
536543f9a75SLakshmi Yadlapati     });
537d1bde9e5SKrzysztof Grobelny }
538d1bde9e5SKrzysztof Grobelny 
539543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
540ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
541543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
542543f9a75SLakshmi Yadlapati {
543ac106bf6SEd Tanous     asyncResp->res.addHeader(
544543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
545543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
546ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
547253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
548253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
549253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
550ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
551ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
552*539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
553*539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
554543f9a75SLakshmi Yadlapati }
5551476687dSEd Tanous 
556a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath(
557a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
558a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId, const std::string& pcieDevicePath,
559a5409991SLakshmi Yadlapati     const std::string& service)
560a5409991SLakshmi Yadlapati {
561a5409991SLakshmi Yadlapati     addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
562a5409991SLakshmi Yadlapati     getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
563a5409991SLakshmi Yadlapati     getPCIeDeviceState(asyncResp, pcieDevicePath, service);
564a5409991SLakshmi Yadlapati     getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
565a5409991SLakshmi Yadlapati     getPCIeDeviceProperties(
566a5409991SLakshmi Yadlapati         asyncResp, pcieDevicePath, service,
567a5409991SLakshmi Yadlapati         std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
568a5409991SLakshmi Yadlapati     getPCIeDeviceSlotPath(
569a5409991SLakshmi Yadlapati         pcieDevicePath, asyncResp,
570a5409991SLakshmi Yadlapati         std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
571a5409991SLakshmi Yadlapati }
572a5409991SLakshmi Yadlapati 
573ac106bf6SEd Tanous inline void
574ac106bf6SEd Tanous     handlePCIeDeviceGet(App& app, const crow::Request& req,
575ac106bf6SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
576543f9a75SLakshmi Yadlapati                         const std::string& systemName,
577543f9a75SLakshmi Yadlapati                         const std::string& pcieDeviceId)
578543f9a75SLakshmi Yadlapati {
579ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
580543f9a75SLakshmi Yadlapati     {
581543f9a75SLakshmi Yadlapati         return;
582543f9a75SLakshmi Yadlapati     }
58325b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5847f3e84a1SEd Tanous     {
5857f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
5867f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5877f3e84a1SEd Tanous                                    systemName);
5887f3e84a1SEd Tanous         return;
5897f3e84a1SEd Tanous     }
590253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
591543f9a75SLakshmi Yadlapati     {
592ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
593ac106bf6SEd Tanous                                    systemName);
594543f9a75SLakshmi Yadlapati         return;
595543f9a75SLakshmi Yadlapati     }
596543f9a75SLakshmi Yadlapati 
597543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
598ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
599a5409991SLakshmi Yadlapati         std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
600543f9a75SLakshmi Yadlapati }
601543f9a75SLakshmi Yadlapati 
602543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
603543f9a75SLakshmi Yadlapati {
604543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
605543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
606543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
607543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
608dede6a98SJason M. Bills }
609dede6a98SJason M. Bills 
61035ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
61135ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
61235ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
61335ad613dSLakshmi Yadlapati {
61435ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
61535ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
61635ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
61735ad613dSLakshmi Yadlapati 
61835ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
61935ad613dSLakshmi Yadlapati     {
62035ad613dSLakshmi Yadlapati         // Check if this function exists by
62135ad613dSLakshmi Yadlapati         // looking for a device ID
62289492a15SPatrick Williams         std::string devIDProperty = "Function" + std::to_string(functionNum) +
62389492a15SPatrick Williams                                     "DeviceId";
62435ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
62535ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
62635ad613dSLakshmi Yadlapati         {
62735ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
62835ad613dSLakshmi Yadlapati             {
62935ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
63035ad613dSLakshmi Yadlapati                 break;
63135ad613dSLakshmi Yadlapati             }
63235ad613dSLakshmi Yadlapati         }
63335ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
63435ad613dSLakshmi Yadlapati         {
63535ad613dSLakshmi Yadlapati             continue;
63635ad613dSLakshmi Yadlapati         }
63735ad613dSLakshmi Yadlapati 
63835ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
639ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
640253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
641253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
642253f11b8SEd Tanous             std::to_string(functionNum));
643b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
64435ad613dSLakshmi Yadlapati     }
64535ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
64635ad613dSLakshmi Yadlapati }
64735ad613dSLakshmi Yadlapati 
64835ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
64935ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
650ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6517f3e84a1SEd Tanous     const std::string& systemName, const std::string& pcieDeviceId)
65235ad613dSLakshmi Yadlapati {
653ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
65435ad613dSLakshmi Yadlapati     {
65535ad613dSLakshmi Yadlapati         return;
65635ad613dSLakshmi Yadlapati     }
65725b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
6587f3e84a1SEd Tanous     {
6597f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
6607f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6617f3e84a1SEd Tanous                                    systemName);
6627f3e84a1SEd Tanous         return;
6637f3e84a1SEd Tanous     }
66435ad613dSLakshmi Yadlapati 
66535ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
666ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
667ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
66835ad613dSLakshmi Yadlapati                                   const std::string& service) {
669ac106bf6SEd Tanous         asyncResp->res.addHeader(
67035ad613dSLakshmi Yadlapati             boost::beast::http::field::link,
67135ad613dSLakshmi Yadlapati             "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
672ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
67335ad613dSLakshmi Yadlapati             "#PCIeFunctionCollection.PCIeFunctionCollection";
674ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
675253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
676253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
677ac106bf6SEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
678ac106bf6SEd Tanous         asyncResp->res.jsonValue["Description"] =
67935ad613dSLakshmi Yadlapati             "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
68035ad613dSLakshmi Yadlapati         getPCIeDeviceProperties(
681ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
682ac106bf6SEd Tanous             [asyncResp, pcieDeviceId](
68335ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
684ac106bf6SEd Tanous             addPCIeFunctionList(asyncResp->res, pcieDeviceId,
685ac106bf6SEd Tanous                                 pcieDevProperties);
68635ad613dSLakshmi Yadlapati         });
68735ad613dSLakshmi Yadlapati     });
68835ad613dSLakshmi Yadlapati }
68935ad613dSLakshmi Yadlapati 
6907e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
6917e860f15SJohn Edward Broadbent {
692dede6a98SJason M. Bills     /**
693dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
694dede6a98SJason M. Bills      */
6957e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
6967f3e84a1SEd Tanous                  "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
697ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
698002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
69935ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
7007e860f15SJohn Edward Broadbent }
7017e860f15SJohn Edward Broadbent 
702727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
703d5e74b80SMyung Bae     uint64_t pcieFunctionId,
704727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
7057e860f15SJohn Edward Broadbent {
706d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
707b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
708b9d36b47SEd Tanous 
709b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
710b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
711b9d36b47SEd Tanous     {
712b9d36b47SEd Tanous         if (property.first == devIDProperty)
713b9d36b47SEd Tanous         {
714002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
715727a046cSLakshmi Yadlapati             break;
716b9d36b47SEd Tanous         }
717b9d36b47SEd Tanous     }
718727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
719727a046cSLakshmi Yadlapati }
720727a046cSLakshmi Yadlapati 
721727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
722e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
723727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
724f5c9f8bdSJason M. Bills {
725e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
726b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
727f5c9f8bdSJason M. Bills     {
728b9d36b47SEd Tanous         const std::string* strProperty =
729b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
730dc8cfa66SEd Tanous         if (strProperty == nullptr)
731dc8cfa66SEd Tanous         {
732dc8cfa66SEd Tanous             BMCWEB_LOG_ERROR("Function wasn't a string?");
733dc8cfa66SEd Tanous             continue;
734dc8cfa66SEd Tanous         }
735b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
736f5c9f8bdSJason M. Bills         {
737727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
738f5c9f8bdSJason M. Bills         }
739b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
740f5c9f8bdSJason M. Bills         {
741727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
742f5c9f8bdSJason M. Bills         }
743727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
744727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
745727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
746b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
747f5c9f8bdSJason M. Bills         {
748727a046cSLakshmi Yadlapati             if (!strProperty->empty())
749727a046cSLakshmi Yadlapati             {
750727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
751727a046cSLakshmi Yadlapati             }
752f5c9f8bdSJason M. Bills         }
753b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
754f5c9f8bdSJason M. Bills         {
755727a046cSLakshmi Yadlapati             if (!strProperty->empty())
756727a046cSLakshmi Yadlapati             {
757727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
758727a046cSLakshmi Yadlapati             }
759f5c9f8bdSJason M. Bills         }
760b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
761f5c9f8bdSJason M. Bills         {
762727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
763f5c9f8bdSJason M. Bills         }
764b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
765f5c9f8bdSJason M. Bills         {
766727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
767f5c9f8bdSJason M. Bills         }
768b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
769b9d36b47SEd Tanous         {
770727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
771b9d36b47SEd Tanous         }
772002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
773f5c9f8bdSJason M. Bills         {
774727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
775b9d36b47SEd Tanous         }
776f5c9f8bdSJason M. Bills     }
777727a046cSLakshmi Yadlapati }
778727a046cSLakshmi Yadlapati 
779727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
780727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
781e14742caSEd Tanous                                             uint64_t pcieFunctionId)
782727a046cSLakshmi Yadlapati {
783727a046cSLakshmi Yadlapati     resp.addHeader(
784727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
785727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
786727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
787ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
788253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
789253f11b8SEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
790253f11b8SEd Tanous         std::to_string(pcieFunctionId));
791727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
792e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
793e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
794253f11b8SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
795253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
796253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
797727a046cSLakshmi Yadlapati }
798727a046cSLakshmi Yadlapati 
799727a046cSLakshmi Yadlapati inline void
800727a046cSLakshmi Yadlapati     handlePCIeFunctionGet(App& app, const crow::Request& req,
801ac106bf6SEd Tanous                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8027f3e84a1SEd Tanous                           const std::string& systemName,
803727a046cSLakshmi Yadlapati                           const std::string& pcieDeviceId,
804e14742caSEd Tanous                           const std::string& pcieFunctionIdStr)
805727a046cSLakshmi Yadlapati {
806ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
807727a046cSLakshmi Yadlapati     {
808727a046cSLakshmi Yadlapati         return;
809727a046cSLakshmi Yadlapati     }
81025b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
8117f3e84a1SEd Tanous     {
8127f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
8137f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8147f3e84a1SEd Tanous                                    systemName);
8157f3e84a1SEd Tanous         return;
8167f3e84a1SEd Tanous     }
817253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
8187f3e84a1SEd Tanous     {
8197f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8207f3e84a1SEd Tanous                                    systemName);
8217f3e84a1SEd Tanous         return;
8227f3e84a1SEd Tanous     }
823dc8cfa66SEd Tanous     std::string_view pcieFunctionIdView = pcieFunctionIdStr;
8247f3e84a1SEd Tanous 
825e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
826e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
827dc8cfa66SEd Tanous         pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId);
828dc8cfa66SEd Tanous     if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end())
829e14742caSEd Tanous     {
830ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
831e14742caSEd Tanous                                    pcieFunctionIdStr);
832e14742caSEd Tanous         return;
833e14742caSEd Tanous     }
834727a046cSLakshmi Yadlapati 
835ac106bf6SEd Tanous     getValidPCIeDevicePath(pcieDeviceId, asyncResp,
836ac106bf6SEd Tanous                            [asyncResp, pcieDeviceId,
837ac106bf6SEd Tanous                             pcieFunctionId](const std::string& pcieDevicePath,
838727a046cSLakshmi Yadlapati                                             const std::string& service) {
839727a046cSLakshmi Yadlapati         getPCIeDeviceProperties(
840ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
841ac106bf6SEd Tanous             [asyncResp, pcieDeviceId, pcieFunctionId](
842727a046cSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
843ac106bf6SEd Tanous             addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId,
844727a046cSLakshmi Yadlapati                                             pcieFunctionId);
845ac106bf6SEd Tanous             addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
846727a046cSLakshmi Yadlapati                                       pcieDevProperties);
8477e860f15SJohn Edward Broadbent         });
848727a046cSLakshmi Yadlapati     });
849727a046cSLakshmi Yadlapati }
850727a046cSLakshmi Yadlapati 
851727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
852727a046cSLakshmi Yadlapati {
853727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
8547f3e84a1SEd Tanous         app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
855727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
856727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
857727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
858f5c9f8bdSJason M. Bills }
859f5c9f8bdSJason M. Bills 
860f5c9f8bdSJason M. Bills } // namespace redfish
861