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> 240bf1b782SLei YU #include <tuple> 250bf1b782SLei YU 260bf1b782SLei YU using json = nlohmann::json; 270bf1b782SLei YU 280bf1b782SLei YU using namespace phosphor::logging; 290bf1b782SLei YU 300bf1b782SLei YU // PsuInfo contains the device path, pmbus read type, and the version string 310bf1b782SLei YU using PsuVersionInfo = 320bf1b782SLei YU std::tuple<std::string, phosphor::pmbus::Type, std::string>; 330bf1b782SLei YU 340bf1b782SLei YU namespace utils 350bf1b782SLei YU { 360bf1b782SLei YU PsuVersionInfo getVersionInfo(const std::string& psuInventoryPath) 370bf1b782SLei YU { 380bf1b782SLei YU auto data = phosphor::power::util::loadJSONFromFile(PSU_JSON_PATH); 390bf1b782SLei YU 400bf1b782SLei YU if (data == nullptr) 410bf1b782SLei YU { 420bf1b782SLei YU return {}; 430bf1b782SLei YU } 440bf1b782SLei YU 450bf1b782SLei YU auto devices = data.find("psuDevices"); 460bf1b782SLei YU if (devices == data.end()) 470bf1b782SLei YU { 480bf1b782SLei YU log<level::WARNING>("Unable to find psuDevices"); 490bf1b782SLei YU return {}; 500bf1b782SLei YU } 510bf1b782SLei YU auto devicePath = devices->find(psuInventoryPath); 520bf1b782SLei YU if (devicePath == devices->end()) 530bf1b782SLei YU { 540bf1b782SLei YU log<level::WARNING>("Unable to find path for PSU", 550bf1b782SLei YU entry("PATH=%s", psuInventoryPath.c_str())); 560bf1b782SLei YU return {}; 570bf1b782SLei YU } 580bf1b782SLei YU 590bf1b782SLei YU auto type = phosphor::power::util::getPMBusAccessType(data); 600bf1b782SLei YU 610bf1b782SLei YU std::string versionStr; 620bf1b782SLei YU for (const auto& fru : data["fruConfigs"]) 630bf1b782SLei YU { 640bf1b782SLei YU if (fru["propertyName"] == "Version") 650bf1b782SLei YU { 660bf1b782SLei YU versionStr = fru["fileName"]; 670bf1b782SLei YU break; 680bf1b782SLei YU } 690bf1b782SLei YU } 700bf1b782SLei YU if (versionStr.empty()) 710bf1b782SLei YU { 720bf1b782SLei YU log<level::WARNING>("Unable to find Version file"); 730bf1b782SLei YU return {}; 740bf1b782SLei YU } 750bf1b782SLei YU return std::make_tuple(*devicePath, type, versionStr); 760bf1b782SLei YU } 77*093b5917SLei YU 78*093b5917SLei YU // A default implemention compare the string itself 79*093b5917SLei YU std::string getLatestDefault(const std::vector<std::string>& versions) 80*093b5917SLei YU { 81*093b5917SLei YU std::string latest; 82*093b5917SLei YU for (const auto& version : versions) 83*093b5917SLei YU { 84*093b5917SLei YU if (latest < version) 85*093b5917SLei YU { 86*093b5917SLei YU latest = version; 87*093b5917SLei YU } 88*093b5917SLei YU } 89*093b5917SLei YU return latest; 90*093b5917SLei YU } 91*093b5917SLei YU 920bf1b782SLei YU } // namespace utils 930bf1b782SLei YU 940bf1b782SLei YU namespace version 950bf1b782SLei YU { 960bf1b782SLei YU 970bf1b782SLei YU std::string getVersion(const std::string& psuInventoryPath) 980bf1b782SLei YU { 990bf1b782SLei YU const auto& [devicePath, type, versionStr] = 1000bf1b782SLei YU utils::getVersionInfo(psuInventoryPath); 1010bf1b782SLei YU if (devicePath.empty() || versionStr.empty()) 1020bf1b782SLei YU { 1030bf1b782SLei YU return {}; 1040bf1b782SLei YU } 1050bf1b782SLei YU std::string version; 1060bf1b782SLei YU try 1070bf1b782SLei YU { 1080bf1b782SLei YU phosphor::pmbus::PMBus pmbus(devicePath); 1090bf1b782SLei YU version = pmbus.readString(versionStr, type); 1100bf1b782SLei YU } 1110bf1b782SLei YU catch (const std::exception& ex) 1120bf1b782SLei YU { 1130bf1b782SLei YU log<level::ERR>(ex.what()); 1140bf1b782SLei YU } 1150bf1b782SLei YU return version; 1160bf1b782SLei YU } 1170bf1b782SLei YU 118*093b5917SLei YU std::string getLatest(const std::vector<std::string>& versions) 119*093b5917SLei YU { 120*093b5917SLei YU // TODO: when multiple PSU/Machines are supported, add configuration options 121*093b5917SLei YU // to implement machine-specific logic. 122*093b5917SLei YU // For now IBM AC Servers and Inspur FP5280G2 are supported. 123*093b5917SLei YU // 124*093b5917SLei YU // IBM AC servers' PSU version has two types: 125*093b5917SLei YU // * XXXXYYYYZZZZ: XXXX is the primary version 126*093b5917SLei YU // YYYY is the secondary version 127*093b5917SLei YU // ZZZZ is the communication version 128*093b5917SLei YU // 129*093b5917SLei YU // * XXXXYYYY: XXXX is the primary version 130*093b5917SLei YU // YYYY is the seconday version 131*093b5917SLei YU // 132*093b5917SLei YU // Inspur FP5280G2 PSU version is human readable text and a larger string 133*093b5917SLei YU // means a newer version. 134*093b5917SLei YU // 135*093b5917SLei YU // So just compare by strings is OK for these cases 136*093b5917SLei YU return utils::getLatestDefault(versions); 137*093b5917SLei YU } 138*093b5917SLei YU 1390bf1b782SLei YU } // namespace version 140