blob: ad0d0ab72954f424a36717238fa4c1886614810a [file] [log] [blame]
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +05301#include "occ_status.hpp"
Gunnar Mills94df8c92018-09-14 14:50:03 -05002
Chris Cain17257672021-10-22 13:41:03 -05003#include "occ_manager.hpp"
Vishwanatha Subbanna6add0b82017-07-21 19:02:37 +05304#include "occ_sensor.hpp"
Chris Cain78e86012021-03-04 16:15:31 -06005#include "powermode.hpp"
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +05306#include "utils.hpp"
Gunnar Mills94df8c92018-09-14 14:50:03 -05007
Chris Caina8857c52021-01-27 11:53:05 -06008#include <fmt/core.h>
9
Chris Cain78e86012021-03-04 16:15:31 -060010#ifdef POWER10
11#include <com/ibm/Host/Target/server.hpp>
12#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -050013#include <phosphor-logging/log.hpp>
Chris Cain78e86012021-03-04 16:15:31 -060014
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +053015namespace open_power
16{
17namespace occ
18{
Chris Cain78e86012021-03-04 16:15:31 -060019
Chris Caina8857c52021-01-27 11:53:05 -060020using namespace phosphor::logging;
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +053021
22// Handles updates to occActive property
23bool Status::occActive(bool value)
24{
Vishwanatha Subbanna32e84e92017-06-28 19:17:28 +053025 if (value != this->occActive())
26 {
Chris Caina8857c52021-01-27 11:53:05 -060027 log<level::INFO>(fmt::format("Status::occActive OCC{} changed to {}",
28 instance, value)
29 .c_str());
Vishwanatha Subbanna32e84e92017-06-28 19:17:28 +053030 if (value)
31 {
32 // Bind the device
33 device.bind();
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053034
Edward A. James9fd2bdc2017-11-08 16:18:57 -060035 // Start watching for errors
36 addErrorWatch();
37
Chris Caina8857c52021-01-27 11:53:05 -060038 // Reset last OCC state
39 lastState = 0;
40
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053041 // Call into Manager to let know that we have bound
Edward A. James9fd2bdc2017-11-08 16:18:57 -060042 if (this->callBack)
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053043 {
44 this->callBack(value);
Edward A. James9fd2bdc2017-11-08 16:18:57 -060045 }
Vishwanatha Subbanna32e84e92017-06-28 19:17:28 +053046 }
47 else
48 {
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053049 // Call into Manager to let know that we will unbind.
Edward A. James9fd2bdc2017-11-08 16:18:57 -060050 if (this->callBack)
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053051 {
52 this->callBack(value);
Edward A. James9fd2bdc2017-11-08 16:18:57 -060053 }
54
55 // Stop watching for errors
56 removeErrorWatch();
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053057
58 // Do the unbind.
Vishwanatha Subbanna32e84e92017-06-28 19:17:28 +053059 device.unBind();
60 }
61 }
Edward A. James5e177972017-10-25 15:50:31 -050062 else if (value && !device.bound())
63 {
64 // Existing error watch is on a dead file descriptor.
Edward A. James9fd2bdc2017-11-08 16:18:57 -060065 removeErrorWatch();
Edward A. James5e177972017-10-25 15:50:31 -050066
67 /*
68 * In it's constructor, Status checks Device::bound() to see if OCC is
69 * active or not.
70 * Device::bound() checks for occX-dev0 directory.
71 * We will lose occX-dev0 directories during FSI rescan.
72 * So, if we start this application (and construct Status), and then
73 * later do FSI rescan, we will end up with occActive = true and device
74 * NOT bound. Lets correct that situation here.
75 */
76 device.bind();
77
78 // Add error watch again
Edward A. James9fd2bdc2017-11-08 16:18:57 -060079 addErrorWatch();
Edward A. James5e177972017-10-25 15:50:31 -050080 }
Eddie James6d6d1b32019-04-22 10:45:08 -050081 else if (!value && device.bound())
82 {
83 removeErrorWatch();
84
85 // In the event that the application never receives the active signal
86 // even though the OCC is active (this can occur if the BMC is rebooted
87 // with the host on, since the initial OCC driver probe will discover
88 // the OCCs), this application needs to be able to unbind the device
89 // when we get the OCC inactive signal.
90 device.unBind();
91 }
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +053092 return Base::Status::occActive(value);
93}
94
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053095// Callback handler when a device error is reported.
Eddie Jamescbad2192021-10-07 09:39:39 -050096void Status::deviceError()
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053097{
Eddie Jamescbad2192021-10-07 09:39:39 -050098 // This would deem OCC inactive
99 this->occActive(false);
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530100
Eddie Jamescbad2192021-10-07 09:39:39 -0500101 // Reset the OCC
102 this->resetOCC();
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530103}
104
105// Sends message to host control command handler to reset OCC
106void Status::resetOCC()
107{
Chris Caina8857c52021-01-27 11:53:05 -0600108 log<level::INFO>(
109 fmt::format(">>Status::resetOCC() - requesting reset for OCC{}",
110 instance)
111 .c_str());
Tom Joseph00325232020-07-29 17:51:48 +0530112#ifdef PLDM
113 if (resetCallBack)
114 {
115 this->resetCallBack(instance);
116 }
117#else
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530118 constexpr auto CONTROL_HOST_PATH = "/org/open_power/control/host0";
119 constexpr auto CONTROL_HOST_INTF = "org.open_power.Control.Host";
120
121 // This will throw exception on failure
George Liuf3b75142021-06-10 11:22:50 +0800122 auto service = utils::getService(CONTROL_HOST_PATH, CONTROL_HOST_INTF);
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530123
George Liuf3b75142021-06-10 11:22:50 +0800124 auto& bus = utils::getBus();
Gunnar Mills94df8c92018-09-14 14:50:03 -0500125 auto method = bus.new_method_call(service.c_str(), CONTROL_HOST_PATH,
126 CONTROL_HOST_INTF, "Execute");
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530127 // OCC Reset control command
Gunnar Mills94df8c92018-09-14 14:50:03 -0500128 method.append(convertForMessage(Control::Host::Command::OCCReset).c_str());
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530129
130 // OCC Sensor ID for callout reasons
Patrick Williamse0962702020-05-13 17:50:22 -0500131 method.append(std::variant<uint8_t>(std::get<0>(sensorMap.at(instance))));
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530132 bus.call_noreply(method);
133 return;
Tom Joseph00325232020-07-29 17:51:48 +0530134#endif
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530135}
136
137// Handler called by Host control command handler to convey the
138// status of the executed command
139void Status::hostControlEvent(sdbusplus::message::message& msg)
140{
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530141 std::string cmdCompleted{};
142 std::string cmdStatus{};
143
144 msg.read(cmdCompleted, cmdStatus);
145
146 log<level::DEBUG>("Host control signal values",
Gunnar Mills94df8c92018-09-14 14:50:03 -0500147 entry("COMMAND=%s", cmdCompleted.c_str()),
148 entry("STATUS=%s", cmdStatus.c_str()));
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530149
Gunnar Mills94df8c92018-09-14 14:50:03 -0500150 if (Control::Host::convertResultFromString(cmdStatus) !=
151 Control::Host::Result::Success)
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530152 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500153 if (Control::Host::convertCommandFromString(cmdCompleted) ==
154 Control::Host::Command::OCCReset)
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530155 {
Gunnar Mills85e65202018-04-08 15:01:54 -0500156 // Must be a Timeout. Log an Error trace
Alexander Filippov1d69e192019-03-21 18:12:07 +0300157 log<level::ERR>(
158 "Error resetting the OCC.", entry("PATH=%s", path.c_str()),
159 entry("SENSORID=0x%X", std::get<0>(sensorMap.at(instance))));
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530160 }
161 }
162 return;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530163}
164
Chris Caina8857c52021-01-27 11:53:05 -0600165void Status::readOccState()
166{
167 unsigned int state;
168 const fs::path filename =
169 fs::path(DEV_PATH) /
170 fs::path(sysfsName + "." + std::to_string(instance + 1)) / "occ_state";
171
Chris Caina8857c52021-01-27 11:53:05 -0600172 std::ifstream file(filename, std::ios::in);
173 const int open_errno = errno;
174 if (file)
175 {
176 file >> state;
177 if (state != lastState)
178 {
179 // Trace OCC state changes
180 log<level::INFO>(
181 fmt::format("Status::readOccState: OCC{} state 0x{:02X}",
182 instance, state)
183 .c_str());
184 lastState = state;
Chris Cain78e86012021-03-04 16:15:31 -0600185
186#ifdef POWER10
187 if ((OccState(state) == OccState::ACTIVE) && (device.master()))
188 {
189 // Kernel detected that the master OCC went to active state
190 occsWentActive();
191 }
Chris Cain17257672021-10-22 13:41:03 -0500192 if (OccState(state) == OccState::ACTIVE)
193 {
194 CmdStatus status = sendAmbient();
195 if (status != CmdStatus::SUCCESS)
196 {
197 log<level::ERR>(
198 fmt::format(
199 "readOccState: Sending Ambient failed with status {}",
200 status)
201 .c_str());
202 }
203 }
Chris Cain78e86012021-03-04 16:15:31 -0600204#endif
Chris Caina8857c52021-01-27 11:53:05 -0600205 }
206 file.close();
207 }
208 else
209 {
210 // If not able to read, OCC may be offline
211 log<level::DEBUG>(
212 fmt::format("Status::readOccState: open failed (errno={})",
213 open_errno)
214 .c_str());
215 lastState = 0;
216 }
217}
218
Chris Cain78e86012021-03-04 16:15:31 -0600219#ifdef POWER10
220// Check if Hypervisor target is PowerVM
221bool Status::isPowerVM()
222{
223 using namespace open_power::occ::powermode;
224 namespace Hyper = sdbusplus::com::ibm::Host::server;
225 constexpr auto HYPE_PATH = "/com/ibm/host0/hypervisor";
226 constexpr auto HYPE_INTERFACE = "com.ibm.Host.Target";
227 constexpr auto HYPE_PROP = "Target";
228
229 bool powerVmTarget = false;
230
231 // This will throw exception on failure
232 auto& bus = utils::getBus();
233 auto service = utils::getService(HYPE_PATH, HYPE_INTERFACE);
234 auto method = bus.new_method_call(service.c_str(), HYPE_PATH,
235 "org.freedesktop.DBus.Properties", "Get");
236 method.append(HYPE_INTERFACE, HYPE_PROP);
237 auto reply = bus.call(method);
238
239 std::variant<std::string> hyperEntryValue;
240 reply.read(hyperEntryValue);
241 auto propVal = std::get<std::string>(hyperEntryValue);
242 if (Hyper::Target::convertHypervisorFromString(propVal) ==
243 Hyper::Target::Hypervisor::PowerVM)
244 {
245 powerVmTarget = true;
246 }
247
248 log<level::DEBUG>(
249 fmt::format("Status::isPowerVM returning {}", powerVmTarget).c_str());
250
251 return powerVmTarget;
252}
253
254// Get the requested power mode
255SysPwrMode Status::getMode()
256{
257 using namespace open_power::occ::powermode;
258 SysPwrMode pmode = SysPwrMode::NO_CHANGE;
259
260 // This will throw exception on failure
261 auto& bus = utils::getBus();
262 auto service = utils::getService(PMODE_PATH, PMODE_INTERFACE);
263 auto method = bus.new_method_call(service.c_str(), PMODE_PATH,
264 "org.freedesktop.DBus.Properties", "Get");
265 method.append(PMODE_INTERFACE, POWER_MODE_PROP);
266 auto reply = bus.call(method);
267
268 std::variant<std::string> stateEntryValue;
269 reply.read(stateEntryValue);
270 auto propVal = std::get<std::string>(stateEntryValue);
271 pmode = powermode::convertStringToMode(propVal);
272
273 log<level::DEBUG>(
274 fmt::format("Status::getMode returning {}", pmode).c_str());
275
276 return pmode;
277}
278
Chris Cain1d51da22021-09-21 14:13:41 -0500279// Get the requested power mode
280bool Status::getIPSParms(uint8_t& enterUtil, uint16_t& enterTime,
281 uint8_t& exitUtil, uint16_t& exitTime)
282{
283 using namespace open_power::occ::powermode;
284 // Defaults:
285 bool ipsEnabled = false; // Disabled
286 enterUtil = 8; // Enter Utilization (8%)
287 enterTime = 240; // Enter Delay Time (240s)
288 exitUtil = 12; // Exit Utilization (12%)
289 exitTime = 10; // Exit Delay Time (10s)
290
291 std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
292 ipsProperties{};
293
294 // Get all IPS properties from DBus
295 try
296 {
297 auto& bus = utils::getBus();
298 auto service = utils::getService(PIPS_PATH, PIPS_INTERFACE);
299 auto method =
300 bus.new_method_call(service.c_str(), PIPS_PATH,
301 "org.freedesktop.DBus.Properties", "GetAll");
302 method.append(PIPS_INTERFACE);
303 auto reply = bus.call(method);
304 reply.read(ipsProperties);
305 }
306 catch (const sdbusplus::exception::exception& e)
307 {
308 log<level::ERR>(
309 fmt::format(
310 "Unable to read Idle Power Saver parameters so it will be disabled: {}",
311 e.what())
312 .c_str());
313 return ipsEnabled;
314 }
315
316 auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
317 if (ipsEntry != ipsProperties.end())
318 {
319 ipsEnabled = std::get<bool>(ipsEntry->second);
320 }
321 else
322 {
323 log<level::ERR>(
324 fmt::format("Status::getIPSParms could not find property: {}",
325 IPS_ENABLED_PROP)
326 .c_str());
327 }
328
329 ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
330 if (ipsEntry != ipsProperties.end())
331 {
332 enterUtil = std::get<uint8_t>(ipsEntry->second);
333 }
334 else
335 {
336 log<level::ERR>(
337 fmt::format("Status::getIPSParms could not find property: {}",
338 IPS_ENTER_UTIL)
339 .c_str());
340 }
341
342 ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
343 if (ipsEntry != ipsProperties.end())
344 {
345 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
346 enterTime =
347 std::chrono::duration_cast<std::chrono::seconds>(ms).count();
348 }
349 else
350 {
351 log<level::ERR>(
352 fmt::format("Status::getIPSParms could not find property: {}",
353 IPS_ENTER_TIME)
354 .c_str());
355 }
356
357 ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
358 if (ipsEntry != ipsProperties.end())
359 {
360 exitUtil = std::get<uint8_t>(ipsEntry->second);
361 }
362 else
363 {
364 log<level::ERR>(
365 fmt::format("Status::getIPSParms could not find property: {}",
366 IPS_EXIT_UTIL)
367 .c_str());
368 }
369
370 ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
371 if (ipsEntry != ipsProperties.end())
372 {
373 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
374 exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
375 }
376 else
377 {
378 log<level::ERR>(
379 fmt::format("Status::getIPSParms could not find property: {}",
380 IPS_EXIT_TIME)
381 .c_str());
382 }
383
384 if (enterUtil > exitUtil)
385 {
386 log<level::ERR>(
387 fmt::format(
388 "ERROR: Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
389 enterUtil, exitUtil)
390 .c_str());
391 enterUtil = exitUtil;
392 }
393
394 return ipsEnabled;
395}
396
Chris Cain78e86012021-03-04 16:15:31 -0600397// Special processing that needs to happen once the OCCs change to ACTIVE state
398void Status::occsWentActive()
399{
400 CmdStatus status = CmdStatus::SUCCESS;
401
402 status = sendModeChange();
403 if (status != CmdStatus::SUCCESS)
404 {
George Liub5ca1012021-09-10 12:53:11 +0800405 log<level::ERR>(
406 fmt::format(
407 "Status::occsWentActive: OCC mode change failed with status {}",
408 status)
409 .c_str());
Chris Cain78e86012021-03-04 16:15:31 -0600410 }
411
412 status = sendIpsData();
413 if (status != CmdStatus::SUCCESS)
414 {
415 log<level::ERR>(
416 fmt::format(
George Liub5ca1012021-09-10 12:53:11 +0800417 "Status::occsWentActive: Sending Idle Power Save Config data failed with status {}",
Chris Cain78e86012021-03-04 16:15:31 -0600418 status)
419 .c_str());
420 }
421}
422
423// Send mode change request to the master OCC
424CmdStatus Status::sendModeChange()
425{
426 CmdStatus status = CmdStatus::FAILURE;
427
428 if (!device.master())
429 {
430 log<level::ERR>(
George Liub5ca1012021-09-10 12:53:11 +0800431 fmt::format(
432 "Status::sendModeChange: MODE CHANGE does not get sent to slave OCC{}",
433 instance)
Chris Cain78e86012021-03-04 16:15:31 -0600434 .c_str());
435 return status;
436 }
437 if (!isPowerVM())
438 {
439 // Mode change is only supported on PowerVM systems
George Liub5ca1012021-09-10 12:53:11 +0800440 log<level::DEBUG>(
441 "Status::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems");
Chris Cain78e86012021-03-04 16:15:31 -0600442 return CmdStatus::SUCCESS;
443 }
444
445 const SysPwrMode newMode = getMode();
446
447 if (VALID_POWER_MODE_SETTING(newMode))
448 {
449 std::vector<std::uint8_t> cmd, rsp;
Chris Cain1d51da22021-09-21 14:13:41 -0500450 cmd.reserve(9);
Chris Cain78e86012021-03-04 16:15:31 -0600451 cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE));
452 cmd.push_back(0x00); // Data Length (2 bytes)
453 cmd.push_back(0x06);
454 cmd.push_back(0x30); // Data (Version)
455 cmd.push_back(uint8_t(OccState::NO_CHANGE));
456 cmd.push_back(uint8_t(newMode));
457 cmd.push_back(0x00); // Mode Data (Freq Point)
458 cmd.push_back(0x00); //
459 cmd.push_back(0x00); // reserved
George Liub5ca1012021-09-10 12:53:11 +0800460 log<level::INFO>(
461 fmt::format(
462 "Status::sendModeChange: SET_MODE({}) command to OCC{} ({} bytes)",
463 newMode, instance, cmd.size())
464 .c_str());
Chris Cain78e86012021-03-04 16:15:31 -0600465 status = occCmd.send(cmd, rsp);
466 if (status == CmdStatus::SUCCESS)
467 {
468 if (rsp.size() == 5)
469 {
Chris Cain1d51da22021-09-21 14:13:41 -0500470 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
Chris Cain78e86012021-03-04 16:15:31 -0600471 {
472 log<level::ERR>(
George Liub5ca1012021-09-10 12:53:11 +0800473 fmt::format(
474 "Status::sendModeChange: SET MODE failed with status 0x{:02X}",
475 rsp[2])
Chris Cain78e86012021-03-04 16:15:31 -0600476 .c_str());
Chris Cain1d51da22021-09-21 14:13:41 -0500477 dump_hex(rsp);
478 status = CmdStatus::FAILURE;
Chris Cain78e86012021-03-04 16:15:31 -0600479 }
480 }
481 else
482 {
483 log<level::ERR>(
484 "Status::sendModeChange: INVALID SET MODE response");
485 dump_hex(rsp);
Chris Cain1d51da22021-09-21 14:13:41 -0500486 status = CmdStatus::FAILURE;
Chris Cain78e86012021-03-04 16:15:31 -0600487 }
488 }
489 else
490 {
491 if (status == CmdStatus::OPEN_FAILURE)
492 {
Chris Cain1d51da22021-09-21 14:13:41 -0500493 log<level::INFO>("Status::sendModeChange: OCC not active yet");
494 status = CmdStatus::SUCCESS;
Chris Cain78e86012021-03-04 16:15:31 -0600495 }
496 else
497 {
498 log<level::ERR>("Status::sendModeChange: SET_MODE FAILED!");
499 }
500 }
501 }
502 else
503 {
504 log<level::ERR>(
505 fmt::format(
506 "Status::sendModeChange: Unable to set power mode to {}",
507 newMode)
508 .c_str());
Chris Cain1d51da22021-09-21 14:13:41 -0500509 status = CmdStatus::FAILURE;
Chris Cain78e86012021-03-04 16:15:31 -0600510 }
511
512 return status;
513}
514
515// Send Idle Power Saver config data to the master OCC
516CmdStatus Status::sendIpsData()
517{
518 CmdStatus status = CmdStatus::FAILURE;
519
520 if (!device.master())
521 {
522 log<level::ERR>(
George Liub5ca1012021-09-10 12:53:11 +0800523 fmt::format(
524 "Status::sendIpsData: SET_CFG_DATA[IPS] does not get sent to slave OCC{}",
525 instance)
Chris Cain78e86012021-03-04 16:15:31 -0600526 .c_str());
527 return status;
528 }
529 if (!isPowerVM())
530 {
531 // Idle Power Saver data is only supported on PowerVM systems
George Liub5ca1012021-09-10 12:53:11 +0800532 log<level::DEBUG>(
533 "Status::sendIpsData: SET_CFG_DATA[IPS] does not get sent on non-PowerVM systems");
Chris Cain78e86012021-03-04 16:15:31 -0600534 return CmdStatus::SUCCESS;
535 }
536
Chris Cain1d51da22021-09-21 14:13:41 -0500537 uint8_t enterUtil, exitUtil;
538 uint16_t enterTime, exitTime;
539 const bool ipsEnabled =
540 getIPSParms(enterUtil, enterTime, exitUtil, exitTime);
541
George Liub5ca1012021-09-10 12:53:11 +0800542 log<level::INFO>(
543 fmt::format(
Chris Cain1d51da22021-09-21 14:13:41 -0500544 "Idle Power Saver Parameters: enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
545 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
George Liub5ca1012021-09-10 12:53:11 +0800546 .c_str());
Chris Cain1d51da22021-09-21 14:13:41 -0500547
548 std::vector<std::uint8_t> cmd, rsp;
549 cmd.reserve(12);
550 cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA));
551 cmd.push_back(0x00); // Data Length (2 bytes)
552 cmd.push_back(0x09); //
553 cmd.push_back(0x11); // Config Format: IPS Settings
554 cmd.push_back(0x00); // Version
555 cmd.push_back(ipsEnabled ? 1 : 0); // IPS Enable
556 cmd.push_back(enterTime >> 8); // Enter Delay Time
557 cmd.push_back(enterTime & 0xFF); //
558 cmd.push_back(enterUtil); // Enter Utilization
559 cmd.push_back(exitTime >> 8); // Exit Delay Time
560 cmd.push_back(exitTime & 0xFF); //
561 cmd.push_back(exitUtil); // Exit Utilization
562 log<level::INFO>(fmt::format("Status::sendIpsData: SET_CFG_DATA[IPS] "
563 "command to OCC{} ({} bytes)",
564 instance, cmd.size())
565 .c_str());
Chris Cain78e86012021-03-04 16:15:31 -0600566 status = occCmd.send(cmd, rsp);
567 if (status == CmdStatus::SUCCESS)
568 {
569 if (rsp.size() == 5)
570 {
Chris Cain1d51da22021-09-21 14:13:41 -0500571 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
Chris Cain78e86012021-03-04 16:15:31 -0600572 {
573 log<level::ERR>(
George Liub5ca1012021-09-10 12:53:11 +0800574 fmt::format(
575 "Status::sendIpsData: SET_CFG_DATA[IPS] failed with status 0x{:02X}",
576 rsp[2])
Chris Cain78e86012021-03-04 16:15:31 -0600577 .c_str());
Chris Cain1d51da22021-09-21 14:13:41 -0500578 dump_hex(rsp);
579 status = CmdStatus::FAILURE;
Chris Cain78e86012021-03-04 16:15:31 -0600580 }
581 }
582 else
583 {
584 log<level::ERR>(
585 "Status::sendIpsData: INVALID SET_CFG_DATA[IPS] response");
586 dump_hex(rsp);
Chris Cain1d51da22021-09-21 14:13:41 -0500587 status = CmdStatus::FAILURE;
Chris Cain78e86012021-03-04 16:15:31 -0600588 }
589 }
590 else
591 {
592 if (status == CmdStatus::OPEN_FAILURE)
593 {
Chris Cain1d51da22021-09-21 14:13:41 -0500594 log<level::INFO>("Status::sendIpsData: OCC not active yet");
595 status = CmdStatus::SUCCESS;
Chris Cain78e86012021-03-04 16:15:31 -0600596 }
597 else
598 {
599 log<level::ERR>("Status::sendIpsData: SET_CFG_DATA[IPS] FAILED!");
600 }
601 }
602
603 return status;
604}
605
Chris Cain17257672021-10-22 13:41:03 -0500606// Send Ambient and Altitude to the OCC
607CmdStatus Status::sendAmbient(const uint8_t inTemp, const uint16_t inAltitude)
608{
609 CmdStatus status = CmdStatus::FAILURE;
610 bool ambientValid = true;
611 uint8_t ambientTemp = inTemp;
612 uint16_t altitude = inAltitude;
613
614 if (ambientTemp == 0xFF)
615 {
616 // Get latest readings from manager
617 manager.getAmbientData(ambientValid, ambientTemp, altitude);
618 log<level::DEBUG>(
619 fmt::format("sendAmbient: valid: {}, Ambient: {}C, altitude: {}m",
620 ambientValid, ambientTemp, altitude)
621 .c_str());
622 }
623
624 std::vector<std::uint8_t> cmd, rsp;
625 cmd.reserve(11);
626 cmd.push_back(uint8_t(CmdType::SEND_AMBIENT));
627 cmd.push_back(0x00); // Data Length (2 bytes)
628 cmd.push_back(0x08); //
629 cmd.push_back(0x00); // Version
630 cmd.push_back(ambientValid ? 0 : 0xFF); // Ambient Status
631 cmd.push_back(ambientTemp); // Ambient Temperature
632 cmd.push_back(altitude >> 8); // Altitude in meters (2 bytes)
633 cmd.push_back(altitude & 0xFF); //
634 cmd.push_back(0x00); // Reserved (3 bytes)
635 cmd.push_back(0x00);
636 cmd.push_back(0x00);
637 log<level::DEBUG>(fmt::format("sendAmbient: SEND_AMBIENT "
638 "command to OCC{} ({} bytes)",
639 instance, cmd.size())
640 .c_str());
641 status = occCmd.send(cmd, rsp);
642 if (status == CmdStatus::SUCCESS)
643 {
644 if (rsp.size() == 5)
645 {
646 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
647 {
648 log<level::ERR>(
649 fmt::format(
650 "sendAmbient: SEND_AMBIENT failed with status 0x{:02X}",
651 rsp[2])
652 .c_str());
653 dump_hex(rsp);
654 status = CmdStatus::FAILURE;
655 }
656 }
657 else
658 {
659 log<level::ERR>("sendAmbient: INVALID SEND_AMBIENT response");
660 dump_hex(rsp);
661 status = CmdStatus::FAILURE;
662 }
663 }
664 else
665 {
666 if (status == CmdStatus::OPEN_FAILURE)
667 {
668 // OCC not active yet
669 status = CmdStatus::SUCCESS;
670 }
671 else
672 {
673 log<level::ERR>("sendAmbient: SEND_AMBIENT FAILED!");
674 }
675 }
676
677 return status;
678}
Chris Cain78e86012021-03-04 16:15:31 -0600679#endif // POWER10
680
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530681} // namespace occ
682} // namespace open_power