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 } 109*7f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 110*7f3e84a1SEd Tanous { 111*7f3e84a1SEd Tanous // Option currently returns no systems. TBD 112*7f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 113*7f3e84a1SEd Tanous systemName); 114*7f3e84a1SEd Tanous return; 115*7f3e84a1SEd 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 135b38fa2abSLakshmi Yadlapati collection_util::getCollectionMembers( 136ac106bf6SEd Tanous asyncResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"), 13794c3a10bSLakshmi Yadlapati pcieDeviceInterface); 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 151ac106bf6SEd Tanous inline void 152e164f1b6SLakshmi Yadlapati getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 153e164f1b6SLakshmi Yadlapati const std::string& pcieDevicePath, 154e164f1b6SLakshmi Yadlapati const std::string& service) 155e164f1b6SLakshmi Yadlapati { 156e164f1b6SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 157e164f1b6SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 158e164f1b6SLakshmi Yadlapati "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 159e164f1b6SLakshmi Yadlapati [asyncResp](const boost::system::error_code& ec, const bool value) { 160e164f1b6SLakshmi Yadlapati if (ec) 161e164f1b6SLakshmi Yadlapati { 162e164f1b6SLakshmi Yadlapati if (ec.value() != EBADR) 163e164f1b6SLakshmi Yadlapati { 164e164f1b6SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Health " 165e164f1b6SLakshmi Yadlapati << ec.value(); 166e164f1b6SLakshmi Yadlapati messages::internalError(asyncResp->res); 167e164f1b6SLakshmi Yadlapati } 168e164f1b6SLakshmi Yadlapati return; 169e164f1b6SLakshmi Yadlapati } 170e164f1b6SLakshmi Yadlapati 171e164f1b6SLakshmi Yadlapati if (!value) 172e164f1b6SLakshmi Yadlapati { 173e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "Critical"; 174e164f1b6SLakshmi Yadlapati } 175e164f1b6SLakshmi Yadlapati }); 176e164f1b6SLakshmi Yadlapati } 177e164f1b6SLakshmi Yadlapati 178e164f1b6SLakshmi Yadlapati inline void 179ac106bf6SEd Tanous getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 180c6bb3285SLakshmi Yadlapati const std::string& pcieDevicePath, 181c6bb3285SLakshmi Yadlapati const std::string& service) 182c6bb3285SLakshmi Yadlapati { 183c6bb3285SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 184c6bb3285SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 185c6bb3285SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item", "Present", 186ac106bf6SEd Tanous [asyncResp](const boost::system::error_code& ec, const bool value) { 187c6bb3285SLakshmi Yadlapati if (ec) 188c6bb3285SLakshmi Yadlapati { 189c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 190c6bb3285SLakshmi Yadlapati { 191c6bb3285SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for State"; 192ac106bf6SEd Tanous messages::internalError(asyncResp->res); 193c6bb3285SLakshmi Yadlapati } 194c6bb3285SLakshmi Yadlapati return; 195c6bb3285SLakshmi Yadlapati } 196c6bb3285SLakshmi Yadlapati 197c6bb3285SLakshmi Yadlapati if (!value) 198c6bb3285SLakshmi Yadlapati { 199ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 200c6bb3285SLakshmi Yadlapati } 201c6bb3285SLakshmi Yadlapati }); 202c6bb3285SLakshmi Yadlapati } 203c6bb3285SLakshmi Yadlapati 204ac106bf6SEd Tanous inline void 205ac106bf6SEd Tanous getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 206913e7732SSunnySrivastava1984 const std::string& pcieDevicePath, 207913e7732SSunnySrivastava1984 const std::string& service) 208913e7732SSunnySrivastava1984 { 209913e7732SSunnySrivastava1984 sdbusplus::asio::getAllProperties( 210913e7732SSunnySrivastava1984 *crow::connections::systemBus, service, pcieDevicePath, 211913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 212ac106bf6SEd Tanous [pcieDevicePath, asyncResp{asyncResp}]( 213ac106bf6SEd Tanous const boost::system::error_code& ec, 214913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 215913e7732SSunnySrivastava1984 if (ec) 216913e7732SSunnySrivastava1984 { 217913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 218913e7732SSunnySrivastava1984 { 219913e7732SSunnySrivastava1984 BMCWEB_LOG_ERROR << "DBUS response error for Properties" 220913e7732SSunnySrivastava1984 << ec.value(); 221ac106bf6SEd Tanous messages::internalError(asyncResp->res); 222913e7732SSunnySrivastava1984 } 223913e7732SSunnySrivastava1984 return; 224913e7732SSunnySrivastava1984 } 225913e7732SSunnySrivastava1984 226913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 227913e7732SSunnySrivastava1984 const std::string* model = nullptr; 228913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 229913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 230913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 231913e7732SSunnySrivastava1984 232913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 233913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 234913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 235913e7732SSunnySrivastava1984 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber); 236913e7732SSunnySrivastava1984 237913e7732SSunnySrivastava1984 if (!success) 238913e7732SSunnySrivastava1984 { 239ac106bf6SEd Tanous messages::internalError(asyncResp->res); 240913e7732SSunnySrivastava1984 return; 241913e7732SSunnySrivastava1984 } 242913e7732SSunnySrivastava1984 243913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 244913e7732SSunnySrivastava1984 { 245ac106bf6SEd Tanous asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 246913e7732SSunnySrivastava1984 } 247913e7732SSunnySrivastava1984 if (model != nullptr) 248913e7732SSunnySrivastava1984 { 249ac106bf6SEd Tanous asyncResp->res.jsonValue["Model"] = *model; 250913e7732SSunnySrivastava1984 } 251913e7732SSunnySrivastava1984 252913e7732SSunnySrivastava1984 if (partNumber != nullptr) 253913e7732SSunnySrivastava1984 { 254ac106bf6SEd Tanous asyncResp->res.jsonValue["PartNumber"] = *partNumber; 255913e7732SSunnySrivastava1984 } 256913e7732SSunnySrivastava1984 257913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 258913e7732SSunnySrivastava1984 { 259ac106bf6SEd Tanous asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 260913e7732SSunnySrivastava1984 } 261913e7732SSunnySrivastava1984 262913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 263913e7732SSunnySrivastava1984 { 264ac106bf6SEd Tanous asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 265913e7732SSunnySrivastava1984 } 266913e7732SSunnySrivastava1984 }); 267913e7732SSunnySrivastava1984 } 268913e7732SSunnySrivastava1984 269543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 27035ad613dSLakshmi Yadlapati crow::Response& resp, const std::string& pcieDeviceId, 271543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 272f5c9f8bdSJason M. Bills { 273d1bde9e5SKrzysztof Grobelny const std::string* deviceType = nullptr; 274d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 275543f9a75SLakshmi Yadlapati const int64_t* lanesInUse = nullptr; 276d1bde9e5SKrzysztof Grobelny 277d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 278543f9a75SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType", 279543f9a75SLakshmi Yadlapati deviceType, "GenerationInUse", generationInUse, "LanesInUse", 280bad2c4a9SLakshmi Yadlapati lanesInUse); 281d1bde9e5SKrzysztof Grobelny 282d1bde9e5SKrzysztof Grobelny if (!success) 283d1bde9e5SKrzysztof Grobelny { 284543f9a75SLakshmi Yadlapati messages::internalError(resp); 285d1bde9e5SKrzysztof Grobelny return; 286d1bde9e5SKrzysztof Grobelny } 287d1bde9e5SKrzysztof Grobelny 288543f9a75SLakshmi Yadlapati if (deviceType != nullptr && !deviceType->empty()) 289703f6741SMyung Bae { 290543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType; 291703f6741SMyung Bae } 292703f6741SMyung Bae 293d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 294d1bde9e5SKrzysztof Grobelny { 2950ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 296c49c329dSLakshmi Yadlapati pcie_util::redfishPcieGenerationFromDbus(*generationInUse); 297543f9a75SLakshmi Yadlapati 298d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 299d1bde9e5SKrzysztof Grobelny { 300543f9a75SLakshmi Yadlapati messages::internalError(resp); 301d1bde9e5SKrzysztof Grobelny return; 302d1bde9e5SKrzysztof Grobelny } 3030ec8b83dSEd Tanous if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid) 304d1bde9e5SKrzysztof Grobelny { 305543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["PCIeType"] = 306d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 307d1bde9e5SKrzysztof Grobelny } 308a9f68bb5STony Lee } 309d1bde9e5SKrzysztof Grobelny 310543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 311543f9a75SLakshmi Yadlapati // left as off if it is a default value. 312543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 313543f9a75SLakshmi Yadlapati { 314543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 315543f9a75SLakshmi Yadlapati } 316543f9a75SLakshmi Yadlapati 317ef4c65b7SEd Tanous resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format( 318ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 319ef4c65b7SEd Tanous pcieDeviceId); 320d1bde9e5SKrzysztof Grobelny } 321d1bde9e5SKrzysztof Grobelny 322543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 323ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 324543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 325543f9a75SLakshmi Yadlapati const std::function<void( 326543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 327d1bde9e5SKrzysztof Grobelny { 328543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 329543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 330543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 331ac106bf6SEd Tanous [asyncResp, 332543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 333543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 334543f9a75SLakshmi Yadlapati if (ec) 335543f9a75SLakshmi Yadlapati { 336543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 337543f9a75SLakshmi Yadlapati { 338543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 339ac106bf6SEd Tanous messages::internalError(asyncResp->res); 340543f9a75SLakshmi Yadlapati } 341543f9a75SLakshmi Yadlapati return; 342543f9a75SLakshmi Yadlapati } 343543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 344543f9a75SLakshmi Yadlapati }); 345d1bde9e5SKrzysztof Grobelny } 346d1bde9e5SKrzysztof Grobelny 347543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 348ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 349543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 350543f9a75SLakshmi Yadlapati { 351ac106bf6SEd Tanous asyncResp->res.addHeader( 352543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 353543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 354ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 355ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 356ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 357ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Device"; 358ac106bf6SEd Tanous asyncResp->res.jsonValue["Id"] = pcieDeviceId; 359ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 360e164f1b6SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 361543f9a75SLakshmi Yadlapati } 3621476687dSEd Tanous 363ac106bf6SEd Tanous inline void 364ac106bf6SEd Tanous handlePCIeDeviceGet(App& app, const crow::Request& req, 365ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 366543f9a75SLakshmi Yadlapati const std::string& systemName, 367543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 368543f9a75SLakshmi Yadlapati { 369ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 370543f9a75SLakshmi Yadlapati { 371543f9a75SLakshmi Yadlapati return; 372543f9a75SLakshmi Yadlapati } 373*7f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 374*7f3e84a1SEd Tanous { 375*7f3e84a1SEd Tanous // Option currently returns no systems. TBD 376*7f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 377*7f3e84a1SEd Tanous systemName); 378*7f3e84a1SEd Tanous return; 379*7f3e84a1SEd Tanous } 380543f9a75SLakshmi Yadlapati if (systemName != "system") 381543f9a75SLakshmi Yadlapati { 382ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 383ac106bf6SEd Tanous systemName); 384543f9a75SLakshmi Yadlapati return; 385543f9a75SLakshmi Yadlapati } 386543f9a75SLakshmi Yadlapati 387543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 388ac106bf6SEd Tanous pcieDeviceId, asyncResp, 389ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 390543f9a75SLakshmi Yadlapati const std::string& service) { 391ac106bf6SEd Tanous addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId); 392ac106bf6SEd Tanous getPCIeDeviceAsset(asyncResp, pcieDevicePath, service); 393ac106bf6SEd Tanous getPCIeDeviceState(asyncResp, pcieDevicePath, service); 394e164f1b6SLakshmi Yadlapati getPCIeDeviceHealth(asyncResp, pcieDevicePath, service); 395543f9a75SLakshmi Yadlapati getPCIeDeviceProperties( 396ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 397ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 39835ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 399ac106bf6SEd Tanous addPCIeDeviceProperties(asyncResp->res, pcieDeviceId, 40035ad613dSLakshmi Yadlapati pcieDevProperties); 4017e860f15SJohn Edward Broadbent }); 402543f9a75SLakshmi Yadlapati }); 403543f9a75SLakshmi Yadlapati } 404543f9a75SLakshmi Yadlapati 405543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 406543f9a75SLakshmi Yadlapati { 407543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 408543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 409543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 410543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 411dede6a98SJason M. Bills } 412dede6a98SJason M. Bills 41335ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 41435ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 41535ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 41635ad613dSLakshmi Yadlapati { 41735ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 41835ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 41935ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 42035ad613dSLakshmi Yadlapati 42135ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 42235ad613dSLakshmi Yadlapati { 42335ad613dSLakshmi Yadlapati // Check if this function exists by 42435ad613dSLakshmi Yadlapati // looking for a device ID 42589492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 42689492a15SPatrick Williams "DeviceId"; 42735ad613dSLakshmi Yadlapati const std::string* property = nullptr; 42835ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 42935ad613dSLakshmi Yadlapati { 43035ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 43135ad613dSLakshmi Yadlapati { 43235ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 43335ad613dSLakshmi Yadlapati break; 43435ad613dSLakshmi Yadlapati } 43535ad613dSLakshmi Yadlapati } 43635ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 43735ad613dSLakshmi Yadlapati { 43835ad613dSLakshmi Yadlapati continue; 43935ad613dSLakshmi Yadlapati } 44035ad613dSLakshmi Yadlapati 44135ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 442ef4c65b7SEd Tanous pcieFunction["@odata.id"] = boost::urls::format( 443ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 444ef4c65b7SEd Tanous pcieDeviceId, std::to_string(functionNum)); 445b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 44635ad613dSLakshmi Yadlapati } 44735ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 44835ad613dSLakshmi Yadlapati } 44935ad613dSLakshmi Yadlapati 45035ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 45135ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 452ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 453*7f3e84a1SEd Tanous const std::string& systemName, const std::string& pcieDeviceId) 45435ad613dSLakshmi Yadlapati { 455ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 45635ad613dSLakshmi Yadlapati { 45735ad613dSLakshmi Yadlapati return; 45835ad613dSLakshmi Yadlapati } 459*7f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 460*7f3e84a1SEd Tanous { 461*7f3e84a1SEd Tanous // Option currently returns no systems. TBD 462*7f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 463*7f3e84a1SEd Tanous systemName); 464*7f3e84a1SEd Tanous return; 465*7f3e84a1SEd Tanous } 46635ad613dSLakshmi Yadlapati 46735ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 468ac106bf6SEd Tanous pcieDeviceId, asyncResp, 469ac106bf6SEd Tanous [asyncResp, pcieDeviceId](const std::string& pcieDevicePath, 47035ad613dSLakshmi Yadlapati const std::string& service) { 471ac106bf6SEd Tanous asyncResp->res.addHeader( 47235ad613dSLakshmi Yadlapati boost::beast::http::field::link, 47335ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 474ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 47535ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 476ac106bf6SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 477ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions", 478ef4c65b7SEd Tanous pcieDeviceId); 479ac106bf6SEd Tanous asyncResp->res.jsonValue["Name"] = "PCIe Function Collection"; 480ac106bf6SEd Tanous asyncResp->res.jsonValue["Description"] = 48135ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 48235ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 483ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 484ac106bf6SEd Tanous [asyncResp, pcieDeviceId]( 48535ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 486ac106bf6SEd Tanous addPCIeFunctionList(asyncResp->res, pcieDeviceId, 487ac106bf6SEd Tanous pcieDevProperties); 48835ad613dSLakshmi Yadlapati }); 48935ad613dSLakshmi Yadlapati }); 49035ad613dSLakshmi Yadlapati } 49135ad613dSLakshmi Yadlapati 4927e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 4937e860f15SJohn Edward Broadbent { 494dede6a98SJason M. Bills /** 495dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 496dede6a98SJason M. Bills */ 4977e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 498*7f3e84a1SEd Tanous "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/") 499ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 500002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 50135ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 5027e860f15SJohn Edward Broadbent } 5037e860f15SJohn Edward Broadbent 504727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 505d5e74b80SMyung Bae uint64_t pcieFunctionId, 506727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 5077e860f15SJohn Edward Broadbent { 508d5e74b80SMyung Bae std::string functionName = "Function" + std::to_string(pcieFunctionId); 509b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 510b9d36b47SEd Tanous 511b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 512b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 513b9d36b47SEd Tanous { 514b9d36b47SEd Tanous if (property.first == devIDProperty) 515b9d36b47SEd Tanous { 516002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 517727a046cSLakshmi Yadlapati break; 518b9d36b47SEd Tanous } 519b9d36b47SEd Tanous } 520727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 521727a046cSLakshmi Yadlapati } 522727a046cSLakshmi Yadlapati 523727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 524e14742caSEd Tanous crow::Response& resp, uint64_t pcieFunctionId, 525727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 526f5c9f8bdSJason M. Bills { 527e14742caSEd Tanous std::string functionName = "Function" + std::to_string(pcieFunctionId); 528b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 529f5c9f8bdSJason M. Bills { 530b9d36b47SEd Tanous const std::string* strProperty = 531b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 532727a046cSLakshmi Yadlapati 533b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 534f5c9f8bdSJason M. Bills { 535727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 536f5c9f8bdSJason M. Bills } 537b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 538f5c9f8bdSJason M. Bills { 539727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 540f5c9f8bdSJason M. Bills } 541727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 542727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 543727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 544b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 545f5c9f8bdSJason M. Bills { 546727a046cSLakshmi Yadlapati if (!strProperty->empty()) 547727a046cSLakshmi Yadlapati { 548727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 549727a046cSLakshmi Yadlapati } 550f5c9f8bdSJason M. Bills } 551b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 552f5c9f8bdSJason M. Bills { 553727a046cSLakshmi Yadlapati if (!strProperty->empty()) 554727a046cSLakshmi Yadlapati { 555727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 556727a046cSLakshmi Yadlapati } 557f5c9f8bdSJason M. Bills } 558b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 559f5c9f8bdSJason M. Bills { 560727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 561f5c9f8bdSJason M. Bills } 562b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 563f5c9f8bdSJason M. Bills { 564727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 565f5c9f8bdSJason M. Bills } 566b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 567b9d36b47SEd Tanous { 568727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 569b9d36b47SEd Tanous } 570002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 571f5c9f8bdSJason M. Bills { 572727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 573b9d36b47SEd Tanous } 574f5c9f8bdSJason M. Bills } 575727a046cSLakshmi Yadlapati } 576727a046cSLakshmi Yadlapati 577727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 578727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 579e14742caSEd Tanous uint64_t pcieFunctionId) 580727a046cSLakshmi Yadlapati { 581727a046cSLakshmi Yadlapati resp.addHeader( 582727a046cSLakshmi Yadlapati boost::beast::http::field::link, 583727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 584727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 585ef4c65b7SEd Tanous resp.jsonValue["@odata.id"] = boost::urls::format( 586ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}", 587768a143dSLakshmi Yadlapati pcieDeviceId, std::to_string(pcieFunctionId)); 588727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 589e14742caSEd Tanous resp.jsonValue["Id"] = std::to_string(pcieFunctionId); 590e14742caSEd Tanous resp.jsonValue["FunctionId"] = pcieFunctionId; 591ef4c65b7SEd Tanous resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format( 592ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId); 593727a046cSLakshmi Yadlapati } 594727a046cSLakshmi Yadlapati 595727a046cSLakshmi Yadlapati inline void 596727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 597ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 598*7f3e84a1SEd Tanous const std::string& systemName, 599727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 600e14742caSEd Tanous const std::string& pcieFunctionIdStr) 601727a046cSLakshmi Yadlapati { 602ac106bf6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 603727a046cSLakshmi Yadlapati { 604727a046cSLakshmi Yadlapati return; 605727a046cSLakshmi Yadlapati } 606*7f3e84a1SEd Tanous if constexpr (bmcwebEnableMultiHost) 607*7f3e84a1SEd Tanous { 608*7f3e84a1SEd Tanous // Option currently returns no systems. TBD 609*7f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 610*7f3e84a1SEd Tanous systemName); 611*7f3e84a1SEd Tanous return; 612*7f3e84a1SEd Tanous } 613*7f3e84a1SEd Tanous if (systemName != "system") 614*7f3e84a1SEd Tanous { 615*7f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 616*7f3e84a1SEd Tanous systemName); 617*7f3e84a1SEd Tanous return; 618*7f3e84a1SEd Tanous } 619*7f3e84a1SEd Tanous 620e14742caSEd Tanous uint64_t pcieFunctionId = 0; 621e14742caSEd Tanous std::from_chars_result result = std::from_chars( 622e14742caSEd Tanous &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId); 623e14742caSEd Tanous if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end()) 624e14742caSEd Tanous { 625ac106bf6SEd Tanous messages::resourceNotFound(asyncResp->res, "PCIeFunction", 626e14742caSEd Tanous pcieFunctionIdStr); 627e14742caSEd Tanous return; 628e14742caSEd Tanous } 629727a046cSLakshmi Yadlapati 630ac106bf6SEd Tanous getValidPCIeDevicePath(pcieDeviceId, asyncResp, 631ac106bf6SEd Tanous [asyncResp, pcieDeviceId, 632ac106bf6SEd Tanous pcieFunctionId](const std::string& pcieDevicePath, 633727a046cSLakshmi Yadlapati const std::string& service) { 634727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 635ac106bf6SEd Tanous asyncResp, pcieDevicePath, service, 636ac106bf6SEd Tanous [asyncResp, pcieDeviceId, pcieFunctionId]( 637727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 638ac106bf6SEd Tanous addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId, 639727a046cSLakshmi Yadlapati pcieFunctionId); 640ac106bf6SEd Tanous addPCIeFunctionProperties(asyncResp->res, pcieFunctionId, 641727a046cSLakshmi Yadlapati pcieDevProperties); 6427e860f15SJohn Edward Broadbent }); 643727a046cSLakshmi Yadlapati }); 644727a046cSLakshmi Yadlapati } 645727a046cSLakshmi Yadlapati 646727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 647727a046cSLakshmi Yadlapati { 648727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 649*7f3e84a1SEd Tanous app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/") 650727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 651727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 652727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 653f5c9f8bdSJason M. Bills } 654f5c9f8bdSJason M. Bills 655f5c9f8bdSJason M. Bills } // namespace redfish 656