blob: 6fafccedd98889d3fd96f18b20276c76ef6a158d [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"
Willy Tu5e577bc2022-07-26 00:41:55 +000021#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080022#include "utils/dbus_utils.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070023
Ed Tanousd7857202025-01-28 15:32:26 -080024#include <boost/beast/http/verb.hpp>
George Liue99073f2022-12-09 11:06:16 +080025#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070026#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080027#include <sdbusplus/message/native_types.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020028#include <sdbusplus/unpack_properties.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070029
Ed Tanousd7857202025-01-28 15:32:26 -080030#include <algorithm>
George Liu7a1dbc42022-12-07 16:03:22 +080031#include <array>
Ed Tanousd7857202025-01-28 15:32:26 -080032#include <cstdint>
33#include <format>
34#include <functional>
35#include <memory>
36#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070037#include <ranges>
Ed Tanousd7857202025-01-28 15:32:26 -080038#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080039#include <string_view>
Ed Tanousd7857202025-01-28 15:32:26 -080040#include <utility>
41#include <variant>
42#include <vector>
George Liu7a1dbc42022-12-07 16:03:22 +080043
Nikhil Potadea25aecc2019-08-23 16:35:26 -070044namespace redfish
45{
Ed Tanous36d52332023-06-09 13:18:40 -070046
47inline void handleSystemsStorageCollectionGet(
48 App& app, const crow::Request& req,
49 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
50 const std::string& systemName)
51{
52 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
53 {
54 return;
55 }
Ed Tanous253f11b2024-05-16 09:38:31 -070056 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous36d52332023-06-09 13:18:40 -070057 {
58 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
59 systemName);
60 return;
61 }
62
63 asyncResp->res.jsonValue["@odata.type"] =
64 "#StorageCollection.StorageCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -070065 asyncResp->res.jsonValue["@odata.id"] = std::format(
66 "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous36d52332023-06-09 13:18:40 -070067 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Willy Tu5e577bc2022-07-26 00:41:55 +000068
Patrick Williams5a39f772023-10-20 11:20:21 -050069 constexpr std::array<std::string_view, 1> interface{
70 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000071 collection_util::getCollectionMembers(
Ed Tanous253f11b2024-05-16 09:38:31 -070072 asyncResp,
73 boost::urls::format("/redfish/v1/Systems/{}/Storage",
74 BMCWEB_REDFISH_SYSTEM_URI_NAME),
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050075 interface, "/xyz/openbmc_project/inventory");
Willy Tu5e577bc2022-07-26 00:41:55 +000076}
77
78inline void handleStorageCollectionGet(
79 App& app, const crow::Request& req,
80 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
81{
82 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
83 {
84 return;
85 }
86 asyncResp->res.jsonValue["@odata.type"] =
87 "#StorageCollection.StorageCollection";
88 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Storage";
89 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Patrick Williams5a39f772023-10-20 11:20:21 -050090 constexpr std::array<std::string_view, 1> interface{
91 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000092 collection_util::getCollectionMembers(
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050093 asyncResp, boost::urls::format("/redfish/v1/Storage"), interface,
94 "/xyz/openbmc_project/inventory");
Ed Tanous36d52332023-06-09 13:18:40 -070095}
96
John Edward Broadbent7e860f12021-04-08 15:57:16 -070097inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070098{
Ed Tanous22d268c2022-05-19 09:39:07 -070099 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -0700100 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700101 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700102 std::bind_front(handleSystemsStorageCollectionGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000103 BMCWEB_ROUTE(app, "/redfish/v1/Storage/")
104 .privileges(redfish::privileges::getStorageCollection)
105 .methods(boost::beast::http::verb::get)(
106 std::bind_front(handleStorageCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700107}
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700108
Ed Tanous36d52332023-06-09 13:18:40 -0700109inline void afterChassisDriveCollectionSubtree(
110 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous36d52332023-06-09 13:18:40 -0700111 const boost::system::error_code& ec,
112 const dbus::utility::MapperGetSubTreePathsResponse& driveList)
113{
114 if (ec)
115 {
Ed Tanous62598e32023-07-17 17:06:25 -0700116 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700117 messages::internalError(asyncResp->res);
118 return;
119 }
120
121 nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
122 driveArray = nlohmann::json::array();
123 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
124 count = 0;
125
Ed Tanous36d52332023-06-09 13:18:40 -0700126 for (const std::string& drive : driveList)
127 {
128 sdbusplus::message::object_path object(drive);
129 if (object.filename().empty())
130 {
Ed Tanous62598e32023-07-17 17:06:25 -0700131 BMCWEB_LOG_ERROR("Failed to find filename in {}", drive);
Ed Tanous36d52332023-06-09 13:18:40 -0700132 return;
133 }
134
135 nlohmann::json::object_t driveJson;
136 driveJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -0700137 "/redfish/v1/Systems/{}/Storage/1/Drives/{}",
138 BMCWEB_REDFISH_SYSTEM_URI_NAME, object.filename());
Ed Tanous36d52332023-06-09 13:18:40 -0700139 driveArray.emplace_back(std::move(driveJson));
140 }
141
142 count = driveArray.size();
143}
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500144inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Willy Tua85afbe2021-12-28 14:43:47 -0800145{
George Liu7a1dbc42022-12-07 16:03:22 +0800146 const std::array<std::string_view, 1> interfaces = {
147 "xyz.openbmc_project.Inventory.Item.Drive"};
148 dbus::utility::getSubTreePaths(
149 "/xyz/openbmc_project/inventory", 0, interfaces,
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500150 std::bind_front(afterChassisDriveCollectionSubtree, asyncResp));
Ed Tanous36d52332023-06-09 13:18:40 -0700151}
Willy Tua85afbe2021-12-28 14:43:47 -0800152
Willy Tu5e577bc2022-07-26 00:41:55 +0000153inline void afterSystemsStorageGetSubtree(
154 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
155 const std::string& storageId, const boost::system::error_code& ec,
156 const dbus::utility::MapperGetSubTreeResponse& subtree)
Ed Tanous36d52332023-06-09 13:18:40 -0700157{
Willy Tu5e577bc2022-07-26 00:41:55 +0000158 if (ec)
Ed Tanous36d52332023-06-09 13:18:40 -0700159 {
Ed Tanous62598e32023-07-17 17:06:25 -0700160 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000161 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
162 storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700163 return;
164 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700165 auto storage = std::ranges::find_if(
166 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000167 [&storageId](const std::pair<std::string,
168 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400169 return sdbusplus::message::object_path(object.first).filename() ==
170 storageId;
171 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000172 if (storage == subtree.end())
173 {
174 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
175 storageId);
176 return;
177 }
178
Ed Tanous36d52332023-06-09 13:18:40 -0700179 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
180 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -0700181 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
182 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700183 asyncResp->res.jsonValue["Name"] = "Storage";
Willy Tu5e577bc2022-07-26 00:41:55 +0000184 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous539d8c62024-06-19 14:38:27 -0700185 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tua85afbe2021-12-28 14:43:47 -0800186
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500187 getDrives(asyncResp);
Ed Tanous253f11b2024-05-16 09:38:31 -0700188 asyncResp->res.jsonValue["Controllers"]["@odata.id"] =
189 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}/Controllers",
190 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Willy Tu5e577bc2022-07-26 00:41:55 +0000191}
192
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400193inline void handleSystemsStorageGet(
194 App& app, const crow::Request& req,
195 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
196 const std::string& systemName, const std::string& storageId)
Willy Tu5e577bc2022-07-26 00:41:55 +0000197{
198 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
199 {
200 return;
201 }
Ed Tanous25b54db2024-04-17 15:40:31 -0700202 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800203 {
204 // Option currently returns no systems. TBD
205 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
206 systemName);
207 return;
208 }
Willy Tu5e577bc2022-07-26 00:41:55 +0000209
210 constexpr std::array<std::string_view, 1> interfaces = {
211 "xyz.openbmc_project.Inventory.Item.Storage"};
212 dbus::utility::getSubTree(
213 "/xyz/openbmc_project/inventory", 0, interfaces,
214 std::bind_front(afterSystemsStorageGetSubtree, asyncResp, storageId));
215}
216
217inline void afterSubtree(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
218 const std::string& storageId,
219 const boost::system::error_code& ec,
220 const dbus::utility::MapperGetSubTreeResponse& subtree)
221{
222 if (ec)
223 {
Ed Tanous62598e32023-07-17 17:06:25 -0700224 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000225 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
226 storageId);
227 return;
228 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700229 auto storage = std::ranges::find_if(
230 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000231 [&storageId](const std::pair<std::string,
232 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400233 return sdbusplus::message::object_path(object.first).filename() ==
234 storageId;
235 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000236 if (storage == subtree.end())
237 {
238 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
239 storageId);
240 return;
241 }
242
243 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
244 asyncResp->res.jsonValue["@odata.id"] =
245 boost::urls::format("/redfish/v1/Storage/{}", storageId);
246 asyncResp->res.jsonValue["Name"] = "Storage";
247 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous539d8c62024-06-19 14:38:27 -0700248 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tu5e577bc2022-07-26 00:41:55 +0000249
250 // Storage subsystem to Storage link.
251 nlohmann::json::array_t storageServices;
252 nlohmann::json::object_t storageService;
253 storageService["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -0700254 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
255 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Willy Tu5e577bc2022-07-26 00:41:55 +0000256 storageServices.emplace_back(storageService);
257 asyncResp->res.jsonValue["Links"]["StorageServices"] =
258 std::move(storageServices);
259 asyncResp->res.jsonValue["Links"]["StorageServices@odata.count"] = 1;
260}
261
Patrick Williams504af5a2025-02-03 14:29:03 -0500262inline void handleStorageGet(
263 App& app, const crow::Request& req,
264 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
265 const std::string& storageId)
Willy Tu5e577bc2022-07-26 00:41:55 +0000266{
267 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
268 {
Ed Tanous62598e32023-07-17 17:06:25 -0700269 BMCWEB_LOG_DEBUG("requestRoutesStorage setUpRedfishRoute failed");
Willy Tu5e577bc2022-07-26 00:41:55 +0000270 return;
271 }
272
273 constexpr std::array<std::string_view, 1> interfaces = {
274 "xyz.openbmc_project.Inventory.Item.Storage"};
275 dbus::utility::getSubTree(
276 "/xyz/openbmc_project/inventory", 0, interfaces,
277 std::bind_front(afterSubtree, asyncResp, storageId));
Willy Tua85afbe2021-12-28 14:43:47 -0800278}
279
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700280inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700281{
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800282 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700283 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -0700284 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700285 std::bind_front(handleSystemsStorageGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000286
287 BMCWEB_ROUTE(app, "/redfish/v1/Storage/<str>/")
288 .privileges(redfish::privileges::getStorage)
289 .methods(boost::beast::http::verb::get)(
290 std::bind_front(handleStorageGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700291}
292
Willy Tu03913172021-11-08 02:03:19 -0800293inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
294 const std::string& connectionName,
295 const std::string& path)
296{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800297 dbus::utility::getAllProperties(
298 connectionName, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800299 [asyncResp](const boost::system::error_code& ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800300 const std::vector<
301 std::pair<std::string, dbus::utility::DbusVariantType>>&
302 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400303 if (ec)
304 {
305 // this interface isn't necessary
306 return;
307 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200308
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400309 const std::string* partNumber = nullptr;
310 const std::string* serialNumber = nullptr;
311 const std::string* manufacturer = nullptr;
312 const std::string* model = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200313
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400314 const bool success = sdbusplus::unpackPropertiesNoThrow(
315 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
316 partNumber, "SerialNumber", serialNumber, "Manufacturer",
317 manufacturer, "Model", model);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200318
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400319 if (!success)
320 {
321 messages::internalError(asyncResp->res);
322 return;
323 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200324
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400325 if (partNumber != nullptr)
326 {
327 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
328 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200329
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400330 if (serialNumber != nullptr)
331 {
332 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
333 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200334
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400335 if (manufacturer != nullptr)
336 {
337 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
338 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200339
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400340 if (model != nullptr)
341 {
342 asyncResp->res.jsonValue["Model"] = *model;
343 }
344 });
Willy Tu03913172021-11-08 02:03:19 -0800345}
346
347inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
348 const std::string& connectionName,
349 const std::string& path)
350{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800351 dbus::utility::getProperty<bool>(
352 connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present",
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400353 [asyncResp,
354 path](const boost::system::error_code& ec, const bool isPresent) {
355 // this interface isn't necessary, only check it if
356 // we get a good return
357 if (ec)
358 {
359 return;
360 }
Willy Tu03913172021-11-08 02:03:19 -0800361
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400362 if (!isPresent)
363 {
364 asyncResp->res.jsonValue["Status"]["State"] =
365 resource::State::Absent;
366 }
367 });
Willy Tu03913172021-11-08 02:03:19 -0800368}
369
370inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
371 const std::string& connectionName,
372 const std::string& path)
373{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800374 dbus::utility::getProperty<bool>(
375 connectionName, path, "xyz.openbmc_project.State.Drive", "Rebuilding",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800376 [asyncResp](const boost::system::error_code& ec, const bool updating) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400377 // this interface isn't necessary, only check it
378 // if we get a good return
379 if (ec)
380 {
381 return;
382 }
Willy Tu03913172021-11-08 02:03:19 -0800383
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400384 // updating and disabled in the backend shouldn't be
385 // able to be set at the same time, so we don't need
386 // to check for the race condition of these two
387 // calls
388 if (updating)
389 {
390 asyncResp->res.jsonValue["Status"]["State"] =
391 resource::State::Updating;
392 }
393 });
Willy Tu03913172021-11-08 02:03:19 -0800394}
395
George Liudde9bc12023-02-22 09:35:51 +0800396inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800397{
398 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
399 {
George Liudde9bc12023-02-22 09:35:51 +0800400 return drive::MediaType::HDD;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800401 }
402 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
403 {
George Liudde9bc12023-02-22 09:35:51 +0800404 return drive::MediaType::SSD;
405 }
406 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
407 {
408 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800409 }
410
George Liudde9bc12023-02-22 09:35:51 +0800411 return drive::MediaType::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800412}
413
Patrick Williams504af5a2025-02-03 14:29:03 -0500414inline std::optional<protocol::Protocol> convertDriveProtocol(
415 std::string_view proto)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800416{
417 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
418 {
George Liudde9bc12023-02-22 09:35:51 +0800419 return protocol::Protocol::SAS;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800420 }
421 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
422 {
George Liudde9bc12023-02-22 09:35:51 +0800423 return protocol::Protocol::SATA;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800424 }
425 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
426 {
George Liudde9bc12023-02-22 09:35:51 +0800427 return protocol::Protocol::NVMe;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800428 }
429 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
430 {
George Liudde9bc12023-02-22 09:35:51 +0800431 return protocol::Protocol::FC;
432 }
433 if (proto ==
434 "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
435 {
436 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800437 }
438
George Liudde9bc12023-02-22 09:35:51 +0800439 return protocol::Protocol::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800440}
441
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400442inline void getDriveItemProperties(
443 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
444 const std::string& connectionName, const std::string& path)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800445{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800446 dbus::utility::getAllProperties(
447 connectionName, path, "xyz.openbmc_project.Inventory.Item.Drive",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800448 [asyncResp](const boost::system::error_code& ec,
Willy Tu19b8e9a2021-11-08 02:55:03 -0800449 const std::vector<
450 std::pair<std::string, dbus::utility::DbusVariantType>>&
451 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400452 if (ec)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800453 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400454 // this interface isn't required
455 return;
456 }
457 const std::string* encryptionStatus = nullptr;
458 const bool* isLocked = nullptr;
459 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
460 property : propertiesList)
461 {
462 const std::string& propertyName = property.first;
463 if (propertyName == "Type")
Ed Tanous002d39b2022-05-31 08:59:27 -0700464 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400465 const std::string* value =
466 std::get_if<std::string>(&property.second);
467 if (value == nullptr)
468 {
469 // illegal property
470 BMCWEB_LOG_ERROR("Illegal property: Type");
471 messages::internalError(asyncResp->res);
472 return;
473 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700474
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400475 std::optional<drive::MediaType> mediaType =
476 convertDriveType(*value);
477 if (!mediaType)
478 {
479 BMCWEB_LOG_WARNING("UnknownDriveType Interface: {}",
480 *value);
481 continue;
482 }
483 if (*mediaType == drive::MediaType::Invalid)
484 {
485 messages::internalError(asyncResp->res);
486 return;
487 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700488
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400489 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800490 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400491 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800492 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400493 const uint64_t* capacity =
494 std::get_if<uint64_t>(&property.second);
495 if (capacity == nullptr)
496 {
497 BMCWEB_LOG_ERROR("Illegal property: Capacity");
498 messages::internalError(asyncResp->res);
499 return;
500 }
501 if (*capacity == 0)
502 {
503 // drive capacity not known
504 continue;
505 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800506
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400507 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Ed Tanous002d39b2022-05-31 08:59:27 -0700508 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400509 else if (propertyName == "Protocol")
510 {
511 const std::string* value =
512 std::get_if<std::string>(&property.second);
513 if (value == nullptr)
514 {
515 BMCWEB_LOG_ERROR("Illegal property: Protocol");
516 messages::internalError(asyncResp->res);
517 return;
518 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700519
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400520 std::optional<protocol::Protocol> proto =
521 convertDriveProtocol(*value);
522 if (!proto)
523 {
524 BMCWEB_LOG_WARNING(
525 "Unknown DrivePrototype Interface: {}", *value);
526 continue;
527 }
528 if (*proto == protocol::Protocol::Invalid)
529 {
530 messages::internalError(asyncResp->res);
531 return;
532 }
533 asyncResp->res.jsonValue["Protocol"] = *proto;
George Liudde9bc12023-02-22 09:35:51 +0800534 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400535 else if (propertyName == "PredictedMediaLifeLeftPercent")
George Liudde9bc12023-02-22 09:35:51 +0800536 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400537 const uint8_t* lifeLeft =
538 std::get_if<uint8_t>(&property.second);
539 if (lifeLeft == nullptr)
540 {
541 BMCWEB_LOG_ERROR(
542 "Illegal property: PredictedMediaLifeLeftPercent");
543 messages::internalError(asyncResp->res);
544 return;
545 }
546 // 255 means reading the value is not supported
547 if (*lifeLeft != 255)
548 {
549 asyncResp->res
550 .jsonValue["PredictedMediaLifeLeftPercent"] =
551 *lifeLeft;
552 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700553 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400554 else if (propertyName == "EncryptionStatus")
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700555 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400556 encryptionStatus =
557 std::get_if<std::string>(&property.second);
558 if (encryptionStatus == nullptr)
559 {
560 BMCWEB_LOG_ERROR("Illegal property: EncryptionStatus");
561 messages::internalError(asyncResp->res);
562 return;
563 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700564 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400565 else if (propertyName == "Locked")
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700566 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400567 isLocked = std::get_if<bool>(&property.second);
568 if (isLocked == nullptr)
569 {
570 BMCWEB_LOG_ERROR("Illegal property: Locked");
571 messages::internalError(asyncResp->res);
572 return;
573 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700574 }
575 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700576
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400577 if (encryptionStatus == nullptr || isLocked == nullptr ||
578 *encryptionStatus ==
579 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Unknown")
580 {
581 return;
582 }
583 if (*encryptionStatus !=
584 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Encrypted")
585 {
586 //"The drive is not currently encrypted."
587 asyncResp->res.jsonValue["EncryptionStatus"] =
588 drive::EncryptionStatus::Unencrypted;
589 return;
590 }
591 if (*isLocked)
592 {
593 //"The drive is currently encrypted and the data is not
594 // accessible to the user."
595 asyncResp->res.jsonValue["EncryptionStatus"] =
596 drive::EncryptionStatus::Locked;
597 return;
598 }
599 // if not locked
600 // "The drive is currently encrypted but the data is accessible
601 // to the user in unencrypted form."
John Edward Broadbente5029d82022-06-08 14:35:21 -0700602 asyncResp->res.jsonValue["EncryptionStatus"] =
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400603 drive::EncryptionStatus::Unlocked;
604 });
Willy Tu19b8e9a2021-11-08 02:55:03 -0800605}
606
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700607inline void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000608 const std::string& connectionName,
609 const std::string& path,
610 const std::vector<std::string>& interfaces)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700611{
612 for (const std::string& interface : interfaces)
613 {
614 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
615 {
616 getDriveAsset(asyncResp, connectionName, path);
617 }
618 else if (interface == "xyz.openbmc_project.Inventory.Item")
619 {
620 getDrivePresent(asyncResp, connectionName, path);
621 }
622 else if (interface == "xyz.openbmc_project.State.Drive")
623 {
624 getDriveState(asyncResp, connectionName, path);
625 }
626 else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
627 {
628 getDriveItemProperties(asyncResp, connectionName, path);
629 }
630 }
631}
632
Ed Tanous36d52332023-06-09 13:18:40 -0700633inline void afterGetSubtreeSystemsStorageDrive(
634 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
635 const std::string& driveId, const boost::system::error_code& ec,
636 const dbus::utility::MapperGetSubTreeResponse& subtree)
637{
638 if (ec)
639 {
Ed Tanous62598e32023-07-17 17:06:25 -0700640 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700641 messages::internalError(asyncResp->res);
642 return;
643 }
644
Ed Tanous3544d2a2023-08-06 18:12:20 -0700645 auto drive = std::ranges::find_if(
646 subtree,
Ed Tanous36d52332023-06-09 13:18:40 -0700647 [&driveId](const std::pair<std::string,
648 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400649 return sdbusplus::message::object_path(object.first).filename() ==
650 driveId;
651 });
Ed Tanous36d52332023-06-09 13:18:40 -0700652
653 if (drive == subtree.end())
654 {
655 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
656 return;
657 }
658
659 const std::string& path = drive->first;
660 const dbus::utility::MapperServiceMap& connectionNames = drive->second;
661
662 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
Ed Tanous253f11b2024-05-16 09:38:31 -0700663 asyncResp->res.jsonValue["@odata.id"] =
664 boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Drives/{}",
665 BMCWEB_REDFISH_SYSTEM_URI_NAME, driveId);
Ed Tanous36d52332023-06-09 13:18:40 -0700666 asyncResp->res.jsonValue["Name"] = driveId;
667 asyncResp->res.jsonValue["Id"] = driveId;
668
669 if (connectionNames.size() != 1)
670 {
Ed Tanous62598e32023-07-17 17:06:25 -0700671 BMCWEB_LOG_ERROR("Connection size {}, not equal to 1",
672 connectionNames.size());
Ed Tanous36d52332023-06-09 13:18:40 -0700673 messages::internalError(asyncResp->res);
674 return;
675 }
676
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400677 getMainChassisId(
678 asyncResp, [](const std::string& chassisId,
679 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
680 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
681 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
682 });
Ed Tanous36d52332023-06-09 13:18:40 -0700683
684 // default it to Enabled
Ed Tanous539d8c62024-06-19 14:38:27 -0700685 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Ed Tanous36d52332023-06-09 13:18:40 -0700686
Ed Tanous36d52332023-06-09 13:18:40 -0700687 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
688 connectionNames[0].second);
689}
690
691inline void handleSystemsStorageDriveGet(
692 App& app, const crow::Request& req,
693 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
694 const std::string& systemName, const std::string& driveId)
695{
696 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
697 {
698 return;
699 }
Ed Tanous25b54db2024-04-17 15:40:31 -0700700 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800701 {
702 // Option currently returns no systems. TBD
703 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
704 systemName);
705 return;
706 }
707
Ed Tanous253f11b2024-05-16 09:38:31 -0700708 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous36d52332023-06-09 13:18:40 -0700709 {
710 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
711 systemName);
712 return;
713 }
714
715 constexpr std::array<std::string_view, 1> interfaces = {
716 "xyz.openbmc_project.Inventory.Item.Drive"};
717 dbus::utility::getSubTree(
718 "/xyz/openbmc_project/inventory", 0, interfaces,
719 std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp,
720 driveId));
721}
722
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700723inline void requestRoutesDrive(App& app)
724{
Ed Tanous22d268c2022-05-19 09:39:07 -0700725 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700726 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700727 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700728 std::bind_front(handleSystemsStorageDriveGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700729}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700730
Ed Tanous36d52332023-06-09 13:18:40 -0700731inline void afterChassisDriveCollectionSubtreeGet(
732 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
733 const std::string& chassisId, const boost::system::error_code& ec,
734 const dbus::utility::MapperGetSubTreeResponse& subtree)
735{
736 if (ec)
737 {
738 if (ec == boost::system::errc::host_unreachable)
739 {
740 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
741 return;
742 }
743 messages::internalError(asyncResp->res);
744 return;
745 }
746
747 // Iterate over all retrieved ObjectPaths.
748 for (const auto& [path, connectionNames] : subtree)
749 {
750 sdbusplus::message::object_path objPath(path);
751 if (objPath.filename() != chassisId)
752 {
753 continue;
754 }
755
756 if (connectionNames.empty())
757 {
Ed Tanous62598e32023-07-17 17:06:25 -0700758 BMCWEB_LOG_ERROR("Got 0 Connection names");
Ed Tanous36d52332023-06-09 13:18:40 -0700759 continue;
760 }
761
762 asyncResp->res.jsonValue["@odata.type"] =
763 "#DriveCollection.DriveCollection";
764 asyncResp->res.jsonValue["@odata.id"] =
765 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
766 asyncResp->res.jsonValue["Name"] = "Drive Collection";
767
768 // Association lambda
769 dbus::utility::getAssociationEndPoints(
770 path + "/drive",
771 [asyncResp, chassisId](const boost::system::error_code& ec3,
772 const dbus::utility::MapperEndPoints& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400773 if (ec3)
774 {
775 BMCWEB_LOG_ERROR("Error in chassis Drive association ");
776 }
777 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
778 // important if array is empty
779 members = nlohmann::json::array();
Ed Tanous36d52332023-06-09 13:18:40 -0700780
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400781 std::vector<std::string> leafNames;
782 for (const auto& drive : resp)
783 {
784 sdbusplus::message::object_path drivePath(drive);
785 leafNames.push_back(drivePath.filename());
786 }
Ed Tanous36d52332023-06-09 13:18:40 -0700787
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400788 std::ranges::sort(leafNames, AlphanumLess<std::string>());
Ed Tanous36d52332023-06-09 13:18:40 -0700789
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400790 for (const auto& leafName : leafNames)
791 {
792 nlohmann::json::object_t member;
793 member["@odata.id"] =
794 boost::urls::format("/redfish/v1/Chassis/{}/Drives/{}",
795 chassisId, leafName);
796 members.emplace_back(std::move(member));
797 // navigation links will be registered in next patch set
798 }
799 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
800 }); // end association lambda
Ed Tanous36d52332023-06-09 13:18:40 -0700801
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400802 } // end Iterate over all retrieved ObjectPaths
Ed Tanous36d52332023-06-09 13:18:40 -0700803}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700804/**
805 * Chassis drives, this URL will show all the DriveCollection
806 * information
807 */
Nan Zhoub53dcd92022-06-21 17:47:50 +0000808inline void chassisDriveCollectionGet(
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700809 crow::App& app, const crow::Request& req,
810 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
811 const std::string& chassisId)
812{
Carson Labrado3ba00072022-06-06 19:40:56 +0000813 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700814 {
815 return;
816 }
817
818 // mapper call lambda
George Liue99073f2022-12-09 11:06:16 +0800819 constexpr std::array<std::string_view, 2> interfaces = {
820 "xyz.openbmc_project.Inventory.Item.Board",
821 "xyz.openbmc_project.Inventory.Item.Chassis"};
822 dbus::utility::getSubTree(
823 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous36d52332023-06-09 13:18:40 -0700824 std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp,
825 chassisId));
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700826}
827
828inline void requestRoutesChassisDrive(App& app)
829{
830 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
831 .privileges(redfish::privileges::getDriveCollection)
832 .methods(boost::beast::http::verb::get)(
833 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
834}
835
Nan Zhoub53dcd92022-06-21 17:47:50 +0000836inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
837 const std::string& chassisId,
838 const std::string& driveName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800839 const boost::system::error_code& ec,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000840 const dbus::utility::MapperGetSubTreeResponse& subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700841{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700842 if (ec)
843 {
Ed Tanous62598e32023-07-17 17:06:25 -0700844 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700845 messages::internalError(asyncResp->res);
846 return;
847 }
848
849 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000850 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700851 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700852 sdbusplus::message::object_path objPath(path);
853 if (objPath.filename() != driveName)
854 {
855 continue;
856 }
857
858 if (connectionNames.empty())
859 {
Ed Tanous62598e32023-07-17 17:06:25 -0700860 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700861 continue;
862 }
863
Ed Tanousef4c65b2023-04-24 15:28:50 -0700864 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
865 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700866
867 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700868 asyncResp->res.jsonValue["Name"] = driveName;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700869 asyncResp->res.jsonValue["Id"] = driveName;
870 // default it to Enabled
Ed Tanous539d8c62024-06-19 14:38:27 -0700871 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700872
873 nlohmann::json::object_t linkChassisNav;
874 linkChassisNav["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700875 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700876 asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
877
878 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
879 connectionNames[0].second);
880 }
881}
882
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400883inline void matchAndFillDrive(
884 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
885 const std::string& chassisId, const std::string& driveName,
886 const std::vector<std::string>& resp)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700887{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700888 for (const std::string& drivePath : resp)
889 {
890 sdbusplus::message::object_path path(drivePath);
891 std::string leaf = path.filename();
892 if (leaf != driveName)
893 {
894 continue;
895 }
896 // mapper call drive
George Liue99073f2022-12-09 11:06:16 +0800897 constexpr std::array<std::string_view, 1> driveInterface = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700898 "xyz.openbmc_project.Inventory.Item.Drive"};
George Liue99073f2022-12-09 11:06:16 +0800899 dbus::utility::getSubTree(
900 "/xyz/openbmc_project/inventory", 0, driveInterface,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700901 [asyncResp, chassisId, driveName](
George Liue99073f2022-12-09 11:06:16 +0800902 const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700903 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400904 buildDrive(asyncResp, chassisId, driveName, ec, subtree);
905 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700906 }
907}
908
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400909inline void handleChassisDriveGet(
910 crow::App& app, const crow::Request& req,
911 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
912 const std::string& chassisId, const std::string& driveName)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700913{
Michal Orzel03810a12022-06-15 14:04:28 +0200914 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700915 {
916 return;
917 }
George Liue99073f2022-12-09 11:06:16 +0800918 constexpr std::array<std::string_view, 2> interfaces = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700919 "xyz.openbmc_project.Inventory.Item.Board",
920 "xyz.openbmc_project.Inventory.Item.Chassis"};
921
922 // mapper call chassis
George Liue99073f2022-12-09 11:06:16 +0800923 dbus::utility::getSubTree(
924 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700925 [asyncResp, chassisId,
George Liue99073f2022-12-09 11:06:16 +0800926 driveName](const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700927 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400928 if (ec)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700929 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400930 messages::internalError(asyncResp->res);
931 return;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700932 }
933
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400934 // Iterate over all retrieved ObjectPaths.
935 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700936 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400937 sdbusplus::message::object_path objPath(path);
938 if (objPath.filename() != chassisId)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700939 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400940 continue;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700941 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400942
943 if (connectionNames.empty())
944 {
945 BMCWEB_LOG_ERROR("Got 0 Connection names");
946 continue;
947 }
948
949 dbus::utility::getAssociationEndPoints(
950 path + "/drive",
951 [asyncResp, chassisId,
952 driveName](const boost::system::error_code& ec3,
953 const dbus::utility::MapperEndPoints& resp) {
954 if (ec3)
955 {
956 return; // no drives = no failures
957 }
958 matchAndFillDrive(asyncResp, chassisId, driveName,
959 resp);
960 });
961 break;
962 }
963 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700964}
965
966/**
967 * This URL will show the drive interface for the specific drive in the chassis
968 */
969inline void requestRoutesChassisDriveName(App& app)
970{
971 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
972 .privileges(redfish::privileges::getChassis)
973 .methods(boost::beast::http::verb::get)(
974 std::bind_front(handleChassisDriveGet, std::ref(app)));
975}
976
Willy Tu61b1eb22023-03-14 11:29:50 -0700977inline void getStorageControllerAsset(
978 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
979 const boost::system::error_code& ec,
980 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
981 propertiesList)
982{
983 if (ec)
984 {
985 // this interface isn't necessary
Ed Tanous62598e32023-07-17 17:06:25 -0700986 BMCWEB_LOG_DEBUG("Failed to get StorageControllerAsset");
Willy Tu61b1eb22023-03-14 11:29:50 -0700987 return;
988 }
989
990 const std::string* partNumber = nullptr;
991 const std::string* serialNumber = nullptr;
992 const std::string* manufacturer = nullptr;
993 const std::string* model = nullptr;
994 if (!sdbusplus::unpackPropertiesNoThrow(
995 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
996 partNumber, "SerialNumber", serialNumber, "Manufacturer",
997 manufacturer, "Model", model))
998 {
999 messages::internalError(asyncResp->res);
1000 return;
1001 }
1002
1003 if (partNumber != nullptr)
1004 {
1005 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
1006 }
1007
1008 if (serialNumber != nullptr)
1009 {
1010 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
1011 }
1012
1013 if (manufacturer != nullptr)
1014 {
1015 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
1016 }
1017
1018 if (model != nullptr)
1019 {
1020 asyncResp->res.jsonValue["Model"] = *model;
1021 }
1022}
1023
1024inline void populateStorageController(
1025 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1026 const std::string& controllerId, const std::string& connectionName,
1027 const std::string& path)
1028{
1029 asyncResp->res.jsonValue["@odata.type"] =
1030 "#StorageController.v1_6_0.StorageController";
Ed Tanous253f11b2024-05-16 09:38:31 -07001031 asyncResp->res.jsonValue["@odata.id"] =
1032 boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
1033 BMCWEB_REDFISH_SYSTEM_URI_NAME, controllerId);
Willy Tu61b1eb22023-03-14 11:29:50 -07001034 asyncResp->res.jsonValue["Name"] = controllerId;
1035 asyncResp->res.jsonValue["Id"] = controllerId;
Ed Tanous539d8c62024-06-19 14:38:27 -07001036 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tu61b1eb22023-03-14 11:29:50 -07001037
Ed Tanousdeae6a72024-11-11 21:58:57 -08001038 dbus::utility::getProperty<bool>(
1039 connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present",
Willy Tu61b1eb22023-03-14 11:29:50 -07001040 [asyncResp](const boost::system::error_code& ec, bool isPresent) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001041 // this interface isn't necessary, only check it
1042 // if we get a good return
1043 if (ec)
1044 {
1045 BMCWEB_LOG_DEBUG("Failed to get Present property");
1046 return;
1047 }
1048 if (!isPresent)
1049 {
1050 asyncResp->res.jsonValue["Status"]["State"] =
1051 resource::State::Absent;
1052 }
1053 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001054
Ed Tanousdeae6a72024-11-11 21:58:57 -08001055 dbus::utility::getAllProperties(
1056 connectionName, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
Willy Tu61b1eb22023-03-14 11:29:50 -07001057 [asyncResp](const boost::system::error_code& ec,
1058 const std::vector<
1059 std::pair<std::string, dbus::utility::DbusVariantType>>&
1060 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001061 getStorageControllerAsset(asyncResp, ec, propertiesList);
1062 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001063}
1064
1065inline void getStorageControllerHandler(
1066 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1067 const std::string& controllerId, const boost::system::error_code& ec,
1068 const dbus::utility::MapperGetSubTreeResponse& subtree)
1069{
1070 if (ec || subtree.empty())
1071 {
1072 // doesn't have to be there
Ed Tanous62598e32023-07-17 17:06:25 -07001073 BMCWEB_LOG_DEBUG("Failed to handle StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001074 return;
1075 }
1076
1077 for (const auto& [path, interfaceDict] : subtree)
1078 {
1079 sdbusplus::message::object_path object(path);
1080 std::string id = object.filename();
1081 if (id.empty())
1082 {
Ed Tanous62598e32023-07-17 17:06:25 -07001083 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001084 return;
1085 }
1086 if (id != controllerId)
1087 {
1088 continue;
1089 }
1090
1091 if (interfaceDict.size() != 1)
1092 {
Ed Tanous62598e32023-07-17 17:06:25 -07001093 BMCWEB_LOG_ERROR("Connection size {}, greater than 1",
1094 interfaceDict.size());
Willy Tu61b1eb22023-03-14 11:29:50 -07001095 messages::internalError(asyncResp->res);
1096 return;
1097 }
1098
1099 const std::string& connectionName = interfaceDict.front().first;
1100 populateStorageController(asyncResp, controllerId, connectionName,
1101 path);
1102 }
1103}
1104
1105inline void populateStorageControllerCollection(
1106 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1107 const boost::system::error_code& ec,
1108 const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
1109{
1110 nlohmann::json::array_t members;
1111 if (ec || controllerList.empty())
1112 {
1113 asyncResp->res.jsonValue["Members"] = std::move(members);
1114 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous62598e32023-07-17 17:06:25 -07001115 BMCWEB_LOG_DEBUG("Failed to find any StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001116 return;
1117 }
1118
1119 for (const std::string& path : controllerList)
1120 {
1121 std::string id = sdbusplus::message::object_path(path).filename();
1122 if (id.empty())
1123 {
Ed Tanous62598e32023-07-17 17:06:25 -07001124 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001125 return;
1126 }
1127 nlohmann::json::object_t member;
1128 member["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001129 "/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
1130 BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
Willy Tu61b1eb22023-03-14 11:29:50 -07001131 members.emplace_back(member);
1132 }
1133 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
1134 asyncResp->res.jsonValue["Members"] = std::move(members);
1135}
1136
Ed Tanous36d52332023-06-09 13:18:40 -07001137inline void handleSystemsStorageControllerCollectionGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001138 App& app, const crow::Request& req,
1139 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1140 const std::string& systemName)
1141{
1142 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1143 {
Ed Tanous62598e32023-07-17 17:06:25 -07001144 BMCWEB_LOG_DEBUG(
1145 "Failed to setup Redfish Route for StorageController Collection");
Willy Tu61b1eb22023-03-14 11:29:50 -07001146 return;
1147 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001148 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Willy Tu61b1eb22023-03-14 11:29:50 -07001149 {
1150 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1151 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001152 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001153 return;
1154 }
1155
1156 asyncResp->res.jsonValue["@odata.type"] =
1157 "#StorageControllerCollection.StorageControllerCollection";
1158 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001159 std::format("/redfish/v1/Systems/{}/Storage/1/Controllers",
1160 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Willy Tu61b1eb22023-03-14 11:29:50 -07001161 asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
1162
1163 constexpr std::array<std::string_view, 1> interfaces = {
1164 "xyz.openbmc_project.Inventory.Item.StorageController"};
1165 dbus::utility::getSubTreePaths(
1166 "/xyz/openbmc_project/inventory", 0, interfaces,
1167 [asyncResp](const boost::system::error_code& ec,
1168 const dbus::utility::MapperGetSubTreePathsResponse&
1169 controllerList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001170 populateStorageControllerCollection(asyncResp, ec, controllerList);
1171 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001172}
1173
Ed Tanous36d52332023-06-09 13:18:40 -07001174inline void handleSystemsStorageControllerGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001175 App& app, const crow::Request& req,
1176 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1177 const std::string& systemName, const std::string& controllerId)
1178{
1179 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1180 {
Ed Tanous62598e32023-07-17 17:06:25 -07001181 BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001182 return;
1183 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001184 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Willy Tu61b1eb22023-03-14 11:29:50 -07001185 {
1186 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1187 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001188 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001189 return;
1190 }
1191 constexpr std::array<std::string_view, 1> interfaces = {
1192 "xyz.openbmc_project.Inventory.Item.StorageController"};
1193 dbus::utility::getSubTree(
1194 "/xyz/openbmc_project/inventory", 0, interfaces,
1195 [asyncResp,
1196 controllerId](const boost::system::error_code& ec,
1197 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001198 getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
1199 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001200}
1201
1202inline void requestRoutesStorageControllerCollection(App& app)
1203{
1204 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
1205 .privileges(redfish::privileges::getStorageControllerCollection)
Ed Tanous36d52332023-06-09 13:18:40 -07001206 .methods(boost::beast::http::verb::get)(std::bind_front(
1207 handleSystemsStorageControllerCollectionGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001208}
1209
1210inline void requestRoutesStorageController(App& app)
1211{
1212 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
1213 .privileges(redfish::privileges::getStorageController)
1214 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -07001215 std::bind_front(handleSystemsStorageControllerGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001216}
1217
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001218} // namespace redfish