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"}; 38f5c9f8bdSJason M. Bills 39543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath( 40543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 41ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 42543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 43543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 44543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 45543f9a75SLakshmi Yadlapati 46543f9a75SLakshmi Yadlapati { 47543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 48543f9a75SLakshmi Yadlapati { 49543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 50543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 51543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 52543f9a75SLakshmi Yadlapati { 53543f9a75SLakshmi Yadlapati continue; 54543f9a75SLakshmi Yadlapati } 55543f9a75SLakshmi Yadlapati 56543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 57543f9a75SLakshmi Yadlapati pcieDevicePath, {}, 58ac106bf6SEd Tanous [pcieDevicePath, asyncResp, 59543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 60543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 61543f9a75SLakshmi Yadlapati if (ec || object.empty()) 62543f9a75SLakshmi Yadlapati { 63543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error " << ec; 64ac106bf6SEd Tanous messages::internalError(asyncResp->res); 65543f9a75SLakshmi Yadlapati return; 66543f9a75SLakshmi Yadlapati } 67543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 68543f9a75SLakshmi Yadlapati }); 69543f9a75SLakshmi Yadlapati return; 70543f9a75SLakshmi Yadlapati } 71543f9a75SLakshmi Yadlapati 72543f9a75SLakshmi Yadlapati BMCWEB_LOG_WARNING << "PCIe Device not found"; 73ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId); 74543f9a75SLakshmi Yadlapati } 75543f9a75SLakshmi Yadlapati 76543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath( 77543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 78ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 79543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 80543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 81543f9a75SLakshmi Yadlapati { 82543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 8394c3a10bSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 84ac106bf6SEd Tanous [pcieDeviceId, asyncResp, 85543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 86543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 87543f9a75SLakshmi Yadlapati pcieDevicePaths) { 88543f9a75SLakshmi Yadlapati if (ec) 89543f9a75SLakshmi Yadlapati { 90543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec; 91ac106bf6SEd Tanous messages::internalError(asyncResp->res); 92543f9a75SLakshmi Yadlapati return; 93543f9a75SLakshmi Yadlapati } 94ac106bf6SEd Tanous handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths, 95ac106bf6SEd Tanous callback); 96543f9a75SLakshmi Yadlapati return; 97543f9a75SLakshmi Yadlapati }); 98543f9a75SLakshmi Yadlapati } 99543f9a75SLakshmi Yadlapati 100b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet( 101b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 102ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 103b38fa2abSLakshmi Yadlapati const std::string& systemName) 104b38fa2abSLakshmi Yadlapati { 105ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 106b38fa2abSLakshmi Yadlapati { 107b38fa2abSLakshmi Yadlapati return; 108b38fa2abSLakshmi Yadlapati } 1097f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 1107f3e84a1SEd Tanous { 1117f3e84a1SEd Tanous // Option currently returns no systems. TBD 1127f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1137f3e84a1SEd Tanous systemName); 1147f3e84a1SEd Tanous return; 1157f3e84a1SEd Tanous } 116b38fa2abSLakshmi Yadlapati if (systemName != "system") 117b38fa2abSLakshmi Yadlapati { 118ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 119ac106bf6SEd Tanous systemName); 120b38fa2abSLakshmi Yadlapati return; 121b38fa2abSLakshmi Yadlapati } 122543f9a75SLakshmi Yadlapati 123ac106bf6SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::link, 124b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 125b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 126ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 127b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 128ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 129b38fa2abSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices"; 130ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device Collection"; 131ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 132ac106bf6SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 133ac106bf6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 134b38fa2abSLakshmi Yadlapati 135*9e9325e6SLakshmi Yadlapati pcie_util::getPCIeDeviceList(asyncResp, "Members"); 136b38fa2abSLakshmi Yadlapati } 137b38fa2abSLakshmi Yadlapati 1387e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 139adbe192aSJason M. Bills { 140adbe192aSJason M. Bills /** 141adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 142adbe192aSJason M. Bills */ 14322d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 144ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1457e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 146b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 147f5c9f8bdSJason M. Bills } 148f5c9f8bdSJason M. Bills 149ac106bf6SEd Tanous inline void 150e164f1b6SLakshmi Yadlapati getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 151e164f1b6SLakshmi Yadlapati const std::string& pcieDevicePath, 152e164f1b6SLakshmi Yadlapati const std::string& service) 153e164f1b6SLakshmi Yadlapati { 154e164f1b6SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 155e164f1b6SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 156e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 157e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 158e164f1b6SLakshmi Yadlapati if (ec) 159e164f1b6SLakshmi Yadlapati { 160e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 161e164f1b6SLakshmi Yadlapati { 162e164f1b6SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Health " 163e164f1b6SLakshmi Yadlapati << ec.value(); 164e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 165e164f1b6SLakshmi Yadlapati } 166e164f1b6SLakshmi Yadlapati return; 167e164f1b6SLakshmi Yadlapati } 168e164f1b6SLakshmi Yadlapati 169e164f1b6SLakshmi Yadlapati if (!value) 170e164f1b6SLakshmi Yadlapati { 171e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "Critical"; 172e164f1b6SLakshmi Yadlapati } 173e164f1b6SLakshmi Yadlapati }); 174e164f1b6SLakshmi Yadlapati } 175e164f1b6SLakshmi Yadlapati 176e164f1b6SLakshmi Yadlapati inline void 177ac106bf6SEd Tanous getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 178c6bb3285SLakshmi Yadlapati const std::string& pcieDevicePath, 179c6bb3285SLakshmi Yadlapati const std::string& service) 180c6bb3285SLakshmi Yadlapati { 181c6bb3285SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 182c6bb3285SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 183c6bb3285SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item", "Present", 184ac106bf6SEd Tanous [asyncResp](const boost::system::error_code& ec, const bool value) { 185c6bb3285SLakshmi Yadlapati if (ec) 186c6bb3285SLakshmi Yadlapati { 187c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 188c6bb3285SLakshmi Yadlapati { 189c6bb3285SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for State"; 190ac106bf6SEd Tanous messages::internalError(asyncResp->res); 191c6bb3285SLakshmi Yadlapati } 192c6bb3285SLakshmi Yadlapati return; 193c6bb3285SLakshmi Yadlapati } 194c6bb3285SLakshmi Yadlapati 195c6bb3285SLakshmi Yadlapati if (!value) 196c6bb3285SLakshmi Yadlapati { 197ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 198c6bb3285SLakshmi Yadlapati } 199c6bb3285SLakshmi Yadlapati }); 200c6bb3285SLakshmi Yadlapati } 201c6bb3285SLakshmi Yadlapati 202ac106bf6SEd Tanous inline void 203ac106bf6SEd Tanous getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 204913e7732SSunnySrivastava1984 const std::string& pcieDevicePath, 205913e7732SSunnySrivastava1984 const std::string& service) 206913e7732SSunnySrivastava1984 { 207913e7732SSunnySrivastava1984 sdbusplus::asio::getAllProperties( 208913e7732SSunnySrivastava1984 *crow::connections::systemBus, service, pcieDevicePath, 209913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 210ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 211ac106bf6SEd Tanous const boost::system::error_code& ec, 212913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 213913e7732SSunnySrivastava1984 if (ec) 214913e7732SSunnySrivastava1984 { 215913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 216913e7732SSunnySrivastava1984 { 217913e7732SSunnySrivastava1984 BMCWEB_LOG_ERROR << "DBUS response error for Properties" 218913e7732SSunnySrivastava1984 << ec.value(); 219ac106bf6SEd Tanous messages::internalError(asyncResp->res); 220913e7732SSunnySrivastava1984 } 221913e7732SSunnySrivastava1984 return; 222913e7732SSunnySrivastava1984 } 223913e7732SSunnySrivastava1984 224913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 225913e7732SSunnySrivastava1984 const std::string* model = nullptr; 226913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 227913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 228913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 229913e7732SSunnySrivastava1984 230913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 231913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 232913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 233913e7732SSunnySrivastava1984 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber); 234913e7732SSunnySrivastava1984 235913e7732SSunnySrivastava1984 if (!success) 236913e7732SSunnySrivastava1984 { 237ac106bf6SEd Tanous messages::internalError(asyncResp->res); 238913e7732SSunnySrivastava1984 return; 239913e7732SSunnySrivastava1984 } 240913e7732SSunnySrivastava1984 241913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 242913e7732SSunnySrivastava1984 { 243ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 244913e7732SSunnySrivastava1984 } 245913e7732SSunnySrivastava1984 if (model != nullptr) 246913e7732SSunnySrivastava1984 { 247ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 248913e7732SSunnySrivastava1984 } 249913e7732SSunnySrivastava1984 250913e7732SSunnySrivastava1984 if (partNumber != nullptr) 251913e7732SSunnySrivastava1984 { 252ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 253913e7732SSunnySrivastava1984 } 254913e7732SSunnySrivastava1984 255913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 256913e7732SSunnySrivastava1984 { 257ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 258913e7732SSunnySrivastava1984 } 259913e7732SSunnySrivastava1984 260913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 261913e7732SSunnySrivastava1984 { 262ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 263913e7732SSunnySrivastava1984 } 264913e7732SSunnySrivastava1984 }); 265913e7732SSunnySrivastava1984 } 266913e7732SSunnySrivastava1984 267543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 26835ad613dSLakshmi Yadlapati crow::Response& resp, const std::string& pcieDeviceId, 269543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 270f5c9f8bdSJason M. Bills { 271d1bde9e5SKrzysztof Grobelny const std::string* deviceType = nullptr; 272d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 273543f9a75SLakshmi Yadlapati const int64_t* lanesInUse = nullptr; 274d1bde9e5SKrzysztof Grobelny 275d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 276543f9a75SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType", 277543f9a75SLakshmi Yadlapati deviceType, "GenerationInUse", generationInUse, "LanesInUse", 278bad2c4a9SLakshmi Yadlapati lanesInUse); 279d1bde9e5SKrzysztof Grobelny 280d1bde9e5SKrzysztof Grobelny if (!success) 281d1bde9e5SKrzysztof Grobelny { 282543f9a75SLakshmi Yadlapati messages::internalError(resp); 283d1bde9e5SKrzysztof Grobelny return; 284d1bde9e5SKrzysztof Grobelny } 285d1bde9e5SKrzysztof Grobelny 286543f9a75SLakshmi Yadlapati if (deviceType != nullptr && !deviceType->empty()) 287703f6741SMyung Bae { 288543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType; 289703f6741SMyung Bae } 290703f6741SMyung Bae 291d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 292d1bde9e5SKrzysztof Grobelny { 2930ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 294c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 295543f9a75SLakshmi Yadlapati 296d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 297d1bde9e5SKrzysztof Grobelny { 298543f9a75SLakshmi Yadlapati messages::internalError(resp); 299d1bde9e5SKrzysztof Grobelny return; 300d1bde9e5SKrzysztof Grobelny } 3010ec8b83dSEd Tanous if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid) 302d1bde9e5SKrzysztof Grobelny { 303543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["PCIeType"] = 304d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 305d1bde9e5SKrzysztof Grobelny } 306a9f68bb5STony Lee } 307d1bde9e5SKrzysztof Grobelny 308543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 309543f9a75SLakshmi Yadlapati // left as off if it is a default value. 310543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 311543f9a75SLakshmi Yadlapati { 312543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 313543f9a75SLakshmi Yadlapati } 314543f9a75SLakshmi Yadlapati 315ef4c65b7SEd Tanous resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format( 316ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 317ef4c65b7SEd Tanous pcieDeviceId); 318d1bde9e5SKrzysztof Grobelny } 319d1bde9e5SKrzysztof Grobelny 320543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 321ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 322543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 323543f9a75SLakshmi Yadlapati const std::function<void( 324543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 325d1bde9e5SKrzysztof Grobelny { 326543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 327543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 328543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 329ac106bf6SEd Tanous [asyncResp, 330543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 331543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 332543f9a75SLakshmi Yadlapati if (ec) 333543f9a75SLakshmi Yadlapati { 334543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 335543f9a75SLakshmi Yadlapati { 336543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 337ac106bf6SEd Tanous messages::internalError(asyncResp->res); 338543f9a75SLakshmi Yadlapati } 339543f9a75SLakshmi Yadlapati return; 340543f9a75SLakshmi Yadlapati } 341543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 342543f9a75SLakshmi Yadlapati }); 343d1bde9e5SKrzysztof Grobelny } 344d1bde9e5SKrzysztof Grobelny 345543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 346ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 347543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 348543f9a75SLakshmi Yadlapati { 349ac106bf6SEd Tanous asyncResp->res.addHeader( 350543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 351543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 352ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 353ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 354ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 355ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 356ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 357ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 358e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 359543f9a75SLakshmi Yadlapati } 3601476687dSEd Tanous 361ac106bf6SEd Tanous inline void 362ac106bf6SEd Tanous handlePCIeDeviceGet(App& app, const crow::Request& req, 363ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 364543f9a75SLakshmi Yadlapati const std::string& systemName, 365543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 366543f9a75SLakshmi Yadlapati { 367ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 368543f9a75SLakshmi Yadlapati { 369543f9a75SLakshmi Yadlapati return; 370543f9a75SLakshmi Yadlapati } 3717f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 3727f3e84a1SEd Tanous { 3737f3e84a1SEd Tanous // Option currently returns no systems. TBD 3747f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3757f3e84a1SEd Tanous systemName); 3767f3e84a1SEd Tanous return; 3777f3e84a1SEd Tanous } 378543f9a75SLakshmi Yadlapati if (systemName != "system") 379543f9a75SLakshmi Yadlapati { 380ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 381ac106bf6SEd Tanous systemName); 382543f9a75SLakshmi Yadlapati return; 383543f9a75SLakshmi Yadlapati } 384543f9a75SLakshmi Yadlapati 385543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 386ac106bf6SEd Tanous pcieDeviceId, asyncResp, 387ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 388543f9a75SLakshmi Yadlapati const std::string& service) { 389ac106bf6SEd Tanous addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 390ac106bf6SEd Tanous getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 391ac106bf6SEd Tanous getPCIeDeviceState(asyncResp, pcieDevicePath, service); 392e164f1b6SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 393543f9a75SLakshmi Yadlapati getPCIeDeviceProperties( 394ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 395ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 39635ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 397ac106bf6SEd Tanous addPCIeDeviceProperties(asyncResp->res, pcieDeviceId, 39835ad613dSLakshmi Yadlapati pcieDevProperties); 3997e860f15SJohn Edward Broadbent }); 400543f9a75SLakshmi Yadlapati }); 401543f9a75SLakshmi Yadlapati } 402543f9a75SLakshmi Yadlapati 403543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 404543f9a75SLakshmi Yadlapati { 405543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 406543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 407543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 408543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 409dede6a98SJason M. Bills } 410dede6a98SJason M. Bills 41135ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 41235ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 41335ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 41435ad613dSLakshmi Yadlapati { 41535ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 41635ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 41735ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 41835ad613dSLakshmi Yadlapati 41935ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 42035ad613dSLakshmi Yadlapati { 42135ad613dSLakshmi Yadlapati // Check if this function exists by 42235ad613dSLakshmi Yadlapati // looking for a device ID 42389492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 42489492a15SPatrick Williams "DeviceId"; 42535ad613dSLakshmi Yadlapati const std::string* property = nullptr; 42635ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 42735ad613dSLakshmi Yadlapati { 42835ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 42935ad613dSLakshmi Yadlapati { 43035ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 43135ad613dSLakshmi Yadlapati break; 43235ad613dSLakshmi Yadlapati } 43335ad613dSLakshmi Yadlapati } 43435ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 43535ad613dSLakshmi Yadlapati { 43635ad613dSLakshmi Yadlapati continue; 43735ad613dSLakshmi Yadlapati } 43835ad613dSLakshmi Yadlapati 43935ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 440ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 441ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 442ef4c65b7SEd Tanous pcieDeviceId, std::to_string(functionNum)); 443b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 44435ad613dSLakshmi Yadlapati } 44535ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 44635ad613dSLakshmi Yadlapati } 44735ad613dSLakshmi Yadlapati 44835ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 44935ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 450ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4517f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 45235ad613dSLakshmi Yadlapati { 453ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 45435ad613dSLakshmi Yadlapati { 45535ad613dSLakshmi Yadlapati return; 45635ad613dSLakshmi Yadlapati } 4577f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 4587f3e84a1SEd Tanous { 4597f3e84a1SEd Tanous // Option currently returns no systems. TBD 4607f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 4617f3e84a1SEd Tanous systemName); 4627f3e84a1SEd Tanous return; 4637f3e84a1SEd Tanous } 46435ad613dSLakshmi Yadlapati 46535ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 466ac106bf6SEd Tanous pcieDeviceId, asyncResp, 467ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 46835ad613dSLakshmi Yadlapati const std::string& service) { 469ac106bf6SEd Tanous asyncResp->res.addHeader( 47035ad613dSLakshmi Yadlapati boost::beast::http::field::link, 47135ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 472ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 47335ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 474ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 475ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 476ef4c65b7SEd Tanous pcieDeviceId); 477ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 478ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 47935ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 48035ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 481ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 482ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 48335ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 484ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 485ac106bf6SEd Tanous pcieDevProperties); 48635ad613dSLakshmi Yadlapati }); 48735ad613dSLakshmi Yadlapati }); 48835ad613dSLakshmi Yadlapati } 48935ad613dSLakshmi Yadlapati 4907e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 4917e860f15SJohn Edward Broadbent { 492dede6a98SJason M. Bills /** 493dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 494dede6a98SJason M. Bills */ 4957e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 4967f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 497ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 498002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 49935ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 5007e860f15SJohn Edward Broadbent } 5017e860f15SJohn Edward Broadbent 502727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 503d5e74b80SMyung Bae uint64_t pcieFunctionId, 504727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 5057e860f15SJohn Edward Broadbent { 506d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 507b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 508b9d36b47SEd Tanous 509b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 510b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 511b9d36b47SEd Tanous { 512b9d36b47SEd Tanous if (property.first == devIDProperty) 513b9d36b47SEd Tanous { 514002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 515727a046cSLakshmi Yadlapati break; 516b9d36b47SEd Tanous } 517b9d36b47SEd Tanous } 518727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 519727a046cSLakshmi Yadlapati } 520727a046cSLakshmi Yadlapati 521727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 522e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 523727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 524f5c9f8bdSJason M. Bills { 525e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 526b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 527f5c9f8bdSJason M. Bills { 528b9d36b47SEd Tanous const std::string* strProperty = 529b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 530727a046cSLakshmi Yadlapati 531b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 532f5c9f8bdSJason M. Bills { 533727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 534f5c9f8bdSJason M. Bills } 535b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 536f5c9f8bdSJason M. Bills { 537727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 538f5c9f8bdSJason M. Bills } 539727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 540727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 541727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 542b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 543f5c9f8bdSJason M. Bills { 544727a046cSLakshmi Yadlapati if (!strProperty->empty()) 545727a046cSLakshmi Yadlapati { 546727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 547727a046cSLakshmi Yadlapati } 548f5c9f8bdSJason M. Bills } 549b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 550f5c9f8bdSJason M. Bills { 551727a046cSLakshmi Yadlapati if (!strProperty->empty()) 552727a046cSLakshmi Yadlapati { 553727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 554727a046cSLakshmi Yadlapati } 555f5c9f8bdSJason M. Bills } 556b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 557f5c9f8bdSJason M. Bills { 558727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 559f5c9f8bdSJason M. Bills } 560b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 561f5c9f8bdSJason M. Bills { 562727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 563f5c9f8bdSJason M. Bills } 564b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 565b9d36b47SEd Tanous { 566727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 567b9d36b47SEd Tanous } 568002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 569f5c9f8bdSJason M. Bills { 570727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 571b9d36b47SEd Tanous } 572f5c9f8bdSJason M. Bills } 573727a046cSLakshmi Yadlapati } 574727a046cSLakshmi Yadlapati 575727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 576727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 577e14742caSEd Tanous uint64_t pcieFunctionId) 578727a046cSLakshmi Yadlapati { 579727a046cSLakshmi Yadlapati resp.addHeader( 580727a046cSLakshmi Yadlapati boost::beast::http::field::link, 581727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 582727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 583ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 584ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 585768a143dSLakshmi Yadlapati pcieDeviceId, std::to_string(pcieFunctionId)); 586727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 587e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 588e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 589ef4c65b7SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format( 590ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 591727a046cSLakshmi Yadlapati } 592727a046cSLakshmi Yadlapati 593727a046cSLakshmi Yadlapati inline void 594727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 595ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5967f3e84a1SEd Tanous const std::string& systemName, 597727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 598e14742caSEd Tanous const std::string& pcieFunctionIdStr) 599727a046cSLakshmi Yadlapati { 600ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 601727a046cSLakshmi Yadlapati { 602727a046cSLakshmi Yadlapati return; 603727a046cSLakshmi Yadlapati } 6047f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 6057f3e84a1SEd Tanous { 6067f3e84a1SEd Tanous // Option currently returns no systems. TBD 6077f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6087f3e84a1SEd Tanous systemName); 6097f3e84a1SEd Tanous return; 6107f3e84a1SEd Tanous } 6117f3e84a1SEd Tanous if (systemName != "system") 6127f3e84a1SEd Tanous { 6137f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6147f3e84a1SEd Tanous systemName); 6157f3e84a1SEd Tanous return; 6167f3e84a1SEd Tanous } 6177f3e84a1SEd Tanous 618e14742caSEd Tanous uint64_t pcieFunctionId = 0; 619e14742caSEd Tanous std::from_chars_result result = std::from_chars( 620e14742caSEd Tanous &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId); 621e14742caSEd Tanous if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end()) 622e14742caSEd Tanous { 623ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 624e14742caSEd Tanous pcieFunctionIdStr); 625e14742caSEd Tanous return; 626e14742caSEd Tanous } 627727a046cSLakshmi Yadlapati 628ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 629ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 630ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 631727a046cSLakshmi Yadlapati const std::string& service) { 632727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 633ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 634ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 635727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 636ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 637727a046cSLakshmi Yadlapati pcieFunctionId); 638ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 639727a046cSLakshmi Yadlapati pcieDevProperties); 6407e860f15SJohn Edward Broadbent }); 641727a046cSLakshmi Yadlapati }); 642727a046cSLakshmi Yadlapati } 643727a046cSLakshmi Yadlapati 644727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 645727a046cSLakshmi Yadlapati { 646727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 6477f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 648727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 649727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 650727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 651f5c9f8bdSJason M. Bills } 652f5c9f8bdSJason M. Bills 653f5c9f8bdSJason M. Bills } // namespace redfish 654