1f5c9f8bdSJason M. Bills /* 2f5c9f8bdSJason M. Bills // Copyright (c) 2018 Intel Corporation 3f5c9f8bdSJason M. Bills // 4f5c9f8bdSJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License"); 5f5c9f8bdSJason M. Bills // you may not use this file except in compliance with the License. 6f5c9f8bdSJason M. Bills // You may obtain a copy of the License at 7f5c9f8bdSJason M. Bills // 8f5c9f8bdSJason M. Bills // http://www.apache.org/licenses/LICENSE-2.0 9f5c9f8bdSJason M. Bills // 10f5c9f8bdSJason M. Bills // Unless required by applicable law or agreed to in writing, software 11f5c9f8bdSJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS, 12f5c9f8bdSJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f5c9f8bdSJason M. Bills // See the License for the specific language governing permissions and 14f5c9f8bdSJason M. Bills // limitations under the License. 15f5c9f8bdSJason M. Bills */ 16f5c9f8bdSJason M. Bills 17f5c9f8bdSJason M. Bills #pragma once 18f5c9f8bdSJason M. Bills 193ccb3adbSEd Tanous #include "app.hpp" 207a1dbc48SGeorge Liu #include "dbus_utility.hpp" 21*539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 223ccb3adbSEd Tanous #include "query.hpp" 233ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 24b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp" 253ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 26c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp" 270ec8b83dSEd Tanous 28f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp> 29ef4c65b7SEd Tanous #include <boost/url/format.hpp> 30d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 31d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 32f5c9f8bdSJason M. Bills 338c1d0549SMyung Bae #include <limits> 348c1d0549SMyung Bae 35f5c9f8bdSJason M. Bills namespace redfish 36f5c9f8bdSJason M. Bills { 37f5c9f8bdSJason M. Bills 3889492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory"; 3994c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = { 4094c3a10bSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 41a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = { 42a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot"}; 43f5c9f8bdSJason M. Bills 44543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath( 45543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 46ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 47543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 48543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 49543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 50543f9a75SLakshmi Yadlapati 51543f9a75SLakshmi Yadlapati { 52543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 53543f9a75SLakshmi Yadlapati { 54543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 55543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 56543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 57543f9a75SLakshmi Yadlapati { 58543f9a75SLakshmi Yadlapati continue; 59543f9a75SLakshmi Yadlapati } 60543f9a75SLakshmi Yadlapati 61543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 62543f9a75SLakshmi Yadlapati pcieDevicePath, {}, 63ac106bf6SEd Tanous [pcieDevicePath, asyncResp, 64543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 65543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 66543f9a75SLakshmi Yadlapati if (ec || object.empty()) 67543f9a75SLakshmi Yadlapati { 6862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 69ac106bf6SEd Tanous messages::internalError(asyncResp->res); 70543f9a75SLakshmi Yadlapati return; 71543f9a75SLakshmi Yadlapati } 72543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 73543f9a75SLakshmi Yadlapati }); 74543f9a75SLakshmi Yadlapati return; 75543f9a75SLakshmi Yadlapati } 76543f9a75SLakshmi Yadlapati 7762598e31SEd Tanous BMCWEB_LOG_WARNING("PCIe Device not found"); 78ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId); 79543f9a75SLakshmi Yadlapati } 80543f9a75SLakshmi Yadlapati 81543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath( 82543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 83ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 84543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 85543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 86543f9a75SLakshmi Yadlapati { 87543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 8894c3a10bSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 89ac106bf6SEd Tanous [pcieDeviceId, asyncResp, 90543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 91543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 92543f9a75SLakshmi Yadlapati pcieDevicePaths) { 93543f9a75SLakshmi Yadlapati if (ec) 94543f9a75SLakshmi Yadlapati { 9562598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec); 96ac106bf6SEd Tanous messages::internalError(asyncResp->res); 97543f9a75SLakshmi Yadlapati return; 98543f9a75SLakshmi Yadlapati } 99ac106bf6SEd Tanous handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths, 100ac106bf6SEd Tanous callback); 101543f9a75SLakshmi Yadlapati return; 102543f9a75SLakshmi Yadlapati }); 103543f9a75SLakshmi Yadlapati } 104543f9a75SLakshmi Yadlapati 105b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet( 106b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 107ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 108b38fa2abSLakshmi Yadlapati const std::string& systemName) 109b38fa2abSLakshmi Yadlapati { 110ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 111b38fa2abSLakshmi Yadlapati { 112b38fa2abSLakshmi Yadlapati return; 113b38fa2abSLakshmi Yadlapati } 11425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 1157f3e84a1SEd Tanous { 1167f3e84a1SEd Tanous // Option currently returns no systems. TBD 1177f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1187f3e84a1SEd Tanous systemName); 1197f3e84a1SEd Tanous return; 1207f3e84a1SEd Tanous } 121253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 122b38fa2abSLakshmi Yadlapati { 123ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 124ac106bf6SEd Tanous systemName); 125b38fa2abSLakshmi Yadlapati return; 126b38fa2abSLakshmi Yadlapati } 127543f9a75SLakshmi Yadlapati 128ac106bf6SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::link, 129b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 130b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 131ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 132b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 133253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 134253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME); 135ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device Collection"; 136ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 137b38fa2abSLakshmi Yadlapati 13870c4d545SLakshmi Yadlapati pcie_util::getPCIeDeviceList(asyncResp, 13970c4d545SLakshmi Yadlapati nlohmann::json::json_pointer("/Members")); 140b38fa2abSLakshmi Yadlapati } 141b38fa2abSLakshmi Yadlapati 1427e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 143adbe192aSJason M. Bills { 144adbe192aSJason M. Bills /** 145adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 146adbe192aSJason M. Bills */ 14722d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 148ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1497e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 150b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 151f5c9f8bdSJason M. Bills } 152f5c9f8bdSJason M. Bills 153a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties( 154a5409991SLakshmi Yadlapati crow::Response& res, const boost::system::error_code& ec, 155a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) 156a5409991SLakshmi Yadlapati { 157a5409991SLakshmi Yadlapati if (ec) 158a5409991SLakshmi Yadlapati { 15962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}", 16062598e31SEd Tanous ec.value()); 161a5409991SLakshmi Yadlapati messages::internalError(res); 162a5409991SLakshmi Yadlapati return; 163a5409991SLakshmi Yadlapati } 164a5409991SLakshmi Yadlapati std::string generation; 165a5409991SLakshmi Yadlapati size_t lanes = 0; 166a5409991SLakshmi Yadlapati std::string slotType; 167a5409991SLakshmi Yadlapati 168a5409991SLakshmi Yadlapati bool success = sdbusplus::unpackPropertiesNoThrow( 169a5409991SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation", 170a5409991SLakshmi Yadlapati generation, "Lanes", lanes, "SlotType", slotType); 171a5409991SLakshmi Yadlapati 172a5409991SLakshmi Yadlapati if (!success) 173a5409991SLakshmi Yadlapati { 174a5409991SLakshmi Yadlapati messages::internalError(res); 175a5409991SLakshmi Yadlapati return; 176a5409991SLakshmi Yadlapati } 177a5409991SLakshmi Yadlapati 178a5409991SLakshmi Yadlapati std::optional<pcie_device::PCIeTypes> pcieType = 179a5409991SLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(generation); 180a5409991SLakshmi Yadlapati if (!pcieType) 181a5409991SLakshmi Yadlapati { 18262598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation); 183a5409991SLakshmi Yadlapati } 184a5409991SLakshmi Yadlapati else 185a5409991SLakshmi Yadlapati { 186a5409991SLakshmi Yadlapati if (*pcieType == pcie_device::PCIeTypes::Invalid) 187a5409991SLakshmi Yadlapati { 18862598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation); 189a5409991SLakshmi Yadlapati messages::internalError(res); 190a5409991SLakshmi Yadlapati return; 191a5409991SLakshmi Yadlapati } 192a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["PCIeType"] = *pcieType; 193a5409991SLakshmi Yadlapati } 194a5409991SLakshmi Yadlapati 19582f80326SKonstantin Aladyshev if (lanes != 0) 19682f80326SKonstantin Aladyshev { 197a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["Lanes"] = lanes; 19882f80326SKonstantin Aladyshev } 199a5409991SLakshmi Yadlapati 200a5409991SLakshmi Yadlapati std::optional<pcie_slots::SlotTypes> redfishSlotType = 201a5409991SLakshmi Yadlapati pcie_util::dbusSlotTypeToRf(slotType); 202a5409991SLakshmi Yadlapati if (!redfishSlotType) 203a5409991SLakshmi Yadlapati { 20462598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType); 205a5409991SLakshmi Yadlapati } 206a5409991SLakshmi Yadlapati else 207a5409991SLakshmi Yadlapati { 208a5409991SLakshmi Yadlapati if (*redfishSlotType == pcie_slots::SlotTypes::Invalid) 209a5409991SLakshmi Yadlapati { 21062598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType); 211a5409991SLakshmi Yadlapati messages::internalError(res); 212a5409991SLakshmi Yadlapati return; 213a5409991SLakshmi Yadlapati } 214a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["SlotType"] = *redfishSlotType; 215a5409991SLakshmi Yadlapati } 216a5409991SLakshmi Yadlapati } 217a5409991SLakshmi Yadlapati 218a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath( 219a5409991SLakshmi Yadlapati const std::string& pcieDevicePath, 220a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 221a5409991SLakshmi Yadlapati std::function<void(const std::string& pcieDeviceSlot)>&& callback) 222a5409991SLakshmi Yadlapati { 223a5409991SLakshmi Yadlapati std::string associationPath = pcieDevicePath + "/contained_by"; 224a5409991SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 225a5409991SLakshmi Yadlapati associationPath, sdbusplus::message::object_path(inventoryPath), 0, 226a5409991SLakshmi Yadlapati pcieSlotInterface, 2278cb2c024SEd Tanous [callback = std::move(callback), asyncResp, pcieDevicePath]( 228a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 229a5409991SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& endpoints) { 230a5409991SLakshmi Yadlapati if (ec) 231a5409991SLakshmi Yadlapati { 232a5409991SLakshmi Yadlapati if (ec.value() == EBADR) 233a5409991SLakshmi Yadlapati { 234a5409991SLakshmi Yadlapati // Missing association is not an error 235a5409991SLakshmi Yadlapati return; 236a5409991SLakshmi Yadlapati } 23762598e31SEd Tanous BMCWEB_LOG_ERROR( 23862598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}", 23962598e31SEd Tanous ec.value()); 240a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 241a5409991SLakshmi Yadlapati return; 242a5409991SLakshmi Yadlapati } 243a5409991SLakshmi Yadlapati if (endpoints.size() > 1) 244a5409991SLakshmi Yadlapati { 24562598e31SEd Tanous BMCWEB_LOG_ERROR( 24662598e31SEd Tanous "PCIeDevice is associated with more than one PCIeSlot: {}", 24762598e31SEd Tanous endpoints.size()); 248a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 249a5409991SLakshmi Yadlapati return; 250a5409991SLakshmi Yadlapati } 251a5409991SLakshmi Yadlapati if (endpoints.empty()) 252a5409991SLakshmi Yadlapati { 253a5409991SLakshmi Yadlapati // If the device doesn't have an association, return without PCIe 254a5409991SLakshmi Yadlapati // Slot properties 25562598e31SEd Tanous BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot"); 256a5409991SLakshmi Yadlapati return; 257a5409991SLakshmi Yadlapati } 258a5409991SLakshmi Yadlapati callback(endpoints[0]); 259a5409991SLakshmi Yadlapati }); 260a5409991SLakshmi Yadlapati } 261a5409991SLakshmi Yadlapati 262a5409991SLakshmi Yadlapati inline void 263a5409991SLakshmi Yadlapati afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 264a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot, 265a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 266a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) 267a5409991SLakshmi Yadlapati { 268a5409991SLakshmi Yadlapati if (ec || object.empty()) 269a5409991SLakshmi Yadlapati { 27062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}", 27162598e31SEd Tanous ec.value()); 272a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 273a5409991SLakshmi Yadlapati return; 274a5409991SLakshmi Yadlapati } 275a5409991SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 276a5409991SLakshmi Yadlapati *crow::connections::systemBus, object.begin()->first, pcieDeviceSlot, 277a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot", 278a5409991SLakshmi Yadlapati [asyncResp]( 279a5409991SLakshmi Yadlapati const boost::system::error_code& ec2, 280a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) { 281a5409991SLakshmi Yadlapati addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties); 282a5409991SLakshmi Yadlapati }); 283a5409991SLakshmi Yadlapati } 284a5409991SLakshmi Yadlapati 285a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath( 286a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 287a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot) 288a5409991SLakshmi Yadlapati { 289a5409991SLakshmi Yadlapati dbus::utility::getDbusObject( 290a5409991SLakshmi Yadlapati pcieDeviceSlot, pcieSlotInterface, 291a5409991SLakshmi Yadlapati [asyncResp, 292a5409991SLakshmi Yadlapati pcieDeviceSlot](const boost::system::error_code& ec, 293a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 294a5409991SLakshmi Yadlapati afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object); 295a5409991SLakshmi Yadlapati }); 296a5409991SLakshmi Yadlapati } 297a5409991SLakshmi Yadlapati 298ac106bf6SEd Tanous inline void 299e164f1b6SLakshmi Yadlapati getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 300e164f1b6SLakshmi Yadlapati const std::string& pcieDevicePath, 301e164f1b6SLakshmi Yadlapati const std::string& service) 302e164f1b6SLakshmi Yadlapati { 303e164f1b6SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 304e164f1b6SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 305e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 306e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 307e164f1b6SLakshmi Yadlapati if (ec) 308e164f1b6SLakshmi Yadlapati { 309e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 310e164f1b6SLakshmi Yadlapati { 31162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 31262598e31SEd Tanous ec.value()); 313e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 314e164f1b6SLakshmi Yadlapati } 315e164f1b6SLakshmi Yadlapati return; 316e164f1b6SLakshmi Yadlapati } 317e164f1b6SLakshmi Yadlapati 318e164f1b6SLakshmi Yadlapati if (!value) 319e164f1b6SLakshmi Yadlapati { 320*539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 321*539d8c6bSEd Tanous resource::Health::Critical; 322e164f1b6SLakshmi Yadlapati } 323e164f1b6SLakshmi Yadlapati }); 324e164f1b6SLakshmi Yadlapati } 325e164f1b6SLakshmi Yadlapati 326e164f1b6SLakshmi Yadlapati inline void 327ac106bf6SEd Tanous getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 328c6bb3285SLakshmi Yadlapati const std::string& pcieDevicePath, 329c6bb3285SLakshmi Yadlapati const std::string& service) 330c6bb3285SLakshmi Yadlapati { 331c6bb3285SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 332c6bb3285SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 333c6bb3285SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item", "Present", 334a5409991SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, bool value) { 335c6bb3285SLakshmi Yadlapati if (ec) 336c6bb3285SLakshmi Yadlapati { 337c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 338c6bb3285SLakshmi Yadlapati { 33962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State"); 340ac106bf6SEd Tanous messages::internalError(asyncResp->res); 341c6bb3285SLakshmi Yadlapati } 342c6bb3285SLakshmi Yadlapati return; 343c6bb3285SLakshmi Yadlapati } 344c6bb3285SLakshmi Yadlapati 345c6bb3285SLakshmi Yadlapati if (!value) 346c6bb3285SLakshmi Yadlapati { 347*539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 348*539d8c6bSEd Tanous resource::State::Absent; 349c6bb3285SLakshmi Yadlapati } 350c6bb3285SLakshmi Yadlapati }); 351c6bb3285SLakshmi Yadlapati } 352c6bb3285SLakshmi Yadlapati 353ac106bf6SEd Tanous inline void 354ac106bf6SEd Tanous getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 355913e7732SSunnySrivastava1984 const std::string& pcieDevicePath, 356913e7732SSunnySrivastava1984 const std::string& service) 357913e7732SSunnySrivastava1984 { 358913e7732SSunnySrivastava1984 sdbusplus::asio::getAllProperties( 359913e7732SSunnySrivastava1984 *crow::connections::systemBus, service, pcieDevicePath, 360913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 361ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 362ac106bf6SEd Tanous const boost::system::error_code& ec, 363913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 364913e7732SSunnySrivastava1984 if (ec) 365913e7732SSunnySrivastava1984 { 366913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 367913e7732SSunnySrivastava1984 { 36862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}", 36962598e31SEd Tanous ec.value()); 370ac106bf6SEd Tanous messages::internalError(asyncResp->res); 371913e7732SSunnySrivastava1984 } 372913e7732SSunnySrivastava1984 return; 373913e7732SSunnySrivastava1984 } 374913e7732SSunnySrivastava1984 375913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 376913e7732SSunnySrivastava1984 const std::string* model = nullptr; 377913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 378913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 379913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 380913e7732SSunnySrivastava1984 381913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 382913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 383913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 384913e7732SSunnySrivastava1984 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber); 385913e7732SSunnySrivastava1984 386913e7732SSunnySrivastava1984 if (!success) 387913e7732SSunnySrivastava1984 { 388ac106bf6SEd Tanous messages::internalError(asyncResp->res); 389913e7732SSunnySrivastava1984 return; 390913e7732SSunnySrivastava1984 } 391913e7732SSunnySrivastava1984 392913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 393913e7732SSunnySrivastava1984 { 394ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 395913e7732SSunnySrivastava1984 } 396913e7732SSunnySrivastava1984 if (model != nullptr) 397913e7732SSunnySrivastava1984 { 398ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 399913e7732SSunnySrivastava1984 } 400913e7732SSunnySrivastava1984 401913e7732SSunnySrivastava1984 if (partNumber != nullptr) 402913e7732SSunnySrivastava1984 { 403ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 404913e7732SSunnySrivastava1984 } 405913e7732SSunnySrivastava1984 406913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 407913e7732SSunnySrivastava1984 { 408ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 409913e7732SSunnySrivastava1984 } 410913e7732SSunnySrivastava1984 411913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 412913e7732SSunnySrivastava1984 { 413ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 414913e7732SSunnySrivastava1984 } 415913e7732SSunnySrivastava1984 }); 416913e7732SSunnySrivastava1984 } 417913e7732SSunnySrivastava1984 418543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 419a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 420a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, 421543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 422f5c9f8bdSJason M. Bills { 423d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 424814bf20aSKonstantin Aladyshev const std::string* generationSupported = nullptr; 4259bb0a7feSKonstantin Aladyshev const size_t* lanesInUse = nullptr; 426814bf20aSKonstantin Aladyshev const size_t* maxLanes = nullptr; 427d1bde9e5SKrzysztof Grobelny 428d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 429609ba4c9SEd Tanous dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse", 430609ba4c9SEd Tanous generationInUse, "GenerationSupported", generationSupported, 431609ba4c9SEd Tanous "LanesInUse", lanesInUse, "MaxLanes", maxLanes); 432d1bde9e5SKrzysztof Grobelny 433d1bde9e5SKrzysztof Grobelny if (!success) 434d1bde9e5SKrzysztof Grobelny { 435a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 436d1bde9e5SKrzysztof Grobelny return; 437d1bde9e5SKrzysztof Grobelny } 438d1bde9e5SKrzysztof Grobelny 439d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 440d1bde9e5SKrzysztof Grobelny { 4410ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 442c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 443543f9a75SLakshmi Yadlapati 444d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 445d1bde9e5SKrzysztof Grobelny { 44662598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 44762598e31SEd Tanous *generationInUse); 448cf3b484eSLakshmi Yadlapati } 449cf3b484eSLakshmi Yadlapati else 450cf3b484eSLakshmi Yadlapati { 451cf3b484eSLakshmi Yadlapati if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid) 452cf3b484eSLakshmi Yadlapati { 45362598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 45462598e31SEd Tanous *generationInUse); 455a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 456d1bde9e5SKrzysztof Grobelny return; 457d1bde9e5SKrzysztof Grobelny } 458a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 459d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 460d1bde9e5SKrzysztof Grobelny } 461a9f68bb5STony Lee } 462d1bde9e5SKrzysztof Grobelny 463814bf20aSKonstantin Aladyshev if (generationSupported != nullptr) 464814bf20aSKonstantin Aladyshev { 465814bf20aSKonstantin Aladyshev std::optional<pcie_device::PCIeTypes> redfishGenerationSupported = 466814bf20aSKonstantin Aladyshev pcie_util::redfishPcieGenerationFromDbus(*generationSupported); 467814bf20aSKonstantin Aladyshev 468814bf20aSKonstantin Aladyshev if (!redfishGenerationSupported) 469814bf20aSKonstantin Aladyshev { 47062598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 47162598e31SEd Tanous *generationSupported); 472814bf20aSKonstantin Aladyshev } 473814bf20aSKonstantin Aladyshev else 474814bf20aSKonstantin Aladyshev { 475814bf20aSKonstantin Aladyshev if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid) 476814bf20aSKonstantin Aladyshev { 47762598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 47862598e31SEd Tanous *generationSupported); 479814bf20aSKonstantin Aladyshev messages::internalError(asyncResp->res); 480814bf20aSKonstantin Aladyshev return; 481814bf20aSKonstantin Aladyshev } 482814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] = 483814bf20aSKonstantin Aladyshev *redfishGenerationSupported; 484814bf20aSKonstantin Aladyshev } 485814bf20aSKonstantin Aladyshev } 486814bf20aSKonstantin Aladyshev 4878c1d0549SMyung Bae if (lanesInUse != nullptr) 488543f9a75SLakshmi Yadlapati { 4898c1d0549SMyung Bae if (*lanesInUse == std::numeric_limits<size_t>::max()) 4908c1d0549SMyung Bae { 4918c1d0549SMyung Bae // The default value of LanesInUse is "maxint", and the field will 4928c1d0549SMyung Bae // be null if it is a default value. 4938c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr; 4948c1d0549SMyung Bae } 4958c1d0549SMyung Bae else 4968c1d0549SMyung Bae { 4978c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = 4988c1d0549SMyung Bae *lanesInUse; 4998c1d0549SMyung Bae } 500543f9a75SLakshmi Yadlapati } 501814bf20aSKonstantin Aladyshev // The default value of MaxLanes is 0, and the field will be 502814bf20aSKonstantin Aladyshev // left as off if it is a default value. 503814bf20aSKonstantin Aladyshev if (maxLanes != nullptr && *maxLanes != 0) 504814bf20aSKonstantin Aladyshev { 505814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes; 506814bf20aSKonstantin Aladyshev } 507543f9a75SLakshmi Yadlapati 508a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 509a5409991SLakshmi Yadlapati boost::urls::format( 510253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 511253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 512d1bde9e5SKrzysztof Grobelny } 513d1bde9e5SKrzysztof Grobelny 514543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 515ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 516543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 517543f9a75SLakshmi Yadlapati const std::function<void( 518543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 519d1bde9e5SKrzysztof Grobelny { 520543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 521543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 522543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 523ac106bf6SEd Tanous [asyncResp, 524543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 525543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 526543f9a75SLakshmi Yadlapati if (ec) 527543f9a75SLakshmi Yadlapati { 528543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 529543f9a75SLakshmi Yadlapati { 53062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties"); 531ac106bf6SEd Tanous messages::internalError(asyncResp->res); 532543f9a75SLakshmi Yadlapati } 533543f9a75SLakshmi Yadlapati return; 534543f9a75SLakshmi Yadlapati } 535543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 536543f9a75SLakshmi Yadlapati }); 537d1bde9e5SKrzysztof Grobelny } 538d1bde9e5SKrzysztof Grobelny 539543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 540ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 541543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 542543f9a75SLakshmi Yadlapati { 543ac106bf6SEd Tanous asyncResp->res.addHeader( 544543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 545543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 546ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 547253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 548253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 549253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 550ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 551ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 552*539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 553*539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 554543f9a75SLakshmi Yadlapati } 5551476687dSEd Tanous 556a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath( 557a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 558a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, const std::string& pcieDevicePath, 559a5409991SLakshmi Yadlapati const std::string& service) 560a5409991SLakshmi Yadlapati { 561a5409991SLakshmi Yadlapati addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 562a5409991SLakshmi Yadlapati getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 563a5409991SLakshmi Yadlapati getPCIeDeviceState(asyncResp, pcieDevicePath, service); 564a5409991SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 565a5409991SLakshmi Yadlapati getPCIeDeviceProperties( 566a5409991SLakshmi Yadlapati asyncResp, pcieDevicePath, service, 567a5409991SLakshmi Yadlapati std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId)); 568a5409991SLakshmi Yadlapati getPCIeDeviceSlotPath( 569a5409991SLakshmi Yadlapati pcieDevicePath, asyncResp, 570a5409991SLakshmi Yadlapati std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp)); 571a5409991SLakshmi Yadlapati } 572a5409991SLakshmi Yadlapati 573ac106bf6SEd Tanous inline void 574ac106bf6SEd Tanous handlePCIeDeviceGet(App& app, const crow::Request& req, 575ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 576543f9a75SLakshmi Yadlapati const std::string& systemName, 577543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 578543f9a75SLakshmi Yadlapati { 579ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 580543f9a75SLakshmi Yadlapati { 581543f9a75SLakshmi Yadlapati return; 582543f9a75SLakshmi Yadlapati } 58325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5847f3e84a1SEd Tanous { 5857f3e84a1SEd Tanous // Option currently returns no systems. TBD 5867f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5877f3e84a1SEd Tanous systemName); 5887f3e84a1SEd Tanous return; 5897f3e84a1SEd Tanous } 590253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 591543f9a75SLakshmi Yadlapati { 592ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 593ac106bf6SEd Tanous systemName); 594543f9a75SLakshmi Yadlapati return; 595543f9a75SLakshmi Yadlapati } 596543f9a75SLakshmi Yadlapati 597543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 598ac106bf6SEd Tanous pcieDeviceId, asyncResp, 599a5409991SLakshmi Yadlapati std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId)); 600543f9a75SLakshmi Yadlapati } 601543f9a75SLakshmi Yadlapati 602543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 603543f9a75SLakshmi Yadlapati { 604543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 605543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 606543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 607543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 608dede6a98SJason M. Bills } 609dede6a98SJason M. Bills 61035ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 61135ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 61235ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 61335ad613dSLakshmi Yadlapati { 61435ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 61535ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 61635ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 61735ad613dSLakshmi Yadlapati 61835ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 61935ad613dSLakshmi Yadlapati { 62035ad613dSLakshmi Yadlapati // Check if this function exists by 62135ad613dSLakshmi Yadlapati // looking for a device ID 62289492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 62389492a15SPatrick Williams "DeviceId"; 62435ad613dSLakshmi Yadlapati const std::string* property = nullptr; 62535ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 62635ad613dSLakshmi Yadlapati { 62735ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 62835ad613dSLakshmi Yadlapati { 62935ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 63035ad613dSLakshmi Yadlapati break; 63135ad613dSLakshmi Yadlapati } 63235ad613dSLakshmi Yadlapati } 63335ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 63435ad613dSLakshmi Yadlapati { 63535ad613dSLakshmi Yadlapati continue; 63635ad613dSLakshmi Yadlapati } 63735ad613dSLakshmi Yadlapati 63835ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 639ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 640253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 641253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 642253f11b8SEd Tanous std::to_string(functionNum)); 643b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 64435ad613dSLakshmi Yadlapati } 64535ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 64635ad613dSLakshmi Yadlapati } 64735ad613dSLakshmi Yadlapati 64835ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 64935ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 650ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6517f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 65235ad613dSLakshmi Yadlapati { 653ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 65435ad613dSLakshmi Yadlapati { 65535ad613dSLakshmi Yadlapati return; 65635ad613dSLakshmi Yadlapati } 65725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6587f3e84a1SEd Tanous { 6597f3e84a1SEd Tanous // Option currently returns no systems. TBD 6607f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6617f3e84a1SEd Tanous systemName); 6627f3e84a1SEd Tanous return; 6637f3e84a1SEd Tanous } 66435ad613dSLakshmi Yadlapati 66535ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 666ac106bf6SEd Tanous pcieDeviceId, asyncResp, 667ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 66835ad613dSLakshmi Yadlapati const std::string& service) { 669ac106bf6SEd Tanous asyncResp->res.addHeader( 67035ad613dSLakshmi Yadlapati boost::beast::http::field::link, 67135ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 672ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 67335ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 674ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 675253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 676253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 677ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 678ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 67935ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 68035ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 681ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 682ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 68335ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 684ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 685ac106bf6SEd Tanous pcieDevProperties); 68635ad613dSLakshmi Yadlapati }); 68735ad613dSLakshmi Yadlapati }); 68835ad613dSLakshmi Yadlapati } 68935ad613dSLakshmi Yadlapati 6907e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 6917e860f15SJohn Edward Broadbent { 692dede6a98SJason M. Bills /** 693dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 694dede6a98SJason M. Bills */ 6957e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 6967f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 697ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 698002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 69935ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 7007e860f15SJohn Edward Broadbent } 7017e860f15SJohn Edward Broadbent 702727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 703d5e74b80SMyung Bae uint64_t pcieFunctionId, 704727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 7057e860f15SJohn Edward Broadbent { 706d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 707b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 708b9d36b47SEd Tanous 709b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 710b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 711b9d36b47SEd Tanous { 712b9d36b47SEd Tanous if (property.first == devIDProperty) 713b9d36b47SEd Tanous { 714002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 715727a046cSLakshmi Yadlapati break; 716b9d36b47SEd Tanous } 717b9d36b47SEd Tanous } 718727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 719727a046cSLakshmi Yadlapati } 720727a046cSLakshmi Yadlapati 721727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 722e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 723727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 724f5c9f8bdSJason M. Bills { 725e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 726b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 727f5c9f8bdSJason M. Bills { 728b9d36b47SEd Tanous const std::string* strProperty = 729b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 730dc8cfa66SEd Tanous if (strProperty == nullptr) 731dc8cfa66SEd Tanous { 732dc8cfa66SEd Tanous BMCWEB_LOG_ERROR("Function wasn't a string?"); 733dc8cfa66SEd Tanous continue; 734dc8cfa66SEd Tanous } 735b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 736f5c9f8bdSJason M. Bills { 737727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 738f5c9f8bdSJason M. Bills } 739b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 740f5c9f8bdSJason M. Bills { 741727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 742f5c9f8bdSJason M. Bills } 743727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 744727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 745727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 746b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 747f5c9f8bdSJason M. Bills { 748727a046cSLakshmi Yadlapati if (!strProperty->empty()) 749727a046cSLakshmi Yadlapati { 750727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 751727a046cSLakshmi Yadlapati } 752f5c9f8bdSJason M. Bills } 753b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 754f5c9f8bdSJason M. Bills { 755727a046cSLakshmi Yadlapati if (!strProperty->empty()) 756727a046cSLakshmi Yadlapati { 757727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 758727a046cSLakshmi Yadlapati } 759f5c9f8bdSJason M. Bills } 760b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 761f5c9f8bdSJason M. Bills { 762727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 763f5c9f8bdSJason M. Bills } 764b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 765f5c9f8bdSJason M. Bills { 766727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 767f5c9f8bdSJason M. Bills } 768b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 769b9d36b47SEd Tanous { 770727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 771b9d36b47SEd Tanous } 772002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 773f5c9f8bdSJason M. Bills { 774727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 775b9d36b47SEd Tanous } 776f5c9f8bdSJason M. Bills } 777727a046cSLakshmi Yadlapati } 778727a046cSLakshmi Yadlapati 779727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 780727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 781e14742caSEd Tanous uint64_t pcieFunctionId) 782727a046cSLakshmi Yadlapati { 783727a046cSLakshmi Yadlapati resp.addHeader( 784727a046cSLakshmi Yadlapati boost::beast::http::field::link, 785727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 786727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 787ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 788253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 789253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 790253f11b8SEd Tanous std::to_string(pcieFunctionId)); 791727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 792e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 793e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 794253f11b8SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 795253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 796253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 797727a046cSLakshmi Yadlapati } 798727a046cSLakshmi Yadlapati 799727a046cSLakshmi Yadlapati inline void 800727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 801ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8027f3e84a1SEd Tanous const std::string& systemName, 803727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 804e14742caSEd Tanous const std::string& pcieFunctionIdStr) 805727a046cSLakshmi Yadlapati { 806ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 807727a046cSLakshmi Yadlapati { 808727a046cSLakshmi Yadlapati return; 809727a046cSLakshmi Yadlapati } 81025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 8117f3e84a1SEd Tanous { 8127f3e84a1SEd Tanous // Option currently returns no systems. TBD 8137f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8147f3e84a1SEd Tanous systemName); 8157f3e84a1SEd Tanous return; 8167f3e84a1SEd Tanous } 817253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 8187f3e84a1SEd Tanous { 8197f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8207f3e84a1SEd Tanous systemName); 8217f3e84a1SEd Tanous return; 8227f3e84a1SEd Tanous } 823dc8cfa66SEd Tanous std::string_view pcieFunctionIdView = pcieFunctionIdStr; 8247f3e84a1SEd Tanous 825e14742caSEd Tanous uint64_t pcieFunctionId = 0; 826e14742caSEd Tanous std::from_chars_result result = std::from_chars( 827dc8cfa66SEd Tanous pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId); 828dc8cfa66SEd Tanous if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end()) 829e14742caSEd Tanous { 830ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 831e14742caSEd Tanous pcieFunctionIdStr); 832e14742caSEd Tanous return; 833e14742caSEd Tanous } 834727a046cSLakshmi Yadlapati 835ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 836ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 837ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 838727a046cSLakshmi Yadlapati const std::string& service) { 839727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 840ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 841ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 842727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 843ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 844727a046cSLakshmi Yadlapati pcieFunctionId); 845ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 846727a046cSLakshmi Yadlapati pcieDevProperties); 8477e860f15SJohn Edward Broadbent }); 848727a046cSLakshmi Yadlapati }); 849727a046cSLakshmi Yadlapati } 850727a046cSLakshmi Yadlapati 851727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 852727a046cSLakshmi Yadlapati { 853727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8547f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 855727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 856727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 857727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 858f5c9f8bdSJason M. Bills } 859f5c9f8bdSJason M. Bills 860f5c9f8bdSJason M. Bills } // namespace redfish 861