140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation 4f5c9f8bdSJason M. Bills 5f5c9f8bdSJason M. Bills #pragma once 6f5c9f8bdSJason M. Bills 7d7857201SEd Tanous #include "bmcweb_config.h" 8d7857201SEd Tanous 93ccb3adbSEd Tanous #include "app.hpp" 10d7857201SEd Tanous #include "async_resp.hpp" 117a1dbc48SGeorge Liu #include "dbus_utility.hpp" 12d7857201SEd Tanous #include "error_messages.hpp" 13d7857201SEd Tanous #include "generated/enums/pcie_device.hpp" 14d7857201SEd Tanous #include "generated/enums/pcie_slots.hpp" 15539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 16d7857201SEd Tanous #include "http_request.hpp" 17d7857201SEd Tanous #include "logging.hpp" 183ccb3adbSEd Tanous #include "query.hpp" 193ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 203ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 21c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp" 220ec8b83dSEd Tanous 23d7857201SEd Tanous #include <asm-generic/errno.h> 24d7857201SEd Tanous 25d7857201SEd Tanous #include <boost/beast/http/field.hpp> 26d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 27ef4c65b7SEd Tanous #include <boost/url/format.hpp> 28d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 29f5c9f8bdSJason M. Bills 30d7857201SEd Tanous #include <array> 31d7857201SEd Tanous #include <charconv> 32d7857201SEd Tanous #include <cstddef> 33d7857201SEd Tanous #include <cstdint> 34d7857201SEd Tanous #include <format> 35d7857201SEd Tanous #include <functional> 368c1d0549SMyung Bae #include <limits> 37d7857201SEd Tanous #include <memory> 38d7857201SEd Tanous #include <optional> 39d7857201SEd Tanous #include <string> 40d7857201SEd Tanous #include <string_view> 41d7857201SEd Tanous #include <system_error> 42d7857201SEd Tanous #include <utility> 43d7857201SEd Tanous #include <variant> 448c1d0549SMyung Bae 45f5c9f8bdSJason M. Bills namespace redfish 46f5c9f8bdSJason M. Bills { 47f5c9f8bdSJason M. Bills 4889492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory"; 4994c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = { 5094c3a10bSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 51a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = { 52a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot"}; 53f5c9f8bdSJason M. Bills 544ff0f1f4SEd Tanous inline void handlePCIeDevicePath( 55543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 56ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 57543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 58543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 59543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 60543f9a75SLakshmi Yadlapati 61543f9a75SLakshmi Yadlapati { 62543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 63543f9a75SLakshmi Yadlapati { 64543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 65543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 66543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 67543f9a75SLakshmi Yadlapati { 68543f9a75SLakshmi Yadlapati continue; 69543f9a75SLakshmi Yadlapati } 70543f9a75SLakshmi Yadlapati 71543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 723a58c5a8SKonstantin Aladyshev pcieDevicePath, pcieDeviceInterface, 73ac106bf6SEd Tanous [pcieDevicePath, asyncResp, 74543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 75543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 76543f9a75SLakshmi Yadlapati if (ec || object.empty()) 77543f9a75SLakshmi Yadlapati { 7862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 79ac106bf6SEd Tanous messages::internalError(asyncResp->res); 80543f9a75SLakshmi Yadlapati return; 81543f9a75SLakshmi Yadlapati } 82543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 83543f9a75SLakshmi Yadlapati }); 84543f9a75SLakshmi Yadlapati return; 85543f9a75SLakshmi Yadlapati } 86543f9a75SLakshmi Yadlapati 8762598e31SEd Tanous BMCWEB_LOG_WARNING("PCIe Device not found"); 88ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId); 89543f9a75SLakshmi Yadlapati } 90543f9a75SLakshmi Yadlapati 914ff0f1f4SEd Tanous inline void getValidPCIeDevicePath( 92543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 93ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 94543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 95543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 96543f9a75SLakshmi Yadlapati { 97543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 9894c3a10bSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 99ac106bf6SEd Tanous [pcieDeviceId, asyncResp, 100543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 101543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 102543f9a75SLakshmi Yadlapati pcieDevicePaths) { 103543f9a75SLakshmi Yadlapati if (ec) 104543f9a75SLakshmi Yadlapati { 10562598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec); 106ac106bf6SEd Tanous messages::internalError(asyncResp->res); 107543f9a75SLakshmi Yadlapati return; 108543f9a75SLakshmi Yadlapati } 109ac106bf6SEd Tanous handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths, 110ac106bf6SEd Tanous callback); 111543f9a75SLakshmi Yadlapati return; 112543f9a75SLakshmi Yadlapati }); 113543f9a75SLakshmi Yadlapati } 114543f9a75SLakshmi Yadlapati 1154ff0f1f4SEd Tanous inline void handlePCIeDeviceCollectionGet( 116b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 117ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 118b38fa2abSLakshmi Yadlapati const std::string& systemName) 119b38fa2abSLakshmi Yadlapati { 120ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 121b38fa2abSLakshmi Yadlapati { 122b38fa2abSLakshmi Yadlapati return; 123b38fa2abSLakshmi Yadlapati } 12425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 1257f3e84a1SEd Tanous { 1267f3e84a1SEd Tanous // Option currently returns no systems. TBD 1277f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1287f3e84a1SEd Tanous systemName); 1297f3e84a1SEd Tanous return; 1307f3e84a1SEd Tanous } 131253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 132b38fa2abSLakshmi Yadlapati { 133ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 134ac106bf6SEd Tanous systemName); 135b38fa2abSLakshmi Yadlapati return; 136b38fa2abSLakshmi Yadlapati } 137543f9a75SLakshmi Yadlapati 138ac106bf6SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::link, 139b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 140b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 141ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 142b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 143253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 144253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME); 145ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device Collection"; 146ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 147b38fa2abSLakshmi Yadlapati 14870c4d545SLakshmi Yadlapati pcie_util::getPCIeDeviceList(asyncResp, 14970c4d545SLakshmi Yadlapati nlohmann::json::json_pointer("/Members")); 150b38fa2abSLakshmi Yadlapati } 151b38fa2abSLakshmi Yadlapati 1527e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 153adbe192aSJason M. Bills { 154adbe192aSJason M. Bills /** 155adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 156adbe192aSJason M. Bills */ 15722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 158ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1597e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 160b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 161f5c9f8bdSJason M. Bills } 162f5c9f8bdSJason M. Bills 163a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties( 164a5409991SLakshmi Yadlapati crow::Response& res, const boost::system::error_code& ec, 165a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) 166a5409991SLakshmi Yadlapati { 167a5409991SLakshmi Yadlapati if (ec) 168a5409991SLakshmi Yadlapati { 16962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}", 17062598e31SEd Tanous ec.value()); 171a5409991SLakshmi Yadlapati messages::internalError(res); 172a5409991SLakshmi Yadlapati return; 173a5409991SLakshmi Yadlapati } 174a5409991SLakshmi Yadlapati std::string generation; 175a5409991SLakshmi Yadlapati size_t lanes = 0; 176a5409991SLakshmi Yadlapati std::string slotType; 177a5409991SLakshmi Yadlapati 178a5409991SLakshmi Yadlapati bool success = sdbusplus::unpackPropertiesNoThrow( 179a5409991SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation", 180a5409991SLakshmi Yadlapati generation, "Lanes", lanes, "SlotType", slotType); 181a5409991SLakshmi Yadlapati 182a5409991SLakshmi Yadlapati if (!success) 183a5409991SLakshmi Yadlapati { 184a5409991SLakshmi Yadlapati messages::internalError(res); 185a5409991SLakshmi Yadlapati return; 186a5409991SLakshmi Yadlapati } 187a5409991SLakshmi Yadlapati 188a5409991SLakshmi Yadlapati std::optional<pcie_device::PCIeTypes> pcieType = 189a5409991SLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(generation); 190a5409991SLakshmi Yadlapati if (!pcieType) 191a5409991SLakshmi Yadlapati { 19262598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation); 193a5409991SLakshmi Yadlapati } 194a5409991SLakshmi Yadlapati else 195a5409991SLakshmi Yadlapati { 196a5409991SLakshmi Yadlapati if (*pcieType == pcie_device::PCIeTypes::Invalid) 197a5409991SLakshmi Yadlapati { 19862598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation); 199a5409991SLakshmi Yadlapati messages::internalError(res); 200a5409991SLakshmi Yadlapati return; 201a5409991SLakshmi Yadlapati } 202a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["PCIeType"] = *pcieType; 203a5409991SLakshmi Yadlapati } 204a5409991SLakshmi Yadlapati 20582f80326SKonstantin Aladyshev if (lanes != 0) 20682f80326SKonstantin Aladyshev { 207a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["Lanes"] = lanes; 20882f80326SKonstantin Aladyshev } 209a5409991SLakshmi Yadlapati 210a5409991SLakshmi Yadlapati std::optional<pcie_slots::SlotTypes> redfishSlotType = 211a5409991SLakshmi Yadlapati pcie_util::dbusSlotTypeToRf(slotType); 212a5409991SLakshmi Yadlapati if (!redfishSlotType) 213a5409991SLakshmi Yadlapati { 21462598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType); 215a5409991SLakshmi Yadlapati } 216a5409991SLakshmi Yadlapati else 217a5409991SLakshmi Yadlapati { 218a5409991SLakshmi Yadlapati if (*redfishSlotType == pcie_slots::SlotTypes::Invalid) 219a5409991SLakshmi Yadlapati { 22062598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType); 221a5409991SLakshmi Yadlapati messages::internalError(res); 222a5409991SLakshmi Yadlapati return; 223a5409991SLakshmi Yadlapati } 224a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["SlotType"] = *redfishSlotType; 225a5409991SLakshmi Yadlapati } 226a5409991SLakshmi Yadlapati } 227a5409991SLakshmi Yadlapati 228a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath( 229a5409991SLakshmi Yadlapati const std::string& pcieDevicePath, 230a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 231a5409991SLakshmi Yadlapati std::function<void(const std::string& pcieDeviceSlot)>&& callback) 232a5409991SLakshmi Yadlapati { 233a5409991SLakshmi Yadlapati std::string associationPath = pcieDevicePath + "/contained_by"; 234a5409991SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 235a5409991SLakshmi Yadlapati associationPath, sdbusplus::message::object_path(inventoryPath), 0, 236a5409991SLakshmi Yadlapati pcieSlotInterface, 2378cb2c024SEd Tanous [callback = std::move(callback), asyncResp, pcieDevicePath]( 238a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 239a5409991SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& endpoints) { 240a5409991SLakshmi Yadlapati if (ec) 241a5409991SLakshmi Yadlapati { 242a5409991SLakshmi Yadlapati if (ec.value() == EBADR) 243a5409991SLakshmi Yadlapati { 244a5409991SLakshmi Yadlapati // Missing association is not an error 245a5409991SLakshmi Yadlapati return; 246a5409991SLakshmi Yadlapati } 24762598e31SEd Tanous BMCWEB_LOG_ERROR( 24862598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}", 24962598e31SEd Tanous ec.value()); 250a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 251a5409991SLakshmi Yadlapati return; 252a5409991SLakshmi Yadlapati } 253a5409991SLakshmi Yadlapati if (endpoints.size() > 1) 254a5409991SLakshmi Yadlapati { 25562598e31SEd Tanous BMCWEB_LOG_ERROR( 256a6bd55b0SGunnar Mills "PCIeDevice {} is associated with more than one PCIeSlot: {}", 257a6bd55b0SGunnar Mills pcieDevicePath, endpoints.size()); 258*67f0b9c0SMyung Bae for (const std::string& slotPath : endpoints) 259*67f0b9c0SMyung Bae { 260*67f0b9c0SMyung Bae BMCWEB_LOG_ERROR("Invalid PCIeSlotPath: {}", slotPath); 261*67f0b9c0SMyung Bae } 262a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 263a5409991SLakshmi Yadlapati return; 264a5409991SLakshmi Yadlapati } 265a5409991SLakshmi Yadlapati if (endpoints.empty()) 266a5409991SLakshmi Yadlapati { 267bd79bce8SPatrick Williams // If the device doesn't have an association, return without 268bd79bce8SPatrick Williams // PCIe Slot properties 26962598e31SEd Tanous BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot"); 270a5409991SLakshmi Yadlapati return; 271a5409991SLakshmi Yadlapati } 272a5409991SLakshmi Yadlapati callback(endpoints[0]); 273a5409991SLakshmi Yadlapati }); 274a5409991SLakshmi Yadlapati } 275a5409991SLakshmi Yadlapati 276bd79bce8SPatrick Williams inline void afterGetDbusObject( 277bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 278bd79bce8SPatrick Williams const std::string& pcieDeviceSlot, const boost::system::error_code& ec, 279a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) 280a5409991SLakshmi Yadlapati { 281a5409991SLakshmi Yadlapati if (ec || object.empty()) 282a5409991SLakshmi Yadlapati { 28362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}", 28462598e31SEd Tanous ec.value()); 285a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 286a5409991SLakshmi Yadlapati return; 287a5409991SLakshmi Yadlapati } 288deae6a78SEd Tanous dbus::utility::getAllProperties( 289deae6a78SEd Tanous object.begin()->first, pcieDeviceSlot, 290a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot", 291a5409991SLakshmi Yadlapati [asyncResp]( 292a5409991SLakshmi Yadlapati const boost::system::error_code& ec2, 293a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) { 294a5409991SLakshmi Yadlapati addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties); 295a5409991SLakshmi Yadlapati }); 296a5409991SLakshmi Yadlapati } 297a5409991SLakshmi Yadlapati 298a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath( 299a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 300a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot) 301a5409991SLakshmi Yadlapati { 302a5409991SLakshmi Yadlapati dbus::utility::getDbusObject( 303a5409991SLakshmi Yadlapati pcieDeviceSlot, pcieSlotInterface, 304a5409991SLakshmi Yadlapati [asyncResp, 305a5409991SLakshmi Yadlapati pcieDeviceSlot](const boost::system::error_code& ec, 306a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 307a5409991SLakshmi Yadlapati afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object); 308a5409991SLakshmi Yadlapati }); 309a5409991SLakshmi Yadlapati } 310a5409991SLakshmi Yadlapati 311bd79bce8SPatrick Williams inline void getPCIeDeviceHealth( 312bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 313bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 314e164f1b6SLakshmi Yadlapati { 315deae6a78SEd Tanous dbus::utility::getProperty<bool>( 316deae6a78SEd Tanous service, pcieDevicePath, 317e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 318e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 319e164f1b6SLakshmi Yadlapati if (ec) 320e164f1b6SLakshmi Yadlapati { 321e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 322e164f1b6SLakshmi Yadlapati { 32362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 32462598e31SEd Tanous ec.value()); 325e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 326e164f1b6SLakshmi Yadlapati } 327e164f1b6SLakshmi Yadlapati return; 328e164f1b6SLakshmi Yadlapati } 329e164f1b6SLakshmi Yadlapati 330e164f1b6SLakshmi Yadlapati if (!value) 331e164f1b6SLakshmi Yadlapati { 332539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 333539d8c6bSEd Tanous resource::Health::Critical; 334e164f1b6SLakshmi Yadlapati } 335e164f1b6SLakshmi Yadlapati }); 336e164f1b6SLakshmi Yadlapati } 337e164f1b6SLakshmi Yadlapati 338bd79bce8SPatrick Williams inline void getPCIeDeviceState( 339bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 340bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 341c6bb3285SLakshmi Yadlapati { 342deae6a78SEd Tanous dbus::utility::getProperty<bool>( 343deae6a78SEd Tanous service, pcieDevicePath, "xyz.openbmc_project.Inventory.Item", 344deae6a78SEd Tanous "Present", 345a5409991SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, bool value) { 346c6bb3285SLakshmi Yadlapati if (ec) 347c6bb3285SLakshmi Yadlapati { 348c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 349c6bb3285SLakshmi Yadlapati { 35062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State"); 351ac106bf6SEd Tanous messages::internalError(asyncResp->res); 352c6bb3285SLakshmi Yadlapati } 353c6bb3285SLakshmi Yadlapati return; 354c6bb3285SLakshmi Yadlapati } 355c6bb3285SLakshmi Yadlapati 356c6bb3285SLakshmi Yadlapati if (!value) 357c6bb3285SLakshmi Yadlapati { 358539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 359539d8c6bSEd Tanous resource::State::Absent; 360c6bb3285SLakshmi Yadlapati } 361c6bb3285SLakshmi Yadlapati }); 362c6bb3285SLakshmi Yadlapati } 363c6bb3285SLakshmi Yadlapati 364bd79bce8SPatrick Williams inline void getPCIeDeviceAsset( 365bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 366bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 367913e7732SSunnySrivastava1984 { 368deae6a78SEd Tanous dbus::utility::getAllProperties( 369deae6a78SEd Tanous service, pcieDevicePath, 370913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 371ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 372ac106bf6SEd Tanous const boost::system::error_code& ec, 373913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 374913e7732SSunnySrivastava1984 if (ec) 375913e7732SSunnySrivastava1984 { 376913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 377913e7732SSunnySrivastava1984 { 37862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}", 37962598e31SEd Tanous ec.value()); 380ac106bf6SEd Tanous messages::internalError(asyncResp->res); 381913e7732SSunnySrivastava1984 } 382913e7732SSunnySrivastava1984 return; 383913e7732SSunnySrivastava1984 } 384913e7732SSunnySrivastava1984 385913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 386913e7732SSunnySrivastava1984 const std::string* model = nullptr; 387913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 388913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 389913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 390913e7732SSunnySrivastava1984 391913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 392913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 393913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 394bd79bce8SPatrick Williams "SerialNumber", serialNumber, "SparePartNumber", 395bd79bce8SPatrick Williams sparePartNumber); 396913e7732SSunnySrivastava1984 397913e7732SSunnySrivastava1984 if (!success) 398913e7732SSunnySrivastava1984 { 399ac106bf6SEd Tanous messages::internalError(asyncResp->res); 400913e7732SSunnySrivastava1984 return; 401913e7732SSunnySrivastava1984 } 402913e7732SSunnySrivastava1984 403913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 404913e7732SSunnySrivastava1984 { 405ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 406913e7732SSunnySrivastava1984 } 407913e7732SSunnySrivastava1984 if (model != nullptr) 408913e7732SSunnySrivastava1984 { 409ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 410913e7732SSunnySrivastava1984 } 411913e7732SSunnySrivastava1984 412913e7732SSunnySrivastava1984 if (partNumber != nullptr) 413913e7732SSunnySrivastava1984 { 414ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 415913e7732SSunnySrivastava1984 } 416913e7732SSunnySrivastava1984 417913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 418913e7732SSunnySrivastava1984 { 419ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 420913e7732SSunnySrivastava1984 } 421913e7732SSunnySrivastava1984 422913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 423913e7732SSunnySrivastava1984 { 424ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 425913e7732SSunnySrivastava1984 } 426913e7732SSunnySrivastava1984 }); 427913e7732SSunnySrivastava1984 } 428913e7732SSunnySrivastava1984 429543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 430a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 431a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, 432543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 433f5c9f8bdSJason M. Bills { 434d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 435814bf20aSKonstantin Aladyshev const std::string* generationSupported = nullptr; 4369bb0a7feSKonstantin Aladyshev const size_t* lanesInUse = nullptr; 437814bf20aSKonstantin Aladyshev const size_t* maxLanes = nullptr; 438d1bde9e5SKrzysztof Grobelny 439d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 440609ba4c9SEd Tanous dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse", 441609ba4c9SEd Tanous generationInUse, "GenerationSupported", generationSupported, 442609ba4c9SEd Tanous "LanesInUse", lanesInUse, "MaxLanes", maxLanes); 443d1bde9e5SKrzysztof Grobelny 444d1bde9e5SKrzysztof Grobelny if (!success) 445d1bde9e5SKrzysztof Grobelny { 446a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 447d1bde9e5SKrzysztof Grobelny return; 448d1bde9e5SKrzysztof Grobelny } 449d1bde9e5SKrzysztof Grobelny 450d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 451d1bde9e5SKrzysztof Grobelny { 4520ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 453c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 454543f9a75SLakshmi Yadlapati 455d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 456d1bde9e5SKrzysztof Grobelny { 45762598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 45862598e31SEd Tanous *generationInUse); 459cf3b484eSLakshmi Yadlapati } 460cf3b484eSLakshmi Yadlapati else 461cf3b484eSLakshmi Yadlapati { 462cf3b484eSLakshmi Yadlapati if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid) 463cf3b484eSLakshmi Yadlapati { 46462598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 46562598e31SEd Tanous *generationInUse); 466a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 467d1bde9e5SKrzysztof Grobelny return; 468d1bde9e5SKrzysztof Grobelny } 469a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 470d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 471d1bde9e5SKrzysztof Grobelny } 472a9f68bb5STony Lee } 473d1bde9e5SKrzysztof Grobelny 474814bf20aSKonstantin Aladyshev if (generationSupported != nullptr) 475814bf20aSKonstantin Aladyshev { 476814bf20aSKonstantin Aladyshev std::optional<pcie_device::PCIeTypes> redfishGenerationSupported = 477814bf20aSKonstantin Aladyshev pcie_util::redfishPcieGenerationFromDbus(*generationSupported); 478814bf20aSKonstantin Aladyshev 479814bf20aSKonstantin Aladyshev if (!redfishGenerationSupported) 480814bf20aSKonstantin Aladyshev { 48162598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 48262598e31SEd Tanous *generationSupported); 483814bf20aSKonstantin Aladyshev } 484814bf20aSKonstantin Aladyshev else 485814bf20aSKonstantin Aladyshev { 486814bf20aSKonstantin Aladyshev if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid) 487814bf20aSKonstantin Aladyshev { 48862598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 48962598e31SEd Tanous *generationSupported); 490814bf20aSKonstantin Aladyshev messages::internalError(asyncResp->res); 491814bf20aSKonstantin Aladyshev return; 492814bf20aSKonstantin Aladyshev } 493814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] = 494814bf20aSKonstantin Aladyshev *redfishGenerationSupported; 495814bf20aSKonstantin Aladyshev } 496814bf20aSKonstantin Aladyshev } 497814bf20aSKonstantin Aladyshev 4988c1d0549SMyung Bae if (lanesInUse != nullptr) 499543f9a75SLakshmi Yadlapati { 5008c1d0549SMyung Bae if (*lanesInUse == std::numeric_limits<size_t>::max()) 5018c1d0549SMyung Bae { 5028c1d0549SMyung Bae // The default value of LanesInUse is "maxint", and the field will 5038c1d0549SMyung Bae // be null if it is a default value. 5048c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr; 5058c1d0549SMyung Bae } 5068c1d0549SMyung Bae else 5078c1d0549SMyung Bae { 5088c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = 5098c1d0549SMyung Bae *lanesInUse; 5108c1d0549SMyung Bae } 511543f9a75SLakshmi Yadlapati } 512814bf20aSKonstantin Aladyshev // The default value of MaxLanes is 0, and the field will be 513814bf20aSKonstantin Aladyshev // left as off if it is a default value. 514814bf20aSKonstantin Aladyshev if (maxLanes != nullptr && *maxLanes != 0) 515814bf20aSKonstantin Aladyshev { 516814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes; 517814bf20aSKonstantin Aladyshev } 518543f9a75SLakshmi Yadlapati 519a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 520a5409991SLakshmi Yadlapati boost::urls::format( 521253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 522253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 523d1bde9e5SKrzysztof Grobelny } 524d1bde9e5SKrzysztof Grobelny 525543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 526ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 527543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 528543f9a75SLakshmi Yadlapati const std::function<void( 529543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 530d1bde9e5SKrzysztof Grobelny { 531deae6a78SEd Tanous dbus::utility::getAllProperties( 532deae6a78SEd Tanous service, pcieDevicePath, 533543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 534ac106bf6SEd Tanous [asyncResp, 535543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 536543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 537543f9a75SLakshmi Yadlapati if (ec) 538543f9a75SLakshmi Yadlapati { 539543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 540543f9a75SLakshmi Yadlapati { 54162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties"); 542ac106bf6SEd Tanous messages::internalError(asyncResp->res); 543543f9a75SLakshmi Yadlapati } 544543f9a75SLakshmi Yadlapati return; 545543f9a75SLakshmi Yadlapati } 546543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 547543f9a75SLakshmi Yadlapati }); 548d1bde9e5SKrzysztof Grobelny } 549d1bde9e5SKrzysztof Grobelny 550543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 551ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 552543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 553543f9a75SLakshmi Yadlapati { 554ac106bf6SEd Tanous asyncResp->res.addHeader( 555543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 556543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 557ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 558253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 559253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 560253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 561ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 562ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 563539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 564539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 565543f9a75SLakshmi Yadlapati } 5661476687dSEd Tanous 567a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath( 568a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 569a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, const std::string& pcieDevicePath, 570a5409991SLakshmi Yadlapati const std::string& service) 571a5409991SLakshmi Yadlapati { 572a5409991SLakshmi Yadlapati addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 573a5409991SLakshmi Yadlapati getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 574a5409991SLakshmi Yadlapati getPCIeDeviceState(asyncResp, pcieDevicePath, service); 575a5409991SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 576a5409991SLakshmi Yadlapati getPCIeDeviceProperties( 577a5409991SLakshmi Yadlapati asyncResp, pcieDevicePath, service, 578a5409991SLakshmi Yadlapati std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId)); 579a5409991SLakshmi Yadlapati getPCIeDeviceSlotPath( 580a5409991SLakshmi Yadlapati pcieDevicePath, asyncResp, 581a5409991SLakshmi Yadlapati std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp)); 582a5409991SLakshmi Yadlapati } 583a5409991SLakshmi Yadlapati 584bd79bce8SPatrick Williams inline void handlePCIeDeviceGet( 585bd79bce8SPatrick Williams App& app, const crow::Request& req, 586ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 587bd79bce8SPatrick Williams const std::string& systemName, const std::string& pcieDeviceId) 588543f9a75SLakshmi Yadlapati { 589ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 590543f9a75SLakshmi Yadlapati { 591543f9a75SLakshmi Yadlapati return; 592543f9a75SLakshmi Yadlapati } 59325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5947f3e84a1SEd Tanous { 5957f3e84a1SEd Tanous // Option currently returns no systems. TBD 5967f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5977f3e84a1SEd Tanous systemName); 5987f3e84a1SEd Tanous return; 5997f3e84a1SEd Tanous } 600253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 601543f9a75SLakshmi Yadlapati { 602ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 603ac106bf6SEd Tanous systemName); 604543f9a75SLakshmi Yadlapati return; 605543f9a75SLakshmi Yadlapati } 606543f9a75SLakshmi Yadlapati 607543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 608ac106bf6SEd Tanous pcieDeviceId, asyncResp, 609a5409991SLakshmi Yadlapati std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId)); 610543f9a75SLakshmi Yadlapati } 611543f9a75SLakshmi Yadlapati 612543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 613543f9a75SLakshmi Yadlapati { 614543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 615543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 616543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 617543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 618dede6a98SJason M. Bills } 619dede6a98SJason M. Bills 62035ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 62135ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 62235ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 62335ad613dSLakshmi Yadlapati { 62435ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 62535ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 62635ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 62735ad613dSLakshmi Yadlapati 62835ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 62935ad613dSLakshmi Yadlapati { 63035ad613dSLakshmi Yadlapati // Check if this function exists by 63135ad613dSLakshmi Yadlapati // looking for a device ID 632bd79bce8SPatrick Williams std::string devIDProperty = 633bd79bce8SPatrick Williams "Function" + std::to_string(functionNum) + "DeviceId"; 63435ad613dSLakshmi Yadlapati const std::string* property = nullptr; 63535ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 63635ad613dSLakshmi Yadlapati { 63735ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 63835ad613dSLakshmi Yadlapati { 63935ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 64035ad613dSLakshmi Yadlapati break; 64135ad613dSLakshmi Yadlapati } 64235ad613dSLakshmi Yadlapati } 64335ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 64435ad613dSLakshmi Yadlapati { 64535ad613dSLakshmi Yadlapati continue; 64635ad613dSLakshmi Yadlapati } 64735ad613dSLakshmi Yadlapati 64835ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 649ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 650253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 651253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 652253f11b8SEd Tanous std::to_string(functionNum)); 653b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 65435ad613dSLakshmi Yadlapati } 65535ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 65635ad613dSLakshmi Yadlapati } 65735ad613dSLakshmi Yadlapati 65835ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 65935ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 660ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6617f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 66235ad613dSLakshmi Yadlapati { 663ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 66435ad613dSLakshmi Yadlapati { 66535ad613dSLakshmi Yadlapati return; 66635ad613dSLakshmi Yadlapati } 66725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6687f3e84a1SEd Tanous { 6697f3e84a1SEd Tanous // Option currently returns no systems. TBD 6707f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6717f3e84a1SEd Tanous systemName); 6727f3e84a1SEd Tanous return; 6737f3e84a1SEd Tanous } 67435ad613dSLakshmi Yadlapati 67535ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 676ac106bf6SEd Tanous pcieDeviceId, asyncResp, 677ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 67835ad613dSLakshmi Yadlapati const std::string& service) { 679ac106bf6SEd Tanous asyncResp->res.addHeader( 68035ad613dSLakshmi Yadlapati boost::beast::http::field::link, 68135ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 682ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 68335ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 684ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 685253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 686253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 687ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 688ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 68935ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 69035ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 691ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 692ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 69335ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 694ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 695ac106bf6SEd Tanous pcieDevProperties); 69635ad613dSLakshmi Yadlapati }); 69735ad613dSLakshmi Yadlapati }); 69835ad613dSLakshmi Yadlapati } 69935ad613dSLakshmi Yadlapati 7007e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 7017e860f15SJohn Edward Broadbent { 702dede6a98SJason M. Bills /** 703dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 704dede6a98SJason M. Bills */ 7057e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 7067f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 707ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 708002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 70935ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 7107e860f15SJohn Edward Broadbent } 7117e860f15SJohn Edward Broadbent 712727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 713d5e74b80SMyung Bae uint64_t pcieFunctionId, 714727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 7157e860f15SJohn Edward Broadbent { 716d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 717b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 718b9d36b47SEd Tanous 719b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 720b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 721b9d36b47SEd Tanous { 722b9d36b47SEd Tanous if (property.first == devIDProperty) 723b9d36b47SEd Tanous { 724002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 725727a046cSLakshmi Yadlapati break; 726b9d36b47SEd Tanous } 727b9d36b47SEd Tanous } 728727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 729727a046cSLakshmi Yadlapati } 730727a046cSLakshmi Yadlapati 731727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 732e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 733727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 734f5c9f8bdSJason M. Bills { 735e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 736b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 737f5c9f8bdSJason M. Bills { 738b9d36b47SEd Tanous const std::string* strProperty = 739b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 740dc8cfa66SEd Tanous if (strProperty == nullptr) 741dc8cfa66SEd Tanous { 742dc8cfa66SEd Tanous continue; 743dc8cfa66SEd Tanous } 744b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 745f5c9f8bdSJason M. Bills { 746727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 747f5c9f8bdSJason M. Bills } 748b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 749f5c9f8bdSJason M. Bills { 750727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 751f5c9f8bdSJason M. Bills } 752727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 753727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 754727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 755b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 756f5c9f8bdSJason M. Bills { 757727a046cSLakshmi Yadlapati if (!strProperty->empty()) 758727a046cSLakshmi Yadlapati { 759727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 760727a046cSLakshmi Yadlapati } 761f5c9f8bdSJason M. Bills } 762b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 763f5c9f8bdSJason M. Bills { 764727a046cSLakshmi Yadlapati if (!strProperty->empty()) 765727a046cSLakshmi Yadlapati { 766727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 767727a046cSLakshmi Yadlapati } 768f5c9f8bdSJason M. Bills } 769b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 770f5c9f8bdSJason M. Bills { 771727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 772f5c9f8bdSJason M. Bills } 773b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 774f5c9f8bdSJason M. Bills { 775727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 776f5c9f8bdSJason M. Bills } 777b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 778b9d36b47SEd Tanous { 779727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 780b9d36b47SEd Tanous } 781002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 782f5c9f8bdSJason M. Bills { 783727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 784b9d36b47SEd Tanous } 785f5c9f8bdSJason M. Bills } 786727a046cSLakshmi Yadlapati } 787727a046cSLakshmi Yadlapati 788727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 789727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 790e14742caSEd Tanous uint64_t pcieFunctionId) 791727a046cSLakshmi Yadlapati { 792727a046cSLakshmi Yadlapati resp.addHeader( 793727a046cSLakshmi Yadlapati boost::beast::http::field::link, 794727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 795727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 796ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 797253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 798253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 799253f11b8SEd Tanous std::to_string(pcieFunctionId)); 800727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 801e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 802e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 803253f11b8SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 804253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 805253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 806727a046cSLakshmi Yadlapati } 807727a046cSLakshmi Yadlapati 808bd79bce8SPatrick Williams inline void handlePCIeFunctionGet( 809bd79bce8SPatrick Williams App& app, const crow::Request& req, 810ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 811bd79bce8SPatrick Williams const std::string& systemName, const std::string& pcieDeviceId, 812e14742caSEd Tanous const std::string& pcieFunctionIdStr) 813727a046cSLakshmi Yadlapati { 814ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 815727a046cSLakshmi Yadlapati { 816727a046cSLakshmi Yadlapati return; 817727a046cSLakshmi Yadlapati } 81825b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 8197f3e84a1SEd Tanous { 8207f3e84a1SEd Tanous // Option currently returns no systems. TBD 8217f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8227f3e84a1SEd Tanous systemName); 8237f3e84a1SEd Tanous return; 8247f3e84a1SEd Tanous } 825253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 8267f3e84a1SEd Tanous { 8277f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8287f3e84a1SEd Tanous systemName); 8297f3e84a1SEd Tanous return; 8307f3e84a1SEd Tanous } 831dc8cfa66SEd Tanous std::string_view pcieFunctionIdView = pcieFunctionIdStr; 8327f3e84a1SEd Tanous 833e14742caSEd Tanous uint64_t pcieFunctionId = 0; 834e14742caSEd Tanous std::from_chars_result result = std::from_chars( 835dc8cfa66SEd Tanous pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId); 836dc8cfa66SEd Tanous if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end()) 837e14742caSEd Tanous { 838ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 839e14742caSEd Tanous pcieFunctionIdStr); 840e14742caSEd Tanous return; 841e14742caSEd Tanous } 842727a046cSLakshmi Yadlapati 843bd79bce8SPatrick Williams getValidPCIeDevicePath( 844bd79bce8SPatrick Williams pcieDeviceId, asyncResp, 845bd79bce8SPatrick Williams [asyncResp, pcieDeviceId, pcieFunctionId]( 846bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) { 847727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 848ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 849ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 850727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 851bd79bce8SPatrick Williams addPCIeFunctionCommonProperties( 852bd79bce8SPatrick Williams asyncResp->res, pcieDeviceId, pcieFunctionId); 853ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 854727a046cSLakshmi Yadlapati pcieDevProperties); 8557e860f15SJohn Edward Broadbent }); 856727a046cSLakshmi Yadlapati }); 857727a046cSLakshmi Yadlapati } 858727a046cSLakshmi Yadlapati 859727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 860727a046cSLakshmi Yadlapati { 861727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8627f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 863727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 864727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 865727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 866f5c9f8bdSJason M. Bills } 867f5c9f8bdSJason M. Bills 868f5c9f8bdSJason M. Bills } // namespace redfish 869