blob: 89ae4b146754f5d6a5d9f26caf1f72d47c5a752f [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3// SPDX-FileCopyrightText: Copyright 2019 Intel Corporation
Nikhil Potadea25aecc2019-08-23 16:35:26 -07004#pragma once
5
Willy Tu13451e32023-05-24 16:08:18 -07006#include "bmcweb_config.h"
7
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08008#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08009#include "async_resp.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080010#include "dbus_utility.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080011#include "error_messages.hpp"
John Edward Broadbente5029d82022-06-08 14:35:21 -070012#include "generated/enums/drive.hpp"
George Liudde9bc12023-02-22 09:35:51 +080013#include "generated/enums/protocol.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070014#include "generated/enums/resource.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080015#include "http_request.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080016#include "human_sort.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080017#include "logging.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "query.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080019#include "redfish_util.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "registries/privilege_registry.hpp"
Myung Bae3f95a272024-03-13 07:32:02 -070021#include "utils/chassis_utils.hpp"
Willy Tu5e577bc2022-07-26 00:41:55 +000022#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080023#include "utils/dbus_utils.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070024
Ed Tanousd7857202025-01-28 15:32:26 -080025#include <boost/beast/http/verb.hpp>
George Liue99073f2022-12-09 11:06:16 +080026#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070027#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080028#include <sdbusplus/message/native_types.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020029#include <sdbusplus/unpack_properties.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070030
Ed Tanousd7857202025-01-28 15:32:26 -080031#include <algorithm>
George Liu7a1dbc42022-12-07 16:03:22 +080032#include <array>
Ed Tanousd7857202025-01-28 15:32:26 -080033#include <cstdint>
34#include <format>
35#include <functional>
36#include <memory>
37#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070038#include <ranges>
Ed Tanousd7857202025-01-28 15:32:26 -080039#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080040#include <string_view>
Ed Tanousd7857202025-01-28 15:32:26 -080041#include <utility>
42#include <variant>
43#include <vector>
George Liu7a1dbc42022-12-07 16:03:22 +080044
Nikhil Potadea25aecc2019-08-23 16:35:26 -070045namespace redfish
46{
Ed Tanous36d52332023-06-09 13:18:40 -070047
48inline void handleSystemsStorageCollectionGet(
49 App& app, const crow::Request& req,
50 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
51 const std::string& systemName)
52{
53 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
54 {
55 return;
56 }
Ed Tanous253f11b2024-05-16 09:38:31 -070057 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous36d52332023-06-09 13:18:40 -070058 {
59 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
60 systemName);
61 return;
62 }
63
64 asyncResp->res.jsonValue["@odata.type"] =
65 "#StorageCollection.StorageCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -070066 asyncResp->res.jsonValue["@odata.id"] = std::format(
67 "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous36d52332023-06-09 13:18:40 -070068 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Willy Tu5e577bc2022-07-26 00:41:55 +000069
Patrick Williams5a39f772023-10-20 11:20:21 -050070 constexpr std::array<std::string_view, 1> interface{
71 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000072 collection_util::getCollectionMembers(
Ed Tanous253f11b2024-05-16 09:38:31 -070073 asyncResp,
74 boost::urls::format("/redfish/v1/Systems/{}/Storage",
75 BMCWEB_REDFISH_SYSTEM_URI_NAME),
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050076 interface, "/xyz/openbmc_project/inventory");
Willy Tu5e577bc2022-07-26 00:41:55 +000077}
78
79inline void handleStorageCollectionGet(
80 App& app, const crow::Request& req,
81 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
82{
83 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
84 {
85 return;
86 }
87 asyncResp->res.jsonValue["@odata.type"] =
88 "#StorageCollection.StorageCollection";
89 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Storage";
90 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Patrick Williams5a39f772023-10-20 11:20:21 -050091 constexpr std::array<std::string_view, 1> interface{
92 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000093 collection_util::getCollectionMembers(
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050094 asyncResp, boost::urls::format("/redfish/v1/Storage"), interface,
95 "/xyz/openbmc_project/inventory");
Ed Tanous36d52332023-06-09 13:18:40 -070096}
97
John Edward Broadbent7e860f12021-04-08 15:57:16 -070098inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070099{
Ed Tanous22d268c2022-05-19 09:39:07 -0700100 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -0700101 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700102 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700103 std::bind_front(handleSystemsStorageCollectionGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000104 BMCWEB_ROUTE(app, "/redfish/v1/Storage/")
105 .privileges(redfish::privileges::getStorageCollection)
106 .methods(boost::beast::http::verb::get)(
107 std::bind_front(handleStorageCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700108}
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700109
Ed Tanous36d52332023-06-09 13:18:40 -0700110inline void afterChassisDriveCollectionSubtree(
111 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous36d52332023-06-09 13:18:40 -0700112 const boost::system::error_code& ec,
113 const dbus::utility::MapperGetSubTreePathsResponse& driveList)
114{
115 if (ec)
116 {
Ed Tanous62598e32023-07-17 17:06:25 -0700117 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700118 messages::internalError(asyncResp->res);
119 return;
120 }
121
122 nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
123 driveArray = nlohmann::json::array();
124 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
125 count = 0;
126
Ed Tanous36d52332023-06-09 13:18:40 -0700127 for (const std::string& drive : driveList)
128 {
129 sdbusplus::message::object_path object(drive);
130 if (object.filename().empty())
131 {
Ed Tanous62598e32023-07-17 17:06:25 -0700132 BMCWEB_LOG_ERROR("Failed to find filename in {}", drive);
Ed Tanous36d52332023-06-09 13:18:40 -0700133 return;
134 }
135
136 nlohmann::json::object_t driveJson;
137 driveJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -0700138 "/redfish/v1/Systems/{}/Storage/1/Drives/{}",
139 BMCWEB_REDFISH_SYSTEM_URI_NAME, object.filename());
Ed Tanous36d52332023-06-09 13:18:40 -0700140 driveArray.emplace_back(std::move(driveJson));
141 }
142
143 count = driveArray.size();
144}
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500145inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Willy Tua85afbe2021-12-28 14:43:47 -0800146{
George Liu7a1dbc42022-12-07 16:03:22 +0800147 const std::array<std::string_view, 1> interfaces = {
148 "xyz.openbmc_project.Inventory.Item.Drive"};
149 dbus::utility::getSubTreePaths(
150 "/xyz/openbmc_project/inventory", 0, interfaces,
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500151 std::bind_front(afterChassisDriveCollectionSubtree, asyncResp));
Ed Tanous36d52332023-06-09 13:18:40 -0700152}
Willy Tua85afbe2021-12-28 14:43:47 -0800153
Willy Tu5e577bc2022-07-26 00:41:55 +0000154inline void afterSystemsStorageGetSubtree(
155 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
156 const std::string& storageId, const boost::system::error_code& ec,
157 const dbus::utility::MapperGetSubTreeResponse& subtree)
Ed Tanous36d52332023-06-09 13:18:40 -0700158{
Willy Tu5e577bc2022-07-26 00:41:55 +0000159 if (ec)
Ed Tanous36d52332023-06-09 13:18:40 -0700160 {
Ed Tanous62598e32023-07-17 17:06:25 -0700161 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000162 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
163 storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700164 return;
165 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700166 auto storage = std::ranges::find_if(
167 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000168 [&storageId](const std::pair<std::string,
169 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400170 return sdbusplus::message::object_path(object.first).filename() ==
171 storageId;
172 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000173 if (storage == subtree.end())
174 {
175 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
176 storageId);
177 return;
178 }
179
Ed Tanous36d52332023-06-09 13:18:40 -0700180 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
181 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -0700182 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
183 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700184 asyncResp->res.jsonValue["Name"] = "Storage";
Willy Tu5e577bc2022-07-26 00:41:55 +0000185 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous539d8c62024-06-19 14:38:27 -0700186 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tua85afbe2021-12-28 14:43:47 -0800187
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500188 getDrives(asyncResp);
Ed Tanous253f11b2024-05-16 09:38:31 -0700189 asyncResp->res.jsonValue["Controllers"]["@odata.id"] =
190 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}/Controllers",
191 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Willy Tu5e577bc2022-07-26 00:41:55 +0000192}
193
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400194inline void handleSystemsStorageGet(
195 App& app, const crow::Request& req,
196 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
197 const std::string& systemName, const std::string& storageId)
Willy Tu5e577bc2022-07-26 00:41:55 +0000198{
199 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
200 {
201 return;
202 }
Ed Tanous25b54db2024-04-17 15:40:31 -0700203 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800204 {
205 // Option currently returns no systems. TBD
206 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
207 systemName);
208 return;
209 }
Willy Tu5e577bc2022-07-26 00:41:55 +0000210
211 constexpr std::array<std::string_view, 1> interfaces = {
212 "xyz.openbmc_project.Inventory.Item.Storage"};
213 dbus::utility::getSubTree(
214 "/xyz/openbmc_project/inventory", 0, interfaces,
215 std::bind_front(afterSystemsStorageGetSubtree, asyncResp, storageId));
216}
217
218inline void afterSubtree(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
219 const std::string& storageId,
220 const boost::system::error_code& ec,
221 const dbus::utility::MapperGetSubTreeResponse& subtree)
222{
223 if (ec)
224 {
Ed Tanous62598e32023-07-17 17:06:25 -0700225 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000226 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
227 storageId);
228 return;
229 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700230 auto storage = std::ranges::find_if(
231 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000232 [&storageId](const std::pair<std::string,
233 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400234 return sdbusplus::message::object_path(object.first).filename() ==
235 storageId;
236 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000237 if (storage == subtree.end())
238 {
239 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
240 storageId);
241 return;
242 }
243
244 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
245 asyncResp->res.jsonValue["@odata.id"] =
246 boost::urls::format("/redfish/v1/Storage/{}", storageId);
247 asyncResp->res.jsonValue["Name"] = "Storage";
248 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous539d8c62024-06-19 14:38:27 -0700249 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tu5e577bc2022-07-26 00:41:55 +0000250
251 // Storage subsystem to Storage link.
252 nlohmann::json::array_t storageServices;
253 nlohmann::json::object_t storageService;
254 storageService["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -0700255 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
256 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Willy Tu5e577bc2022-07-26 00:41:55 +0000257 storageServices.emplace_back(storageService);
258 asyncResp->res.jsonValue["Links"]["StorageServices"] =
259 std::move(storageServices);
260 asyncResp->res.jsonValue["Links"]["StorageServices@odata.count"] = 1;
261}
262
Patrick Williams504af5a2025-02-03 14:29:03 -0500263inline void handleStorageGet(
264 App& app, const crow::Request& req,
265 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
266 const std::string& storageId)
Willy Tu5e577bc2022-07-26 00:41:55 +0000267{
268 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
269 {
Ed Tanous62598e32023-07-17 17:06:25 -0700270 BMCWEB_LOG_DEBUG("requestRoutesStorage setUpRedfishRoute failed");
Willy Tu5e577bc2022-07-26 00:41:55 +0000271 return;
272 }
273
274 constexpr std::array<std::string_view, 1> interfaces = {
275 "xyz.openbmc_project.Inventory.Item.Storage"};
276 dbus::utility::getSubTree(
277 "/xyz/openbmc_project/inventory", 0, interfaces,
278 std::bind_front(afterSubtree, asyncResp, storageId));
Willy Tua85afbe2021-12-28 14:43:47 -0800279}
280
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700281inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700282{
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800283 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700284 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -0700285 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700286 std::bind_front(handleSystemsStorageGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000287
288 BMCWEB_ROUTE(app, "/redfish/v1/Storage/<str>/")
289 .privileges(redfish::privileges::getStorage)
290 .methods(boost::beast::http::verb::get)(
291 std::bind_front(handleStorageGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700292}
293
Willy Tu03913172021-11-08 02:03:19 -0800294inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
295 const std::string& connectionName,
296 const std::string& path)
297{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800298 dbus::utility::getProperty<bool>(
299 connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present",
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400300 [asyncResp,
301 path](const boost::system::error_code& ec, const bool isPresent) {
302 // this interface isn't necessary, only check it if
303 // we get a good return
304 if (ec)
305 {
306 return;
307 }
Willy Tu03913172021-11-08 02:03:19 -0800308
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400309 if (!isPresent)
310 {
311 asyncResp->res.jsonValue["Status"]["State"] =
312 resource::State::Absent;
313 }
314 });
Willy Tu03913172021-11-08 02:03:19 -0800315}
316
317inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
318 const std::string& connectionName,
319 const std::string& path)
320{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800321 dbus::utility::getProperty<bool>(
322 connectionName, path, "xyz.openbmc_project.State.Drive", "Rebuilding",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800323 [asyncResp](const boost::system::error_code& ec, const bool updating) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400324 // this interface isn't necessary, only check it
325 // if we get a good return
326 if (ec)
327 {
328 return;
329 }
Willy Tu03913172021-11-08 02:03:19 -0800330
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400331 // updating and disabled in the backend shouldn't be
332 // able to be set at the same time, so we don't need
333 // to check for the race condition of these two
334 // calls
335 if (updating)
336 {
337 asyncResp->res.jsonValue["Status"]["State"] =
338 resource::State::Updating;
339 }
340 });
Willy Tu03913172021-11-08 02:03:19 -0800341}
342
George Liudde9bc12023-02-22 09:35:51 +0800343inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800344{
345 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
346 {
George Liudde9bc12023-02-22 09:35:51 +0800347 return drive::MediaType::HDD;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800348 }
349 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
350 {
George Liudde9bc12023-02-22 09:35:51 +0800351 return drive::MediaType::SSD;
352 }
353 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
354 {
355 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800356 }
357
George Liudde9bc12023-02-22 09:35:51 +0800358 return drive::MediaType::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800359}
360
Patrick Williams504af5a2025-02-03 14:29:03 -0500361inline std::optional<protocol::Protocol> convertDriveProtocol(
362 std::string_view proto)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800363{
364 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
365 {
George Liudde9bc12023-02-22 09:35:51 +0800366 return protocol::Protocol::SAS;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800367 }
368 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
369 {
George Liudde9bc12023-02-22 09:35:51 +0800370 return protocol::Protocol::SATA;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800371 }
372 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
373 {
George Liudde9bc12023-02-22 09:35:51 +0800374 return protocol::Protocol::NVMe;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800375 }
376 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
377 {
George Liudde9bc12023-02-22 09:35:51 +0800378 return protocol::Protocol::FC;
379 }
380 if (proto ==
381 "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
382 {
383 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800384 }
385
George Liudde9bc12023-02-22 09:35:51 +0800386 return protocol::Protocol::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800387}
388
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400389inline void getDriveItemProperties(
390 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
391 const std::string& connectionName, const std::string& path)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800392{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800393 dbus::utility::getAllProperties(
394 connectionName, path, "xyz.openbmc_project.Inventory.Item.Drive",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800395 [asyncResp](const boost::system::error_code& ec,
Willy Tu19b8e9a2021-11-08 02:55:03 -0800396 const std::vector<
397 std::pair<std::string, dbus::utility::DbusVariantType>>&
398 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400399 if (ec)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800400 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400401 // this interface isn't required
402 return;
403 }
404 const std::string* encryptionStatus = nullptr;
405 const bool* isLocked = nullptr;
406 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
407 property : propertiesList)
408 {
409 const std::string& propertyName = property.first;
410 if (propertyName == "Type")
Ed Tanous002d39b2022-05-31 08:59:27 -0700411 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400412 const std::string* value =
413 std::get_if<std::string>(&property.second);
414 if (value == nullptr)
415 {
416 // illegal property
417 BMCWEB_LOG_ERROR("Illegal property: Type");
418 messages::internalError(asyncResp->res);
419 return;
420 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700421
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400422 std::optional<drive::MediaType> mediaType =
423 convertDriveType(*value);
424 if (!mediaType)
425 {
426 BMCWEB_LOG_WARNING("UnknownDriveType Interface: {}",
427 *value);
428 continue;
429 }
430 if (*mediaType == drive::MediaType::Invalid)
431 {
432 messages::internalError(asyncResp->res);
433 return;
434 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700435
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400436 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800437 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400438 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800439 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400440 const uint64_t* capacity =
441 std::get_if<uint64_t>(&property.second);
442 if (capacity == nullptr)
443 {
444 BMCWEB_LOG_ERROR("Illegal property: Capacity");
445 messages::internalError(asyncResp->res);
446 return;
447 }
448 if (*capacity == 0)
449 {
450 // drive capacity not known
451 continue;
452 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800453
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400454 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Ed Tanous002d39b2022-05-31 08:59:27 -0700455 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400456 else if (propertyName == "Protocol")
457 {
458 const std::string* value =
459 std::get_if<std::string>(&property.second);
460 if (value == nullptr)
461 {
462 BMCWEB_LOG_ERROR("Illegal property: Protocol");
463 messages::internalError(asyncResp->res);
464 return;
465 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700466
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400467 std::optional<protocol::Protocol> proto =
468 convertDriveProtocol(*value);
469 if (!proto)
470 {
471 BMCWEB_LOG_WARNING(
472 "Unknown DrivePrototype Interface: {}", *value);
473 continue;
474 }
475 if (*proto == protocol::Protocol::Invalid)
476 {
477 messages::internalError(asyncResp->res);
478 return;
479 }
480 asyncResp->res.jsonValue["Protocol"] = *proto;
George Liudde9bc12023-02-22 09:35:51 +0800481 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400482 else if (propertyName == "PredictedMediaLifeLeftPercent")
George Liudde9bc12023-02-22 09:35:51 +0800483 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400484 const uint8_t* lifeLeft =
485 std::get_if<uint8_t>(&property.second);
486 if (lifeLeft == nullptr)
487 {
488 BMCWEB_LOG_ERROR(
489 "Illegal property: PredictedMediaLifeLeftPercent");
490 messages::internalError(asyncResp->res);
491 return;
492 }
493 // 255 means reading the value is not supported
494 if (*lifeLeft != 255)
495 {
496 asyncResp->res
497 .jsonValue["PredictedMediaLifeLeftPercent"] =
498 *lifeLeft;
499 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700500 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400501 else if (propertyName == "EncryptionStatus")
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700502 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400503 encryptionStatus =
504 std::get_if<std::string>(&property.second);
505 if (encryptionStatus == nullptr)
506 {
507 BMCWEB_LOG_ERROR("Illegal property: EncryptionStatus");
508 messages::internalError(asyncResp->res);
509 return;
510 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700511 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400512 else if (propertyName == "Locked")
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700513 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400514 isLocked = std::get_if<bool>(&property.second);
515 if (isLocked == nullptr)
516 {
517 BMCWEB_LOG_ERROR("Illegal property: Locked");
518 messages::internalError(asyncResp->res);
519 return;
520 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700521 }
522 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700523
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400524 if (encryptionStatus == nullptr || isLocked == nullptr ||
525 *encryptionStatus ==
526 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Unknown")
527 {
528 return;
529 }
530 if (*encryptionStatus !=
531 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Encrypted")
532 {
533 //"The drive is not currently encrypted."
534 asyncResp->res.jsonValue["EncryptionStatus"] =
535 drive::EncryptionStatus::Unencrypted;
536 return;
537 }
538 if (*isLocked)
539 {
540 //"The drive is currently encrypted and the data is not
541 // accessible to the user."
542 asyncResp->res.jsonValue["EncryptionStatus"] =
543 drive::EncryptionStatus::Locked;
544 return;
545 }
546 // if not locked
547 // "The drive is currently encrypted but the data is accessible
548 // to the user in unencrypted form."
John Edward Broadbente5029d82022-06-08 14:35:21 -0700549 asyncResp->res.jsonValue["EncryptionStatus"] =
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400550 drive::EncryptionStatus::Unlocked;
551 });
Willy Tu19b8e9a2021-11-08 02:55:03 -0800552}
553
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700554inline void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000555 const std::string& connectionName,
556 const std::string& path,
557 const std::vector<std::string>& interfaces)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700558{
559 for (const std::string& interface : interfaces)
560 {
561 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
562 {
Myung Baef7e62c12025-09-07 14:02:08 -0500563 asset_utils::getAssetInfo(asyncResp, connectionName, path,
564 ""_json_pointer, false);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700565 }
566 else if (interface == "xyz.openbmc_project.Inventory.Item")
567 {
568 getDrivePresent(asyncResp, connectionName, path);
569 }
570 else if (interface == "xyz.openbmc_project.State.Drive")
571 {
572 getDriveState(asyncResp, connectionName, path);
573 }
574 else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
575 {
576 getDriveItemProperties(asyncResp, connectionName, path);
577 }
578 }
579}
580
Ed Tanous36d52332023-06-09 13:18:40 -0700581inline void afterGetSubtreeSystemsStorageDrive(
582 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
583 const std::string& driveId, const boost::system::error_code& ec,
584 const dbus::utility::MapperGetSubTreeResponse& subtree)
585{
586 if (ec)
587 {
Ed Tanous62598e32023-07-17 17:06:25 -0700588 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700589 messages::internalError(asyncResp->res);
590 return;
591 }
592
Ed Tanous3544d2a2023-08-06 18:12:20 -0700593 auto drive = std::ranges::find_if(
594 subtree,
Ed Tanous36d52332023-06-09 13:18:40 -0700595 [&driveId](const std::pair<std::string,
596 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400597 return sdbusplus::message::object_path(object.first).filename() ==
598 driveId;
599 });
Ed Tanous36d52332023-06-09 13:18:40 -0700600
601 if (drive == subtree.end())
602 {
603 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
604 return;
605 }
606
607 const std::string& path = drive->first;
608 const dbus::utility::MapperServiceMap& connectionNames = drive->second;
609
610 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
Ed Tanous253f11b2024-05-16 09:38:31 -0700611 asyncResp->res.jsonValue["@odata.id"] =
612 boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Drives/{}",
613 BMCWEB_REDFISH_SYSTEM_URI_NAME, driveId);
Ed Tanous36d52332023-06-09 13:18:40 -0700614 asyncResp->res.jsonValue["Name"] = driveId;
615 asyncResp->res.jsonValue["Id"] = driveId;
616
617 if (connectionNames.size() != 1)
618 {
Ed Tanous62598e32023-07-17 17:06:25 -0700619 BMCWEB_LOG_ERROR("Connection size {}, not equal to 1",
620 connectionNames.size());
Ed Tanous36d52332023-06-09 13:18:40 -0700621 messages::internalError(asyncResp->res);
622 return;
623 }
624
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400625 getMainChassisId(
626 asyncResp, [](const std::string& chassisId,
627 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
628 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
629 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
630 });
Ed Tanous36d52332023-06-09 13:18:40 -0700631
632 // default it to Enabled
Ed Tanous539d8c62024-06-19 14:38:27 -0700633 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Ed Tanous36d52332023-06-09 13:18:40 -0700634
Ed Tanous36d52332023-06-09 13:18:40 -0700635 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
636 connectionNames[0].second);
637}
638
639inline void handleSystemsStorageDriveGet(
640 App& app, const crow::Request& req,
641 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
642 const std::string& systemName, const std::string& driveId)
643{
644 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
645 {
646 return;
647 }
Ed Tanous25b54db2024-04-17 15:40:31 -0700648 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800649 {
650 // Option currently returns no systems. TBD
651 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
652 systemName);
653 return;
654 }
655
Ed Tanous253f11b2024-05-16 09:38:31 -0700656 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous36d52332023-06-09 13:18:40 -0700657 {
658 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
659 systemName);
660 return;
661 }
662
663 constexpr std::array<std::string_view, 1> interfaces = {
664 "xyz.openbmc_project.Inventory.Item.Drive"};
665 dbus::utility::getSubTree(
666 "/xyz/openbmc_project/inventory", 0, interfaces,
667 std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp,
668 driveId));
669}
670
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700671inline void requestRoutesDrive(App& app)
672{
Ed Tanous22d268c2022-05-19 09:39:07 -0700673 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700674 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700675 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700676 std::bind_front(handleSystemsStorageDriveGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700677}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700678
Ed Tanous36d52332023-06-09 13:18:40 -0700679inline void afterChassisDriveCollectionSubtreeGet(
680 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
681 const std::string& chassisId, const boost::system::error_code& ec,
682 const dbus::utility::MapperGetSubTreeResponse& subtree)
683{
684 if (ec)
685 {
686 if (ec == boost::system::errc::host_unreachable)
687 {
688 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
689 return;
690 }
691 messages::internalError(asyncResp->res);
692 return;
693 }
694
695 // Iterate over all retrieved ObjectPaths.
696 for (const auto& [path, connectionNames] : subtree)
697 {
698 sdbusplus::message::object_path objPath(path);
699 if (objPath.filename() != chassisId)
700 {
701 continue;
702 }
703
704 if (connectionNames.empty())
705 {
Ed Tanous62598e32023-07-17 17:06:25 -0700706 BMCWEB_LOG_ERROR("Got 0 Connection names");
Ed Tanous36d52332023-06-09 13:18:40 -0700707 continue;
708 }
709
710 asyncResp->res.jsonValue["@odata.type"] =
711 "#DriveCollection.DriveCollection";
712 asyncResp->res.jsonValue["@odata.id"] =
713 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
714 asyncResp->res.jsonValue["Name"] = "Drive Collection";
715
716 // Association lambda
717 dbus::utility::getAssociationEndPoints(
718 path + "/drive",
719 [asyncResp, chassisId](const boost::system::error_code& ec3,
720 const dbus::utility::MapperEndPoints& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400721 if (ec3)
722 {
723 BMCWEB_LOG_ERROR("Error in chassis Drive association ");
724 }
725 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
726 // important if array is empty
727 members = nlohmann::json::array();
Ed Tanous36d52332023-06-09 13:18:40 -0700728
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400729 std::vector<std::string> leafNames;
730 for (const auto& drive : resp)
731 {
732 sdbusplus::message::object_path drivePath(drive);
733 leafNames.push_back(drivePath.filename());
734 }
Ed Tanous36d52332023-06-09 13:18:40 -0700735
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400736 std::ranges::sort(leafNames, AlphanumLess<std::string>());
Ed Tanous36d52332023-06-09 13:18:40 -0700737
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400738 for (const auto& leafName : leafNames)
739 {
740 nlohmann::json::object_t member;
741 member["@odata.id"] =
742 boost::urls::format("/redfish/v1/Chassis/{}/Drives/{}",
743 chassisId, leafName);
744 members.emplace_back(std::move(member));
745 // navigation links will be registered in next patch set
746 }
747 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
748 }); // end association lambda
Ed Tanous36d52332023-06-09 13:18:40 -0700749
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400750 } // end Iterate over all retrieved ObjectPaths
Ed Tanous36d52332023-06-09 13:18:40 -0700751}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700752/**
753 * Chassis drives, this URL will show all the DriveCollection
754 * information
755 */
Nan Zhoub53dcd92022-06-21 17:47:50 +0000756inline void chassisDriveCollectionGet(
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700757 crow::App& app, const crow::Request& req,
758 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
759 const std::string& chassisId)
760{
Carson Labrado3ba00072022-06-06 19:40:56 +0000761 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700762 {
763 return;
764 }
765
766 // mapper call lambda
George Liue99073f2022-12-09 11:06:16 +0800767 dbus::utility::getSubTree(
Myung Bae3f95a272024-03-13 07:32:02 -0700768 "/xyz/openbmc_project/inventory", 0, chassisInterfaces,
Ed Tanous36d52332023-06-09 13:18:40 -0700769 std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp,
770 chassisId));
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700771}
772
773inline void requestRoutesChassisDrive(App& app)
774{
775 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
776 .privileges(redfish::privileges::getDriveCollection)
777 .methods(boost::beast::http::verb::get)(
778 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
779}
780
Nan Zhoub53dcd92022-06-21 17:47:50 +0000781inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
782 const std::string& chassisId,
783 const std::string& driveName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800784 const boost::system::error_code& ec,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000785 const dbus::utility::MapperGetSubTreeResponse& subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700786{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700787 if (ec)
788 {
Ed Tanous62598e32023-07-17 17:06:25 -0700789 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700790 messages::internalError(asyncResp->res);
791 return;
792 }
793
794 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000795 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700796 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700797 sdbusplus::message::object_path objPath(path);
798 if (objPath.filename() != driveName)
799 {
800 continue;
801 }
802
803 if (connectionNames.empty())
804 {
Ed Tanous62598e32023-07-17 17:06:25 -0700805 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700806 continue;
807 }
808
Ed Tanousef4c65b2023-04-24 15:28:50 -0700809 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
810 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700811
812 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700813 asyncResp->res.jsonValue["Name"] = driveName;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700814 asyncResp->res.jsonValue["Id"] = driveName;
815 // default it to Enabled
Ed Tanous539d8c62024-06-19 14:38:27 -0700816 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700817
818 nlohmann::json::object_t linkChassisNav;
819 linkChassisNav["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700820 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700821 asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
822
823 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
824 connectionNames[0].second);
825 }
826}
827
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400828inline void matchAndFillDrive(
829 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
830 const std::string& chassisId, const std::string& driveName,
831 const std::vector<std::string>& resp)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700832{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700833 for (const std::string& drivePath : resp)
834 {
835 sdbusplus::message::object_path path(drivePath);
836 std::string leaf = path.filename();
837 if (leaf != driveName)
838 {
839 continue;
840 }
841 // mapper call drive
George Liue99073f2022-12-09 11:06:16 +0800842 constexpr std::array<std::string_view, 1> driveInterface = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700843 "xyz.openbmc_project.Inventory.Item.Drive"};
George Liue99073f2022-12-09 11:06:16 +0800844 dbus::utility::getSubTree(
845 "/xyz/openbmc_project/inventory", 0, driveInterface,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700846 [asyncResp, chassisId, driveName](
George Liue99073f2022-12-09 11:06:16 +0800847 const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700848 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400849 buildDrive(asyncResp, chassisId, driveName, ec, subtree);
850 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700851 }
852}
853
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400854inline void handleChassisDriveGet(
855 crow::App& app, const crow::Request& req,
856 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
857 const std::string& chassisId, const std::string& driveName)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700858{
Michal Orzel03810a12022-06-15 14:04:28 +0200859 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700860 {
861 return;
862 }
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700863
864 // mapper call chassis
George Liue99073f2022-12-09 11:06:16 +0800865 dbus::utility::getSubTree(
Myung Bae3f95a272024-03-13 07:32:02 -0700866 "/xyz/openbmc_project/inventory", 0, chassisInterfaces,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700867 [asyncResp, chassisId,
George Liue99073f2022-12-09 11:06:16 +0800868 driveName](const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700869 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400870 if (ec)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700871 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400872 messages::internalError(asyncResp->res);
873 return;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700874 }
875
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400876 // Iterate over all retrieved ObjectPaths.
877 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700878 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400879 sdbusplus::message::object_path objPath(path);
880 if (objPath.filename() != chassisId)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700881 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400882 continue;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700883 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400884
885 if (connectionNames.empty())
886 {
887 BMCWEB_LOG_ERROR("Got 0 Connection names");
888 continue;
889 }
890
891 dbus::utility::getAssociationEndPoints(
892 path + "/drive",
893 [asyncResp, chassisId,
894 driveName](const boost::system::error_code& ec3,
895 const dbus::utility::MapperEndPoints& resp) {
896 if (ec3)
897 {
898 return; // no drives = no failures
899 }
900 matchAndFillDrive(asyncResp, chassisId, driveName,
901 resp);
902 });
Jian Zhangd8f53b82024-02-01 16:10:07 +0800903 return;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400904 }
Jian Zhangd8f53b82024-02-01 16:10:07 +0800905 // Couldn't find an object with that name. return an error
906 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400907 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700908}
909
910/**
911 * This URL will show the drive interface for the specific drive in the chassis
912 */
913inline void requestRoutesChassisDriveName(App& app)
914{
915 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
916 .privileges(redfish::privileges::getChassis)
917 .methods(boost::beast::http::verb::get)(
918 std::bind_front(handleChassisDriveGet, std::ref(app)));
919}
920
Willy Tu61b1eb22023-03-14 11:29:50 -0700921inline void populateStorageController(
922 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
923 const std::string& controllerId, const std::string& connectionName,
924 const std::string& path)
925{
926 asyncResp->res.jsonValue["@odata.type"] =
927 "#StorageController.v1_6_0.StorageController";
Ed Tanous253f11b2024-05-16 09:38:31 -0700928 asyncResp->res.jsonValue["@odata.id"] =
929 boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
930 BMCWEB_REDFISH_SYSTEM_URI_NAME, controllerId);
Willy Tu61b1eb22023-03-14 11:29:50 -0700931 asyncResp->res.jsonValue["Name"] = controllerId;
932 asyncResp->res.jsonValue["Id"] = controllerId;
Ed Tanous539d8c62024-06-19 14:38:27 -0700933 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tu61b1eb22023-03-14 11:29:50 -0700934
Ed Tanousdeae6a72024-11-11 21:58:57 -0800935 dbus::utility::getProperty<bool>(
936 connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present",
Willy Tu61b1eb22023-03-14 11:29:50 -0700937 [asyncResp](const boost::system::error_code& ec, bool isPresent) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400938 // this interface isn't necessary, only check it
939 // if we get a good return
940 if (ec)
941 {
942 BMCWEB_LOG_DEBUG("Failed to get Present property");
943 return;
944 }
945 if (!isPresent)
946 {
947 asyncResp->res.jsonValue["Status"]["State"] =
948 resource::State::Absent;
949 }
950 });
Willy Tu61b1eb22023-03-14 11:29:50 -0700951
Myung Baef7e62c12025-09-07 14:02:08 -0500952 asset_utils::getAssetInfo(asyncResp, connectionName, path, ""_json_pointer,
953 false);
Willy Tu61b1eb22023-03-14 11:29:50 -0700954}
955
956inline void getStorageControllerHandler(
957 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
958 const std::string& controllerId, const boost::system::error_code& ec,
959 const dbus::utility::MapperGetSubTreeResponse& subtree)
960{
961 if (ec || subtree.empty())
962 {
963 // doesn't have to be there
Ed Tanous62598e32023-07-17 17:06:25 -0700964 BMCWEB_LOG_DEBUG("Failed to handle StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -0700965 return;
966 }
967
968 for (const auto& [path, interfaceDict] : subtree)
969 {
970 sdbusplus::message::object_path object(path);
971 std::string id = object.filename();
972 if (id.empty())
973 {
Ed Tanous62598e32023-07-17 17:06:25 -0700974 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -0700975 return;
976 }
977 if (id != controllerId)
978 {
979 continue;
980 }
981
982 if (interfaceDict.size() != 1)
983 {
Ed Tanous62598e32023-07-17 17:06:25 -0700984 BMCWEB_LOG_ERROR("Connection size {}, greater than 1",
985 interfaceDict.size());
Willy Tu61b1eb22023-03-14 11:29:50 -0700986 messages::internalError(asyncResp->res);
987 return;
988 }
989
990 const std::string& connectionName = interfaceDict.front().first;
991 populateStorageController(asyncResp, controllerId, connectionName,
992 path);
993 }
994}
995
996inline void populateStorageControllerCollection(
997 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
998 const boost::system::error_code& ec,
999 const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
1000{
1001 nlohmann::json::array_t members;
1002 if (ec || controllerList.empty())
1003 {
1004 asyncResp->res.jsonValue["Members"] = std::move(members);
1005 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous62598e32023-07-17 17:06:25 -07001006 BMCWEB_LOG_DEBUG("Failed to find any StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001007 return;
1008 }
1009
1010 for (const std::string& path : controllerList)
1011 {
1012 std::string id = sdbusplus::message::object_path(path).filename();
1013 if (id.empty())
1014 {
Ed Tanous62598e32023-07-17 17:06:25 -07001015 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001016 return;
1017 }
1018 nlohmann::json::object_t member;
1019 member["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001020 "/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
1021 BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
Willy Tu61b1eb22023-03-14 11:29:50 -07001022 members.emplace_back(member);
1023 }
1024 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
1025 asyncResp->res.jsonValue["Members"] = std::move(members);
1026}
1027
Ed Tanous36d52332023-06-09 13:18:40 -07001028inline void handleSystemsStorageControllerCollectionGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001029 App& app, const crow::Request& req,
1030 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1031 const std::string& systemName)
1032{
1033 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1034 {
Ed Tanous62598e32023-07-17 17:06:25 -07001035 BMCWEB_LOG_DEBUG(
1036 "Failed to setup Redfish Route for StorageController Collection");
Willy Tu61b1eb22023-03-14 11:29:50 -07001037 return;
1038 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001039 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Willy Tu61b1eb22023-03-14 11:29:50 -07001040 {
1041 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1042 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001043 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001044 return;
1045 }
1046
1047 asyncResp->res.jsonValue["@odata.type"] =
1048 "#StorageControllerCollection.StorageControllerCollection";
1049 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001050 std::format("/redfish/v1/Systems/{}/Storage/1/Controllers",
1051 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Willy Tu61b1eb22023-03-14 11:29:50 -07001052 asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
1053
1054 constexpr std::array<std::string_view, 1> interfaces = {
1055 "xyz.openbmc_project.Inventory.Item.StorageController"};
1056 dbus::utility::getSubTreePaths(
1057 "/xyz/openbmc_project/inventory", 0, interfaces,
1058 [asyncResp](const boost::system::error_code& ec,
1059 const dbus::utility::MapperGetSubTreePathsResponse&
1060 controllerList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001061 populateStorageControllerCollection(asyncResp, ec, controllerList);
1062 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001063}
1064
Ed Tanous36d52332023-06-09 13:18:40 -07001065inline void handleSystemsStorageControllerGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001066 App& app, const crow::Request& req,
1067 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1068 const std::string& systemName, const std::string& controllerId)
1069{
1070 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1071 {
Ed Tanous62598e32023-07-17 17:06:25 -07001072 BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001073 return;
1074 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001075 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Willy Tu61b1eb22023-03-14 11:29:50 -07001076 {
1077 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1078 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001079 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001080 return;
1081 }
1082 constexpr std::array<std::string_view, 1> interfaces = {
1083 "xyz.openbmc_project.Inventory.Item.StorageController"};
1084 dbus::utility::getSubTree(
1085 "/xyz/openbmc_project/inventory", 0, interfaces,
1086 [asyncResp,
1087 controllerId](const boost::system::error_code& ec,
1088 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001089 getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
1090 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001091}
1092
1093inline void requestRoutesStorageControllerCollection(App& app)
1094{
1095 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
1096 .privileges(redfish::privileges::getStorageControllerCollection)
Ed Tanous36d52332023-06-09 13:18:40 -07001097 .methods(boost::beast::http::verb::get)(std::bind_front(
1098 handleSystemsStorageControllerCollectionGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001099}
1100
1101inline void requestRoutesStorageController(App& app)
1102{
1103 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
1104 .privileges(redfish::privileges::getStorageController)
1105 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -07001106 std::bind_front(handleSystemsStorageControllerGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001107}
1108
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001109} // namespace redfish