xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision a6bd55b0ecd2db86509843380f28445c9bf655dc)
1f5c9f8bdSJason M. Bills /*
26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous 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"
21539d8c6bSEd 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 
444ff0f1f4SEd Tanous 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(
623a58c5a8SKonstantin Aladyshev             pcieDevicePath, pcieDeviceInterface,
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 
814ff0f1f4SEd Tanous 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 
1054ff0f1f4SEd Tanous 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(
246*a6bd55b0SGunnar Mills                     "PCIeDevice {} is associated with more than one PCIeSlot: {}",
247*a6bd55b0SGunnar Mills                     pcieDevicePath, endpoints.size());
248a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
249a5409991SLakshmi Yadlapati                 return;
250a5409991SLakshmi Yadlapati             }
251a5409991SLakshmi Yadlapati             if (endpoints.empty())
252a5409991SLakshmi Yadlapati             {
253bd79bce8SPatrick Williams                 // If the device doesn't have an association, return without
254bd79bce8SPatrick Williams                 // PCIe 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 
262bd79bce8SPatrick Williams inline void afterGetDbusObject(
263bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
264bd79bce8SPatrick Williams     const std::string& pcieDeviceSlot, const boost::system::error_code& ec,
265a5409991SLakshmi Yadlapati     const dbus::utility::MapperGetObject& object)
266a5409991SLakshmi Yadlapati {
267a5409991SLakshmi Yadlapati     if (ec || object.empty())
268a5409991SLakshmi Yadlapati     {
26962598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}",
27062598e31SEd Tanous                          ec.value());
271a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
272a5409991SLakshmi Yadlapati         return;
273a5409991SLakshmi Yadlapati     }
274deae6a78SEd Tanous     dbus::utility::getAllProperties(
275deae6a78SEd Tanous         object.begin()->first, pcieDeviceSlot,
276a5409991SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
277a5409991SLakshmi Yadlapati         [asyncResp](
278a5409991SLakshmi Yadlapati             const boost::system::error_code& ec2,
279a5409991SLakshmi Yadlapati             const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
280a5409991SLakshmi Yadlapati             addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
281a5409991SLakshmi Yadlapati         });
282a5409991SLakshmi Yadlapati }
283a5409991SLakshmi Yadlapati 
284a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath(
285a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
286a5409991SLakshmi Yadlapati     const std::string& pcieDeviceSlot)
287a5409991SLakshmi Yadlapati {
288a5409991SLakshmi Yadlapati     dbus::utility::getDbusObject(
289a5409991SLakshmi Yadlapati         pcieDeviceSlot, pcieSlotInterface,
290a5409991SLakshmi Yadlapati         [asyncResp,
291a5409991SLakshmi Yadlapati          pcieDeviceSlot](const boost::system::error_code& ec,
292a5409991SLakshmi Yadlapati                          const dbus::utility::MapperGetObject& object) {
293a5409991SLakshmi Yadlapati             afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
294a5409991SLakshmi Yadlapati         });
295a5409991SLakshmi Yadlapati }
296a5409991SLakshmi Yadlapati 
297bd79bce8SPatrick Williams inline void getPCIeDeviceHealth(
298bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
299bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
300e164f1b6SLakshmi Yadlapati {
301deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
302deae6a78SEd Tanous         service, pcieDevicePath,
303e164f1b6SLakshmi Yadlapati         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
304e164f1b6SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, const bool value) {
305e164f1b6SLakshmi Yadlapati             if (ec)
306e164f1b6SLakshmi Yadlapati             {
307e164f1b6SLakshmi Yadlapati                 if (ec.value() != EBADR)
308e164f1b6SLakshmi Yadlapati                 {
30962598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Health {}",
31062598e31SEd Tanous                                      ec.value());
311e164f1b6SLakshmi Yadlapati                     messages::internalError(asyncResp->res);
312e164f1b6SLakshmi Yadlapati                 }
313e164f1b6SLakshmi Yadlapati                 return;
314e164f1b6SLakshmi Yadlapati             }
315e164f1b6SLakshmi Yadlapati 
316e164f1b6SLakshmi Yadlapati             if (!value)
317e164f1b6SLakshmi Yadlapati             {
318539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["Health"] =
319539d8c6bSEd Tanous                     resource::Health::Critical;
320e164f1b6SLakshmi Yadlapati             }
321e164f1b6SLakshmi Yadlapati         });
322e164f1b6SLakshmi Yadlapati }
323e164f1b6SLakshmi Yadlapati 
324bd79bce8SPatrick Williams inline void getPCIeDeviceState(
325bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
326bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
327c6bb3285SLakshmi Yadlapati {
328deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
329deae6a78SEd Tanous         service, pcieDevicePath, "xyz.openbmc_project.Inventory.Item",
330deae6a78SEd Tanous         "Present",
331a5409991SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, bool value) {
332c6bb3285SLakshmi Yadlapati             if (ec)
333c6bb3285SLakshmi Yadlapati             {
334c6bb3285SLakshmi Yadlapati                 if (ec.value() != EBADR)
335c6bb3285SLakshmi Yadlapati                 {
33662598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for State");
337ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
338c6bb3285SLakshmi Yadlapati                 }
339c6bb3285SLakshmi Yadlapati                 return;
340c6bb3285SLakshmi Yadlapati             }
341c6bb3285SLakshmi Yadlapati 
342c6bb3285SLakshmi Yadlapati             if (!value)
343c6bb3285SLakshmi Yadlapati             {
344539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
345539d8c6bSEd Tanous                     resource::State::Absent;
346c6bb3285SLakshmi Yadlapati             }
347c6bb3285SLakshmi Yadlapati         });
348c6bb3285SLakshmi Yadlapati }
349c6bb3285SLakshmi Yadlapati 
350bd79bce8SPatrick Williams inline void getPCIeDeviceAsset(
351bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
352bd79bce8SPatrick Williams     const std::string& pcieDevicePath, const std::string& service)
353913e7732SSunnySrivastava1984 {
354deae6a78SEd Tanous     dbus::utility::getAllProperties(
355deae6a78SEd Tanous         service, pcieDevicePath,
356913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
357ac106bf6SEd Tanous         [pcieDevicePath, asyncResp{asyncResp}](
358ac106bf6SEd Tanous             const boost::system::error_code& ec,
359913e7732SSunnySrivastava1984             const dbus::utility::DBusPropertiesMap& assetList) {
360913e7732SSunnySrivastava1984             if (ec)
361913e7732SSunnySrivastava1984             {
362913e7732SSunnySrivastava1984                 if (ec.value() != EBADR)
363913e7732SSunnySrivastava1984                 {
36462598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties{}",
36562598e31SEd Tanous                                      ec.value());
366ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
367913e7732SSunnySrivastava1984                 }
368913e7732SSunnySrivastava1984                 return;
369913e7732SSunnySrivastava1984             }
370913e7732SSunnySrivastava1984 
371913e7732SSunnySrivastava1984             const std::string* manufacturer = nullptr;
372913e7732SSunnySrivastava1984             const std::string* model = nullptr;
373913e7732SSunnySrivastava1984             const std::string* partNumber = nullptr;
374913e7732SSunnySrivastava1984             const std::string* serialNumber = nullptr;
375913e7732SSunnySrivastava1984             const std::string* sparePartNumber = nullptr;
376913e7732SSunnySrivastava1984 
377913e7732SSunnySrivastava1984             const bool success = sdbusplus::unpackPropertiesNoThrow(
378913e7732SSunnySrivastava1984                 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
379913e7732SSunnySrivastava1984                 manufacturer, "Model", model, "PartNumber", partNumber,
380bd79bce8SPatrick Williams                 "SerialNumber", serialNumber, "SparePartNumber",
381bd79bce8SPatrick Williams                 sparePartNumber);
382913e7732SSunnySrivastava1984 
383913e7732SSunnySrivastava1984             if (!success)
384913e7732SSunnySrivastava1984             {
385ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
386913e7732SSunnySrivastava1984                 return;
387913e7732SSunnySrivastava1984             }
388913e7732SSunnySrivastava1984 
389913e7732SSunnySrivastava1984             if (manufacturer != nullptr)
390913e7732SSunnySrivastava1984             {
391ac106bf6SEd Tanous                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
392913e7732SSunnySrivastava1984             }
393913e7732SSunnySrivastava1984             if (model != nullptr)
394913e7732SSunnySrivastava1984             {
395ac106bf6SEd Tanous                 asyncResp->res.jsonValue["Model"] = *model;
396913e7732SSunnySrivastava1984             }
397913e7732SSunnySrivastava1984 
398913e7732SSunnySrivastava1984             if (partNumber != nullptr)
399913e7732SSunnySrivastava1984             {
400ac106bf6SEd Tanous                 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
401913e7732SSunnySrivastava1984             }
402913e7732SSunnySrivastava1984 
403913e7732SSunnySrivastava1984             if (serialNumber != nullptr)
404913e7732SSunnySrivastava1984             {
405ac106bf6SEd Tanous                 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
406913e7732SSunnySrivastava1984             }
407913e7732SSunnySrivastava1984 
408913e7732SSunnySrivastava1984             if (sparePartNumber != nullptr && !sparePartNumber->empty())
409913e7732SSunnySrivastava1984             {
410ac106bf6SEd Tanous                 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
411913e7732SSunnySrivastava1984             }
412913e7732SSunnySrivastava1984         });
413913e7732SSunnySrivastava1984 }
414913e7732SSunnySrivastava1984 
415543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
416a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
417a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId,
418543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
419f5c9f8bdSJason M. Bills {
420d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
421814bf20aSKonstantin Aladyshev     const std::string* generationSupported = nullptr;
4229bb0a7feSKonstantin Aladyshev     const size_t* lanesInUse = nullptr;
423814bf20aSKonstantin Aladyshev     const size_t* maxLanes = nullptr;
424d1bde9e5SKrzysztof Grobelny 
425d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
426609ba4c9SEd Tanous         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse",
427609ba4c9SEd Tanous         generationInUse, "GenerationSupported", generationSupported,
428609ba4c9SEd Tanous         "LanesInUse", lanesInUse, "MaxLanes", maxLanes);
429d1bde9e5SKrzysztof Grobelny 
430d1bde9e5SKrzysztof Grobelny     if (!success)
431d1bde9e5SKrzysztof Grobelny     {
432a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
433d1bde9e5SKrzysztof Grobelny         return;
434d1bde9e5SKrzysztof Grobelny     }
435d1bde9e5SKrzysztof Grobelny 
436d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
437d1bde9e5SKrzysztof Grobelny     {
4380ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
439c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
440543f9a75SLakshmi Yadlapati 
441d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
442d1bde9e5SKrzysztof Grobelny         {
44362598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
44462598e31SEd Tanous                                *generationInUse);
445cf3b484eSLakshmi Yadlapati         }
446cf3b484eSLakshmi Yadlapati         else
447cf3b484eSLakshmi Yadlapati         {
448cf3b484eSLakshmi Yadlapati             if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
449cf3b484eSLakshmi Yadlapati             {
45062598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
45162598e31SEd Tanous                                  *generationInUse);
452a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
453d1bde9e5SKrzysztof Grobelny                 return;
454d1bde9e5SKrzysztof Grobelny             }
455a5409991SLakshmi Yadlapati             asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
456d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
457d1bde9e5SKrzysztof Grobelny         }
458a9f68bb5STony Lee     }
459d1bde9e5SKrzysztof Grobelny 
460814bf20aSKonstantin Aladyshev     if (generationSupported != nullptr)
461814bf20aSKonstantin Aladyshev     {
462814bf20aSKonstantin Aladyshev         std::optional<pcie_device::PCIeTypes> redfishGenerationSupported =
463814bf20aSKonstantin Aladyshev             pcie_util::redfishPcieGenerationFromDbus(*generationSupported);
464814bf20aSKonstantin Aladyshev 
465814bf20aSKonstantin Aladyshev         if (!redfishGenerationSupported)
466814bf20aSKonstantin Aladyshev         {
46762598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
46862598e31SEd Tanous                                *generationSupported);
469814bf20aSKonstantin Aladyshev         }
470814bf20aSKonstantin Aladyshev         else
471814bf20aSKonstantin Aladyshev         {
472814bf20aSKonstantin Aladyshev             if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid)
473814bf20aSKonstantin Aladyshev             {
47462598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
47562598e31SEd Tanous                                  *generationSupported);
476814bf20aSKonstantin Aladyshev                 messages::internalError(asyncResp->res);
477814bf20aSKonstantin Aladyshev                 return;
478814bf20aSKonstantin Aladyshev             }
479814bf20aSKonstantin Aladyshev             asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] =
480814bf20aSKonstantin Aladyshev                 *redfishGenerationSupported;
481814bf20aSKonstantin Aladyshev         }
482814bf20aSKonstantin Aladyshev     }
483814bf20aSKonstantin Aladyshev 
4848c1d0549SMyung Bae     if (lanesInUse != nullptr)
485543f9a75SLakshmi Yadlapati     {
4868c1d0549SMyung Bae         if (*lanesInUse == std::numeric_limits<size_t>::max())
4878c1d0549SMyung Bae         {
4888c1d0549SMyung Bae             // The default value of LanesInUse is "maxint", and the field will
4898c1d0549SMyung Bae             // be null if it is a default value.
4908c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr;
4918c1d0549SMyung Bae         }
4928c1d0549SMyung Bae         else
4938c1d0549SMyung Bae         {
4948c1d0549SMyung Bae             asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] =
4958c1d0549SMyung Bae                 *lanesInUse;
4968c1d0549SMyung Bae         }
497543f9a75SLakshmi Yadlapati     }
498814bf20aSKonstantin Aladyshev     // The default value of MaxLanes is 0, and the field will be
499814bf20aSKonstantin Aladyshev     // left as off if it is a default value.
500814bf20aSKonstantin Aladyshev     if (maxLanes != nullptr && *maxLanes != 0)
501814bf20aSKonstantin Aladyshev     {
502814bf20aSKonstantin Aladyshev         asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes;
503814bf20aSKonstantin Aladyshev     }
504543f9a75SLakshmi Yadlapati 
505a5409991SLakshmi Yadlapati     asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
506a5409991SLakshmi Yadlapati         boost::urls::format(
507253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
508253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
509d1bde9e5SKrzysztof Grobelny }
510d1bde9e5SKrzysztof Grobelny 
511543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
512ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
513543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
514543f9a75SLakshmi Yadlapati     const std::function<void(
515543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
516d1bde9e5SKrzysztof Grobelny {
517deae6a78SEd Tanous     dbus::utility::getAllProperties(
518deae6a78SEd Tanous         service, pcieDevicePath,
519543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
520ac106bf6SEd Tanous         [asyncResp,
521543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
522543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
523543f9a75SLakshmi Yadlapati             if (ec)
524543f9a75SLakshmi Yadlapati             {
525543f9a75SLakshmi Yadlapati                 if (ec.value() != EBADR)
526543f9a75SLakshmi Yadlapati                 {
52762598e31SEd Tanous                     BMCWEB_LOG_ERROR("DBUS response error for Properties");
528ac106bf6SEd Tanous                     messages::internalError(asyncResp->res);
529543f9a75SLakshmi Yadlapati                 }
530543f9a75SLakshmi Yadlapati                 return;
531543f9a75SLakshmi Yadlapati             }
532543f9a75SLakshmi Yadlapati             callback(pcieDevProperties);
533543f9a75SLakshmi Yadlapati         });
534d1bde9e5SKrzysztof Grobelny }
535d1bde9e5SKrzysztof Grobelny 
536543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
537ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
538543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
539543f9a75SLakshmi Yadlapati {
540ac106bf6SEd Tanous     asyncResp->res.addHeader(
541543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
542543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
543ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
544253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
545253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
546253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
547ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
548ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
549539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
550539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
551543f9a75SLakshmi Yadlapati }
5521476687dSEd Tanous 
553a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath(
554a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
555a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId, const std::string& pcieDevicePath,
556a5409991SLakshmi Yadlapati     const std::string& service)
557a5409991SLakshmi Yadlapati {
558a5409991SLakshmi Yadlapati     addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
559a5409991SLakshmi Yadlapati     getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
560a5409991SLakshmi Yadlapati     getPCIeDeviceState(asyncResp, pcieDevicePath, service);
561a5409991SLakshmi Yadlapati     getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
562a5409991SLakshmi Yadlapati     getPCIeDeviceProperties(
563a5409991SLakshmi Yadlapati         asyncResp, pcieDevicePath, service,
564a5409991SLakshmi Yadlapati         std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
565a5409991SLakshmi Yadlapati     getPCIeDeviceSlotPath(
566a5409991SLakshmi Yadlapati         pcieDevicePath, asyncResp,
567a5409991SLakshmi Yadlapati         std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
568a5409991SLakshmi Yadlapati }
569a5409991SLakshmi Yadlapati 
570bd79bce8SPatrick Williams inline void handlePCIeDeviceGet(
571bd79bce8SPatrick Williams     App& app, const crow::Request& req,
572ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
573bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId)
574543f9a75SLakshmi Yadlapati {
575ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
576543f9a75SLakshmi Yadlapati     {
577543f9a75SLakshmi Yadlapati         return;
578543f9a75SLakshmi Yadlapati     }
57925b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5807f3e84a1SEd Tanous     {
5817f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
5827f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5837f3e84a1SEd Tanous                                    systemName);
5847f3e84a1SEd Tanous         return;
5857f3e84a1SEd Tanous     }
586253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
587543f9a75SLakshmi Yadlapati     {
588ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
589ac106bf6SEd Tanous                                    systemName);
590543f9a75SLakshmi Yadlapati         return;
591543f9a75SLakshmi Yadlapati     }
592543f9a75SLakshmi Yadlapati 
593543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
594ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
595a5409991SLakshmi Yadlapati         std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
596543f9a75SLakshmi Yadlapati }
597543f9a75SLakshmi Yadlapati 
598543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
599543f9a75SLakshmi Yadlapati {
600543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
601543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
602543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
603543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
604dede6a98SJason M. Bills }
605dede6a98SJason M. Bills 
60635ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
60735ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
60835ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
60935ad613dSLakshmi Yadlapati {
61035ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
61135ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
61235ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
61335ad613dSLakshmi Yadlapati 
61435ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
61535ad613dSLakshmi Yadlapati     {
61635ad613dSLakshmi Yadlapati         // Check if this function exists by
61735ad613dSLakshmi Yadlapati         // looking for a device ID
618bd79bce8SPatrick Williams         std::string devIDProperty =
619bd79bce8SPatrick Williams             "Function" + std::to_string(functionNum) + "DeviceId";
62035ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
62135ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
62235ad613dSLakshmi Yadlapati         {
62335ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
62435ad613dSLakshmi Yadlapati             {
62535ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
62635ad613dSLakshmi Yadlapati                 break;
62735ad613dSLakshmi Yadlapati             }
62835ad613dSLakshmi Yadlapati         }
62935ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
63035ad613dSLakshmi Yadlapati         {
63135ad613dSLakshmi Yadlapati             continue;
63235ad613dSLakshmi Yadlapati         }
63335ad613dSLakshmi Yadlapati 
63435ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
635ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
636253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
637253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
638253f11b8SEd Tanous             std::to_string(functionNum));
639b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
64035ad613dSLakshmi Yadlapati     }
64135ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
64235ad613dSLakshmi Yadlapati }
64335ad613dSLakshmi Yadlapati 
64435ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
64535ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
646ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6477f3e84a1SEd Tanous     const std::string& systemName, const std::string& pcieDeviceId)
64835ad613dSLakshmi Yadlapati {
649ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
65035ad613dSLakshmi Yadlapati     {
65135ad613dSLakshmi Yadlapati         return;
65235ad613dSLakshmi Yadlapati     }
65325b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
6547f3e84a1SEd Tanous     {
6557f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
6567f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6577f3e84a1SEd Tanous                                    systemName);
6587f3e84a1SEd Tanous         return;
6597f3e84a1SEd Tanous     }
66035ad613dSLakshmi Yadlapati 
66135ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
662ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
663ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
66435ad613dSLakshmi Yadlapati                                   const std::string& service) {
665ac106bf6SEd Tanous             asyncResp->res.addHeader(
66635ad613dSLakshmi Yadlapati                 boost::beast::http::field::link,
66735ad613dSLakshmi Yadlapati                 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
668ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
66935ad613dSLakshmi Yadlapati                 "#PCIeFunctionCollection.PCIeFunctionCollection";
670ac106bf6SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
671253f11b8SEd Tanous                 "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
672253f11b8SEd Tanous                 BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
673ac106bf6SEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
674ac106bf6SEd Tanous             asyncResp->res.jsonValue["Description"] =
67535ad613dSLakshmi Yadlapati                 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
67635ad613dSLakshmi Yadlapati             getPCIeDeviceProperties(
677ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
678ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId](
67935ad613dSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
680ac106bf6SEd Tanous                     addPCIeFunctionList(asyncResp->res, pcieDeviceId,
681ac106bf6SEd Tanous                                         pcieDevProperties);
68235ad613dSLakshmi Yadlapati                 });
68335ad613dSLakshmi Yadlapati         });
68435ad613dSLakshmi Yadlapati }
68535ad613dSLakshmi Yadlapati 
6867e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
6877e860f15SJohn Edward Broadbent {
688dede6a98SJason M. Bills     /**
689dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
690dede6a98SJason M. Bills      */
6917e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
6927f3e84a1SEd Tanous                  "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
693ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
694002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
69535ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
6967e860f15SJohn Edward Broadbent }
6977e860f15SJohn Edward Broadbent 
698727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
699d5e74b80SMyung Bae     uint64_t pcieFunctionId,
700727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
7017e860f15SJohn Edward Broadbent {
702d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
703b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
704b9d36b47SEd Tanous 
705b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
706b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
707b9d36b47SEd Tanous     {
708b9d36b47SEd Tanous         if (property.first == devIDProperty)
709b9d36b47SEd Tanous         {
710002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
711727a046cSLakshmi Yadlapati             break;
712b9d36b47SEd Tanous         }
713b9d36b47SEd Tanous     }
714727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
715727a046cSLakshmi Yadlapati }
716727a046cSLakshmi Yadlapati 
717727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
718e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
719727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
720f5c9f8bdSJason M. Bills {
721e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
722b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
723f5c9f8bdSJason M. Bills     {
724b9d36b47SEd Tanous         const std::string* strProperty =
725b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
726dc8cfa66SEd Tanous         if (strProperty == nullptr)
727dc8cfa66SEd Tanous         {
728dc8cfa66SEd Tanous             continue;
729dc8cfa66SEd Tanous         }
730b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
731f5c9f8bdSJason M. Bills         {
732727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
733f5c9f8bdSJason M. Bills         }
734b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
735f5c9f8bdSJason M. Bills         {
736727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
737f5c9f8bdSJason M. Bills         }
738727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
739727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
740727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
741b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
742f5c9f8bdSJason M. Bills         {
743727a046cSLakshmi Yadlapati             if (!strProperty->empty())
744727a046cSLakshmi Yadlapati             {
745727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
746727a046cSLakshmi Yadlapati             }
747f5c9f8bdSJason M. Bills         }
748b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
749f5c9f8bdSJason M. Bills         {
750727a046cSLakshmi Yadlapati             if (!strProperty->empty())
751727a046cSLakshmi Yadlapati             {
752727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
753727a046cSLakshmi Yadlapati             }
754f5c9f8bdSJason M. Bills         }
755b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
756f5c9f8bdSJason M. Bills         {
757727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
758f5c9f8bdSJason M. Bills         }
759b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
760f5c9f8bdSJason M. Bills         {
761727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
762f5c9f8bdSJason M. Bills         }
763b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
764b9d36b47SEd Tanous         {
765727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
766b9d36b47SEd Tanous         }
767002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
768f5c9f8bdSJason M. Bills         {
769727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
770b9d36b47SEd Tanous         }
771f5c9f8bdSJason M. Bills     }
772727a046cSLakshmi Yadlapati }
773727a046cSLakshmi Yadlapati 
774727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
775727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
776e14742caSEd Tanous                                             uint64_t pcieFunctionId)
777727a046cSLakshmi Yadlapati {
778727a046cSLakshmi Yadlapati     resp.addHeader(
779727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
780727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
781727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
782ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
783253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
784253f11b8SEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
785253f11b8SEd Tanous         std::to_string(pcieFunctionId));
786727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
787e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
788e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
789253f11b8SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
790253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
791253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
792727a046cSLakshmi Yadlapati }
793727a046cSLakshmi Yadlapati 
794bd79bce8SPatrick Williams inline void handlePCIeFunctionGet(
795bd79bce8SPatrick Williams     App& app, const crow::Request& req,
796ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
797bd79bce8SPatrick Williams     const std::string& systemName, const std::string& pcieDeviceId,
798e14742caSEd Tanous     const std::string& pcieFunctionIdStr)
799727a046cSLakshmi Yadlapati {
800ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
801727a046cSLakshmi Yadlapati     {
802727a046cSLakshmi Yadlapati         return;
803727a046cSLakshmi Yadlapati     }
80425b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
8057f3e84a1SEd Tanous     {
8067f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
8077f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8087f3e84a1SEd Tanous                                    systemName);
8097f3e84a1SEd Tanous         return;
8107f3e84a1SEd Tanous     }
811253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
8127f3e84a1SEd Tanous     {
8137f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8147f3e84a1SEd Tanous                                    systemName);
8157f3e84a1SEd Tanous         return;
8167f3e84a1SEd Tanous     }
817dc8cfa66SEd Tanous     std::string_view pcieFunctionIdView = pcieFunctionIdStr;
8187f3e84a1SEd Tanous 
819e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
820e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
821dc8cfa66SEd Tanous         pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId);
822dc8cfa66SEd Tanous     if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end())
823e14742caSEd Tanous     {
824ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
825e14742caSEd Tanous                                    pcieFunctionIdStr);
826e14742caSEd Tanous         return;
827e14742caSEd Tanous     }
828727a046cSLakshmi Yadlapati 
829bd79bce8SPatrick Williams     getValidPCIeDevicePath(
830bd79bce8SPatrick Williams         pcieDeviceId, asyncResp,
831bd79bce8SPatrick Williams         [asyncResp, pcieDeviceId, pcieFunctionId](
832bd79bce8SPatrick Williams             const std::string& pcieDevicePath, const std::string& service) {
833727a046cSLakshmi Yadlapati             getPCIeDeviceProperties(
834ac106bf6SEd Tanous                 asyncResp, pcieDevicePath, service,
835ac106bf6SEd Tanous                 [asyncResp, pcieDeviceId, pcieFunctionId](
836727a046cSLakshmi Yadlapati                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
837bd79bce8SPatrick Williams                     addPCIeFunctionCommonProperties(
838bd79bce8SPatrick Williams                         asyncResp->res, pcieDeviceId, pcieFunctionId);
839ac106bf6SEd Tanous                     addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
840727a046cSLakshmi Yadlapati                                               pcieDevProperties);
8417e860f15SJohn Edward Broadbent                 });
842727a046cSLakshmi Yadlapati         });
843727a046cSLakshmi Yadlapati }
844727a046cSLakshmi Yadlapati 
845727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
846727a046cSLakshmi Yadlapati {
847727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
8487f3e84a1SEd Tanous         app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
849727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
850727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
851727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
852f5c9f8bdSJason M. Bills }
853f5c9f8bdSJason M. Bills 
854f5c9f8bdSJason M. Bills } // namespace redfish
855