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 32f5c9f8bdSJason M. Bills namespace redfish 33f5c9f8bdSJason M. Bills { 34f5c9f8bdSJason M. Bills 3589492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory"; 3694c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = { 3794c3a10bSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 38a5409991SLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieSlotInterface = { 39a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot"}; 40f5c9f8bdSJason M. Bills 41543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath( 42543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 43ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 44543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 45543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 46543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 47543f9a75SLakshmi Yadlapati 48543f9a75SLakshmi Yadlapati { 49543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 50543f9a75SLakshmi Yadlapati { 51543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 52543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 53543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 54543f9a75SLakshmi Yadlapati { 55543f9a75SLakshmi Yadlapati continue; 56543f9a75SLakshmi Yadlapati } 57543f9a75SLakshmi Yadlapati 58543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 59543f9a75SLakshmi Yadlapati pcieDevicePath, {}, 60ac106bf6SEd Tanous [pcieDevicePath, asyncResp, 61543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 62543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 63543f9a75SLakshmi Yadlapati if (ec || object.empty()) 64543f9a75SLakshmi Yadlapati { 6562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 66ac106bf6SEd Tanous messages::internalError(asyncResp->res); 67543f9a75SLakshmi Yadlapati return; 68543f9a75SLakshmi Yadlapati } 69543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 70543f9a75SLakshmi Yadlapati }); 71543f9a75SLakshmi Yadlapati return; 72543f9a75SLakshmi Yadlapati } 73543f9a75SLakshmi Yadlapati 7462598e31SEd Tanous BMCWEB_LOG_WARNING("PCIe Device not found"); 75ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId); 76543f9a75SLakshmi Yadlapati } 77543f9a75SLakshmi Yadlapati 78543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath( 79543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 80ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 81543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 82543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 83543f9a75SLakshmi Yadlapati { 84543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 8594c3a10bSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 86ac106bf6SEd Tanous [pcieDeviceId, asyncResp, 87543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 88543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 89543f9a75SLakshmi Yadlapati pcieDevicePaths) { 90543f9a75SLakshmi Yadlapati if (ec) 91543f9a75SLakshmi Yadlapati { 9262598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec); 93ac106bf6SEd Tanous messages::internalError(asyncResp->res); 94543f9a75SLakshmi Yadlapati return; 95543f9a75SLakshmi Yadlapati } 96ac106bf6SEd Tanous handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths, 97ac106bf6SEd Tanous callback); 98543f9a75SLakshmi Yadlapati return; 99543f9a75SLakshmi Yadlapati }); 100543f9a75SLakshmi Yadlapati } 101543f9a75SLakshmi Yadlapati 102b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet( 103b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 104ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 105b38fa2abSLakshmi Yadlapati const std::string& systemName) 106b38fa2abSLakshmi Yadlapati { 107ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 108b38fa2abSLakshmi Yadlapati { 109b38fa2abSLakshmi Yadlapati return; 110b38fa2abSLakshmi Yadlapati } 11125b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 1127f3e84a1SEd Tanous { 1137f3e84a1SEd Tanous // Option currently returns no systems. TBD 1147f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1157f3e84a1SEd Tanous systemName); 1167f3e84a1SEd Tanous return; 1177f3e84a1SEd Tanous } 118*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 119b38fa2abSLakshmi Yadlapati { 120ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 121ac106bf6SEd Tanous systemName); 122b38fa2abSLakshmi Yadlapati return; 123b38fa2abSLakshmi Yadlapati } 124543f9a75SLakshmi Yadlapati 125ac106bf6SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::link, 126b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 127b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 128ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 129b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 130*253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 131*253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices", BMCWEB_REDFISH_SYSTEM_URI_NAME); 132ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device Collection"; 133ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 134b38fa2abSLakshmi Yadlapati 13570c4d545SLakshmi Yadlapati pcie_util::getPCIeDeviceList(asyncResp, 13670c4d545SLakshmi Yadlapati nlohmann::json::json_pointer("/Members")); 137b38fa2abSLakshmi Yadlapati } 138b38fa2abSLakshmi Yadlapati 1397e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 140adbe192aSJason M. Bills { 141adbe192aSJason M. Bills /** 142adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 143adbe192aSJason M. Bills */ 14422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 145ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1467e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 147b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 148f5c9f8bdSJason M. Bills } 149f5c9f8bdSJason M. Bills 150a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties( 151a5409991SLakshmi Yadlapati crow::Response& res, const boost::system::error_code& ec, 152a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) 153a5409991SLakshmi Yadlapati { 154a5409991SLakshmi Yadlapati if (ec) 155a5409991SLakshmi Yadlapati { 15662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}", 15762598e31SEd Tanous ec.value()); 158a5409991SLakshmi Yadlapati messages::internalError(res); 159a5409991SLakshmi Yadlapati return; 160a5409991SLakshmi Yadlapati } 161a5409991SLakshmi Yadlapati std::string generation; 162a5409991SLakshmi Yadlapati size_t lanes = 0; 163a5409991SLakshmi Yadlapati std::string slotType; 164a5409991SLakshmi Yadlapati 165a5409991SLakshmi Yadlapati bool success = sdbusplus::unpackPropertiesNoThrow( 166a5409991SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation", 167a5409991SLakshmi Yadlapati generation, "Lanes", lanes, "SlotType", slotType); 168a5409991SLakshmi Yadlapati 169a5409991SLakshmi Yadlapati if (!success) 170a5409991SLakshmi Yadlapati { 171a5409991SLakshmi Yadlapati messages::internalError(res); 172a5409991SLakshmi Yadlapati return; 173a5409991SLakshmi Yadlapati } 174a5409991SLakshmi Yadlapati 175a5409991SLakshmi Yadlapati std::optional<pcie_device::PCIeTypes> pcieType = 176a5409991SLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(generation); 177a5409991SLakshmi Yadlapati if (!pcieType) 178a5409991SLakshmi Yadlapati { 17962598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation); 180a5409991SLakshmi Yadlapati } 181a5409991SLakshmi Yadlapati else 182a5409991SLakshmi Yadlapati { 183a5409991SLakshmi Yadlapati if (*pcieType == pcie_device::PCIeTypes::Invalid) 184a5409991SLakshmi Yadlapati { 18562598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation); 186a5409991SLakshmi Yadlapati messages::internalError(res); 187a5409991SLakshmi Yadlapati return; 188a5409991SLakshmi Yadlapati } 189a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["PCIeType"] = *pcieType; 190a5409991SLakshmi Yadlapati } 191a5409991SLakshmi Yadlapati 19282f80326SKonstantin Aladyshev if (lanes != 0) 19382f80326SKonstantin Aladyshev { 194a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["Lanes"] = lanes; 19582f80326SKonstantin Aladyshev } 196a5409991SLakshmi Yadlapati 197a5409991SLakshmi Yadlapati std::optional<pcie_slots::SlotTypes> redfishSlotType = 198a5409991SLakshmi Yadlapati pcie_util::dbusSlotTypeToRf(slotType); 199a5409991SLakshmi Yadlapati if (!redfishSlotType) 200a5409991SLakshmi Yadlapati { 20162598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType); 202a5409991SLakshmi Yadlapati } 203a5409991SLakshmi Yadlapati else 204a5409991SLakshmi Yadlapati { 205a5409991SLakshmi Yadlapati if (*redfishSlotType == pcie_slots::SlotTypes::Invalid) 206a5409991SLakshmi Yadlapati { 20762598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType); 208a5409991SLakshmi Yadlapati messages::internalError(res); 209a5409991SLakshmi Yadlapati return; 210a5409991SLakshmi Yadlapati } 211a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["SlotType"] = *redfishSlotType; 212a5409991SLakshmi Yadlapati } 213a5409991SLakshmi Yadlapati } 214a5409991SLakshmi Yadlapati 215a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath( 216a5409991SLakshmi Yadlapati const std::string& pcieDevicePath, 217a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 218a5409991SLakshmi Yadlapati std::function<void(const std::string& pcieDeviceSlot)>&& callback) 219a5409991SLakshmi Yadlapati { 220a5409991SLakshmi Yadlapati std::string associationPath = pcieDevicePath + "/contained_by"; 221a5409991SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 222a5409991SLakshmi Yadlapati associationPath, sdbusplus::message::object_path(inventoryPath), 0, 223a5409991SLakshmi Yadlapati pcieSlotInterface, 2248cb2c024SEd Tanous [callback = std::move(callback), asyncResp, pcieDevicePath]( 225a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 226a5409991SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& endpoints) { 227a5409991SLakshmi Yadlapati if (ec) 228a5409991SLakshmi Yadlapati { 229a5409991SLakshmi Yadlapati if (ec.value() == EBADR) 230a5409991SLakshmi Yadlapati { 231a5409991SLakshmi Yadlapati // Missing association is not an error 232a5409991SLakshmi Yadlapati return; 233a5409991SLakshmi Yadlapati } 23462598e31SEd Tanous BMCWEB_LOG_ERROR( 23562598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}", 23662598e31SEd Tanous ec.value()); 237a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 238a5409991SLakshmi Yadlapati return; 239a5409991SLakshmi Yadlapati } 240a5409991SLakshmi Yadlapati if (endpoints.size() > 1) 241a5409991SLakshmi Yadlapati { 24262598e31SEd Tanous BMCWEB_LOG_ERROR( 24362598e31SEd Tanous "PCIeDevice is associated with more than one PCIeSlot: {}", 24462598e31SEd Tanous endpoints.size()); 245a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 246a5409991SLakshmi Yadlapati return; 247a5409991SLakshmi Yadlapati } 248a5409991SLakshmi Yadlapati if (endpoints.empty()) 249a5409991SLakshmi Yadlapati { 250a5409991SLakshmi Yadlapati // If the device doesn't have an association, return without PCIe 251a5409991SLakshmi Yadlapati // Slot properties 25262598e31SEd Tanous BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot"); 253a5409991SLakshmi Yadlapati return; 254a5409991SLakshmi Yadlapati } 255a5409991SLakshmi Yadlapati callback(endpoints[0]); 256a5409991SLakshmi Yadlapati }); 257a5409991SLakshmi Yadlapati } 258a5409991SLakshmi Yadlapati 259a5409991SLakshmi Yadlapati inline void 260a5409991SLakshmi Yadlapati afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 261a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot, 262a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 263a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) 264a5409991SLakshmi Yadlapati { 265a5409991SLakshmi Yadlapati if (ec || object.empty()) 266a5409991SLakshmi Yadlapati { 26762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}", 26862598e31SEd Tanous ec.value()); 269a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 270a5409991SLakshmi Yadlapati return; 271a5409991SLakshmi Yadlapati } 272a5409991SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 273a5409991SLakshmi Yadlapati *crow::connections::systemBus, object.begin()->first, pcieDeviceSlot, 274a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot", 275a5409991SLakshmi Yadlapati [asyncResp]( 276a5409991SLakshmi Yadlapati const boost::system::error_code& ec2, 277a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) { 278a5409991SLakshmi Yadlapati addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties); 279a5409991SLakshmi Yadlapati }); 280a5409991SLakshmi Yadlapati } 281a5409991SLakshmi Yadlapati 282a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath( 283a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 284a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot) 285a5409991SLakshmi Yadlapati { 286a5409991SLakshmi Yadlapati dbus::utility::getDbusObject( 287a5409991SLakshmi Yadlapati pcieDeviceSlot, pcieSlotInterface, 288a5409991SLakshmi Yadlapati [asyncResp, 289a5409991SLakshmi Yadlapati pcieDeviceSlot](const boost::system::error_code& ec, 290a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 291a5409991SLakshmi Yadlapati afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object); 292a5409991SLakshmi Yadlapati }); 293a5409991SLakshmi Yadlapati } 294a5409991SLakshmi Yadlapati 295ac106bf6SEd Tanous inline void 296e164f1b6SLakshmi Yadlapati getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 297e164f1b6SLakshmi Yadlapati const std::string& pcieDevicePath, 298e164f1b6SLakshmi Yadlapati const std::string& service) 299e164f1b6SLakshmi Yadlapati { 300e164f1b6SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 301e164f1b6SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 302e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 303e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 304e164f1b6SLakshmi Yadlapati if (ec) 305e164f1b6SLakshmi Yadlapati { 306e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 307e164f1b6SLakshmi Yadlapati { 30862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 30962598e31SEd Tanous ec.value()); 310e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 311e164f1b6SLakshmi Yadlapati } 312e164f1b6SLakshmi Yadlapati return; 313e164f1b6SLakshmi Yadlapati } 314e164f1b6SLakshmi Yadlapati 315e164f1b6SLakshmi Yadlapati if (!value) 316e164f1b6SLakshmi Yadlapati { 317e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "Critical"; 318e164f1b6SLakshmi Yadlapati } 319e164f1b6SLakshmi Yadlapati }); 320e164f1b6SLakshmi Yadlapati } 321e164f1b6SLakshmi Yadlapati 322e164f1b6SLakshmi Yadlapati inline void 323ac106bf6SEd Tanous getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 324c6bb3285SLakshmi Yadlapati const std::string& pcieDevicePath, 325c6bb3285SLakshmi Yadlapati const std::string& service) 326c6bb3285SLakshmi Yadlapati { 327c6bb3285SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 328c6bb3285SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 329c6bb3285SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item", "Present", 330a5409991SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, bool value) { 331c6bb3285SLakshmi Yadlapati if (ec) 332c6bb3285SLakshmi Yadlapati { 333c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 334c6bb3285SLakshmi Yadlapati { 33562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State"); 336ac106bf6SEd Tanous messages::internalError(asyncResp->res); 337c6bb3285SLakshmi Yadlapati } 338c6bb3285SLakshmi Yadlapati return; 339c6bb3285SLakshmi Yadlapati } 340c6bb3285SLakshmi Yadlapati 341c6bb3285SLakshmi Yadlapati if (!value) 342c6bb3285SLakshmi Yadlapati { 343ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 344c6bb3285SLakshmi Yadlapati } 345c6bb3285SLakshmi Yadlapati }); 346c6bb3285SLakshmi Yadlapati } 347c6bb3285SLakshmi Yadlapati 348ac106bf6SEd Tanous inline void 349ac106bf6SEd Tanous getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 350913e7732SSunnySrivastava1984 const std::string& pcieDevicePath, 351913e7732SSunnySrivastava1984 const std::string& service) 352913e7732SSunnySrivastava1984 { 353913e7732SSunnySrivastava1984 sdbusplus::asio::getAllProperties( 354913e7732SSunnySrivastava1984 *crow::connections::systemBus, service, pcieDevicePath, 355913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 356ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 357ac106bf6SEd Tanous const boost::system::error_code& ec, 358913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 359913e7732SSunnySrivastava1984 if (ec) 360913e7732SSunnySrivastava1984 { 361913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 362913e7732SSunnySrivastava1984 { 36362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}", 36462598e31SEd Tanous ec.value()); 365ac106bf6SEd Tanous messages::internalError(asyncResp->res); 366913e7732SSunnySrivastava1984 } 367913e7732SSunnySrivastava1984 return; 368913e7732SSunnySrivastava1984 } 369913e7732SSunnySrivastava1984 370913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 371913e7732SSunnySrivastava1984 const std::string* model = nullptr; 372913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 373913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 374913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 375913e7732SSunnySrivastava1984 376913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 377913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 378913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 379913e7732SSunnySrivastava1984 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber); 380913e7732SSunnySrivastava1984 381913e7732SSunnySrivastava1984 if (!success) 382913e7732SSunnySrivastava1984 { 383ac106bf6SEd Tanous messages::internalError(asyncResp->res); 384913e7732SSunnySrivastava1984 return; 385913e7732SSunnySrivastava1984 } 386913e7732SSunnySrivastava1984 387913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 388913e7732SSunnySrivastava1984 { 389ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 390913e7732SSunnySrivastava1984 } 391913e7732SSunnySrivastava1984 if (model != nullptr) 392913e7732SSunnySrivastava1984 { 393ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 394913e7732SSunnySrivastava1984 } 395913e7732SSunnySrivastava1984 396913e7732SSunnySrivastava1984 if (partNumber != nullptr) 397913e7732SSunnySrivastava1984 { 398ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 399913e7732SSunnySrivastava1984 } 400913e7732SSunnySrivastava1984 401913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 402913e7732SSunnySrivastava1984 { 403ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 404913e7732SSunnySrivastava1984 } 405913e7732SSunnySrivastava1984 406913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 407913e7732SSunnySrivastava1984 { 408ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 409913e7732SSunnySrivastava1984 } 410913e7732SSunnySrivastava1984 }); 411913e7732SSunnySrivastava1984 } 412913e7732SSunnySrivastava1984 413543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 414a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 415a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, 416543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 417f5c9f8bdSJason M. Bills { 418d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 419814bf20aSKonstantin Aladyshev const std::string* generationSupported = nullptr; 4209bb0a7feSKonstantin Aladyshev const size_t* lanesInUse = nullptr; 421814bf20aSKonstantin Aladyshev const size_t* maxLanes = nullptr; 422d1bde9e5SKrzysztof Grobelny 423d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 424609ba4c9SEd Tanous dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse", 425609ba4c9SEd Tanous generationInUse, "GenerationSupported", generationSupported, 426609ba4c9SEd Tanous "LanesInUse", lanesInUse, "MaxLanes", maxLanes); 427d1bde9e5SKrzysztof Grobelny 428d1bde9e5SKrzysztof Grobelny if (!success) 429d1bde9e5SKrzysztof Grobelny { 430a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 431d1bde9e5SKrzysztof Grobelny return; 432d1bde9e5SKrzysztof Grobelny } 433d1bde9e5SKrzysztof Grobelny 434d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 435d1bde9e5SKrzysztof Grobelny { 4360ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 437c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 438543f9a75SLakshmi Yadlapati 439d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 440d1bde9e5SKrzysztof Grobelny { 44162598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 44262598e31SEd Tanous *generationInUse); 443cf3b484eSLakshmi Yadlapati } 444cf3b484eSLakshmi Yadlapati else 445cf3b484eSLakshmi Yadlapati { 446cf3b484eSLakshmi Yadlapati if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid) 447cf3b484eSLakshmi Yadlapati { 44862598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 44962598e31SEd Tanous *generationInUse); 450a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 451d1bde9e5SKrzysztof Grobelny return; 452d1bde9e5SKrzysztof Grobelny } 453a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 454d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 455d1bde9e5SKrzysztof Grobelny } 456a9f68bb5STony Lee } 457d1bde9e5SKrzysztof Grobelny 458814bf20aSKonstantin Aladyshev if (generationSupported != nullptr) 459814bf20aSKonstantin Aladyshev { 460814bf20aSKonstantin Aladyshev std::optional<pcie_device::PCIeTypes> redfishGenerationSupported = 461814bf20aSKonstantin Aladyshev pcie_util::redfishPcieGenerationFromDbus(*generationSupported); 462814bf20aSKonstantin Aladyshev 463814bf20aSKonstantin Aladyshev if (!redfishGenerationSupported) 464814bf20aSKonstantin Aladyshev { 46562598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 46662598e31SEd Tanous *generationSupported); 467814bf20aSKonstantin Aladyshev } 468814bf20aSKonstantin Aladyshev else 469814bf20aSKonstantin Aladyshev { 470814bf20aSKonstantin Aladyshev if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid) 471814bf20aSKonstantin Aladyshev { 47262598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 47362598e31SEd Tanous *generationSupported); 474814bf20aSKonstantin Aladyshev messages::internalError(asyncResp->res); 475814bf20aSKonstantin Aladyshev return; 476814bf20aSKonstantin Aladyshev } 477814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] = 478814bf20aSKonstantin Aladyshev *redfishGenerationSupported; 479814bf20aSKonstantin Aladyshev } 480814bf20aSKonstantin Aladyshev } 481814bf20aSKonstantin Aladyshev 482543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 483543f9a75SLakshmi Yadlapati // left as off if it is a default value. 484543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 485543f9a75SLakshmi Yadlapati { 486a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 487543f9a75SLakshmi Yadlapati } 488814bf20aSKonstantin Aladyshev // The default value of MaxLanes is 0, and the field will be 489814bf20aSKonstantin Aladyshev // left as off if it is a default value. 490814bf20aSKonstantin Aladyshev if (maxLanes != nullptr && *maxLanes != 0) 491814bf20aSKonstantin Aladyshev { 492814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes; 493814bf20aSKonstantin Aladyshev } 494543f9a75SLakshmi Yadlapati 495a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 496a5409991SLakshmi Yadlapati boost::urls::format( 497*253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 498*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 499d1bde9e5SKrzysztof Grobelny } 500d1bde9e5SKrzysztof Grobelny 501543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 502ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 503543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 504543f9a75SLakshmi Yadlapati const std::function<void( 505543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 506d1bde9e5SKrzysztof Grobelny { 507543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 508543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 509543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 510ac106bf6SEd Tanous [asyncResp, 511543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 512543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 513543f9a75SLakshmi Yadlapati if (ec) 514543f9a75SLakshmi Yadlapati { 515543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 516543f9a75SLakshmi Yadlapati { 51762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties"); 518ac106bf6SEd Tanous messages::internalError(asyncResp->res); 519543f9a75SLakshmi Yadlapati } 520543f9a75SLakshmi Yadlapati return; 521543f9a75SLakshmi Yadlapati } 522543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 523543f9a75SLakshmi Yadlapati }); 524d1bde9e5SKrzysztof Grobelny } 525d1bde9e5SKrzysztof Grobelny 526543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 527ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 528543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 529543f9a75SLakshmi Yadlapati { 530ac106bf6SEd Tanous asyncResp->res.addHeader( 531543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 532543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 533ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 534*253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 535*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 536*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 537ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 538ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 539ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 540e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 541543f9a75SLakshmi Yadlapati } 5421476687dSEd Tanous 543a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath( 544a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 545a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, const std::string& pcieDevicePath, 546a5409991SLakshmi Yadlapati const std::string& service) 547a5409991SLakshmi Yadlapati { 548a5409991SLakshmi Yadlapati addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 549a5409991SLakshmi Yadlapati getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 550a5409991SLakshmi Yadlapati getPCIeDeviceState(asyncResp, pcieDevicePath, service); 551a5409991SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 552a5409991SLakshmi Yadlapati getPCIeDeviceProperties( 553a5409991SLakshmi Yadlapati asyncResp, pcieDevicePath, service, 554a5409991SLakshmi Yadlapati std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId)); 555a5409991SLakshmi Yadlapati getPCIeDeviceSlotPath( 556a5409991SLakshmi Yadlapati pcieDevicePath, asyncResp, 557a5409991SLakshmi Yadlapati std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp)); 558a5409991SLakshmi Yadlapati } 559a5409991SLakshmi Yadlapati 560ac106bf6SEd Tanous inline void 561ac106bf6SEd Tanous handlePCIeDeviceGet(App& app, const crow::Request& req, 562ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 563543f9a75SLakshmi Yadlapati const std::string& systemName, 564543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 565543f9a75SLakshmi Yadlapati { 566ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 567543f9a75SLakshmi Yadlapati { 568543f9a75SLakshmi Yadlapati return; 569543f9a75SLakshmi Yadlapati } 57025b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 5717f3e84a1SEd Tanous { 5727f3e84a1SEd Tanous // Option currently returns no systems. TBD 5737f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5747f3e84a1SEd Tanous systemName); 5757f3e84a1SEd Tanous return; 5767f3e84a1SEd Tanous } 577*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 578543f9a75SLakshmi Yadlapati { 579ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 580ac106bf6SEd Tanous systemName); 581543f9a75SLakshmi Yadlapati return; 582543f9a75SLakshmi Yadlapati } 583543f9a75SLakshmi Yadlapati 584543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 585ac106bf6SEd Tanous pcieDeviceId, asyncResp, 586a5409991SLakshmi Yadlapati std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId)); 587543f9a75SLakshmi Yadlapati } 588543f9a75SLakshmi Yadlapati 589543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 590543f9a75SLakshmi Yadlapati { 591543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 592543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 593543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 594543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 595dede6a98SJason M. Bills } 596dede6a98SJason M. Bills 59735ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 59835ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 59935ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 60035ad613dSLakshmi Yadlapati { 60135ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 60235ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 60335ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 60435ad613dSLakshmi Yadlapati 60535ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 60635ad613dSLakshmi Yadlapati { 60735ad613dSLakshmi Yadlapati // Check if this function exists by 60835ad613dSLakshmi Yadlapati // looking for a device ID 60989492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 61089492a15SPatrick Williams "DeviceId"; 61135ad613dSLakshmi Yadlapati const std::string* property = nullptr; 61235ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 61335ad613dSLakshmi Yadlapati { 61435ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 61535ad613dSLakshmi Yadlapati { 61635ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 61735ad613dSLakshmi Yadlapati break; 61835ad613dSLakshmi Yadlapati } 61935ad613dSLakshmi Yadlapati } 62035ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 62135ad613dSLakshmi Yadlapati { 62235ad613dSLakshmi Yadlapati continue; 62335ad613dSLakshmi Yadlapati } 62435ad613dSLakshmi Yadlapati 62535ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 626ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 627*253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 628*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 629*253f11b8SEd Tanous std::to_string(functionNum)); 630b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 63135ad613dSLakshmi Yadlapati } 63235ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 63335ad613dSLakshmi Yadlapati } 63435ad613dSLakshmi Yadlapati 63535ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 63635ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 637ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6387f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 63935ad613dSLakshmi Yadlapati { 640ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 64135ad613dSLakshmi Yadlapati { 64235ad613dSLakshmi Yadlapati return; 64335ad613dSLakshmi Yadlapati } 64425b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6457f3e84a1SEd Tanous { 6467f3e84a1SEd Tanous // Option currently returns no systems. TBD 6477f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6487f3e84a1SEd Tanous systemName); 6497f3e84a1SEd Tanous return; 6507f3e84a1SEd Tanous } 65135ad613dSLakshmi Yadlapati 65235ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 653ac106bf6SEd Tanous pcieDeviceId, asyncResp, 654ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 65535ad613dSLakshmi Yadlapati const std::string& service) { 656ac106bf6SEd Tanous asyncResp->res.addHeader( 65735ad613dSLakshmi Yadlapati boost::beast::http::field::link, 65835ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 659ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 66035ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 661ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 662*253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions", 663*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 664ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 665ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 66635ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 66735ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 668ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 669ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 67035ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 671ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 672ac106bf6SEd Tanous pcieDevProperties); 67335ad613dSLakshmi Yadlapati }); 67435ad613dSLakshmi Yadlapati }); 67535ad613dSLakshmi Yadlapati } 67635ad613dSLakshmi Yadlapati 6777e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 6787e860f15SJohn Edward Broadbent { 679dede6a98SJason M. Bills /** 680dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 681dede6a98SJason M. Bills */ 6827e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 6837f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 684ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 685002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 68635ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 6877e860f15SJohn Edward Broadbent } 6887e860f15SJohn Edward Broadbent 689727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 690d5e74b80SMyung Bae uint64_t pcieFunctionId, 691727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 6927e860f15SJohn Edward Broadbent { 693d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 694b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 695b9d36b47SEd Tanous 696b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 697b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 698b9d36b47SEd Tanous { 699b9d36b47SEd Tanous if (property.first == devIDProperty) 700b9d36b47SEd Tanous { 701002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 702727a046cSLakshmi Yadlapati break; 703b9d36b47SEd Tanous } 704b9d36b47SEd Tanous } 705727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 706727a046cSLakshmi Yadlapati } 707727a046cSLakshmi Yadlapati 708727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 709e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 710727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 711f5c9f8bdSJason M. Bills { 712e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 713b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 714f5c9f8bdSJason M. Bills { 715b9d36b47SEd Tanous const std::string* strProperty = 716b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 717dc8cfa66SEd Tanous if (strProperty == nullptr) 718dc8cfa66SEd Tanous { 719dc8cfa66SEd Tanous BMCWEB_LOG_ERROR("Function wasn't a string?"); 720dc8cfa66SEd Tanous continue; 721dc8cfa66SEd Tanous } 722b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 723f5c9f8bdSJason M. Bills { 724727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 725f5c9f8bdSJason M. Bills } 726b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 727f5c9f8bdSJason M. Bills { 728727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 729f5c9f8bdSJason M. Bills } 730727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 731727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 732727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 733b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 734f5c9f8bdSJason M. Bills { 735727a046cSLakshmi Yadlapati if (!strProperty->empty()) 736727a046cSLakshmi Yadlapati { 737727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 738727a046cSLakshmi Yadlapati } 739f5c9f8bdSJason M. Bills } 740b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 741f5c9f8bdSJason M. Bills { 742727a046cSLakshmi Yadlapati if (!strProperty->empty()) 743727a046cSLakshmi Yadlapati { 744727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 745727a046cSLakshmi Yadlapati } 746f5c9f8bdSJason M. Bills } 747b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 748f5c9f8bdSJason M. Bills { 749727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 750f5c9f8bdSJason M. Bills } 751b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 752f5c9f8bdSJason M. Bills { 753727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 754f5c9f8bdSJason M. Bills } 755b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 756b9d36b47SEd Tanous { 757727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 758b9d36b47SEd Tanous } 759002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 760f5c9f8bdSJason M. Bills { 761727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 762b9d36b47SEd Tanous } 763f5c9f8bdSJason M. Bills } 764727a046cSLakshmi Yadlapati } 765727a046cSLakshmi Yadlapati 766727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 767727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 768e14742caSEd Tanous uint64_t pcieFunctionId) 769727a046cSLakshmi Yadlapati { 770727a046cSLakshmi Yadlapati resp.addHeader( 771727a046cSLakshmi Yadlapati boost::beast::http::field::link, 772727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 773727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 774ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 775*253f11b8SEd Tanous "/redfish/v1/Systems/{}/PCIeDevices/{}/PCIeFunctions/{}", 776*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId, 777*253f11b8SEd Tanous std::to_string(pcieFunctionId)); 778727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 779e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 780e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 781*253f11b8SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 782*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/PCIeDevices/{}", 783*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, pcieDeviceId); 784727a046cSLakshmi Yadlapati } 785727a046cSLakshmi Yadlapati 786727a046cSLakshmi Yadlapati inline void 787727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 788ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7897f3e84a1SEd Tanous const std::string& systemName, 790727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 791e14742caSEd Tanous const std::string& pcieFunctionIdStr) 792727a046cSLakshmi Yadlapati { 793ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 794727a046cSLakshmi Yadlapati { 795727a046cSLakshmi Yadlapati return; 796727a046cSLakshmi Yadlapati } 79725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 7987f3e84a1SEd Tanous { 7997f3e84a1SEd Tanous // Option currently returns no systems. TBD 8007f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8017f3e84a1SEd Tanous systemName); 8027f3e84a1SEd Tanous return; 8037f3e84a1SEd Tanous } 804*253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 8057f3e84a1SEd Tanous { 8067f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8077f3e84a1SEd Tanous systemName); 8087f3e84a1SEd Tanous return; 8097f3e84a1SEd Tanous } 810dc8cfa66SEd Tanous std::string_view pcieFunctionIdView = pcieFunctionIdStr; 8117f3e84a1SEd Tanous 812e14742caSEd Tanous uint64_t pcieFunctionId = 0; 813e14742caSEd Tanous std::from_chars_result result = std::from_chars( 814dc8cfa66SEd Tanous pcieFunctionIdView.begin(), pcieFunctionIdView.end(), pcieFunctionId); 815dc8cfa66SEd Tanous if (result.ec != std::errc{} || result.ptr != pcieFunctionIdView.end()) 816e14742caSEd Tanous { 817ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 818e14742caSEd Tanous pcieFunctionIdStr); 819e14742caSEd Tanous return; 820e14742caSEd Tanous } 821727a046cSLakshmi Yadlapati 822ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 823ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 824ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 825727a046cSLakshmi Yadlapati const std::string& service) { 826727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 827ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 828ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 829727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 830ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 831727a046cSLakshmi Yadlapati pcieFunctionId); 832ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 833727a046cSLakshmi Yadlapati pcieDevProperties); 8347e860f15SJohn Edward Broadbent }); 835727a046cSLakshmi Yadlapati }); 836727a046cSLakshmi Yadlapati } 837727a046cSLakshmi Yadlapati 838727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 839727a046cSLakshmi Yadlapati { 840727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8417f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 842727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 843727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 844727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 845f5c9f8bdSJason M. Bills } 846f5c9f8bdSJason M. Bills 847f5c9f8bdSJason M. Bills } // namespace redfish 848