blob: 9438144c12935afa9acc5578fffc620592a1a43a [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"
James Feiste284a7c2019-11-20 16:20:23 -080025#include "openbmc_dbus_rest.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "query.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080027#include "redfish_util.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080028#include "registries/privilege_registry.hpp"
Willy Tu5e577bc2022-07-26 00:41:55 +000029#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080030#include "utils/dbus_utils.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070031
George Liue99073f2022-12-09 11:06:16 +080032#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070033#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070034#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020035#include <sdbusplus/unpack_properties.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070036
George Liu7a1dbc42022-12-07 16:03:22 +080037#include <array>
Ed Tanous3544d2a2023-08-06 18:12:20 -070038#include <ranges>
George Liu7a1dbc42022-12-07 16:03:22 +080039#include <string_view>
40
Nikhil Potadea25aecc2019-08-23 16:35:26 -070041namespace redfish
42{
Ed Tanous36d52332023-06-09 13:18:40 -070043
44inline void handleSystemsStorageCollectionGet(
45 App& app, const crow::Request& req,
46 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
47 const std::string& systemName)
48{
49 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
50 {
51 return;
52 }
53 if (systemName != "system")
54 {
55 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
56 systemName);
57 return;
58 }
59
60 asyncResp->res.jsonValue["@odata.type"] =
61 "#StorageCollection.StorageCollection";
62 asyncResp->res.jsonValue["@odata.id"] =
63 "/redfish/v1/Systems/system/Storage";
64 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Willy Tu5e577bc2022-07-26 00:41:55 +000065
Patrick Williams5a39f772023-10-20 11:20:21 -050066 constexpr std::array<std::string_view, 1> interface{
67 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000068 collection_util::getCollectionMembers(
69 asyncResp, boost::urls::format("/redfish/v1/Systems/system/Storage"),
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050070 interface, "/xyz/openbmc_project/inventory");
Willy Tu5e577bc2022-07-26 00:41:55 +000071}
72
73inline void handleStorageCollectionGet(
74 App& app, const crow::Request& req,
75 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
76{
77 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
78 {
79 return;
80 }
81 asyncResp->res.jsonValue["@odata.type"] =
82 "#StorageCollection.StorageCollection";
83 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Storage";
84 asyncResp->res.jsonValue["Name"] = "Storage Collection";
Patrick Williams5a39f772023-10-20 11:20:21 -050085 constexpr std::array<std::string_view, 1> interface{
86 "xyz.openbmc_project.Inventory.Item.Storage"};
Willy Tu5e577bc2022-07-26 00:41:55 +000087 collection_util::getCollectionMembers(
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050088 asyncResp, boost::urls::format("/redfish/v1/Storage"), interface,
89 "/xyz/openbmc_project/inventory");
Ed Tanous36d52332023-06-09 13:18:40 -070090}
91
John Edward Broadbent7e860f12021-04-08 15:57:16 -070092inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070093{
Ed Tanous22d268c2022-05-19 09:39:07 -070094 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -070095 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070096 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -070097 std::bind_front(handleSystemsStorageCollectionGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +000098 BMCWEB_ROUTE(app, "/redfish/v1/Storage/")
99 .privileges(redfish::privileges::getStorageCollection)
100 .methods(boost::beast::http::verb::get)(
101 std::bind_front(handleStorageCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700102}
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700103
Ed Tanous36d52332023-06-09 13:18:40 -0700104inline void afterChassisDriveCollectionSubtree(
105 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous36d52332023-06-09 13:18:40 -0700106 const boost::system::error_code& ec,
107 const dbus::utility::MapperGetSubTreePathsResponse& driveList)
108{
109 if (ec)
110 {
Ed Tanous62598e32023-07-17 17:06:25 -0700111 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700112 messages::internalError(asyncResp->res);
113 return;
114 }
115
116 nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
117 driveArray = nlohmann::json::array();
118 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
119 count = 0;
120
Ed Tanous36d52332023-06-09 13:18:40 -0700121 for (const std::string& drive : driveList)
122 {
123 sdbusplus::message::object_path object(drive);
124 if (object.filename().empty())
125 {
Ed Tanous62598e32023-07-17 17:06:25 -0700126 BMCWEB_LOG_ERROR("Failed to find filename in {}", drive);
Ed Tanous36d52332023-06-09 13:18:40 -0700127 return;
128 }
129
130 nlohmann::json::object_t driveJson;
131 driveJson["@odata.id"] = boost::urls::format(
132 "/redfish/v1/Systems/system/Storage/1/Drives/{}",
133 object.filename());
134 driveArray.emplace_back(std::move(driveJson));
135 }
136
137 count = driveArray.size();
138}
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500139inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Willy Tua85afbe2021-12-28 14:43:47 -0800140{
George Liu7a1dbc42022-12-07 16:03:22 +0800141 const std::array<std::string_view, 1> interfaces = {
142 "xyz.openbmc_project.Inventory.Item.Drive"};
143 dbus::utility::getSubTreePaths(
144 "/xyz/openbmc_project/inventory", 0, interfaces,
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500145 std::bind_front(afterChassisDriveCollectionSubtree, asyncResp));
Ed Tanous36d52332023-06-09 13:18:40 -0700146}
Willy Tua85afbe2021-12-28 14:43:47 -0800147
Willy Tu5e577bc2022-07-26 00:41:55 +0000148inline void afterSystemsStorageGetSubtree(
149 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
150 const std::string& storageId, const boost::system::error_code& ec,
151 const dbus::utility::MapperGetSubTreeResponse& subtree)
Ed Tanous36d52332023-06-09 13:18:40 -0700152{
Willy Tu5e577bc2022-07-26 00:41:55 +0000153 if (ec)
Ed Tanous36d52332023-06-09 13:18:40 -0700154 {
Ed Tanous62598e32023-07-17 17:06:25 -0700155 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000156 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
157 storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700158 return;
159 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700160 auto storage = std::ranges::find_if(
161 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000162 [&storageId](const std::pair<std::string,
163 dbus::utility::MapperServiceMap>& object) {
164 return sdbusplus::message::object_path(object.first).filename() ==
165 storageId;
Patrick Williams5a39f772023-10-20 11:20:21 -0500166 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000167 if (storage == subtree.end())
168 {
169 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
170 storageId);
171 return;
172 }
173
Ed Tanous36d52332023-06-09 13:18:40 -0700174 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
175 asyncResp->res.jsonValue["@odata.id"] =
Willy Tu5e577bc2022-07-26 00:41:55 +0000176 boost::urls::format("/redfish/v1/Systems/system/Storage/{}", storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700177 asyncResp->res.jsonValue["Name"] = "Storage";
Willy Tu5e577bc2022-07-26 00:41:55 +0000178 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous36d52332023-06-09 13:18:40 -0700179 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
Willy Tua85afbe2021-12-28 14:43:47 -0800180
Gunnar Mills7ac13cc2024-04-01 16:05:21 -0500181 getDrives(asyncResp);
Willy Tu5e577bc2022-07-26 00:41:55 +0000182 asyncResp->res.jsonValue["Controllers"]["@odata.id"] = boost::urls::format(
183 "/redfish/v1/Systems/system/Storage/{}/Controllers", storageId);
184}
185
186inline void
187 handleSystemsStorageGet(App& app, const crow::Request& req,
188 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800189 const std::string& systemName,
Willy Tu5e577bc2022-07-26 00:41:55 +0000190 const std::string& storageId)
191{
192 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
193 {
194 return;
195 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800196 if constexpr (bmcwebEnableMultiHost)
197 {
198 // Option currently returns no systems. TBD
199 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
200 systemName);
201 return;
202 }
Willy Tu5e577bc2022-07-26 00:41:55 +0000203
204 constexpr std::array<std::string_view, 1> interfaces = {
205 "xyz.openbmc_project.Inventory.Item.Storage"};
206 dbus::utility::getSubTree(
207 "/xyz/openbmc_project/inventory", 0, interfaces,
208 std::bind_front(afterSystemsStorageGetSubtree, asyncResp, storageId));
209}
210
211inline void afterSubtree(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
212 const std::string& storageId,
213 const boost::system::error_code& ec,
214 const dbus::utility::MapperGetSubTreeResponse& subtree)
215{
216 if (ec)
217 {
Ed Tanous62598e32023-07-17 17:06:25 -0700218 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000219 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
220 storageId);
221 return;
222 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700223 auto storage = std::ranges::find_if(
224 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000225 [&storageId](const std::pair<std::string,
226 dbus::utility::MapperServiceMap>& object) {
227 return sdbusplus::message::object_path(object.first).filename() ==
228 storageId;
Patrick Williams5a39f772023-10-20 11:20:21 -0500229 });
Willy Tu5e577bc2022-07-26 00:41:55 +0000230 if (storage == subtree.end())
231 {
232 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
233 storageId);
234 return;
235 }
236
237 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
238 asyncResp->res.jsonValue["@odata.id"] =
239 boost::urls::format("/redfish/v1/Storage/{}", storageId);
240 asyncResp->res.jsonValue["Name"] = "Storage";
241 asyncResp->res.jsonValue["Id"] = storageId;
242 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
243
244 // Storage subsystem to Storage link.
245 nlohmann::json::array_t storageServices;
246 nlohmann::json::object_t storageService;
247 storageService["@odata.id"] =
248 boost::urls::format("/redfish/v1/Systems/system/Storage/{}", storageId);
249 storageServices.emplace_back(storageService);
250 asyncResp->res.jsonValue["Links"]["StorageServices"] =
251 std::move(storageServices);
252 asyncResp->res.jsonValue["Links"]["StorageServices@odata.count"] = 1;
253}
254
255inline void
256 handleStorageGet(App& app, const crow::Request& req,
257 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
258 const std::string& storageId)
259{
260 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
261 {
Ed Tanous62598e32023-07-17 17:06:25 -0700262 BMCWEB_LOG_DEBUG("requestRoutesStorage setUpRedfishRoute failed");
Willy Tu5e577bc2022-07-26 00:41:55 +0000263 return;
264 }
265
266 constexpr std::array<std::string_view, 1> interfaces = {
267 "xyz.openbmc_project.Inventory.Item.Storage"};
268 dbus::utility::getSubTree(
269 "/xyz/openbmc_project/inventory", 0, interfaces,
270 std::bind_front(afterSubtree, asyncResp, storageId));
Willy Tua85afbe2021-12-28 14:43:47 -0800271}
272
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700273inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700274{
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800275 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700276 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -0700277 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700278 std::bind_front(handleSystemsStorageGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000279
280 BMCWEB_ROUTE(app, "/redfish/v1/Storage/<str>/")
281 .privileges(redfish::privileges::getStorage)
282 .methods(boost::beast::http::verb::get)(
283 std::bind_front(handleStorageGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700284}
285
Willy Tu03913172021-11-08 02:03:19 -0800286inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
287 const std::string& connectionName,
288 const std::string& path)
289{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200290 sdbusplus::asio::getAllProperties(
291 *crow::connections::systemBus, connectionName, path,
292 "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800293 [asyncResp](const boost::system::error_code& ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800294 const std::vector<
295 std::pair<std::string, dbus::utility::DbusVariantType>>&
296 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700297 if (ec)
298 {
299 // this interface isn't necessary
300 return;
301 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200302
303 const std::string* partNumber = nullptr;
304 const std::string* serialNumber = nullptr;
305 const std::string* manufacturer = nullptr;
306 const std::string* model = nullptr;
307
308 const bool success = sdbusplus::unpackPropertiesNoThrow(
309 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
310 partNumber, "SerialNumber", serialNumber, "Manufacturer",
311 manufacturer, "Model", model);
312
313 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700314 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200315 messages::internalError(asyncResp->res);
316 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700317 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200318
319 if (partNumber != nullptr)
320 {
321 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
322 }
323
324 if (serialNumber != nullptr)
325 {
326 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
327 }
328
329 if (manufacturer != nullptr)
330 {
331 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
332 }
333
334 if (model != nullptr)
335 {
336 asyncResp->res.jsonValue["Model"] = *model;
337 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500338 });
Willy Tu03913172021-11-08 02:03:19 -0800339}
340
341inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
342 const std::string& connectionName,
343 const std::string& path)
344{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700345 sdbusplus::asio::getProperty<bool>(
346 *crow::connections::systemBus, connectionName, path,
347 "xyz.openbmc_project.Inventory.Item", "Present",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800348 [asyncResp, path](const boost::system::error_code& ec,
Willy Tucef57e82022-12-15 16:42:02 -0800349 const bool isPresent) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700350 // this interface isn't necessary, only check it if
351 // we get a good return
352 if (ec)
353 {
354 return;
355 }
Willy Tu03913172021-11-08 02:03:19 -0800356
Willy Tucef57e82022-12-15 16:42:02 -0800357 if (!isPresent)
Ed Tanous002d39b2022-05-31 08:59:27 -0700358 {
Willy Tucef57e82022-12-15 16:42:02 -0800359 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
Ed Tanous002d39b2022-05-31 08:59:27 -0700360 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500361 });
Willy Tu03913172021-11-08 02:03:19 -0800362}
363
364inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
365 const std::string& connectionName,
366 const std::string& path)
367{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700368 sdbusplus::asio::getProperty<bool>(
369 *crow::connections::systemBus, connectionName, path,
370 "xyz.openbmc_project.State.Drive", "Rebuilding",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800371 [asyncResp](const boost::system::error_code& ec, const bool updating) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700372 // this interface isn't necessary, only check it
373 // if we get a good return
374 if (ec)
375 {
376 return;
377 }
Willy Tu03913172021-11-08 02:03:19 -0800378
Ed Tanous002d39b2022-05-31 08:59:27 -0700379 // updating and disabled in the backend shouldn't be
380 // able to be set at the same time, so we don't need
381 // to check for the race condition of these two
382 // calls
383 if (updating)
384 {
385 asyncResp->res.jsonValue["Status"]["State"] = "Updating";
386 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500387 });
Willy Tu03913172021-11-08 02:03:19 -0800388}
389
George Liudde9bc12023-02-22 09:35:51 +0800390inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800391{
392 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
393 {
George Liudde9bc12023-02-22 09:35:51 +0800394 return drive::MediaType::HDD;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800395 }
396 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
397 {
George Liudde9bc12023-02-22 09:35:51 +0800398 return drive::MediaType::SSD;
399 }
400 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
401 {
402 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800403 }
404
George Liudde9bc12023-02-22 09:35:51 +0800405 return drive::MediaType::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800406}
407
George Liudde9bc12023-02-22 09:35:51 +0800408inline std::optional<protocol::Protocol>
409 convertDriveProtocol(std::string_view proto)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800410{
411 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
412 {
George Liudde9bc12023-02-22 09:35:51 +0800413 return protocol::Protocol::SAS;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800414 }
415 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
416 {
George Liudde9bc12023-02-22 09:35:51 +0800417 return protocol::Protocol::SATA;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800418 }
419 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
420 {
George Liudde9bc12023-02-22 09:35:51 +0800421 return protocol::Protocol::NVMe;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800422 }
423 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
424 {
George Liudde9bc12023-02-22 09:35:51 +0800425 return protocol::Protocol::FC;
426 }
427 if (proto ==
428 "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
429 {
430 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800431 }
432
George Liudde9bc12023-02-22 09:35:51 +0800433 return protocol::Protocol::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800434}
435
436inline void
437 getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
438 const std::string& connectionName,
439 const std::string& path)
440{
441 sdbusplus::asio::getAllProperties(
442 *crow::connections::systemBus, connectionName, path,
443 "xyz.openbmc_project.Inventory.Item.Drive",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800444 [asyncResp](const boost::system::error_code& ec,
Willy Tu19b8e9a2021-11-08 02:55:03 -0800445 const std::vector<
446 std::pair<std::string, dbus::utility::DbusVariantType>>&
447 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700448 if (ec)
449 {
450 // this interface isn't required
451 return;
452 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700453 const std::string* encryptionStatus = nullptr;
454 const bool* isLocked = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700455 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
456 property : propertiesList)
457 {
458 const std::string& propertyName = property.first;
459 if (propertyName == "Type")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800460 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700461 const std::string* value =
462 std::get_if<std::string>(&property.second);
463 if (value == nullptr)
464 {
465 // illegal property
Ed Tanous62598e32023-07-17 17:06:25 -0700466 BMCWEB_LOG_ERROR("Illegal property: Type");
Ed Tanous002d39b2022-05-31 08:59:27 -0700467 messages::internalError(asyncResp->res);
468 return;
469 }
470
George Liudde9bc12023-02-22 09:35:51 +0800471 std::optional<drive::MediaType> mediaType =
472 convertDriveType(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700473 if (!mediaType)
474 {
Ed Tanous62598e32023-07-17 17:06:25 -0700475 BMCWEB_LOG_WARNING("UnknownDriveType Interface: {}",
476 *value);
George Liudde9bc12023-02-22 09:35:51 +0800477 continue;
478 }
479 if (*mediaType == drive::MediaType::Invalid)
480 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700481 messages::internalError(asyncResp->res);
482 return;
483 }
484
485 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800486 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700487 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800488 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700489 const uint64_t* capacity =
490 std::get_if<uint64_t>(&property.second);
491 if (capacity == nullptr)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800492 {
Ed Tanous62598e32023-07-17 17:06:25 -0700493 BMCWEB_LOG_ERROR("Illegal property: Capacity");
Ed Tanous002d39b2022-05-31 08:59:27 -0700494 messages::internalError(asyncResp->res);
495 return;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800496 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700497 if (*capacity == 0)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800498 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700499 // drive capacity not known
500 continue;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800501 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800502
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800504 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700505 else if (propertyName == "Protocol")
506 {
507 const std::string* value =
508 std::get_if<std::string>(&property.second);
509 if (value == nullptr)
510 {
Ed Tanous62598e32023-07-17 17:06:25 -0700511 BMCWEB_LOG_ERROR("Illegal property: Protocol");
Ed Tanous002d39b2022-05-31 08:59:27 -0700512 messages::internalError(asyncResp->res);
513 return;
514 }
515
George Liudde9bc12023-02-22 09:35:51 +0800516 std::optional<protocol::Protocol> proto =
517 convertDriveProtocol(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700518 if (!proto)
519 {
Ed Tanous62598e32023-07-17 17:06:25 -0700520 BMCWEB_LOG_WARNING("Unknown DrivePrototype Interface: {}",
521 *value);
George Liudde9bc12023-02-22 09:35:51 +0800522 continue;
523 }
524 if (*proto == protocol::Protocol::Invalid)
525 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700526 messages::internalError(asyncResp->res);
527 return;
528 }
529 asyncResp->res.jsonValue["Protocol"] = *proto;
530 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700531 else if (propertyName == "PredictedMediaLifeLeftPercent")
532 {
533 const uint8_t* lifeLeft =
534 std::get_if<uint8_t>(&property.second);
535 if (lifeLeft == nullptr)
536 {
Ed Tanous62598e32023-07-17 17:06:25 -0700537 BMCWEB_LOG_ERROR(
538 "Illegal property: PredictedMediaLifeLeftPercent");
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700539 messages::internalError(asyncResp->res);
540 return;
541 }
542 // 255 means reading the value is not supported
543 if (*lifeLeft != 255)
544 {
545 asyncResp->res.jsonValue["PredictedMediaLifeLeftPercent"] =
546 *lifeLeft;
547 }
548 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700549 else if (propertyName == "EncryptionStatus")
550 {
551 encryptionStatus = std::get_if<std::string>(&property.second);
552 if (encryptionStatus == nullptr)
553 {
Ed Tanous62598e32023-07-17 17:06:25 -0700554 BMCWEB_LOG_ERROR("Illegal property: EncryptionStatus");
John Edward Broadbente5029d82022-06-08 14:35:21 -0700555 messages::internalError(asyncResp->res);
556 return;
557 }
558 }
559 else if (propertyName == "Locked")
560 {
561 isLocked = std::get_if<bool>(&property.second);
562 if (isLocked == nullptr)
563 {
Ed Tanous62598e32023-07-17 17:06:25 -0700564 BMCWEB_LOG_ERROR("Illegal property: Locked");
John Edward Broadbente5029d82022-06-08 14:35:21 -0700565 messages::internalError(asyncResp->res);
566 return;
567 }
568 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700569 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700570
571 if (encryptionStatus == nullptr || isLocked == nullptr ||
572 *encryptionStatus ==
Konda Reddy Kachanaa684c222024-01-09 02:04:37 +0000573 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Unknown")
John Edward Broadbente5029d82022-06-08 14:35:21 -0700574 {
575 return;
576 }
577 if (*encryptionStatus !=
Konda Reddy Kachanaa684c222024-01-09 02:04:37 +0000578 "xyz.openbmc_project.Inventory.Item.Drive.DriveEncryptionState.Encrypted")
John Edward Broadbente5029d82022-06-08 14:35:21 -0700579 {
580 //"The drive is not currently encrypted."
581 asyncResp->res.jsonValue["EncryptionStatus"] =
582 drive::EncryptionStatus::Unencrypted;
583 return;
584 }
585 if (*isLocked)
586 {
587 //"The drive is currently encrypted and the data is not
588 // accessible to the user."
589 asyncResp->res.jsonValue["EncryptionStatus"] =
590 drive::EncryptionStatus::Locked;
591 return;
592 }
593 // if not locked
594 // "The drive is currently encrypted but the data is accessible
595 // to the user in unencrypted form."
596 asyncResp->res.jsonValue["EncryptionStatus"] =
597 drive::EncryptionStatus::Unlocked;
Patrick Williams5a39f772023-10-20 11:20:21 -0500598 });
Willy Tu19b8e9a2021-11-08 02:55:03 -0800599}
600
Nan Zhoub53dcd92022-06-21 17:47:50 +0000601static void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
602 const std::string& connectionName,
603 const std::string& path,
604 const std::vector<std::string>& interfaces)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700605{
606 for (const std::string& interface : interfaces)
607 {
608 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
609 {
610 getDriveAsset(asyncResp, connectionName, path);
611 }
612 else if (interface == "xyz.openbmc_project.Inventory.Item")
613 {
614 getDrivePresent(asyncResp, connectionName, path);
615 }
616 else if (interface == "xyz.openbmc_project.State.Drive")
617 {
618 getDriveState(asyncResp, connectionName, path);
619 }
620 else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
621 {
622 getDriveItemProperties(asyncResp, connectionName, path);
623 }
624 }
625}
626
Ed Tanous36d52332023-06-09 13:18:40 -0700627inline void afterGetSubtreeSystemsStorageDrive(
628 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
629 const std::string& driveId, const boost::system::error_code& ec,
630 const dbus::utility::MapperGetSubTreeResponse& subtree)
631{
632 if (ec)
633 {
Ed Tanous62598e32023-07-17 17:06:25 -0700634 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700635 messages::internalError(asyncResp->res);
636 return;
637 }
638
Ed Tanous3544d2a2023-08-06 18:12:20 -0700639 auto drive = std::ranges::find_if(
640 subtree,
Ed Tanous36d52332023-06-09 13:18:40 -0700641 [&driveId](const std::pair<std::string,
642 dbus::utility::MapperServiceMap>& object) {
643 return sdbusplus::message::object_path(object.first).filename() ==
644 driveId;
Patrick Williams5a39f772023-10-20 11:20:21 -0500645 });
Ed Tanous36d52332023-06-09 13:18:40 -0700646
647 if (drive == subtree.end())
648 {
649 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
650 return;
651 }
652
653 const std::string& path = drive->first;
654 const dbus::utility::MapperServiceMap& connectionNames = drive->second;
655
656 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
657 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
658 "/redfish/v1/Systems/system/Storage/1/Drives/{}", driveId);
659 asyncResp->res.jsonValue["Name"] = driveId;
660 asyncResp->res.jsonValue["Id"] = driveId;
661
662 if (connectionNames.size() != 1)
663 {
Ed Tanous62598e32023-07-17 17:06:25 -0700664 BMCWEB_LOG_ERROR("Connection size {}, not equal to 1",
665 connectionNames.size());
Ed Tanous36d52332023-06-09 13:18:40 -0700666 messages::internalError(asyncResp->res);
667 return;
668 }
669
670 getMainChassisId(asyncResp,
671 [](const std::string& chassisId,
672 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
673 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
674 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
675 });
676
677 // default it to Enabled
678 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
679
Ed Tanous36d52332023-06-09 13:18:40 -0700680 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
681 connectionNames[0].second);
682}
683
684inline void handleSystemsStorageDriveGet(
685 App& app, const crow::Request& req,
686 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
687 const std::string& systemName, const std::string& driveId)
688{
689 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
690 {
691 return;
692 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800693 if constexpr (bmcwebEnableMultiHost)
694 {
695 // Option currently returns no systems. TBD
696 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
697 systemName);
698 return;
699 }
700
Ed Tanous36d52332023-06-09 13:18:40 -0700701 if (systemName != "system")
702 {
703 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
704 systemName);
705 return;
706 }
707
708 constexpr std::array<std::string_view, 1> interfaces = {
709 "xyz.openbmc_project.Inventory.Item.Drive"};
710 dbus::utility::getSubTree(
711 "/xyz/openbmc_project/inventory", 0, interfaces,
712 std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp,
713 driveId));
714}
715
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700716inline void requestRoutesDrive(App& app)
717{
Ed Tanous22d268c2022-05-19 09:39:07 -0700718 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700719 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700720 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700721 std::bind_front(handleSystemsStorageDriveGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700722}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700723
Ed Tanous36d52332023-06-09 13:18:40 -0700724inline void afterChassisDriveCollectionSubtreeGet(
725 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
726 const std::string& chassisId, const boost::system::error_code& ec,
727 const dbus::utility::MapperGetSubTreeResponse& subtree)
728{
729 if (ec)
730 {
731 if (ec == boost::system::errc::host_unreachable)
732 {
733 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
734 return;
735 }
736 messages::internalError(asyncResp->res);
737 return;
738 }
739
740 // Iterate over all retrieved ObjectPaths.
741 for (const auto& [path, connectionNames] : subtree)
742 {
743 sdbusplus::message::object_path objPath(path);
744 if (objPath.filename() != chassisId)
745 {
746 continue;
747 }
748
749 if (connectionNames.empty())
750 {
Ed Tanous62598e32023-07-17 17:06:25 -0700751 BMCWEB_LOG_ERROR("Got 0 Connection names");
Ed Tanous36d52332023-06-09 13:18:40 -0700752 continue;
753 }
754
755 asyncResp->res.jsonValue["@odata.type"] =
756 "#DriveCollection.DriveCollection";
757 asyncResp->res.jsonValue["@odata.id"] =
758 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
759 asyncResp->res.jsonValue["Name"] = "Drive Collection";
760
761 // Association lambda
762 dbus::utility::getAssociationEndPoints(
763 path + "/drive",
764 [asyncResp, chassisId](const boost::system::error_code& ec3,
765 const dbus::utility::MapperEndPoints& resp) {
766 if (ec3)
767 {
Ed Tanous62598e32023-07-17 17:06:25 -0700768 BMCWEB_LOG_ERROR("Error in chassis Drive association ");
Ed Tanous36d52332023-06-09 13:18:40 -0700769 }
770 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
771 // important if array is empty
772 members = nlohmann::json::array();
773
774 std::vector<std::string> leafNames;
775 for (const auto& drive : resp)
776 {
777 sdbusplus::message::object_path drivePath(drive);
778 leafNames.push_back(drivePath.filename());
779 }
780
Ed Tanous3544d2a2023-08-06 18:12:20 -0700781 std::ranges::sort(leafNames, AlphanumLess<std::string>());
Ed Tanous36d52332023-06-09 13:18:40 -0700782
783 for (const auto& leafName : leafNames)
784 {
785 nlohmann::json::object_t member;
786 member["@odata.id"] = boost::urls::format(
787 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, leafName);
788 members.emplace_back(std::move(member));
789 // navigation links will be registered in next patch set
790 }
791 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
Patrick Williams5a39f772023-10-20 11:20:21 -0500792 }); // end association lambda
Ed Tanous36d52332023-06-09 13:18:40 -0700793
Patrick Williams5a39f772023-10-20 11:20:21 -0500794 } // end Iterate over all retrieved ObjectPaths
Ed Tanous36d52332023-06-09 13:18:40 -0700795}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700796/**
797 * Chassis drives, this URL will show all the DriveCollection
798 * information
799 */
Nan Zhoub53dcd92022-06-21 17:47:50 +0000800inline void chassisDriveCollectionGet(
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700801 crow::App& app, const crow::Request& req,
802 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
803 const std::string& chassisId)
804{
Carson Labrado3ba00072022-06-06 19:40:56 +0000805 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700806 {
807 return;
808 }
809
810 // mapper call lambda
George Liue99073f2022-12-09 11:06:16 +0800811 constexpr std::array<std::string_view, 2> interfaces = {
812 "xyz.openbmc_project.Inventory.Item.Board",
813 "xyz.openbmc_project.Inventory.Item.Chassis"};
814 dbus::utility::getSubTree(
815 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous36d52332023-06-09 13:18:40 -0700816 std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp,
817 chassisId));
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700818}
819
820inline void requestRoutesChassisDrive(App& app)
821{
822 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
823 .privileges(redfish::privileges::getDriveCollection)
824 .methods(boost::beast::http::verb::get)(
825 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
826}
827
Nan Zhoub53dcd92022-06-21 17:47:50 +0000828inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
829 const std::string& chassisId,
830 const std::string& driveName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800831 const boost::system::error_code& ec,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000832 const dbus::utility::MapperGetSubTreeResponse& subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700833{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700834 if (ec)
835 {
Ed Tanous62598e32023-07-17 17:06:25 -0700836 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700837 messages::internalError(asyncResp->res);
838 return;
839 }
840
841 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000842 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700843 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700844 sdbusplus::message::object_path objPath(path);
845 if (objPath.filename() != driveName)
846 {
847 continue;
848 }
849
850 if (connectionNames.empty())
851 {
Ed Tanous62598e32023-07-17 17:06:25 -0700852 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700853 continue;
854 }
855
Ed Tanousef4c65b2023-04-24 15:28:50 -0700856 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
857 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700858
859 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700860 asyncResp->res.jsonValue["Name"] = driveName;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700861 asyncResp->res.jsonValue["Id"] = driveName;
862 // default it to Enabled
863 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
864
865 nlohmann::json::object_t linkChassisNav;
866 linkChassisNav["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700867 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700868 asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
869
870 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
871 connectionNames[0].second);
872 }
873}
874
Nan Zhoub53dcd92022-06-21 17:47:50 +0000875inline void
876 matchAndFillDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
877 const std::string& chassisId,
878 const std::string& driveName,
879 const std::vector<std::string>& resp)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700880{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700881 for (const std::string& drivePath : resp)
882 {
883 sdbusplus::message::object_path path(drivePath);
884 std::string leaf = path.filename();
885 if (leaf != driveName)
886 {
887 continue;
888 }
889 // mapper call drive
George Liue99073f2022-12-09 11:06:16 +0800890 constexpr std::array<std::string_view, 1> driveInterface = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700891 "xyz.openbmc_project.Inventory.Item.Drive"};
George Liue99073f2022-12-09 11:06:16 +0800892 dbus::utility::getSubTree(
893 "/xyz/openbmc_project/inventory", 0, driveInterface,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700894 [asyncResp, chassisId, driveName](
George Liue99073f2022-12-09 11:06:16 +0800895 const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700896 const dbus::utility::MapperGetSubTreeResponse& subtree) {
897 buildDrive(asyncResp, chassisId, driveName, ec, subtree);
Patrick Williams5a39f772023-10-20 11:20:21 -0500898 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700899 }
900}
901
Nan Zhoub53dcd92022-06-21 17:47:50 +0000902inline void
903 handleChassisDriveGet(crow::App& app, const crow::Request& req,
904 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
905 const std::string& chassisId,
906 const std::string& driveName)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700907{
Michal Orzel03810a12022-06-15 14:04:28 +0200908 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700909 {
910 return;
911 }
George Liue99073f2022-12-09 11:06:16 +0800912 constexpr std::array<std::string_view, 2> interfaces = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700913 "xyz.openbmc_project.Inventory.Item.Board",
914 "xyz.openbmc_project.Inventory.Item.Chassis"};
915
916 // mapper call chassis
George Liue99073f2022-12-09 11:06:16 +0800917 dbus::utility::getSubTree(
918 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700919 [asyncResp, chassisId,
George Liue99073f2022-12-09 11:06:16 +0800920 driveName](const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700921 const dbus::utility::MapperGetSubTreeResponse& subtree) {
922 if (ec)
923 {
924 messages::internalError(asyncResp->res);
925 return;
926 }
927
928 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000929 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700930 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700931 sdbusplus::message::object_path objPath(path);
932 if (objPath.filename() != chassisId)
933 {
934 continue;
935 }
936
937 if (connectionNames.empty())
938 {
Ed Tanous62598e32023-07-17 17:06:25 -0700939 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700940 continue;
941 }
942
George Liu6c3e9452023-03-03 13:55:29 +0800943 dbus::utility::getAssociationEndPoints(
944 path + "/drive",
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700945 [asyncResp, chassisId,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800946 driveName](const boost::system::error_code& ec3,
George Liu6c3e9452023-03-03 13:55:29 +0800947 const dbus::utility::MapperEndPoints& resp) {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700948 if (ec3)
949 {
950 return; // no drives = no failures
951 }
952 matchAndFillDrive(asyncResp, chassisId, driveName, resp);
Patrick Williams5a39f772023-10-20 11:20:21 -0500953 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700954 break;
955 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500956 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700957}
958
959/**
960 * This URL will show the drive interface for the specific drive in the chassis
961 */
962inline void requestRoutesChassisDriveName(App& app)
963{
964 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
965 .privileges(redfish::privileges::getChassis)
966 .methods(boost::beast::http::verb::get)(
967 std::bind_front(handleChassisDriveGet, std::ref(app)));
968}
969
Willy Tu61b1eb22023-03-14 11:29:50 -0700970inline void getStorageControllerAsset(
971 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
972 const boost::system::error_code& ec,
973 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
974 propertiesList)
975{
976 if (ec)
977 {
978 // this interface isn't necessary
Ed Tanous62598e32023-07-17 17:06:25 -0700979 BMCWEB_LOG_DEBUG("Failed to get StorageControllerAsset");
Willy Tu61b1eb22023-03-14 11:29:50 -0700980 return;
981 }
982
983 const std::string* partNumber = nullptr;
984 const std::string* serialNumber = nullptr;
985 const std::string* manufacturer = nullptr;
986 const std::string* model = nullptr;
987 if (!sdbusplus::unpackPropertiesNoThrow(
988 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
989 partNumber, "SerialNumber", serialNumber, "Manufacturer",
990 manufacturer, "Model", model))
991 {
992 messages::internalError(asyncResp->res);
993 return;
994 }
995
996 if (partNumber != nullptr)
997 {
998 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
999 }
1000
1001 if (serialNumber != nullptr)
1002 {
1003 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
1004 }
1005
1006 if (manufacturer != nullptr)
1007 {
1008 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
1009 }
1010
1011 if (model != nullptr)
1012 {
1013 asyncResp->res.jsonValue["Model"] = *model;
1014 }
1015}
1016
1017inline void populateStorageController(
1018 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1019 const std::string& controllerId, const std::string& connectionName,
1020 const std::string& path)
1021{
1022 asyncResp->res.jsonValue["@odata.type"] =
1023 "#StorageController.v1_6_0.StorageController";
1024 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1025 "/redfish/v1/Systems/system/Storage/1/Controllers/{}", controllerId);
1026 asyncResp->res.jsonValue["Name"] = controllerId;
1027 asyncResp->res.jsonValue["Id"] = controllerId;
1028 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
1029
1030 sdbusplus::asio::getProperty<bool>(
1031 *crow::connections::systemBus, connectionName, path,
1032 "xyz.openbmc_project.Inventory.Item", "Present",
1033 [asyncResp](const boost::system::error_code& ec, bool isPresent) {
1034 // this interface isn't necessary, only check it
1035 // if we get a good return
1036 if (ec)
1037 {
Ed Tanous62598e32023-07-17 17:06:25 -07001038 BMCWEB_LOG_DEBUG("Failed to get Present property");
Willy Tu61b1eb22023-03-14 11:29:50 -07001039 return;
1040 }
1041 if (!isPresent)
1042 {
1043 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
1044 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001045 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001046
1047 sdbusplus::asio::getAllProperties(
1048 *crow::connections::systemBus, connectionName, path,
1049 "xyz.openbmc_project.Inventory.Decorator.Asset",
1050 [asyncResp](const boost::system::error_code& ec,
1051 const std::vector<
1052 std::pair<std::string, dbus::utility::DbusVariantType>>&
1053 propertiesList) {
1054 getStorageControllerAsset(asyncResp, ec, propertiesList);
Patrick Williams5a39f772023-10-20 11:20:21 -05001055 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001056}
1057
1058inline void getStorageControllerHandler(
1059 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1060 const std::string& controllerId, const boost::system::error_code& ec,
1061 const dbus::utility::MapperGetSubTreeResponse& subtree)
1062{
1063 if (ec || subtree.empty())
1064 {
1065 // doesn't have to be there
Ed Tanous62598e32023-07-17 17:06:25 -07001066 BMCWEB_LOG_DEBUG("Failed to handle StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001067 return;
1068 }
1069
1070 for (const auto& [path, interfaceDict] : subtree)
1071 {
1072 sdbusplus::message::object_path object(path);
1073 std::string id = object.filename();
1074 if (id.empty())
1075 {
Ed Tanous62598e32023-07-17 17:06:25 -07001076 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001077 return;
1078 }
1079 if (id != controllerId)
1080 {
1081 continue;
1082 }
1083
1084 if (interfaceDict.size() != 1)
1085 {
Ed Tanous62598e32023-07-17 17:06:25 -07001086 BMCWEB_LOG_ERROR("Connection size {}, greater than 1",
1087 interfaceDict.size());
Willy Tu61b1eb22023-03-14 11:29:50 -07001088 messages::internalError(asyncResp->res);
1089 return;
1090 }
1091
1092 const std::string& connectionName = interfaceDict.front().first;
1093 populateStorageController(asyncResp, controllerId, connectionName,
1094 path);
1095 }
1096}
1097
1098inline void populateStorageControllerCollection(
1099 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1100 const boost::system::error_code& ec,
1101 const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
1102{
1103 nlohmann::json::array_t members;
1104 if (ec || controllerList.empty())
1105 {
1106 asyncResp->res.jsonValue["Members"] = std::move(members);
1107 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous62598e32023-07-17 17:06:25 -07001108 BMCWEB_LOG_DEBUG("Failed to find any StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001109 return;
1110 }
1111
1112 for (const std::string& path : controllerList)
1113 {
1114 std::string id = sdbusplus::message::object_path(path).filename();
1115 if (id.empty())
1116 {
Ed Tanous62598e32023-07-17 17:06:25 -07001117 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001118 return;
1119 }
1120 nlohmann::json::object_t member;
1121 member["@odata.id"] = boost::urls::format(
1122 "/redfish/v1/Systems/system/Storage/1/Controllers/{}", id);
1123 members.emplace_back(member);
1124 }
1125 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
1126 asyncResp->res.jsonValue["Members"] = std::move(members);
1127}
1128
Ed Tanous36d52332023-06-09 13:18:40 -07001129inline void handleSystemsStorageControllerCollectionGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001130 App& app, const crow::Request& req,
1131 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1132 const std::string& systemName)
1133{
1134 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1135 {
Ed Tanous62598e32023-07-17 17:06:25 -07001136 BMCWEB_LOG_DEBUG(
1137 "Failed to setup Redfish Route for StorageController Collection");
Willy Tu61b1eb22023-03-14 11:29:50 -07001138 return;
1139 }
1140 if (systemName != "system")
1141 {
1142 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1143 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001144 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001145 return;
1146 }
1147
1148 asyncResp->res.jsonValue["@odata.type"] =
1149 "#StorageControllerCollection.StorageControllerCollection";
1150 asyncResp->res.jsonValue["@odata.id"] =
1151 "/redfish/v1/Systems/system/Storage/1/Controllers";
1152 asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
1153
1154 constexpr std::array<std::string_view, 1> interfaces = {
1155 "xyz.openbmc_project.Inventory.Item.StorageController"};
1156 dbus::utility::getSubTreePaths(
1157 "/xyz/openbmc_project/inventory", 0, interfaces,
1158 [asyncResp](const boost::system::error_code& ec,
1159 const dbus::utility::MapperGetSubTreePathsResponse&
1160 controllerList) {
1161 populateStorageControllerCollection(asyncResp, ec, controllerList);
Patrick Williams5a39f772023-10-20 11:20:21 -05001162 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001163}
1164
Ed Tanous36d52332023-06-09 13:18:40 -07001165inline void handleSystemsStorageControllerGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001166 App& app, const crow::Request& req,
1167 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1168 const std::string& systemName, const std::string& controllerId)
1169{
1170 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1171 {
Ed Tanous62598e32023-07-17 17:06:25 -07001172 BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001173 return;
1174 }
1175 if (systemName != "system")
1176 {
1177 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1178 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001179 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001180 return;
1181 }
1182 constexpr std::array<std::string_view, 1> interfaces = {
1183 "xyz.openbmc_project.Inventory.Item.StorageController"};
1184 dbus::utility::getSubTree(
1185 "/xyz/openbmc_project/inventory", 0, interfaces,
1186 [asyncResp,
1187 controllerId](const boost::system::error_code& ec,
1188 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1189 getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
Patrick Williams5a39f772023-10-20 11:20:21 -05001190 });
Willy Tu61b1eb22023-03-14 11:29:50 -07001191}
1192
1193inline void requestRoutesStorageControllerCollection(App& app)
1194{
1195 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
1196 .privileges(redfish::privileges::getStorageControllerCollection)
Ed Tanous36d52332023-06-09 13:18:40 -07001197 .methods(boost::beast::http::verb::get)(std::bind_front(
1198 handleSystemsStorageControllerCollectionGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001199}
1200
1201inline void requestRoutesStorageController(App& app)
1202{
1203 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
1204 .privileges(redfish::privileges::getStorageController)
1205 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -07001206 std::bind_front(handleSystemsStorageControllerGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001207}
1208
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001209} // namespace redfish