xref: /openbmc/bmcweb/features/redfish/lib/storage.hpp (revision dfababfc65fb9f07050070910be0cc015df4fd2c)
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 
182ad9c2f6SJames Feist #include "health.hpp"
19e284a7c1SJames Feist #include "openbmc_dbus_rest.hpp"
202ad9c2f6SJames Feist 
217e860f15SJohn Edward Broadbent #include <app.hpp>
22168e20c1SEd Tanous #include <dbus_utility.hpp>
2345ca1b86SEd Tanous #include <query.hpp>
24ed398213SEd Tanous #include <registries/privilege_registry.hpp>
251e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
26a25aeccfSNikhil Potade 
27a25aeccfSNikhil Potade namespace redfish
28a25aeccfSNikhil Potade {
297e860f15SJohn Edward Broadbent inline void requestRoutesStorageCollection(App& app)
30a25aeccfSNikhil Potade {
317e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/")
32ed398213SEd Tanous         .privileges(redfish::privileges::getStorageCollection)
337e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
3445ca1b86SEd Tanous             [&app](const crow::Request& req,
357e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3645ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3745ca1b86SEd Tanous                 {
3845ca1b86SEd Tanous                     return;
3945ca1b86SEd Tanous                 }
408d1b46d7Szhanghch05                 asyncResp->res.jsonValue["@odata.type"] =
418d1b46d7Szhanghch05                     "#StorageCollection.StorageCollection";
428d1b46d7Szhanghch05                 asyncResp->res.jsonValue["@odata.id"] =
438d1b46d7Szhanghch05                     "/redfish/v1/Systems/system/Storage";
448d1b46d7Szhanghch05                 asyncResp->res.jsonValue["Name"] = "Storage Collection";
451476687dSEd Tanous                 nlohmann::json::array_t members;
461476687dSEd Tanous                 nlohmann::json::object_t member;
471476687dSEd Tanous                 member["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
481476687dSEd Tanous                 members.emplace_back(member);
491476687dSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(members);
508d1b46d7Szhanghch05                 asyncResp->res.jsonValue["Members@odata.count"] = 1;
517e860f15SJohn Edward Broadbent             });
52a25aeccfSNikhil Potade }
53a25aeccfSNikhil Potade 
547e860f15SJohn Edward Broadbent inline void requestRoutesStorage(App& app)
55a25aeccfSNikhil Potade {
567e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/")
57ed398213SEd Tanous         .privileges(redfish::privileges::getStorage)
5845ca1b86SEd Tanous         .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
5945ca1b86SEd Tanous                                                        const std::shared_ptr<
6045ca1b86SEd Tanous                                                            bmcweb::AsyncResp>&
6145ca1b86SEd Tanous                                                            asyncResp) {
6245ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
6345ca1b86SEd Tanous             {
6445ca1b86SEd Tanous                 return;
6545ca1b86SEd Tanous             }
668d1b46d7Szhanghch05             asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage";
678d1b46d7Szhanghch05             asyncResp->res.jsonValue["@odata.id"] =
688d1b46d7Szhanghch05                 "/redfish/v1/Systems/system/Storage/1";
698d1b46d7Szhanghch05             asyncResp->res.jsonValue["Name"] = "Storage";
708d1b46d7Szhanghch05             asyncResp->res.jsonValue["Id"] = "1";
718d1b46d7Szhanghch05             asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
72a25aeccfSNikhil Potade 
73e284a7c1SJames Feist             auto health = std::make_shared<HealthPopulate>(asyncResp);
74e284a7c1SJames Feist             health->populate();
75e284a7c1SJames Feist 
76a25aeccfSNikhil Potade             crow::connections::systemBus->async_method_call(
777e860f15SJohn Edward Broadbent                 [asyncResp,
787e860f15SJohn Edward Broadbent                  health](const boost::system::error_code ec,
79b9d36b47SEd Tanous                          const dbus::utility::MapperGetSubTreePathsResponse&
80b9d36b47SEd Tanous                              storageList) {
81a25aeccfSNikhil Potade                     nlohmann::json& storageArray =
82a25aeccfSNikhil Potade                         asyncResp->res.jsonValue["Drives"];
83a25aeccfSNikhil Potade                     storageArray = nlohmann::json::array();
847e860f15SJohn Edward Broadbent                     auto& count =
857e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Drives@odata.count"];
86e284a7c1SJames Feist                     count = 0;
872ad9c2f6SJames Feist 
88a25aeccfSNikhil Potade                     if (ec)
89a25aeccfSNikhil Potade                     {
90a25aeccfSNikhil Potade                         BMCWEB_LOG_ERROR << "Drive mapper call error";
91a25aeccfSNikhil Potade                         messages::internalError(asyncResp->res);
92a25aeccfSNikhil Potade                         return;
93a25aeccfSNikhil Potade                     }
942ad9c2f6SJames Feist 
95e284a7c1SJames Feist                     health->inventory.insert(health->inventory.end(),
96e284a7c1SJames Feist                                              storageList.begin(),
97e284a7c1SJames Feist                                              storageList.end());
982ad9c2f6SJames Feist 
99a25aeccfSNikhil Potade                     for (const std::string& objpath : storageList)
100a25aeccfSNikhil Potade                     {
101f23b7296SEd Tanous                         std::size_t lastPos = objpath.rfind('/');
102a25aeccfSNikhil Potade                         if (lastPos == std::string::npos ||
103a25aeccfSNikhil Potade                             (objpath.size() <= lastPos + 1))
104a25aeccfSNikhil Potade                         {
1057e860f15SJohn Edward Broadbent                             BMCWEB_LOG_ERROR << "Failed to find '/' in "
1067e860f15SJohn Edward Broadbent                                              << objpath;
107a25aeccfSNikhil Potade                             continue;
108a25aeccfSNikhil Potade                         }
1091476687dSEd Tanous                         nlohmann::json::object_t storage;
1101476687dSEd Tanous                         storage["@odata.id"] =
111be13ceceSJames Feist                             "/redfish/v1/Systems/system/Storage/1/Drives/" +
1121476687dSEd Tanous                             objpath.substr(lastPos + 1);
1131476687dSEd Tanous                         storageArray.push_back(std::move(storage));
114a25aeccfSNikhil Potade                     }
115a25aeccfSNikhil Potade 
116e284a7c1SJames Feist                     count = storageArray.size();
117a25aeccfSNikhil Potade                 },
118a25aeccfSNikhil Potade                 "xyz.openbmc_project.ObjectMapper",
119a25aeccfSNikhil Potade                 "/xyz/openbmc_project/object_mapper",
120a25aeccfSNikhil Potade                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
121a25aeccfSNikhil Potade                 "/xyz/openbmc_project/inventory", int32_t(0),
122a25aeccfSNikhil Potade                 std::array<const char*, 1>{
123a25aeccfSNikhil Potade                     "xyz.openbmc_project.Inventory.Item.Drive"});
124e284a7c1SJames Feist 
125e284a7c1SJames Feist             crow::connections::systemBus->async_method_call(
126b9d36b47SEd Tanous                 [asyncResp, health](
127b9d36b47SEd Tanous                     const boost::system::error_code ec,
128b9d36b47SEd Tanous                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
12926f6976fSEd Tanous                     if (ec || subtree.empty())
130e284a7c1SJames Feist                     {
131d819a420SJames Feist                         // doesn't have to be there
132e284a7c1SJames Feist                         return;
133e284a7c1SJames Feist                     }
134e284a7c1SJames Feist 
135e284a7c1SJames Feist                     nlohmann::json& root =
136e284a7c1SJames Feist                         asyncResp->res.jsonValue["StorageControllers"];
137e284a7c1SJames Feist                     root = nlohmann::json::array();
138e284a7c1SJames Feist                     for (const auto& [path, interfaceDict] : subtree)
139e284a7c1SJames Feist                     {
140f23b7296SEd Tanous                         std::size_t lastPos = path.rfind('/');
141e284a7c1SJames Feist                         if (lastPos == std::string::npos ||
142e284a7c1SJames Feist                             (path.size() <= lastPos + 1))
143e284a7c1SJames Feist                         {
1447e860f15SJohn Edward Broadbent                             BMCWEB_LOG_ERROR << "Failed to find '/' in "
1457e860f15SJohn Edward Broadbent                                              << path;
146e284a7c1SJames Feist                             return;
147e284a7c1SJames Feist                         }
148e284a7c1SJames Feist 
149e284a7c1SJames Feist                         if (interfaceDict.size() != 1)
150e284a7c1SJames Feist                         {
151e284a7c1SJames Feist                             BMCWEB_LOG_ERROR << "Connection size "
152e284a7c1SJames Feist                                              << interfaceDict.size()
153e284a7c1SJames Feist                                              << ", greater than 1";
154e284a7c1SJames Feist                             messages::internalError(asyncResp->res);
155e284a7c1SJames Feist                             return;
156e284a7c1SJames Feist                         }
157e284a7c1SJames Feist 
158e284a7c1SJames Feist                         const std::string& connectionName =
159e284a7c1SJames Feist                             interfaceDict.front().first;
160e284a7c1SJames Feist 
161e284a7c1SJames Feist                         size_t index = root.size();
162e284a7c1SJames Feist                         nlohmann::json& storageController =
163e284a7c1SJames Feist                             root.emplace_back(nlohmann::json::object());
164e284a7c1SJames Feist 
165e284a7c1SJames Feist                         std::string id = path.substr(lastPos + 1);
166e284a7c1SJames Feist 
167e284a7c1SJames Feist                         storageController["@odata.type"] =
168e284a7c1SJames Feist                             "#Storage.v1_7_0.StorageController";
169e284a7c1SJames Feist                         storageController["@odata.id"] =
1700fda0f12SGeorge Liu                             "/redfish/v1/Systems/system/Storage/1#/StorageControllers/" +
171e284a7c1SJames Feist                             std::to_string(index);
172e284a7c1SJames Feist                         storageController["Name"] = id;
173e284a7c1SJames Feist                         storageController["MemberId"] = id;
174e284a7c1SJames Feist                         storageController["Status"]["State"] = "Enabled";
175e284a7c1SJames Feist 
1761e1e598dSJonathan Doman                         sdbusplus::asio::getProperty<bool>(
1771e1e598dSJonathan Doman                             *crow::connections::systemBus, connectionName, path,
1781e1e598dSJonathan Doman                             "xyz.openbmc_project.Inventory.Item", "Present",
1791e1e598dSJonathan Doman                             [asyncResp,
1801e1e598dSJonathan Doman                              index](const boost::system::error_code ec2,
1811e1e598dSJonathan Doman                                     bool enabled) {
1827e860f15SJohn Edward Broadbent                                 // this interface isn't necessary, only check it
1837e860f15SJohn Edward Broadbent                                 // if we get a good return
18423a21a1cSEd Tanous                                 if (ec2)
185e284a7c1SJames Feist                                 {
186e284a7c1SJames Feist                                     return;
187e284a7c1SJames Feist                                 }
1881e1e598dSJonathan Doman                                 if (!enabled)
189e284a7c1SJames Feist                                 {
190e284a7c1SJames Feist                                     asyncResp->res
191e284a7c1SJames Feist                                         .jsonValue["StorageControllers"][index]
1927e860f15SJohn Edward Broadbent                                                   ["Status"]["State"] =
1937e860f15SJohn Edward Broadbent                                         "Disabled";
194e284a7c1SJames Feist                                 }
1951e1e598dSJonathan Doman                             });
196e284a7c1SJames Feist 
197e284a7c1SJames Feist                         crow::connections::systemBus->async_method_call(
1987e860f15SJohn Edward Broadbent                             [asyncResp, index](
1997e860f15SJohn Edward Broadbent                                 const boost::system::error_code ec2,
200168e20c1SEd Tanous                                 const std::vector<
201168e20c1SEd Tanous                                     std::pair<std::string,
202168e20c1SEd Tanous                                               dbus::utility::DbusVariantType>>&
2037e860f15SJohn Edward Broadbent                                     propertiesList) {
2047e860f15SJohn Edward Broadbent                                 if (ec2)
2057e860f15SJohn Edward Broadbent                                 {
2067e860f15SJohn Edward Broadbent                                     // this interface isn't necessary
2077e860f15SJohn Edward Broadbent                                     return;
2087e860f15SJohn Edward Broadbent                                 }
2097e860f15SJohn Edward Broadbent                                 for (const std::pair<
2107e860f15SJohn Edward Broadbent                                          std::string,
211168e20c1SEd Tanous                                          dbus::utility::DbusVariantType>&
212168e20c1SEd Tanous                                          property : propertiesList)
2137e860f15SJohn Edward Broadbent                                 {
2147e860f15SJohn Edward Broadbent                                     // Store DBus properties that are also
2157e860f15SJohn Edward Broadbent                                     // Redfish properties with same name and a
2167e860f15SJohn Edward Broadbent                                     // string value
2177e860f15SJohn Edward Broadbent                                     const std::string& propertyName =
2187e860f15SJohn Edward Broadbent                                         property.first;
2197e860f15SJohn Edward Broadbent                                     nlohmann::json& object =
2207e860f15SJohn Edward Broadbent                                         asyncResp->res
2217e860f15SJohn Edward Broadbent                                             .jsonValue["StorageControllers"]
2227e860f15SJohn Edward Broadbent                                                       [index];
2237e860f15SJohn Edward Broadbent                                     if ((propertyName == "PartNumber") ||
2247e860f15SJohn Edward Broadbent                                         (propertyName == "SerialNumber") ||
2257e860f15SJohn Edward Broadbent                                         (propertyName == "Manufacturer") ||
2267e860f15SJohn Edward Broadbent                                         (propertyName == "Model"))
2277e860f15SJohn Edward Broadbent                                     {
2287e860f15SJohn Edward Broadbent                                         const std::string* value =
2297e860f15SJohn Edward Broadbent                                             std::get_if<std::string>(
2307e860f15SJohn Edward Broadbent                                                 &property.second);
2317e860f15SJohn Edward Broadbent                                         if (value == nullptr)
2327e860f15SJohn Edward Broadbent                                         {
2337e860f15SJohn Edward Broadbent                                             // illegal property
2347e860f15SJohn Edward Broadbent                                             messages::internalError(
2357e860f15SJohn Edward Broadbent                                                 asyncResp->res);
2367e860f15SJohn Edward Broadbent                                             return;
2377e860f15SJohn Edward Broadbent                                         }
2387e860f15SJohn Edward Broadbent                                         object[propertyName] = *value;
2397e860f15SJohn Edward Broadbent                                     }
2407e860f15SJohn Edward Broadbent                                 }
2417e860f15SJohn Edward Broadbent                             },
2427e860f15SJohn Edward Broadbent                             connectionName, path,
2437e860f15SJohn Edward Broadbent                             "org.freedesktop.DBus.Properties", "GetAll",
2447e860f15SJohn Edward Broadbent                             "xyz.openbmc_project.Inventory.Decorator.Asset");
2457e860f15SJohn Edward Broadbent                     }
2467e860f15SJohn Edward Broadbent 
2477e860f15SJohn Edward Broadbent                     // this is done after we know the json array will no longer
2487e860f15SJohn Edward Broadbent                     // be resized, as json::array uses vector underneath and we
2497e860f15SJohn Edward Broadbent                     // need references to its members that won't change
2507e860f15SJohn Edward Broadbent                     size_t count = 0;
251*dfababfcSNan Zhou                     // Pointer based on |asyncResp->res.jsonValue|
252*dfababfcSNan Zhou                     nlohmann::json::json_pointer rootPtr =
253*dfababfcSNan Zhou                         "/StorageControllers"_json_pointer;
2547e860f15SJohn Edward Broadbent                     for (const auto& [path, interfaceDict] : subtree)
2557e860f15SJohn Edward Broadbent                     {
2567e860f15SJohn Edward Broadbent                         auto subHealth = std::make_shared<HealthPopulate>(
257*dfababfcSNan Zhou                             asyncResp, rootPtr / count / "Status");
2587e860f15SJohn Edward Broadbent                         subHealth->inventory.emplace_back(path);
2597e860f15SJohn Edward Broadbent                         health->inventory.emplace_back(path);
2607e860f15SJohn Edward Broadbent                         health->children.emplace_back(subHealth);
2617e860f15SJohn Edward Broadbent                         count++;
2627e860f15SJohn Edward Broadbent                     }
2637e860f15SJohn Edward Broadbent                 },
2647e860f15SJohn Edward Broadbent                 "xyz.openbmc_project.ObjectMapper",
2657e860f15SJohn Edward Broadbent                 "/xyz/openbmc_project/object_mapper",
2667e860f15SJohn Edward Broadbent                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
2677e860f15SJohn Edward Broadbent                 "/xyz/openbmc_project/inventory", int32_t(0),
2687e860f15SJohn Edward Broadbent                 std::array<const char*, 1>{
2697e860f15SJohn Edward Broadbent                     "xyz.openbmc_project.Inventory.Item.StorageController"});
2707e860f15SJohn Edward Broadbent         });
2717e860f15SJohn Edward Broadbent }
2727e860f15SJohn Edward Broadbent 
27303913171SWilly Tu inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
27403913171SWilly Tu                           const std::string& connectionName,
27503913171SWilly Tu                           const std::string& path)
27603913171SWilly Tu {
27703913171SWilly Tu     crow::connections::systemBus->async_method_call(
278168e20c1SEd Tanous         [asyncResp](const boost::system::error_code ec,
279168e20c1SEd Tanous                     const std::vector<
280168e20c1SEd Tanous                         std::pair<std::string, dbus::utility::DbusVariantType>>&
28103913171SWilly Tu                         propertiesList) {
28203913171SWilly Tu             if (ec)
28303913171SWilly Tu             {
28403913171SWilly Tu                 // this interface isn't necessary
28503913171SWilly Tu                 return;
28603913171SWilly Tu             }
287168e20c1SEd Tanous             for (const std::pair<std::string, dbus::utility::DbusVariantType>&
28803913171SWilly Tu                      property : propertiesList)
28903913171SWilly Tu             {
29003913171SWilly Tu                 // Store DBus properties that are also
29103913171SWilly Tu                 // Redfish properties with same name and a
29203913171SWilly Tu                 // string value
29303913171SWilly Tu                 const std::string& propertyName = property.first;
29403913171SWilly Tu                 if ((propertyName == "PartNumber") ||
29503913171SWilly Tu                     (propertyName == "SerialNumber") ||
29603913171SWilly Tu                     (propertyName == "Manufacturer") ||
29703913171SWilly Tu                     (propertyName == "Model"))
29803913171SWilly Tu                 {
29903913171SWilly Tu                     const std::string* value =
30003913171SWilly Tu                         std::get_if<std::string>(&property.second);
30103913171SWilly Tu                     if (value == nullptr)
30203913171SWilly Tu                     {
30303913171SWilly Tu                         // illegal property
30403913171SWilly Tu                         messages::internalError(asyncResp->res);
30503913171SWilly Tu                         return;
30603913171SWilly Tu                     }
30703913171SWilly Tu                     asyncResp->res.jsonValue[propertyName] = *value;
30803913171SWilly Tu                 }
30903913171SWilly Tu             }
31003913171SWilly Tu         },
31103913171SWilly Tu         connectionName, path, "org.freedesktop.DBus.Properties", "GetAll",
31203913171SWilly Tu         "xyz.openbmc_project.Inventory.Decorator.Asset");
31303913171SWilly Tu }
31403913171SWilly Tu 
31503913171SWilly Tu inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
31603913171SWilly Tu                             const std::string& connectionName,
31703913171SWilly Tu                             const std::string& path)
31803913171SWilly Tu {
3191e1e598dSJonathan Doman     sdbusplus::asio::getProperty<bool>(
3201e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3211e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Item", "Present",
32203913171SWilly Tu         [asyncResp, path](const boost::system::error_code ec,
3231e1e598dSJonathan Doman                           const bool enabled) {
32403913171SWilly Tu             // this interface isn't necessary, only check it if
32503913171SWilly Tu             // we get a good return
32603913171SWilly Tu             if (ec)
32703913171SWilly Tu             {
32803913171SWilly Tu                 return;
32903913171SWilly Tu             }
33003913171SWilly Tu 
3311e1e598dSJonathan Doman             if (!enabled)
33203913171SWilly Tu             {
33303913171SWilly Tu                 asyncResp->res.jsonValue["Status"]["State"] = "Disabled";
33403913171SWilly Tu             }
3351e1e598dSJonathan Doman         });
33603913171SWilly Tu }
33703913171SWilly Tu 
33803913171SWilly Tu inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
33903913171SWilly Tu                           const std::string& connectionName,
34003913171SWilly Tu                           const std::string& path)
34103913171SWilly Tu {
3421e1e598dSJonathan Doman     sdbusplus::asio::getProperty<bool>(
3431e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3441e1e598dSJonathan Doman         "xyz.openbmc_project.State.Drive", "Rebuilding",
3451e1e598dSJonathan Doman         [asyncResp](const boost::system::error_code ec, const bool updating) {
34603913171SWilly Tu             // this interface isn't necessary, only check it
34703913171SWilly Tu             // if we get a good return
34803913171SWilly Tu             if (ec)
34903913171SWilly Tu             {
35003913171SWilly Tu                 return;
35103913171SWilly Tu             }
35203913171SWilly Tu 
35303913171SWilly Tu             // updating and disabled in the backend shouldn't be
35403913171SWilly Tu             // able to be set at the same time, so we don't need
35503913171SWilly Tu             // to check for the race condition of these two
35603913171SWilly Tu             // calls
3571e1e598dSJonathan Doman             if (updating)
35803913171SWilly Tu             {
35903913171SWilly Tu                 asyncResp->res.jsonValue["Status"]["State"] = "Updating";
36003913171SWilly Tu             }
3611e1e598dSJonathan Doman         });
36203913171SWilly Tu }
36303913171SWilly Tu 
36419b8e9a0SWilly Tu inline std::optional<std::string> convertDriveType(const std::string& type)
36519b8e9a0SWilly Tu {
36619b8e9a0SWilly Tu     if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
36719b8e9a0SWilly Tu     {
36819b8e9a0SWilly Tu         return "HDD";
36919b8e9a0SWilly Tu     }
37019b8e9a0SWilly Tu     if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
37119b8e9a0SWilly Tu     {
37219b8e9a0SWilly Tu         return "SSD";
37319b8e9a0SWilly Tu     }
37419b8e9a0SWilly Tu 
37519b8e9a0SWilly Tu     return std::nullopt;
37619b8e9a0SWilly Tu }
37719b8e9a0SWilly Tu 
37819b8e9a0SWilly Tu inline std::optional<std::string> convertDriveProtocol(const std::string& proto)
37919b8e9a0SWilly Tu {
38019b8e9a0SWilly Tu     if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
38119b8e9a0SWilly Tu     {
38219b8e9a0SWilly Tu         return "SAS";
38319b8e9a0SWilly Tu     }
38419b8e9a0SWilly Tu     if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
38519b8e9a0SWilly Tu     {
38619b8e9a0SWilly Tu         return "SATA";
38719b8e9a0SWilly Tu     }
38819b8e9a0SWilly Tu     if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
38919b8e9a0SWilly Tu     {
39019b8e9a0SWilly Tu         return "NVMe";
39119b8e9a0SWilly Tu     }
39219b8e9a0SWilly Tu     if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
39319b8e9a0SWilly Tu     {
39419b8e9a0SWilly Tu         return "FC";
39519b8e9a0SWilly Tu     }
39619b8e9a0SWilly Tu 
39719b8e9a0SWilly Tu     return std::nullopt;
39819b8e9a0SWilly Tu }
39919b8e9a0SWilly Tu 
40019b8e9a0SWilly Tu inline void
40119b8e9a0SWilly Tu     getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
40219b8e9a0SWilly Tu                            const std::string& connectionName,
40319b8e9a0SWilly Tu                            const std::string& path)
40419b8e9a0SWilly Tu {
40519b8e9a0SWilly Tu     sdbusplus::asio::getAllProperties(
40619b8e9a0SWilly Tu         *crow::connections::systemBus, connectionName, path,
40719b8e9a0SWilly Tu         "xyz.openbmc_project.Inventory.Item.Drive",
40819b8e9a0SWilly Tu         [asyncResp](const boost::system::error_code ec,
40919b8e9a0SWilly Tu                     const std::vector<
41019b8e9a0SWilly Tu                         std::pair<std::string, dbus::utility::DbusVariantType>>&
41119b8e9a0SWilly Tu                         propertiesList) {
41219b8e9a0SWilly Tu             if (ec)
41319b8e9a0SWilly Tu             {
41419b8e9a0SWilly Tu                 // this interface isn't required
41519b8e9a0SWilly Tu                 return;
41619b8e9a0SWilly Tu             }
41719b8e9a0SWilly Tu             for (const std::pair<std::string, dbus::utility::DbusVariantType>&
41819b8e9a0SWilly Tu                      property : propertiesList)
41919b8e9a0SWilly Tu             {
42019b8e9a0SWilly Tu                 const std::string& propertyName = property.first;
42119b8e9a0SWilly Tu                 if (propertyName == "Type")
42219b8e9a0SWilly Tu                 {
42319b8e9a0SWilly Tu                     const std::string* value =
42419b8e9a0SWilly Tu                         std::get_if<std::string>(&property.second);
42519b8e9a0SWilly Tu                     if (value == nullptr)
42619b8e9a0SWilly Tu                     {
42719b8e9a0SWilly Tu                         // illegal property
42819b8e9a0SWilly Tu                         BMCWEB_LOG_ERROR << "Illegal property: Type";
42919b8e9a0SWilly Tu                         messages::internalError(asyncResp->res);
43019b8e9a0SWilly Tu                         return;
43119b8e9a0SWilly Tu                     }
43219b8e9a0SWilly Tu 
43319b8e9a0SWilly Tu                     std::optional<std::string> mediaType =
43419b8e9a0SWilly Tu                         convertDriveType(*value);
43519b8e9a0SWilly Tu                     if (!mediaType)
43619b8e9a0SWilly Tu                     {
43719b8e9a0SWilly Tu                         BMCWEB_LOG_ERROR << "Unsupported DriveType Interface: "
43819b8e9a0SWilly Tu                                          << *value;
43919b8e9a0SWilly Tu                         messages::internalError(asyncResp->res);
44019b8e9a0SWilly Tu                         return;
44119b8e9a0SWilly Tu                     }
44219b8e9a0SWilly Tu 
44319b8e9a0SWilly Tu                     asyncResp->res.jsonValue["MediaType"] = *mediaType;
44419b8e9a0SWilly Tu                 }
44519b8e9a0SWilly Tu                 else if (propertyName == "Capacity")
44619b8e9a0SWilly Tu                 {
44719b8e9a0SWilly Tu                     const uint64_t* capacity =
44819b8e9a0SWilly Tu                         std::get_if<uint64_t>(&property.second);
44919b8e9a0SWilly Tu                     if (capacity == nullptr)
45019b8e9a0SWilly Tu                     {
45119b8e9a0SWilly Tu                         BMCWEB_LOG_ERROR << "Illegal property: Capacity";
45219b8e9a0SWilly Tu                         messages::internalError(asyncResp->res);
45319b8e9a0SWilly Tu                         return;
45419b8e9a0SWilly Tu                     }
45519b8e9a0SWilly Tu                     if (*capacity == 0)
45619b8e9a0SWilly Tu                     {
45719b8e9a0SWilly Tu                         // drive capacity not known
45819b8e9a0SWilly Tu                         continue;
45919b8e9a0SWilly Tu                     }
46019b8e9a0SWilly Tu 
46119b8e9a0SWilly Tu                     asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
46219b8e9a0SWilly Tu                 }
46319b8e9a0SWilly Tu                 else if (propertyName == "Protocol")
46419b8e9a0SWilly Tu                 {
46519b8e9a0SWilly Tu                     const std::string* value =
46619b8e9a0SWilly Tu                         std::get_if<std::string>(&property.second);
46719b8e9a0SWilly Tu                     if (value == nullptr)
46819b8e9a0SWilly Tu                     {
46919b8e9a0SWilly Tu                         BMCWEB_LOG_ERROR << "Illegal property: Protocol";
47019b8e9a0SWilly Tu                         messages::internalError(asyncResp->res);
47119b8e9a0SWilly Tu                         return;
47219b8e9a0SWilly Tu                     }
47319b8e9a0SWilly Tu 
47419b8e9a0SWilly Tu                     std::optional<std::string> proto =
47519b8e9a0SWilly Tu                         convertDriveProtocol(*value);
47619b8e9a0SWilly Tu                     if (!proto)
47719b8e9a0SWilly Tu                     {
47819b8e9a0SWilly Tu                         BMCWEB_LOG_ERROR
47919b8e9a0SWilly Tu                             << "Unsupported DrivePrototype Interface: "
48019b8e9a0SWilly Tu                             << *value;
48119b8e9a0SWilly Tu                         messages::internalError(asyncResp->res);
48219b8e9a0SWilly Tu                         return;
48319b8e9a0SWilly Tu                     }
48419b8e9a0SWilly Tu                     asyncResp->res.jsonValue["Protocol"] = *proto;
48519b8e9a0SWilly Tu                 }
48619b8e9a0SWilly Tu             }
48719b8e9a0SWilly Tu         });
48819b8e9a0SWilly Tu }
48919b8e9a0SWilly Tu 
4907e860f15SJohn Edward Broadbent inline void requestRoutesDrive(App& app)
4917e860f15SJohn Edward Broadbent {
4927e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/Drives/<str>/")
493ed398213SEd Tanous         .privileges(redfish::privileges::getDrive)
4947e860f15SJohn Edward Broadbent         .methods(
49545ca1b86SEd Tanous             boost::beast::http::verb::
49645ca1b86SEd Tanous                 get)([&app](const crow::Request& req,
49745ca1b86SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4987e860f15SJohn Edward Broadbent                             const std::string& driveId) {
49945ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
50045ca1b86SEd Tanous             {
50145ca1b86SEd Tanous                 return;
50245ca1b86SEd Tanous             }
5037e860f15SJohn Edward Broadbent             crow::connections::systemBus->async_method_call(
504b9d36b47SEd Tanous                 [asyncResp, driveId](
505b9d36b47SEd Tanous                     const boost::system::error_code ec,
506b9d36b47SEd Tanous                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
5077e860f15SJohn Edward Broadbent                     if (ec)
5087e860f15SJohn Edward Broadbent                     {
5097e860f15SJohn Edward Broadbent                         BMCWEB_LOG_ERROR << "Drive mapper call error";
5107e860f15SJohn Edward Broadbent                         messages::internalError(asyncResp->res);
5117e860f15SJohn Edward Broadbent                         return;
5127e860f15SJohn Edward Broadbent                     }
5137e860f15SJohn Edward Broadbent 
51403913171SWilly Tu                     auto drive = std::find_if(
5157e860f15SJohn Edward Broadbent                         subtree.begin(), subtree.end(),
51603913171SWilly Tu                         [&driveId](const std::pair<
51703913171SWilly Tu                                    std::string,
51803913171SWilly Tu                                    std::vector<std::pair<
51903913171SWilly Tu                                        std::string, std::vector<std::string>>>>&
52003913171SWilly Tu                                        object) {
52103913171SWilly Tu                             return sdbusplus::message::object_path(object.first)
52203913171SWilly Tu                                        .filename() == driveId;
5237e860f15SJohn Edward Broadbent                         });
5247e860f15SJohn Edward Broadbent 
52503913171SWilly Tu                     if (drive == subtree.end())
5267e860f15SJohn Edward Broadbent                     {
5277e860f15SJohn Edward Broadbent                         messages::resourceNotFound(asyncResp->res, "Drive",
5287e860f15SJohn Edward Broadbent                                                    driveId);
5297e860f15SJohn Edward Broadbent                         return;
5307e860f15SJohn Edward Broadbent                     }
5317e860f15SJohn Edward Broadbent 
53203913171SWilly Tu                     const std::string& path = drive->first;
5337e860f15SJohn Edward Broadbent                     const std::vector<
5347e860f15SJohn Edward Broadbent                         std::pair<std::string, std::vector<std::string>>>&
53503913171SWilly Tu                         connectionNames = drive->second;
5367e860f15SJohn Edward Broadbent 
5377e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["@odata.type"] =
5387e860f15SJohn Edward Broadbent                         "#Drive.v1_7_0.Drive";
5397e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["@odata.id"] =
5407e860f15SJohn Edward Broadbent                         "/redfish/v1/Systems/system/Storage/1/Drives/" +
5417e860f15SJohn Edward Broadbent                         driveId;
5427e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Name"] = driveId;
5437e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Id"] = driveId;
5447e860f15SJohn Edward Broadbent 
5457e860f15SJohn Edward Broadbent                     if (connectionNames.size() != 1)
5467e860f15SJohn Edward Broadbent                     {
5477e860f15SJohn Edward Broadbent                         BMCWEB_LOG_ERROR << "Connection size "
5487e860f15SJohn Edward Broadbent                                          << connectionNames.size()
54903913171SWilly Tu                                          << ", not equal to 1";
5507e860f15SJohn Edward Broadbent                         messages::internalError(asyncResp->res);
5517e860f15SJohn Edward Broadbent                         return;
5527e860f15SJohn Edward Broadbent                     }
5537e860f15SJohn Edward Broadbent 
5547e860f15SJohn Edward Broadbent                     getMainChassisId(
5557e860f15SJohn Edward Broadbent                         asyncResp,
5567e860f15SJohn Edward Broadbent                         [](const std::string& chassisId,
5577e860f15SJohn Edward Broadbent                            const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
5581476687dSEd Tanous                             aRsp->res
5591476687dSEd Tanous                                 .jsonValue["Links"]["Chassis"]["@odata.id"] =
5601476687dSEd Tanous                                 "/redfish/v1/Chassis/" + chassisId;
5617e860f15SJohn Edward Broadbent                         });
5627e860f15SJohn Edward Broadbent 
563a25aeccfSNikhil Potade                     // default it to Enabled
564a25aeccfSNikhil Potade                     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
565a25aeccfSNikhil Potade 
5662ad9c2f6SJames Feist                     auto health = std::make_shared<HealthPopulate>(asyncResp);
567e284a7c1SJames Feist                     health->inventory.emplace_back(path);
5682ad9c2f6SJames Feist                     health->populate();
5692ad9c2f6SJames Feist 
57003913171SWilly Tu                     const std::string& connectionName =
57103913171SWilly Tu                         connectionNames[0].first;
57222984074SJames Feist 
57361b83d0cSWilly Tu                     for (const std::string& interface :
57461b83d0cSWilly Tu                          connectionNames[0].second)
57561b83d0cSWilly Tu                     {
57661b83d0cSWilly Tu                         if (interface ==
57761b83d0cSWilly Tu                             "xyz.openbmc_project.Inventory.Decorator.Asset")
57861b83d0cSWilly Tu                         {
57903913171SWilly Tu                             getDriveAsset(asyncResp, connectionName, path);
58061b83d0cSWilly Tu                         }
58161b83d0cSWilly Tu                         else if (interface ==
58261b83d0cSWilly Tu                                  "xyz.openbmc_project.Inventory.Item")
58361b83d0cSWilly Tu                         {
58403913171SWilly Tu                             getDrivePresent(asyncResp, connectionName, path);
58561b83d0cSWilly Tu                         }
58661b83d0cSWilly Tu                         else if (interface == "xyz.openbmc_project.State.Drive")
58761b83d0cSWilly Tu                         {
58803913171SWilly Tu                             getDriveState(asyncResp, connectionName, path);
58961b83d0cSWilly Tu                         }
59061b83d0cSWilly Tu                         else if (interface ==
59161b83d0cSWilly Tu                                  "xyz.openbmc_project.Inventory.Item.Drive")
59261b83d0cSWilly Tu                         {
59361b83d0cSWilly Tu                             getDriveItemProperties(asyncResp, connectionName,
59461b83d0cSWilly Tu                                                    path);
59561b83d0cSWilly Tu                         }
59661b83d0cSWilly Tu                     }
597a25aeccfSNikhil Potade                 },
598a25aeccfSNikhil Potade                 "xyz.openbmc_project.ObjectMapper",
599a25aeccfSNikhil Potade                 "/xyz/openbmc_project/object_mapper",
600a25aeccfSNikhil Potade                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
601a25aeccfSNikhil Potade                 "/xyz/openbmc_project/inventory", int32_t(0),
602a25aeccfSNikhil Potade                 std::array<const char*, 1>{
603a25aeccfSNikhil Potade                     "xyz.openbmc_project.Inventory.Item.Drive"});
6047e860f15SJohn Edward Broadbent         });
605a25aeccfSNikhil Potade }
606a25aeccfSNikhil Potade } // namespace redfish
607