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 = 37*b8f38eadSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"; 38f5c9f8bdSJason M. Bills 39b5a76932SEd Tanous static inline void 408d1b46d7Szhanghch05 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 41adbe192aSJason M. Bills const std::string& name) 42f5c9f8bdSJason M. Bills { 437a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 447a1dbc48SGeorge Liu pciePath, 1, {}, 457a1dbc48SGeorge Liu [asyncResp, name](const boost::system::error_code& ec, 46b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 47b9d36b47SEd Tanous pcieDevicePaths) { 48f5c9f8bdSJason M. Bills if (ec) 49f5c9f8bdSJason M. Bills { 50a2730f01SAndrew Geissler BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: " 51f5c9f8bdSJason M. Bills << ec.message(); 52a2730f01SAndrew Geissler // Not an error, system just doesn't have PCIe info 53f5c9f8bdSJason M. Bills return; 54f5c9f8bdSJason M. Bills } 55adbe192aSJason M. Bills nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name]; 56f5c9f8bdSJason M. Bills pcieDeviceList = nlohmann::json::array(); 57f5c9f8bdSJason M. Bills for (const std::string& pcieDevicePath : pcieDevicePaths) 58f5c9f8bdSJason M. Bills { 593174e4dfSEd Tanous size_t devStart = pcieDevicePath.rfind('/'); 60f5c9f8bdSJason M. Bills if (devStart == std::string::npos) 61f5c9f8bdSJason M. Bills { 62f5c9f8bdSJason M. Bills continue; 63f5c9f8bdSJason M. Bills } 64f5c9f8bdSJason M. Bills 65f5c9f8bdSJason M. Bills std::string devName = pcieDevicePath.substr(devStart + 1); 66f5c9f8bdSJason M. Bills if (devName.empty()) 67f5c9f8bdSJason M. Bills { 68f5c9f8bdSJason M. Bills continue; 69f5c9f8bdSJason M. Bills } 701476687dSEd Tanous nlohmann::json::object_t pcieDevice; 71eddfc437SWilly Tu pcieDevice["@odata.id"] = crow::utility::urlFromPieces( 72eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "PCIeDevices", devName); 731476687dSEd Tanous pcieDeviceList.push_back(std::move(pcieDevice)); 74f5c9f8bdSJason M. Bills } 75002d39b4SEd Tanous asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size(); 767a1dbc48SGeorge Liu }); 77f5c9f8bdSJason M. Bills } 78f5c9f8bdSJason M. Bills 79b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet( 80b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 81b38fa2abSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 82b38fa2abSLakshmi Yadlapati const std::string& systemName) 83b38fa2abSLakshmi Yadlapati { 84b38fa2abSLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 85b38fa2abSLakshmi Yadlapati { 86b38fa2abSLakshmi Yadlapati return; 87b38fa2abSLakshmi Yadlapati } 88b38fa2abSLakshmi Yadlapati if (systemName != "system") 89b38fa2abSLakshmi Yadlapati { 90b38fa2abSLakshmi Yadlapati messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 91b38fa2abSLakshmi Yadlapati return; 92b38fa2abSLakshmi Yadlapati } 93b38fa2abSLakshmi Yadlapati aResp->res.addHeader(boost::beast::http::field::link, 94b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 95b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 96b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["@odata.type"] = 97b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 98b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["@odata.id"] = 99b38fa2abSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices"; 100b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Name"] = "PCIe Device Collection"; 101b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 102b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Members"] = nlohmann::json::array(); 103b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Members@odata.count"] = 0; 104b38fa2abSLakshmi Yadlapati 105b38fa2abSLakshmi Yadlapati constexpr std::array<std::string_view, 1> interfaces{ 106b38fa2abSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 107b38fa2abSLakshmi Yadlapati collection_util::getCollectionMembers( 108b38fa2abSLakshmi Yadlapati aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"), 109b38fa2abSLakshmi Yadlapati interfaces); 110b38fa2abSLakshmi Yadlapati } 111b38fa2abSLakshmi Yadlapati 1127e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 113adbe192aSJason M. Bills { 114adbe192aSJason M. Bills /** 115adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 116adbe192aSJason M. Bills */ 11722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 118ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1197e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 120b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 121f5c9f8bdSJason M. Bills } 122f5c9f8bdSJason M. Bills 1230ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes> 12462cd45afSSpencer Ku redfishPcieGenerationFromDbus(const std::string& generationInUse) 12562cd45afSSpencer Ku { 12662cd45afSSpencer Ku if (generationInUse == 12762cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1") 12862cd45afSSpencer Ku { 1290ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen1; 13062cd45afSSpencer Ku } 13162cd45afSSpencer Ku if (generationInUse == 13262cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2") 13362cd45afSSpencer Ku { 1340ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen2; 13562cd45afSSpencer Ku } 13662cd45afSSpencer Ku if (generationInUse == 13762cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3") 13862cd45afSSpencer Ku { 1390ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen3; 14062cd45afSSpencer Ku } 14162cd45afSSpencer Ku if (generationInUse == 14262cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4") 14362cd45afSSpencer Ku { 1440ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen4; 14562cd45afSSpencer Ku } 14662cd45afSSpencer Ku if (generationInUse == 14762cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5") 14862cd45afSSpencer Ku { 1490ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen5; 15062cd45afSSpencer Ku } 151e825cbc8SEd Tanous if (generationInUse.empty() || 152e825cbc8SEd Tanous generationInUse == 15362cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown") 15462cd45afSSpencer Ku { 1550ec8b83dSEd Tanous return pcie_device::PCIeTypes::Invalid; 15662cd45afSSpencer Ku } 15762cd45afSSpencer Ku 15862cd45afSSpencer Ku // The value is not unknown or Gen1-5, need return an internal error. 15962cd45afSSpencer Ku return std::nullopt; 16062cd45afSSpencer Ku } 16162cd45afSSpencer Ku 1627e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDevice(App& app) 163f5c9f8bdSJason M. Bills { 16422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 165ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDevice) 166002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 167002d39b4SEd Tanous [&app](const crow::Request& req, 1687e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 16922d268cbSEd Tanous const std::string& systemName, const std::string& device) { 1703ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1717e860f15SJohn Edward Broadbent { 17245ca1b86SEd Tanous return; 17345ca1b86SEd Tanous } 17422d268cbSEd Tanous if (systemName != "system") 17522d268cbSEd Tanous { 17622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 17722d268cbSEd Tanous systemName); 17822d268cbSEd Tanous return; 17922d268cbSEd Tanous } 18022d268cbSEd Tanous 181168e20c1SEd Tanous auto getPCIeDeviceCallback = 18245ca1b86SEd Tanous [asyncResp, device]( 1835e7e2dc5SEd Tanous const boost::system::error_code& ec, 18445ca1b86SEd Tanous const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 185f5c9f8bdSJason M. Bills if (ec) 186f5c9f8bdSJason M. Bills { 187f5c9f8bdSJason M. Bills BMCWEB_LOG_DEBUG 188002d39b4SEd Tanous << "failed to get PCIe Device properties ec: " << ec.value() 189002d39b4SEd Tanous << ": " << ec.message(); 19045ca1b86SEd Tanous if (ec.value() == 19145ca1b86SEd Tanous boost::system::linux_error::bad_request_descriptor) 192f5c9f8bdSJason M. Bills { 193002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", 194002d39b4SEd Tanous device); 195f5c9f8bdSJason M. Bills } 196f5c9f8bdSJason M. Bills else 197f5c9f8bdSJason M. Bills { 198f5c9f8bdSJason M. Bills messages::internalError(asyncResp->res); 199f5c9f8bdSJason M. Bills } 200f5c9f8bdSJason M. Bills return; 201f5c9f8bdSJason M. Bills } 202f5c9f8bdSJason M. Bills 203d1bde9e5SKrzysztof Grobelny const std::string* manufacturer = nullptr; 204d1bde9e5SKrzysztof Grobelny const std::string* deviceType = nullptr; 205d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 206703f6741SMyung Bae const size_t* lanesInUse = nullptr; 207d1bde9e5SKrzysztof Grobelny 208d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 209d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), pcieDevProperties, 210d1bde9e5SKrzysztof Grobelny "Manufacturer", manufacturer, "DeviceType", deviceType, 211703f6741SMyung Bae "LanesInUse", lanesInUse, "GenerationInUse", generationInUse); 212d1bde9e5SKrzysztof Grobelny 213d1bde9e5SKrzysztof Grobelny if (!success) 214d1bde9e5SKrzysztof Grobelny { 215d1bde9e5SKrzysztof Grobelny messages::internalError(asyncResp->res); 216d1bde9e5SKrzysztof Grobelny return; 217d1bde9e5SKrzysztof Grobelny } 218d1bde9e5SKrzysztof Grobelny 219703f6741SMyung Bae // The default value of LanesInUse is 0, and the field will be 220703f6741SMyung Bae // left as off if it is a default value. 221703f6741SMyung Bae if (lanesInUse != nullptr && *lanesInUse != 0) 222703f6741SMyung Bae { 223703f6741SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = 224703f6741SMyung Bae *lanesInUse; 225703f6741SMyung Bae } 226703f6741SMyung Bae 227d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 228d1bde9e5SKrzysztof Grobelny { 2290ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 230d1bde9e5SKrzysztof Grobelny redfishPcieGenerationFromDbus(*generationInUse); 231d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 232d1bde9e5SKrzysztof Grobelny { 233d1bde9e5SKrzysztof Grobelny messages::internalError(asyncResp->res); 234d1bde9e5SKrzysztof Grobelny return; 235d1bde9e5SKrzysztof Grobelny } 2360ec8b83dSEd Tanous if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid) 237d1bde9e5SKrzysztof Grobelny { 238d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 239d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 240d1bde9e5SKrzysztof Grobelny } 241a9f68bb5STony Lee } 242d1bde9e5SKrzysztof Grobelny 243d1bde9e5SKrzysztof Grobelny if (manufacturer != nullptr) 244d1bde9e5SKrzysztof Grobelny { 245d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 246d1bde9e5SKrzysztof Grobelny } 247d1bde9e5SKrzysztof Grobelny 248d1bde9e5SKrzysztof Grobelny if (deviceType != nullptr) 249d1bde9e5SKrzysztof Grobelny { 250d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["DeviceType"] = *deviceType; 251d1bde9e5SKrzysztof Grobelny } 252d1bde9e5SKrzysztof Grobelny 2531476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2541476687dSEd Tanous "#PCIeDevice.v1_4_0.PCIeDevice"; 2551476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 256eddfc437SWilly Tu crow::utility::urlFromPieces("redfish", "v1", "Systems", 257eddfc437SWilly Tu "system", "PCIeDevices", device); 2581476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 2591476687dSEd Tanous asyncResp->res.jsonValue["Id"] = device; 2601476687dSEd Tanous 2611476687dSEd Tanous asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 262eddfc437SWilly Tu crow::utility::urlFromPieces("redfish", "v1", "Systems", 263eddfc437SWilly Tu "system", "PCIeDevices", device, 264eddfc437SWilly Tu "PCIeFunctions"); 265dede6a98SJason M. Bills }; 266dede6a98SJason M. Bills std::string escapedPath = std::string(pciePath) + "/" + device; 267dede6a98SJason M. Bills dbus::utility::escapePathForDbus(escapedPath); 268d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 269d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, pcieService, escapedPath, 270d1bde9e5SKrzysztof Grobelny pcieDeviceInterface, std::move(getPCIeDeviceCallback)); 2717e860f15SJohn Edward Broadbent }); 272dede6a98SJason M. Bills } 273dede6a98SJason M. Bills 2747e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 2757e860f15SJohn Edward Broadbent { 276dede6a98SJason M. Bills /** 277dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 278dede6a98SJason M. Bills */ 2797e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 2807e860f15SJohn Edward Broadbent "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/") 281ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 282002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 283002d39b4SEd Tanous [&app](const crow::Request& req, 2847e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 28545ca1b86SEd Tanous const std::string& device) { 2863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 287dede6a98SJason M. Bills { 28845ca1b86SEd Tanous return; 28945ca1b86SEd Tanous } 2901476687dSEd Tanous 2911476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2921476687dSEd Tanous "#PCIeFunctionCollection.PCIeFunctionCollection"; 293eddfc437SWilly Tu asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 294eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "PCIeDevices", device, 295eddfc437SWilly Tu "PCIeFunctions"); 2961476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 2971476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 2981476687dSEd Tanous "Collection of PCIe Functions for PCIe Device " + device; 299dede6a98SJason M. Bills 300b9d36b47SEd Tanous auto getPCIeDeviceCallback = 30145ca1b86SEd Tanous [asyncResp, device]( 3025e7e2dc5SEd Tanous const boost::system::error_code& ec, 30345ca1b86SEd Tanous const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 3047e860f15SJohn Edward Broadbent if (ec) 3057e860f15SJohn Edward Broadbent { 3067e860f15SJohn Edward Broadbent BMCWEB_LOG_DEBUG 307002d39b4SEd Tanous << "failed to get PCIe Device properties ec: " << ec.value() 308002d39b4SEd Tanous << ": " << ec.message(); 30945ca1b86SEd Tanous if (ec.value() == 31045ca1b86SEd Tanous boost::system::linux_error::bad_request_descriptor) 3117e860f15SJohn Edward Broadbent { 312002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", 313002d39b4SEd Tanous device); 3147e860f15SJohn Edward Broadbent } 3157e860f15SJohn Edward Broadbent else 3167e860f15SJohn Edward Broadbent { 3177e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 3187e860f15SJohn Edward Broadbent } 3197e860f15SJohn Edward Broadbent return; 3207e860f15SJohn Edward Broadbent } 3217e860f15SJohn Edward Broadbent 3227e860f15SJohn Edward Broadbent nlohmann::json& pcieFunctionList = 3237e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 3247e860f15SJohn Edward Broadbent pcieFunctionList = nlohmann::json::array(); 3257e860f15SJohn Edward Broadbent static constexpr const int maxPciFunctionNum = 8; 32645ca1b86SEd Tanous for (int functionNum = 0; functionNum < maxPciFunctionNum; 32745ca1b86SEd Tanous functionNum++) 3287e860f15SJohn Edward Broadbent { 329b9d36b47SEd Tanous // Check if this function exists by looking for a 330b9d36b47SEd Tanous // device ID 3317e860f15SJohn Edward Broadbent std::string devIDProperty = 332002d39b4SEd Tanous "Function" + std::to_string(functionNum) + "DeviceId"; 333b9d36b47SEd Tanous const std::string* property = nullptr; 334b9d36b47SEd Tanous for (const auto& propEntry : pcieDevProperties) 3357e860f15SJohn Edward Broadbent { 336b9d36b47SEd Tanous if (propEntry.first == devIDProperty) 337b9d36b47SEd Tanous { 338002d39b4SEd Tanous property = std::get_if<std::string>(&propEntry.second); 339b9d36b47SEd Tanous } 340b9d36b47SEd Tanous } 341fb0ecc3eSNan Zhou if (property == nullptr || property->empty()) 342b9d36b47SEd Tanous { 343e28ce0e6SNan Zhou continue; 344b9d36b47SEd Tanous } 3451476687dSEd Tanous nlohmann::json::object_t pcieFunction; 346eddfc437SWilly Tu pcieFunction["@odata.id"] = crow::utility::urlFromPieces( 347eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "PCIeDevices", device, 348eddfc437SWilly Tu "PCIeFunctions", std::to_string(functionNum)); 3491476687dSEd Tanous pcieFunctionList.push_back(std::move(pcieFunction)); 3507e860f15SJohn Edward Broadbent } 351a818d15aSJiaqing Zhao asyncResp->res.jsonValue["Members@odata.count"] = 3527e860f15SJohn Edward Broadbent pcieFunctionList.size(); 3537e860f15SJohn Edward Broadbent }; 3547e860f15SJohn Edward Broadbent std::string escapedPath = std::string(pciePath) + "/" + device; 3557e860f15SJohn Edward Broadbent dbus::utility::escapePathForDbus(escapedPath); 356d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 357d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, pcieService, escapedPath, 358d1bde9e5SKrzysztof Grobelny pcieDeviceInterface, std::move(getPCIeDeviceCallback)); 3597e860f15SJohn Edward Broadbent }); 3607e860f15SJohn Edward Broadbent } 3617e860f15SJohn Edward Broadbent 3627e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app) 3637e860f15SJohn Edward Broadbent { 3647e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 3657e860f15SJohn Edward Broadbent app, 3667e860f15SJohn Edward Broadbent "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/") 367ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunction) 368002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 369002d39b4SEd Tanous [&app](const crow::Request& req, 37045ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 371002d39b4SEd Tanous const std::string& device, const std::string& function) { 3723ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 37345ca1b86SEd Tanous { 37445ca1b86SEd Tanous return; 37545ca1b86SEd Tanous } 376168e20c1SEd Tanous auto getPCIeDeviceCallback = 377168e20c1SEd Tanous [asyncResp, device, function]( 3785e7e2dc5SEd Tanous const boost::system::error_code& ec, 379b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 380dede6a98SJason M. Bills if (ec) 381dede6a98SJason M. Bills { 382dede6a98SJason M. Bills BMCWEB_LOG_DEBUG 383002d39b4SEd Tanous << "failed to get PCIe Device properties ec: " << ec.value() 384002d39b4SEd Tanous << ": " << ec.message(); 385dede6a98SJason M. Bills if (ec.value() == 386dede6a98SJason M. Bills boost::system::linux_error::bad_request_descriptor) 387dede6a98SJason M. Bills { 388002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", 389002d39b4SEd Tanous device); 390dede6a98SJason M. Bills } 391dede6a98SJason M. Bills else 392dede6a98SJason M. Bills { 393dede6a98SJason M. Bills messages::internalError(asyncResp->res); 394dede6a98SJason M. Bills } 395dede6a98SJason M. Bills return; 396dede6a98SJason M. Bills } 397dede6a98SJason M. Bills 3981476687dSEd Tanous // Check if this function exists by looking for a device 3991476687dSEd Tanous // ID 400b9d36b47SEd Tanous std::string functionName = "Function" + function; 401b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 402b9d36b47SEd Tanous 403b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 404b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 405b9d36b47SEd Tanous { 406b9d36b47SEd Tanous if (property.first == devIDProperty) 407b9d36b47SEd Tanous { 408002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 409b9d36b47SEd Tanous continue; 410b9d36b47SEd Tanous } 411b9d36b47SEd Tanous } 412973c1355STony Lee if (devIdProperty == nullptr || devIdProperty->empty()) 413f5c9f8bdSJason M. Bills { 414002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 415002d39b4SEd Tanous function); 416f5c9f8bdSJason M. Bills return; 417f5c9f8bdSJason M. Bills } 418f5c9f8bdSJason M. Bills 4191476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 4201476687dSEd Tanous "#PCIeFunction.v1_2_0.PCIeFunction"; 4211476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 422eddfc437SWilly Tu crow::utility::urlFromPieces("redfish", "v1", "Systems", 423eddfc437SWilly Tu "system", "PCIeDevices", device, 424eddfc437SWilly Tu "PCIeFunctions", function); 4251476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function"; 4261476687dSEd Tanous asyncResp->res.jsonValue["Id"] = function; 427002d39b4SEd Tanous asyncResp->res.jsonValue["FunctionId"] = std::stoi(function); 428002d39b4SEd Tanous asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 429eddfc437SWilly Tu crow::utility::urlFromPieces("redfish", "v1", "Systems", 430eddfc437SWilly Tu "system", "PCIeDevices", device); 431f5c9f8bdSJason M. Bills 432b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 433f5c9f8bdSJason M. Bills { 434b9d36b47SEd Tanous const std::string* strProperty = 435b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 436b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 437f5c9f8bdSJason M. Bills { 438b9d36b47SEd Tanous asyncResp->res.jsonValue["DeviceId"] = *strProperty; 439f5c9f8bdSJason M. Bills } 440b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 441f5c9f8bdSJason M. Bills { 442b9d36b47SEd Tanous asyncResp->res.jsonValue["VendorId"] = *strProperty; 443f5c9f8bdSJason M. Bills } 444b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 445f5c9f8bdSJason M. Bills { 446002d39b4SEd Tanous asyncResp->res.jsonValue["FunctionType"] = *strProperty; 447f5c9f8bdSJason M. Bills } 448b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 449f5c9f8bdSJason M. Bills { 450002d39b4SEd Tanous asyncResp->res.jsonValue["DeviceClass"] = *strProperty; 451f5c9f8bdSJason M. Bills } 452b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 453f5c9f8bdSJason M. Bills { 454002d39b4SEd Tanous asyncResp->res.jsonValue["ClassCode"] = *strProperty; 455f5c9f8bdSJason M. Bills } 456b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 457f5c9f8bdSJason M. Bills { 458002d39b4SEd Tanous asyncResp->res.jsonValue["RevisionId"] = *strProperty; 459f5c9f8bdSJason M. Bills } 460b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 461b9d36b47SEd Tanous { 462002d39b4SEd Tanous asyncResp->res.jsonValue["SubsystemId"] = *strProperty; 463b9d36b47SEd Tanous } 464002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 465f5c9f8bdSJason M. Bills { 466168e20c1SEd Tanous asyncResp->res.jsonValue["SubsystemVendorId"] = 467b9d36b47SEd Tanous *strProperty; 468b9d36b47SEd Tanous } 469f5c9f8bdSJason M. Bills } 470f5c9f8bdSJason M. Bills }; 471f5c9f8bdSJason M. Bills std::string escapedPath = std::string(pciePath) + "/" + device; 472f5c9f8bdSJason M. Bills dbus::utility::escapePathForDbus(escapedPath); 473d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 474d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, pcieService, escapedPath, 475d1bde9e5SKrzysztof Grobelny pcieDeviceInterface, std::move(getPCIeDeviceCallback)); 4767e860f15SJohn Edward Broadbent }); 477f5c9f8bdSJason M. Bills } 478f5c9f8bdSJason M. Bills 479f5c9f8bdSJason M. Bills } // namespace redfish 480