blob: fc32f0e63df558b20ad202468ebc9a618d368d29 [file] [log] [blame]
John Edward Broadbenta6e3b992022-03-17 14:33:15 -07001#include "util.hpp"
John Edward Broadbente6ffe702021-10-14 14:03:11 -07002
Tom Tung043af592023-11-24 13:37:05 +08003#include "estoraged_conf.hpp"
John Wedigd32b9662022-04-13 18:12:25 -07004#include "getConfig.hpp"
5
John Edward Broadbente6ffe702021-10-14 14:03:11 -07006#include <linux/fs.h>
7
8#include <phosphor-logging/lg2.hpp>
9#include <stdplus/fd/create.hpp>
10#include <stdplus/fd/managed.hpp>
11#include <stdplus/handle/managed.hpp>
John Wedig972c3fa2021-12-29 17:30:41 -080012#include <xyz/openbmc_project/Common/error.hpp>
John Edward Broadbente6ffe702021-10-14 14:03:11 -070013
John Wedigd32b9662022-04-13 18:12:25 -070014#include <filesystem>
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070015#include <fstream>
16#include <iostream>
Tom Tung043af592023-11-24 13:37:05 +080017#include <optional>
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070018#include <string>
John Edward Broadbenta6e3b992022-03-17 14:33:15 -070019
John Edward Broadbentd3bfa7b2022-01-13 17:41:32 -080020namespace estoraged
21{
John Edward Broadbenta6e3b992022-03-17 14:33:15 -070022namespace util
23{
24using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
25using ::stdplus::fd::ManagedFd;
John Edward Broadbentd3bfa7b2022-01-13 17:41:32 -080026
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070027uint64_t findSizeOfBlockDevice(const std::string& devPath)
John Edward Broadbente6ffe702021-10-14 14:03:11 -070028{
29 ManagedFd fd;
Ed Tanous82897c32022-02-21 14:11:59 -080030 uint64_t bytes = 0;
John Edward Broadbente6ffe702021-10-14 14:03:11 -070031 try
32 {
33 // open block dev
34 fd = stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly);
35 // get block size
36 fd.ioctl(BLKGETSIZE64, &bytes);
37 }
38 catch (...)
39 {
40 lg2::error("erase unable to open blockdev", "REDFISH_MESSAGE_ID",
41 std::string("OpenBMC.0.1.DriveEraseFailure"),
42 "REDFISH_MESSAGE_ARGS", std::to_string(fd.get()));
John Wedig972c3fa2021-12-29 17:30:41 -080043 throw InternalFailure();
John Edward Broadbente6ffe702021-10-14 14:03:11 -070044 }
45 return bytes;
46}
John Edward Broadbentd3bfa7b2022-01-13 17:41:32 -080047
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070048uint8_t findPredictedMediaLifeLeftPercent(const std::string& sysfsPath)
49{
50 // The eMMC spec defines two estimates for the life span of the device
51 // in the extended CSD field 269 and 268, named estimate A and estimate B.
52 // Linux exposes the values in the /life_time node.
53 // estimate A is for A type memory
54 // estimate B is for B type memory
55 //
56 // the estimate are encoded as such
57 // 0x01 <=> 0% - 10% device life time used
58 // 0x02 <=> 10% -20% device life time used
59 // ...
60 // 0x0A <=> 90% - 100% device life time used
61 // 0x0B <=> Exceeded its maximum estimated device life time
62
63 uint16_t estA = 0, estB = 0;
64 std::ifstream lifeTimeFile;
65 try
66 {
67 lifeTimeFile.open(sysfsPath + "/life_time", std::ios_base::in);
68 lifeTimeFile >> std::hex >> estA;
69 lifeTimeFile >> std::hex >> estB;
70 if ((estA == 0) || (estA > 11) || (estB == 0) || (estB > 11))
71 {
72 throw InternalFailure();
73 }
74 }
75 catch (...)
76 {
77 lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID",
78 std::string("OpenBMC.0.1.DriveEraseFailure"));
79 lifeTimeFile.close();
80 return 255;
81 }
82 lifeTimeFile.close();
83 // we are returning lowest LifeLeftPercent
84 uint8_t maxLifeUsed = 0;
85 if (estA > estB)
86 {
87 maxLifeUsed = estA;
88 }
89 else
90 {
91 maxLifeUsed = estB;
92 }
93
94 return static_cast<uint8_t>(11 - maxLifeUsed) * 10;
95}
96
John Wedigb4838302022-07-22 13:51:16 -070097std::string getPartNumber(const std::filesystem::path& sysfsPath)
98{
99 std::ifstream partNameFile;
100 std::string partName;
101 try
102 {
103 std::filesystem::path namePath(sysfsPath);
104 namePath /= "name";
105 partNameFile.open(namePath, std::ios_base::in);
106 partNameFile >> partName;
107 }
108 catch (...)
109 {
110 lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID",
111 std::string("OpenBMC.0.1.PartNumberFailure"));
112 }
113 partNameFile.close();
114 if (partName.empty())
115 {
116 partName = "unknown";
117 }
118
119 return partName;
120}
121
122std::string getSerialNumber(const std::filesystem::path& sysfsPath)
123{
124 std::ifstream serialNumberFile;
125 std::string serialNumber;
126 try
127 {
128 std::filesystem::path serialPath(sysfsPath);
129 serialPath /= "serial";
130 serialNumberFile.open(serialPath, std::ios_base::in);
131 serialNumberFile >> serialNumber;
132 }
133 catch (...)
134 {
135 lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID",
136 std::string("OpenBMC.0.1.SerialNumberFailure"));
137 }
138 serialNumberFile.close();
139 if (serialNumber.empty())
140 {
141 serialNumber = "unknown";
142 }
143
144 return serialNumber;
145}
146
Tom Tung043af592023-11-24 13:37:05 +0800147std::optional<DeviceInfo> findDevice(const StorageData& data,
148 const std::filesystem::path& searchDir)
John Wedigd32b9662022-04-13 18:12:25 -0700149{
150 /* Check what type of storage device this is. */
151 estoraged::BasicVariantType typeVariant;
152 try
153 {
154 /* The EntityManager config should have this property set. */
155 typeVariant = data.at("Type");
156 }
157 catch (const boost::container::out_of_range& e)
158 {
159 lg2::error("Could not read device type", "REDFISH_MESSAGE_ID",
160 std::string("OpenBMC.0.1.FindDeviceFail"));
Tom Tung043af592023-11-24 13:37:05 +0800161 return std::nullopt;
John Wedigd32b9662022-04-13 18:12:25 -0700162 }
163
Rahul Kapoor19825052023-05-27 01:52:23 +0000164 /* Check if location code/ silkscreen name is provided for the drive. */
Tom Tung043af592023-11-24 13:37:05 +0800165 std::string locationCode;
Rahul Kapoor19825052023-05-27 01:52:23 +0000166 auto findLocationCode = data.find("LocationCode");
167 if (findLocationCode != data.end())
168 {
169 const std::string* locationCodePtr =
170 std::get_if<std::string>(&findLocationCode->second);
171 if (locationCodePtr != nullptr)
172 {
173 locationCode = *locationCodePtr;
174 }
175 }
176
Tom Tung043af592023-11-24 13:37:05 +0800177 /* Check if EraseMaxGeometry is provided. */
178 uint64_t eraseMaxGeometry = ERASE_MAX_GEOMETRY;
179 auto findEraseMaxGeometry = data.find("EraseMaxGeometry");
180 if (findEraseMaxGeometry != data.end())
181 {
182 const auto* eraseMaxGeometryPtr =
183 std::get_if<uint64_t>(&findEraseMaxGeometry->second);
184 if (eraseMaxGeometryPtr != nullptr)
185 {
186 lg2::info("eStorageD new eraseMaxGeometry found on system");
187 eraseMaxGeometry = *eraseMaxGeometryPtr;
188 }
189 }
190
191 /* Check if EraseMinGeometry is provided. */
192 uint64_t eraseMinGeometry = ERASE_MIN_GEOMETRY;
193 auto findEraseMinGeometry = data.find("EraseMinGeometry");
194 if (findEraseMinGeometry != data.end())
195 {
196 const auto* eraseMinGeometryPtr =
197 std::get_if<uint64_t>(&findEraseMinGeometry->second);
198 if (eraseMinGeometryPtr != nullptr)
199 {
200 lg2::info("eStorageD new eraseMinGeometry found on system");
201 eraseMinGeometry = *eraseMinGeometryPtr;
202 }
203 }
204
John Wedigd32b9662022-04-13 18:12:25 -0700205 /*
John Wedigc0d66eb2024-02-26 15:54:47 -0800206 * Determine the drive type and protocol to report for this device. Note
207 * that we only support eMMC currently, so report an error for any other
208 * device types.
John Wedigd32b9662022-04-13 18:12:25 -0700209 */
John Wedigd7be42b2024-01-19 16:07:19 -0800210 std::string deviceType = std::get<std::string>(typeVariant);
John Wedigc0d66eb2024-02-26 15:54:47 -0800211 /* drive type and protocol to report in the Item.Drive dbus interface */
John Wedigd7be42b2024-01-19 16:07:19 -0800212 std::string driveType;
John Wedigc0d66eb2024-02-26 15:54:47 -0800213 std::string driveProtocol;
John Wedigd7be42b2024-01-19 16:07:19 -0800214 if (deviceType.compare("EmmcDevice") == 0)
John Wedigd32b9662022-04-13 18:12:25 -0700215 {
John Wedigd7be42b2024-01-19 16:07:19 -0800216 driveType = "SSD";
John Wedigc0d66eb2024-02-26 15:54:47 -0800217 driveProtocol = "eMMC";
John Wedigd7be42b2024-01-19 16:07:19 -0800218 }
219 else
220 {
221 lg2::error("Unsupported device type {TYPE}", "TYPE", deviceType,
John Wedigd32b9662022-04-13 18:12:25 -0700222 "REDFISH_MESSAGE_ID",
223 std::string("OpenBMC.0.1.FindDeviceFail"));
Tom Tung043af592023-11-24 13:37:05 +0800224 return std::nullopt;
John Wedigd32b9662022-04-13 18:12:25 -0700225 }
226
227 /* Look for the eMMC in the specified searchDir directory. */
Patrick Williams04c28fa2023-05-10 07:51:24 -0500228 for (const auto& dirEntry : std::filesystem::directory_iterator{searchDir})
John Wedigd32b9662022-04-13 18:12:25 -0700229 {
John Wedigf78215f2022-06-07 13:39:22 -0700230 /*
231 * We will look at the 'type' file to determine if this is an MMC
232 * device.
233 */
234 std::filesystem::path curPath(dirEntry.path());
235 curPath /= "device/type";
236 if (!std::filesystem::exists(curPath))
John Wedigd32b9662022-04-13 18:12:25 -0700237 {
John Wedigf78215f2022-06-07 13:39:22 -0700238 /* The 'type' file doesn't exist. This must not be an eMMC. */
239 continue;
240 }
John Wedigd32b9662022-04-13 18:12:25 -0700241
John Wedigf78215f2022-06-07 13:39:22 -0700242 try
243 {
244 std::ifstream typeFile(curPath, std::ios_base::in);
245 std::string devType;
246 typeFile >> devType;
John Edward Broadbent9be2f0f2023-04-11 13:58:33 -0700247 if (devType.compare("MMC") == 0 || devType.compare("SD") == 0)
John Wedigf78215f2022-06-07 13:39:22 -0700248 {
249 /* Found it. Get the sysfs directory and device file. */
250 std::filesystem::path deviceName(dirEntry.path().filename());
John Wedigd32b9662022-04-13 18:12:25 -0700251
Tom Tung043af592023-11-24 13:37:05 +0800252 std::filesystem::path sysfsDir = dirEntry.path();
John Wedigf78215f2022-06-07 13:39:22 -0700253 sysfsDir /= "device";
254
Tom Tung043af592023-11-24 13:37:05 +0800255 std::filesystem::path deviceFile = "/dev";
John Wedigf78215f2022-06-07 13:39:22 -0700256 deviceFile /= deviceName;
257
Tom Tung043af592023-11-24 13:37:05 +0800258 std::string luksName = "luks-" + deviceName.string();
John Wedigc0d66eb2024-02-26 15:54:47 -0800259 return DeviceInfo{deviceFile, sysfsDir,
260 luksName, locationCode,
261 eraseMaxGeometry, eraseMinGeometry,
262 driveType, driveProtocol};
John Wedigf78215f2022-06-07 13:39:22 -0700263 }
264 }
265 catch (...)
266 {
267 lg2::error("Failed to read device type for {PATH}", "PATH", curPath,
268 "REDFISH_MESSAGE_ID",
269 std::string("OpenBMC.0.1.FindDeviceFail"));
270 /*
271 * We will still continue searching, though. Maybe this wasn't the
272 * device we were looking for, anyway.
273 */
John Wedigd32b9662022-04-13 18:12:25 -0700274 }
275 }
276
277 /* Device wasn't found. */
Tom Tung043af592023-11-24 13:37:05 +0800278 return std::nullopt;
John Wedigd32b9662022-04-13 18:12:25 -0700279}
280
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700281} // namespace util
282
John Edward Broadbentd3bfa7b2022-01-13 17:41:32 -0800283} // namespace estoraged