1 /** 2 * Copyright © 2019 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "config.h" 17 18 #include "version.hpp" 19 20 #include "pmbus.hpp" 21 #include "utility.hpp" 22 #include "utils.hpp" 23 24 #include <nlohmann/json.hpp> 25 #include <phosphor-logging/log.hpp> 26 27 #include <exception> 28 #include <tuple> 29 30 using json = nlohmann::json; 31 32 using namespace utils; 33 using namespace phosphor::logging; 34 using namespace phosphor::power::util; 35 36 namespace version 37 { 38 39 namespace internal 40 { 41 42 PsuVersionInfo getVersionInfo(const std::string& psuInventoryPath) 43 { 44 auto data = loadJSONFromFile(PSU_JSON_PATH); 45 46 if (data == nullptr) 47 { 48 return {}; 49 } 50 51 auto devices = data.find("psuDevices"); 52 if (devices == data.end()) 53 { 54 log<level::WARNING>("Unable to find psuDevices"); 55 return {}; 56 } 57 auto devicePath = devices->find(psuInventoryPath); 58 if (devicePath == devices->end()) 59 { 60 log<level::WARNING>("Unable to find path for PSU", 61 entry("PATH=%s", psuInventoryPath.c_str())); 62 return {}; 63 } 64 65 auto type = getPMBusAccessType(data); 66 67 std::string versionStr; 68 for (const auto& fru : data["fruConfigs"]) 69 { 70 if (fru["propertyName"] == "Version") 71 { 72 versionStr = fru["fileName"].get<std::string>(); 73 break; 74 } 75 } 76 if (versionStr.empty()) 77 { 78 log<level::WARNING>("Unable to find Version file"); 79 return {}; 80 } 81 return std::make_tuple(*devicePath, type, versionStr); 82 } 83 84 // A default implemention compare the string itself 85 std::string getLatestDefault(const std::vector<std::string>& versions) 86 { 87 std::string latest; 88 for (const auto& version : versions) 89 { 90 if (latest < version) 91 { 92 latest = version; 93 } 94 } 95 return latest; 96 } 97 98 } // namespace internal 99 100 std::string getVersion(const std::string& psuInventoryPath) 101 { 102 const auto& [devicePath, type, versionStr] = 103 internal::getVersionInfo(psuInventoryPath); 104 if (devicePath.empty() || versionStr.empty()) 105 { 106 return ""; 107 } 108 std::string version; 109 try 110 { 111 phosphor::pmbus::PMBus pmbus(devicePath); 112 version = pmbus.readString(versionStr, type); 113 } 114 catch (const std::exception& ex) 115 { 116 log<level::ERR>(ex.what()); 117 } 118 return version; 119 } 120 121 std::string getVersion(sdbusplus::bus_t& bus, 122 const std::string& psuInventoryPath) 123 { 124 std::string version; 125 try 126 { 127 const auto& [i2cbus, i2caddr] = getPsuI2c(bus, psuInventoryPath); 128 auto pmbus = getPmbusIntf(i2cbus, i2caddr); 129 std::string name = "fw_version"; 130 auto type = phosphor::pmbus::Type::HwmonDeviceDebug; 131 version = pmbus->readString(name, type); 132 } 133 catch (const std::exception& e) 134 { 135 log<level::ERR>(std::format("Error: {}", e.what()).c_str()); 136 } 137 return version; 138 } 139 140 std::string getLatest(const std::vector<std::string>& versions) 141 { 142 // TODO: when multiple PSU/Machines are supported, add configuration options 143 // to implement machine-specific logic. 144 // For now IBM AC Servers and Inspur FP5280G2 are supported. 145 // 146 // IBM AC servers' PSU version has two types: 147 // * XXXXYYYYZZZZ: XXXX is the primary version 148 // YYYY is the secondary version 149 // ZZZZ is the communication version 150 // 151 // * XXXXYYYY: XXXX is the primary version 152 // YYYY is the seconday version 153 // 154 // Inspur FP5280G2 PSU version is human readable text and a larger string 155 // means a newer version. 156 // 157 // So just compare by strings is OK for these cases 158 return internal::getLatestDefault(versions); 159 } 160 } // namespace version 161