10bf1b782SLei YU /** 20bf1b782SLei YU * Copyright © 2019 IBM Corporation 30bf1b782SLei YU * 40bf1b782SLei YU * Licensed under the Apache License, Version 2.0 (the "License"); 50bf1b782SLei YU * you may not use this file except in compliance with the License. 60bf1b782SLei YU * You may obtain a copy of the License at 70bf1b782SLei YU * 80bf1b782SLei YU * http://www.apache.org/licenses/LICENSE-2.0 90bf1b782SLei YU * 100bf1b782SLei YU * Unless required by applicable law or agreed to in writing, software 110bf1b782SLei YU * distributed under the License is distributed on an "AS IS" BASIS, 120bf1b782SLei YU * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130bf1b782SLei YU * See the License for the specific language governing permissions and 140bf1b782SLei YU * limitations under the License. 150bf1b782SLei YU */ 160bf1b782SLei YU #include "config.h" 170bf1b782SLei YU 180bf1b782SLei YU #include "version.hpp" 190bf1b782SLei YU 200bf1b782SLei YU #include "pmbus.hpp" 210bf1b782SLei YU #include "utility.hpp" 220bf1b782SLei YU 230bf1b782SLei YU #include <phosphor-logging/log.hpp> 24*d1bc4cecSBrandon Wyman 250bf1b782SLei YU #include <tuple> 260bf1b782SLei YU 270bf1b782SLei YU using json = nlohmann::json; 280bf1b782SLei YU 290bf1b782SLei YU using namespace phosphor::logging; 300bf1b782SLei YU 310bf1b782SLei YU // PsuInfo contains the device path, pmbus read type, and the version string 320bf1b782SLei YU using PsuVersionInfo = 330bf1b782SLei YU std::tuple<std::string, phosphor::pmbus::Type, std::string>; 340bf1b782SLei YU 350bf1b782SLei YU namespace utils 360bf1b782SLei YU { 370bf1b782SLei YU PsuVersionInfo getVersionInfo(const std::string& psuInventoryPath) 380bf1b782SLei YU { 390bf1b782SLei YU auto data = phosphor::power::util::loadJSONFromFile(PSU_JSON_PATH); 400bf1b782SLei YU 410bf1b782SLei YU if (data == nullptr) 420bf1b782SLei YU { 430bf1b782SLei YU return {}; 440bf1b782SLei YU } 450bf1b782SLei YU 460bf1b782SLei YU auto devices = data.find("psuDevices"); 470bf1b782SLei YU if (devices == data.end()) 480bf1b782SLei YU { 490bf1b782SLei YU log<level::WARNING>("Unable to find psuDevices"); 500bf1b782SLei YU return {}; 510bf1b782SLei YU } 520bf1b782SLei YU auto devicePath = devices->find(psuInventoryPath); 530bf1b782SLei YU if (devicePath == devices->end()) 540bf1b782SLei YU { 550bf1b782SLei YU log<level::WARNING>("Unable to find path for PSU", 560bf1b782SLei YU entry("PATH=%s", psuInventoryPath.c_str())); 570bf1b782SLei YU return {}; 580bf1b782SLei YU } 590bf1b782SLei YU 600bf1b782SLei YU auto type = phosphor::power::util::getPMBusAccessType(data); 610bf1b782SLei YU 620bf1b782SLei YU std::string versionStr; 630bf1b782SLei YU for (const auto& fru : data["fruConfigs"]) 640bf1b782SLei YU { 650bf1b782SLei YU if (fru["propertyName"] == "Version") 660bf1b782SLei YU { 670bf1b782SLei YU versionStr = fru["fileName"]; 680bf1b782SLei YU break; 690bf1b782SLei YU } 700bf1b782SLei YU } 710bf1b782SLei YU if (versionStr.empty()) 720bf1b782SLei YU { 730bf1b782SLei YU log<level::WARNING>("Unable to find Version file"); 740bf1b782SLei YU return {}; 750bf1b782SLei YU } 760bf1b782SLei YU return std::make_tuple(*devicePath, type, versionStr); 770bf1b782SLei YU } 78093b5917SLei YU 79093b5917SLei YU // A default implemention compare the string itself 80093b5917SLei YU std::string getLatestDefault(const std::vector<std::string>& versions) 81093b5917SLei YU { 82093b5917SLei YU std::string latest; 83093b5917SLei YU for (const auto& version : versions) 84093b5917SLei YU { 85093b5917SLei YU if (latest < version) 86093b5917SLei YU { 87093b5917SLei YU latest = version; 88093b5917SLei YU } 89093b5917SLei YU } 90093b5917SLei YU return latest; 91093b5917SLei YU } 92093b5917SLei YU 930bf1b782SLei YU } // namespace utils 940bf1b782SLei YU 950bf1b782SLei YU namespace version 960bf1b782SLei YU { 970bf1b782SLei YU 980bf1b782SLei YU std::string getVersion(const std::string& psuInventoryPath) 990bf1b782SLei YU { 1000bf1b782SLei YU const auto& [devicePath, type, versionStr] = 1010bf1b782SLei YU utils::getVersionInfo(psuInventoryPath); 1020bf1b782SLei YU if (devicePath.empty() || versionStr.empty()) 1030bf1b782SLei YU { 1040bf1b782SLei YU return {}; 1050bf1b782SLei YU } 1060bf1b782SLei YU std::string version; 1070bf1b782SLei YU try 1080bf1b782SLei YU { 1090bf1b782SLei YU phosphor::pmbus::PMBus pmbus(devicePath); 1100bf1b782SLei YU version = pmbus.readString(versionStr, type); 1110bf1b782SLei YU } 1120bf1b782SLei YU catch (const std::exception& ex) 1130bf1b782SLei YU { 1140bf1b782SLei YU log<level::ERR>(ex.what()); 1150bf1b782SLei YU } 1160bf1b782SLei YU return version; 1170bf1b782SLei YU } 1180bf1b782SLei YU 119093b5917SLei YU std::string getLatest(const std::vector<std::string>& versions) 120093b5917SLei YU { 121093b5917SLei YU // TODO: when multiple PSU/Machines are supported, add configuration options 122093b5917SLei YU // to implement machine-specific logic. 123093b5917SLei YU // For now IBM AC Servers and Inspur FP5280G2 are supported. 124093b5917SLei YU // 125093b5917SLei YU // IBM AC servers' PSU version has two types: 126093b5917SLei YU // * XXXXYYYYZZZZ: XXXX is the primary version 127093b5917SLei YU // YYYY is the secondary version 128093b5917SLei YU // ZZZZ is the communication version 129093b5917SLei YU // 130093b5917SLei YU // * XXXXYYYY: XXXX is the primary version 131093b5917SLei YU // YYYY is the seconday version 132093b5917SLei YU // 133093b5917SLei YU // Inspur FP5280G2 PSU version is human readable text and a larger string 134093b5917SLei YU // means a newer version. 135093b5917SLei YU // 136093b5917SLei YU // So just compare by strings is OK for these cases 137093b5917SLei YU return utils::getLatestDefault(versions); 138093b5917SLei YU } 139093b5917SLei YU 1400bf1b782SLei YU } // namespace version 141