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 { 65543f9a75SLakshmi Yadlapati 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 74543f9a75SLakshmi Yadlapati 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 { 92543f9a75SLakshmi Yadlapati 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 { 157a5409991SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for getAllProperties" 158a5409991SLakshmi Yadlapati << 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 { 180a5409991SLakshmi Yadlapati BMCWEB_LOG_WARNING << "Unknown PCIeType: " << generation; 181a5409991SLakshmi Yadlapati } 182a5409991SLakshmi Yadlapati else 183a5409991SLakshmi Yadlapati { 184a5409991SLakshmi Yadlapati if (*pcieType == pcie_device::PCIeTypes::Invalid) 185a5409991SLakshmi Yadlapati { 186a5409991SLakshmi Yadlapati 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 193*82f80326SKonstantin Aladyshev if (lanes != 0) 194*82f80326SKonstantin Aladyshev { 195a5409991SLakshmi Yadlapati res.jsonValue["Slot"]["Lanes"] = lanes; 196*82f80326SKonstantin Aladyshev } 197a5409991SLakshmi Yadlapati 198a5409991SLakshmi Yadlapati std::optional<pcie_slots::SlotTypes> redfishSlotType = 199a5409991SLakshmi Yadlapati pcie_util::dbusSlotTypeToRf(slotType); 200a5409991SLakshmi Yadlapati if (!redfishSlotType) 201a5409991SLakshmi Yadlapati { 202a5409991SLakshmi Yadlapati BMCWEB_LOG_WARNING << "Unknown PCIeSlot Type: " << slotType; 203a5409991SLakshmi Yadlapati } 204a5409991SLakshmi Yadlapati else 205a5409991SLakshmi Yadlapati { 206a5409991SLakshmi Yadlapati if (*redfishSlotType == pcie_slots::SlotTypes::Invalid) 207a5409991SLakshmi Yadlapati { 208a5409991SLakshmi Yadlapati 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 } 235a5409991SLakshmi Yadlapati BMCWEB_LOG_ERROR 236a5409991SLakshmi Yadlapati << "DBUS response error for getAssociatedSubTreePaths " 237a5409991SLakshmi Yadlapati << ec.value(); 238a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 239a5409991SLakshmi Yadlapati return; 240a5409991SLakshmi Yadlapati } 241a5409991SLakshmi Yadlapati if (endpoints.size() > 1) 242a5409991SLakshmi Yadlapati { 243a5409991SLakshmi Yadlapati BMCWEB_LOG_ERROR 244a5409991SLakshmi Yadlapati << "PCIeDevice is associated with more than one PCIeSlot: " 245a5409991SLakshmi Yadlapati << 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 253a5409991SLakshmi Yadlapati 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 { 268a5409991SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for getDbusObject " 269a5409991SLakshmi Yadlapati << 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 { 309e164f1b6SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Health " 310e164f1b6SLakshmi Yadlapati << 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 { 336c6bb3285SLakshmi Yadlapati 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 { 364913e7732SSunnySrivastava1984 BMCWEB_LOG_ERROR << "DBUS response error for Properties" 365913e7732SSunnySrivastava1984 << 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* deviceType = nullptr; 420d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 4219bb0a7feSKonstantin Aladyshev const size_t* lanesInUse = nullptr; 422d1bde9e5SKrzysztof Grobelny 423d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 424543f9a75SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType", 425543f9a75SLakshmi Yadlapati deviceType, "GenerationInUse", generationInUse, "LanesInUse", 426bad2c4a9SLakshmi Yadlapati lanesInUse); 427d1bde9e5SKrzysztof Grobelny 428d1bde9e5SKrzysztof Grobelny if (!success) 429d1bde9e5SKrzysztof Grobelny { 430a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 431d1bde9e5SKrzysztof Grobelny return; 432d1bde9e5SKrzysztof Grobelny } 433d1bde9e5SKrzysztof Grobelny 434543f9a75SLakshmi Yadlapati if (deviceType != nullptr && !deviceType->empty()) 435703f6741SMyung Bae { 436a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType; 437703f6741SMyung Bae } 438703f6741SMyung Bae 439d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 440d1bde9e5SKrzysztof Grobelny { 4410ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 442c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 443543f9a75SLakshmi Yadlapati 444d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 445d1bde9e5SKrzysztof Grobelny { 446cf3b484eSLakshmi Yadlapati BMCWEB_LOG_WARNING << "Unknown PCIe Device Generation: " 447cf3b484eSLakshmi Yadlapati << *generationInUse; 448cf3b484eSLakshmi Yadlapati } 449cf3b484eSLakshmi Yadlapati else 450cf3b484eSLakshmi Yadlapati { 451cf3b484eSLakshmi Yadlapati if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid) 452cf3b484eSLakshmi Yadlapati { 453cf3b484eSLakshmi Yadlapati BMCWEB_LOG_ERROR << "Invalid PCIe Device Generation: " 454cf3b484eSLakshmi Yadlapati << *generationInUse; 455a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 456d1bde9e5SKrzysztof Grobelny return; 457d1bde9e5SKrzysztof Grobelny } 458a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 459d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 460d1bde9e5SKrzysztof Grobelny } 461a9f68bb5STony Lee } 462d1bde9e5SKrzysztof Grobelny 463543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 464543f9a75SLakshmi Yadlapati // left as off if it is a default value. 465543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 466543f9a75SLakshmi Yadlapati { 467a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 468543f9a75SLakshmi Yadlapati } 469543f9a75SLakshmi Yadlapati 470a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 471a5409991SLakshmi Yadlapati boost::urls::format( 472ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 473ef4c65b7SEd Tanous pcieDeviceId); 474d1bde9e5SKrzysztof Grobelny } 475d1bde9e5SKrzysztof Grobelny 476543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 477ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 478543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 479543f9a75SLakshmi Yadlapati const std::function<void( 480543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 481d1bde9e5SKrzysztof Grobelny { 482543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 483543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 484543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 485ac106bf6SEd Tanous [asyncResp, 486543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 487543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 488543f9a75SLakshmi Yadlapati if (ec) 489543f9a75SLakshmi Yadlapati { 490543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 491543f9a75SLakshmi Yadlapati { 492543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 493ac106bf6SEd Tanous messages::internalError(asyncResp->res); 494543f9a75SLakshmi Yadlapati } 495543f9a75SLakshmi Yadlapati return; 496543f9a75SLakshmi Yadlapati } 497543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 498543f9a75SLakshmi Yadlapati }); 499d1bde9e5SKrzysztof Grobelny } 500d1bde9e5SKrzysztof Grobelny 501543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 502ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 503543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 504543f9a75SLakshmi Yadlapati { 505ac106bf6SEd Tanous asyncResp->res.addHeader( 506543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 507543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 508ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 509ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 510ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 511ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 512ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 513ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 514e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 515543f9a75SLakshmi Yadlapati } 5161476687dSEd Tanous 517a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath( 518a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 519a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, const std::string& pcieDevicePath, 520a5409991SLakshmi Yadlapati const std::string& service) 521a5409991SLakshmi Yadlapati { 522a5409991SLakshmi Yadlapati addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 523a5409991SLakshmi Yadlapati getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 524a5409991SLakshmi Yadlapati getPCIeDeviceState(asyncResp, pcieDevicePath, service); 525a5409991SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 526a5409991SLakshmi Yadlapati getPCIeDeviceProperties( 527a5409991SLakshmi Yadlapati asyncResp, pcieDevicePath, service, 528a5409991SLakshmi Yadlapati std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId)); 529a5409991SLakshmi Yadlapati getPCIeDeviceSlotPath( 530a5409991SLakshmi Yadlapati pcieDevicePath, asyncResp, 531a5409991SLakshmi Yadlapati std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp)); 532a5409991SLakshmi Yadlapati } 533a5409991SLakshmi Yadlapati 534ac106bf6SEd Tanous inline void 535ac106bf6SEd Tanous handlePCIeDeviceGet(App& app, const crow::Request& req, 536ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 537543f9a75SLakshmi Yadlapati const std::string& systemName, 538543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 539543f9a75SLakshmi Yadlapati { 540ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 541543f9a75SLakshmi Yadlapati { 542543f9a75SLakshmi Yadlapati return; 543543f9a75SLakshmi Yadlapati } 5447f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 5457f3e84a1SEd Tanous { 5467f3e84a1SEd Tanous // Option currently returns no systems. TBD 5477f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5487f3e84a1SEd Tanous systemName); 5497f3e84a1SEd Tanous return; 5507f3e84a1SEd Tanous } 551543f9a75SLakshmi Yadlapati if (systemName != "system") 552543f9a75SLakshmi Yadlapati { 553ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 554ac106bf6SEd Tanous systemName); 555543f9a75SLakshmi Yadlapati return; 556543f9a75SLakshmi Yadlapati } 557543f9a75SLakshmi Yadlapati 558543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 559ac106bf6SEd Tanous pcieDeviceId, asyncResp, 560a5409991SLakshmi Yadlapati std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId)); 561543f9a75SLakshmi Yadlapati } 562543f9a75SLakshmi Yadlapati 563543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 564543f9a75SLakshmi Yadlapati { 565543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 566543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 567543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 568543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 569dede6a98SJason M. Bills } 570dede6a98SJason M. Bills 57135ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 57235ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 57335ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 57435ad613dSLakshmi Yadlapati { 57535ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 57635ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 57735ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 57835ad613dSLakshmi Yadlapati 57935ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 58035ad613dSLakshmi Yadlapati { 58135ad613dSLakshmi Yadlapati // Check if this function exists by 58235ad613dSLakshmi Yadlapati // looking for a device ID 58389492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 58489492a15SPatrick Williams "DeviceId"; 58535ad613dSLakshmi Yadlapati const std::string* property = nullptr; 58635ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 58735ad613dSLakshmi Yadlapati { 58835ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 58935ad613dSLakshmi Yadlapati { 59035ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 59135ad613dSLakshmi Yadlapati break; 59235ad613dSLakshmi Yadlapati } 59335ad613dSLakshmi Yadlapati } 59435ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 59535ad613dSLakshmi Yadlapati { 59635ad613dSLakshmi Yadlapati continue; 59735ad613dSLakshmi Yadlapati } 59835ad613dSLakshmi Yadlapati 59935ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 600ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 601ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 602ef4c65b7SEd Tanous pcieDeviceId, std::to_string(functionNum)); 603b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 60435ad613dSLakshmi Yadlapati } 60535ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 60635ad613dSLakshmi Yadlapati } 60735ad613dSLakshmi Yadlapati 60835ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 60935ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 610ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6117f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 61235ad613dSLakshmi Yadlapati { 613ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 61435ad613dSLakshmi Yadlapati { 61535ad613dSLakshmi Yadlapati return; 61635ad613dSLakshmi Yadlapati } 6177f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 6187f3e84a1SEd Tanous { 6197f3e84a1SEd Tanous // Option currently returns no systems. TBD 6207f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6217f3e84a1SEd Tanous systemName); 6227f3e84a1SEd Tanous return; 6237f3e84a1SEd Tanous } 62435ad613dSLakshmi Yadlapati 62535ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 626ac106bf6SEd Tanous pcieDeviceId, asyncResp, 627ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 62835ad613dSLakshmi Yadlapati const std::string& service) { 629ac106bf6SEd Tanous asyncResp->res.addHeader( 63035ad613dSLakshmi Yadlapati boost::beast::http::field::link, 63135ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 632ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 63335ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 634ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 635ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 636ef4c65b7SEd Tanous pcieDeviceId); 637ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 638ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 63935ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 64035ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 641ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 642ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 64335ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 644ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 645ac106bf6SEd Tanous pcieDevProperties); 64635ad613dSLakshmi Yadlapati }); 64735ad613dSLakshmi Yadlapati }); 64835ad613dSLakshmi Yadlapati } 64935ad613dSLakshmi Yadlapati 6507e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 6517e860f15SJohn Edward Broadbent { 652dede6a98SJason M. Bills /** 653dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 654dede6a98SJason M. Bills */ 6557e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 6567f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 657ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 658002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 65935ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 6607e860f15SJohn Edward Broadbent } 6617e860f15SJohn Edward Broadbent 662727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 663d5e74b80SMyung Bae uint64_t pcieFunctionId, 664727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 6657e860f15SJohn Edward Broadbent { 666d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 667b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 668b9d36b47SEd Tanous 669b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 670b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 671b9d36b47SEd Tanous { 672b9d36b47SEd Tanous if (property.first == devIDProperty) 673b9d36b47SEd Tanous { 674002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 675727a046cSLakshmi Yadlapati break; 676b9d36b47SEd Tanous } 677b9d36b47SEd Tanous } 678727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 679727a046cSLakshmi Yadlapati } 680727a046cSLakshmi Yadlapati 681727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 682e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 683727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 684f5c9f8bdSJason M. Bills { 685e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 686b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 687f5c9f8bdSJason M. Bills { 688b9d36b47SEd Tanous const std::string* strProperty = 689b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 690727a046cSLakshmi Yadlapati 691b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 692f5c9f8bdSJason M. Bills { 693727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 694f5c9f8bdSJason M. Bills } 695b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 696f5c9f8bdSJason M. Bills { 697727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 698f5c9f8bdSJason M. Bills } 699727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 700727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 701727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 702b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 703f5c9f8bdSJason M. Bills { 704727a046cSLakshmi Yadlapati if (!strProperty->empty()) 705727a046cSLakshmi Yadlapati { 706727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 707727a046cSLakshmi Yadlapati } 708f5c9f8bdSJason M. Bills } 709b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 710f5c9f8bdSJason M. Bills { 711727a046cSLakshmi Yadlapati if (!strProperty->empty()) 712727a046cSLakshmi Yadlapati { 713727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 714727a046cSLakshmi Yadlapati } 715f5c9f8bdSJason M. Bills } 716b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 717f5c9f8bdSJason M. Bills { 718727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 719f5c9f8bdSJason M. Bills } 720b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 721f5c9f8bdSJason M. Bills { 722727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 723f5c9f8bdSJason M. Bills } 724b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 725b9d36b47SEd Tanous { 726727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 727b9d36b47SEd Tanous } 728002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 729f5c9f8bdSJason M. Bills { 730727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 731b9d36b47SEd Tanous } 732f5c9f8bdSJason M. Bills } 733727a046cSLakshmi Yadlapati } 734727a046cSLakshmi Yadlapati 735727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 736727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 737e14742caSEd Tanous uint64_t pcieFunctionId) 738727a046cSLakshmi Yadlapati { 739727a046cSLakshmi Yadlapati resp.addHeader( 740727a046cSLakshmi Yadlapati boost::beast::http::field::link, 741727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 742727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 743ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 744ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 745768a143dSLakshmi Yadlapati pcieDeviceId, std::to_string(pcieFunctionId)); 746727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 747e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 748e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 749ef4c65b7SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format( 750ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 751727a046cSLakshmi Yadlapati } 752727a046cSLakshmi Yadlapati 753727a046cSLakshmi Yadlapati inline void 754727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 755ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7567f3e84a1SEd Tanous const std::string& systemName, 757727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 758e14742caSEd Tanous const std::string& pcieFunctionIdStr) 759727a046cSLakshmi Yadlapati { 760ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 761727a046cSLakshmi Yadlapati { 762727a046cSLakshmi Yadlapati return; 763727a046cSLakshmi Yadlapati } 7647f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 7657f3e84a1SEd Tanous { 7667f3e84a1SEd Tanous // Option currently returns no systems. TBD 7677f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 7687f3e84a1SEd Tanous systemName); 7697f3e84a1SEd Tanous return; 7707f3e84a1SEd Tanous } 7717f3e84a1SEd Tanous if (systemName != "system") 7727f3e84a1SEd Tanous { 7737f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 7747f3e84a1SEd Tanous systemName); 7757f3e84a1SEd Tanous return; 7767f3e84a1SEd Tanous } 7777f3e84a1SEd Tanous 778e14742caSEd Tanous uint64_t pcieFunctionId = 0; 779e14742caSEd Tanous std::from_chars_result result = std::from_chars( 780e14742caSEd Tanous &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId); 781e14742caSEd Tanous if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end()) 782e14742caSEd Tanous { 783ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 784e14742caSEd Tanous pcieFunctionIdStr); 785e14742caSEd Tanous return; 786e14742caSEd Tanous } 787727a046cSLakshmi Yadlapati 788ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 789ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 790ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 791727a046cSLakshmi Yadlapati const std::string& service) { 792727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 793ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 794ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 795727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 796ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 797727a046cSLakshmi Yadlapati pcieFunctionId); 798ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 799727a046cSLakshmi Yadlapati pcieDevProperties); 8007e860f15SJohn Edward Broadbent }); 801727a046cSLakshmi Yadlapati }); 802727a046cSLakshmi Yadlapati } 803727a046cSLakshmi Yadlapati 804727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 805727a046cSLakshmi Yadlapati { 806727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8077f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 808727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 809727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 810727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 811f5c9f8bdSJason M. Bills } 812f5c9f8bdSJason M. Bills 813f5c9f8bdSJason M. Bills } // namespace redfish 814