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 95b4838308SJohn Wedig std::string getPartNumber(const std::filesystem::path& sysfsPath) 96b4838308SJohn Wedig { 97b4838308SJohn Wedig std::ifstream partNameFile; 98b4838308SJohn Wedig std::string partName; 99b4838308SJohn Wedig try 100b4838308SJohn Wedig { 101b4838308SJohn Wedig std::filesystem::path namePath(sysfsPath); 102b4838308SJohn Wedig namePath /= "name"; 103b4838308SJohn Wedig partNameFile.open(namePath, std::ios_base::in); 104b4838308SJohn Wedig partNameFile >> partName; 105b4838308SJohn Wedig } 106b4838308SJohn Wedig catch (...) 107b4838308SJohn Wedig { 108b4838308SJohn Wedig lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID", 109b4838308SJohn Wedig std::string("OpenBMC.0.1.PartNumberFailure")); 110b4838308SJohn Wedig } 111b4838308SJohn Wedig partNameFile.close(); 112b4838308SJohn Wedig if (partName.empty()) 113b4838308SJohn Wedig { 114b4838308SJohn Wedig partName = "unknown"; 115b4838308SJohn Wedig } 116b4838308SJohn Wedig 117b4838308SJohn Wedig return partName; 118b4838308SJohn Wedig } 119b4838308SJohn Wedig 120b4838308SJohn Wedig std::string getSerialNumber(const std::filesystem::path& sysfsPath) 121b4838308SJohn Wedig { 122b4838308SJohn Wedig std::ifstream serialNumberFile; 123b4838308SJohn Wedig std::string serialNumber; 124b4838308SJohn Wedig try 125b4838308SJohn Wedig { 126b4838308SJohn Wedig std::filesystem::path serialPath(sysfsPath); 127b4838308SJohn Wedig serialPath /= "serial"; 128b4838308SJohn Wedig serialNumberFile.open(serialPath, std::ios_base::in); 129b4838308SJohn Wedig serialNumberFile >> serialNumber; 130b4838308SJohn Wedig } 131b4838308SJohn Wedig catch (...) 132b4838308SJohn Wedig { 133b4838308SJohn Wedig lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID", 134b4838308SJohn Wedig std::string("OpenBMC.0.1.SerialNumberFailure")); 135b4838308SJohn Wedig } 136b4838308SJohn Wedig serialNumberFile.close(); 137b4838308SJohn Wedig if (serialNumber.empty()) 138b4838308SJohn Wedig { 139b4838308SJohn Wedig serialNumber = "unknown"; 140b4838308SJohn Wedig } 141b4838308SJohn Wedig 142b4838308SJohn Wedig return serialNumber; 143b4838308SJohn Wedig } 144b4838308SJohn Wedig 145d32b9667SJohn Wedig bool findDevice(const StorageData& data, const std::filesystem::path& searchDir, 146d32b9667SJohn Wedig std::filesystem::path& deviceFile, 147d32b9667SJohn Wedig std::filesystem::path& sysfsDir, std::string& luksName) 148d32b9667SJohn Wedig { 149d32b9667SJohn Wedig /* Check what type of storage device this is. */ 150d32b9667SJohn Wedig estoraged::BasicVariantType typeVariant; 151d32b9667SJohn Wedig try 152d32b9667SJohn Wedig { 153d32b9667SJohn Wedig /* The EntityManager config should have this property set. */ 154d32b9667SJohn Wedig typeVariant = data.at("Type"); 155d32b9667SJohn Wedig } 156d32b9667SJohn Wedig catch (const boost::container::out_of_range& e) 157d32b9667SJohn Wedig { 158d32b9667SJohn Wedig lg2::error("Could not read device type", "REDFISH_MESSAGE_ID", 159d32b9667SJohn Wedig std::string("OpenBMC.0.1.FindDeviceFail")); 160d32b9667SJohn Wedig return false; 161d32b9667SJohn Wedig } 162d32b9667SJohn Wedig 163d32b9667SJohn Wedig /* 164d32b9667SJohn Wedig * Currently, we only support eMMC, so report an error for any other device 165d32b9667SJohn Wedig * types. 166d32b9667SJohn Wedig */ 167d32b9667SJohn Wedig std::string type = std::get<std::string>(typeVariant); 168d32b9667SJohn Wedig if (type.compare("EmmcDevice") != 0) 169d32b9667SJohn Wedig { 170d32b9667SJohn Wedig lg2::error("Unsupported device type {TYPE}", "TYPE", type, 171d32b9667SJohn Wedig "REDFISH_MESSAGE_ID", 172d32b9667SJohn Wedig std::string("OpenBMC.0.1.FindDeviceFail")); 173d32b9667SJohn Wedig return false; 174d32b9667SJohn Wedig } 175d32b9667SJohn Wedig 176d32b9667SJohn Wedig /* Look for the eMMC in the specified searchDir directory. */ 177*04c28fadSPatrick Williams for (const auto& dirEntry : std::filesystem::directory_iterator{searchDir}) 178d32b9667SJohn Wedig { 179f78215fdSJohn Wedig /* 180f78215fdSJohn Wedig * We will look at the 'type' file to determine if this is an MMC 181f78215fdSJohn Wedig * device. 182f78215fdSJohn Wedig */ 183f78215fdSJohn Wedig std::filesystem::path curPath(dirEntry.path()); 184f78215fdSJohn Wedig curPath /= "device/type"; 185f78215fdSJohn Wedig if (!std::filesystem::exists(curPath)) 186d32b9667SJohn Wedig { 187f78215fdSJohn Wedig /* The 'type' file doesn't exist. This must not be an eMMC. */ 188f78215fdSJohn Wedig continue; 189f78215fdSJohn Wedig } 190f78215fdSJohn Wedig 191f78215fdSJohn Wedig try 192f78215fdSJohn Wedig { 193f78215fdSJohn Wedig std::ifstream typeFile(curPath, std::ios_base::in); 194f78215fdSJohn Wedig std::string devType; 195f78215fdSJohn Wedig typeFile >> devType; 1969be2f0fcSJohn Edward Broadbent if (devType.compare("MMC") == 0 || devType.compare("SD") == 0) 197f78215fdSJohn Wedig { 198f78215fdSJohn Wedig /* Found it. Get the sysfs directory and device file. */ 199f78215fdSJohn Wedig std::filesystem::path deviceName(dirEntry.path().filename()); 200f78215fdSJohn Wedig 201d32b9667SJohn Wedig sysfsDir = dirEntry.path(); 202d32b9667SJohn Wedig sysfsDir /= "device"; 203d32b9667SJohn Wedig 204d32b9667SJohn Wedig deviceFile = "/dev"; 205f78215fdSJohn Wedig deviceFile /= deviceName; 206d32b9667SJohn Wedig 207f78215fdSJohn Wedig luksName = "luks-" + deviceName.string(); 208d32b9667SJohn Wedig return true; 209d32b9667SJohn Wedig } 210d32b9667SJohn Wedig } 211f78215fdSJohn Wedig catch (...) 212f78215fdSJohn Wedig { 213f78215fdSJohn Wedig lg2::error("Failed to read device type for {PATH}", "PATH", curPath, 214f78215fdSJohn Wedig "REDFISH_MESSAGE_ID", 215f78215fdSJohn Wedig std::string("OpenBMC.0.1.FindDeviceFail")); 216f78215fdSJohn Wedig /* 217f78215fdSJohn Wedig * We will still continue searching, though. Maybe this wasn't the 218f78215fdSJohn Wedig * device we were looking for, anyway. 219f78215fdSJohn Wedig */ 220f78215fdSJohn Wedig } 221f78215fdSJohn Wedig } 222d32b9667SJohn Wedig 223d32b9667SJohn Wedig /* Device wasn't found. */ 224d32b9667SJohn Wedig return false; 225d32b9667SJohn Wedig } 226d32b9667SJohn Wedig 227a6e3b99dSJohn Edward Broadbent } // namespace util 228a6e3b99dSJohn Edward Broadbent 229a6e3b99dSJohn Edward Broadbent } // namespace estoraged 230