xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision e164f1b66eb2cde5b885df342c9a5bb4e0c2beeb)
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"};
38f5c9f8bdSJason M. Bills 
39543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath(
40543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
41ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
42543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
43543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
44543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
45543f9a75SLakshmi Yadlapati 
46543f9a75SLakshmi Yadlapati {
47543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
48543f9a75SLakshmi Yadlapati     {
49543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
50543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
51543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
52543f9a75SLakshmi Yadlapati         {
53543f9a75SLakshmi Yadlapati             continue;
54543f9a75SLakshmi Yadlapati         }
55543f9a75SLakshmi Yadlapati 
56543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
57543f9a75SLakshmi Yadlapati             pcieDevicePath, {},
58ac106bf6SEd Tanous             [pcieDevicePath, asyncResp,
59543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
60543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
61543f9a75SLakshmi Yadlapati             if (ec || object.empty())
62543f9a75SLakshmi Yadlapati             {
63543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
64ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
65543f9a75SLakshmi Yadlapati                 return;
66543f9a75SLakshmi Yadlapati             }
67543f9a75SLakshmi Yadlapati             callback(pcieDevicePath, object.begin()->first);
68543f9a75SLakshmi Yadlapati             });
69543f9a75SLakshmi Yadlapati         return;
70543f9a75SLakshmi Yadlapati     }
71543f9a75SLakshmi Yadlapati 
72543f9a75SLakshmi Yadlapati     BMCWEB_LOG_WARNING << "PCIe Device not found";
73ac106bf6SEd Tanous     messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
74543f9a75SLakshmi Yadlapati }
75543f9a75SLakshmi Yadlapati 
76543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath(
77543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
78ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
79543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
80543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
81543f9a75SLakshmi Yadlapati {
82543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
8394c3a10bSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
84ac106bf6SEd Tanous         [pcieDeviceId, asyncResp,
85543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
86543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
87543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
88543f9a75SLakshmi Yadlapati         if (ec)
89543f9a75SLakshmi Yadlapati         {
90543f9a75SLakshmi Yadlapati             BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
91ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
92543f9a75SLakshmi Yadlapati             return;
93543f9a75SLakshmi Yadlapati         }
94ac106bf6SEd Tanous         handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
95ac106bf6SEd Tanous                              callback);
96543f9a75SLakshmi Yadlapati         return;
97543f9a75SLakshmi Yadlapati         });
98543f9a75SLakshmi Yadlapati }
99543f9a75SLakshmi Yadlapati 
100b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet(
101b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
102ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
103b38fa2abSLakshmi Yadlapati     const std::string& systemName)
104b38fa2abSLakshmi Yadlapati {
105ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
106b38fa2abSLakshmi Yadlapati     {
107b38fa2abSLakshmi Yadlapati         return;
108b38fa2abSLakshmi Yadlapati     }
109b38fa2abSLakshmi Yadlapati     if (systemName != "system")
110b38fa2abSLakshmi Yadlapati     {
111ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
112ac106bf6SEd Tanous                                    systemName);
113b38fa2abSLakshmi Yadlapati         return;
114b38fa2abSLakshmi Yadlapati     }
115543f9a75SLakshmi Yadlapati 
116ac106bf6SEd Tanous     asyncResp->res.addHeader(boost::beast::http::field::link,
117b38fa2abSLakshmi Yadlapati                              "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
118b38fa2abSLakshmi Yadlapati                              "PCIeDeviceCollection.json>; rel=describedby");
119ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
120b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
121ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
122b38fa2abSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices";
123ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
124ac106bf6SEd Tanous     asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
125ac106bf6SEd Tanous     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
126ac106bf6SEd Tanous     asyncResp->res.jsonValue["Members@odata.count"] = 0;
127b38fa2abSLakshmi Yadlapati 
128b38fa2abSLakshmi Yadlapati     collection_util::getCollectionMembers(
129ac106bf6SEd Tanous         asyncResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
13094c3a10bSLakshmi Yadlapati         pcieDeviceInterface);
131b38fa2abSLakshmi Yadlapati }
132b38fa2abSLakshmi Yadlapati 
1337e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
134adbe192aSJason M. Bills {
135adbe192aSJason M. Bills     /**
136adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
137adbe192aSJason M. Bills      */
13822d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
139ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1407e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
141b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
142f5c9f8bdSJason M. Bills }
143f5c9f8bdSJason M. Bills 
144ac106bf6SEd Tanous inline void
145*e164f1b6SLakshmi Yadlapati     getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
146*e164f1b6SLakshmi Yadlapati                         const std::string& pcieDevicePath,
147*e164f1b6SLakshmi Yadlapati                         const std::string& service)
148*e164f1b6SLakshmi Yadlapati {
149*e164f1b6SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
150*e164f1b6SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
151*e164f1b6SLakshmi Yadlapati         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
152*e164f1b6SLakshmi Yadlapati         [asyncResp](const boost::system::error_code& ec, const bool value) {
153*e164f1b6SLakshmi Yadlapati         if (ec)
154*e164f1b6SLakshmi Yadlapati         {
155*e164f1b6SLakshmi Yadlapati             if (ec.value() != EBADR)
156*e164f1b6SLakshmi Yadlapati             {
157*e164f1b6SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Health "
158*e164f1b6SLakshmi Yadlapati                                  << ec.value();
159*e164f1b6SLakshmi Yadlapati                 messages::internalError(asyncResp->res);
160*e164f1b6SLakshmi Yadlapati             }
161*e164f1b6SLakshmi Yadlapati             return;
162*e164f1b6SLakshmi Yadlapati         }
163*e164f1b6SLakshmi Yadlapati 
164*e164f1b6SLakshmi Yadlapati         if (!value)
165*e164f1b6SLakshmi Yadlapati         {
166*e164f1b6SLakshmi Yadlapati             asyncResp->res.jsonValue["Status"]["Health"] = "Critical";
167*e164f1b6SLakshmi Yadlapati         }
168*e164f1b6SLakshmi Yadlapati         });
169*e164f1b6SLakshmi Yadlapati }
170*e164f1b6SLakshmi Yadlapati 
171*e164f1b6SLakshmi Yadlapati inline void
172ac106bf6SEd Tanous     getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
173c6bb3285SLakshmi Yadlapati                        const std::string& pcieDevicePath,
174c6bb3285SLakshmi Yadlapati                        const std::string& service)
175c6bb3285SLakshmi Yadlapati {
176c6bb3285SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
177c6bb3285SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
178c6bb3285SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item", "Present",
179ac106bf6SEd Tanous         [asyncResp](const boost::system::error_code& ec, const bool value) {
180c6bb3285SLakshmi Yadlapati         if (ec)
181c6bb3285SLakshmi Yadlapati         {
182c6bb3285SLakshmi Yadlapati             if (ec.value() != EBADR)
183c6bb3285SLakshmi Yadlapati             {
184c6bb3285SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for State";
185ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
186c6bb3285SLakshmi Yadlapati             }
187c6bb3285SLakshmi Yadlapati             return;
188c6bb3285SLakshmi Yadlapati         }
189c6bb3285SLakshmi Yadlapati 
190c6bb3285SLakshmi Yadlapati         if (!value)
191c6bb3285SLakshmi Yadlapati         {
192ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "Absent";
193c6bb3285SLakshmi Yadlapati         }
194c6bb3285SLakshmi Yadlapati         });
195c6bb3285SLakshmi Yadlapati }
196c6bb3285SLakshmi Yadlapati 
197ac106bf6SEd Tanous inline void
198ac106bf6SEd Tanous     getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
199913e7732SSunnySrivastava1984                        const std::string& pcieDevicePath,
200913e7732SSunnySrivastava1984                        const std::string& service)
201913e7732SSunnySrivastava1984 {
202913e7732SSunnySrivastava1984     sdbusplus::asio::getAllProperties(
203913e7732SSunnySrivastava1984         *crow::connections::systemBus, service, pcieDevicePath,
204913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
205ac106bf6SEd Tanous         [pcieDevicePath, asyncResp{asyncResp}](
206ac106bf6SEd Tanous             const boost::system::error_code& ec,
207913e7732SSunnySrivastava1984             const dbus::utility::DBusPropertiesMap& assetList) {
208913e7732SSunnySrivastava1984         if (ec)
209913e7732SSunnySrivastava1984         {
210913e7732SSunnySrivastava1984             if (ec.value() != EBADR)
211913e7732SSunnySrivastava1984             {
212913e7732SSunnySrivastava1984                 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
213913e7732SSunnySrivastava1984                                  << ec.value();
214ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
215913e7732SSunnySrivastava1984             }
216913e7732SSunnySrivastava1984             return;
217913e7732SSunnySrivastava1984         }
218913e7732SSunnySrivastava1984 
219913e7732SSunnySrivastava1984         const std::string* manufacturer = nullptr;
220913e7732SSunnySrivastava1984         const std::string* model = nullptr;
221913e7732SSunnySrivastava1984         const std::string* partNumber = nullptr;
222913e7732SSunnySrivastava1984         const std::string* serialNumber = nullptr;
223913e7732SSunnySrivastava1984         const std::string* sparePartNumber = nullptr;
224913e7732SSunnySrivastava1984 
225913e7732SSunnySrivastava1984         const bool success = sdbusplus::unpackPropertiesNoThrow(
226913e7732SSunnySrivastava1984             dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
227913e7732SSunnySrivastava1984             manufacturer, "Model", model, "PartNumber", partNumber,
228913e7732SSunnySrivastava1984             "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
229913e7732SSunnySrivastava1984 
230913e7732SSunnySrivastava1984         if (!success)
231913e7732SSunnySrivastava1984         {
232ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
233913e7732SSunnySrivastava1984             return;
234913e7732SSunnySrivastava1984         }
235913e7732SSunnySrivastava1984 
236913e7732SSunnySrivastava1984         if (manufacturer != nullptr)
237913e7732SSunnySrivastava1984         {
238ac106bf6SEd Tanous             asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
239913e7732SSunnySrivastava1984         }
240913e7732SSunnySrivastava1984         if (model != nullptr)
241913e7732SSunnySrivastava1984         {
242ac106bf6SEd Tanous             asyncResp->res.jsonValue["Model"] = *model;
243913e7732SSunnySrivastava1984         }
244913e7732SSunnySrivastava1984 
245913e7732SSunnySrivastava1984         if (partNumber != nullptr)
246913e7732SSunnySrivastava1984         {
247ac106bf6SEd Tanous             asyncResp->res.jsonValue["PartNumber"] = *partNumber;
248913e7732SSunnySrivastava1984         }
249913e7732SSunnySrivastava1984 
250913e7732SSunnySrivastava1984         if (serialNumber != nullptr)
251913e7732SSunnySrivastava1984         {
252ac106bf6SEd Tanous             asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
253913e7732SSunnySrivastava1984         }
254913e7732SSunnySrivastava1984 
255913e7732SSunnySrivastava1984         if (sparePartNumber != nullptr && !sparePartNumber->empty())
256913e7732SSunnySrivastava1984         {
257ac106bf6SEd Tanous             asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
258913e7732SSunnySrivastava1984         }
259913e7732SSunnySrivastava1984         });
260913e7732SSunnySrivastava1984 }
261913e7732SSunnySrivastava1984 
262543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
26335ad613dSLakshmi Yadlapati     crow::Response& resp, const std::string& pcieDeviceId,
264543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
265f5c9f8bdSJason M. Bills {
266d1bde9e5SKrzysztof Grobelny     const std::string* deviceType = nullptr;
267d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
268543f9a75SLakshmi Yadlapati     const int64_t* lanesInUse = nullptr;
269d1bde9e5SKrzysztof Grobelny 
270d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
271543f9a75SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
272543f9a75SLakshmi Yadlapati         deviceType, "GenerationInUse", generationInUse, "LanesInUse",
273bad2c4a9SLakshmi Yadlapati         lanesInUse);
274d1bde9e5SKrzysztof Grobelny 
275d1bde9e5SKrzysztof Grobelny     if (!success)
276d1bde9e5SKrzysztof Grobelny     {
277543f9a75SLakshmi Yadlapati         messages::internalError(resp);
278d1bde9e5SKrzysztof Grobelny         return;
279d1bde9e5SKrzysztof Grobelny     }
280d1bde9e5SKrzysztof Grobelny 
281543f9a75SLakshmi Yadlapati     if (deviceType != nullptr && !deviceType->empty())
282703f6741SMyung Bae     {
283543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
284703f6741SMyung Bae     }
285703f6741SMyung Bae 
286d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
287d1bde9e5SKrzysztof Grobelny     {
2880ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
289c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
290543f9a75SLakshmi Yadlapati 
291d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
292d1bde9e5SKrzysztof Grobelny         {
293543f9a75SLakshmi Yadlapati             messages::internalError(resp);
294d1bde9e5SKrzysztof Grobelny             return;
295d1bde9e5SKrzysztof Grobelny         }
2960ec8b83dSEd Tanous         if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
297d1bde9e5SKrzysztof Grobelny         {
298543f9a75SLakshmi Yadlapati             resp.jsonValue["PCIeInterface"]["PCIeType"] =
299d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
300d1bde9e5SKrzysztof Grobelny         }
301a9f68bb5STony Lee     }
302d1bde9e5SKrzysztof Grobelny 
303543f9a75SLakshmi Yadlapati     // The default value of LanesInUse is 0, and the field will be
304543f9a75SLakshmi Yadlapati     // left as off if it is a default value.
305543f9a75SLakshmi Yadlapati     if (lanesInUse != nullptr && *lanesInUse != 0)
306543f9a75SLakshmi Yadlapati     {
307543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
308543f9a75SLakshmi Yadlapati     }
309543f9a75SLakshmi Yadlapati 
310ef4c65b7SEd Tanous     resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format(
311ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
312ef4c65b7SEd Tanous         pcieDeviceId);
313d1bde9e5SKrzysztof Grobelny }
314d1bde9e5SKrzysztof Grobelny 
315543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
316ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
317543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
318543f9a75SLakshmi Yadlapati     const std::function<void(
319543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
320d1bde9e5SKrzysztof Grobelny {
321543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
322543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
323543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
324ac106bf6SEd Tanous         [asyncResp,
325543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
326543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
327543f9a75SLakshmi Yadlapati         if (ec)
328543f9a75SLakshmi Yadlapati         {
329543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
330543f9a75SLakshmi Yadlapati             {
331543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
332ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
333543f9a75SLakshmi Yadlapati             }
334543f9a75SLakshmi Yadlapati             return;
335543f9a75SLakshmi Yadlapati         }
336543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
337543f9a75SLakshmi Yadlapati         });
338d1bde9e5SKrzysztof Grobelny }
339d1bde9e5SKrzysztof Grobelny 
340543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
341ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
342543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
343543f9a75SLakshmi Yadlapati {
344ac106bf6SEd Tanous     asyncResp->res.addHeader(
345543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
346543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
347ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
348ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
349ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
350ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
351ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
352ac106bf6SEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
353*e164f1b6SLakshmi Yadlapati     asyncResp->res.jsonValue["Status"]["Health"] = "OK";
354543f9a75SLakshmi Yadlapati }
3551476687dSEd Tanous 
356ac106bf6SEd Tanous inline void
357ac106bf6SEd Tanous     handlePCIeDeviceGet(App& app, const crow::Request& req,
358ac106bf6SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
359543f9a75SLakshmi Yadlapati                         const std::string& systemName,
360543f9a75SLakshmi Yadlapati                         const std::string& pcieDeviceId)
361543f9a75SLakshmi Yadlapati {
362ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
363543f9a75SLakshmi Yadlapati     {
364543f9a75SLakshmi Yadlapati         return;
365543f9a75SLakshmi Yadlapati     }
366543f9a75SLakshmi Yadlapati     if (systemName != "system")
367543f9a75SLakshmi Yadlapati     {
368ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
369ac106bf6SEd Tanous                                    systemName);
370543f9a75SLakshmi Yadlapati         return;
371543f9a75SLakshmi Yadlapati     }
372543f9a75SLakshmi Yadlapati 
373543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
374ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
375ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
376543f9a75SLakshmi Yadlapati                                   const std::string& service) {
377ac106bf6SEd Tanous         addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
378ac106bf6SEd Tanous         getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
379ac106bf6SEd Tanous         getPCIeDeviceState(asyncResp, pcieDevicePath, service);
380*e164f1b6SLakshmi Yadlapati         getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
381543f9a75SLakshmi Yadlapati         getPCIeDeviceProperties(
382ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
383ac106bf6SEd Tanous             [asyncResp, pcieDeviceId](
38435ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
385ac106bf6SEd Tanous             addPCIeDeviceProperties(asyncResp->res, pcieDeviceId,
38635ad613dSLakshmi Yadlapati                                     pcieDevProperties);
3877e860f15SJohn Edward Broadbent             });
388543f9a75SLakshmi Yadlapati         });
389543f9a75SLakshmi Yadlapati }
390543f9a75SLakshmi Yadlapati 
391543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
392543f9a75SLakshmi Yadlapati {
393543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
394543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
395543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
396543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
397dede6a98SJason M. Bills }
398dede6a98SJason M. Bills 
39935ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
40035ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
40135ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
40235ad613dSLakshmi Yadlapati {
40335ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
40435ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
40535ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
40635ad613dSLakshmi Yadlapati 
40735ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
40835ad613dSLakshmi Yadlapati     {
40935ad613dSLakshmi Yadlapati         // Check if this function exists by
41035ad613dSLakshmi Yadlapati         // looking for a device ID
41189492a15SPatrick Williams         std::string devIDProperty = "Function" + std::to_string(functionNum) +
41289492a15SPatrick Williams                                     "DeviceId";
41335ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
41435ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
41535ad613dSLakshmi Yadlapati         {
41635ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
41735ad613dSLakshmi Yadlapati             {
41835ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
41935ad613dSLakshmi Yadlapati                 break;
42035ad613dSLakshmi Yadlapati             }
42135ad613dSLakshmi Yadlapati         }
42235ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
42335ad613dSLakshmi Yadlapati         {
42435ad613dSLakshmi Yadlapati             continue;
42535ad613dSLakshmi Yadlapati         }
42635ad613dSLakshmi Yadlapati 
42735ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
428ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
429ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
430ef4c65b7SEd Tanous             pcieDeviceId, std::to_string(functionNum));
431b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
43235ad613dSLakshmi Yadlapati     }
43335ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
43435ad613dSLakshmi Yadlapati }
43535ad613dSLakshmi Yadlapati 
43635ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
43735ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
438ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
43935ad613dSLakshmi Yadlapati     const std::string& pcieDeviceId)
44035ad613dSLakshmi Yadlapati {
441ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
44235ad613dSLakshmi Yadlapati     {
44335ad613dSLakshmi Yadlapati         return;
44435ad613dSLakshmi Yadlapati     }
44535ad613dSLakshmi Yadlapati 
44635ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
447ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
448ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
44935ad613dSLakshmi Yadlapati                                   const std::string& service) {
450ac106bf6SEd Tanous         asyncResp->res.addHeader(
45135ad613dSLakshmi Yadlapati             boost::beast::http::field::link,
45235ad613dSLakshmi Yadlapati             "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
453ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
45435ad613dSLakshmi Yadlapati             "#PCIeFunctionCollection.PCIeFunctionCollection";
455ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
456ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
457ef4c65b7SEd Tanous             pcieDeviceId);
458ac106bf6SEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
459ac106bf6SEd Tanous         asyncResp->res.jsonValue["Description"] =
46035ad613dSLakshmi Yadlapati             "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
46135ad613dSLakshmi Yadlapati         getPCIeDeviceProperties(
462ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
463ac106bf6SEd Tanous             [asyncResp, pcieDeviceId](
46435ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
465ac106bf6SEd Tanous             addPCIeFunctionList(asyncResp->res, pcieDeviceId,
466ac106bf6SEd Tanous                                 pcieDevProperties);
46735ad613dSLakshmi Yadlapati             });
46835ad613dSLakshmi Yadlapati         });
46935ad613dSLakshmi Yadlapati }
47035ad613dSLakshmi Yadlapati 
4717e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
4727e860f15SJohn Edward Broadbent {
473dede6a98SJason M. Bills     /**
474dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
475dede6a98SJason M. Bills      */
4767e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
4777e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
478ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
479002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
48035ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
4817e860f15SJohn Edward Broadbent }
4827e860f15SJohn Edward Broadbent 
483727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
484d5e74b80SMyung Bae     uint64_t pcieFunctionId,
485727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
4867e860f15SJohn Edward Broadbent {
487d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
488b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
489b9d36b47SEd Tanous 
490b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
491b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
492b9d36b47SEd Tanous     {
493b9d36b47SEd Tanous         if (property.first == devIDProperty)
494b9d36b47SEd Tanous         {
495002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
496727a046cSLakshmi Yadlapati             break;
497b9d36b47SEd Tanous         }
498b9d36b47SEd Tanous     }
499727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
500727a046cSLakshmi Yadlapati }
501727a046cSLakshmi Yadlapati 
502727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
503e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
504727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
505f5c9f8bdSJason M. Bills {
506e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
507b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
508f5c9f8bdSJason M. Bills     {
509b9d36b47SEd Tanous         const std::string* strProperty =
510b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
511727a046cSLakshmi Yadlapati 
512b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
513f5c9f8bdSJason M. Bills         {
514727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
515f5c9f8bdSJason M. Bills         }
516b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
517f5c9f8bdSJason M. Bills         {
518727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
519f5c9f8bdSJason M. Bills         }
520727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
521727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
522727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
523b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
524f5c9f8bdSJason M. Bills         {
525727a046cSLakshmi Yadlapati             if (!strProperty->empty())
526727a046cSLakshmi Yadlapati             {
527727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
528727a046cSLakshmi Yadlapati             }
529f5c9f8bdSJason M. Bills         }
530b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
531f5c9f8bdSJason M. Bills         {
532727a046cSLakshmi Yadlapati             if (!strProperty->empty())
533727a046cSLakshmi Yadlapati             {
534727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
535727a046cSLakshmi Yadlapati             }
536f5c9f8bdSJason M. Bills         }
537b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
538f5c9f8bdSJason M. Bills         {
539727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
540f5c9f8bdSJason M. Bills         }
541b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
542f5c9f8bdSJason M. Bills         {
543727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
544f5c9f8bdSJason M. Bills         }
545b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
546b9d36b47SEd Tanous         {
547727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
548b9d36b47SEd Tanous         }
549002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
550f5c9f8bdSJason M. Bills         {
551727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
552b9d36b47SEd Tanous         }
553f5c9f8bdSJason M. Bills     }
554727a046cSLakshmi Yadlapati }
555727a046cSLakshmi Yadlapati 
556727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
557727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
558e14742caSEd Tanous                                             uint64_t pcieFunctionId)
559727a046cSLakshmi Yadlapati {
560727a046cSLakshmi Yadlapati     resp.addHeader(
561727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
562727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
563727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
564ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
565ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
566ef4c65b7SEd Tanous         pcieDeviceId, pcieFunctionId);
567727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
568e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
569e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
570ef4c65b7SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
571ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
572727a046cSLakshmi Yadlapati }
573727a046cSLakshmi Yadlapati 
574727a046cSLakshmi Yadlapati inline void
575727a046cSLakshmi Yadlapati     handlePCIeFunctionGet(App& app, const crow::Request& req,
576ac106bf6SEd Tanous                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
577727a046cSLakshmi Yadlapati                           const std::string& pcieDeviceId,
578e14742caSEd Tanous                           const std::string& pcieFunctionIdStr)
579727a046cSLakshmi Yadlapati {
580ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
581727a046cSLakshmi Yadlapati     {
582727a046cSLakshmi Yadlapati         return;
583727a046cSLakshmi Yadlapati     }
584e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
585e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
586e14742caSEd Tanous         &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId);
587e14742caSEd Tanous     if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end())
588e14742caSEd Tanous     {
589ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
590e14742caSEd Tanous                                    pcieFunctionIdStr);
591e14742caSEd Tanous         return;
592e14742caSEd Tanous     }
593727a046cSLakshmi Yadlapati 
594ac106bf6SEd Tanous     getValidPCIeDevicePath(pcieDeviceId, asyncResp,
595ac106bf6SEd Tanous                            [asyncResp, pcieDeviceId,
596ac106bf6SEd Tanous                             pcieFunctionId](const std::string& pcieDevicePath,
597727a046cSLakshmi Yadlapati                                             const std::string& service) {
598727a046cSLakshmi Yadlapati         getPCIeDeviceProperties(
599ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
600ac106bf6SEd Tanous             [asyncResp, pcieDeviceId, pcieFunctionId](
601727a046cSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
602ac106bf6SEd Tanous             addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId,
603727a046cSLakshmi Yadlapati                                             pcieFunctionId);
604ac106bf6SEd Tanous             addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
605727a046cSLakshmi Yadlapati                                       pcieDevProperties);
6067e860f15SJohn Edward Broadbent             });
607727a046cSLakshmi Yadlapati     });
608727a046cSLakshmi Yadlapati }
609727a046cSLakshmi Yadlapati 
610727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
611727a046cSLakshmi Yadlapati {
612727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
613727a046cSLakshmi Yadlapati         app,
614727a046cSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
615727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
616727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
617727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
618f5c9f8bdSJason M. Bills }
619f5c9f8bdSJason M. Bills 
620f5c9f8bdSJason M. Bills } // namespace redfish
621