blob: 9c3af7056b8a96c5e5dcc2842de992c2d34a81de [file] [log] [blame]
Brandon Wyman1d7a7df2020-03-26 10:14:05 -05001#include "config.h"
2
Brandon Wymanaed1f752019-11-25 18:10:52 -06003#include "power_supply.hpp"
4
5#include "types.hpp"
Brandon Wyman3f1242f2020-01-28 13:11:25 -06006#include "util.hpp"
Brandon Wymanaed1f752019-11-25 18:10:52 -06007
Brandon Wymandf13c3a2020-12-15 14:25:22 -06008#include <fmt/format.h>
9
Brandon Wyman3f1242f2020-01-28 13:11:25 -060010#include <xyz/openbmc_project/Common/Device/error.hpp>
11
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050012#include <chrono> // sleep_for()
13#include <cstdint> // uint8_t...
14#include <thread> // sleep_for()
15
Brandon Wyman3f1242f2020-01-28 13:11:25 -060016namespace phosphor::power::psu
Brandon Wymanaed1f752019-11-25 18:10:52 -060017{
18
19using namespace phosphor::logging;
Brandon Wyman3f1242f2020-01-28 13:11:25 -060020using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
Brandon Wymanaed1f752019-11-25 18:10:52 -060021
22void PowerSupply::updatePresence()
23{
24 try
25 {
Brandon Wyman3f1242f2020-01-28 13:11:25 -060026 present = getPresence(bus, inventoryPath);
Brandon Wymanaed1f752019-11-25 18:10:52 -060027 }
28 catch (const sdbusplus::exception::SdBusError& e)
29 {
30 // Relying on property change or interface added to retry.
31 // Log an informational trace to the journal.
Brandon Wymandf13c3a2020-12-15 14:25:22 -060032 log<level::INFO>(
33 fmt::format("D-Bus property {} access failure exception",
34 inventoryPath)
35 .c_str());
Brandon Wymanaed1f752019-11-25 18:10:52 -060036 }
37}
38
Brandon Wyman3f1242f2020-01-28 13:11:25 -060039void PowerSupply::analyze()
40{
41 using namespace phosphor::pmbus;
42
Brandon Wymanf65c4062020-08-19 13:15:53 -050043 if ((present) && (readFail < LOG_LIMIT))
Brandon Wyman3f1242f2020-01-28 13:11:25 -060044 {
45 try
46 {
Brandon Wymanfed0ba22020-09-26 20:02:51 -050047 statusWord = pmbusIntf->read(STATUS_WORD, Type::Debug);
Brandon Wymanf65c4062020-08-19 13:15:53 -050048 // Read worked, reset the fail count.
49 readFail = 0;
Brandon Wyman3f1242f2020-01-28 13:11:25 -060050
51 if (statusWord)
52 {
53 if (statusWord & status_word::INPUT_FAULT_WARN)
54 {
55 if (!inputFault)
56 {
57 log<level::INFO>(
58 "INPUT fault",
59 entry("STATUS_WORD=0x%04X",
60 static_cast<uint16_t>(statusWord)));
61 }
62
63 faultFound = true;
64 inputFault = true;
65 }
66
67 if (statusWord & status_word::MFR_SPECIFIC_FAULT)
68 {
69 if (!mfrFault)
70 {
71 log<level::INFO>(
72 "MFRSPECIFIC fault",
73 entry("STATUS_WORD=0x%04X",
74 static_cast<uint16_t>(statusWord)));
75 }
76 faultFound = true;
77 mfrFault = true;
78 }
79
80 if (statusWord & status_word::VIN_UV_FAULT)
81 {
82 if (!vinUVFault)
83 {
84 log<level::INFO>(
85 "VIN_UV fault",
86 entry("STATUS_WORD=0x%04X",
87 static_cast<uint16_t>(statusWord)));
88 }
89
90 faultFound = true;
91 vinUVFault = true;
92 }
93 }
94 else
95 {
96 faultFound = false;
97 inputFault = false;
98 mfrFault = false;
99 vinUVFault = false;
100 }
101 }
102 catch (ReadFailure& e)
103 {
Brandon Wymanf65c4062020-08-19 13:15:53 -0500104 readFail++;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600105 phosphor::logging::commit<ReadFailure>();
106 }
107 }
108}
109
Brandon Wyman59a35792020-06-04 12:37:40 -0500110void PowerSupply::onOffConfig(uint8_t data)
111{
112 using namespace phosphor::pmbus;
113
114 if (present)
115 {
116 log<level::INFO>("ON_OFF_CONFIG write", entry("DATA=0x%02X", data));
117 try
118 {
119 std::vector<uint8_t> configData{data};
120 pmbusIntf->writeBinary(ON_OFF_CONFIG, configData,
121 Type::HwmonDeviceDebug);
122 }
123 catch (...)
124 {
125 // The underlying code in writeBinary will log a message to the
126 // journal if the write fails. If the ON_OFF_CONFIG is not setup as
127 // desired, later fault detection and analysis code should catch any
128 // of the fall out. We should not need to terminate the application
129 // if this write fails.
130 }
131 }
132}
133
Brandon Wyman3c208462020-05-13 16:25:58 -0500134void PowerSupply::clearFaults()
135{
Brandon Wyman3c208462020-05-13 16:25:58 -0500136 // The PMBus device driver does not allow for writing CLEAR_FAULTS
137 // directly. However, the pmbus hwmon device driver code will send a
138 // CLEAR_FAULTS after reading from any of the hwmon "files" in sysfs, so
139 // reading in1_input should result in clearing the fault bits in
140 // STATUS_BYTE/STATUS_WORD.
141 // I do not care what the return value is.
Brandon Wyman11151532020-11-10 13:45:57 -0600142 if (present)
Brandon Wyman3c208462020-05-13 16:25:58 -0500143 {
Brandon Wyman9564e942020-11-10 14:01:42 -0600144 faultFound = false;
145 inputFault = false;
146 mfrFault = false;
147 vinUVFault = false;
148 readFail = 0;
149 faultLogged = false;
150
Brandon Wyman11151532020-11-10 13:45:57 -0600151 try
152 {
153 static_cast<void>(
154 pmbusIntf->read("in1_input", phosphor::pmbus::Type::Hwmon));
155 }
156 catch (ReadFailure& e)
157 {
158 // Since I do not care what the return value is, I really do not
159 // care much if it gets a ReadFailure either. However, this should
160 // not prevent the application from continuing to run, so catching
161 // the read failure.
162 }
Brandon Wyman3c208462020-05-13 16:25:58 -0500163 }
164}
165
Brandon Wymanaed1f752019-11-25 18:10:52 -0600166void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
167{
168 std::string msgSensor;
Patrick Williamsabe49412020-05-13 17:59:47 -0500169 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Brandon Wymanaed1f752019-11-25 18:10:52 -0600170 msg.read(msgSensor, msgData);
171
172 // Check if it was the Present property that changed.
173 auto valPropMap = msgData.find(PRESENT_PROP);
174 if (valPropMap != msgData.end())
175 {
176 if (std::get<bool>(valPropMap->second))
177 {
178 present = true;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500179 // TODO: Immediately trying to read or write the "files" causes read
180 // or write failures.
181 using namespace std::chrono_literals;
182 std::this_thread::sleep_for(20ms);
Brandon Wyman9564e942020-11-10 14:01:42 -0600183 pmbusIntf->findHwmonDir();
Brandon Wyman59a35792020-06-04 12:37:40 -0500184 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600185 clearFaults();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500186 updateInventory();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600187 }
188 else
189 {
190 present = false;
191
192 // Clear out the now outdated inventory properties
193 updateInventory();
194 }
195 }
196}
197
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500198void PowerSupply::updateInventory()
199{
200 using namespace phosphor::pmbus;
201
202#ifdef IBM_VPD
203 std::string ccin;
204 std::string pn;
205 std::string fn;
206 std::string header;
207 std::string sn;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500208 using PropertyMap =
George Liu070c1bc2020-10-12 11:28:01 +0800209 std::map<std::string,
210 std::variant<std::string, std::vector<uint8_t>, bool>>;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500211 PropertyMap assetProps;
George Liu070c1bc2020-10-12 11:28:01 +0800212 PropertyMap operProps;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500213 PropertyMap versionProps;
214 PropertyMap ipzvpdDINFProps;
215 PropertyMap ipzvpdVINIProps;
216 using InterfaceMap = std::map<std::string, PropertyMap>;
217 InterfaceMap interfaces;
218 using ObjectMap = std::map<sdbusplus::message::object_path, InterfaceMap>;
219 ObjectMap object;
220#endif
221
222 if (present)
223 {
224 // TODO: non-IBM inventory updates?
225
226#ifdef IBM_VPD
227 try
228 {
229 ccin = pmbusIntf->readString(CCIN, Type::HwmonDeviceDebug);
230 assetProps.emplace(MODEL_PROP, ccin);
231 }
232 catch (ReadFailure& e)
233 {
234 // Ignore the read failure, let pmbus code indicate failure, path...
235 // TODO - ibm918
236 // https://github.com/openbmc/docs/blob/master/designs/vpd-collection.md
237 // The BMC must log errors if any of the VPD cannot be properly
238 // parsed or fails ECC checks.
239 }
240
241 try
242 {
243 pn = pmbusIntf->readString(PART_NUMBER, Type::HwmonDeviceDebug);
244 assetProps.emplace(PN_PROP, pn);
245 }
246 catch (ReadFailure& e)
247 {
248 // Ignore the read failure, let pmbus code indicate failure, path...
249 }
250
251 try
252 {
253 fn = pmbusIntf->readString(FRU_NUMBER, Type::HwmonDeviceDebug);
254 }
255 catch (ReadFailure& e)
256 {
257 // Ignore the read failure, let pmbus code indicate failure, path...
258 }
259
260 try
261 {
262 header =
263 pmbusIntf->readString(SERIAL_HEADER, Type::HwmonDeviceDebug);
264 sn = pmbusIntf->readString(SERIAL_NUMBER, Type::HwmonDeviceDebug);
265 assetProps.emplace(SN_PROP, sn);
266 }
267 catch (ReadFailure& e)
268 {
269 // Ignore the read failure, let pmbus code indicate failure, path...
270 }
271
272 try
273 {
Brandon Wymanc9efe412020-10-09 15:42:50 -0500274 fwVersion =
275 pmbusIntf->readString(FW_VERSION, Type::HwmonDeviceDebug);
276 versionProps.emplace(VERSION_PROP, fwVersion);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500277 }
278 catch (ReadFailure& e)
279 {
280 // Ignore the read failure, let pmbus code indicate failure, path...
281 }
282
283 ipzvpdVINIProps.emplace("CC",
284 std::vector<uint8_t>(ccin.begin(), ccin.end()));
285 ipzvpdVINIProps.emplace("PN",
286 std::vector<uint8_t>(pn.begin(), pn.end()));
287 ipzvpdVINIProps.emplace("FN",
288 std::vector<uint8_t>(fn.begin(), fn.end()));
289 std::string header_sn = header + sn + '\0';
290 ipzvpdVINIProps.emplace(
291 "SN", std::vector<uint8_t>(header_sn.begin(), header_sn.end()));
292 std::string description = "IBM PS";
293 ipzvpdVINIProps.emplace(
294 "DR", std::vector<uint8_t>(description.begin(), description.end()));
295
296 // Update the Resource Identifier (RI) keyword
297 // 2 byte FRC: 0x0003
298 // 2 byte RID: 0x1000, 0x1001...
299 std::uint8_t num = std::stoul(
300 inventoryPath.substr(inventoryPath.size() - 1, 1), nullptr, 0);
301 std::vector<uint8_t> ri{0x00, 0x03, 0x10, num};
302 ipzvpdDINFProps.emplace("RI", ri);
303
304 // Fill in the FRU Label (FL) keyword.
305 std::string fl = "E";
306 fl.push_back(inventoryPath.back());
307 fl.resize(FL_KW_SIZE, ' ');
308 ipzvpdDINFProps.emplace("FL",
309 std::vector<uint8_t>(fl.begin(), fl.end()));
310
311 interfaces.emplace(ASSET_IFACE, std::move(assetProps));
312 interfaces.emplace(VERSION_IFACE, std::move(versionProps));
313 interfaces.emplace(DINF_IFACE, std::move(ipzvpdDINFProps));
314 interfaces.emplace(VINI_IFACE, std::move(ipzvpdVINIProps));
315
George Liu070c1bc2020-10-12 11:28:01 +0800316 // Update the Functional
317 operProps.emplace(FUNCTIONAL_PROP, present);
318 interfaces.emplace(OPERATIONAL_STATE_IFACE, std::move(operProps));
319
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500320 auto path = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
321 object.emplace(path, std::move(interfaces));
322
323 try
324 {
325 auto service =
326 util::getService(INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
327
328 if (service.empty())
329 {
330 log<level::ERR>("Unable to get inventory manager service");
331 return;
332 }
333
334 auto method =
335 bus.new_method_call(service.c_str(), INVENTORY_OBJ_PATH,
336 INVENTORY_MGR_IFACE, "Notify");
337
338 method.append(std::move(object));
339
340 auto reply = bus.call(method);
341 }
342 catch (std::exception& e)
343 {
Jay Meyer6a3fd2c2020-08-25 16:37:16 -0500344 log<level::ERR>(
345 std::string(e.what() + std::string(" PATH=") + inventoryPath)
346 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500347 }
348#endif
349 }
350}
351
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600352} // namespace phosphor::power::psu