blob: 22587dac4fa5e57a1ec5e10e7ce1165a019b9b5b [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"
George Liu7a1dbc42022-12-07 16:03:22 +08009#include "dbus_utility.hpp"
John Edward Broadbente5029d82022-06-08 14:35:21 -070010#include "generated/enums/drive.hpp"
George Liudde9bc12023-02-22 09:35:51 +080011#include "generated/enums/protocol.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070012#include "generated/enums/resource.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080013#include "human_sort.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080014#include "query.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080015#include "redfish_util.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080016#include "registries/privilege_registry.hpp"
Willy Tu5e577bc2022-07-26 00:41:55 +000017#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "utils/dbus_utils.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070019
George Liue99073f2022-12-09 11:06:16 +080020#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070021#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070022#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020023#include <sdbusplus/unpack_properties.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070024
George Liu7a1dbc42022-12-07 16:03:22 +080025#include <array>
Ed Tanous3544d2a2023-08-06 18:12:20 -070026#include <ranges>
George Liu7a1dbc42022-12-07 16:03:22 +080027#include <string_view>
28
Nikhil Potadea25aecc2019-08-23 16:35:26 -070029namespace redfish
30{
Ed Tanous36d52332023-06-09 13:18:40 -070031
32inline void handleSystemsStorageCollectionGet(
33 App& app, const crow::Request& req,
34 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
35 const std::string& systemName)
36{
37 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
38 {
39 return;
40 }
Ed Tanous253f11b2024-05-16 09:38:31 -070041 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous36d52332023-06-09 13:18:40 -070042 {
43 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
44 systemName);
45 return;
46 }
47
48 asyncResp->res.jsonValue["@odata.type"] =
49 "#StorageCollection.StorageCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -070050 asyncResp->res.jsonValue["@odata.id"] = std::format(
51 "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous36d52332023-06-09 13:18:40 -070052 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Willy Tu5e577bc2022-07-26 00:41:55 +000053
Patrick Williams5a39f772023-10-20 11:20:21 -050054 constexpr std::array<std::string_view, 1> interface{
55 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000056 collection_util::getCollectionMembers(
Ed Tanous253f11b2024-05-16 09:38:31 -070057 asyncResp,
58 boost::urls::format("/redfish/v1/Systems/{}/Storage",
59 BMCWEB_REDFISH_SYSTEM_URI_NAME),
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050060 interface, "/xyz/openbmc_project/inventory");
Willy Tu5e577bc2022-07-26 00:41:55 +000061}
62
63inline void handleStorageCollectionGet(
64 App& app, const crow::Request& req,
65 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
66{
67 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
68 {
69 return;
70 }
71 asyncResp->res.jsonValue["@odata.type"] =
72 "#StorageCollection.StorageCollection";
73 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Storage";
74 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Patrick Williams5a39f772023-10-20 11:20:21 -050075 constexpr std::array<std::string_view, 1> interface{
76 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000077 collection_util::getCollectionMembers(
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050078 asyncResp, boost::urls::format("/redfish/v1/Storage"), interface,
79 "/xyz/openbmc_project/inventory");
Ed Tanous36d52332023-06-09 13:18:40 -070080}
81
John Edward Broadbent7e860f12021-04-08 15:57:16 -070082inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070083{
Ed Tanous22d268c2022-05-19 09:39:07 -070084 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -070085 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070086 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -070087 std::bind_front(handleSystemsStorageCollectionGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +000088 BMCWEB_ROUTE(app, "/redfish/v1/Storage/")
89 .privileges(redfish::privileges::getStorageCollection)
90 .methods(boost::beast::http::verb::get)(
91 std::bind_front(handleStorageCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -070092}
Nikhil Potadea25aecc2019-08-23 16:35:26 -070093
Ed Tanous36d52332023-06-09 13:18:40 -070094inline void afterChassisDriveCollectionSubtree(
95 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous36d52332023-06-09 13:18:40 -070096 const boost::system::error_code& ec,
97 const dbus::utility::MapperGetSubTreePathsResponse& driveList)
98{
99 if (ec)
100 {
Ed Tanous62598e32023-07-17 17:06:25 -0700101 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700102 messages::internalError(asyncResp->res);
103 return;
104 }
105
106 nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
107 driveArray = nlohmann::json::array();
108 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
109 count = 0;
110
Ed Tanous36d52332023-06-09 13:18:40 -0700111 for (const std::string& drive : driveList)
112 {
113 sdbusplus::message::object_path object(drive);
114 if (object.filename().empty())
115 {
Ed Tanous62598e32023-07-17 17:06:25 -0700116 BMCWEB_LOG_ERROR("Failed to find filename in {}", drive);
Ed Tanous36d52332023-06-09 13:18:40 -0700117 return;
118 }
119
120 nlohmann::json::object_t driveJson;
121 driveJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -0700122 "/redfish/v1/Systems/{}/Storage/1/Drives/{}",
123 BMCWEB_REDFISH_SYSTEM_URI_NAME, object.filename());
Ed Tanous36d52332023-06-09 13:18:40 -0700124 driveArray.emplace_back(std::move(driveJson));
125 }
126
127 count = driveArray.size();
128}
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500129inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Willy Tua85afbe2021-12-28 14:43:47 -0800130{
George Liu7a1dbc42022-12-07 16:03:22 +0800131 const std::array<std::string_view, 1> interfaces = {
132 "xyz.openbmc_project.Inventory.Item.Drive"};
133 dbus::utility::getSubTreePaths(
134 "/xyz/openbmc_project/inventory", 0, interfaces,
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500135 std::bind_front(afterChassisDriveCollectionSubtree, asyncResp));
Ed Tanous36d52332023-06-09 13:18:40 -0700136}
Willy Tua85afbe2021-12-28 14:43:47 -0800137
Willy Tu5e577bc2022-07-26 00:41:55 +0000138inline void afterSystemsStorageGetSubtree(
139 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
140 const std::string& storageId, const boost::system::error_code& ec,
141 const dbus::utility::MapperGetSubTreeResponse& subtree)
Ed Tanous36d52332023-06-09 13:18:40 -0700142{
Willy Tu5e577bc2022-07-26 00:41:55 +0000143 if (ec)
Ed Tanous36d52332023-06-09 13:18:40 -0700144 {
Ed Tanous62598e32023-07-17 17:06:25 -0700145 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000146 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
147 storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700148 return;
149 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700150 auto storage = std::ranges::find_if(
151 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000152 [&storageId](const std::pair<std::string,
153 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400154 return sdbusplus::message::object_path(object.first).filename() ==
155 storageId;
156 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000157 if (storage == subtree.end())
158 {
159 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
160 storageId);
161 return;
162 }
163
Ed Tanous36d52332023-06-09 13:18:40 -0700164 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
165 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -0700166 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
167 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700168 asyncResp->res.jsonValue["Name"] = "Storage";
Willy Tu5e577bc2022-07-26 00:41:55 +0000169 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous539d8c62024-06-19 14:38:27 -0700170 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tua85afbe2021-12-28 14:43:47 -0800171
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500172 getDrives(asyncResp);
Ed Tanous253f11b2024-05-16 09:38:31 -0700173 asyncResp->res.jsonValue["Controllers"]["@odata.id"] =
174 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}/Controllers",
175 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Willy Tu5e577bc2022-07-26 00:41:55 +0000176}
177
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400178inline void handleSystemsStorageGet(
179 App& app, const crow::Request& req,
180 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
181 const std::string& systemName, const std::string& storageId)
Willy Tu5e577bc2022-07-26 00:41:55 +0000182{
183 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
184 {
185 return;
186 }
Ed Tanous25b54db2024-04-17 15:40:31 -0700187 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800188 {
189 // Option currently returns no systems. TBD
190 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
191 systemName);
192 return;
193 }
Willy Tu5e577bc2022-07-26 00:41:55 +0000194
195 constexpr std::array<std::string_view, 1> interfaces = {
196 "xyz.openbmc_project.Inventory.Item.Storage"};
197 dbus::utility::getSubTree(
198 "/xyz/openbmc_project/inventory", 0, interfaces,
199 std::bind_front(afterSystemsStorageGetSubtree, asyncResp, storageId));
200}
201
202inline void afterSubtree(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
203 const std::string& storageId,
204 const boost::system::error_code& ec,
205 const dbus::utility::MapperGetSubTreeResponse& subtree)
206{
207 if (ec)
208 {
Ed Tanous62598e32023-07-17 17:06:25 -0700209 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000210 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
211 storageId);
212 return;
213 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700214 auto storage = std::ranges::find_if(
215 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000216 [&storageId](const std::pair<std::string,
217 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400218 return sdbusplus::message::object_path(object.first).filename() ==
219 storageId;
220 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000221 if (storage == subtree.end())
222 {
223 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
224 storageId);
225 return;
226 }
227
228 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
229 asyncResp->res.jsonValue["@odata.id"] =
230 boost::urls::format("/redfish/v1/Storage/{}", storageId);
231 asyncResp->res.jsonValue["Name"] = "Storage";
232 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous539d8c62024-06-19 14:38:27 -0700233 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tu5e577bc2022-07-26 00:41:55 +0000234
235 // Storage subsystem to Storage link.
236 nlohmann::json::array_t storageServices;
237 nlohmann::json::object_t storageService;
238 storageService["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -0700239 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
240 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Willy Tu5e577bc2022-07-26 00:41:55 +0000241 storageServices.emplace_back(storageService);
242 asyncResp->res.jsonValue["Links"]["StorageServices"] =
243 std::move(storageServices);
244 asyncResp->res.jsonValue["Links"]["StorageServices@odata.count"] = 1;
245}
246
247inline void
248 handleStorageGet(App& app, const crow::Request& req,
249 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
250 const std::string& storageId)
251{
252 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
253 {
Ed Tanous62598e32023-07-17 17:06:25 -0700254 BMCWEB_LOG_DEBUG("requestRoutesStorage setUpRedfishRoute failed");
Willy Tu5e577bc2022-07-26 00:41:55 +0000255 return;
256 }
257
258 constexpr std::array<std::string_view, 1> interfaces = {
259 "xyz.openbmc_project.Inventory.Item.Storage"};
260 dbus::utility::getSubTree(
261 "/xyz/openbmc_project/inventory", 0, interfaces,
262 std::bind_front(afterSubtree, asyncResp, storageId));
Willy Tua85afbe2021-12-28 14:43:47 -0800263}
264
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700265inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700266{
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800267 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700268 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -0700269 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700270 std::bind_front(handleSystemsStorageGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000271
272 BMCWEB_ROUTE(app, "/redfish/v1/Storage/<str>/")
273 .privileges(redfish::privileges::getStorage)
274 .methods(boost::beast::http::verb::get)(
275 std::bind_front(handleStorageGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700276}
277
Willy Tu03913172021-11-08 02:03:19 -0800278inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
279 const std::string& connectionName,
280 const std::string& path)
281{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800282 dbus::utility::getAllProperties(
283 connectionName, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800284 [asyncResp](const boost::system::error_code& ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800285 const std::vector<
286 std::pair<std::string, dbus::utility::DbusVariantType>>&
287 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400288 if (ec)
289 {
290 // this interface isn't necessary
291 return;
292 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200293
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400294 const std::string* partNumber = nullptr;
295 const std::string* serialNumber = nullptr;
296 const std::string* manufacturer = nullptr;
297 const std::string* model = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200298
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400299 const bool success = sdbusplus::unpackPropertiesNoThrow(
300 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
301 partNumber, "SerialNumber", serialNumber, "Manufacturer",
302 manufacturer, "Model", model);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200303
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400304 if (!success)
305 {
306 messages::internalError(asyncResp->res);
307 return;
308 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200309
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400310 if (partNumber != nullptr)
311 {
312 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
313 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200314
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400315 if (serialNumber != nullptr)
316 {
317 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
318 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200319
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400320 if (manufacturer != nullptr)
321 {
322 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
323 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200324
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400325 if (model != nullptr)
326 {
327 asyncResp->res.jsonValue["Model"] = *model;
328 }
329 });
Willy Tu03913172021-11-08 02:03:19 -0800330}
331
332inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
333 const std::string& connectionName,
334 const std::string& path)
335{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800336 dbus::utility::getProperty<bool>(
337 connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present",
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400338 [asyncResp,
339 path](const boost::system::error_code& ec, const bool isPresent) {
340 // this interface isn't necessary, only check it if
341 // we get a good return
342 if (ec)
343 {
344 return;
345 }
Willy Tu03913172021-11-08 02:03:19 -0800346
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400347 if (!isPresent)
348 {
349 asyncResp->res.jsonValue["Status"]["State"] =
350 resource::State::Absent;
351 }
352 });
Willy Tu03913172021-11-08 02:03:19 -0800353}
354
355inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
356 const std::string& connectionName,
357 const std::string& path)
358{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800359 dbus::utility::getProperty<bool>(
360 connectionName, path, "xyz.openbmc_project.State.Drive", "Rebuilding",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800361 [asyncResp](const boost::system::error_code& ec, const bool updating) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400362 // this interface isn't necessary, only check it
363 // if we get a good return
364 if (ec)
365 {
366 return;
367 }
Willy Tu03913172021-11-08 02:03:19 -0800368
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400369 // updating and disabled in the backend shouldn't be
370 // able to be set at the same time, so we don't need
371 // to check for the race condition of these two
372 // calls
373 if (updating)
374 {
375 asyncResp->res.jsonValue["Status"]["State"] =
376 resource::State::Updating;
377 }
378 });
Willy Tu03913172021-11-08 02:03:19 -0800379}
380
George Liudde9bc12023-02-22 09:35:51 +0800381inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800382{
383 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
384 {
George Liudde9bc12023-02-22 09:35:51 +0800385 return drive::MediaType::HDD;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800386 }
387 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
388 {
George Liudde9bc12023-02-22 09:35:51 +0800389 return drive::MediaType::SSD;
390 }
391 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
392 {
393 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800394 }
395
George Liudde9bc12023-02-22 09:35:51 +0800396 return drive::MediaType::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800397}
398
George Liudde9bc12023-02-22 09:35:51 +0800399inline std::optional<protocol::Protocol>
400 convertDriveProtocol(std::string_view proto)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800401{
402 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
403 {
George Liudde9bc12023-02-22 09:35:51 +0800404 return protocol::Protocol::SAS;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800405 }
406 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
407 {
George Liudde9bc12023-02-22 09:35:51 +0800408 return protocol::Protocol::SATA;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800409 }
410 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
411 {
George Liudde9bc12023-02-22 09:35:51 +0800412 return protocol::Protocol::NVMe;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800413 }
414 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
415 {
George Liudde9bc12023-02-22 09:35:51 +0800416 return protocol::Protocol::FC;
417 }
418 if (proto ==
419 "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
420 {
421 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800422 }
423
George Liudde9bc12023-02-22 09:35:51 +0800424 return protocol::Protocol::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800425}
426
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400427inline void getDriveItemProperties(
428 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
429 const std::string& connectionName, const std::string& path)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800430{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800431 dbus::utility::getAllProperties(
432 connectionName, path, "xyz.openbmc_project.Inventory.Item.Drive",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800433 [asyncResp](const boost::system::error_code& ec,
Willy Tu19b8e9a2021-11-08 02:55:03 -0800434 const std::vector<
435 std::pair<std::string, dbus::utility::DbusVariantType>>&
436 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400437 if (ec)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800438 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400439 // this interface isn't required
440 return;
441 }
442 const std::string* encryptionStatus = nullptr;
443 const bool* isLocked = nullptr;
444 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
445 property : propertiesList)
446 {
447 const std::string& propertyName = property.first;
448 if (propertyName == "Type")
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400450 const std::string* value =
451 std::get_if<std::string>(&property.second);
452 if (value == nullptr)
453 {
454 // illegal property
455 BMCWEB_LOG_ERROR("Illegal property: Type");
456 messages::internalError(asyncResp->res);
457 return;
458 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700459
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400460 std::optional<drive::MediaType> mediaType =
461 convertDriveType(*value);
462 if (!mediaType)
463 {
464 BMCWEB_LOG_WARNING("UnknownDriveType Interface: {}",
465 *value);
466 continue;
467 }
468 if (*mediaType == drive::MediaType::Invalid)
469 {
470 messages::internalError(asyncResp->res);
471 return;
472 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700473
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400474 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800475 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400476 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800477 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400478 const uint64_t* capacity =
479 std::get_if<uint64_t>(&property.second);
480 if (capacity == nullptr)
481 {
482 BMCWEB_LOG_ERROR("Illegal property: Capacity");
483 messages::internalError(asyncResp->res);
484 return;
485 }
486 if (*capacity == 0)
487 {
488 // drive capacity not known
489 continue;
490 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800491
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400492 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400494 else if (propertyName == "Protocol")
495 {
496 const std::string* value =
497 std::get_if<std::string>(&property.second);
498 if (value == nullptr)
499 {
500 BMCWEB_LOG_ERROR("Illegal property: Protocol");
501 messages::internalError(asyncResp->res);
502 return;
503 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700504
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400505 std::optional<protocol::Protocol> proto =
506 convertDriveProtocol(*value);
507 if (!proto)
508 {
509 BMCWEB_LOG_WARNING(
510 "Unknown DrivePrototype Interface: {}", *value);
511 continue;
512 }
513 if (*proto == protocol::Protocol::Invalid)
514 {
515 messages::internalError(asyncResp->res);
516 return;
517 }
518 asyncResp->res.jsonValue["Protocol"] = *proto;
George Liudde9bc12023-02-22 09:35:51 +0800519 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400520 else if (propertyName == "PredictedMediaLifeLeftPercent")
George Liudde9bc12023-02-22 09:35:51 +0800521 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400522 const uint8_t* lifeLeft =
523 std::get_if<uint8_t>(&property.second);
524 if (lifeLeft == nullptr)
525 {
526 BMCWEB_LOG_ERROR(
527 "Illegal property: PredictedMediaLifeLeftPercent");
528 messages::internalError(asyncResp->res);
529 return;
530 }
531 // 255 means reading the value is not supported
532 if (*lifeLeft != 255)
533 {
534 asyncResp->res
535 .jsonValue["PredictedMediaLifeLeftPercent"] =
536 *lifeLeft;
537 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700538 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400539 else if (propertyName == "EncryptionStatus")
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700540 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400541 encryptionStatus =
542 std::get_if<std::string>(&property.second);
543 if (encryptionStatus == nullptr)
544 {
545 BMCWEB_LOG_ERROR("Illegal property: EncryptionStatus");
546 messages::internalError(asyncResp->res);
547 return;
548 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700549 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400550 else if (propertyName == "Locked")
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700551 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400552 isLocked = std::get_if<bool>(&property.second);
553 if (isLocked == nullptr)
554 {
555 BMCWEB_LOG_ERROR("Illegal property: Locked");
556 messages::internalError(asyncResp->res);
557 return;
558 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700559 }
560 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700561
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400562 if (encryptionStatus == nullptr || isLocked == nullptr ||
563 *encryptionStatus ==
564 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Unknown")
565 {
566 return;
567 }
568 if (*encryptionStatus !=
569 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Encrypted")
570 {
571 //"The drive is not currently encrypted."
572 asyncResp->res.jsonValue["EncryptionStatus"] =
573 drive::EncryptionStatus::Unencrypted;
574 return;
575 }
576 if (*isLocked)
577 {
578 //"The drive is currently encrypted and the data is not
579 // accessible to the user."
580 asyncResp->res.jsonValue["EncryptionStatus"] =
581 drive::EncryptionStatus::Locked;
582 return;
583 }
584 // if not locked
585 // "The drive is currently encrypted but the data is accessible
586 // to the user in unencrypted form."
John Edward Broadbente5029d82022-06-08 14:35:21 -0700587 asyncResp->res.jsonValue["EncryptionStatus"] =
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400588 drive::EncryptionStatus::Unlocked;
589 });
Willy Tu19b8e9a2021-11-08 02:55:03 -0800590}
591
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700592inline void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000593 const std::string& connectionName,
594 const std::string& path,
595 const std::vector<std::string>& interfaces)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700596{
597 for (const std::string& interface : interfaces)
598 {
599 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
600 {
601 getDriveAsset(asyncResp, connectionName, path);
602 }
603 else if (interface == "xyz.openbmc_project.Inventory.Item")
604 {
605 getDrivePresent(asyncResp, connectionName, path);
606 }
607 else if (interface == "xyz.openbmc_project.State.Drive")
608 {
609 getDriveState(asyncResp, connectionName, path);
610 }
611 else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
612 {
613 getDriveItemProperties(asyncResp, connectionName, path);
614 }
615 }
616}
617
Ed Tanous36d52332023-06-09 13:18:40 -0700618inline void afterGetSubtreeSystemsStorageDrive(
619 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
620 const std::string& driveId, const boost::system::error_code& ec,
621 const dbus::utility::MapperGetSubTreeResponse& subtree)
622{
623 if (ec)
624 {
Ed Tanous62598e32023-07-17 17:06:25 -0700625 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700626 messages::internalError(asyncResp->res);
627 return;
628 }
629
Ed Tanous3544d2a2023-08-06 18:12:20 -0700630 auto drive = std::ranges::find_if(
631 subtree,
Ed Tanous36d52332023-06-09 13:18:40 -0700632 [&driveId](const std::pair<std::string,
633 dbus::utility::MapperServiceMap>& object) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400634 return sdbusplus::message::object_path(object.first).filename() ==
635 driveId;
636 });
Ed Tanous36d52332023-06-09 13:18:40 -0700637
638 if (drive == subtree.end())
639 {
640 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
641 return;
642 }
643
644 const std::string& path = drive->first;
645 const dbus::utility::MapperServiceMap& connectionNames = drive->second;
646
647 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
Ed Tanous253f11b2024-05-16 09:38:31 -0700648 asyncResp->res.jsonValue["@odata.id"] =
649 boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Drives/{}",
650 BMCWEB_REDFISH_SYSTEM_URI_NAME, driveId);
Ed Tanous36d52332023-06-09 13:18:40 -0700651 asyncResp->res.jsonValue["Name"] = driveId;
652 asyncResp->res.jsonValue["Id"] = driveId;
653
654 if (connectionNames.size() != 1)
655 {
Ed Tanous62598e32023-07-17 17:06:25 -0700656 BMCWEB_LOG_ERROR("Connection size {}, not equal to 1",
657 connectionNames.size());
Ed Tanous36d52332023-06-09 13:18:40 -0700658 messages::internalError(asyncResp->res);
659 return;
660 }
661
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400662 getMainChassisId(
663 asyncResp, [](const std::string& chassisId,
664 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
665 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
666 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
667 });
Ed Tanous36d52332023-06-09 13:18:40 -0700668
669 // default it to Enabled
Ed Tanous539d8c62024-06-19 14:38:27 -0700670 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Ed Tanous36d52332023-06-09 13:18:40 -0700671
Ed Tanous36d52332023-06-09 13:18:40 -0700672 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
673 connectionNames[0].second);
674}
675
676inline void handleSystemsStorageDriveGet(
677 App& app, const crow::Request& req,
678 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
679 const std::string& systemName, const std::string& driveId)
680{
681 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
682 {
683 return;
684 }
Ed Tanous25b54db2024-04-17 15:40:31 -0700685 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800686 {
687 // Option currently returns no systems. TBD
688 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
689 systemName);
690 return;
691 }
692
Ed Tanous253f11b2024-05-16 09:38:31 -0700693 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous36d52332023-06-09 13:18:40 -0700694 {
695 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
696 systemName);
697 return;
698 }
699
700 constexpr std::array<std::string_view, 1> interfaces = {
701 "xyz.openbmc_project.Inventory.Item.Drive"};
702 dbus::utility::getSubTree(
703 "/xyz/openbmc_project/inventory", 0, interfaces,
704 std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp,
705 driveId));
706}
707
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700708inline void requestRoutesDrive(App& app)
709{
Ed Tanous22d268c2022-05-19 09:39:07 -0700710 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700711 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700712 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700713 std::bind_front(handleSystemsStorageDriveGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700714}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700715
Ed Tanous36d52332023-06-09 13:18:40 -0700716inline void afterChassisDriveCollectionSubtreeGet(
717 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
718 const std::string& chassisId, const boost::system::error_code& ec,
719 const dbus::utility::MapperGetSubTreeResponse& subtree)
720{
721 if (ec)
722 {
723 if (ec == boost::system::errc::host_unreachable)
724 {
725 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
726 return;
727 }
728 messages::internalError(asyncResp->res);
729 return;
730 }
731
732 // Iterate over all retrieved ObjectPaths.
733 for (const auto& [path, connectionNames] : subtree)
734 {
735 sdbusplus::message::object_path objPath(path);
736 if (objPath.filename() != chassisId)
737 {
738 continue;
739 }
740
741 if (connectionNames.empty())
742 {
Ed Tanous62598e32023-07-17 17:06:25 -0700743 BMCWEB_LOG_ERROR("Got 0 Connection names");
Ed Tanous36d52332023-06-09 13:18:40 -0700744 continue;
745 }
746
747 asyncResp->res.jsonValue["@odata.type"] =
748 "#DriveCollection.DriveCollection";
749 asyncResp->res.jsonValue["@odata.id"] =
750 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
751 asyncResp->res.jsonValue["Name"] = "Drive Collection";
752
753 // Association lambda
754 dbus::utility::getAssociationEndPoints(
755 path + "/drive",
756 [asyncResp, chassisId](const boost::system::error_code& ec3,
757 const dbus::utility::MapperEndPoints& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400758 if (ec3)
759 {
760 BMCWEB_LOG_ERROR("Error in chassis Drive association ");
761 }
762 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
763 // important if array is empty
764 members = nlohmann::json::array();
Ed Tanous36d52332023-06-09 13:18:40 -0700765
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400766 std::vector<std::string> leafNames;
767 for (const auto& drive : resp)
768 {
769 sdbusplus::message::object_path drivePath(drive);
770 leafNames.push_back(drivePath.filename());
771 }
Ed Tanous36d52332023-06-09 13:18:40 -0700772
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400773 std::ranges::sort(leafNames, AlphanumLess<std::string>());
Ed Tanous36d52332023-06-09 13:18:40 -0700774
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400775 for (const auto& leafName : leafNames)
776 {
777 nlohmann::json::object_t member;
778 member["@odata.id"] =
779 boost::urls::format("/redfish/v1/Chassis/{}/Drives/{}",
780 chassisId, leafName);
781 members.emplace_back(std::move(member));
782 // navigation links will be registered in next patch set
783 }
784 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
785 }); // end association lambda
Ed Tanous36d52332023-06-09 13:18:40 -0700786
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400787 } // end Iterate over all retrieved ObjectPaths
Ed Tanous36d52332023-06-09 13:18:40 -0700788}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700789/**
790 * Chassis drives, this URL will show all the DriveCollection
791 * information
792 */
Nan Zhoub53dcd92022-06-21 17:47:50 +0000793inline void chassisDriveCollectionGet(
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700794 crow::App& app, const crow::Request& req,
795 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
796 const std::string& chassisId)
797{
Carson Labrado3ba00072022-06-06 19:40:56 +0000798 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700799 {
800 return;
801 }
802
803 // mapper call lambda
George Liue99073f2022-12-09 11:06:16 +0800804 constexpr std::array<std::string_view, 2> interfaces = {
805 "xyz.openbmc_project.Inventory.Item.Board",
806 "xyz.openbmc_project.Inventory.Item.Chassis"};
807 dbus::utility::getSubTree(
808 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous36d52332023-06-09 13:18:40 -0700809 std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp,
810 chassisId));
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700811}
812
813inline void requestRoutesChassisDrive(App& app)
814{
815 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
816 .privileges(redfish::privileges::getDriveCollection)
817 .methods(boost::beast::http::verb::get)(
818 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
819}
820
Nan Zhoub53dcd92022-06-21 17:47:50 +0000821inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
822 const std::string& chassisId,
823 const std::string& driveName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800824 const boost::system::error_code& ec,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000825 const dbus::utility::MapperGetSubTreeResponse& subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700826{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700827 if (ec)
828 {
Ed Tanous62598e32023-07-17 17:06:25 -0700829 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700830 messages::internalError(asyncResp->res);
831 return;
832 }
833
834 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000835 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700836 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700837 sdbusplus::message::object_path objPath(path);
838 if (objPath.filename() != driveName)
839 {
840 continue;
841 }
842
843 if (connectionNames.empty())
844 {
Ed Tanous62598e32023-07-17 17:06:25 -0700845 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700846 continue;
847 }
848
Ed Tanousef4c65b2023-04-24 15:28:50 -0700849 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
850 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700851
852 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700853 asyncResp->res.jsonValue["Name"] = driveName;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700854 asyncResp->res.jsonValue["Id"] = driveName;
855 // default it to Enabled
Ed Tanous539d8c62024-06-19 14:38:27 -0700856 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700857
858 nlohmann::json::object_t linkChassisNav;
859 linkChassisNav["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700860 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700861 asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
862
863 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
864 connectionNames[0].second);
865 }
866}
867
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400868inline void matchAndFillDrive(
869 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
870 const std::string& chassisId, const std::string& driveName,
871 const std::vector<std::string>& resp)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700872{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700873 for (const std::string& drivePath : resp)
874 {
875 sdbusplus::message::object_path path(drivePath);
876 std::string leaf = path.filename();
877 if (leaf != driveName)
878 {
879 continue;
880 }
881 // mapper call drive
George Liue99073f2022-12-09 11:06:16 +0800882 constexpr std::array<std::string_view, 1> driveInterface = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700883 "xyz.openbmc_project.Inventory.Item.Drive"};
George Liue99073f2022-12-09 11:06:16 +0800884 dbus::utility::getSubTree(
885 "/xyz/openbmc_project/inventory", 0, driveInterface,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700886 [asyncResp, chassisId, driveName](
George Liue99073f2022-12-09 11:06:16 +0800887 const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700888 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400889 buildDrive(asyncResp, chassisId, driveName, ec, subtree);
890 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700891 }
892}
893
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400894inline void handleChassisDriveGet(
895 crow::App& app, const crow::Request& req,
896 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
897 const std::string& chassisId, const std::string& driveName)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700898{
Michal Orzel03810a12022-06-15 14:04:28 +0200899 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700900 {
901 return;
902 }
George Liue99073f2022-12-09 11:06:16 +0800903 constexpr std::array<std::string_view, 2> interfaces = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700904 "xyz.openbmc_project.Inventory.Item.Board",
905 "xyz.openbmc_project.Inventory.Item.Chassis"};
906
907 // mapper call chassis
George Liue99073f2022-12-09 11:06:16 +0800908 dbus::utility::getSubTree(
909 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700910 [asyncResp, chassisId,
George Liue99073f2022-12-09 11:06:16 +0800911 driveName](const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700912 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400913 if (ec)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700914 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400915 messages::internalError(asyncResp->res);
916 return;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700917 }
918
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400919 // Iterate over all retrieved ObjectPaths.
920 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700921 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400922 sdbusplus::message::object_path objPath(path);
923 if (objPath.filename() != chassisId)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700924 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400925 continue;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700926 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400927
928 if (connectionNames.empty())
929 {
930 BMCWEB_LOG_ERROR("Got 0 Connection names");
931 continue;
932 }
933
934 dbus::utility::getAssociationEndPoints(
935 path + "/drive",
936 [asyncResp, chassisId,
937 driveName](const boost::system::error_code& ec3,
938 const dbus::utility::MapperEndPoints& resp) {
939 if (ec3)
940 {
941 return; // no drives = no failures
942 }
943 matchAndFillDrive(asyncResp, chassisId, driveName,
944 resp);
945 });
946 break;
947 }
948 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700949}
950
951/**
952 * This URL will show the drive interface for the specific drive in the chassis
953 */
954inline void requestRoutesChassisDriveName(App& app)
955{
956 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
957 .privileges(redfish::privileges::getChassis)
958 .methods(boost::beast::http::verb::get)(
959 std::bind_front(handleChassisDriveGet, std::ref(app)));
960}
961
Willy Tu61b1eb22023-03-14 11:29:50 -0700962inline void getStorageControllerAsset(
963 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
964 const boost::system::error_code& ec,
965 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
966 propertiesList)
967{
968 if (ec)
969 {
970 // this interface isn't necessary
Ed Tanous62598e32023-07-17 17:06:25 -0700971 BMCWEB_LOG_DEBUG("Failed to get StorageControllerAsset");
Willy Tu61b1eb22023-03-14 11:29:50 -0700972 return;
973 }
974
975 const std::string* partNumber = nullptr;
976 const std::string* serialNumber = nullptr;
977 const std::string* manufacturer = nullptr;
978 const std::string* model = nullptr;
979 if (!sdbusplus::unpackPropertiesNoThrow(
980 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
981 partNumber, "SerialNumber", serialNumber, "Manufacturer",
982 manufacturer, "Model", model))
983 {
984 messages::internalError(asyncResp->res);
985 return;
986 }
987
988 if (partNumber != nullptr)
989 {
990 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
991 }
992
993 if (serialNumber != nullptr)
994 {
995 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
996 }
997
998 if (manufacturer != nullptr)
999 {
1000 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
1001 }
1002
1003 if (model != nullptr)
1004 {
1005 asyncResp->res.jsonValue["Model"] = *model;
1006 }
1007}
1008
1009inline void populateStorageController(
1010 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1011 const std::string& controllerId, const std::string& connectionName,
1012 const std::string& path)
1013{
1014 asyncResp->res.jsonValue["@odata.type"] =
1015 "#StorageController.v1_6_0.StorageController";
Ed Tanous253f11b2024-05-16 09:38:31 -07001016 asyncResp->res.jsonValue["@odata.id"] =
1017 boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
1018 BMCWEB_REDFISH_SYSTEM_URI_NAME, controllerId);
Willy Tu61b1eb22023-03-14 11:29:50 -07001019 asyncResp->res.jsonValue["Name"] = controllerId;
1020 asyncResp->res.jsonValue["Id"] = controllerId;
Ed Tanous539d8c62024-06-19 14:38:27 -07001021 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
Willy Tu61b1eb22023-03-14 11:29:50 -07001022
Ed Tanousdeae6a72024-11-11 21:58:57 -08001023 dbus::utility::getProperty<bool>(
1024 connectionName, path, "xyz.openbmc_project.Inventory.Item", "Present",
Willy Tu61b1eb22023-03-14 11:29:50 -07001025 [asyncResp](const boost::system::error_code& ec, bool isPresent) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001026 // this interface isn't necessary, only check it
1027 // if we get a good return
1028 if (ec)
1029 {
1030 BMCWEB_LOG_DEBUG("Failed to get Present property");
1031 return;
1032 }
1033 if (!isPresent)
1034 {
1035 asyncResp->res.jsonValue["Status"]["State"] =
1036 resource::State::Absent;
1037 }
1038 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001039
Ed Tanousdeae6a72024-11-11 21:58:57 -08001040 dbus::utility::getAllProperties(
1041 connectionName, path, "xyz.openbmc_project.Inventory.Decorator.Asset",
Willy Tu61b1eb22023-03-14 11:29:50 -07001042 [asyncResp](const boost::system::error_code& ec,
1043 const std::vector<
1044 std::pair<std::string, dbus::utility::DbusVariantType>>&
1045 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001046 getStorageControllerAsset(asyncResp, ec, propertiesList);
1047 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001048}
1049
1050inline void getStorageControllerHandler(
1051 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1052 const std::string& controllerId, const boost::system::error_code& ec,
1053 const dbus::utility::MapperGetSubTreeResponse& subtree)
1054{
1055 if (ec || subtree.empty())
1056 {
1057 // doesn't have to be there
Ed Tanous62598e32023-07-17 17:06:25 -07001058 BMCWEB_LOG_DEBUG("Failed to handle StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001059 return;
1060 }
1061
1062 for (const auto& [path, interfaceDict] : subtree)
1063 {
1064 sdbusplus::message::object_path object(path);
1065 std::string id = object.filename();
1066 if (id.empty())
1067 {
Ed Tanous62598e32023-07-17 17:06:25 -07001068 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001069 return;
1070 }
1071 if (id != controllerId)
1072 {
1073 continue;
1074 }
1075
1076 if (interfaceDict.size() != 1)
1077 {
Ed Tanous62598e32023-07-17 17:06:25 -07001078 BMCWEB_LOG_ERROR("Connection size {}, greater than 1",
1079 interfaceDict.size());
Willy Tu61b1eb22023-03-14 11:29:50 -07001080 messages::internalError(asyncResp->res);
1081 return;
1082 }
1083
1084 const std::string& connectionName = interfaceDict.front().first;
1085 populateStorageController(asyncResp, controllerId, connectionName,
1086 path);
1087 }
1088}
1089
1090inline void populateStorageControllerCollection(
1091 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1092 const boost::system::error_code& ec,
1093 const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
1094{
1095 nlohmann::json::array_t members;
1096 if (ec || controllerList.empty())
1097 {
1098 asyncResp->res.jsonValue["Members"] = std::move(members);
1099 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous62598e32023-07-17 17:06:25 -07001100 BMCWEB_LOG_DEBUG("Failed to find any StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001101 return;
1102 }
1103
1104 for (const std::string& path : controllerList)
1105 {
1106 std::string id = sdbusplus::message::object_path(path).filename();
1107 if (id.empty())
1108 {
Ed Tanous62598e32023-07-17 17:06:25 -07001109 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001110 return;
1111 }
1112 nlohmann::json::object_t member;
1113 member["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001114 "/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
1115 BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
Willy Tu61b1eb22023-03-14 11:29:50 -07001116 members.emplace_back(member);
1117 }
1118 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
1119 asyncResp->res.jsonValue["Members"] = std::move(members);
1120}
1121
Ed Tanous36d52332023-06-09 13:18:40 -07001122inline void handleSystemsStorageControllerCollectionGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001123 App& app, const crow::Request& req,
1124 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1125 const std::string& systemName)
1126{
1127 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1128 {
Ed Tanous62598e32023-07-17 17:06:25 -07001129 BMCWEB_LOG_DEBUG(
1130 "Failed to setup Redfish Route for StorageController Collection");
Willy Tu61b1eb22023-03-14 11:29:50 -07001131 return;
1132 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001133 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Willy Tu61b1eb22023-03-14 11:29:50 -07001134 {
1135 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1136 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001137 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001138 return;
1139 }
1140
1141 asyncResp->res.jsonValue["@odata.type"] =
1142 "#StorageControllerCollection.StorageControllerCollection";
1143 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001144 std::format("/redfish/v1/Systems/{}/Storage/1/Controllers",
1145 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Willy Tu61b1eb22023-03-14 11:29:50 -07001146 asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
1147
1148 constexpr std::array<std::string_view, 1> interfaces = {
1149 "xyz.openbmc_project.Inventory.Item.StorageController"};
1150 dbus::utility::getSubTreePaths(
1151 "/xyz/openbmc_project/inventory", 0, interfaces,
1152 [asyncResp](const boost::system::error_code& ec,
1153 const dbus::utility::MapperGetSubTreePathsResponse&
1154 controllerList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001155 populateStorageControllerCollection(asyncResp, ec, controllerList);
1156 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001157}
1158
Ed Tanous36d52332023-06-09 13:18:40 -07001159inline void handleSystemsStorageControllerGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001160 App& app, const crow::Request& req,
1161 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1162 const std::string& systemName, const std::string& controllerId)
1163{
1164 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1165 {
Ed Tanous62598e32023-07-17 17:06:25 -07001166 BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001167 return;
1168 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001169 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Willy Tu61b1eb22023-03-14 11:29:50 -07001170 {
1171 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1172 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001173 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001174 return;
1175 }
1176 constexpr std::array<std::string_view, 1> interfaces = {
1177 "xyz.openbmc_project.Inventory.Item.StorageController"};
1178 dbus::utility::getSubTree(
1179 "/xyz/openbmc_project/inventory", 0, interfaces,
1180 [asyncResp,
1181 controllerId](const boost::system::error_code& ec,
1182 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001183 getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
1184 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001185}
1186
1187inline void requestRoutesStorageControllerCollection(App& app)
1188{
1189 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
1190 .privileges(redfish::privileges::getStorageControllerCollection)
Ed Tanous36d52332023-06-09 13:18:40 -07001191 .methods(boost::beast::http::verb::get)(std::bind_front(
1192 handleSystemsStorageControllerCollectionGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001193}
1194
1195inline void requestRoutesStorageController(App& app)
1196{
1197 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
1198 .privileges(redfish::privileges::getStorageController)
1199 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -07001200 std::bind_front(handleSystemsStorageControllerGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001201}
1202
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001203} // namespace redfish