1a25aeccfSNikhil Potade /* 26be832e2SEd Tanous Copyright (c) 2019 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd Tanous limitations under the License. 15a25aeccfSNikhil Potade */ 16a25aeccfSNikhil Potade #pragma once 17a25aeccfSNikhil Potade 1813451e39SWilly Tu #include "bmcweb_config.h" 1913451e39SWilly Tu 203ccb3adbSEd Tanous #include "app.hpp" 217a1dbc48SGeorge Liu #include "dbus_utility.hpp" 22e5029d88SJohn Edward Broadbent #include "generated/enums/drive.hpp" 23dde9bc12SGeorge Liu #include "generated/enums/protocol.hpp" 24539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 25a8e884fcSEd Tanous #include "human_sort.hpp" 263ccb3adbSEd Tanous #include "query.hpp" 27a8e884fcSEd Tanous #include "redfish_util.hpp" 283ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 295e577bc1SWilly Tu #include "utils/collection.hpp" 303ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 312ad9c2f6SJames Feist 32e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 33ef4c65b7SEd Tanous #include <boost/url/format.hpp> 341e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 35d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 36a25aeccfSNikhil Potade 377a1dbc48SGeorge Liu #include <array> 383544d2a7SEd Tanous #include <ranges> 397a1dbc48SGeorge Liu #include <string_view> 407a1dbc48SGeorge Liu 41a25aeccfSNikhil Potade namespace redfish 42a25aeccfSNikhil Potade { 4336d52334SEd Tanous 4436d52334SEd Tanous inline void handleSystemsStorageCollectionGet( 4536d52334SEd Tanous App& app, const crow::Request& req, 4622d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4736d52334SEd Tanous const std::string& systemName) 4836d52334SEd Tanous { 493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5045ca1b86SEd Tanous { 5145ca1b86SEd Tanous return; 5245ca1b86SEd Tanous } 53253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 5422d268cbSEd Tanous { 5522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5622d268cbSEd Tanous systemName); 5722d268cbSEd Tanous return; 5822d268cbSEd Tanous } 5922d268cbSEd Tanous 608d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 618d1b46d7Szhanghch05 "#StorageCollection.StorageCollection"; 62253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = std::format( 63253f11b8SEd Tanous "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME); 648d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Storage Collection"; 655e577bc1SWilly Tu 665e577bc1SWilly Tu constexpr std::array<std::string_view, 1> interface{ 675a39f77aSPatrick Williams "xyz.openbmc_project.Inventory.Item.Storage"}; 685e577bc1SWilly Tu collection_util::getCollectionMembers( 69253f11b8SEd Tanous asyncResp, 70253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage", 71253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME), 7236b5f1edSLakshmi Yadlapati interface, "/xyz/openbmc_project/inventory"); 735e577bc1SWilly Tu } 745e577bc1SWilly Tu 755e577bc1SWilly Tu inline void handleStorageCollectionGet( 765e577bc1SWilly Tu App& app, const crow::Request& req, 775e577bc1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 785e577bc1SWilly Tu { 795e577bc1SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 805e577bc1SWilly Tu { 815e577bc1SWilly Tu return; 825e577bc1SWilly Tu } 835e577bc1SWilly Tu asyncResp->res.jsonValue["@odata.type"] = 845e577bc1SWilly Tu "#StorageCollection.StorageCollection"; 855e577bc1SWilly Tu asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Storage"; 865e577bc1SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage Collection"; 875e577bc1SWilly Tu constexpr std::array<std::string_view, 1> interface{ 885a39f77aSPatrick Williams "xyz.openbmc_project.Inventory.Item.Storage"}; 895e577bc1SWilly Tu collection_util::getCollectionMembers( 9036b5f1edSLakshmi Yadlapati asyncResp, boost::urls::format("/redfish/v1/Storage"), interface, 9136b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 92a25aeccfSNikhil Potade } 93a25aeccfSNikhil Potade 9436d52334SEd Tanous inline void requestRoutesStorageCollection(App& app) 95a25aeccfSNikhil Potade { 9636d52334SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/") 9736d52334SEd Tanous .privileges(redfish::privileges::getStorageCollection) 9836d52334SEd Tanous .methods(boost::beast::http::verb::get)( 9936d52334SEd Tanous std::bind_front(handleSystemsStorageCollectionGet, std::ref(app))); 1005e577bc1SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Storage/") 1015e577bc1SWilly Tu .privileges(redfish::privileges::getStorageCollection) 1025e577bc1SWilly Tu .methods(boost::beast::http::verb::get)( 1035e577bc1SWilly Tu std::bind_front(handleStorageCollectionGet, std::ref(app))); 10436d52334SEd Tanous } 10536d52334SEd Tanous 10636d52334SEd Tanous inline void afterChassisDriveCollectionSubtree( 10736d52334SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1087a1dbc48SGeorge Liu const boost::system::error_code& ec, 10936d52334SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& driveList) 11036d52334SEd Tanous { 111a25aeccfSNikhil Potade if (ec) 112a25aeccfSNikhil Potade { 11362598e31SEd Tanous BMCWEB_LOG_ERROR("Drive mapper call error"); 114a25aeccfSNikhil Potade messages::internalError(asyncResp->res); 115a25aeccfSNikhil Potade return; 116a25aeccfSNikhil Potade } 1172ad9c2f6SJames Feist 118a85afbe1SWilly Tu nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"]; 119a85afbe1SWilly Tu driveArray = nlohmann::json::array(); 120a85afbe1SWilly Tu auto& count = asyncResp->res.jsonValue["Drives@odata.count"]; 121a85afbe1SWilly Tu count = 0; 1222ad9c2f6SJames Feist 123a85afbe1SWilly Tu for (const std::string& drive : driveList) 124a25aeccfSNikhil Potade { 125a85afbe1SWilly Tu sdbusplus::message::object_path object(drive); 126a85afbe1SWilly Tu if (object.filename().empty()) 127a25aeccfSNikhil Potade { 12862598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find filename in {}", drive); 129a85afbe1SWilly Tu return; 130a25aeccfSNikhil Potade } 131a85afbe1SWilly Tu 132a85afbe1SWilly Tu nlohmann::json::object_t driveJson; 133ef4c65b7SEd Tanous driveJson["@odata.id"] = boost::urls::format( 134253f11b8SEd Tanous "/redfish/v1/Systems/{}/Storage/1/Drives/{}", 135253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, object.filename()); 136b2ba3072SPatrick Williams driveArray.emplace_back(std::move(driveJson)); 137a25aeccfSNikhil Potade } 138a25aeccfSNikhil Potade 139a85afbe1SWilly Tu count = driveArray.size(); 14036d52334SEd Tanous } 1417ac13cc9SGunnar Mills inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 14236d52334SEd Tanous { 14336d52334SEd Tanous const std::array<std::string_view, 1> interfaces = { 14436d52334SEd Tanous "xyz.openbmc_project.Inventory.Item.Drive"}; 14536d52334SEd Tanous dbus::utility::getSubTreePaths( 14636d52334SEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces, 1477ac13cc9SGunnar Mills std::bind_front(afterChassisDriveCollectionSubtree, asyncResp)); 148a85afbe1SWilly Tu } 149e284a7c1SJames Feist 1505e577bc1SWilly Tu inline void afterSystemsStorageGetSubtree( 1515e577bc1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1525e577bc1SWilly Tu const std::string& storageId, const boost::system::error_code& ec, 1535e577bc1SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) 154a85afbe1SWilly Tu { 1555e577bc1SWilly Tu if (ec) 156a85afbe1SWilly Tu { 15762598e31SEd Tanous BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error"); 1585e577bc1SWilly Tu messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage", 1595e577bc1SWilly Tu storageId); 160a85afbe1SWilly Tu return; 161a85afbe1SWilly Tu } 1623544d2a7SEd Tanous auto storage = std::ranges::find_if( 1633544d2a7SEd Tanous subtree, 1645e577bc1SWilly Tu [&storageId](const std::pair<std::string, 1655e577bc1SWilly Tu dbus::utility::MapperServiceMap>& object) { 1665e577bc1SWilly Tu return sdbusplus::message::object_path(object.first).filename() == 1675e577bc1SWilly Tu storageId; 1685e577bc1SWilly Tu }); 1695e577bc1SWilly Tu if (storage == subtree.end()) 1705e577bc1SWilly Tu { 1715e577bc1SWilly Tu messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage", 1725e577bc1SWilly Tu storageId); 1735e577bc1SWilly Tu return; 1745e577bc1SWilly Tu } 1755e577bc1SWilly Tu 17661b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage"; 177a85afbe1SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 178253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", 179253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId); 180a85afbe1SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage"; 1815e577bc1SWilly Tu asyncResp->res.jsonValue["Id"] = storageId; 182539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 183a85afbe1SWilly Tu 1847ac13cc9SGunnar Mills getDrives(asyncResp); 185253f11b8SEd Tanous asyncResp->res.jsonValue["Controllers"]["@odata.id"] = 186253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}/Controllers", 187253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId); 1885e577bc1SWilly Tu } 1895e577bc1SWilly Tu 190bd79bce8SPatrick Williams inline void handleSystemsStorageGet( 191bd79bce8SPatrick Williams App& app, const crow::Request& req, 1925e577bc1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 193bd79bce8SPatrick Williams const std::string& systemName, const std::string& storageId) 1945e577bc1SWilly Tu { 1955e577bc1SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1965e577bc1SWilly Tu { 1975e577bc1SWilly Tu return; 1985e577bc1SWilly Tu } 19925b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 2007f3e84a1SEd Tanous { 2017f3e84a1SEd Tanous // Option currently returns no systems. TBD 2027f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2037f3e84a1SEd Tanous systemName); 2047f3e84a1SEd Tanous return; 2057f3e84a1SEd Tanous } 2065e577bc1SWilly Tu 2075e577bc1SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 2085e577bc1SWilly Tu "xyz.openbmc_project.Inventory.Item.Storage"}; 2095e577bc1SWilly Tu dbus::utility::getSubTree( 2105e577bc1SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 2115e577bc1SWilly Tu std::bind_front(afterSystemsStorageGetSubtree, asyncResp, storageId)); 2125e577bc1SWilly Tu } 2135e577bc1SWilly Tu 2145e577bc1SWilly Tu inline void afterSubtree(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2155e577bc1SWilly Tu const std::string& storageId, 2165e577bc1SWilly Tu const boost::system::error_code& ec, 2175e577bc1SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) 2185e577bc1SWilly Tu { 2195e577bc1SWilly Tu if (ec) 2205e577bc1SWilly Tu { 22162598e31SEd Tanous BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error"); 2225e577bc1SWilly Tu messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage", 2235e577bc1SWilly Tu storageId); 2245e577bc1SWilly Tu return; 2255e577bc1SWilly Tu } 2263544d2a7SEd Tanous auto storage = std::ranges::find_if( 2273544d2a7SEd Tanous subtree, 2285e577bc1SWilly Tu [&storageId](const std::pair<std::string, 2295e577bc1SWilly Tu dbus::utility::MapperServiceMap>& object) { 2305e577bc1SWilly Tu return sdbusplus::message::object_path(object.first).filename() == 2315e577bc1SWilly Tu storageId; 2325e577bc1SWilly Tu }); 2335e577bc1SWilly Tu if (storage == subtree.end()) 2345e577bc1SWilly Tu { 2355e577bc1SWilly Tu messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage", 2365e577bc1SWilly Tu storageId); 2375e577bc1SWilly Tu return; 2385e577bc1SWilly Tu } 2395e577bc1SWilly Tu 2405e577bc1SWilly Tu asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage"; 2415e577bc1SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 2425e577bc1SWilly Tu boost::urls::format("/redfish/v1/Storage/{}", storageId); 2435e577bc1SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage"; 2445e577bc1SWilly Tu asyncResp->res.jsonValue["Id"] = storageId; 245539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 2465e577bc1SWilly Tu 2475e577bc1SWilly Tu // Storage subsystem to Storage link. 2485e577bc1SWilly Tu nlohmann::json::array_t storageServices; 2495e577bc1SWilly Tu nlohmann::json::object_t storageService; 2505e577bc1SWilly Tu storageService["@odata.id"] = 251253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", 252253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId); 2535e577bc1SWilly Tu storageServices.emplace_back(storageService); 2545e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["StorageServices"] = 2555e577bc1SWilly Tu std::move(storageServices); 2565e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["StorageServices@odata.count"] = 1; 2575e577bc1SWilly Tu } 2585e577bc1SWilly Tu 2595e577bc1SWilly Tu inline void 2605e577bc1SWilly Tu handleStorageGet(App& app, const crow::Request& req, 2615e577bc1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2625e577bc1SWilly Tu const std::string& storageId) 2635e577bc1SWilly Tu { 2645e577bc1SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2655e577bc1SWilly Tu { 26662598e31SEd Tanous BMCWEB_LOG_DEBUG("requestRoutesStorage setUpRedfishRoute failed"); 2675e577bc1SWilly Tu return; 2685e577bc1SWilly Tu } 2695e577bc1SWilly Tu 2705e577bc1SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 2715e577bc1SWilly Tu "xyz.openbmc_project.Inventory.Item.Storage"}; 2725e577bc1SWilly Tu dbus::utility::getSubTree( 2735e577bc1SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 2745e577bc1SWilly Tu std::bind_front(afterSubtree, asyncResp, storageId)); 27536d52334SEd Tanous } 27636d52334SEd Tanous 27736d52334SEd Tanous inline void requestRoutesStorage(App& app) 27836d52334SEd Tanous { 2797f3e84a1SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/<str>/") 28036d52334SEd Tanous .privileges(redfish::privileges::getStorage) 28136d52334SEd Tanous .methods(boost::beast::http::verb::get)( 28236d52334SEd Tanous std::bind_front(handleSystemsStorageGet, std::ref(app))); 2835e577bc1SWilly Tu 2845e577bc1SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Storage/<str>/") 2855e577bc1SWilly Tu .privileges(redfish::privileges::getStorage) 2865e577bc1SWilly Tu .methods(boost::beast::http::verb::get)( 2875e577bc1SWilly Tu std::bind_front(handleStorageGet, std::ref(app))); 2887e860f15SJohn Edward Broadbent } 2897e860f15SJohn Edward Broadbent 29003913171SWilly Tu inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 29103913171SWilly Tu const std::string& connectionName, 29203913171SWilly Tu const std::string& path) 29303913171SWilly Tu { 294*deae6a78SEd Tanous dbus::utility::getAllProperties( 295*deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Inventory.Decorator.Asset", 2965e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 297168e20c1SEd Tanous const std::vector< 298168e20c1SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 29903913171SWilly Tu propertiesList) { 30003913171SWilly Tu if (ec) 30103913171SWilly Tu { 30203913171SWilly Tu // this interface isn't necessary 30303913171SWilly Tu return; 30403913171SWilly Tu } 305d1bde9e5SKrzysztof Grobelny 306d1bde9e5SKrzysztof Grobelny const std::string* partNumber = nullptr; 307d1bde9e5SKrzysztof Grobelny const std::string* serialNumber = nullptr; 308d1bde9e5SKrzysztof Grobelny const std::string* manufacturer = nullptr; 309d1bde9e5SKrzysztof Grobelny const std::string* model = nullptr; 310d1bde9e5SKrzysztof Grobelny 311d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 312d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 313d1bde9e5SKrzysztof Grobelny partNumber, "SerialNumber", serialNumber, "Manufacturer", 314d1bde9e5SKrzysztof Grobelny manufacturer, "Model", model); 315d1bde9e5SKrzysztof Grobelny 316d1bde9e5SKrzysztof Grobelny if (!success) 31703913171SWilly Tu { 31803913171SWilly Tu messages::internalError(asyncResp->res); 31903913171SWilly Tu return; 32003913171SWilly Tu } 321d1bde9e5SKrzysztof Grobelny 322d1bde9e5SKrzysztof Grobelny if (partNumber != nullptr) 323d1bde9e5SKrzysztof Grobelny { 324d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["PartNumber"] = *partNumber; 32503913171SWilly Tu } 326d1bde9e5SKrzysztof Grobelny 327d1bde9e5SKrzysztof Grobelny if (serialNumber != nullptr) 328d1bde9e5SKrzysztof Grobelny { 329d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 33003913171SWilly Tu } 331d1bde9e5SKrzysztof Grobelny 332d1bde9e5SKrzysztof Grobelny if (manufacturer != nullptr) 333d1bde9e5SKrzysztof Grobelny { 334d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 335d1bde9e5SKrzysztof Grobelny } 336d1bde9e5SKrzysztof Grobelny 337d1bde9e5SKrzysztof Grobelny if (model != nullptr) 338d1bde9e5SKrzysztof Grobelny { 339d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["Model"] = *model; 340d1bde9e5SKrzysztof Grobelny } 341d1bde9e5SKrzysztof Grobelny }); 34203913171SWilly Tu } 34303913171SWilly Tu 34403913171SWilly Tu inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 34503913171SWilly Tu const std::string& connectionName, 34603913171SWilly Tu const std::string& path) 34703913171SWilly Tu { 348*deae6a78SEd Tanous dbus::utility::getProperty<bool>( 349*deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present", 350bd79bce8SPatrick Williams [asyncResp, 351bd79bce8SPatrick Williams path](const boost::system::error_code& ec, const bool isPresent) { 35203913171SWilly Tu // this interface isn't necessary, only check it if 35303913171SWilly Tu // we get a good return 35403913171SWilly Tu if (ec) 35503913171SWilly Tu { 35603913171SWilly Tu return; 35703913171SWilly Tu } 35803913171SWilly Tu 359cef57e85SWilly Tu if (!isPresent) 36003913171SWilly Tu { 361539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 362539d8c6bSEd Tanous resource::State::Absent; 36303913171SWilly Tu } 3641e1e598dSJonathan Doman }); 36503913171SWilly Tu } 36603913171SWilly Tu 36703913171SWilly Tu inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 36803913171SWilly Tu const std::string& connectionName, 36903913171SWilly Tu const std::string& path) 37003913171SWilly Tu { 371*deae6a78SEd Tanous dbus::utility::getProperty<bool>( 372*deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.State.Drive", "Rebuilding", 3735e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, const bool updating) { 37403913171SWilly Tu // this interface isn't necessary, only check it 37503913171SWilly Tu // if we get a good return 37603913171SWilly Tu if (ec) 37703913171SWilly Tu { 37803913171SWilly Tu return; 37903913171SWilly Tu } 38003913171SWilly Tu 38103913171SWilly Tu // updating and disabled in the backend shouldn't be 38203913171SWilly Tu // able to be set at the same time, so we don't need 38303913171SWilly Tu // to check for the race condition of these two 38403913171SWilly Tu // calls 3851e1e598dSJonathan Doman if (updating) 38603913171SWilly Tu { 387539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 388539d8c6bSEd Tanous resource::State::Updating; 38903913171SWilly Tu } 3901e1e598dSJonathan Doman }); 39103913171SWilly Tu } 39203913171SWilly Tu 393dde9bc12SGeorge Liu inline std::optional<drive::MediaType> convertDriveType(std::string_view type) 39419b8e9a0SWilly Tu { 39519b8e9a0SWilly Tu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD") 39619b8e9a0SWilly Tu { 397dde9bc12SGeorge Liu return drive::MediaType::HDD; 39819b8e9a0SWilly Tu } 39919b8e9a0SWilly Tu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD") 40019b8e9a0SWilly Tu { 401dde9bc12SGeorge Liu return drive::MediaType::SSD; 40219b8e9a0SWilly Tu } 403dde9bc12SGeorge Liu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown") 404dde9bc12SGeorge Liu { 40519b8e9a0SWilly Tu return std::nullopt; 40619b8e9a0SWilly Tu } 40719b8e9a0SWilly Tu 408dde9bc12SGeorge Liu return drive::MediaType::Invalid; 409dde9bc12SGeorge Liu } 410dde9bc12SGeorge Liu 411dde9bc12SGeorge Liu inline std::optional<protocol::Protocol> 412dde9bc12SGeorge Liu convertDriveProtocol(std::string_view proto) 41319b8e9a0SWilly Tu { 41419b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS") 41519b8e9a0SWilly Tu { 416dde9bc12SGeorge Liu return protocol::Protocol::SAS; 41719b8e9a0SWilly Tu } 41819b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA") 41919b8e9a0SWilly Tu { 420dde9bc12SGeorge Liu return protocol::Protocol::SATA; 42119b8e9a0SWilly Tu } 42219b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe") 42319b8e9a0SWilly Tu { 424dde9bc12SGeorge Liu return protocol::Protocol::NVMe; 42519b8e9a0SWilly Tu } 42619b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC") 42719b8e9a0SWilly Tu { 428dde9bc12SGeorge Liu return protocol::Protocol::FC; 429dde9bc12SGeorge Liu } 430dde9bc12SGeorge Liu if (proto == 431dde9bc12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown") 432dde9bc12SGeorge Liu { 433dde9bc12SGeorge Liu return std::nullopt; 43419b8e9a0SWilly Tu } 43519b8e9a0SWilly Tu 436dde9bc12SGeorge Liu return protocol::Protocol::Invalid; 43719b8e9a0SWilly Tu } 43819b8e9a0SWilly Tu 439bd79bce8SPatrick Williams inline void getDriveItemProperties( 440bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 441bd79bce8SPatrick Williams const std::string& connectionName, const std::string& path) 44219b8e9a0SWilly Tu { 443*deae6a78SEd Tanous dbus::utility::getAllProperties( 444*deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Inventory.Item.Drive", 4455e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 44619b8e9a0SWilly Tu const std::vector< 44719b8e9a0SWilly Tu std::pair<std::string, dbus::utility::DbusVariantType>>& 44819b8e9a0SWilly Tu propertiesList) { 44919b8e9a0SWilly Tu if (ec) 45019b8e9a0SWilly Tu { 45119b8e9a0SWilly Tu // this interface isn't required 45219b8e9a0SWilly Tu return; 45319b8e9a0SWilly Tu } 454e5029d88SJohn Edward Broadbent const std::string* encryptionStatus = nullptr; 455e5029d88SJohn Edward Broadbent const bool* isLocked = nullptr; 45619b8e9a0SWilly Tu for (const std::pair<std::string, dbus::utility::DbusVariantType>& 45719b8e9a0SWilly Tu property : propertiesList) 45819b8e9a0SWilly Tu { 45919b8e9a0SWilly Tu const std::string& propertyName = property.first; 46019b8e9a0SWilly Tu if (propertyName == "Type") 46119b8e9a0SWilly Tu { 46219b8e9a0SWilly Tu const std::string* value = 46319b8e9a0SWilly Tu std::get_if<std::string>(&property.second); 46419b8e9a0SWilly Tu if (value == nullptr) 46519b8e9a0SWilly Tu { 46619b8e9a0SWilly Tu // illegal property 46762598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: Type"); 46819b8e9a0SWilly Tu messages::internalError(asyncResp->res); 46919b8e9a0SWilly Tu return; 47019b8e9a0SWilly Tu } 47119b8e9a0SWilly Tu 472dde9bc12SGeorge Liu std::optional<drive::MediaType> mediaType = 473dde9bc12SGeorge Liu convertDriveType(*value); 47419b8e9a0SWilly Tu if (!mediaType) 47519b8e9a0SWilly Tu { 47662598e31SEd Tanous BMCWEB_LOG_WARNING("UnknownDriveType Interface: {}", 47762598e31SEd Tanous *value); 478dde9bc12SGeorge Liu continue; 479dde9bc12SGeorge Liu } 480dde9bc12SGeorge Liu if (*mediaType == drive::MediaType::Invalid) 481dde9bc12SGeorge Liu { 48219b8e9a0SWilly Tu messages::internalError(asyncResp->res); 48319b8e9a0SWilly Tu return; 48419b8e9a0SWilly Tu } 48519b8e9a0SWilly Tu 48619b8e9a0SWilly Tu asyncResp->res.jsonValue["MediaType"] = *mediaType; 48719b8e9a0SWilly Tu } 48819b8e9a0SWilly Tu else if (propertyName == "Capacity") 48919b8e9a0SWilly Tu { 49019b8e9a0SWilly Tu const uint64_t* capacity = 49119b8e9a0SWilly Tu std::get_if<uint64_t>(&property.second); 49219b8e9a0SWilly Tu if (capacity == nullptr) 49319b8e9a0SWilly Tu { 49462598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: Capacity"); 49519b8e9a0SWilly Tu messages::internalError(asyncResp->res); 49619b8e9a0SWilly Tu return; 49719b8e9a0SWilly Tu } 49819b8e9a0SWilly Tu if (*capacity == 0) 49919b8e9a0SWilly Tu { 50019b8e9a0SWilly Tu // drive capacity not known 50119b8e9a0SWilly Tu continue; 50219b8e9a0SWilly Tu } 50319b8e9a0SWilly Tu 50419b8e9a0SWilly Tu asyncResp->res.jsonValue["CapacityBytes"] = *capacity; 50519b8e9a0SWilly Tu } 50619b8e9a0SWilly Tu else if (propertyName == "Protocol") 50719b8e9a0SWilly Tu { 50819b8e9a0SWilly Tu const std::string* value = 50919b8e9a0SWilly Tu std::get_if<std::string>(&property.second); 51019b8e9a0SWilly Tu if (value == nullptr) 51119b8e9a0SWilly Tu { 51262598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: Protocol"); 51319b8e9a0SWilly Tu messages::internalError(asyncResp->res); 51419b8e9a0SWilly Tu return; 51519b8e9a0SWilly Tu } 51619b8e9a0SWilly Tu 517dde9bc12SGeorge Liu std::optional<protocol::Protocol> proto = 518dde9bc12SGeorge Liu convertDriveProtocol(*value); 51919b8e9a0SWilly Tu if (!proto) 52019b8e9a0SWilly Tu { 521bd79bce8SPatrick Williams BMCWEB_LOG_WARNING( 522bd79bce8SPatrick Williams "Unknown DrivePrototype Interface: {}", *value); 523dde9bc12SGeorge Liu continue; 524dde9bc12SGeorge Liu } 525dde9bc12SGeorge Liu if (*proto == protocol::Protocol::Invalid) 526dde9bc12SGeorge Liu { 52719b8e9a0SWilly Tu messages::internalError(asyncResp->res); 52819b8e9a0SWilly Tu return; 52919b8e9a0SWilly Tu } 53019b8e9a0SWilly Tu asyncResp->res.jsonValue["Protocol"] = *proto; 53119b8e9a0SWilly Tu } 5323fe4d5ccSJohn Edward Broadbent else if (propertyName == "PredictedMediaLifeLeftPercent") 5333fe4d5ccSJohn Edward Broadbent { 5343fe4d5ccSJohn Edward Broadbent const uint8_t* lifeLeft = 5353fe4d5ccSJohn Edward Broadbent std::get_if<uint8_t>(&property.second); 5363fe4d5ccSJohn Edward Broadbent if (lifeLeft == nullptr) 5373fe4d5ccSJohn Edward Broadbent { 53862598e31SEd Tanous BMCWEB_LOG_ERROR( 53962598e31SEd Tanous "Illegal property: PredictedMediaLifeLeftPercent"); 5403fe4d5ccSJohn Edward Broadbent messages::internalError(asyncResp->res); 5413fe4d5ccSJohn Edward Broadbent return; 5423fe4d5ccSJohn Edward Broadbent } 5433fe4d5ccSJohn Edward Broadbent // 255 means reading the value is not supported 5443fe4d5ccSJohn Edward Broadbent if (*lifeLeft != 255) 5453fe4d5ccSJohn Edward Broadbent { 546bd79bce8SPatrick Williams asyncResp->res 547bd79bce8SPatrick Williams .jsonValue["PredictedMediaLifeLeftPercent"] = 5483fe4d5ccSJohn Edward Broadbent *lifeLeft; 5493fe4d5ccSJohn Edward Broadbent } 5503fe4d5ccSJohn Edward Broadbent } 551e5029d88SJohn Edward Broadbent else if (propertyName == "EncryptionStatus") 552e5029d88SJohn Edward Broadbent { 553bd79bce8SPatrick Williams encryptionStatus = 554bd79bce8SPatrick Williams std::get_if<std::string>(&property.second); 555e5029d88SJohn Edward Broadbent if (encryptionStatus == nullptr) 556e5029d88SJohn Edward Broadbent { 55762598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: EncryptionStatus"); 558e5029d88SJohn Edward Broadbent messages::internalError(asyncResp->res); 559e5029d88SJohn Edward Broadbent return; 56019b8e9a0SWilly Tu } 561e5029d88SJohn Edward Broadbent } 562e5029d88SJohn Edward Broadbent else if (propertyName == "Locked") 563e5029d88SJohn Edward Broadbent { 564e5029d88SJohn Edward Broadbent isLocked = std::get_if<bool>(&property.second); 565e5029d88SJohn Edward Broadbent if (isLocked == nullptr) 566e5029d88SJohn Edward Broadbent { 56762598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal property: Locked"); 568e5029d88SJohn Edward Broadbent messages::internalError(asyncResp->res); 569e5029d88SJohn Edward Broadbent return; 570e5029d88SJohn Edward Broadbent } 571e5029d88SJohn Edward Broadbent } 572e5029d88SJohn Edward Broadbent } 573e5029d88SJohn Edward Broadbent 574e5029d88SJohn Edward Broadbent if (encryptionStatus == nullptr || isLocked == nullptr || 575e5029d88SJohn Edward Broadbent *encryptionStatus == 576a684c226SKonda Reddy Kachana "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Unknown") 577e5029d88SJohn Edward Broadbent { 578e5029d88SJohn Edward Broadbent return; 579e5029d88SJohn Edward Broadbent } 580e5029d88SJohn Edward Broadbent if (*encryptionStatus != 581a684c226SKonda Reddy Kachana "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Encrypted") 582e5029d88SJohn Edward Broadbent { 583e5029d88SJohn Edward Broadbent //"The drive is not currently encrypted." 584e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 585e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Unencrypted; 586e5029d88SJohn Edward Broadbent return; 587e5029d88SJohn Edward Broadbent } 588e5029d88SJohn Edward Broadbent if (*isLocked) 589e5029d88SJohn Edward Broadbent { 590e5029d88SJohn Edward Broadbent //"The drive is currently encrypted and the data is not 591e5029d88SJohn Edward Broadbent // accessible to the user." 592e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 593e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Locked; 594e5029d88SJohn Edward Broadbent return; 595e5029d88SJohn Edward Broadbent } 596e5029d88SJohn Edward Broadbent // if not locked 597e5029d88SJohn Edward Broadbent // "The drive is currently encrypted but the data is accessible 598e5029d88SJohn Edward Broadbent // to the user in unencrypted form." 599e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 600e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Unlocked; 60119b8e9a0SWilly Tu }); 60219b8e9a0SWilly Tu } 60319b8e9a0SWilly Tu 6044ff0f1f4SEd Tanous inline void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 605b53dcd9dSNan Zhou const std::string& connectionName, 606b53dcd9dSNan Zhou const std::string& path, 607e56ed6b9SJohn Edward Broadbent const std::vector<std::string>& interfaces) 608e56ed6b9SJohn Edward Broadbent { 609e56ed6b9SJohn Edward Broadbent for (const std::string& interface : interfaces) 610e56ed6b9SJohn Edward Broadbent { 611e56ed6b9SJohn Edward Broadbent if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset") 612e56ed6b9SJohn Edward Broadbent { 613e56ed6b9SJohn Edward Broadbent getDriveAsset(asyncResp, connectionName, path); 614e56ed6b9SJohn Edward Broadbent } 615e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.Inventory.Item") 616e56ed6b9SJohn Edward Broadbent { 617e56ed6b9SJohn Edward Broadbent getDrivePresent(asyncResp, connectionName, path); 618e56ed6b9SJohn Edward Broadbent } 619e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.State.Drive") 620e56ed6b9SJohn Edward Broadbent { 621e56ed6b9SJohn Edward Broadbent getDriveState(asyncResp, connectionName, path); 622e56ed6b9SJohn Edward Broadbent } 623e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.Inventory.Item.Drive") 624e56ed6b9SJohn Edward Broadbent { 625e56ed6b9SJohn Edward Broadbent getDriveItemProperties(asyncResp, connectionName, path); 626e56ed6b9SJohn Edward Broadbent } 627e56ed6b9SJohn Edward Broadbent } 628e56ed6b9SJohn Edward Broadbent } 629e56ed6b9SJohn Edward Broadbent 63036d52334SEd Tanous inline void afterGetSubtreeSystemsStorageDrive( 63145ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 63236d52334SEd Tanous const std::string& driveId, const boost::system::error_code& ec, 63336d52334SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) 63445ca1b86SEd Tanous { 6357e860f15SJohn Edward Broadbent if (ec) 6367e860f15SJohn Edward Broadbent { 63762598e31SEd Tanous BMCWEB_LOG_ERROR("Drive mapper call error"); 6387e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 6397e860f15SJohn Edward Broadbent return; 6407e860f15SJohn Edward Broadbent } 6417e860f15SJohn Edward Broadbent 6423544d2a7SEd Tanous auto drive = std::ranges::find_if( 6433544d2a7SEd Tanous subtree, 64436d52334SEd Tanous [&driveId](const std::pair<std::string, 6458cb65f8aSNan Zhou dbus::utility::MapperServiceMap>& object) { 64636d52334SEd Tanous return sdbusplus::message::object_path(object.first).filename() == 64736d52334SEd Tanous driveId; 6487e860f15SJohn Edward Broadbent }); 6497e860f15SJohn Edward Broadbent 65003913171SWilly Tu if (drive == subtree.end()) 6517e860f15SJohn Edward Broadbent { 652002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "Drive", driveId); 6537e860f15SJohn Edward Broadbent return; 6547e860f15SJohn Edward Broadbent } 6557e860f15SJohn Edward Broadbent 65603913171SWilly Tu const std::string& path = drive->first; 65736d52334SEd Tanous const dbus::utility::MapperServiceMap& connectionNames = drive->second; 6587e860f15SJohn Edward Broadbent 659002d39b4SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive"; 660253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 661253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Drives/{}", 662253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, driveId); 6637e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = driveId; 6647e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Id"] = driveId; 6657e860f15SJohn Edward Broadbent 6667e860f15SJohn Edward Broadbent if (connectionNames.size() != 1) 6677e860f15SJohn Edward Broadbent { 66862598e31SEd Tanous BMCWEB_LOG_ERROR("Connection size {}, not equal to 1", 66962598e31SEd Tanous connectionNames.size()); 6707e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 6717e860f15SJohn Edward Broadbent return; 6727e860f15SJohn Edward Broadbent } 6737e860f15SJohn Edward Broadbent 674bd79bce8SPatrick Williams getMainChassisId( 675bd79bce8SPatrick Williams asyncResp, [](const std::string& chassisId, 6767e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 677002d39b4SEd Tanous aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] = 678ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 6797e860f15SJohn Edward Broadbent }); 6807e860f15SJohn Edward Broadbent 681a25aeccfSNikhil Potade // default it to Enabled 682539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 683a25aeccfSNikhil Potade 684e56ed6b9SJohn Edward Broadbent addAllDriveInfo(asyncResp, connectionNames[0].first, path, 685e56ed6b9SJohn Edward Broadbent connectionNames[0].second); 686a25aeccfSNikhil Potade } 68792903bd4SJohn Edward Broadbent 68836d52334SEd Tanous inline void handleSystemsStorageDriveGet( 68936d52334SEd Tanous App& app, const crow::Request& req, 69092903bd4SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 69136d52334SEd Tanous const std::string& systemName, const std::string& driveId) 69292903bd4SJohn Edward Broadbent { 6933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 69492903bd4SJohn Edward Broadbent { 69592903bd4SJohn Edward Broadbent return; 69692903bd4SJohn Edward Broadbent } 69725b54dbaSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 6987f3e84a1SEd Tanous { 6997f3e84a1SEd Tanous // Option currently returns no systems. TBD 7007f3e84a1SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 7017f3e84a1SEd Tanous systemName); 7027f3e84a1SEd Tanous return; 7037f3e84a1SEd Tanous } 7047f3e84a1SEd Tanous 705253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 70636d52334SEd Tanous { 70736d52334SEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 70836d52334SEd Tanous systemName); 70936d52334SEd Tanous return; 71036d52334SEd Tanous } 71192903bd4SJohn Edward Broadbent 71236d52334SEd Tanous constexpr std::array<std::string_view, 1> interfaces = { 71336d52334SEd Tanous "xyz.openbmc_project.Inventory.Item.Drive"}; 714e99073f5SGeorge Liu dbus::utility::getSubTree( 715e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 71636d52334SEd Tanous std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp, 71736d52334SEd Tanous driveId)); 71836d52334SEd Tanous } 71936d52334SEd Tanous 72036d52334SEd Tanous inline void requestRoutesDrive(App& app) 72136d52334SEd Tanous { 72236d52334SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/") 72336d52334SEd Tanous .privileges(redfish::privileges::getDrive) 72436d52334SEd Tanous .methods(boost::beast::http::verb::get)( 72536d52334SEd Tanous std::bind_front(handleSystemsStorageDriveGet, std::ref(app))); 72636d52334SEd Tanous } 72736d52334SEd Tanous 72836d52334SEd Tanous inline void afterChassisDriveCollectionSubtreeGet( 72936d52334SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 73036d52334SEd Tanous const std::string& chassisId, const boost::system::error_code& ec, 73136d52334SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) 73236d52334SEd Tanous { 73392903bd4SJohn Edward Broadbent if (ec) 73492903bd4SJohn Edward Broadbent { 73592903bd4SJohn Edward Broadbent if (ec == boost::system::errc::host_unreachable) 73692903bd4SJohn Edward Broadbent { 73736d52334SEd Tanous messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 73892903bd4SJohn Edward Broadbent return; 73992903bd4SJohn Edward Broadbent } 74092903bd4SJohn Edward Broadbent messages::internalError(asyncResp->res); 74192903bd4SJohn Edward Broadbent return; 74292903bd4SJohn Edward Broadbent } 74392903bd4SJohn Edward Broadbent 74492903bd4SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 7458cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 74692903bd4SJohn Edward Broadbent { 74792903bd4SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 74892903bd4SJohn Edward Broadbent if (objPath.filename() != chassisId) 74992903bd4SJohn Edward Broadbent { 75092903bd4SJohn Edward Broadbent continue; 75192903bd4SJohn Edward Broadbent } 75292903bd4SJohn Edward Broadbent 75392903bd4SJohn Edward Broadbent if (connectionNames.empty()) 75492903bd4SJohn Edward Broadbent { 75562598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 75692903bd4SJohn Edward Broadbent continue; 75792903bd4SJohn Edward Broadbent } 75892903bd4SJohn Edward Broadbent 75992903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.type"] = 76092903bd4SJohn Edward Broadbent "#DriveCollection.DriveCollection"; 76192903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.id"] = 762ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId); 76392903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = "Drive Collection"; 76492903bd4SJohn Edward Broadbent 76592903bd4SJohn Edward Broadbent // Association lambda 7666c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 7676c3e9451SGeorge Liu path + "/drive", 76836d52334SEd Tanous [asyncResp, chassisId](const boost::system::error_code& ec3, 7696c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 77092903bd4SJohn Edward Broadbent if (ec3) 77192903bd4SJohn Edward Broadbent { 77262598e31SEd Tanous BMCWEB_LOG_ERROR("Error in chassis Drive association "); 77392903bd4SJohn Edward Broadbent } 77492903bd4SJohn Edward Broadbent nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 77592903bd4SJohn Edward Broadbent // important if array is empty 77692903bd4SJohn Edward Broadbent members = nlohmann::json::array(); 77792903bd4SJohn Edward Broadbent 77892903bd4SJohn Edward Broadbent std::vector<std::string> leafNames; 77992903bd4SJohn Edward Broadbent for (const auto& drive : resp) 78092903bd4SJohn Edward Broadbent { 7818a592810SEd Tanous sdbusplus::message::object_path drivePath(drive); 7828a592810SEd Tanous leafNames.push_back(drivePath.filename()); 78392903bd4SJohn Edward Broadbent } 78492903bd4SJohn Edward Broadbent 7853544d2a7SEd Tanous std::ranges::sort(leafNames, AlphanumLess<std::string>()); 78692903bd4SJohn Edward Broadbent 78792903bd4SJohn Edward Broadbent for (const auto& leafName : leafNames) 78892903bd4SJohn Edward Broadbent { 78992903bd4SJohn Edward Broadbent nlohmann::json::object_t member; 790bd79bce8SPatrick Williams member["@odata.id"] = 791bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}/Drives/{}", 792bd79bce8SPatrick Williams chassisId, leafName); 793b2ba3072SPatrick Williams members.emplace_back(std::move(member)); 79492903bd4SJohn Edward Broadbent // navigation links will be registered in next patch set 79592903bd4SJohn Edward Broadbent } 79692903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = resp.size(); 79792903bd4SJohn Edward Broadbent }); // end association lambda 79892903bd4SJohn Edward Broadbent 79992903bd4SJohn Edward Broadbent } // end Iterate over all retrieved ObjectPaths 80036d52334SEd Tanous } 80136d52334SEd Tanous /** 80236d52334SEd Tanous * Chassis drives, this URL will show all the DriveCollection 80336d52334SEd Tanous * information 80436d52334SEd Tanous */ 80536d52334SEd Tanous inline void chassisDriveCollectionGet( 80636d52334SEd Tanous crow::App& app, const crow::Request& req, 80736d52334SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 80836d52334SEd Tanous const std::string& chassisId) 80936d52334SEd Tanous { 81036d52334SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 81136d52334SEd Tanous { 81236d52334SEd Tanous return; 81336d52334SEd Tanous } 81436d52334SEd Tanous 81536d52334SEd Tanous // mapper call lambda 81636d52334SEd Tanous constexpr std::array<std::string_view, 2> interfaces = { 81736d52334SEd Tanous "xyz.openbmc_project.Inventory.Item.Board", 81836d52334SEd Tanous "xyz.openbmc_project.Inventory.Item.Chassis"}; 81936d52334SEd Tanous dbus::utility::getSubTree( 82036d52334SEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces, 82136d52334SEd Tanous std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp, 82236d52334SEd Tanous chassisId)); 82392903bd4SJohn Edward Broadbent } 82492903bd4SJohn Edward Broadbent 82592903bd4SJohn Edward Broadbent inline void requestRoutesChassisDrive(App& app) 82692903bd4SJohn Edward Broadbent { 82792903bd4SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/") 82892903bd4SJohn Edward Broadbent .privileges(redfish::privileges::getDriveCollection) 82992903bd4SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 83092903bd4SJohn Edward Broadbent std::bind_front(chassisDriveCollectionGet, std::ref(app))); 83192903bd4SJohn Edward Broadbent } 83292903bd4SJohn Edward Broadbent 833b53dcd9dSNan Zhou inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 834b53dcd9dSNan Zhou const std::string& chassisId, 835b53dcd9dSNan Zhou const std::string& driveName, 8365e7e2dc5SEd Tanous const boost::system::error_code& ec, 837e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) 838e56ed6b9SJohn Edward Broadbent { 839e56ed6b9SJohn Edward Broadbent if (ec) 840e56ed6b9SJohn Edward Broadbent { 84162598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 842e56ed6b9SJohn Edward Broadbent messages::internalError(asyncResp->res); 843e56ed6b9SJohn Edward Broadbent return; 844e56ed6b9SJohn Edward Broadbent } 845e56ed6b9SJohn Edward Broadbent 846e56ed6b9SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 8478cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 848e56ed6b9SJohn Edward Broadbent { 849e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 850e56ed6b9SJohn Edward Broadbent if (objPath.filename() != driveName) 851e56ed6b9SJohn Edward Broadbent { 852e56ed6b9SJohn Edward Broadbent continue; 853e56ed6b9SJohn Edward Broadbent } 854e56ed6b9SJohn Edward Broadbent 855e56ed6b9SJohn Edward Broadbent if (connectionNames.empty()) 856e56ed6b9SJohn Edward Broadbent { 85762598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 858e56ed6b9SJohn Edward Broadbent continue; 859e56ed6b9SJohn Edward Broadbent } 860e56ed6b9SJohn Edward Broadbent 861ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 862ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName); 863e56ed6b9SJohn Edward Broadbent 864e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive"; 865a0cb40cbSJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = driveName; 866e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["Id"] = driveName; 867e56ed6b9SJohn Edward Broadbent // default it to Enabled 868539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 869e56ed6b9SJohn Edward Broadbent 870e56ed6b9SJohn Edward Broadbent nlohmann::json::object_t linkChassisNav; 871e56ed6b9SJohn Edward Broadbent linkChassisNav["@odata.id"] = 872ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 873e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav; 874e56ed6b9SJohn Edward Broadbent 875e56ed6b9SJohn Edward Broadbent addAllDriveInfo(asyncResp, connectionNames[0].first, path, 876e56ed6b9SJohn Edward Broadbent connectionNames[0].second); 877e56ed6b9SJohn Edward Broadbent } 878e56ed6b9SJohn Edward Broadbent } 879e56ed6b9SJohn Edward Broadbent 880bd79bce8SPatrick Williams inline void matchAndFillDrive( 881bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 882bd79bce8SPatrick Williams const std::string& chassisId, const std::string& driveName, 883e56ed6b9SJohn Edward Broadbent const std::vector<std::string>& resp) 884e56ed6b9SJohn Edward Broadbent { 885e56ed6b9SJohn Edward Broadbent for (const std::string& drivePath : resp) 886e56ed6b9SJohn Edward Broadbent { 887e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path path(drivePath); 888e56ed6b9SJohn Edward Broadbent std::string leaf = path.filename(); 889e56ed6b9SJohn Edward Broadbent if (leaf != driveName) 890e56ed6b9SJohn Edward Broadbent { 891e56ed6b9SJohn Edward Broadbent continue; 892e56ed6b9SJohn Edward Broadbent } 893e56ed6b9SJohn Edward Broadbent // mapper call drive 894e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> driveInterface = { 895e56ed6b9SJohn Edward Broadbent "xyz.openbmc_project.Inventory.Item.Drive"}; 896e99073f5SGeorge Liu dbus::utility::getSubTree( 897e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, driveInterface, 898e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, driveName]( 899e99073f5SGeorge Liu const boost::system::error_code& ec, 900e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) { 901e56ed6b9SJohn Edward Broadbent buildDrive(asyncResp, chassisId, driveName, ec, subtree); 902e99073f5SGeorge Liu }); 903e56ed6b9SJohn Edward Broadbent } 904e56ed6b9SJohn Edward Broadbent } 905e56ed6b9SJohn Edward Broadbent 906bd79bce8SPatrick Williams inline void handleChassisDriveGet( 907bd79bce8SPatrick Williams crow::App& app, const crow::Request& req, 908e56ed6b9SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 909bd79bce8SPatrick Williams const std::string& chassisId, const std::string& driveName) 910e56ed6b9SJohn Edward Broadbent { 91103810a11SMichal Orzel if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 912e56ed6b9SJohn Edward Broadbent { 913e56ed6b9SJohn Edward Broadbent return; 914e56ed6b9SJohn Edward Broadbent } 915e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 916e56ed6b9SJohn Edward Broadbent "xyz.openbmc_project.Inventory.Item.Board", 917e56ed6b9SJohn Edward Broadbent "xyz.openbmc_project.Inventory.Item.Chassis"}; 918e56ed6b9SJohn Edward Broadbent 919e56ed6b9SJohn Edward Broadbent // mapper call chassis 920e99073f5SGeorge Liu dbus::utility::getSubTree( 921e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 922e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, 923e99073f5SGeorge Liu driveName](const boost::system::error_code& ec, 924e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) { 925e56ed6b9SJohn Edward Broadbent if (ec) 926e56ed6b9SJohn Edward Broadbent { 927e56ed6b9SJohn Edward Broadbent messages::internalError(asyncResp->res); 928e56ed6b9SJohn Edward Broadbent return; 929e56ed6b9SJohn Edward Broadbent } 930e56ed6b9SJohn Edward Broadbent 931e56ed6b9SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 9328cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 933e56ed6b9SJohn Edward Broadbent { 934e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 935e56ed6b9SJohn Edward Broadbent if (objPath.filename() != chassisId) 936e56ed6b9SJohn Edward Broadbent { 937e56ed6b9SJohn Edward Broadbent continue; 938e56ed6b9SJohn Edward Broadbent } 939e56ed6b9SJohn Edward Broadbent 940e56ed6b9SJohn Edward Broadbent if (connectionNames.empty()) 941e56ed6b9SJohn Edward Broadbent { 94262598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 943e56ed6b9SJohn Edward Broadbent continue; 944e56ed6b9SJohn Edward Broadbent } 945e56ed6b9SJohn Edward Broadbent 9466c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 9476c3e9451SGeorge Liu path + "/drive", 948e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, 9495e7e2dc5SEd Tanous driveName](const boost::system::error_code& ec3, 9506c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 951e56ed6b9SJohn Edward Broadbent if (ec3) 952e56ed6b9SJohn Edward Broadbent { 953e56ed6b9SJohn Edward Broadbent return; // no drives = no failures 954e56ed6b9SJohn Edward Broadbent } 955bd79bce8SPatrick Williams matchAndFillDrive(asyncResp, chassisId, driveName, 956bd79bce8SPatrick Williams resp); 957e56ed6b9SJohn Edward Broadbent }); 958e56ed6b9SJohn Edward Broadbent break; 959e56ed6b9SJohn Edward Broadbent } 960e99073f5SGeorge Liu }); 961e56ed6b9SJohn Edward Broadbent } 962e56ed6b9SJohn Edward Broadbent 963e56ed6b9SJohn Edward Broadbent /** 964e56ed6b9SJohn Edward Broadbent * This URL will show the drive interface for the specific drive in the chassis 965e56ed6b9SJohn Edward Broadbent */ 966e56ed6b9SJohn Edward Broadbent inline void requestRoutesChassisDriveName(App& app) 967e56ed6b9SJohn Edward Broadbent { 968e56ed6b9SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/") 969e56ed6b9SJohn Edward Broadbent .privileges(redfish::privileges::getChassis) 970e56ed6b9SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 971e56ed6b9SJohn Edward Broadbent std::bind_front(handleChassisDriveGet, std::ref(app))); 972e56ed6b9SJohn Edward Broadbent } 973e56ed6b9SJohn Edward Broadbent 97461b1eb21SWilly Tu inline void getStorageControllerAsset( 97561b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 97661b1eb21SWilly Tu const boost::system::error_code& ec, 97761b1eb21SWilly Tu const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>& 97861b1eb21SWilly Tu propertiesList) 97961b1eb21SWilly Tu { 98061b1eb21SWilly Tu if (ec) 98161b1eb21SWilly Tu { 98261b1eb21SWilly Tu // this interface isn't necessary 98362598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to get StorageControllerAsset"); 98461b1eb21SWilly Tu return; 98561b1eb21SWilly Tu } 98661b1eb21SWilly Tu 98761b1eb21SWilly Tu const std::string* partNumber = nullptr; 98861b1eb21SWilly Tu const std::string* serialNumber = nullptr; 98961b1eb21SWilly Tu const std::string* manufacturer = nullptr; 99061b1eb21SWilly Tu const std::string* model = nullptr; 99161b1eb21SWilly Tu if (!sdbusplus::unpackPropertiesNoThrow( 99261b1eb21SWilly Tu dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 99361b1eb21SWilly Tu partNumber, "SerialNumber", serialNumber, "Manufacturer", 99461b1eb21SWilly Tu manufacturer, "Model", model)) 99561b1eb21SWilly Tu { 99661b1eb21SWilly Tu messages::internalError(asyncResp->res); 99761b1eb21SWilly Tu return; 99861b1eb21SWilly Tu } 99961b1eb21SWilly Tu 100061b1eb21SWilly Tu if (partNumber != nullptr) 100161b1eb21SWilly Tu { 100261b1eb21SWilly Tu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 100361b1eb21SWilly Tu } 100461b1eb21SWilly Tu 100561b1eb21SWilly Tu if (serialNumber != nullptr) 100661b1eb21SWilly Tu { 100761b1eb21SWilly Tu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 100861b1eb21SWilly Tu } 100961b1eb21SWilly Tu 101061b1eb21SWilly Tu if (manufacturer != nullptr) 101161b1eb21SWilly Tu { 101261b1eb21SWilly Tu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 101361b1eb21SWilly Tu } 101461b1eb21SWilly Tu 101561b1eb21SWilly Tu if (model != nullptr) 101661b1eb21SWilly Tu { 101761b1eb21SWilly Tu asyncResp->res.jsonValue["Model"] = *model; 101861b1eb21SWilly Tu } 101961b1eb21SWilly Tu } 102061b1eb21SWilly Tu 102161b1eb21SWilly Tu inline void populateStorageController( 102261b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 102361b1eb21SWilly Tu const std::string& controllerId, const std::string& connectionName, 102461b1eb21SWilly Tu const std::string& path) 102561b1eb21SWilly Tu { 102661b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = 102761b1eb21SWilly Tu "#StorageController.v1_6_0.StorageController"; 1028253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 1029253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Controllers/{}", 1030253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, controllerId); 103161b1eb21SWilly Tu asyncResp->res.jsonValue["Name"] = controllerId; 103261b1eb21SWilly Tu asyncResp->res.jsonValue["Id"] = controllerId; 1033539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 103461b1eb21SWilly Tu 1035*deae6a78SEd Tanous dbus::utility::getProperty<bool>( 1036*deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present", 103761b1eb21SWilly Tu [asyncResp](const boost::system::error_code& ec, bool isPresent) { 103861b1eb21SWilly Tu // this interface isn't necessary, only check it 103961b1eb21SWilly Tu // if we get a good return 104061b1eb21SWilly Tu if (ec) 104161b1eb21SWilly Tu { 104262598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to get Present property"); 104361b1eb21SWilly Tu return; 104461b1eb21SWilly Tu } 104561b1eb21SWilly Tu if (!isPresent) 104661b1eb21SWilly Tu { 1047539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 1048539d8c6bSEd Tanous resource::State::Absent; 104961b1eb21SWilly Tu } 105061b1eb21SWilly Tu }); 105161b1eb21SWilly Tu 1052*deae6a78SEd Tanous dbus::utility::getAllProperties( 1053*deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Inventory.Decorator.Asset", 105461b1eb21SWilly Tu [asyncResp](const boost::system::error_code& ec, 105561b1eb21SWilly Tu const std::vector< 105661b1eb21SWilly Tu std::pair<std::string, dbus::utility::DbusVariantType>>& 105761b1eb21SWilly Tu propertiesList) { 105861b1eb21SWilly Tu getStorageControllerAsset(asyncResp, ec, propertiesList); 105961b1eb21SWilly Tu }); 106061b1eb21SWilly Tu } 106161b1eb21SWilly Tu 106261b1eb21SWilly Tu inline void getStorageControllerHandler( 106361b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 106461b1eb21SWilly Tu const std::string& controllerId, const boost::system::error_code& ec, 106561b1eb21SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) 106661b1eb21SWilly Tu { 106761b1eb21SWilly Tu if (ec || subtree.empty()) 106861b1eb21SWilly Tu { 106961b1eb21SWilly Tu // doesn't have to be there 107062598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to handle StorageController"); 107161b1eb21SWilly Tu return; 107261b1eb21SWilly Tu } 107361b1eb21SWilly Tu 107461b1eb21SWilly Tu for (const auto& [path, interfaceDict] : subtree) 107561b1eb21SWilly Tu { 107661b1eb21SWilly Tu sdbusplus::message::object_path object(path); 107761b1eb21SWilly Tu std::string id = object.filename(); 107861b1eb21SWilly Tu if (id.empty()) 107961b1eb21SWilly Tu { 108062598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find filename in {}", path); 108161b1eb21SWilly Tu return; 108261b1eb21SWilly Tu } 108361b1eb21SWilly Tu if (id != controllerId) 108461b1eb21SWilly Tu { 108561b1eb21SWilly Tu continue; 108661b1eb21SWilly Tu } 108761b1eb21SWilly Tu 108861b1eb21SWilly Tu if (interfaceDict.size() != 1) 108961b1eb21SWilly Tu { 109062598e31SEd Tanous BMCWEB_LOG_ERROR("Connection size {}, greater than 1", 109162598e31SEd Tanous interfaceDict.size()); 109261b1eb21SWilly Tu messages::internalError(asyncResp->res); 109361b1eb21SWilly Tu return; 109461b1eb21SWilly Tu } 109561b1eb21SWilly Tu 109661b1eb21SWilly Tu const std::string& connectionName = interfaceDict.front().first; 109761b1eb21SWilly Tu populateStorageController(asyncResp, controllerId, connectionName, 109861b1eb21SWilly Tu path); 109961b1eb21SWilly Tu } 110061b1eb21SWilly Tu } 110161b1eb21SWilly Tu 110261b1eb21SWilly Tu inline void populateStorageControllerCollection( 110361b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 110461b1eb21SWilly Tu const boost::system::error_code& ec, 110561b1eb21SWilly Tu const dbus::utility::MapperGetSubTreePathsResponse& controllerList) 110661b1eb21SWilly Tu { 110761b1eb21SWilly Tu nlohmann::json::array_t members; 110861b1eb21SWilly Tu if (ec || controllerList.empty()) 110961b1eb21SWilly Tu { 111061b1eb21SWilly Tu asyncResp->res.jsonValue["Members"] = std::move(members); 111161b1eb21SWilly Tu asyncResp->res.jsonValue["Members@odata.count"] = 0; 111262598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to find any StorageController"); 111361b1eb21SWilly Tu return; 111461b1eb21SWilly Tu } 111561b1eb21SWilly Tu 111661b1eb21SWilly Tu for (const std::string& path : controllerList) 111761b1eb21SWilly Tu { 111861b1eb21SWilly Tu std::string id = sdbusplus::message::object_path(path).filename(); 111961b1eb21SWilly Tu if (id.empty()) 112061b1eb21SWilly Tu { 112162598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find filename in {}", path); 112261b1eb21SWilly Tu return; 112361b1eb21SWilly Tu } 112461b1eb21SWilly Tu nlohmann::json::object_t member; 112561b1eb21SWilly Tu member["@odata.id"] = boost::urls::format( 1126253f11b8SEd Tanous "/redfish/v1/Systems/{}/Storage/1/Controllers/{}", 1127253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, id); 112861b1eb21SWilly Tu members.emplace_back(member); 112961b1eb21SWilly Tu } 113061b1eb21SWilly Tu asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 113161b1eb21SWilly Tu asyncResp->res.jsonValue["Members"] = std::move(members); 113261b1eb21SWilly Tu } 113361b1eb21SWilly Tu 113436d52334SEd Tanous inline void handleSystemsStorageControllerCollectionGet( 113561b1eb21SWilly Tu App& app, const crow::Request& req, 113661b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 113761b1eb21SWilly Tu const std::string& systemName) 113861b1eb21SWilly Tu { 113961b1eb21SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 114061b1eb21SWilly Tu { 114162598e31SEd Tanous BMCWEB_LOG_DEBUG( 114262598e31SEd Tanous "Failed to setup Redfish Route for StorageController Collection"); 114361b1eb21SWilly Tu return; 114461b1eb21SWilly Tu } 1145253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 114661b1eb21SWilly Tu { 114761b1eb21SWilly Tu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 114861b1eb21SWilly Tu systemName); 114962598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName); 115061b1eb21SWilly Tu return; 115161b1eb21SWilly Tu } 115261b1eb21SWilly Tu 115361b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = 115461b1eb21SWilly Tu "#StorageControllerCollection.StorageControllerCollection"; 115561b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 1156253f11b8SEd Tanous std::format("/redfish/v1/Systems/{}/Storage/1/Controllers", 1157253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 115861b1eb21SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage Controller Collection"; 115961b1eb21SWilly Tu 116061b1eb21SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 116161b1eb21SWilly Tu "xyz.openbmc_project.Inventory.Item.StorageController"}; 116261b1eb21SWilly Tu dbus::utility::getSubTreePaths( 116361b1eb21SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 116461b1eb21SWilly Tu [asyncResp](const boost::system::error_code& ec, 116561b1eb21SWilly Tu const dbus::utility::MapperGetSubTreePathsResponse& 116661b1eb21SWilly Tu controllerList) { 116761b1eb21SWilly Tu populateStorageControllerCollection(asyncResp, ec, controllerList); 116861b1eb21SWilly Tu }); 116961b1eb21SWilly Tu } 117061b1eb21SWilly Tu 117136d52334SEd Tanous inline void handleSystemsStorageControllerGet( 117261b1eb21SWilly Tu App& app, const crow::Request& req, 117361b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 117461b1eb21SWilly Tu const std::string& systemName, const std::string& controllerId) 117561b1eb21SWilly Tu { 117661b1eb21SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117761b1eb21SWilly Tu { 117862598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController"); 117961b1eb21SWilly Tu return; 118061b1eb21SWilly Tu } 1181253f11b8SEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 118261b1eb21SWilly Tu { 118361b1eb21SWilly Tu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 118461b1eb21SWilly Tu systemName); 118562598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName); 118661b1eb21SWilly Tu return; 118761b1eb21SWilly Tu } 118861b1eb21SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 118961b1eb21SWilly Tu "xyz.openbmc_project.Inventory.Item.StorageController"}; 119061b1eb21SWilly Tu dbus::utility::getSubTree( 119161b1eb21SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 119261b1eb21SWilly Tu [asyncResp, 119361b1eb21SWilly Tu controllerId](const boost::system::error_code& ec, 119461b1eb21SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) { 119561b1eb21SWilly Tu getStorageControllerHandler(asyncResp, controllerId, ec, subtree); 119661b1eb21SWilly Tu }); 119761b1eb21SWilly Tu } 119861b1eb21SWilly Tu 119961b1eb21SWilly Tu inline void requestRoutesStorageControllerCollection(App& app) 120061b1eb21SWilly Tu { 120161b1eb21SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/") 120261b1eb21SWilly Tu .privileges(redfish::privileges::getStorageControllerCollection) 120336d52334SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 120436d52334SEd Tanous handleSystemsStorageControllerCollectionGet, std::ref(app))); 120561b1eb21SWilly Tu } 120661b1eb21SWilly Tu 120761b1eb21SWilly Tu inline void requestRoutesStorageController(App& app) 120861b1eb21SWilly Tu { 120961b1eb21SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>") 121061b1eb21SWilly Tu .privileges(redfish::privileges::getStorageController) 121161b1eb21SWilly Tu .methods(boost::beast::http::verb::get)( 121236d52334SEd Tanous std::bind_front(handleSystemsStorageControllerGet, std::ref(app))); 121361b1eb21SWilly Tu } 121461b1eb21SWilly Tu 1215a25aeccfSNikhil Potade } // namespace redfish 1216