xref: /openbmc/estoraged/src/util.cpp (revision f78215fd)
1a6e3b99dSJohn Edward Broadbent #include "util.hpp"
2a6e3b99dSJohn Edward Broadbent 
3d32b9667SJohn Wedig #include "getConfig.hpp"
4d32b9667SJohn Wedig 
5a6e3b99dSJohn Edward Broadbent #include <linux/fs.h>
6a6e3b99dSJohn Edward Broadbent 
7a6e3b99dSJohn Edward Broadbent #include <phosphor-logging/lg2.hpp>
8a6e3b99dSJohn Edward Broadbent #include <stdplus/fd/create.hpp>
9a6e3b99dSJohn Edward Broadbent #include <stdplus/fd/managed.hpp>
10a6e3b99dSJohn Edward Broadbent #include <stdplus/handle/managed.hpp>
11a6e3b99dSJohn Edward Broadbent #include <xyz/openbmc_project/Common/error.hpp>
12a6e3b99dSJohn Edward Broadbent 
13d32b9667SJohn Wedig #include <filesystem>
145d799bb9SJohn Edward Broadbent #include <fstream>
155d799bb9SJohn Edward Broadbent #include <iostream>
165d799bb9SJohn Edward Broadbent #include <string>
17a6e3b99dSJohn Edward Broadbent 
18a6e3b99dSJohn Edward Broadbent namespace estoraged
19a6e3b99dSJohn Edward Broadbent {
20a6e3b99dSJohn Edward Broadbent namespace util
21a6e3b99dSJohn Edward Broadbent {
22a6e3b99dSJohn Edward Broadbent using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23a6e3b99dSJohn Edward Broadbent using ::stdplus::fd::ManagedFd;
24a6e3b99dSJohn Edward Broadbent 
255d799bb9SJohn Edward Broadbent uint64_t findSizeOfBlockDevice(const std::string& devPath)
26a6e3b99dSJohn Edward Broadbent {
27a6e3b99dSJohn Edward Broadbent     ManagedFd fd;
28a6e3b99dSJohn Edward Broadbent     uint64_t bytes = 0;
29a6e3b99dSJohn Edward Broadbent     try
30a6e3b99dSJohn Edward Broadbent     {
31a6e3b99dSJohn Edward Broadbent         // open block dev
32a6e3b99dSJohn Edward Broadbent         fd = stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly);
33a6e3b99dSJohn Edward Broadbent         // get block size
34a6e3b99dSJohn Edward Broadbent         fd.ioctl(BLKGETSIZE64, &bytes);
35a6e3b99dSJohn Edward Broadbent     }
36a6e3b99dSJohn Edward Broadbent     catch (...)
37a6e3b99dSJohn Edward Broadbent     {
38a6e3b99dSJohn Edward Broadbent         lg2::error("erase unable to open blockdev", "REDFISH_MESSAGE_ID",
39a6e3b99dSJohn Edward Broadbent                    std::string("OpenBMC.0.1.DriveEraseFailure"),
40a6e3b99dSJohn Edward Broadbent                    "REDFISH_MESSAGE_ARGS", std::to_string(fd.get()));
41a6e3b99dSJohn Edward Broadbent         throw InternalFailure();
42a6e3b99dSJohn Edward Broadbent     }
43a6e3b99dSJohn Edward Broadbent     return bytes;
44a6e3b99dSJohn Edward Broadbent }
45a6e3b99dSJohn Edward Broadbent 
465d799bb9SJohn Edward Broadbent uint8_t findPredictedMediaLifeLeftPercent(const std::string& sysfsPath)
475d799bb9SJohn Edward Broadbent {
485d799bb9SJohn Edward Broadbent     // The eMMC spec defines two estimates for the life span of the device
495d799bb9SJohn Edward Broadbent     // in the extended CSD field 269 and 268, named estimate A and estimate B.
505d799bb9SJohn Edward Broadbent     // Linux exposes the values in the /life_time node.
515d799bb9SJohn Edward Broadbent     // estimate A is for A type memory
525d799bb9SJohn Edward Broadbent     // estimate B is for B type memory
535d799bb9SJohn Edward Broadbent     //
545d799bb9SJohn Edward Broadbent     // the estimate are encoded as such
555d799bb9SJohn Edward Broadbent     // 0x01 <=>  0% - 10% device life time used
565d799bb9SJohn Edward Broadbent     // 0x02 <=>  10% -20% device life time used
575d799bb9SJohn Edward Broadbent     // ...
585d799bb9SJohn Edward Broadbent     // 0x0A <=>  90% - 100% device life time used
595d799bb9SJohn Edward Broadbent     // 0x0B <=> Exceeded its maximum estimated device life time
605d799bb9SJohn Edward Broadbent 
615d799bb9SJohn Edward Broadbent     uint16_t estA = 0, estB = 0;
625d799bb9SJohn Edward Broadbent     std::ifstream lifeTimeFile;
635d799bb9SJohn Edward Broadbent     try
645d799bb9SJohn Edward Broadbent     {
655d799bb9SJohn Edward Broadbent         lifeTimeFile.open(sysfsPath + "/life_time", std::ios_base::in);
665d799bb9SJohn Edward Broadbent         lifeTimeFile >> std::hex >> estA;
675d799bb9SJohn Edward Broadbent         lifeTimeFile >> std::hex >> estB;
685d799bb9SJohn Edward Broadbent         if ((estA == 0) || (estA > 11) || (estB == 0) || (estB > 11))
695d799bb9SJohn Edward Broadbent         {
705d799bb9SJohn Edward Broadbent             throw InternalFailure();
715d799bb9SJohn Edward Broadbent         }
725d799bb9SJohn Edward Broadbent     }
735d799bb9SJohn Edward Broadbent     catch (...)
745d799bb9SJohn Edward Broadbent     {
755d799bb9SJohn Edward Broadbent         lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID",
765d799bb9SJohn Edward Broadbent                    std::string("OpenBMC.0.1.DriveEraseFailure"));
775d799bb9SJohn Edward Broadbent         lifeTimeFile.close();
785d799bb9SJohn Edward Broadbent         return 255;
795d799bb9SJohn Edward Broadbent     }
805d799bb9SJohn Edward Broadbent     lifeTimeFile.close();
815d799bb9SJohn Edward Broadbent     // we are returning lowest LifeLeftPercent
825d799bb9SJohn Edward Broadbent     uint8_t maxLifeUsed = 0;
835d799bb9SJohn Edward Broadbent     if (estA > estB)
845d799bb9SJohn Edward Broadbent     {
855d799bb9SJohn Edward Broadbent         maxLifeUsed = estA;
865d799bb9SJohn Edward Broadbent     }
875d799bb9SJohn Edward Broadbent     else
885d799bb9SJohn Edward Broadbent     {
895d799bb9SJohn Edward Broadbent         maxLifeUsed = estB;
905d799bb9SJohn Edward Broadbent     }
915d799bb9SJohn Edward Broadbent 
925d799bb9SJohn Edward Broadbent     return static_cast<uint8_t>(11 - maxLifeUsed) * 10;
935d799bb9SJohn Edward Broadbent }
945d799bb9SJohn Edward Broadbent 
95d32b9667SJohn Wedig bool findDevice(const StorageData& data, const std::filesystem::path& searchDir,
96d32b9667SJohn Wedig                 std::filesystem::path& deviceFile,
97d32b9667SJohn Wedig                 std::filesystem::path& sysfsDir, std::string& luksName)
98d32b9667SJohn Wedig {
99d32b9667SJohn Wedig     /* Check what type of storage device this is. */
100d32b9667SJohn Wedig     estoraged::BasicVariantType typeVariant;
101d32b9667SJohn Wedig     try
102d32b9667SJohn Wedig     {
103d32b9667SJohn Wedig         /* The EntityManager config should have this property set. */
104d32b9667SJohn Wedig         typeVariant = data.at("Type");
105d32b9667SJohn Wedig     }
106d32b9667SJohn Wedig     catch (const boost::container::out_of_range& e)
107d32b9667SJohn Wedig     {
108d32b9667SJohn Wedig         lg2::error("Could not read device type", "REDFISH_MESSAGE_ID",
109d32b9667SJohn Wedig                    std::string("OpenBMC.0.1.FindDeviceFail"));
110d32b9667SJohn Wedig         return false;
111d32b9667SJohn Wedig     }
112d32b9667SJohn Wedig 
113d32b9667SJohn Wedig     /*
114d32b9667SJohn Wedig      * Currently, we only support eMMC, so report an error for any other device
115d32b9667SJohn Wedig      * types.
116d32b9667SJohn Wedig      */
117d32b9667SJohn Wedig     std::string type = std::get<std::string>(typeVariant);
118d32b9667SJohn Wedig     if (type.compare("EmmcDevice") != 0)
119d32b9667SJohn Wedig     {
120d32b9667SJohn Wedig         lg2::error("Unsupported device type {TYPE}", "TYPE", type,
121d32b9667SJohn Wedig                    "REDFISH_MESSAGE_ID",
122d32b9667SJohn Wedig                    std::string("OpenBMC.0.1.FindDeviceFail"));
123d32b9667SJohn Wedig         return false;
124d32b9667SJohn Wedig     }
125d32b9667SJohn Wedig 
126d32b9667SJohn Wedig     /* Look for the eMMC in the specified searchDir directory. */
127d32b9667SJohn Wedig     for (auto const& dirEntry : std::filesystem::directory_iterator{searchDir})
128d32b9667SJohn Wedig     {
129*f78215fdSJohn Wedig         /*
130*f78215fdSJohn Wedig          * We will look at the 'type' file to determine if this is an MMC
131*f78215fdSJohn Wedig          * device.
132*f78215fdSJohn Wedig          */
133*f78215fdSJohn Wedig         std::filesystem::path curPath(dirEntry.path());
134*f78215fdSJohn Wedig         curPath /= "device/type";
135*f78215fdSJohn Wedig         if (!std::filesystem::exists(curPath))
136d32b9667SJohn Wedig         {
137*f78215fdSJohn Wedig             /* The 'type' file doesn't exist. This must not be an eMMC. */
138*f78215fdSJohn Wedig             continue;
139*f78215fdSJohn Wedig         }
140*f78215fdSJohn Wedig 
141*f78215fdSJohn Wedig         try
142*f78215fdSJohn Wedig         {
143*f78215fdSJohn Wedig             std::ifstream typeFile(curPath, std::ios_base::in);
144*f78215fdSJohn Wedig             std::string devType;
145*f78215fdSJohn Wedig             typeFile >> devType;
146*f78215fdSJohn Wedig             if (devType.compare("MMC") == 0)
147*f78215fdSJohn Wedig             {
148*f78215fdSJohn Wedig                 /* Found it. Get the sysfs directory and device file. */
149*f78215fdSJohn Wedig                 std::filesystem::path deviceName(dirEntry.path().filename());
150*f78215fdSJohn Wedig 
151d32b9667SJohn Wedig                 sysfsDir = dirEntry.path();
152d32b9667SJohn Wedig                 sysfsDir /= "device";
153d32b9667SJohn Wedig 
154d32b9667SJohn Wedig                 deviceFile = "/dev";
155*f78215fdSJohn Wedig                 deviceFile /= deviceName;
156d32b9667SJohn Wedig 
157*f78215fdSJohn Wedig                 luksName = "luks-" + deviceName.string();
158d32b9667SJohn Wedig                 return true;
159d32b9667SJohn Wedig             }
160d32b9667SJohn Wedig         }
161*f78215fdSJohn Wedig         catch (...)
162*f78215fdSJohn Wedig         {
163*f78215fdSJohn Wedig             lg2::error("Failed to read device type for {PATH}", "PATH", curPath,
164*f78215fdSJohn Wedig                        "REDFISH_MESSAGE_ID",
165*f78215fdSJohn Wedig                        std::string("OpenBMC.0.1.FindDeviceFail"));
166*f78215fdSJohn Wedig             /*
167*f78215fdSJohn Wedig              * We will still continue searching, though. Maybe this wasn't the
168*f78215fdSJohn Wedig              * device we were looking for, anyway.
169*f78215fdSJohn Wedig              */
170*f78215fdSJohn Wedig         }
171*f78215fdSJohn Wedig     }
172d32b9667SJohn Wedig 
173d32b9667SJohn Wedig     /* Device wasn't found. */
174d32b9667SJohn Wedig     return false;
175d32b9667SJohn Wedig }
176d32b9667SJohn Wedig 
177a6e3b99dSJohn Edward Broadbent } // namespace util
178a6e3b99dSJohn Edward Broadbent 
179a6e3b99dSJohn Edward Broadbent } // namespace estoraged
180