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" 22*14572cf4SShawn McCarney #include "utils.hpp" 230bf1b782SLei YU 24*14572cf4SShawn McCarney #include <nlohmann/json.hpp> 250bf1b782SLei YU #include <phosphor-logging/log.hpp> 26d1bc4cecSBrandon Wyman 275dce1a74SFaisal Awada #include <exception> 280bf1b782SLei YU #include <tuple> 290bf1b782SLei YU 300bf1b782SLei YU using json = nlohmann::json; 310bf1b782SLei YU 32*14572cf4SShawn McCarney using namespace utils; 330bf1b782SLei YU using namespace phosphor::logging; 345dce1a74SFaisal Awada using namespace phosphor::power::util; 350bf1b782SLei YU 365dce1a74SFaisal Awada namespace version 375dce1a74SFaisal Awada { 38*14572cf4SShawn McCarney 39*14572cf4SShawn McCarney namespace internal 400bf1b782SLei YU { 415dce1a74SFaisal Awada 420bf1b782SLei YU PsuVersionInfo getVersionInfo(const std::string& psuInventoryPath) 430bf1b782SLei YU { 44*14572cf4SShawn McCarney auto data = loadJSONFromFile(PSU_JSON_PATH); 450bf1b782SLei YU 460bf1b782SLei YU if (data == nullptr) 470bf1b782SLei YU { 480bf1b782SLei YU return {}; 490bf1b782SLei YU } 500bf1b782SLei YU 510bf1b782SLei YU auto devices = data.find("psuDevices"); 520bf1b782SLei YU if (devices == data.end()) 530bf1b782SLei YU { 540bf1b782SLei YU log<level::WARNING>("Unable to find psuDevices"); 550bf1b782SLei YU return {}; 560bf1b782SLei YU } 570bf1b782SLei YU auto devicePath = devices->find(psuInventoryPath); 580bf1b782SLei YU if (devicePath == devices->end()) 590bf1b782SLei YU { 600bf1b782SLei YU log<level::WARNING>("Unable to find path for PSU", 610bf1b782SLei YU entry("PATH=%s", psuInventoryPath.c_str())); 620bf1b782SLei YU return {}; 630bf1b782SLei YU } 640bf1b782SLei YU 65*14572cf4SShawn McCarney auto type = getPMBusAccessType(data); 660bf1b782SLei YU 670bf1b782SLei YU std::string versionStr; 680bf1b782SLei YU for (const auto& fru : data["fruConfigs"]) 690bf1b782SLei YU { 700bf1b782SLei YU if (fru["propertyName"] == "Version") 710bf1b782SLei YU { 72c0b9e9e4SMatt Spinler versionStr = fru["fileName"].get<std::string>(); 730bf1b782SLei YU break; 740bf1b782SLei YU } 750bf1b782SLei YU } 760bf1b782SLei YU if (versionStr.empty()) 770bf1b782SLei YU { 780bf1b782SLei YU log<level::WARNING>("Unable to find Version file"); 790bf1b782SLei YU return {}; 800bf1b782SLei YU } 810bf1b782SLei YU return std::make_tuple(*devicePath, type, versionStr); 820bf1b782SLei YU } 83093b5917SLei YU 84093b5917SLei YU // A default implemention compare the string itself 85093b5917SLei YU std::string getLatestDefault(const std::vector<std::string>& versions) 86093b5917SLei YU { 87093b5917SLei YU std::string latest; 88093b5917SLei YU for (const auto& version : versions) 89093b5917SLei YU { 90093b5917SLei YU if (latest < version) 91093b5917SLei YU { 92093b5917SLei YU latest = version; 93093b5917SLei YU } 94093b5917SLei YU } 95093b5917SLei YU return latest; 96093b5917SLei YU } 97093b5917SLei YU 98*14572cf4SShawn McCarney } // namespace internal 990bf1b782SLei YU 1000bf1b782SLei YU std::string getVersion(const std::string& psuInventoryPath) 1010bf1b782SLei YU { 102f5402197SPatrick Williams const auto& [devicePath, type, versionStr] = 103*14572cf4SShawn McCarney internal::getVersionInfo(psuInventoryPath); 1040bf1b782SLei YU if (devicePath.empty() || versionStr.empty()) 1050bf1b782SLei YU { 1065dce1a74SFaisal Awada return ""; 1070bf1b782SLei YU } 1080bf1b782SLei YU std::string version; 1090bf1b782SLei YU try 1100bf1b782SLei YU { 1110bf1b782SLei YU phosphor::pmbus::PMBus pmbus(devicePath); 1120bf1b782SLei YU version = pmbus.readString(versionStr, type); 1130bf1b782SLei YU } 1140bf1b782SLei YU catch (const std::exception& ex) 1150bf1b782SLei YU { 1160bf1b782SLei YU log<level::ERR>(ex.what()); 1170bf1b782SLei YU } 1180bf1b782SLei YU return version; 1190bf1b782SLei YU } 1200bf1b782SLei YU 1215dce1a74SFaisal Awada std::string getVersion(sdbusplus::bus_t& bus, 1225dce1a74SFaisal Awada const std::string& psuInventoryPath) 1235dce1a74SFaisal Awada { 12437c2612bSShawn McCarney std::string version; 1255dce1a74SFaisal Awada try 1265dce1a74SFaisal Awada { 127*14572cf4SShawn McCarney const auto& [i2cbus, i2caddr] = getPsuI2c(bus, psuInventoryPath); 128*14572cf4SShawn McCarney auto pmbus = getPmbusIntf(i2cbus, i2caddr); 12937c2612bSShawn McCarney std::string name = "fw_version"; 13037c2612bSShawn McCarney auto type = phosphor::pmbus::Type::HwmonDeviceDebug; 13137c2612bSShawn McCarney version = pmbus->readString(name, type); 1325dce1a74SFaisal Awada } 1335dce1a74SFaisal Awada catch (const std::exception& e) 1345dce1a74SFaisal Awada { 1355dce1a74SFaisal Awada log<level::ERR>(std::format("Error: {}", e.what()).c_str()); 1365dce1a74SFaisal Awada } 13737c2612bSShawn McCarney return version; 1385dce1a74SFaisal Awada } 1395dce1a74SFaisal Awada 140093b5917SLei YU std::string getLatest(const std::vector<std::string>& versions) 141093b5917SLei YU { 142093b5917SLei YU // TODO: when multiple PSU/Machines are supported, add configuration options 143093b5917SLei YU // to implement machine-specific logic. 144093b5917SLei YU // For now IBM AC Servers and Inspur FP5280G2 are supported. 145093b5917SLei YU // 146093b5917SLei YU // IBM AC servers' PSU version has two types: 147093b5917SLei YU // * XXXXYYYYZZZZ: XXXX is the primary version 148093b5917SLei YU // YYYY is the secondary version 149093b5917SLei YU // ZZZZ is the communication version 150093b5917SLei YU // 151093b5917SLei YU // * XXXXYYYY: XXXX is the primary version 152093b5917SLei YU // YYYY is the seconday version 153093b5917SLei YU // 154093b5917SLei YU // Inspur FP5280G2 PSU version is human readable text and a larger string 155093b5917SLei YU // means a newer version. 156093b5917SLei YU // 157093b5917SLei YU // So just compare by strings is OK for these cases 158*14572cf4SShawn McCarney return internal::getLatestDefault(versions); 159093b5917SLei YU } 1600bf1b782SLei YU } // namespace version 161