1f5c9f8bdSJason M. Bills /* 26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd Tanous 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" 21539d8c6bSEd 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 444ff0f1f4SEd Tanous 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( 623a58c5a8SKonstantin Aladyshev pcieDevicePath, pcieDeviceInterface, 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 814ff0f1f4SEd Tanous 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 1054ff0f1f4SEd Tanous 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 { 253bd79bce8SPatrick Williams // If the device doesn't have an association, return without 254bd79bce8SPatrick Williams // PCIe 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 262bd79bce8SPatrick Williams inline void afterGetDbusObject( 263bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 264bd79bce8SPatrick Williams const std::string& pcieDeviceSlot, const boost::system::error_code& ec, 265a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) 266a5409991SLakshmi Yadlapati { 267a5409991SLakshmi Yadlapati if (ec || object.empty()) 268a5409991SLakshmi Yadlapati { 26962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}", 27062598e31SEd Tanous ec.value()); 271a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 272a5409991SLakshmi Yadlapati return; 273a5409991SLakshmi Yadlapati } 274*deae6a78SEd Tanous dbus::utility::getAllProperties( 275*deae6a78SEd Tanous object.begin()->first, pcieDeviceSlot, 276a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot", 277a5409991SLakshmi Yadlapati [asyncResp]( 278a5409991SLakshmi Yadlapati const boost::system::error_code& ec2, 279a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) { 280a5409991SLakshmi Yadlapati addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties); 281a5409991SLakshmi Yadlapati }); 282a5409991SLakshmi Yadlapati } 283a5409991SLakshmi Yadlapati 284a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath( 285a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 286a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot) 287a5409991SLakshmi Yadlapati { 288a5409991SLakshmi Yadlapati dbus::utility::getDbusObject( 289a5409991SLakshmi Yadlapati pcieDeviceSlot, pcieSlotInterface, 290a5409991SLakshmi Yadlapati [asyncResp, 291a5409991SLakshmi Yadlapati pcieDeviceSlot](const boost::system::error_code& ec, 292a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 293a5409991SLakshmi Yadlapati afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object); 294a5409991SLakshmi Yadlapati }); 295a5409991SLakshmi Yadlapati } 296a5409991SLakshmi Yadlapati 297bd79bce8SPatrick Williams inline void getPCIeDeviceHealth( 298bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 299bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 300e164f1b6SLakshmi Yadlapati { 301*deae6a78SEd Tanous dbus::utility::getProperty<bool>( 302*deae6a78SEd Tanous service, pcieDevicePath, 303e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 304e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 305e164f1b6SLakshmi Yadlapati if (ec) 306e164f1b6SLakshmi Yadlapati { 307e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 308e164f1b6SLakshmi Yadlapati { 30962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 31062598e31SEd Tanous ec.value()); 311e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 312e164f1b6SLakshmi Yadlapati } 313e164f1b6SLakshmi Yadlapati return; 314e164f1b6SLakshmi Yadlapati } 315e164f1b6SLakshmi Yadlapati 316e164f1b6SLakshmi Yadlapati if (!value) 317e164f1b6SLakshmi Yadlapati { 318539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 319539d8c6bSEd Tanous resource::Health::Critical; 320e164f1b6SLakshmi Yadlapati } 321e164f1b6SLakshmi Yadlapati }); 322e164f1b6SLakshmi Yadlapati } 323e164f1b6SLakshmi Yadlapati 324bd79bce8SPatrick Williams inline void getPCIeDeviceState( 325bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 326bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 327c6bb3285SLakshmi Yadlapati { 328*deae6a78SEd Tanous dbus::utility::getProperty<bool>( 329*deae6a78SEd Tanous service, pcieDevicePath, "xyz.openbmc_project.Inventory.Item", 330*deae6a78SEd Tanous "Present", 331a5409991SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, bool value) { 332c6bb3285SLakshmi Yadlapati if (ec) 333c6bb3285SLakshmi Yadlapati { 334c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 335c6bb3285SLakshmi Yadlapati { 33662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State"); 337ac106bf6SEd Tanous messages::internalError(asyncResp->res); 338c6bb3285SLakshmi Yadlapati } 339c6bb3285SLakshmi Yadlapati return; 340c6bb3285SLakshmi Yadlapati } 341c6bb3285SLakshmi Yadlapati 342c6bb3285SLakshmi Yadlapati if (!value) 343c6bb3285SLakshmi Yadlapati { 344539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 345539d8c6bSEd Tanous resource::State::Absent; 346c6bb3285SLakshmi Yadlapati } 347c6bb3285SLakshmi Yadlapati }); 348c6bb3285SLakshmi Yadlapati } 349c6bb3285SLakshmi Yadlapati 350bd79bce8SPatrick Williams inline void getPCIeDeviceAsset( 351bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 352bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) 353913e7732SSunnySrivastava1984 { 354*deae6a78SEd Tanous dbus::utility::getAllProperties( 355*deae6a78SEd Tanous service, pcieDevicePath, 356913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 357ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 358ac106bf6SEd Tanous const boost::system::error_code& ec, 359913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 360913e7732SSunnySrivastava1984 if (ec) 361913e7732SSunnySrivastava1984 { 362913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 363913e7732SSunnySrivastava1984 { 36462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}", 36562598e31SEd Tanous ec.value()); 366ac106bf6SEd Tanous messages::internalError(asyncResp->res); 367913e7732SSunnySrivastava1984 } 368913e7732SSunnySrivastava1984 return; 369913e7732SSunnySrivastava1984 } 370913e7732SSunnySrivastava1984 371913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 372913e7732SSunnySrivastava1984 const std::string* model = nullptr; 373913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 374913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 375913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 376913e7732SSunnySrivastava1984 377913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 378913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 379913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 380bd79bce8SPatrick Williams "SerialNumber", serialNumber, "SparePartNumber", 381bd79bce8SPatrick Williams sparePartNumber); 382913e7732SSunnySrivastava1984 383913e7732SSunnySrivastava1984 if (!success) 384913e7732SSunnySrivastava1984 { 385ac106bf6SEd Tanous messages::internalError(asyncResp->res); 386913e7732SSunnySrivastava1984 return; 387913e7732SSunnySrivastava1984 } 388913e7732SSunnySrivastava1984 389913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 390913e7732SSunnySrivastava1984 { 391ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 392913e7732SSunnySrivastava1984 } 393913e7732SSunnySrivastava1984 if (model != nullptr) 394913e7732SSunnySrivastava1984 { 395ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 396913e7732SSunnySrivastava1984 } 397913e7732SSunnySrivastava1984 398913e7732SSunnySrivastava1984 if (partNumber != nullptr) 399913e7732SSunnySrivastava1984 { 400ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 401913e7732SSunnySrivastava1984 } 402913e7732SSunnySrivastava1984 403913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 404913e7732SSunnySrivastava1984 { 405ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 406913e7732SSunnySrivastava1984 } 407913e7732SSunnySrivastava1984 408913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 409913e7732SSunnySrivastava1984 { 410ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 411913e7732SSunnySrivastava1984 } 412913e7732SSunnySrivastava1984 }); 413913e7732SSunnySrivastava1984 } 414913e7732SSunnySrivastava1984 415543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 416a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 417a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, 418543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 419f5c9f8bdSJason M. Bills { 420d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 421814bf20aSKonstantin Aladyshev const std::string* generationSupported = nullptr; 4229bb0a7feSKonstantin Aladyshev const size_t* lanesInUse = nullptr; 423814bf20aSKonstantin Aladyshev const size_t* maxLanes = nullptr; 424d1bde9e5SKrzysztof Grobelny 425d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 426609ba4c9SEd Tanous dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse", 427609ba4c9SEd Tanous generationInUse, "GenerationSupported", generationSupported, 428609ba4c9SEd Tanous "LanesInUse", lanesInUse, "MaxLanes", maxLanes); 429d1bde9e5SKrzysztof Grobelny 430d1bde9e5SKrzysztof Grobelny if (!success) 431d1bde9e5SKrzysztof Grobelny { 432a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 433d1bde9e5SKrzysztof Grobelny return; 434d1bde9e5SKrzysztof Grobelny } 435d1bde9e5SKrzysztof Grobelny 436d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 437d1bde9e5SKrzysztof Grobelny { 4380ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 439c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 440543f9a75SLakshmi Yadlapati 441d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 442d1bde9e5SKrzysztof Grobelny { 44362598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 44462598e31SEd Tanous *generationInUse); 445cf3b484eSLakshmi Yadlapati } 446cf3b484eSLakshmi Yadlapati else 447cf3b484eSLakshmi Yadlapati { 448cf3b484eSLakshmi Yadlapati if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid) 449cf3b484eSLakshmi Yadlapati { 45062598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 45162598e31SEd Tanous *generationInUse); 452a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 453d1bde9e5SKrzysztof Grobelny return; 454d1bde9e5SKrzysztof Grobelny } 455a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 456d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 457d1bde9e5SKrzysztof Grobelny } 458a9f68bb5STony Lee } 459d1bde9e5SKrzysztof Grobelny 460814bf20aSKonstantin Aladyshev if (generationSupported != nullptr) 461814bf20aSKonstantin Aladyshev { 462814bf20aSKonstantin Aladyshev std::optional<pcie_device::PCIeTypes> redfishGenerationSupported = 463814bf20aSKonstantin Aladyshev pcie_util::redfishPcieGenerationFromDbus(*generationSupported); 464814bf20aSKonstantin Aladyshev 465814bf20aSKonstantin Aladyshev if (!redfishGenerationSupported) 466814bf20aSKonstantin Aladyshev { 46762598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 46862598e31SEd Tanous *generationSupported); 469814bf20aSKonstantin Aladyshev } 470814bf20aSKonstantin Aladyshev else 471814bf20aSKonstantin Aladyshev { 472814bf20aSKonstantin Aladyshev if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid) 473814bf20aSKonstantin Aladyshev { 47462598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 47562598e31SEd Tanous *generationSupported); 476814bf20aSKonstantin Aladyshev messages::internalError(asyncResp->res); 477814bf20aSKonstantin Aladyshev return; 478814bf20aSKonstantin Aladyshev } 479814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] = 480814bf20aSKonstantin Aladyshev *redfishGenerationSupported; 481814bf20aSKonstantin Aladyshev } 482814bf20aSKonstantin Aladyshev } 483814bf20aSKonstantin Aladyshev 4848c1d0549SMyung Bae if (lanesInUse != nullptr) 485543f9a75SLakshmi Yadlapati { 4868c1d0549SMyung Bae if (*lanesInUse == std::numeric_limits<size_t>::max()) 4878c1d0549SMyung Bae { 4888c1d0549SMyung Bae // The default value of LanesInUse is "maxint", and the field will 4898c1d0549SMyung Bae // be null if it is a default value. 4908c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr; 4918c1d0549SMyung Bae } 4928c1d0549SMyung Bae else 4938c1d0549SMyung Bae { 4948c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = 4958c1d0549SMyung Bae *lanesInUse; 4968c1d0549SMyung Bae } 497543f9a75SLakshmi Yadlapati } 498814bf20aSKonstantin Aladyshev // The default value of MaxLanes is 0, and the field will be 499814bf20aSKonstantin Aladyshev // left as off if it is a default value. 500814bf20aSKonstantin Aladyshev if (maxLanes != nullptr && *maxLanes != 0) 501814bf20aSKonstantin Aladyshev { 502814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes; 503814bf20aSKonstantin Aladyshev } 504543f9a75SLakshmi Yadlapati 505a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 506a5409991SLakshmi Yadlapati boost::urls::format( 507253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 508253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 509d1bde9e5SKrzysztof Grobelny } 510d1bde9e5SKrzysztof Grobelny 511543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 512ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 513543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 514543f9a75SLakshmi Yadlapati const std::function<void( 515543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 516d1bde9e5SKrzysztof Grobelny { 517*deae6a78SEd Tanous dbus::utility::getAllProperties( 518*deae6a78SEd Tanous service, pcieDevicePath, 519543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 520ac106bf6SEd Tanous [asyncResp, 521543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 522543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 523543f9a75SLakshmi Yadlapati if (ec) 524543f9a75SLakshmi Yadlapati { 525543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 526543f9a75SLakshmi Yadlapati { 52762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties"); 528ac106bf6SEd Tanous messages::internalError(asyncResp->res); 529543f9a75SLakshmi Yadlapati } 530543f9a75SLakshmi Yadlapati return; 531543f9a75SLakshmi Yadlapati } 532543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 533543f9a75SLakshmi Yadlapati }); 534d1bde9e5SKrzysztof Grobelny } 535d1bde9e5SKrzysztof Grobelny 536543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 537ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 538543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 539543f9a75SLakshmi Yadlapati { 540ac106bf6SEd Tanous asyncResp->res.addHeader( 541543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 542543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 543ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 544253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 545253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 546253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 547ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 548ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 549539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 550539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 551543f9a75SLakshmi Yadlapati } 5521476687dSEd Tanous 553a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath( 554a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 555a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, const std::string& pcieDevicePath, 556a5409991SLakshmi Yadlapati const std::string& service) 557a5409991SLakshmi Yadlapati { 558a5409991SLakshmi Yadlapati addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 559a5409991SLakshmi Yadlapati getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 560a5409991SLakshmi Yadlapati getPCIeDeviceState(asyncResp, pcieDevicePath, service); 561a5409991SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 562a5409991SLakshmi Yadlapati getPCIeDeviceProperties( 563a5409991SLakshmi Yadlapati asyncResp, pcieDevicePath, service, 564a5409991SLakshmi Yadlapati std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId)); 565a5409991SLakshmi Yadlapati getPCIeDeviceSlotPath( 566a5409991SLakshmi Yadlapati pcieDevicePath, asyncResp, 567a5409991SLakshmi Yadlapati std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp)); 568a5409991SLakshmi Yadlapati } 569a5409991SLakshmi Yadlapati 570bd79bce8SPatrick Williams inline void handlePCIeDeviceGet( 571bd79bce8SPatrick Williams App& app, const crow::Request& req, 572ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 573bd79bce8SPatrick Williams const std::string& systemName, const std::string& pcieDeviceId) 574543f9a75SLakshmi Yadlapati { 575ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 576543f9a75SLakshmi Yadlapati { 577543f9a75SLakshmi Yadlapati return; 578543f9a75SLakshmi Yadlapati } 57925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5807f3e84a1SEd Tanous { 5817f3e84a1SEd Tanous // Option currently returns no systems. TBD 5827f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5837f3e84a1SEd Tanous systemName); 5847f3e84a1SEd Tanous return; 5857f3e84a1SEd Tanous } 586253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 587543f9a75SLakshmi Yadlapati { 588ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 589ac106bf6SEd Tanous systemName); 590543f9a75SLakshmi Yadlapati return; 591543f9a75SLakshmi Yadlapati } 592543f9a75SLakshmi Yadlapati 593543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 594ac106bf6SEd Tanous pcieDeviceId, asyncResp, 595a5409991SLakshmi Yadlapati std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId)); 596543f9a75SLakshmi Yadlapati } 597543f9a75SLakshmi Yadlapati 598543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 599543f9a75SLakshmi Yadlapati { 600543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 601543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 602543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 603543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 604dede6a98SJason M. Bills } 605dede6a98SJason M. Bills 60635ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 60735ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 60835ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 60935ad613dSLakshmi Yadlapati { 61035ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 61135ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 61235ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 61335ad613dSLakshmi Yadlapati 61435ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 61535ad613dSLakshmi Yadlapati { 61635ad613dSLakshmi Yadlapati // Check if this function exists by 61735ad613dSLakshmi Yadlapati // looking for a device ID 618bd79bce8SPatrick Williams std::string devIDProperty = 619bd79bce8SPatrick Williams "Function" + std::to_string(functionNum) + "DeviceId"; 62035ad613dSLakshmi Yadlapati const std::string* property = nullptr; 62135ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 62235ad613dSLakshmi Yadlapati { 62335ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 62435ad613dSLakshmi Yadlapati { 62535ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 62635ad613dSLakshmi Yadlapati break; 62735ad613dSLakshmi Yadlapati } 62835ad613dSLakshmi Yadlapati } 62935ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 63035ad613dSLakshmi Yadlapati { 63135ad613dSLakshmi Yadlapati continue; 63235ad613dSLakshmi Yadlapati } 63335ad613dSLakshmi Yadlapati 63435ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 635ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 636253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 637253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 638253f11b8SEd Tanous std::to_string(functionNum)); 639b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 64035ad613dSLakshmi Yadlapati } 64135ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 64235ad613dSLakshmi Yadlapati } 64335ad613dSLakshmi Yadlapati 64435ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 64535ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 646ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6477f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 64835ad613dSLakshmi Yadlapati { 649ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 65035ad613dSLakshmi Yadlapati { 65135ad613dSLakshmi Yadlapati return; 65235ad613dSLakshmi Yadlapati } 65325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6547f3e84a1SEd Tanous { 6557f3e84a1SEd Tanous // Option currently returns no systems. TBD 6567f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6577f3e84a1SEd Tanous systemName); 6587f3e84a1SEd Tanous return; 6597f3e84a1SEd Tanous } 66035ad613dSLakshmi Yadlapati 66135ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 662ac106bf6SEd Tanous pcieDeviceId, asyncResp, 663ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 66435ad613dSLakshmi Yadlapati const std::string& service) { 665ac106bf6SEd Tanous asyncResp->res.addHeader( 66635ad613dSLakshmi Yadlapati boost::beast::http::field::link, 66735ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 668ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 66935ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 670ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 671253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 672253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 673ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 674ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 67535ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 67635ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 677ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 678ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 67935ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 680ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 681ac106bf6SEd Tanous pcieDevProperties); 68235ad613dSLakshmi Yadlapati }); 68335ad613dSLakshmi Yadlapati }); 68435ad613dSLakshmi Yadlapati } 68535ad613dSLakshmi Yadlapati 6867e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 6877e860f15SJohn Edward Broadbent { 688dede6a98SJason M. Bills /** 689dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 690dede6a98SJason M. Bills */ 6917e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 6927f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 693ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 694002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 69535ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 6967e860f15SJohn Edward Broadbent } 6977e860f15SJohn Edward Broadbent 698727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 699d5e74b80SMyung Bae uint64_t pcieFunctionId, 700727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 7017e860f15SJohn Edward Broadbent { 702d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 703b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 704b9d36b47SEd Tanous 705b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 706b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 707b9d36b47SEd Tanous { 708b9d36b47SEd Tanous if (property.first == devIDProperty) 709b9d36b47SEd Tanous { 710002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 711727a046cSLakshmi Yadlapati break; 712b9d36b47SEd Tanous } 713b9d36b47SEd Tanous } 714727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 715727a046cSLakshmi Yadlapati } 716727a046cSLakshmi Yadlapati 717727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 718e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 719727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 720f5c9f8bdSJason M. Bills { 721e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 722b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 723f5c9f8bdSJason M. Bills { 724b9d36b47SEd Tanous const std::string* strProperty = 725b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 726dc8cfa66SEd Tanous if (strProperty == nullptr) 727dc8cfa66SEd Tanous { 728dc8cfa66SEd Tanous continue; 729dc8cfa66SEd Tanous } 730b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 731f5c9f8bdSJason M. Bills { 732727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 733f5c9f8bdSJason M. Bills } 734b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 735f5c9f8bdSJason M. Bills { 736727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 737f5c9f8bdSJason M. Bills } 738727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 739727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 740727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 741b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 742f5c9f8bdSJason M. Bills { 743727a046cSLakshmi Yadlapati if (!strProperty->empty()) 744727a046cSLakshmi Yadlapati { 745727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 746727a046cSLakshmi Yadlapati } 747f5c9f8bdSJason M. Bills } 748b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 749f5c9f8bdSJason M. Bills { 750727a046cSLakshmi Yadlapati if (!strProperty->empty()) 751727a046cSLakshmi Yadlapati { 752727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 753727a046cSLakshmi Yadlapati } 754f5c9f8bdSJason M. Bills } 755b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 756f5c9f8bdSJason M. Bills { 757727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 758f5c9f8bdSJason M. Bills } 759b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 760f5c9f8bdSJason M. Bills { 761727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 762f5c9f8bdSJason M. Bills } 763b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 764b9d36b47SEd Tanous { 765727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 766b9d36b47SEd Tanous } 767002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 768f5c9f8bdSJason M. Bills { 769727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 770b9d36b47SEd Tanous } 771f5c9f8bdSJason M. Bills } 772727a046cSLakshmi Yadlapati } 773727a046cSLakshmi Yadlapati 774727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 775727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 776e14742caSEd Tanous uint64_t pcieFunctionId) 777727a046cSLakshmi Yadlapati { 778727a046cSLakshmi Yadlapati resp.addHeader( 779727a046cSLakshmi Yadlapati boost::beast::http::field::link, 780727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 781727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 782ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 783253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 784253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 785253f11b8SEd Tanous std::to_string(pcieFunctionId)); 786727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 787e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 788e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 789253f11b8SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 790253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 791253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 792727a046cSLakshmi Yadlapati } 793727a046cSLakshmi Yadlapati 794bd79bce8SPatrick Williams inline void handlePCIeFunctionGet( 795bd79bce8SPatrick Williams App& app, const crow::Request& req, 796ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 797bd79bce8SPatrick Williams const std::string& systemName, const std::string& pcieDeviceId, 798e14742caSEd Tanous const std::string& pcieFunctionIdStr) 799727a046cSLakshmi Yadlapati { 800ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 801727a046cSLakshmi Yadlapati { 802727a046cSLakshmi Yadlapati return; 803727a046cSLakshmi Yadlapati } 80425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 8057f3e84a1SEd Tanous { 8067f3e84a1SEd Tanous // Option currently returns no systems. TBD 8077f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8087f3e84a1SEd Tanous systemName); 8097f3e84a1SEd Tanous return; 8107f3e84a1SEd Tanous } 811253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 8127f3e84a1SEd Tanous { 8137f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8147f3e84a1SEd Tanous systemName); 8157f3e84a1SEd Tanous return; 8167f3e84a1SEd Tanous } 817dc8cfa66SEd Tanous std::string_view pcieFunctionIdView = pcieFunctionIdStr; 8187f3e84a1SEd Tanous 819e14742caSEd Tanous uint64_t pcieFunctionId = 0; 820e14742caSEd Tanous std::from_chars_result result = std::from_chars( 821dc8cfa66SEd Tanous pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId); 822dc8cfa66SEd Tanous if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end()) 823e14742caSEd Tanous { 824ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 825e14742caSEd Tanous pcieFunctionIdStr); 826e14742caSEd Tanous return; 827e14742caSEd Tanous } 828727a046cSLakshmi Yadlapati 829bd79bce8SPatrick Williams getValidPCIeDevicePath( 830bd79bce8SPatrick Williams pcieDeviceId, asyncResp, 831bd79bce8SPatrick Williams [asyncResp, pcieDeviceId, pcieFunctionId]( 832bd79bce8SPatrick Williams const std::string& pcieDevicePath, const std::string& service) { 833727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 834ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 835ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 836727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 837bd79bce8SPatrick Williams addPCIeFunctionCommonProperties( 838bd79bce8SPatrick Williams asyncResp->res, pcieDeviceId, pcieFunctionId); 839ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 840727a046cSLakshmi Yadlapati pcieDevProperties); 8417e860f15SJohn Edward Broadbent }); 842727a046cSLakshmi Yadlapati }); 843727a046cSLakshmi Yadlapati } 844727a046cSLakshmi Yadlapati 845727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 846727a046cSLakshmi Yadlapati { 847727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8487f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 849727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 850727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 851727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 852f5c9f8bdSJason M. Bills } 853f5c9f8bdSJason M. Bills 854f5c9f8bdSJason M. Bills } // namespace redfish 855