xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 45ca1b868e47978a4d2e8ebb680cb384e804c97e)
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>
22*45ca1b86SEd 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                 }
63f5c9f8bdSJason M. Bills                 pcieDeviceList.push_back(
64f5c9f8bdSJason M. Bills                     {{"@odata.id",
65f5c9f8bdSJason M. Bills                       "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
66f5c9f8bdSJason M. Bills             }
67b9d36b47SEd Tanous             asyncResp->res.jsonValue[name + "@odata.count"] =
68b9d36b47SEd Tanous                 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)(
85*45ca1b86SEd Tanous             [&app](const crow::Request& req,
86*45ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
87*45ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
88adbe192aSJason M. Bills                 {
89*45ca1b86SEd Tanous                     return;
90*45ca1b86SEd Tanous                 }
91adbe192aSJason M. Bills                 asyncResp->res.jsonValue = {
927e860f15SJohn Edward Broadbent                     {"@odata.type",
937e860f15SJohn Edward Broadbent                      "#PCIeDeviceCollection.PCIeDeviceCollection"},
94adbe192aSJason M. Bills                     {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices"},
95adbe192aSJason M. Bills                     {"Name", "PCIe Device Collection"},
96adbe192aSJason M. Bills                     {"Description", "Collection of PCIe Devices"},
97adbe192aSJason M. Bills                     {"Members", nlohmann::json::array()},
98adbe192aSJason M. Bills                     {"Members@odata.count", 0}};
99adbe192aSJason M. Bills                 getPCIeDeviceList(asyncResp, "Members");
1007e860f15SJohn Edward Broadbent             });
101f5c9f8bdSJason M. Bills }
102f5c9f8bdSJason M. Bills 
10362cd45afSSpencer Ku inline std::optional<std::string>
10462cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
10562cd45afSSpencer Ku {
10662cd45afSSpencer Ku     if (generationInUse ==
10762cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
10862cd45afSSpencer Ku     {
10962cd45afSSpencer Ku         return "Gen1";
11062cd45afSSpencer Ku     }
11162cd45afSSpencer Ku     if (generationInUse ==
11262cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
11362cd45afSSpencer Ku     {
11462cd45afSSpencer Ku         return "Gen2";
11562cd45afSSpencer Ku     }
11662cd45afSSpencer Ku     if (generationInUse ==
11762cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
11862cd45afSSpencer Ku     {
11962cd45afSSpencer Ku         return "Gen3";
12062cd45afSSpencer Ku     }
12162cd45afSSpencer Ku     if (generationInUse ==
12262cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
12362cd45afSSpencer Ku     {
12462cd45afSSpencer Ku         return "Gen4";
12562cd45afSSpencer Ku     }
12662cd45afSSpencer Ku     if (generationInUse ==
12762cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
12862cd45afSSpencer Ku     {
12962cd45afSSpencer Ku         return "Gen5";
13062cd45afSSpencer Ku     }
13162cd45afSSpencer Ku     if (generationInUse.empty() ||
13262cd45afSSpencer Ku         generationInUse ==
13362cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
13462cd45afSSpencer Ku     {
13562cd45afSSpencer Ku         return "";
13662cd45afSSpencer Ku     }
13762cd45afSSpencer Ku 
13862cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
13962cd45afSSpencer Ku     return std::nullopt;
14062cd45afSSpencer Ku }
14162cd45afSSpencer Ku 
1427e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDevice(App& app)
143f5c9f8bdSJason M. Bills {
1447e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
145ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDevice)
146*45ca1b86SEd Tanous         .methods(
147*45ca1b86SEd Tanous             boost::beast::http::verb::
148*45ca1b86SEd Tanous                 get)([&app](const crow::Request& req,
1497e860f15SJohn Edward Broadbent                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
150*45ca1b86SEd Tanous                             const std::string& device) {
151*45ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1527e860f15SJohn Edward Broadbent             {
153*45ca1b86SEd Tanous                 return;
154*45ca1b86SEd Tanous             }
155168e20c1SEd Tanous             auto getPCIeDeviceCallback =
156*45ca1b86SEd Tanous                 [asyncResp, device](
157*45ca1b86SEd Tanous                     const boost::system::error_code ec,
158*45ca1b86SEd Tanous                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
159f5c9f8bdSJason M. Bills                     if (ec)
160f5c9f8bdSJason M. Bills                     {
161f5c9f8bdSJason M. Bills                         BMCWEB_LOG_DEBUG
162f5c9f8bdSJason M. Bills                             << "failed to get PCIe Device properties ec: "
163271584abSEd Tanous                             << ec.value() << ": " << ec.message();
164*45ca1b86SEd Tanous                         if (ec.value() ==
165*45ca1b86SEd Tanous                             boost::system::linux_error::bad_request_descriptor)
166f5c9f8bdSJason M. Bills                         {
167*45ca1b86SEd Tanous                             messages::resourceNotFound(asyncResp->res,
168*45ca1b86SEd Tanous                                                        "PCIeDevice", 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 
177f5c9f8bdSJason M. Bills                     asyncResp->res.jsonValue = {
178dede6a98SJason M. Bills                         {"@odata.type", "#PCIeDevice.v1_4_0.PCIeDevice"},
179f5c9f8bdSJason M. Bills                         {"@odata.id",
180*45ca1b86SEd Tanous                          "/redfish/v1/Systems/system/PCIeDevices/" + device},
181f5c9f8bdSJason M. Bills                         {"Name", "PCIe Device"},
182f5c9f8bdSJason M. Bills                         {"Id", device}};
183b9d36b47SEd Tanous                     asyncResp->res.jsonValue["PCIeFunctions"] = {
184b9d36b47SEd Tanous                         {"@odata.id",
185*45ca1b86SEd Tanous                          "/redfish/v1/Systems/system/PCIeDevices/" + device +
186*45ca1b86SEd 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                             }
198168e20c1SEd Tanous                             asyncResp->res.jsonValue["Manufacturer"] =
199b9d36b47SEd Tanous                                 *propertyString;
200168e20c1SEd Tanous                         }
201b9d36b47SEd Tanous                         if (property.first == "DeviceType")
202168e20c1SEd Tanous                         {
203b9d36b47SEd Tanous                             if (propertyString == nullptr)
204b9d36b47SEd Tanous                             {
205b9d36b47SEd Tanous                                 messages::internalError(asyncResp->res);
206b9d36b47SEd Tanous                                 return;
207168e20c1SEd Tanous                             }
208b9d36b47SEd Tanous                             asyncResp->res.jsonValue["DeviceType"] =
209b9d36b47SEd Tanous                                 *propertyString;
210f5c9f8bdSJason M. Bills                         }
211b9d36b47SEd Tanous                         if (property.first == "DeviceType")
212f5c9f8bdSJason M. Bills                         {
213b9d36b47SEd Tanous                             if (propertyString == nullptr)
214b9d36b47SEd Tanous                             {
215b9d36b47SEd Tanous                                 messages::internalError(asyncResp->res);
216b9d36b47SEd Tanous                                 return;
217f5c9f8bdSJason M. Bills                             }
218b9d36b47SEd Tanous                             asyncResp->res.jsonValue["DeviceType"] =
219b9d36b47SEd Tanous                                 *propertyString;
220b9d36b47SEd Tanous                         }
221b9d36b47SEd Tanous                         if (property.first == "GenerationInUse")
22262cd45afSSpencer Ku                         {
223b9d36b47SEd Tanous                             if (propertyString == nullptr)
224b9d36b47SEd Tanous                             {
225b9d36b47SEd Tanous                                 messages::internalError(asyncResp->res);
226b9d36b47SEd Tanous                                 return;
227b9d36b47SEd Tanous                             }
22862cd45afSSpencer Ku                             std::optional<std::string> generationInUse =
229*45ca1b86SEd Tanous                                 redfishPcieGenerationFromDbus(*propertyString);
23062cd45afSSpencer Ku                             if (!generationInUse)
23162cd45afSSpencer Ku                             {
23262cd45afSSpencer Ku                                 messages::internalError(asyncResp->res);
23362cd45afSSpencer Ku                                 return;
23462cd45afSSpencer Ku                             }
23526f6976fSEd Tanous                             if (generationInUse->empty())
23662cd45afSSpencer Ku                             {
23762cd45afSSpencer Ku                                 // unknown, no need to handle
23862cd45afSSpencer Ku                                 return;
23962cd45afSSpencer Ku                             }
240168e20c1SEd Tanous                             asyncResp->res
241213ffc70SAnjaliintel-21                                 .jsonValue["PCIeInterface"]["PCIeType"] =
24262cd45afSSpencer Ku                                 *generationInUse;
24362cd45afSSpencer Ku                         }
244b9d36b47SEd Tanous                     }
245dede6a98SJason M. Bills                 };
246dede6a98SJason M. Bills             std::string escapedPath = std::string(pciePath) + "/" + device;
247dede6a98SJason M. Bills             dbus::utility::escapePathForDbus(escapedPath);
248dede6a98SJason M. Bills             crow::connections::systemBus->async_method_call(
249dede6a98SJason M. Bills                 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
2507e860f15SJohn Edward Broadbent                 "org.freedesktop.DBus.Properties", "GetAll",
2517e860f15SJohn Edward Broadbent                 pcieDeviceInterface);
2527e860f15SJohn Edward Broadbent         });
253dede6a98SJason M. Bills }
254dede6a98SJason M. Bills 
2557e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
2567e860f15SJohn Edward Broadbent {
257dede6a98SJason M. Bills     /**
258dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
259dede6a98SJason M. Bills      */
2607e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2617e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
262ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
263*45ca1b86SEd Tanous         .methods(
264*45ca1b86SEd Tanous             boost::beast::http::verb::
265*45ca1b86SEd Tanous                 get)([&app](const crow::Request& req,
2667e860f15SJohn Edward Broadbent                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
267*45ca1b86SEd Tanous                             const std::string& device) {
268*45ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
269dede6a98SJason M. Bills             {
270*45ca1b86SEd Tanous                 return;
271*45ca1b86SEd Tanous             }
272dede6a98SJason M. Bills             asyncResp->res.jsonValue = {
2737e860f15SJohn Edward Broadbent                 {"@odata.type",
2747e860f15SJohn Edward Broadbent                  "#PCIeFunctionCollection.PCIeFunctionCollection"},
2757e860f15SJohn Edward Broadbent                 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
2767e860f15SJohn Edward Broadbent                                   device + "/PCIeFunctions"},
277dede6a98SJason M. Bills                 {"Name", "PCIe Function Collection"},
278dede6a98SJason M. Bills                 {"Description",
279dede6a98SJason M. Bills                  "Collection of PCIe Functions for PCIe Device " + device}};
280dede6a98SJason M. Bills 
281b9d36b47SEd Tanous             auto getPCIeDeviceCallback =
282*45ca1b86SEd Tanous                 [asyncResp, device](
283*45ca1b86SEd Tanous                     const boost::system::error_code ec,
284*45ca1b86SEd Tanous                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
2857e860f15SJohn Edward Broadbent                     if (ec)
2867e860f15SJohn Edward Broadbent                     {
2877e860f15SJohn Edward Broadbent                         BMCWEB_LOG_DEBUG
2887e860f15SJohn Edward Broadbent                             << "failed to get PCIe Device properties ec: "
2897e860f15SJohn Edward Broadbent                             << ec.value() << ": " << ec.message();
290*45ca1b86SEd Tanous                         if (ec.value() ==
291*45ca1b86SEd Tanous                             boost::system::linux_error::bad_request_descriptor)
2927e860f15SJohn Edward Broadbent                         {
293*45ca1b86SEd Tanous                             messages::resourceNotFound(asyncResp->res,
294*45ca1b86SEd Tanous                                                        "PCIeDevice", device);
2957e860f15SJohn Edward Broadbent                         }
2967e860f15SJohn Edward Broadbent                         else
2977e860f15SJohn Edward Broadbent                         {
2987e860f15SJohn Edward Broadbent                             messages::internalError(asyncResp->res);
2997e860f15SJohn Edward Broadbent                         }
3007e860f15SJohn Edward Broadbent                         return;
3017e860f15SJohn Edward Broadbent                     }
3027e860f15SJohn Edward Broadbent 
3037e860f15SJohn Edward Broadbent                     nlohmann::json& pcieFunctionList =
3047e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Members"];
3057e860f15SJohn Edward Broadbent                     pcieFunctionList = nlohmann::json::array();
3067e860f15SJohn Edward Broadbent                     static constexpr const int maxPciFunctionNum = 8;
307*45ca1b86SEd Tanous                     for (int functionNum = 0; functionNum < maxPciFunctionNum;
308*45ca1b86SEd Tanous                          functionNum++)
3097e860f15SJohn Edward Broadbent                     {
310b9d36b47SEd Tanous                         // Check if this function exists by looking for a
311b9d36b47SEd Tanous                         // device ID
3127e860f15SJohn Edward Broadbent                         std::string devIDProperty =
3137e860f15SJohn Edward Broadbent                             "Function" + std::to_string(functionNum) +
3147e860f15SJohn Edward Broadbent                             "DeviceId";
315b9d36b47SEd Tanous                         const std::string* property = nullptr;
316b9d36b47SEd Tanous                         for (const auto& propEntry : pcieDevProperties)
3177e860f15SJohn Edward Broadbent                         {
318b9d36b47SEd Tanous                             if (propEntry.first == devIDProperty)
319b9d36b47SEd Tanous                             {
320*45ca1b86SEd Tanous                                 property =
321*45ca1b86SEd Tanous                                     std::get_if<std::string>(&propEntry.second);
322b9d36b47SEd Tanous                             }
323b9d36b47SEd Tanous                         }
324b9d36b47SEd Tanous                         if (property == nullptr || !property->empty())
325b9d36b47SEd Tanous                         {
326b9d36b47SEd Tanous                             return;
327b9d36b47SEd Tanous                         }
3287e860f15SJohn Edward Broadbent                         pcieFunctionList.push_back(
3297e860f15SJohn Edward Broadbent                             {{"@odata.id",
3307e860f15SJohn Edward Broadbent                               "/redfish/v1/Systems/system/PCIeDevices/" +
3317e860f15SJohn Edward Broadbent                                   device + "/PCIeFunctions/" +
3327e860f15SJohn Edward Broadbent                                   std::to_string(functionNum)}});
3337e860f15SJohn Edward Broadbent                     }
334a818d15aSJiaqing Zhao                     asyncResp->res.jsonValue["Members@odata.count"] =
3357e860f15SJohn Edward Broadbent                         pcieFunctionList.size();
3367e860f15SJohn Edward Broadbent                 };
3377e860f15SJohn Edward Broadbent             std::string escapedPath = std::string(pciePath) + "/" + device;
3387e860f15SJohn Edward Broadbent             dbus::utility::escapePathForDbus(escapedPath);
3397e860f15SJohn Edward Broadbent             crow::connections::systemBus->async_method_call(
3407e860f15SJohn Edward Broadbent                 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
3417e860f15SJohn Edward Broadbent                 "org.freedesktop.DBus.Properties", "GetAll",
3427e860f15SJohn Edward Broadbent                 pcieDeviceInterface);
3437e860f15SJohn Edward Broadbent         });
3447e860f15SJohn Edward Broadbent }
3457e860f15SJohn Edward Broadbent 
3467e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app)
3477e860f15SJohn Edward Broadbent {
3487e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
3497e860f15SJohn Edward Broadbent         app,
3507e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
351ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunction)
3527e860f15SJohn Edward Broadbent         .methods(
353*45ca1b86SEd Tanous             boost::beast::http::verb::
354*45ca1b86SEd Tanous                 get)([&app](const crow::Request& req,
355*45ca1b86SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3567e860f15SJohn Edward Broadbent                             const std::string& device,
3577e860f15SJohn Edward Broadbent                             const std::string& function) {
358*45ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
359*45ca1b86SEd Tanous             {
360*45ca1b86SEd Tanous                 return;
361*45ca1b86SEd Tanous             }
362168e20c1SEd Tanous             auto getPCIeDeviceCallback =
363168e20c1SEd Tanous                 [asyncResp, device, function](
3647e860f15SJohn Edward Broadbent                     const boost::system::error_code ec,
365b9d36b47SEd Tanous                     const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
366dede6a98SJason M. Bills                     if (ec)
367dede6a98SJason M. Bills                     {
368dede6a98SJason M. Bills                         BMCWEB_LOG_DEBUG
369dede6a98SJason M. Bills                             << "failed to get PCIe Device properties ec: "
370dede6a98SJason M. Bills                             << ec.value() << ": " << ec.message();
371dede6a98SJason M. Bills                         if (ec.value() ==
372dede6a98SJason M. Bills                             boost::system::linux_error::bad_request_descriptor)
373dede6a98SJason M. Bills                         {
374168e20c1SEd Tanous                             messages::resourceNotFound(asyncResp->res,
375168e20c1SEd Tanous                                                        "PCIeDevice", device);
376dede6a98SJason M. Bills                         }
377dede6a98SJason M. Bills                         else
378dede6a98SJason M. Bills                         {
379dede6a98SJason M. Bills                             messages::internalError(asyncResp->res);
380dede6a98SJason M. Bills                         }
381dede6a98SJason M. Bills                         return;
382dede6a98SJason M. Bills                     }
383dede6a98SJason M. Bills 
384f5c9f8bdSJason M. Bills                     // Check if this function exists by looking for a device ID
385b9d36b47SEd Tanous                     std::string functionName = "Function" + function;
386b9d36b47SEd Tanous                     std::string devIDProperty = functionName + "DeviceId";
387b9d36b47SEd Tanous 
388b9d36b47SEd Tanous                     const std::string* devIdProperty = nullptr;
389b9d36b47SEd Tanous                     for (const auto& property : pcieDevProperties)
390b9d36b47SEd Tanous                     {
391b9d36b47SEd Tanous                         if (property.first == devIDProperty)
392b9d36b47SEd Tanous                         {
393b9d36b47SEd Tanous                             devIdProperty =
394b9d36b47SEd Tanous                                 std::get_if<std::string>(&property.second);
395b9d36b47SEd Tanous                             continue;
396b9d36b47SEd Tanous                         }
397b9d36b47SEd Tanous                     }
398b9d36b47SEd Tanous                     if (devIdProperty == nullptr || !devIdProperty->empty())
399f5c9f8bdSJason M. Bills                     {
400168e20c1SEd Tanous                         messages::resourceNotFound(asyncResp->res,
401168e20c1SEd Tanous                                                    "PCIeFunction", function);
402f5c9f8bdSJason M. Bills                         return;
403f5c9f8bdSJason M. Bills                     }
404f5c9f8bdSJason M. Bills 
405f5c9f8bdSJason M. Bills                     asyncResp->res.jsonValue = {
406f5c9f8bdSJason M. Bills                         {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
407168e20c1SEd Tanous                         {"@odata.id",
408168e20c1SEd Tanous                          "/redfish/v1/Systems/system/PCIeDevices/" + device +
409168e20c1SEd Tanous                              "/PCIeFunctions/" + function},
410f5c9f8bdSJason M. Bills                         {"Name", "PCIe Function"},
411f5c9f8bdSJason M. Bills                         {"Id", function},
412f5c9f8bdSJason M. Bills                         {"FunctionId", std::stoi(function)},
413f5c9f8bdSJason M. Bills                         {"Links",
414f5c9f8bdSJason M. Bills                          {{"PCIeDevice",
415f5c9f8bdSJason M. Bills                            {{"@odata.id",
4167e860f15SJohn Edward Broadbent                              "/redfish/v1/Systems/system/PCIeDevices/" +
4177e860f15SJohn Edward Broadbent                                  device}}}}}};
418f5c9f8bdSJason M. Bills 
419b9d36b47SEd Tanous                     for (const auto& property : pcieDevProperties)
420f5c9f8bdSJason M. Bills                     {
421b9d36b47SEd Tanous                         const std::string* strProperty =
422b9d36b47SEd Tanous                             std::get_if<std::string>(&property.second);
423b9d36b47SEd Tanous                         if (property.first == functionName + "DeviceId")
424f5c9f8bdSJason M. Bills                         {
425b9d36b47SEd Tanous                             asyncResp->res.jsonValue["DeviceId"] = *strProperty;
426f5c9f8bdSJason M. Bills                         }
427b9d36b47SEd Tanous                         if (property.first == functionName + "VendorId")
428f5c9f8bdSJason M. Bills                         {
429b9d36b47SEd Tanous                             asyncResp->res.jsonValue["VendorId"] = *strProperty;
430f5c9f8bdSJason M. Bills                         }
431b9d36b47SEd Tanous                         if (property.first == functionName + "FunctionType")
432f5c9f8bdSJason M. Bills                         {
433b9d36b47SEd Tanous                             asyncResp->res.jsonValue["FunctionType"] =
434b9d36b47SEd Tanous                                 *strProperty;
435f5c9f8bdSJason M. Bills                         }
436b9d36b47SEd Tanous                         if (property.first == functionName + "DeviceClass")
437f5c9f8bdSJason M. Bills                         {
438b9d36b47SEd Tanous                             asyncResp->res.jsonValue["DeviceClass"] =
439b9d36b47SEd Tanous                                 *strProperty;
440f5c9f8bdSJason M. Bills                         }
441b9d36b47SEd Tanous                         if (property.first == functionName + "ClassCode")
442f5c9f8bdSJason M. Bills                         {
443b9d36b47SEd Tanous                             asyncResp->res.jsonValue["ClassCode"] =
444b9d36b47SEd Tanous                                 *strProperty;
445f5c9f8bdSJason M. Bills                         }
446b9d36b47SEd Tanous                         if (property.first == functionName + "RevisionId")
447f5c9f8bdSJason M. Bills                         {
448b9d36b47SEd Tanous                             asyncResp->res.jsonValue["RevisionId"] =
449b9d36b47SEd Tanous                                 *strProperty;
450f5c9f8bdSJason M. Bills                         }
451b9d36b47SEd Tanous                         if (property.first == functionName + "SubsystemId")
452b9d36b47SEd Tanous                         {
453b9d36b47SEd Tanous                             asyncResp->res.jsonValue["SubsystemId"] =
454b9d36b47SEd Tanous                                 *strProperty;
455b9d36b47SEd Tanous                         }
456b9d36b47SEd Tanous                         if (property.first ==
457b9d36b47SEd Tanous                             functionName + "SubsystemVendorId")
458f5c9f8bdSJason M. Bills                         {
459168e20c1SEd Tanous                             asyncResp->res.jsonValue["SubsystemVendorId"] =
460b9d36b47SEd Tanous                                 *strProperty;
461b9d36b47SEd Tanous                         }
462f5c9f8bdSJason M. Bills                     }
463f5c9f8bdSJason M. Bills                 };
464f5c9f8bdSJason M. Bills             std::string escapedPath = std::string(pciePath) + "/" + device;
465f5c9f8bdSJason M. Bills             dbus::utility::escapePathForDbus(escapedPath);
466f5c9f8bdSJason M. Bills             crow::connections::systemBus->async_method_call(
467f5c9f8bdSJason M. Bills                 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
4687e860f15SJohn Edward Broadbent                 "org.freedesktop.DBus.Properties", "GetAll",
4697e860f15SJohn Edward Broadbent                 pcieDeviceInterface);
4707e860f15SJohn Edward Broadbent         });
471f5c9f8bdSJason M. Bills }
472f5c9f8bdSJason M. Bills 
473f5c9f8bdSJason M. Bills } // namespace redfish
474