1 #include "util.hpp" 2 3 #include "getConfig.hpp" 4 5 #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> 11 #include <xyz/openbmc_project/Common/error.hpp> 12 13 #include <filesystem> 14 #include <fstream> 15 #include <iostream> 16 #include <string> 17 18 namespace estoraged 19 { 20 namespace util 21 { 22 using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 23 using ::stdplus::fd::ManagedFd; 24 25 uint64_t findSizeOfBlockDevice(const std::string& devPath) 26 { 27 ManagedFd fd; 28 uint64_t bytes = 0; 29 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())); 41 throw InternalFailure(); 42 } 43 return bytes; 44 } 45 46 uint8_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 95 bool findDevice(const StorageData& data, const std::filesystem::path& searchDir, 96 std::filesystem::path& deviceFile, 97 std::filesystem::path& sysfsDir, std::string& luksName) 98 { 99 /* Check what type of storage device this is. */ 100 estoraged::BasicVariantType typeVariant; 101 try 102 { 103 /* The EntityManager config should have this property set. */ 104 typeVariant = data.at("Type"); 105 } 106 catch (const boost::container::out_of_range& e) 107 { 108 lg2::error("Could not read device type", "REDFISH_MESSAGE_ID", 109 std::string("OpenBMC.0.1.FindDeviceFail")); 110 return false; 111 } 112 113 /* 114 * Currently, we only support eMMC, so report an error for any other device 115 * types. 116 */ 117 std::string type = std::get<std::string>(typeVariant); 118 if (type.compare("EmmcDevice") != 0) 119 { 120 lg2::error("Unsupported device type {TYPE}", "TYPE", type, 121 "REDFISH_MESSAGE_ID", 122 std::string("OpenBMC.0.1.FindDeviceFail")); 123 return false; 124 } 125 126 /* Look for the eMMC in the specified searchDir directory. */ 127 for (auto const& dirEntry : std::filesystem::directory_iterator{searchDir}) 128 { 129 std::filesystem::path curDevice(dirEntry.path().filename()); 130 if (curDevice.string().starts_with("mmcblk")) 131 { 132 sysfsDir = dirEntry.path(); 133 sysfsDir /= "device"; 134 135 deviceFile = "/dev"; 136 deviceFile /= curDevice; 137 138 luksName = "luks-" + curDevice.string(); 139 return true; 140 } 141 } 142 143 /* Device wasn't found. */ 144 return false; 145 } 146 147 } // namespace util 148 149 } // namespace estoraged 150