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"
2214572cf4SShawn McCarney #include "utils.hpp"
230bf1b782SLei YU
2414572cf4SShawn 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
3214572cf4SShawn 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 {
3814572cf4SShawn McCarney
3914572cf4SShawn McCarney namespace internal
400bf1b782SLei YU {
415dce1a74SFaisal Awada
42*23dee383SShawn McCarney // PsuInfo contains the device path, PMBus access type, and sysfs file name
43*23dee383SShawn McCarney using PsuVersionInfo =
44*23dee383SShawn McCarney std::tuple<std::string, phosphor::pmbus::Type, std::string>;
45*23dee383SShawn McCarney
46*23dee383SShawn McCarney /**
47*23dee383SShawn McCarney * @brief Get PSU version information
48*23dee383SShawn McCarney *
49*23dee383SShawn McCarney * @param[in] psuInventoryPath - The PSU inventory path.
50*23dee383SShawn McCarney *
51*23dee383SShawn McCarney * @return tuple - device path, PMBus access type, and sysfs file name
52*23dee383SShawn McCarney */
getVersionInfo(const std::string & psuInventoryPath)530bf1b782SLei YU PsuVersionInfo getVersionInfo(const std::string& psuInventoryPath)
540bf1b782SLei YU {
5514572cf4SShawn McCarney auto data = loadJSONFromFile(PSU_JSON_PATH);
560bf1b782SLei YU
570bf1b782SLei YU if (data == nullptr)
580bf1b782SLei YU {
590bf1b782SLei YU return {};
600bf1b782SLei YU }
610bf1b782SLei YU
620bf1b782SLei YU auto devices = data.find("psuDevices");
630bf1b782SLei YU if (devices == data.end())
640bf1b782SLei YU {
650bf1b782SLei YU log<level::WARNING>("Unable to find psuDevices");
660bf1b782SLei YU return {};
670bf1b782SLei YU }
680bf1b782SLei YU auto devicePath = devices->find(psuInventoryPath);
690bf1b782SLei YU if (devicePath == devices->end())
700bf1b782SLei YU {
710bf1b782SLei YU log<level::WARNING>("Unable to find path for PSU",
720bf1b782SLei YU entry("PATH=%s", psuInventoryPath.c_str()));
730bf1b782SLei YU return {};
740bf1b782SLei YU }
750bf1b782SLei YU
7614572cf4SShawn McCarney auto type = getPMBusAccessType(data);
770bf1b782SLei YU
78*23dee383SShawn McCarney std::string fileName;
790bf1b782SLei YU for (const auto& fru : data["fruConfigs"])
800bf1b782SLei YU {
81*23dee383SShawn McCarney if (fru.contains("propertyName") &&
82*23dee383SShawn McCarney (fru["propertyName"] == "Version") && fru.contains("fileName"))
830bf1b782SLei YU {
84*23dee383SShawn McCarney fileName = fru["fileName"];
850bf1b782SLei YU break;
860bf1b782SLei YU }
870bf1b782SLei YU }
88*23dee383SShawn McCarney if (fileName.empty())
890bf1b782SLei YU {
900bf1b782SLei YU log<level::WARNING>("Unable to find Version file");
910bf1b782SLei YU return {};
920bf1b782SLei YU }
93*23dee383SShawn McCarney return std::make_tuple(*devicePath, type, fileName);
940bf1b782SLei YU }
95093b5917SLei YU
96*23dee383SShawn McCarney /**
97*23dee383SShawn McCarney * @brief Get the PSU version from sysfs.
98*23dee383SShawn McCarney *
99*23dee383SShawn McCarney * Obtain PSU information from the PSU JSON file.
100*23dee383SShawn McCarney *
101*23dee383SShawn McCarney * Throws an exception if an error occurs.
102*23dee383SShawn McCarney *
103*23dee383SShawn McCarney * @param[in] psuInventoryPath - PSU D-Bus inventory path
104*23dee383SShawn McCarney *
105*23dee383SShawn McCarney * @return PSU version, or "" if none found
106*23dee383SShawn McCarney */
getVersionJson(const std::string & psuInventoryPath)107*23dee383SShawn McCarney std::string getVersionJson(const std::string& psuInventoryPath)
108*23dee383SShawn McCarney {
109*23dee383SShawn McCarney // Get PSU device path, PMBus access type, and sysfs file name from JSON
110*23dee383SShawn McCarney const auto [devicePath, type, fileName] = getVersionInfo(psuInventoryPath);
111*23dee383SShawn McCarney
112*23dee383SShawn McCarney // Read version from sysfs file
113*23dee383SShawn McCarney std::string version;
114*23dee383SShawn McCarney if (!devicePath.empty() && !fileName.empty())
115*23dee383SShawn McCarney {
116*23dee383SShawn McCarney phosphor::pmbus::PMBus pmbus(devicePath);
117*23dee383SShawn McCarney version = pmbus.readString(fileName, type);
118*23dee383SShawn McCarney }
119*23dee383SShawn McCarney return version;
120*23dee383SShawn McCarney }
121*23dee383SShawn McCarney
122*23dee383SShawn McCarney /**
123*23dee383SShawn McCarney * @brief Get the PSU version from sysfs.
124*23dee383SShawn McCarney *
125*23dee383SShawn McCarney * Obtain PSU information from D-Bus.
126*23dee383SShawn McCarney *
127*23dee383SShawn McCarney * Throws an exception if an error occurs.
128*23dee383SShawn McCarney *
129*23dee383SShawn McCarney * @param[in] bus - D-Bus connection
130*23dee383SShawn McCarney * @param[in] psuInventoryPath - PSU D-Bus inventory path
131*23dee383SShawn McCarney *
132*23dee383SShawn McCarney * @return PSU version, or "" if none found
133*23dee383SShawn McCarney */
getVersionDbus(sdbusplus::bus_t & bus,const std::string & psuInventoryPath)134*23dee383SShawn McCarney std::string getVersionDbus(sdbusplus::bus_t& bus,
135*23dee383SShawn McCarney const std::string& psuInventoryPath)
136*23dee383SShawn McCarney {
137*23dee383SShawn McCarney // Get PSU I2C bus/address and create PMBus interface
138*23dee383SShawn McCarney const auto [i2cbus, i2caddr] = getPsuI2c(bus, psuInventoryPath);
139*23dee383SShawn McCarney auto pmbus = getPmbusIntf(i2cbus, i2caddr);
140*23dee383SShawn McCarney
141*23dee383SShawn McCarney // Read version from sysfs file
142*23dee383SShawn McCarney std::string name = "fw_version";
143*23dee383SShawn McCarney auto type = phosphor::pmbus::Type::HwmonDeviceDebug;
144*23dee383SShawn McCarney std::string version = pmbus->readString(name, type);
145*23dee383SShawn McCarney return version;
146*23dee383SShawn McCarney }
147*23dee383SShawn McCarney
148*23dee383SShawn McCarney /**
149*23dee383SShawn McCarney * @brief Get firmware latest version
150*23dee383SShawn McCarney *
151*23dee383SShawn McCarney * @param[in] versions - String of versions
152*23dee383SShawn McCarney *
153*23dee383SShawn McCarney * @return version - latest firmware level
154*23dee383SShawn McCarney */
getLatestDefault(const std::vector<std::string> & versions)155093b5917SLei YU std::string getLatestDefault(const std::vector<std::string>& versions)
156093b5917SLei YU {
157093b5917SLei YU std::string latest;
158093b5917SLei YU for (const auto& version : versions)
159093b5917SLei YU {
160093b5917SLei YU if (latest < version)
161093b5917SLei YU {
162093b5917SLei YU latest = version;
163093b5917SLei YU }
164093b5917SLei YU }
165093b5917SLei YU return latest;
166093b5917SLei YU }
167093b5917SLei YU
16814572cf4SShawn McCarney } // namespace internal
1690bf1b782SLei YU
getVersion(sdbusplus::bus_t & bus,const std::string & psuInventoryPath)1705dce1a74SFaisal Awada std::string getVersion(sdbusplus::bus_t& bus,
1715dce1a74SFaisal Awada const std::string& psuInventoryPath)
1725dce1a74SFaisal Awada {
17337c2612bSShawn McCarney std::string version;
1745dce1a74SFaisal Awada try
1755dce1a74SFaisal Awada {
176*23dee383SShawn McCarney if (usePsuJsonFile())
177*23dee383SShawn McCarney {
178*23dee383SShawn McCarney // Obtain PSU information from JSON file
179*23dee383SShawn McCarney version = internal::getVersionJson(psuInventoryPath);
180*23dee383SShawn McCarney }
181*23dee383SShawn McCarney else
182*23dee383SShawn McCarney {
183*23dee383SShawn McCarney // Obtain PSU information from D-Bus
184*23dee383SShawn McCarney version = internal::getVersionDbus(bus, psuInventoryPath);
185*23dee383SShawn McCarney }
1865dce1a74SFaisal Awada }
1875dce1a74SFaisal Awada catch (const std::exception& e)
1885dce1a74SFaisal Awada {
1895dce1a74SFaisal Awada log<level::ERR>(std::format("Error: {}", e.what()).c_str());
1905dce1a74SFaisal Awada }
19137c2612bSShawn McCarney return version;
1925dce1a74SFaisal Awada }
1935dce1a74SFaisal Awada
getLatest(const std::vector<std::string> & versions)194093b5917SLei YU std::string getLatest(const std::vector<std::string>& versions)
195093b5917SLei YU {
196093b5917SLei YU // TODO: when multiple PSU/Machines are supported, add configuration options
197093b5917SLei YU // to implement machine-specific logic.
198093b5917SLei YU // For now IBM AC Servers and Inspur FP5280G2 are supported.
199093b5917SLei YU //
200093b5917SLei YU // IBM AC servers' PSU version has two types:
201093b5917SLei YU // * XXXXYYYYZZZZ: XXXX is the primary version
202093b5917SLei YU // YYYY is the secondary version
203093b5917SLei YU // ZZZZ is the communication version
204093b5917SLei YU //
205093b5917SLei YU // * XXXXYYYY: XXXX is the primary version
206093b5917SLei YU // YYYY is the seconday version
207093b5917SLei YU //
208093b5917SLei YU // Inspur FP5280G2 PSU version is human readable text and a larger string
209093b5917SLei YU // means a newer version.
210093b5917SLei YU //
211093b5917SLei YU // So just compare by strings is OK for these cases
21214572cf4SShawn McCarney return internal::getLatestDefault(versions);
213093b5917SLei YU }
214*23dee383SShawn McCarney
2150bf1b782SLei YU } // namespace version
216