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 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 { 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; 421*814bf20aSKonstantin Aladyshev const std::string* generationSupported = nullptr; 4229bb0a7feSKonstantin Aladyshev const size_t* lanesInUse = nullptr; 423*814bf20aSKonstantin Aladyshev const size_t* maxLanes = nullptr; 424d1bde9e5SKrzysztof Grobelny 425d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 426543f9a75SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType", 427*814bf20aSKonstantin Aladyshev deviceType, "GenerationInUse", generationInUse, "GenerationSupported", 428*814bf20aSKonstantin Aladyshev generationSupported, "LanesInUse", lanesInUse, "MaxLanes", maxLanes); 429d1bde9e5SKrzysztof Grobelny 430d1bde9e5SKrzysztof Grobelny if (!success) 431d1bde9e5SKrzysztof Grobelny { 432a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 433d1bde9e5SKrzysztof Grobelny return; 434d1bde9e5SKrzysztof Grobelny } 435d1bde9e5SKrzysztof Grobelny 436543f9a75SLakshmi Yadlapati if (deviceType != nullptr && !deviceType->empty()) 437703f6741SMyung Bae { 438a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType; 439703f6741SMyung Bae } 440703f6741SMyung Bae 441d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 442d1bde9e5SKrzysztof Grobelny { 4430ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 444c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 445543f9a75SLakshmi Yadlapati 446d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 447d1bde9e5SKrzysztof Grobelny { 448cf3b484eSLakshmi Yadlapati BMCWEB_LOG_WARNING << "Unknown PCIe Device Generation: " 449cf3b484eSLakshmi Yadlapati << *generationInUse; 450cf3b484eSLakshmi Yadlapati } 451cf3b484eSLakshmi Yadlapati else 452cf3b484eSLakshmi Yadlapati { 453cf3b484eSLakshmi Yadlapati if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid) 454cf3b484eSLakshmi Yadlapati { 455cf3b484eSLakshmi Yadlapati BMCWEB_LOG_ERROR << "Invalid PCIe Device Generation: " 456cf3b484eSLakshmi Yadlapati << *generationInUse; 457a5409991SLakshmi Yadlapati messages::internalError(asyncResp->res); 458d1bde9e5SKrzysztof Grobelny return; 459d1bde9e5SKrzysztof Grobelny } 460a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] = 461d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 462d1bde9e5SKrzysztof Grobelny } 463a9f68bb5STony Lee } 464d1bde9e5SKrzysztof Grobelny 465*814bf20aSKonstantin Aladyshev if (generationSupported != nullptr) 466*814bf20aSKonstantin Aladyshev { 467*814bf20aSKonstantin Aladyshev std::optional<pcie_device::PCIeTypes> redfishGenerationSupported = 468*814bf20aSKonstantin Aladyshev pcie_util::redfishPcieGenerationFromDbus(*generationSupported); 469*814bf20aSKonstantin Aladyshev 470*814bf20aSKonstantin Aladyshev if (!redfishGenerationSupported) 471*814bf20aSKonstantin Aladyshev { 472*814bf20aSKonstantin Aladyshev BMCWEB_LOG_WARNING << "Unknown PCIe Device Generation: " 473*814bf20aSKonstantin Aladyshev << *generationSupported; 474*814bf20aSKonstantin Aladyshev } 475*814bf20aSKonstantin Aladyshev else 476*814bf20aSKonstantin Aladyshev { 477*814bf20aSKonstantin Aladyshev if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid) 478*814bf20aSKonstantin Aladyshev { 479*814bf20aSKonstantin Aladyshev BMCWEB_LOG_ERROR << "Invalid PCIe Device Generation: " 480*814bf20aSKonstantin Aladyshev << *generationSupported; 481*814bf20aSKonstantin Aladyshev messages::internalError(asyncResp->res); 482*814bf20aSKonstantin Aladyshev return; 483*814bf20aSKonstantin Aladyshev } 484*814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] = 485*814bf20aSKonstantin Aladyshev *redfishGenerationSupported; 486*814bf20aSKonstantin Aladyshev } 487*814bf20aSKonstantin Aladyshev } 488*814bf20aSKonstantin Aladyshev 489543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 490543f9a75SLakshmi Yadlapati // left as off if it is a default value. 491543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 492543f9a75SLakshmi Yadlapati { 493a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 494543f9a75SLakshmi Yadlapati } 495*814bf20aSKonstantin Aladyshev // The default value of MaxLanes is 0, and the field will be 496*814bf20aSKonstantin Aladyshev // left as off if it is a default value. 497*814bf20aSKonstantin Aladyshev if (maxLanes != nullptr && *maxLanes != 0) 498*814bf20aSKonstantin Aladyshev { 499*814bf20aSKonstantin Aladyshev asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes; 500*814bf20aSKonstantin Aladyshev } 501543f9a75SLakshmi Yadlapati 502a5409991SLakshmi Yadlapati asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] = 503a5409991SLakshmi Yadlapati boost::urls::format( 504ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 505ef4c65b7SEd Tanous pcieDeviceId); 506d1bde9e5SKrzysztof Grobelny } 507d1bde9e5SKrzysztof Grobelny 508543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 509ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 510543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 511543f9a75SLakshmi Yadlapati const std::function<void( 512543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 513d1bde9e5SKrzysztof Grobelny { 514543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 515543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 516543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 517ac106bf6SEd Tanous [asyncResp, 518543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 519543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 520543f9a75SLakshmi Yadlapati if (ec) 521543f9a75SLakshmi Yadlapati { 522543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 523543f9a75SLakshmi Yadlapati { 524543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 525ac106bf6SEd Tanous messages::internalError(asyncResp->res); 526543f9a75SLakshmi Yadlapati } 527543f9a75SLakshmi Yadlapati return; 528543f9a75SLakshmi Yadlapati } 529543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 530543f9a75SLakshmi Yadlapati }); 531d1bde9e5SKrzysztof Grobelny } 532d1bde9e5SKrzysztof Grobelny 533543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 534ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 535543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 536543f9a75SLakshmi Yadlapati { 537ac106bf6SEd Tanous asyncResp->res.addHeader( 538543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 539543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 540ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 541ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 542ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 543ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 544ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 545ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 546e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 547543f9a75SLakshmi Yadlapati } 5481476687dSEd Tanous 549a5409991SLakshmi Yadlapati inline void afterGetValidPcieDevicePath( 550a5409991SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 551a5409991SLakshmi Yadlapati const std::string& pcieDeviceId, const std::string& pcieDevicePath, 552a5409991SLakshmi Yadlapati const std::string& service) 553a5409991SLakshmi Yadlapati { 554a5409991SLakshmi Yadlapati addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 555a5409991SLakshmi Yadlapati getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 556a5409991SLakshmi Yadlapati getPCIeDeviceState(asyncResp, pcieDevicePath, service); 557a5409991SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 558a5409991SLakshmi Yadlapati getPCIeDeviceProperties( 559a5409991SLakshmi Yadlapati asyncResp, pcieDevicePath, service, 560a5409991SLakshmi Yadlapati std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId)); 561a5409991SLakshmi Yadlapati getPCIeDeviceSlotPath( 562a5409991SLakshmi Yadlapati pcieDevicePath, asyncResp, 563a5409991SLakshmi Yadlapati std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp)); 564a5409991SLakshmi Yadlapati } 565a5409991SLakshmi Yadlapati 566ac106bf6SEd Tanous inline void 567ac106bf6SEd Tanous handlePCIeDeviceGet(App& app, const crow::Request& req, 568ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 569543f9a75SLakshmi Yadlapati const std::string& systemName, 570543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 571543f9a75SLakshmi Yadlapati { 572ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 573543f9a75SLakshmi Yadlapati { 574543f9a75SLakshmi Yadlapati return; 575543f9a75SLakshmi Yadlapati } 5767f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 5777f3e84a1SEd Tanous { 5787f3e84a1SEd Tanous // Option currently returns no systems. TBD 5797f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5807f3e84a1SEd Tanous systemName); 5817f3e84a1SEd Tanous return; 5827f3e84a1SEd Tanous } 583543f9a75SLakshmi Yadlapati if (systemName != "system") 584543f9a75SLakshmi Yadlapati { 585ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 586ac106bf6SEd Tanous systemName); 587543f9a75SLakshmi Yadlapati return; 588543f9a75SLakshmi Yadlapati } 589543f9a75SLakshmi Yadlapati 590543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 591ac106bf6SEd Tanous pcieDeviceId, asyncResp, 592a5409991SLakshmi Yadlapati std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId)); 593543f9a75SLakshmi Yadlapati } 594543f9a75SLakshmi Yadlapati 595543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 596543f9a75SLakshmi Yadlapati { 597543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 598543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 599543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 600543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 601dede6a98SJason M. Bills } 602dede6a98SJason M. Bills 60335ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 60435ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 60535ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 60635ad613dSLakshmi Yadlapati { 60735ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 60835ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 60935ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 61035ad613dSLakshmi Yadlapati 61135ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 61235ad613dSLakshmi Yadlapati { 61335ad613dSLakshmi Yadlapati // Check if this function exists by 61435ad613dSLakshmi Yadlapati // looking for a device ID 61589492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 61689492a15SPatrick Williams "DeviceId"; 61735ad613dSLakshmi Yadlapati const std::string* property = nullptr; 61835ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 61935ad613dSLakshmi Yadlapati { 62035ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 62135ad613dSLakshmi Yadlapati { 62235ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 62335ad613dSLakshmi Yadlapati break; 62435ad613dSLakshmi Yadlapati } 62535ad613dSLakshmi Yadlapati } 62635ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 62735ad613dSLakshmi Yadlapati { 62835ad613dSLakshmi Yadlapati continue; 62935ad613dSLakshmi Yadlapati } 63035ad613dSLakshmi Yadlapati 63135ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 632ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 633ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 634ef4c65b7SEd Tanous pcieDeviceId, std::to_string(functionNum)); 635b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 63635ad613dSLakshmi Yadlapati } 63735ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 63835ad613dSLakshmi Yadlapati } 63935ad613dSLakshmi Yadlapati 64035ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 64135ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 642ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 6437f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 64435ad613dSLakshmi Yadlapati { 645ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 64635ad613dSLakshmi Yadlapati { 64735ad613dSLakshmi Yadlapati return; 64835ad613dSLakshmi Yadlapati } 6497f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 6507f3e84a1SEd Tanous { 6517f3e84a1SEd Tanous // Option currently returns no systems. TBD 6527f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6537f3e84a1SEd Tanous systemName); 6547f3e84a1SEd Tanous return; 6557f3e84a1SEd Tanous } 65635ad613dSLakshmi Yadlapati 65735ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 658ac106bf6SEd Tanous pcieDeviceId, asyncResp, 659ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 66035ad613dSLakshmi Yadlapati const std::string& service) { 661ac106bf6SEd Tanous asyncResp->res.addHeader( 66235ad613dSLakshmi Yadlapati boost::beast::http::field::link, 66335ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 664ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 66535ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 666ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 667ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 668ef4c65b7SEd Tanous pcieDeviceId); 669ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 670ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 67135ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 67235ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 673ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 674ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 67535ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 676ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 677ac106bf6SEd Tanous pcieDevProperties); 67835ad613dSLakshmi Yadlapati }); 67935ad613dSLakshmi Yadlapati }); 68035ad613dSLakshmi Yadlapati } 68135ad613dSLakshmi Yadlapati 6827e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 6837e860f15SJohn Edward Broadbent { 684dede6a98SJason M. Bills /** 685dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 686dede6a98SJason M. Bills */ 6877e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 6887f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 689ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 690002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 69135ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 6927e860f15SJohn Edward Broadbent } 6937e860f15SJohn Edward Broadbent 694727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 695d5e74b80SMyung Bae uint64_t pcieFunctionId, 696727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 6977e860f15SJohn Edward Broadbent { 698d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 699b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 700b9d36b47SEd Tanous 701b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 702b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 703b9d36b47SEd Tanous { 704b9d36b47SEd Tanous if (property.first == devIDProperty) 705b9d36b47SEd Tanous { 706002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 707727a046cSLakshmi Yadlapati break; 708b9d36b47SEd Tanous } 709b9d36b47SEd Tanous } 710727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 711727a046cSLakshmi Yadlapati } 712727a046cSLakshmi Yadlapati 713727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 714e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 715727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 716f5c9f8bdSJason M. Bills { 717e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 718b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 719f5c9f8bdSJason M. Bills { 720b9d36b47SEd Tanous const std::string* strProperty = 721b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 722727a046cSLakshmi Yadlapati 723b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 724f5c9f8bdSJason M. Bills { 725727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 726f5c9f8bdSJason M. Bills } 727b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 728f5c9f8bdSJason M. Bills { 729727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 730f5c9f8bdSJason M. Bills } 731727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 732727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 733727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 734b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 735f5c9f8bdSJason M. Bills { 736727a046cSLakshmi Yadlapati if (!strProperty->empty()) 737727a046cSLakshmi Yadlapati { 738727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 739727a046cSLakshmi Yadlapati } 740f5c9f8bdSJason M. Bills } 741b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 742f5c9f8bdSJason M. Bills { 743727a046cSLakshmi Yadlapati if (!strProperty->empty()) 744727a046cSLakshmi Yadlapati { 745727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 746727a046cSLakshmi Yadlapati } 747f5c9f8bdSJason M. Bills } 748b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 749f5c9f8bdSJason M. Bills { 750727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 751f5c9f8bdSJason M. Bills } 752b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 753f5c9f8bdSJason M. Bills { 754727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 755f5c9f8bdSJason M. Bills } 756b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 757b9d36b47SEd Tanous { 758727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 759b9d36b47SEd Tanous } 760002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 761f5c9f8bdSJason M. Bills { 762727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 763b9d36b47SEd Tanous } 764f5c9f8bdSJason M. Bills } 765727a046cSLakshmi Yadlapati } 766727a046cSLakshmi Yadlapati 767727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 768727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 769e14742caSEd Tanous uint64_t pcieFunctionId) 770727a046cSLakshmi Yadlapati { 771727a046cSLakshmi Yadlapati resp.addHeader( 772727a046cSLakshmi Yadlapati boost::beast::http::field::link, 773727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 774727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 775ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 776ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 777768a143dSLakshmi Yadlapati pcieDeviceId, std::to_string(pcieFunctionId)); 778727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 779e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 780e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 781ef4c65b7SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format( 782ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 783727a046cSLakshmi Yadlapati } 784727a046cSLakshmi Yadlapati 785727a046cSLakshmi Yadlapati inline void 786727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 787ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7887f3e84a1SEd Tanous const std::string& systemName, 789727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 790e14742caSEd Tanous const std::string& pcieFunctionIdStr) 791727a046cSLakshmi Yadlapati { 792ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 793727a046cSLakshmi Yadlapati { 794727a046cSLakshmi Yadlapati return; 795727a046cSLakshmi Yadlapati } 7967f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 7977f3e84a1SEd Tanous { 7987f3e84a1SEd Tanous // Option currently returns no systems. TBD 7997f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8007f3e84a1SEd Tanous systemName); 8017f3e84a1SEd Tanous return; 8027f3e84a1SEd Tanous } 8037f3e84a1SEd Tanous if (systemName != "system") 8047f3e84a1SEd Tanous { 8057f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 8067f3e84a1SEd Tanous systemName); 8077f3e84a1SEd Tanous return; 8087f3e84a1SEd Tanous } 8097f3e84a1SEd Tanous 810e14742caSEd Tanous uint64_t pcieFunctionId = 0; 811e14742caSEd Tanous std::from_chars_result result = std::from_chars( 812e14742caSEd Tanous &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId); 813e14742caSEd Tanous if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end()) 814e14742caSEd Tanous { 815ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 816e14742caSEd Tanous pcieFunctionIdStr); 817e14742caSEd Tanous return; 818e14742caSEd Tanous } 819727a046cSLakshmi Yadlapati 820ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 821ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 822ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 823727a046cSLakshmi Yadlapati const std::string& service) { 824727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 825ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 826ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 827727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 828ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 829727a046cSLakshmi Yadlapati pcieFunctionId); 830ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 831727a046cSLakshmi Yadlapati pcieDevProperties); 8327e860f15SJohn Edward Broadbent }); 833727a046cSLakshmi Yadlapati }); 834727a046cSLakshmi Yadlapati } 835727a046cSLakshmi Yadlapati 836727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 837727a046cSLakshmi Yadlapati { 838727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 8397f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 840727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 841727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 842727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 843f5c9f8bdSJason M. Bills } 844f5c9f8bdSJason M. Bills 845f5c9f8bdSJason M. Bills } // namespace redfish 846