blob: 2ea0b5b95d57e8211b8e0ac5f61bdfb836f844e4 [file] [log] [blame]
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301#include "config.h"
2
Gunnar Mills94df8c92018-09-14 14:50:03 -05003#include "occ_manager.hpp"
4
5#include "i2c_occ.hpp"
Chicago Duanbb895cb2021-06-18 19:37:16 +08006#include "occ_dbus.hpp"
Gunnar Mills94df8c92018-09-14 14:50:03 -05007#include "utils.hpp"
8
George Liub5ca1012021-09-10 12:53:11 +08009#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/log.hpp>
11#include <xyz/openbmc_project/Common/error.hpp>
12
Matt Spinlerd267cec2021-09-01 14:49:19 -050013#include <chrono>
Chicago Duanbb895cb2021-06-18 19:37:16 +080014#include <cmath>
George Liubcef3b42021-09-10 12:39:02 +080015#include <filesystem>
Chris Cain36f9cde2021-11-22 11:18:21 -060016#include <fstream>
Chicago Duanbb895cb2021-06-18 19:37:16 +080017#include <regex>
Gunnar Mills94df8c92018-09-14 14:50:03 -050018
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053019namespace open_power
20{
21namespace occ
22{
23
Matt Spinler8b8abee2021-08-25 15:18:21 -050024constexpr uint32_t fruTypeNotAvailable = 0xFF;
Matt Spinlera26f1522021-08-25 15:50:20 -050025constexpr auto fruTypeSuffix = "fru_type";
26constexpr auto faultSuffix = "fault";
27constexpr auto inputSuffix = "input";
Matt Spinlerace67d82021-10-18 13:41:57 -050028constexpr auto maxSuffix = "max";
Matt Spinler8b8abee2021-08-25 15:18:21 -050029
Chris Cain1718fd82022-02-16 16:39:50 -060030const auto HOST_ON_FILE = "/run/openbmc/host@0-on";
31
Chris Caina8857c52021-01-27 11:53:05 -060032using namespace phosphor::logging;
Chris Caina7b74dc2021-11-10 17:03:43 -060033using namespace std::literals::chrono_literals;
Chris Caina8857c52021-01-27 11:53:05 -060034
Matt Spinlera26f1522021-08-25 15:50:20 -050035template <typename T>
36T readFile(const std::string& path)
37{
38 std::ifstream ifs;
39 ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
40 std::ifstream::eofbit);
41 T data;
42
43 try
44 {
45 ifs.open(path);
46 ifs >> data;
47 ifs.close();
48 }
49 catch (const std::exception& e)
50 {
51 auto err = errno;
52 throw std::system_error(err, std::generic_category());
53 }
54
55 return data;
56}
57
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053058void Manager::findAndCreateObjects()
59{
Matt Spinlerd267cec2021-09-01 14:49:19 -050060#ifndef POWER10
Deepak Kodihalli370f06b2017-10-25 04:26:07 -050061 for (auto id = 0; id < MAX_CPUS; ++id)
62 {
Deepak Kodihalli30417a12017-12-04 00:54:01 -060063 // Create one occ per cpu
64 auto occ = std::string(OCC_NAME) + std::to_string(id);
65 createObjects(occ);
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053066 }
Matt Spinlerd267cec2021-09-01 14:49:19 -050067#else
Chris Cain613dc902022-04-08 09:56:22 -050068 if (!pmode)
69 {
70 // Create the power mode object
71 pmode = std::make_unique<powermode::PowerMode>(
72 *this, powermode::PMODE_PATH, powermode::PIPS_PATH, event);
73 }
74
Chris Cain1718fd82022-02-16 16:39:50 -060075 if (!fs::exists(HOST_ON_FILE))
Matt Spinlerd267cec2021-09-01 14:49:19 -050076 {
Chris Cainbae4d072022-02-28 09:46:50 -060077 static bool statusObjCreated = false;
78 if (!statusObjCreated)
Chris Cain1718fd82022-02-16 16:39:50 -060079 {
Chris Cainbae4d072022-02-28 09:46:50 -060080 // Create the OCCs based on on the /dev/occX devices
81 auto occs = findOCCsInDev();
Chris Cain1718fd82022-02-16 16:39:50 -060082
Chris Cainbae4d072022-02-28 09:46:50 -060083 if (occs.empty() || (prevOCCSearch.size() != occs.size()))
Chris Cain1718fd82022-02-16 16:39:50 -060084 {
Chris Cainbae4d072022-02-28 09:46:50 -060085 // Something changed or no OCCs yet, try again in 10s.
86 // Note on the first pass prevOCCSearch will be empty,
87 // so there will be at least one delay to give things
88 // a chance to settle.
89 prevOCCSearch = occs;
90
91 log<level::INFO>(
92 fmt::format(
93 "Manager::findAndCreateObjects(): Waiting for OCCs (currently {})",
94 occs.size())
95 .c_str());
96
97 discoverTimer->restartOnce(10s);
98 }
99 else
100 {
101 // All OCCs appear to be available, create status objects
102
103 // createObjects requires OCC0 first.
104 std::sort(occs.begin(), occs.end());
105
106 log<level::INFO>(
107 fmt::format(
108 "Manager::findAndCreateObjects(): Creating {} OCC Status Objects",
109 occs.size())
110 .c_str());
111 for (auto id : occs)
112 {
113 createObjects(std::string(OCC_NAME) + std::to_string(id));
114 }
115 statusObjCreated = true;
Chris Cain6d8f37a2022-04-29 13:46:01 -0500116 waitingForAllOccActiveSensors = true;
Chris Cainbae4d072022-02-28 09:46:50 -0600117 }
118 }
119
Chris Cain6d8f37a2022-04-29 13:46:01 -0500120 if (statusObjCreated && waitingForAllOccActiveSensors)
Chris Cainbae4d072022-02-28 09:46:50 -0600121 {
122 static bool tracedHostWait = false;
123 if (utils::isHostRunning())
124 {
125 if (tracedHostWait)
126 {
127 log<level::INFO>(
128 "Manager::findAndCreateObjects(): Host is running");
129 tracedHostWait = false;
130 }
Chris Cainbae4d072022-02-28 09:46:50 -0600131 checkAllActiveSensors();
132 }
133 else
134 {
135 if (!tracedHostWait)
136 {
137 log<level::INFO>(
138 "Manager::findAndCreateObjects(): Waiting for host to start");
139 tracedHostWait = true;
140 }
141 discoverTimer->restartOnce(30s);
Chris Cain1718fd82022-02-16 16:39:50 -0600142 }
143 }
Matt Spinlerd267cec2021-09-01 14:49:19 -0500144 }
145 else
146 {
Chris Cain1718fd82022-02-16 16:39:50 -0600147 log<level::INFO>(
148 fmt::format(
149 "Manager::findAndCreateObjects(): Waiting for {} to complete...",
150 HOST_ON_FILE)
151 .c_str());
152 discoverTimer->restartOnce(10s);
Matt Spinlerd267cec2021-09-01 14:49:19 -0500153 }
154#endif
155}
156
Chris Cainbae4d072022-02-28 09:46:50 -0600157#ifdef POWER10
158// Check if all occActive sensors are available
159void Manager::checkAllActiveSensors()
160{
161 static bool allActiveSensorAvailable = false;
162 static bool tracedSensorWait = false;
163
164 // Start with the assumption that all are available
165 allActiveSensorAvailable = true;
166 for (auto& obj : statusObjects)
167 {
Chris Cain7f89e4d2022-05-09 13:27:45 -0500168 if (!obj->occActive())
Chris Cainbae4d072022-02-28 09:46:50 -0600169 {
Chris Cain7f89e4d2022-05-09 13:27:45 -0500170 if (!obj->getPldmSensorReceived())
Chris Cainbae4d072022-02-28 09:46:50 -0600171 {
Chris Cain7f89e4d2022-05-09 13:27:45 -0500172 auto instance = obj->getOccInstanceID();
173 // Check if sensor was queued while waiting for discovery
174 auto match = queuedActiveState.find(instance);
175 if (match != queuedActiveState.end())
Chris Cainbd551de2022-04-26 13:41:16 -0500176 {
Chris Cain7f89e4d2022-05-09 13:27:45 -0500177 queuedActiveState.erase(match);
Chris Cainbd551de2022-04-26 13:41:16 -0500178 log<level::INFO>(
179 fmt::format(
Chris Cain7f89e4d2022-05-09 13:27:45 -0500180 "checkAllActiveSensors(): OCC{} is ACTIVE (queued)",
Chris Cainbd551de2022-04-26 13:41:16 -0500181 instance)
182 .c_str());
Chris Cain7f89e4d2022-05-09 13:27:45 -0500183 obj->occActive(true);
Chris Cainbd551de2022-04-26 13:41:16 -0500184 }
Chris Cain7f89e4d2022-05-09 13:27:45 -0500185 else
186 {
187 allActiveSensorAvailable = false;
188 if (!tracedSensorWait)
189 {
190 log<level::INFO>(
191 fmt::format(
192 "checkAllActiveSensors(): Waiting on OCC{} Active sensor",
193 instance)
194 .c_str());
195 tracedSensorWait = true;
196 }
197 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
198 break;
199 }
Chris Cainbd551de2022-04-26 13:41:16 -0500200 }
Chris Cainbae4d072022-02-28 09:46:50 -0600201 }
202 }
203
204 if (allActiveSensorAvailable)
205 {
206 // All sensors were found, disable the discovery timer
Chris Cain7f89e4d2022-05-09 13:27:45 -0500207 if (discoverTimer->isEnabled())
208 {
209 discoverTimer.reset();
210 }
Chris Cainbae4d072022-02-28 09:46:50 -0600211
Chris Cain7f89e4d2022-05-09 13:27:45 -0500212 if (waitingForAllOccActiveSensors)
213 {
214 log<level::INFO>(
215 "checkAllActiveSensors(): OCC Active sensors are available");
216 waitingForAllOccActiveSensors = false;
217 }
218 queuedActiveState.clear();
Chris Cainbae4d072022-02-28 09:46:50 -0600219 tracedSensorWait = false;
220 }
221 else
222 {
223 // Not all sensors were available, so keep waiting
224 if (!tracedSensorWait)
225 {
226 log<level::INFO>(
Chris Cainbd551de2022-04-26 13:41:16 -0500227 "checkAllActiveSensors(): Waiting for OCC Active sensors to become available");
Chris Cainbae4d072022-02-28 09:46:50 -0600228 tracedSensorWait = true;
229 }
Chris Cain7f89e4d2022-05-09 13:27:45 -0500230 if (discoverTimer->isEnabled())
231 {
232 discoverTimer->restartOnce(10s);
233 }
Chris Cainbae4d072022-02-28 09:46:50 -0600234 }
235}
236#endif
237
Matt Spinlerd267cec2021-09-01 14:49:19 -0500238std::vector<int> Manager::findOCCsInDev()
239{
240 std::vector<int> occs;
241 std::regex expr{R"(occ(\d+)$)"};
242
243 for (auto& file : fs::directory_iterator("/dev"))
244 {
245 std::smatch match;
246 std::string path{file.path().string()};
247 if (std::regex_search(path, match, expr))
248 {
249 auto num = std::stoi(match[1].str());
250
251 // /dev numbering starts at 1, ours starts at 0.
252 occs.push_back(num - 1);
253 }
254 }
255
256 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530257}
258
259int Manager::cpuCreated(sdbusplus::message::message& msg)
260{
George Liubcef3b42021-09-10 12:39:02 +0800261 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530262
263 sdbusplus::message::object_path o;
264 msg.read(o);
265 fs::path cpuPath(std::string(std::move(o)));
266
267 auto name = cpuPath.filename().string();
268 auto index = name.find(CPU_NAME);
269 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
270
271 createObjects(name);
272
273 return 0;
274}
275
276void Manager::createObjects(const std::string& occ)
277{
278 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
279
Gunnar Mills94df8c92018-09-14 14:50:03 -0500280 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800281 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600282#ifdef POWER10
283 pmode,
284#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500285 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Sheldon Bailey373af752022-02-21 15:14:00 -0600286 std::placeholders::_1, std::placeholders::_2)
Tom Joseph00325232020-07-29 17:51:48 +0530287#ifdef PLDM
288 ,
289 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
290 std::placeholders::_1)
291#endif
292 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530293
Chris Cain40501a22022-03-14 17:33:27 -0500294 // Create the power cap monitor object
295 if (!pcap)
296 {
297 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
298 *statusObjects.back());
299 }
300
Chris Cain36f9cde2021-11-22 11:18:21 -0600301 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530302 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600303 log<level::INFO>(
304 fmt::format("Manager::createObjects(): OCC{} is the master",
305 statusObjects.back()->getOccInstanceID())
306 .c_str());
307 _pollTimer->setEnabled(false);
308
Chris Cain78e86012021-03-04 16:15:31 -0600309#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600310 // Set the master OCC on the PowerMode object
311 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600312#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600313 }
314
315 passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str()
316#ifdef POWER10
317 ,
318 pmode
319#endif
320 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530321}
322
Sheldon Bailey373af752022-02-21 15:14:00 -0600323void Manager::statusCallBack(instanceID instance, bool status)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530324{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500325 using InternalFailure =
326 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530327
328 // At this time, it won't happen but keeping it
329 // here just in case something changes in the future
330 if ((activeCount == 0) && (!status))
331 {
Sheldon Bailey373af752022-02-21 15:14:00 -0600332 log<level::ERR>(
333 fmt::format("Invalid update on OCCActive with OCC{}", instance)
334 .c_str());
335
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530336 elog<InternalFailure>();
337 }
338
Chris Caina7b74dc2021-11-10 17:03:43 -0600339 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600340 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600341 // OCC went active
342 ++activeCount;
343
344#ifdef POWER10
345 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600346 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600347 // First OCC went active (allow some time for all OCCs to go active)
Chris Cainbd551de2022-04-26 13:41:16 -0500348 waitForAllOccsTimer->restartOnce(60s);
Matt Spinler53f68142021-08-25 15:47:31 -0500349 }
350#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600351
352 if (activeCount == statusObjects.size())
353 {
354#ifdef POWER10
355 // All OCCs are now running
356 if (waitForAllOccsTimer->isEnabled())
357 {
358 // stop occ wait timer
359 waitForAllOccsTimer->setEnabled(false);
360 }
361#endif
362
363 // Verify master OCC and start presence monitor
364 validateOccMaster();
365 }
366
367 // Start poll timer if not already started
368 if (!_pollTimer->isEnabled())
369 {
370 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -0600371 fmt::format("Manager: OCCs will be polled every {} seconds",
372 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600373 .c_str());
374
375 // Send poll and start OCC poll timer
376 pollerTimerExpired();
377 }
378 }
379 else
380 {
381 // OCC went away
382 --activeCount;
383
384 if (activeCount == 0)
385 {
386 // No OCCs are running
387
388 // Stop OCC poll timer
389 if (_pollTimer->isEnabled())
390 {
391 log<level::INFO>(
392 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
393 _pollTimer->setEnabled(false);
394 }
395
396#ifdef POWER10
397 // stop wait timer
398 if (waitForAllOccsTimer->isEnabled())
399 {
400 waitForAllOccsTimer->setEnabled(false);
401 }
402#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600403 }
Sheldon Bailey373af752022-02-21 15:14:00 -0600404#ifdef READ_OCC_SENSORS
405 // Clear OCC sensors
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500406 setSensorValueToNaN(instance);
Sheldon Bailey373af752022-02-21 15:14:00 -0600407#endif
Chris Caina8857c52021-01-27 11:53:05 -0600408 }
Chris Cainbae4d072022-02-28 09:46:50 -0600409
410#ifdef POWER10
411 if (waitingForAllOccActiveSensors)
412 {
Chris Cain6d8f37a2022-04-29 13:46:01 -0500413 if (utils::isHostRunning())
414 {
415 checkAllActiveSensors();
416 }
Chris Cainbae4d072022-02-28 09:46:50 -0600417 }
418#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530419}
420
421#ifdef I2C_OCC
422void Manager::initStatusObjects()
423{
424 // Make sure we have a valid path string
425 static_assert(sizeof(DEV_PATH) != 0);
426
427 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
428 for (auto& name : deviceNames)
429 {
430 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800431 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530432 auto path = fs::path(OCC_CONTROL_ROOT) / name;
433 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800434 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530435 }
Chris Cain40501a22022-03-14 17:33:27 -0500436 // The first device is master occ
437 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
438 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600439#ifdef POWER10
Chris Cain5d66a0a2022-02-09 08:52:10 -0600440 pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
441 powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600442 // Set the master OCC on the PowerMode object
443 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600444#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530445}
446#endif
447
Tom Joseph815f9f52020-07-27 12:12:13 +0530448#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500449void Manager::sbeTimeout(unsigned int instance)
450{
Eddie James2a751d72022-03-04 09:16:12 -0600451 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
452 [instance](const auto& obj) {
453 return instance == obj->getOccInstanceID();
454 });
Eddie Jamescbad2192021-10-07 09:39:39 -0500455
Eddie Jamescb018da2022-03-05 11:49:37 -0600456 if (obj != statusObjects.end() && (*obj)->occActive())
Eddie James2a751d72022-03-04 09:16:12 -0600457 {
Chris Cainbae4d072022-02-28 09:46:50 -0600458 log<level::INFO>(
459 fmt::format("SBE timeout, requesting HRESET (OCC{})", instance)
460 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500461
Eddie James2a751d72022-03-04 09:16:12 -0600462 setSBEState(instance, SBE_STATE_NOT_USABLE);
463
464 pldmHandle->sendHRESET(instance);
465 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500466}
467
Tom Joseph815f9f52020-07-27 12:12:13 +0530468bool Manager::updateOCCActive(instanceID instance, bool status)
469{
Chris Cain7e374fb2022-04-07 09:47:23 -0500470 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
471 [instance](const auto& obj) {
472 return instance == obj->getOccInstanceID();
473 });
474
475 if (obj != statusObjects.end())
476 {
Chris Cain733b2012022-05-04 11:54:06 -0500477 (*obj)->setPldmSensorReceived(true);
Chris Cain7e374fb2022-04-07 09:47:23 -0500478 return (*obj)->occActive(status);
479 }
480 else
481 {
482 log<level::WARNING>(
483 fmt::format(
484 "Manager::updateOCCActive: No status object to update for OCC{} (active={})",
485 instance, status)
486 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -0500487 if (status == true)
488 {
489 // OCC went active
490 queuedActiveState.insert(instance);
491 }
492 else
493 {
494 auto match = queuedActiveState.find(instance);
495 if (match != queuedActiveState.end())
496 {
497 // OCC was disabled
498 queuedActiveState.erase(match);
499 }
500 }
Chris Cain7e374fb2022-04-07 09:47:23 -0500501 return false;
502 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530503}
Eddie Jamescbad2192021-10-07 09:39:39 -0500504
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500505// Called upon pldm event To set powermode Safe Mode State for system.
506void Manager::updateOccSafeMode(bool safeMode)
507{
508#ifdef POWER10
509 pmode->updateDbusSafeMode(safeMode);
510#endif
511}
512
Eddie Jamescbad2192021-10-07 09:39:39 -0500513void Manager::sbeHRESETResult(instanceID instance, bool success)
514{
515 if (success)
516 {
Chris Cainbae4d072022-02-28 09:46:50 -0600517 log<level::INFO>(
518 fmt::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500519
520 setSBEState(instance, SBE_STATE_BOOTED);
521
522 return;
523 }
524
525 setSBEState(instance, SBE_STATE_FAILED);
526
527 if (sbeCanDump(instance))
528 {
Chris Cainbae4d072022-02-28 09:46:50 -0600529 log<level::INFO>(
530 fmt::format("HRESET failed (OCC{}), triggering SBE dump", instance)
531 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500532
533 auto& bus = utils::getBus();
534 uint32_t src6 = instance << 16;
535 uint32_t logId =
536 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
537 src6, "SBE command timeout");
538
539 try
540 {
George Liuf3a4a692021-12-28 13:59:51 +0800541 constexpr auto path = "/org/openpower/dump";
542 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
543 constexpr auto function = "CreateDump";
544
Eddie Jamescbad2192021-10-07 09:39:39 -0500545 std::string service = utils::getService(path, interface);
546 auto method =
547 bus.new_method_call(service.c_str(), path, interface, function);
548
549 std::map<std::string, std::variant<std::string, uint64_t>>
550 createParams{
551 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
552 uint64_t(logId)},
553 {"com.ibm.Dump.Create.CreateParameters.DumpType",
554 "com.ibm.Dump.Create.DumpType.SBE"},
555 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
556 uint64_t(instance)},
557 };
558
559 method.append(createParams);
560
561 auto response = bus.call(method);
562 }
563 catch (const sdbusplus::exception::exception& e)
564 {
565 constexpr auto ERROR_DUMP_DISABLED =
566 "xyz.openbmc_project.Dump.Create.Error.Disabled";
567 if (e.name() == ERROR_DUMP_DISABLED)
568 {
569 log<level::INFO>("Dump is disabled, skipping");
570 }
571 else
572 {
573 log<level::ERR>("Dump failed");
574 }
575 }
576 }
577}
578
579bool Manager::sbeCanDump(unsigned int instance)
580{
581 struct pdbg_target* proc = getPdbgTarget(instance);
582
583 if (!proc)
584 {
585 // allow the dump in the error case
586 return true;
587 }
588
589 try
590 {
591 if (!openpower::phal::sbe::isDumpAllowed(proc))
592 {
593 return false;
594 }
595
596 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
597 {
598 return false;
599 }
600 }
601 catch (openpower::phal::exception::SbeError& e)
602 {
603 log<level::INFO>("Failed to query SBE state");
604 }
605
606 // allow the dump in the error case
607 return true;
608}
609
610void Manager::setSBEState(unsigned int instance, enum sbe_state state)
611{
612 struct pdbg_target* proc = getPdbgTarget(instance);
613
614 if (!proc)
615 {
616 return;
617 }
618
619 try
620 {
621 openpower::phal::sbe::setState(proc, state);
622 }
623 catch (const openpower::phal::exception::SbeError& e)
624 {
625 log<level::ERR>("Failed to set SBE state");
626 }
627}
628
629struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
630{
631 if (!pdbgInitialized)
632 {
633 try
634 {
635 openpower::phal::pdbg::init();
636 pdbgInitialized = true;
637 }
638 catch (const openpower::phal::exception::PdbgError& e)
639 {
640 log<level::ERR>("pdbg initialization failed");
641 return nullptr;
642 }
643 }
644
645 struct pdbg_target* proc = nullptr;
646 pdbg_for_each_class_target("proc", proc)
647 {
648 if (pdbg_target_index(proc) == instance)
649 {
650 return proc;
651 }
652 }
653
654 log<level::ERR>("Failed to get pdbg target");
655 return nullptr;
656}
Tom Joseph815f9f52020-07-27 12:12:13 +0530657#endif
658
Chris Caina8857c52021-01-27 11:53:05 -0600659void Manager::pollerTimerExpired()
660{
Chris Caina8857c52021-01-27 11:53:05 -0600661 if (!_pollTimer)
662 {
663 log<level::ERR>(
664 "Manager::pollerTimerExpired() ERROR: Timer not defined");
665 return;
666 }
667
668 for (auto& obj : statusObjects)
669 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600670 if (!obj->occActive())
671 {
672 // OCC is not running yet
673#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600674 auto id = obj->getOccInstanceID();
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500675 setSensorValueToNaN(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600676#endif
677 continue;
678 }
679
Chris Caina8857c52021-01-27 11:53:05 -0600680 // Read sysfs to force kernel to poll OCC
681 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800682
683#ifdef READ_OCC_SENSORS
684 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600685 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800686#endif
Chris Caina8857c52021-01-27 11:53:05 -0600687 }
688
Chris Caina7b74dc2021-11-10 17:03:43 -0600689 if (activeCount > 0)
690 {
691 // Restart OCC poll timer
692 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
693 }
694 else
695 {
696 // No OCCs running, so poll timer will not be restarted
697 log<level::INFO>(
698 fmt::format(
699 "Manager::pollerTimerExpired: poll timer will not be restarted")
700 .c_str());
701 }
Chris Caina8857c52021-01-27 11:53:05 -0600702}
703
Chicago Duanbb895cb2021-06-18 19:37:16 +0800704#ifdef READ_OCC_SENSORS
705void Manager::readTempSensors(const fs::path& path, uint32_t id)
706{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800707 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
708 for (auto& file : fs::directory_iterator(path))
709 {
710 if (!std::regex_search(file.path().string(), expr))
711 {
712 continue;
713 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800714
Matt Spinlera26f1522021-08-25 15:50:20 -0500715 uint32_t labelValue{0};
716
717 try
718 {
719 labelValue = readFile<uint32_t>(file.path());
720 }
721 catch (const std::system_error& e)
722 {
723 log<level::DEBUG>(
724 fmt::format("readTempSensors: Failed reading {}, errno = {}",
725 file.path().string(), e.code().value())
726 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800727 continue;
728 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800729
730 const std::string& tempLabel = "label";
731 const std::string filePathString = file.path().string().substr(
732 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500733
734 uint32_t fruTypeValue{0};
735 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800736 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500737 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
738 }
739 catch (const std::system_error& e)
740 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800741 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500742 fmt::format("readTempSensors: Failed reading {}, errno = {}",
743 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800744 .c_str());
745 continue;
746 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800747
748 std::string sensorPath =
749 OCC_SENSORS_ROOT + std::string("/temperature/");
750
Matt Spinlerace67d82021-10-18 13:41:57 -0500751 std::string dvfsTempPath;
752
Chicago Duanbb895cb2021-06-18 19:37:16 +0800753 if (fruTypeValue == VRMVdd)
754 {
755 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
756 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500757 else if (fruTypeValue == processorIoRing)
758 {
759 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
760 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
761 std::to_string(id) + "_ioring_dvfs_temp";
762 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800763 else
764 {
Matt Spinler14d14022021-08-25 15:38:29 -0500765 uint16_t type = (labelValue & 0xFF000000) >> 24;
766 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800767
768 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
769 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500770 if (fruTypeValue == fruTypeNotAvailable)
771 {
772 // Not all DIMM related temps are available to read
773 // (no _input file in this case)
774 continue;
775 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800776 auto iter = dimmTempSensorName.find(fruTypeValue);
777 if (iter == dimmTempSensorName.end())
778 {
George Liub5ca1012021-09-10 12:53:11 +0800779 log<level::ERR>(
780 fmt::format(
781 "readTempSensors: Fru type error! fruTypeValue = {}) ",
782 fruTypeValue)
783 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800784 continue;
785 }
786
787 sensorPath.append("dimm" + std::to_string(instanceID) +
788 iter->second);
789 }
790 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
791 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500792 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800793 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500794 // The OCC reports small core temps, of which there are
795 // two per big core. All current P10 systems are in big
796 // core mode, so use a big core name.
797 uint16_t coreNum = instanceID / 2;
798 uint16_t tempNum = instanceID % 2;
799 sensorPath.append("proc" + std::to_string(id) + "_core" +
800 std::to_string(coreNum) + "_" +
801 std::to_string(tempNum) + "_temp");
802
803 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
804 "/temperature/proc" + std::to_string(id) +
805 "_core_dvfs_temp";
806 }
807 else
808 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800809 continue;
810 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800811 }
812 else
813 {
814 continue;
815 }
816 }
817
Matt Spinlerace67d82021-10-18 13:41:57 -0500818 // The dvfs temp file only needs to be read once per chip per type.
819 if (!dvfsTempPath.empty() &&
820 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
821 {
822 try
823 {
824 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
825
826 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
827 dvfsTempPath, dvfsValue * std::pow(10, -3));
828 }
829 catch (const std::system_error& e)
830 {
831 log<level::DEBUG>(
832 fmt::format(
833 "readTempSensors: Failed reading {}, errno = {}",
834 filePathString + maxSuffix, e.code().value())
835 .c_str());
836 }
837 }
838
Matt Spinlera26f1522021-08-25 15:50:20 -0500839 uint32_t faultValue{0};
840 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800841 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500842 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
843 }
844 catch (const std::system_error& e)
845 {
846 log<level::DEBUG>(
847 fmt::format("readTempSensors: Failed reading {}, errno = {}",
848 filePathString + faultSuffix, e.code().value())
849 .c_str());
850 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800851 }
852
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500853 // NOTE: if OCC sends back 0xFF kernal sets this fault value to 1.
Matt Spinlera26f1522021-08-25 15:50:20 -0500854 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800855 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600856 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500857 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800858
Chris Cain5d66a0a2022-02-09 08:52:10 -0600859 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
860 false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800861
Matt Spinlera26f1522021-08-25 15:50:20 -0500862 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800863 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500864
865 double tempValue{0};
866
867 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800868 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500869 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800870 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500871 catch (const std::system_error& e)
872 {
873 log<level::DEBUG>(
874 fmt::format("readTempSensors: Failed reading {}, errno = {}",
875 filePathString + inputSuffix, e.code().value())
876 .c_str());
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500877
878 // if errno == EAGAIN(Resource temporarily unavailable) then set
879 // temp to 0, to avoid using old temp, and affecting FAN Control.
880 if (e.code().value() == EAGAIN)
881 {
882 tempValue = 0;
883 }
884 // else the errno would be something like
885 // EBADF(Bad file descriptor)
886 // or ENOENT(No such file or directory)
887 else
888 {
889 continue;
890 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500891 }
892
Chris Cain5d66a0a2022-02-09 08:52:10 -0600893 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500894 sensorPath, tempValue * std::pow(10, -3));
895
Chris Cain5d66a0a2022-02-09 08:52:10 -0600896 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
897 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500898
Chris Cain6fa848a2022-01-24 14:54:38 -0600899 // At this point, the sensor will be created for sure.
900 if (existingSensors.find(sensorPath) == existingSensors.end())
901 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600902 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
903 sensorPath);
Chris Cain6fa848a2022-01-24 14:54:38 -0600904 }
905
Matt Spinlera26f1522021-08-25 15:50:20 -0500906 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800907 }
908 return;
909}
910
911std::optional<std::string>
912 Manager::getPowerLabelFunctionID(const std::string& value)
913{
914 // If the value is "system", then the FunctionID is "system".
915 if (value == "system")
916 {
917 return value;
918 }
919
920 // If the value is not "system", then the label value have 3 numbers, of
921 // which we only care about the middle one:
922 // <sensor id>_<function id>_<apss channel>
923 // eg: The value is "0_10_5" , then the FunctionID is "10".
924 if (value.find("_") == std::string::npos)
925 {
926 return std::nullopt;
927 }
928
929 auto powerLabelValue = value.substr((value.find("_") + 1));
930
931 if (powerLabelValue.find("_") == std::string::npos)
932 {
933 return std::nullopt;
934 }
935
936 return powerLabelValue.substr(0, powerLabelValue.find("_"));
937}
938
939void Manager::readPowerSensors(const fs::path& path, uint32_t id)
940{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800941 std::regex expr{"power\\d+_label$"}; // Example: power5_label
942 for (auto& file : fs::directory_iterator(path))
943 {
944 if (!std::regex_search(file.path().string(), expr))
945 {
946 continue;
947 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800948
Matt Spinlera26f1522021-08-25 15:50:20 -0500949 std::string labelValue;
950 try
951 {
952 labelValue = readFile<std::string>(file.path());
953 }
954 catch (const std::system_error& e)
955 {
956 log<level::DEBUG>(
957 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
958 file.path().string(), e.code().value())
959 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800960 continue;
961 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800962
963 auto functionID = getPowerLabelFunctionID(labelValue);
964 if (functionID == std::nullopt)
965 {
966 continue;
967 }
968
969 const std::string& tempLabel = "label";
970 const std::string filePathString = file.path().string().substr(
971 0, file.path().string().length() - tempLabel.length());
972
973 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
974
975 auto iter = powerSensorName.find(*functionID);
976 if (iter == powerSensorName.end())
977 {
978 continue;
979 }
980 sensorPath.append(iter->second);
981
Matt Spinlera26f1522021-08-25 15:50:20 -0500982 double tempValue{0};
983
984 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800985 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500986 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800987 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500988 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800989 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800990 log<level::DEBUG>(
Chris Cain5d66a0a2022-02-09 08:52:10 -0600991 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500992 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800993 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500994 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800995 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500996
Chris Cain5d66a0a2022-02-09 08:52:10 -0600997 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -0600998 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
999
Chris Cain5d66a0a2022-02-09 08:52:10 -06001000 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -05001001 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
1002
Chris Cain5d66a0a2022-02-09 08:52:10 -06001003 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
1004 true);
Matt Spinlera26f1522021-08-25 15:50:20 -05001005
Matt Spinler5901abd2021-09-23 13:50:03 -05001006 if (existingSensors.find(sensorPath) == existingSensors.end())
1007 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001008 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
1009 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -05001010 }
1011
Matt Spinlera26f1522021-08-25 15:50:20 -05001012 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +08001013 }
1014 return;
1015}
1016
Sheldon Baileyc8dd4592022-05-12 10:15:14 -05001017void Manager::setSensorValueToNaN(uint32_t id) const
Chicago Duanbb895cb2021-06-18 19:37:16 +08001018{
1019 for (const auto& [sensorPath, occId] : existingSensors)
1020 {
1021 if (occId == id)
1022 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001023 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +08001024 sensorPath, std::numeric_limits<double>::quiet_NaN());
Sheldon Baileyc8dd4592022-05-12 10:15:14 -05001025
1026 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
1027 true);
Chicago Duanbb895cb2021-06-18 19:37:16 +08001028 }
1029 }
1030 return;
1031}
1032
Sheldon Bailey373af752022-02-21 15:14:00 -06001033void Manager::setSensorValueToNonFunctional(uint32_t id) const
1034{
1035 for (const auto& [sensorPath, occId] : existingSensors)
1036 {
1037 if (occId == id)
1038 {
1039 dbus::OccDBusSensors::getOccDBus().setValue(
1040 sensorPath, std::numeric_limits<double>::quiet_NaN());
1041
1042 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
1043 false);
1044 }
1045 }
1046 return;
1047}
1048
Chris Cain5d66a0a2022-02-09 08:52:10 -06001049void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +08001050{
Chris Caine2d0a432022-03-28 11:08:49 -05001051 static bool tracedError[8] = {0};
1052 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -06001053 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +08001054
Chris Caine2d0a432022-03-28 11:08:49 -05001055 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +08001056 {
Chris Caine2d0a432022-03-28 11:08:49 -05001057 // Read temperature sensors
1058 readTempSensors(sensorPath, id);
1059
1060 if (occ->isMasterOcc())
1061 {
1062 // Read power sensors
1063 readPowerSensors(sensorPath, id);
1064 }
1065 tracedError[id] = false;
1066 }
1067 else
1068 {
1069 if (!tracedError[id])
1070 {
1071 log<level::ERR>(
1072 fmt::format(
1073 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1074 id, sensorPath.c_str())
1075 .c_str());
1076 tracedError[id] = true;
1077 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001078 }
1079
1080 return;
1081}
1082#endif
Chris Cain17257672021-10-22 13:41:03 -05001083
1084// Read the altitude from DBus
1085void Manager::readAltitude()
1086{
1087 static bool traceAltitudeErr = true;
1088
1089 utils::PropertyValue altitudeProperty{};
1090 try
1091 {
1092 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1093 ALTITUDE_PROP);
1094 auto sensorVal = std::get<double>(altitudeProperty);
1095 if (sensorVal < 0xFFFF)
1096 {
1097 if (sensorVal < 0)
1098 {
1099 altitude = 0;
1100 }
1101 else
1102 {
1103 // Round to nearest meter
1104 altitude = uint16_t(sensorVal + 0.5);
1105 }
1106 log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)",
1107 sensorVal, altitude)
1108 .c_str());
1109 traceAltitudeErr = true;
1110 }
1111 else
1112 {
1113 if (traceAltitudeErr)
1114 {
1115 traceAltitudeErr = false;
1116 log<level::DEBUG>(
1117 fmt::format("Invalid altitude value: {}", sensorVal)
1118 .c_str());
1119 }
1120 }
1121 }
1122 catch (const sdbusplus::exception::exception& e)
1123 {
1124 if (traceAltitudeErr)
1125 {
1126 traceAltitudeErr = false;
1127 log<level::INFO>(
1128 fmt::format("Unable to read Altitude: {}", e.what()).c_str());
1129 }
1130 altitude = 0xFFFF; // not available
1131 }
1132}
1133
1134// Callback function when ambient temperature changes
1135void Manager::ambientCallback(sdbusplus::message::message& msg)
1136{
1137 double currentTemp = 0;
1138 uint8_t truncatedTemp = 0xFF;
1139 std::string msgSensor;
1140 std::map<std::string, std::variant<double>> msgData;
1141 msg.read(msgSensor, msgData);
1142
1143 auto valPropMap = msgData.find(AMBIENT_PROP);
1144 if (valPropMap == msgData.end())
1145 {
1146 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1147 return;
1148 }
1149 currentTemp = std::get<double>(valPropMap->second);
1150 if (std::isnan(currentTemp))
1151 {
1152 truncatedTemp = 0xFF;
1153 }
1154 else
1155 {
1156 if (currentTemp < 0)
1157 {
1158 truncatedTemp = 0;
1159 }
1160 else
1161 {
1162 // Round to nearest degree C
1163 truncatedTemp = uint8_t(currentTemp + 0.5);
1164 }
1165 }
1166
1167 // If ambient changes, notify OCCs
1168 if (truncatedTemp != ambient)
1169 {
1170 log<level::DEBUG>(
1171 fmt::format("ambientCallback: Ambient change from {} to {}C",
1172 ambient, currentTemp)
1173 .c_str());
1174
1175 ambient = truncatedTemp;
1176 if (altitude == 0xFFFF)
1177 {
1178 // No altitude yet, try reading again
1179 readAltitude();
1180 }
1181
1182 log<level::DEBUG>(
1183 fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
1184 altitude)
1185 .c_str());
1186#ifdef POWER10
1187 // Send ambient and altitude to all OCCs
1188 for (auto& obj : statusObjects)
1189 {
1190 if (obj->occActive())
1191 {
1192 obj->sendAmbient(ambient, altitude);
1193 }
1194 }
1195#endif // POWER10
1196 }
1197}
1198
1199// return the current ambient and altitude readings
1200void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1201 uint16_t& altitudeValue) const
1202{
1203 ambientValid = true;
1204 ambientTemp = ambient;
1205 altitudeValue = altitude;
1206
1207 if (ambient == 0xFF)
1208 {
1209 ambientValid = false;
1210 }
1211}
1212
Chris Caina7b74dc2021-11-10 17:03:43 -06001213#ifdef POWER10
Chris Cain7f89e4d2022-05-09 13:27:45 -05001214// Called when waitForAllOccsTimer expires
1215// After the first OCC goes active, this timer will be started (60 seconds)
Chris Caina7b74dc2021-11-10 17:03:43 -06001216void Manager::occsNotAllRunning()
1217{
Chris Caina7b74dc2021-11-10 17:03:43 -06001218 if (activeCount != statusObjects.size())
1219 {
1220 // Not all OCCs went active
1221 log<level::WARNING>(
1222 fmt::format(
1223 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1224 activeCount, statusObjects.size())
1225 .c_str());
Chris Cain7f89e4d2022-05-09 13:27:45 -05001226 // Procs may be garded, so may be expected
Chris Caina7b74dc2021-11-10 17:03:43 -06001227 }
1228
1229 validateOccMaster();
1230}
1231#endif // POWER10
1232
1233// Verify single master OCC and start presence monitor
1234void Manager::validateOccMaster()
1235{
1236 int masterInstance = -1;
1237 for (auto& obj : statusObjects)
1238 {
Chris Cainbd551de2022-04-26 13:41:16 -05001239 auto instance = obj->getOccInstanceID();
Chris Cainbae4d072022-02-28 09:46:50 -06001240#ifdef POWER10
1241 if (!obj->occActive())
1242 {
1243 if (utils::isHostRunning())
1244 {
Chris Cainbd551de2022-04-26 13:41:16 -05001245 // Check if sensor was queued while waiting for discovery
1246 auto match = queuedActiveState.find(instance);
1247 if (match != queuedActiveState.end())
Chris Cainbae4d072022-02-28 09:46:50 -06001248 {
Chris Cain7f89e4d2022-05-09 13:27:45 -05001249 queuedActiveState.erase(match);
Chris Cainbae4d072022-02-28 09:46:50 -06001250 log<level::INFO>(
1251 fmt::format(
Chris Cainbd551de2022-04-26 13:41:16 -05001252 "validateOccMaster: OCC{} is ACTIVE (queued)",
1253 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001254 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -05001255 obj->occActive(true);
1256 }
1257 else
1258 {
1259 // OCC does not appear to be active yet, check active sensor
1260 pldmHandle->checkActiveSensor(instance);
1261 if (obj->occActive())
1262 {
1263 log<level::INFO>(
1264 fmt::format(
1265 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1266 instance)
1267 .c_str());
1268 }
Chris Cainbae4d072022-02-28 09:46:50 -06001269 }
1270 }
1271 else
1272 {
1273 log<level::WARNING>(
1274 fmt::format(
1275 "validateOccMaster: HOST is not running (OCC{})",
Chris Cainbd551de2022-04-26 13:41:16 -05001276 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001277 .c_str());
1278 return;
1279 }
1280 }
1281#endif // POWER10
1282
Chris Caina7b74dc2021-11-10 17:03:43 -06001283 if (obj->isMasterOcc())
1284 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001285 obj->addPresenceWatchMaster();
1286
Chris Caina7b74dc2021-11-10 17:03:43 -06001287 if (masterInstance == -1)
1288 {
Chris Cainbd551de2022-04-26 13:41:16 -05001289 masterInstance = instance;
Chris Caina7b74dc2021-11-10 17:03:43 -06001290 }
1291 else
1292 {
1293 log<level::ERR>(
1294 fmt::format(
1295 "validateOccMaster: Multiple OCC masters! ({} and {})",
Chris Cainbd551de2022-04-26 13:41:16 -05001296 masterInstance, instance)
Chris Caina7b74dc2021-11-10 17:03:43 -06001297 .c_str());
1298 // request reset
Eddie James9789e712022-05-25 15:43:40 -05001299 obj->deviceError(Error::Descriptor(PRESENCE_ERROR_PATH));
Chris Caina7b74dc2021-11-10 17:03:43 -06001300 }
1301 }
1302 }
Chris Cainbae4d072022-02-28 09:46:50 -06001303
Chris Caina7b74dc2021-11-10 17:03:43 -06001304 if (masterInstance < 0)
1305 {
Chris Cainbae4d072022-02-28 09:46:50 -06001306 log<level::ERR>(
1307 fmt::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
1308 statusObjects.size())
1309 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001310 // request reset
Eddie James9789e712022-05-25 15:43:40 -05001311 statusObjects.front()->deviceError(
1312 Error::Descriptor(PRESENCE_ERROR_PATH));
Chris Caina7b74dc2021-11-10 17:03:43 -06001313 }
1314 else
1315 {
1316 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -06001317 fmt::format("validateOccMaster: OCC{} is master of {} OCCs",
1318 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001319 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -05001320#ifdef POWER10
1321 pmode->updateDbusSafeMode(false);
1322#endif
Chris Caina7b74dc2021-11-10 17:03:43 -06001323 }
1324}
1325
Chris Cain40501a22022-03-14 17:33:27 -05001326void Manager::updatePcapBounds() const
1327{
1328 if (pcap)
1329 {
1330 pcap->updatePcapBounds();
1331 }
1332}
1333
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301334} // namespace occ
1335} // namespace open_power