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 34f5c9f8bdSJason M. Bills static constexpr char const* pcieService = "xyz.openbmc_project.PCIe"; 35f5c9f8bdSJason M. Bills static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe"; 36f5c9f8bdSJason M. Bills static constexpr char const* pcieDeviceInterface = 37b8f38eadSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"; 38f5c9f8bdSJason M. Bills 39543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath( 40543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 41543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 42543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 43543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 44543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 45543f9a75SLakshmi Yadlapati 46543f9a75SLakshmi Yadlapati { 47543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 48543f9a75SLakshmi Yadlapati { 49543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 50543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 51543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 52543f9a75SLakshmi Yadlapati { 53543f9a75SLakshmi Yadlapati continue; 54543f9a75SLakshmi Yadlapati } 55543f9a75SLakshmi Yadlapati 56543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 57543f9a75SLakshmi Yadlapati pcieDevicePath, {}, 58543f9a75SLakshmi Yadlapati [pcieDevicePath, aResp, 59543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 60543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 61543f9a75SLakshmi Yadlapati if (ec || object.empty()) 62543f9a75SLakshmi Yadlapati { 63543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error " << ec; 64543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 65543f9a75SLakshmi Yadlapati return; 66543f9a75SLakshmi Yadlapati } 67543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 68543f9a75SLakshmi Yadlapati }); 69543f9a75SLakshmi Yadlapati return; 70543f9a75SLakshmi Yadlapati } 71543f9a75SLakshmi Yadlapati 72543f9a75SLakshmi Yadlapati BMCWEB_LOG_WARNING << "PCIe Device not found"; 73543f9a75SLakshmi Yadlapati messages::resourceNotFound(aResp->res, "PCIeDevice", pcieDeviceId); 74543f9a75SLakshmi Yadlapati } 75543f9a75SLakshmi Yadlapati 76543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath( 77543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 78543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 79543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 80543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 81543f9a75SLakshmi Yadlapati { 82543f9a75SLakshmi Yadlapati constexpr std::array<std::string_view, 1> interfaces{ 83543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 84543f9a75SLakshmi Yadlapati 85543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 86543f9a75SLakshmi Yadlapati "/xyz/openbmc_project/inventory", 0, interfaces, 87543f9a75SLakshmi Yadlapati [pcieDeviceId, aResp, 88543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 89543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 90543f9a75SLakshmi Yadlapati pcieDevicePaths) { 91543f9a75SLakshmi Yadlapati if (ec) 92543f9a75SLakshmi Yadlapati { 93543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec; 94543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 95543f9a75SLakshmi Yadlapati return; 96543f9a75SLakshmi Yadlapati } 97543f9a75SLakshmi Yadlapati handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback); 98543f9a75SLakshmi Yadlapati return; 99543f9a75SLakshmi Yadlapati }); 100543f9a75SLakshmi Yadlapati } 101543f9a75SLakshmi Yadlapati 102b5a76932SEd Tanous static inline void 1038d1b46d7Szhanghch05 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 104adbe192aSJason M. Bills const std::string& name) 105f5c9f8bdSJason M. Bills { 1067a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 1077a1dbc48SGeorge Liu pciePath, 1, {}, 1087a1dbc48SGeorge Liu [asyncResp, name](const boost::system::error_code& ec, 109b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 110b9d36b47SEd Tanous pcieDevicePaths) { 111f5c9f8bdSJason M. Bills if (ec) 112f5c9f8bdSJason M. Bills { 113a2730f01SAndrew Geissler BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: " 114f5c9f8bdSJason M. Bills << ec.message(); 115a2730f01SAndrew Geissler // Not an error, system just doesn't have PCIe info 116f5c9f8bdSJason M. Bills return; 117f5c9f8bdSJason M. Bills } 118adbe192aSJason M. Bills nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name]; 119f5c9f8bdSJason M. Bills pcieDeviceList = nlohmann::json::array(); 120f5c9f8bdSJason M. Bills for (const std::string& pcieDevicePath : pcieDevicePaths) 121f5c9f8bdSJason M. Bills { 1223174e4dfSEd Tanous size_t devStart = pcieDevicePath.rfind('/'); 123f5c9f8bdSJason M. Bills if (devStart == std::string::npos) 124f5c9f8bdSJason M. Bills { 125f5c9f8bdSJason M. Bills continue; 126f5c9f8bdSJason M. Bills } 127f5c9f8bdSJason M. Bills 128f5c9f8bdSJason M. Bills std::string devName = pcieDevicePath.substr(devStart + 1); 129f5c9f8bdSJason M. Bills if (devName.empty()) 130f5c9f8bdSJason M. Bills { 131f5c9f8bdSJason M. Bills continue; 132f5c9f8bdSJason M. Bills } 1331476687dSEd Tanous nlohmann::json::object_t pcieDevice; 134eddfc437SWilly Tu pcieDevice["@odata.id"] = crow::utility::urlFromPieces( 135eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "PCIeDevices", devName); 1361476687dSEd Tanous pcieDeviceList.push_back(std::move(pcieDevice)); 137f5c9f8bdSJason M. Bills } 138002d39b4SEd Tanous asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size(); 1397a1dbc48SGeorge Liu }); 140f5c9f8bdSJason M. Bills } 141f5c9f8bdSJason M. Bills 142b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet( 143b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 144b38fa2abSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 145b38fa2abSLakshmi Yadlapati const std::string& systemName) 146b38fa2abSLakshmi Yadlapati { 147b38fa2abSLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 148b38fa2abSLakshmi Yadlapati { 149b38fa2abSLakshmi Yadlapati return; 150b38fa2abSLakshmi Yadlapati } 151b38fa2abSLakshmi Yadlapati if (systemName != "system") 152b38fa2abSLakshmi Yadlapati { 153b38fa2abSLakshmi Yadlapati messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 154b38fa2abSLakshmi Yadlapati return; 155b38fa2abSLakshmi Yadlapati } 156543f9a75SLakshmi Yadlapati 157b38fa2abSLakshmi Yadlapati aResp->res.addHeader(boost::beast::http::field::link, 158b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 159b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 160b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["@odata.type"] = 161b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 162b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["@odata.id"] = 163b38fa2abSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices"; 164b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Name"] = "PCIe Device Collection"; 165b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 166b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Members"] = nlohmann::json::array(); 167b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Members@odata.count"] = 0; 168b38fa2abSLakshmi Yadlapati 169b38fa2abSLakshmi Yadlapati constexpr std::array<std::string_view, 1> interfaces{ 170b38fa2abSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 171b38fa2abSLakshmi Yadlapati collection_util::getCollectionMembers( 172b38fa2abSLakshmi Yadlapati aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"), 173b38fa2abSLakshmi Yadlapati interfaces); 174b38fa2abSLakshmi Yadlapati } 175b38fa2abSLakshmi Yadlapati 1767e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 177adbe192aSJason M. Bills { 178adbe192aSJason M. Bills /** 179adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 180adbe192aSJason M. Bills */ 18122d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 182ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1837e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 184b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 185f5c9f8bdSJason M. Bills } 186f5c9f8bdSJason M. Bills 1870ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes> 18862cd45afSSpencer Ku redfishPcieGenerationFromDbus(const std::string& generationInUse) 18962cd45afSSpencer Ku { 19062cd45afSSpencer Ku if (generationInUse == 19162cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1") 19262cd45afSSpencer Ku { 1930ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen1; 19462cd45afSSpencer Ku } 19562cd45afSSpencer Ku if (generationInUse == 19662cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2") 19762cd45afSSpencer Ku { 1980ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen2; 19962cd45afSSpencer Ku } 20062cd45afSSpencer Ku if (generationInUse == 20162cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3") 20262cd45afSSpencer Ku { 2030ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen3; 20462cd45afSSpencer Ku } 20562cd45afSSpencer Ku if (generationInUse == 20662cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4") 20762cd45afSSpencer Ku { 2080ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen4; 20962cd45afSSpencer Ku } 21062cd45afSSpencer Ku if (generationInUse == 21162cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5") 21262cd45afSSpencer Ku { 2130ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen5; 21462cd45afSSpencer Ku } 215e825cbc8SEd Tanous if (generationInUse.empty() || 216e825cbc8SEd Tanous generationInUse == 21762cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown") 21862cd45afSSpencer Ku { 2190ec8b83dSEd Tanous return pcie_device::PCIeTypes::Invalid; 22062cd45afSSpencer Ku } 22162cd45afSSpencer Ku 22262cd45afSSpencer Ku // The value is not unknown or Gen1-5, need return an internal error. 22362cd45afSSpencer Ku return std::nullopt; 22462cd45afSSpencer Ku } 22562cd45afSSpencer Ku 226543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 22735ad613dSLakshmi Yadlapati crow::Response& resp, const std::string& pcieDeviceId, 228543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 229f5c9f8bdSJason M. Bills { 230d1bde9e5SKrzysztof Grobelny const std::string* manufacturer = nullptr; 231d1bde9e5SKrzysztof Grobelny const std::string* deviceType = nullptr; 232d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 233543f9a75SLakshmi Yadlapati const int64_t* lanesInUse = nullptr; 234d1bde9e5SKrzysztof Grobelny 235d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 236543f9a75SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType", 237543f9a75SLakshmi Yadlapati deviceType, "GenerationInUse", generationInUse, "LanesInUse", 238543f9a75SLakshmi Yadlapati lanesInUse, "Manufacturer", manufacturer); 239d1bde9e5SKrzysztof Grobelny 240d1bde9e5SKrzysztof Grobelny if (!success) 241d1bde9e5SKrzysztof Grobelny { 242543f9a75SLakshmi Yadlapati messages::internalError(resp); 243d1bde9e5SKrzysztof Grobelny return; 244d1bde9e5SKrzysztof Grobelny } 245d1bde9e5SKrzysztof Grobelny 246543f9a75SLakshmi Yadlapati if (deviceType != nullptr && !deviceType->empty()) 247703f6741SMyung Bae { 248543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType; 249703f6741SMyung Bae } 250703f6741SMyung Bae 251d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 252d1bde9e5SKrzysztof Grobelny { 2530ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 254d1bde9e5SKrzysztof Grobelny redfishPcieGenerationFromDbus(*generationInUse); 255543f9a75SLakshmi Yadlapati 256d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 257d1bde9e5SKrzysztof Grobelny { 258543f9a75SLakshmi Yadlapati messages::internalError(resp); 259d1bde9e5SKrzysztof Grobelny return; 260d1bde9e5SKrzysztof Grobelny } 2610ec8b83dSEd Tanous if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid) 262d1bde9e5SKrzysztof Grobelny { 263543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["PCIeType"] = 264d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 265d1bde9e5SKrzysztof Grobelny } 266a9f68bb5STony Lee } 267d1bde9e5SKrzysztof Grobelny 268543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 269543f9a75SLakshmi Yadlapati // left as off if it is a default value. 270543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 271543f9a75SLakshmi Yadlapati { 272543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 273543f9a75SLakshmi Yadlapati } 274543f9a75SLakshmi Yadlapati 275d1bde9e5SKrzysztof Grobelny if (manufacturer != nullptr) 276d1bde9e5SKrzysztof Grobelny { 277543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["Manufacturer"] = *manufacturer; 278543f9a75SLakshmi Yadlapati } 27935ad613dSLakshmi Yadlapati 28035ad613dSLakshmi Yadlapati resp.jsonValue["PCIeFunctions"]["@odata.id"] = crow::utility::urlFromPieces( 28135ad613dSLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId, 28235ad613dSLakshmi Yadlapati "PCIeFunctions"); 283d1bde9e5SKrzysztof Grobelny } 284d1bde9e5SKrzysztof Grobelny 285543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 286543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 287543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 288543f9a75SLakshmi Yadlapati const std::function<void( 289543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 290d1bde9e5SKrzysztof Grobelny { 291543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 292543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 293543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 294543f9a75SLakshmi Yadlapati [aResp, 295543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 296543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 297543f9a75SLakshmi Yadlapati if (ec) 298543f9a75SLakshmi Yadlapati { 299543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 300543f9a75SLakshmi Yadlapati { 301543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 302543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 303543f9a75SLakshmi Yadlapati } 304543f9a75SLakshmi Yadlapati return; 305543f9a75SLakshmi Yadlapati } 306543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 307543f9a75SLakshmi Yadlapati }); 308d1bde9e5SKrzysztof Grobelny } 309d1bde9e5SKrzysztof Grobelny 310543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 311543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 312543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 313543f9a75SLakshmi Yadlapati { 314543f9a75SLakshmi Yadlapati aResp->res.addHeader( 315543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 316543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 317543f9a75SLakshmi Yadlapati aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 318543f9a75SLakshmi Yadlapati aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 319543f9a75SLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId); 320543f9a75SLakshmi Yadlapati aResp->res.jsonValue["Name"] = "PCIe Device"; 321543f9a75SLakshmi Yadlapati aResp->res.jsonValue["Id"] = pcieDeviceId; 322543f9a75SLakshmi Yadlapati } 3231476687dSEd Tanous 324543f9a75SLakshmi Yadlapati inline void handlePCIeDeviceGet(App& app, const crow::Request& req, 325543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 326543f9a75SLakshmi Yadlapati const std::string& systemName, 327543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 328543f9a75SLakshmi Yadlapati { 329543f9a75SLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 330543f9a75SLakshmi Yadlapati { 331543f9a75SLakshmi Yadlapati return; 332543f9a75SLakshmi Yadlapati } 333543f9a75SLakshmi Yadlapati if (systemName != "system") 334543f9a75SLakshmi Yadlapati { 335543f9a75SLakshmi Yadlapati messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 336543f9a75SLakshmi Yadlapati return; 337543f9a75SLakshmi Yadlapati } 338543f9a75SLakshmi Yadlapati 339543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 340543f9a75SLakshmi Yadlapati pcieDeviceId, aResp, 341543f9a75SLakshmi Yadlapati [aResp, pcieDeviceId](const std::string& pcieDevicePath, 342543f9a75SLakshmi Yadlapati const std::string& service) { 343543f9a75SLakshmi Yadlapati addPCIeDeviceCommonProperties(aResp, pcieDeviceId); 344543f9a75SLakshmi Yadlapati getPCIeDeviceProperties( 345543f9a75SLakshmi Yadlapati aResp, pcieDevicePath, service, 34635ad613dSLakshmi Yadlapati [aResp, pcieDeviceId]( 34735ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 34835ad613dSLakshmi Yadlapati addPCIeDeviceProperties(aResp->res, pcieDeviceId, 34935ad613dSLakshmi Yadlapati pcieDevProperties); 3507e860f15SJohn Edward Broadbent }); 351543f9a75SLakshmi Yadlapati }); 352543f9a75SLakshmi Yadlapati } 353543f9a75SLakshmi Yadlapati 354543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 355543f9a75SLakshmi Yadlapati { 356543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 357543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 358543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 359543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 360dede6a98SJason M. Bills } 361dede6a98SJason M. Bills 36235ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 36335ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 36435ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 36535ad613dSLakshmi Yadlapati { 36635ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 36735ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 36835ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 36935ad613dSLakshmi Yadlapati 37035ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 37135ad613dSLakshmi Yadlapati { 37235ad613dSLakshmi Yadlapati // Check if this function exists by 37335ad613dSLakshmi Yadlapati // looking for a device ID 37435ad613dSLakshmi Yadlapati std::string devIDProperty = 37535ad613dSLakshmi Yadlapati "Function" + std::to_string(functionNum) + "DeviceId"; 37635ad613dSLakshmi Yadlapati const std::string* property = nullptr; 37735ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 37835ad613dSLakshmi Yadlapati { 37935ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 38035ad613dSLakshmi Yadlapati { 38135ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 38235ad613dSLakshmi Yadlapati break; 38335ad613dSLakshmi Yadlapati } 38435ad613dSLakshmi Yadlapati } 38535ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 38635ad613dSLakshmi Yadlapati { 38735ad613dSLakshmi Yadlapati continue; 38835ad613dSLakshmi Yadlapati } 38935ad613dSLakshmi Yadlapati 39035ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 39135ad613dSLakshmi Yadlapati pcieFunction["@odata.id"] = crow::utility::urlFromPieces( 39235ad613dSLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId, 39335ad613dSLakshmi Yadlapati "PCIeFunctions", std::to_string(functionNum)); 39435ad613dSLakshmi Yadlapati pcieFunctionList.push_back(std::move(pcieFunction)); 39535ad613dSLakshmi Yadlapati } 39635ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 39735ad613dSLakshmi Yadlapati } 39835ad613dSLakshmi Yadlapati 39935ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 40035ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 40135ad613dSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 40235ad613dSLakshmi Yadlapati const std::string& pcieDeviceId) 40335ad613dSLakshmi Yadlapati { 40435ad613dSLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 40535ad613dSLakshmi Yadlapati { 40635ad613dSLakshmi Yadlapati return; 40735ad613dSLakshmi Yadlapati } 40835ad613dSLakshmi Yadlapati 40935ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 41035ad613dSLakshmi Yadlapati pcieDeviceId, aResp, 41135ad613dSLakshmi Yadlapati [aResp, pcieDeviceId](const std::string& pcieDevicePath, 41235ad613dSLakshmi Yadlapati const std::string& service) { 41335ad613dSLakshmi Yadlapati aResp->res.addHeader( 41435ad613dSLakshmi Yadlapati boost::beast::http::field::link, 41535ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 41635ad613dSLakshmi Yadlapati aResp->res.jsonValue["@odata.type"] = 41735ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 41835ad613dSLakshmi Yadlapati aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 41935ad613dSLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId, 42035ad613dSLakshmi Yadlapati "PCIeFunctions"); 42135ad613dSLakshmi Yadlapati aResp->res.jsonValue["Name"] = "PCIe Function Collection"; 42235ad613dSLakshmi Yadlapati aResp->res.jsonValue["Description"] = 42335ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 42435ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 42535ad613dSLakshmi Yadlapati aResp, pcieDevicePath, service, 42635ad613dSLakshmi Yadlapati [aResp, pcieDeviceId]( 42735ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 42835ad613dSLakshmi Yadlapati addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties); 42935ad613dSLakshmi Yadlapati }); 43035ad613dSLakshmi Yadlapati }); 43135ad613dSLakshmi Yadlapati } 43235ad613dSLakshmi Yadlapati 4337e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 4347e860f15SJohn Edward Broadbent { 435dede6a98SJason M. Bills /** 436dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 437dede6a98SJason M. Bills */ 4387e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 4397e860f15SJohn Edward Broadbent "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/") 440ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 441002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 44235ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 4437e860f15SJohn Edward Broadbent } 4447e860f15SJohn Edward Broadbent 445*727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 446*727a046cSLakshmi Yadlapati const std::string& pcieFunctionId, 447*727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 4487e860f15SJohn Edward Broadbent { 449*727a046cSLakshmi Yadlapati std::string functionName = "Function" + pcieFunctionId; 450b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 451b9d36b47SEd Tanous 452b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 453b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 454b9d36b47SEd Tanous { 455b9d36b47SEd Tanous if (property.first == devIDProperty) 456b9d36b47SEd Tanous { 457002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 458*727a046cSLakshmi Yadlapati break; 459b9d36b47SEd Tanous } 460b9d36b47SEd Tanous } 461*727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 462*727a046cSLakshmi Yadlapati } 463*727a046cSLakshmi Yadlapati 464*727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 465*727a046cSLakshmi Yadlapati crow::Response& resp, const std::string& pcieFunctionId, 466*727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 467f5c9f8bdSJason M. Bills { 468*727a046cSLakshmi Yadlapati std::string functionName = "Function" + pcieFunctionId; 469*727a046cSLakshmi Yadlapati if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties)) 470*727a046cSLakshmi Yadlapati { 471*727a046cSLakshmi Yadlapati messages::resourceNotFound(resp, "PCIeFunction", pcieFunctionId); 472f5c9f8bdSJason M. Bills return; 473f5c9f8bdSJason M. Bills } 474b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 475f5c9f8bdSJason M. Bills { 476b9d36b47SEd Tanous const std::string* strProperty = 477b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 478*727a046cSLakshmi Yadlapati 479b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 480f5c9f8bdSJason M. Bills { 481*727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 482f5c9f8bdSJason M. Bills } 483b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 484f5c9f8bdSJason M. Bills { 485*727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 486f5c9f8bdSJason M. Bills } 487*727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 488*727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 489*727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 490b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 491f5c9f8bdSJason M. Bills { 492*727a046cSLakshmi Yadlapati if (!strProperty->empty()) 493*727a046cSLakshmi Yadlapati { 494*727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 495*727a046cSLakshmi Yadlapati } 496f5c9f8bdSJason M. Bills } 497b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 498f5c9f8bdSJason M. Bills { 499*727a046cSLakshmi Yadlapati if (!strProperty->empty()) 500*727a046cSLakshmi Yadlapati { 501*727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 502*727a046cSLakshmi Yadlapati } 503f5c9f8bdSJason M. Bills } 504b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 505f5c9f8bdSJason M. Bills { 506*727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 507f5c9f8bdSJason M. Bills } 508b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 509f5c9f8bdSJason M. Bills { 510*727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 511f5c9f8bdSJason M. Bills } 512b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 513b9d36b47SEd Tanous { 514*727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 515b9d36b47SEd Tanous } 516002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 517f5c9f8bdSJason M. Bills { 518*727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 519b9d36b47SEd Tanous } 520f5c9f8bdSJason M. Bills } 521*727a046cSLakshmi Yadlapati } 522*727a046cSLakshmi Yadlapati 523*727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 524*727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 525*727a046cSLakshmi Yadlapati const std::string& pcieFunctionId) 526*727a046cSLakshmi Yadlapati { 527*727a046cSLakshmi Yadlapati resp.addHeader( 528*727a046cSLakshmi Yadlapati boost::beast::http::field::link, 529*727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 530*727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 531*727a046cSLakshmi Yadlapati resp.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 532*727a046cSLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId, 533*727a046cSLakshmi Yadlapati "PCIeFunctions", pcieFunctionId); 534*727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 535*727a046cSLakshmi Yadlapati resp.jsonValue["Id"] = pcieFunctionId; 536*727a046cSLakshmi Yadlapati resp.jsonValue["FunctionId"] = std::stoi(pcieFunctionId); 537*727a046cSLakshmi Yadlapati resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 538*727a046cSLakshmi Yadlapati crow::utility::urlFromPieces("redfish", "v1", "Systems", "system", 539*727a046cSLakshmi Yadlapati "PCIeDevices", pcieDeviceId); 540*727a046cSLakshmi Yadlapati } 541*727a046cSLakshmi Yadlapati 542*727a046cSLakshmi Yadlapati inline void 543*727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 544*727a046cSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 545*727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 546*727a046cSLakshmi Yadlapati const std::string& pcieFunctionId) 547*727a046cSLakshmi Yadlapati { 548*727a046cSLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 549*727a046cSLakshmi Yadlapati { 550*727a046cSLakshmi Yadlapati return; 551*727a046cSLakshmi Yadlapati } 552*727a046cSLakshmi Yadlapati 553*727a046cSLakshmi Yadlapati getValidPCIeDevicePath( 554*727a046cSLakshmi Yadlapati pcieDeviceId, aResp, 555*727a046cSLakshmi Yadlapati [aResp, pcieDeviceId, pcieFunctionId](const std::string& pcieDevicePath, 556*727a046cSLakshmi Yadlapati const std::string& service) { 557*727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 558*727a046cSLakshmi Yadlapati aResp, pcieDevicePath, service, 559*727a046cSLakshmi Yadlapati [aResp, pcieDeviceId, pcieFunctionId]( 560*727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 561*727a046cSLakshmi Yadlapati addPCIeFunctionCommonProperties(aResp->res, pcieDeviceId, 562*727a046cSLakshmi Yadlapati pcieFunctionId); 563*727a046cSLakshmi Yadlapati addPCIeFunctionProperties(aResp->res, pcieFunctionId, 564*727a046cSLakshmi Yadlapati pcieDevProperties); 5657e860f15SJohn Edward Broadbent }); 566*727a046cSLakshmi Yadlapati }); 567*727a046cSLakshmi Yadlapati } 568*727a046cSLakshmi Yadlapati 569*727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 570*727a046cSLakshmi Yadlapati { 571*727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 572*727a046cSLakshmi Yadlapati app, 573*727a046cSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/") 574*727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 575*727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 576*727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 577f5c9f8bdSJason M. Bills } 578f5c9f8bdSJason M. Bills 579f5c9f8bdSJason M. Bills } // namespace redfish 580