xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 82f80326afb1e1cfd6b682d4fa2f75319c83004f)
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"
213ccb3adbSEd Tanous #include "query.hpp"
223ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
23b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp"
243ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
25c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp"
260ec8b83dSEd Tanous 
27f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp>
28ef4c65b7SEd Tanous #include <boost/url/format.hpp>
29d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
30d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
31f5c9f8bdSJason M. Bills 
32f5c9f8bdSJason M. Bills namespace redfish
33f5c9f8bdSJason M. Bills {
34f5c9f8bdSJason M. Bills 
3589492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
3694c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
3794c3a10bSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
38a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = {
39a5409991SLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeSlot"};
40f5c9f8bdSJason M. Bills 
41543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath(
42543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
43ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
44543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
45543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
46543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
47543f9a75SLakshmi Yadlapati 
48543f9a75SLakshmi Yadlapati {
49543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
50543f9a75SLakshmi Yadlapati     {
51543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
52543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
53543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
54543f9a75SLakshmi Yadlapati         {
55543f9a75SLakshmi Yadlapati             continue;
56543f9a75SLakshmi Yadlapati         }
57543f9a75SLakshmi Yadlapati 
58543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
59543f9a75SLakshmi Yadlapati             pcieDevicePath, {},
60ac106bf6SEd Tanous             [pcieDevicePath, asyncResp,
61543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
62543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
63543f9a75SLakshmi Yadlapati             if (ec || object.empty())
64543f9a75SLakshmi Yadlapati             {
65543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
66ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
67543f9a75SLakshmi Yadlapati                 return;
68543f9a75SLakshmi Yadlapati             }
69543f9a75SLakshmi Yadlapati             callback(pcieDevicePath, object.begin()->first);
70543f9a75SLakshmi Yadlapati             });
71543f9a75SLakshmi Yadlapati         return;
72543f9a75SLakshmi Yadlapati     }
73543f9a75SLakshmi Yadlapati 
74543f9a75SLakshmi Yadlapati     BMCWEB_LOG_WARNING << "PCIe Device not found";
75ac106bf6SEd Tanous     messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
76543f9a75SLakshmi Yadlapati }
77543f9a75SLakshmi Yadlapati 
78543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath(
79543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
80ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
81543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
82543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
83543f9a75SLakshmi Yadlapati {
84543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
8594c3a10bSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
86ac106bf6SEd Tanous         [pcieDeviceId, asyncResp,
87543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
88543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
89543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
90543f9a75SLakshmi Yadlapati         if (ec)
91543f9a75SLakshmi Yadlapati         {
92543f9a75SLakshmi Yadlapati             BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
93ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
94543f9a75SLakshmi Yadlapati             return;
95543f9a75SLakshmi Yadlapati         }
96ac106bf6SEd Tanous         handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
97ac106bf6SEd Tanous                              callback);
98543f9a75SLakshmi Yadlapati         return;
99543f9a75SLakshmi Yadlapati         });
100543f9a75SLakshmi Yadlapati }
101543f9a75SLakshmi Yadlapati 
102b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet(
103b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
104ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
105b38fa2abSLakshmi Yadlapati     const std::string& systemName)
106b38fa2abSLakshmi Yadlapati {
107ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
108b38fa2abSLakshmi Yadlapati     {
109b38fa2abSLakshmi Yadlapati         return;
110b38fa2abSLakshmi Yadlapati     }
1117f3e84a1SEd Tanous     if constexpr (bmcwebEnableMultiHost)
1127f3e84a1SEd Tanous     {
1137f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
1147f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1157f3e84a1SEd Tanous                                    systemName);
1167f3e84a1SEd Tanous         return;
1177f3e84a1SEd Tanous     }
118b38fa2abSLakshmi Yadlapati     if (systemName != "system")
119b38fa2abSLakshmi Yadlapati     {
120ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
121ac106bf6SEd Tanous                                    systemName);
122b38fa2abSLakshmi Yadlapati         return;
123b38fa2abSLakshmi Yadlapati     }
124543f9a75SLakshmi Yadlapati 
125ac106bf6SEd Tanous     asyncResp->res.addHeader(boost::beast::http::field::link,
126b38fa2abSLakshmi Yadlapati                              "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
127b38fa2abSLakshmi Yadlapati                              "PCIeDeviceCollection.json>; rel=describedby");
128ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
129b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
130ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
131b38fa2abSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices";
132ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
133ac106bf6SEd Tanous     asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
134ac106bf6SEd Tanous     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
135ac106bf6SEd Tanous     asyncResp->res.jsonValue["Members@odata.count"] = 0;
136b38fa2abSLakshmi Yadlapati 
1379e9325e6SLakshmi Yadlapati     pcie_util::getPCIeDeviceList(asyncResp, "Members");
138b38fa2abSLakshmi Yadlapati }
139b38fa2abSLakshmi Yadlapati 
1407e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
141adbe192aSJason M. Bills {
142adbe192aSJason M. Bills     /**
143adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
144adbe192aSJason M. Bills      */
14522d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
146ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1477e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
148b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
149f5c9f8bdSJason M. Bills }
150f5c9f8bdSJason M. Bills 
151a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties(
152a5409991SLakshmi Yadlapati     crow::Response& res, const boost::system::error_code& ec,
153a5409991SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieSlotProperties)
154a5409991SLakshmi Yadlapati {
155a5409991SLakshmi Yadlapati     if (ec)
156a5409991SLakshmi Yadlapati     {
157a5409991SLakshmi Yadlapati         BMCWEB_LOG_ERROR << "DBUS response error for getAllProperties"
158a5409991SLakshmi Yadlapati                          << ec.value();
159a5409991SLakshmi Yadlapati         messages::internalError(res);
160a5409991SLakshmi Yadlapati         return;
161a5409991SLakshmi Yadlapati     }
162a5409991SLakshmi Yadlapati     std::string generation;
163a5409991SLakshmi Yadlapati     size_t lanes = 0;
164a5409991SLakshmi Yadlapati     std::string slotType;
165a5409991SLakshmi Yadlapati 
166a5409991SLakshmi Yadlapati     bool success = sdbusplus::unpackPropertiesNoThrow(
167a5409991SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation",
168a5409991SLakshmi Yadlapati         generation, "Lanes", lanes, "SlotType", slotType);
169a5409991SLakshmi Yadlapati 
170a5409991SLakshmi Yadlapati     if (!success)
171a5409991SLakshmi Yadlapati     {
172a5409991SLakshmi Yadlapati         messages::internalError(res);
173a5409991SLakshmi Yadlapati         return;
174a5409991SLakshmi Yadlapati     }
175a5409991SLakshmi Yadlapati 
176a5409991SLakshmi Yadlapati     std::optional<pcie_device::PCIeTypes> pcieType =
177a5409991SLakshmi Yadlapati         pcie_util::redfishPcieGenerationFromDbus(generation);
178a5409991SLakshmi Yadlapati     if (!pcieType)
179a5409991SLakshmi Yadlapati     {
180a5409991SLakshmi Yadlapati         BMCWEB_LOG_WARNING << "Unknown PCIeType: " << generation;
181a5409991SLakshmi Yadlapati     }
182a5409991SLakshmi Yadlapati     else
183a5409991SLakshmi Yadlapati     {
184a5409991SLakshmi Yadlapati         if (*pcieType == pcie_device::PCIeTypes::Invalid)
185a5409991SLakshmi Yadlapati         {
186a5409991SLakshmi Yadlapati             BMCWEB_LOG_ERROR << "Invalid PCIeType: " << generation;
187a5409991SLakshmi Yadlapati             messages::internalError(res);
188a5409991SLakshmi Yadlapati             return;
189a5409991SLakshmi Yadlapati         }
190a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["PCIeType"] = *pcieType;
191a5409991SLakshmi Yadlapati     }
192a5409991SLakshmi Yadlapati 
193*82f80326SKonstantin Aladyshev     if (lanes != 0)
194*82f80326SKonstantin Aladyshev     {
195a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["Lanes"] = lanes;
196*82f80326SKonstantin Aladyshev     }
197a5409991SLakshmi Yadlapati 
198a5409991SLakshmi Yadlapati     std::optional<pcie_slots::SlotTypes> redfishSlotType =
199a5409991SLakshmi Yadlapati         pcie_util::dbusSlotTypeToRf(slotType);
200a5409991SLakshmi Yadlapati     if (!redfishSlotType)
201a5409991SLakshmi Yadlapati     {
202a5409991SLakshmi Yadlapati         BMCWEB_LOG_WARNING << "Unknown PCIeSlot Type: " << slotType;
203a5409991SLakshmi Yadlapati     }
204a5409991SLakshmi Yadlapati     else
205a5409991SLakshmi Yadlapati     {
206a5409991SLakshmi Yadlapati         if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
207a5409991SLakshmi Yadlapati         {
208a5409991SLakshmi Yadlapati             BMCWEB_LOG_ERROR << "Invalid PCIeSlot type: " << slotType;
209a5409991SLakshmi Yadlapati             messages::internalError(res);
210a5409991SLakshmi Yadlapati             return;
211a5409991SLakshmi Yadlapati         }
212a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["SlotType"] = *redfishSlotType;
213a5409991SLakshmi Yadlapati     }
214a5409991SLakshmi Yadlapati }
215a5409991SLakshmi Yadlapati 
216a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath(
217a5409991SLakshmi Yadlapati     const std::string& pcieDevicePath,
218a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
219a5409991SLakshmi Yadlapati     std::function<void(const std::string& pcieDeviceSlot)>&& callback)
220a5409991SLakshmi Yadlapati {
221a5409991SLakshmi Yadlapati     std::string associationPath = pcieDevicePath + "/contained_by";
222a5409991SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
223a5409991SLakshmi Yadlapati         associationPath, sdbusplus::message::object_path(inventoryPath), 0,
224a5409991SLakshmi Yadlapati         pcieSlotInterface,
225a5409991SLakshmi Yadlapati         [callback, asyncResp, pcieDevicePath](
226a5409991SLakshmi Yadlapati             const boost::system::error_code& ec,
227a5409991SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& endpoints) {
228a5409991SLakshmi Yadlapati         if (ec)
229a5409991SLakshmi Yadlapati         {
230a5409991SLakshmi Yadlapati             if (ec.value() == EBADR)
231a5409991SLakshmi Yadlapati             {
232a5409991SLakshmi Yadlapati                 // Missing association is not an error
233a5409991SLakshmi Yadlapati                 return;
234a5409991SLakshmi Yadlapati             }
235a5409991SLakshmi Yadlapati             BMCWEB_LOG_ERROR
236a5409991SLakshmi Yadlapati                 << "DBUS response error for getAssociatedSubTreePaths "
237a5409991SLakshmi Yadlapati                 << ec.value();
238a5409991SLakshmi Yadlapati             messages::internalError(asyncResp->res);
239a5409991SLakshmi Yadlapati             return;
240a5409991SLakshmi Yadlapati         }
241a5409991SLakshmi Yadlapati         if (endpoints.size() > 1)
242a5409991SLakshmi Yadlapati         {
243a5409991SLakshmi Yadlapati             BMCWEB_LOG_ERROR
244a5409991SLakshmi Yadlapati                 << "PCIeDevice is associated with more than one PCIeSlot: "
245a5409991SLakshmi Yadlapati                 << endpoints.size();
246a5409991SLakshmi Yadlapati             messages::internalError(asyncResp->res);
247a5409991SLakshmi Yadlapati             return;
248a5409991SLakshmi Yadlapati         }
249a5409991SLakshmi Yadlapati         if (endpoints.empty())
250a5409991SLakshmi Yadlapati         {
251a5409991SLakshmi Yadlapati             // If the device doesn't have an association, return without PCIe
252a5409991SLakshmi Yadlapati             // Slot properties
253a5409991SLakshmi Yadlapati             BMCWEB_LOG_DEBUG << "PCIeDevice is not associated with PCIeSlot";
254a5409991SLakshmi Yadlapati             return;
255a5409991SLakshmi Yadlapati         }
256a5409991SLakshmi Yadlapati         callback(endpoints[0]);
257a5409991SLakshmi Yadlapati         });
258a5409991SLakshmi Yadlapati }
259a5409991SLakshmi Yadlapati 
260a5409991SLakshmi Yadlapati inline void
261a5409991SLakshmi Yadlapati     afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
262a5409991SLakshmi Yadlapati                        const std::string& pcieDeviceSlot,
263a5409991SLakshmi Yadlapati                        const boost::system::error_code& ec,
264a5409991SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object)
265a5409991SLakshmi Yadlapati {
266a5409991SLakshmi Yadlapati     if (ec || object.empty())
267a5409991SLakshmi Yadlapati     {
268a5409991SLakshmi Yadlapati         BMCWEB_LOG_ERROR << "DBUS response error for getDbusObject "
269a5409991SLakshmi Yadlapati                          << ec.value();
270a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
271a5409991SLakshmi Yadlapati         return;
272a5409991SLakshmi Yadlapati     }
273a5409991SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
274a5409991SLakshmi Yadlapati         *crow::connections::systemBus, object.begin()->first, pcieDeviceSlot,
275a5409991SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
276a5409991SLakshmi Yadlapati         [asyncResp](
277a5409991SLakshmi Yadlapati             const boost::system::error_code& ec2,
278a5409991SLakshmi Yadlapati             const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
279a5409991SLakshmi Yadlapati         addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
280a5409991SLakshmi Yadlapati         });
281a5409991SLakshmi Yadlapati }
282a5409991SLakshmi Yadlapati 
283a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath(
284a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
285a5409991SLakshmi Yadlapati     const std::string& pcieDeviceSlot)
286a5409991SLakshmi Yadlapati {
287a5409991SLakshmi Yadlapati     dbus::utility::getDbusObject(
288a5409991SLakshmi Yadlapati         pcieDeviceSlot, pcieSlotInterface,
289a5409991SLakshmi Yadlapati         [asyncResp,
290a5409991SLakshmi Yadlapati          pcieDeviceSlot](const boost::system::error_code& ec,
291a5409991SLakshmi Yadlapati                          const dbus::utility::MapperGetObject& object) {
292a5409991SLakshmi Yadlapati         afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
293a5409991SLakshmi Yadlapati         });
294a5409991SLakshmi Yadlapati }
295a5409991SLakshmi Yadlapati 
296ac106bf6SEd Tanous inline void
297e164f1b6SLakshmi Yadlapati     getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
298e164f1b6SLakshmi Yadlapati                         const std::string& pcieDevicePath,
299e164f1b6SLakshmi Yadlapati                         const std::string& service)
300e164f1b6SLakshmi Yadlapati {
301e164f1b6SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
302e164f1b6SLakshmi Yadlapati         *crow::connections::systemBus, 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             {
309e164f1b6SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Health "
310e164f1b6SLakshmi Yadlapati                                  << ec.value();
311e164f1b6SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
312e164f1b6SLakshmi Yadlapati             }
313e164f1b6SLakshmi Yadlapati             return;
314e164f1b6SLakshmi Yadlapati         }
315e164f1b6SLakshmi Yadlapati 
316e164f1b6SLakshmi Yadlapati         if (!value)
317e164f1b6SLakshmi Yadlapati         {
318e164f1b6SLakshmi Yadlapati             asyncResp->res.jsonValue["Status"]["Health"] = "Critical";
319e164f1b6SLakshmi Yadlapati         }
320e164f1b6SLakshmi Yadlapati         });
321e164f1b6SLakshmi Yadlapati }
322e164f1b6SLakshmi Yadlapati 
323e164f1b6SLakshmi Yadlapati inline void
324ac106bf6SEd Tanous     getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
325c6bb3285SLakshmi Yadlapati                        const std::string& pcieDevicePath,
326c6bb3285SLakshmi Yadlapati                        const std::string& service)
327c6bb3285SLakshmi Yadlapati {
328c6bb3285SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
329c6bb3285SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
330c6bb3285SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item", "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             {
336c6bb3285SLakshmi Yadlapati                 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         {
344ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "Absent";
345c6bb3285SLakshmi Yadlapati         }
346c6bb3285SLakshmi Yadlapati         });
347c6bb3285SLakshmi Yadlapati }
348c6bb3285SLakshmi Yadlapati 
349ac106bf6SEd Tanous inline void
350ac106bf6SEd Tanous     getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
351913e7732SSunnySrivastava1984                        const std::string& pcieDevicePath,
352913e7732SSunnySrivastava1984                        const std::string& service)
353913e7732SSunnySrivastava1984 {
354913e7732SSunnySrivastava1984     sdbusplus::asio::getAllProperties(
355913e7732SSunnySrivastava1984         *crow::connections::systemBus, 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             {
364913e7732SSunnySrivastava1984                 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
365913e7732SSunnySrivastava1984                                  << 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,
380913e7732SSunnySrivastava1984             "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
381913e7732SSunnySrivastava1984 
382913e7732SSunnySrivastava1984         if (!success)
383913e7732SSunnySrivastava1984         {
384ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
385913e7732SSunnySrivastava1984             return;
386913e7732SSunnySrivastava1984         }
387913e7732SSunnySrivastava1984 
388913e7732SSunnySrivastava1984         if (manufacturer != nullptr)
389913e7732SSunnySrivastava1984         {
390ac106bf6SEd Tanous             asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
391913e7732SSunnySrivastava1984         }
392913e7732SSunnySrivastava1984         if (model != nullptr)
393913e7732SSunnySrivastava1984         {
394ac106bf6SEd Tanous             asyncResp->res.jsonValue["Model"] = *model;
395913e7732SSunnySrivastava1984         }
396913e7732SSunnySrivastava1984 
397913e7732SSunnySrivastava1984         if (partNumber != nullptr)
398913e7732SSunnySrivastava1984         {
399ac106bf6SEd Tanous             asyncResp->res.jsonValue["PartNumber"] = *partNumber;
400913e7732SSunnySrivastava1984         }
401913e7732SSunnySrivastava1984 
402913e7732SSunnySrivastava1984         if (serialNumber != nullptr)
403913e7732SSunnySrivastava1984         {
404ac106bf6SEd Tanous             asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
405913e7732SSunnySrivastava1984         }
406913e7732SSunnySrivastava1984 
407913e7732SSunnySrivastava1984         if (sparePartNumber != nullptr && !sparePartNumber->empty())
408913e7732SSunnySrivastava1984         {
409ac106bf6SEd Tanous             asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
410913e7732SSunnySrivastava1984         }
411913e7732SSunnySrivastava1984         });
412913e7732SSunnySrivastava1984 }
413913e7732SSunnySrivastava1984 
414543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
415a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
416a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId,
417543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
418f5c9f8bdSJason M. Bills {
419d1bde9e5SKrzysztof Grobelny     const std::string* deviceType = nullptr;
420d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
4219bb0a7feSKonstantin Aladyshev     const size_t* lanesInUse = nullptr;
422d1bde9e5SKrzysztof Grobelny 
423d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
424543f9a75SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
425543f9a75SLakshmi Yadlapati         deviceType, "GenerationInUse", generationInUse, "LanesInUse",
426bad2c4a9SLakshmi Yadlapati         lanesInUse);
427d1bde9e5SKrzysztof Grobelny 
428d1bde9e5SKrzysztof Grobelny     if (!success)
429d1bde9e5SKrzysztof Grobelny     {
430a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
431d1bde9e5SKrzysztof Grobelny         return;
432d1bde9e5SKrzysztof Grobelny     }
433d1bde9e5SKrzysztof Grobelny 
434543f9a75SLakshmi Yadlapati     if (deviceType != nullptr && !deviceType->empty())
435703f6741SMyung Bae     {
436a5409991SLakshmi Yadlapati         asyncResp->res.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
437703f6741SMyung Bae     }
438703f6741SMyung Bae 
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         {
446cf3b484eSLakshmi Yadlapati             BMCWEB_LOG_WARNING << "Unknown PCIe Device Generation: "
447cf3b484eSLakshmi Yadlapati                                << *generationInUse;
448cf3b484eSLakshmi Yadlapati         }
449cf3b484eSLakshmi Yadlapati         else
450cf3b484eSLakshmi Yadlapati         {
451cf3b484eSLakshmi Yadlapati             if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
452cf3b484eSLakshmi Yadlapati             {
453cf3b484eSLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "Invalid PCIe Device Generation: "
454cf3b484eSLakshmi Yadlapati                                  << *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 
463543f9a75SLakshmi Yadlapati     // The default value of LanesInUse is 0, and the field will be
464543f9a75SLakshmi Yadlapati     // left as off if it is a default value.
465543f9a75SLakshmi Yadlapati     if (lanesInUse != nullptr && *lanesInUse != 0)
466543f9a75SLakshmi Yadlapati     {
467a5409991SLakshmi Yadlapati         asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
468543f9a75SLakshmi Yadlapati     }
469543f9a75SLakshmi Yadlapati 
470a5409991SLakshmi Yadlapati     asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
471a5409991SLakshmi Yadlapati         boost::urls::format(
472ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
473ef4c65b7SEd Tanous             pcieDeviceId);
474d1bde9e5SKrzysztof Grobelny }
475d1bde9e5SKrzysztof Grobelny 
476543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
477ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
478543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
479543f9a75SLakshmi Yadlapati     const std::function<void(
480543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
481d1bde9e5SKrzysztof Grobelny {
482543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
483543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
484543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
485ac106bf6SEd Tanous         [asyncResp,
486543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
487543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
488543f9a75SLakshmi Yadlapati         if (ec)
489543f9a75SLakshmi Yadlapati         {
490543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
491543f9a75SLakshmi Yadlapati             {
492543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
493ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
494543f9a75SLakshmi Yadlapati             }
495543f9a75SLakshmi Yadlapati             return;
496543f9a75SLakshmi Yadlapati         }
497543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
498543f9a75SLakshmi Yadlapati         });
499d1bde9e5SKrzysztof Grobelny }
500d1bde9e5SKrzysztof Grobelny 
501543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
502ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
503543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
504543f9a75SLakshmi Yadlapati {
505ac106bf6SEd Tanous     asyncResp->res.addHeader(
506543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
507543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
508ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
509ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
510ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
511ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
512ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
513ac106bf6SEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
514e164f1b6SLakshmi Yadlapati     asyncResp->res.jsonValue["Status"]["Health"] = "OK";
515543f9a75SLakshmi Yadlapati }
5161476687dSEd Tanous 
517a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath(
518a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
519a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId, const std::string& pcieDevicePath,
520a5409991SLakshmi Yadlapati     const std::string& service)
521a5409991SLakshmi Yadlapati {
522a5409991SLakshmi Yadlapati     addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
523a5409991SLakshmi Yadlapati     getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
524a5409991SLakshmi Yadlapati     getPCIeDeviceState(asyncResp, pcieDevicePath, service);
525a5409991SLakshmi Yadlapati     getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
526a5409991SLakshmi Yadlapati     getPCIeDeviceProperties(
527a5409991SLakshmi Yadlapati         asyncResp, pcieDevicePath, service,
528a5409991SLakshmi Yadlapati         std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
529a5409991SLakshmi Yadlapati     getPCIeDeviceSlotPath(
530a5409991SLakshmi Yadlapati         pcieDevicePath, asyncResp,
531a5409991SLakshmi Yadlapati         std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
532a5409991SLakshmi Yadlapati }
533a5409991SLakshmi Yadlapati 
534ac106bf6SEd Tanous inline void
535ac106bf6SEd Tanous     handlePCIeDeviceGet(App& app, const crow::Request& req,
536ac106bf6SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
537543f9a75SLakshmi Yadlapati                         const std::string& systemName,
538543f9a75SLakshmi Yadlapati                         const std::string& pcieDeviceId)
539543f9a75SLakshmi Yadlapati {
540ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
541543f9a75SLakshmi Yadlapati     {
542543f9a75SLakshmi Yadlapati         return;
543543f9a75SLakshmi Yadlapati     }
5447f3e84a1SEd Tanous     if constexpr (bmcwebEnableMultiHost)
5457f3e84a1SEd Tanous     {
5467f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
5477f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5487f3e84a1SEd Tanous                                    systemName);
5497f3e84a1SEd Tanous         return;
5507f3e84a1SEd Tanous     }
551543f9a75SLakshmi Yadlapati     if (systemName != "system")
552543f9a75SLakshmi Yadlapati     {
553ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
554ac106bf6SEd Tanous                                    systemName);
555543f9a75SLakshmi Yadlapati         return;
556543f9a75SLakshmi Yadlapati     }
557543f9a75SLakshmi Yadlapati 
558543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
559ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
560a5409991SLakshmi Yadlapati         std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
561543f9a75SLakshmi Yadlapati }
562543f9a75SLakshmi Yadlapati 
563543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
564543f9a75SLakshmi Yadlapati {
565543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
566543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
567543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
568543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
569dede6a98SJason M. Bills }
570dede6a98SJason M. Bills 
57135ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
57235ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
57335ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
57435ad613dSLakshmi Yadlapati {
57535ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
57635ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
57735ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
57835ad613dSLakshmi Yadlapati 
57935ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
58035ad613dSLakshmi Yadlapati     {
58135ad613dSLakshmi Yadlapati         // Check if this function exists by
58235ad613dSLakshmi Yadlapati         // looking for a device ID
58389492a15SPatrick Williams         std::string devIDProperty = "Function" + std::to_string(functionNum) +
58489492a15SPatrick Williams                                     "DeviceId";
58535ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
58635ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
58735ad613dSLakshmi Yadlapati         {
58835ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
58935ad613dSLakshmi Yadlapati             {
59035ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
59135ad613dSLakshmi Yadlapati                 break;
59235ad613dSLakshmi Yadlapati             }
59335ad613dSLakshmi Yadlapati         }
59435ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
59535ad613dSLakshmi Yadlapati         {
59635ad613dSLakshmi Yadlapati             continue;
59735ad613dSLakshmi Yadlapati         }
59835ad613dSLakshmi Yadlapati 
59935ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
600ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
601ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
602ef4c65b7SEd Tanous             pcieDeviceId, std::to_string(functionNum));
603b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
60435ad613dSLakshmi Yadlapati     }
60535ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
60635ad613dSLakshmi Yadlapati }
60735ad613dSLakshmi Yadlapati 
60835ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
60935ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
610ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6117f3e84a1SEd Tanous     const std::string& systemName, const std::string& pcieDeviceId)
61235ad613dSLakshmi Yadlapati {
613ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
61435ad613dSLakshmi Yadlapati     {
61535ad613dSLakshmi Yadlapati         return;
61635ad613dSLakshmi Yadlapati     }
6177f3e84a1SEd Tanous     if constexpr (bmcwebEnableMultiHost)
6187f3e84a1SEd Tanous     {
6197f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
6207f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6217f3e84a1SEd Tanous                                    systemName);
6227f3e84a1SEd Tanous         return;
6237f3e84a1SEd Tanous     }
62435ad613dSLakshmi Yadlapati 
62535ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
626ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
627ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
62835ad613dSLakshmi Yadlapati                                   const std::string& service) {
629ac106bf6SEd Tanous         asyncResp->res.addHeader(
63035ad613dSLakshmi Yadlapati             boost::beast::http::field::link,
63135ad613dSLakshmi Yadlapati             "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
632ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
63335ad613dSLakshmi Yadlapati             "#PCIeFunctionCollection.PCIeFunctionCollection";
634ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
635ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
636ef4c65b7SEd Tanous             pcieDeviceId);
637ac106bf6SEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
638ac106bf6SEd Tanous         asyncResp->res.jsonValue["Description"] =
63935ad613dSLakshmi Yadlapati             "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
64035ad613dSLakshmi Yadlapati         getPCIeDeviceProperties(
641ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
642ac106bf6SEd Tanous             [asyncResp, pcieDeviceId](
64335ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
644ac106bf6SEd Tanous             addPCIeFunctionList(asyncResp->res, pcieDeviceId,
645ac106bf6SEd Tanous                                 pcieDevProperties);
64635ad613dSLakshmi Yadlapati             });
64735ad613dSLakshmi Yadlapati         });
64835ad613dSLakshmi Yadlapati }
64935ad613dSLakshmi Yadlapati 
6507e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
6517e860f15SJohn Edward Broadbent {
652dede6a98SJason M. Bills     /**
653dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
654dede6a98SJason M. Bills      */
6557e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
6567f3e84a1SEd Tanous                  "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
657ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
658002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
65935ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
6607e860f15SJohn Edward Broadbent }
6617e860f15SJohn Edward Broadbent 
662727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
663d5e74b80SMyung Bae     uint64_t pcieFunctionId,
664727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
6657e860f15SJohn Edward Broadbent {
666d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
667b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
668b9d36b47SEd Tanous 
669b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
670b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
671b9d36b47SEd Tanous     {
672b9d36b47SEd Tanous         if (property.first == devIDProperty)
673b9d36b47SEd Tanous         {
674002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
675727a046cSLakshmi Yadlapati             break;
676b9d36b47SEd Tanous         }
677b9d36b47SEd Tanous     }
678727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
679727a046cSLakshmi Yadlapati }
680727a046cSLakshmi Yadlapati 
681727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
682e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
683727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
684f5c9f8bdSJason M. Bills {
685e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
686b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
687f5c9f8bdSJason M. Bills     {
688b9d36b47SEd Tanous         const std::string* strProperty =
689b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
690727a046cSLakshmi Yadlapati 
691b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
692f5c9f8bdSJason M. Bills         {
693727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
694f5c9f8bdSJason M. Bills         }
695b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
696f5c9f8bdSJason M. Bills         {
697727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
698f5c9f8bdSJason M. Bills         }
699727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
700727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
701727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
702b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
703f5c9f8bdSJason M. Bills         {
704727a046cSLakshmi Yadlapati             if (!strProperty->empty())
705727a046cSLakshmi Yadlapati             {
706727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
707727a046cSLakshmi Yadlapati             }
708f5c9f8bdSJason M. Bills         }
709b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
710f5c9f8bdSJason M. Bills         {
711727a046cSLakshmi Yadlapati             if (!strProperty->empty())
712727a046cSLakshmi Yadlapati             {
713727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
714727a046cSLakshmi Yadlapati             }
715f5c9f8bdSJason M. Bills         }
716b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
717f5c9f8bdSJason M. Bills         {
718727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
719f5c9f8bdSJason M. Bills         }
720b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
721f5c9f8bdSJason M. Bills         {
722727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
723f5c9f8bdSJason M. Bills         }
724b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
725b9d36b47SEd Tanous         {
726727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
727b9d36b47SEd Tanous         }
728002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
729f5c9f8bdSJason M. Bills         {
730727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
731b9d36b47SEd Tanous         }
732f5c9f8bdSJason M. Bills     }
733727a046cSLakshmi Yadlapati }
734727a046cSLakshmi Yadlapati 
735727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
736727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
737e14742caSEd Tanous                                             uint64_t pcieFunctionId)
738727a046cSLakshmi Yadlapati {
739727a046cSLakshmi Yadlapati     resp.addHeader(
740727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
741727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
742727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
743ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
744ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
745768a143dSLakshmi Yadlapati         pcieDeviceId, std::to_string(pcieFunctionId));
746727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
747e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
748e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
749ef4c65b7SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
750ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
751727a046cSLakshmi Yadlapati }
752727a046cSLakshmi Yadlapati 
753727a046cSLakshmi Yadlapati inline void
754727a046cSLakshmi Yadlapati     handlePCIeFunctionGet(App& app, const crow::Request& req,
755ac106bf6SEd Tanous                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7567f3e84a1SEd Tanous                           const std::string& systemName,
757727a046cSLakshmi Yadlapati                           const std::string& pcieDeviceId,
758e14742caSEd Tanous                           const std::string& pcieFunctionIdStr)
759727a046cSLakshmi Yadlapati {
760ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
761727a046cSLakshmi Yadlapati     {
762727a046cSLakshmi Yadlapati         return;
763727a046cSLakshmi Yadlapati     }
7647f3e84a1SEd Tanous     if constexpr (bmcwebEnableMultiHost)
7657f3e84a1SEd Tanous     {
7667f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
7677f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
7687f3e84a1SEd Tanous                                    systemName);
7697f3e84a1SEd Tanous         return;
7707f3e84a1SEd Tanous     }
7717f3e84a1SEd Tanous     if (systemName != "system")
7727f3e84a1SEd Tanous     {
7737f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
7747f3e84a1SEd Tanous                                    systemName);
7757f3e84a1SEd Tanous         return;
7767f3e84a1SEd Tanous     }
7777f3e84a1SEd Tanous 
778e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
779e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
780e14742caSEd Tanous         &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId);
781e14742caSEd Tanous     if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end())
782e14742caSEd Tanous     {
783ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
784e14742caSEd Tanous                                    pcieFunctionIdStr);
785e14742caSEd Tanous         return;
786e14742caSEd Tanous     }
787727a046cSLakshmi Yadlapati 
788ac106bf6SEd Tanous     getValidPCIeDevicePath(pcieDeviceId, asyncResp,
789ac106bf6SEd Tanous                            [asyncResp, pcieDeviceId,
790ac106bf6SEd Tanous                             pcieFunctionId](const std::string& pcieDevicePath,
791727a046cSLakshmi Yadlapati                                             const std::string& service) {
792727a046cSLakshmi Yadlapati         getPCIeDeviceProperties(
793ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
794ac106bf6SEd Tanous             [asyncResp, pcieDeviceId, pcieFunctionId](
795727a046cSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
796ac106bf6SEd Tanous             addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId,
797727a046cSLakshmi Yadlapati                                             pcieFunctionId);
798ac106bf6SEd Tanous             addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
799727a046cSLakshmi Yadlapati                                       pcieDevProperties);
8007e860f15SJohn Edward Broadbent             });
801727a046cSLakshmi Yadlapati     });
802727a046cSLakshmi Yadlapati }
803727a046cSLakshmi Yadlapati 
804727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
805727a046cSLakshmi Yadlapati {
806727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
8077f3e84a1SEd Tanous         app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
808727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
809727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
810727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
811f5c9f8bdSJason M. Bills }
812f5c9f8bdSJason M. Bills 
813f5c9f8bdSJason M. Bills } // namespace redfish
814