xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 002d39b4a7a5ed7166e2acad84e0943c3def9492)
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 
197e860f15SJohn Edward Broadbent #include <app.hpp>
20f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp>
21168e20c1SEd Tanous #include <dbus_utility.hpp>
2245ca1b86SEd Tanous #include <query.hpp>
23ed398213SEd Tanous #include <registries/privilege_registry.hpp>
24f5c9f8bdSJason M. Bills 
25f5c9f8bdSJason M. Bills namespace redfish
26f5c9f8bdSJason M. Bills {
27f5c9f8bdSJason M. Bills 
28f5c9f8bdSJason M. Bills static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
29f5c9f8bdSJason M. Bills static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
30f5c9f8bdSJason M. Bills static constexpr char const* pcieDeviceInterface =
31f5c9f8bdSJason M. Bills     "xyz.openbmc_project.PCIe.Device";
32f5c9f8bdSJason M. Bills 
33b5a76932SEd Tanous static inline void
348d1b46d7Szhanghch05     getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
35adbe192aSJason M. Bills                       const std::string& name)
36f5c9f8bdSJason M. Bills {
37b9d36b47SEd Tanous     auto getPCIeMapCallback =
38b9d36b47SEd Tanous         [asyncResp, name](const boost::system::error_code ec,
39b9d36b47SEd Tanous                           const dbus::utility::MapperGetSubTreePathsResponse&
40b9d36b47SEd Tanous                               pcieDevicePaths) {
41f5c9f8bdSJason M. Bills         if (ec)
42f5c9f8bdSJason M. Bills         {
43a2730f01SAndrew Geissler             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
44f5c9f8bdSJason M. Bills                              << ec.message();
45a2730f01SAndrew Geissler             // Not an error, system just doesn't have PCIe info
46f5c9f8bdSJason M. Bills             return;
47f5c9f8bdSJason M. Bills         }
48adbe192aSJason M. Bills         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
49f5c9f8bdSJason M. Bills         pcieDeviceList = nlohmann::json::array();
50f5c9f8bdSJason M. Bills         for (const std::string& pcieDevicePath : pcieDevicePaths)
51f5c9f8bdSJason M. Bills         {
523174e4dfSEd Tanous             size_t devStart = pcieDevicePath.rfind('/');
53f5c9f8bdSJason M. Bills             if (devStart == std::string::npos)
54f5c9f8bdSJason M. Bills             {
55f5c9f8bdSJason M. Bills                 continue;
56f5c9f8bdSJason M. Bills             }
57f5c9f8bdSJason M. Bills 
58f5c9f8bdSJason M. Bills             std::string devName = pcieDevicePath.substr(devStart + 1);
59f5c9f8bdSJason M. Bills             if (devName.empty())
60f5c9f8bdSJason M. Bills             {
61f5c9f8bdSJason M. Bills                 continue;
62f5c9f8bdSJason M. Bills             }
631476687dSEd Tanous             nlohmann::json::object_t pcieDevice;
641476687dSEd Tanous             pcieDevice["@odata.id"] =
651476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + devName;
661476687dSEd Tanous             pcieDeviceList.push_back(std::move(pcieDevice));
67f5c9f8bdSJason M. Bills         }
68*002d39b4SEd Tanous         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
69f5c9f8bdSJason M. Bills     };
70f5c9f8bdSJason M. Bills     crow::connections::systemBus->async_method_call(
71f5c9f8bdSJason M. Bills         std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
72f5c9f8bdSJason M. Bills         "/xyz/openbmc_project/object_mapper",
73f5c9f8bdSJason M. Bills         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
74f5c9f8bdSJason M. Bills         std::string(pciePath) + "/", 1, std::array<std::string, 0>());
75f5c9f8bdSJason M. Bills }
76f5c9f8bdSJason M. Bills 
777e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
78adbe192aSJason M. Bills {
79adbe192aSJason M. Bills     /**
80adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
81adbe192aSJason M. Bills      */
827e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/")
83ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
847e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
8545ca1b86SEd Tanous             [&app](const crow::Request& req,
8645ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8745ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
88adbe192aSJason M. Bills         {
8945ca1b86SEd Tanous             return;
9045ca1b86SEd Tanous         }
911476687dSEd Tanous 
921476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
931476687dSEd Tanous             "#PCIeDeviceCollection.PCIeDeviceCollection";
941476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
951476687dSEd Tanous             "/redfish/v1/Systems/system/PCIeDevices";
961476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
97*002d39b4SEd Tanous         asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
981476687dSEd Tanous         asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
991476687dSEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = 0;
100adbe192aSJason M. Bills         getPCIeDeviceList(asyncResp, "Members");
1017e860f15SJohn Edward Broadbent         });
102f5c9f8bdSJason M. Bills }
103f5c9f8bdSJason M. Bills 
10462cd45afSSpencer Ku inline std::optional<std::string>
10562cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
10662cd45afSSpencer Ku {
10762cd45afSSpencer Ku     if (generationInUse ==
10862cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
10962cd45afSSpencer Ku     {
11062cd45afSSpencer Ku         return "Gen1";
11162cd45afSSpencer Ku     }
11262cd45afSSpencer Ku     if (generationInUse ==
11362cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
11462cd45afSSpencer Ku     {
11562cd45afSSpencer Ku         return "Gen2";
11662cd45afSSpencer Ku     }
11762cd45afSSpencer Ku     if (generationInUse ==
11862cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
11962cd45afSSpencer Ku     {
12062cd45afSSpencer Ku         return "Gen3";
12162cd45afSSpencer Ku     }
12262cd45afSSpencer Ku     if (generationInUse ==
12362cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
12462cd45afSSpencer Ku     {
12562cd45afSSpencer Ku         return "Gen4";
12662cd45afSSpencer Ku     }
12762cd45afSSpencer Ku     if (generationInUse ==
12862cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
12962cd45afSSpencer Ku     {
13062cd45afSSpencer Ku         return "Gen5";
13162cd45afSSpencer Ku     }
13262cd45afSSpencer Ku     if (generationInUse.empty() ||
13362cd45afSSpencer Ku         generationInUse ==
13462cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
13562cd45afSSpencer Ku     {
13662cd45afSSpencer Ku         return "";
13762cd45afSSpencer Ku     }
13862cd45afSSpencer Ku 
13962cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
14062cd45afSSpencer Ku     return std::nullopt;
14162cd45afSSpencer Ku }
14262cd45afSSpencer Ku 
1437e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDevice(App& app)
144f5c9f8bdSJason M. Bills {
1457e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
146ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDevice)
147*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
148*002d39b4SEd Tanous             [&app](const crow::Request& req,
1497e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15045ca1b86SEd Tanous                    const std::string& device) {
15145ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1527e860f15SJohn Edward Broadbent         {
15345ca1b86SEd Tanous             return;
15445ca1b86SEd Tanous         }
155168e20c1SEd Tanous         auto getPCIeDeviceCallback =
15645ca1b86SEd Tanous             [asyncResp, device](
15745ca1b86SEd Tanous                 const boost::system::error_code ec,
15845ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
159f5c9f8bdSJason M. Bills             if (ec)
160f5c9f8bdSJason M. Bills             {
161f5c9f8bdSJason M. Bills                 BMCWEB_LOG_DEBUG
162*002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
163*002d39b4SEd Tanous                     << ": " << ec.message();
16445ca1b86SEd Tanous                 if (ec.value() ==
16545ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
166f5c9f8bdSJason M. Bills                 {
167*002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
168*002d39b4SEd Tanous                                                device);
169f5c9f8bdSJason M. Bills                 }
170f5c9f8bdSJason M. Bills                 else
171f5c9f8bdSJason M. Bills                 {
172f5c9f8bdSJason M. Bills                     messages::internalError(asyncResp->res);
173f5c9f8bdSJason M. Bills                 }
174f5c9f8bdSJason M. Bills                 return;
175f5c9f8bdSJason M. Bills             }
176f5c9f8bdSJason M. Bills 
1771476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
1781476687dSEd Tanous                 "#PCIeDevice.v1_4_0.PCIeDevice";
1791476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
1801476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device;
1811476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Device";
1821476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = device;
1831476687dSEd Tanous 
1841476687dSEd Tanous             asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
18545ca1b86SEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device +
1861476687dSEd Tanous                 "/PCIeFunctions";
187b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
188f5c9f8bdSJason M. Bills             {
189b9d36b47SEd Tanous                 const std::string* propertyString =
190b9d36b47SEd Tanous                     std::get_if<std::string>(&property.second);
191b9d36b47SEd Tanous                 if (property.first == "Manufacturer")
192b9d36b47SEd Tanous                 {
193b9d36b47SEd Tanous                     if (propertyString == nullptr)
194b9d36b47SEd Tanous                     {
195b9d36b47SEd Tanous                         messages::internalError(asyncResp->res);
196b9d36b47SEd Tanous                         return;
197b9d36b47SEd Tanous                     }
198*002d39b4SEd Tanous                     asyncResp->res.jsonValue["Manufacturer"] = *propertyString;
199168e20c1SEd Tanous                 }
200b9d36b47SEd Tanous                 if (property.first == "DeviceType")
201168e20c1SEd Tanous                 {
202b9d36b47SEd Tanous                     if (propertyString == nullptr)
203b9d36b47SEd Tanous                     {
204b9d36b47SEd Tanous                         messages::internalError(asyncResp->res);
205b9d36b47SEd Tanous                         return;
206168e20c1SEd Tanous                     }
207*002d39b4SEd Tanous                     asyncResp->res.jsonValue["DeviceType"] = *propertyString;
208f5c9f8bdSJason M. Bills                 }
209b9d36b47SEd Tanous                 if (property.first == "GenerationInUse")
21062cd45afSSpencer Ku                 {
211b9d36b47SEd Tanous                     if (propertyString == nullptr)
212b9d36b47SEd Tanous                     {
213b9d36b47SEd Tanous                         messages::internalError(asyncResp->res);
214b9d36b47SEd Tanous                         return;
215b9d36b47SEd Tanous                     }
21662cd45afSSpencer Ku                     std::optional<std::string> generationInUse =
21745ca1b86SEd Tanous                         redfishPcieGenerationFromDbus(*propertyString);
21862cd45afSSpencer Ku                     if (!generationInUse)
21962cd45afSSpencer Ku                     {
22062cd45afSSpencer Ku                         messages::internalError(asyncResp->res);
22162cd45afSSpencer Ku                         return;
22262cd45afSSpencer Ku                     }
22326f6976fSEd Tanous                     if (generationInUse->empty())
22462cd45afSSpencer Ku                     {
22562cd45afSSpencer Ku                         // unknown, no need to handle
22662cd45afSSpencer Ku                         return;
22762cd45afSSpencer Ku                     }
228*002d39b4SEd Tanous                     asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
22962cd45afSSpencer Ku                         *generationInUse;
23062cd45afSSpencer Ku                 }
231b9d36b47SEd Tanous             }
232dede6a98SJason M. Bills         };
233dede6a98SJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
234dede6a98SJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
235dede6a98SJason M. Bills         crow::connections::systemBus->async_method_call(
236dede6a98SJason M. Bills             std::move(getPCIeDeviceCallback), pcieService, escapedPath,
237*002d39b4SEd Tanous             "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
2387e860f15SJohn Edward Broadbent         });
239dede6a98SJason M. Bills }
240dede6a98SJason M. Bills 
2417e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
2427e860f15SJohn Edward Broadbent {
243dede6a98SJason M. Bills     /**
244dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
245dede6a98SJason M. Bills      */
2467e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2477e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
248ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
249*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
250*002d39b4SEd Tanous             [&app](const crow::Request& req,
2517e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
25245ca1b86SEd Tanous                    const std::string& device) {
25345ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
254dede6a98SJason M. Bills         {
25545ca1b86SEd Tanous             return;
25645ca1b86SEd Tanous         }
2571476687dSEd Tanous 
2581476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
2591476687dSEd Tanous             "#PCIeFunctionCollection.PCIeFunctionCollection";
2601476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
2611476687dSEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/" + device +
2621476687dSEd Tanous             "/PCIeFunctions";
2631476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
2641476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
2651476687dSEd Tanous             "Collection of PCIe Functions for PCIe Device " + device;
266dede6a98SJason M. Bills 
267b9d36b47SEd Tanous         auto getPCIeDeviceCallback =
26845ca1b86SEd Tanous             [asyncResp, device](
26945ca1b86SEd Tanous                 const boost::system::error_code ec,
27045ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
2717e860f15SJohn Edward Broadbent             if (ec)
2727e860f15SJohn Edward Broadbent             {
2737e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG
274*002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
275*002d39b4SEd Tanous                     << ": " << ec.message();
27645ca1b86SEd Tanous                 if (ec.value() ==
27745ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
2787e860f15SJohn Edward Broadbent                 {
279*002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
280*002d39b4SEd Tanous                                                device);
2817e860f15SJohn Edward Broadbent                 }
2827e860f15SJohn Edward Broadbent                 else
2837e860f15SJohn Edward Broadbent                 {
2847e860f15SJohn Edward Broadbent                     messages::internalError(asyncResp->res);
2857e860f15SJohn Edward Broadbent                 }
2867e860f15SJohn Edward Broadbent                 return;
2877e860f15SJohn Edward Broadbent             }
2887e860f15SJohn Edward Broadbent 
2897e860f15SJohn Edward Broadbent             nlohmann::json& pcieFunctionList =
2907e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members"];
2917e860f15SJohn Edward Broadbent             pcieFunctionList = nlohmann::json::array();
2927e860f15SJohn Edward Broadbent             static constexpr const int maxPciFunctionNum = 8;
29345ca1b86SEd Tanous             for (int functionNum = 0; functionNum < maxPciFunctionNum;
29445ca1b86SEd Tanous                  functionNum++)
2957e860f15SJohn Edward Broadbent             {
296b9d36b47SEd Tanous                 // Check if this function exists by looking for a
297b9d36b47SEd Tanous                 // device ID
2987e860f15SJohn Edward Broadbent                 std::string devIDProperty =
299*002d39b4SEd Tanous                     "Function" + std::to_string(functionNum) + "DeviceId";
300b9d36b47SEd Tanous                 const std::string* property = nullptr;
301b9d36b47SEd Tanous                 for (const auto& propEntry : pcieDevProperties)
3027e860f15SJohn Edward Broadbent                 {
303b9d36b47SEd Tanous                     if (propEntry.first == devIDProperty)
304b9d36b47SEd Tanous                     {
305*002d39b4SEd Tanous                         property = std::get_if<std::string>(&propEntry.second);
306b9d36b47SEd Tanous                     }
307b9d36b47SEd Tanous                 }
308b9d36b47SEd Tanous                 if (property == nullptr || !property->empty())
309b9d36b47SEd Tanous                 {
310b9d36b47SEd Tanous                     return;
311b9d36b47SEd Tanous                 }
3121476687dSEd Tanous                 nlohmann::json::object_t pcieFunction;
3131476687dSEd Tanous                 pcieFunction["@odata.id"] =
3141476687dSEd Tanous                     "/redfish/v1/Systems/system/PCIeDevices/" + device +
3151476687dSEd Tanous                     "/PCIeFunctions/" + std::to_string(functionNum);
3161476687dSEd Tanous                 pcieFunctionList.push_back(std::move(pcieFunction));
3177e860f15SJohn Edward Broadbent             }
318a818d15aSJiaqing Zhao             asyncResp->res.jsonValue["Members@odata.count"] =
3197e860f15SJohn Edward Broadbent                 pcieFunctionList.size();
3207e860f15SJohn Edward Broadbent         };
3217e860f15SJohn Edward Broadbent         std::string escapedPath = std::string(pciePath) + "/" + device;
3227e860f15SJohn Edward Broadbent         dbus::utility::escapePathForDbus(escapedPath);
3237e860f15SJohn Edward Broadbent         crow::connections::systemBus->async_method_call(
3247e860f15SJohn Edward Broadbent             std::move(getPCIeDeviceCallback), pcieService, escapedPath,
325*002d39b4SEd Tanous             "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
3267e860f15SJohn Edward Broadbent         });
3277e860f15SJohn Edward Broadbent }
3287e860f15SJohn Edward Broadbent 
3297e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app)
3307e860f15SJohn Edward Broadbent {
3317e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
3327e860f15SJohn Edward Broadbent         app,
3337e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
334ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunction)
335*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
336*002d39b4SEd Tanous             [&app](const crow::Request& req,
33745ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
338*002d39b4SEd Tanous                    const std::string& device, const std::string& function) {
33945ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
34045ca1b86SEd Tanous         {
34145ca1b86SEd Tanous             return;
34245ca1b86SEd Tanous         }
343168e20c1SEd Tanous         auto getPCIeDeviceCallback =
344168e20c1SEd Tanous             [asyncResp, device, function](
3457e860f15SJohn Edward Broadbent                 const boost::system::error_code ec,
346b9d36b47SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
347dede6a98SJason M. Bills             if (ec)
348dede6a98SJason M. Bills             {
349dede6a98SJason M. Bills                 BMCWEB_LOG_DEBUG
350*002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
351*002d39b4SEd Tanous                     << ": " << ec.message();
352dede6a98SJason M. Bills                 if (ec.value() ==
353dede6a98SJason M. Bills                     boost::system::linux_error::bad_request_descriptor)
354dede6a98SJason M. Bills                 {
355*002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
356*002d39b4SEd Tanous                                                device);
357dede6a98SJason M. Bills                 }
358dede6a98SJason M. Bills                 else
359dede6a98SJason M. Bills                 {
360dede6a98SJason M. Bills                     messages::internalError(asyncResp->res);
361dede6a98SJason M. Bills                 }
362dede6a98SJason M. Bills                 return;
363dede6a98SJason M. Bills             }
364dede6a98SJason M. Bills 
3651476687dSEd Tanous             // Check if this function exists by looking for a device
3661476687dSEd Tanous             // ID
367b9d36b47SEd Tanous             std::string functionName = "Function" + function;
368b9d36b47SEd Tanous             std::string devIDProperty = functionName + "DeviceId";
369b9d36b47SEd Tanous 
370b9d36b47SEd Tanous             const std::string* devIdProperty = nullptr;
371b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
372b9d36b47SEd Tanous             {
373b9d36b47SEd Tanous                 if (property.first == devIDProperty)
374b9d36b47SEd Tanous                 {
375*002d39b4SEd Tanous                     devIdProperty = std::get_if<std::string>(&property.second);
376b9d36b47SEd Tanous                     continue;
377b9d36b47SEd Tanous                 }
378b9d36b47SEd Tanous             }
379b9d36b47SEd Tanous             if (devIdProperty == nullptr || !devIdProperty->empty())
380f5c9f8bdSJason M. Bills             {
381*002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
382*002d39b4SEd Tanous                                            function);
383f5c9f8bdSJason M. Bills                 return;
384f5c9f8bdSJason M. Bills             }
385f5c9f8bdSJason M. Bills 
3861476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
3871476687dSEd Tanous                 "#PCIeFunction.v1_2_0.PCIeFunction";
3881476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
389168e20c1SEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device +
3901476687dSEd Tanous                 "/PCIeFunctions/" + function;
3911476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function";
3921476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = function;
393*002d39b4SEd Tanous             asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
394*002d39b4SEd Tanous             asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
3951476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device;
396f5c9f8bdSJason M. Bills 
397b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
398f5c9f8bdSJason M. Bills             {
399b9d36b47SEd Tanous                 const std::string* strProperty =
400b9d36b47SEd Tanous                     std::get_if<std::string>(&property.second);
401b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceId")
402f5c9f8bdSJason M. Bills                 {
403b9d36b47SEd Tanous                     asyncResp->res.jsonValue["DeviceId"] = *strProperty;
404f5c9f8bdSJason M. Bills                 }
405b9d36b47SEd Tanous                 if (property.first == functionName + "VendorId")
406f5c9f8bdSJason M. Bills                 {
407b9d36b47SEd Tanous                     asyncResp->res.jsonValue["VendorId"] = *strProperty;
408f5c9f8bdSJason M. Bills                 }
409b9d36b47SEd Tanous                 if (property.first == functionName + "FunctionType")
410f5c9f8bdSJason M. Bills                 {
411*002d39b4SEd Tanous                     asyncResp->res.jsonValue["FunctionType"] = *strProperty;
412f5c9f8bdSJason M. Bills                 }
413b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceClass")
414f5c9f8bdSJason M. Bills                 {
415*002d39b4SEd Tanous                     asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
416f5c9f8bdSJason M. Bills                 }
417b9d36b47SEd Tanous                 if (property.first == functionName + "ClassCode")
418f5c9f8bdSJason M. Bills                 {
419*002d39b4SEd Tanous                     asyncResp->res.jsonValue["ClassCode"] = *strProperty;
420f5c9f8bdSJason M. Bills                 }
421b9d36b47SEd Tanous                 if (property.first == functionName + "RevisionId")
422f5c9f8bdSJason M. Bills                 {
423*002d39b4SEd Tanous                     asyncResp->res.jsonValue["RevisionId"] = *strProperty;
424f5c9f8bdSJason M. Bills                 }
425b9d36b47SEd Tanous                 if (property.first == functionName + "SubsystemId")
426b9d36b47SEd Tanous                 {
427*002d39b4SEd Tanous                     asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
428b9d36b47SEd Tanous                 }
429*002d39b4SEd Tanous                 if (property.first == functionName + "SubsystemVendorId")
430f5c9f8bdSJason M. Bills                 {
431168e20c1SEd Tanous                     asyncResp->res.jsonValue["SubsystemVendorId"] =
432b9d36b47SEd Tanous                         *strProperty;
433b9d36b47SEd Tanous                 }
434f5c9f8bdSJason M. Bills             }
435f5c9f8bdSJason M. Bills         };
436f5c9f8bdSJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
437f5c9f8bdSJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
438f5c9f8bdSJason M. Bills         crow::connections::systemBus->async_method_call(
439f5c9f8bdSJason M. Bills             std::move(getPCIeDeviceCallback), pcieService, escapedPath,
440*002d39b4SEd Tanous             "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
4417e860f15SJohn Edward Broadbent         });
442f5c9f8bdSJason M. Bills }
443f5c9f8bdSJason M. Bills 
444f5c9f8bdSJason M. Bills } // namespace redfish
445