1f5c9f8bdSJason M. Bills /* 2f5c9f8bdSJason M. Bills // Copyright (c) 2018 Intel Corporation 3f5c9f8bdSJason M. Bills // 4f5c9f8bdSJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License"); 5f5c9f8bdSJason M. Bills // you may not use this file except in compliance with the License. 6f5c9f8bdSJason M. Bills // You may obtain a copy of the License at 7f5c9f8bdSJason M. Bills // 8f5c9f8bdSJason M. Bills // http://www.apache.org/licenses/LICENSE-2.0 9f5c9f8bdSJason M. Bills // 10f5c9f8bdSJason M. Bills // Unless required by applicable law or agreed to in writing, software 11f5c9f8bdSJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS, 12f5c9f8bdSJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f5c9f8bdSJason M. Bills // See the License for the specific language governing permissions and 14f5c9f8bdSJason M. Bills // limitations under the License. 15f5c9f8bdSJason M. Bills */ 16f5c9f8bdSJason M. Bills 17f5c9f8bdSJason M. Bills #pragma once 18f5c9f8bdSJason M. Bills 193ccb3adbSEd Tanous #include "app.hpp" 207a1dbc48SGeorge Liu #include "dbus_utility.hpp" 213ccb3adbSEd Tanous #include "query.hpp" 223ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 23b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp" 243ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 25c49c329dSLakshmi Yadlapati #include "utils/pcie_util.hpp" 260ec8b83dSEd Tanous 27f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp> 28ef4c65b7SEd Tanous #include <boost/url/format.hpp> 29d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 30d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 31f5c9f8bdSJason M. Bills 32*8c1d0549SMyung Bae #include <limits> 33*8c1d0549SMyung Bae 34f5c9f8bdSJason M. Bills namespace redfish 35f5c9f8bdSJason M. Bills { 36f5c9f8bdSJason M. Bills 3789492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory"; 3894c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = { 3994c3a10bSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 40a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = { 41a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot"}; 42f5c9f8bdSJason M. Bills 43543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath( 44543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 45ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 46543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 47543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 48543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 49543f9a75SLakshmi Yadlapati 50543f9a75SLakshmi Yadlapati { 51543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 52543f9a75SLakshmi Yadlapati { 53543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 54543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 55543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 56543f9a75SLakshmi Yadlapati { 57543f9a75SLakshmi Yadlapati continue; 58543f9a75SLakshmi Yadlapati } 59543f9a75SLakshmi Yadlapati 60543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 61543f9a75SLakshmi Yadlapati pcieDevicePath, {}, 62ac106bf6SEd Tanous [pcieDevicePath, asyncResp, 63543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 64543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 65543f9a75SLakshmi Yadlapati if (ec || object.empty()) 66543f9a75SLakshmi Yadlapati { 6762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 68ac106bf6SEd Tanous messages::internalError(asyncResp->res); 69543f9a75SLakshmi Yadlapati return; 70543f9a75SLakshmi Yadlapati } 71543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 72543f9a75SLakshmi Yadlapati }); 73543f9a75SLakshmi Yadlapati return; 74543f9a75SLakshmi Yadlapati } 75543f9a75SLakshmi Yadlapati 7662598e31SEd Tanous BMCWEB_LOG_WARNING("PCIe Device not found"); 77ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId); 78543f9a75SLakshmi Yadlapati } 79543f9a75SLakshmi Yadlapati 80543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath( 81543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 82ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 83543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 84543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 85543f9a75SLakshmi Yadlapati { 86543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 8794c3a10bSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 88ac106bf6SEd Tanous [pcieDeviceId, asyncResp, 89543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 90543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 91543f9a75SLakshmi Yadlapati pcieDevicePaths) { 92543f9a75SLakshmi Yadlapati if (ec) 93543f9a75SLakshmi Yadlapati { 9462598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec); 95ac106bf6SEd Tanous messages::internalError(asyncResp->res); 96543f9a75SLakshmi Yadlapati return; 97543f9a75SLakshmi Yadlapati } 98ac106bf6SEd Tanous handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths, 99ac106bf6SEd Tanous callback); 100543f9a75SLakshmi Yadlapati return; 101543f9a75SLakshmi Yadlapati }); 102543f9a75SLakshmi Yadlapati } 103543f9a75SLakshmi Yadlapati 104b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet( 105b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 106ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 107b38fa2abSLakshmi Yadlapati const std::string& systemName) 108b38fa2abSLakshmi Yadlapati { 109ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 110b38fa2abSLakshmi Yadlapati { 111b38fa2abSLakshmi Yadlapati return; 112b38fa2abSLakshmi Yadlapati } 11325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 1147f3e84a1SEd Tanous { 1157f3e84a1SEd Tanous // Option currently returns no systems. TBD 1167f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1177f3e84a1SEd Tanous systemName); 1187f3e84a1SEd Tanous return; 1197f3e84a1SEd Tanous } 120253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 121b38fa2abSLakshmi Yadlapati { 122ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 123ac106bf6SEd Tanous systemName); 124b38fa2abSLakshmi Yadlapati return; 125b38fa2abSLakshmi Yadlapati } 126543f9a75SLakshmi Yadlapati 127ac106bf6SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::link, 128b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 129b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 130ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 131b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 132253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 133253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME); 134ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device Collection"; 135ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 136b38fa2abSLakshmi Yadlapati 13770c4d545SLakshmi Yadlapati pcie_util::getPCIeDeviceList(asyncResp, 13870c4d545SLakshmi Yadlapati nlohmann::json::json_pointer("/Members")); 139b38fa2abSLakshmi Yadlapati } 140b38fa2abSLakshmi Yadlapati 1417e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 142adbe192aSJason M. Bills { 143adbe192aSJason M. Bills /** 144adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 145adbe192aSJason M. Bills */ 14622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 147ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1487e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 149b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 150f5c9f8bdSJason M. Bills } 151f5c9f8bdSJason M. Bills 152a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties( 153a5409991SLakshmi Yadlapati crow::Response& res, const boost::system::error_code& ec, 154a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) 155a5409991SLakshmi Yadlapati { 156a5409991SLakshmi Yadlapati if (ec) 157a5409991SLakshmi Yadlapati { 15862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}", 15962598e31SEd Tanous ec.value()); 160a5409991SLakshmi Yadlapati messages::internalError(res); 161a5409991SLakshmi Yadlapati return; 162a5409991SLakshmi Yadlapati } 163a5409991SLakshmi Yadlapati std::string generation; 164a5409991SLakshmi Yadlapati size_t lanes = 0; 165a5409991SLakshmi Yadlapati std::string slotType; 166a5409991SLakshmi Yadlapati 167a5409991SLakshmi Yadlapati bool success = sdbusplus::unpackPropertiesNoThrow( 168a5409991SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation", 169a5409991SLakshmi Yadlapati generation, "Lanes", lanes, "SlotType", slotType); 170a5409991SLakshmi Yadlapati 171a5409991SLakshmi Yadlapati if (!success) 172a5409991SLakshmi Yadlapati { 173a5409991SLakshmi Yadlapati messages::internalError(res); 174a5409991SLakshmi Yadlapati return; 175a5409991SLakshmi Yadlapati } 176a5409991SLakshmi Yadlapati 177a5409991SLakshmi Yadlapati std::optional<pcie_device::PCIeTypes> pcieType = 178a5409991SLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(generation); 179a5409991SLakshmi Yadlapati if (!pcieType) 180a5409991SLakshmi Yadlapati { 18162598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation); 182a5409991SLakshmi Yadlapati } 183a5409991SLakshmi Yadlapati else 184a5409991SLakshmi Yadlapati { 185a5409991SLakshmi Yadlapati if (*pcieType == pcie_device::PCIeTypes::Invalid) 186a5409991SLakshmi Yadlapati { 18762598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation); 188a5409991SLakshmi Yadlapati messages::internalError(res); 189a5409991SLakshmi Yadlapati return; 190a5409991SLakshmi Yadlapati } 191a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["PCIeType"] = *pcieType; 192a5409991SLakshmi Yadlapati } 193a5409991SLakshmi Yadlapati 19482f80326SKonstantin Aladyshev if (lanes != 0) 19582f80326SKonstantin Aladyshev { 196a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["Lanes"] = lanes; 19782f80326SKonstantin Aladyshev } 198a5409991SLakshmi Yadlapati 199a5409991SLakshmi Yadlapati std::optional<pcie_slots::SlotTypes> redfishSlotType = 200a5409991SLakshmi Yadlapati pcie_util::dbusSlotTypeToRf(slotType); 201a5409991SLakshmi Yadlapati if (!redfishSlotType) 202a5409991SLakshmi Yadlapati { 20362598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType); 204a5409991SLakshmi Yadlapati } 205a5409991SLakshmi Yadlapati else 206a5409991SLakshmi Yadlapati { 207a5409991SLakshmi Yadlapati if (*redfishSlotType == pcie_slots::SlotTypes::Invalid) 208a5409991SLakshmi Yadlapati { 20962598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType); 210a5409991SLakshmi Yadlapati messages::internalError(res); 211a5409991SLakshmi Yadlapati return; 212a5409991SLakshmi Yadlapati } 213a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["SlotType"] = *redfishSlotType; 214a5409991SLakshmi Yadlapati } 215a5409991SLakshmi Yadlapati } 216a5409991SLakshmi Yadlapati 217a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath( 218a5409991SLakshmi Yadlapati const std::string& pcieDevicePath, 219a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 220a5409991SLakshmi Yadlapati std::function<void(const std::string& pcieDeviceSlot)>&& callback) 221a5409991SLakshmi Yadlapati { 222a5409991SLakshmi Yadlapati std::string associationPath = pcieDevicePath + "/contained_by"; 223a5409991SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 224a5409991SLakshmi Yadlapati associationPath, sdbusplus::message::object_path(inventoryPath), 0, 225a5409991SLakshmi Yadlapati pcieSlotInterface, 2268cb2c024SEd Tanous [callback = std::move(callback), asyncResp, pcieDevicePath]( 227a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 228a5409991SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& endpoints) { 229a5409991SLakshmi Yadlapati if (ec) 230a5409991SLakshmi Yadlapati { 231a5409991SLakshmi Yadlapati if (ec.value() == EBADR) 232a5409991SLakshmi Yadlapati { 233a5409991SLakshmi Yadlapati // Missing association is not an error 234a5409991SLakshmi Yadlapati return; 235a5409991SLakshmi Yadlapati } 23662598e31SEd Tanous BMCWEB_LOG_ERROR( 23762598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}", 23862598e31SEd Tanous ec.value()); 239a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 240a5409991SLakshmi Yadlapati return; 241a5409991SLakshmi Yadlapati } 242a5409991SLakshmi Yadlapati if (endpoints.size() > 1) 243a5409991SLakshmi Yadlapati { 24462598e31SEd Tanous BMCWEB_LOG_ERROR( 24562598e31SEd Tanous "PCIeDevice is associated with more than one PCIeSlot: {}", 24662598e31SEd Tanous endpoints.size()); 247a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 248a5409991SLakshmi Yadlapati return; 249a5409991SLakshmi Yadlapati } 250a5409991SLakshmi Yadlapati if (endpoints.empty()) 251a5409991SLakshmi Yadlapati { 252a5409991SLakshmi Yadlapati // If the device doesn't have an association, return without PCIe 253a5409991SLakshmi Yadlapati // Slot properties 25462598e31SEd Tanous BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot"); 255a5409991SLakshmi Yadlapati return; 256a5409991SLakshmi Yadlapati } 257a5409991SLakshmi Yadlapati callback(endpoints[0]); 258a5409991SLakshmi Yadlapati }); 259a5409991SLakshmi Yadlapati } 260a5409991SLakshmi Yadlapati 261a5409991SLakshmi Yadlapati inline void 262a5409991SLakshmi Yadlapati afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 263a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot, 264a5409991SLakshmi Yadlapati 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 } 274a5409991SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 275a5409991SLakshmi Yadlapati *crow::connections::systemBus, 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 297ac106bf6SEd Tanous inline void 298e164f1b6SLakshmi Yadlapati getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 299e164f1b6SLakshmi Yadlapati const std::string& pcieDevicePath, 300e164f1b6SLakshmi Yadlapati const std::string& service) 301e164f1b6SLakshmi Yadlapati { 302e164f1b6SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 303e164f1b6SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 304e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 305e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 306e164f1b6SLakshmi Yadlapati if (ec) 307e164f1b6SLakshmi Yadlapati { 308e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 309e164f1b6SLakshmi Yadlapati { 31062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 31162598e31SEd Tanous ec.value()); 312e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 313e164f1b6SLakshmi Yadlapati } 314e164f1b6SLakshmi Yadlapati return; 315e164f1b6SLakshmi Yadlapati } 316e164f1b6SLakshmi Yadlapati 317e164f1b6SLakshmi Yadlapati if (!value) 318e164f1b6SLakshmi Yadlapati { 319e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "Critical"; 320e164f1b6SLakshmi Yadlapati } 321e164f1b6SLakshmi Yadlapati }); 322e164f1b6SLakshmi Yadlapati } 323e164f1b6SLakshmi Yadlapati 324e164f1b6SLakshmi Yadlapati inline void 325ac106bf6SEd Tanous getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 326c6bb3285SLakshmi Yadlapati const std::string& pcieDevicePath, 327c6bb3285SLakshmi Yadlapati const std::string& service) 328c6bb3285SLakshmi Yadlapati { 329c6bb3285SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 330c6bb3285SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 331c6bb3285SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item", "Present", 332a5409991SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, bool value) { 333c6bb3285SLakshmi Yadlapati if (ec) 334c6bb3285SLakshmi Yadlapati { 335c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 336c6bb3285SLakshmi Yadlapati { 33762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State"); 338ac106bf6SEd Tanous messages::internalError(asyncResp->res); 339c6bb3285SLakshmi Yadlapati } 340c6bb3285SLakshmi Yadlapati return; 341c6bb3285SLakshmi Yadlapati } 342c6bb3285SLakshmi Yadlapati 343c6bb3285SLakshmi Yadlapati if (!value) 344c6bb3285SLakshmi Yadlapati { 345ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 346c6bb3285SLakshmi Yadlapati } 347c6bb3285SLakshmi Yadlapati }); 348c6bb3285SLakshmi Yadlapati } 349c6bb3285SLakshmi Yadlapati 350ac106bf6SEd Tanous inline void 351ac106bf6SEd Tanous getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 352913e7732SSunnySrivastava1984 const std::string& pcieDevicePath, 353913e7732SSunnySrivastava1984 const std::string& service) 354913e7732SSunnySrivastava1984 { 355913e7732SSunnySrivastava1984 sdbusplus::asio::getAllProperties( 356913e7732SSunnySrivastava1984 *crow::connections::systemBus, service, pcieDevicePath, 357913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 358ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 359ac106bf6SEd Tanous const boost::system::error_code& ec, 360913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 361913e7732SSunnySrivastava1984 if (ec) 362913e7732SSunnySrivastava1984 { 363913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 364913e7732SSunnySrivastava1984 { 36562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}", 36662598e31SEd Tanous ec.value()); 367ac106bf6SEd Tanous messages::internalError(asyncResp->res); 368913e7732SSunnySrivastava1984 } 369913e7732SSunnySrivastava1984 return; 370913e7732SSunnySrivastava1984 } 371913e7732SSunnySrivastava1984 372913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 373913e7732SSunnySrivastava1984 const std::string* model = nullptr; 374913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 375913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 376913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 377913e7732SSunnySrivastava1984 378913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 379913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 380913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 381913e7732SSunnySrivastava1984 "SerialNumber", serialNumber, "SparePartNumber", 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 484*8c1d0549SMyung Bae if (lanesInUse != nullptr) 485543f9a75SLakshmi Yadlapati { 486*8c1d0549SMyung Bae if (*lanesInUse == std::numeric_limits<size_t>::max()) 487*8c1d0549SMyung Bae { 488*8c1d0549SMyung Bae // The default value of LanesInUse is "maxint", and the field will 489*8c1d0549SMyung Bae // be null if it is a default value. 490*8c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = nullptr; 491*8c1d0549SMyung Bae } 492*8c1d0549SMyung Bae else 493*8c1d0549SMyung Bae { 494*8c1d0549SMyung Bae asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = 495*8c1d0549SMyung Bae *lanesInUse; 496*8c1d0549SMyung 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 { 517543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 518543f9a75SLakshmi Yadlapati *crow::connections::systemBus, 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; 549ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 550e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["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 570ac106bf6SEd Tanous inline void 571ac106bf6SEd Tanous handlePCIeDeviceGet(App& app, const crow::Request& req, 572ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 573543f9a75SLakshmi Yadlapati const std::string& systemName, 574543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 575543f9a75SLakshmi Yadlapati { 576ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 577543f9a75SLakshmi Yadlapati { 578543f9a75SLakshmi Yadlapati return; 579543f9a75SLakshmi Yadlapati } 58025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5817f3e84a1SEd Tanous { 5827f3e84a1SEd Tanous // Option currently returns no systems. TBD 5837f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5847f3e84a1SEd Tanous systemName); 5857f3e84a1SEd Tanous return; 5867f3e84a1SEd Tanous } 587253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 588543f9a75SLakshmi Yadlapati { 589ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 590ac106bf6SEd Tanous systemName); 591543f9a75SLakshmi Yadlapati return; 592543f9a75SLakshmi Yadlapati } 593543f9a75SLakshmi Yadlapati 594543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 595ac106bf6SEd Tanous pcieDeviceId, asyncResp, 596a5409991SLakshmi Yadlapati std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId)); 597543f9a75SLakshmi Yadlapati } 598543f9a75SLakshmi Yadlapati 599543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 600543f9a75SLakshmi Yadlapati { 601543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 602543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 603543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 604543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 605dede6a98SJason M. Bills } 606dede6a98SJason M. Bills 60735ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 60835ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 60935ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 61035ad613dSLakshmi Yadlapati { 61135ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 61235ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 61335ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 61435ad613dSLakshmi Yadlapati 61535ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 61635ad613dSLakshmi Yadlapati { 61735ad613dSLakshmi Yadlapati // Check if this function exists by 61835ad613dSLakshmi Yadlapati // looking for a device ID 61989492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 62089492a15SPatrick Williams "DeviceId"; 62135ad613dSLakshmi Yadlapati const std::string* property = nullptr; 62235ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 62335ad613dSLakshmi Yadlapati { 62435ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 62535ad613dSLakshmi Yadlapati { 62635ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 62735ad613dSLakshmi Yadlapati break; 62835ad613dSLakshmi Yadlapati } 62935ad613dSLakshmi Yadlapati } 63035ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 63135ad613dSLakshmi Yadlapati { 63235ad613dSLakshmi Yadlapati continue; 63335ad613dSLakshmi Yadlapati } 63435ad613dSLakshmi Yadlapati 63535ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 636ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 637253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 638253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 639253f11b8SEd Tanous std::to_string(functionNum)); 640b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 64135ad613dSLakshmi Yadlapati } 64235ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 64335ad613dSLakshmi Yadlapati } 64435ad613dSLakshmi Yadlapati 64535ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 64635ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 647ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6487f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 64935ad613dSLakshmi Yadlapati { 650ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 65135ad613dSLakshmi Yadlapati { 65235ad613dSLakshmi Yadlapati return; 65335ad613dSLakshmi Yadlapati } 65425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6557f3e84a1SEd Tanous { 6567f3e84a1SEd Tanous // Option currently returns no systems. TBD 6577f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6587f3e84a1SEd Tanous systemName); 6597f3e84a1SEd Tanous return; 6607f3e84a1SEd Tanous } 66135ad613dSLakshmi Yadlapati 66235ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 663ac106bf6SEd Tanous pcieDeviceId, asyncResp, 664ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 66535ad613dSLakshmi Yadlapati const std::string& service) { 666ac106bf6SEd Tanous asyncResp->res.addHeader( 66735ad613dSLakshmi Yadlapati boost::beast::http::field::link, 66835ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 669ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 67035ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 671ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 672253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 673253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 674ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 675ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 67635ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 67735ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 678ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 679ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 68035ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 681ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 682ac106bf6SEd Tanous pcieDevProperties); 68335ad613dSLakshmi Yadlapati }); 68435ad613dSLakshmi Yadlapati }); 68535ad613dSLakshmi Yadlapati } 68635ad613dSLakshmi Yadlapati 6877e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 6887e860f15SJohn Edward Broadbent { 689dede6a98SJason M. Bills /** 690dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 691dede6a98SJason M. Bills */ 6927e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 6937f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 694ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 695002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 69635ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 6977e860f15SJohn Edward Broadbent } 6987e860f15SJohn Edward Broadbent 699727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 700d5e74b80SMyung Bae uint64_t pcieFunctionId, 701727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 7027e860f15SJohn Edward Broadbent { 703d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 704b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 705b9d36b47SEd Tanous 706b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 707b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 708b9d36b47SEd Tanous { 709b9d36b47SEd Tanous if (property.first == devIDProperty) 710b9d36b47SEd Tanous { 711002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 712727a046cSLakshmi Yadlapati break; 713b9d36b47SEd Tanous } 714b9d36b47SEd Tanous } 715727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 716727a046cSLakshmi Yadlapati } 717727a046cSLakshmi Yadlapati 718727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 719e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 720727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 721f5c9f8bdSJason M. Bills { 722e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 723b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 724f5c9f8bdSJason M. Bills { 725b9d36b47SEd Tanous const std::string* strProperty = 726b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 727dc8cfa66SEd Tanous if (strProperty == nullptr) 728dc8cfa66SEd Tanous { 729dc8cfa66SEd Tanous BMCWEB_LOG_ERROR("Function wasn't a string?"); 730dc8cfa66SEd Tanous continue; 731dc8cfa66SEd Tanous } 732b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 733f5c9f8bdSJason M. Bills { 734727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 735f5c9f8bdSJason M. Bills } 736b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 737f5c9f8bdSJason M. Bills { 738727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 739f5c9f8bdSJason M. Bills } 740727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 741727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 742727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 743b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 744f5c9f8bdSJason M. Bills { 745727a046cSLakshmi Yadlapati if (!strProperty->empty()) 746727a046cSLakshmi Yadlapati { 747727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 748727a046cSLakshmi Yadlapati } 749f5c9f8bdSJason M. Bills } 750b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 751f5c9f8bdSJason M. Bills { 752727a046cSLakshmi Yadlapati if (!strProperty->empty()) 753727a046cSLakshmi Yadlapati { 754727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 755727a046cSLakshmi Yadlapati } 756f5c9f8bdSJason M. Bills } 757b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 758f5c9f8bdSJason M. Bills { 759727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 760f5c9f8bdSJason M. Bills } 761b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 762f5c9f8bdSJason M. Bills { 763727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 764f5c9f8bdSJason M. Bills } 765b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 766b9d36b47SEd Tanous { 767727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 768b9d36b47SEd Tanous } 769002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 770f5c9f8bdSJason M. Bills { 771727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 772b9d36b47SEd Tanous } 773f5c9f8bdSJason M. Bills } 774727a046cSLakshmi Yadlapati } 775727a046cSLakshmi Yadlapati 776727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 777727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 778e14742caSEd Tanous uint64_t pcieFunctionId) 779727a046cSLakshmi Yadlapati { 780727a046cSLakshmi Yadlapati resp.addHeader( 781727a046cSLakshmi Yadlapati boost::beast::http::field::link, 782727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 783727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 784ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 785253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 786253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 787253f11b8SEd Tanous std::to_string(pcieFunctionId)); 788727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 789e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 790e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 791253f11b8SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 792253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 793253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 794727a046cSLakshmi Yadlapati } 795727a046cSLakshmi Yadlapati 796727a046cSLakshmi Yadlapati inline void 797727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 798ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7997f3e84a1SEd Tanous const std::string& systemName, 800727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 801e14742caSEd Tanous const std::string& pcieFunctionIdStr) 802727a046cSLakshmi Yadlapati { 803ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 804727a046cSLakshmi Yadlapati { 805727a046cSLakshmi Yadlapati return; 806727a046cSLakshmi Yadlapati } 80725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 8087f3e84a1SEd Tanous { 8097f3e84a1SEd Tanous // Option currently returns no systems. TBD 8107f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8117f3e84a1SEd Tanous systemName); 8127f3e84a1SEd Tanous return; 8137f3e84a1SEd Tanous } 814253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 8157f3e84a1SEd Tanous { 8167f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8177f3e84a1SEd Tanous systemName); 8187f3e84a1SEd Tanous return; 8197f3e84a1SEd Tanous } 820dc8cfa66SEd Tanous std::string_view pcieFunctionIdView = pcieFunctionIdStr; 8217f3e84a1SEd Tanous 822e14742caSEd Tanous uint64_t pcieFunctionId = 0; 823e14742caSEd Tanous std::from_chars_result result = std::from_chars( 824dc8cfa66SEd Tanous pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId); 825dc8cfa66SEd Tanous if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end()) 826e14742caSEd Tanous { 827ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 828e14742caSEd Tanous pcieFunctionIdStr); 829e14742caSEd Tanous return; 830e14742caSEd Tanous } 831727a046cSLakshmi Yadlapati 832ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 833ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 834ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 835727a046cSLakshmi Yadlapati const std::string& service) { 836727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 837ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 838ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 839727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 840ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 841727a046cSLakshmi Yadlapati pcieFunctionId); 842ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 843727a046cSLakshmi Yadlapati pcieDevProperties); 8447e860f15SJohn Edward Broadbent }); 845727a046cSLakshmi Yadlapati }); 846727a046cSLakshmi Yadlapati } 847727a046cSLakshmi Yadlapati 848727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 849727a046cSLakshmi Yadlapati { 850727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8517f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 852727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 853727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 854727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 855f5c9f8bdSJason M. Bills } 856f5c9f8bdSJason M. Bills 857f5c9f8bdSJason M. Bills } // namespace redfish 858