xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 94c3a10b94c3ce063d6c1aed3a597f0d524594d5)
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"
210ec8b83dSEd Tanous #include "generated/enums/pcie_device.hpp"
223ccb3adbSEd Tanous #include "query.hpp"
233ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
24b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp"
253ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
260ec8b83dSEd Tanous 
27f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp>
28d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
29d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
30f5c9f8bdSJason M. Bills 
31f5c9f8bdSJason M. Bills namespace redfish
32f5c9f8bdSJason M. Bills {
33f5c9f8bdSJason M. Bills 
34*94c3a10bSLakshmi Yadlapati static constexpr char const* inventoryPath = "/xyz/openbmc_project/inventory";
35*94c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
36*94c3a10bSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
37f5c9f8bdSJason M. Bills 
38543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath(
39543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
40543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
41543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
42543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
43543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
44543f9a75SLakshmi Yadlapati 
45543f9a75SLakshmi Yadlapati {
46543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
47543f9a75SLakshmi Yadlapati     {
48543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
49543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
50543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
51543f9a75SLakshmi Yadlapati         {
52543f9a75SLakshmi Yadlapati             continue;
53543f9a75SLakshmi Yadlapati         }
54543f9a75SLakshmi Yadlapati 
55543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
56543f9a75SLakshmi Yadlapati             pcieDevicePath, {},
57543f9a75SLakshmi Yadlapati             [pcieDevicePath, aResp,
58543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
59543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
60543f9a75SLakshmi Yadlapati             if (ec || object.empty())
61543f9a75SLakshmi Yadlapati             {
62543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
63543f9a75SLakshmi Yadlapati                 messages::internalError(aResp->res);
64543f9a75SLakshmi Yadlapati                 return;
65543f9a75SLakshmi Yadlapati             }
66543f9a75SLakshmi Yadlapati             callback(pcieDevicePath, object.begin()->first);
67543f9a75SLakshmi Yadlapati             });
68543f9a75SLakshmi Yadlapati         return;
69543f9a75SLakshmi Yadlapati     }
70543f9a75SLakshmi Yadlapati 
71543f9a75SLakshmi Yadlapati     BMCWEB_LOG_WARNING << "PCIe Device not found";
72543f9a75SLakshmi Yadlapati     messages::resourceNotFound(aResp->res, "PCIeDevice", pcieDeviceId);
73543f9a75SLakshmi Yadlapati }
74543f9a75SLakshmi Yadlapati 
75543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath(
76543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
77543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
78543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
79543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
80543f9a75SLakshmi Yadlapati {
81543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
82*94c3a10bSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
83543f9a75SLakshmi Yadlapati         [pcieDeviceId, aResp,
84543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
85543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
86543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
87543f9a75SLakshmi Yadlapati         if (ec)
88543f9a75SLakshmi Yadlapati         {
89543f9a75SLakshmi Yadlapati             BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
90543f9a75SLakshmi Yadlapati             messages::internalError(aResp->res);
91543f9a75SLakshmi Yadlapati             return;
92543f9a75SLakshmi Yadlapati         }
93543f9a75SLakshmi Yadlapati         handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback);
94543f9a75SLakshmi Yadlapati         return;
95543f9a75SLakshmi Yadlapati         });
96543f9a75SLakshmi Yadlapati }
97543f9a75SLakshmi Yadlapati 
98b5a76932SEd Tanous static inline void
998d1b46d7Szhanghch05     getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
100adbe192aSJason M. Bills                       const std::string& name)
101f5c9f8bdSJason M. Bills {
1027a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
103*94c3a10bSLakshmi Yadlapati         inventoryPath, 1, {},
1047a1dbc48SGeorge Liu         [asyncResp, name](const boost::system::error_code& ec,
105b9d36b47SEd Tanous                           const dbus::utility::MapperGetSubTreePathsResponse&
106b9d36b47SEd Tanous                               pcieDevicePaths) {
107f5c9f8bdSJason M. Bills         if (ec)
108f5c9f8bdSJason M. Bills         {
109a2730f01SAndrew Geissler             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
110f5c9f8bdSJason M. Bills                              << ec.message();
111a2730f01SAndrew Geissler             // Not an error, system just doesn't have PCIe info
112f5c9f8bdSJason M. Bills             return;
113f5c9f8bdSJason M. Bills         }
114adbe192aSJason M. Bills         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
115f5c9f8bdSJason M. Bills         pcieDeviceList = nlohmann::json::array();
116f5c9f8bdSJason M. Bills         for (const std::string& pcieDevicePath : pcieDevicePaths)
117f5c9f8bdSJason M. Bills         {
1183174e4dfSEd Tanous             size_t devStart = pcieDevicePath.rfind('/');
119f5c9f8bdSJason M. Bills             if (devStart == std::string::npos)
120f5c9f8bdSJason M. Bills             {
121f5c9f8bdSJason M. Bills                 continue;
122f5c9f8bdSJason M. Bills             }
123f5c9f8bdSJason M. Bills 
124f5c9f8bdSJason M. Bills             std::string devName = pcieDevicePath.substr(devStart + 1);
125f5c9f8bdSJason M. Bills             if (devName.empty())
126f5c9f8bdSJason M. Bills             {
127f5c9f8bdSJason M. Bills                 continue;
128f5c9f8bdSJason M. Bills             }
1291476687dSEd Tanous             nlohmann::json::object_t pcieDevice;
130eddfc437SWilly Tu             pcieDevice["@odata.id"] = crow::utility::urlFromPieces(
131eddfc437SWilly Tu                 "redfish", "v1", "Systems", "system", "PCIeDevices", devName);
1321476687dSEd Tanous             pcieDeviceList.push_back(std::move(pcieDevice));
133f5c9f8bdSJason M. Bills         }
134002d39b4SEd Tanous         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
1357a1dbc48SGeorge Liu         });
136f5c9f8bdSJason M. Bills }
137f5c9f8bdSJason M. Bills 
138b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet(
139b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
140b38fa2abSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
141b38fa2abSLakshmi Yadlapati     const std::string& systemName)
142b38fa2abSLakshmi Yadlapati {
143b38fa2abSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
144b38fa2abSLakshmi Yadlapati     {
145b38fa2abSLakshmi Yadlapati         return;
146b38fa2abSLakshmi Yadlapati     }
147b38fa2abSLakshmi Yadlapati     if (systemName != "system")
148b38fa2abSLakshmi Yadlapati     {
149b38fa2abSLakshmi Yadlapati         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
150b38fa2abSLakshmi Yadlapati         return;
151b38fa2abSLakshmi Yadlapati     }
152543f9a75SLakshmi Yadlapati 
153b38fa2abSLakshmi Yadlapati     aResp->res.addHeader(boost::beast::http::field::link,
154b38fa2abSLakshmi Yadlapati                          "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
155b38fa2abSLakshmi Yadlapati                          "PCIeDeviceCollection.json>; rel=describedby");
156b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["@odata.type"] =
157b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
158b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["@odata.id"] =
159b38fa2abSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices";
160b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Name"] = "PCIe Device Collection";
161b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
162b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Members"] = nlohmann::json::array();
163b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Members@odata.count"] = 0;
164b38fa2abSLakshmi Yadlapati 
165b38fa2abSLakshmi Yadlapati     collection_util::getCollectionMembers(
166b38fa2abSLakshmi Yadlapati         aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
167*94c3a10bSLakshmi Yadlapati         pcieDeviceInterface);
168b38fa2abSLakshmi Yadlapati }
169b38fa2abSLakshmi Yadlapati 
1707e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
171adbe192aSJason M. Bills {
172adbe192aSJason M. Bills     /**
173adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
174adbe192aSJason M. Bills      */
17522d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
176ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1777e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
178b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
179f5c9f8bdSJason M. Bills }
180f5c9f8bdSJason M. Bills 
1810ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes>
18262cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
18362cd45afSSpencer Ku {
18462cd45afSSpencer Ku     if (generationInUse ==
18562cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
18662cd45afSSpencer Ku     {
1870ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen1;
18862cd45afSSpencer Ku     }
18962cd45afSSpencer Ku     if (generationInUse ==
19062cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
19162cd45afSSpencer Ku     {
1920ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen2;
19362cd45afSSpencer Ku     }
19462cd45afSSpencer Ku     if (generationInUse ==
19562cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
19662cd45afSSpencer Ku     {
1970ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen3;
19862cd45afSSpencer Ku     }
19962cd45afSSpencer Ku     if (generationInUse ==
20062cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
20162cd45afSSpencer Ku     {
2020ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen4;
20362cd45afSSpencer Ku     }
20462cd45afSSpencer Ku     if (generationInUse ==
20562cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
20662cd45afSSpencer Ku     {
2070ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen5;
20862cd45afSSpencer Ku     }
209e825cbc8SEd Tanous     if (generationInUse.empty() ||
210e825cbc8SEd Tanous         generationInUse ==
21162cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
21262cd45afSSpencer Ku     {
2130ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Invalid;
21462cd45afSSpencer Ku     }
21562cd45afSSpencer Ku 
21662cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
21762cd45afSSpencer Ku     return std::nullopt;
21862cd45afSSpencer Ku }
21962cd45afSSpencer Ku 
220913e7732SSunnySrivastava1984 inline void getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
221913e7732SSunnySrivastava1984                                const std::string& pcieDevicePath,
222913e7732SSunnySrivastava1984                                const std::string& service)
223913e7732SSunnySrivastava1984 {
224913e7732SSunnySrivastava1984     sdbusplus::asio::getAllProperties(
225913e7732SSunnySrivastava1984         *crow::connections::systemBus, service, pcieDevicePath,
226913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
227913e7732SSunnySrivastava1984         [pcieDevicePath,
228913e7732SSunnySrivastava1984          aResp{aResp}](const boost::system::error_code& ec,
229913e7732SSunnySrivastava1984                        const dbus::utility::DBusPropertiesMap& assetList) {
230913e7732SSunnySrivastava1984         if (ec)
231913e7732SSunnySrivastava1984         {
232913e7732SSunnySrivastava1984             if (ec.value() != EBADR)
233913e7732SSunnySrivastava1984             {
234913e7732SSunnySrivastava1984                 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
235913e7732SSunnySrivastava1984                                  << ec.value();
236913e7732SSunnySrivastava1984                 messages::internalError(aResp->res);
237913e7732SSunnySrivastava1984             }
238913e7732SSunnySrivastava1984             return;
239913e7732SSunnySrivastava1984         }
240913e7732SSunnySrivastava1984 
241913e7732SSunnySrivastava1984         const std::string* manufacturer = nullptr;
242913e7732SSunnySrivastava1984         const std::string* model = nullptr;
243913e7732SSunnySrivastava1984         const std::string* partNumber = nullptr;
244913e7732SSunnySrivastava1984         const std::string* serialNumber = nullptr;
245913e7732SSunnySrivastava1984         const std::string* sparePartNumber = nullptr;
246913e7732SSunnySrivastava1984 
247913e7732SSunnySrivastava1984         const bool success = sdbusplus::unpackPropertiesNoThrow(
248913e7732SSunnySrivastava1984             dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
249913e7732SSunnySrivastava1984             manufacturer, "Model", model, "PartNumber", partNumber,
250913e7732SSunnySrivastava1984             "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
251913e7732SSunnySrivastava1984 
252913e7732SSunnySrivastava1984         if (!success)
253913e7732SSunnySrivastava1984         {
254913e7732SSunnySrivastava1984             messages::internalError(aResp->res);
255913e7732SSunnySrivastava1984             return;
256913e7732SSunnySrivastava1984         }
257913e7732SSunnySrivastava1984 
258913e7732SSunnySrivastava1984         if (manufacturer != nullptr)
259913e7732SSunnySrivastava1984         {
260913e7732SSunnySrivastava1984             aResp->res.jsonValue["Manufacturer"] = *manufacturer;
261913e7732SSunnySrivastava1984         }
262913e7732SSunnySrivastava1984         if (model != nullptr)
263913e7732SSunnySrivastava1984         {
264913e7732SSunnySrivastava1984             aResp->res.jsonValue["Model"] = *model;
265913e7732SSunnySrivastava1984         }
266913e7732SSunnySrivastava1984 
267913e7732SSunnySrivastava1984         if (partNumber != nullptr)
268913e7732SSunnySrivastava1984         {
269913e7732SSunnySrivastava1984             aResp->res.jsonValue["PartNumber"] = *partNumber;
270913e7732SSunnySrivastava1984         }
271913e7732SSunnySrivastava1984 
272913e7732SSunnySrivastava1984         if (serialNumber != nullptr)
273913e7732SSunnySrivastava1984         {
274913e7732SSunnySrivastava1984             aResp->res.jsonValue["SerialNumber"] = *serialNumber;
275913e7732SSunnySrivastava1984         }
276913e7732SSunnySrivastava1984 
277913e7732SSunnySrivastava1984         if (sparePartNumber != nullptr && !sparePartNumber->empty())
278913e7732SSunnySrivastava1984         {
279913e7732SSunnySrivastava1984             aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
280913e7732SSunnySrivastava1984         }
281913e7732SSunnySrivastava1984         });
282913e7732SSunnySrivastava1984 }
283913e7732SSunnySrivastava1984 
284543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
28535ad613dSLakshmi Yadlapati     crow::Response& resp, const std::string& pcieDeviceId,
286543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
287f5c9f8bdSJason M. Bills {
288d1bde9e5SKrzysztof Grobelny     const std::string* manufacturer = nullptr;
289d1bde9e5SKrzysztof Grobelny     const std::string* deviceType = nullptr;
290d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
291543f9a75SLakshmi Yadlapati     const int64_t* lanesInUse = nullptr;
292d1bde9e5SKrzysztof Grobelny 
293d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
294543f9a75SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
295543f9a75SLakshmi Yadlapati         deviceType, "GenerationInUse", generationInUse, "LanesInUse",
296543f9a75SLakshmi Yadlapati         lanesInUse, "Manufacturer", manufacturer);
297d1bde9e5SKrzysztof Grobelny 
298d1bde9e5SKrzysztof Grobelny     if (!success)
299d1bde9e5SKrzysztof Grobelny     {
300543f9a75SLakshmi Yadlapati         messages::internalError(resp);
301d1bde9e5SKrzysztof Grobelny         return;
302d1bde9e5SKrzysztof Grobelny     }
303d1bde9e5SKrzysztof Grobelny 
304543f9a75SLakshmi Yadlapati     if (deviceType != nullptr && !deviceType->empty())
305703f6741SMyung Bae     {
306543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
307703f6741SMyung Bae     }
308703f6741SMyung Bae 
309d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
310d1bde9e5SKrzysztof Grobelny     {
3110ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
312d1bde9e5SKrzysztof Grobelny             redfishPcieGenerationFromDbus(*generationInUse);
313543f9a75SLakshmi Yadlapati 
314d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
315d1bde9e5SKrzysztof Grobelny         {
316543f9a75SLakshmi Yadlapati             messages::internalError(resp);
317d1bde9e5SKrzysztof Grobelny             return;
318d1bde9e5SKrzysztof Grobelny         }
3190ec8b83dSEd Tanous         if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
320d1bde9e5SKrzysztof Grobelny         {
321543f9a75SLakshmi Yadlapati             resp.jsonValue["PCIeInterface"]["PCIeType"] =
322d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
323d1bde9e5SKrzysztof Grobelny         }
324a9f68bb5STony Lee     }
325d1bde9e5SKrzysztof Grobelny 
326543f9a75SLakshmi Yadlapati     // The default value of LanesInUse is 0, and the field will be
327543f9a75SLakshmi Yadlapati     // left as off if it is a default value.
328543f9a75SLakshmi Yadlapati     if (lanesInUse != nullptr && *lanesInUse != 0)
329543f9a75SLakshmi Yadlapati     {
330543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
331543f9a75SLakshmi Yadlapati     }
332543f9a75SLakshmi Yadlapati 
333d1bde9e5SKrzysztof Grobelny     if (manufacturer != nullptr)
334d1bde9e5SKrzysztof Grobelny     {
335543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["Manufacturer"] = *manufacturer;
336543f9a75SLakshmi Yadlapati     }
33735ad613dSLakshmi Yadlapati 
33835ad613dSLakshmi Yadlapati     resp.jsonValue["PCIeFunctions"]["@odata.id"] = crow::utility::urlFromPieces(
33935ad613dSLakshmi Yadlapati         "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
34035ad613dSLakshmi Yadlapati         "PCIeFunctions");
341d1bde9e5SKrzysztof Grobelny }
342d1bde9e5SKrzysztof Grobelny 
343543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
344543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
345543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
346543f9a75SLakshmi Yadlapati     const std::function<void(
347543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
348d1bde9e5SKrzysztof Grobelny {
349543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
350543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
351543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
352543f9a75SLakshmi Yadlapati         [aResp,
353543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
354543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
355543f9a75SLakshmi Yadlapati         if (ec)
356543f9a75SLakshmi Yadlapati         {
357543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
358543f9a75SLakshmi Yadlapati             {
359543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
360543f9a75SLakshmi Yadlapati                 messages::internalError(aResp->res);
361543f9a75SLakshmi Yadlapati             }
362543f9a75SLakshmi Yadlapati             return;
363543f9a75SLakshmi Yadlapati         }
364543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
365543f9a75SLakshmi Yadlapati         });
366d1bde9e5SKrzysztof Grobelny }
367d1bde9e5SKrzysztof Grobelny 
368543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
369543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
370543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
371543f9a75SLakshmi Yadlapati {
372543f9a75SLakshmi Yadlapati     aResp->res.addHeader(
373543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
374543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
375543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
376543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
377543f9a75SLakshmi Yadlapati         "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId);
378543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["Name"] = "PCIe Device";
379543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["Id"] = pcieDeviceId;
380543f9a75SLakshmi Yadlapati }
3811476687dSEd Tanous 
382543f9a75SLakshmi Yadlapati inline void handlePCIeDeviceGet(App& app, const crow::Request& req,
383543f9a75SLakshmi Yadlapati                                 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
384543f9a75SLakshmi Yadlapati                                 const std::string& systemName,
385543f9a75SLakshmi Yadlapati                                 const std::string& pcieDeviceId)
386543f9a75SLakshmi Yadlapati {
387543f9a75SLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
388543f9a75SLakshmi Yadlapati     {
389543f9a75SLakshmi Yadlapati         return;
390543f9a75SLakshmi Yadlapati     }
391543f9a75SLakshmi Yadlapati     if (systemName != "system")
392543f9a75SLakshmi Yadlapati     {
393543f9a75SLakshmi Yadlapati         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
394543f9a75SLakshmi Yadlapati         return;
395543f9a75SLakshmi Yadlapati     }
396543f9a75SLakshmi Yadlapati 
397543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
398543f9a75SLakshmi Yadlapati         pcieDeviceId, aResp,
399543f9a75SLakshmi Yadlapati         [aResp, pcieDeviceId](const std::string& pcieDevicePath,
400543f9a75SLakshmi Yadlapati                               const std::string& service) {
401543f9a75SLakshmi Yadlapati         addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
402913e7732SSunnySrivastava1984         getPCIeDeviceAsset(aResp, pcieDevicePath, service);
403543f9a75SLakshmi Yadlapati         getPCIeDeviceProperties(
404543f9a75SLakshmi Yadlapati             aResp, pcieDevicePath, service,
40535ad613dSLakshmi Yadlapati             [aResp, pcieDeviceId](
40635ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
40735ad613dSLakshmi Yadlapati             addPCIeDeviceProperties(aResp->res, pcieDeviceId,
40835ad613dSLakshmi Yadlapati                                     pcieDevProperties);
4097e860f15SJohn Edward Broadbent             });
410543f9a75SLakshmi Yadlapati         });
411543f9a75SLakshmi Yadlapati }
412543f9a75SLakshmi Yadlapati 
413543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
414543f9a75SLakshmi Yadlapati {
415543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
416543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
417543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
418543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
419dede6a98SJason M. Bills }
420dede6a98SJason M. Bills 
42135ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
42235ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
42335ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
42435ad613dSLakshmi Yadlapati {
42535ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
42635ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
42735ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
42835ad613dSLakshmi Yadlapati 
42935ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
43035ad613dSLakshmi Yadlapati     {
43135ad613dSLakshmi Yadlapati         // Check if this function exists by
43235ad613dSLakshmi Yadlapati         // looking for a device ID
43335ad613dSLakshmi Yadlapati         std::string devIDProperty =
43435ad613dSLakshmi Yadlapati             "Function" + std::to_string(functionNum) + "DeviceId";
43535ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
43635ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
43735ad613dSLakshmi Yadlapati         {
43835ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
43935ad613dSLakshmi Yadlapati             {
44035ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
44135ad613dSLakshmi Yadlapati                 break;
44235ad613dSLakshmi Yadlapati             }
44335ad613dSLakshmi Yadlapati         }
44435ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
44535ad613dSLakshmi Yadlapati         {
44635ad613dSLakshmi Yadlapati             continue;
44735ad613dSLakshmi Yadlapati         }
44835ad613dSLakshmi Yadlapati 
44935ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
45035ad613dSLakshmi Yadlapati         pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
45135ad613dSLakshmi Yadlapati             "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
45235ad613dSLakshmi Yadlapati             "PCIeFunctions", std::to_string(functionNum));
45335ad613dSLakshmi Yadlapati         pcieFunctionList.push_back(std::move(pcieFunction));
45435ad613dSLakshmi Yadlapati     }
45535ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
45635ad613dSLakshmi Yadlapati }
45735ad613dSLakshmi Yadlapati 
45835ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
45935ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
46035ad613dSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
46135ad613dSLakshmi Yadlapati     const std::string& pcieDeviceId)
46235ad613dSLakshmi Yadlapati {
46335ad613dSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
46435ad613dSLakshmi Yadlapati     {
46535ad613dSLakshmi Yadlapati         return;
46635ad613dSLakshmi Yadlapati     }
46735ad613dSLakshmi Yadlapati 
46835ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
46935ad613dSLakshmi Yadlapati         pcieDeviceId, aResp,
47035ad613dSLakshmi Yadlapati         [aResp, pcieDeviceId](const std::string& pcieDevicePath,
47135ad613dSLakshmi Yadlapati                               const std::string& service) {
47235ad613dSLakshmi Yadlapati         aResp->res.addHeader(
47335ad613dSLakshmi Yadlapati             boost::beast::http::field::link,
47435ad613dSLakshmi Yadlapati             "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
47535ad613dSLakshmi Yadlapati         aResp->res.jsonValue["@odata.type"] =
47635ad613dSLakshmi Yadlapati             "#PCIeFunctionCollection.PCIeFunctionCollection";
47735ad613dSLakshmi Yadlapati         aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
47835ad613dSLakshmi Yadlapati             "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
47935ad613dSLakshmi Yadlapati             "PCIeFunctions");
48035ad613dSLakshmi Yadlapati         aResp->res.jsonValue["Name"] = "PCIe Function Collection";
48135ad613dSLakshmi Yadlapati         aResp->res.jsonValue["Description"] =
48235ad613dSLakshmi Yadlapati             "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
48335ad613dSLakshmi Yadlapati         getPCIeDeviceProperties(
48435ad613dSLakshmi Yadlapati             aResp, pcieDevicePath, service,
48535ad613dSLakshmi Yadlapati             [aResp, pcieDeviceId](
48635ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
48735ad613dSLakshmi Yadlapati             addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties);
48835ad613dSLakshmi Yadlapati             });
48935ad613dSLakshmi Yadlapati         });
49035ad613dSLakshmi Yadlapati }
49135ad613dSLakshmi Yadlapati 
4927e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
4937e860f15SJohn Edward Broadbent {
494dede6a98SJason M. Bills     /**
495dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
496dede6a98SJason M. Bills      */
4977e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
4987e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
499ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
500002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
50135ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
5027e860f15SJohn Edward Broadbent }
5037e860f15SJohn Edward Broadbent 
504727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
505727a046cSLakshmi Yadlapati     const std::string& pcieFunctionId,
506727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
5077e860f15SJohn Edward Broadbent {
508727a046cSLakshmi Yadlapati     std::string functionName = "Function" + pcieFunctionId;
509b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
510b9d36b47SEd Tanous 
511b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
512b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
513b9d36b47SEd Tanous     {
514b9d36b47SEd Tanous         if (property.first == devIDProperty)
515b9d36b47SEd Tanous         {
516002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
517727a046cSLakshmi Yadlapati             break;
518b9d36b47SEd Tanous         }
519b9d36b47SEd Tanous     }
520727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
521727a046cSLakshmi Yadlapati }
522727a046cSLakshmi Yadlapati 
523727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
524727a046cSLakshmi Yadlapati     crow::Response& resp, const std::string& pcieFunctionId,
525727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
526f5c9f8bdSJason M. Bills {
527727a046cSLakshmi Yadlapati     std::string functionName = "Function" + pcieFunctionId;
528727a046cSLakshmi Yadlapati     if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties))
529727a046cSLakshmi Yadlapati     {
530727a046cSLakshmi Yadlapati         messages::resourceNotFound(resp, "PCIeFunction", pcieFunctionId);
531f5c9f8bdSJason M. Bills         return;
532f5c9f8bdSJason M. Bills     }
533b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
534f5c9f8bdSJason M. Bills     {
535b9d36b47SEd Tanous         const std::string* strProperty =
536b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
537727a046cSLakshmi Yadlapati 
538b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
539f5c9f8bdSJason M. Bills         {
540727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
541f5c9f8bdSJason M. Bills         }
542b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
543f5c9f8bdSJason M. Bills         {
544727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
545f5c9f8bdSJason M. Bills         }
546727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
547727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
548727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
549b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
550f5c9f8bdSJason M. Bills         {
551727a046cSLakshmi Yadlapati             if (!strProperty->empty())
552727a046cSLakshmi Yadlapati             {
553727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
554727a046cSLakshmi Yadlapati             }
555f5c9f8bdSJason M. Bills         }
556b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
557f5c9f8bdSJason M. Bills         {
558727a046cSLakshmi Yadlapati             if (!strProperty->empty())
559727a046cSLakshmi Yadlapati             {
560727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
561727a046cSLakshmi Yadlapati             }
562f5c9f8bdSJason M. Bills         }
563b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
564f5c9f8bdSJason M. Bills         {
565727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
566f5c9f8bdSJason M. Bills         }
567b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
568f5c9f8bdSJason M. Bills         {
569727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
570f5c9f8bdSJason M. Bills         }
571b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
572b9d36b47SEd Tanous         {
573727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
574b9d36b47SEd Tanous         }
575002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
576f5c9f8bdSJason M. Bills         {
577727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
578b9d36b47SEd Tanous         }
579f5c9f8bdSJason M. Bills     }
580727a046cSLakshmi Yadlapati }
581727a046cSLakshmi Yadlapati 
582727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
583727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
584727a046cSLakshmi Yadlapati                                             const std::string& pcieFunctionId)
585727a046cSLakshmi Yadlapati {
586727a046cSLakshmi Yadlapati     resp.addHeader(
587727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
588727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
589727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
590727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
591727a046cSLakshmi Yadlapati         "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
592727a046cSLakshmi Yadlapati         "PCIeFunctions", pcieFunctionId);
593727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
594727a046cSLakshmi Yadlapati     resp.jsonValue["Id"] = pcieFunctionId;
595727a046cSLakshmi Yadlapati     resp.jsonValue["FunctionId"] = std::stoi(pcieFunctionId);
596727a046cSLakshmi Yadlapati     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
597727a046cSLakshmi Yadlapati         crow::utility::urlFromPieces("redfish", "v1", "Systems", "system",
598727a046cSLakshmi Yadlapati                                      "PCIeDevices", pcieDeviceId);
599727a046cSLakshmi Yadlapati }
600727a046cSLakshmi Yadlapati 
601727a046cSLakshmi Yadlapati inline void
602727a046cSLakshmi Yadlapati     handlePCIeFunctionGet(App& app, const crow::Request& req,
603727a046cSLakshmi Yadlapati                           const std::shared_ptr<bmcweb::AsyncResp>& aResp,
604727a046cSLakshmi Yadlapati                           const std::string& pcieDeviceId,
605727a046cSLakshmi Yadlapati                           const std::string& pcieFunctionId)
606727a046cSLakshmi Yadlapati {
607727a046cSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
608727a046cSLakshmi Yadlapati     {
609727a046cSLakshmi Yadlapati         return;
610727a046cSLakshmi Yadlapati     }
611727a046cSLakshmi Yadlapati 
612727a046cSLakshmi Yadlapati     getValidPCIeDevicePath(
613727a046cSLakshmi Yadlapati         pcieDeviceId, aResp,
614727a046cSLakshmi Yadlapati         [aResp, pcieDeviceId, pcieFunctionId](const std::string& pcieDevicePath,
615727a046cSLakshmi Yadlapati                                               const std::string& service) {
616727a046cSLakshmi Yadlapati         getPCIeDeviceProperties(
617727a046cSLakshmi Yadlapati             aResp, pcieDevicePath, service,
618727a046cSLakshmi Yadlapati             [aResp, pcieDeviceId, pcieFunctionId](
619727a046cSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
620727a046cSLakshmi Yadlapati             addPCIeFunctionCommonProperties(aResp->res, pcieDeviceId,
621727a046cSLakshmi Yadlapati                                             pcieFunctionId);
622727a046cSLakshmi Yadlapati             addPCIeFunctionProperties(aResp->res, pcieFunctionId,
623727a046cSLakshmi Yadlapati                                       pcieDevProperties);
6247e860f15SJohn Edward Broadbent             });
625727a046cSLakshmi Yadlapati         });
626727a046cSLakshmi Yadlapati }
627727a046cSLakshmi Yadlapati 
628727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
629727a046cSLakshmi Yadlapati {
630727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
631727a046cSLakshmi Yadlapati         app,
632727a046cSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
633727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
634727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
635727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
636f5c9f8bdSJason M. Bills }
637f5c9f8bdSJason M. Bills 
638f5c9f8bdSJason M. Bills } // namespace redfish
639