blob: 72d7ada33b96e4da992d2dd44cea45f1089abb4c [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 {
168 // If active sensor is already true, then no need to query sensor
169 if (!obj->occActive())
170 {
Chris Cainbd551de2022-04-26 13:41:16 -0500171 auto instance = obj->getOccInstanceID();
172 // Check if sensor was queued while waiting for discovery
173 auto match = queuedActiveState.find(instance);
174 if (match != queuedActiveState.end())
Chris Cainbae4d072022-02-28 09:46:50 -0600175 {
176 log<level::INFO>(
177 fmt::format(
Chris Cainbd551de2022-04-26 13:41:16 -0500178 "checkAllActiveSensors(): OCC{} is ACTIVE (queued)",
179 instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600180 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -0500181 obj->occActive(true);
Chris Cainbae4d072022-02-28 09:46:50 -0600182 }
Chris Cainbd551de2022-04-26 13:41:16 -0500183 else
184 {
185 allActiveSensorAvailable = false;
186 if (!tracedSensorWait)
187 {
188 log<level::INFO>(
189 fmt::format(
190 "checkAllActiveSensors(): Waiting on OCC{} Active sensor",
191 instance)
192 .c_str());
193 tracedSensorWait = true;
194 }
195 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
196 break;
197 }
Chris Cainbae4d072022-02-28 09:46:50 -0600198 }
199 }
200
201 if (allActiveSensorAvailable)
202 {
203 // All sensors were found, disable the discovery timer
204 discoverTimer.reset();
205 waitingForAllOccActiveSensors = false;
Chris Cainbd551de2022-04-26 13:41:16 -0500206 queuedActiveState.clear();
Chris Cainbae4d072022-02-28 09:46:50 -0600207
208 log<level::INFO>(
Chris Cainbd551de2022-04-26 13:41:16 -0500209 "checkAllActiveSensors(): OCC Active sensors are available");
Chris Cainbae4d072022-02-28 09:46:50 -0600210 tracedSensorWait = false;
211 }
212 else
213 {
214 // Not all sensors were available, so keep waiting
215 if (!tracedSensorWait)
216 {
217 log<level::INFO>(
Chris Cainbd551de2022-04-26 13:41:16 -0500218 "checkAllActiveSensors(): Waiting for OCC Active sensors to become available");
Chris Cainbae4d072022-02-28 09:46:50 -0600219 tracedSensorWait = true;
220 }
Chris Cainbd551de2022-04-26 13:41:16 -0500221 discoverTimer->restartOnce(10s);
Chris Cainbae4d072022-02-28 09:46:50 -0600222 }
223}
224#endif
225
Matt Spinlerd267cec2021-09-01 14:49:19 -0500226std::vector<int> Manager::findOCCsInDev()
227{
228 std::vector<int> occs;
229 std::regex expr{R"(occ(\d+)$)"};
230
231 for (auto& file : fs::directory_iterator("/dev"))
232 {
233 std::smatch match;
234 std::string path{file.path().string()};
235 if (std::regex_search(path, match, expr))
236 {
237 auto num = std::stoi(match[1].str());
238
239 // /dev numbering starts at 1, ours starts at 0.
240 occs.push_back(num - 1);
241 }
242 }
243
244 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530245}
246
247int Manager::cpuCreated(sdbusplus::message::message& msg)
248{
George Liubcef3b42021-09-10 12:39:02 +0800249 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530250
251 sdbusplus::message::object_path o;
252 msg.read(o);
253 fs::path cpuPath(std::string(std::move(o)));
254
255 auto name = cpuPath.filename().string();
256 auto index = name.find(CPU_NAME);
257 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
258
259 createObjects(name);
260
261 return 0;
262}
263
264void Manager::createObjects(const std::string& occ)
265{
266 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
267
Gunnar Mills94df8c92018-09-14 14:50:03 -0500268 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800269 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600270#ifdef POWER10
271 pmode,
272#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500273 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Sheldon Bailey373af752022-02-21 15:14:00 -0600274 std::placeholders::_1, std::placeholders::_2)
Tom Joseph00325232020-07-29 17:51:48 +0530275#ifdef PLDM
276 ,
277 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
278 std::placeholders::_1)
279#endif
280 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530281
Chris Cain40501a22022-03-14 17:33:27 -0500282 // Create the power cap monitor object
283 if (!pcap)
284 {
285 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
286 *statusObjects.back());
287 }
288
Chris Cain36f9cde2021-11-22 11:18:21 -0600289 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530290 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600291 log<level::INFO>(
292 fmt::format("Manager::createObjects(): OCC{} is the master",
293 statusObjects.back()->getOccInstanceID())
294 .c_str());
295 _pollTimer->setEnabled(false);
296
Chris Cain78e86012021-03-04 16:15:31 -0600297#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600298 // Set the master OCC on the PowerMode object
299 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600300#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600301 }
302
303 passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str()
304#ifdef POWER10
305 ,
306 pmode
307#endif
308 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530309}
310
Sheldon Bailey373af752022-02-21 15:14:00 -0600311void Manager::statusCallBack(instanceID instance, bool status)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530312{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500313 using InternalFailure =
314 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530315
316 // At this time, it won't happen but keeping it
317 // here just in case something changes in the future
318 if ((activeCount == 0) && (!status))
319 {
Sheldon Bailey373af752022-02-21 15:14:00 -0600320 log<level::ERR>(
321 fmt::format("Invalid update on OCCActive with OCC{}", instance)
322 .c_str());
323
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530324 elog<InternalFailure>();
325 }
326
Chris Caina7b74dc2021-11-10 17:03:43 -0600327 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600328 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600329 // OCC went active
330 ++activeCount;
331
332#ifdef POWER10
333 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600334 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600335 // First OCC went active (allow some time for all OCCs to go active)
Chris Cainbd551de2022-04-26 13:41:16 -0500336 waitForAllOccsTimer->restartOnce(60s);
Matt Spinler53f68142021-08-25 15:47:31 -0500337 }
338#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600339
340 if (activeCount == statusObjects.size())
341 {
342#ifdef POWER10
343 // All OCCs are now running
344 if (waitForAllOccsTimer->isEnabled())
345 {
346 // stop occ wait timer
347 waitForAllOccsTimer->setEnabled(false);
348 }
349#endif
350
351 // Verify master OCC and start presence monitor
352 validateOccMaster();
353 }
354
355 // Start poll timer if not already started
356 if (!_pollTimer->isEnabled())
357 {
358 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -0600359 fmt::format("Manager: OCCs will be polled every {} seconds",
360 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600361 .c_str());
362
363 // Send poll and start OCC poll timer
364 pollerTimerExpired();
365 }
366 }
367 else
368 {
369 // OCC went away
370 --activeCount;
371
372 if (activeCount == 0)
373 {
374 // No OCCs are running
375
376 // Stop OCC poll timer
377 if (_pollTimer->isEnabled())
378 {
379 log<level::INFO>(
380 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
381 _pollTimer->setEnabled(false);
382 }
383
384#ifdef POWER10
385 // stop wait timer
386 if (waitForAllOccsTimer->isEnabled())
387 {
388 waitForAllOccsTimer->setEnabled(false);
389 }
390#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600391 }
Sheldon Bailey373af752022-02-21 15:14:00 -0600392#ifdef READ_OCC_SENSORS
393 // Clear OCC sensors
394 setSensorValueToNonFunctional(instance);
395#endif
Chris Caina8857c52021-01-27 11:53:05 -0600396 }
Chris Cainbae4d072022-02-28 09:46:50 -0600397
398#ifdef POWER10
399 if (waitingForAllOccActiveSensors)
400 {
Chris Cain6d8f37a2022-04-29 13:46:01 -0500401 if (utils::isHostRunning())
402 {
403 checkAllActiveSensors();
404 }
Chris Cainbae4d072022-02-28 09:46:50 -0600405 }
406#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530407}
408
409#ifdef I2C_OCC
410void Manager::initStatusObjects()
411{
412 // Make sure we have a valid path string
413 static_assert(sizeof(DEV_PATH) != 0);
414
415 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
416 for (auto& name : deviceNames)
417 {
418 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800419 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530420 auto path = fs::path(OCC_CONTROL_ROOT) / name;
421 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800422 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530423 }
Chris Cain40501a22022-03-14 17:33:27 -0500424 // The first device is master occ
425 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
426 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600427#ifdef POWER10
Chris Cain5d66a0a2022-02-09 08:52:10 -0600428 pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
429 powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600430 // Set the master OCC on the PowerMode object
431 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600432#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530433}
434#endif
435
Tom Joseph815f9f52020-07-27 12:12:13 +0530436#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500437void Manager::sbeTimeout(unsigned int instance)
438{
Eddie James2a751d72022-03-04 09:16:12 -0600439 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
440 [instance](const auto& obj) {
441 return instance == obj->getOccInstanceID();
442 });
Eddie Jamescbad2192021-10-07 09:39:39 -0500443
Eddie Jamescb018da2022-03-05 11:49:37 -0600444 if (obj != statusObjects.end() && (*obj)->occActive())
Eddie James2a751d72022-03-04 09:16:12 -0600445 {
Chris Cainbae4d072022-02-28 09:46:50 -0600446 log<level::INFO>(
447 fmt::format("SBE timeout, requesting HRESET (OCC{})", instance)
448 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500449
Eddie James2a751d72022-03-04 09:16:12 -0600450 setSBEState(instance, SBE_STATE_NOT_USABLE);
451
452 pldmHandle->sendHRESET(instance);
453 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500454}
455
Tom Joseph815f9f52020-07-27 12:12:13 +0530456bool Manager::updateOCCActive(instanceID instance, bool status)
457{
Chris Cain7e374fb2022-04-07 09:47:23 -0500458 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
459 [instance](const auto& obj) {
460 return instance == obj->getOccInstanceID();
461 });
462
463 if (obj != statusObjects.end())
464 {
465 return (*obj)->occActive(status);
466 }
467 else
468 {
469 log<level::WARNING>(
470 fmt::format(
471 "Manager::updateOCCActive: No status object to update for OCC{} (active={})",
472 instance, status)
473 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -0500474 if (status == true)
475 {
476 // OCC went active
477 queuedActiveState.insert(instance);
478 }
479 else
480 {
481 auto match = queuedActiveState.find(instance);
482 if (match != queuedActiveState.end())
483 {
484 // OCC was disabled
485 queuedActiveState.erase(match);
486 }
487 }
Chris Cain7e374fb2022-04-07 09:47:23 -0500488 return false;
489 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530490}
Eddie Jamescbad2192021-10-07 09:39:39 -0500491
492void Manager::sbeHRESETResult(instanceID instance, bool success)
493{
494 if (success)
495 {
Chris Cainbae4d072022-02-28 09:46:50 -0600496 log<level::INFO>(
497 fmt::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500498
499 setSBEState(instance, SBE_STATE_BOOTED);
500
501 return;
502 }
503
504 setSBEState(instance, SBE_STATE_FAILED);
505
506 if (sbeCanDump(instance))
507 {
Chris Cainbae4d072022-02-28 09:46:50 -0600508 log<level::INFO>(
509 fmt::format("HRESET failed (OCC{}), triggering SBE dump", instance)
510 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500511
512 auto& bus = utils::getBus();
513 uint32_t src6 = instance << 16;
514 uint32_t logId =
515 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
516 src6, "SBE command timeout");
517
518 try
519 {
George Liuf3a4a692021-12-28 13:59:51 +0800520 constexpr auto path = "/org/openpower/dump";
521 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
522 constexpr auto function = "CreateDump";
523
Eddie Jamescbad2192021-10-07 09:39:39 -0500524 std::string service = utils::getService(path, interface);
525 auto method =
526 bus.new_method_call(service.c_str(), path, interface, function);
527
528 std::map<std::string, std::variant<std::string, uint64_t>>
529 createParams{
530 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
531 uint64_t(logId)},
532 {"com.ibm.Dump.Create.CreateParameters.DumpType",
533 "com.ibm.Dump.Create.DumpType.SBE"},
534 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
535 uint64_t(instance)},
536 };
537
538 method.append(createParams);
539
540 auto response = bus.call(method);
541 }
542 catch (const sdbusplus::exception::exception& e)
543 {
544 constexpr auto ERROR_DUMP_DISABLED =
545 "xyz.openbmc_project.Dump.Create.Error.Disabled";
546 if (e.name() == ERROR_DUMP_DISABLED)
547 {
548 log<level::INFO>("Dump is disabled, skipping");
549 }
550 else
551 {
552 log<level::ERR>("Dump failed");
553 }
554 }
555 }
556}
557
558bool Manager::sbeCanDump(unsigned int instance)
559{
560 struct pdbg_target* proc = getPdbgTarget(instance);
561
562 if (!proc)
563 {
564 // allow the dump in the error case
565 return true;
566 }
567
568 try
569 {
570 if (!openpower::phal::sbe::isDumpAllowed(proc))
571 {
572 return false;
573 }
574
575 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
576 {
577 return false;
578 }
579 }
580 catch (openpower::phal::exception::SbeError& e)
581 {
582 log<level::INFO>("Failed to query SBE state");
583 }
584
585 // allow the dump in the error case
586 return true;
587}
588
589void Manager::setSBEState(unsigned int instance, enum sbe_state state)
590{
591 struct pdbg_target* proc = getPdbgTarget(instance);
592
593 if (!proc)
594 {
595 return;
596 }
597
598 try
599 {
600 openpower::phal::sbe::setState(proc, state);
601 }
602 catch (const openpower::phal::exception::SbeError& e)
603 {
604 log<level::ERR>("Failed to set SBE state");
605 }
606}
607
608struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
609{
610 if (!pdbgInitialized)
611 {
612 try
613 {
614 openpower::phal::pdbg::init();
615 pdbgInitialized = true;
616 }
617 catch (const openpower::phal::exception::PdbgError& e)
618 {
619 log<level::ERR>("pdbg initialization failed");
620 return nullptr;
621 }
622 }
623
624 struct pdbg_target* proc = nullptr;
625 pdbg_for_each_class_target("proc", proc)
626 {
627 if (pdbg_target_index(proc) == instance)
628 {
629 return proc;
630 }
631 }
632
633 log<level::ERR>("Failed to get pdbg target");
634 return nullptr;
635}
Tom Joseph815f9f52020-07-27 12:12:13 +0530636#endif
637
Chris Caina8857c52021-01-27 11:53:05 -0600638void Manager::pollerTimerExpired()
639{
Chris Caina8857c52021-01-27 11:53:05 -0600640 if (!_pollTimer)
641 {
642 log<level::ERR>(
643 "Manager::pollerTimerExpired() ERROR: Timer not defined");
644 return;
645 }
646
647 for (auto& obj : statusObjects)
648 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600649 if (!obj->occActive())
650 {
651 // OCC is not running yet
652#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600653 auto id = obj->getOccInstanceID();
Sheldon Bailey373af752022-02-21 15:14:00 -0600654 setSensorValueToNonFunctional(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600655#endif
656 continue;
657 }
658
Chris Caina8857c52021-01-27 11:53:05 -0600659 // Read sysfs to force kernel to poll OCC
660 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800661
662#ifdef READ_OCC_SENSORS
663 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600664 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800665#endif
Chris Caina8857c52021-01-27 11:53:05 -0600666 }
667
Chris Caina7b74dc2021-11-10 17:03:43 -0600668 if (activeCount > 0)
669 {
670 // Restart OCC poll timer
671 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
672 }
673 else
674 {
675 // No OCCs running, so poll timer will not be restarted
676 log<level::INFO>(
677 fmt::format(
678 "Manager::pollerTimerExpired: poll timer will not be restarted")
679 .c_str());
680 }
Chris Caina8857c52021-01-27 11:53:05 -0600681}
682
Chicago Duanbb895cb2021-06-18 19:37:16 +0800683#ifdef READ_OCC_SENSORS
684void Manager::readTempSensors(const fs::path& path, uint32_t id)
685{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800686 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
687 for (auto& file : fs::directory_iterator(path))
688 {
689 if (!std::regex_search(file.path().string(), expr))
690 {
691 continue;
692 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800693
Matt Spinlera26f1522021-08-25 15:50:20 -0500694 uint32_t labelValue{0};
695
696 try
697 {
698 labelValue = readFile<uint32_t>(file.path());
699 }
700 catch (const std::system_error& e)
701 {
702 log<level::DEBUG>(
703 fmt::format("readTempSensors: Failed reading {}, errno = {}",
704 file.path().string(), e.code().value())
705 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800706 continue;
707 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800708
709 const std::string& tempLabel = "label";
710 const std::string filePathString = file.path().string().substr(
711 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500712
713 uint32_t fruTypeValue{0};
714 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800715 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500716 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
717 }
718 catch (const std::system_error& e)
719 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800720 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500721 fmt::format("readTempSensors: Failed reading {}, errno = {}",
722 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800723 .c_str());
724 continue;
725 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800726
727 std::string sensorPath =
728 OCC_SENSORS_ROOT + std::string("/temperature/");
729
Matt Spinlerace67d82021-10-18 13:41:57 -0500730 std::string dvfsTempPath;
731
Chicago Duanbb895cb2021-06-18 19:37:16 +0800732 if (fruTypeValue == VRMVdd)
733 {
734 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
735 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500736 else if (fruTypeValue == processorIoRing)
737 {
738 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
739 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
740 std::to_string(id) + "_ioring_dvfs_temp";
741 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800742 else
743 {
Matt Spinler14d14022021-08-25 15:38:29 -0500744 uint16_t type = (labelValue & 0xFF000000) >> 24;
745 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800746
747 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
748 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500749 if (fruTypeValue == fruTypeNotAvailable)
750 {
751 // Not all DIMM related temps are available to read
752 // (no _input file in this case)
753 continue;
754 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800755 auto iter = dimmTempSensorName.find(fruTypeValue);
756 if (iter == dimmTempSensorName.end())
757 {
George Liub5ca1012021-09-10 12:53:11 +0800758 log<level::ERR>(
759 fmt::format(
760 "readTempSensors: Fru type error! fruTypeValue = {}) ",
761 fruTypeValue)
762 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800763 continue;
764 }
765
766 sensorPath.append("dimm" + std::to_string(instanceID) +
767 iter->second);
768 }
769 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
770 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500771 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800772 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500773 // The OCC reports small core temps, of which there are
774 // two per big core. All current P10 systems are in big
775 // core mode, so use a big core name.
776 uint16_t coreNum = instanceID / 2;
777 uint16_t tempNum = instanceID % 2;
778 sensorPath.append("proc" + std::to_string(id) + "_core" +
779 std::to_string(coreNum) + "_" +
780 std::to_string(tempNum) + "_temp");
781
782 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
783 "/temperature/proc" + std::to_string(id) +
784 "_core_dvfs_temp";
785 }
786 else
787 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800788 continue;
789 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800790 }
791 else
792 {
793 continue;
794 }
795 }
796
Matt Spinlerace67d82021-10-18 13:41:57 -0500797 // The dvfs temp file only needs to be read once per chip per type.
798 if (!dvfsTempPath.empty() &&
799 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
800 {
801 try
802 {
803 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
804
805 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
806 dvfsTempPath, dvfsValue * std::pow(10, -3));
807 }
808 catch (const std::system_error& e)
809 {
810 log<level::DEBUG>(
811 fmt::format(
812 "readTempSensors: Failed reading {}, errno = {}",
813 filePathString + maxSuffix, e.code().value())
814 .c_str());
815 }
816 }
817
Matt Spinlera26f1522021-08-25 15:50:20 -0500818 uint32_t faultValue{0};
819 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800820 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500821 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
822 }
823 catch (const std::system_error& e)
824 {
825 log<level::DEBUG>(
826 fmt::format("readTempSensors: Failed reading {}, errno = {}",
827 filePathString + faultSuffix, e.code().value())
828 .c_str());
829 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800830 }
831
Matt Spinlera26f1522021-08-25 15:50:20 -0500832 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800833 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600834 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500835 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800836
Chris Cain5d66a0a2022-02-09 08:52:10 -0600837 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
838 false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800839
Matt Spinlera26f1522021-08-25 15:50:20 -0500840 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800841 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500842
843 double tempValue{0};
844
845 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800846 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500847 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800848 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500849 catch (const std::system_error& e)
850 {
851 log<level::DEBUG>(
852 fmt::format("readTempSensors: Failed reading {}, errno = {}",
853 filePathString + inputSuffix, e.code().value())
854 .c_str());
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500855
856 // if errno == EAGAIN(Resource temporarily unavailable) then set
857 // temp to 0, to avoid using old temp, and affecting FAN Control.
858 if (e.code().value() == EAGAIN)
859 {
860 tempValue = 0;
861 }
862 // else the errno would be something like
863 // EBADF(Bad file descriptor)
864 // or ENOENT(No such file or directory)
865 else
866 {
867 continue;
868 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500869 }
870
Chris Cain5d66a0a2022-02-09 08:52:10 -0600871 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500872 sensorPath, tempValue * std::pow(10, -3));
873
Chris Cain5d66a0a2022-02-09 08:52:10 -0600874 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
875 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500876
Chris Cain6fa848a2022-01-24 14:54:38 -0600877 // At this point, the sensor will be created for sure.
878 if (existingSensors.find(sensorPath) == existingSensors.end())
879 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600880 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
881 sensorPath);
Chris Cain6fa848a2022-01-24 14:54:38 -0600882 }
883
Matt Spinlera26f1522021-08-25 15:50:20 -0500884 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800885 }
886 return;
887}
888
889std::optional<std::string>
890 Manager::getPowerLabelFunctionID(const std::string& value)
891{
892 // If the value is "system", then the FunctionID is "system".
893 if (value == "system")
894 {
895 return value;
896 }
897
898 // If the value is not "system", then the label value have 3 numbers, of
899 // which we only care about the middle one:
900 // <sensor id>_<function id>_<apss channel>
901 // eg: The value is "0_10_5" , then the FunctionID is "10".
902 if (value.find("_") == std::string::npos)
903 {
904 return std::nullopt;
905 }
906
907 auto powerLabelValue = value.substr((value.find("_") + 1));
908
909 if (powerLabelValue.find("_") == std::string::npos)
910 {
911 return std::nullopt;
912 }
913
914 return powerLabelValue.substr(0, powerLabelValue.find("_"));
915}
916
917void Manager::readPowerSensors(const fs::path& path, uint32_t id)
918{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800919 std::regex expr{"power\\d+_label$"}; // Example: power5_label
920 for (auto& file : fs::directory_iterator(path))
921 {
922 if (!std::regex_search(file.path().string(), expr))
923 {
924 continue;
925 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800926
Matt Spinlera26f1522021-08-25 15:50:20 -0500927 std::string labelValue;
928 try
929 {
930 labelValue = readFile<std::string>(file.path());
931 }
932 catch (const std::system_error& e)
933 {
934 log<level::DEBUG>(
935 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
936 file.path().string(), e.code().value())
937 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800938 continue;
939 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800940
941 auto functionID = getPowerLabelFunctionID(labelValue);
942 if (functionID == std::nullopt)
943 {
944 continue;
945 }
946
947 const std::string& tempLabel = "label";
948 const std::string filePathString = file.path().string().substr(
949 0, file.path().string().length() - tempLabel.length());
950
951 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
952
953 auto iter = powerSensorName.find(*functionID);
954 if (iter == powerSensorName.end())
955 {
956 continue;
957 }
958 sensorPath.append(iter->second);
959
Matt Spinlera26f1522021-08-25 15:50:20 -0500960 double tempValue{0};
961
962 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800963 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500964 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800965 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500966 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800967 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800968 log<level::DEBUG>(
Chris Cain5d66a0a2022-02-09 08:52:10 -0600969 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500970 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800971 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500972 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800973 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500974
Chris Cain5d66a0a2022-02-09 08:52:10 -0600975 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -0600976 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
977
Chris Cain5d66a0a2022-02-09 08:52:10 -0600978 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500979 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
980
Chris Cain5d66a0a2022-02-09 08:52:10 -0600981 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
982 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500983
Matt Spinler5901abd2021-09-23 13:50:03 -0500984 if (existingSensors.find(sensorPath) == existingSensors.end())
985 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600986 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
987 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -0500988 }
989
Matt Spinlera26f1522021-08-25 15:50:20 -0500990 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800991 }
992 return;
993}
994
995void Manager::setSensorValueToNaN(uint32_t id)
996{
997 for (const auto& [sensorPath, occId] : existingSensors)
998 {
999 if (occId == id)
1000 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001001 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +08001002 sensorPath, std::numeric_limits<double>::quiet_NaN());
1003 }
1004 }
1005 return;
1006}
1007
Sheldon Bailey373af752022-02-21 15:14:00 -06001008void Manager::setSensorValueToNonFunctional(uint32_t id) const
1009{
1010 for (const auto& [sensorPath, occId] : existingSensors)
1011 {
1012 if (occId == id)
1013 {
1014 dbus::OccDBusSensors::getOccDBus().setValue(
1015 sensorPath, std::numeric_limits<double>::quiet_NaN());
1016
1017 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
1018 false);
1019 }
1020 }
1021 return;
1022}
1023
Chris Cain5d66a0a2022-02-09 08:52:10 -06001024void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +08001025{
Chris Caine2d0a432022-03-28 11:08:49 -05001026 static bool tracedError[8] = {0};
1027 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -06001028 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +08001029
Chris Caine2d0a432022-03-28 11:08:49 -05001030 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +08001031 {
Chris Caine2d0a432022-03-28 11:08:49 -05001032 // Read temperature sensors
1033 readTempSensors(sensorPath, id);
1034
1035 if (occ->isMasterOcc())
1036 {
1037 // Read power sensors
1038 readPowerSensors(sensorPath, id);
1039 }
1040 tracedError[id] = false;
1041 }
1042 else
1043 {
1044 if (!tracedError[id])
1045 {
1046 log<level::ERR>(
1047 fmt::format(
1048 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1049 id, sensorPath.c_str())
1050 .c_str());
1051 tracedError[id] = true;
1052 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001053 }
1054
1055 return;
1056}
1057#endif
Chris Cain17257672021-10-22 13:41:03 -05001058
1059// Read the altitude from DBus
1060void Manager::readAltitude()
1061{
1062 static bool traceAltitudeErr = true;
1063
1064 utils::PropertyValue altitudeProperty{};
1065 try
1066 {
1067 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1068 ALTITUDE_PROP);
1069 auto sensorVal = std::get<double>(altitudeProperty);
1070 if (sensorVal < 0xFFFF)
1071 {
1072 if (sensorVal < 0)
1073 {
1074 altitude = 0;
1075 }
1076 else
1077 {
1078 // Round to nearest meter
1079 altitude = uint16_t(sensorVal + 0.5);
1080 }
1081 log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)",
1082 sensorVal, altitude)
1083 .c_str());
1084 traceAltitudeErr = true;
1085 }
1086 else
1087 {
1088 if (traceAltitudeErr)
1089 {
1090 traceAltitudeErr = false;
1091 log<level::DEBUG>(
1092 fmt::format("Invalid altitude value: {}", sensorVal)
1093 .c_str());
1094 }
1095 }
1096 }
1097 catch (const sdbusplus::exception::exception& e)
1098 {
1099 if (traceAltitudeErr)
1100 {
1101 traceAltitudeErr = false;
1102 log<level::INFO>(
1103 fmt::format("Unable to read Altitude: {}", e.what()).c_str());
1104 }
1105 altitude = 0xFFFF; // not available
1106 }
1107}
1108
1109// Callback function when ambient temperature changes
1110void Manager::ambientCallback(sdbusplus::message::message& msg)
1111{
1112 double currentTemp = 0;
1113 uint8_t truncatedTemp = 0xFF;
1114 std::string msgSensor;
1115 std::map<std::string, std::variant<double>> msgData;
1116 msg.read(msgSensor, msgData);
1117
1118 auto valPropMap = msgData.find(AMBIENT_PROP);
1119 if (valPropMap == msgData.end())
1120 {
1121 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1122 return;
1123 }
1124 currentTemp = std::get<double>(valPropMap->second);
1125 if (std::isnan(currentTemp))
1126 {
1127 truncatedTemp = 0xFF;
1128 }
1129 else
1130 {
1131 if (currentTemp < 0)
1132 {
1133 truncatedTemp = 0;
1134 }
1135 else
1136 {
1137 // Round to nearest degree C
1138 truncatedTemp = uint8_t(currentTemp + 0.5);
1139 }
1140 }
1141
1142 // If ambient changes, notify OCCs
1143 if (truncatedTemp != ambient)
1144 {
1145 log<level::DEBUG>(
1146 fmt::format("ambientCallback: Ambient change from {} to {}C",
1147 ambient, currentTemp)
1148 .c_str());
1149
1150 ambient = truncatedTemp;
1151 if (altitude == 0xFFFF)
1152 {
1153 // No altitude yet, try reading again
1154 readAltitude();
1155 }
1156
1157 log<level::DEBUG>(
1158 fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
1159 altitude)
1160 .c_str());
1161#ifdef POWER10
1162 // Send ambient and altitude to all OCCs
1163 for (auto& obj : statusObjects)
1164 {
1165 if (obj->occActive())
1166 {
1167 obj->sendAmbient(ambient, altitude);
1168 }
1169 }
1170#endif // POWER10
1171 }
1172}
1173
1174// return the current ambient and altitude readings
1175void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1176 uint16_t& altitudeValue) const
1177{
1178 ambientValid = true;
1179 ambientTemp = ambient;
1180 altitudeValue = altitude;
1181
1182 if (ambient == 0xFF)
1183 {
1184 ambientValid = false;
1185 }
1186}
1187
Chris Caina7b74dc2021-11-10 17:03:43 -06001188#ifdef POWER10
1189void Manager::occsNotAllRunning()
1190{
Chris Cain6fa848a2022-01-24 14:54:38 -06001191 // Function will also gets called when occ-control app gets
1192 // restarted. (occ active sensors do not change, so the Status
1193 // object does not call Manager back for all OCCs)
Chris Caina7b74dc2021-11-10 17:03:43 -06001194
1195 if (activeCount != statusObjects.size())
1196 {
1197 // Not all OCCs went active
1198 log<level::WARNING>(
1199 fmt::format(
1200 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1201 activeCount, statusObjects.size())
1202 .c_str());
1203 // Procs may be garded, so may not need reset.
1204 }
1205
1206 validateOccMaster();
1207}
1208#endif // POWER10
1209
1210// Verify single master OCC and start presence monitor
1211void Manager::validateOccMaster()
1212{
1213 int masterInstance = -1;
1214 for (auto& obj : statusObjects)
1215 {
Chris Cainbd551de2022-04-26 13:41:16 -05001216 auto instance = obj->getOccInstanceID();
Chris Cainbae4d072022-02-28 09:46:50 -06001217#ifdef POWER10
1218 if (!obj->occActive())
1219 {
1220 if (utils::isHostRunning())
1221 {
Chris Cainbd551de2022-04-26 13:41:16 -05001222 // Check if sensor was queued while waiting for discovery
1223 auto match = queuedActiveState.find(instance);
1224 if (match != queuedActiveState.end())
Chris Cainbae4d072022-02-28 09:46:50 -06001225 {
1226 log<level::INFO>(
1227 fmt::format(
Chris Cainbd551de2022-04-26 13:41:16 -05001228 "validateOccMaster: OCC{} is ACTIVE (queued)",
1229 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001230 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -05001231 obj->occActive(true);
1232 }
1233 else
1234 {
1235 // OCC does not appear to be active yet, check active sensor
1236 pldmHandle->checkActiveSensor(instance);
1237 if (obj->occActive())
1238 {
1239 log<level::INFO>(
1240 fmt::format(
1241 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1242 instance)
1243 .c_str());
1244 }
Chris Cainbae4d072022-02-28 09:46:50 -06001245 }
1246 }
1247 else
1248 {
1249 log<level::WARNING>(
1250 fmt::format(
1251 "validateOccMaster: HOST is not running (OCC{})",
Chris Cainbd551de2022-04-26 13:41:16 -05001252 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001253 .c_str());
1254 return;
1255 }
1256 }
1257#endif // POWER10
1258
Chris Caina7b74dc2021-11-10 17:03:43 -06001259 if (obj->isMasterOcc())
1260 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001261 obj->addPresenceWatchMaster();
1262
Chris Caina7b74dc2021-11-10 17:03:43 -06001263 if (masterInstance == -1)
1264 {
Chris Cainbd551de2022-04-26 13:41:16 -05001265 masterInstance = instance;
Chris Caina7b74dc2021-11-10 17:03:43 -06001266 }
1267 else
1268 {
1269 log<level::ERR>(
1270 fmt::format(
1271 "validateOccMaster: Multiple OCC masters! ({} and {})",
Chris Cainbd551de2022-04-26 13:41:16 -05001272 masterInstance, instance)
Chris Caina7b74dc2021-11-10 17:03:43 -06001273 .c_str());
1274 // request reset
1275 obj->deviceError();
1276 }
1277 }
1278 }
Chris Cainbae4d072022-02-28 09:46:50 -06001279
Chris Caina7b74dc2021-11-10 17:03:43 -06001280 if (masterInstance < 0)
1281 {
Chris Cainbae4d072022-02-28 09:46:50 -06001282 log<level::ERR>(
1283 fmt::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
1284 statusObjects.size())
1285 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001286 // request reset
1287 statusObjects.front()->deviceError();
1288 }
1289 else
1290 {
1291 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -06001292 fmt::format("validateOccMaster: OCC{} is master of {} OCCs",
1293 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001294 .c_str());
1295 }
1296}
1297
Chris Cain40501a22022-03-14 17:33:27 -05001298void Manager::updatePcapBounds() const
1299{
1300 if (pcap)
1301 {
1302 pcap->updatePcapBounds();
1303 }
1304}
1305
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301306} // namespace occ
1307} // namespace open_power