blob: f71144f0eb7803ca15e2a73c366f8d857b03f1f7 [file] [log] [blame]
Jayanth Othayothdb8d46c2021-10-09 02:19:57 -05001/**
2 * Copyright (C) 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "registration.hpp"
18
19extern "C"
20{
21#include <libpdbg.h>
22#include <libpdbg_sbe.h>
23}
24
25#include "extensions/phal/create_pel.hpp"
Jayanth Othayoth6aba83d2021-10-09 03:04:48 -050026#include "extensions/phal/dump_utils.hpp"
Jayanth Othayothdb8d46c2021-10-09 02:19:57 -050027
28#include <attributes_info.H>
29#include <fmt/format.h>
30#include <libphal.H>
31#include <phal_exception.H>
32#include <sys/wait.h>
33#include <unistd.h>
34
35#include <phosphor-logging/log.hpp>
36
37#include <system_error>
38#include <vector>
39
40namespace openpower
41{
42namespace misc
43{
44
45/**
46 * @brief Calls sbe_enter_mpipl on the SBE in the provided target.
47 * @return void
48 */
49void sbeEnterMpReboot(struct pdbg_target* tgt)
50{
51 using namespace openpower::pel;
52 using namespace openpower::phal;
53 using namespace openpower::phal::sbe;
54 using namespace openpower::phal::exception;
55 using namespace phosphor::logging;
56
57 try
58 {
59 mpiplEnter(tgt);
60 }
61 catch (const sbeError_t& sbeError)
62 {
Jayanth Othayoth62638202021-10-13 02:40:15 -050063 if (sbeError.errType() == SBE_CHIPOP_NOT_ALLOWED)
64 {
65 // SBE is not ready to accept chip-ops,
66 // Skip the request, no additional error handling required.
67 log<level::INFO>(
68 fmt::format("EnterMPIPL: Skipping ({}) on proc({})",
69 sbeError.what(), pdbg_target_index(tgt))
70 .c_str());
71 return;
72 }
73
Jayanth Othayothdb8d46c2021-10-09 02:19:57 -050074 log<level::ERR>(fmt::format("EnterMPIPL failed({}) on proc({})",
75 sbeError.what(), pdbg_target_index(tgt))
76 .c_str());
77
78 std::string event;
79 bool dumpIsRequired = false;
80
81 if (sbeError.errType() == SBE_CMD_TIMEOUT)
82 {
83 event = "org.open_power.Processor.Error.SbeChipOpTimeout";
84 dumpIsRequired = true;
85 }
86 else
87 {
88 event = "org.open_power.Processor.Error.SbeChipOpFailure";
89 }
90
91 // SRC6 : [0:15] chip position [16:23] command class, [24:31] Type
92 uint32_t index = pdbg_target_index(tgt);
93
94 // TODO Replace these consts with pdbg defines once it is exported.
95 // Ref : pdbg/libsbefifo/sbefifo_private.h
96 constexpr auto SBEFIFO_CMD_CLASS_MPIPL = 0xA900;
97 constexpr auto SBEFIFO_CMD_ENTER_MPIPL = 0x01;
98 uint32_t cmd = SBEFIFO_CMD_CLASS_MPIPL | SBEFIFO_CMD_ENTER_MPIPL;
99
100 // To store additional data about ffdc.
101 FFDCData pelAdditionalData;
102 pelAdditionalData.emplace_back("SRC6",
103 std::to_string((index << 16) | cmd));
Jayanth Othayoth6aba83d2021-10-09 03:04:48 -0500104 auto logId = createSbeErrorPEL(event, sbeError, pelAdditionalData);
Jayanth Othayothdb8d46c2021-10-09 02:19:57 -0500105
106 if (dumpIsRequired)
107 {
Jayanth Othayoth6aba83d2021-10-09 03:04:48 -0500108 // Request SBE Dump
109 using namespace openpower::phal::dump;
110 DumpParameters dumpParameters = {logId, index, SBE_DUMP_TIMEOUT,
111 DumpType::SBE};
112 requestDump(dumpParameters);
Jayanth Othayothdb8d46c2021-10-09 02:19:57 -0500113 }
114 throw;
115 }
116 // Capture genaral libphal error
117 catch (const phalError_t& phalError)
118 {
119 // Failure reported
120 log<level::ERR>(fmt::format("captureFFDC: Exception({}) on proc({})",
121 phalError.what(), pdbg_target_index(tgt))
122 .c_str());
123 openpower::pel::createPEL(
124 "org.open_power.Processor.Error.SbeChipOpFailure");
125 throw;
126 }
127
128 log<level::INFO>(
129 fmt::format("Enter MPIPL completed on proc({})", pdbg_target_index(tgt))
130 .c_str());
131}
132
133/**
134 * @brief initiate memory preserving reboot on each SBE.
135 * @return void
136 */
137void enterMpReboot()
138{
139 using namespace phosphor::logging;
140 struct pdbg_target* target;
141 std::vector<pid_t> pidList;
142 bool failed = false;
143 pdbg_targets_init(NULL);
144 ATTR_HWAS_STATE_Type hwasState;
145
146 log<level::INFO>("Starting memory preserving reboot");
147 pdbg_for_each_class_target("proc", target)
148 {
149 if (DT_GET_PROP(ATTR_HWAS_STATE, target, hwasState))
150 {
151 log<level::ERR>("Could not read HWAS_STATE attribute");
152 }
153 if (!hwasState.functional)
154 {
155 continue;
156 }
157
158 pid_t pid = fork();
159
160 if (pid < 0)
161 {
162 log<level::ERR>("Fork failed while starting mp reboot");
163 failed = true;
164 }
165 else if (pid == 0)
166 {
167 sbeEnterMpReboot(target);
168 std::exit(EXIT_SUCCESS);
169 }
170 else
171 {
172 pidList.push_back(std::move(pid));
173 }
174 }
175
176 for (auto& p : pidList)
177 {
178 int status = 0;
179 waitpid(p, &status, 0);
180 if (WEXITSTATUS(status))
181 {
182 log<level::ERR>("Memory preserving reboot failed");
183 failed = true;
184 }
185 }
186
187 if (failed)
188 {
189 std::exit(EXIT_FAILURE);
190 }
191}
192
193REGISTER_PROCEDURE("enterMpReboot", enterMpReboot)
194
195} // namespace misc
196} // namespace openpower