xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 253f11b84347de6bff7c6b624bef270fefae5f5a)
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             {
6562598e31SEd Tanous                 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 
7462598e31SEd Tanous     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         {
9262598e31SEd Tanous             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     }
11125b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
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     }
118*253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
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";
130*253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = std::format(
131*253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME);
132ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
133ac106bf6SEd Tanous     asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
134b38fa2abSLakshmi Yadlapati 
13570c4d545SLakshmi Yadlapati     pcie_util::getPCIeDeviceList(asyncResp,
13670c4d545SLakshmi Yadlapati                                  nlohmann::json::json_pointer("/Members"));
137b38fa2abSLakshmi Yadlapati }
138b38fa2abSLakshmi Yadlapati 
1397e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
140adbe192aSJason M. Bills {
141adbe192aSJason M. Bills     /**
142adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
143adbe192aSJason M. Bills      */
14422d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
145ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1467e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
147b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
148f5c9f8bdSJason M. Bills }
149f5c9f8bdSJason M. Bills 
150a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties(
151a5409991SLakshmi Yadlapati     crow::Response& res, const boost::system::error_code& ec,
152a5409991SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieSlotProperties)
153a5409991SLakshmi Yadlapati {
154a5409991SLakshmi Yadlapati     if (ec)
155a5409991SLakshmi Yadlapati     {
15662598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}",
15762598e31SEd Tanous                          ec.value());
158a5409991SLakshmi Yadlapati         messages::internalError(res);
159a5409991SLakshmi Yadlapati         return;
160a5409991SLakshmi Yadlapati     }
161a5409991SLakshmi Yadlapati     std::string generation;
162a5409991SLakshmi Yadlapati     size_t lanes = 0;
163a5409991SLakshmi Yadlapati     std::string slotType;
164a5409991SLakshmi Yadlapati 
165a5409991SLakshmi Yadlapati     bool success = sdbusplus::unpackPropertiesNoThrow(
166a5409991SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation",
167a5409991SLakshmi Yadlapati         generation, "Lanes", lanes, "SlotType", slotType);
168a5409991SLakshmi Yadlapati 
169a5409991SLakshmi Yadlapati     if (!success)
170a5409991SLakshmi Yadlapati     {
171a5409991SLakshmi Yadlapati         messages::internalError(res);
172a5409991SLakshmi Yadlapati         return;
173a5409991SLakshmi Yadlapati     }
174a5409991SLakshmi Yadlapati 
175a5409991SLakshmi Yadlapati     std::optional<pcie_device::PCIeTypes> pcieType =
176a5409991SLakshmi Yadlapati         pcie_util::redfishPcieGenerationFromDbus(generation);
177a5409991SLakshmi Yadlapati     if (!pcieType)
178a5409991SLakshmi Yadlapati     {
17962598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation);
180a5409991SLakshmi Yadlapati     }
181a5409991SLakshmi Yadlapati     else
182a5409991SLakshmi Yadlapati     {
183a5409991SLakshmi Yadlapati         if (*pcieType == pcie_device::PCIeTypes::Invalid)
184a5409991SLakshmi Yadlapati         {
18562598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation);
186a5409991SLakshmi Yadlapati             messages::internalError(res);
187a5409991SLakshmi Yadlapati             return;
188a5409991SLakshmi Yadlapati         }
189a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["PCIeType"] = *pcieType;
190a5409991SLakshmi Yadlapati     }
191a5409991SLakshmi Yadlapati 
19282f80326SKonstantin Aladyshev     if (lanes != 0)
19382f80326SKonstantin Aladyshev     {
194a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["Lanes"] = lanes;
19582f80326SKonstantin Aladyshev     }
196a5409991SLakshmi Yadlapati 
197a5409991SLakshmi Yadlapati     std::optional<pcie_slots::SlotTypes> redfishSlotType =
198a5409991SLakshmi Yadlapati         pcie_util::dbusSlotTypeToRf(slotType);
199a5409991SLakshmi Yadlapati     if (!redfishSlotType)
200a5409991SLakshmi Yadlapati     {
20162598e31SEd Tanous         BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType);
202a5409991SLakshmi Yadlapati     }
203a5409991SLakshmi Yadlapati     else
204a5409991SLakshmi Yadlapati     {
205a5409991SLakshmi Yadlapati         if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
206a5409991SLakshmi Yadlapati         {
20762598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType);
208a5409991SLakshmi Yadlapati             messages::internalError(res);
209a5409991SLakshmi Yadlapati             return;
210a5409991SLakshmi Yadlapati         }
211a5409991SLakshmi Yadlapati         res.jsonValue["Slot"]["SlotType"] = *redfishSlotType;
212a5409991SLakshmi Yadlapati     }
213a5409991SLakshmi Yadlapati }
214a5409991SLakshmi Yadlapati 
215a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath(
216a5409991SLakshmi Yadlapati     const std::string& pcieDevicePath,
217a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
218a5409991SLakshmi Yadlapati     std::function<void(const std::string& pcieDeviceSlot)>&& callback)
219a5409991SLakshmi Yadlapati {
220a5409991SLakshmi Yadlapati     std::string associationPath = pcieDevicePath + "/contained_by";
221a5409991SLakshmi Yadlapati     dbus::utility::getAssociatedSubTreePaths(
222a5409991SLakshmi Yadlapati         associationPath, sdbusplus::message::object_path(inventoryPath), 0,
223a5409991SLakshmi Yadlapati         pcieSlotInterface,
2248cb2c024SEd Tanous         [callback = std::move(callback), asyncResp, pcieDevicePath](
225a5409991SLakshmi Yadlapati             const boost::system::error_code& ec,
226a5409991SLakshmi Yadlapati             const dbus::utility::MapperGetSubTreePathsResponse& endpoints) {
227a5409991SLakshmi Yadlapati         if (ec)
228a5409991SLakshmi Yadlapati         {
229a5409991SLakshmi Yadlapati             if (ec.value() == EBADR)
230a5409991SLakshmi Yadlapati             {
231a5409991SLakshmi Yadlapati                 // Missing association is not an error
232a5409991SLakshmi Yadlapati                 return;
233a5409991SLakshmi Yadlapati             }
23462598e31SEd Tanous             BMCWEB_LOG_ERROR(
23562598e31SEd Tanous                 "DBUS response error for getAssociatedSubTreePaths {}",
23662598e31SEd Tanous                 ec.value());
237a5409991SLakshmi Yadlapati             messages::internalError(asyncResp->res);
238a5409991SLakshmi Yadlapati             return;
239a5409991SLakshmi Yadlapati         }
240a5409991SLakshmi Yadlapati         if (endpoints.size() > 1)
241a5409991SLakshmi Yadlapati         {
24262598e31SEd Tanous             BMCWEB_LOG_ERROR(
24362598e31SEd Tanous                 "PCIeDevice is associated with more than one PCIeSlot: {}",
24462598e31SEd Tanous                 endpoints.size());
245a5409991SLakshmi Yadlapati             messages::internalError(asyncResp->res);
246a5409991SLakshmi Yadlapati             return;
247a5409991SLakshmi Yadlapati         }
248a5409991SLakshmi Yadlapati         if (endpoints.empty())
249a5409991SLakshmi Yadlapati         {
250a5409991SLakshmi Yadlapati             // If the device doesn't have an association, return without PCIe
251a5409991SLakshmi Yadlapati             // Slot properties
25262598e31SEd Tanous             BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot");
253a5409991SLakshmi Yadlapati             return;
254a5409991SLakshmi Yadlapati         }
255a5409991SLakshmi Yadlapati         callback(endpoints[0]);
256a5409991SLakshmi Yadlapati     });
257a5409991SLakshmi Yadlapati }
258a5409991SLakshmi Yadlapati 
259a5409991SLakshmi Yadlapati inline void
260a5409991SLakshmi Yadlapati     afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
261a5409991SLakshmi Yadlapati                        const std::string& pcieDeviceSlot,
262a5409991SLakshmi Yadlapati                        const boost::system::error_code& ec,
263a5409991SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object)
264a5409991SLakshmi Yadlapati {
265a5409991SLakshmi Yadlapati     if (ec || object.empty())
266a5409991SLakshmi Yadlapati     {
26762598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}",
26862598e31SEd Tanous                          ec.value());
269a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
270a5409991SLakshmi Yadlapati         return;
271a5409991SLakshmi Yadlapati     }
272a5409991SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
273a5409991SLakshmi Yadlapati         *crow::connections::systemBus, object.begin()->first, pcieDeviceSlot,
274a5409991SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeSlot",
275a5409991SLakshmi Yadlapati         [asyncResp](
276a5409991SLakshmi Yadlapati             const boost::system::error_code& ec2,
277a5409991SLakshmi Yadlapati             const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
278a5409991SLakshmi Yadlapati         addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
279a5409991SLakshmi Yadlapati     });
280a5409991SLakshmi Yadlapati }
281a5409991SLakshmi Yadlapati 
282a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath(
283a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
284a5409991SLakshmi Yadlapati     const std::string& pcieDeviceSlot)
285a5409991SLakshmi Yadlapati {
286a5409991SLakshmi Yadlapati     dbus::utility::getDbusObject(
287a5409991SLakshmi Yadlapati         pcieDeviceSlot, pcieSlotInterface,
288a5409991SLakshmi Yadlapati         [asyncResp,
289a5409991SLakshmi Yadlapati          pcieDeviceSlot](const boost::system::error_code& ec,
290a5409991SLakshmi Yadlapati                          const dbus::utility::MapperGetObject& object) {
291a5409991SLakshmi Yadlapati         afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
292a5409991SLakshmi Yadlapati     });
293a5409991SLakshmi Yadlapati }
294a5409991SLakshmi Yadlapati 
295ac106bf6SEd Tanous inline void
296e164f1b6SLakshmi Yadlapati     getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
297e164f1b6SLakshmi Yadlapati                         const std::string& pcieDevicePath,
298e164f1b6SLakshmi Yadlapati                         const std::string& service)
299e164f1b6SLakshmi Yadlapati {
300e164f1b6SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
301e164f1b6SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
302e164f1b6SLakshmi Yadlapati         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
303e164f1b6SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, const bool value) {
304e164f1b6SLakshmi Yadlapati         if (ec)
305e164f1b6SLakshmi Yadlapati         {
306e164f1b6SLakshmi Yadlapati             if (ec.value() != EBADR)
307e164f1b6SLakshmi Yadlapati             {
30862598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Health {}",
30962598e31SEd Tanous                                  ec.value());
310e164f1b6SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
311e164f1b6SLakshmi Yadlapati             }
312e164f1b6SLakshmi Yadlapati             return;
313e164f1b6SLakshmi Yadlapati         }
314e164f1b6SLakshmi Yadlapati 
315e164f1b6SLakshmi Yadlapati         if (!value)
316e164f1b6SLakshmi Yadlapati         {
317e164f1b6SLakshmi Yadlapati             asyncResp->res.jsonValue["Status"]["Health"] = "Critical";
318e164f1b6SLakshmi Yadlapati         }
319e164f1b6SLakshmi Yadlapati     });
320e164f1b6SLakshmi Yadlapati }
321e164f1b6SLakshmi Yadlapati 
322e164f1b6SLakshmi Yadlapati inline void
323ac106bf6SEd Tanous     getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
324c6bb3285SLakshmi Yadlapati                        const std::string& pcieDevicePath,
325c6bb3285SLakshmi Yadlapati                        const std::string& service)
326c6bb3285SLakshmi Yadlapati {
327c6bb3285SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
328c6bb3285SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
329c6bb3285SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item", "Present",
330a5409991SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, bool value) {
331c6bb3285SLakshmi Yadlapati         if (ec)
332c6bb3285SLakshmi Yadlapati         {
333c6bb3285SLakshmi Yadlapati             if (ec.value() != EBADR)
334c6bb3285SLakshmi Yadlapati             {
33562598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for State");
336ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
337c6bb3285SLakshmi Yadlapati             }
338c6bb3285SLakshmi Yadlapati             return;
339c6bb3285SLakshmi Yadlapati         }
340c6bb3285SLakshmi Yadlapati 
341c6bb3285SLakshmi Yadlapati         if (!value)
342c6bb3285SLakshmi Yadlapati         {
343ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "Absent";
344c6bb3285SLakshmi Yadlapati         }
345c6bb3285SLakshmi Yadlapati     });
346c6bb3285SLakshmi Yadlapati }
347c6bb3285SLakshmi Yadlapati 
348ac106bf6SEd Tanous inline void
349ac106bf6SEd Tanous     getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
350913e7732SSunnySrivastava1984                        const std::string& pcieDevicePath,
351913e7732SSunnySrivastava1984                        const std::string& service)
352913e7732SSunnySrivastava1984 {
353913e7732SSunnySrivastava1984     sdbusplus::asio::getAllProperties(
354913e7732SSunnySrivastava1984         *crow::connections::systemBus, service, pcieDevicePath,
355913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
356ac106bf6SEd Tanous         [pcieDevicePath, asyncResp{asyncResp}](
357ac106bf6SEd Tanous             const boost::system::error_code& ec,
358913e7732SSunnySrivastava1984             const dbus::utility::DBusPropertiesMap& assetList) {
359913e7732SSunnySrivastava1984         if (ec)
360913e7732SSunnySrivastava1984         {
361913e7732SSunnySrivastava1984             if (ec.value() != EBADR)
362913e7732SSunnySrivastava1984             {
36362598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Properties{}",
36462598e31SEd Tanous                                  ec.value());
365ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
366913e7732SSunnySrivastava1984             }
367913e7732SSunnySrivastava1984             return;
368913e7732SSunnySrivastava1984         }
369913e7732SSunnySrivastava1984 
370913e7732SSunnySrivastava1984         const std::string* manufacturer = nullptr;
371913e7732SSunnySrivastava1984         const std::string* model = nullptr;
372913e7732SSunnySrivastava1984         const std::string* partNumber = nullptr;
373913e7732SSunnySrivastava1984         const std::string* serialNumber = nullptr;
374913e7732SSunnySrivastava1984         const std::string* sparePartNumber = nullptr;
375913e7732SSunnySrivastava1984 
376913e7732SSunnySrivastava1984         const bool success = sdbusplus::unpackPropertiesNoThrow(
377913e7732SSunnySrivastava1984             dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
378913e7732SSunnySrivastava1984             manufacturer, "Model", model, "PartNumber", partNumber,
379913e7732SSunnySrivastava1984             "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
380913e7732SSunnySrivastava1984 
381913e7732SSunnySrivastava1984         if (!success)
382913e7732SSunnySrivastava1984         {
383ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
384913e7732SSunnySrivastava1984             return;
385913e7732SSunnySrivastava1984         }
386913e7732SSunnySrivastava1984 
387913e7732SSunnySrivastava1984         if (manufacturer != nullptr)
388913e7732SSunnySrivastava1984         {
389ac106bf6SEd Tanous             asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
390913e7732SSunnySrivastava1984         }
391913e7732SSunnySrivastava1984         if (model != nullptr)
392913e7732SSunnySrivastava1984         {
393ac106bf6SEd Tanous             asyncResp->res.jsonValue["Model"] = *model;
394913e7732SSunnySrivastava1984         }
395913e7732SSunnySrivastava1984 
396913e7732SSunnySrivastava1984         if (partNumber != nullptr)
397913e7732SSunnySrivastava1984         {
398ac106bf6SEd Tanous             asyncResp->res.jsonValue["PartNumber"] = *partNumber;
399913e7732SSunnySrivastava1984         }
400913e7732SSunnySrivastava1984 
401913e7732SSunnySrivastava1984         if (serialNumber != nullptr)
402913e7732SSunnySrivastava1984         {
403ac106bf6SEd Tanous             asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
404913e7732SSunnySrivastava1984         }
405913e7732SSunnySrivastava1984 
406913e7732SSunnySrivastava1984         if (sparePartNumber != nullptr && !sparePartNumber->empty())
407913e7732SSunnySrivastava1984         {
408ac106bf6SEd Tanous             asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
409913e7732SSunnySrivastava1984         }
410913e7732SSunnySrivastava1984     });
411913e7732SSunnySrivastava1984 }
412913e7732SSunnySrivastava1984 
413543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
414a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
415a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId,
416543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
417f5c9f8bdSJason M. Bills {
418d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
419814bf20aSKonstantin Aladyshev     const std::string* generationSupported = nullptr;
4209bb0a7feSKonstantin Aladyshev     const size_t* lanesInUse = nullptr;
421814bf20aSKonstantin Aladyshev     const size_t* maxLanes = nullptr;
422d1bde9e5SKrzysztof Grobelny 
423d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
424609ba4c9SEd Tanous         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse",
425609ba4c9SEd Tanous         generationInUse, "GenerationSupported", generationSupported,
426609ba4c9SEd Tanous         "LanesInUse", lanesInUse, "MaxLanes", maxLanes);
427d1bde9e5SKrzysztof Grobelny 
428d1bde9e5SKrzysztof Grobelny     if (!success)
429d1bde9e5SKrzysztof Grobelny     {
430a5409991SLakshmi Yadlapati         messages::internalError(asyncResp->res);
431d1bde9e5SKrzysztof Grobelny         return;
432d1bde9e5SKrzysztof Grobelny     }
433d1bde9e5SKrzysztof Grobelny 
434d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
435d1bde9e5SKrzysztof Grobelny     {
4360ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
437c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
438543f9a75SLakshmi Yadlapati 
439d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
440d1bde9e5SKrzysztof Grobelny         {
44162598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
44262598e31SEd Tanous                                *generationInUse);
443cf3b484eSLakshmi Yadlapati         }
444cf3b484eSLakshmi Yadlapati         else
445cf3b484eSLakshmi Yadlapati         {
446cf3b484eSLakshmi Yadlapati             if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
447cf3b484eSLakshmi Yadlapati             {
44862598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
44962598e31SEd Tanous                                  *generationInUse);
450a5409991SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
451d1bde9e5SKrzysztof Grobelny                 return;
452d1bde9e5SKrzysztof Grobelny             }
453a5409991SLakshmi Yadlapati             asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
454d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
455d1bde9e5SKrzysztof Grobelny         }
456a9f68bb5STony Lee     }
457d1bde9e5SKrzysztof Grobelny 
458814bf20aSKonstantin Aladyshev     if (generationSupported != nullptr)
459814bf20aSKonstantin Aladyshev     {
460814bf20aSKonstantin Aladyshev         std::optional<pcie_device::PCIeTypes> redfishGenerationSupported =
461814bf20aSKonstantin Aladyshev             pcie_util::redfishPcieGenerationFromDbus(*generationSupported);
462814bf20aSKonstantin Aladyshev 
463814bf20aSKonstantin Aladyshev         if (!redfishGenerationSupported)
464814bf20aSKonstantin Aladyshev         {
46562598e31SEd Tanous             BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}",
46662598e31SEd Tanous                                *generationSupported);
467814bf20aSKonstantin Aladyshev         }
468814bf20aSKonstantin Aladyshev         else
469814bf20aSKonstantin Aladyshev         {
470814bf20aSKonstantin Aladyshev             if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid)
471814bf20aSKonstantin Aladyshev             {
47262598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}",
47362598e31SEd Tanous                                  *generationSupported);
474814bf20aSKonstantin Aladyshev                 messages::internalError(asyncResp->res);
475814bf20aSKonstantin Aladyshev                 return;
476814bf20aSKonstantin Aladyshev             }
477814bf20aSKonstantin Aladyshev             asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] =
478814bf20aSKonstantin Aladyshev                 *redfishGenerationSupported;
479814bf20aSKonstantin Aladyshev         }
480814bf20aSKonstantin Aladyshev     }
481814bf20aSKonstantin Aladyshev 
482543f9a75SLakshmi Yadlapati     // The default value of LanesInUse is 0, and the field will be
483543f9a75SLakshmi Yadlapati     // left as off if it is a default value.
484543f9a75SLakshmi Yadlapati     if (lanesInUse != nullptr && *lanesInUse != 0)
485543f9a75SLakshmi Yadlapati     {
486a5409991SLakshmi Yadlapati         asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
487543f9a75SLakshmi Yadlapati     }
488814bf20aSKonstantin Aladyshev     // The default value of MaxLanes is 0, and the field will be
489814bf20aSKonstantin Aladyshev     // left as off if it is a default value.
490814bf20aSKonstantin Aladyshev     if (maxLanes != nullptr && *maxLanes != 0)
491814bf20aSKonstantin Aladyshev     {
492814bf20aSKonstantin Aladyshev         asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes;
493814bf20aSKonstantin Aladyshev     }
494543f9a75SLakshmi Yadlapati 
495a5409991SLakshmi Yadlapati     asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
496a5409991SLakshmi Yadlapati         boost::urls::format(
497*253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
498*253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
499d1bde9e5SKrzysztof Grobelny }
500d1bde9e5SKrzysztof Grobelny 
501543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
502ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
503543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
504543f9a75SLakshmi Yadlapati     const std::function<void(
505543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
506d1bde9e5SKrzysztof Grobelny {
507543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
508543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
509543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
510ac106bf6SEd Tanous         [asyncResp,
511543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
512543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
513543f9a75SLakshmi Yadlapati         if (ec)
514543f9a75SLakshmi Yadlapati         {
515543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
516543f9a75SLakshmi Yadlapati             {
51762598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Properties");
518ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
519543f9a75SLakshmi Yadlapati             }
520543f9a75SLakshmi Yadlapati             return;
521543f9a75SLakshmi Yadlapati         }
522543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
523543f9a75SLakshmi Yadlapati     });
524d1bde9e5SKrzysztof Grobelny }
525d1bde9e5SKrzysztof Grobelny 
526543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
527ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
528543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
529543f9a75SLakshmi Yadlapati {
530ac106bf6SEd Tanous     asyncResp->res.addHeader(
531543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
532543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
533ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
534*253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
535*253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
536*253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
537ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
538ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
539ac106bf6SEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
540e164f1b6SLakshmi Yadlapati     asyncResp->res.jsonValue["Status"]["Health"] = "OK";
541543f9a75SLakshmi Yadlapati }
5421476687dSEd Tanous 
543a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath(
544a5409991SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
545a5409991SLakshmi Yadlapati     const std::string& pcieDeviceId, const std::string& pcieDevicePath,
546a5409991SLakshmi Yadlapati     const std::string& service)
547a5409991SLakshmi Yadlapati {
548a5409991SLakshmi Yadlapati     addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
549a5409991SLakshmi Yadlapati     getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
550a5409991SLakshmi Yadlapati     getPCIeDeviceState(asyncResp, pcieDevicePath, service);
551a5409991SLakshmi Yadlapati     getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
552a5409991SLakshmi Yadlapati     getPCIeDeviceProperties(
553a5409991SLakshmi Yadlapati         asyncResp, pcieDevicePath, service,
554a5409991SLakshmi Yadlapati         std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
555a5409991SLakshmi Yadlapati     getPCIeDeviceSlotPath(
556a5409991SLakshmi Yadlapati         pcieDevicePath, asyncResp,
557a5409991SLakshmi Yadlapati         std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
558a5409991SLakshmi Yadlapati }
559a5409991SLakshmi Yadlapati 
560ac106bf6SEd Tanous inline void
561ac106bf6SEd Tanous     handlePCIeDeviceGet(App& app, const crow::Request& req,
562ac106bf6SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
563543f9a75SLakshmi Yadlapati                         const std::string& systemName,
564543f9a75SLakshmi Yadlapati                         const std::string& pcieDeviceId)
565543f9a75SLakshmi Yadlapati {
566ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
567543f9a75SLakshmi Yadlapati     {
568543f9a75SLakshmi Yadlapati         return;
569543f9a75SLakshmi Yadlapati     }
57025b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5717f3e84a1SEd Tanous     {
5727f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
5737f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5747f3e84a1SEd Tanous                                    systemName);
5757f3e84a1SEd Tanous         return;
5767f3e84a1SEd Tanous     }
577*253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
578543f9a75SLakshmi Yadlapati     {
579ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
580ac106bf6SEd Tanous                                    systemName);
581543f9a75SLakshmi Yadlapati         return;
582543f9a75SLakshmi Yadlapati     }
583543f9a75SLakshmi Yadlapati 
584543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
585ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
586a5409991SLakshmi Yadlapati         std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
587543f9a75SLakshmi Yadlapati }
588543f9a75SLakshmi Yadlapati 
589543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
590543f9a75SLakshmi Yadlapati {
591543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
592543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
593543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
594543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
595dede6a98SJason M. Bills }
596dede6a98SJason M. Bills 
59735ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
59835ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
59935ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
60035ad613dSLakshmi Yadlapati {
60135ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
60235ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
60335ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
60435ad613dSLakshmi Yadlapati 
60535ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
60635ad613dSLakshmi Yadlapati     {
60735ad613dSLakshmi Yadlapati         // Check if this function exists by
60835ad613dSLakshmi Yadlapati         // looking for a device ID
60989492a15SPatrick Williams         std::string devIDProperty = "Function" + std::to_string(functionNum) +
61089492a15SPatrick Williams                                     "DeviceId";
61135ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
61235ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
61335ad613dSLakshmi Yadlapati         {
61435ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
61535ad613dSLakshmi Yadlapati             {
61635ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
61735ad613dSLakshmi Yadlapati                 break;
61835ad613dSLakshmi Yadlapati             }
61935ad613dSLakshmi Yadlapati         }
62035ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
62135ad613dSLakshmi Yadlapati         {
62235ad613dSLakshmi Yadlapati             continue;
62335ad613dSLakshmi Yadlapati         }
62435ad613dSLakshmi Yadlapati 
62535ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
626ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
627*253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
628*253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
629*253f11b8SEd Tanous             std::to_string(functionNum));
630b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
63135ad613dSLakshmi Yadlapati     }
63235ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
63335ad613dSLakshmi Yadlapati }
63435ad613dSLakshmi Yadlapati 
63535ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
63635ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
637ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6387f3e84a1SEd Tanous     const std::string& systemName, const std::string& pcieDeviceId)
63935ad613dSLakshmi Yadlapati {
640ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
64135ad613dSLakshmi Yadlapati     {
64235ad613dSLakshmi Yadlapati         return;
64335ad613dSLakshmi Yadlapati     }
64425b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
6457f3e84a1SEd Tanous     {
6467f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
6477f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6487f3e84a1SEd Tanous                                    systemName);
6497f3e84a1SEd Tanous         return;
6507f3e84a1SEd Tanous     }
65135ad613dSLakshmi Yadlapati 
65235ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
653ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
654ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
65535ad613dSLakshmi Yadlapati                                   const std::string& service) {
656ac106bf6SEd Tanous         asyncResp->res.addHeader(
65735ad613dSLakshmi Yadlapati             boost::beast::http::field::link,
65835ad613dSLakshmi Yadlapati             "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
659ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
66035ad613dSLakshmi Yadlapati             "#PCIeFunctionCollection.PCIeFunctionCollection";
661ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
662*253f11b8SEd Tanous             "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions",
663*253f11b8SEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
664ac106bf6SEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
665ac106bf6SEd Tanous         asyncResp->res.jsonValue["Description"] =
66635ad613dSLakshmi Yadlapati             "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
66735ad613dSLakshmi Yadlapati         getPCIeDeviceProperties(
668ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
669ac106bf6SEd Tanous             [asyncResp, pcieDeviceId](
67035ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
671ac106bf6SEd Tanous             addPCIeFunctionList(asyncResp->res, pcieDeviceId,
672ac106bf6SEd Tanous                                 pcieDevProperties);
67335ad613dSLakshmi Yadlapati         });
67435ad613dSLakshmi Yadlapati     });
67535ad613dSLakshmi Yadlapati }
67635ad613dSLakshmi Yadlapati 
6777e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
6787e860f15SJohn Edward Broadbent {
679dede6a98SJason M. Bills     /**
680dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
681dede6a98SJason M. Bills      */
6827e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
6837f3e84a1SEd Tanous                  "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
684ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
685002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
68635ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
6877e860f15SJohn Edward Broadbent }
6887e860f15SJohn Edward Broadbent 
689727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
690d5e74b80SMyung Bae     uint64_t pcieFunctionId,
691727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
6927e860f15SJohn Edward Broadbent {
693d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
694b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
695b9d36b47SEd Tanous 
696b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
697b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
698b9d36b47SEd Tanous     {
699b9d36b47SEd Tanous         if (property.first == devIDProperty)
700b9d36b47SEd Tanous         {
701002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
702727a046cSLakshmi Yadlapati             break;
703b9d36b47SEd Tanous         }
704b9d36b47SEd Tanous     }
705727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
706727a046cSLakshmi Yadlapati }
707727a046cSLakshmi Yadlapati 
708727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
709e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
710727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
711f5c9f8bdSJason M. Bills {
712e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
713b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
714f5c9f8bdSJason M. Bills     {
715b9d36b47SEd Tanous         const std::string* strProperty =
716b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
717dc8cfa66SEd Tanous         if (strProperty == nullptr)
718dc8cfa66SEd Tanous         {
719dc8cfa66SEd Tanous             BMCWEB_LOG_ERROR("Function wasn't a string?");
720dc8cfa66SEd Tanous             continue;
721dc8cfa66SEd Tanous         }
722b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
723f5c9f8bdSJason M. Bills         {
724727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
725f5c9f8bdSJason M. Bills         }
726b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
727f5c9f8bdSJason M. Bills         {
728727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
729f5c9f8bdSJason M. Bills         }
730727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
731727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
732727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
733b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
734f5c9f8bdSJason M. Bills         {
735727a046cSLakshmi Yadlapati             if (!strProperty->empty())
736727a046cSLakshmi Yadlapati             {
737727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
738727a046cSLakshmi Yadlapati             }
739f5c9f8bdSJason M. Bills         }
740b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
741f5c9f8bdSJason M. Bills         {
742727a046cSLakshmi Yadlapati             if (!strProperty->empty())
743727a046cSLakshmi Yadlapati             {
744727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
745727a046cSLakshmi Yadlapati             }
746f5c9f8bdSJason M. Bills         }
747b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
748f5c9f8bdSJason M. Bills         {
749727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
750f5c9f8bdSJason M. Bills         }
751b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
752f5c9f8bdSJason M. Bills         {
753727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
754f5c9f8bdSJason M. Bills         }
755b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
756b9d36b47SEd Tanous         {
757727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
758b9d36b47SEd Tanous         }
759002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
760f5c9f8bdSJason M. Bills         {
761727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
762b9d36b47SEd Tanous         }
763f5c9f8bdSJason M. Bills     }
764727a046cSLakshmi Yadlapati }
765727a046cSLakshmi Yadlapati 
766727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
767727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
768e14742caSEd Tanous                                             uint64_t pcieFunctionId)
769727a046cSLakshmi Yadlapati {
770727a046cSLakshmi Yadlapati     resp.addHeader(
771727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
772727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
773727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
774ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
775*253f11b8SEd Tanous         "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}",
776*253f11b8SEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId,
777*253f11b8SEd Tanous         std::to_string(pcieFunctionId));
778727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
779e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
780e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
781*253f11b8SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
782*253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}",
783*253f11b8SEd Tanous                             BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId);
784727a046cSLakshmi Yadlapati }
785727a046cSLakshmi Yadlapati 
786727a046cSLakshmi Yadlapati inline void
787727a046cSLakshmi Yadlapati     handlePCIeFunctionGet(App& app, const crow::Request& req,
788ac106bf6SEd Tanous                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7897f3e84a1SEd Tanous                           const std::string& systemName,
790727a046cSLakshmi Yadlapati                           const std::string& pcieDeviceId,
791e14742caSEd Tanous                           const std::string& pcieFunctionIdStr)
792727a046cSLakshmi Yadlapati {
793ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
794727a046cSLakshmi Yadlapati     {
795727a046cSLakshmi Yadlapati         return;
796727a046cSLakshmi Yadlapati     }
79725b54dbaSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
7987f3e84a1SEd Tanous     {
7997f3e84a1SEd Tanous         // Option currently returns no systems.  TBD
8007f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8017f3e84a1SEd Tanous                                    systemName);
8027f3e84a1SEd Tanous         return;
8037f3e84a1SEd Tanous     }
804*253f11b8SEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
8057f3e84a1SEd Tanous     {
8067f3e84a1SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
8077f3e84a1SEd Tanous                                    systemName);
8087f3e84a1SEd Tanous         return;
8097f3e84a1SEd Tanous     }
810dc8cfa66SEd Tanous     std::string_view pcieFunctionIdView = pcieFunctionIdStr;
8117f3e84a1SEd Tanous 
812e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
813e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
814dc8cfa66SEd Tanous         pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId);
815dc8cfa66SEd Tanous     if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end())
816e14742caSEd Tanous     {
817ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
818e14742caSEd Tanous                                    pcieFunctionIdStr);
819e14742caSEd Tanous         return;
820e14742caSEd Tanous     }
821727a046cSLakshmi Yadlapati 
822ac106bf6SEd Tanous     getValidPCIeDevicePath(pcieDeviceId, asyncResp,
823ac106bf6SEd Tanous                            [asyncResp, pcieDeviceId,
824ac106bf6SEd Tanous                             pcieFunctionId](const std::string& pcieDevicePath,
825727a046cSLakshmi Yadlapati                                             const std::string& service) {
826727a046cSLakshmi Yadlapati         getPCIeDeviceProperties(
827ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
828ac106bf6SEd Tanous             [asyncResp, pcieDeviceId, pcieFunctionId](
829727a046cSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
830ac106bf6SEd Tanous             addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId,
831727a046cSLakshmi Yadlapati                                             pcieFunctionId);
832ac106bf6SEd Tanous             addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
833727a046cSLakshmi Yadlapati                                       pcieDevProperties);
8347e860f15SJohn Edward Broadbent         });
835727a046cSLakshmi Yadlapati     });
836727a046cSLakshmi Yadlapati }
837727a046cSLakshmi Yadlapati 
838727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
839727a046cSLakshmi Yadlapati {
840727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
8417f3e84a1SEd Tanous         app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
842727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
843727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
844727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
845f5c9f8bdSJason M. Bills }
846f5c9f8bdSJason M. Bills 
847f5c9f8bdSJason M. Bills } // namespace redfish
848