blob: 8aad066c743bbee3d200e00db50dd42df3c0434d [file] [log] [blame]
John Edward Broadbenta6e3b992022-03-17 14:33:15 -07001#include "util.hpp"
John Edward Broadbente6ffe702021-10-14 14:03:11 -07002
John Wedigd32b9662022-04-13 18:12:25 -07003#include "getConfig.hpp"
4
John Edward Broadbente6ffe702021-10-14 14:03:11 -07005#include <linux/fs.h>
6
7#include <phosphor-logging/lg2.hpp>
8#include <stdplus/fd/create.hpp>
9#include <stdplus/fd/managed.hpp>
10#include <stdplus/handle/managed.hpp>
John Wedig972c3fa2021-12-29 17:30:41 -080011#include <xyz/openbmc_project/Common/error.hpp>
John Edward Broadbente6ffe702021-10-14 14:03:11 -070012
John Wedigd32b9662022-04-13 18:12:25 -070013#include <filesystem>
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070014#include <fstream>
15#include <iostream>
16#include <string>
John Edward Broadbenta6e3b992022-03-17 14:33:15 -070017
John Edward Broadbentd3bfa7b2022-01-13 17:41:32 -080018namespace estoraged
19{
John Edward Broadbenta6e3b992022-03-17 14:33:15 -070020namespace util
21{
22using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23using ::stdplus::fd::ManagedFd;
John Edward Broadbentd3bfa7b2022-01-13 17:41:32 -080024
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070025uint64_t findSizeOfBlockDevice(const std::string& devPath)
John Edward Broadbente6ffe702021-10-14 14:03:11 -070026{
27 ManagedFd fd;
Ed Tanous82897c32022-02-21 14:11:59 -080028 uint64_t bytes = 0;
John Edward Broadbente6ffe702021-10-14 14:03:11 -070029 try
30 {
31 // open block dev
32 fd = stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly);
33 // get block size
34 fd.ioctl(BLKGETSIZE64, &bytes);
35 }
36 catch (...)
37 {
38 lg2::error("erase unable to open blockdev", "REDFISH_MESSAGE_ID",
39 std::string("OpenBMC.0.1.DriveEraseFailure"),
40 "REDFISH_MESSAGE_ARGS", std::to_string(fd.get()));
John Wedig972c3fa2021-12-29 17:30:41 -080041 throw InternalFailure();
John Edward Broadbente6ffe702021-10-14 14:03:11 -070042 }
43 return bytes;
44}
John Edward Broadbentd3bfa7b2022-01-13 17:41:32 -080045
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070046uint8_t findPredictedMediaLifeLeftPercent(const std::string& sysfsPath)
47{
48 // The eMMC spec defines two estimates for the life span of the device
49 // in the extended CSD field 269 and 268, named estimate A and estimate B.
50 // Linux exposes the values in the /life_time node.
51 // estimate A is for A type memory
52 // estimate B is for B type memory
53 //
54 // the estimate are encoded as such
55 // 0x01 <=> 0% - 10% device life time used
56 // 0x02 <=> 10% -20% device life time used
57 // ...
58 // 0x0A <=> 90% - 100% device life time used
59 // 0x0B <=> Exceeded its maximum estimated device life time
60
61 uint16_t estA = 0, estB = 0;
62 std::ifstream lifeTimeFile;
63 try
64 {
65 lifeTimeFile.open(sysfsPath + "/life_time", std::ios_base::in);
66 lifeTimeFile >> std::hex >> estA;
67 lifeTimeFile >> std::hex >> estB;
68 if ((estA == 0) || (estA > 11) || (estB == 0) || (estB > 11))
69 {
70 throw InternalFailure();
71 }
72 }
73 catch (...)
74 {
75 lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID",
76 std::string("OpenBMC.0.1.DriveEraseFailure"));
77 lifeTimeFile.close();
78 return 255;
79 }
80 lifeTimeFile.close();
81 // we are returning lowest LifeLeftPercent
82 uint8_t maxLifeUsed = 0;
83 if (estA > estB)
84 {
85 maxLifeUsed = estA;
86 }
87 else
88 {
89 maxLifeUsed = estB;
90 }
91
92 return static_cast<uint8_t>(11 - maxLifeUsed) * 10;
93}
94
John Wedigb4838302022-07-22 13:51:16 -070095std::string getPartNumber(const std::filesystem::path& sysfsPath)
96{
97 std::ifstream partNameFile;
98 std::string partName;
99 try
100 {
101 std::filesystem::path namePath(sysfsPath);
102 namePath /= "name";
103 partNameFile.open(namePath, std::ios_base::in);
104 partNameFile >> partName;
105 }
106 catch (...)
107 {
108 lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID",
109 std::string("OpenBMC.0.1.PartNumberFailure"));
110 }
111 partNameFile.close();
112 if (partName.empty())
113 {
114 partName = "unknown";
115 }
116
117 return partName;
118}
119
120std::string getSerialNumber(const std::filesystem::path& sysfsPath)
121{
122 std::ifstream serialNumberFile;
123 std::string serialNumber;
124 try
125 {
126 std::filesystem::path serialPath(sysfsPath);
127 serialPath /= "serial";
128 serialNumberFile.open(serialPath, std::ios_base::in);
129 serialNumberFile >> serialNumber;
130 }
131 catch (...)
132 {
133 lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID",
134 std::string("OpenBMC.0.1.SerialNumberFailure"));
135 }
136 serialNumberFile.close();
137 if (serialNumber.empty())
138 {
139 serialNumber = "unknown";
140 }
141
142 return serialNumber;
143}
144
John Wedigd32b9662022-04-13 18:12:25 -0700145bool findDevice(const StorageData& data, const std::filesystem::path& searchDir,
146 std::filesystem::path& deviceFile,
147 std::filesystem::path& sysfsDir, std::string& luksName)
148{
149 /* Check what type of storage device this is. */
150 estoraged::BasicVariantType typeVariant;
151 try
152 {
153 /* The EntityManager config should have this property set. */
154 typeVariant = data.at("Type");
155 }
156 catch (const boost::container::out_of_range& e)
157 {
158 lg2::error("Could not read device type", "REDFISH_MESSAGE_ID",
159 std::string("OpenBMC.0.1.FindDeviceFail"));
160 return false;
161 }
162
163 /*
164 * Currently, we only support eMMC, so report an error for any other device
165 * types.
166 */
167 std::string type = std::get<std::string>(typeVariant);
168 if (type.compare("EmmcDevice") != 0)
169 {
170 lg2::error("Unsupported device type {TYPE}", "TYPE", type,
171 "REDFISH_MESSAGE_ID",
172 std::string("OpenBMC.0.1.FindDeviceFail"));
173 return false;
174 }
175
176 /* Look for the eMMC in the specified searchDir directory. */
Patrick Williams04c28fa2023-05-10 07:51:24 -0500177 for (const auto& dirEntry : std::filesystem::directory_iterator{searchDir})
John Wedigd32b9662022-04-13 18:12:25 -0700178 {
John Wedigf78215f2022-06-07 13:39:22 -0700179 /*
180 * We will look at the 'type' file to determine if this is an MMC
181 * device.
182 */
183 std::filesystem::path curPath(dirEntry.path());
184 curPath /= "device/type";
185 if (!std::filesystem::exists(curPath))
John Wedigd32b9662022-04-13 18:12:25 -0700186 {
John Wedigf78215f2022-06-07 13:39:22 -0700187 /* The 'type' file doesn't exist. This must not be an eMMC. */
188 continue;
189 }
John Wedigd32b9662022-04-13 18:12:25 -0700190
John Wedigf78215f2022-06-07 13:39:22 -0700191 try
192 {
193 std::ifstream typeFile(curPath, std::ios_base::in);
194 std::string devType;
195 typeFile >> devType;
John Edward Broadbent9be2f0f2023-04-11 13:58:33 -0700196 if (devType.compare("MMC") == 0 || devType.compare("SD") == 0)
John Wedigf78215f2022-06-07 13:39:22 -0700197 {
198 /* Found it. Get the sysfs directory and device file. */
199 std::filesystem::path deviceName(dirEntry.path().filename());
John Wedigd32b9662022-04-13 18:12:25 -0700200
John Wedigf78215f2022-06-07 13:39:22 -0700201 sysfsDir = dirEntry.path();
202 sysfsDir /= "device";
203
204 deviceFile = "/dev";
205 deviceFile /= deviceName;
206
207 luksName = "luks-" + deviceName.string();
208 return true;
209 }
210 }
211 catch (...)
212 {
213 lg2::error("Failed to read device type for {PATH}", "PATH", curPath,
214 "REDFISH_MESSAGE_ID",
215 std::string("OpenBMC.0.1.FindDeviceFail"));
216 /*
217 * We will still continue searching, though. Maybe this wasn't the
218 * device we were looking for, anyway.
219 */
John Wedigd32b9662022-04-13 18:12:25 -0700220 }
221 }
222
223 /* Device wasn't found. */
224 return false;
225}
226
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700227} // namespace util
228
John Edward Broadbentd3bfa7b2022-01-13 17:41:32 -0800229} // namespace estoraged