140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3a7210020SGeorge Liu #pragma once 4a7210020SGeorge Liu 5a7210020SGeorge Liu #include "app.hpp" 6d7857201SEd Tanous #include "async_resp.hpp" 7a7210020SGeorge Liu #include "dbus_utility.hpp" 8d7857201SEd Tanous #include "error_messages.hpp" 9539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 10d7857201SEd Tanous #include "http_request.hpp" 11*7066dc58SMyung Bae #include "led.hpp" 12d7857201SEd Tanous #include "logging.hpp" 13a7210020SGeorge Liu #include "query.hpp" 14a7210020SGeorge Liu #include "registries/privilege_registry.hpp" 15a7210020SGeorge Liu #include "utils/chassis_utils.hpp" 162b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp" 17*7066dc58SMyung Bae #include "utils/json_utils.hpp" 18b5190062SHieu Huynh #include "utils/time_utils.hpp" 19a7210020SGeorge Liu 20d7857201SEd Tanous #include <asm-generic/errno.h> 21d7857201SEd Tanous 22d7857201SEd Tanous #include <boost/beast/http/field.hpp> 23d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 2434dfcb94SGeorge Liu #include <boost/system/error_code.hpp> 25ef4c65b7SEd Tanous #include <boost/url/format.hpp> 26d7857201SEd Tanous #include <nlohmann/json.hpp> 27d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp> 28ef4c65b7SEd Tanous 29d7857201SEd Tanous #include <array> 30d7857201SEd Tanous #include <cstdint> 31d7857201SEd Tanous #include <functional> 32a7210020SGeorge Liu #include <memory> 33a7210020SGeorge Liu #include <optional> 34a7210020SGeorge Liu #include <string> 35d7857201SEd Tanous #include <string_view> 36d7857201SEd Tanous #include <utility> 37a7210020SGeorge Liu 38a7210020SGeorge Liu namespace redfish 39a7210020SGeorge Liu { 40a7210020SGeorge Liu 41788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = { 42788fe6cfSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 43788fe6cfSLakshmi Yadlapati 44788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList( 45788fe6cfSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4600ef5dc6SGeorge Liu const std::string& chassisId, 47788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths) 48788fe6cfSLakshmi Yadlapati { 49788fe6cfSLakshmi Yadlapati nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"]; 50788fe6cfSLakshmi Yadlapati for (const std::string& powerSupplyPath : powerSupplyPaths) 51a7210020SGeorge Liu { 5200ef5dc6SGeorge Liu std::string powerSupplyName = 5300ef5dc6SGeorge Liu sdbusplus::message::object_path(powerSupplyPath).filename(); 5400ef5dc6SGeorge Liu if (powerSupplyName.empty()) 5500ef5dc6SGeorge Liu { 56788fe6cfSLakshmi Yadlapati continue; 5700ef5dc6SGeorge Liu } 5800ef5dc6SGeorge Liu 5900ef5dc6SGeorge Liu nlohmann::json item = nlohmann::json::object(); 6000ef5dc6SGeorge Liu item["@odata.id"] = boost::urls::format( 6100ef5dc6SGeorge Liu "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 6200ef5dc6SGeorge Liu powerSupplyName); 6300ef5dc6SGeorge Liu 6400ef5dc6SGeorge Liu powerSupplyList.emplace_back(std::move(item)); 65788fe6cfSLakshmi Yadlapati } 6600ef5dc6SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size(); 67a7210020SGeorge Liu } 68a7210020SGeorge Liu 693e42a329SLakshmi Yadlapati inline void doPowerSupplyCollection( 703e42a329SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 713e42a329SLakshmi Yadlapati const std::string& chassisId, const boost::system::error_code& ec, 723e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) 73a7210020SGeorge Liu { 743e42a329SLakshmi Yadlapati if (ec) 75a7210020SGeorge Liu { 76193582b6SMyung Bae if (ec.value() == boost::system::errc::io_error) 77193582b6SMyung Bae { 78193582b6SMyung Bae BMCWEB_LOG_WARNING("Chassis not found"); 79193582b6SMyung Bae messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 80193582b6SMyung Bae return; 81193582b6SMyung Bae } 823e42a329SLakshmi Yadlapati if (ec.value() != EBADR) 833e42a329SLakshmi Yadlapati { 843e42a329SLakshmi Yadlapati BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 853e42a329SLakshmi Yadlapati messages::internalError(asyncResp->res); 863e42a329SLakshmi Yadlapati } 87a7210020SGeorge Liu return; 88a7210020SGeorge Liu } 89a7210020SGeorge Liu asyncResp->res.addHeader( 90a7210020SGeorge Liu boost::beast::http::field::link, 91a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 92a7210020SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = 93a7210020SGeorge Liu "#PowerSupplyCollection.PowerSupplyCollection"; 94a7210020SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply Collection"; 95ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 96ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId); 97a7210020SGeorge Liu asyncResp->res.jsonValue["Description"] = 98a7210020SGeorge Liu "The collection of PowerSupply resource instances."; 997a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 1007a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0; 101a7210020SGeorge Liu 102788fe6cfSLakshmi Yadlapati updatePowerSupplyList(asyncResp, chassisId, subtreePaths); 103a7210020SGeorge Liu } 104a7210020SGeorge Liu 105a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead( 106a7210020SGeorge Liu App& app, const crow::Request& req, 107a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 108a7210020SGeorge Liu const std::string& chassisId) 109a7210020SGeorge Liu { 110a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 111a7210020SGeorge Liu { 112a7210020SGeorge Liu return; 113a7210020SGeorge Liu } 114a7210020SGeorge Liu 115a7210020SGeorge Liu redfish::chassis_utils::getValidChassisPath( 116a7210020SGeorge Liu asyncResp, chassisId, 117a7210020SGeorge Liu [asyncResp, 118a7210020SGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) { 119a7210020SGeorge Liu if (!validChassisPath) 120a7210020SGeorge Liu { 121193582b6SMyung Bae BMCWEB_LOG_WARNING("Chassis not found"); 122bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 123bd79bce8SPatrick Williams chassisId); 124a7210020SGeorge Liu return; 125a7210020SGeorge Liu } 126a7210020SGeorge Liu asyncResp->res.addHeader( 127a7210020SGeorge Liu boost::beast::http::field::link, 128a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 129a7210020SGeorge Liu }); 130a7210020SGeorge Liu } 131a7210020SGeorge Liu 132a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet( 133a7210020SGeorge Liu App& app, const crow::Request& req, 134a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 135a7210020SGeorge Liu const std::string& chassisId) 136a7210020SGeorge Liu { 137a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 138a7210020SGeorge Liu { 139a7210020SGeorge Liu return; 140a7210020SGeorge Liu } 141a7210020SGeorge Liu 1423e42a329SLakshmi Yadlapati const std::string reqpath = "/xyz/openbmc_project/inventory"; 1433e42a329SLakshmi Yadlapati 1443e42a329SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePathsById( 1453f95a277SMyung Bae chassisId, reqpath, chassisInterfaces, "powered_by", 1463e42a329SLakshmi Yadlapati powerSupplyInterface, 1473e42a329SLakshmi Yadlapati [asyncResp, chassisId]( 1483e42a329SLakshmi Yadlapati const boost::system::error_code& ec, 1493e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 1503e42a329SLakshmi Yadlapati doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths); 1513e42a329SLakshmi Yadlapati }); 152a7210020SGeorge Liu } 153a7210020SGeorge Liu 154a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app) 155a7210020SGeorge Liu { 156a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 157a7210020SGeorge Liu .privileges(redfish::privileges::headPowerSupplyCollection) 158a7210020SGeorge Liu .methods(boost::beast::http::verb::head)( 159a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionHead, std::ref(app))); 160a7210020SGeorge Liu 161a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 162a7210020SGeorge Liu .privileges(redfish::privileges::getPowerSupplyCollection) 163a7210020SGeorge Liu .methods(boost::beast::http::verb::get)( 164a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionGet, std::ref(app))); 165a7210020SGeorge Liu } 166a7210020SGeorge Liu 1673e42a329SLakshmi Yadlapati inline void afterGetValidPowerSupplyPath( 16834dfcb94SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1693e42a329SLakshmi Yadlapati const std::string& powerSupplyId, const boost::system::error_code& ec, 1703e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreeResponse& subtree, 1713e42a329SLakshmi Yadlapati const std::function<void(const std::string& powerSupplyPath, 1723e42a329SLakshmi Yadlapati const std::string& service)>& callback) 17300ef5dc6SGeorge Liu { 17400ef5dc6SGeorge Liu if (ec) 17500ef5dc6SGeorge Liu { 176193582b6SMyung Bae if (ec.value() == boost::system::errc::io_error) 177193582b6SMyung Bae { 178193582b6SMyung Bae // Not found 179193582b6SMyung Bae callback(std::string(), std::string()); 180193582b6SMyung Bae return; 181193582b6SMyung Bae } 18200ef5dc6SGeorge Liu if (ec.value() != EBADR) 18300ef5dc6SGeorge Liu { 1843e42a329SLakshmi Yadlapati BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 18500ef5dc6SGeorge Liu messages::internalError(asyncResp->res); 186193582b6SMyung Bae return; 1873e42a329SLakshmi Yadlapati } 188193582b6SMyung Bae callback(std::string(), std::string()); 18900ef5dc6SGeorge Liu return; 19000ef5dc6SGeorge Liu } 1913e42a329SLakshmi Yadlapati for (const auto& [objectPath, service] : subtree) 19200ef5dc6SGeorge Liu { 1933e42a329SLakshmi Yadlapati sdbusplus::message::object_path path(objectPath); 194d8e2b618SMyung Bae if (path.filename() == powerSupplyId) 19500ef5dc6SGeorge Liu { 1963e42a329SLakshmi Yadlapati callback(path, service.begin()->first); 19700ef5dc6SGeorge Liu return; 19800ef5dc6SGeorge Liu } 19900ef5dc6SGeorge Liu } 20000ef5dc6SGeorge Liu 20162598e31SEd Tanous BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId); 2023e42a329SLakshmi Yadlapati messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId); 20300ef5dc6SGeorge Liu } 2043e42a329SLakshmi Yadlapati 2053e42a329SLakshmi Yadlapati inline void getValidPowerSupplyPath( 2063e42a329SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2073e42a329SLakshmi Yadlapati const std::string& chassisId, const std::string& powerSupplyId, 2083e42a329SLakshmi Yadlapati std::function<void(const std::string& powerSupplyPath, 2093e42a329SLakshmi Yadlapati const std::string& service)>&& callback) 2103e42a329SLakshmi Yadlapati { 2113e42a329SLakshmi Yadlapati const std::string reqpath = "/xyz/openbmc_project/inventory"; 2123e42a329SLakshmi Yadlapati 2133e42a329SLakshmi Yadlapati dbus::utility::getAssociatedSubTreeById( 2143f95a277SMyung Bae chassisId, reqpath, chassisInterfaces, "powered_by", 2153e42a329SLakshmi Yadlapati powerSupplyInterface, 2163e42a329SLakshmi Yadlapati [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}]( 2173e42a329SLakshmi Yadlapati const boost::system::error_code& ec, 2183e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreeResponse& subtree) { 2193e42a329SLakshmi Yadlapati afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree, 2203e42a329SLakshmi Yadlapati callback); 22100ef5dc6SGeorge Liu }); 22200ef5dc6SGeorge Liu } 22300ef5dc6SGeorge Liu 224504af5a0SPatrick Williams inline void getPowerSupplyState( 225504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 22634dfcb94SGeorge Liu const std::string& service, const std::string& path) 22734dfcb94SGeorge Liu { 228deae6a78SEd Tanous dbus::utility::getProperty<bool>( 229deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Item", "Present", 23034dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 23134dfcb94SGeorge Liu if (ec) 23234dfcb94SGeorge Liu { 23334dfcb94SGeorge Liu if (ec.value() != EBADR) 23434dfcb94SGeorge Liu { 23562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State {}", 23662598e31SEd Tanous ec.value()); 23734dfcb94SGeorge Liu messages::internalError(asyncResp->res); 23834dfcb94SGeorge Liu } 23934dfcb94SGeorge Liu return; 24034dfcb94SGeorge Liu } 24134dfcb94SGeorge Liu 24234dfcb94SGeorge Liu if (!value) 24334dfcb94SGeorge Liu { 244539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 245539d8c6bSEd Tanous resource::State::Absent; 24634dfcb94SGeorge Liu } 24734dfcb94SGeorge Liu }); 24834dfcb94SGeorge Liu } 24934dfcb94SGeorge Liu 250504af5a0SPatrick Williams inline void getPowerSupplyHealth( 251504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 25234dfcb94SGeorge Liu const std::string& service, const std::string& path) 25334dfcb94SGeorge Liu { 254deae6a78SEd Tanous dbus::utility::getProperty<bool>( 255deae6a78SEd Tanous service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus", 256deae6a78SEd Tanous "Functional", 25734dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 25834dfcb94SGeorge Liu if (ec) 25934dfcb94SGeorge Liu { 26034dfcb94SGeorge Liu if (ec.value() != EBADR) 26134dfcb94SGeorge Liu { 26262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 26362598e31SEd Tanous ec.value()); 26434dfcb94SGeorge Liu messages::internalError(asyncResp->res); 26534dfcb94SGeorge Liu } 26634dfcb94SGeorge Liu return; 26734dfcb94SGeorge Liu } 26834dfcb94SGeorge Liu 26934dfcb94SGeorge Liu if (!value) 27034dfcb94SGeorge Liu { 271539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 272539d8c6bSEd Tanous resource::Health::Critical; 27334dfcb94SGeorge Liu } 27434dfcb94SGeorge Liu }); 27534dfcb94SGeorge Liu } 27634dfcb94SGeorge Liu 277504af5a0SPatrick Williams inline void getPowerSupplyAsset( 278504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2792b45fb3bSGeorge Liu const std::string& service, const std::string& path) 2802b45fb3bSGeorge Liu { 281deae6a78SEd Tanous dbus::utility::getAllProperties( 282deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Decorator.Asset", 2832b45fb3bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 2842b45fb3bSGeorge Liu const dbus::utility::DBusPropertiesMap& propertiesList) { 2852b45fb3bSGeorge Liu if (ec) 2862b45fb3bSGeorge Liu { 2872b45fb3bSGeorge Liu if (ec.value() != EBADR) 2882b45fb3bSGeorge Liu { 28962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Asset {}", 29062598e31SEd Tanous ec.value()); 2912b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2922b45fb3bSGeorge Liu } 2932b45fb3bSGeorge Liu return; 2942b45fb3bSGeorge Liu } 2952b45fb3bSGeorge Liu 2962b45fb3bSGeorge Liu const std::string* partNumber = nullptr; 2972b45fb3bSGeorge Liu const std::string* serialNumber = nullptr; 2982b45fb3bSGeorge Liu const std::string* manufacturer = nullptr; 2992b45fb3bSGeorge Liu const std::string* model = nullptr; 3002b45fb3bSGeorge Liu const std::string* sparePartNumber = nullptr; 301b5190062SHieu Huynh const std::string* buildDate = nullptr; 3022b45fb3bSGeorge Liu 3032b45fb3bSGeorge Liu const bool success = sdbusplus::unpackPropertiesNoThrow( 3042b45fb3bSGeorge Liu dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 3052b45fb3bSGeorge Liu partNumber, "SerialNumber", serialNumber, "Manufacturer", 306bd79bce8SPatrick Williams manufacturer, "Model", model, "SparePartNumber", 307b5190062SHieu Huynh sparePartNumber, "BuildDate", buildDate); 3082b45fb3bSGeorge Liu 3092b45fb3bSGeorge Liu if (!success) 3102b45fb3bSGeorge Liu { 3112b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 3122b45fb3bSGeorge Liu return; 3132b45fb3bSGeorge Liu } 3142b45fb3bSGeorge Liu 3152b45fb3bSGeorge Liu if (partNumber != nullptr) 3162b45fb3bSGeorge Liu { 3172b45fb3bSGeorge Liu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 3182b45fb3bSGeorge Liu } 3192b45fb3bSGeorge Liu 3202b45fb3bSGeorge Liu if (serialNumber != nullptr) 3212b45fb3bSGeorge Liu { 3222b45fb3bSGeorge Liu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 3232b45fb3bSGeorge Liu } 3242b45fb3bSGeorge Liu 3252b45fb3bSGeorge Liu if (manufacturer != nullptr) 3262b45fb3bSGeorge Liu { 3272b45fb3bSGeorge Liu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 3282b45fb3bSGeorge Liu } 3292b45fb3bSGeorge Liu 3302b45fb3bSGeorge Liu if (model != nullptr) 3312b45fb3bSGeorge Liu { 3322b45fb3bSGeorge Liu asyncResp->res.jsonValue["Model"] = *model; 3332b45fb3bSGeorge Liu } 3342b45fb3bSGeorge Liu 3352b45fb3bSGeorge Liu // SparePartNumber is optional on D-Bus so skip if it is empty 3362b45fb3bSGeorge Liu if (sparePartNumber != nullptr && !sparePartNumber->empty()) 3372b45fb3bSGeorge Liu { 3382b45fb3bSGeorge Liu asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 3392b45fb3bSGeorge Liu } 340b5190062SHieu Huynh 341b5190062SHieu Huynh if (buildDate != nullptr) 342b5190062SHieu Huynh { 343b5190062SHieu Huynh time_utils::productionDateReport(asyncResp->res, *buildDate); 344b5190062SHieu Huynh } 3452b45fb3bSGeorge Liu }); 3462b45fb3bSGeorge Liu } 3472b45fb3bSGeorge Liu 348a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion( 349a0dba87bSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 350a0dba87bSGeorge Liu const std::string& service, const std::string& path) 351a0dba87bSGeorge Liu { 352deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 353deae6a78SEd Tanous service, path, "xyz.openbmc_project.Software.Version", "Version", 354a0dba87bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 355a0dba87bSGeorge Liu const std::string& value) { 356a0dba87bSGeorge Liu if (ec) 357a0dba87bSGeorge Liu { 358a0dba87bSGeorge Liu if (ec.value() != EBADR) 359a0dba87bSGeorge Liu { 360bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 361bd79bce8SPatrick Williams "DBUS response error for FirmwareVersion {}", 36262598e31SEd Tanous ec.value()); 363a0dba87bSGeorge Liu messages::internalError(asyncResp->res); 364a0dba87bSGeorge Liu } 365a0dba87bSGeorge Liu return; 366a0dba87bSGeorge Liu } 367a0dba87bSGeorge Liu asyncResp->res.jsonValue["FirmwareVersion"] = value; 368a0dba87bSGeorge Liu }); 369a0dba87bSGeorge Liu } 370a0dba87bSGeorge Liu 371504af5a0SPatrick Williams inline void getPowerSupplyLocation( 372504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 37344845e5fSGeorge Liu const std::string& service, const std::string& path) 37444845e5fSGeorge Liu { 375deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 376deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode", 377deae6a78SEd Tanous "LocationCode", 37844845e5fSGeorge Liu [asyncResp](const boost::system::error_code& ec, 37944845e5fSGeorge Liu const std::string& value) { 38044845e5fSGeorge Liu if (ec) 38144845e5fSGeorge Liu { 38244845e5fSGeorge Liu if (ec.value() != EBADR) 38344845e5fSGeorge Liu { 38462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location {}", 38562598e31SEd Tanous ec.value()); 38644845e5fSGeorge Liu messages::internalError(asyncResp->res); 38744845e5fSGeorge Liu } 38844845e5fSGeorge Liu return; 38944845e5fSGeorge Liu } 390bd79bce8SPatrick Williams asyncResp->res 391bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value; 39244845e5fSGeorge Liu }); 39344845e5fSGeorge Liu } 39444845e5fSGeorge Liu 395ddceee07SGeorge Liu inline void handleGetEfficiencyResponse( 396ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 397ddceee07SGeorge Liu const boost::system::error_code& ec, uint32_t value) 398ddceee07SGeorge Liu { 399ddceee07SGeorge Liu if (ec) 400ddceee07SGeorge Liu { 401ddceee07SGeorge Liu if (ec.value() != EBADR) 402ddceee07SGeorge Liu { 40362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}", 40462598e31SEd Tanous ec.value()); 405ddceee07SGeorge Liu messages::internalError(asyncResp->res); 406ddceee07SGeorge Liu } 407ddceee07SGeorge Liu return; 408ddceee07SGeorge Liu } 409ddceee07SGeorge Liu // The PDI default value is 0, if it hasn't been set leave off 410ddceee07SGeorge Liu if (value == 0) 411ddceee07SGeorge Liu { 412ddceee07SGeorge Liu return; 413ddceee07SGeorge Liu } 414ddceee07SGeorge Liu 415ddceee07SGeorge Liu nlohmann::json::array_t efficiencyRatings; 416ddceee07SGeorge Liu nlohmann::json::object_t efficiencyPercent; 417ddceee07SGeorge Liu efficiencyPercent["EfficiencyPercent"] = value; 418ddceee07SGeorge Liu efficiencyRatings.emplace_back(std::move(efficiencyPercent)); 419ddceee07SGeorge Liu asyncResp->res.jsonValue["EfficiencyRatings"] = 420ddceee07SGeorge Liu std::move(efficiencyRatings); 421ddceee07SGeorge Liu } 422ddceee07SGeorge Liu 423ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse( 424ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 425ddceee07SGeorge Liu const boost::system::error_code& ec, 426ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) 427ddceee07SGeorge Liu { 428ddceee07SGeorge Liu if (ec) 429ddceee07SGeorge Liu { 430ddceee07SGeorge Liu if (ec.value() != EBADR) 431ddceee07SGeorge Liu { 43262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}", 43362598e31SEd Tanous ec.value()); 434ddceee07SGeorge Liu messages::internalError(asyncResp->res); 435ddceee07SGeorge Liu } 436ddceee07SGeorge Liu return; 437ddceee07SGeorge Liu } 438ddceee07SGeorge Liu 439ddceee07SGeorge Liu if (subtree.empty()) 440ddceee07SGeorge Liu { 44162598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!"); 442ddceee07SGeorge Liu return; 443ddceee07SGeorge Liu } 444ddceee07SGeorge Liu 445ddceee07SGeorge Liu if (subtree.size() != 1) 446ddceee07SGeorge Liu { 44762598e31SEd Tanous BMCWEB_LOG_ERROR( 44862598e31SEd Tanous "Unexpected number of paths returned by getSubTree: {}", 44962598e31SEd Tanous subtree.size()); 450ddceee07SGeorge Liu messages::internalError(asyncResp->res); 451ddceee07SGeorge Liu return; 452ddceee07SGeorge Liu } 453ddceee07SGeorge Liu 454ddceee07SGeorge Liu const auto& [path, serviceMap] = *subtree.begin(); 455ddceee07SGeorge Liu const auto& [service, interfaces] = *serviceMap.begin(); 456deae6a78SEd Tanous dbus::utility::getProperty<uint32_t>( 457deae6a78SEd Tanous service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes", 458deae6a78SEd Tanous "DeratingFactor", 459ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec1, uint32_t value) { 460ddceee07SGeorge Liu handleGetEfficiencyResponse(asyncResp, ec1, value); 461ddceee07SGeorge Liu }); 462ddceee07SGeorge Liu } 463ddceee07SGeorge Liu 464504af5a0SPatrick Williams inline void getEfficiencyPercent( 465504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 466ddceee07SGeorge Liu { 467ddceee07SGeorge Liu constexpr std::array<std::string_view, 1> efficiencyIntf = { 468ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 469ddceee07SGeorge Liu 470ddceee07SGeorge Liu dbus::utility::getSubTree( 471ddceee07SGeorge Liu "/xyz/openbmc_project", 0, efficiencyIntf, 472ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec, 473ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) { 474ddceee07SGeorge Liu handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree); 475ddceee07SGeorge Liu }); 476ddceee07SGeorge Liu } 477ddceee07SGeorge Liu 478bd79bce8SPatrick Williams inline void doPowerSupplyGet( 479bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 480bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId, 4813e42a329SLakshmi Yadlapati const std::string& powerSupplyPath, const std::string& service) 48200ef5dc6SGeorge Liu { 483193582b6SMyung Bae if (powerSupplyPath.empty() || service.empty()) 484193582b6SMyung Bae { 485193582b6SMyung Bae BMCWEB_LOG_WARNING("PowerSupply not found"); 486193582b6SMyung Bae messages::resourceNotFound(asyncResp->res, "PowerSupply", 487193582b6SMyung Bae powerSupplyId); 488193582b6SMyung Bae return; 489193582b6SMyung Bae } 490193582b6SMyung Bae 49100ef5dc6SGeorge Liu asyncResp->res.addHeader( 49200ef5dc6SGeorge Liu boost::beast::http::field::link, 49300ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 4943e42a329SLakshmi Yadlapati asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply"; 49500ef5dc6SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply"; 49600ef5dc6SGeorge Liu asyncResp->res.jsonValue["Id"] = powerSupplyId; 49700ef5dc6SGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 4983e42a329SLakshmi Yadlapati "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 4993e42a329SLakshmi Yadlapati powerSupplyId); 50034dfcb94SGeorge Liu 5013e42a329SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 502539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 50334dfcb94SGeorge Liu 5043e42a329SLakshmi Yadlapati getPowerSupplyState(asyncResp, service, powerSupplyPath); 5053e42a329SLakshmi Yadlapati getPowerSupplyHealth(asyncResp, service, powerSupplyPath); 5063e42a329SLakshmi Yadlapati getPowerSupplyAsset(asyncResp, service, powerSupplyPath); 5073e42a329SLakshmi Yadlapati getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath); 5083e42a329SLakshmi Yadlapati getPowerSupplyLocation(asyncResp, service, powerSupplyPath); 509ddceee07SGeorge Liu getEfficiencyPercent(asyncResp); 510*7066dc58SMyung Bae getLocationIndicatorActive(asyncResp, powerSupplyPath); 51100ef5dc6SGeorge Liu } 51200ef5dc6SGeorge Liu 513bd79bce8SPatrick Williams inline void handlePowerSupplyHead( 514bd79bce8SPatrick Williams App& app, const crow::Request& req, 51500ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 516bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 51700ef5dc6SGeorge Liu { 51800ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 51900ef5dc6SGeorge Liu { 52000ef5dc6SGeorge Liu return; 52100ef5dc6SGeorge Liu } 52200ef5dc6SGeorge Liu 52300ef5dc6SGeorge Liu // Get the correct Path and Service that match the input parameters 524bd79bce8SPatrick Williams getValidPowerSupplyPath( 5253e42a329SLakshmi Yadlapati asyncResp, chassisId, powerSupplyId, 526193582b6SMyung Bae [asyncResp, powerSupplyId](const std::string& powerSupplyPath, 527193582b6SMyung Bae const std::string& service) { 528193582b6SMyung Bae if (powerSupplyPath.empty() || service.empty()) 529193582b6SMyung Bae { 530193582b6SMyung Bae BMCWEB_LOG_WARNING("PowerSupply not found"); 531193582b6SMyung Bae messages::resourceNotFound(asyncResp->res, "PowerSupply", 532193582b6SMyung Bae powerSupplyId); 533193582b6SMyung Bae return; 534193582b6SMyung Bae } 53500ef5dc6SGeorge Liu asyncResp->res.addHeader( 53600ef5dc6SGeorge Liu boost::beast::http::field::link, 53700ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 53800ef5dc6SGeorge Liu }); 53900ef5dc6SGeorge Liu } 54000ef5dc6SGeorge Liu 541bd79bce8SPatrick Williams inline void handlePowerSupplyGet( 542bd79bce8SPatrick Williams App& app, const crow::Request& req, 54300ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 544bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 54500ef5dc6SGeorge Liu { 54600ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 54700ef5dc6SGeorge Liu { 54800ef5dc6SGeorge Liu return; 54900ef5dc6SGeorge Liu } 5503e42a329SLakshmi Yadlapati getValidPowerSupplyPath( 5513e42a329SLakshmi Yadlapati asyncResp, chassisId, powerSupplyId, 55200ef5dc6SGeorge Liu std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId)); 55300ef5dc6SGeorge Liu } 55400ef5dc6SGeorge Liu 555*7066dc58SMyung Bae inline void doPatchPowerSupply( 556*7066dc58SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 557*7066dc58SMyung Bae const bool locationIndicatorActive, const std::string& powerSupplyPath, 558*7066dc58SMyung Bae const std::string& /*service*/) 559*7066dc58SMyung Bae { 560*7066dc58SMyung Bae setLocationIndicatorActive(asyncResp, powerSupplyPath, 561*7066dc58SMyung Bae locationIndicatorActive); 562*7066dc58SMyung Bae } 563*7066dc58SMyung Bae 564*7066dc58SMyung Bae inline void handlePowerSupplyPatch( 565*7066dc58SMyung Bae App& app, const crow::Request& req, 566*7066dc58SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 567*7066dc58SMyung Bae const std::string& chassisId, const std::string& powerSupplyId) 568*7066dc58SMyung Bae { 569*7066dc58SMyung Bae if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 570*7066dc58SMyung Bae { 571*7066dc58SMyung Bae return; 572*7066dc58SMyung Bae } 573*7066dc58SMyung Bae 574*7066dc58SMyung Bae std::optional<bool> locationIndicatorActive; 575*7066dc58SMyung Bae if (!json_util::readJsonPatch( // 576*7066dc58SMyung Bae req, asyncResp->res, // 577*7066dc58SMyung Bae "LocationIndicatorActive", locationIndicatorActive // 578*7066dc58SMyung Bae )) 579*7066dc58SMyung Bae { 580*7066dc58SMyung Bae return; 581*7066dc58SMyung Bae } 582*7066dc58SMyung Bae 583*7066dc58SMyung Bae if (locationIndicatorActive) 584*7066dc58SMyung Bae { 585*7066dc58SMyung Bae // Get the correct power supply Path that match the input parameters 586*7066dc58SMyung Bae getValidPowerSupplyPath(asyncResp, chassisId, powerSupplyId, 587*7066dc58SMyung Bae std::bind_front(doPatchPowerSupply, asyncResp, 588*7066dc58SMyung Bae *locationIndicatorActive)); 589*7066dc58SMyung Bae } 590*7066dc58SMyung Bae } 591*7066dc58SMyung Bae 59200ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app) 59300ef5dc6SGeorge Liu { 59400ef5dc6SGeorge Liu BMCWEB_ROUTE( 59500ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 59600ef5dc6SGeorge Liu .privileges(redfish::privileges::headPowerSupply) 59700ef5dc6SGeorge Liu .methods(boost::beast::http::verb::head)( 59800ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyHead, std::ref(app))); 59900ef5dc6SGeorge Liu 60000ef5dc6SGeorge Liu BMCWEB_ROUTE( 60100ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 60200ef5dc6SGeorge Liu .privileges(redfish::privileges::getPowerSupply) 60300ef5dc6SGeorge Liu .methods(boost::beast::http::verb::get)( 60400ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyGet, std::ref(app))); 605*7066dc58SMyung Bae 606*7066dc58SMyung Bae BMCWEB_ROUTE( 607*7066dc58SMyung Bae app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 608*7066dc58SMyung Bae .privileges(redfish::privileges::patchPowerSupply) 609*7066dc58SMyung Bae .methods(boost::beast::http::verb::patch)( 610*7066dc58SMyung Bae std::bind_front(handlePowerSupplyPatch, std::ref(app))); 61100ef5dc6SGeorge Liu } 61200ef5dc6SGeorge Liu 613a7210020SGeorge Liu } // namespace redfish 614