blob: 2ae3fbaa7ad72c5ac4b09117aed75bcac07aef89 [file] [log] [blame]
Andrew Geissler65c01012021-06-15 14:03:34 -05001extern "C"
2{
3#include "libpdbg.h"
4}
5
Jayanth Othayoth25e39c82021-07-12 01:00:17 -05006#include "extensions/phal/common_utils.hpp"
Jayanth Othayoth6552de02021-07-12 00:55:57 -05007#include "extensions/phal/create_pel.hpp"
Jayanth Othayothc3d6b872021-07-28 05:07:25 -05008#include "extensions/phal/pdbg_utils.hpp"
Andrew Geissler65c01012021-06-15 14:03:34 -05009#include "p10_cfam.hpp"
Andrew Geissler65c01012021-06-15 14:03:34 -050010#include "registration.hpp"
11
12#include <phosphor-logging/log.hpp>
13
14#include <cstdio>
15#include <fstream>
16#include <memory>
17
18namespace openpower
19{
20namespace phal
21{
22
23using namespace openpower::cfam::p10;
24using namespace phosphor::logging;
25
26/**
27 * This is the backup plan to ensuring the host is not running before the
28 * BMC issues a power off to the system. Prior to this procedure being called,
29 * the BMC has tried all other communication mechanisms to talk with the host
30 * and they have failed. The design is that the host firmware will write the
31 * value 0xA5000001 to Mailbox scratch register 12 when they are up and running
32 * to a point where communication to the BMC is no longer required to function.
33 * On a power off or shutdown this register is cleared by the host and BMC
34 * firmware. If the BMC sees the 0xA5000001 pattern in the scratch register
35 * then it assumes the host is running and will leave power on to the system.
36 */
37void checkHostRunning()
38{
39 struct pdbg_target* procTarget;
40
41 try
42 {
43 phal_init();
44 }
45 catch (std::exception& ex)
46 {
47 // This should "never" happen so just throw the exception and let
48 // our systemd error handling process this
49 log<level::ERR>("Exception raised during init PHAL",
50 entry("EXCEPTION=%s", ex.what()));
51 throw std::runtime_error("PHAL initialization failed");
52 }
53
54 pdbg_for_each_class_target("proc", procTarget)
55 {
56 // Only check the primary proc
57 if (!isPrimaryProc(procTarget))
58 {
59 continue;
60 }
61
62 uint32_t val = 0;
63 constexpr uint32_t HOST_RUNNING_INDICATION = 0xA5000001;
64 auto rc = getCFAM(procTarget, P10_SCRATCH_REG_12, val);
65 if ((rc == 0) && (val != HOST_RUNNING_INDICATION))
66 {
67 log<level::INFO>("CFAM read indicates host is not running",
68 entry("CFAM=0x%X", val));
69 return;
70 }
71
72 if (rc != 0)
73 {
74 // On error, we have to assume host is up so just fall through
75 // to code below
76 log<level::ERR>("CFAM read error, assume host is running");
77 }
78 else if (val == HOST_RUNNING_INDICATION)
79 {
80 // This is not good. Normal communication path to host did not work
81 // but CFAM indicates host is running.
82 log<level::ERR>("CFAM read indicates host is running");
83 }
84
Andrew Geissler61febf02021-06-22 17:19:32 -050085 // Create an error so user knows system is in a bad state
Jayanth Othayothac95c562021-07-16 05:56:04 -050086 openpower::pel::createPEL("org.open_power.PHAL.Error.HostRunning");
Andrew Geissler65c01012021-06-15 14:03:34 -050087
88 // Create file for host instance and create in filesystem to
89 // indicate to services that host is running.
90 // This file is cleared by the phosphor-state-manager once the host
91 // start target completes.
92 constexpr auto HOST_RUNNING_FILE = "/run/openbmc/host@%d-on";
93 auto size = std::snprintf(nullptr, 0, HOST_RUNNING_FILE, 0);
94 size++; // null
95 std::unique_ptr<char[]> buf(new char[size]);
96 std::snprintf(buf.get(), size, HOST_RUNNING_FILE, 0);
97 std::ofstream outfile(buf.get());
98 outfile.close();
99 return;
100 }
101
102 // We should "never" make it here. If we did it implies no primary processor
103 // was found. Once again, rely on systemd recovery if this happens
104 log<level::ERR>("No primary processor found in checkHostRunning");
105 throw std::runtime_error("No primary processor found in checkHostRunning");
106}
107
Andrew Geissleraa599152021-06-24 10:10:43 -0500108/**
109 * The BMC is to make a best effort to clear the CFAM register used by PHYP
110 * to indicate it is running when the host is stopped. This procedure will do
111 * that.
112 */
113void clearHostRunning()
114{
115 struct pdbg_target* procTarget;
116 log<level::INFO>("Entering clearHostRunning");
117
118 try
119 {
120 phal_init();
121 }
122 catch (std::exception& ex)
123 {
124 // This should "never" happen so just throw the exception and let
125 // our systemd error handling process this
126 log<level::ERR>("Exception raised during init PHAL",
127 entry("EXCEPTION=%s", ex.what()));
128 throw std::runtime_error("PHAL initialization failed");
129 }
130
131 pdbg_for_each_class_target("proc", procTarget)
132 {
133 // Only check the primary proc
134 if (!isPrimaryProc(procTarget))
135 {
136 continue;
137 }
138
139 constexpr uint32_t HOST_NOT_RUNNING_INDICATION = 0;
140 auto rc = putCFAM(procTarget, P10_SCRATCH_REG_12,
141 HOST_NOT_RUNNING_INDICATION);
142 if (rc != 0)
143 {
144 log<level::ERR>("CFAM write to clear host running status failed");
145 }
146
147 // It's best effort, so just return either way
148 return;
149 }
150 log<level::ERR>("No primary processor found in clearHostRunning");
151}
152
Andrew Geissler65c01012021-06-15 14:03:34 -0500153REGISTER_PROCEDURE("checkHostRunning", checkHostRunning)
Andrew Geissleraa599152021-06-24 10:10:43 -0500154REGISTER_PROCEDURE("clearHostRunning", clearHostRunning)
Andrew Geissler65c01012021-06-15 14:03:34 -0500155
156} // namespace phal
157} // namespace openpower