xref: /openbmc/bmcweb/features/redfish/lib/storage.hpp (revision 36d5233493623768bbea0e4d33248b2736240a3e)
1a25aeccfSNikhil Potade /*
2a25aeccfSNikhil Potade // Copyright (c) 2019 Intel Corporation
3a25aeccfSNikhil Potade //
4a25aeccfSNikhil Potade // Licensed under the Apache License, Version 2.0 (the "License");
5a25aeccfSNikhil Potade // you may not use this file except in compliance with the License.
6a25aeccfSNikhil Potade // You may obtain a copy of the License at
7a25aeccfSNikhil Potade //
8a25aeccfSNikhil Potade //      http://www.apache.org/licenses/LICENSE-2.0
9a25aeccfSNikhil Potade //
10a25aeccfSNikhil Potade // Unless required by applicable law or agreed to in writing, software
11a25aeccfSNikhil Potade // distributed under the License is distributed on an "AS IS" BASIS,
12a25aeccfSNikhil Potade // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a25aeccfSNikhil Potade // See the License for the specific language governing permissions and
14a25aeccfSNikhil Potade // limitations under the License.
15a25aeccfSNikhil Potade */
16a25aeccfSNikhil Potade #pragma once
17a25aeccfSNikhil Potade 
1813451e39SWilly Tu #include "bmcweb_config.h"
1913451e39SWilly Tu 
203ccb3adbSEd Tanous #include "app.hpp"
217a1dbc48SGeorge Liu #include "dbus_utility.hpp"
22e5029d88SJohn Edward Broadbent #include "generated/enums/drive.hpp"
23dde9bc12SGeorge Liu #include "generated/enums/protocol.hpp"
242ad9c2f6SJames Feist #include "health.hpp"
25a8e884fcSEd Tanous #include "human_sort.hpp"
26e284a7c1SJames Feist #include "openbmc_dbus_rest.hpp"
273ccb3adbSEd Tanous #include "query.hpp"
28a8e884fcSEd Tanous #include "redfish_util.hpp"
293ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
303ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
312ad9c2f6SJames Feist 
32e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
33ef4c65b7SEd Tanous #include <boost/url/format.hpp>
341e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
35d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
36a25aeccfSNikhil Potade 
377a1dbc48SGeorge Liu #include <array>
387a1dbc48SGeorge Liu #include <string_view>
397a1dbc48SGeorge Liu 
40a25aeccfSNikhil Potade namespace redfish
41a25aeccfSNikhil Potade {
42*36d52334SEd Tanous 
43*36d52334SEd Tanous inline void handleSystemsStorageCollectionGet(
44*36d52334SEd Tanous     App& app, const crow::Request& req,
4522d268cbSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
46*36d52334SEd Tanous     const std::string& systemName)
47*36d52334SEd Tanous {
483ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
4945ca1b86SEd Tanous     {
5045ca1b86SEd Tanous         return;
5145ca1b86SEd Tanous     }
5222d268cbSEd Tanous     if (systemName != "system")
5322d268cbSEd Tanous     {
5422d268cbSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5522d268cbSEd Tanous                                    systemName);
5622d268cbSEd Tanous         return;
5722d268cbSEd Tanous     }
5822d268cbSEd Tanous 
598d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
608d1b46d7Szhanghch05         "#StorageCollection.StorageCollection";
618d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] =
628d1b46d7Szhanghch05         "/redfish/v1/Systems/system/Storage";
638d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Storage Collection";
641476687dSEd Tanous     nlohmann::json::array_t members;
651476687dSEd Tanous     nlohmann::json::object_t member;
661476687dSEd Tanous     member["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
671476687dSEd Tanous     members.emplace_back(member);
681476687dSEd Tanous     asyncResp->res.jsonValue["Members"] = std::move(members);
698d1b46d7Szhanghch05     asyncResp->res.jsonValue["Members@odata.count"] = 1;
70a25aeccfSNikhil Potade }
71a25aeccfSNikhil Potade 
72*36d52334SEd Tanous inline void requestRoutesStorageCollection(App& app)
73a25aeccfSNikhil Potade {
74*36d52334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
75*36d52334SEd Tanous         .privileges(redfish::privileges::getStorageCollection)
76*36d52334SEd Tanous         .methods(boost::beast::http::verb::get)(
77*36d52334SEd Tanous             std::bind_front(handleSystemsStorageCollectionGet, std::ref(app)));
78*36d52334SEd Tanous }
79*36d52334SEd Tanous 
80*36d52334SEd Tanous inline void afterChassisDriveCollectionSubtree(
81*36d52334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
82*36d52334SEd Tanous     const std::shared_ptr<HealthPopulate>& health,
837a1dbc48SGeorge Liu     const boost::system::error_code& ec,
84*36d52334SEd Tanous     const dbus::utility::MapperGetSubTreePathsResponse& driveList)
85*36d52334SEd Tanous {
86a25aeccfSNikhil Potade     if (ec)
87a25aeccfSNikhil Potade     {
88a25aeccfSNikhil Potade         BMCWEB_LOG_ERROR << "Drive mapper call error";
89a25aeccfSNikhil Potade         messages::internalError(asyncResp->res);
90a25aeccfSNikhil Potade         return;
91a25aeccfSNikhil Potade     }
922ad9c2f6SJames Feist 
93a85afbe1SWilly Tu     nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
94a85afbe1SWilly Tu     driveArray = nlohmann::json::array();
95a85afbe1SWilly Tu     auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
96a85afbe1SWilly Tu     count = 0;
972ad9c2f6SJames Feist 
9813451e39SWilly Tu     if constexpr (bmcwebEnableHealthPopulate)
9913451e39SWilly Tu     {
100a85afbe1SWilly Tu         health->inventory.insert(health->inventory.end(), driveList.begin(),
101a85afbe1SWilly Tu                                  driveList.end());
10213451e39SWilly Tu     }
103a85afbe1SWilly Tu 
104a85afbe1SWilly Tu     for (const std::string& drive : driveList)
105a25aeccfSNikhil Potade     {
106a85afbe1SWilly Tu         sdbusplus::message::object_path object(drive);
107a85afbe1SWilly Tu         if (object.filename().empty())
108a25aeccfSNikhil Potade         {
109a85afbe1SWilly Tu             BMCWEB_LOG_ERROR << "Failed to find filename in " << drive;
110a85afbe1SWilly Tu             return;
111a25aeccfSNikhil Potade         }
112a85afbe1SWilly Tu 
113a85afbe1SWilly Tu         nlohmann::json::object_t driveJson;
114ef4c65b7SEd Tanous         driveJson["@odata.id"] = boost::urls::format(
115ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/Storage/1/Drives/{}",
116eddfc437SWilly Tu             object.filename());
117b2ba3072SPatrick Williams         driveArray.emplace_back(std::move(driveJson));
118a25aeccfSNikhil Potade     }
119a25aeccfSNikhil Potade 
120a85afbe1SWilly Tu     count = driveArray.size();
121*36d52334SEd Tanous }
122*36d52334SEd Tanous inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
123*36d52334SEd Tanous                       const std::shared_ptr<HealthPopulate>& health)
124*36d52334SEd Tanous {
125*36d52334SEd Tanous     const std::array<std::string_view, 1> interfaces = {
126*36d52334SEd Tanous         "xyz.openbmc_project.Inventory.Item.Drive"};
127*36d52334SEd Tanous     dbus::utility::getSubTreePaths(
128*36d52334SEd Tanous         "/xyz/openbmc_project/inventory", 0, interfaces,
129*36d52334SEd Tanous         std::bind_front(afterChassisDriveCollectionSubtree, asyncResp, health));
130a85afbe1SWilly Tu }
131e284a7c1SJames Feist 
132*36d52334SEd Tanous inline void
133*36d52334SEd Tanous     handleSystemsStorageGet(App& app, const crow::Request& req,
134*36d52334SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
135a85afbe1SWilly Tu {
1363ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
137a85afbe1SWilly Tu     {
138a85afbe1SWilly Tu         return;
139a85afbe1SWilly Tu     }
14061b1eb21SWilly Tu     asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
141a85afbe1SWilly Tu     asyncResp->res.jsonValue["@odata.id"] =
142a85afbe1SWilly Tu         "/redfish/v1/Systems/system/Storage/1";
143a85afbe1SWilly Tu     asyncResp->res.jsonValue["Name"] = "Storage";
144a85afbe1SWilly Tu     asyncResp->res.jsonValue["Id"] = "1";
145a85afbe1SWilly Tu     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
146a85afbe1SWilly Tu 
147a85afbe1SWilly Tu     auto health = std::make_shared<HealthPopulate>(asyncResp);
14813451e39SWilly Tu     if constexpr (bmcwebEnableHealthPopulate)
14913451e39SWilly Tu     {
150a85afbe1SWilly Tu         health->populate();
15113451e39SWilly Tu     }
152a85afbe1SWilly Tu 
153a85afbe1SWilly Tu     getDrives(asyncResp, health);
15461b1eb21SWilly Tu     asyncResp->res.jsonValue["Controllers"]["@odata.id"] =
15561b1eb21SWilly Tu         "/redfish/v1/Systems/system/Storage/1/Controllers";
156*36d52334SEd Tanous }
157*36d52334SEd Tanous 
158*36d52334SEd Tanous inline void requestRoutesStorage(App& app)
159*36d52334SEd Tanous {
160*36d52334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/")
161*36d52334SEd Tanous         .privileges(redfish::privileges::getStorage)
162*36d52334SEd Tanous         .methods(boost::beast::http::verb::get)(
163*36d52334SEd Tanous             std::bind_front(handleSystemsStorageGet, std::ref(app)));
1647e860f15SJohn Edward Broadbent }
1657e860f15SJohn Edward Broadbent 
16603913171SWilly Tu inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16703913171SWilly Tu                           const std::string& connectionName,
16803913171SWilly Tu                           const std::string& path)
16903913171SWilly Tu {
170d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
171d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, connectionName, path,
172d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Inventory.Decorator.Asset",
1735e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
174168e20c1SEd Tanous                     const std::vector<
175168e20c1SEd Tanous                         std::pair<std::string, dbus::utility::DbusVariantType>>&
17603913171SWilly Tu                         propertiesList) {
17703913171SWilly Tu         if (ec)
17803913171SWilly Tu         {
17903913171SWilly Tu             // this interface isn't necessary
18003913171SWilly Tu             return;
18103913171SWilly Tu         }
182d1bde9e5SKrzysztof Grobelny 
183d1bde9e5SKrzysztof Grobelny         const std::string* partNumber = nullptr;
184d1bde9e5SKrzysztof Grobelny         const std::string* serialNumber = nullptr;
185d1bde9e5SKrzysztof Grobelny         const std::string* manufacturer = nullptr;
186d1bde9e5SKrzysztof Grobelny         const std::string* model = nullptr;
187d1bde9e5SKrzysztof Grobelny 
188d1bde9e5SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
189d1bde9e5SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
190d1bde9e5SKrzysztof Grobelny             partNumber, "SerialNumber", serialNumber, "Manufacturer",
191d1bde9e5SKrzysztof Grobelny             manufacturer, "Model", model);
192d1bde9e5SKrzysztof Grobelny 
193d1bde9e5SKrzysztof Grobelny         if (!success)
19403913171SWilly Tu         {
19503913171SWilly Tu             messages::internalError(asyncResp->res);
19603913171SWilly Tu             return;
19703913171SWilly Tu         }
198d1bde9e5SKrzysztof Grobelny 
199d1bde9e5SKrzysztof Grobelny         if (partNumber != nullptr)
200d1bde9e5SKrzysztof Grobelny         {
201d1bde9e5SKrzysztof Grobelny             asyncResp->res.jsonValue["PartNumber"] = *partNumber;
20203913171SWilly Tu         }
203d1bde9e5SKrzysztof Grobelny 
204d1bde9e5SKrzysztof Grobelny         if (serialNumber != nullptr)
205d1bde9e5SKrzysztof Grobelny         {
206d1bde9e5SKrzysztof Grobelny             asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
20703913171SWilly Tu         }
208d1bde9e5SKrzysztof Grobelny 
209d1bde9e5SKrzysztof Grobelny         if (manufacturer != nullptr)
210d1bde9e5SKrzysztof Grobelny         {
211d1bde9e5SKrzysztof Grobelny             asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
212d1bde9e5SKrzysztof Grobelny         }
213d1bde9e5SKrzysztof Grobelny 
214d1bde9e5SKrzysztof Grobelny         if (model != nullptr)
215d1bde9e5SKrzysztof Grobelny         {
216d1bde9e5SKrzysztof Grobelny             asyncResp->res.jsonValue["Model"] = *model;
217d1bde9e5SKrzysztof Grobelny         }
218d1bde9e5SKrzysztof Grobelny         });
21903913171SWilly Tu }
22003913171SWilly Tu 
22103913171SWilly Tu inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22203913171SWilly Tu                             const std::string& connectionName,
22303913171SWilly Tu                             const std::string& path)
22403913171SWilly Tu {
2251e1e598dSJonathan Doman     sdbusplus::asio::getProperty<bool>(
2261e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
2271e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Item", "Present",
2285e7e2dc5SEd Tanous         [asyncResp, path](const boost::system::error_code& ec,
229cef57e85SWilly Tu                           const bool isPresent) {
23003913171SWilly Tu         // this interface isn't necessary, only check it if
23103913171SWilly Tu         // we get a good return
23203913171SWilly Tu         if (ec)
23303913171SWilly Tu         {
23403913171SWilly Tu             return;
23503913171SWilly Tu         }
23603913171SWilly Tu 
237cef57e85SWilly Tu         if (!isPresent)
23803913171SWilly Tu         {
239cef57e85SWilly Tu             asyncResp->res.jsonValue["Status"]["State"] = "Absent";
24003913171SWilly Tu         }
2411e1e598dSJonathan Doman         });
24203913171SWilly Tu }
24303913171SWilly Tu 
24403913171SWilly Tu inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24503913171SWilly Tu                           const std::string& connectionName,
24603913171SWilly Tu                           const std::string& path)
24703913171SWilly Tu {
2481e1e598dSJonathan Doman     sdbusplus::asio::getProperty<bool>(
2491e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
2501e1e598dSJonathan Doman         "xyz.openbmc_project.State.Drive", "Rebuilding",
2515e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec, const bool updating) {
25203913171SWilly Tu         // this interface isn't necessary, only check it
25303913171SWilly Tu         // if we get a good return
25403913171SWilly Tu         if (ec)
25503913171SWilly Tu         {
25603913171SWilly Tu             return;
25703913171SWilly Tu         }
25803913171SWilly Tu 
25903913171SWilly Tu         // updating and disabled in the backend shouldn't be
26003913171SWilly Tu         // able to be set at the same time, so we don't need
26103913171SWilly Tu         // to check for the race condition of these two
26203913171SWilly Tu         // calls
2631e1e598dSJonathan Doman         if (updating)
26403913171SWilly Tu         {
26503913171SWilly Tu             asyncResp->res.jsonValue["Status"]["State"] = "Updating";
26603913171SWilly Tu         }
2671e1e598dSJonathan Doman         });
26803913171SWilly Tu }
26903913171SWilly Tu 
270dde9bc12SGeorge Liu inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
27119b8e9a0SWilly Tu {
27219b8e9a0SWilly Tu     if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
27319b8e9a0SWilly Tu     {
274dde9bc12SGeorge Liu         return drive::MediaType::HDD;
27519b8e9a0SWilly Tu     }
27619b8e9a0SWilly Tu     if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
27719b8e9a0SWilly Tu     {
278dde9bc12SGeorge Liu         return drive::MediaType::SSD;
27919b8e9a0SWilly Tu     }
280dde9bc12SGeorge Liu     if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
281dde9bc12SGeorge Liu     {
28219b8e9a0SWilly Tu         return std::nullopt;
28319b8e9a0SWilly Tu     }
28419b8e9a0SWilly Tu 
285dde9bc12SGeorge Liu     return drive::MediaType::Invalid;
286dde9bc12SGeorge Liu }
287dde9bc12SGeorge Liu 
288dde9bc12SGeorge Liu inline std::optional<protocol::Protocol>
289dde9bc12SGeorge Liu     convertDriveProtocol(std::string_view proto)
29019b8e9a0SWilly Tu {
29119b8e9a0SWilly Tu     if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
29219b8e9a0SWilly Tu     {
293dde9bc12SGeorge Liu         return protocol::Protocol::SAS;
29419b8e9a0SWilly Tu     }
29519b8e9a0SWilly Tu     if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
29619b8e9a0SWilly Tu     {
297dde9bc12SGeorge Liu         return protocol::Protocol::SATA;
29819b8e9a0SWilly Tu     }
29919b8e9a0SWilly Tu     if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
30019b8e9a0SWilly Tu     {
301dde9bc12SGeorge Liu         return protocol::Protocol::NVMe;
30219b8e9a0SWilly Tu     }
30319b8e9a0SWilly Tu     if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
30419b8e9a0SWilly Tu     {
305dde9bc12SGeorge Liu         return protocol::Protocol::FC;
306dde9bc12SGeorge Liu     }
307dde9bc12SGeorge Liu     if (proto ==
308dde9bc12SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
309dde9bc12SGeorge Liu     {
310dde9bc12SGeorge Liu         return std::nullopt;
31119b8e9a0SWilly Tu     }
31219b8e9a0SWilly Tu 
313dde9bc12SGeorge Liu     return protocol::Protocol::Invalid;
31419b8e9a0SWilly Tu }
31519b8e9a0SWilly Tu 
31619b8e9a0SWilly Tu inline void
31719b8e9a0SWilly Tu     getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
31819b8e9a0SWilly Tu                            const std::string& connectionName,
31919b8e9a0SWilly Tu                            const std::string& path)
32019b8e9a0SWilly Tu {
32119b8e9a0SWilly Tu     sdbusplus::asio::getAllProperties(
32219b8e9a0SWilly Tu         *crow::connections::systemBus, connectionName, path,
32319b8e9a0SWilly Tu         "xyz.openbmc_project.Inventory.Item.Drive",
3245e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
32519b8e9a0SWilly Tu                     const std::vector<
32619b8e9a0SWilly Tu                         std::pair<std::string, dbus::utility::DbusVariantType>>&
32719b8e9a0SWilly Tu                         propertiesList) {
32819b8e9a0SWilly Tu         if (ec)
32919b8e9a0SWilly Tu         {
33019b8e9a0SWilly Tu             // this interface isn't required
33119b8e9a0SWilly Tu             return;
33219b8e9a0SWilly Tu         }
333e5029d88SJohn Edward Broadbent         const std::string* encryptionStatus = nullptr;
334e5029d88SJohn Edward Broadbent         const bool* isLocked = nullptr;
33519b8e9a0SWilly Tu         for (const std::pair<std::string, dbus::utility::DbusVariantType>&
33619b8e9a0SWilly Tu                  property : propertiesList)
33719b8e9a0SWilly Tu         {
33819b8e9a0SWilly Tu             const std::string& propertyName = property.first;
33919b8e9a0SWilly Tu             if (propertyName == "Type")
34019b8e9a0SWilly Tu             {
34119b8e9a0SWilly Tu                 const std::string* value =
34219b8e9a0SWilly Tu                     std::get_if<std::string>(&property.second);
34319b8e9a0SWilly Tu                 if (value == nullptr)
34419b8e9a0SWilly Tu                 {
34519b8e9a0SWilly Tu                     // illegal property
34619b8e9a0SWilly Tu                     BMCWEB_LOG_ERROR << "Illegal property: Type";
34719b8e9a0SWilly Tu                     messages::internalError(asyncResp->res);
34819b8e9a0SWilly Tu                     return;
34919b8e9a0SWilly Tu                 }
35019b8e9a0SWilly Tu 
351dde9bc12SGeorge Liu                 std::optional<drive::MediaType> mediaType =
352dde9bc12SGeorge Liu                     convertDriveType(*value);
35319b8e9a0SWilly Tu                 if (!mediaType)
35419b8e9a0SWilly Tu                 {
355dde9bc12SGeorge Liu                     BMCWEB_LOG_WARNING << "UnknownDriveType Interface: "
35619b8e9a0SWilly Tu                                        << *value;
357dde9bc12SGeorge Liu                     continue;
358dde9bc12SGeorge Liu                 }
359dde9bc12SGeorge Liu                 if (*mediaType == drive::MediaType::Invalid)
360dde9bc12SGeorge Liu                 {
36119b8e9a0SWilly Tu                     messages::internalError(asyncResp->res);
36219b8e9a0SWilly Tu                     return;
36319b8e9a0SWilly Tu                 }
36419b8e9a0SWilly Tu 
36519b8e9a0SWilly Tu                 asyncResp->res.jsonValue["MediaType"] = *mediaType;
36619b8e9a0SWilly Tu             }
36719b8e9a0SWilly Tu             else if (propertyName == "Capacity")
36819b8e9a0SWilly Tu             {
36919b8e9a0SWilly Tu                 const uint64_t* capacity =
37019b8e9a0SWilly Tu                     std::get_if<uint64_t>(&property.second);
37119b8e9a0SWilly Tu                 if (capacity == nullptr)
37219b8e9a0SWilly Tu                 {
37319b8e9a0SWilly Tu                     BMCWEB_LOG_ERROR << "Illegal property: Capacity";
37419b8e9a0SWilly Tu                     messages::internalError(asyncResp->res);
37519b8e9a0SWilly Tu                     return;
37619b8e9a0SWilly Tu                 }
37719b8e9a0SWilly Tu                 if (*capacity == 0)
37819b8e9a0SWilly Tu                 {
37919b8e9a0SWilly Tu                     // drive capacity not known
38019b8e9a0SWilly Tu                     continue;
38119b8e9a0SWilly Tu                 }
38219b8e9a0SWilly Tu 
38319b8e9a0SWilly Tu                 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
38419b8e9a0SWilly Tu             }
38519b8e9a0SWilly Tu             else if (propertyName == "Protocol")
38619b8e9a0SWilly Tu             {
38719b8e9a0SWilly Tu                 const std::string* value =
38819b8e9a0SWilly Tu                     std::get_if<std::string>(&property.second);
38919b8e9a0SWilly Tu                 if (value == nullptr)
39019b8e9a0SWilly Tu                 {
39119b8e9a0SWilly Tu                     BMCWEB_LOG_ERROR << "Illegal property: Protocol";
39219b8e9a0SWilly Tu                     messages::internalError(asyncResp->res);
39319b8e9a0SWilly Tu                     return;
39419b8e9a0SWilly Tu                 }
39519b8e9a0SWilly Tu 
396dde9bc12SGeorge Liu                 std::optional<protocol::Protocol> proto =
397dde9bc12SGeorge Liu                     convertDriveProtocol(*value);
39819b8e9a0SWilly Tu                 if (!proto)
39919b8e9a0SWilly Tu                 {
400dde9bc12SGeorge Liu                     BMCWEB_LOG_WARNING << "Unknown DrivePrototype Interface: "
40119b8e9a0SWilly Tu                                        << *value;
402dde9bc12SGeorge Liu                     continue;
403dde9bc12SGeorge Liu                 }
404dde9bc12SGeorge Liu                 if (*proto == protocol::Protocol::Invalid)
405dde9bc12SGeorge Liu                 {
40619b8e9a0SWilly Tu                     messages::internalError(asyncResp->res);
40719b8e9a0SWilly Tu                     return;
40819b8e9a0SWilly Tu                 }
40919b8e9a0SWilly Tu                 asyncResp->res.jsonValue["Protocol"] = *proto;
41019b8e9a0SWilly Tu             }
4113fe4d5ccSJohn Edward Broadbent             else if (propertyName == "PredictedMediaLifeLeftPercent")
4123fe4d5ccSJohn Edward Broadbent             {
4133fe4d5ccSJohn Edward Broadbent                 const uint8_t* lifeLeft =
4143fe4d5ccSJohn Edward Broadbent                     std::get_if<uint8_t>(&property.second);
4153fe4d5ccSJohn Edward Broadbent                 if (lifeLeft == nullptr)
4163fe4d5ccSJohn Edward Broadbent                 {
4173fe4d5ccSJohn Edward Broadbent                     BMCWEB_LOG_ERROR
4183fe4d5ccSJohn Edward Broadbent                         << "Illegal property: PredictedMediaLifeLeftPercent";
4193fe4d5ccSJohn Edward Broadbent                     messages::internalError(asyncResp->res);
4203fe4d5ccSJohn Edward Broadbent                     return;
4213fe4d5ccSJohn Edward Broadbent                 }
4223fe4d5ccSJohn Edward Broadbent                 // 255 means reading the value is not supported
4233fe4d5ccSJohn Edward Broadbent                 if (*lifeLeft != 255)
4243fe4d5ccSJohn Edward Broadbent                 {
4253fe4d5ccSJohn Edward Broadbent                     asyncResp->res.jsonValue["PredictedMediaLifeLeftPercent"] =
4263fe4d5ccSJohn Edward Broadbent                         *lifeLeft;
4273fe4d5ccSJohn Edward Broadbent                 }
4283fe4d5ccSJohn Edward Broadbent             }
429e5029d88SJohn Edward Broadbent             else if (propertyName == "EncryptionStatus")
430e5029d88SJohn Edward Broadbent             {
431e5029d88SJohn Edward Broadbent                 encryptionStatus = std::get_if<std::string>(&property.second);
432e5029d88SJohn Edward Broadbent                 if (encryptionStatus == nullptr)
433e5029d88SJohn Edward Broadbent                 {
434e5029d88SJohn Edward Broadbent                     BMCWEB_LOG_ERROR << "Illegal property: EncryptionStatus";
435e5029d88SJohn Edward Broadbent                     messages::internalError(asyncResp->res);
436e5029d88SJohn Edward Broadbent                     return;
43719b8e9a0SWilly Tu                 }
438e5029d88SJohn Edward Broadbent             }
439e5029d88SJohn Edward Broadbent             else if (propertyName == "Locked")
440e5029d88SJohn Edward Broadbent             {
441e5029d88SJohn Edward Broadbent                 isLocked = std::get_if<bool>(&property.second);
442e5029d88SJohn Edward Broadbent                 if (isLocked == nullptr)
443e5029d88SJohn Edward Broadbent                 {
444e5029d88SJohn Edward Broadbent                     BMCWEB_LOG_ERROR << "Illegal property: Locked";
445e5029d88SJohn Edward Broadbent                     messages::internalError(asyncResp->res);
446e5029d88SJohn Edward Broadbent                     return;
447e5029d88SJohn Edward Broadbent                 }
448e5029d88SJohn Edward Broadbent             }
449e5029d88SJohn Edward Broadbent         }
450e5029d88SJohn Edward Broadbent 
451e5029d88SJohn Edward Broadbent         if (encryptionStatus == nullptr || isLocked == nullptr ||
452e5029d88SJohn Edward Broadbent             *encryptionStatus ==
453e5029d88SJohn Edward Broadbent                 "xyz.openbmc_project.Drive.DriveEncryptionState.Unknown")
454e5029d88SJohn Edward Broadbent         {
455e5029d88SJohn Edward Broadbent             return;
456e5029d88SJohn Edward Broadbent         }
457e5029d88SJohn Edward Broadbent         if (*encryptionStatus !=
458e5029d88SJohn Edward Broadbent             "xyz.openbmc_project.Drive.DriveEncryptionState.Encrypted")
459e5029d88SJohn Edward Broadbent         {
460e5029d88SJohn Edward Broadbent             //"The drive is not currently encrypted."
461e5029d88SJohn Edward Broadbent             asyncResp->res.jsonValue["EncryptionStatus"] =
462e5029d88SJohn Edward Broadbent                 drive::EncryptionStatus::Unencrypted;
463e5029d88SJohn Edward Broadbent             return;
464e5029d88SJohn Edward Broadbent         }
465e5029d88SJohn Edward Broadbent         if (*isLocked)
466e5029d88SJohn Edward Broadbent         {
467e5029d88SJohn Edward Broadbent             //"The drive is currently encrypted and the data is not
468e5029d88SJohn Edward Broadbent             // accessible to the user."
469e5029d88SJohn Edward Broadbent             asyncResp->res.jsonValue["EncryptionStatus"] =
470e5029d88SJohn Edward Broadbent                 drive::EncryptionStatus::Locked;
471e5029d88SJohn Edward Broadbent             return;
472e5029d88SJohn Edward Broadbent         }
473e5029d88SJohn Edward Broadbent         // if not locked
474e5029d88SJohn Edward Broadbent         // "The drive is currently encrypted but the data is accessible
475e5029d88SJohn Edward Broadbent         // to the user in unencrypted form."
476e5029d88SJohn Edward Broadbent         asyncResp->res.jsonValue["EncryptionStatus"] =
477e5029d88SJohn Edward Broadbent             drive::EncryptionStatus::Unlocked;
47819b8e9a0SWilly Tu         });
47919b8e9a0SWilly Tu }
48019b8e9a0SWilly Tu 
481b53dcd9dSNan Zhou static void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
482b53dcd9dSNan Zhou                             const std::string& connectionName,
483b53dcd9dSNan Zhou                             const std::string& path,
484e56ed6b9SJohn Edward Broadbent                             const std::vector<std::string>& interfaces)
485e56ed6b9SJohn Edward Broadbent {
486e56ed6b9SJohn Edward Broadbent     for (const std::string& interface : interfaces)
487e56ed6b9SJohn Edward Broadbent     {
488e56ed6b9SJohn Edward Broadbent         if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
489e56ed6b9SJohn Edward Broadbent         {
490e56ed6b9SJohn Edward Broadbent             getDriveAsset(asyncResp, connectionName, path);
491e56ed6b9SJohn Edward Broadbent         }
492e56ed6b9SJohn Edward Broadbent         else if (interface == "xyz.openbmc_project.Inventory.Item")
493e56ed6b9SJohn Edward Broadbent         {
494e56ed6b9SJohn Edward Broadbent             getDrivePresent(asyncResp, connectionName, path);
495e56ed6b9SJohn Edward Broadbent         }
496e56ed6b9SJohn Edward Broadbent         else if (interface == "xyz.openbmc_project.State.Drive")
497e56ed6b9SJohn Edward Broadbent         {
498e56ed6b9SJohn Edward Broadbent             getDriveState(asyncResp, connectionName, path);
499e56ed6b9SJohn Edward Broadbent         }
500e56ed6b9SJohn Edward Broadbent         else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
501e56ed6b9SJohn Edward Broadbent         {
502e56ed6b9SJohn Edward Broadbent             getDriveItemProperties(asyncResp, connectionName, path);
503e56ed6b9SJohn Edward Broadbent         }
504e56ed6b9SJohn Edward Broadbent     }
505e56ed6b9SJohn Edward Broadbent }
506e56ed6b9SJohn Edward Broadbent 
507*36d52334SEd Tanous inline void afterGetSubtreeSystemsStorageDrive(
50845ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
509*36d52334SEd Tanous     const std::string& driveId, const boost::system::error_code& ec,
510*36d52334SEd Tanous     const dbus::utility::MapperGetSubTreeResponse& subtree)
51145ca1b86SEd Tanous {
5127e860f15SJohn Edward Broadbent     if (ec)
5137e860f15SJohn Edward Broadbent     {
5147e860f15SJohn Edward Broadbent         BMCWEB_LOG_ERROR << "Drive mapper call error";
5157e860f15SJohn Edward Broadbent         messages::internalError(asyncResp->res);
5167e860f15SJohn Edward Broadbent         return;
5177e860f15SJohn Edward Broadbent     }
5187e860f15SJohn Edward Broadbent 
51903913171SWilly Tu     auto drive = std::find_if(
5207e860f15SJohn Edward Broadbent         subtree.begin(), subtree.end(),
521*36d52334SEd Tanous         [&driveId](const std::pair<std::string,
5228cb65f8aSNan Zhou                                    dbus::utility::MapperServiceMap>& object) {
523*36d52334SEd Tanous         return sdbusplus::message::object_path(object.first).filename() ==
524*36d52334SEd Tanous                driveId;
5257e860f15SJohn Edward Broadbent         });
5267e860f15SJohn Edward Broadbent 
52703913171SWilly Tu     if (drive == subtree.end())
5287e860f15SJohn Edward Broadbent     {
529002d39b4SEd Tanous         messages::resourceNotFound(asyncResp->res, "Drive", driveId);
5307e860f15SJohn Edward Broadbent         return;
5317e860f15SJohn Edward Broadbent     }
5327e860f15SJohn Edward Broadbent 
53303913171SWilly Tu     const std::string& path = drive->first;
534*36d52334SEd Tanous     const dbus::utility::MapperServiceMap& connectionNames = drive->second;
5357e860f15SJohn Edward Broadbent 
536002d39b4SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
537ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
538ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/Storage/1/Drives/{}", driveId);
5397e860f15SJohn Edward Broadbent     asyncResp->res.jsonValue["Name"] = driveId;
5407e860f15SJohn Edward Broadbent     asyncResp->res.jsonValue["Id"] = driveId;
5417e860f15SJohn Edward Broadbent 
5427e860f15SJohn Edward Broadbent     if (connectionNames.size() != 1)
5437e860f15SJohn Edward Broadbent     {
544002d39b4SEd Tanous         BMCWEB_LOG_ERROR << "Connection size " << connectionNames.size()
54503913171SWilly Tu                          << ", not equal to 1";
5467e860f15SJohn Edward Broadbent         messages::internalError(asyncResp->res);
5477e860f15SJohn Edward Broadbent         return;
5487e860f15SJohn Edward Broadbent     }
5497e860f15SJohn Edward Broadbent 
550*36d52334SEd Tanous     getMainChassisId(asyncResp,
551ef4c65b7SEd Tanous                      [](const std::string& chassisId,
5527e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
553002d39b4SEd Tanous         aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
554ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
5557e860f15SJohn Edward Broadbent     });
5567e860f15SJohn Edward Broadbent 
557a25aeccfSNikhil Potade     // default it to Enabled
558a25aeccfSNikhil Potade     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
559a25aeccfSNikhil Potade 
56013451e39SWilly Tu     if constexpr (bmcwebEnableHealthPopulate)
56113451e39SWilly Tu     {
5622ad9c2f6SJames Feist         auto health = std::make_shared<HealthPopulate>(asyncResp);
563e284a7c1SJames Feist         health->inventory.emplace_back(path);
5642ad9c2f6SJames Feist         health->populate();
56513451e39SWilly Tu     }
5662ad9c2f6SJames Feist 
567e56ed6b9SJohn Edward Broadbent     addAllDriveInfo(asyncResp, connectionNames[0].first, path,
568e56ed6b9SJohn Edward Broadbent                     connectionNames[0].second);
569a25aeccfSNikhil Potade }
57092903bd4SJohn Edward Broadbent 
571*36d52334SEd Tanous inline void handleSystemsStorageDriveGet(
572*36d52334SEd Tanous     App& app, const crow::Request& req,
57392903bd4SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
574*36d52334SEd Tanous     const std::string& systemName, const std::string& driveId)
57592903bd4SJohn Edward Broadbent {
5763ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
57792903bd4SJohn Edward Broadbent     {
57892903bd4SJohn Edward Broadbent         return;
57992903bd4SJohn Edward Broadbent     }
580*36d52334SEd Tanous     if (systemName != "system")
581*36d52334SEd Tanous     {
582*36d52334SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
583*36d52334SEd Tanous                                    systemName);
584*36d52334SEd Tanous         return;
585*36d52334SEd Tanous     }
58692903bd4SJohn Edward Broadbent 
587*36d52334SEd Tanous     constexpr std::array<std::string_view, 1> interfaces = {
588*36d52334SEd Tanous         "xyz.openbmc_project.Inventory.Item.Drive"};
589e99073f5SGeorge Liu     dbus::utility::getSubTree(
590e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
591*36d52334SEd Tanous         std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp,
592*36d52334SEd Tanous                         driveId));
593*36d52334SEd Tanous }
594*36d52334SEd Tanous 
595*36d52334SEd Tanous inline void requestRoutesDrive(App& app)
596*36d52334SEd Tanous {
597*36d52334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
598*36d52334SEd Tanous         .privileges(redfish::privileges::getDrive)
599*36d52334SEd Tanous         .methods(boost::beast::http::verb::get)(
600*36d52334SEd Tanous             std::bind_front(handleSystemsStorageDriveGet, std::ref(app)));
601*36d52334SEd Tanous }
602*36d52334SEd Tanous 
603*36d52334SEd Tanous inline void afterChassisDriveCollectionSubtreeGet(
604*36d52334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
605*36d52334SEd Tanous     const std::string& chassisId, const boost::system::error_code& ec,
606*36d52334SEd Tanous     const dbus::utility::MapperGetSubTreeResponse& subtree)
607*36d52334SEd Tanous {
60892903bd4SJohn Edward Broadbent     if (ec)
60992903bd4SJohn Edward Broadbent     {
61092903bd4SJohn Edward Broadbent         if (ec == boost::system::errc::host_unreachable)
61192903bd4SJohn Edward Broadbent         {
612*36d52334SEd Tanous             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
61392903bd4SJohn Edward Broadbent             return;
61492903bd4SJohn Edward Broadbent         }
61592903bd4SJohn Edward Broadbent         messages::internalError(asyncResp->res);
61692903bd4SJohn Edward Broadbent         return;
61792903bd4SJohn Edward Broadbent     }
61892903bd4SJohn Edward Broadbent 
61992903bd4SJohn Edward Broadbent     // Iterate over all retrieved ObjectPaths.
6208cb65f8aSNan Zhou     for (const auto& [path, connectionNames] : subtree)
62192903bd4SJohn Edward Broadbent     {
62292903bd4SJohn Edward Broadbent         sdbusplus::message::object_path objPath(path);
62392903bd4SJohn Edward Broadbent         if (objPath.filename() != chassisId)
62492903bd4SJohn Edward Broadbent         {
62592903bd4SJohn Edward Broadbent             continue;
62692903bd4SJohn Edward Broadbent         }
62792903bd4SJohn Edward Broadbent 
62892903bd4SJohn Edward Broadbent         if (connectionNames.empty())
62992903bd4SJohn Edward Broadbent         {
63092903bd4SJohn Edward Broadbent             BMCWEB_LOG_ERROR << "Got 0 Connection names";
63192903bd4SJohn Edward Broadbent             continue;
63292903bd4SJohn Edward Broadbent         }
63392903bd4SJohn Edward Broadbent 
63492903bd4SJohn Edward Broadbent         asyncResp->res.jsonValue["@odata.type"] =
63592903bd4SJohn Edward Broadbent             "#DriveCollection.DriveCollection";
63692903bd4SJohn Edward Broadbent         asyncResp->res.jsonValue["@odata.id"] =
637ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
63892903bd4SJohn Edward Broadbent         asyncResp->res.jsonValue["Name"] = "Drive Collection";
63992903bd4SJohn Edward Broadbent 
64092903bd4SJohn Edward Broadbent         // Association lambda
6416c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
6426c3e9451SGeorge Liu             path + "/drive",
643*36d52334SEd Tanous             [asyncResp, chassisId](const boost::system::error_code& ec3,
6446c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
64592903bd4SJohn Edward Broadbent             if (ec3)
64692903bd4SJohn Edward Broadbent             {
64792903bd4SJohn Edward Broadbent                 BMCWEB_LOG_ERROR << "Error in chassis Drive association ";
64892903bd4SJohn Edward Broadbent             }
64992903bd4SJohn Edward Broadbent             nlohmann::json& members = asyncResp->res.jsonValue["Members"];
65092903bd4SJohn Edward Broadbent             // important if array is empty
65192903bd4SJohn Edward Broadbent             members = nlohmann::json::array();
65292903bd4SJohn Edward Broadbent 
65392903bd4SJohn Edward Broadbent             std::vector<std::string> leafNames;
65492903bd4SJohn Edward Broadbent             for (const auto& drive : resp)
65592903bd4SJohn Edward Broadbent             {
6568a592810SEd Tanous                 sdbusplus::message::object_path drivePath(drive);
6578a592810SEd Tanous                 leafNames.push_back(drivePath.filename());
65892903bd4SJohn Edward Broadbent             }
65992903bd4SJohn Edward Broadbent 
66092903bd4SJohn Edward Broadbent             std::sort(leafNames.begin(), leafNames.end(),
66192903bd4SJohn Edward Broadbent                       AlphanumLess<std::string>());
66292903bd4SJohn Edward Broadbent 
66392903bd4SJohn Edward Broadbent             for (const auto& leafName : leafNames)
66492903bd4SJohn Edward Broadbent             {
66592903bd4SJohn Edward Broadbent                 nlohmann::json::object_t member;
666*36d52334SEd Tanous                 member["@odata.id"] = boost::urls::format(
667*36d52334SEd Tanous                     "/redfish/v1/Chassis/{}/Drives/{}", chassisId, leafName);
668b2ba3072SPatrick Williams                 members.emplace_back(std::move(member));
66992903bd4SJohn Edward Broadbent                 // navigation links will be registered in next patch set
67092903bd4SJohn Edward Broadbent             }
67192903bd4SJohn Edward Broadbent             asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
67292903bd4SJohn Edward Broadbent             }); // end association lambda
67392903bd4SJohn Edward Broadbent 
67492903bd4SJohn Edward Broadbent     }           // end Iterate over all retrieved ObjectPaths
675*36d52334SEd Tanous }
676*36d52334SEd Tanous /**
677*36d52334SEd Tanous  * Chassis drives, this URL will show all the DriveCollection
678*36d52334SEd Tanous  * information
679*36d52334SEd Tanous  */
680*36d52334SEd Tanous inline void chassisDriveCollectionGet(
681*36d52334SEd Tanous     crow::App& app, const crow::Request& req,
682*36d52334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
683*36d52334SEd Tanous     const std::string& chassisId)
684*36d52334SEd Tanous {
685*36d52334SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
686*36d52334SEd Tanous     {
687*36d52334SEd Tanous         return;
688*36d52334SEd Tanous     }
689*36d52334SEd Tanous 
690*36d52334SEd Tanous     // mapper call lambda
691*36d52334SEd Tanous     constexpr std::array<std::string_view, 2> interfaces = {
692*36d52334SEd Tanous         "xyz.openbmc_project.Inventory.Item.Board",
693*36d52334SEd Tanous         "xyz.openbmc_project.Inventory.Item.Chassis"};
694*36d52334SEd Tanous     dbus::utility::getSubTree(
695*36d52334SEd Tanous         "/xyz/openbmc_project/inventory", 0, interfaces,
696*36d52334SEd Tanous         std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp,
697*36d52334SEd Tanous                         chassisId));
69892903bd4SJohn Edward Broadbent }
69992903bd4SJohn Edward Broadbent 
70092903bd4SJohn Edward Broadbent inline void requestRoutesChassisDrive(App& app)
70192903bd4SJohn Edward Broadbent {
70292903bd4SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
70392903bd4SJohn Edward Broadbent         .privileges(redfish::privileges::getDriveCollection)
70492903bd4SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
70592903bd4SJohn Edward Broadbent             std::bind_front(chassisDriveCollectionGet, std::ref(app)));
70692903bd4SJohn Edward Broadbent }
70792903bd4SJohn Edward Broadbent 
708b53dcd9dSNan Zhou inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
709b53dcd9dSNan Zhou                        const std::string& chassisId,
710b53dcd9dSNan Zhou                        const std::string& driveName,
7115e7e2dc5SEd Tanous                        const boost::system::error_code& ec,
712e56ed6b9SJohn Edward Broadbent                        const dbus::utility::MapperGetSubTreeResponse& subtree)
713e56ed6b9SJohn Edward Broadbent {
714e56ed6b9SJohn Edward Broadbent     if (ec)
715e56ed6b9SJohn Edward Broadbent     {
716e56ed6b9SJohn Edward Broadbent         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
717e56ed6b9SJohn Edward Broadbent         messages::internalError(asyncResp->res);
718e56ed6b9SJohn Edward Broadbent         return;
719e56ed6b9SJohn Edward Broadbent     }
720e56ed6b9SJohn Edward Broadbent 
721e56ed6b9SJohn Edward Broadbent     // Iterate over all retrieved ObjectPaths.
7228cb65f8aSNan Zhou     for (const auto& [path, connectionNames] : subtree)
723e56ed6b9SJohn Edward Broadbent     {
724e56ed6b9SJohn Edward Broadbent         sdbusplus::message::object_path objPath(path);
725e56ed6b9SJohn Edward Broadbent         if (objPath.filename() != driveName)
726e56ed6b9SJohn Edward Broadbent         {
727e56ed6b9SJohn Edward Broadbent             continue;
728e56ed6b9SJohn Edward Broadbent         }
729e56ed6b9SJohn Edward Broadbent 
730e56ed6b9SJohn Edward Broadbent         if (connectionNames.empty())
731e56ed6b9SJohn Edward Broadbent         {
732e56ed6b9SJohn Edward Broadbent             BMCWEB_LOG_ERROR << "Got 0 Connection names";
733e56ed6b9SJohn Edward Broadbent             continue;
734e56ed6b9SJohn Edward Broadbent         }
735e56ed6b9SJohn Edward Broadbent 
736ef4c65b7SEd Tanous         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
737ef4c65b7SEd Tanous             "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
738e56ed6b9SJohn Edward Broadbent 
739e56ed6b9SJohn Edward Broadbent         asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
740a0cb40cbSJohn Edward Broadbent         asyncResp->res.jsonValue["Name"] = driveName;
741e56ed6b9SJohn Edward Broadbent         asyncResp->res.jsonValue["Id"] = driveName;
742e56ed6b9SJohn Edward Broadbent         // default it to Enabled
743e56ed6b9SJohn Edward Broadbent         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
744e56ed6b9SJohn Edward Broadbent 
745e56ed6b9SJohn Edward Broadbent         nlohmann::json::object_t linkChassisNav;
746e56ed6b9SJohn Edward Broadbent         linkChassisNav["@odata.id"] =
747ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
748e56ed6b9SJohn Edward Broadbent         asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
749e56ed6b9SJohn Edward Broadbent 
750e56ed6b9SJohn Edward Broadbent         addAllDriveInfo(asyncResp, connectionNames[0].first, path,
751e56ed6b9SJohn Edward Broadbent                         connectionNames[0].second);
752e56ed6b9SJohn Edward Broadbent     }
753e56ed6b9SJohn Edward Broadbent }
754e56ed6b9SJohn Edward Broadbent 
755b53dcd9dSNan Zhou inline void
756b53dcd9dSNan Zhou     matchAndFillDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
757e56ed6b9SJohn Edward Broadbent                       const std::string& chassisId,
758e56ed6b9SJohn Edward Broadbent                       const std::string& driveName,
759e56ed6b9SJohn Edward Broadbent                       const std::vector<std::string>& resp)
760e56ed6b9SJohn Edward Broadbent {
761e56ed6b9SJohn Edward Broadbent     for (const std::string& drivePath : resp)
762e56ed6b9SJohn Edward Broadbent     {
763e56ed6b9SJohn Edward Broadbent         sdbusplus::message::object_path path(drivePath);
764e56ed6b9SJohn Edward Broadbent         std::string leaf = path.filename();
765e56ed6b9SJohn Edward Broadbent         if (leaf != driveName)
766e56ed6b9SJohn Edward Broadbent         {
767e56ed6b9SJohn Edward Broadbent             continue;
768e56ed6b9SJohn Edward Broadbent         }
769e56ed6b9SJohn Edward Broadbent         //  mapper call drive
770e99073f5SGeorge Liu         constexpr std::array<std::string_view, 1> driveInterface = {
771e56ed6b9SJohn Edward Broadbent             "xyz.openbmc_project.Inventory.Item.Drive"};
772e99073f5SGeorge Liu         dbus::utility::getSubTree(
773e99073f5SGeorge Liu             "/xyz/openbmc_project/inventory", 0, driveInterface,
774e56ed6b9SJohn Edward Broadbent             [asyncResp, chassisId, driveName](
775e99073f5SGeorge Liu                 const boost::system::error_code& ec,
776e56ed6b9SJohn Edward Broadbent                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
777e56ed6b9SJohn Edward Broadbent             buildDrive(asyncResp, chassisId, driveName, ec, subtree);
778e99073f5SGeorge Liu             });
779e56ed6b9SJohn Edward Broadbent     }
780e56ed6b9SJohn Edward Broadbent }
781e56ed6b9SJohn Edward Broadbent 
782b53dcd9dSNan Zhou inline void
783b53dcd9dSNan Zhou     handleChassisDriveGet(crow::App& app, const crow::Request& req,
784e56ed6b9SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
785e56ed6b9SJohn Edward Broadbent                           const std::string& chassisId,
786e56ed6b9SJohn Edward Broadbent                           const std::string& driveName)
787e56ed6b9SJohn Edward Broadbent {
78803810a11SMichal Orzel     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
789e56ed6b9SJohn Edward Broadbent     {
790e56ed6b9SJohn Edward Broadbent         return;
791e56ed6b9SJohn Edward Broadbent     }
792e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
793e56ed6b9SJohn Edward Broadbent         "xyz.openbmc_project.Inventory.Item.Board",
794e56ed6b9SJohn Edward Broadbent         "xyz.openbmc_project.Inventory.Item.Chassis"};
795e56ed6b9SJohn Edward Broadbent 
796e56ed6b9SJohn Edward Broadbent     // mapper call chassis
797e99073f5SGeorge Liu     dbus::utility::getSubTree(
798e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
799e56ed6b9SJohn Edward Broadbent         [asyncResp, chassisId,
800e99073f5SGeorge Liu          driveName](const boost::system::error_code& ec,
801e56ed6b9SJohn Edward Broadbent                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
802e56ed6b9SJohn Edward Broadbent         if (ec)
803e56ed6b9SJohn Edward Broadbent         {
804e56ed6b9SJohn Edward Broadbent             messages::internalError(asyncResp->res);
805e56ed6b9SJohn Edward Broadbent             return;
806e56ed6b9SJohn Edward Broadbent         }
807e56ed6b9SJohn Edward Broadbent 
808e56ed6b9SJohn Edward Broadbent         // Iterate over all retrieved ObjectPaths.
8098cb65f8aSNan Zhou         for (const auto& [path, connectionNames] : subtree)
810e56ed6b9SJohn Edward Broadbent         {
811e56ed6b9SJohn Edward Broadbent             sdbusplus::message::object_path objPath(path);
812e56ed6b9SJohn Edward Broadbent             if (objPath.filename() != chassisId)
813e56ed6b9SJohn Edward Broadbent             {
814e56ed6b9SJohn Edward Broadbent                 continue;
815e56ed6b9SJohn Edward Broadbent             }
816e56ed6b9SJohn Edward Broadbent 
817e56ed6b9SJohn Edward Broadbent             if (connectionNames.empty())
818e56ed6b9SJohn Edward Broadbent             {
819e56ed6b9SJohn Edward Broadbent                 BMCWEB_LOG_ERROR << "Got 0 Connection names";
820e56ed6b9SJohn Edward Broadbent                 continue;
821e56ed6b9SJohn Edward Broadbent             }
822e56ed6b9SJohn Edward Broadbent 
8236c3e9451SGeorge Liu             dbus::utility::getAssociationEndPoints(
8246c3e9451SGeorge Liu                 path + "/drive",
825e56ed6b9SJohn Edward Broadbent                 [asyncResp, chassisId,
8265e7e2dc5SEd Tanous                  driveName](const boost::system::error_code& ec3,
8276c3e9451SGeorge Liu                             const dbus::utility::MapperEndPoints& resp) {
828e56ed6b9SJohn Edward Broadbent                 if (ec3)
829e56ed6b9SJohn Edward Broadbent                 {
830e56ed6b9SJohn Edward Broadbent                     return; // no drives = no failures
831e56ed6b9SJohn Edward Broadbent                 }
832e56ed6b9SJohn Edward Broadbent                 matchAndFillDrive(asyncResp, chassisId, driveName, resp);
833e56ed6b9SJohn Edward Broadbent                 });
834e56ed6b9SJohn Edward Broadbent             break;
835e56ed6b9SJohn Edward Broadbent         }
836e99073f5SGeorge Liu         });
837e56ed6b9SJohn Edward Broadbent }
838e56ed6b9SJohn Edward Broadbent 
839e56ed6b9SJohn Edward Broadbent /**
840e56ed6b9SJohn Edward Broadbent  * This URL will show the drive interface for the specific drive in the chassis
841e56ed6b9SJohn Edward Broadbent  */
842e56ed6b9SJohn Edward Broadbent inline void requestRoutesChassisDriveName(App& app)
843e56ed6b9SJohn Edward Broadbent {
844e56ed6b9SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
845e56ed6b9SJohn Edward Broadbent         .privileges(redfish::privileges::getChassis)
846e56ed6b9SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
847e56ed6b9SJohn Edward Broadbent             std::bind_front(handleChassisDriveGet, std::ref(app)));
848e56ed6b9SJohn Edward Broadbent }
849e56ed6b9SJohn Edward Broadbent 
85061b1eb21SWilly Tu inline void getStorageControllerAsset(
85161b1eb21SWilly Tu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
85261b1eb21SWilly Tu     const boost::system::error_code& ec,
85361b1eb21SWilly Tu     const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
85461b1eb21SWilly Tu         propertiesList)
85561b1eb21SWilly Tu {
85661b1eb21SWilly Tu     if (ec)
85761b1eb21SWilly Tu     {
85861b1eb21SWilly Tu         // this interface isn't necessary
85961b1eb21SWilly Tu         BMCWEB_LOG_DEBUG << "Failed to get StorageControllerAsset";
86061b1eb21SWilly Tu         return;
86161b1eb21SWilly Tu     }
86261b1eb21SWilly Tu 
86361b1eb21SWilly Tu     const std::string* partNumber = nullptr;
86461b1eb21SWilly Tu     const std::string* serialNumber = nullptr;
86561b1eb21SWilly Tu     const std::string* manufacturer = nullptr;
86661b1eb21SWilly Tu     const std::string* model = nullptr;
86761b1eb21SWilly Tu     if (!sdbusplus::unpackPropertiesNoThrow(
86861b1eb21SWilly Tu             dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
86961b1eb21SWilly Tu             partNumber, "SerialNumber", serialNumber, "Manufacturer",
87061b1eb21SWilly Tu             manufacturer, "Model", model))
87161b1eb21SWilly Tu     {
87261b1eb21SWilly Tu         messages::internalError(asyncResp->res);
87361b1eb21SWilly Tu         return;
87461b1eb21SWilly Tu     }
87561b1eb21SWilly Tu 
87661b1eb21SWilly Tu     if (partNumber != nullptr)
87761b1eb21SWilly Tu     {
87861b1eb21SWilly Tu         asyncResp->res.jsonValue["PartNumber"] = *partNumber;
87961b1eb21SWilly Tu     }
88061b1eb21SWilly Tu 
88161b1eb21SWilly Tu     if (serialNumber != nullptr)
88261b1eb21SWilly Tu     {
88361b1eb21SWilly Tu         asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
88461b1eb21SWilly Tu     }
88561b1eb21SWilly Tu 
88661b1eb21SWilly Tu     if (manufacturer != nullptr)
88761b1eb21SWilly Tu     {
88861b1eb21SWilly Tu         asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
88961b1eb21SWilly Tu     }
89061b1eb21SWilly Tu 
89161b1eb21SWilly Tu     if (model != nullptr)
89261b1eb21SWilly Tu     {
89361b1eb21SWilly Tu         asyncResp->res.jsonValue["Model"] = *model;
89461b1eb21SWilly Tu     }
89561b1eb21SWilly Tu }
89661b1eb21SWilly Tu 
89761b1eb21SWilly Tu inline void populateStorageController(
89861b1eb21SWilly Tu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
89961b1eb21SWilly Tu     const std::string& controllerId, const std::string& connectionName,
90061b1eb21SWilly Tu     const std::string& path)
90161b1eb21SWilly Tu {
90261b1eb21SWilly Tu     asyncResp->res.jsonValue["@odata.type"] =
90361b1eb21SWilly Tu         "#StorageController.v1_6_0.StorageController";
90461b1eb21SWilly Tu     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
90561b1eb21SWilly Tu         "/redfish/v1/Systems/system/Storage/1/Controllers/{}", controllerId);
90661b1eb21SWilly Tu     asyncResp->res.jsonValue["Name"] = controllerId;
90761b1eb21SWilly Tu     asyncResp->res.jsonValue["Id"] = controllerId;
90861b1eb21SWilly Tu     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
90961b1eb21SWilly Tu 
91061b1eb21SWilly Tu     sdbusplus::asio::getProperty<bool>(
91161b1eb21SWilly Tu         *crow::connections::systemBus, connectionName, path,
91261b1eb21SWilly Tu         "xyz.openbmc_project.Inventory.Item", "Present",
91361b1eb21SWilly Tu         [asyncResp](const boost::system::error_code& ec, bool isPresent) {
91461b1eb21SWilly Tu         // this interface isn't necessary, only check it
91561b1eb21SWilly Tu         // if we get a good return
91661b1eb21SWilly Tu         if (ec)
91761b1eb21SWilly Tu         {
91861b1eb21SWilly Tu             BMCWEB_LOG_DEBUG << "Failed to get Present property";
91961b1eb21SWilly Tu             return;
92061b1eb21SWilly Tu         }
92161b1eb21SWilly Tu         if (!isPresent)
92261b1eb21SWilly Tu         {
92361b1eb21SWilly Tu             asyncResp->res.jsonValue["Status"]["State"] = "Absent";
92461b1eb21SWilly Tu         }
92561b1eb21SWilly Tu         });
92661b1eb21SWilly Tu 
92761b1eb21SWilly Tu     sdbusplus::asio::getAllProperties(
92861b1eb21SWilly Tu         *crow::connections::systemBus, connectionName, path,
92961b1eb21SWilly Tu         "xyz.openbmc_project.Inventory.Decorator.Asset",
93061b1eb21SWilly Tu         [asyncResp](const boost::system::error_code& ec,
93161b1eb21SWilly Tu                     const std::vector<
93261b1eb21SWilly Tu                         std::pair<std::string, dbus::utility::DbusVariantType>>&
93361b1eb21SWilly Tu                         propertiesList) {
93461b1eb21SWilly Tu         getStorageControllerAsset(asyncResp, ec, propertiesList);
93561b1eb21SWilly Tu         });
93661b1eb21SWilly Tu }
93761b1eb21SWilly Tu 
93861b1eb21SWilly Tu inline void getStorageControllerHandler(
93961b1eb21SWilly Tu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
94061b1eb21SWilly Tu     const std::string& controllerId, const boost::system::error_code& ec,
94161b1eb21SWilly Tu     const dbus::utility::MapperGetSubTreeResponse& subtree)
94261b1eb21SWilly Tu {
94361b1eb21SWilly Tu     if (ec || subtree.empty())
94461b1eb21SWilly Tu     {
94561b1eb21SWilly Tu         // doesn't have to be there
94661b1eb21SWilly Tu         BMCWEB_LOG_DEBUG << "Failed to handle StorageController";
94761b1eb21SWilly Tu         return;
94861b1eb21SWilly Tu     }
94961b1eb21SWilly Tu 
95061b1eb21SWilly Tu     for (const auto& [path, interfaceDict] : subtree)
95161b1eb21SWilly Tu     {
95261b1eb21SWilly Tu         sdbusplus::message::object_path object(path);
95361b1eb21SWilly Tu         std::string id = object.filename();
95461b1eb21SWilly Tu         if (id.empty())
95561b1eb21SWilly Tu         {
95661b1eb21SWilly Tu             BMCWEB_LOG_ERROR << "Failed to find filename in " << path;
95761b1eb21SWilly Tu             return;
95861b1eb21SWilly Tu         }
95961b1eb21SWilly Tu         if (id != controllerId)
96061b1eb21SWilly Tu         {
96161b1eb21SWilly Tu             continue;
96261b1eb21SWilly Tu         }
96361b1eb21SWilly Tu 
96461b1eb21SWilly Tu         if (interfaceDict.size() != 1)
96561b1eb21SWilly Tu         {
96661b1eb21SWilly Tu             BMCWEB_LOG_ERROR << "Connection size " << interfaceDict.size()
96761b1eb21SWilly Tu                              << ", greater than 1";
96861b1eb21SWilly Tu             messages::internalError(asyncResp->res);
96961b1eb21SWilly Tu             return;
97061b1eb21SWilly Tu         }
97161b1eb21SWilly Tu 
97261b1eb21SWilly Tu         const std::string& connectionName = interfaceDict.front().first;
97361b1eb21SWilly Tu         populateStorageController(asyncResp, controllerId, connectionName,
97461b1eb21SWilly Tu                                   path);
97561b1eb21SWilly Tu     }
97661b1eb21SWilly Tu }
97761b1eb21SWilly Tu 
97861b1eb21SWilly Tu inline void populateStorageControllerCollection(
97961b1eb21SWilly Tu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
98061b1eb21SWilly Tu     const boost::system::error_code& ec,
98161b1eb21SWilly Tu     const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
98261b1eb21SWilly Tu {
98361b1eb21SWilly Tu     nlohmann::json::array_t members;
98461b1eb21SWilly Tu     if (ec || controllerList.empty())
98561b1eb21SWilly Tu     {
98661b1eb21SWilly Tu         asyncResp->res.jsonValue["Members"] = std::move(members);
98761b1eb21SWilly Tu         asyncResp->res.jsonValue["Members@odata.count"] = 0;
98861b1eb21SWilly Tu         BMCWEB_LOG_DEBUG << "Failed to find any StorageController";
98961b1eb21SWilly Tu         return;
99061b1eb21SWilly Tu     }
99161b1eb21SWilly Tu 
99261b1eb21SWilly Tu     for (const std::string& path : controllerList)
99361b1eb21SWilly Tu     {
99461b1eb21SWilly Tu         std::string id = sdbusplus::message::object_path(path).filename();
99561b1eb21SWilly Tu         if (id.empty())
99661b1eb21SWilly Tu         {
99761b1eb21SWilly Tu             BMCWEB_LOG_ERROR << "Failed to find filename in " << path;
99861b1eb21SWilly Tu             return;
99961b1eb21SWilly Tu         }
100061b1eb21SWilly Tu         nlohmann::json::object_t member;
100161b1eb21SWilly Tu         member["@odata.id"] = boost::urls::format(
100261b1eb21SWilly Tu             "/redfish/v1/Systems/system/Storage/1/Controllers/{}", id);
100361b1eb21SWilly Tu         members.emplace_back(member);
100461b1eb21SWilly Tu     }
100561b1eb21SWilly Tu     asyncResp->res.jsonValue["Members@odata.count"] = members.size();
100661b1eb21SWilly Tu     asyncResp->res.jsonValue["Members"] = std::move(members);
100761b1eb21SWilly Tu }
100861b1eb21SWilly Tu 
1009*36d52334SEd Tanous inline void handleSystemsStorageControllerCollectionGet(
101061b1eb21SWilly Tu     App& app, const crow::Request& req,
101161b1eb21SWilly Tu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
101261b1eb21SWilly Tu     const std::string& systemName)
101361b1eb21SWilly Tu {
101461b1eb21SWilly Tu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
101561b1eb21SWilly Tu     {
101661b1eb21SWilly Tu         BMCWEB_LOG_DEBUG
101761b1eb21SWilly Tu             << "Failed to setup Redfish Route for StorageController Collection";
101861b1eb21SWilly Tu         return;
101961b1eb21SWilly Tu     }
102061b1eb21SWilly Tu     if (systemName != "system")
102161b1eb21SWilly Tu     {
102261b1eb21SWilly Tu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
102361b1eb21SWilly Tu                                    systemName);
102461b1eb21SWilly Tu         BMCWEB_LOG_DEBUG << "Failed to find ComputerSystem of " << systemName;
102561b1eb21SWilly Tu         return;
102661b1eb21SWilly Tu     }
102761b1eb21SWilly Tu 
102861b1eb21SWilly Tu     asyncResp->res.jsonValue["@odata.type"] =
102961b1eb21SWilly Tu         "#StorageControllerCollection.StorageControllerCollection";
103061b1eb21SWilly Tu     asyncResp->res.jsonValue["@odata.id"] =
103161b1eb21SWilly Tu         "/redfish/v1/Systems/system/Storage/1/Controllers";
103261b1eb21SWilly Tu     asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
103361b1eb21SWilly Tu 
103461b1eb21SWilly Tu     constexpr std::array<std::string_view, 1> interfaces = {
103561b1eb21SWilly Tu         "xyz.openbmc_project.Inventory.Item.StorageController"};
103661b1eb21SWilly Tu     dbus::utility::getSubTreePaths(
103761b1eb21SWilly Tu         "/xyz/openbmc_project/inventory", 0, interfaces,
103861b1eb21SWilly Tu         [asyncResp](const boost::system::error_code& ec,
103961b1eb21SWilly Tu                     const dbus::utility::MapperGetSubTreePathsResponse&
104061b1eb21SWilly Tu                         controllerList) {
104161b1eb21SWilly Tu         populateStorageControllerCollection(asyncResp, ec, controllerList);
104261b1eb21SWilly Tu         });
104361b1eb21SWilly Tu }
104461b1eb21SWilly Tu 
1045*36d52334SEd Tanous inline void handleSystemsStorageControllerGet(
104661b1eb21SWilly Tu     App& app, const crow::Request& req,
104761b1eb21SWilly Tu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
104861b1eb21SWilly Tu     const std::string& systemName, const std::string& controllerId)
104961b1eb21SWilly Tu {
105061b1eb21SWilly Tu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
105161b1eb21SWilly Tu     {
105261b1eb21SWilly Tu         BMCWEB_LOG_DEBUG
105361b1eb21SWilly Tu             << "Failed to setup Redfish Route for StorageController";
105461b1eb21SWilly Tu         return;
105561b1eb21SWilly Tu     }
105661b1eb21SWilly Tu     if (systemName != "system")
105761b1eb21SWilly Tu     {
105861b1eb21SWilly Tu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
105961b1eb21SWilly Tu                                    systemName);
106061b1eb21SWilly Tu         BMCWEB_LOG_DEBUG << "Failed to find ComputerSystem of " << systemName;
106161b1eb21SWilly Tu         return;
106261b1eb21SWilly Tu     }
106361b1eb21SWilly Tu     constexpr std::array<std::string_view, 1> interfaces = {
106461b1eb21SWilly Tu         "xyz.openbmc_project.Inventory.Item.StorageController"};
106561b1eb21SWilly Tu     dbus::utility::getSubTree(
106661b1eb21SWilly Tu         "/xyz/openbmc_project/inventory", 0, interfaces,
106761b1eb21SWilly Tu         [asyncResp,
106861b1eb21SWilly Tu          controllerId](const boost::system::error_code& ec,
106961b1eb21SWilly Tu                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
107061b1eb21SWilly Tu         getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
107161b1eb21SWilly Tu         });
107261b1eb21SWilly Tu }
107361b1eb21SWilly Tu 
107461b1eb21SWilly Tu inline void requestRoutesStorageControllerCollection(App& app)
107561b1eb21SWilly Tu {
107661b1eb21SWilly Tu     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
107761b1eb21SWilly Tu         .privileges(redfish::privileges::getStorageControllerCollection)
1078*36d52334SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
1079*36d52334SEd Tanous             handleSystemsStorageControllerCollectionGet, std::ref(app)));
108061b1eb21SWilly Tu }
108161b1eb21SWilly Tu 
108261b1eb21SWilly Tu inline void requestRoutesStorageController(App& app)
108361b1eb21SWilly Tu {
108461b1eb21SWilly Tu     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
108561b1eb21SWilly Tu         .privileges(redfish::privileges::getStorageController)
108661b1eb21SWilly Tu         .methods(boost::beast::http::verb::get)(
1087*36d52334SEd Tanous             std::bind_front(handleSystemsStorageControllerGet, std::ref(app)));
108861b1eb21SWilly Tu }
108961b1eb21SWilly Tu 
1090a25aeccfSNikhil Potade } // namespace redfish
1091