140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation 4a25aeccfSNikhil Potade #pragma once 5a25aeccfSNikhil Potade 613451e39SWilly Tu #include "bmcweb_config.h" 713451e39SWilly Tu 83ccb3adbSEd Tanous #include "app.hpp" 9d7857201SEd Tanous #include "async_resp.hpp" 107a1dbc48SGeorge Liu #include "dbus_utility.hpp" 11d7857201SEd Tanous #include "error_messages.hpp" 12e5029d88SJohn Edward Broadbent #include "generated/enums/drive.hpp" 13dde9bc12SGeorge Liu #include "generated/enums/protocol.hpp" 14539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 15d7857201SEd Tanous #include "http_request.hpp" 16a8e884fcSEd Tanous #include "human_sort.hpp" 17d7857201SEd Tanous #include "logging.hpp" 183ccb3adbSEd Tanous #include "query.hpp" 19a8e884fcSEd Tanous #include "redfish_util.hpp" 203ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 213f95a277SMyung Bae #include "utils/chassis_utils.hpp" 225e577bc1SWilly Tu #include "utils/collection.hpp" 233ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 242ad9c2f6SJames Feist 25d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 26e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 27ef4c65b7SEd Tanous #include <boost/url/format.hpp> 28d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 29d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 30a25aeccfSNikhil Potade 31d7857201SEd Tanous #include <algorithm> 327a1dbc48SGeorge Liu #include <array> 33d7857201SEd Tanous #include <cstdint> 34d7857201SEd Tanous #include <format> 35d7857201SEd Tanous #include <functional> 36d7857201SEd Tanous #include <memory> 37d7857201SEd Tanous #include <optional> 383544d2a7SEd Tanous #include <ranges> 39d7857201SEd Tanous #include <string> 407a1dbc48SGeorge Liu #include <string_view> 41d7857201SEd Tanous #include <utility> 42d7857201SEd Tanous #include <variant> 43d7857201SEd Tanous #include <vector> 447a1dbc48SGeorge Liu 45a25aeccfSNikhil Potade namespace redfish 46a25aeccfSNikhil Potade { 4736d52334SEd Tanous 4836d52334SEd Tanous inline void handleSystemsStorageCollectionGet( 4936d52334SEd Tanous App& app, const crow::Request& req, 5022d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5136d52334SEd Tanous const std::string& systemName) 5236d52334SEd Tanous { 533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5445ca1b86SEd Tanous { 5545ca1b86SEd Tanous return; 5645ca1b86SEd Tanous } 57253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 5822d268cbSEd Tanous { 5922d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6022d268cbSEd Tanous systemName); 6122d268cbSEd Tanous return; 6222d268cbSEd Tanous } 6322d268cbSEd Tanous 648d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 658d1b46d7Szhanghch05 "#StorageCollection.StorageCollection"; 66253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 67253f11b8SEd Tanous "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME); 688d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Storage Collection"; 695e577bc1SWilly Tu 705e577bc1SWilly Tu constexpr std::array<std::string_view, 1> interface{ 715a39f77aSPatrick Williams "xyz.openbmc_project.Inventory.Item.Storage"}; 725e577bc1SWilly Tu collection_util::getCollectionMembers( 73253f11b8SEd Tanous asyncResp, 74253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage", 75253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME), 7636b5f1edSLakshmi Yadlapati interface, "/xyz/openbmc_project/inventory"); 775e577bc1SWilly Tu } 785e577bc1SWilly Tu 795e577bc1SWilly Tu inline void handleStorageCollectionGet( 805e577bc1SWilly Tu App& app, const crow::Request& req, 815e577bc1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 825e577bc1SWilly Tu { 835e577bc1SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 845e577bc1SWilly Tu { 855e577bc1SWilly Tu return; 865e577bc1SWilly Tu } 875e577bc1SWilly Tu asyncResp->res.jsonValue["@odata.type"] = 885e577bc1SWilly Tu "#StorageCollection.StorageCollection"; 895e577bc1SWilly Tu asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Storage"; 905e577bc1SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage Collection"; 915e577bc1SWilly Tu constexpr std::array<std::string_view, 1> interface{ 925a39f77aSPatrick Williams "xyz.openbmc_project.Inventory.Item.Storage"}; 935e577bc1SWilly Tu collection_util::getCollectionMembers( 9436b5f1edSLakshmi Yadlapati asyncResp, boost::urls::format("/redfish/v1/Storage"), interface, 9536b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 96a25aeccfSNikhil Potade } 97a25aeccfSNikhil Potade 9836d52334SEd Tanous inline void requestRoutesStorageCollection(App& app) 99a25aeccfSNikhil Potade { 10036d52334SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/") 10136d52334SEd Tanous .privileges(redfish::privileges::getStorageCollection) 10236d52334SEd Tanous .methods(boost::beast::http::verb::get)( 10336d52334SEd Tanous std::bind_front(handleSystemsStorageCollectionGet, std::ref(app))); 1045e577bc1SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Storage/") 1055e577bc1SWilly Tu .privileges(redfish::privileges::getStorageCollection) 1065e577bc1SWilly Tu .methods(boost::beast::http::verb::get)( 1075e577bc1SWilly Tu std::bind_front(handleStorageCollectionGet, std::ref(app))); 10836d52334SEd Tanous } 10936d52334SEd Tanous 11036d52334SEd Tanous inline void afterChassisDriveCollectionSubtree( 11136d52334SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1127a1dbc48SGeorge Liu const boost::system::error_code& ec, 11336d52334SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& driveList) 11436d52334SEd Tanous { 115a25aeccfSNikhil Potade if (ec) 116a25aeccfSNikhil Potade { 11762598e31SEd Tanous BMCWEB_LOG_ERROR("Drive mapper call error"); 118a25aeccfSNikhil Potade messages::internalError(asyncResp->res); 119a25aeccfSNikhil Potade return; 120a25aeccfSNikhil Potade } 1212ad9c2f6SJames Feist 122a85afbe1SWilly Tu nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"]; 123a85afbe1SWilly Tu driveArray = nlohmann::json::array(); 124a85afbe1SWilly Tu auto& count = asyncResp->res.jsonValue["Drives@odata.count"]; 125a85afbe1SWilly Tu count = 0; 1262ad9c2f6SJames Feist 127a85afbe1SWilly Tu for (const std::string& drive : driveList) 128a25aeccfSNikhil Potade { 129a85afbe1SWilly Tu sdbusplus::message::object_path object(drive); 130a85afbe1SWilly Tu if (object.filename().empty()) 131a25aeccfSNikhil Potade { 13262598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find filename in {}", drive); 133a85afbe1SWilly Tu return; 134a25aeccfSNikhil Potade } 135a85afbe1SWilly Tu 136a85afbe1SWilly Tu nlohmann::json::object_t driveJson; 137ef4c65b7SEd Tanous driveJson["@odata.id"] = boost::urls::format( 138253f11b8SEd Tanous "/redfish/v1/Systems/{}/Storage/1/Drives/{}", 139253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, object.filename()); 140b2ba3072SPatrick Williams driveArray.emplace_back(std::move(driveJson)); 141a25aeccfSNikhil Potade } 142a25aeccfSNikhil Potade 143a85afbe1SWilly Tu count = driveArray.size(); 14436d52334SEd Tanous } 1457ac13cc9SGunnar Mills inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 14636d52334SEd Tanous { 14736d52334SEd Tanous const std::array<std::string_view, 1> interfaces = { 14836d52334SEd Tanous "xyz.openbmc_project.Inventory.Item.Drive"}; 14936d52334SEd Tanous dbus::utility::getSubTreePaths( 15036d52334SEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces, 1517ac13cc9SGunnar Mills std::bind_front(afterChassisDriveCollectionSubtree, asyncResp)); 152a85afbe1SWilly Tu } 153e284a7c1SJames Feist 1545e577bc1SWilly Tu inline void afterSystemsStorageGetSubtree( 1555e577bc1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1565e577bc1SWilly Tu const std::string& storageId, const boost::system::error_code& ec, 1575e577bc1SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) 158a85afbe1SWilly Tu { 1595e577bc1SWilly Tu if (ec) 160a85afbe1SWilly Tu { 16162598e31SEd Tanous BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error"); 1625e577bc1SWilly Tu messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage", 1635e577bc1SWilly Tu storageId); 164a85afbe1SWilly Tu return; 165a85afbe1SWilly Tu } 1663544d2a7SEd Tanous auto storage = std::ranges::find_if( 1673544d2a7SEd Tanous subtree, 1685e577bc1SWilly Tu [&storageId](const std::pair<std::string, 1695e577bc1SWilly Tu dbus::utility::MapperServiceMap>& object) { 1705e577bc1SWilly Tu return sdbusplus::message::object_path(object.first).filename() == 1715e577bc1SWilly Tu storageId; 1725e577bc1SWilly Tu }); 1735e577bc1SWilly Tu if (storage == subtree.end()) 1745e577bc1SWilly Tu { 1755e577bc1SWilly Tu messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage", 1765e577bc1SWilly Tu storageId); 1775e577bc1SWilly Tu return; 1785e577bc1SWilly Tu } 1795e577bc1SWilly Tu 18061b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage"; 181a85afbe1SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 182253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", 183253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId); 184a85afbe1SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage"; 1855e577bc1SWilly Tu asyncResp->res.jsonValue["Id"] = storageId; 186539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 187a85afbe1SWilly Tu 1887ac13cc9SGunnar Mills getDrives(asyncResp); 189253f11b8SEd Tanous asyncResp->res.jsonValue["Controllers"]["@odata.id"] = 190253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}/Controllers", 191253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId); 1925e577bc1SWilly Tu } 1935e577bc1SWilly Tu 194bd79bce8SPatrick Williams inline void handleSystemsStorageGet( 195bd79bce8SPatrick Williams App& app, const crow::Request& req, 1965e577bc1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 197bd79bce8SPatrick Williams const std::string& systemName, const std::string& storageId) 1985e577bc1SWilly Tu { 1995e577bc1SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2005e577bc1SWilly Tu { 2015e577bc1SWilly Tu return; 2025e577bc1SWilly Tu } 20325b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 2047f3e84a1SEd Tanous { 2057f3e84a1SEd Tanous // Option currently returns no systems. TBD 2067f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2077f3e84a1SEd Tanous systemName); 2087f3e84a1SEd Tanous return; 2097f3e84a1SEd Tanous } 2105e577bc1SWilly Tu 2115e577bc1SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 2125e577bc1SWilly Tu "xyz.openbmc_project.Inventory.Item.Storage"}; 2135e577bc1SWilly Tu dbus::utility::getSubTree( 2145e577bc1SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 2155e577bc1SWilly Tu std::bind_front(afterSystemsStorageGetSubtree, asyncResp, storageId)); 2165e577bc1SWilly Tu } 2175e577bc1SWilly Tu 2185e577bc1SWilly Tu inline void afterSubtree(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2195e577bc1SWilly Tu const std::string& storageId, 2205e577bc1SWilly Tu const boost::system::error_code& ec, 2215e577bc1SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) 2225e577bc1SWilly Tu { 2235e577bc1SWilly Tu if (ec) 2245e577bc1SWilly Tu { 22562598e31SEd Tanous BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error"); 2265e577bc1SWilly Tu messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage", 2275e577bc1SWilly Tu storageId); 2285e577bc1SWilly Tu return; 2295e577bc1SWilly Tu } 2303544d2a7SEd Tanous auto storage = std::ranges::find_if( 2313544d2a7SEd Tanous subtree, 2325e577bc1SWilly Tu [&storageId](const std::pair<std::string, 2335e577bc1SWilly Tu dbus::utility::MapperServiceMap>& object) { 2345e577bc1SWilly Tu return sdbusplus::message::object_path(object.first).filename() == 2355e577bc1SWilly Tu storageId; 2365e577bc1SWilly Tu }); 2375e577bc1SWilly Tu if (storage == subtree.end()) 2385e577bc1SWilly Tu { 2395e577bc1SWilly Tu messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage", 2405e577bc1SWilly Tu storageId); 2415e577bc1SWilly Tu return; 2425e577bc1SWilly Tu } 2435e577bc1SWilly Tu 2445e577bc1SWilly Tu asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage"; 2455e577bc1SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 2465e577bc1SWilly Tu boost::urls::format("/redfish/v1/Storage/{}", storageId); 2475e577bc1SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage"; 2485e577bc1SWilly Tu asyncResp->res.jsonValue["Id"] = storageId; 249539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 2505e577bc1SWilly Tu 2515e577bc1SWilly Tu // Storage subsystem to Storage link. 2525e577bc1SWilly Tu nlohmann::json::array_t storageServices; 2535e577bc1SWilly Tu nlohmann::json::object_t storageService; 2545e577bc1SWilly Tu storageService["@odata.id"] = 255253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", 256253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId); 2575e577bc1SWilly Tu storageServices.emplace_back(storageService); 2585e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["StorageServices"] = 2595e577bc1SWilly Tu std::move(storageServices); 2605e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["StorageServices@odata.count"] = 1; 2615e577bc1SWilly Tu } 2625e577bc1SWilly Tu 263504af5a0SPatrick Williams inline void handleStorageGet( 264504af5a0SPatrick Williams App& app, const crow::Request& req, 2655e577bc1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2665e577bc1SWilly Tu const std::string& storageId) 2675e577bc1SWilly Tu { 2685e577bc1SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2695e577bc1SWilly Tu { 27062598e31SEd Tanous BMCWEB_LOG_DEBUG("requestRoutesStorage setUpRedfishRoute failed"); 2715e577bc1SWilly Tu return; 2725e577bc1SWilly Tu } 2735e577bc1SWilly Tu 2745e577bc1SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 2755e577bc1SWilly Tu "xyz.openbmc_project.Inventory.Item.Storage"}; 2765e577bc1SWilly Tu dbus::utility::getSubTree( 2775e577bc1SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 2785e577bc1SWilly Tu std::bind_front(afterSubtree, asyncResp, storageId)); 27936d52334SEd Tanous } 28036d52334SEd Tanous 28136d52334SEd Tanous inline void requestRoutesStorage(App& app) 28236d52334SEd Tanous { 2837f3e84a1SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/<str>/") 28436d52334SEd Tanous .privileges(redfish::privileges::getStorage) 28536d52334SEd Tanous .methods(boost::beast::http::verb::get)( 28636d52334SEd Tanous std::bind_front(handleSystemsStorageGet, std::ref(app))); 2875e577bc1SWilly Tu 2885e577bc1SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Storage/<str>/") 2895e577bc1SWilly Tu .privileges(redfish::privileges::getStorage) 2905e577bc1SWilly Tu .methods(boost::beast::http::verb::get)( 2915e577bc1SWilly Tu std::bind_front(handleStorageGet, std::ref(app))); 2927e860f15SJohn Edward Broadbent } 2937e860f15SJohn Edward Broadbent 29403913171SWilly Tu inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 29503913171SWilly Tu const std::string& connectionName, 29603913171SWilly Tu const std::string& path) 29703913171SWilly Tu { 298deae6a78SEd Tanous dbus::utility::getProperty<bool>( 299deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present", 300bd79bce8SPatrick Williams [asyncResp, 301bd79bce8SPatrick Williams path](const boost::system::error_code& ec, const bool isPresent) { 30203913171SWilly Tu // this interface isn't necessary, only check it if 30303913171SWilly Tu // we get a good return 30403913171SWilly Tu if (ec) 30503913171SWilly Tu { 30603913171SWilly Tu return; 30703913171SWilly Tu } 30803913171SWilly Tu 309cef57e85SWilly Tu if (!isPresent) 31003913171SWilly Tu { 311539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 312539d8c6bSEd Tanous resource::State::Absent; 31303913171SWilly Tu } 3141e1e598dSJonathan Doman }); 31503913171SWilly Tu } 31603913171SWilly Tu 31703913171SWilly Tu inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 31803913171SWilly Tu const std::string& connectionName, 31903913171SWilly Tu const std::string& path) 32003913171SWilly Tu { 321deae6a78SEd Tanous dbus::utility::getProperty<bool>( 322deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.State.Drive", "Rebuilding", 3235e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, const bool updating) { 32403913171SWilly Tu // this interface isn't necessary, only check it 32503913171SWilly Tu // if we get a good return 32603913171SWilly Tu if (ec) 32703913171SWilly Tu { 32803913171SWilly Tu return; 32903913171SWilly Tu } 33003913171SWilly Tu 33103913171SWilly Tu // updating and disabled in the backend shouldn't be 33203913171SWilly Tu // able to be set at the same time, so we don't need 33303913171SWilly Tu // to check for the race condition of these two 33403913171SWilly Tu // calls 3351e1e598dSJonathan Doman if (updating) 33603913171SWilly Tu { 337539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 338539d8c6bSEd Tanous resource::State::Updating; 33903913171SWilly Tu } 3401e1e598dSJonathan Doman }); 34103913171SWilly Tu } 34203913171SWilly Tu 343dde9bc12SGeorge Liu inline std::optional<drive::MediaType> convertDriveType(std::string_view type) 34419b8e9a0SWilly Tu { 34519b8e9a0SWilly Tu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD") 34619b8e9a0SWilly Tu { 347dde9bc12SGeorge Liu return drive::MediaType::HDD; 34819b8e9a0SWilly Tu } 34919b8e9a0SWilly Tu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD") 35019b8e9a0SWilly Tu { 351dde9bc12SGeorge Liu return drive::MediaType::SSD; 35219b8e9a0SWilly Tu } 353dde9bc12SGeorge Liu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown") 354dde9bc12SGeorge Liu { 35519b8e9a0SWilly Tu return std::nullopt; 35619b8e9a0SWilly Tu } 35719b8e9a0SWilly Tu 358dde9bc12SGeorge Liu return drive::MediaType::Invalid; 359dde9bc12SGeorge Liu } 360dde9bc12SGeorge Liu 361504af5a0SPatrick Williams inline std::optional<protocol::Protocol> convertDriveProtocol( 362504af5a0SPatrick Williams std::string_view proto) 36319b8e9a0SWilly Tu { 36419b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS") 36519b8e9a0SWilly Tu { 366dde9bc12SGeorge Liu return protocol::Protocol::SAS; 36719b8e9a0SWilly Tu } 36819b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA") 36919b8e9a0SWilly Tu { 370dde9bc12SGeorge Liu return protocol::Protocol::SATA; 37119b8e9a0SWilly Tu } 37219b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe") 37319b8e9a0SWilly Tu { 374dde9bc12SGeorge Liu return protocol::Protocol::NVMe; 37519b8e9a0SWilly Tu } 37619b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC") 37719b8e9a0SWilly Tu { 378dde9bc12SGeorge Liu return protocol::Protocol::FC; 379dde9bc12SGeorge Liu } 380dde9bc12SGeorge Liu if (proto == 381dde9bc12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown") 382dde9bc12SGeorge Liu { 383dde9bc12SGeorge Liu return std::nullopt; 38419b8e9a0SWilly Tu } 38519b8e9a0SWilly Tu 386dde9bc12SGeorge Liu return protocol::Protocol::Invalid; 38719b8e9a0SWilly Tu } 38819b8e9a0SWilly Tu 389bd79bce8SPatrick Williams inline void getDriveItemProperties( 390bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 391bd79bce8SPatrick Williams const std::string& connectionName, const std::string& path) 39219b8e9a0SWilly Tu { 393deae6a78SEd Tanous dbus::utility::getAllProperties( 394deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Inventory.Item.Drive", 3955e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 39619b8e9a0SWilly Tu const std::vector< 39719b8e9a0SWilly Tu std::pair<std::string, dbus::utility::DbusVariantType>>& 39819b8e9a0SWilly Tu propertiesList) { 39919b8e9a0SWilly Tu if (ec) 40019b8e9a0SWilly Tu { 40119b8e9a0SWilly Tu // this interface isn't required 40219b8e9a0SWilly Tu return; 40319b8e9a0SWilly Tu } 404e5029d88SJohn Edward Broadbent const std::string* encryptionStatus = nullptr; 405e5029d88SJohn Edward Broadbent const bool* isLocked = nullptr; 40619b8e9a0SWilly Tu for (const std::pair<std::string, dbus::utility::DbusVariantType>& 40719b8e9a0SWilly Tu property : propertiesList) 40819b8e9a0SWilly Tu { 40919b8e9a0SWilly Tu const std::string& propertyName = property.first; 41019b8e9a0SWilly Tu if (propertyName == "Type") 41119b8e9a0SWilly Tu { 41219b8e9a0SWilly Tu const std::string* value = 41319b8e9a0SWilly Tu std::get_if<std::string>(&property.second); 41419b8e9a0SWilly Tu if (value == nullptr) 41519b8e9a0SWilly Tu { 41619b8e9a0SWilly Tu // illegal property 41762598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: Type"); 41819b8e9a0SWilly Tu messages::internalError(asyncResp->res); 41919b8e9a0SWilly Tu return; 42019b8e9a0SWilly Tu } 42119b8e9a0SWilly Tu 422dde9bc12SGeorge Liu std::optional<drive::MediaType> mediaType = 423dde9bc12SGeorge Liu convertDriveType(*value); 42419b8e9a0SWilly Tu if (!mediaType) 42519b8e9a0SWilly Tu { 42662598e31SEd Tanous BMCWEB_LOG_WARNING("UnknownDriveType Interface: {}", 42762598e31SEd Tanous *value); 428dde9bc12SGeorge Liu continue; 429dde9bc12SGeorge Liu } 430dde9bc12SGeorge Liu if (*mediaType == drive::MediaType::Invalid) 431dde9bc12SGeorge Liu { 43219b8e9a0SWilly Tu messages::internalError(asyncResp->res); 43319b8e9a0SWilly Tu return; 43419b8e9a0SWilly Tu } 43519b8e9a0SWilly Tu 43619b8e9a0SWilly Tu asyncResp->res.jsonValue["MediaType"] = *mediaType; 43719b8e9a0SWilly Tu } 43819b8e9a0SWilly Tu else if (propertyName == "Capacity") 43919b8e9a0SWilly Tu { 44019b8e9a0SWilly Tu const uint64_t* capacity = 44119b8e9a0SWilly Tu std::get_if<uint64_t>(&property.second); 44219b8e9a0SWilly Tu if (capacity == nullptr) 44319b8e9a0SWilly Tu { 44462598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: Capacity"); 44519b8e9a0SWilly Tu messages::internalError(asyncResp->res); 44619b8e9a0SWilly Tu return; 44719b8e9a0SWilly Tu } 44819b8e9a0SWilly Tu if (*capacity == 0) 44919b8e9a0SWilly Tu { 45019b8e9a0SWilly Tu // drive capacity not known 45119b8e9a0SWilly Tu continue; 45219b8e9a0SWilly Tu } 45319b8e9a0SWilly Tu 45419b8e9a0SWilly Tu asyncResp->res.jsonValue["CapacityBytes"] = *capacity; 45519b8e9a0SWilly Tu } 45619b8e9a0SWilly Tu else if (propertyName == "Protocol") 45719b8e9a0SWilly Tu { 45819b8e9a0SWilly Tu const std::string* value = 45919b8e9a0SWilly Tu std::get_if<std::string>(&property.second); 46019b8e9a0SWilly Tu if (value == nullptr) 46119b8e9a0SWilly Tu { 46262598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: Protocol"); 46319b8e9a0SWilly Tu messages::internalError(asyncResp->res); 46419b8e9a0SWilly Tu return; 46519b8e9a0SWilly Tu } 46619b8e9a0SWilly Tu 467dde9bc12SGeorge Liu std::optional<protocol::Protocol> proto = 468dde9bc12SGeorge Liu convertDriveProtocol(*value); 46919b8e9a0SWilly Tu if (!proto) 47019b8e9a0SWilly Tu { 471bd79bce8SPatrick Williams BMCWEB_LOG_WARNING( 472bd79bce8SPatrick Williams "Unknown DrivePrototype Interface: {}", *value); 473dde9bc12SGeorge Liu continue; 474dde9bc12SGeorge Liu } 475dde9bc12SGeorge Liu if (*proto == protocol::Protocol::Invalid) 476dde9bc12SGeorge Liu { 47719b8e9a0SWilly Tu messages::internalError(asyncResp->res); 47819b8e9a0SWilly Tu return; 47919b8e9a0SWilly Tu } 48019b8e9a0SWilly Tu asyncResp->res.jsonValue["Protocol"] = *proto; 48119b8e9a0SWilly Tu } 4823fe4d5ccSJohn Edward Broadbent else if (propertyName == "PredictedMediaLifeLeftPercent") 4833fe4d5ccSJohn Edward Broadbent { 4843fe4d5ccSJohn Edward Broadbent const uint8_t* lifeLeft = 4853fe4d5ccSJohn Edward Broadbent std::get_if<uint8_t>(&property.second); 4863fe4d5ccSJohn Edward Broadbent if (lifeLeft == nullptr) 4873fe4d5ccSJohn Edward Broadbent { 48862598e31SEd Tanous BMCWEB_LOG_ERROR( 48962598e31SEd Tanous "Illegal property: PredictedMediaLifeLeftPercent"); 4903fe4d5ccSJohn Edward Broadbent messages::internalError(asyncResp->res); 4913fe4d5ccSJohn Edward Broadbent return; 4923fe4d5ccSJohn Edward Broadbent } 4933fe4d5ccSJohn Edward Broadbent // 255 means reading the value is not supported 4943fe4d5ccSJohn Edward Broadbent if (*lifeLeft != 255) 4953fe4d5ccSJohn Edward Broadbent { 496bd79bce8SPatrick Williams asyncResp->res 497bd79bce8SPatrick Williams .jsonValue["PredictedMediaLifeLeftPercent"] = 4983fe4d5ccSJohn Edward Broadbent *lifeLeft; 4993fe4d5ccSJohn Edward Broadbent } 5003fe4d5ccSJohn Edward Broadbent } 501e5029d88SJohn Edward Broadbent else if (propertyName == "EncryptionStatus") 502e5029d88SJohn Edward Broadbent { 503bd79bce8SPatrick Williams encryptionStatus = 504bd79bce8SPatrick Williams std::get_if<std::string>(&property.second); 505e5029d88SJohn Edward Broadbent if (encryptionStatus == nullptr) 506e5029d88SJohn Edward Broadbent { 50762598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: EncryptionStatus"); 508e5029d88SJohn Edward Broadbent messages::internalError(asyncResp->res); 509e5029d88SJohn Edward Broadbent return; 51019b8e9a0SWilly Tu } 511e5029d88SJohn Edward Broadbent } 512e5029d88SJohn Edward Broadbent else if (propertyName == "Locked") 513e5029d88SJohn Edward Broadbent { 514e5029d88SJohn Edward Broadbent isLocked = std::get_if<bool>(&property.second); 515e5029d88SJohn Edward Broadbent if (isLocked == nullptr) 516e5029d88SJohn Edward Broadbent { 51762598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: Locked"); 518e5029d88SJohn Edward Broadbent messages::internalError(asyncResp->res); 519e5029d88SJohn Edward Broadbent return; 520e5029d88SJohn Edward Broadbent } 521e5029d88SJohn Edward Broadbent } 522e5029d88SJohn Edward Broadbent } 523e5029d88SJohn Edward Broadbent 524e5029d88SJohn Edward Broadbent if (encryptionStatus == nullptr || isLocked == nullptr || 525e5029d88SJohn Edward Broadbent *encryptionStatus == 526a684c226SKonda Reddy Kachana "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Unknown") 527e5029d88SJohn Edward Broadbent { 528e5029d88SJohn Edward Broadbent return; 529e5029d88SJohn Edward Broadbent } 530e5029d88SJohn Edward Broadbent if (*encryptionStatus != 531a684c226SKonda Reddy Kachana "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Encrypted") 532e5029d88SJohn Edward Broadbent { 533e5029d88SJohn Edward Broadbent //"The drive is not currently encrypted." 534e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 535e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Unencrypted; 536e5029d88SJohn Edward Broadbent return; 537e5029d88SJohn Edward Broadbent } 538e5029d88SJohn Edward Broadbent if (*isLocked) 539e5029d88SJohn Edward Broadbent { 540e5029d88SJohn Edward Broadbent //"The drive is currently encrypted and the data is not 541e5029d88SJohn Edward Broadbent // accessible to the user." 542e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 543e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Locked; 544e5029d88SJohn Edward Broadbent return; 545e5029d88SJohn Edward Broadbent } 546e5029d88SJohn Edward Broadbent // if not locked 547e5029d88SJohn Edward Broadbent // "The drive is currently encrypted but the data is accessible 548e5029d88SJohn Edward Broadbent // to the user in unencrypted form." 549e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 550e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Unlocked; 55119b8e9a0SWilly Tu }); 55219b8e9a0SWilly Tu } 55319b8e9a0SWilly Tu 5544ff0f1f4SEd Tanous inline void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 555b53dcd9dSNan Zhou const std::string& connectionName, 556b53dcd9dSNan Zhou const std::string& path, 557e56ed6b9SJohn Edward Broadbent const std::vector<std::string>& interfaces) 558e56ed6b9SJohn Edward Broadbent { 559e56ed6b9SJohn Edward Broadbent for (const std::string& interface : interfaces) 560e56ed6b9SJohn Edward Broadbent { 561e56ed6b9SJohn Edward Broadbent if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset") 562e56ed6b9SJohn Edward Broadbent { 563*f7e62c14SMyung Bae asset_utils::getAssetInfo(asyncResp, connectionName, path, 564*f7e62c14SMyung Bae ""_json_pointer, false); 565e56ed6b9SJohn Edward Broadbent } 566e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.Inventory.Item") 567e56ed6b9SJohn Edward Broadbent { 568e56ed6b9SJohn Edward Broadbent getDrivePresent(asyncResp, connectionName, path); 569e56ed6b9SJohn Edward Broadbent } 570e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.State.Drive") 571e56ed6b9SJohn Edward Broadbent { 572e56ed6b9SJohn Edward Broadbent getDriveState(asyncResp, connectionName, path); 573e56ed6b9SJohn Edward Broadbent } 574e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.Inventory.Item.Drive") 575e56ed6b9SJohn Edward Broadbent { 576e56ed6b9SJohn Edward Broadbent getDriveItemProperties(asyncResp, connectionName, path); 577e56ed6b9SJohn Edward Broadbent } 578e56ed6b9SJohn Edward Broadbent } 579e56ed6b9SJohn Edward Broadbent } 580e56ed6b9SJohn Edward Broadbent 58136d52334SEd Tanous inline void afterGetSubtreeSystemsStorageDrive( 58245ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 58336d52334SEd Tanous const std::string& driveId, const boost::system::error_code& ec, 58436d52334SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) 58545ca1b86SEd Tanous { 5867e860f15SJohn Edward Broadbent if (ec) 5877e860f15SJohn Edward Broadbent { 58862598e31SEd Tanous BMCWEB_LOG_ERROR("Drive mapper call error"); 5897e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 5907e860f15SJohn Edward Broadbent return; 5917e860f15SJohn Edward Broadbent } 5927e860f15SJohn Edward Broadbent 5933544d2a7SEd Tanous auto drive = std::ranges::find_if( 5943544d2a7SEd Tanous subtree, 59536d52334SEd Tanous [&driveId](const std::pair<std::string, 5968cb65f8aSNan Zhou dbus::utility::MapperServiceMap>& object) { 59736d52334SEd Tanous return sdbusplus::message::object_path(object.first).filename() == 59836d52334SEd Tanous driveId; 5997e860f15SJohn Edward Broadbent }); 6007e860f15SJohn Edward Broadbent 60103913171SWilly Tu if (drive == subtree.end()) 6027e860f15SJohn Edward Broadbent { 603002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "Drive", driveId); 6047e860f15SJohn Edward Broadbent return; 6057e860f15SJohn Edward Broadbent } 6067e860f15SJohn Edward Broadbent 60703913171SWilly Tu const std::string& path = drive->first; 60836d52334SEd Tanous const dbus::utility::MapperServiceMap& connectionNames = drive->second; 6097e860f15SJohn Edward Broadbent 610002d39b4SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive"; 611253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 612253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Drives/{}", 613253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, driveId); 6147e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = driveId; 6157e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Id"] = driveId; 6167e860f15SJohn Edward Broadbent 6177e860f15SJohn Edward Broadbent if (connectionNames.size() != 1) 6187e860f15SJohn Edward Broadbent { 61962598e31SEd Tanous BMCWEB_LOG_ERROR("Connection size {}, not equal to 1", 62062598e31SEd Tanous connectionNames.size()); 6217e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 6227e860f15SJohn Edward Broadbent return; 6237e860f15SJohn Edward Broadbent } 6247e860f15SJohn Edward Broadbent 625bd79bce8SPatrick Williams getMainChassisId( 626bd79bce8SPatrick Williams asyncResp, [](const std::string& chassisId, 6277e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 628002d39b4SEd Tanous aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] = 629ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 6307e860f15SJohn Edward Broadbent }); 6317e860f15SJohn Edward Broadbent 632a25aeccfSNikhil Potade // default it to Enabled 633539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 634a25aeccfSNikhil Potade 635e56ed6b9SJohn Edward Broadbent addAllDriveInfo(asyncResp, connectionNames[0].first, path, 636e56ed6b9SJohn Edward Broadbent connectionNames[0].second); 637a25aeccfSNikhil Potade } 63892903bd4SJohn Edward Broadbent 63936d52334SEd Tanous inline void handleSystemsStorageDriveGet( 64036d52334SEd Tanous App& app, const crow::Request& req, 64192903bd4SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 64236d52334SEd Tanous const std::string& systemName, const std::string& driveId) 64392903bd4SJohn Edward Broadbent { 6443ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 64592903bd4SJohn Edward Broadbent { 64692903bd4SJohn Edward Broadbent return; 64792903bd4SJohn Edward Broadbent } 64825b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6497f3e84a1SEd Tanous { 6507f3e84a1SEd Tanous // Option currently returns no systems. TBD 6517f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 6527f3e84a1SEd Tanous systemName); 6537f3e84a1SEd Tanous return; 6547f3e84a1SEd Tanous } 6557f3e84a1SEd Tanous 656253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 65736d52334SEd Tanous { 65836d52334SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 65936d52334SEd Tanous systemName); 66036d52334SEd Tanous return; 66136d52334SEd Tanous } 66292903bd4SJohn Edward Broadbent 66336d52334SEd Tanous constexpr std::array<std::string_view, 1> interfaces = { 66436d52334SEd Tanous "xyz.openbmc_project.Inventory.Item.Drive"}; 665e99073f5SGeorge Liu dbus::utility::getSubTree( 666e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 66736d52334SEd Tanous std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp, 66836d52334SEd Tanous driveId)); 66936d52334SEd Tanous } 67036d52334SEd Tanous 67136d52334SEd Tanous inline void requestRoutesDrive(App& app) 67236d52334SEd Tanous { 67336d52334SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/") 67436d52334SEd Tanous .privileges(redfish::privileges::getDrive) 67536d52334SEd Tanous .methods(boost::beast::http::verb::get)( 67636d52334SEd Tanous std::bind_front(handleSystemsStorageDriveGet, std::ref(app))); 67736d52334SEd Tanous } 67836d52334SEd Tanous 67936d52334SEd Tanous inline void afterChassisDriveCollectionSubtreeGet( 68036d52334SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 68136d52334SEd Tanous const std::string& chassisId, const boost::system::error_code& ec, 68236d52334SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) 68336d52334SEd Tanous { 68492903bd4SJohn Edward Broadbent if (ec) 68592903bd4SJohn Edward Broadbent { 68692903bd4SJohn Edward Broadbent if (ec == boost::system::errc::host_unreachable) 68792903bd4SJohn Edward Broadbent { 68836d52334SEd Tanous messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 68992903bd4SJohn Edward Broadbent return; 69092903bd4SJohn Edward Broadbent } 69192903bd4SJohn Edward Broadbent messages::internalError(asyncResp->res); 69292903bd4SJohn Edward Broadbent return; 69392903bd4SJohn Edward Broadbent } 69492903bd4SJohn Edward Broadbent 69592903bd4SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 6968cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 69792903bd4SJohn Edward Broadbent { 69892903bd4SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 69992903bd4SJohn Edward Broadbent if (objPath.filename() != chassisId) 70092903bd4SJohn Edward Broadbent { 70192903bd4SJohn Edward Broadbent continue; 70292903bd4SJohn Edward Broadbent } 70392903bd4SJohn Edward Broadbent 70492903bd4SJohn Edward Broadbent if (connectionNames.empty()) 70592903bd4SJohn Edward Broadbent { 70662598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 70792903bd4SJohn Edward Broadbent continue; 70892903bd4SJohn Edward Broadbent } 70992903bd4SJohn Edward Broadbent 71092903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.type"] = 71192903bd4SJohn Edward Broadbent "#DriveCollection.DriveCollection"; 71292903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.id"] = 713ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId); 71492903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = "Drive Collection"; 71592903bd4SJohn Edward Broadbent 71692903bd4SJohn Edward Broadbent // Association lambda 7176c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 7186c3e9451SGeorge Liu path + "/drive", 71936d52334SEd Tanous [asyncResp, chassisId](const boost::system::error_code& ec3, 7206c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 72192903bd4SJohn Edward Broadbent if (ec3) 72292903bd4SJohn Edward Broadbent { 72362598e31SEd Tanous BMCWEB_LOG_ERROR("Error in chassis Drive association "); 72492903bd4SJohn Edward Broadbent } 72592903bd4SJohn Edward Broadbent nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 72692903bd4SJohn Edward Broadbent // important if array is empty 72792903bd4SJohn Edward Broadbent members = nlohmann::json::array(); 72892903bd4SJohn Edward Broadbent 72992903bd4SJohn Edward Broadbent std::vector<std::string> leafNames; 73092903bd4SJohn Edward Broadbent for (const auto& drive : resp) 73192903bd4SJohn Edward Broadbent { 7328a592810SEd Tanous sdbusplus::message::object_path drivePath(drive); 7338a592810SEd Tanous leafNames.push_back(drivePath.filename()); 73492903bd4SJohn Edward Broadbent } 73592903bd4SJohn Edward Broadbent 7363544d2a7SEd Tanous std::ranges::sort(leafNames, AlphanumLess<std::string>()); 73792903bd4SJohn Edward Broadbent 73892903bd4SJohn Edward Broadbent for (const auto& leafName : leafNames) 73992903bd4SJohn Edward Broadbent { 74092903bd4SJohn Edward Broadbent nlohmann::json::object_t member; 741bd79bce8SPatrick Williams member["@odata.id"] = 742bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}/Drives/{}", 743bd79bce8SPatrick Williams chassisId, leafName); 744b2ba3072SPatrick Williams members.emplace_back(std::move(member)); 74592903bd4SJohn Edward Broadbent // navigation links will be registered in next patch set 74692903bd4SJohn Edward Broadbent } 74792903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = resp.size(); 74892903bd4SJohn Edward Broadbent }); // end association lambda 74992903bd4SJohn Edward Broadbent 75092903bd4SJohn Edward Broadbent } // end Iterate over all retrieved ObjectPaths 75136d52334SEd Tanous } 75236d52334SEd Tanous /** 75336d52334SEd Tanous * Chassis drives, this URL will show all the DriveCollection 75436d52334SEd Tanous * information 75536d52334SEd Tanous */ 75636d52334SEd Tanous inline void chassisDriveCollectionGet( 75736d52334SEd Tanous crow::App& app, const crow::Request& req, 75836d52334SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 75936d52334SEd Tanous const std::string& chassisId) 76036d52334SEd Tanous { 76136d52334SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 76236d52334SEd Tanous { 76336d52334SEd Tanous return; 76436d52334SEd Tanous } 76536d52334SEd Tanous 76636d52334SEd Tanous // mapper call lambda 76736d52334SEd Tanous dbus::utility::getSubTree( 7683f95a277SMyung Bae "/xyz/openbmc_project/inventory", 0, chassisInterfaces, 76936d52334SEd Tanous std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp, 77036d52334SEd Tanous chassisId)); 77192903bd4SJohn Edward Broadbent } 77292903bd4SJohn Edward Broadbent 77392903bd4SJohn Edward Broadbent inline void requestRoutesChassisDrive(App& app) 77492903bd4SJohn Edward Broadbent { 77592903bd4SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/") 77692903bd4SJohn Edward Broadbent .privileges(redfish::privileges::getDriveCollection) 77792903bd4SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 77892903bd4SJohn Edward Broadbent std::bind_front(chassisDriveCollectionGet, std::ref(app))); 77992903bd4SJohn Edward Broadbent } 78092903bd4SJohn Edward Broadbent 781b53dcd9dSNan Zhou inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 782b53dcd9dSNan Zhou const std::string& chassisId, 783b53dcd9dSNan Zhou const std::string& driveName, 7845e7e2dc5SEd Tanous const boost::system::error_code& ec, 785e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) 786e56ed6b9SJohn Edward Broadbent { 787e56ed6b9SJohn Edward Broadbent if (ec) 788e56ed6b9SJohn Edward Broadbent { 78962598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 790e56ed6b9SJohn Edward Broadbent messages::internalError(asyncResp->res); 791e56ed6b9SJohn Edward Broadbent return; 792e56ed6b9SJohn Edward Broadbent } 793e56ed6b9SJohn Edward Broadbent 794e56ed6b9SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 7958cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 796e56ed6b9SJohn Edward Broadbent { 797e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 798e56ed6b9SJohn Edward Broadbent if (objPath.filename() != driveName) 799e56ed6b9SJohn Edward Broadbent { 800e56ed6b9SJohn Edward Broadbent continue; 801e56ed6b9SJohn Edward Broadbent } 802e56ed6b9SJohn Edward Broadbent 803e56ed6b9SJohn Edward Broadbent if (connectionNames.empty()) 804e56ed6b9SJohn Edward Broadbent { 80562598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 806e56ed6b9SJohn Edward Broadbent continue; 807e56ed6b9SJohn Edward Broadbent } 808e56ed6b9SJohn Edward Broadbent 809ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 810ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName); 811e56ed6b9SJohn Edward Broadbent 812e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive"; 813a0cb40cbSJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = driveName; 814e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["Id"] = driveName; 815e56ed6b9SJohn Edward Broadbent // default it to Enabled 816539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 817e56ed6b9SJohn Edward Broadbent 818e56ed6b9SJohn Edward Broadbent nlohmann::json::object_t linkChassisNav; 819e56ed6b9SJohn Edward Broadbent linkChassisNav["@odata.id"] = 820ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 821e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav; 822e56ed6b9SJohn Edward Broadbent 823e56ed6b9SJohn Edward Broadbent addAllDriveInfo(asyncResp, connectionNames[0].first, path, 824e56ed6b9SJohn Edward Broadbent connectionNames[0].second); 825e56ed6b9SJohn Edward Broadbent } 826e56ed6b9SJohn Edward Broadbent } 827e56ed6b9SJohn Edward Broadbent 828bd79bce8SPatrick Williams inline void matchAndFillDrive( 829bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 830bd79bce8SPatrick Williams const std::string& chassisId, const std::string& driveName, 831e56ed6b9SJohn Edward Broadbent const std::vector<std::string>& resp) 832e56ed6b9SJohn Edward Broadbent { 833e56ed6b9SJohn Edward Broadbent for (const std::string& drivePath : resp) 834e56ed6b9SJohn Edward Broadbent { 835e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path path(drivePath); 836e56ed6b9SJohn Edward Broadbent std::string leaf = path.filename(); 837e56ed6b9SJohn Edward Broadbent if (leaf != driveName) 838e56ed6b9SJohn Edward Broadbent { 839e56ed6b9SJohn Edward Broadbent continue; 840e56ed6b9SJohn Edward Broadbent } 841e56ed6b9SJohn Edward Broadbent // mapper call drive 842e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> driveInterface = { 843e56ed6b9SJohn Edward Broadbent "xyz.openbmc_project.Inventory.Item.Drive"}; 844e99073f5SGeorge Liu dbus::utility::getSubTree( 845e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, driveInterface, 846e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, driveName]( 847e99073f5SGeorge Liu const boost::system::error_code& ec, 848e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) { 849e56ed6b9SJohn Edward Broadbent buildDrive(asyncResp, chassisId, driveName, ec, subtree); 850e99073f5SGeorge Liu }); 851e56ed6b9SJohn Edward Broadbent } 852e56ed6b9SJohn Edward Broadbent } 853e56ed6b9SJohn Edward Broadbent 854bd79bce8SPatrick Williams inline void handleChassisDriveGet( 855bd79bce8SPatrick Williams crow::App& app, const crow::Request& req, 856e56ed6b9SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 857bd79bce8SPatrick Williams const std::string& chassisId, const std::string& driveName) 858e56ed6b9SJohn Edward Broadbent { 85903810a11SMichal Orzel if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 860e56ed6b9SJohn Edward Broadbent { 861e56ed6b9SJohn Edward Broadbent return; 862e56ed6b9SJohn Edward Broadbent } 863e56ed6b9SJohn Edward Broadbent 864e56ed6b9SJohn Edward Broadbent // mapper call chassis 865e99073f5SGeorge Liu dbus::utility::getSubTree( 8663f95a277SMyung Bae "/xyz/openbmc_project/inventory", 0, chassisInterfaces, 867e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, 868e99073f5SGeorge Liu driveName](const boost::system::error_code& ec, 869e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) { 870e56ed6b9SJohn Edward Broadbent if (ec) 871e56ed6b9SJohn Edward Broadbent { 872e56ed6b9SJohn Edward Broadbent messages::internalError(asyncResp->res); 873e56ed6b9SJohn Edward Broadbent return; 874e56ed6b9SJohn Edward Broadbent } 875e56ed6b9SJohn Edward Broadbent 876e56ed6b9SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 8778cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 878e56ed6b9SJohn Edward Broadbent { 879e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 880e56ed6b9SJohn Edward Broadbent if (objPath.filename() != chassisId) 881e56ed6b9SJohn Edward Broadbent { 882e56ed6b9SJohn Edward Broadbent continue; 883e56ed6b9SJohn Edward Broadbent } 884e56ed6b9SJohn Edward Broadbent 885e56ed6b9SJohn Edward Broadbent if (connectionNames.empty()) 886e56ed6b9SJohn Edward Broadbent { 88762598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 888e56ed6b9SJohn Edward Broadbent continue; 889e56ed6b9SJohn Edward Broadbent } 890e56ed6b9SJohn Edward Broadbent 8916c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 8926c3e9451SGeorge Liu path + "/drive", 893e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, 8945e7e2dc5SEd Tanous driveName](const boost::system::error_code& ec3, 8956c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 896e56ed6b9SJohn Edward Broadbent if (ec3) 897e56ed6b9SJohn Edward Broadbent { 898e56ed6b9SJohn Edward Broadbent return; // no drives = no failures 899e56ed6b9SJohn Edward Broadbent } 900bd79bce8SPatrick Williams matchAndFillDrive(asyncResp, chassisId, driveName, 901bd79bce8SPatrick Williams resp); 902e56ed6b9SJohn Edward Broadbent }); 903d8f53b82SJian Zhang return; 904e56ed6b9SJohn Edward Broadbent } 905d8f53b82SJian Zhang // Couldn't find an object with that name. return an error 906d8f53b82SJian Zhang messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 907e99073f5SGeorge Liu }); 908e56ed6b9SJohn Edward Broadbent } 909e56ed6b9SJohn Edward Broadbent 910e56ed6b9SJohn Edward Broadbent /** 911e56ed6b9SJohn Edward Broadbent * This URL will show the drive interface for the specific drive in the chassis 912e56ed6b9SJohn Edward Broadbent */ 913e56ed6b9SJohn Edward Broadbent inline void requestRoutesChassisDriveName(App& app) 914e56ed6b9SJohn Edward Broadbent { 915e56ed6b9SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/") 916e56ed6b9SJohn Edward Broadbent .privileges(redfish::privileges::getChassis) 917e56ed6b9SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 918e56ed6b9SJohn Edward Broadbent std::bind_front(handleChassisDriveGet, std::ref(app))); 919e56ed6b9SJohn Edward Broadbent } 920e56ed6b9SJohn Edward Broadbent 92161b1eb21SWilly Tu inline void populateStorageController( 92261b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 92361b1eb21SWilly Tu const std::string& controllerId, const std::string& connectionName, 92461b1eb21SWilly Tu const std::string& path) 92561b1eb21SWilly Tu { 92661b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = 92761b1eb21SWilly Tu "#StorageController.v1_6_0.StorageController"; 928253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 929253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Controllers/{}", 930253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, controllerId); 93161b1eb21SWilly Tu asyncResp->res.jsonValue["Name"] = controllerId; 93261b1eb21SWilly Tu asyncResp->res.jsonValue["Id"] = controllerId; 933539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 93461b1eb21SWilly Tu 935deae6a78SEd Tanous dbus::utility::getProperty<bool>( 936deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present", 93761b1eb21SWilly Tu [asyncResp](const boost::system::error_code& ec, bool isPresent) { 93861b1eb21SWilly Tu // this interface isn't necessary, only check it 93961b1eb21SWilly Tu // if we get a good return 94061b1eb21SWilly Tu if (ec) 94161b1eb21SWilly Tu { 94262598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to get Present property"); 94361b1eb21SWilly Tu return; 94461b1eb21SWilly Tu } 94561b1eb21SWilly Tu if (!isPresent) 94661b1eb21SWilly Tu { 947539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 948539d8c6bSEd Tanous resource::State::Absent; 94961b1eb21SWilly Tu } 95061b1eb21SWilly Tu }); 95161b1eb21SWilly Tu 952*f7e62c14SMyung Bae asset_utils::getAssetInfo(asyncResp, connectionName, path, ""_json_pointer, 953*f7e62c14SMyung Bae false); 95461b1eb21SWilly Tu } 95561b1eb21SWilly Tu 95661b1eb21SWilly Tu inline void getStorageControllerHandler( 95761b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 95861b1eb21SWilly Tu const std::string& controllerId, const boost::system::error_code& ec, 95961b1eb21SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) 96061b1eb21SWilly Tu { 96161b1eb21SWilly Tu if (ec || subtree.empty()) 96261b1eb21SWilly Tu { 96361b1eb21SWilly Tu // doesn't have to be there 96462598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to handle StorageController"); 96561b1eb21SWilly Tu return; 96661b1eb21SWilly Tu } 96761b1eb21SWilly Tu 96861b1eb21SWilly Tu for (const auto& [path, interfaceDict] : subtree) 96961b1eb21SWilly Tu { 97061b1eb21SWilly Tu sdbusplus::message::object_path object(path); 97161b1eb21SWilly Tu std::string id = object.filename(); 97261b1eb21SWilly Tu if (id.empty()) 97361b1eb21SWilly Tu { 97462598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find filename in {}", path); 97561b1eb21SWilly Tu return; 97661b1eb21SWilly Tu } 97761b1eb21SWilly Tu if (id != controllerId) 97861b1eb21SWilly Tu { 97961b1eb21SWilly Tu continue; 98061b1eb21SWilly Tu } 98161b1eb21SWilly Tu 98261b1eb21SWilly Tu if (interfaceDict.size() != 1) 98361b1eb21SWilly Tu { 98462598e31SEd Tanous BMCWEB_LOG_ERROR("Connection size {}, greater than 1", 98562598e31SEd Tanous interfaceDict.size()); 98661b1eb21SWilly Tu messages::internalError(asyncResp->res); 98761b1eb21SWilly Tu return; 98861b1eb21SWilly Tu } 98961b1eb21SWilly Tu 99061b1eb21SWilly Tu const std::string& connectionName = interfaceDict.front().first; 99161b1eb21SWilly Tu populateStorageController(asyncResp, controllerId, connectionName, 99261b1eb21SWilly Tu path); 99361b1eb21SWilly Tu } 99461b1eb21SWilly Tu } 99561b1eb21SWilly Tu 99661b1eb21SWilly Tu inline void populateStorageControllerCollection( 99761b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 99861b1eb21SWilly Tu const boost::system::error_code& ec, 99961b1eb21SWilly Tu const dbus::utility::MapperGetSubTreePathsResponse& controllerList) 100061b1eb21SWilly Tu { 100161b1eb21SWilly Tu nlohmann::json::array_t members; 100261b1eb21SWilly Tu if (ec || controllerList.empty()) 100361b1eb21SWilly Tu { 100461b1eb21SWilly Tu asyncResp->res.jsonValue["Members"] = std::move(members); 100561b1eb21SWilly Tu asyncResp->res.jsonValue["Members@odata.count"] = 0; 100662598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to find any StorageController"); 100761b1eb21SWilly Tu return; 100861b1eb21SWilly Tu } 100961b1eb21SWilly Tu 101061b1eb21SWilly Tu for (const std::string& path : controllerList) 101161b1eb21SWilly Tu { 101261b1eb21SWilly Tu std::string id = sdbusplus::message::object_path(path).filename(); 101361b1eb21SWilly Tu if (id.empty()) 101461b1eb21SWilly Tu { 101562598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find filename in {}", path); 101661b1eb21SWilly Tu return; 101761b1eb21SWilly Tu } 101861b1eb21SWilly Tu nlohmann::json::object_t member; 101961b1eb21SWilly Tu member["@odata.id"] = boost::urls::format( 1020253f11b8SEd Tanous "/redfish/v1/Systems/{}/Storage/1/Controllers/{}", 1021253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, id); 102261b1eb21SWilly Tu members.emplace_back(member); 102361b1eb21SWilly Tu } 102461b1eb21SWilly Tu asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 102561b1eb21SWilly Tu asyncResp->res.jsonValue["Members"] = std::move(members); 102661b1eb21SWilly Tu } 102761b1eb21SWilly Tu 102836d52334SEd Tanous inline void handleSystemsStorageControllerCollectionGet( 102961b1eb21SWilly Tu App& app, const crow::Request& req, 103061b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 103161b1eb21SWilly Tu const std::string& systemName) 103261b1eb21SWilly Tu { 103361b1eb21SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 103461b1eb21SWilly Tu { 103562598e31SEd Tanous BMCWEB_LOG_DEBUG( 103662598e31SEd Tanous "Failed to setup Redfish Route for StorageController Collection"); 103761b1eb21SWilly Tu return; 103861b1eb21SWilly Tu } 1039253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 104061b1eb21SWilly Tu { 104161b1eb21SWilly Tu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 104261b1eb21SWilly Tu systemName); 104362598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName); 104461b1eb21SWilly Tu return; 104561b1eb21SWilly Tu } 104661b1eb21SWilly Tu 104761b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = 104861b1eb21SWilly Tu "#StorageControllerCollection.StorageControllerCollection"; 104961b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 1050253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/Storage/1/Controllers", 1051253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 105261b1eb21SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage Controller Collection"; 105361b1eb21SWilly Tu 105461b1eb21SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 105561b1eb21SWilly Tu "xyz.openbmc_project.Inventory.Item.StorageController"}; 105661b1eb21SWilly Tu dbus::utility::getSubTreePaths( 105761b1eb21SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 105861b1eb21SWilly Tu [asyncResp](const boost::system::error_code& ec, 105961b1eb21SWilly Tu const dbus::utility::MapperGetSubTreePathsResponse& 106061b1eb21SWilly Tu controllerList) { 106161b1eb21SWilly Tu populateStorageControllerCollection(asyncResp, ec, controllerList); 106261b1eb21SWilly Tu }); 106361b1eb21SWilly Tu } 106461b1eb21SWilly Tu 106536d52334SEd Tanous inline void handleSystemsStorageControllerGet( 106661b1eb21SWilly Tu App& app, const crow::Request& req, 106761b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 106861b1eb21SWilly Tu const std::string& systemName, const std::string& controllerId) 106961b1eb21SWilly Tu { 107061b1eb21SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 107161b1eb21SWilly Tu { 107262598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController"); 107361b1eb21SWilly Tu return; 107461b1eb21SWilly Tu } 1075253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 107661b1eb21SWilly Tu { 107761b1eb21SWilly Tu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 107861b1eb21SWilly Tu systemName); 107962598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName); 108061b1eb21SWilly Tu return; 108161b1eb21SWilly Tu } 108261b1eb21SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 108361b1eb21SWilly Tu "xyz.openbmc_project.Inventory.Item.StorageController"}; 108461b1eb21SWilly Tu dbus::utility::getSubTree( 108561b1eb21SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 108661b1eb21SWilly Tu [asyncResp, 108761b1eb21SWilly Tu controllerId](const boost::system::error_code& ec, 108861b1eb21SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) { 108961b1eb21SWilly Tu getStorageControllerHandler(asyncResp, controllerId, ec, subtree); 109061b1eb21SWilly Tu }); 109161b1eb21SWilly Tu } 109261b1eb21SWilly Tu 109361b1eb21SWilly Tu inline void requestRoutesStorageControllerCollection(App& app) 109461b1eb21SWilly Tu { 109561b1eb21SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/") 109661b1eb21SWilly Tu .privileges(redfish::privileges::getStorageControllerCollection) 109736d52334SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 109836d52334SEd Tanous handleSystemsStorageControllerCollectionGet, std::ref(app))); 109961b1eb21SWilly Tu } 110061b1eb21SWilly Tu 110161b1eb21SWilly Tu inline void requestRoutesStorageController(App& app) 110261b1eb21SWilly Tu { 110361b1eb21SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>") 110461b1eb21SWilly Tu .privileges(redfish::privileges::getStorageController) 110561b1eb21SWilly Tu .methods(boost::beast::http::verb::get)( 110636d52334SEd Tanous std::bind_front(handleSystemsStorageControllerGet, std::ref(app))); 110761b1eb21SWilly Tu } 110861b1eb21SWilly Tu 1109a25aeccfSNikhil Potade } // namespace redfish 1110