xref: /openbmc/phosphor-power/tools/power-utils/version.cpp (revision 093b5917372974419b13739c4a519867d3efc3cb)
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