blob: e0ad737752f53640444b2749ffa70e82f154979d [file] [log] [blame]
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Willy Tu13451e32023-05-24 16:08:18 -070018#include "bmcweb_config.h"
19
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080021#include "dbus_utility.hpp"
John Edward Broadbente5029d82022-06-08 14:35:21 -070022#include "generated/enums/drive.hpp"
George Liudde9bc12023-02-22 09:35:51 +080023#include "generated/enums/protocol.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080024#include "human_sort.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080025#include "query.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080026#include "redfish_util.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080027#include "registries/privilege_registry.hpp"
Willy Tu5e577bc2022-07-26 00:41:55 +000028#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080029#include "utils/dbus_utils.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070030
George Liue99073f2022-12-09 11:06:16 +080031#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070032#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070033#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020034#include <sdbusplus/unpack_properties.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070035
George Liu7a1dbc42022-12-07 16:03:22 +080036#include <array>
Ed Tanous3544d2a2023-08-06 18:12:20 -070037#include <ranges>
George Liu7a1dbc42022-12-07 16:03:22 +080038#include <string_view>
39
Nikhil Potadea25aecc2019-08-23 16:35:26 -070040namespace redfish
41{
Ed Tanous36d52332023-06-09 13:18:40 -070042
43inline void handleSystemsStorageCollectionGet(
44 App& app, const crow::Request& req,
45 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
46 const std::string& systemName)
47{
48 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
49 {
50 return;
51 }
Ed Tanous253f11b2024-05-16 09:38:31 -070052 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous36d52332023-06-09 13:18:40 -070053 {
54 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
55 systemName);
56 return;
57 }
58
59 asyncResp->res.jsonValue["@odata.type"] =
60 "#StorageCollection.StorageCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -070061 asyncResp->res.jsonValue["@odata.id"] = std::format(
62 "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous36d52332023-06-09 13:18:40 -070063 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Willy Tu5e577bc2022-07-26 00:41:55 +000064
Patrick Williams5a39f772023-10-20 11:20:21 -050065 constexpr std::array<std::string_view, 1> interface{
66 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000067 collection_util::getCollectionMembers(
Ed Tanous253f11b2024-05-16 09:38:31 -070068 asyncResp,
69 boost::urls::format("/redfish/v1/Systems/{}/Storage",
70 BMCWEB_REDFISH_SYSTEM_URI_NAME),
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050071 interface, "/xyz/openbmc_project/inventory");
Willy Tu5e577bc2022-07-26 00:41:55 +000072}
73
74inline void handleStorageCollectionGet(
75 App& app, const crow::Request& req,
76 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
77{
78 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
79 {
80 return;
81 }
82 asyncResp->res.jsonValue["@odata.type"] =
83 "#StorageCollection.StorageCollection";
84 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Storage";
85 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Patrick Williams5a39f772023-10-20 11:20:21 -050086 constexpr std::array<std::string_view, 1> interface{
87 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000088 collection_util::getCollectionMembers(
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050089 asyncResp, boost::urls::format("/redfish/v1/Storage"), interface,
90 "/xyz/openbmc_project/inventory");
Ed Tanous36d52332023-06-09 13:18:40 -070091}
92
John Edward Broadbent7e860f12021-04-08 15:57:16 -070093inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070094{
Ed Tanous22d268c2022-05-19 09:39:07 -070095 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -070096 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070097 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -070098 std::bind_front(handleSystemsStorageCollectionGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +000099 BMCWEB_ROUTE(app, "/redfish/v1/Storage/")
100 .privileges(redfish::privileges::getStorageCollection)
101 .methods(boost::beast::http::verb::get)(
102 std::bind_front(handleStorageCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700103}
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700104
Ed Tanous36d52332023-06-09 13:18:40 -0700105inline void afterChassisDriveCollectionSubtree(
106 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous36d52332023-06-09 13:18:40 -0700107 const boost::system::error_code& ec,
108 const dbus::utility::MapperGetSubTreePathsResponse& driveList)
109{
110 if (ec)
111 {
Ed Tanous62598e32023-07-17 17:06:25 -0700112 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700113 messages::internalError(asyncResp->res);
114 return;
115 }
116
117 nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
118 driveArray = nlohmann::json::array();
119 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
120 count = 0;
121
Ed Tanous36d52332023-06-09 13:18:40 -0700122 for (const std::string& drive : driveList)
123 {
124 sdbusplus::message::object_path object(drive);
125 if (object.filename().empty())
126 {
Ed Tanous62598e32023-07-17 17:06:25 -0700127 BMCWEB_LOG_ERROR("Failed to find filename in {}", drive);
Ed Tanous36d52332023-06-09 13:18:40 -0700128 return;
129 }
130
131 nlohmann::json::object_t driveJson;
132 driveJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -0700133 "/redfish/v1/Systems/{}/Storage/1/Drives/{}",
134 BMCWEB_REDFISH_SYSTEM_URI_NAME, object.filename());
Ed Tanous36d52332023-06-09 13:18:40 -0700135 driveArray.emplace_back(std::move(driveJson));
136 }
137
138 count = driveArray.size();
139}
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500140inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Willy Tua85afbe2021-12-28 14:43:47 -0800141{
George Liu7a1dbc42022-12-07 16:03:22 +0800142 const std::array<std::string_view, 1> interfaces = {
143 "xyz.openbmc_project.Inventory.Item.Drive"};
144 dbus::utility::getSubTreePaths(
145 "/xyz/openbmc_project/inventory", 0, interfaces,
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500146 std::bind_front(afterChassisDriveCollectionSubtree, asyncResp));
Ed Tanous36d52332023-06-09 13:18:40 -0700147}
Willy Tua85afbe2021-12-28 14:43:47 -0800148
Willy Tu5e577bc2022-07-26 00:41:55 +0000149inline void afterSystemsStorageGetSubtree(
150 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
151 const std::string& storageId, const boost::system::error_code& ec,
152 const dbus::utility::MapperGetSubTreeResponse& subtree)
Ed Tanous36d52332023-06-09 13:18:40 -0700153{
Willy Tu5e577bc2022-07-26 00:41:55 +0000154 if (ec)
Ed Tanous36d52332023-06-09 13:18:40 -0700155 {
Ed Tanous62598e32023-07-17 17:06:25 -0700156 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000157 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
158 storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700159 return;
160 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700161 auto storage = std::ranges::find_if(
162 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000163 [&storageId](const std::pair<std::string,
164 dbus::utility::MapperServiceMap>& object) {
165 return sdbusplus::message::object_path(object.first).filename() ==
166 storageId;
Patrick Williams5a39f772023-10-20 11:20:21 -0500167 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000168 if (storage == subtree.end())
169 {
170 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
171 storageId);
172 return;
173 }
174
Ed Tanous36d52332023-06-09 13:18:40 -0700175 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
176 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -0700177 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
178 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700179 asyncResp->res.jsonValue["Name"] = "Storage";
Willy Tu5e577bc2022-07-26 00:41:55 +0000180 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous36d52332023-06-09 13:18:40 -0700181 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
Willy Tua85afbe2021-12-28 14:43:47 -0800182
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500183 getDrives(asyncResp);
Ed Tanous253f11b2024-05-16 09:38:31 -0700184 asyncResp->res.jsonValue["Controllers"]["@odata.id"] =
185 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}/Controllers",
186 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Willy Tu5e577bc2022-07-26 00:41:55 +0000187}
188
189inline void
190 handleSystemsStorageGet(App& app, const crow::Request& req,
191 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800192 const std::string& systemName,
Willy Tu5e577bc2022-07-26 00:41:55 +0000193 const std::string& storageId)
194{
195 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
196 {
197 return;
198 }
Ed Tanous25b54db2024-04-17 15:40:31 -0700199 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800200 {
201 // Option currently returns no systems. TBD
202 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
203 systemName);
204 return;
205 }
Willy Tu5e577bc2022-07-26 00:41:55 +0000206
207 constexpr std::array<std::string_view, 1> interfaces = {
208 "xyz.openbmc_project.Inventory.Item.Storage"};
209 dbus::utility::getSubTree(
210 "/xyz/openbmc_project/inventory", 0, interfaces,
211 std::bind_front(afterSystemsStorageGetSubtree, asyncResp, storageId));
212}
213
214inline void afterSubtree(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
215 const std::string& storageId,
216 const boost::system::error_code& ec,
217 const dbus::utility::MapperGetSubTreeResponse& subtree)
218{
219 if (ec)
220 {
Ed Tanous62598e32023-07-17 17:06:25 -0700221 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000222 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
223 storageId);
224 return;
225 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700226 auto storage = std::ranges::find_if(
227 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000228 [&storageId](const std::pair<std::string,
229 dbus::utility::MapperServiceMap>& object) {
230 return sdbusplus::message::object_path(object.first).filename() ==
231 storageId;
Patrick Williams5a39f772023-10-20 11:20:21 -0500232 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000233 if (storage == subtree.end())
234 {
235 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
236 storageId);
237 return;
238 }
239
240 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
241 asyncResp->res.jsonValue["@odata.id"] =
242 boost::urls::format("/redfish/v1/Storage/{}", storageId);
243 asyncResp->res.jsonValue["Name"] = "Storage";
244 asyncResp->res.jsonValue["Id"] = storageId;
245 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
246
247 // Storage subsystem to Storage link.
248 nlohmann::json::array_t storageServices;
249 nlohmann::json::object_t storageService;
250 storageService["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -0700251 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
252 BMCWEB_REDFISH_SYSTEM_URI_NAME, storageId);
Willy Tu5e577bc2022-07-26 00:41:55 +0000253 storageServices.emplace_back(storageService);
254 asyncResp->res.jsonValue["Links"]["StorageServices"] =
255 std::move(storageServices);
256 asyncResp->res.jsonValue["Links"]["StorageServices@odata.count"] = 1;
257}
258
259inline void
260 handleStorageGet(App& app, const crow::Request& req,
261 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
262 const std::string& storageId)
263{
264 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
265 {
Ed Tanous62598e32023-07-17 17:06:25 -0700266 BMCWEB_LOG_DEBUG("requestRoutesStorage setUpRedfishRoute failed");
Willy Tu5e577bc2022-07-26 00:41:55 +0000267 return;
268 }
269
270 constexpr std::array<std::string_view, 1> interfaces = {
271 "xyz.openbmc_project.Inventory.Item.Storage"};
272 dbus::utility::getSubTree(
273 "/xyz/openbmc_project/inventory", 0, interfaces,
274 std::bind_front(afterSubtree, asyncResp, storageId));
Willy Tua85afbe2021-12-28 14:43:47 -0800275}
276
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700277inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700278{
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800279 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700280 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -0700281 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700282 std::bind_front(handleSystemsStorageGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000283
284 BMCWEB_ROUTE(app, "/redfish/v1/Storage/<str>/")
285 .privileges(redfish::privileges::getStorage)
286 .methods(boost::beast::http::verb::get)(
287 std::bind_front(handleStorageGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700288}
289
Willy Tu03913172021-11-08 02:03:19 -0800290inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
291 const std::string& connectionName,
292 const std::string& path)
293{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200294 sdbusplus::asio::getAllProperties(
295 *crow::connections::systemBus, connectionName, path,
296 "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800297 [asyncResp](const boost::system::error_code& ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800298 const std::vector<
299 std::pair<std::string, dbus::utility::DbusVariantType>>&
300 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700301 if (ec)
302 {
303 // this interface isn't necessary
304 return;
305 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200306
307 const std::string* partNumber = nullptr;
308 const std::string* serialNumber = nullptr;
309 const std::string* manufacturer = nullptr;
310 const std::string* model = nullptr;
311
312 const bool success = sdbusplus::unpackPropertiesNoThrow(
313 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
314 partNumber, "SerialNumber", serialNumber, "Manufacturer",
315 manufacturer, "Model", model);
316
317 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200319 messages::internalError(asyncResp->res);
320 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700321 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200322
323 if (partNumber != nullptr)
324 {
325 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
326 }
327
328 if (serialNumber != nullptr)
329 {
330 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
331 }
332
333 if (manufacturer != nullptr)
334 {
335 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
336 }
337
338 if (model != nullptr)
339 {
340 asyncResp->res.jsonValue["Model"] = *model;
341 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500342 });
Willy Tu03913172021-11-08 02:03:19 -0800343}
344
345inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
346 const std::string& connectionName,
347 const std::string& path)
348{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700349 sdbusplus::asio::getProperty<bool>(
350 *crow::connections::systemBus, connectionName, path,
351 "xyz.openbmc_project.Inventory.Item", "Present",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800352 [asyncResp, path](const boost::system::error_code& ec,
Willy Tucef57e82022-12-15 16:42:02 -0800353 const bool isPresent) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700354 // this interface isn't necessary, only check it if
355 // we get a good return
356 if (ec)
357 {
358 return;
359 }
Willy Tu03913172021-11-08 02:03:19 -0800360
Willy Tucef57e82022-12-15 16:42:02 -0800361 if (!isPresent)
Ed Tanous002d39b2022-05-31 08:59:27 -0700362 {
Willy Tucef57e82022-12-15 16:42:02 -0800363 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
Ed Tanous002d39b2022-05-31 08:59:27 -0700364 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500365 });
Willy Tu03913172021-11-08 02:03:19 -0800366}
367
368inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
369 const std::string& connectionName,
370 const std::string& path)
371{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700372 sdbusplus::asio::getProperty<bool>(
373 *crow::connections::systemBus, connectionName, path,
374 "xyz.openbmc_project.State.Drive", "Rebuilding",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800375 [asyncResp](const boost::system::error_code& ec, const bool updating) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700376 // this interface isn't necessary, only check it
377 // if we get a good return
378 if (ec)
379 {
380 return;
381 }
Willy Tu03913172021-11-08 02:03:19 -0800382
Ed Tanous002d39b2022-05-31 08:59:27 -0700383 // updating and disabled in the backend shouldn't be
384 // able to be set at the same time, so we don't need
385 // to check for the race condition of these two
386 // calls
387 if (updating)
388 {
389 asyncResp->res.jsonValue["Status"]["State"] = "Updating";
390 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500391 });
Willy Tu03913172021-11-08 02:03:19 -0800392}
393
George Liudde9bc12023-02-22 09:35:51 +0800394inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800395{
396 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
397 {
George Liudde9bc12023-02-22 09:35:51 +0800398 return drive::MediaType::HDD;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800399 }
400 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
401 {
George Liudde9bc12023-02-22 09:35:51 +0800402 return drive::MediaType::SSD;
403 }
404 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
405 {
406 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800407 }
408
George Liudde9bc12023-02-22 09:35:51 +0800409 return drive::MediaType::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800410}
411
George Liudde9bc12023-02-22 09:35:51 +0800412inline std::optional<protocol::Protocol>
413 convertDriveProtocol(std::string_view proto)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800414{
415 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
416 {
George Liudde9bc12023-02-22 09:35:51 +0800417 return protocol::Protocol::SAS;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800418 }
419 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
420 {
George Liudde9bc12023-02-22 09:35:51 +0800421 return protocol::Protocol::SATA;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800422 }
423 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
424 {
George Liudde9bc12023-02-22 09:35:51 +0800425 return protocol::Protocol::NVMe;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800426 }
427 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
428 {
George Liudde9bc12023-02-22 09:35:51 +0800429 return protocol::Protocol::FC;
430 }
431 if (proto ==
432 "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
433 {
434 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800435 }
436
George Liudde9bc12023-02-22 09:35:51 +0800437 return protocol::Protocol::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800438}
439
440inline void
441 getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
442 const std::string& connectionName,
443 const std::string& path)
444{
445 sdbusplus::asio::getAllProperties(
446 *crow::connections::systemBus, connectionName, path,
447 "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) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700452 if (ec)
453 {
454 // this interface isn't required
455 return;
456 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700457 const std::string* encryptionStatus = nullptr;
458 const bool* isLocked = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700459 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
460 property : propertiesList)
461 {
462 const std::string& propertyName = property.first;
463 if (propertyName == "Type")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800464 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700465 const std::string* value =
466 std::get_if<std::string>(&property.second);
467 if (value == nullptr)
468 {
469 // illegal property
Ed Tanous62598e32023-07-17 17:06:25 -0700470 BMCWEB_LOG_ERROR("Illegal property: Type");
Ed Tanous002d39b2022-05-31 08:59:27 -0700471 messages::internalError(asyncResp->res);
472 return;
473 }
474
George Liudde9bc12023-02-22 09:35:51 +0800475 std::optional<drive::MediaType> mediaType =
476 convertDriveType(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700477 if (!mediaType)
478 {
Ed Tanous62598e32023-07-17 17:06:25 -0700479 BMCWEB_LOG_WARNING("UnknownDriveType Interface: {}",
480 *value);
George Liudde9bc12023-02-22 09:35:51 +0800481 continue;
482 }
483 if (*mediaType == drive::MediaType::Invalid)
484 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700485 messages::internalError(asyncResp->res);
486 return;
487 }
488
489 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800490 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700491 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800492 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 const uint64_t* capacity =
494 std::get_if<uint64_t>(&property.second);
495 if (capacity == nullptr)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800496 {
Ed Tanous62598e32023-07-17 17:06:25 -0700497 BMCWEB_LOG_ERROR("Illegal property: Capacity");
Ed Tanous002d39b2022-05-31 08:59:27 -0700498 messages::internalError(asyncResp->res);
499 return;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800500 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700501 if (*capacity == 0)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800502 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 // drive capacity not known
504 continue;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800505 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800506
Ed Tanous002d39b2022-05-31 08:59:27 -0700507 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800508 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700509 else if (propertyName == "Protocol")
510 {
511 const std::string* value =
512 std::get_if<std::string>(&property.second);
513 if (value == nullptr)
514 {
Ed Tanous62598e32023-07-17 17:06:25 -0700515 BMCWEB_LOG_ERROR("Illegal property: Protocol");
Ed Tanous002d39b2022-05-31 08:59:27 -0700516 messages::internalError(asyncResp->res);
517 return;
518 }
519
George Liudde9bc12023-02-22 09:35:51 +0800520 std::optional<protocol::Protocol> proto =
521 convertDriveProtocol(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700522 if (!proto)
523 {
Ed Tanous62598e32023-07-17 17:06:25 -0700524 BMCWEB_LOG_WARNING("Unknown DrivePrototype Interface: {}",
525 *value);
George Liudde9bc12023-02-22 09:35:51 +0800526 continue;
527 }
528 if (*proto == protocol::Protocol::Invalid)
529 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700530 messages::internalError(asyncResp->res);
531 return;
532 }
533 asyncResp->res.jsonValue["Protocol"] = *proto;
534 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700535 else if (propertyName == "PredictedMediaLifeLeftPercent")
536 {
537 const uint8_t* lifeLeft =
538 std::get_if<uint8_t>(&property.second);
539 if (lifeLeft == nullptr)
540 {
Ed Tanous62598e32023-07-17 17:06:25 -0700541 BMCWEB_LOG_ERROR(
542 "Illegal property: PredictedMediaLifeLeftPercent");
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700543 messages::internalError(asyncResp->res);
544 return;
545 }
546 // 255 means reading the value is not supported
547 if (*lifeLeft != 255)
548 {
549 asyncResp->res.jsonValue["PredictedMediaLifeLeftPercent"] =
550 *lifeLeft;
551 }
552 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700553 else if (propertyName == "EncryptionStatus")
554 {
555 encryptionStatus = std::get_if<std::string>(&property.second);
556 if (encryptionStatus == nullptr)
557 {
Ed Tanous62598e32023-07-17 17:06:25 -0700558 BMCWEB_LOG_ERROR("Illegal property: EncryptionStatus");
John Edward Broadbente5029d82022-06-08 14:35:21 -0700559 messages::internalError(asyncResp->res);
560 return;
561 }
562 }
563 else if (propertyName == "Locked")
564 {
565 isLocked = std::get_if<bool>(&property.second);
566 if (isLocked == nullptr)
567 {
Ed Tanous62598e32023-07-17 17:06:25 -0700568 BMCWEB_LOG_ERROR("Illegal property: Locked");
John Edward Broadbente5029d82022-06-08 14:35:21 -0700569 messages::internalError(asyncResp->res);
570 return;
571 }
572 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700573 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700574
575 if (encryptionStatus == nullptr || isLocked == nullptr ||
576 *encryptionStatus ==
Konda Reddy Kachanaa684c222024-01-09 02:04:37 +0000577 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Unknown")
John Edward Broadbente5029d82022-06-08 14:35:21 -0700578 {
579 return;
580 }
581 if (*encryptionStatus !=
Konda Reddy Kachanaa684c222024-01-09 02:04:37 +0000582 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Encrypted")
John Edward Broadbente5029d82022-06-08 14:35:21 -0700583 {
584 //"The drive is not currently encrypted."
585 asyncResp->res.jsonValue["EncryptionStatus"] =
586 drive::EncryptionStatus::Unencrypted;
587 return;
588 }
589 if (*isLocked)
590 {
591 //"The drive is currently encrypted and the data is not
592 // accessible to the user."
593 asyncResp->res.jsonValue["EncryptionStatus"] =
594 drive::EncryptionStatus::Locked;
595 return;
596 }
597 // if not locked
598 // "The drive is currently encrypted but the data is accessible
599 // to the user in unencrypted form."
600 asyncResp->res.jsonValue["EncryptionStatus"] =
601 drive::EncryptionStatus::Unlocked;
Patrick Williams5a39f772023-10-20 11:20:21 -0500602 });
Willy Tu19b8e9a2021-11-08 02:55:03 -0800603}
604
Nan Zhoub53dcd92022-06-21 17:47:50 +0000605static void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
606 const std::string& connectionName,
607 const std::string& path,
608 const std::vector<std::string>& interfaces)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700609{
610 for (const std::string& interface : interfaces)
611 {
612 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
613 {
614 getDriveAsset(asyncResp, connectionName, path);
615 }
616 else if (interface == "xyz.openbmc_project.Inventory.Item")
617 {
618 getDrivePresent(asyncResp, connectionName, path);
619 }
620 else if (interface == "xyz.openbmc_project.State.Drive")
621 {
622 getDriveState(asyncResp, connectionName, path);
623 }
624 else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
625 {
626 getDriveItemProperties(asyncResp, connectionName, path);
627 }
628 }
629}
630
Ed Tanous36d52332023-06-09 13:18:40 -0700631inline void afterGetSubtreeSystemsStorageDrive(
632 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
633 const std::string& driveId, const boost::system::error_code& ec,
634 const dbus::utility::MapperGetSubTreeResponse& subtree)
635{
636 if (ec)
637 {
Ed Tanous62598e32023-07-17 17:06:25 -0700638 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700639 messages::internalError(asyncResp->res);
640 return;
641 }
642
Ed Tanous3544d2a2023-08-06 18:12:20 -0700643 auto drive = std::ranges::find_if(
644 subtree,
Ed Tanous36d52332023-06-09 13:18:40 -0700645 [&driveId](const std::pair<std::string,
646 dbus::utility::MapperServiceMap>& object) {
647 return sdbusplus::message::object_path(object.first).filename() ==
648 driveId;
Patrick Williams5a39f772023-10-20 11:20:21 -0500649 });
Ed Tanous36d52332023-06-09 13:18:40 -0700650
651 if (drive == subtree.end())
652 {
653 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
654 return;
655 }
656
657 const std::string& path = drive->first;
658 const dbus::utility::MapperServiceMap& connectionNames = drive->second;
659
660 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
Ed Tanous253f11b2024-05-16 09:38:31 -0700661 asyncResp->res.jsonValue["@odata.id"] =
662 boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Drives/{}",
663 BMCWEB_REDFISH_SYSTEM_URI_NAME, driveId);
Ed Tanous36d52332023-06-09 13:18:40 -0700664 asyncResp->res.jsonValue["Name"] = driveId;
665 asyncResp->res.jsonValue["Id"] = driveId;
666
667 if (connectionNames.size() != 1)
668 {
Ed Tanous62598e32023-07-17 17:06:25 -0700669 BMCWEB_LOG_ERROR("Connection size {}, not equal to 1",
670 connectionNames.size());
Ed Tanous36d52332023-06-09 13:18:40 -0700671 messages::internalError(asyncResp->res);
672 return;
673 }
674
675 getMainChassisId(asyncResp,
676 [](const std::string& chassisId,
677 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
678 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
679 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
680 });
681
682 // default it to Enabled
683 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
684
Ed Tanous36d52332023-06-09 13:18:40 -0700685 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
686 connectionNames[0].second);
687}
688
689inline void handleSystemsStorageDriveGet(
690 App& app, const crow::Request& req,
691 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
692 const std::string& systemName, const std::string& driveId)
693{
694 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
695 {
696 return;
697 }
Ed Tanous25b54db2024-04-17 15:40:31 -0700698 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800699 {
700 // Option currently returns no systems. TBD
701 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
702 systemName);
703 return;
704 }
705
Ed Tanous253f11b2024-05-16 09:38:31 -0700706 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous36d52332023-06-09 13:18:40 -0700707 {
708 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
709 systemName);
710 return;
711 }
712
713 constexpr std::array<std::string_view, 1> interfaces = {
714 "xyz.openbmc_project.Inventory.Item.Drive"};
715 dbus::utility::getSubTree(
716 "/xyz/openbmc_project/inventory", 0, interfaces,
717 std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp,
718 driveId));
719}
720
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700721inline void requestRoutesDrive(App& app)
722{
Ed Tanous22d268c2022-05-19 09:39:07 -0700723 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700724 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700725 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700726 std::bind_front(handleSystemsStorageDriveGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700727}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700728
Ed Tanous36d52332023-06-09 13:18:40 -0700729inline void afterChassisDriveCollectionSubtreeGet(
730 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
731 const std::string& chassisId, const boost::system::error_code& ec,
732 const dbus::utility::MapperGetSubTreeResponse& subtree)
733{
734 if (ec)
735 {
736 if (ec == boost::system::errc::host_unreachable)
737 {
738 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
739 return;
740 }
741 messages::internalError(asyncResp->res);
742 return;
743 }
744
745 // Iterate over all retrieved ObjectPaths.
746 for (const auto& [path, connectionNames] : subtree)
747 {
748 sdbusplus::message::object_path objPath(path);
749 if (objPath.filename() != chassisId)
750 {
751 continue;
752 }
753
754 if (connectionNames.empty())
755 {
Ed Tanous62598e32023-07-17 17:06:25 -0700756 BMCWEB_LOG_ERROR("Got 0 Connection names");
Ed Tanous36d52332023-06-09 13:18:40 -0700757 continue;
758 }
759
760 asyncResp->res.jsonValue["@odata.type"] =
761 "#DriveCollection.DriveCollection";
762 asyncResp->res.jsonValue["@odata.id"] =
763 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
764 asyncResp->res.jsonValue["Name"] = "Drive Collection";
765
766 // Association lambda
767 dbus::utility::getAssociationEndPoints(
768 path + "/drive",
769 [asyncResp, chassisId](const boost::system::error_code& ec3,
770 const dbus::utility::MapperEndPoints& resp) {
771 if (ec3)
772 {
Ed Tanous62598e32023-07-17 17:06:25 -0700773 BMCWEB_LOG_ERROR("Error in chassis Drive association ");
Ed Tanous36d52332023-06-09 13:18:40 -0700774 }
775 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
776 // important if array is empty
777 members = nlohmann::json::array();
778
779 std::vector<std::string> leafNames;
780 for (const auto& drive : resp)
781 {
782 sdbusplus::message::object_path drivePath(drive);
783 leafNames.push_back(drivePath.filename());
784 }
785
Ed Tanous3544d2a2023-08-06 18:12:20 -0700786 std::ranges::sort(leafNames, AlphanumLess<std::string>());
Ed Tanous36d52332023-06-09 13:18:40 -0700787
788 for (const auto& leafName : leafNames)
789 {
790 nlohmann::json::object_t member;
791 member["@odata.id"] = boost::urls::format(
792 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, leafName);
793 members.emplace_back(std::move(member));
794 // navigation links will be registered in next patch set
795 }
796 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
Patrick Williams5a39f772023-10-20 11:20:21 -0500797 }); // end association lambda
Ed Tanous36d52332023-06-09 13:18:40 -0700798
Patrick Williams5a39f772023-10-20 11:20:21 -0500799 } // end Iterate over all retrieved ObjectPaths
Ed Tanous36d52332023-06-09 13:18:40 -0700800}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700801/**
802 * Chassis drives, this URL will show all the DriveCollection
803 * information
804 */
Nan Zhoub53dcd92022-06-21 17:47:50 +0000805inline void chassisDriveCollectionGet(
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700806 crow::App& app, const crow::Request& req,
807 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
808 const std::string& chassisId)
809{
Carson Labrado3ba00072022-06-06 19:40:56 +0000810 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700811 {
812 return;
813 }
814
815 // mapper call lambda
George Liue99073f2022-12-09 11:06:16 +0800816 constexpr std::array<std::string_view, 2> interfaces = {
817 "xyz.openbmc_project.Inventory.Item.Board",
818 "xyz.openbmc_project.Inventory.Item.Chassis"};
819 dbus::utility::getSubTree(
820 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous36d52332023-06-09 13:18:40 -0700821 std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp,
822 chassisId));
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700823}
824
825inline void requestRoutesChassisDrive(App& app)
826{
827 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
828 .privileges(redfish::privileges::getDriveCollection)
829 .methods(boost::beast::http::verb::get)(
830 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
831}
832
Nan Zhoub53dcd92022-06-21 17:47:50 +0000833inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
834 const std::string& chassisId,
835 const std::string& driveName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800836 const boost::system::error_code& ec,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000837 const dbus::utility::MapperGetSubTreeResponse& subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700838{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700839 if (ec)
840 {
Ed Tanous62598e32023-07-17 17:06:25 -0700841 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700842 messages::internalError(asyncResp->res);
843 return;
844 }
845
846 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000847 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700848 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700849 sdbusplus::message::object_path objPath(path);
850 if (objPath.filename() != driveName)
851 {
852 continue;
853 }
854
855 if (connectionNames.empty())
856 {
Ed Tanous62598e32023-07-17 17:06:25 -0700857 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700858 continue;
859 }
860
Ed Tanousef4c65b2023-04-24 15:28:50 -0700861 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
862 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700863
864 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700865 asyncResp->res.jsonValue["Name"] = driveName;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700866 asyncResp->res.jsonValue["Id"] = driveName;
867 // default it to Enabled
868 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
869
870 nlohmann::json::object_t linkChassisNav;
871 linkChassisNav["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700872 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700873 asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
874
875 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
876 connectionNames[0].second);
877 }
878}
879
Nan Zhoub53dcd92022-06-21 17:47:50 +0000880inline void
881 matchAndFillDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
882 const std::string& chassisId,
883 const std::string& driveName,
884 const std::vector<std::string>& resp)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700885{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700886 for (const std::string& drivePath : resp)
887 {
888 sdbusplus::message::object_path path(drivePath);
889 std::string leaf = path.filename();
890 if (leaf != driveName)
891 {
892 continue;
893 }
894 // mapper call drive
George Liue99073f2022-12-09 11:06:16 +0800895 constexpr std::array<std::string_view, 1> driveInterface = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700896 "xyz.openbmc_project.Inventory.Item.Drive"};
George Liue99073f2022-12-09 11:06:16 +0800897 dbus::utility::getSubTree(
898 "/xyz/openbmc_project/inventory", 0, driveInterface,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700899 [asyncResp, chassisId, driveName](
George Liue99073f2022-12-09 11:06:16 +0800900 const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700901 const dbus::utility::MapperGetSubTreeResponse& subtree) {
902 buildDrive(asyncResp, chassisId, driveName, ec, subtree);
Patrick Williams5a39f772023-10-20 11:20:21 -0500903 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700904 }
905}
906
Nan Zhoub53dcd92022-06-21 17:47:50 +0000907inline void
908 handleChassisDriveGet(crow::App& app, const crow::Request& req,
909 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
910 const std::string& chassisId,
911 const std::string& driveName)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700912{
Michal Orzel03810a12022-06-15 14:04:28 +0200913 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700914 {
915 return;
916 }
George Liue99073f2022-12-09 11:06:16 +0800917 constexpr std::array<std::string_view, 2> interfaces = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700918 "xyz.openbmc_project.Inventory.Item.Board",
919 "xyz.openbmc_project.Inventory.Item.Chassis"};
920
921 // mapper call chassis
George Liue99073f2022-12-09 11:06:16 +0800922 dbus::utility::getSubTree(
923 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700924 [asyncResp, chassisId,
George Liue99073f2022-12-09 11:06:16 +0800925 driveName](const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700926 const dbus::utility::MapperGetSubTreeResponse& subtree) {
927 if (ec)
928 {
929 messages::internalError(asyncResp->res);
930 return;
931 }
932
933 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000934 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700935 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700936 sdbusplus::message::object_path objPath(path);
937 if (objPath.filename() != chassisId)
938 {
939 continue;
940 }
941
942 if (connectionNames.empty())
943 {
Ed Tanous62598e32023-07-17 17:06:25 -0700944 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700945 continue;
946 }
947
George Liu6c3e9452023-03-03 13:55:29 +0800948 dbus::utility::getAssociationEndPoints(
949 path + "/drive",
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700950 [asyncResp, chassisId,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800951 driveName](const boost::system::error_code& ec3,
George Liu6c3e9452023-03-03 13:55:29 +0800952 const dbus::utility::MapperEndPoints& resp) {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700953 if (ec3)
954 {
955 return; // no drives = no failures
956 }
957 matchAndFillDrive(asyncResp, chassisId, driveName, resp);
Patrick Williams5a39f772023-10-20 11:20:21 -0500958 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700959 break;
960 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500961 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700962}
963
964/**
965 * This URL will show the drive interface for the specific drive in the chassis
966 */
967inline void requestRoutesChassisDriveName(App& app)
968{
969 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
970 .privileges(redfish::privileges::getChassis)
971 .methods(boost::beast::http::verb::get)(
972 std::bind_front(handleChassisDriveGet, std::ref(app)));
973}
974
Willy Tu61b1eb22023-03-14 11:29:50 -0700975inline void getStorageControllerAsset(
976 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
977 const boost::system::error_code& ec,
978 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
979 propertiesList)
980{
981 if (ec)
982 {
983 // this interface isn't necessary
Ed Tanous62598e32023-07-17 17:06:25 -0700984 BMCWEB_LOG_DEBUG("Failed to get StorageControllerAsset");
Willy Tu61b1eb22023-03-14 11:29:50 -0700985 return;
986 }
987
988 const std::string* partNumber = nullptr;
989 const std::string* serialNumber = nullptr;
990 const std::string* manufacturer = nullptr;
991 const std::string* model = nullptr;
992 if (!sdbusplus::unpackPropertiesNoThrow(
993 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
994 partNumber, "SerialNumber", serialNumber, "Manufacturer",
995 manufacturer, "Model", model))
996 {
997 messages::internalError(asyncResp->res);
998 return;
999 }
1000
1001 if (partNumber != nullptr)
1002 {
1003 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
1004 }
1005
1006 if (serialNumber != nullptr)
1007 {
1008 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
1009 }
1010
1011 if (manufacturer != nullptr)
1012 {
1013 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
1014 }
1015
1016 if (model != nullptr)
1017 {
1018 asyncResp->res.jsonValue["Model"] = *model;
1019 }
1020}
1021
1022inline void populateStorageController(
1023 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1024 const std::string& controllerId, const std::string& connectionName,
1025 const std::string& path)
1026{
1027 asyncResp->res.jsonValue["@odata.type"] =
1028 "#StorageController.v1_6_0.StorageController";
Ed Tanous253f11b2024-05-16 09:38:31 -07001029 asyncResp->res.jsonValue["@odata.id"] =
1030 boost::urls::format("/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
1031 BMCWEB_REDFISH_SYSTEM_URI_NAME, controllerId);
Willy Tu61b1eb22023-03-14 11:29:50 -07001032 asyncResp->res.jsonValue["Name"] = controllerId;
1033 asyncResp->res.jsonValue["Id"] = controllerId;
1034 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
1035
1036 sdbusplus::asio::getProperty<bool>(
1037 *crow::connections::systemBus, connectionName, path,
1038 "xyz.openbmc_project.Inventory.Item", "Present",
1039 [asyncResp](const boost::system::error_code& ec, bool isPresent) {
1040 // this interface isn't necessary, only check it
1041 // if we get a good return
1042 if (ec)
1043 {
Ed Tanous62598e32023-07-17 17:06:25 -07001044 BMCWEB_LOG_DEBUG("Failed to get Present property");
Willy Tu61b1eb22023-03-14 11:29:50 -07001045 return;
1046 }
1047 if (!isPresent)
1048 {
1049 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
1050 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001051 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001052
1053 sdbusplus::asio::getAllProperties(
1054 *crow::connections::systemBus, connectionName, path,
1055 "xyz.openbmc_project.Inventory.Decorator.Asset",
1056 [asyncResp](const boost::system::error_code& ec,
1057 const std::vector<
1058 std::pair<std::string, dbus::utility::DbusVariantType>>&
1059 propertiesList) {
1060 getStorageControllerAsset(asyncResp, ec, propertiesList);
Patrick Williams5a39f772023-10-20 11:20:21 -05001061 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001062}
1063
1064inline void getStorageControllerHandler(
1065 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1066 const std::string& controllerId, const boost::system::error_code& ec,
1067 const dbus::utility::MapperGetSubTreeResponse& subtree)
1068{
1069 if (ec || subtree.empty())
1070 {
1071 // doesn't have to be there
Ed Tanous62598e32023-07-17 17:06:25 -07001072 BMCWEB_LOG_DEBUG("Failed to handle StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001073 return;
1074 }
1075
1076 for (const auto& [path, interfaceDict] : subtree)
1077 {
1078 sdbusplus::message::object_path object(path);
1079 std::string id = object.filename();
1080 if (id.empty())
1081 {
Ed Tanous62598e32023-07-17 17:06:25 -07001082 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001083 return;
1084 }
1085 if (id != controllerId)
1086 {
1087 continue;
1088 }
1089
1090 if (interfaceDict.size() != 1)
1091 {
Ed Tanous62598e32023-07-17 17:06:25 -07001092 BMCWEB_LOG_ERROR("Connection size {}, greater than 1",
1093 interfaceDict.size());
Willy Tu61b1eb22023-03-14 11:29:50 -07001094 messages::internalError(asyncResp->res);
1095 return;
1096 }
1097
1098 const std::string& connectionName = interfaceDict.front().first;
1099 populateStorageController(asyncResp, controllerId, connectionName,
1100 path);
1101 }
1102}
1103
1104inline void populateStorageControllerCollection(
1105 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1106 const boost::system::error_code& ec,
1107 const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
1108{
1109 nlohmann::json::array_t members;
1110 if (ec || controllerList.empty())
1111 {
1112 asyncResp->res.jsonValue["Members"] = std::move(members);
1113 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous62598e32023-07-17 17:06:25 -07001114 BMCWEB_LOG_DEBUG("Failed to find any StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001115 return;
1116 }
1117
1118 for (const std::string& path : controllerList)
1119 {
1120 std::string id = sdbusplus::message::object_path(path).filename();
1121 if (id.empty())
1122 {
Ed Tanous62598e32023-07-17 17:06:25 -07001123 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001124 return;
1125 }
1126 nlohmann::json::object_t member;
1127 member["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001128 "/redfish/v1/Systems/{}/Storage/1/Controllers/{}",
1129 BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
Willy Tu61b1eb22023-03-14 11:29:50 -07001130 members.emplace_back(member);
1131 }
1132 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
1133 asyncResp->res.jsonValue["Members"] = std::move(members);
1134}
1135
Ed Tanous36d52332023-06-09 13:18:40 -07001136inline void handleSystemsStorageControllerCollectionGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001137 App& app, const crow::Request& req,
1138 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1139 const std::string& systemName)
1140{
1141 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1142 {
Ed Tanous62598e32023-07-17 17:06:25 -07001143 BMCWEB_LOG_DEBUG(
1144 "Failed to setup Redfish Route for StorageController Collection");
Willy Tu61b1eb22023-03-14 11:29:50 -07001145 return;
1146 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001147 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Willy Tu61b1eb22023-03-14 11:29:50 -07001148 {
1149 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1150 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001151 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001152 return;
1153 }
1154
1155 asyncResp->res.jsonValue["@odata.type"] =
1156 "#StorageControllerCollection.StorageControllerCollection";
1157 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001158 std::format("/redfish/v1/Systems/{}/Storage/1/Controllers",
1159 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Willy Tu61b1eb22023-03-14 11:29:50 -07001160 asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
1161
1162 constexpr std::array<std::string_view, 1> interfaces = {
1163 "xyz.openbmc_project.Inventory.Item.StorageController"};
1164 dbus::utility::getSubTreePaths(
1165 "/xyz/openbmc_project/inventory", 0, interfaces,
1166 [asyncResp](const boost::system::error_code& ec,
1167 const dbus::utility::MapperGetSubTreePathsResponse&
1168 controllerList) {
1169 populateStorageControllerCollection(asyncResp, ec, controllerList);
Patrick Williams5a39f772023-10-20 11:20:21 -05001170 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001171}
1172
Ed Tanous36d52332023-06-09 13:18:40 -07001173inline void handleSystemsStorageControllerGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001174 App& app, const crow::Request& req,
1175 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1176 const std::string& systemName, const std::string& controllerId)
1177{
1178 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1179 {
Ed Tanous62598e32023-07-17 17:06:25 -07001180 BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001181 return;
1182 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001183 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Willy Tu61b1eb22023-03-14 11:29:50 -07001184 {
1185 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1186 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001187 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001188 return;
1189 }
1190 constexpr std::array<std::string_view, 1> interfaces = {
1191 "xyz.openbmc_project.Inventory.Item.StorageController"};
1192 dbus::utility::getSubTree(
1193 "/xyz/openbmc_project/inventory", 0, interfaces,
1194 [asyncResp,
1195 controllerId](const boost::system::error_code& ec,
1196 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1197 getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
Patrick Williams5a39f772023-10-20 11:20:21 -05001198 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001199}
1200
1201inline void requestRoutesStorageControllerCollection(App& app)
1202{
1203 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
1204 .privileges(redfish::privileges::getStorageControllerCollection)
Ed Tanous36d52332023-06-09 13:18:40 -07001205 .methods(boost::beast::http::verb::get)(std::bind_front(
1206 handleSystemsStorageControllerCollectionGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001207}
1208
1209inline void requestRoutesStorageController(App& app)
1210{
1211 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
1212 .privileges(redfish::privileges::getStorageController)
1213 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -07001214 std::bind_front(handleSystemsStorageControllerGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001215}
1216
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001217} // namespace redfish