1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation 4f5c9f8bdSJason M. Bills 5f5c9f8bdSJason M. Bills #pragma once 6f5c9f8bdSJason M. Bills 73ccb3adbSEd Tanous #include "app.hpp" 87a1dbc48SGeorge Liu #include "dbus_utility.hpp" 9539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 103ccb3adbSEd Tanous #include "query.hpp" 113ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 12b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp" 133ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 14c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp" 150ec8b83dSEd Tanous 16f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp> 17ef4c65b7SEd Tanous #include <boost/url/format.hpp> 18d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 19d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 20f5c9f8bdSJason M. Bills 218c1d0549SMyung Bae #include <limits> 228c1d0549SMyung Bae 23f5c9f8bdSJason M. Bills namespace redfish 24f5c9f8bdSJason M. Bills { 25f5c9f8bdSJason M. Bills 2689492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory"; 2794c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = { 2894c3a10bSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 29a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = { 30a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot"}; 31f5c9f8bdSJason M. Bills 324ff0f1f4SEd Tanous inline void handlePCIeDevicePath( 33543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 34ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 35543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 36543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 37543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 38543f9a75SLakshmi Yadlapati 39543f9a75SLakshmi Yadlapati { 40543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 41543f9a75SLakshmi Yadlapati { 42543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 43543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 44543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 45543f9a75SLakshmi Yadlapati { 46543f9a75SLakshmi Yadlapati continue; 47543f9a75SLakshmi Yadlapati } 48543f9a75SLakshmi Yadlapati 49543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 503a58c5a8SKonstantin Aladyshev pcieDevicePath, pcieDeviceInterface, 51ac106bf6SEd Tanous [pcieDevicePath, asyncResp, 52543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 53543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 54543f9a75SLakshmi Yadlapati if (ec || object.empty()) 55543f9a75SLakshmi Yadlapati { 5662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 57ac106bf6SEd Tanous messages::internalError(asyncResp->res); 58543f9a75SLakshmi Yadlapati return; 59543f9a75SLakshmi Yadlapati } 60543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 61543f9a75SLakshmi Yadlapati }); 62543f9a75SLakshmi Yadlapati return; 63543f9a75SLakshmi Yadlapati } 64543f9a75SLakshmi Yadlapati 6562598e31SEd Tanous BMCWEB_LOG_WARNING("PCIe Device not found"); 66ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId); 67543f9a75SLakshmi Yadlapati } 68543f9a75SLakshmi Yadlapati 694ff0f1f4SEd Tanous inline void getValidPCIeDevicePath( 70543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 71ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 72543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 73543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 74543f9a75SLakshmi Yadlapati { 75543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 7694c3a10bSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 77ac106bf6SEd Tanous [pcieDeviceId, asyncResp, 78543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 79543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 80543f9a75SLakshmi Yadlapati pcieDevicePaths) { 81543f9a75SLakshmi Yadlapati if (ec) 82543f9a75SLakshmi Yadlapati { 8362598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec); 84ac106bf6SEd Tanous messages::internalError(asyncResp->res); 85543f9a75SLakshmi Yadlapati return; 86543f9a75SLakshmi Yadlapati } 87ac106bf6SEd Tanous handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths, 88ac106bf6SEd Tanous callback); 89543f9a75SLakshmi Yadlapati return; 90543f9a75SLakshmi Yadlapati }); 91543f9a75SLakshmi Yadlapati } 92543f9a75SLakshmi Yadlapati 934ff0f1f4SEd Tanous inline void handlePCIeDeviceCollectionGet( 94b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 95ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 96b38fa2abSLakshmi Yadlapati const std::string& systemName) 97b38fa2abSLakshmi Yadlapati { 98ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 99b38fa2abSLakshmi Yadlapati { 100b38fa2abSLakshmi Yadlapati return; 101b38fa2abSLakshmi Yadlapati } 10225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 1037f3e84a1SEd Tanous { 1047f3e84a1SEd Tanous // Option currently returns no systems. TBD 1057f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1067f3e84a1SEd Tanous systemName); 1077f3e84a1SEd Tanous return; 1087f3e84a1SEd Tanous } 109253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 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"; 121253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 122253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME); 123ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device Collection"; 124ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 125b38fa2abSLakshmi Yadlapati 12670c4d545SLakshmi Yadlapati pcie_util::getPCIeDeviceList(asyncResp, 12770c4d545SLakshmi Yadlapati nlohmann::json::json_pointer("/Members")); 128b38fa2abSLakshmi Yadlapati } 129b38fa2abSLakshmi Yadlapati 1307e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 131adbe192aSJason M. Bills { 132adbe192aSJason M. Bills /** 133adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 134adbe192aSJason M. Bills */ 13522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 136ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1377e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 138b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 139f5c9f8bdSJason M. Bills } 140f5c9f8bdSJason M. Bills 141a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties( 142a5409991SLakshmi Yadlapati crow::Response& res, const boost::system::error_code& ec, 143a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) 144a5409991SLakshmi Yadlapati { 145a5409991SLakshmi Yadlapati if (ec) 146a5409991SLakshmi Yadlapati { 14762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}", 14862598e31SEd Tanous ec.value()); 149a5409991SLakshmi Yadlapati messages::internalError(res); 150a5409991SLakshmi Yadlapati return; 151a5409991SLakshmi Yadlapati } 152a5409991SLakshmi Yadlapati std::string generation; 153a5409991SLakshmi Yadlapati size_t lanes = 0; 154a5409991SLakshmi Yadlapati std::string slotType; 155a5409991SLakshmi Yadlapati 156a5409991SLakshmi Yadlapati bool success = sdbusplus::unpackPropertiesNoThrow( 157a5409991SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation", 158a5409991SLakshmi Yadlapati generation, "Lanes", lanes, "SlotType", slotType); 159a5409991SLakshmi Yadlapati 160a5409991SLakshmi Yadlapati if (!success) 161a5409991SLakshmi Yadlapati { 162a5409991SLakshmi Yadlapati messages::internalError(res); 163a5409991SLakshmi Yadlapati return; 164a5409991SLakshmi Yadlapati } 165a5409991SLakshmi Yadlapati 166a5409991SLakshmi Yadlapati std::optional<pcie_device::PCIeTypes> pcieType = 167a5409991SLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(generation); 168a5409991SLakshmi Yadlapati if (!pcieType) 169a5409991SLakshmi Yadlapati { 17062598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation); 171a5409991SLakshmi Yadlapati } 172a5409991SLakshmi Yadlapati else 173a5409991SLakshmi Yadlapati { 174a5409991SLakshmi Yadlapati if (*pcieType == pcie_device::PCIeTypes::Invalid) 175a5409991SLakshmi Yadlapati { 17662598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation); 177a5409991SLakshmi Yadlapati messages::internalError(res); 178a5409991SLakshmi Yadlapati return; 179a5409991SLakshmi Yadlapati } 180a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["PCIeType"] = *pcieType; 181a5409991SLakshmi Yadlapati } 182a5409991SLakshmi Yadlapati 18382f80326SKonstantin Aladyshev if (lanes != 0) 18482f80326SKonstantin Aladyshev { 185a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["Lanes"] = lanes; 18682f80326SKonstantin Aladyshev } 187a5409991SLakshmi Yadlapati 188a5409991SLakshmi Yadlapati std::optional<pcie_slots::SlotTypes> redfishSlotType = 189a5409991SLakshmi Yadlapati pcie_util::dbusSlotTypeToRf(slotType); 190a5409991SLakshmi Yadlapati if (!redfishSlotType) 191a5409991SLakshmi Yadlapati { 19262598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType); 193a5409991SLakshmi Yadlapati } 194a5409991SLakshmi Yadlapati else 195a5409991SLakshmi Yadlapati { 196a5409991SLakshmi Yadlapati if (*redfishSlotType == pcie_slots::SlotTypes::Invalid) 197a5409991SLakshmi Yadlapati { 19862598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType); 199a5409991SLakshmi Yadlapati messages::internalError(res); 200a5409991SLakshmi Yadlapati return; 201a5409991SLakshmi Yadlapati } 202a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["SlotType"] = *redfishSlotType; 203a5409991SLakshmi Yadlapati } 204a5409991SLakshmi Yadlapati } 205a5409991SLakshmi Yadlapati 206a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath( 207a5409991SLakshmi Yadlapati const std::string& pcieDevicePath, 208a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 209a5409991SLakshmi Yadlapati std::function<void(const std::string& pcieDeviceSlot)>&& callback) 210a5409991SLakshmi Yadlapati { 211a5409991SLakshmi Yadlapati std::string associationPath = pcieDevicePath + "/contained_by"; 212a5409991SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 213a5409991SLakshmi Yadlapati associationPath, sdbusplus::message::object_path(inventoryPath), 0, 214a5409991SLakshmi Yadlapati pcieSlotInterface, 2158cb2c024SEd Tanous [callback = std::move(callback), asyncResp, pcieDevicePath]( 216a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 217a5409991SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& endpoints) { 218a5409991SLakshmi Yadlapati if (ec) 219a5409991SLakshmi Yadlapati { 220a5409991SLakshmi Yadlapati if (ec.value() == EBADR) 221a5409991SLakshmi Yadlapati { 222a5409991SLakshmi Yadlapati // Missing association is not an error 223a5409991SLakshmi Yadlapati return; 224a5409991SLakshmi Yadlapati } 22562598e31SEd Tanous BMCWEB_LOG_ERROR( 22662598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}", 22762598e31SEd Tanous ec.value()); 228a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 229a5409991SLakshmi Yadlapati return; 230a5409991SLakshmi Yadlapati } 231a5409991SLakshmi Yadlapati if (endpoints.size() > 1) 232a5409991SLakshmi Yadlapati { 23362598e31SEd Tanous BMCWEB_LOG_ERROR( 234a6bd55b0SGunnar Mills "PCIeDevice {} is associated with more than one PCIeSlot: {}", 235a6bd55b0SGunnar Mills pcieDevicePath, endpoints.size()); 236a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 237a5409991SLakshmi Yadlapati return; 238a5409991SLakshmi Yadlapati } 239a5409991SLakshmi Yadlapati if (endpoints.empty()) 240a5409991SLakshmi Yadlapati { 241bd79bce8SPatrick Williams // If the device doesn't have an association, return without 242bd79bce8SPatrick Williams // PCIe Slot properties 24362598e31SEd Tanous BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot"); 244a5409991SLakshmi Yadlapati return; 245a5409991SLakshmi Yadlapati } 246a5409991SLakshmi Yadlapati callback(endpoints[0]); 247a5409991SLakshmi Yadlapati }); 248a5409991SLakshmi Yadlapati } 249a5409991SLakshmi Yadlapati 250bd79bce8SPatrick Williams inline void afterGetDbusObject( 251bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 252bd79bce8SPatrick Williams const std::string& pcieDeviceSlot, const boost::system::error_code& ec, 253a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) 254a5409991SLakshmi Yadlapati { 255a5409991SLakshmi Yadlapati if (ec || object.empty()) 256a5409991SLakshmi Yadlapati { 25762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}", 25862598e31SEd Tanous ec.value()); 259a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 260a5409991SLakshmi Yadlapati return; 261a5409991SLakshmi Yadlapati } 262deae6a78SEd Tanous dbus::utility::getAllProperties( 263deae6a78SEd Tanous object.begin()->first, pcieDeviceSlot, 264a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot", 265a5409991SLakshmi Yadlapati [asyncResp]( 266a5409991SLakshmi Yadlapati const boost::system::error_code& ec2, 267a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) { 268a5409991SLakshmi Yadlapati addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties); 269a5409991SLakshmi Yadlapati }); 270a5409991SLakshmi Yadlapati } 271a5409991SLakshmi Yadlapati 272a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath( 273a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 274a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot) 275a5409991SLakshmi Yadlapati { 276a5409991SLakshmi Yadlapati dbus::utility::getDbusObject( 277a5409991SLakshmi Yadlapati pcieDeviceSlot, pcieSlotInterface, 278a5409991SLakshmi Yadlapati [asyncResp, 279a5409991SLakshmi Yadlapati pcieDeviceSlot](const boost::system::error_code& ec, 280a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 281a5409991SLakshmi Yadlapati afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object); 282a5409991SLakshmi Yadlapati }); 283a5409991SLakshmi Yadlapati } 284a5409991SLakshmi Yadlapati 285bd79bce8SPatrick Williams inline void getPCIeDeviceHealth( 286bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 287bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 288e164f1b6SLakshmi Yadlapati { 289deae6a78SEd Tanous dbus::utility::getProperty<bool>( 290deae6a78SEd Tanous service, pcieDevicePath, 291e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 292e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 293e164f1b6SLakshmi Yadlapati if (ec) 294e164f1b6SLakshmi Yadlapati { 295e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 296e164f1b6SLakshmi Yadlapati { 29762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 29862598e31SEd Tanous ec.value()); 299e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 300e164f1b6SLakshmi Yadlapati } 301e164f1b6SLakshmi Yadlapati return; 302e164f1b6SLakshmi Yadlapati } 303e164f1b6SLakshmi Yadlapati 304e164f1b6SLakshmi Yadlapati if (!value) 305e164f1b6SLakshmi Yadlapati { 306539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 307539d8c6bSEd Tanous resource::Health::Critical; 308e164f1b6SLakshmi Yadlapati } 309e164f1b6SLakshmi Yadlapati }); 310e164f1b6SLakshmi Yadlapati } 311e164f1b6SLakshmi Yadlapati 312bd79bce8SPatrick Williams inline void getPCIeDeviceState( 313bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 314bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 315c6bb3285SLakshmi Yadlapati { 316deae6a78SEd Tanous dbus::utility::getProperty<bool>( 317deae6a78SEd Tanous service, pcieDevicePath, "xyz.openbmc_project.Inventory.Item", 318deae6a78SEd Tanous "Present", 319a5409991SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, bool value) { 320c6bb3285SLakshmi Yadlapati if (ec) 321c6bb3285SLakshmi Yadlapati { 322c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 323c6bb3285SLakshmi Yadlapati { 32462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State"); 325ac106bf6SEd Tanous messages::internalError(asyncResp->res); 326c6bb3285SLakshmi Yadlapati } 327c6bb3285SLakshmi Yadlapati return; 328c6bb3285SLakshmi Yadlapati } 329c6bb3285SLakshmi Yadlapati 330c6bb3285SLakshmi Yadlapati if (!value) 331c6bb3285SLakshmi Yadlapati { 332539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 333539d8c6bSEd Tanous resource::State::Absent; 334c6bb3285SLakshmi Yadlapati } 335c6bb3285SLakshmi Yadlapati }); 336c6bb3285SLakshmi Yadlapati } 337c6bb3285SLakshmi Yadlapati 338bd79bce8SPatrick Williams inline void getPCIeDeviceAsset( 339bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 340bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 341913e7732SSunnySrivastava1984 { 342deae6a78SEd Tanous dbus::utility::getAllProperties( 343deae6a78SEd Tanous service, pcieDevicePath, 344913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 345ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 346ac106bf6SEd Tanous const boost::system::error_code& ec, 347913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 348913e7732SSunnySrivastava1984 if (ec) 349913e7732SSunnySrivastava1984 { 350913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 351913e7732SSunnySrivastava1984 { 35262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}", 35362598e31SEd Tanous ec.value()); 354ac106bf6SEd Tanous messages::internalError(asyncResp->res); 355913e7732SSunnySrivastava1984 } 356913e7732SSunnySrivastava1984 return; 357913e7732SSunnySrivastava1984 } 358913e7732SSunnySrivastava1984 359913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 360913e7732SSunnySrivastava1984 const std::string* model = nullptr; 361913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 362913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 363913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 364913e7732SSunnySrivastava1984 365913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 366913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 367913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 368bd79bce8SPatrick Williams "SerialNumber", serialNumber, "SparePartNumber", 369bd79bce8SPatrick Williams sparePartNumber); 370913e7732SSunnySrivastava1984 371913e7732SSunnySrivastava1984 if (!success) 372913e7732SSunnySrivastava1984 { 373ac106bf6SEd Tanous messages::internalError(asyncResp->res); 374913e7732SSunnySrivastava1984 return; 375913e7732SSunnySrivastava1984 } 376913e7732SSunnySrivastava1984 377913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 378913e7732SSunnySrivastava1984 { 379ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 380913e7732SSunnySrivastava1984 } 381913e7732SSunnySrivastava1984 if (model != nullptr) 382913e7732SSunnySrivastava1984 { 383ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 384913e7732SSunnySrivastava1984 } 385913e7732SSunnySrivastava1984 386913e7732SSunnySrivastava1984 if (partNumber != nullptr) 387913e7732SSunnySrivastava1984 { 388ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 389913e7732SSunnySrivastava1984 } 390913e7732SSunnySrivastava1984 391913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 392913e7732SSunnySrivastava1984 { 393ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 394913e7732SSunnySrivastava1984 } 395913e7732SSunnySrivastava1984 396913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 397913e7732SSunnySrivastava1984 { 398ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 399913e7732SSunnySrivastava1984 } 400913e7732SSunnySrivastava1984 }); 401913e7732SSunnySrivastava1984 } 402913e7732SSunnySrivastava1984 403543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 404a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 405a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, 406543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 407f5c9f8bdSJason M. Bills { 408d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 409814bf20aSKonstantin Aladyshev const std::string* generationSupported = nullptr; 4109bb0a7feSKonstantin Aladyshev const size_t* lanesInUse = nullptr; 411814bf20aSKonstantin Aladyshev const size_t* maxLanes = nullptr; 412d1bde9e5SKrzysztof Grobelny 413d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 414609ba4c9SEd Tanous dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse", 415609ba4c9SEd Tanous generationInUse, "GenerationSupported", generationSupported, 416609ba4c9SEd Tanous "LanesInUse", lanesInUse, "MaxLanes", maxLanes); 417d1bde9e5SKrzysztof Grobelny 418d1bde9e5SKrzysztof Grobelny if (!success) 419d1bde9e5SKrzysztof Grobelny { 420a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 421d1bde9e5SKrzysztof Grobelny return; 422d1bde9e5SKrzysztof Grobelny } 423d1bde9e5SKrzysztof Grobelny 424d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 425d1bde9e5SKrzysztof Grobelny { 4260ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 427c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 428543f9a75SLakshmi Yadlapati 429d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 430d1bde9e5SKrzysztof Grobelny { 43162598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 43262598e31SEd Tanous *generationInUse); 433cf3b484eSLakshmi Yadlapati } 434cf3b484eSLakshmi Yadlapati else 435cf3b484eSLakshmi Yadlapati { 436cf3b484eSLakshmi Yadlapati if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid) 437cf3b484eSLakshmi Yadlapati { 43862598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 43962598e31SEd Tanous *generationInUse); 440a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 441d1bde9e5SKrzysztof Grobelny return; 442d1bde9e5SKrzysztof Grobelny } 443a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 444d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 445d1bde9e5SKrzysztof Grobelny } 446a9f68bb5STony Lee } 447d1bde9e5SKrzysztof Grobelny 448814bf20aSKonstantin Aladyshev if (generationSupported != nullptr) 449814bf20aSKonstantin Aladyshev { 450814bf20aSKonstantin Aladyshev std::optional<pcie_device::PCIeTypes> redfishGenerationSupported = 451814bf20aSKonstantin Aladyshev pcie_util::redfishPcieGenerationFromDbus(*generationSupported); 452814bf20aSKonstantin Aladyshev 453814bf20aSKonstantin Aladyshev if (!redfishGenerationSupported) 454814bf20aSKonstantin Aladyshev { 45562598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 45662598e31SEd Tanous *generationSupported); 457814bf20aSKonstantin Aladyshev } 458814bf20aSKonstantin Aladyshev else 459814bf20aSKonstantin Aladyshev { 460814bf20aSKonstantin Aladyshev if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid) 461814bf20aSKonstantin Aladyshev { 46262598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 46362598e31SEd Tanous *generationSupported); 464814bf20aSKonstantin Aladyshev messages::internalError(asyncResp->res); 465814bf20aSKonstantin Aladyshev return; 466814bf20aSKonstantin Aladyshev } 467814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] = 468814bf20aSKonstantin Aladyshev *redfishGenerationSupported; 469814bf20aSKonstantin Aladyshev } 470814bf20aSKonstantin Aladyshev } 471814bf20aSKonstantin Aladyshev 4728c1d0549SMyung Bae if (lanesInUse != nullptr) 473543f9a75SLakshmi Yadlapati { 4748c1d0549SMyung Bae if (*lanesInUse == std::numeric_limits<size_t>::max()) 4758c1d0549SMyung Bae { 4768c1d0549SMyung Bae // The default value of LanesInUse is "maxint", and the field will 4778c1d0549SMyung Bae // be null if it is a default value. 4788c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr; 4798c1d0549SMyung Bae } 4808c1d0549SMyung Bae else 4818c1d0549SMyung Bae { 4828c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = 4838c1d0549SMyung Bae *lanesInUse; 4848c1d0549SMyung Bae } 485543f9a75SLakshmi Yadlapati } 486814bf20aSKonstantin Aladyshev // The default value of MaxLanes is 0, and the field will be 487814bf20aSKonstantin Aladyshev // left as off if it is a default value. 488814bf20aSKonstantin Aladyshev if (maxLanes != nullptr && *maxLanes != 0) 489814bf20aSKonstantin Aladyshev { 490814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes; 491814bf20aSKonstantin Aladyshev } 492543f9a75SLakshmi Yadlapati 493a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 494a5409991SLakshmi Yadlapati boost::urls::format( 495253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 496253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 497d1bde9e5SKrzysztof Grobelny } 498d1bde9e5SKrzysztof Grobelny 499543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 500ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 501543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 502543f9a75SLakshmi Yadlapati const std::function<void( 503543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 504d1bde9e5SKrzysztof Grobelny { 505deae6a78SEd Tanous dbus::utility::getAllProperties( 506deae6a78SEd Tanous service, pcieDevicePath, 507543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 508ac106bf6SEd Tanous [asyncResp, 509543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 510543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 511543f9a75SLakshmi Yadlapati if (ec) 512543f9a75SLakshmi Yadlapati { 513543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 514543f9a75SLakshmi Yadlapati { 51562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties"); 516ac106bf6SEd Tanous messages::internalError(asyncResp->res); 517543f9a75SLakshmi Yadlapati } 518543f9a75SLakshmi Yadlapati return; 519543f9a75SLakshmi Yadlapati } 520543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 521543f9a75SLakshmi Yadlapati }); 522d1bde9e5SKrzysztof Grobelny } 523d1bde9e5SKrzysztof Grobelny 524543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 525ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 526543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 527543f9a75SLakshmi Yadlapati { 528ac106bf6SEd Tanous asyncResp->res.addHeader( 529543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 530543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 531ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 532253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 533253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 534253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 535ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 536ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 537539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 538539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 539543f9a75SLakshmi Yadlapati } 5401476687dSEd Tanous 541a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath( 542a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 543a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, const std::string& pcieDevicePath, 544a5409991SLakshmi Yadlapati const std::string& service) 545a5409991SLakshmi Yadlapati { 546a5409991SLakshmi Yadlapati addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 547a5409991SLakshmi Yadlapati getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 548a5409991SLakshmi Yadlapati getPCIeDeviceState(asyncResp, pcieDevicePath, service); 549a5409991SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 550a5409991SLakshmi Yadlapati getPCIeDeviceProperties( 551a5409991SLakshmi Yadlapati asyncResp, pcieDevicePath, service, 552a5409991SLakshmi Yadlapati std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId)); 553a5409991SLakshmi Yadlapati getPCIeDeviceSlotPath( 554a5409991SLakshmi Yadlapati pcieDevicePath, asyncResp, 555a5409991SLakshmi Yadlapati std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp)); 556a5409991SLakshmi Yadlapati } 557a5409991SLakshmi Yadlapati 558bd79bce8SPatrick Williams inline void handlePCIeDeviceGet( 559bd79bce8SPatrick Williams App& app, const crow::Request& req, 560ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 561bd79bce8SPatrick Williams const std::string& systemName, const std::string& pcieDeviceId) 562543f9a75SLakshmi Yadlapati { 563ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 564543f9a75SLakshmi Yadlapati { 565543f9a75SLakshmi Yadlapati return; 566543f9a75SLakshmi Yadlapati } 56725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5687f3e84a1SEd Tanous { 5697f3e84a1SEd Tanous // Option currently returns no systems. TBD 5707f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5717f3e84a1SEd Tanous systemName); 5727f3e84a1SEd Tanous return; 5737f3e84a1SEd Tanous } 574253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 575543f9a75SLakshmi Yadlapati { 576ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 577ac106bf6SEd Tanous systemName); 578543f9a75SLakshmi Yadlapati return; 579543f9a75SLakshmi Yadlapati } 580543f9a75SLakshmi Yadlapati 581543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 582ac106bf6SEd Tanous pcieDeviceId, asyncResp, 583a5409991SLakshmi Yadlapati std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId)); 584543f9a75SLakshmi Yadlapati } 585543f9a75SLakshmi Yadlapati 586543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 587543f9a75SLakshmi Yadlapati { 588543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 589543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 590543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 591543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 592dede6a98SJason M. Bills } 593dede6a98SJason M. Bills 59435ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 59535ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 59635ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 59735ad613dSLakshmi Yadlapati { 59835ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 59935ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 60035ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 60135ad613dSLakshmi Yadlapati 60235ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 60335ad613dSLakshmi Yadlapati { 60435ad613dSLakshmi Yadlapati // Check if this function exists by 60535ad613dSLakshmi Yadlapati // looking for a device ID 606bd79bce8SPatrick Williams std::string devIDProperty = 607bd79bce8SPatrick Williams "Function" + std::to_string(functionNum) + "DeviceId"; 60835ad613dSLakshmi Yadlapati const std::string* property = nullptr; 60935ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 61035ad613dSLakshmi Yadlapati { 61135ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 61235ad613dSLakshmi Yadlapati { 61335ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 61435ad613dSLakshmi Yadlapati break; 61535ad613dSLakshmi Yadlapati } 61635ad613dSLakshmi Yadlapati } 61735ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 61835ad613dSLakshmi Yadlapati { 61935ad613dSLakshmi Yadlapati continue; 62035ad613dSLakshmi Yadlapati } 62135ad613dSLakshmi Yadlapati 62235ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 623ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 624253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 625253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 626253f11b8SEd Tanous std::to_string(functionNum)); 627b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 62835ad613dSLakshmi Yadlapati } 62935ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 63035ad613dSLakshmi Yadlapati } 63135ad613dSLakshmi Yadlapati 63235ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 63335ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 634ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6357f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 63635ad613dSLakshmi Yadlapati { 637ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 63835ad613dSLakshmi Yadlapati { 63935ad613dSLakshmi Yadlapati return; 64035ad613dSLakshmi Yadlapati } 64125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6427f3e84a1SEd Tanous { 6437f3e84a1SEd Tanous // Option currently returns no systems. TBD 6447f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6457f3e84a1SEd Tanous systemName); 6467f3e84a1SEd Tanous return; 6477f3e84a1SEd Tanous } 64835ad613dSLakshmi Yadlapati 64935ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 650ac106bf6SEd Tanous pcieDeviceId, asyncResp, 651ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 65235ad613dSLakshmi Yadlapati const std::string& service) { 653ac106bf6SEd Tanous asyncResp->res.addHeader( 65435ad613dSLakshmi Yadlapati boost::beast::http::field::link, 65535ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 656ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 65735ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 658ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 659253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 660253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 661ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 662ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 66335ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 66435ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 665ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 666ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 66735ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 668ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 669ac106bf6SEd Tanous pcieDevProperties); 67035ad613dSLakshmi Yadlapati }); 67135ad613dSLakshmi Yadlapati }); 67235ad613dSLakshmi Yadlapati } 67335ad613dSLakshmi Yadlapati 6747e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 6757e860f15SJohn Edward Broadbent { 676dede6a98SJason M. Bills /** 677dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 678dede6a98SJason M. Bills */ 6797e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 6807f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 681ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 682002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 68335ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 6847e860f15SJohn Edward Broadbent } 6857e860f15SJohn Edward Broadbent 686727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 687d5e74b80SMyung Bae uint64_t pcieFunctionId, 688727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 6897e860f15SJohn Edward Broadbent { 690d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 691b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 692b9d36b47SEd Tanous 693b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 694b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 695b9d36b47SEd Tanous { 696b9d36b47SEd Tanous if (property.first == devIDProperty) 697b9d36b47SEd Tanous { 698002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 699727a046cSLakshmi Yadlapati break; 700b9d36b47SEd Tanous } 701b9d36b47SEd Tanous } 702727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 703727a046cSLakshmi Yadlapati } 704727a046cSLakshmi Yadlapati 705727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 706e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 707727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 708f5c9f8bdSJason M. Bills { 709e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 710b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 711f5c9f8bdSJason M. Bills { 712b9d36b47SEd Tanous const std::string* strProperty = 713b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 714dc8cfa66SEd Tanous if (strProperty == nullptr) 715dc8cfa66SEd Tanous { 716dc8cfa66SEd Tanous continue; 717dc8cfa66SEd Tanous } 718b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 719f5c9f8bdSJason M. Bills { 720727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 721f5c9f8bdSJason M. Bills } 722b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 723f5c9f8bdSJason M. Bills { 724727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 725f5c9f8bdSJason M. Bills } 726727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 727727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 728727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 729b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 730f5c9f8bdSJason M. Bills { 731727a046cSLakshmi Yadlapati if (!strProperty->empty()) 732727a046cSLakshmi Yadlapati { 733727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 734727a046cSLakshmi Yadlapati } 735f5c9f8bdSJason M. Bills } 736b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 737f5c9f8bdSJason M. Bills { 738727a046cSLakshmi Yadlapati if (!strProperty->empty()) 739727a046cSLakshmi Yadlapati { 740727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 741727a046cSLakshmi Yadlapati } 742f5c9f8bdSJason M. Bills } 743b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 744f5c9f8bdSJason M. Bills { 745727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 746f5c9f8bdSJason M. Bills } 747b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 748f5c9f8bdSJason M. Bills { 749727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 750f5c9f8bdSJason M. Bills } 751b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 752b9d36b47SEd Tanous { 753727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 754b9d36b47SEd Tanous } 755002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 756f5c9f8bdSJason M. Bills { 757727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 758b9d36b47SEd Tanous } 759f5c9f8bdSJason M. Bills } 760727a046cSLakshmi Yadlapati } 761727a046cSLakshmi Yadlapati 762727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 763727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 764e14742caSEd Tanous uint64_t pcieFunctionId) 765727a046cSLakshmi Yadlapati { 766727a046cSLakshmi Yadlapati resp.addHeader( 767727a046cSLakshmi Yadlapati boost::beast::http::field::link, 768727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 769727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 770ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 771253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 772253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 773253f11b8SEd Tanous std::to_string(pcieFunctionId)); 774727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 775e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 776e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 777253f11b8SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 778253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 779253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 780727a046cSLakshmi Yadlapati } 781727a046cSLakshmi Yadlapati 782bd79bce8SPatrick Williams inline void handlePCIeFunctionGet( 783bd79bce8SPatrick Williams App& app, const crow::Request& req, 784ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 785bd79bce8SPatrick Williams const std::string& systemName, const std::string& pcieDeviceId, 786e14742caSEd Tanous const std::string& pcieFunctionIdStr) 787727a046cSLakshmi Yadlapati { 788ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 789727a046cSLakshmi Yadlapati { 790727a046cSLakshmi Yadlapati return; 791727a046cSLakshmi Yadlapati } 79225b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 7937f3e84a1SEd Tanous { 7947f3e84a1SEd Tanous // Option currently returns no systems. TBD 7957f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 7967f3e84a1SEd Tanous systemName); 7977f3e84a1SEd Tanous return; 7987f3e84a1SEd Tanous } 799253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 8007f3e84a1SEd Tanous { 8017f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8027f3e84a1SEd Tanous systemName); 8037f3e84a1SEd Tanous return; 8047f3e84a1SEd Tanous } 805dc8cfa66SEd Tanous std::string_view pcieFunctionIdView = pcieFunctionIdStr; 8067f3e84a1SEd Tanous 807e14742caSEd Tanous uint64_t pcieFunctionId = 0; 808e14742caSEd Tanous std::from_chars_result result = std::from_chars( 809dc8cfa66SEd Tanous pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId); 810dc8cfa66SEd Tanous if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end()) 811e14742caSEd Tanous { 812ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 813e14742caSEd Tanous pcieFunctionIdStr); 814e14742caSEd Tanous return; 815e14742caSEd Tanous } 816727a046cSLakshmi Yadlapati 817bd79bce8SPatrick Williams getValidPCIeDevicePath( 818bd79bce8SPatrick Williams pcieDeviceId, asyncResp, 819bd79bce8SPatrick Williams [asyncResp, pcieDeviceId, pcieFunctionId]( 820bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) { 821727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 822ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 823ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 824727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 825bd79bce8SPatrick Williams addPCIeFunctionCommonProperties( 826bd79bce8SPatrick Williams asyncResp->res, pcieDeviceId, pcieFunctionId); 827ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 828727a046cSLakshmi Yadlapati pcieDevProperties); 8297e860f15SJohn Edward Broadbent }); 830727a046cSLakshmi Yadlapati }); 831727a046cSLakshmi Yadlapati } 832727a046cSLakshmi Yadlapati 833727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 834727a046cSLakshmi Yadlapati { 835727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8367f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 837727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 838727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 839727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 840f5c9f8bdSJason M. Bills } 841f5c9f8bdSJason M. Bills 842f5c9f8bdSJason M. Bills } // namespace redfish 843