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 23 #include <phosphor-logging/log.hpp> 24 25 #include <tuple> 26 27 using json = nlohmann::json; 28 29 using namespace phosphor::logging; 30 31 // PsuInfo contains the device path, pmbus read type, and the version string 32 using PsuVersionInfo = 33 std::tuple<std::string, phosphor::pmbus::Type, std::string>; 34 35 namespace utils 36 { 37 PsuVersionInfo getVersionInfo(const std::string& psuInventoryPath) 38 { 39 auto data = phosphor::power::util::loadJSONFromFile(PSU_JSON_PATH); 40 41 if (data == nullptr) 42 { 43 return {}; 44 } 45 46 auto devices = data.find("psuDevices"); 47 if (devices == data.end()) 48 { 49 log<level::WARNING>("Unable to find psuDevices"); 50 return {}; 51 } 52 auto devicePath = devices->find(psuInventoryPath); 53 if (devicePath == devices->end()) 54 { 55 log<level::WARNING>("Unable to find path for PSU", 56 entry("PATH=%s", psuInventoryPath.c_str())); 57 return {}; 58 } 59 60 auto type = phosphor::power::util::getPMBusAccessType(data); 61 62 std::string versionStr; 63 for (const auto& fru : data["fruConfigs"]) 64 { 65 if (fru["propertyName"] == "Version") 66 { 67 versionStr = fru["fileName"].get<std::string>(); 68 break; 69 } 70 } 71 if (versionStr.empty()) 72 { 73 log<level::WARNING>("Unable to find Version file"); 74 return {}; 75 } 76 return std::make_tuple(*devicePath, type, versionStr); 77 } 78 79 // A default implemention compare the string itself 80 std::string getLatestDefault(const std::vector<std::string>& versions) 81 { 82 std::string latest; 83 for (const auto& version : versions) 84 { 85 if (latest < version) 86 { 87 latest = version; 88 } 89 } 90 return latest; 91 } 92 93 } // namespace utils 94 95 namespace version 96 { 97 98 std::string getVersion(const std::string& psuInventoryPath) 99 { 100 const auto& [devicePath, type, 101 versionStr] = utils::getVersionInfo(psuInventoryPath); 102 if (devicePath.empty() || versionStr.empty()) 103 { 104 return {}; 105 } 106 std::string version; 107 try 108 { 109 phosphor::pmbus::PMBus pmbus(devicePath); 110 version = pmbus.readString(versionStr, type); 111 } 112 catch (const std::exception& ex) 113 { 114 log<level::ERR>(ex.what()); 115 } 116 return version; 117 } 118 119 std::string getLatest(const std::vector<std::string>& versions) 120 { 121 // TODO: when multiple PSU/Machines are supported, add configuration options 122 // to implement machine-specific logic. 123 // For now IBM AC Servers and Inspur FP5280G2 are supported. 124 // 125 // IBM AC servers' PSU version has two types: 126 // * XXXXYYYYZZZZ: XXXX is the primary version 127 // YYYY is the secondary version 128 // ZZZZ is the communication version 129 // 130 // * XXXXYYYY: XXXX is the primary version 131 // YYYY is the seconday version 132 // 133 // Inspur FP5280G2 PSU version is human readable text and a larger string 134 // means a newer version. 135 // 136 // So just compare by strings is OK for these cases 137 return utils::getLatestDefault(versions); 138 } 139 140 } // namespace version 141