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 39*543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath( 40*543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 41*543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 42*543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 43*543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 44*543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 45*543f9a75SLakshmi Yadlapati 46*543f9a75SLakshmi Yadlapati { 47*543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 48*543f9a75SLakshmi Yadlapati { 49*543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 50*543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 51*543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 52*543f9a75SLakshmi Yadlapati { 53*543f9a75SLakshmi Yadlapati continue; 54*543f9a75SLakshmi Yadlapati } 55*543f9a75SLakshmi Yadlapati 56*543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 57*543f9a75SLakshmi Yadlapati pcieDevicePath, {}, 58*543f9a75SLakshmi Yadlapati [pcieDevicePath, aResp, 59*543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 60*543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 61*543f9a75SLakshmi Yadlapati if (ec || object.empty()) 62*543f9a75SLakshmi Yadlapati { 63*543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error " << ec; 64*543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 65*543f9a75SLakshmi Yadlapati return; 66*543f9a75SLakshmi Yadlapati } 67*543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 68*543f9a75SLakshmi Yadlapati }); 69*543f9a75SLakshmi Yadlapati return; 70*543f9a75SLakshmi Yadlapati } 71*543f9a75SLakshmi Yadlapati 72*543f9a75SLakshmi Yadlapati BMCWEB_LOG_WARNING << "PCIe Device not found"; 73*543f9a75SLakshmi Yadlapati messages::resourceNotFound(aResp->res, "PCIeDevice", pcieDeviceId); 74*543f9a75SLakshmi Yadlapati } 75*543f9a75SLakshmi Yadlapati 76*543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath( 77*543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 78*543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 79*543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 80*543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 81*543f9a75SLakshmi Yadlapati { 82*543f9a75SLakshmi Yadlapati constexpr std::array<std::string_view, 1> interfaces{ 83*543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 84*543f9a75SLakshmi Yadlapati 85*543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 86*543f9a75SLakshmi Yadlapati "/xyz/openbmc_project/inventory", 0, interfaces, 87*543f9a75SLakshmi Yadlapati [pcieDeviceId, aResp, 88*543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 89*543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 90*543f9a75SLakshmi Yadlapati pcieDevicePaths) { 91*543f9a75SLakshmi Yadlapati if (ec) 92*543f9a75SLakshmi Yadlapati { 93*543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec; 94*543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 95*543f9a75SLakshmi Yadlapati return; 96*543f9a75SLakshmi Yadlapati } 97*543f9a75SLakshmi Yadlapati handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback); 98*543f9a75SLakshmi Yadlapati return; 99*543f9a75SLakshmi Yadlapati }); 100*543f9a75SLakshmi Yadlapati } 101*543f9a75SLakshmi 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 } 156*543f9a75SLakshmi 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 226*543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 227*543f9a75SLakshmi Yadlapati crow::Response& resp, 228*543f9a75SLakshmi 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; 233*543f9a75SLakshmi Yadlapati const int64_t* lanesInUse = nullptr; 234d1bde9e5SKrzysztof Grobelny 235d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 236*543f9a75SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType", 237*543f9a75SLakshmi Yadlapati deviceType, "GenerationInUse", generationInUse, "LanesInUse", 238*543f9a75SLakshmi Yadlapati lanesInUse, "Manufacturer", manufacturer); 239d1bde9e5SKrzysztof Grobelny 240d1bde9e5SKrzysztof Grobelny if (!success) 241d1bde9e5SKrzysztof Grobelny { 242*543f9a75SLakshmi Yadlapati messages::internalError(resp); 243d1bde9e5SKrzysztof Grobelny return; 244d1bde9e5SKrzysztof Grobelny } 245d1bde9e5SKrzysztof Grobelny 246*543f9a75SLakshmi Yadlapati if (deviceType != nullptr && !deviceType->empty()) 247703f6741SMyung Bae { 248*543f9a75SLakshmi 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); 255*543f9a75SLakshmi Yadlapati 256d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 257d1bde9e5SKrzysztof Grobelny { 258*543f9a75SLakshmi Yadlapati messages::internalError(resp); 259d1bde9e5SKrzysztof Grobelny return; 260d1bde9e5SKrzysztof Grobelny } 2610ec8b83dSEd Tanous if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid) 262d1bde9e5SKrzysztof Grobelny { 263*543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["PCIeType"] = 264d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 265d1bde9e5SKrzysztof Grobelny } 266a9f68bb5STony Lee } 267d1bde9e5SKrzysztof Grobelny 268*543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 269*543f9a75SLakshmi Yadlapati // left as off if it is a default value. 270*543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 271*543f9a75SLakshmi Yadlapati { 272*543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 273*543f9a75SLakshmi Yadlapati } 274*543f9a75SLakshmi Yadlapati 275d1bde9e5SKrzysztof Grobelny if (manufacturer != nullptr) 276d1bde9e5SKrzysztof Grobelny { 277*543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["Manufacturer"] = *manufacturer; 278*543f9a75SLakshmi Yadlapati } 279d1bde9e5SKrzysztof Grobelny } 280d1bde9e5SKrzysztof Grobelny 281*543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 282*543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 283*543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 284*543f9a75SLakshmi Yadlapati const std::function<void( 285*543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 286d1bde9e5SKrzysztof Grobelny { 287*543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 288*543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 289*543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 290*543f9a75SLakshmi Yadlapati [aResp, 291*543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 292*543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 293*543f9a75SLakshmi Yadlapati if (ec) 294*543f9a75SLakshmi Yadlapati { 295*543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 296*543f9a75SLakshmi Yadlapati { 297*543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 298*543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 299*543f9a75SLakshmi Yadlapati } 300*543f9a75SLakshmi Yadlapati return; 301*543f9a75SLakshmi Yadlapati } 302*543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 303*543f9a75SLakshmi Yadlapati }); 304d1bde9e5SKrzysztof Grobelny } 305d1bde9e5SKrzysztof Grobelny 306*543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 307*543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 308*543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 309*543f9a75SLakshmi Yadlapati { 310*543f9a75SLakshmi Yadlapati aResp->res.addHeader( 311*543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 312*543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 313*543f9a75SLakshmi Yadlapati aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 314*543f9a75SLakshmi Yadlapati aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 315*543f9a75SLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId); 316*543f9a75SLakshmi Yadlapati aResp->res.jsonValue["Name"] = "PCIe Device"; 317*543f9a75SLakshmi Yadlapati aResp->res.jsonValue["Id"] = pcieDeviceId; 318*543f9a75SLakshmi Yadlapati } 3191476687dSEd Tanous 320*543f9a75SLakshmi Yadlapati inline void handlePCIeDeviceGet(App& app, const crow::Request& req, 321*543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 322*543f9a75SLakshmi Yadlapati const std::string& systemName, 323*543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 324*543f9a75SLakshmi Yadlapati { 325*543f9a75SLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 326*543f9a75SLakshmi Yadlapati { 327*543f9a75SLakshmi Yadlapati return; 328*543f9a75SLakshmi Yadlapati } 329*543f9a75SLakshmi Yadlapati if (systemName != "system") 330*543f9a75SLakshmi Yadlapati { 331*543f9a75SLakshmi Yadlapati messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 332*543f9a75SLakshmi Yadlapati return; 333*543f9a75SLakshmi Yadlapati } 334*543f9a75SLakshmi Yadlapati 335*543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 336*543f9a75SLakshmi Yadlapati pcieDeviceId, aResp, 337*543f9a75SLakshmi Yadlapati [aResp, pcieDeviceId](const std::string& pcieDevicePath, 338*543f9a75SLakshmi Yadlapati const std::string& service) { 339*543f9a75SLakshmi Yadlapati addPCIeDeviceCommonProperties(aResp, pcieDeviceId); 340*543f9a75SLakshmi Yadlapati getPCIeDeviceProperties( 341*543f9a75SLakshmi Yadlapati aResp, pcieDevicePath, service, 342*543f9a75SLakshmi Yadlapati [aResp](const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 343*543f9a75SLakshmi Yadlapati addPCIeDeviceProperties(aResp->res, pcieDevProperties); 3447e860f15SJohn Edward Broadbent }); 345*543f9a75SLakshmi Yadlapati }); 346*543f9a75SLakshmi Yadlapati } 347*543f9a75SLakshmi Yadlapati 348*543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 349*543f9a75SLakshmi Yadlapati { 350*543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 351*543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 352*543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 353*543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 354dede6a98SJason M. Bills } 355dede6a98SJason M. Bills 3567e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 3577e860f15SJohn Edward Broadbent { 358dede6a98SJason M. Bills /** 359dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 360dede6a98SJason M. Bills */ 3617e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 3627e860f15SJohn Edward Broadbent "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/") 363ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 364002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 365002d39b4SEd Tanous [&app](const crow::Request& req, 3667e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 36745ca1b86SEd Tanous const std::string& device) { 3683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 369dede6a98SJason M. Bills { 37045ca1b86SEd Tanous return; 37145ca1b86SEd Tanous } 3721476687dSEd Tanous 3731476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3741476687dSEd Tanous "#PCIeFunctionCollection.PCIeFunctionCollection"; 375eddfc437SWilly Tu asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 376eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "PCIeDevices", device, 377eddfc437SWilly Tu "PCIeFunctions"); 3781476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 3791476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 3801476687dSEd Tanous "Collection of PCIe Functions for PCIe Device " + device; 381dede6a98SJason M. Bills 382b9d36b47SEd Tanous auto getPCIeDeviceCallback = 38345ca1b86SEd Tanous [asyncResp, device]( 3845e7e2dc5SEd Tanous const boost::system::error_code& ec, 38545ca1b86SEd Tanous const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 3867e860f15SJohn Edward Broadbent if (ec) 3877e860f15SJohn Edward Broadbent { 3887e860f15SJohn Edward Broadbent BMCWEB_LOG_DEBUG 389002d39b4SEd Tanous << "failed to get PCIe Device properties ec: " << ec.value() 390002d39b4SEd Tanous << ": " << ec.message(); 39145ca1b86SEd Tanous if (ec.value() == 39245ca1b86SEd Tanous boost::system::linux_error::bad_request_descriptor) 3937e860f15SJohn Edward Broadbent { 394002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", 395002d39b4SEd Tanous device); 3967e860f15SJohn Edward Broadbent } 3977e860f15SJohn Edward Broadbent else 3987e860f15SJohn Edward Broadbent { 3997e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 4007e860f15SJohn Edward Broadbent } 4017e860f15SJohn Edward Broadbent return; 4027e860f15SJohn Edward Broadbent } 4037e860f15SJohn Edward Broadbent 4047e860f15SJohn Edward Broadbent nlohmann::json& pcieFunctionList = 4057e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 4067e860f15SJohn Edward Broadbent pcieFunctionList = nlohmann::json::array(); 4077e860f15SJohn Edward Broadbent static constexpr const int maxPciFunctionNum = 8; 40845ca1b86SEd Tanous for (int functionNum = 0; functionNum < maxPciFunctionNum; 40945ca1b86SEd Tanous functionNum++) 4107e860f15SJohn Edward Broadbent { 411b9d36b47SEd Tanous // Check if this function exists by looking for a 412b9d36b47SEd Tanous // device ID 4137e860f15SJohn Edward Broadbent std::string devIDProperty = 414002d39b4SEd Tanous "Function" + std::to_string(functionNum) + "DeviceId"; 415b9d36b47SEd Tanous const std::string* property = nullptr; 416b9d36b47SEd Tanous for (const auto& propEntry : pcieDevProperties) 4177e860f15SJohn Edward Broadbent { 418b9d36b47SEd Tanous if (propEntry.first == devIDProperty) 419b9d36b47SEd Tanous { 420002d39b4SEd Tanous property = std::get_if<std::string>(&propEntry.second); 421b9d36b47SEd Tanous } 422b9d36b47SEd Tanous } 423fb0ecc3eSNan Zhou if (property == nullptr || property->empty()) 424b9d36b47SEd Tanous { 425e28ce0e6SNan Zhou continue; 426b9d36b47SEd Tanous } 4271476687dSEd Tanous nlohmann::json::object_t pcieFunction; 428eddfc437SWilly Tu pcieFunction["@odata.id"] = crow::utility::urlFromPieces( 429eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "PCIeDevices", device, 430eddfc437SWilly Tu "PCIeFunctions", std::to_string(functionNum)); 4311476687dSEd Tanous pcieFunctionList.push_back(std::move(pcieFunction)); 4327e860f15SJohn Edward Broadbent } 433a818d15aSJiaqing Zhao asyncResp->res.jsonValue["Members@odata.count"] = 4347e860f15SJohn Edward Broadbent pcieFunctionList.size(); 4357e860f15SJohn Edward Broadbent }; 4367e860f15SJohn Edward Broadbent std::string escapedPath = std::string(pciePath) + "/" + device; 4377e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(escapedPath); 438d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 439d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, pcieService, escapedPath, 440d1bde9e5SKrzysztof Grobelny pcieDeviceInterface, std::move(getPCIeDeviceCallback)); 4417e860f15SJohn Edward Broadbent }); 4427e860f15SJohn Edward Broadbent } 4437e860f15SJohn Edward Broadbent 4447e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app) 4457e860f15SJohn Edward Broadbent { 4467e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 4477e860f15SJohn Edward Broadbent app, 4487e860f15SJohn Edward Broadbent "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/") 449ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunction) 450002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 451002d39b4SEd Tanous [&app](const crow::Request& req, 45245ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 453002d39b4SEd Tanous const std::string& device, const std::string& function) { 4543ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 45545ca1b86SEd Tanous { 45645ca1b86SEd Tanous return; 45745ca1b86SEd Tanous } 458168e20c1SEd Tanous auto getPCIeDeviceCallback = 459168e20c1SEd Tanous [asyncResp, device, function]( 4605e7e2dc5SEd Tanous const boost::system::error_code& ec, 461b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 462dede6a98SJason M. Bills if (ec) 463dede6a98SJason M. Bills { 464dede6a98SJason M. Bills BMCWEB_LOG_DEBUG 465002d39b4SEd Tanous << "failed to get PCIe Device properties ec: " << ec.value() 466002d39b4SEd Tanous << ": " << ec.message(); 467dede6a98SJason M. Bills if (ec.value() == 468dede6a98SJason M. Bills boost::system::linux_error::bad_request_descriptor) 469dede6a98SJason M. Bills { 470002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", 471002d39b4SEd Tanous device); 472dede6a98SJason M. Bills } 473dede6a98SJason M. Bills else 474dede6a98SJason M. Bills { 475dede6a98SJason M. Bills messages::internalError(asyncResp->res); 476dede6a98SJason M. Bills } 477dede6a98SJason M. Bills return; 478dede6a98SJason M. Bills } 479dede6a98SJason M. Bills 4801476687dSEd Tanous // Check if this function exists by looking for a device 4811476687dSEd Tanous // ID 482b9d36b47SEd Tanous std::string functionName = "Function" + function; 483b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 484b9d36b47SEd Tanous 485b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 486b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 487b9d36b47SEd Tanous { 488b9d36b47SEd Tanous if (property.first == devIDProperty) 489b9d36b47SEd Tanous { 490002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 491b9d36b47SEd Tanous continue; 492b9d36b47SEd Tanous } 493b9d36b47SEd Tanous } 494973c1355STony Lee if (devIdProperty == nullptr || devIdProperty->empty()) 495f5c9f8bdSJason M. Bills { 496002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 497002d39b4SEd Tanous function); 498f5c9f8bdSJason M. Bills return; 499f5c9f8bdSJason M. Bills } 500f5c9f8bdSJason M. Bills 5011476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 5021476687dSEd Tanous "#PCIeFunction.v1_2_0.PCIeFunction"; 5031476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 504eddfc437SWilly Tu crow::utility::urlFromPieces("redfish", "v1", "Systems", 505eddfc437SWilly Tu "system", "PCIeDevices", device, 506eddfc437SWilly Tu "PCIeFunctions", function); 5071476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function"; 5081476687dSEd Tanous asyncResp->res.jsonValue["Id"] = function; 509002d39b4SEd Tanous asyncResp->res.jsonValue["FunctionId"] = std::stoi(function); 510002d39b4SEd Tanous asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 511eddfc437SWilly Tu crow::utility::urlFromPieces("redfish", "v1", "Systems", 512eddfc437SWilly Tu "system", "PCIeDevices", device); 513f5c9f8bdSJason M. Bills 514b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 515f5c9f8bdSJason M. Bills { 516b9d36b47SEd Tanous const std::string* strProperty = 517b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 518b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 519f5c9f8bdSJason M. Bills { 520b9d36b47SEd Tanous asyncResp->res.jsonValue["DeviceId"] = *strProperty; 521f5c9f8bdSJason M. Bills } 522b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 523f5c9f8bdSJason M. Bills { 524b9d36b47SEd Tanous asyncResp->res.jsonValue["VendorId"] = *strProperty; 525f5c9f8bdSJason M. Bills } 526b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 527f5c9f8bdSJason M. Bills { 528002d39b4SEd Tanous asyncResp->res.jsonValue["FunctionType"] = *strProperty; 529f5c9f8bdSJason M. Bills } 530b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 531f5c9f8bdSJason M. Bills { 532002d39b4SEd Tanous asyncResp->res.jsonValue["DeviceClass"] = *strProperty; 533f5c9f8bdSJason M. Bills } 534b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 535f5c9f8bdSJason M. Bills { 536002d39b4SEd Tanous asyncResp->res.jsonValue["ClassCode"] = *strProperty; 537f5c9f8bdSJason M. Bills } 538b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 539f5c9f8bdSJason M. Bills { 540002d39b4SEd Tanous asyncResp->res.jsonValue["RevisionId"] = *strProperty; 541f5c9f8bdSJason M. Bills } 542b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 543b9d36b47SEd Tanous { 544002d39b4SEd Tanous asyncResp->res.jsonValue["SubsystemId"] = *strProperty; 545b9d36b47SEd Tanous } 546002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 547f5c9f8bdSJason M. Bills { 548168e20c1SEd Tanous asyncResp->res.jsonValue["SubsystemVendorId"] = 549b9d36b47SEd Tanous *strProperty; 550b9d36b47SEd Tanous } 551f5c9f8bdSJason M. Bills } 552f5c9f8bdSJason M. Bills }; 553f5c9f8bdSJason M. Bills std::string escapedPath = std::string(pciePath) + "/" + device; 554f5c9f8bdSJason M. Bills dbus::utility::escapePathForDbus(escapedPath); 555d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 556d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, pcieService, escapedPath, 557d1bde9e5SKrzysztof Grobelny pcieDeviceInterface, std::move(getPCIeDeviceCallback)); 5587e860f15SJohn Edward Broadbent }); 559f5c9f8bdSJason M. Bills } 560f5c9f8bdSJason M. Bills 561f5c9f8bdSJason M. Bills } // namespace redfish 562