xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision d1bde9e590f165f28d948fda93e48d51b30bb463)
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>
24*d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
25*d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
26*d1bde9e5SKrzysztof Grobelny #include <utils/dbus_utils.hpp>
27f5c9f8bdSJason M. Bills 
28f5c9f8bdSJason M. Bills namespace redfish
29f5c9f8bdSJason M. Bills {
30f5c9f8bdSJason M. Bills 
31f5c9f8bdSJason M. Bills static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
32f5c9f8bdSJason M. Bills static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
33f5c9f8bdSJason M. Bills static constexpr char const* pcieDeviceInterface =
34f5c9f8bdSJason M. Bills     "xyz.openbmc_project.PCIe.Device";
35f5c9f8bdSJason M. Bills 
36b5a76932SEd Tanous static inline void
378d1b46d7Szhanghch05     getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
38adbe192aSJason M. Bills                       const std::string& name)
39f5c9f8bdSJason M. Bills {
40b9d36b47SEd Tanous     auto getPCIeMapCallback =
41b9d36b47SEd Tanous         [asyncResp, name](const boost::system::error_code ec,
42b9d36b47SEd Tanous                           const dbus::utility::MapperGetSubTreePathsResponse&
43b9d36b47SEd Tanous                               pcieDevicePaths) {
44f5c9f8bdSJason M. Bills         if (ec)
45f5c9f8bdSJason M. Bills         {
46a2730f01SAndrew Geissler             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
47f5c9f8bdSJason M. Bills                              << ec.message();
48a2730f01SAndrew Geissler             // Not an error, system just doesn't have PCIe info
49f5c9f8bdSJason M. Bills             return;
50f5c9f8bdSJason M. Bills         }
51adbe192aSJason M. Bills         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
52f5c9f8bdSJason M. Bills         pcieDeviceList = nlohmann::json::array();
53f5c9f8bdSJason M. Bills         for (const std::string& pcieDevicePath : pcieDevicePaths)
54f5c9f8bdSJason M. Bills         {
553174e4dfSEd Tanous             size_t devStart = pcieDevicePath.rfind('/');
56f5c9f8bdSJason M. Bills             if (devStart == std::string::npos)
57f5c9f8bdSJason M. Bills             {
58f5c9f8bdSJason M. Bills                 continue;
59f5c9f8bdSJason M. Bills             }
60f5c9f8bdSJason M. Bills 
61f5c9f8bdSJason M. Bills             std::string devName = pcieDevicePath.substr(devStart + 1);
62f5c9f8bdSJason M. Bills             if (devName.empty())
63f5c9f8bdSJason M. Bills             {
64f5c9f8bdSJason M. Bills                 continue;
65f5c9f8bdSJason M. Bills             }
661476687dSEd Tanous             nlohmann::json::object_t pcieDevice;
671476687dSEd Tanous             pcieDevice["@odata.id"] =
681476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + devName;
691476687dSEd Tanous             pcieDeviceList.push_back(std::move(pcieDevice));
70f5c9f8bdSJason M. Bills         }
71002d39b4SEd Tanous         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
72f5c9f8bdSJason M. Bills     };
73f5c9f8bdSJason M. Bills     crow::connections::systemBus->async_method_call(
74f5c9f8bdSJason M. Bills         std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
75f5c9f8bdSJason M. Bills         "/xyz/openbmc_project/object_mapper",
76f5c9f8bdSJason M. Bills         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
77f5c9f8bdSJason M. Bills         std::string(pciePath) + "/", 1, std::array<std::string, 0>());
78f5c9f8bdSJason M. Bills }
79f5c9f8bdSJason M. Bills 
807e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
81adbe192aSJason M. Bills {
82adbe192aSJason M. Bills     /**
83adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
84adbe192aSJason M. Bills      */
857e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/")
86ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
877e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
8845ca1b86SEd Tanous             [&app](const crow::Request& req,
8945ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
903ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
91adbe192aSJason M. Bills         {
9245ca1b86SEd Tanous             return;
9345ca1b86SEd Tanous         }
941476687dSEd Tanous 
951476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
961476687dSEd Tanous             "#PCIeDeviceCollection.PCIeDeviceCollection";
971476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
981476687dSEd Tanous             "/redfish/v1/Systems/system/PCIeDevices";
991476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
100002d39b4SEd Tanous         asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
1011476687dSEd Tanous         asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
1021476687dSEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = 0;
103adbe192aSJason M. Bills         getPCIeDeviceList(asyncResp, "Members");
1047e860f15SJohn Edward Broadbent         });
105f5c9f8bdSJason M. Bills }
106f5c9f8bdSJason M. Bills 
10762cd45afSSpencer Ku inline std::optional<std::string>
10862cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
10962cd45afSSpencer Ku {
11062cd45afSSpencer Ku     if (generationInUse ==
11162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
11262cd45afSSpencer Ku     {
11362cd45afSSpencer Ku         return "Gen1";
11462cd45afSSpencer Ku     }
11562cd45afSSpencer Ku     if (generationInUse ==
11662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
11762cd45afSSpencer Ku     {
11862cd45afSSpencer Ku         return "Gen2";
11962cd45afSSpencer Ku     }
12062cd45afSSpencer Ku     if (generationInUse ==
12162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
12262cd45afSSpencer Ku     {
12362cd45afSSpencer Ku         return "Gen3";
12462cd45afSSpencer Ku     }
12562cd45afSSpencer Ku     if (generationInUse ==
12662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
12762cd45afSSpencer Ku     {
12862cd45afSSpencer Ku         return "Gen4";
12962cd45afSSpencer Ku     }
13062cd45afSSpencer Ku     if (generationInUse ==
13162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
13262cd45afSSpencer Ku     {
13362cd45afSSpencer Ku         return "Gen5";
13462cd45afSSpencer Ku     }
135e825cbc8SEd Tanous     if (generationInUse.empty() ||
136e825cbc8SEd Tanous         generationInUse ==
13762cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
13862cd45afSSpencer Ku     {
13962cd45afSSpencer Ku         return "";
14062cd45afSSpencer Ku     }
14162cd45afSSpencer Ku 
14262cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
14362cd45afSSpencer Ku     return std::nullopt;
14462cd45afSSpencer Ku }
14562cd45afSSpencer Ku 
1467e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDevice(App& app)
147f5c9f8bdSJason M. Bills {
1487e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
149ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDevice)
150002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
151002d39b4SEd Tanous             [&app](const crow::Request& req,
1527e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15345ca1b86SEd Tanous                    const std::string& device) {
1543ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1557e860f15SJohn Edward Broadbent         {
15645ca1b86SEd Tanous             return;
15745ca1b86SEd Tanous         }
158168e20c1SEd Tanous         auto getPCIeDeviceCallback =
15945ca1b86SEd Tanous             [asyncResp, device](
16045ca1b86SEd Tanous                 const boost::system::error_code ec,
16145ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
162f5c9f8bdSJason M. Bills             if (ec)
163f5c9f8bdSJason M. Bills             {
164f5c9f8bdSJason M. Bills                 BMCWEB_LOG_DEBUG
165002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
166002d39b4SEd Tanous                     << ": " << ec.message();
16745ca1b86SEd Tanous                 if (ec.value() ==
16845ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
169f5c9f8bdSJason M. Bills                 {
170002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
171002d39b4SEd Tanous                                                device);
172f5c9f8bdSJason M. Bills                 }
173f5c9f8bdSJason M. Bills                 else
174f5c9f8bdSJason M. Bills                 {
175f5c9f8bdSJason M. Bills                     messages::internalError(asyncResp->res);
176f5c9f8bdSJason M. Bills                 }
177f5c9f8bdSJason M. Bills                 return;
178f5c9f8bdSJason M. Bills             }
179f5c9f8bdSJason M. Bills 
180*d1bde9e5SKrzysztof Grobelny             const std::string* manufacturer = nullptr;
181*d1bde9e5SKrzysztof Grobelny             const std::string* deviceType = nullptr;
182*d1bde9e5SKrzysztof Grobelny             const std::string* generationInUse = nullptr;
183*d1bde9e5SKrzysztof Grobelny 
184*d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
185*d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), pcieDevProperties,
186*d1bde9e5SKrzysztof Grobelny                 "Manufacturer", manufacturer, "DeviceType", deviceType,
187*d1bde9e5SKrzysztof Grobelny                 "GenerationInUse", generationInUse);
188*d1bde9e5SKrzysztof Grobelny 
189*d1bde9e5SKrzysztof Grobelny             if (!success)
190*d1bde9e5SKrzysztof Grobelny             {
191*d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
192*d1bde9e5SKrzysztof Grobelny                 return;
193*d1bde9e5SKrzysztof Grobelny             }
194*d1bde9e5SKrzysztof Grobelny 
195*d1bde9e5SKrzysztof Grobelny             if (generationInUse != nullptr)
196*d1bde9e5SKrzysztof Grobelny             {
197*d1bde9e5SKrzysztof Grobelny                 std::optional<std::string> redfishGenerationInUse =
198*d1bde9e5SKrzysztof Grobelny                     redfishPcieGenerationFromDbus(*generationInUse);
199*d1bde9e5SKrzysztof Grobelny                 if (!redfishGenerationInUse)
200*d1bde9e5SKrzysztof Grobelny                 {
201*d1bde9e5SKrzysztof Grobelny                     messages::internalError(asyncResp->res);
202*d1bde9e5SKrzysztof Grobelny                     return;
203*d1bde9e5SKrzysztof Grobelny                 }
204*d1bde9e5SKrzysztof Grobelny                 if (redfishGenerationInUse->empty())
205*d1bde9e5SKrzysztof Grobelny                 {
206*d1bde9e5SKrzysztof Grobelny                     // unknown, no need to handle
207*d1bde9e5SKrzysztof Grobelny                     return;
208*d1bde9e5SKrzysztof Grobelny                 }
209*d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
210*d1bde9e5SKrzysztof Grobelny                     *redfishGenerationInUse;
211*d1bde9e5SKrzysztof Grobelny             }
212*d1bde9e5SKrzysztof Grobelny 
213*d1bde9e5SKrzysztof Grobelny             if (manufacturer != nullptr)
214*d1bde9e5SKrzysztof Grobelny             {
215*d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
216*d1bde9e5SKrzysztof Grobelny             }
217*d1bde9e5SKrzysztof Grobelny 
218*d1bde9e5SKrzysztof Grobelny             if (deviceType != nullptr)
219*d1bde9e5SKrzysztof Grobelny             {
220*d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["DeviceType"] = *deviceType;
221*d1bde9e5SKrzysztof Grobelny             }
222*d1bde9e5SKrzysztof Grobelny 
2231476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
2241476687dSEd Tanous                 "#PCIeDevice.v1_4_0.PCIeDevice";
2251476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
2261476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device;
2271476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Device";
2281476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = device;
2291476687dSEd Tanous 
2301476687dSEd Tanous             asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
23145ca1b86SEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device +
2321476687dSEd Tanous                 "/PCIeFunctions";
233dede6a98SJason M. Bills         };
234dede6a98SJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
235dede6a98SJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
236*d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
237*d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
238*d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
2397e860f15SJohn Edward Broadbent         });
240dede6a98SJason M. Bills }
241dede6a98SJason M. Bills 
2427e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
2437e860f15SJohn Edward Broadbent {
244dede6a98SJason M. Bills     /**
245dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
246dede6a98SJason M. Bills      */
2477e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2487e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
249ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
250002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
251002d39b4SEd Tanous             [&app](const crow::Request& req,
2527e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
25345ca1b86SEd Tanous                    const std::string& device) {
2543ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
255dede6a98SJason M. Bills         {
25645ca1b86SEd Tanous             return;
25745ca1b86SEd Tanous         }
2581476687dSEd Tanous 
2591476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
2601476687dSEd Tanous             "#PCIeFunctionCollection.PCIeFunctionCollection";
2611476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
2621476687dSEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/" + device +
2631476687dSEd Tanous             "/PCIeFunctions";
2641476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
2651476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
2661476687dSEd Tanous             "Collection of PCIe Functions for PCIe Device " + device;
267dede6a98SJason M. Bills 
268b9d36b47SEd Tanous         auto getPCIeDeviceCallback =
26945ca1b86SEd Tanous             [asyncResp, device](
27045ca1b86SEd Tanous                 const boost::system::error_code ec,
27145ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
2727e860f15SJohn Edward Broadbent             if (ec)
2737e860f15SJohn Edward Broadbent             {
2747e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG
275002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
276002d39b4SEd Tanous                     << ": " << ec.message();
27745ca1b86SEd Tanous                 if (ec.value() ==
27845ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
2797e860f15SJohn Edward Broadbent                 {
280002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
281002d39b4SEd Tanous                                                device);
2827e860f15SJohn Edward Broadbent                 }
2837e860f15SJohn Edward Broadbent                 else
2847e860f15SJohn Edward Broadbent                 {
2857e860f15SJohn Edward Broadbent                     messages::internalError(asyncResp->res);
2867e860f15SJohn Edward Broadbent                 }
2877e860f15SJohn Edward Broadbent                 return;
2887e860f15SJohn Edward Broadbent             }
2897e860f15SJohn Edward Broadbent 
2907e860f15SJohn Edward Broadbent             nlohmann::json& pcieFunctionList =
2917e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members"];
2927e860f15SJohn Edward Broadbent             pcieFunctionList = nlohmann::json::array();
2937e860f15SJohn Edward Broadbent             static constexpr const int maxPciFunctionNum = 8;
29445ca1b86SEd Tanous             for (int functionNum = 0; functionNum < maxPciFunctionNum;
29545ca1b86SEd Tanous                  functionNum++)
2967e860f15SJohn Edward Broadbent             {
297b9d36b47SEd Tanous                 // Check if this function exists by looking for a
298b9d36b47SEd Tanous                 // device ID
2997e860f15SJohn Edward Broadbent                 std::string devIDProperty =
300002d39b4SEd Tanous                     "Function" + std::to_string(functionNum) + "DeviceId";
301b9d36b47SEd Tanous                 const std::string* property = nullptr;
302b9d36b47SEd Tanous                 for (const auto& propEntry : pcieDevProperties)
3037e860f15SJohn Edward Broadbent                 {
304b9d36b47SEd Tanous                     if (propEntry.first == devIDProperty)
305b9d36b47SEd Tanous                     {
306002d39b4SEd Tanous                         property = std::get_if<std::string>(&propEntry.second);
307b9d36b47SEd Tanous                     }
308b9d36b47SEd Tanous                 }
309b9d36b47SEd Tanous                 if (property == nullptr || !property->empty())
310b9d36b47SEd Tanous                 {
311b9d36b47SEd Tanous                     return;
312b9d36b47SEd Tanous                 }
3131476687dSEd Tanous                 nlohmann::json::object_t pcieFunction;
3141476687dSEd Tanous                 pcieFunction["@odata.id"] =
3151476687dSEd Tanous                     "/redfish/v1/Systems/system/PCIeDevices/" + device +
3161476687dSEd Tanous                     "/PCIeFunctions/" + std::to_string(functionNum);
3171476687dSEd Tanous                 pcieFunctionList.push_back(std::move(pcieFunction));
3187e860f15SJohn Edward Broadbent             }
319a818d15aSJiaqing Zhao             asyncResp->res.jsonValue["Members@odata.count"] =
3207e860f15SJohn Edward Broadbent                 pcieFunctionList.size();
3217e860f15SJohn Edward Broadbent         };
3227e860f15SJohn Edward Broadbent         std::string escapedPath = std::string(pciePath) + "/" + device;
3237e860f15SJohn Edward Broadbent         dbus::utility::escapePathForDbus(escapedPath);
324*d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
325*d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
326*d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
3277e860f15SJohn Edward Broadbent         });
3287e860f15SJohn Edward Broadbent }
3297e860f15SJohn Edward Broadbent 
3307e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app)
3317e860f15SJohn Edward Broadbent {
3327e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
3337e860f15SJohn Edward Broadbent         app,
3347e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
335ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunction)
336002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
337002d39b4SEd Tanous             [&app](const crow::Request& req,
33845ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
339002d39b4SEd Tanous                    const std::string& device, const std::string& function) {
3403ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
34145ca1b86SEd Tanous         {
34245ca1b86SEd Tanous             return;
34345ca1b86SEd Tanous         }
344168e20c1SEd Tanous         auto getPCIeDeviceCallback =
345168e20c1SEd Tanous             [asyncResp, device, function](
3467e860f15SJohn Edward Broadbent                 const boost::system::error_code ec,
347b9d36b47SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
348dede6a98SJason M. Bills             if (ec)
349dede6a98SJason M. Bills             {
350dede6a98SJason M. Bills                 BMCWEB_LOG_DEBUG
351002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
352002d39b4SEd Tanous                     << ": " << ec.message();
353dede6a98SJason M. Bills                 if (ec.value() ==
354dede6a98SJason M. Bills                     boost::system::linux_error::bad_request_descriptor)
355dede6a98SJason M. Bills                 {
356002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
357002d39b4SEd Tanous                                                device);
358dede6a98SJason M. Bills                 }
359dede6a98SJason M. Bills                 else
360dede6a98SJason M. Bills                 {
361dede6a98SJason M. Bills                     messages::internalError(asyncResp->res);
362dede6a98SJason M. Bills                 }
363dede6a98SJason M. Bills                 return;
364dede6a98SJason M. Bills             }
365dede6a98SJason M. Bills 
3661476687dSEd Tanous             // Check if this function exists by looking for a device
3671476687dSEd Tanous             // ID
368b9d36b47SEd Tanous             std::string functionName = "Function" + function;
369b9d36b47SEd Tanous             std::string devIDProperty = functionName + "DeviceId";
370b9d36b47SEd Tanous 
371b9d36b47SEd Tanous             const std::string* devIdProperty = nullptr;
372b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
373b9d36b47SEd Tanous             {
374b9d36b47SEd Tanous                 if (property.first == devIDProperty)
375b9d36b47SEd Tanous                 {
376002d39b4SEd Tanous                     devIdProperty = std::get_if<std::string>(&property.second);
377b9d36b47SEd Tanous                     continue;
378b9d36b47SEd Tanous                 }
379b9d36b47SEd Tanous             }
380b9d36b47SEd Tanous             if (devIdProperty == nullptr || !devIdProperty->empty())
381f5c9f8bdSJason M. Bills             {
382002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
383002d39b4SEd Tanous                                            function);
384f5c9f8bdSJason M. Bills                 return;
385f5c9f8bdSJason M. Bills             }
386f5c9f8bdSJason M. Bills 
3871476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
3881476687dSEd Tanous                 "#PCIeFunction.v1_2_0.PCIeFunction";
3891476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
390168e20c1SEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device +
3911476687dSEd Tanous                 "/PCIeFunctions/" + function;
3921476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function";
3931476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = function;
394002d39b4SEd Tanous             asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
395002d39b4SEd Tanous             asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
3961476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device;
397f5c9f8bdSJason M. Bills 
398b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
399f5c9f8bdSJason M. Bills             {
400b9d36b47SEd Tanous                 const std::string* strProperty =
401b9d36b47SEd Tanous                     std::get_if<std::string>(&property.second);
402b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceId")
403f5c9f8bdSJason M. Bills                 {
404b9d36b47SEd Tanous                     asyncResp->res.jsonValue["DeviceId"] = *strProperty;
405f5c9f8bdSJason M. Bills                 }
406b9d36b47SEd Tanous                 if (property.first == functionName + "VendorId")
407f5c9f8bdSJason M. Bills                 {
408b9d36b47SEd Tanous                     asyncResp->res.jsonValue["VendorId"] = *strProperty;
409f5c9f8bdSJason M. Bills                 }
410b9d36b47SEd Tanous                 if (property.first == functionName + "FunctionType")
411f5c9f8bdSJason M. Bills                 {
412002d39b4SEd Tanous                     asyncResp->res.jsonValue["FunctionType"] = *strProperty;
413f5c9f8bdSJason M. Bills                 }
414b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceClass")
415f5c9f8bdSJason M. Bills                 {
416002d39b4SEd Tanous                     asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
417f5c9f8bdSJason M. Bills                 }
418b9d36b47SEd Tanous                 if (property.first == functionName + "ClassCode")
419f5c9f8bdSJason M. Bills                 {
420002d39b4SEd Tanous                     asyncResp->res.jsonValue["ClassCode"] = *strProperty;
421f5c9f8bdSJason M. Bills                 }
422b9d36b47SEd Tanous                 if (property.first == functionName + "RevisionId")
423f5c9f8bdSJason M. Bills                 {
424002d39b4SEd Tanous                     asyncResp->res.jsonValue["RevisionId"] = *strProperty;
425f5c9f8bdSJason M. Bills                 }
426b9d36b47SEd Tanous                 if (property.first == functionName + "SubsystemId")
427b9d36b47SEd Tanous                 {
428002d39b4SEd Tanous                     asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
429b9d36b47SEd Tanous                 }
430002d39b4SEd Tanous                 if (property.first == functionName + "SubsystemVendorId")
431f5c9f8bdSJason M. Bills                 {
432168e20c1SEd Tanous                     asyncResp->res.jsonValue["SubsystemVendorId"] =
433b9d36b47SEd Tanous                         *strProperty;
434b9d36b47SEd Tanous                 }
435f5c9f8bdSJason M. Bills             }
436f5c9f8bdSJason M. Bills         };
437f5c9f8bdSJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
438f5c9f8bdSJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
439*d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
440*d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
441*d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
4427e860f15SJohn Edward Broadbent         });
443f5c9f8bdSJason M. Bills }
444f5c9f8bdSJason M. Bills 
445f5c9f8bdSJason M. Bills } // namespace redfish
446