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" 213ccb3adbSEd Tanous #include "query.hpp" 223ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 23b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp" 243ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 25*c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp" 260ec8b83dSEd Tanous 27f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp> 28ef4c65b7SEd Tanous #include <boost/url/format.hpp> 29d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 30d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 31f5c9f8bdSJason M. Bills 32f5c9f8bdSJason M. Bills namespace redfish 33f5c9f8bdSJason M. Bills { 34f5c9f8bdSJason M. Bills 3589492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory"; 3694c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = { 3794c3a10bSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 38f5c9f8bdSJason M. Bills 39543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath( 40543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 41ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 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, {}, 58ac106bf6SEd Tanous [pcieDevicePath, asyncResp, 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; 64ac106bf6SEd Tanous messages::internalError(asyncResp->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"; 73ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId); 74543f9a75SLakshmi Yadlapati } 75543f9a75SLakshmi Yadlapati 76543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath( 77543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 78ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 79543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 80543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 81543f9a75SLakshmi Yadlapati { 82543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 8394c3a10bSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 84ac106bf6SEd Tanous [pcieDeviceId, asyncResp, 85543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 86543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 87543f9a75SLakshmi Yadlapati pcieDevicePaths) { 88543f9a75SLakshmi Yadlapati if (ec) 89543f9a75SLakshmi Yadlapati { 90543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec; 91ac106bf6SEd Tanous messages::internalError(asyncResp->res); 92543f9a75SLakshmi Yadlapati return; 93543f9a75SLakshmi Yadlapati } 94ac106bf6SEd Tanous handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths, 95ac106bf6SEd Tanous callback); 96543f9a75SLakshmi Yadlapati return; 97543f9a75SLakshmi Yadlapati }); 98543f9a75SLakshmi Yadlapati } 99543f9a75SLakshmi Yadlapati 100b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet( 101b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 102ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 103b38fa2abSLakshmi Yadlapati const std::string& systemName) 104b38fa2abSLakshmi Yadlapati { 105ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 106b38fa2abSLakshmi Yadlapati { 107b38fa2abSLakshmi Yadlapati return; 108b38fa2abSLakshmi Yadlapati } 109b38fa2abSLakshmi Yadlapati if (systemName != "system") 110b38fa2abSLakshmi Yadlapati { 111ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 112ac106bf6SEd Tanous systemName); 113b38fa2abSLakshmi Yadlapati return; 114b38fa2abSLakshmi Yadlapati } 115543f9a75SLakshmi Yadlapati 116ac106bf6SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::link, 117b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 118b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 119ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 120b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 121ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 122b38fa2abSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices"; 123ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device Collection"; 124ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 125ac106bf6SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 126ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 127b38fa2abSLakshmi Yadlapati 128b38fa2abSLakshmi Yadlapati collection_util::getCollectionMembers( 129ac106bf6SEd Tanous asyncResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"), 13094c3a10bSLakshmi Yadlapati pcieDeviceInterface); 131b38fa2abSLakshmi Yadlapati } 132b38fa2abSLakshmi Yadlapati 1337e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 134adbe192aSJason M. Bills { 135adbe192aSJason M. Bills /** 136adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 137adbe192aSJason M. Bills */ 13822d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 139ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1407e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 141b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 142f5c9f8bdSJason M. Bills } 143f5c9f8bdSJason M. Bills 144ac106bf6SEd Tanous inline void 145ac106bf6SEd Tanous getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 146c6bb3285SLakshmi Yadlapati const std::string& pcieDevicePath, 147c6bb3285SLakshmi Yadlapati const std::string& service) 148c6bb3285SLakshmi Yadlapati { 149c6bb3285SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 150c6bb3285SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 151c6bb3285SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item", "Present", 152ac106bf6SEd Tanous [asyncResp](const boost::system::error_code& ec, const bool value) { 153c6bb3285SLakshmi Yadlapati if (ec) 154c6bb3285SLakshmi Yadlapati { 155c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 156c6bb3285SLakshmi Yadlapati { 157c6bb3285SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for State"; 158ac106bf6SEd Tanous messages::internalError(asyncResp->res); 159c6bb3285SLakshmi Yadlapati } 160c6bb3285SLakshmi Yadlapati return; 161c6bb3285SLakshmi Yadlapati } 162c6bb3285SLakshmi Yadlapati 163c6bb3285SLakshmi Yadlapati if (!value) 164c6bb3285SLakshmi Yadlapati { 165ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 166c6bb3285SLakshmi Yadlapati } 167c6bb3285SLakshmi Yadlapati }); 168c6bb3285SLakshmi Yadlapati } 169c6bb3285SLakshmi Yadlapati 170ac106bf6SEd Tanous inline void 171ac106bf6SEd Tanous getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 172913e7732SSunnySrivastava1984 const std::string& pcieDevicePath, 173913e7732SSunnySrivastava1984 const std::string& service) 174913e7732SSunnySrivastava1984 { 175913e7732SSunnySrivastava1984 sdbusplus::asio::getAllProperties( 176913e7732SSunnySrivastava1984 *crow::connections::systemBus, service, pcieDevicePath, 177913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 178ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 179ac106bf6SEd Tanous const boost::system::error_code& ec, 180913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 181913e7732SSunnySrivastava1984 if (ec) 182913e7732SSunnySrivastava1984 { 183913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 184913e7732SSunnySrivastava1984 { 185913e7732SSunnySrivastava1984 BMCWEB_LOG_ERROR << "DBUS response error for Properties" 186913e7732SSunnySrivastava1984 << ec.value(); 187ac106bf6SEd Tanous messages::internalError(asyncResp->res); 188913e7732SSunnySrivastava1984 } 189913e7732SSunnySrivastava1984 return; 190913e7732SSunnySrivastava1984 } 191913e7732SSunnySrivastava1984 192913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 193913e7732SSunnySrivastava1984 const std::string* model = nullptr; 194913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 195913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 196913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 197913e7732SSunnySrivastava1984 198913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 199913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 200913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 201913e7732SSunnySrivastava1984 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber); 202913e7732SSunnySrivastava1984 203913e7732SSunnySrivastava1984 if (!success) 204913e7732SSunnySrivastava1984 { 205ac106bf6SEd Tanous messages::internalError(asyncResp->res); 206913e7732SSunnySrivastava1984 return; 207913e7732SSunnySrivastava1984 } 208913e7732SSunnySrivastava1984 209913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 210913e7732SSunnySrivastava1984 { 211ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 212913e7732SSunnySrivastava1984 } 213913e7732SSunnySrivastava1984 if (model != nullptr) 214913e7732SSunnySrivastava1984 { 215ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 216913e7732SSunnySrivastava1984 } 217913e7732SSunnySrivastava1984 218913e7732SSunnySrivastava1984 if (partNumber != nullptr) 219913e7732SSunnySrivastava1984 { 220ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 221913e7732SSunnySrivastava1984 } 222913e7732SSunnySrivastava1984 223913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 224913e7732SSunnySrivastava1984 { 225ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 226913e7732SSunnySrivastava1984 } 227913e7732SSunnySrivastava1984 228913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 229913e7732SSunnySrivastava1984 { 230ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 231913e7732SSunnySrivastava1984 } 232913e7732SSunnySrivastava1984 }); 233913e7732SSunnySrivastava1984 } 234913e7732SSunnySrivastava1984 235543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 23635ad613dSLakshmi Yadlapati crow::Response& resp, const std::string& pcieDeviceId, 237543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 238f5c9f8bdSJason M. Bills { 239d1bde9e5SKrzysztof Grobelny const std::string* deviceType = nullptr; 240d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 241543f9a75SLakshmi Yadlapati const int64_t* lanesInUse = nullptr; 242d1bde9e5SKrzysztof Grobelny 243d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 244543f9a75SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType", 245543f9a75SLakshmi Yadlapati deviceType, "GenerationInUse", generationInUse, "LanesInUse", 246bad2c4a9SLakshmi Yadlapati lanesInUse); 247d1bde9e5SKrzysztof Grobelny 248d1bde9e5SKrzysztof Grobelny if (!success) 249d1bde9e5SKrzysztof Grobelny { 250543f9a75SLakshmi Yadlapati messages::internalError(resp); 251d1bde9e5SKrzysztof Grobelny return; 252d1bde9e5SKrzysztof Grobelny } 253d1bde9e5SKrzysztof Grobelny 254543f9a75SLakshmi Yadlapati if (deviceType != nullptr && !deviceType->empty()) 255703f6741SMyung Bae { 256543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType; 257703f6741SMyung Bae } 258703f6741SMyung Bae 259d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 260d1bde9e5SKrzysztof Grobelny { 2610ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 262*c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 263543f9a75SLakshmi Yadlapati 264d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 265d1bde9e5SKrzysztof Grobelny { 266543f9a75SLakshmi Yadlapati messages::internalError(resp); 267d1bde9e5SKrzysztof Grobelny return; 268d1bde9e5SKrzysztof Grobelny } 2690ec8b83dSEd Tanous if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid) 270d1bde9e5SKrzysztof Grobelny { 271543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["PCIeType"] = 272d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 273d1bde9e5SKrzysztof Grobelny } 274a9f68bb5STony Lee } 275d1bde9e5SKrzysztof Grobelny 276543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 277543f9a75SLakshmi Yadlapati // left as off if it is a default value. 278543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 279543f9a75SLakshmi Yadlapati { 280543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 281543f9a75SLakshmi Yadlapati } 282543f9a75SLakshmi Yadlapati 283ef4c65b7SEd Tanous resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format( 284ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 285ef4c65b7SEd Tanous pcieDeviceId); 286d1bde9e5SKrzysztof Grobelny } 287d1bde9e5SKrzysztof Grobelny 288543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 289ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 290543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 291543f9a75SLakshmi Yadlapati const std::function<void( 292543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 293d1bde9e5SKrzysztof Grobelny { 294543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 295543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 296543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 297ac106bf6SEd Tanous [asyncResp, 298543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 299543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 300543f9a75SLakshmi Yadlapati if (ec) 301543f9a75SLakshmi Yadlapati { 302543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 303543f9a75SLakshmi Yadlapati { 304543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 305ac106bf6SEd Tanous messages::internalError(asyncResp->res); 306543f9a75SLakshmi Yadlapati } 307543f9a75SLakshmi Yadlapati return; 308543f9a75SLakshmi Yadlapati } 309543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 310543f9a75SLakshmi Yadlapati }); 311d1bde9e5SKrzysztof Grobelny } 312d1bde9e5SKrzysztof Grobelny 313543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 314ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 315543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 316543f9a75SLakshmi Yadlapati { 317ac106bf6SEd Tanous asyncResp->res.addHeader( 318543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 319543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 320ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 321ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 322ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 323ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 324ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 325ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 326543f9a75SLakshmi Yadlapati } 3271476687dSEd Tanous 328ac106bf6SEd Tanous inline void 329ac106bf6SEd Tanous handlePCIeDeviceGet(App& app, const crow::Request& req, 330ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 331543f9a75SLakshmi Yadlapati const std::string& systemName, 332543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 333543f9a75SLakshmi Yadlapati { 334ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 335543f9a75SLakshmi Yadlapati { 336543f9a75SLakshmi Yadlapati return; 337543f9a75SLakshmi Yadlapati } 338543f9a75SLakshmi Yadlapati if (systemName != "system") 339543f9a75SLakshmi Yadlapati { 340ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 341ac106bf6SEd Tanous systemName); 342543f9a75SLakshmi Yadlapati return; 343543f9a75SLakshmi Yadlapati } 344543f9a75SLakshmi Yadlapati 345543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 346ac106bf6SEd Tanous pcieDeviceId, asyncResp, 347ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 348543f9a75SLakshmi Yadlapati const std::string& service) { 349ac106bf6SEd Tanous addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 350ac106bf6SEd Tanous getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 351ac106bf6SEd Tanous getPCIeDeviceState(asyncResp, pcieDevicePath, service); 352543f9a75SLakshmi Yadlapati getPCIeDeviceProperties( 353ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 354ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 35535ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 356ac106bf6SEd Tanous addPCIeDeviceProperties(asyncResp->res, pcieDeviceId, 35735ad613dSLakshmi Yadlapati pcieDevProperties); 3587e860f15SJohn Edward Broadbent }); 359543f9a75SLakshmi Yadlapati }); 360543f9a75SLakshmi Yadlapati } 361543f9a75SLakshmi Yadlapati 362543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 363543f9a75SLakshmi Yadlapati { 364543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 365543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 366543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 367543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 368dede6a98SJason M. Bills } 369dede6a98SJason M. Bills 37035ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 37135ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 37235ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 37335ad613dSLakshmi Yadlapati { 37435ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 37535ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 37635ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 37735ad613dSLakshmi Yadlapati 37835ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 37935ad613dSLakshmi Yadlapati { 38035ad613dSLakshmi Yadlapati // Check if this function exists by 38135ad613dSLakshmi Yadlapati // looking for a device ID 38289492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 38389492a15SPatrick Williams "DeviceId"; 38435ad613dSLakshmi Yadlapati const std::string* property = nullptr; 38535ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 38635ad613dSLakshmi Yadlapati { 38735ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 38835ad613dSLakshmi Yadlapati { 38935ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 39035ad613dSLakshmi Yadlapati break; 39135ad613dSLakshmi Yadlapati } 39235ad613dSLakshmi Yadlapati } 39335ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 39435ad613dSLakshmi Yadlapati { 39535ad613dSLakshmi Yadlapati continue; 39635ad613dSLakshmi Yadlapati } 39735ad613dSLakshmi Yadlapati 39835ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 399ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 400ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 401ef4c65b7SEd Tanous pcieDeviceId, std::to_string(functionNum)); 402b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 40335ad613dSLakshmi Yadlapati } 40435ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 40535ad613dSLakshmi Yadlapati } 40635ad613dSLakshmi Yadlapati 40735ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 40835ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 409ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 41035ad613dSLakshmi Yadlapati const std::string& pcieDeviceId) 41135ad613dSLakshmi Yadlapati { 412ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 41335ad613dSLakshmi Yadlapati { 41435ad613dSLakshmi Yadlapati return; 41535ad613dSLakshmi Yadlapati } 41635ad613dSLakshmi Yadlapati 41735ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 418ac106bf6SEd Tanous pcieDeviceId, asyncResp, 419ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 42035ad613dSLakshmi Yadlapati const std::string& service) { 421ac106bf6SEd Tanous asyncResp->res.addHeader( 42235ad613dSLakshmi Yadlapati boost::beast::http::field::link, 42335ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 424ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 42535ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 426ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 427ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 428ef4c65b7SEd Tanous pcieDeviceId); 429ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 430ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 43135ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 43235ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 433ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 434ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 43535ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 436ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 437ac106bf6SEd Tanous pcieDevProperties); 43835ad613dSLakshmi Yadlapati }); 43935ad613dSLakshmi Yadlapati }); 44035ad613dSLakshmi Yadlapati } 44135ad613dSLakshmi Yadlapati 4427e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 4437e860f15SJohn Edward Broadbent { 444dede6a98SJason M. Bills /** 445dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 446dede6a98SJason M. Bills */ 4477e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 4487e860f15SJohn Edward Broadbent "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/") 449ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 450002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 45135ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 4527e860f15SJohn Edward Broadbent } 4537e860f15SJohn Edward Broadbent 454727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 455d5e74b80SMyung Bae uint64_t pcieFunctionId, 456727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 4577e860f15SJohn Edward Broadbent { 458d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 459b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 460b9d36b47SEd Tanous 461b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 462b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 463b9d36b47SEd Tanous { 464b9d36b47SEd Tanous if (property.first == devIDProperty) 465b9d36b47SEd Tanous { 466002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 467727a046cSLakshmi Yadlapati break; 468b9d36b47SEd Tanous } 469b9d36b47SEd Tanous } 470727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 471727a046cSLakshmi Yadlapati } 472727a046cSLakshmi Yadlapati 473727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 474e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 475727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 476f5c9f8bdSJason M. Bills { 477e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 478b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 479f5c9f8bdSJason M. Bills { 480b9d36b47SEd Tanous const std::string* strProperty = 481b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 482727a046cSLakshmi Yadlapati 483b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 484f5c9f8bdSJason M. Bills { 485727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 486f5c9f8bdSJason M. Bills } 487b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 488f5c9f8bdSJason M. Bills { 489727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 490f5c9f8bdSJason M. Bills } 491727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 492727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 493727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 494b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 495f5c9f8bdSJason M. Bills { 496727a046cSLakshmi Yadlapati if (!strProperty->empty()) 497727a046cSLakshmi Yadlapati { 498727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 499727a046cSLakshmi Yadlapati } 500f5c9f8bdSJason M. Bills } 501b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 502f5c9f8bdSJason M. Bills { 503727a046cSLakshmi Yadlapati if (!strProperty->empty()) 504727a046cSLakshmi Yadlapati { 505727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 506727a046cSLakshmi Yadlapati } 507f5c9f8bdSJason M. Bills } 508b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 509f5c9f8bdSJason M. Bills { 510727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 511f5c9f8bdSJason M. Bills } 512b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 513f5c9f8bdSJason M. Bills { 514727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 515f5c9f8bdSJason M. Bills } 516b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 517b9d36b47SEd Tanous { 518727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 519b9d36b47SEd Tanous } 520002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 521f5c9f8bdSJason M. Bills { 522727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 523b9d36b47SEd Tanous } 524f5c9f8bdSJason M. Bills } 525727a046cSLakshmi Yadlapati } 526727a046cSLakshmi Yadlapati 527727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 528727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 529e14742caSEd Tanous uint64_t pcieFunctionId) 530727a046cSLakshmi Yadlapati { 531727a046cSLakshmi Yadlapati resp.addHeader( 532727a046cSLakshmi Yadlapati boost::beast::http::field::link, 533727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 534727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 535ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 536ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 537ef4c65b7SEd Tanous pcieDeviceId, pcieFunctionId); 538727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 539e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 540e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 541ef4c65b7SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format( 542ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 543727a046cSLakshmi Yadlapati } 544727a046cSLakshmi Yadlapati 545727a046cSLakshmi Yadlapati inline void 546727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 547ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 548727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 549e14742caSEd Tanous const std::string& pcieFunctionIdStr) 550727a046cSLakshmi Yadlapati { 551ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 552727a046cSLakshmi Yadlapati { 553727a046cSLakshmi Yadlapati return; 554727a046cSLakshmi Yadlapati } 555e14742caSEd Tanous uint64_t pcieFunctionId = 0; 556e14742caSEd Tanous std::from_chars_result result = std::from_chars( 557e14742caSEd Tanous &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId); 558e14742caSEd Tanous if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end()) 559e14742caSEd Tanous { 560ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 561e14742caSEd Tanous pcieFunctionIdStr); 562e14742caSEd Tanous return; 563e14742caSEd Tanous } 564727a046cSLakshmi Yadlapati 565ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 566ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 567ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 568727a046cSLakshmi Yadlapati const std::string& service) { 569727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 570ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 571ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 572727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 573ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 574727a046cSLakshmi Yadlapati pcieFunctionId); 575ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 576727a046cSLakshmi Yadlapati pcieDevProperties); 5777e860f15SJohn Edward Broadbent }); 578727a046cSLakshmi Yadlapati }); 579727a046cSLakshmi Yadlapati } 580727a046cSLakshmi Yadlapati 581727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 582727a046cSLakshmi Yadlapati { 583727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 584727a046cSLakshmi Yadlapati app, 585727a046cSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/") 586727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 587727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 588727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 589f5c9f8bdSJason M. Bills } 590f5c9f8bdSJason M. Bills 591f5c9f8bdSJason M. Bills } // namespace redfish 592