blob: 82bd9aa804faf59bc4c8254eef71047f87190924 [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 Wyman3f1242f2020-01-28 13:11:25 -06008#include <xyz/openbmc_project/Common/Device/error.hpp>
9
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050010#include <chrono> // sleep_for()
11#include <cstdint> // uint8_t...
12#include <thread> // sleep_for()
13
Brandon Wyman3f1242f2020-01-28 13:11:25 -060014namespace phosphor::power::psu
Brandon Wymanaed1f752019-11-25 18:10:52 -060015{
16
17using namespace phosphor::logging;
Brandon Wyman3f1242f2020-01-28 13:11:25 -060018using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
Brandon Wymanaed1f752019-11-25 18:10:52 -060019
20void PowerSupply::updatePresence()
21{
22 try
23 {
Brandon Wyman3f1242f2020-01-28 13:11:25 -060024 present = getPresence(bus, inventoryPath);
Brandon Wymanaed1f752019-11-25 18:10:52 -060025 }
26 catch (const sdbusplus::exception::SdBusError& e)
27 {
28 // Relying on property change or interface added to retry.
29 // Log an informational trace to the journal.
30 log<level::INFO>("D-Bus property access failure exception");
31 }
32}
33
Brandon Wyman3f1242f2020-01-28 13:11:25 -060034void PowerSupply::analyze()
35{
36 using namespace phosphor::pmbus;
37
Brandon Wymanf65c4062020-08-19 13:15:53 -050038 if ((present) && (readFail < LOG_LIMIT))
Brandon Wyman3f1242f2020-01-28 13:11:25 -060039 {
40 try
41 {
Brandon Wymanfed0ba22020-09-26 20:02:51 -050042 statusWord = pmbusIntf->read(STATUS_WORD, Type::Debug);
Brandon Wymanf65c4062020-08-19 13:15:53 -050043 // Read worked, reset the fail count.
44 readFail = 0;
Brandon Wyman3f1242f2020-01-28 13:11:25 -060045
46 if (statusWord)
47 {
48 if (statusWord & status_word::INPUT_FAULT_WARN)
49 {
50 if (!inputFault)
51 {
52 log<level::INFO>(
53 "INPUT fault",
54 entry("STATUS_WORD=0x%04X",
55 static_cast<uint16_t>(statusWord)));
56 }
57
58 faultFound = true;
59 inputFault = true;
60 }
61
62 if (statusWord & status_word::MFR_SPECIFIC_FAULT)
63 {
64 if (!mfrFault)
65 {
66 log<level::INFO>(
67 "MFRSPECIFIC fault",
68 entry("STATUS_WORD=0x%04X",
69 static_cast<uint16_t>(statusWord)));
70 }
71 faultFound = true;
72 mfrFault = true;
73 }
74
75 if (statusWord & status_word::VIN_UV_FAULT)
76 {
77 if (!vinUVFault)
78 {
79 log<level::INFO>(
80 "VIN_UV fault",
81 entry("STATUS_WORD=0x%04X",
82 static_cast<uint16_t>(statusWord)));
83 }
84
85 faultFound = true;
86 vinUVFault = true;
87 }
88 }
89 else
90 {
91 faultFound = false;
92 inputFault = false;
93 mfrFault = false;
94 vinUVFault = false;
95 }
96 }
97 catch (ReadFailure& e)
98 {
Brandon Wymanf65c4062020-08-19 13:15:53 -050099 readFail++;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600100 phosphor::logging::commit<ReadFailure>();
101 }
102 }
103}
104
Brandon Wyman59a35792020-06-04 12:37:40 -0500105void PowerSupply::onOffConfig(uint8_t data)
106{
107 using namespace phosphor::pmbus;
108
109 if (present)
110 {
111 log<level::INFO>("ON_OFF_CONFIG write", entry("DATA=0x%02X", data));
112 try
113 {
114 std::vector<uint8_t> configData{data};
115 pmbusIntf->writeBinary(ON_OFF_CONFIG, configData,
116 Type::HwmonDeviceDebug);
117 }
118 catch (...)
119 {
120 // The underlying code in writeBinary will log a message to the
121 // journal if the write fails. If the ON_OFF_CONFIG is not setup as
122 // desired, later fault detection and analysis code should catch any
123 // of the fall out. We should not need to terminate the application
124 // if this write fails.
125 }
126 }
127}
128
Brandon Wyman3c208462020-05-13 16:25:58 -0500129void PowerSupply::clearFaults()
130{
Brandon Wyman3c208462020-05-13 16:25:58 -0500131 // The PMBus device driver does not allow for writing CLEAR_FAULTS
132 // directly. However, the pmbus hwmon device driver code will send a
133 // CLEAR_FAULTS after reading from any of the hwmon "files" in sysfs, so
134 // reading in1_input should result in clearing the fault bits in
135 // STATUS_BYTE/STATUS_WORD.
136 // I do not care what the return value is.
Brandon Wyman11151532020-11-10 13:45:57 -0600137 if (present)
Brandon Wyman3c208462020-05-13 16:25:58 -0500138 {
Brandon Wyman9564e942020-11-10 14:01:42 -0600139 faultFound = false;
140 inputFault = false;
141 mfrFault = false;
142 vinUVFault = false;
143 readFail = 0;
144 faultLogged = false;
145
Brandon Wyman11151532020-11-10 13:45:57 -0600146 try
147 {
148 static_cast<void>(
149 pmbusIntf->read("in1_input", phosphor::pmbus::Type::Hwmon));
150 }
151 catch (ReadFailure& e)
152 {
153 // Since I do not care what the return value is, I really do not
154 // care much if it gets a ReadFailure either. However, this should
155 // not prevent the application from continuing to run, so catching
156 // the read failure.
157 }
Brandon Wyman3c208462020-05-13 16:25:58 -0500158 }
159}
160
Brandon Wymanaed1f752019-11-25 18:10:52 -0600161void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
162{
163 std::string msgSensor;
Patrick Williamsabe49412020-05-13 17:59:47 -0500164 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Brandon Wymanaed1f752019-11-25 18:10:52 -0600165 msg.read(msgSensor, msgData);
166
167 // Check if it was the Present property that changed.
168 auto valPropMap = msgData.find(PRESENT_PROP);
169 if (valPropMap != msgData.end())
170 {
171 if (std::get<bool>(valPropMap->second))
172 {
173 present = true;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500174 // TODO: Immediately trying to read or write the "files" causes read
175 // or write failures.
176 using namespace std::chrono_literals;
177 std::this_thread::sleep_for(20ms);
Brandon Wyman9564e942020-11-10 14:01:42 -0600178 pmbusIntf->findHwmonDir();
Brandon Wyman59a35792020-06-04 12:37:40 -0500179 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600180 clearFaults();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500181 updateInventory();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600182 }
183 else
184 {
185 present = false;
186
187 // Clear out the now outdated inventory properties
188 updateInventory();
189 }
190 }
191}
192
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500193void PowerSupply::updateInventory()
194{
195 using namespace phosphor::pmbus;
196
197#ifdef IBM_VPD
198 std::string ccin;
199 std::string pn;
200 std::string fn;
201 std::string header;
202 std::string sn;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500203 using PropertyMap =
George Liu070c1bc2020-10-12 11:28:01 +0800204 std::map<std::string,
205 std::variant<std::string, std::vector<uint8_t>, bool>>;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500206 PropertyMap assetProps;
George Liu070c1bc2020-10-12 11:28:01 +0800207 PropertyMap operProps;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500208 PropertyMap versionProps;
209 PropertyMap ipzvpdDINFProps;
210 PropertyMap ipzvpdVINIProps;
211 using InterfaceMap = std::map<std::string, PropertyMap>;
212 InterfaceMap interfaces;
213 using ObjectMap = std::map<sdbusplus::message::object_path, InterfaceMap>;
214 ObjectMap object;
215#endif
216
217 if (present)
218 {
219 // TODO: non-IBM inventory updates?
220
221#ifdef IBM_VPD
222 try
223 {
224 ccin = pmbusIntf->readString(CCIN, Type::HwmonDeviceDebug);
225 assetProps.emplace(MODEL_PROP, ccin);
226 }
227 catch (ReadFailure& e)
228 {
229 // Ignore the read failure, let pmbus code indicate failure, path...
230 // TODO - ibm918
231 // https://github.com/openbmc/docs/blob/master/designs/vpd-collection.md
232 // The BMC must log errors if any of the VPD cannot be properly
233 // parsed or fails ECC checks.
234 }
235
236 try
237 {
238 pn = pmbusIntf->readString(PART_NUMBER, Type::HwmonDeviceDebug);
239 assetProps.emplace(PN_PROP, pn);
240 }
241 catch (ReadFailure& e)
242 {
243 // Ignore the read failure, let pmbus code indicate failure, path...
244 }
245
246 try
247 {
248 fn = pmbusIntf->readString(FRU_NUMBER, Type::HwmonDeviceDebug);
249 }
250 catch (ReadFailure& e)
251 {
252 // Ignore the read failure, let pmbus code indicate failure, path...
253 }
254
255 try
256 {
257 header =
258 pmbusIntf->readString(SERIAL_HEADER, Type::HwmonDeviceDebug);
259 sn = pmbusIntf->readString(SERIAL_NUMBER, Type::HwmonDeviceDebug);
260 assetProps.emplace(SN_PROP, sn);
261 }
262 catch (ReadFailure& e)
263 {
264 // Ignore the read failure, let pmbus code indicate failure, path...
265 }
266
267 try
268 {
Brandon Wymanc9efe412020-10-09 15:42:50 -0500269 fwVersion =
270 pmbusIntf->readString(FW_VERSION, Type::HwmonDeviceDebug);
271 versionProps.emplace(VERSION_PROP, fwVersion);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500272 }
273 catch (ReadFailure& e)
274 {
275 // Ignore the read failure, let pmbus code indicate failure, path...
276 }
277
278 ipzvpdVINIProps.emplace("CC",
279 std::vector<uint8_t>(ccin.begin(), ccin.end()));
280 ipzvpdVINIProps.emplace("PN",
281 std::vector<uint8_t>(pn.begin(), pn.end()));
282 ipzvpdVINIProps.emplace("FN",
283 std::vector<uint8_t>(fn.begin(), fn.end()));
284 std::string header_sn = header + sn + '\0';
285 ipzvpdVINIProps.emplace(
286 "SN", std::vector<uint8_t>(header_sn.begin(), header_sn.end()));
287 std::string description = "IBM PS";
288 ipzvpdVINIProps.emplace(
289 "DR", std::vector<uint8_t>(description.begin(), description.end()));
290
291 // Update the Resource Identifier (RI) keyword
292 // 2 byte FRC: 0x0003
293 // 2 byte RID: 0x1000, 0x1001...
294 std::uint8_t num = std::stoul(
295 inventoryPath.substr(inventoryPath.size() - 1, 1), nullptr, 0);
296 std::vector<uint8_t> ri{0x00, 0x03, 0x10, num};
297 ipzvpdDINFProps.emplace("RI", ri);
298
299 // Fill in the FRU Label (FL) keyword.
300 std::string fl = "E";
301 fl.push_back(inventoryPath.back());
302 fl.resize(FL_KW_SIZE, ' ');
303 ipzvpdDINFProps.emplace("FL",
304 std::vector<uint8_t>(fl.begin(), fl.end()));
305
306 interfaces.emplace(ASSET_IFACE, std::move(assetProps));
307 interfaces.emplace(VERSION_IFACE, std::move(versionProps));
308 interfaces.emplace(DINF_IFACE, std::move(ipzvpdDINFProps));
309 interfaces.emplace(VINI_IFACE, std::move(ipzvpdVINIProps));
310
George Liu070c1bc2020-10-12 11:28:01 +0800311 // Update the Functional
312 operProps.emplace(FUNCTIONAL_PROP, present);
313 interfaces.emplace(OPERATIONAL_STATE_IFACE, std::move(operProps));
314
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500315 auto path = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
316 object.emplace(path, std::move(interfaces));
317
318 try
319 {
320 auto service =
321 util::getService(INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
322
323 if (service.empty())
324 {
325 log<level::ERR>("Unable to get inventory manager service");
326 return;
327 }
328
329 auto method =
330 bus.new_method_call(service.c_str(), INVENTORY_OBJ_PATH,
331 INVENTORY_MGR_IFACE, "Notify");
332
333 method.append(std::move(object));
334
335 auto reply = bus.call(method);
336 }
337 catch (std::exception& e)
338 {
Jay Meyer6a3fd2c2020-08-25 16:37:16 -0500339 log<level::ERR>(
340 std::string(e.what() + std::string(" PATH=") + inventoryPath)
341 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500342 }
343#endif
344 }
345}
346
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600347} // namespace phosphor::power::psu