1 /**
2 * Copyright © 2024 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 "model.hpp"
19
20 #include "pmbus.hpp"
21 #include "utility.hpp"
22 #include "utils.hpp"
23
24 #include <nlohmann/json.hpp>
25 #include <phosphor-logging/log.hpp>
26
27 #include <exception>
28 #include <format>
29 #include <fstream>
30 #include <stdexcept>
31
32 using json = nlohmann::json;
33
34 using namespace utils;
35 using namespace phosphor::logging;
36 using namespace phosphor::power::util;
37
38 namespace model
39 {
40
41 namespace internal
42 {
43
44 /**
45 * @brief Get the PSU model from sysfs.
46 *
47 * Obtain PSU information from the PSU JSON file.
48 *
49 * Throws an exception if an error occurs.
50 *
51 * @param[in] psuInventoryPath - PSU D-Bus inventory path
52 *
53 * @return PSU model
54 */
getModelJson(const std::string & psuInventoryPath)55 std::string getModelJson(const std::string& psuInventoryPath)
56 {
57 // Parse PSU JSON file
58 std::ifstream file{PSU_JSON_PATH};
59 json data = json::parse(file);
60
61 // Get PSU device path from JSON
62 auto it = data.find("psuDevices");
63 if (it == data.end())
64 {
65 throw std::runtime_error{"Unable to find psuDevices"};
66 }
67 auto device = it->find(psuInventoryPath);
68 if (device == it->end())
69 {
70 throw std::runtime_error{std::format(
71 "Unable to find device path for PSU {}", psuInventoryPath)};
72 }
73 std::string devicePath = *device;
74 if (devicePath.empty())
75 {
76 throw std::runtime_error{
77 std::format("Empty device path for PSU {}", psuInventoryPath)};
78 }
79
80 // Get sysfs filename from JSON for Model information
81 it = data.find("fruConfigs");
82 if (it == data.end())
83 {
84 throw std::runtime_error{"Unable to find fruConfigs"};
85 }
86 std::string fileName;
87 for (const auto& fru : *it)
88 {
89 if (fru.contains("propertyName") && (fru["propertyName"] == "Model") &&
90 fru.contains("fileName"))
91 {
92 fileName = fru["fileName"];
93 break;
94 }
95 }
96 if (fileName.empty())
97 {
98 throw std::runtime_error{"Unable to find file name for Model"};
99 }
100
101 // Get PMBus access type from JSON
102 phosphor::pmbus::Type type = getPMBusAccessType(data);
103
104 // Read model from sysfs file
105 phosphor::pmbus::PMBus pmbus(devicePath);
106 std::string model = pmbus.readString(fileName, type);
107 return model;
108 }
109
110 /**
111 * @brief Get the PSU model from sysfs.
112 *
113 * Obtain PSU information from D-Bus.
114 *
115 * Throws an exception if an error occurs.
116 *
117 * @param[in] bus - D-Bus connection
118 * @param[in] psuInventoryPath - PSU D-Bus inventory path
119 *
120 * @return PSU model
121 */
getModelDbus(sdbusplus::bus_t & bus,const std::string & psuInventoryPath)122 std::string getModelDbus(sdbusplus::bus_t& bus,
123 const std::string& psuInventoryPath)
124 {
125 // Get PSU I2C bus/address and create PMBus interface
126 const auto [i2cBus, i2cAddr] = getPsuI2c(bus, psuInventoryPath);
127 auto pmbus = getPmbusIntf(i2cBus, i2cAddr);
128
129 // Read model from sysfs file
130 std::string fileName = "ccin";
131 auto type = phosphor::pmbus::Type::HwmonDeviceDebug;
132 std::string model = pmbus->readString(fileName, type);
133 return model;
134 }
135
136 } // namespace internal
137
getModel(sdbusplus::bus_t & bus,const std::string & psuInventoryPath)138 std::string getModel(sdbusplus::bus_t& bus, const std::string& psuInventoryPath)
139 {
140 std::string model;
141 try
142 {
143 if (usePsuJsonFile())
144 {
145 // Obtain PSU information from JSON file
146 model = internal::getModelJson(psuInventoryPath);
147 }
148 else
149 {
150 // Obtain PSU information from D-Bus
151 model = internal::getModelDbus(bus, psuInventoryPath);
152 }
153 }
154 catch (const std::exception& e)
155 {
156 log<level::ERR>(std::format("Error: {}", e.what()).c_str());
157 }
158 return model;
159 }
160
161 } // namespace model
162