1a25aeccfSNikhil Potade /* 2a25aeccfSNikhil Potade // Copyright (c) 2019 Intel Corporation 3a25aeccfSNikhil Potade // 4a25aeccfSNikhil Potade // Licensed under the Apache License, Version 2.0 (the "License"); 5a25aeccfSNikhil Potade // you may not use this file except in compliance with the License. 6a25aeccfSNikhil Potade // You may obtain a copy of the License at 7a25aeccfSNikhil Potade // 8a25aeccfSNikhil Potade // http://www.apache.org/licenses/LICENSE-2.0 9a25aeccfSNikhil Potade // 10a25aeccfSNikhil Potade // Unless required by applicable law or agreed to in writing, software 11a25aeccfSNikhil Potade // distributed under the License is distributed on an "AS IS" BASIS, 12a25aeccfSNikhil Potade // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a25aeccfSNikhil Potade // See the License for the specific language governing permissions and 14a25aeccfSNikhil Potade // 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" 242ad9c2f6SJames Feist #include "health.hpp" 25a8e884fcSEd Tanous #include "human_sort.hpp" 26e284a7c1SJames Feist #include "openbmc_dbus_rest.hpp" 273ccb3adbSEd Tanous #include "query.hpp" 28a8e884fcSEd Tanous #include "redfish_util.hpp" 293ccb3adbSEd Tanous #include "registries/privilege_registry.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> 387a1dbc48SGeorge Liu #include <string_view> 397a1dbc48SGeorge Liu 40a25aeccfSNikhil Potade namespace redfish 41a25aeccfSNikhil Potade { 427e860f15SJohn Edward Broadbent inline void requestRoutesStorageCollection(App& app) 43a25aeccfSNikhil Potade { 4422d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/") 45ed398213SEd Tanous .privileges(redfish::privileges::getStorageCollection) 467e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 4745ca1b86SEd Tanous [&app](const crow::Request& req, 4822d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4922d268cbSEd Tanous const std::string& systemName) { 503ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 5145ca1b86SEd Tanous { 5245ca1b86SEd Tanous return; 5345ca1b86SEd Tanous } 5422d268cbSEd Tanous if (systemName != "system") 5522d268cbSEd Tanous { 5622d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 5722d268cbSEd Tanous systemName); 5822d268cbSEd Tanous return; 5922d268cbSEd Tanous } 6022d268cbSEd Tanous 618d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 628d1b46d7Szhanghch05 "#StorageCollection.StorageCollection"; 638d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = 648d1b46d7Szhanghch05 "/redfish/v1/Systems/system/Storage"; 658d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Storage Collection"; 661476687dSEd Tanous nlohmann::json::array_t members; 671476687dSEd Tanous nlohmann::json::object_t member; 681476687dSEd Tanous member["@odata.id"] = "/redfish/v1/Systems/system/Storage/1"; 691476687dSEd Tanous members.emplace_back(member); 701476687dSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(members); 718d1b46d7Szhanghch05 asyncResp->res.jsonValue["Members@odata.count"] = 1; 727e860f15SJohn Edward Broadbent }); 73a25aeccfSNikhil Potade } 74a25aeccfSNikhil Potade 75a85afbe1SWilly Tu inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 76a85afbe1SWilly Tu const std::shared_ptr<HealthPopulate>& health) 77a25aeccfSNikhil Potade { 787a1dbc48SGeorge Liu const std::array<std::string_view, 1> interfaces = { 797a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Drive"}; 807a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 817a1dbc48SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 82a85afbe1SWilly Tu [asyncResp, health]( 837a1dbc48SGeorge Liu const boost::system::error_code& ec, 84a85afbe1SWilly Tu const dbus::utility::MapperGetSubTreePathsResponse& driveList) { 85a25aeccfSNikhil Potade if (ec) 86a25aeccfSNikhil Potade { 87a25aeccfSNikhil Potade BMCWEB_LOG_ERROR << "Drive mapper call error"; 88a25aeccfSNikhil Potade messages::internalError(asyncResp->res); 89a25aeccfSNikhil Potade return; 90a25aeccfSNikhil Potade } 912ad9c2f6SJames Feist 92a85afbe1SWilly Tu nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"]; 93a85afbe1SWilly Tu driveArray = nlohmann::json::array(); 94a85afbe1SWilly Tu auto& count = asyncResp->res.jsonValue["Drives@odata.count"]; 95a85afbe1SWilly Tu count = 0; 962ad9c2f6SJames Feist 9713451e39SWilly Tu if constexpr (bmcwebEnableHealthPopulate) 9813451e39SWilly Tu { 99a85afbe1SWilly Tu health->inventory.insert(health->inventory.end(), driveList.begin(), 100a85afbe1SWilly Tu driveList.end()); 10113451e39SWilly Tu } 102a85afbe1SWilly Tu 103a85afbe1SWilly Tu for (const std::string& drive : driveList) 104a25aeccfSNikhil Potade { 105a85afbe1SWilly Tu sdbusplus::message::object_path object(drive); 106a85afbe1SWilly Tu if (object.filename().empty()) 107a25aeccfSNikhil Potade { 108a85afbe1SWilly Tu BMCWEB_LOG_ERROR << "Failed to find filename in " << drive; 109a85afbe1SWilly Tu return; 110a25aeccfSNikhil Potade } 111a85afbe1SWilly Tu 112a85afbe1SWilly Tu nlohmann::json::object_t driveJson; 113ef4c65b7SEd Tanous driveJson["@odata.id"] = boost::urls::format( 114ef4c65b7SEd Tanous "/redfish/v1/Systems/system/Storage/1/Drives/{}", 115eddfc437SWilly Tu object.filename()); 116b2ba3072SPatrick Williams driveArray.emplace_back(std::move(driveJson)); 117a25aeccfSNikhil Potade } 118a25aeccfSNikhil Potade 119a85afbe1SWilly Tu count = driveArray.size(); 1207a1dbc48SGeorge Liu }); 121a85afbe1SWilly Tu } 122e284a7c1SJames Feist 123a85afbe1SWilly Tu inline void requestRoutesStorage(App& app) 124a85afbe1SWilly Tu { 125a85afbe1SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/") 126a85afbe1SWilly Tu .privileges(redfish::privileges::getStorage) 127a85afbe1SWilly Tu .methods(boost::beast::http::verb::get)( 128a85afbe1SWilly Tu [&app](const crow::Request& req, 129a85afbe1SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 131a85afbe1SWilly Tu { 132a85afbe1SWilly Tu return; 133a85afbe1SWilly Tu } 134*61b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage"; 135a85afbe1SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 136a85afbe1SWilly Tu "/redfish/v1/Systems/system/Storage/1"; 137a85afbe1SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage"; 138a85afbe1SWilly Tu asyncResp->res.jsonValue["Id"] = "1"; 139a85afbe1SWilly Tu asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 140a85afbe1SWilly Tu 141a85afbe1SWilly Tu auto health = std::make_shared<HealthPopulate>(asyncResp); 14213451e39SWilly Tu if constexpr (bmcwebEnableHealthPopulate) 14313451e39SWilly Tu { 144a85afbe1SWilly Tu health->populate(); 14513451e39SWilly Tu } 146a85afbe1SWilly Tu 147a85afbe1SWilly Tu getDrives(asyncResp, health); 148*61b1eb21SWilly Tu asyncResp->res.jsonValue["Controllers"]["@odata.id"] = 149*61b1eb21SWilly Tu "/redfish/v1/Systems/system/Storage/1/Controllers"; 1507e860f15SJohn Edward Broadbent }); 1517e860f15SJohn Edward Broadbent } 1527e860f15SJohn Edward Broadbent 15303913171SWilly Tu inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 15403913171SWilly Tu const std::string& connectionName, 15503913171SWilly Tu const std::string& path) 15603913171SWilly Tu { 157d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 158d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 159d1bde9e5SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 1605e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 161168e20c1SEd Tanous const std::vector< 162168e20c1SEd Tanous std::pair<std::string, dbus::utility::DbusVariantType>>& 16303913171SWilly Tu propertiesList) { 16403913171SWilly Tu if (ec) 16503913171SWilly Tu { 16603913171SWilly Tu // this interface isn't necessary 16703913171SWilly Tu return; 16803913171SWilly Tu } 169d1bde9e5SKrzysztof Grobelny 170d1bde9e5SKrzysztof Grobelny const std::string* partNumber = nullptr; 171d1bde9e5SKrzysztof Grobelny const std::string* serialNumber = nullptr; 172d1bde9e5SKrzysztof Grobelny const std::string* manufacturer = nullptr; 173d1bde9e5SKrzysztof Grobelny const std::string* model = nullptr; 174d1bde9e5SKrzysztof Grobelny 175d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 176d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 177d1bde9e5SKrzysztof Grobelny partNumber, "SerialNumber", serialNumber, "Manufacturer", 178d1bde9e5SKrzysztof Grobelny manufacturer, "Model", model); 179d1bde9e5SKrzysztof Grobelny 180d1bde9e5SKrzysztof Grobelny if (!success) 18103913171SWilly Tu { 18203913171SWilly Tu messages::internalError(asyncResp->res); 18303913171SWilly Tu return; 18403913171SWilly Tu } 185d1bde9e5SKrzysztof Grobelny 186d1bde9e5SKrzysztof Grobelny if (partNumber != nullptr) 187d1bde9e5SKrzysztof Grobelny { 188d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["PartNumber"] = *partNumber; 18903913171SWilly Tu } 190d1bde9e5SKrzysztof Grobelny 191d1bde9e5SKrzysztof Grobelny if (serialNumber != nullptr) 192d1bde9e5SKrzysztof Grobelny { 193d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 19403913171SWilly Tu } 195d1bde9e5SKrzysztof Grobelny 196d1bde9e5SKrzysztof Grobelny if (manufacturer != nullptr) 197d1bde9e5SKrzysztof Grobelny { 198d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 199d1bde9e5SKrzysztof Grobelny } 200d1bde9e5SKrzysztof Grobelny 201d1bde9e5SKrzysztof Grobelny if (model != nullptr) 202d1bde9e5SKrzysztof Grobelny { 203d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["Model"] = *model; 204d1bde9e5SKrzysztof Grobelny } 205d1bde9e5SKrzysztof Grobelny }); 20603913171SWilly Tu } 20703913171SWilly Tu 20803913171SWilly Tu inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 20903913171SWilly Tu const std::string& connectionName, 21003913171SWilly Tu const std::string& path) 21103913171SWilly Tu { 2121e1e598dSJonathan Doman sdbusplus::asio::getProperty<bool>( 2131e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 2141e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Item", "Present", 2155e7e2dc5SEd Tanous [asyncResp, path](const boost::system::error_code& ec, 216cef57e85SWilly Tu const bool isPresent) { 21703913171SWilly Tu // this interface isn't necessary, only check it if 21803913171SWilly Tu // we get a good return 21903913171SWilly Tu if (ec) 22003913171SWilly Tu { 22103913171SWilly Tu return; 22203913171SWilly Tu } 22303913171SWilly Tu 224cef57e85SWilly Tu if (!isPresent) 22503913171SWilly Tu { 226cef57e85SWilly Tu asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 22703913171SWilly Tu } 2281e1e598dSJonathan Doman }); 22903913171SWilly Tu } 23003913171SWilly Tu 23103913171SWilly Tu inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 23203913171SWilly Tu const std::string& connectionName, 23303913171SWilly Tu const std::string& path) 23403913171SWilly Tu { 2351e1e598dSJonathan Doman sdbusplus::asio::getProperty<bool>( 2361e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 2371e1e598dSJonathan Doman "xyz.openbmc_project.State.Drive", "Rebuilding", 2385e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, const bool updating) { 23903913171SWilly Tu // this interface isn't necessary, only check it 24003913171SWilly Tu // if we get a good return 24103913171SWilly Tu if (ec) 24203913171SWilly Tu { 24303913171SWilly Tu return; 24403913171SWilly Tu } 24503913171SWilly Tu 24603913171SWilly Tu // updating and disabled in the backend shouldn't be 24703913171SWilly Tu // able to be set at the same time, so we don't need 24803913171SWilly Tu // to check for the race condition of these two 24903913171SWilly Tu // calls 2501e1e598dSJonathan Doman if (updating) 25103913171SWilly Tu { 25203913171SWilly Tu asyncResp->res.jsonValue["Status"]["State"] = "Updating"; 25303913171SWilly Tu } 2541e1e598dSJonathan Doman }); 25503913171SWilly Tu } 25603913171SWilly Tu 257dde9bc12SGeorge Liu inline std::optional<drive::MediaType> convertDriveType(std::string_view type) 25819b8e9a0SWilly Tu { 25919b8e9a0SWilly Tu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD") 26019b8e9a0SWilly Tu { 261dde9bc12SGeorge Liu return drive::MediaType::HDD; 26219b8e9a0SWilly Tu } 26319b8e9a0SWilly Tu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD") 26419b8e9a0SWilly Tu { 265dde9bc12SGeorge Liu return drive::MediaType::SSD; 26619b8e9a0SWilly Tu } 267dde9bc12SGeorge Liu if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown") 268dde9bc12SGeorge Liu { 26919b8e9a0SWilly Tu return std::nullopt; 27019b8e9a0SWilly Tu } 27119b8e9a0SWilly Tu 272dde9bc12SGeorge Liu return drive::MediaType::Invalid; 273dde9bc12SGeorge Liu } 274dde9bc12SGeorge Liu 275dde9bc12SGeorge Liu inline std::optional<protocol::Protocol> 276dde9bc12SGeorge Liu convertDriveProtocol(std::string_view proto) 27719b8e9a0SWilly Tu { 27819b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS") 27919b8e9a0SWilly Tu { 280dde9bc12SGeorge Liu return protocol::Protocol::SAS; 28119b8e9a0SWilly Tu } 28219b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA") 28319b8e9a0SWilly Tu { 284dde9bc12SGeorge Liu return protocol::Protocol::SATA; 28519b8e9a0SWilly Tu } 28619b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe") 28719b8e9a0SWilly Tu { 288dde9bc12SGeorge Liu return protocol::Protocol::NVMe; 28919b8e9a0SWilly Tu } 29019b8e9a0SWilly Tu if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC") 29119b8e9a0SWilly Tu { 292dde9bc12SGeorge Liu return protocol::Protocol::FC; 293dde9bc12SGeorge Liu } 294dde9bc12SGeorge Liu if (proto == 295dde9bc12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown") 296dde9bc12SGeorge Liu { 297dde9bc12SGeorge Liu return std::nullopt; 29819b8e9a0SWilly Tu } 29919b8e9a0SWilly Tu 300dde9bc12SGeorge Liu return protocol::Protocol::Invalid; 30119b8e9a0SWilly Tu } 30219b8e9a0SWilly Tu 30319b8e9a0SWilly Tu inline void 30419b8e9a0SWilly Tu getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30519b8e9a0SWilly Tu const std::string& connectionName, 30619b8e9a0SWilly Tu const std::string& path) 30719b8e9a0SWilly Tu { 30819b8e9a0SWilly Tu sdbusplus::asio::getAllProperties( 30919b8e9a0SWilly Tu *crow::connections::systemBus, connectionName, path, 31019b8e9a0SWilly Tu "xyz.openbmc_project.Inventory.Item.Drive", 3115e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 31219b8e9a0SWilly Tu const std::vector< 31319b8e9a0SWilly Tu std::pair<std::string, dbus::utility::DbusVariantType>>& 31419b8e9a0SWilly Tu propertiesList) { 31519b8e9a0SWilly Tu if (ec) 31619b8e9a0SWilly Tu { 31719b8e9a0SWilly Tu // this interface isn't required 31819b8e9a0SWilly Tu return; 31919b8e9a0SWilly Tu } 320e5029d88SJohn Edward Broadbent const std::string* encryptionStatus = nullptr; 321e5029d88SJohn Edward Broadbent const bool* isLocked = nullptr; 32219b8e9a0SWilly Tu for (const std::pair<std::string, dbus::utility::DbusVariantType>& 32319b8e9a0SWilly Tu property : propertiesList) 32419b8e9a0SWilly Tu { 32519b8e9a0SWilly Tu const std::string& propertyName = property.first; 32619b8e9a0SWilly Tu if (propertyName == "Type") 32719b8e9a0SWilly Tu { 32819b8e9a0SWilly Tu const std::string* value = 32919b8e9a0SWilly Tu std::get_if<std::string>(&property.second); 33019b8e9a0SWilly Tu if (value == nullptr) 33119b8e9a0SWilly Tu { 33219b8e9a0SWilly Tu // illegal property 33319b8e9a0SWilly Tu BMCWEB_LOG_ERROR << "Illegal property: Type"; 33419b8e9a0SWilly Tu messages::internalError(asyncResp->res); 33519b8e9a0SWilly Tu return; 33619b8e9a0SWilly Tu } 33719b8e9a0SWilly Tu 338dde9bc12SGeorge Liu std::optional<drive::MediaType> mediaType = 339dde9bc12SGeorge Liu convertDriveType(*value); 34019b8e9a0SWilly Tu if (!mediaType) 34119b8e9a0SWilly Tu { 342dde9bc12SGeorge Liu BMCWEB_LOG_WARNING << "UnknownDriveType Interface: " 34319b8e9a0SWilly Tu << *value; 344dde9bc12SGeorge Liu continue; 345dde9bc12SGeorge Liu } 346dde9bc12SGeorge Liu if (*mediaType == drive::MediaType::Invalid) 347dde9bc12SGeorge Liu { 34819b8e9a0SWilly Tu messages::internalError(asyncResp->res); 34919b8e9a0SWilly Tu return; 35019b8e9a0SWilly Tu } 35119b8e9a0SWilly Tu 35219b8e9a0SWilly Tu asyncResp->res.jsonValue["MediaType"] = *mediaType; 35319b8e9a0SWilly Tu } 35419b8e9a0SWilly Tu else if (propertyName == "Capacity") 35519b8e9a0SWilly Tu { 35619b8e9a0SWilly Tu const uint64_t* capacity = 35719b8e9a0SWilly Tu std::get_if<uint64_t>(&property.second); 35819b8e9a0SWilly Tu if (capacity == nullptr) 35919b8e9a0SWilly Tu { 36019b8e9a0SWilly Tu BMCWEB_LOG_ERROR << "Illegal property: Capacity"; 36119b8e9a0SWilly Tu messages::internalError(asyncResp->res); 36219b8e9a0SWilly Tu return; 36319b8e9a0SWilly Tu } 36419b8e9a0SWilly Tu if (*capacity == 0) 36519b8e9a0SWilly Tu { 36619b8e9a0SWilly Tu // drive capacity not known 36719b8e9a0SWilly Tu continue; 36819b8e9a0SWilly Tu } 36919b8e9a0SWilly Tu 37019b8e9a0SWilly Tu asyncResp->res.jsonValue["CapacityBytes"] = *capacity; 37119b8e9a0SWilly Tu } 37219b8e9a0SWilly Tu else if (propertyName == "Protocol") 37319b8e9a0SWilly Tu { 37419b8e9a0SWilly Tu const std::string* value = 37519b8e9a0SWilly Tu std::get_if<std::string>(&property.second); 37619b8e9a0SWilly Tu if (value == nullptr) 37719b8e9a0SWilly Tu { 37819b8e9a0SWilly Tu BMCWEB_LOG_ERROR << "Illegal property: Protocol"; 37919b8e9a0SWilly Tu messages::internalError(asyncResp->res); 38019b8e9a0SWilly Tu return; 38119b8e9a0SWilly Tu } 38219b8e9a0SWilly Tu 383dde9bc12SGeorge Liu std::optional<protocol::Protocol> proto = 384dde9bc12SGeorge Liu convertDriveProtocol(*value); 38519b8e9a0SWilly Tu if (!proto) 38619b8e9a0SWilly Tu { 387dde9bc12SGeorge Liu BMCWEB_LOG_WARNING << "Unknown DrivePrototype Interface: " 38819b8e9a0SWilly Tu << *value; 389dde9bc12SGeorge Liu continue; 390dde9bc12SGeorge Liu } 391dde9bc12SGeorge Liu if (*proto == protocol::Protocol::Invalid) 392dde9bc12SGeorge Liu { 39319b8e9a0SWilly Tu messages::internalError(asyncResp->res); 39419b8e9a0SWilly Tu return; 39519b8e9a0SWilly Tu } 39619b8e9a0SWilly Tu asyncResp->res.jsonValue["Protocol"] = *proto; 39719b8e9a0SWilly Tu } 3983fe4d5ccSJohn Edward Broadbent else if (propertyName == "PredictedMediaLifeLeftPercent") 3993fe4d5ccSJohn Edward Broadbent { 4003fe4d5ccSJohn Edward Broadbent const uint8_t* lifeLeft = 4013fe4d5ccSJohn Edward Broadbent std::get_if<uint8_t>(&property.second); 4023fe4d5ccSJohn Edward Broadbent if (lifeLeft == nullptr) 4033fe4d5ccSJohn Edward Broadbent { 4043fe4d5ccSJohn Edward Broadbent BMCWEB_LOG_ERROR 4053fe4d5ccSJohn Edward Broadbent << "Illegal property: PredictedMediaLifeLeftPercent"; 4063fe4d5ccSJohn Edward Broadbent messages::internalError(asyncResp->res); 4073fe4d5ccSJohn Edward Broadbent return; 4083fe4d5ccSJohn Edward Broadbent } 4093fe4d5ccSJohn Edward Broadbent // 255 means reading the value is not supported 4103fe4d5ccSJohn Edward Broadbent if (*lifeLeft != 255) 4113fe4d5ccSJohn Edward Broadbent { 4123fe4d5ccSJohn Edward Broadbent asyncResp->res.jsonValue["PredictedMediaLifeLeftPercent"] = 4133fe4d5ccSJohn Edward Broadbent *lifeLeft; 4143fe4d5ccSJohn Edward Broadbent } 4153fe4d5ccSJohn Edward Broadbent } 416e5029d88SJohn Edward Broadbent else if (propertyName == "EncryptionStatus") 417e5029d88SJohn Edward Broadbent { 418e5029d88SJohn Edward Broadbent encryptionStatus = std::get_if<std::string>(&property.second); 419e5029d88SJohn Edward Broadbent if (encryptionStatus == nullptr) 420e5029d88SJohn Edward Broadbent { 421e5029d88SJohn Edward Broadbent BMCWEB_LOG_ERROR << "Illegal property: EncryptionStatus"; 422e5029d88SJohn Edward Broadbent messages::internalError(asyncResp->res); 423e5029d88SJohn Edward Broadbent return; 42419b8e9a0SWilly Tu } 425e5029d88SJohn Edward Broadbent } 426e5029d88SJohn Edward Broadbent else if (propertyName == "Locked") 427e5029d88SJohn Edward Broadbent { 428e5029d88SJohn Edward Broadbent isLocked = std::get_if<bool>(&property.second); 429e5029d88SJohn Edward Broadbent if (isLocked == nullptr) 430e5029d88SJohn Edward Broadbent { 431e5029d88SJohn Edward Broadbent BMCWEB_LOG_ERROR << "Illegal property: Locked"; 432e5029d88SJohn Edward Broadbent messages::internalError(asyncResp->res); 433e5029d88SJohn Edward Broadbent return; 434e5029d88SJohn Edward Broadbent } 435e5029d88SJohn Edward Broadbent } 436e5029d88SJohn Edward Broadbent } 437e5029d88SJohn Edward Broadbent 438e5029d88SJohn Edward Broadbent if (encryptionStatus == nullptr || isLocked == nullptr || 439e5029d88SJohn Edward Broadbent *encryptionStatus == 440e5029d88SJohn Edward Broadbent "xyz.openbmc_project.Drive.DriveEncryptionState.Unknown") 441e5029d88SJohn Edward Broadbent { 442e5029d88SJohn Edward Broadbent return; 443e5029d88SJohn Edward Broadbent } 444e5029d88SJohn Edward Broadbent if (*encryptionStatus != 445e5029d88SJohn Edward Broadbent "xyz.openbmc_project.Drive.DriveEncryptionState.Encrypted") 446e5029d88SJohn Edward Broadbent { 447e5029d88SJohn Edward Broadbent //"The drive is not currently encrypted." 448e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 449e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Unencrypted; 450e5029d88SJohn Edward Broadbent return; 451e5029d88SJohn Edward Broadbent } 452e5029d88SJohn Edward Broadbent if (*isLocked) 453e5029d88SJohn Edward Broadbent { 454e5029d88SJohn Edward Broadbent //"The drive is currently encrypted and the data is not 455e5029d88SJohn Edward Broadbent // accessible to the user." 456e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 457e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Locked; 458e5029d88SJohn Edward Broadbent return; 459e5029d88SJohn Edward Broadbent } 460e5029d88SJohn Edward Broadbent // if not locked 461e5029d88SJohn Edward Broadbent // "The drive is currently encrypted but the data is accessible 462e5029d88SJohn Edward Broadbent // to the user in unencrypted form." 463e5029d88SJohn Edward Broadbent asyncResp->res.jsonValue["EncryptionStatus"] = 464e5029d88SJohn Edward Broadbent drive::EncryptionStatus::Unlocked; 46519b8e9a0SWilly Tu }); 46619b8e9a0SWilly Tu } 46719b8e9a0SWilly Tu 468b53dcd9dSNan Zhou static void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 469b53dcd9dSNan Zhou const std::string& connectionName, 470b53dcd9dSNan Zhou const std::string& path, 471e56ed6b9SJohn Edward Broadbent const std::vector<std::string>& interfaces) 472e56ed6b9SJohn Edward Broadbent { 473e56ed6b9SJohn Edward Broadbent for (const std::string& interface : interfaces) 474e56ed6b9SJohn Edward Broadbent { 475e56ed6b9SJohn Edward Broadbent if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset") 476e56ed6b9SJohn Edward Broadbent { 477e56ed6b9SJohn Edward Broadbent getDriveAsset(asyncResp, connectionName, path); 478e56ed6b9SJohn Edward Broadbent } 479e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.Inventory.Item") 480e56ed6b9SJohn Edward Broadbent { 481e56ed6b9SJohn Edward Broadbent getDrivePresent(asyncResp, connectionName, path); 482e56ed6b9SJohn Edward Broadbent } 483e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.State.Drive") 484e56ed6b9SJohn Edward Broadbent { 485e56ed6b9SJohn Edward Broadbent getDriveState(asyncResp, connectionName, path); 486e56ed6b9SJohn Edward Broadbent } 487e56ed6b9SJohn Edward Broadbent else if (interface == "xyz.openbmc_project.Inventory.Item.Drive") 488e56ed6b9SJohn Edward Broadbent { 489e56ed6b9SJohn Edward Broadbent getDriveItemProperties(asyncResp, connectionName, path); 490e56ed6b9SJohn Edward Broadbent } 491e56ed6b9SJohn Edward Broadbent } 492e56ed6b9SJohn Edward Broadbent } 493e56ed6b9SJohn Edward Broadbent 4947e860f15SJohn Edward Broadbent inline void requestRoutesDrive(App& app) 4957e860f15SJohn Edward Broadbent { 49622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/") 497ed398213SEd Tanous .privileges(redfish::privileges::getDrive) 498002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 499002d39b4SEd Tanous [&app](const crow::Request& req, 50045ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 50122d268cbSEd Tanous const std::string& systemName, const std::string& driveId) { 5023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 50345ca1b86SEd Tanous { 50445ca1b86SEd Tanous return; 50545ca1b86SEd Tanous } 50622d268cbSEd Tanous if (systemName != "system") 50722d268cbSEd Tanous { 50822d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 50922d268cbSEd Tanous systemName); 51022d268cbSEd Tanous return; 51122d268cbSEd Tanous } 51222d268cbSEd Tanous 513e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 514e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Item.Drive"}; 515e99073f5SGeorge Liu dbus::utility::getSubTree( 516e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 517002d39b4SEd Tanous [asyncResp, 518e99073f5SGeorge Liu driveId](const boost::system::error_code& ec, 519b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 5207e860f15SJohn Edward Broadbent if (ec) 5217e860f15SJohn Edward Broadbent { 5227e860f15SJohn Edward Broadbent BMCWEB_LOG_ERROR << "Drive mapper call error"; 5237e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 5247e860f15SJohn Edward Broadbent return; 5257e860f15SJohn Edward Broadbent } 5267e860f15SJohn Edward Broadbent 52703913171SWilly Tu auto drive = std::find_if( 5287e860f15SJohn Edward Broadbent subtree.begin(), subtree.end(), 529002d39b4SEd Tanous [&driveId]( 5308cb65f8aSNan Zhou const std::pair<std::string, 5318cb65f8aSNan Zhou dbus::utility::MapperServiceMap>& object) { 53203913171SWilly Tu return sdbusplus::message::object_path(object.first) 53303913171SWilly Tu .filename() == driveId; 5347e860f15SJohn Edward Broadbent }); 5357e860f15SJohn Edward Broadbent 53603913171SWilly Tu if (drive == subtree.end()) 5377e860f15SJohn Edward Broadbent { 538002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "Drive", driveId); 5397e860f15SJohn Edward Broadbent return; 5407e860f15SJohn Edward Broadbent } 5417e860f15SJohn Edward Broadbent 54203913171SWilly Tu const std::string& path = drive->first; 5438cb65f8aSNan Zhou const dbus::utility::MapperServiceMap& connectionNames = 5448cb65f8aSNan Zhou drive->second; 5457e860f15SJohn Edward Broadbent 546002d39b4SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive"; 547ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 548ef4c65b7SEd Tanous "/redfish/v1/Systems/system/Storage/1/Drives/{}", driveId); 5497e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = driveId; 5507e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Id"] = driveId; 5517e860f15SJohn Edward Broadbent 5527e860f15SJohn Edward Broadbent if (connectionNames.size() != 1) 5537e860f15SJohn Edward Broadbent { 554002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Connection size " << connectionNames.size() 55503913171SWilly Tu << ", not equal to 1"; 5567e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 5577e860f15SJohn Edward Broadbent return; 5587e860f15SJohn Edward Broadbent } 5597e860f15SJohn Edward Broadbent 5607e860f15SJohn Edward Broadbent getMainChassisId( 561ef4c65b7SEd Tanous asyncResp, 562ef4c65b7SEd Tanous [](const std::string& chassisId, 5637e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 564002d39b4SEd Tanous aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] = 565ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 5667e860f15SJohn Edward Broadbent }); 5677e860f15SJohn Edward Broadbent 568a25aeccfSNikhil Potade // default it to Enabled 569a25aeccfSNikhil Potade asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 570a25aeccfSNikhil Potade 57113451e39SWilly Tu if constexpr (bmcwebEnableHealthPopulate) 57213451e39SWilly Tu { 5732ad9c2f6SJames Feist auto health = std::make_shared<HealthPopulate>(asyncResp); 574e284a7c1SJames Feist health->inventory.emplace_back(path); 5752ad9c2f6SJames Feist health->populate(); 57613451e39SWilly Tu } 5772ad9c2f6SJames Feist 578e56ed6b9SJohn Edward Broadbent addAllDriveInfo(asyncResp, connectionNames[0].first, path, 579e56ed6b9SJohn Edward Broadbent connectionNames[0].second); 580e99073f5SGeorge Liu }); 5817e860f15SJohn Edward Broadbent }); 582a25aeccfSNikhil Potade } 58392903bd4SJohn Edward Broadbent 58492903bd4SJohn Edward Broadbent /** 58592903bd4SJohn Edward Broadbent * Chassis drives, this URL will show all the DriveCollection 58692903bd4SJohn Edward Broadbent * information 58792903bd4SJohn Edward Broadbent */ 588b53dcd9dSNan Zhou inline void chassisDriveCollectionGet( 58992903bd4SJohn Edward Broadbent crow::App& app, const crow::Request& req, 59092903bd4SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 59192903bd4SJohn Edward Broadbent const std::string& chassisId) 59292903bd4SJohn Edward Broadbent { 5933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 59492903bd4SJohn Edward Broadbent { 59592903bd4SJohn Edward Broadbent return; 59692903bd4SJohn Edward Broadbent } 59792903bd4SJohn Edward Broadbent 59892903bd4SJohn Edward Broadbent // mapper call lambda 599e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 600e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board", 601e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis"}; 602e99073f5SGeorge Liu dbus::utility::getSubTree( 603e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 60492903bd4SJohn Edward Broadbent [asyncResp, 605e99073f5SGeorge Liu chassisId](const boost::system::error_code& ec, 60692903bd4SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) { 60792903bd4SJohn Edward Broadbent if (ec) 60892903bd4SJohn Edward Broadbent { 60992903bd4SJohn Edward Broadbent if (ec == boost::system::errc::host_unreachable) 61092903bd4SJohn Edward Broadbent { 61192903bd4SJohn Edward Broadbent messages::resourceNotFound(asyncResp->res, "Chassis", 61292903bd4SJohn Edward Broadbent chassisId); 61392903bd4SJohn Edward Broadbent return; 61492903bd4SJohn Edward Broadbent } 61592903bd4SJohn Edward Broadbent messages::internalError(asyncResp->res); 61692903bd4SJohn Edward Broadbent return; 61792903bd4SJohn Edward Broadbent } 61892903bd4SJohn Edward Broadbent 61992903bd4SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 6208cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 62192903bd4SJohn Edward Broadbent { 62292903bd4SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 62392903bd4SJohn Edward Broadbent if (objPath.filename() != chassisId) 62492903bd4SJohn Edward Broadbent { 62592903bd4SJohn Edward Broadbent continue; 62692903bd4SJohn Edward Broadbent } 62792903bd4SJohn Edward Broadbent 62892903bd4SJohn Edward Broadbent if (connectionNames.empty()) 62992903bd4SJohn Edward Broadbent { 63092903bd4SJohn Edward Broadbent BMCWEB_LOG_ERROR << "Got 0 Connection names"; 63192903bd4SJohn Edward Broadbent continue; 63292903bd4SJohn Edward Broadbent } 63392903bd4SJohn Edward Broadbent 63492903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.type"] = 63592903bd4SJohn Edward Broadbent "#DriveCollection.DriveCollection"; 63692903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.id"] = 637ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId); 63892903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = "Drive Collection"; 63992903bd4SJohn Edward Broadbent 64092903bd4SJohn Edward Broadbent // Association lambda 6416c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 6426c3e9451SGeorge Liu path + "/drive", 6436c3e9451SGeorge Liu [asyncResp, 6446c3e9451SGeorge Liu chassisId](const boost::system::error_code& ec3, 6456c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 64692903bd4SJohn Edward Broadbent if (ec3) 64792903bd4SJohn Edward Broadbent { 64892903bd4SJohn Edward Broadbent BMCWEB_LOG_ERROR << "Error in chassis Drive association "; 64992903bd4SJohn Edward Broadbent } 65092903bd4SJohn Edward Broadbent nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 65192903bd4SJohn Edward Broadbent // important if array is empty 65292903bd4SJohn Edward Broadbent members = nlohmann::json::array(); 65392903bd4SJohn Edward Broadbent 65492903bd4SJohn Edward Broadbent std::vector<std::string> leafNames; 65592903bd4SJohn Edward Broadbent for (const auto& drive : resp) 65692903bd4SJohn Edward Broadbent { 6578a592810SEd Tanous sdbusplus::message::object_path drivePath(drive); 6588a592810SEd Tanous leafNames.push_back(drivePath.filename()); 65992903bd4SJohn Edward Broadbent } 66092903bd4SJohn Edward Broadbent 66192903bd4SJohn Edward Broadbent std::sort(leafNames.begin(), leafNames.end(), 66292903bd4SJohn Edward Broadbent AlphanumLess<std::string>()); 66392903bd4SJohn Edward Broadbent 66492903bd4SJohn Edward Broadbent for (const auto& leafName : leafNames) 66592903bd4SJohn Edward Broadbent { 66692903bd4SJohn Edward Broadbent nlohmann::json::object_t member; 667ef4c65b7SEd Tanous member["@odata.id"] = 668ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/Drives/{}", 669ef4c65b7SEd Tanous chassisId, leafName); 670b2ba3072SPatrick Williams members.emplace_back(std::move(member)); 67192903bd4SJohn Edward Broadbent // navigation links will be registered in next patch set 67292903bd4SJohn Edward Broadbent } 67392903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = resp.size(); 67492903bd4SJohn Edward Broadbent }); // end association lambda 67592903bd4SJohn Edward Broadbent 67692903bd4SJohn Edward Broadbent } // end Iterate over all retrieved ObjectPaths 677e99073f5SGeorge Liu }); 67892903bd4SJohn Edward Broadbent } 67992903bd4SJohn Edward Broadbent 68092903bd4SJohn Edward Broadbent inline void requestRoutesChassisDrive(App& app) 68192903bd4SJohn Edward Broadbent { 68292903bd4SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/") 68392903bd4SJohn Edward Broadbent .privileges(redfish::privileges::getDriveCollection) 68492903bd4SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 68592903bd4SJohn Edward Broadbent std::bind_front(chassisDriveCollectionGet, std::ref(app))); 68692903bd4SJohn Edward Broadbent } 68792903bd4SJohn Edward Broadbent 688b53dcd9dSNan Zhou inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 689b53dcd9dSNan Zhou const std::string& chassisId, 690b53dcd9dSNan Zhou const std::string& driveName, 6915e7e2dc5SEd Tanous const boost::system::error_code& ec, 692e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) 693e56ed6b9SJohn Edward Broadbent { 694e56ed6b9SJohn Edward Broadbent if (ec) 695e56ed6b9SJohn Edward Broadbent { 696e56ed6b9SJohn Edward Broadbent BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 697e56ed6b9SJohn Edward Broadbent messages::internalError(asyncResp->res); 698e56ed6b9SJohn Edward Broadbent return; 699e56ed6b9SJohn Edward Broadbent } 700e56ed6b9SJohn Edward Broadbent 701e56ed6b9SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 7028cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 703e56ed6b9SJohn Edward Broadbent { 704e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 705e56ed6b9SJohn Edward Broadbent if (objPath.filename() != driveName) 706e56ed6b9SJohn Edward Broadbent { 707e56ed6b9SJohn Edward Broadbent continue; 708e56ed6b9SJohn Edward Broadbent } 709e56ed6b9SJohn Edward Broadbent 710e56ed6b9SJohn Edward Broadbent if (connectionNames.empty()) 711e56ed6b9SJohn Edward Broadbent { 712e56ed6b9SJohn Edward Broadbent BMCWEB_LOG_ERROR << "Got 0 Connection names"; 713e56ed6b9SJohn Edward Broadbent continue; 714e56ed6b9SJohn Edward Broadbent } 715e56ed6b9SJohn Edward Broadbent 716ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 717ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName); 718e56ed6b9SJohn Edward Broadbent 719e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive"; 720a0cb40cbSJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = driveName; 721e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["Id"] = driveName; 722e56ed6b9SJohn Edward Broadbent // default it to Enabled 723e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 724e56ed6b9SJohn Edward Broadbent 725e56ed6b9SJohn Edward Broadbent nlohmann::json::object_t linkChassisNav; 726e56ed6b9SJohn Edward Broadbent linkChassisNav["@odata.id"] = 727ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 728e56ed6b9SJohn Edward Broadbent asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav; 729e56ed6b9SJohn Edward Broadbent 730e56ed6b9SJohn Edward Broadbent addAllDriveInfo(asyncResp, connectionNames[0].first, path, 731e56ed6b9SJohn Edward Broadbent connectionNames[0].second); 732e56ed6b9SJohn Edward Broadbent } 733e56ed6b9SJohn Edward Broadbent } 734e56ed6b9SJohn Edward Broadbent 735b53dcd9dSNan Zhou inline void 736b53dcd9dSNan Zhou matchAndFillDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 737e56ed6b9SJohn Edward Broadbent const std::string& chassisId, 738e56ed6b9SJohn Edward Broadbent const std::string& driveName, 739e56ed6b9SJohn Edward Broadbent const std::vector<std::string>& resp) 740e56ed6b9SJohn Edward Broadbent { 741e56ed6b9SJohn Edward Broadbent for (const std::string& drivePath : resp) 742e56ed6b9SJohn Edward Broadbent { 743e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path path(drivePath); 744e56ed6b9SJohn Edward Broadbent std::string leaf = path.filename(); 745e56ed6b9SJohn Edward Broadbent if (leaf != driveName) 746e56ed6b9SJohn Edward Broadbent { 747e56ed6b9SJohn Edward Broadbent continue; 748e56ed6b9SJohn Edward Broadbent } 749e56ed6b9SJohn Edward Broadbent // mapper call drive 750e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> driveInterface = { 751e56ed6b9SJohn Edward Broadbent "xyz.openbmc_project.Inventory.Item.Drive"}; 752e99073f5SGeorge Liu dbus::utility::getSubTree( 753e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, driveInterface, 754e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, driveName]( 755e99073f5SGeorge Liu const boost::system::error_code& ec, 756e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) { 757e56ed6b9SJohn Edward Broadbent buildDrive(asyncResp, chassisId, driveName, ec, subtree); 758e99073f5SGeorge Liu }); 759e56ed6b9SJohn Edward Broadbent } 760e56ed6b9SJohn Edward Broadbent } 761e56ed6b9SJohn Edward Broadbent 762b53dcd9dSNan Zhou inline void 763b53dcd9dSNan Zhou handleChassisDriveGet(crow::App& app, const crow::Request& req, 764e56ed6b9SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 765e56ed6b9SJohn Edward Broadbent const std::string& chassisId, 766e56ed6b9SJohn Edward Broadbent const std::string& driveName) 767e56ed6b9SJohn Edward Broadbent { 76803810a11SMichal Orzel if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 769e56ed6b9SJohn Edward Broadbent { 770e56ed6b9SJohn Edward Broadbent return; 771e56ed6b9SJohn Edward Broadbent } 772e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 773e56ed6b9SJohn Edward Broadbent "xyz.openbmc_project.Inventory.Item.Board", 774e56ed6b9SJohn Edward Broadbent "xyz.openbmc_project.Inventory.Item.Chassis"}; 775e56ed6b9SJohn Edward Broadbent 776e56ed6b9SJohn Edward Broadbent // mapper call chassis 777e99073f5SGeorge Liu dbus::utility::getSubTree( 778e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 779e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, 780e99073f5SGeorge Liu driveName](const boost::system::error_code& ec, 781e56ed6b9SJohn Edward Broadbent const dbus::utility::MapperGetSubTreeResponse& subtree) { 782e56ed6b9SJohn Edward Broadbent if (ec) 783e56ed6b9SJohn Edward Broadbent { 784e56ed6b9SJohn Edward Broadbent messages::internalError(asyncResp->res); 785e56ed6b9SJohn Edward Broadbent return; 786e56ed6b9SJohn Edward Broadbent } 787e56ed6b9SJohn Edward Broadbent 788e56ed6b9SJohn Edward Broadbent // Iterate over all retrieved ObjectPaths. 7898cb65f8aSNan Zhou for (const auto& [path, connectionNames] : subtree) 790e56ed6b9SJohn Edward Broadbent { 791e56ed6b9SJohn Edward Broadbent sdbusplus::message::object_path objPath(path); 792e56ed6b9SJohn Edward Broadbent if (objPath.filename() != chassisId) 793e56ed6b9SJohn Edward Broadbent { 794e56ed6b9SJohn Edward Broadbent continue; 795e56ed6b9SJohn Edward Broadbent } 796e56ed6b9SJohn Edward Broadbent 797e56ed6b9SJohn Edward Broadbent if (connectionNames.empty()) 798e56ed6b9SJohn Edward Broadbent { 799e56ed6b9SJohn Edward Broadbent BMCWEB_LOG_ERROR << "Got 0 Connection names"; 800e56ed6b9SJohn Edward Broadbent continue; 801e56ed6b9SJohn Edward Broadbent } 802e56ed6b9SJohn Edward Broadbent 8036c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 8046c3e9451SGeorge Liu path + "/drive", 805e56ed6b9SJohn Edward Broadbent [asyncResp, chassisId, 8065e7e2dc5SEd Tanous driveName](const boost::system::error_code& ec3, 8076c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 808e56ed6b9SJohn Edward Broadbent if (ec3) 809e56ed6b9SJohn Edward Broadbent { 810e56ed6b9SJohn Edward Broadbent return; // no drives = no failures 811e56ed6b9SJohn Edward Broadbent } 812e56ed6b9SJohn Edward Broadbent matchAndFillDrive(asyncResp, chassisId, driveName, resp); 813e56ed6b9SJohn Edward Broadbent }); 814e56ed6b9SJohn Edward Broadbent break; 815e56ed6b9SJohn Edward Broadbent } 816e99073f5SGeorge Liu }); 817e56ed6b9SJohn Edward Broadbent } 818e56ed6b9SJohn Edward Broadbent 819e56ed6b9SJohn Edward Broadbent /** 820e56ed6b9SJohn Edward Broadbent * This URL will show the drive interface for the specific drive in the chassis 821e56ed6b9SJohn Edward Broadbent */ 822e56ed6b9SJohn Edward Broadbent inline void requestRoutesChassisDriveName(App& app) 823e56ed6b9SJohn Edward Broadbent { 824e56ed6b9SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/") 825e56ed6b9SJohn Edward Broadbent .privileges(redfish::privileges::getChassis) 826e56ed6b9SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 827e56ed6b9SJohn Edward Broadbent std::bind_front(handleChassisDriveGet, std::ref(app))); 828e56ed6b9SJohn Edward Broadbent } 829e56ed6b9SJohn Edward Broadbent 830*61b1eb21SWilly Tu inline void getStorageControllerAsset( 831*61b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 832*61b1eb21SWilly Tu const boost::system::error_code& ec, 833*61b1eb21SWilly Tu const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>& 834*61b1eb21SWilly Tu propertiesList) 835*61b1eb21SWilly Tu { 836*61b1eb21SWilly Tu if (ec) 837*61b1eb21SWilly Tu { 838*61b1eb21SWilly Tu // this interface isn't necessary 839*61b1eb21SWilly Tu BMCWEB_LOG_DEBUG << "Failed to get StorageControllerAsset"; 840*61b1eb21SWilly Tu return; 841*61b1eb21SWilly Tu } 842*61b1eb21SWilly Tu 843*61b1eb21SWilly Tu const std::string* partNumber = nullptr; 844*61b1eb21SWilly Tu const std::string* serialNumber = nullptr; 845*61b1eb21SWilly Tu const std::string* manufacturer = nullptr; 846*61b1eb21SWilly Tu const std::string* model = nullptr; 847*61b1eb21SWilly Tu if (!sdbusplus::unpackPropertiesNoThrow( 848*61b1eb21SWilly Tu dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 849*61b1eb21SWilly Tu partNumber, "SerialNumber", serialNumber, "Manufacturer", 850*61b1eb21SWilly Tu manufacturer, "Model", model)) 851*61b1eb21SWilly Tu { 852*61b1eb21SWilly Tu messages::internalError(asyncResp->res); 853*61b1eb21SWilly Tu return; 854*61b1eb21SWilly Tu } 855*61b1eb21SWilly Tu 856*61b1eb21SWilly Tu if (partNumber != nullptr) 857*61b1eb21SWilly Tu { 858*61b1eb21SWilly Tu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 859*61b1eb21SWilly Tu } 860*61b1eb21SWilly Tu 861*61b1eb21SWilly Tu if (serialNumber != nullptr) 862*61b1eb21SWilly Tu { 863*61b1eb21SWilly Tu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 864*61b1eb21SWilly Tu } 865*61b1eb21SWilly Tu 866*61b1eb21SWilly Tu if (manufacturer != nullptr) 867*61b1eb21SWilly Tu { 868*61b1eb21SWilly Tu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 869*61b1eb21SWilly Tu } 870*61b1eb21SWilly Tu 871*61b1eb21SWilly Tu if (model != nullptr) 872*61b1eb21SWilly Tu { 873*61b1eb21SWilly Tu asyncResp->res.jsonValue["Model"] = *model; 874*61b1eb21SWilly Tu } 875*61b1eb21SWilly Tu } 876*61b1eb21SWilly Tu 877*61b1eb21SWilly Tu inline void populateStorageController( 878*61b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 879*61b1eb21SWilly Tu const std::string& controllerId, const std::string& connectionName, 880*61b1eb21SWilly Tu const std::string& path) 881*61b1eb21SWilly Tu { 882*61b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = 883*61b1eb21SWilly Tu "#StorageController.v1_6_0.StorageController"; 884*61b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 885*61b1eb21SWilly Tu "/redfish/v1/Systems/system/Storage/1/Controllers/{}", controllerId); 886*61b1eb21SWilly Tu asyncResp->res.jsonValue["Name"] = controllerId; 887*61b1eb21SWilly Tu asyncResp->res.jsonValue["Id"] = controllerId; 888*61b1eb21SWilly Tu asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 889*61b1eb21SWilly Tu 890*61b1eb21SWilly Tu sdbusplus::asio::getProperty<bool>( 891*61b1eb21SWilly Tu *crow::connections::systemBus, connectionName, path, 892*61b1eb21SWilly Tu "xyz.openbmc_project.Inventory.Item", "Present", 893*61b1eb21SWilly Tu [asyncResp](const boost::system::error_code& ec, bool isPresent) { 894*61b1eb21SWilly Tu // this interface isn't necessary, only check it 895*61b1eb21SWilly Tu // if we get a good return 896*61b1eb21SWilly Tu if (ec) 897*61b1eb21SWilly Tu { 898*61b1eb21SWilly Tu BMCWEB_LOG_DEBUG << "Failed to get Present property"; 899*61b1eb21SWilly Tu return; 900*61b1eb21SWilly Tu } 901*61b1eb21SWilly Tu if (!isPresent) 902*61b1eb21SWilly Tu { 903*61b1eb21SWilly Tu asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 904*61b1eb21SWilly Tu } 905*61b1eb21SWilly Tu }); 906*61b1eb21SWilly Tu 907*61b1eb21SWilly Tu sdbusplus::asio::getAllProperties( 908*61b1eb21SWilly Tu *crow::connections::systemBus, connectionName, path, 909*61b1eb21SWilly Tu "xyz.openbmc_project.Inventory.Decorator.Asset", 910*61b1eb21SWilly Tu [asyncResp](const boost::system::error_code& ec, 911*61b1eb21SWilly Tu const std::vector< 912*61b1eb21SWilly Tu std::pair<std::string, dbus::utility::DbusVariantType>>& 913*61b1eb21SWilly Tu propertiesList) { 914*61b1eb21SWilly Tu getStorageControllerAsset(asyncResp, ec, propertiesList); 915*61b1eb21SWilly Tu }); 916*61b1eb21SWilly Tu } 917*61b1eb21SWilly Tu 918*61b1eb21SWilly Tu inline void getStorageControllerHandler( 919*61b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 920*61b1eb21SWilly Tu const std::string& controllerId, const boost::system::error_code& ec, 921*61b1eb21SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) 922*61b1eb21SWilly Tu { 923*61b1eb21SWilly Tu if (ec || subtree.empty()) 924*61b1eb21SWilly Tu { 925*61b1eb21SWilly Tu // doesn't have to be there 926*61b1eb21SWilly Tu BMCWEB_LOG_DEBUG << "Failed to handle StorageController"; 927*61b1eb21SWilly Tu return; 928*61b1eb21SWilly Tu } 929*61b1eb21SWilly Tu 930*61b1eb21SWilly Tu for (const auto& [path, interfaceDict] : subtree) 931*61b1eb21SWilly Tu { 932*61b1eb21SWilly Tu sdbusplus::message::object_path object(path); 933*61b1eb21SWilly Tu std::string id = object.filename(); 934*61b1eb21SWilly Tu if (id.empty()) 935*61b1eb21SWilly Tu { 936*61b1eb21SWilly Tu BMCWEB_LOG_ERROR << "Failed to find filename in " << path; 937*61b1eb21SWilly Tu return; 938*61b1eb21SWilly Tu } 939*61b1eb21SWilly Tu if (id != controllerId) 940*61b1eb21SWilly Tu { 941*61b1eb21SWilly Tu continue; 942*61b1eb21SWilly Tu } 943*61b1eb21SWilly Tu 944*61b1eb21SWilly Tu if (interfaceDict.size() != 1) 945*61b1eb21SWilly Tu { 946*61b1eb21SWilly Tu BMCWEB_LOG_ERROR << "Connection size " << interfaceDict.size() 947*61b1eb21SWilly Tu << ", greater than 1"; 948*61b1eb21SWilly Tu messages::internalError(asyncResp->res); 949*61b1eb21SWilly Tu return; 950*61b1eb21SWilly Tu } 951*61b1eb21SWilly Tu 952*61b1eb21SWilly Tu const std::string& connectionName = interfaceDict.front().first; 953*61b1eb21SWilly Tu populateStorageController(asyncResp, controllerId, connectionName, 954*61b1eb21SWilly Tu path); 955*61b1eb21SWilly Tu } 956*61b1eb21SWilly Tu } 957*61b1eb21SWilly Tu 958*61b1eb21SWilly Tu inline void populateStorageControllerCollection( 959*61b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 960*61b1eb21SWilly Tu const boost::system::error_code& ec, 961*61b1eb21SWilly Tu const dbus::utility::MapperGetSubTreePathsResponse& controllerList) 962*61b1eb21SWilly Tu { 963*61b1eb21SWilly Tu nlohmann::json::array_t members; 964*61b1eb21SWilly Tu if (ec || controllerList.empty()) 965*61b1eb21SWilly Tu { 966*61b1eb21SWilly Tu asyncResp->res.jsonValue["Members"] = std::move(members); 967*61b1eb21SWilly Tu asyncResp->res.jsonValue["Members@odata.count"] = 0; 968*61b1eb21SWilly Tu BMCWEB_LOG_DEBUG << "Failed to find any StorageController"; 969*61b1eb21SWilly Tu return; 970*61b1eb21SWilly Tu } 971*61b1eb21SWilly Tu 972*61b1eb21SWilly Tu for (const std::string& path : controllerList) 973*61b1eb21SWilly Tu { 974*61b1eb21SWilly Tu std::string id = sdbusplus::message::object_path(path).filename(); 975*61b1eb21SWilly Tu if (id.empty()) 976*61b1eb21SWilly Tu { 977*61b1eb21SWilly Tu BMCWEB_LOG_ERROR << "Failed to find filename in " << path; 978*61b1eb21SWilly Tu return; 979*61b1eb21SWilly Tu } 980*61b1eb21SWilly Tu nlohmann::json::object_t member; 981*61b1eb21SWilly Tu member["@odata.id"] = boost::urls::format( 982*61b1eb21SWilly Tu "/redfish/v1/Systems/system/Storage/1/Controllers/{}", id); 983*61b1eb21SWilly Tu members.emplace_back(member); 984*61b1eb21SWilly Tu } 985*61b1eb21SWilly Tu asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 986*61b1eb21SWilly Tu asyncResp->res.jsonValue["Members"] = std::move(members); 987*61b1eb21SWilly Tu } 988*61b1eb21SWilly Tu 989*61b1eb21SWilly Tu inline void storageControllerCollectionHandler( 990*61b1eb21SWilly Tu App& app, const crow::Request& req, 991*61b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 992*61b1eb21SWilly Tu const std::string& systemName) 993*61b1eb21SWilly Tu { 994*61b1eb21SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 995*61b1eb21SWilly Tu { 996*61b1eb21SWilly Tu BMCWEB_LOG_DEBUG 997*61b1eb21SWilly Tu << "Failed to setup Redfish Route for StorageController Collection"; 998*61b1eb21SWilly Tu return; 999*61b1eb21SWilly Tu } 1000*61b1eb21SWilly Tu if (systemName != "system") 1001*61b1eb21SWilly Tu { 1002*61b1eb21SWilly Tu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1003*61b1eb21SWilly Tu systemName); 1004*61b1eb21SWilly Tu BMCWEB_LOG_DEBUG << "Failed to find ComputerSystem of " << systemName; 1005*61b1eb21SWilly Tu return; 1006*61b1eb21SWilly Tu } 1007*61b1eb21SWilly Tu 1008*61b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.type"] = 1009*61b1eb21SWilly Tu "#StorageControllerCollection.StorageControllerCollection"; 1010*61b1eb21SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 1011*61b1eb21SWilly Tu "/redfish/v1/Systems/system/Storage/1/Controllers"; 1012*61b1eb21SWilly Tu asyncResp->res.jsonValue["Name"] = "Storage Controller Collection"; 1013*61b1eb21SWilly Tu 1014*61b1eb21SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 1015*61b1eb21SWilly Tu "xyz.openbmc_project.Inventory.Item.StorageController"}; 1016*61b1eb21SWilly Tu dbus::utility::getSubTreePaths( 1017*61b1eb21SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 1018*61b1eb21SWilly Tu [asyncResp](const boost::system::error_code& ec, 1019*61b1eb21SWilly Tu const dbus::utility::MapperGetSubTreePathsResponse& 1020*61b1eb21SWilly Tu controllerList) { 1021*61b1eb21SWilly Tu populateStorageControllerCollection(asyncResp, ec, controllerList); 1022*61b1eb21SWilly Tu }); 1023*61b1eb21SWilly Tu } 1024*61b1eb21SWilly Tu 1025*61b1eb21SWilly Tu inline void storageControllerHandler( 1026*61b1eb21SWilly Tu App& app, const crow::Request& req, 1027*61b1eb21SWilly Tu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1028*61b1eb21SWilly Tu const std::string& systemName, const std::string& controllerId) 1029*61b1eb21SWilly Tu { 1030*61b1eb21SWilly Tu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1031*61b1eb21SWilly Tu { 1032*61b1eb21SWilly Tu BMCWEB_LOG_DEBUG 1033*61b1eb21SWilly Tu << "Failed to setup Redfish Route for StorageController"; 1034*61b1eb21SWilly Tu return; 1035*61b1eb21SWilly Tu } 1036*61b1eb21SWilly Tu if (systemName != "system") 1037*61b1eb21SWilly Tu { 1038*61b1eb21SWilly Tu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 1039*61b1eb21SWilly Tu systemName); 1040*61b1eb21SWilly Tu BMCWEB_LOG_DEBUG << "Failed to find ComputerSystem of " << systemName; 1041*61b1eb21SWilly Tu return; 1042*61b1eb21SWilly Tu } 1043*61b1eb21SWilly Tu constexpr std::array<std::string_view, 1> interfaces = { 1044*61b1eb21SWilly Tu "xyz.openbmc_project.Inventory.Item.StorageController"}; 1045*61b1eb21SWilly Tu dbus::utility::getSubTree( 1046*61b1eb21SWilly Tu "/xyz/openbmc_project/inventory", 0, interfaces, 1047*61b1eb21SWilly Tu [asyncResp, 1048*61b1eb21SWilly Tu controllerId](const boost::system::error_code& ec, 1049*61b1eb21SWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) { 1050*61b1eb21SWilly Tu getStorageControllerHandler(asyncResp, controllerId, ec, subtree); 1051*61b1eb21SWilly Tu }); 1052*61b1eb21SWilly Tu } 1053*61b1eb21SWilly Tu 1054*61b1eb21SWilly Tu inline void requestRoutesStorageControllerCollection(App& app) 1055*61b1eb21SWilly Tu { 1056*61b1eb21SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/") 1057*61b1eb21SWilly Tu .privileges(redfish::privileges::getStorageControllerCollection) 1058*61b1eb21SWilly Tu .methods(boost::beast::http::verb::get)( 1059*61b1eb21SWilly Tu std::bind_front(storageControllerCollectionHandler, std::ref(app))); 1060*61b1eb21SWilly Tu } 1061*61b1eb21SWilly Tu 1062*61b1eb21SWilly Tu inline void requestRoutesStorageController(App& app) 1063*61b1eb21SWilly Tu { 1064*61b1eb21SWilly Tu BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>") 1065*61b1eb21SWilly Tu .privileges(redfish::privileges::getStorageController) 1066*61b1eb21SWilly Tu .methods(boost::beast::http::verb::get)( 1067*61b1eb21SWilly Tu std::bind_front(storageControllerHandler, std::ref(app))); 1068*61b1eb21SWilly Tu } 1069*61b1eb21SWilly Tu 1070a25aeccfSNikhil Potade } // namespace redfish 1071