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 { 65*62598e31SEd 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 74*62598e31SEd 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 { 92*62598e31SEd 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 } 1117f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 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 } 118b38fa2abSLakshmi Yadlapati if (systemName != "system") 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"; 130ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 131b38fa2abSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices"; 132ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device Collection"; 133ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 134ac106bf6SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 135ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 136b38fa2abSLakshmi Yadlapati 1379e9325e6SLakshmi Yadlapati pcie_util::getPCIeDeviceList(asyncResp, "Members"); 138b38fa2abSLakshmi Yadlapati } 139b38fa2abSLakshmi Yadlapati 1407e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 141adbe192aSJason M. Bills { 142adbe192aSJason M. Bills /** 143adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 144adbe192aSJason M. Bills */ 14522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 146ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1477e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 148b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 149f5c9f8bdSJason M. Bills } 150f5c9f8bdSJason M. Bills 151a5409991SLakshmi Yadlapati inline void addPCIeSlotProperties( 152a5409991SLakshmi Yadlapati crow::Response& res, const boost::system::error_code& ec, 153a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) 154a5409991SLakshmi Yadlapati { 155a5409991SLakshmi Yadlapati if (ec) 156a5409991SLakshmi Yadlapati { 157*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getAllProperties{}", 158*62598e31SEd Tanous ec.value()); 159a5409991SLakshmi Yadlapati messages::internalError(res); 160a5409991SLakshmi Yadlapati return; 161a5409991SLakshmi Yadlapati } 162a5409991SLakshmi Yadlapati std::string generation; 163a5409991SLakshmi Yadlapati size_t lanes = 0; 164a5409991SLakshmi Yadlapati std::string slotType; 165a5409991SLakshmi Yadlapati 166a5409991SLakshmi Yadlapati bool success = sdbusplus::unpackPropertiesNoThrow( 167a5409991SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation", 168a5409991SLakshmi Yadlapati generation, "Lanes", lanes, "SlotType", slotType); 169a5409991SLakshmi Yadlapati 170a5409991SLakshmi Yadlapati if (!success) 171a5409991SLakshmi Yadlapati { 172a5409991SLakshmi Yadlapati messages::internalError(res); 173a5409991SLakshmi Yadlapati return; 174a5409991SLakshmi Yadlapati } 175a5409991SLakshmi Yadlapati 176a5409991SLakshmi Yadlapati std::optional<pcie_device::PCIeTypes> pcieType = 177a5409991SLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(generation); 178a5409991SLakshmi Yadlapati if (!pcieType) 179a5409991SLakshmi Yadlapati { 180*62598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeType: {}", generation); 181a5409991SLakshmi Yadlapati } 182a5409991SLakshmi Yadlapati else 183a5409991SLakshmi Yadlapati { 184a5409991SLakshmi Yadlapati if (*pcieType == pcie_device::PCIeTypes::Invalid) 185a5409991SLakshmi Yadlapati { 186*62598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeType: {}", generation); 187a5409991SLakshmi Yadlapati messages::internalError(res); 188a5409991SLakshmi Yadlapati return; 189a5409991SLakshmi Yadlapati } 190a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["PCIeType"] = *pcieType; 191a5409991SLakshmi Yadlapati } 192a5409991SLakshmi Yadlapati 19382f80326SKonstantin Aladyshev if (lanes != 0) 19482f80326SKonstantin Aladyshev { 195a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["Lanes"] = lanes; 19682f80326SKonstantin Aladyshev } 197a5409991SLakshmi Yadlapati 198a5409991SLakshmi Yadlapati std::optional<pcie_slots::SlotTypes> redfishSlotType = 199a5409991SLakshmi Yadlapati pcie_util::dbusSlotTypeToRf(slotType); 200a5409991SLakshmi Yadlapati if (!redfishSlotType) 201a5409991SLakshmi Yadlapati { 202*62598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIeSlot Type: {}", slotType); 203a5409991SLakshmi Yadlapati } 204a5409991SLakshmi Yadlapati else 205a5409991SLakshmi Yadlapati { 206a5409991SLakshmi Yadlapati if (*redfishSlotType == pcie_slots::SlotTypes::Invalid) 207a5409991SLakshmi Yadlapati { 208*62598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIeSlot type: {}", slotType); 209a5409991SLakshmi Yadlapati messages::internalError(res); 210a5409991SLakshmi Yadlapati return; 211a5409991SLakshmi Yadlapati } 212a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["SlotType"] = *redfishSlotType; 213a5409991SLakshmi Yadlapati } 214a5409991SLakshmi Yadlapati } 215a5409991SLakshmi Yadlapati 216a5409991SLakshmi Yadlapati inline void getPCIeDeviceSlotPath( 217a5409991SLakshmi Yadlapati const std::string& pcieDevicePath, 218a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 219a5409991SLakshmi Yadlapati std::function<void(const std::string& pcieDeviceSlot)>&& callback) 220a5409991SLakshmi Yadlapati { 221a5409991SLakshmi Yadlapati std::string associationPath = pcieDevicePath + "/contained_by"; 222a5409991SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 223a5409991SLakshmi Yadlapati associationPath, sdbusplus::message::object_path(inventoryPath), 0, 224a5409991SLakshmi Yadlapati pcieSlotInterface, 225a5409991SLakshmi Yadlapati [callback, asyncResp, pcieDevicePath]( 226a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 227a5409991SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& endpoints) { 228a5409991SLakshmi Yadlapati if (ec) 229a5409991SLakshmi Yadlapati { 230a5409991SLakshmi Yadlapati if (ec.value() == EBADR) 231a5409991SLakshmi Yadlapati { 232a5409991SLakshmi Yadlapati // Missing association is not an error 233a5409991SLakshmi Yadlapati return; 234a5409991SLakshmi Yadlapati } 235*62598e31SEd Tanous BMCWEB_LOG_ERROR( 236*62598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths {}", 237*62598e31SEd Tanous ec.value()); 238a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 239a5409991SLakshmi Yadlapati return; 240a5409991SLakshmi Yadlapati } 241a5409991SLakshmi Yadlapati if (endpoints.size() > 1) 242a5409991SLakshmi Yadlapati { 243*62598e31SEd Tanous BMCWEB_LOG_ERROR( 244*62598e31SEd Tanous "PCIeDevice is associated with more than one PCIeSlot: {}", 245*62598e31SEd Tanous endpoints.size()); 246a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 247a5409991SLakshmi Yadlapati return; 248a5409991SLakshmi Yadlapati } 249a5409991SLakshmi Yadlapati if (endpoints.empty()) 250a5409991SLakshmi Yadlapati { 251a5409991SLakshmi Yadlapati // If the device doesn't have an association, return without PCIe 252a5409991SLakshmi Yadlapati // Slot properties 253*62598e31SEd Tanous BMCWEB_LOG_DEBUG("PCIeDevice is not associated with PCIeSlot"); 254a5409991SLakshmi Yadlapati return; 255a5409991SLakshmi Yadlapati } 256a5409991SLakshmi Yadlapati callback(endpoints[0]); 257a5409991SLakshmi Yadlapati }); 258a5409991SLakshmi Yadlapati } 259a5409991SLakshmi Yadlapati 260a5409991SLakshmi Yadlapati inline void 261a5409991SLakshmi Yadlapati afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 262a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot, 263a5409991SLakshmi Yadlapati const boost::system::error_code& ec, 264a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) 265a5409991SLakshmi Yadlapati { 266a5409991SLakshmi Yadlapati if (ec || object.empty()) 267a5409991SLakshmi Yadlapati { 268*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for getDbusObject {}", 269*62598e31SEd Tanous ec.value()); 270a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 271a5409991SLakshmi Yadlapati return; 272a5409991SLakshmi Yadlapati } 273a5409991SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 274a5409991SLakshmi Yadlapati *crow::connections::systemBus, object.begin()->first, pcieDeviceSlot, 275a5409991SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeSlot", 276a5409991SLakshmi Yadlapati [asyncResp]( 277a5409991SLakshmi Yadlapati const boost::system::error_code& ec2, 278a5409991SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieSlotProperties) { 279a5409991SLakshmi Yadlapati addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties); 280a5409991SLakshmi Yadlapati }); 281a5409991SLakshmi Yadlapati } 282a5409991SLakshmi Yadlapati 283a5409991SLakshmi Yadlapati inline void afterGetPCIeDeviceSlotPath( 284a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 285a5409991SLakshmi Yadlapati const std::string& pcieDeviceSlot) 286a5409991SLakshmi Yadlapati { 287a5409991SLakshmi Yadlapati dbus::utility::getDbusObject( 288a5409991SLakshmi Yadlapati pcieDeviceSlot, pcieSlotInterface, 289a5409991SLakshmi Yadlapati [asyncResp, 290a5409991SLakshmi Yadlapati pcieDeviceSlot](const boost::system::error_code& ec, 291a5409991SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 292a5409991SLakshmi Yadlapati afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object); 293a5409991SLakshmi Yadlapati }); 294a5409991SLakshmi Yadlapati } 295a5409991SLakshmi Yadlapati 296ac106bf6SEd Tanous inline void 297e164f1b6SLakshmi Yadlapati getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 298e164f1b6SLakshmi Yadlapati const std::string& pcieDevicePath, 299e164f1b6SLakshmi Yadlapati const std::string& service) 300e164f1b6SLakshmi Yadlapati { 301e164f1b6SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 302e164f1b6SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 303e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 304e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 305e164f1b6SLakshmi Yadlapati if (ec) 306e164f1b6SLakshmi Yadlapati { 307e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 308e164f1b6SLakshmi Yadlapati { 309*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 310*62598e31SEd Tanous ec.value()); 311e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 312e164f1b6SLakshmi Yadlapati } 313e164f1b6SLakshmi Yadlapati return; 314e164f1b6SLakshmi Yadlapati } 315e164f1b6SLakshmi Yadlapati 316e164f1b6SLakshmi Yadlapati if (!value) 317e164f1b6SLakshmi Yadlapati { 318e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "Critical"; 319e164f1b6SLakshmi Yadlapati } 320e164f1b6SLakshmi Yadlapati }); 321e164f1b6SLakshmi Yadlapati } 322e164f1b6SLakshmi Yadlapati 323e164f1b6SLakshmi Yadlapati inline void 324ac106bf6SEd Tanous getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 325c6bb3285SLakshmi Yadlapati const std::string& pcieDevicePath, 326c6bb3285SLakshmi Yadlapati const std::string& service) 327c6bb3285SLakshmi Yadlapati { 328c6bb3285SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 329c6bb3285SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 330c6bb3285SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item", "Present", 331a5409991SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, bool value) { 332c6bb3285SLakshmi Yadlapati if (ec) 333c6bb3285SLakshmi Yadlapati { 334c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 335c6bb3285SLakshmi Yadlapati { 336*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State"); 337ac106bf6SEd Tanous messages::internalError(asyncResp->res); 338c6bb3285SLakshmi Yadlapati } 339c6bb3285SLakshmi Yadlapati return; 340c6bb3285SLakshmi Yadlapati } 341c6bb3285SLakshmi Yadlapati 342c6bb3285SLakshmi Yadlapati if (!value) 343c6bb3285SLakshmi Yadlapati { 344ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 345c6bb3285SLakshmi Yadlapati } 346c6bb3285SLakshmi Yadlapati }); 347c6bb3285SLakshmi Yadlapati } 348c6bb3285SLakshmi Yadlapati 349ac106bf6SEd Tanous inline void 350ac106bf6SEd Tanous getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 351913e7732SSunnySrivastava1984 const std::string& pcieDevicePath, 352913e7732SSunnySrivastava1984 const std::string& service) 353913e7732SSunnySrivastava1984 { 354913e7732SSunnySrivastava1984 sdbusplus::asio::getAllProperties( 355913e7732SSunnySrivastava1984 *crow::connections::systemBus, service, pcieDevicePath, 356913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 357ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 358ac106bf6SEd Tanous const boost::system::error_code& ec, 359913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 360913e7732SSunnySrivastava1984 if (ec) 361913e7732SSunnySrivastava1984 { 362913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 363913e7732SSunnySrivastava1984 { 364*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties{}", 365*62598e31SEd Tanous ec.value()); 366ac106bf6SEd Tanous messages::internalError(asyncResp->res); 367913e7732SSunnySrivastava1984 } 368913e7732SSunnySrivastava1984 return; 369913e7732SSunnySrivastava1984 } 370913e7732SSunnySrivastava1984 371913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 372913e7732SSunnySrivastava1984 const std::string* model = nullptr; 373913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 374913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 375913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 376913e7732SSunnySrivastava1984 377913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 378913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 379913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 380913e7732SSunnySrivastava1984 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber); 381913e7732SSunnySrivastava1984 382913e7732SSunnySrivastava1984 if (!success) 383913e7732SSunnySrivastava1984 { 384ac106bf6SEd Tanous messages::internalError(asyncResp->res); 385913e7732SSunnySrivastava1984 return; 386913e7732SSunnySrivastava1984 } 387913e7732SSunnySrivastava1984 388913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 389913e7732SSunnySrivastava1984 { 390ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 391913e7732SSunnySrivastava1984 } 392913e7732SSunnySrivastava1984 if (model != nullptr) 393913e7732SSunnySrivastava1984 { 394ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 395913e7732SSunnySrivastava1984 } 396913e7732SSunnySrivastava1984 397913e7732SSunnySrivastava1984 if (partNumber != nullptr) 398913e7732SSunnySrivastava1984 { 399ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 400913e7732SSunnySrivastava1984 } 401913e7732SSunnySrivastava1984 402913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 403913e7732SSunnySrivastava1984 { 404ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 405913e7732SSunnySrivastava1984 } 406913e7732SSunnySrivastava1984 407913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 408913e7732SSunnySrivastava1984 { 409ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 410913e7732SSunnySrivastava1984 } 411913e7732SSunnySrivastava1984 }); 412913e7732SSunnySrivastava1984 } 413913e7732SSunnySrivastava1984 414543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 415a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 416a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, 417543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 418f5c9f8bdSJason M. Bills { 419d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 420814bf20aSKonstantin Aladyshev const std::string* generationSupported = nullptr; 4219bb0a7feSKonstantin Aladyshev const size_t* lanesInUse = nullptr; 422814bf20aSKonstantin Aladyshev const size_t* maxLanes = nullptr; 423d1bde9e5SKrzysztof Grobelny 424d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 425609ba4c9SEd Tanous dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "GenerationInUse", 426609ba4c9SEd Tanous generationInUse, "GenerationSupported", generationSupported, 427609ba4c9SEd Tanous "LanesInUse", lanesInUse, "MaxLanes", maxLanes); 428d1bde9e5SKrzysztof Grobelny 429d1bde9e5SKrzysztof Grobelny if (!success) 430d1bde9e5SKrzysztof Grobelny { 431a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 432d1bde9e5SKrzysztof Grobelny return; 433d1bde9e5SKrzysztof Grobelny } 434d1bde9e5SKrzysztof Grobelny 435d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 436d1bde9e5SKrzysztof Grobelny { 4370ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 438c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 439543f9a75SLakshmi Yadlapati 440d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 441d1bde9e5SKrzysztof Grobelny { 442*62598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 443*62598e31SEd Tanous *generationInUse); 444cf3b484eSLakshmi Yadlapati } 445cf3b484eSLakshmi Yadlapati else 446cf3b484eSLakshmi Yadlapati { 447cf3b484eSLakshmi Yadlapati if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid) 448cf3b484eSLakshmi Yadlapati { 449*62598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 450*62598e31SEd Tanous *generationInUse); 451a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 452d1bde9e5SKrzysztof Grobelny return; 453d1bde9e5SKrzysztof Grobelny } 454a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 455d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 456d1bde9e5SKrzysztof Grobelny } 457a9f68bb5STony Lee } 458d1bde9e5SKrzysztof Grobelny 459814bf20aSKonstantin Aladyshev if (generationSupported != nullptr) 460814bf20aSKonstantin Aladyshev { 461814bf20aSKonstantin Aladyshev std::optional<pcie_device::PCIeTypes> redfishGenerationSupported = 462814bf20aSKonstantin Aladyshev pcie_util::redfishPcieGenerationFromDbus(*generationSupported); 463814bf20aSKonstantin Aladyshev 464814bf20aSKonstantin Aladyshev if (!redfishGenerationSupported) 465814bf20aSKonstantin Aladyshev { 466*62598e31SEd Tanous BMCWEB_LOG_WARNING("Unknown PCIe Device Generation: {}", 467*62598e31SEd Tanous *generationSupported); 468814bf20aSKonstantin Aladyshev } 469814bf20aSKonstantin Aladyshev else 470814bf20aSKonstantin Aladyshev { 471814bf20aSKonstantin Aladyshev if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid) 472814bf20aSKonstantin Aladyshev { 473*62598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid PCIe Device Generation: {}", 474*62598e31SEd Tanous *generationSupported); 475814bf20aSKonstantin Aladyshev messages::internalError(asyncResp->res); 476814bf20aSKonstantin Aladyshev return; 477814bf20aSKonstantin Aladyshev } 478814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] = 479814bf20aSKonstantin Aladyshev *redfishGenerationSupported; 480814bf20aSKonstantin Aladyshev } 481814bf20aSKonstantin Aladyshev } 482814bf20aSKonstantin Aladyshev 483543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 484543f9a75SLakshmi Yadlapati // left as off if it is a default value. 485543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 486543f9a75SLakshmi Yadlapati { 487a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 488543f9a75SLakshmi Yadlapati } 489814bf20aSKonstantin Aladyshev // The default value of MaxLanes is 0, and the field will be 490814bf20aSKonstantin Aladyshev // left as off if it is a default value. 491814bf20aSKonstantin Aladyshev if (maxLanes != nullptr && *maxLanes != 0) 492814bf20aSKonstantin Aladyshev { 493814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes; 494814bf20aSKonstantin Aladyshev } 495543f9a75SLakshmi Yadlapati 496a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 497a5409991SLakshmi Yadlapati boost::urls::format( 498ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 499ef4c65b7SEd Tanous pcieDeviceId); 500d1bde9e5SKrzysztof Grobelny } 501d1bde9e5SKrzysztof Grobelny 502543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 503ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 504543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 505543f9a75SLakshmi Yadlapati const std::function<void( 506543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 507d1bde9e5SKrzysztof Grobelny { 508543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 509543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 510543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 511ac106bf6SEd Tanous [asyncResp, 512543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 513543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 514543f9a75SLakshmi Yadlapati if (ec) 515543f9a75SLakshmi Yadlapati { 516543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 517543f9a75SLakshmi Yadlapati { 518*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Properties"); 519ac106bf6SEd Tanous messages::internalError(asyncResp->res); 520543f9a75SLakshmi Yadlapati } 521543f9a75SLakshmi Yadlapati return; 522543f9a75SLakshmi Yadlapati } 523543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 524543f9a75SLakshmi Yadlapati }); 525d1bde9e5SKrzysztof Grobelny } 526d1bde9e5SKrzysztof Grobelny 527543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 528ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 529543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 530543f9a75SLakshmi Yadlapati { 531ac106bf6SEd Tanous asyncResp->res.addHeader( 532543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 533543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 534ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 535ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 536ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", 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 } 5707f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 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 } 577543f9a75SLakshmi Yadlapati if (systemName != "system") 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( 627ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 628ef4c65b7SEd Tanous pcieDeviceId, std::to_string(functionNum)); 629b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 63035ad613dSLakshmi Yadlapati } 63135ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 63235ad613dSLakshmi Yadlapati } 63335ad613dSLakshmi Yadlapati 63435ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 63535ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 636ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6377f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 63835ad613dSLakshmi Yadlapati { 639ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 64035ad613dSLakshmi Yadlapati { 64135ad613dSLakshmi Yadlapati return; 64235ad613dSLakshmi Yadlapati } 6437f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 6447f3e84a1SEd Tanous { 6457f3e84a1SEd Tanous // Option currently returns no systems. TBD 6467f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6477f3e84a1SEd Tanous systemName); 6487f3e84a1SEd Tanous return; 6497f3e84a1SEd Tanous } 65035ad613dSLakshmi Yadlapati 65135ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 652ac106bf6SEd Tanous pcieDeviceId, asyncResp, 653ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 65435ad613dSLakshmi Yadlapati const std::string& service) { 655ac106bf6SEd Tanous asyncResp->res.addHeader( 65635ad613dSLakshmi Yadlapati boost::beast::http::field::link, 65735ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 658ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 65935ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 660ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 661ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 662ef4c65b7SEd Tanous pcieDeviceId); 663ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 664ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 66535ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 66635ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 667ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 668ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 66935ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 670ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 671ac106bf6SEd Tanous pcieDevProperties); 67235ad613dSLakshmi Yadlapati }); 67335ad613dSLakshmi Yadlapati }); 67435ad613dSLakshmi Yadlapati } 67535ad613dSLakshmi Yadlapati 6767e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 6777e860f15SJohn Edward Broadbent { 678dede6a98SJason M. Bills /** 679dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 680dede6a98SJason M. Bills */ 6817e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 6827f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 683ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 684002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 68535ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 6867e860f15SJohn Edward Broadbent } 6877e860f15SJohn Edward Broadbent 688727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 689d5e74b80SMyung Bae uint64_t pcieFunctionId, 690727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 6917e860f15SJohn Edward Broadbent { 692d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 693b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 694b9d36b47SEd Tanous 695b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 696b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 697b9d36b47SEd Tanous { 698b9d36b47SEd Tanous if (property.first == devIDProperty) 699b9d36b47SEd Tanous { 700002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 701727a046cSLakshmi Yadlapati break; 702b9d36b47SEd Tanous } 703b9d36b47SEd Tanous } 704727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 705727a046cSLakshmi Yadlapati } 706727a046cSLakshmi Yadlapati 707727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 708e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 709727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 710f5c9f8bdSJason M. Bills { 711e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 712b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 713f5c9f8bdSJason M. Bills { 714b9d36b47SEd Tanous const std::string* strProperty = 715b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 716727a046cSLakshmi Yadlapati 717b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 718f5c9f8bdSJason M. Bills { 719727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 720f5c9f8bdSJason M. Bills } 721b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 722f5c9f8bdSJason M. Bills { 723727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 724f5c9f8bdSJason M. Bills } 725727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 726727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 727727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 728b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 729f5c9f8bdSJason M. Bills { 730727a046cSLakshmi Yadlapati if (!strProperty->empty()) 731727a046cSLakshmi Yadlapati { 732727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 733727a046cSLakshmi Yadlapati } 734f5c9f8bdSJason M. Bills } 735b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 736f5c9f8bdSJason M. Bills { 737727a046cSLakshmi Yadlapati if (!strProperty->empty()) 738727a046cSLakshmi Yadlapati { 739727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 740727a046cSLakshmi Yadlapati } 741f5c9f8bdSJason M. Bills } 742b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 743f5c9f8bdSJason M. Bills { 744727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 745f5c9f8bdSJason M. Bills } 746b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 747f5c9f8bdSJason M. Bills { 748727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 749f5c9f8bdSJason M. Bills } 750b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 751b9d36b47SEd Tanous { 752727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 753b9d36b47SEd Tanous } 754002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 755f5c9f8bdSJason M. Bills { 756727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 757b9d36b47SEd Tanous } 758f5c9f8bdSJason M. Bills } 759727a046cSLakshmi Yadlapati } 760727a046cSLakshmi Yadlapati 761727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 762727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 763e14742caSEd Tanous uint64_t pcieFunctionId) 764727a046cSLakshmi Yadlapati { 765727a046cSLakshmi Yadlapati resp.addHeader( 766727a046cSLakshmi Yadlapati boost::beast::http::field::link, 767727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 768727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 769ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 770ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 771768a143dSLakshmi Yadlapati pcieDeviceId, std::to_string(pcieFunctionId)); 772727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 773e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 774e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 775ef4c65b7SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format( 776ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 777727a046cSLakshmi Yadlapati } 778727a046cSLakshmi Yadlapati 779727a046cSLakshmi Yadlapati inline void 780727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 781ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7827f3e84a1SEd Tanous const std::string& systemName, 783727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 784e14742caSEd Tanous const std::string& pcieFunctionIdStr) 785727a046cSLakshmi Yadlapati { 786ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 787727a046cSLakshmi Yadlapati { 788727a046cSLakshmi Yadlapati return; 789727a046cSLakshmi Yadlapati } 7907f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 7917f3e84a1SEd Tanous { 7927f3e84a1SEd Tanous // Option currently returns no systems. TBD 7937f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 7947f3e84a1SEd Tanous systemName); 7957f3e84a1SEd Tanous return; 7967f3e84a1SEd Tanous } 7977f3e84a1SEd Tanous if (systemName != "system") 7987f3e84a1SEd Tanous { 7997f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8007f3e84a1SEd Tanous systemName); 8017f3e84a1SEd Tanous return; 8027f3e84a1SEd Tanous } 8037f3e84a1SEd Tanous 804e14742caSEd Tanous uint64_t pcieFunctionId = 0; 805e14742caSEd Tanous std::from_chars_result result = std::from_chars( 806e14742caSEd Tanous &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId); 807e14742caSEd Tanous if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end()) 808e14742caSEd Tanous { 809ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 810e14742caSEd Tanous pcieFunctionIdStr); 811e14742caSEd Tanous return; 812e14742caSEd Tanous } 813727a046cSLakshmi Yadlapati 814ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 815ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 816ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 817727a046cSLakshmi Yadlapati const std::string& service) { 818727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 819ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 820ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 821727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 822ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 823727a046cSLakshmi Yadlapati pcieFunctionId); 824ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 825727a046cSLakshmi Yadlapati pcieDevProperties); 8267e860f15SJohn Edward Broadbent }); 827727a046cSLakshmi Yadlapati }); 828727a046cSLakshmi Yadlapati } 829727a046cSLakshmi Yadlapati 830727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 831727a046cSLakshmi Yadlapati { 832727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8337f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 834727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 835727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 836727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 837f5c9f8bdSJason M. Bills } 838f5c9f8bdSJason M. Bills 839f5c9f8bdSJason M. Bills } // namespace redfish 840