blob: c5c1f5fcd28fb5a2fbcd812cdb374c4f48edae8a [file] [log] [blame]
Lei YU0bf1b782019-08-29 16:02:30 +08001/**
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>
Brandon Wymand1bc4ce2019-12-13 14:20:34 -060024
Lei YU0bf1b782019-08-29 16:02:30 +080025#include <tuple>
26
27using json = nlohmann::json;
28
29using namespace phosphor::logging;
30
31// PsuInfo contains the device path, pmbus read type, and the version string
32using PsuVersionInfo =
33 std::tuple<std::string, phosphor::pmbus::Type, std::string>;
34
35namespace utils
36{
37PsuVersionInfo 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"];
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}
Lei YU093b5912019-10-22 15:28:51 +080078
79// A default implemention compare the string itself
80std::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
Lei YU0bf1b782019-08-29 16:02:30 +080093} // namespace utils
94
95namespace version
96{
97
98std::string getVersion(const std::string& psuInventoryPath)
99{
100 const auto& [devicePath, type, versionStr] =
101 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
Lei YU093b5912019-10-22 15:28:51 +0800119std::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
Lei YU0bf1b782019-08-29 16:02:30 +0800140} // namespace version