blob: 17cd40303724e7c4986ff9a2ef276c02c67473c0 [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 {
Chris Cainf55f91a2022-05-27 13:40:15 -0500209 discoverTimer->setEnabled(false);
Chris Cain7f89e4d2022-05-09 13:27:45 -0500210 }
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 Cainf55f91a2022-05-27 13:40:15 -0500230 discoverTimer->restartOnce(10s);
Chris Cainbae4d072022-02-28 09:46:50 -0600231 }
232}
233#endif
234
Matt Spinlerd267cec2021-09-01 14:49:19 -0500235std::vector<int> Manager::findOCCsInDev()
236{
237 std::vector<int> occs;
238 std::regex expr{R"(occ(\d+)$)"};
239
240 for (auto& file : fs::directory_iterator("/dev"))
241 {
242 std::smatch match;
243 std::string path{file.path().string()};
244 if (std::regex_search(path, match, expr))
245 {
246 auto num = std::stoi(match[1].str());
247
248 // /dev numbering starts at 1, ours starts at 0.
249 occs.push_back(num - 1);
250 }
251 }
252
253 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530254}
255
Patrick Williamsaf408082022-07-22 19:26:54 -0500256int Manager::cpuCreated(sdbusplus::message_t& msg)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530257{
George Liubcef3b42021-09-10 12:39:02 +0800258 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530259
260 sdbusplus::message::object_path o;
261 msg.read(o);
262 fs::path cpuPath(std::string(std::move(o)));
263
264 auto name = cpuPath.filename().string();
265 auto index = name.find(CPU_NAME);
266 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
267
268 createObjects(name);
269
270 return 0;
271}
272
273void Manager::createObjects(const std::string& occ)
274{
275 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
276
Gunnar Mills94df8c92018-09-14 14:50:03 -0500277 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800278 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600279#ifdef POWER10
280 pmode,
281#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500282 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Sheldon Bailey373af752022-02-21 15:14:00 -0600283 std::placeholders::_1, std::placeholders::_2)
Tom Joseph00325232020-07-29 17:51:48 +0530284#ifdef PLDM
285 ,
286 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
287 std::placeholders::_1)
288#endif
289 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530290
Chris Cain40501a22022-03-14 17:33:27 -0500291 // Create the power cap monitor object
292 if (!pcap)
293 {
294 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
295 *statusObjects.back());
296 }
297
Chris Cain36f9cde2021-11-22 11:18:21 -0600298 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530299 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600300 log<level::INFO>(
301 fmt::format("Manager::createObjects(): OCC{} is the master",
302 statusObjects.back()->getOccInstanceID())
303 .c_str());
304 _pollTimer->setEnabled(false);
305
Chris Cain78e86012021-03-04 16:15:31 -0600306#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600307 // Set the master OCC on the PowerMode object
308 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600309#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600310 }
311
312 passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str()
313#ifdef POWER10
314 ,
315 pmode
316#endif
317 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530318}
319
Sheldon Bailey373af752022-02-21 15:14:00 -0600320void Manager::statusCallBack(instanceID instance, bool status)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530321{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500322 using InternalFailure =
323 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530324
325 // At this time, it won't happen but keeping it
326 // here just in case something changes in the future
327 if ((activeCount == 0) && (!status))
328 {
Sheldon Bailey373af752022-02-21 15:14:00 -0600329 log<level::ERR>(
330 fmt::format("Invalid update on OCCActive with OCC{}", instance)
331 .c_str());
332
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530333 elog<InternalFailure>();
334 }
335
Chris Caina7b74dc2021-11-10 17:03:43 -0600336 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600337 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600338 // OCC went active
339 ++activeCount;
340
341#ifdef POWER10
342 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600343 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600344 // First OCC went active (allow some time for all OCCs to go active)
Chris Cainbd551de2022-04-26 13:41:16 -0500345 waitForAllOccsTimer->restartOnce(60s);
Matt Spinler53f68142021-08-25 15:47:31 -0500346 }
347#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600348
349 if (activeCount == statusObjects.size())
350 {
351#ifdef POWER10
352 // All OCCs are now running
353 if (waitForAllOccsTimer->isEnabled())
354 {
355 // stop occ wait timer
356 waitForAllOccsTimer->setEnabled(false);
357 }
358#endif
359
360 // Verify master OCC and start presence monitor
361 validateOccMaster();
362 }
363
364 // Start poll timer if not already started
365 if (!_pollTimer->isEnabled())
366 {
367 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -0600368 fmt::format("Manager: OCCs will be polled every {} seconds",
369 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600370 .c_str());
371
372 // Send poll and start OCC poll timer
373 pollerTimerExpired();
374 }
375 }
376 else
377 {
378 // OCC went away
379 --activeCount;
380
381 if (activeCount == 0)
382 {
383 // No OCCs are running
384
385 // Stop OCC poll timer
386 if (_pollTimer->isEnabled())
387 {
388 log<level::INFO>(
389 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
390 _pollTimer->setEnabled(false);
391 }
392
393#ifdef POWER10
394 // stop wait timer
395 if (waitForAllOccsTimer->isEnabled())
396 {
397 waitForAllOccsTimer->setEnabled(false);
398 }
399#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600400 }
Sheldon Bailey373af752022-02-21 15:14:00 -0600401#ifdef READ_OCC_SENSORS
402 // Clear OCC sensors
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500403 setSensorValueToNaN(instance);
Sheldon Bailey373af752022-02-21 15:14:00 -0600404#endif
Chris Caina8857c52021-01-27 11:53:05 -0600405 }
Chris Cainbae4d072022-02-28 09:46:50 -0600406
407#ifdef POWER10
408 if (waitingForAllOccActiveSensors)
409 {
Chris Cain6d8f37a2022-04-29 13:46:01 -0500410 if (utils::isHostRunning())
411 {
412 checkAllActiveSensors();
413 }
Chris Cainbae4d072022-02-28 09:46:50 -0600414 }
415#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530416}
417
418#ifdef I2C_OCC
419void Manager::initStatusObjects()
420{
421 // Make sure we have a valid path string
422 static_assert(sizeof(DEV_PATH) != 0);
423
424 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
425 for (auto& name : deviceNames)
426 {
427 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800428 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530429 auto path = fs::path(OCC_CONTROL_ROOT) / name;
430 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800431 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530432 }
Chris Cain40501a22022-03-14 17:33:27 -0500433 // The first device is master occ
434 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
435 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600436#ifdef POWER10
Chris Cain5d66a0a2022-02-09 08:52:10 -0600437 pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
438 powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600439 // Set the master OCC on the PowerMode object
440 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600441#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530442}
443#endif
444
Tom Joseph815f9f52020-07-27 12:12:13 +0530445#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500446void Manager::sbeTimeout(unsigned int instance)
447{
Eddie James2a751d72022-03-04 09:16:12 -0600448 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
449 [instance](const auto& obj) {
450 return instance == obj->getOccInstanceID();
451 });
Eddie Jamescbad2192021-10-07 09:39:39 -0500452
Eddie Jamescb018da2022-03-05 11:49:37 -0600453 if (obj != statusObjects.end() && (*obj)->occActive())
Eddie James2a751d72022-03-04 09:16:12 -0600454 {
Chris Cainbae4d072022-02-28 09:46:50 -0600455 log<level::INFO>(
456 fmt::format("SBE timeout, requesting HRESET (OCC{})", instance)
457 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500458
Eddie James2a751d72022-03-04 09:16:12 -0600459 setSBEState(instance, SBE_STATE_NOT_USABLE);
460
461 pldmHandle->sendHRESET(instance);
462 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500463}
464
Tom Joseph815f9f52020-07-27 12:12:13 +0530465bool Manager::updateOCCActive(instanceID instance, bool status)
466{
Chris Cain7e374fb2022-04-07 09:47:23 -0500467 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
468 [instance](const auto& obj) {
469 return instance == obj->getOccInstanceID();
470 });
471
472 if (obj != statusObjects.end())
473 {
Chris Cain733b2012022-05-04 11:54:06 -0500474 (*obj)->setPldmSensorReceived(true);
Chris Cain7e374fb2022-04-07 09:47:23 -0500475 return (*obj)->occActive(status);
476 }
477 else
478 {
479 log<level::WARNING>(
480 fmt::format(
481 "Manager::updateOCCActive: No status object to update for OCC{} (active={})",
482 instance, status)
483 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -0500484 if (status == true)
485 {
486 // OCC went active
487 queuedActiveState.insert(instance);
488 }
489 else
490 {
491 auto match = queuedActiveState.find(instance);
492 if (match != queuedActiveState.end())
493 {
494 // OCC was disabled
495 queuedActiveState.erase(match);
496 }
497 }
Chris Cain7e374fb2022-04-07 09:47:23 -0500498 return false;
499 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530500}
Eddie Jamescbad2192021-10-07 09:39:39 -0500501
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500502// Called upon pldm event To set powermode Safe Mode State for system.
503void Manager::updateOccSafeMode(bool safeMode)
504{
505#ifdef POWER10
506 pmode->updateDbusSafeMode(safeMode);
507#endif
508}
509
Eddie Jamescbad2192021-10-07 09:39:39 -0500510void Manager::sbeHRESETResult(instanceID instance, bool success)
511{
512 if (success)
513 {
Chris Cainbae4d072022-02-28 09:46:50 -0600514 log<level::INFO>(
515 fmt::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500516
517 setSBEState(instance, SBE_STATE_BOOTED);
518
519 return;
520 }
521
522 setSBEState(instance, SBE_STATE_FAILED);
523
524 if (sbeCanDump(instance))
525 {
Chris Cainbae4d072022-02-28 09:46:50 -0600526 log<level::INFO>(
527 fmt::format("HRESET failed (OCC{}), triggering SBE dump", instance)
528 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500529
530 auto& bus = utils::getBus();
531 uint32_t src6 = instance << 16;
532 uint32_t logId =
533 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
534 src6, "SBE command timeout");
535
536 try
537 {
George Liuf3a4a692021-12-28 13:59:51 +0800538 constexpr auto path = "/org/openpower/dump";
539 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
540 constexpr auto function = "CreateDump";
541
Eddie Jamescbad2192021-10-07 09:39:39 -0500542 std::string service = utils::getService(path, interface);
543 auto method =
544 bus.new_method_call(service.c_str(), path, interface, function);
545
546 std::map<std::string, std::variant<std::string, uint64_t>>
547 createParams{
548 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
549 uint64_t(logId)},
550 {"com.ibm.Dump.Create.CreateParameters.DumpType",
551 "com.ibm.Dump.Create.DumpType.SBE"},
552 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
553 uint64_t(instance)},
554 };
555
556 method.append(createParams);
557
558 auto response = bus.call(method);
559 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500560 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -0500561 {
562 constexpr auto ERROR_DUMP_DISABLED =
563 "xyz.openbmc_project.Dump.Create.Error.Disabled";
564 if (e.name() == ERROR_DUMP_DISABLED)
565 {
566 log<level::INFO>("Dump is disabled, skipping");
567 }
568 else
569 {
570 log<level::ERR>("Dump failed");
571 }
572 }
573 }
574}
575
576bool Manager::sbeCanDump(unsigned int instance)
577{
578 struct pdbg_target* proc = getPdbgTarget(instance);
579
580 if (!proc)
581 {
582 // allow the dump in the error case
583 return true;
584 }
585
586 try
587 {
588 if (!openpower::phal::sbe::isDumpAllowed(proc))
589 {
590 return false;
591 }
592
593 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
594 {
595 return false;
596 }
597 }
598 catch (openpower::phal::exception::SbeError& e)
599 {
600 log<level::INFO>("Failed to query SBE state");
601 }
602
603 // allow the dump in the error case
604 return true;
605}
606
607void Manager::setSBEState(unsigned int instance, enum sbe_state state)
608{
609 struct pdbg_target* proc = getPdbgTarget(instance);
610
611 if (!proc)
612 {
613 return;
614 }
615
616 try
617 {
618 openpower::phal::sbe::setState(proc, state);
619 }
620 catch (const openpower::phal::exception::SbeError& e)
621 {
622 log<level::ERR>("Failed to set SBE state");
623 }
624}
625
626struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
627{
628 if (!pdbgInitialized)
629 {
630 try
631 {
632 openpower::phal::pdbg::init();
633 pdbgInitialized = true;
634 }
635 catch (const openpower::phal::exception::PdbgError& e)
636 {
637 log<level::ERR>("pdbg initialization failed");
638 return nullptr;
639 }
640 }
641
642 struct pdbg_target* proc = nullptr;
643 pdbg_for_each_class_target("proc", proc)
644 {
645 if (pdbg_target_index(proc) == instance)
646 {
647 return proc;
648 }
649 }
650
651 log<level::ERR>("Failed to get pdbg target");
652 return nullptr;
653}
Tom Joseph815f9f52020-07-27 12:12:13 +0530654#endif
655
Chris Caina8857c52021-01-27 11:53:05 -0600656void Manager::pollerTimerExpired()
657{
Chris Caina8857c52021-01-27 11:53:05 -0600658 if (!_pollTimer)
659 {
660 log<level::ERR>(
661 "Manager::pollerTimerExpired() ERROR: Timer not defined");
662 return;
663 }
664
665 for (auto& obj : statusObjects)
666 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600667 if (!obj->occActive())
668 {
669 // OCC is not running yet
670#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600671 auto id = obj->getOccInstanceID();
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500672 setSensorValueToNaN(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600673#endif
674 continue;
675 }
676
Chris Caina8857c52021-01-27 11:53:05 -0600677 // Read sysfs to force kernel to poll OCC
678 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800679
680#ifdef READ_OCC_SENSORS
681 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600682 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800683#endif
Chris Caina8857c52021-01-27 11:53:05 -0600684 }
685
Chris Caina7b74dc2021-11-10 17:03:43 -0600686 if (activeCount > 0)
687 {
688 // Restart OCC poll timer
689 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
690 }
691 else
692 {
693 // No OCCs running, so poll timer will not be restarted
694 log<level::INFO>(
695 fmt::format(
696 "Manager::pollerTimerExpired: poll timer will not be restarted")
697 .c_str());
698 }
Chris Caina8857c52021-01-27 11:53:05 -0600699}
700
Chicago Duanbb895cb2021-06-18 19:37:16 +0800701#ifdef READ_OCC_SENSORS
702void Manager::readTempSensors(const fs::path& path, uint32_t id)
703{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800704 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
705 for (auto& file : fs::directory_iterator(path))
706 {
707 if (!std::regex_search(file.path().string(), expr))
708 {
709 continue;
710 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800711
Matt Spinlera26f1522021-08-25 15:50:20 -0500712 uint32_t labelValue{0};
713
714 try
715 {
716 labelValue = readFile<uint32_t>(file.path());
717 }
718 catch (const std::system_error& e)
719 {
720 log<level::DEBUG>(
721 fmt::format("readTempSensors: Failed reading {}, errno = {}",
722 file.path().string(), e.code().value())
723 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800724 continue;
725 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800726
727 const std::string& tempLabel = "label";
728 const std::string filePathString = file.path().string().substr(
729 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500730
731 uint32_t fruTypeValue{0};
732 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800733 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500734 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
735 }
736 catch (const std::system_error& e)
737 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800738 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500739 fmt::format("readTempSensors: Failed reading {}, errno = {}",
740 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800741 .c_str());
742 continue;
743 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800744
745 std::string sensorPath =
746 OCC_SENSORS_ROOT + std::string("/temperature/");
747
Matt Spinlerace67d82021-10-18 13:41:57 -0500748 std::string dvfsTempPath;
749
Chicago Duanbb895cb2021-06-18 19:37:16 +0800750 if (fruTypeValue == VRMVdd)
751 {
752 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
753 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500754 else if (fruTypeValue == processorIoRing)
755 {
756 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
757 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
758 std::to_string(id) + "_ioring_dvfs_temp";
759 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800760 else
761 {
Matt Spinler14d14022021-08-25 15:38:29 -0500762 uint16_t type = (labelValue & 0xFF000000) >> 24;
763 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800764
765 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
766 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500767 if (fruTypeValue == fruTypeNotAvailable)
768 {
769 // Not all DIMM related temps are available to read
770 // (no _input file in this case)
771 continue;
772 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800773 auto iter = dimmTempSensorName.find(fruTypeValue);
774 if (iter == dimmTempSensorName.end())
775 {
George Liub5ca1012021-09-10 12:53:11 +0800776 log<level::ERR>(
777 fmt::format(
778 "readTempSensors: Fru type error! fruTypeValue = {}) ",
779 fruTypeValue)
780 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800781 continue;
782 }
783
784 sensorPath.append("dimm" + std::to_string(instanceID) +
785 iter->second);
786 }
787 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
788 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500789 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800790 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500791 // The OCC reports small core temps, of which there are
792 // two per big core. All current P10 systems are in big
793 // core mode, so use a big core name.
794 uint16_t coreNum = instanceID / 2;
795 uint16_t tempNum = instanceID % 2;
796 sensorPath.append("proc" + std::to_string(id) + "_core" +
797 std::to_string(coreNum) + "_" +
798 std::to_string(tempNum) + "_temp");
799
800 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
801 "/temperature/proc" + std::to_string(id) +
802 "_core_dvfs_temp";
803 }
804 else
805 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800806 continue;
807 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800808 }
809 else
810 {
811 continue;
812 }
813 }
814
Matt Spinlerace67d82021-10-18 13:41:57 -0500815 // The dvfs temp file only needs to be read once per chip per type.
816 if (!dvfsTempPath.empty() &&
817 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
818 {
819 try
820 {
821 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
822
823 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
824 dvfsTempPath, dvfsValue * std::pow(10, -3));
825 }
826 catch (const std::system_error& e)
827 {
828 log<level::DEBUG>(
829 fmt::format(
830 "readTempSensors: Failed reading {}, errno = {}",
831 filePathString + maxSuffix, e.code().value())
832 .c_str());
833 }
834 }
835
Matt Spinlera26f1522021-08-25 15:50:20 -0500836 uint32_t faultValue{0};
837 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800838 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500839 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
840 }
841 catch (const std::system_error& e)
842 {
843 log<level::DEBUG>(
844 fmt::format("readTempSensors: Failed reading {}, errno = {}",
845 filePathString + faultSuffix, e.code().value())
846 .c_str());
847 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800848 }
849
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500850 // NOTE: if OCC sends back 0xFF kernal sets this fault value to 1.
Matt Spinlera26f1522021-08-25 15:50:20 -0500851 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800852 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600853 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500854 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800855
Chris Cain5d66a0a2022-02-09 08:52:10 -0600856 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
857 false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800858
Matt Spinlera26f1522021-08-25 15:50:20 -0500859 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800860 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500861
862 double tempValue{0};
863
864 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800865 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500866 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800867 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500868 catch (const std::system_error& e)
869 {
870 log<level::DEBUG>(
871 fmt::format("readTempSensors: Failed reading {}, errno = {}",
872 filePathString + inputSuffix, e.code().value())
873 .c_str());
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500874
875 // if errno == EAGAIN(Resource temporarily unavailable) then set
876 // temp to 0, to avoid using old temp, and affecting FAN Control.
877 if (e.code().value() == EAGAIN)
878 {
879 tempValue = 0;
880 }
881 // else the errno would be something like
882 // EBADF(Bad file descriptor)
883 // or ENOENT(No such file or directory)
884 else
885 {
886 continue;
887 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500888 }
889
Chris Cain5d66a0a2022-02-09 08:52:10 -0600890 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500891 sensorPath, tempValue * std::pow(10, -3));
892
Chris Cain5d66a0a2022-02-09 08:52:10 -0600893 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
894 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500895
Chris Cain6fa848a2022-01-24 14:54:38 -0600896 // At this point, the sensor will be created for sure.
897 if (existingSensors.find(sensorPath) == existingSensors.end())
898 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600899 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
900 sensorPath);
Chris Cain6fa848a2022-01-24 14:54:38 -0600901 }
902
Matt Spinlera26f1522021-08-25 15:50:20 -0500903 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800904 }
905 return;
906}
907
908std::optional<std::string>
909 Manager::getPowerLabelFunctionID(const std::string& value)
910{
911 // If the value is "system", then the FunctionID is "system".
912 if (value == "system")
913 {
914 return value;
915 }
916
917 // If the value is not "system", then the label value have 3 numbers, of
918 // which we only care about the middle one:
919 // <sensor id>_<function id>_<apss channel>
920 // eg: The value is "0_10_5" , then the FunctionID is "10".
921 if (value.find("_") == std::string::npos)
922 {
923 return std::nullopt;
924 }
925
926 auto powerLabelValue = value.substr((value.find("_") + 1));
927
928 if (powerLabelValue.find("_") == std::string::npos)
929 {
930 return std::nullopt;
931 }
932
933 return powerLabelValue.substr(0, powerLabelValue.find("_"));
934}
935
936void Manager::readPowerSensors(const fs::path& path, uint32_t id)
937{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800938 std::regex expr{"power\\d+_label$"}; // Example: power5_label
939 for (auto& file : fs::directory_iterator(path))
940 {
941 if (!std::regex_search(file.path().string(), expr))
942 {
943 continue;
944 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800945
Matt Spinlera26f1522021-08-25 15:50:20 -0500946 std::string labelValue;
947 try
948 {
949 labelValue = readFile<std::string>(file.path());
950 }
951 catch (const std::system_error& e)
952 {
953 log<level::DEBUG>(
954 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
955 file.path().string(), e.code().value())
956 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800957 continue;
958 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800959
960 auto functionID = getPowerLabelFunctionID(labelValue);
961 if (functionID == std::nullopt)
962 {
963 continue;
964 }
965
966 const std::string& tempLabel = "label";
967 const std::string filePathString = file.path().string().substr(
968 0, file.path().string().length() - tempLabel.length());
969
970 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
971
972 auto iter = powerSensorName.find(*functionID);
973 if (iter == powerSensorName.end())
974 {
975 continue;
976 }
977 sensorPath.append(iter->second);
978
Matt Spinlera26f1522021-08-25 15:50:20 -0500979 double tempValue{0};
980
981 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800982 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500983 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800984 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500985 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800986 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800987 log<level::DEBUG>(
Chris Cain5d66a0a2022-02-09 08:52:10 -0600988 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500989 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800990 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500991 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800992 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500993
Chris Cain5d66a0a2022-02-09 08:52:10 -0600994 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -0600995 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
996
Chris Cain5d66a0a2022-02-09 08:52:10 -0600997 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500998 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
999
Chris Cain5d66a0a2022-02-09 08:52:10 -06001000 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
1001 true);
Matt Spinlera26f1522021-08-25 15:50:20 -05001002
Matt Spinler5901abd2021-09-23 13:50:03 -05001003 if (existingSensors.find(sensorPath) == existingSensors.end())
1004 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001005 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
1006 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -05001007 }
1008
Matt Spinlera26f1522021-08-25 15:50:20 -05001009 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +08001010 }
1011 return;
1012}
1013
Sheldon Baileyc8dd4592022-05-12 10:15:14 -05001014void Manager::setSensorValueToNaN(uint32_t id) const
Chicago Duanbb895cb2021-06-18 19:37:16 +08001015{
1016 for (const auto& [sensorPath, occId] : existingSensors)
1017 {
1018 if (occId == id)
1019 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001020 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +08001021 sensorPath, std::numeric_limits<double>::quiet_NaN());
Sheldon Baileyc8dd4592022-05-12 10:15:14 -05001022
1023 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
1024 true);
Chicago Duanbb895cb2021-06-18 19:37:16 +08001025 }
1026 }
1027 return;
1028}
1029
Sheldon Bailey373af752022-02-21 15:14:00 -06001030void Manager::setSensorValueToNonFunctional(uint32_t id) const
1031{
1032 for (const auto& [sensorPath, occId] : existingSensors)
1033 {
1034 if (occId == id)
1035 {
1036 dbus::OccDBusSensors::getOccDBus().setValue(
1037 sensorPath, std::numeric_limits<double>::quiet_NaN());
1038
1039 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
1040 false);
1041 }
1042 }
1043 return;
1044}
1045
Chris Cain5d66a0a2022-02-09 08:52:10 -06001046void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +08001047{
Chris Caine2d0a432022-03-28 11:08:49 -05001048 static bool tracedError[8] = {0};
1049 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -06001050 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +08001051
Chris Caine2d0a432022-03-28 11:08:49 -05001052 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +08001053 {
Chris Caine2d0a432022-03-28 11:08:49 -05001054 // Read temperature sensors
1055 readTempSensors(sensorPath, id);
1056
1057 if (occ->isMasterOcc())
1058 {
1059 // Read power sensors
1060 readPowerSensors(sensorPath, id);
1061 }
1062 tracedError[id] = false;
1063 }
1064 else
1065 {
1066 if (!tracedError[id])
1067 {
1068 log<level::ERR>(
1069 fmt::format(
1070 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1071 id, sensorPath.c_str())
1072 .c_str());
1073 tracedError[id] = true;
1074 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001075 }
1076
1077 return;
1078}
1079#endif
Chris Cain17257672021-10-22 13:41:03 -05001080
1081// Read the altitude from DBus
1082void Manager::readAltitude()
1083{
1084 static bool traceAltitudeErr = true;
1085
1086 utils::PropertyValue altitudeProperty{};
1087 try
1088 {
1089 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1090 ALTITUDE_PROP);
1091 auto sensorVal = std::get<double>(altitudeProperty);
1092 if (sensorVal < 0xFFFF)
1093 {
1094 if (sensorVal < 0)
1095 {
1096 altitude = 0;
1097 }
1098 else
1099 {
1100 // Round to nearest meter
1101 altitude = uint16_t(sensorVal + 0.5);
1102 }
1103 log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)",
1104 sensorVal, altitude)
1105 .c_str());
1106 traceAltitudeErr = true;
1107 }
1108 else
1109 {
1110 if (traceAltitudeErr)
1111 {
1112 traceAltitudeErr = false;
1113 log<level::DEBUG>(
1114 fmt::format("Invalid altitude value: {}", sensorVal)
1115 .c_str());
1116 }
1117 }
1118 }
Patrick Williamsaf408082022-07-22 19:26:54 -05001119 catch (const sdbusplus::exception_t& e)
Chris Cain17257672021-10-22 13:41:03 -05001120 {
1121 if (traceAltitudeErr)
1122 {
1123 traceAltitudeErr = false;
1124 log<level::INFO>(
1125 fmt::format("Unable to read Altitude: {}", e.what()).c_str());
1126 }
1127 altitude = 0xFFFF; // not available
1128 }
1129}
1130
1131// Callback function when ambient temperature changes
Patrick Williamsaf408082022-07-22 19:26:54 -05001132void Manager::ambientCallback(sdbusplus::message_t& msg)
Chris Cain17257672021-10-22 13:41:03 -05001133{
1134 double currentTemp = 0;
1135 uint8_t truncatedTemp = 0xFF;
1136 std::string msgSensor;
1137 std::map<std::string, std::variant<double>> msgData;
1138 msg.read(msgSensor, msgData);
1139
1140 auto valPropMap = msgData.find(AMBIENT_PROP);
1141 if (valPropMap == msgData.end())
1142 {
1143 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1144 return;
1145 }
1146 currentTemp = std::get<double>(valPropMap->second);
1147 if (std::isnan(currentTemp))
1148 {
1149 truncatedTemp = 0xFF;
1150 }
1151 else
1152 {
1153 if (currentTemp < 0)
1154 {
1155 truncatedTemp = 0;
1156 }
1157 else
1158 {
1159 // Round to nearest degree C
1160 truncatedTemp = uint8_t(currentTemp + 0.5);
1161 }
1162 }
1163
1164 // If ambient changes, notify OCCs
1165 if (truncatedTemp != ambient)
1166 {
1167 log<level::DEBUG>(
1168 fmt::format("ambientCallback: Ambient change from {} to {}C",
1169 ambient, currentTemp)
1170 .c_str());
1171
1172 ambient = truncatedTemp;
1173 if (altitude == 0xFFFF)
1174 {
1175 // No altitude yet, try reading again
1176 readAltitude();
1177 }
1178
1179 log<level::DEBUG>(
1180 fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
1181 altitude)
1182 .c_str());
1183#ifdef POWER10
1184 // Send ambient and altitude to all OCCs
1185 for (auto& obj : statusObjects)
1186 {
1187 if (obj->occActive())
1188 {
1189 obj->sendAmbient(ambient, altitude);
1190 }
1191 }
1192#endif // POWER10
1193 }
1194}
1195
1196// return the current ambient and altitude readings
1197void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1198 uint16_t& altitudeValue) const
1199{
1200 ambientValid = true;
1201 ambientTemp = ambient;
1202 altitudeValue = altitude;
1203
1204 if (ambient == 0xFF)
1205 {
1206 ambientValid = false;
1207 }
1208}
1209
Chris Caina7b74dc2021-11-10 17:03:43 -06001210#ifdef POWER10
Chris Cain7f89e4d2022-05-09 13:27:45 -05001211// Called when waitForAllOccsTimer expires
1212// After the first OCC goes active, this timer will be started (60 seconds)
Chris Caina7b74dc2021-11-10 17:03:43 -06001213void Manager::occsNotAllRunning()
1214{
Chris Caina7b74dc2021-11-10 17:03:43 -06001215 if (activeCount != statusObjects.size())
1216 {
1217 // Not all OCCs went active
1218 log<level::WARNING>(
1219 fmt::format(
1220 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1221 activeCount, statusObjects.size())
1222 .c_str());
Chris Cain7f89e4d2022-05-09 13:27:45 -05001223 // Procs may be garded, so may be expected
Chris Caina7b74dc2021-11-10 17:03:43 -06001224 }
1225
1226 validateOccMaster();
1227}
1228#endif // POWER10
1229
1230// Verify single master OCC and start presence monitor
1231void Manager::validateOccMaster()
1232{
1233 int masterInstance = -1;
1234 for (auto& obj : statusObjects)
1235 {
Chris Cainbd551de2022-04-26 13:41:16 -05001236 auto instance = obj->getOccInstanceID();
Chris Cainbae4d072022-02-28 09:46:50 -06001237#ifdef POWER10
1238 if (!obj->occActive())
1239 {
1240 if (utils::isHostRunning())
1241 {
Chris Cainbd551de2022-04-26 13:41:16 -05001242 // Check if sensor was queued while waiting for discovery
1243 auto match = queuedActiveState.find(instance);
1244 if (match != queuedActiveState.end())
Chris Cainbae4d072022-02-28 09:46:50 -06001245 {
Chris Cain7f89e4d2022-05-09 13:27:45 -05001246 queuedActiveState.erase(match);
Chris Cainbae4d072022-02-28 09:46:50 -06001247 log<level::INFO>(
1248 fmt::format(
Chris Cainbd551de2022-04-26 13:41:16 -05001249 "validateOccMaster: OCC{} is ACTIVE (queued)",
1250 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001251 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -05001252 obj->occActive(true);
1253 }
1254 else
1255 {
1256 // OCC does not appear to be active yet, check active sensor
1257 pldmHandle->checkActiveSensor(instance);
1258 if (obj->occActive())
1259 {
1260 log<level::INFO>(
1261 fmt::format(
1262 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1263 instance)
1264 .c_str());
1265 }
Chris Cainbae4d072022-02-28 09:46:50 -06001266 }
1267 }
1268 else
1269 {
1270 log<level::WARNING>(
1271 fmt::format(
1272 "validateOccMaster: HOST is not running (OCC{})",
Chris Cainbd551de2022-04-26 13:41:16 -05001273 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001274 .c_str());
1275 return;
1276 }
1277 }
1278#endif // POWER10
1279
Chris Caina7b74dc2021-11-10 17:03:43 -06001280 if (obj->isMasterOcc())
1281 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001282 obj->addPresenceWatchMaster();
1283
Chris Caina7b74dc2021-11-10 17:03:43 -06001284 if (masterInstance == -1)
1285 {
Chris Cainbd551de2022-04-26 13:41:16 -05001286 masterInstance = instance;
Chris Caina7b74dc2021-11-10 17:03:43 -06001287 }
1288 else
1289 {
1290 log<level::ERR>(
1291 fmt::format(
1292 "validateOccMaster: Multiple OCC masters! ({} and {})",
Chris Cainbd551de2022-04-26 13:41:16 -05001293 masterInstance, instance)
Chris Caina7b74dc2021-11-10 17:03:43 -06001294 .c_str());
1295 // request reset
Eddie James9789e712022-05-25 15:43:40 -05001296 obj->deviceError(Error::Descriptor(PRESENCE_ERROR_PATH));
Chris Caina7b74dc2021-11-10 17:03:43 -06001297 }
1298 }
1299 }
Chris Cainbae4d072022-02-28 09:46:50 -06001300
Chris Caina7b74dc2021-11-10 17:03:43 -06001301 if (masterInstance < 0)
1302 {
Chris Cainbae4d072022-02-28 09:46:50 -06001303 log<level::ERR>(
1304 fmt::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
1305 statusObjects.size())
1306 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001307 // request reset
Eddie James9789e712022-05-25 15:43:40 -05001308 statusObjects.front()->deviceError(
1309 Error::Descriptor(PRESENCE_ERROR_PATH));
Chris Caina7b74dc2021-11-10 17:03:43 -06001310 }
1311 else
1312 {
1313 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -06001314 fmt::format("validateOccMaster: OCC{} is master of {} OCCs",
1315 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001316 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -05001317#ifdef POWER10
1318 pmode->updateDbusSafeMode(false);
1319#endif
Chris Caina7b74dc2021-11-10 17:03:43 -06001320 }
1321}
1322
Chris Cain40501a22022-03-14 17:33:27 -05001323void Manager::updatePcapBounds() const
1324{
1325 if (pcap)
1326 {
1327 pcap->updatePcapBounds();
1328 }
1329}
1330
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301331} // namespace occ
1332} // namespace open_power