blob: c883b697c8394ca1c60c0850e3d3262609806b09 [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
Chris Caine2d0a432022-03-28 11:08:49 -050015#include <filesystem>
16
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +053017namespace open_power
18{
19namespace occ
20{
Chris Cain78e86012021-03-04 16:15:31 -060021
Chris Caina8857c52021-01-27 11:53:05 -060022using namespace phosphor::logging;
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +053023
24// Handles updates to occActive property
25bool Status::occActive(bool value)
26{
Vishwanatha Subbanna32e84e92017-06-28 19:17:28 +053027 if (value != this->occActive())
28 {
Chris Caina8857c52021-01-27 11:53:05 -060029 log<level::INFO>(fmt::format("Status::occActive OCC{} changed to {}",
30 instance, value)
31 .c_str());
Vishwanatha Subbanna32e84e92017-06-28 19:17:28 +053032 if (value)
33 {
Eddie Jamesaced3092022-04-22 16:19:30 -050034 // Set the device active
35 device.setActive(true);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053036
Edward A. James9fd2bdc2017-11-08 16:18:57 -060037 // Start watching for errors
38 addErrorWatch();
39
Chris Caina8857c52021-01-27 11:53:05 -060040 // Reset last OCC state
41 lastState = 0;
42
Chris Cain5d66a0a2022-02-09 08:52:10 -060043 if (device.master())
44 {
Chris Cain5d66a0a2022-02-09 08:52:10 -060045 // Update powercap bounds from OCC
Chris Cain40501a22022-03-14 17:33:27 -050046 manager.updatePcapBounds();
Chris Cain5d66a0a2022-02-09 08:52:10 -060047 }
48
Chris Cainbae4d072022-02-28 09:46:50 -060049 // Update the OCC active sensor before notifying Manager
50 Base::Status::occActive(value);
51
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053052 // Call into Manager to let know that we have bound
Chris Cain1be43372021-12-09 19:29:37 -060053 if (this->managerCallBack)
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053054 {
Sheldon Bailey373af752022-02-21 15:14:00 -060055 this->managerCallBack(instance, value);
Edward A. James9fd2bdc2017-11-08 16:18:57 -060056 }
Vishwanatha Subbanna32e84e92017-06-28 19:17:28 +053057 }
58 else
59 {
Chris Caina7b74dc2021-11-10 17:03:43 -060060#ifdef POWER10
Chris Cain1be43372021-12-09 19:29:37 -060061 if (pmode && device.master())
Chris Cain36f9cde2021-11-22 11:18:21 -060062 {
63 // Prevent mode changes
64 pmode->setMasterActive(false);
65 }
Chris Caina7b74dc2021-11-10 17:03:43 -060066 if (safeStateDelayTimer.isEnabled())
67 {
68 // stop safe delay timer
69 safeStateDelayTimer.setEnabled(false);
70 }
71#endif
Chris Cain36f9cde2021-11-22 11:18:21 -060072 // Call into Manager to let know that we will unbind.
Chris Cain1be43372021-12-09 19:29:37 -060073 if (this->managerCallBack)
Chris Cain36f9cde2021-11-22 11:18:21 -060074 {
Sheldon Bailey373af752022-02-21 15:14:00 -060075 this->managerCallBack(instance, value);
Chris Cain36f9cde2021-11-22 11:18:21 -060076 }
77
Edward A. James9fd2bdc2017-11-08 16:18:57 -060078 // Stop watching for errors
79 removeErrorWatch();
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053080
Eddie Jamesaced3092022-04-22 16:19:30 -050081 // Set the device inactive
82 device.setActive(false);
Vishwanatha Subbanna32e84e92017-06-28 19:17:28 +053083 }
84 }
Eddie Jamesaced3092022-04-22 16:19:30 -050085 else if (value && !device.active())
Edward A. James5e177972017-10-25 15:50:31 -050086 {
87 // Existing error watch is on a dead file descriptor.
Edward A. James9fd2bdc2017-11-08 16:18:57 -060088 removeErrorWatch();
Edward A. James5e177972017-10-25 15:50:31 -050089
90 /*
91 * In it's constructor, Status checks Device::bound() to see if OCC is
92 * active or not.
93 * Device::bound() checks for occX-dev0 directory.
94 * We will lose occX-dev0 directories during FSI rescan.
95 * So, if we start this application (and construct Status), and then
96 * later do FSI rescan, we will end up with occActive = true and device
97 * NOT bound. Lets correct that situation here.
98 */
Eddie Jamesaced3092022-04-22 16:19:30 -050099 device.setActive(true);
Edward A. James5e177972017-10-25 15:50:31 -0500100
101 // Add error watch again
Edward A. James9fd2bdc2017-11-08 16:18:57 -0600102 addErrorWatch();
Edward A. James5e177972017-10-25 15:50:31 -0500103 }
Eddie Jamesaced3092022-04-22 16:19:30 -0500104 else if (!value && device.active())
Eddie James6d6d1b32019-04-22 10:45:08 -0500105 {
106 removeErrorWatch();
107
108 // In the event that the application never receives the active signal
109 // even though the OCC is active (this can occur if the BMC is rebooted
110 // with the host on, since the initial OCC driver probe will discover
111 // the OCCs), this application needs to be able to unbind the device
112 // when we get the OCC inactive signal.
Eddie Jamesaced3092022-04-22 16:19:30 -0500113 device.setActive(false);
Eddie James6d6d1b32019-04-22 10:45:08 -0500114 }
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530115 return Base::Status::occActive(value);
116}
117
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530118// Callback handler when a device error is reported.
Eddie Jamescbad2192021-10-07 09:39:39 -0500119void Status::deviceError()
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530120{
Chris Cain36f9cde2021-11-22 11:18:21 -0600121#ifdef POWER10
Chris Cain1be43372021-12-09 19:29:37 -0600122 if (pmode && device.master())
123 {
124 // Prevent mode changes
125 pmode->setMasterActive(false);
126 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600127#endif
128
Eddie Jamescbad2192021-10-07 09:39:39 -0500129 // This would deem OCC inactive
130 this->occActive(false);
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530131
Eddie Jamescbad2192021-10-07 09:39:39 -0500132 // Reset the OCC
133 this->resetOCC();
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530134}
135
136// Sends message to host control command handler to reset OCC
137void Status::resetOCC()
138{
Chris Caina8857c52021-01-27 11:53:05 -0600139 log<level::INFO>(
140 fmt::format(">>Status::resetOCC() - requesting reset for OCC{}",
141 instance)
142 .c_str());
Tom Joseph00325232020-07-29 17:51:48 +0530143#ifdef PLDM
144 if (resetCallBack)
145 {
146 this->resetCallBack(instance);
147 }
148#else
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530149 constexpr auto CONTROL_HOST_PATH = "/org/open_power/control/host0";
150 constexpr auto CONTROL_HOST_INTF = "org.open_power.Control.Host";
151
152 // This will throw exception on failure
George Liuf3b75142021-06-10 11:22:50 +0800153 auto service = utils::getService(CONTROL_HOST_PATH, CONTROL_HOST_INTF);
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530154
George Liuf3b75142021-06-10 11:22:50 +0800155 auto& bus = utils::getBus();
Gunnar Mills94df8c92018-09-14 14:50:03 -0500156 auto method = bus.new_method_call(service.c_str(), CONTROL_HOST_PATH,
157 CONTROL_HOST_INTF, "Execute");
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530158 // OCC Reset control command
Gunnar Mills94df8c92018-09-14 14:50:03 -0500159 method.append(convertForMessage(Control::Host::Command::OCCReset).c_str());
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530160
161 // OCC Sensor ID for callout reasons
Patrick Williamse0962702020-05-13 17:50:22 -0500162 method.append(std::variant<uint8_t>(std::get<0>(sensorMap.at(instance))));
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530163 bus.call_noreply(method);
164 return;
Tom Joseph00325232020-07-29 17:51:48 +0530165#endif
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530166}
167
168// Handler called by Host control command handler to convey the
169// status of the executed command
170void Status::hostControlEvent(sdbusplus::message::message& msg)
171{
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530172 std::string cmdCompleted{};
173 std::string cmdStatus{};
174
175 msg.read(cmdCompleted, cmdStatus);
176
177 log<level::DEBUG>("Host control signal values",
Gunnar Mills94df8c92018-09-14 14:50:03 -0500178 entry("COMMAND=%s", cmdCompleted.c_str()),
179 entry("STATUS=%s", cmdStatus.c_str()));
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530180
Gunnar Mills94df8c92018-09-14 14:50:03 -0500181 if (Control::Host::convertResultFromString(cmdStatus) !=
182 Control::Host::Result::Success)
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530183 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500184 if (Control::Host::convertCommandFromString(cmdCompleted) ==
185 Control::Host::Command::OCCReset)
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530186 {
Gunnar Mills85e65202018-04-08 15:01:54 -0500187 // Must be a Timeout. Log an Error trace
Alexander Filippov1d69e192019-03-21 18:12:07 +0300188 log<level::ERR>(
189 "Error resetting the OCC.", entry("PATH=%s", path.c_str()),
190 entry("SENSORID=0x%X", std::get<0>(sensorMap.at(instance))));
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530191 }
192 }
193 return;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530194}
195
Sheldon Bailey373af752022-02-21 15:14:00 -0600196// Called from Manager::pollerTimerExpired() in preperation to POLL OCC.
Chris Caina8857c52021-01-27 11:53:05 -0600197void Status::readOccState()
198{
Sheldon Bailey373af752022-02-21 15:14:00 -0600199 currentOccReadRetriesCount = occReadRetries;
200 occReadStateNow();
Chris Caina8857c52021-01-27 11:53:05 -0600201}
202
Chris Cain78e86012021-03-04 16:15:31 -0600203#ifdef POWER10
Chris Cain78e86012021-03-04 16:15:31 -0600204// Special processing that needs to happen once the OCCs change to ACTIVE state
205void Status::occsWentActive()
206{
207 CmdStatus status = CmdStatus::SUCCESS;
208
Chris Cain36f9cde2021-11-22 11:18:21 -0600209 status = pmode->sendModeChange();
Chris Cain78e86012021-03-04 16:15:31 -0600210 if (status != CmdStatus::SUCCESS)
211 {
George Liub5ca1012021-09-10 12:53:11 +0800212 log<level::ERR>(
213 fmt::format(
214 "Status::occsWentActive: OCC mode change failed with status {}",
215 status)
216 .c_str());
Chris Cainc567dc82022-04-01 15:09:17 -0500217
218 // Disable and reset to try recovering
219 deviceError();
Chris Cain78e86012021-03-04 16:15:31 -0600220 }
221
Chris Cain36f9cde2021-11-22 11:18:21 -0600222 status = pmode->sendIpsData();
Chris Cain78e86012021-03-04 16:15:31 -0600223 if (status != CmdStatus::SUCCESS)
224 {
225 log<level::ERR>(
226 fmt::format(
George Liub5ca1012021-09-10 12:53:11 +0800227 "Status::occsWentActive: Sending Idle Power Save Config data failed with status {}",
Chris Cain78e86012021-03-04 16:15:31 -0600228 status)
229 .c_str());
Chris Cainc567dc82022-04-01 15:09:17 -0500230
231 if (status == CmdStatus::COMM_FAILURE)
232 {
233 // Disable and reset to try recovering
234 deviceError();
235 }
Chris Cain78e86012021-03-04 16:15:31 -0600236 }
237}
238
Chris Cain17257672021-10-22 13:41:03 -0500239// Send Ambient and Altitude to the OCC
240CmdStatus Status::sendAmbient(const uint8_t inTemp, const uint16_t inAltitude)
241{
242 CmdStatus status = CmdStatus::FAILURE;
243 bool ambientValid = true;
244 uint8_t ambientTemp = inTemp;
245 uint16_t altitude = inAltitude;
246
247 if (ambientTemp == 0xFF)
248 {
249 // Get latest readings from manager
250 manager.getAmbientData(ambientValid, ambientTemp, altitude);
251 log<level::DEBUG>(
252 fmt::format("sendAmbient: valid: {}, Ambient: {}C, altitude: {}m",
253 ambientValid, ambientTemp, altitude)
254 .c_str());
255 }
256
257 std::vector<std::uint8_t> cmd, rsp;
258 cmd.reserve(11);
259 cmd.push_back(uint8_t(CmdType::SEND_AMBIENT));
260 cmd.push_back(0x00); // Data Length (2 bytes)
261 cmd.push_back(0x08); //
262 cmd.push_back(0x00); // Version
263 cmd.push_back(ambientValid ? 0 : 0xFF); // Ambient Status
264 cmd.push_back(ambientTemp); // Ambient Temperature
265 cmd.push_back(altitude >> 8); // Altitude in meters (2 bytes)
266 cmd.push_back(altitude & 0xFF); //
267 cmd.push_back(0x00); // Reserved (3 bytes)
268 cmd.push_back(0x00);
269 cmd.push_back(0x00);
270 log<level::DEBUG>(fmt::format("sendAmbient: SEND_AMBIENT "
271 "command to OCC{} ({} bytes)",
272 instance, cmd.size())
273 .c_str());
274 status = occCmd.send(cmd, rsp);
275 if (status == CmdStatus::SUCCESS)
276 {
277 if (rsp.size() == 5)
278 {
279 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
280 {
281 log<level::ERR>(
282 fmt::format(
Chris Cainc567dc82022-04-01 15:09:17 -0500283 "sendAmbient: SEND_AMBIENT failed with rspStatus 0x{:02X}",
Chris Cain17257672021-10-22 13:41:03 -0500284 rsp[2])
285 .c_str());
286 dump_hex(rsp);
287 status = CmdStatus::FAILURE;
288 }
289 }
290 else
291 {
Chris Cainc567dc82022-04-01 15:09:17 -0500292 log<level::ERR>(
293 fmt::format(
294 "sendAmbient: INVALID SEND_AMBIENT response length:{}",
295 rsp.size())
296 .c_str());
Chris Cain17257672021-10-22 13:41:03 -0500297 dump_hex(rsp);
298 status = CmdStatus::FAILURE;
299 }
300 }
301 else
302 {
Chris Cainc567dc82022-04-01 15:09:17 -0500303 log<level::ERR>(
304 fmt::format(
305 "sendAmbient: SEND_AMBIENT FAILED! with status 0x{:02X}",
306 status)
307 .c_str());
308
309 if (status == CmdStatus::COMM_FAILURE)
Chris Cain17257672021-10-22 13:41:03 -0500310 {
Chris Cainc567dc82022-04-01 15:09:17 -0500311 // Disable and reset to try recovering
312 deviceError();
Chris Cain17257672021-10-22 13:41:03 -0500313 }
314 }
315
316 return status;
317}
Chris Caina7b74dc2021-11-10 17:03:43 -0600318
319// Called when safe timer expires to determine if OCCs need to be reset
320void Status::safeStateDelayExpired()
321{
322 if (this->occActive())
323 {
324 log<level::INFO>(
325 fmt::format(
326 "safeStateDelayExpired: OCC{} is in SAFE state, requesting reset",
327 instance)
328 .c_str());
329 // Disable and reset to try recovering
330 deviceError();
331 }
332}
Chris Cain78e86012021-03-04 16:15:31 -0600333#endif // POWER10
334
Chris Caine2d0a432022-03-28 11:08:49 -0500335fs::path Status::getHwmonPath()
Chris Cain5d66a0a2022-02-09 08:52:10 -0600336{
337 using namespace std::literals::string_literals;
338
Chris Caine2d0a432022-03-28 11:08:49 -0500339 if (!fs::exists(hwmonPath))
340 {
341 static bool tracedFail[8] = {0};
Chris Cain5d66a0a2022-02-09 08:52:10 -0600342
Chris Caine2d0a432022-03-28 11:08:49 -0500343 if (!hwmonPath.empty())
344 {
345 log<level::ERR>(
346 fmt::format("Status::getHwmonPath(): path no longer exists: {}",
347 hwmonPath.c_str())
348 .c_str());
349 hwmonPath.clear();
350 }
351
352 // Build the base HWMON path
353 fs::path prefixPath =
354 fs::path{OCC_HWMON_PATH + "occ-hwmon."s +
355 std::to_string(instance + 1) + "/hwmon/"s};
356
357 // Get the hwmonXX directory name
358 try
359 {
360 // there should only be one directory
361 const int numDirs = std::distance(
362 fs::directory_iterator(prefixPath), fs::directory_iterator{});
363 if (numDirs == 1)
364 {
365 hwmonPath = *fs::directory_iterator(prefixPath);
366 tracedFail[instance] = false;
367 }
368 else
369 {
370 if (!tracedFail[instance])
371 {
372 log<level::ERR>(
373 fmt::format(
374 "Status::getHwmonPath(): Found multiple ({}) hwmon paths!",
375 numDirs)
376 .c_str());
377 tracedFail[instance] = true;
378 }
379 }
380 }
381 catch (const fs::filesystem_error& e)
382 {
383 if (!tracedFail[instance])
384 {
385 log<level::ERR>(
386 fmt::format(
387 "Status::getHwmonPath(): error accessing {}: {}",
388 prefixPath.c_str(), e.what())
389 .c_str());
390 tracedFail[instance] = true;
391 }
392 }
393 }
394
395 return hwmonPath;
Chris Cain5d66a0a2022-02-09 08:52:10 -0600396}
397
Sheldon Bailey373af752022-02-21 15:14:00 -0600398// Called to read state and upon failure to read after occReadStateFailTimer.
399void Status::occReadStateNow()
400{
401 unsigned int state;
402 const fs::path filename =
403 fs::path(DEV_PATH) /
404 fs::path(sysfsName + "." + std::to_string(instance + 1)) / "occ_state";
405
406 std::ifstream file;
407 bool goodFile = false;
408
409 // open file.
410 file.open(filename, std::ios::in);
411 const int openErrno = errno;
412
413 // File is open and state can be used.
414 if (file.is_open() && file.good())
415 {
416 goodFile = true;
417 file >> state;
418
419 if (state != lastState)
420 {
421 // Trace OCC state changes
422 log<level::INFO>(
423 fmt::format("Status::readOccState: OCC{} state 0x{:02X}",
424 instance, state)
425 .c_str());
426 lastState = state;
427#ifdef POWER10
428 if (OccState(state) == OccState::ACTIVE)
429 {
430 if (pmode && device.master())
431 {
432 // Set the master OCC on the PowerMode object
433 pmode->setMasterOcc(path);
434 // Enable mode changes
435 pmode->setMasterActive();
436
437 // Special processing by master OCC when it goes active
438 occsWentActive();
439 }
440
441 CmdStatus status = sendAmbient();
442 if (status != CmdStatus::SUCCESS)
443 {
444 log<level::ERR>(
445 fmt::format(
446 "readOccState: Sending Ambient failed with status {}",
447 status)
448 .c_str());
449 }
450 }
451
452 // If OCC in known Good State.
453 if ((OccState(state) == OccState::ACTIVE) ||
454 (OccState(state) == OccState::CHARACTERIZATION) ||
455 (OccState(state) == OccState::OBSERVATION))
456 {
457 // Good OCC State then sensors valid again
458 stateValid = true;
459
460 if (safeStateDelayTimer.isEnabled())
461 {
462 // stop safe delay timer (no longer in SAFE state)
463 safeStateDelayTimer.setEnabled(false);
464 }
465 }
466 // Else not Valid state We would be in SAFE mode.
467 // This captures both SAFE mode, and 0x00, or other invalid
468 // state values.
469 else
470 {
471 if (!safeStateDelayTimer.isEnabled())
472 {
473 // start safe delay timer (before requesting reset)
474 using namespace std::literals::chrono_literals;
475 safeStateDelayTimer.restartOnce(60s);
476 }
477 // Not valid state, update sensors to Nan & not functional.
478 stateValid = false;
479 }
480#else
481 // Before P10 state not checked, only used good file open.
482 stateValid = true;
483#endif
484 }
485 }
486 file.close();
487
488 // if failed to Read a state or not a valid state -> Attempt retry
489 // after 1 Second delay if allowed.
490 if ((!goodFile) || (!stateValid))
491 {
492 if (!goodFile)
493 {
494 // If not able to read, OCC may be offline
495 log<level::ERR>(
496 fmt::format("Status::readOccState: open failed (errno={})",
497 openErrno)
498 .c_str());
499 }
500 else
501 {
502 // else this failed due to state not valid.
503 log<level::ERR>(
504 fmt::format(
505 "Status::readOccState: OCC{} Invalid state 0x{:02X}",
506 instance, state)
507 .c_str());
508 }
509
510#ifdef READ_OCC_SENSORS
511 manager.setSensorValueToNonFunctional(instance);
512#endif
513
514 // See occReadRetries for number of retry attempts.
515 if (currentOccReadRetriesCount > 0)
516 {
517 --currentOccReadRetriesCount;
518#ifdef POWER10
519 using namespace std::chrono_literals;
520 occReadStateFailTimer.restartOnce(1s);
521#endif
522 }
523 else
524 {
Chris Cainbae4d072022-02-28 09:46:50 -0600525#ifdef POWER10
526 if (!stateValid && occActive())
527 {
528 if (!safeStateDelayTimer.isEnabled())
529 {
530 log<level::ERR>(
531 "Starting 60 sec delay timer before requesting a reset");
532 // start safe delay timer (before requesting reset)
533 using namespace std::literals::chrono_literals;
534 safeStateDelayTimer.restartOnce(60s);
535 }
536 }
537#else
Sheldon Bailey373af752022-02-21 15:14:00 -0600538 // State could not be determined, set it to NO State.
539 lastState = 0;
540
541 // Disable the ability to send Failed actions until OCC is
542 // Active again.
543 stateValid = false;
544
545 // Disable and reset to try recovering
546 deviceError();
Chris Cainbae4d072022-02-28 09:46:50 -0600547#endif
Sheldon Bailey373af752022-02-21 15:14:00 -0600548 }
549 }
550}
551
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530552} // namespace occ
553} // namespace open_power