blob: aa7365ec380a94f9c75d26a303695835f51ce4b3 [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"
26
27#include <attributes_info.H>
28#include <fmt/format.h>
29#include <libphal.H>
30#include <phal_exception.H>
31#include <sys/wait.h>
32#include <unistd.h>
33
34#include <phosphor-logging/log.hpp>
35
36#include <system_error>
37#include <vector>
38
39namespace openpower
40{
41namespace misc
42{
43
44/**
45 * @brief Calls sbe_enter_mpipl on the SBE in the provided target.
46 * @return void
47 */
48void sbeEnterMpReboot(struct pdbg_target* tgt)
49{
50 using namespace openpower::pel;
51 using namespace openpower::phal;
52 using namespace openpower::phal::sbe;
53 using namespace openpower::phal::exception;
54 using namespace phosphor::logging;
55
56 try
57 {
58 mpiplEnter(tgt);
59 }
60 catch (const sbeError_t& sbeError)
61 {
62 log<level::ERR>(fmt::format("EnterMPIPL failed({}) on proc({})",
63 sbeError.what(), pdbg_target_index(tgt))
64 .c_str());
65
66 std::string event;
67 bool dumpIsRequired = false;
68
69 if (sbeError.errType() == SBE_CMD_TIMEOUT)
70 {
71 event = "org.open_power.Processor.Error.SbeChipOpTimeout";
72 dumpIsRequired = true;
73 }
74 else
75 {
76 event = "org.open_power.Processor.Error.SbeChipOpFailure";
77 }
78
79 // SRC6 : [0:15] chip position [16:23] command class, [24:31] Type
80 uint32_t index = pdbg_target_index(tgt);
81
82 // TODO Replace these consts with pdbg defines once it is exported.
83 // Ref : pdbg/libsbefifo/sbefifo_private.h
84 constexpr auto SBEFIFO_CMD_CLASS_MPIPL = 0xA900;
85 constexpr auto SBEFIFO_CMD_ENTER_MPIPL = 0x01;
86 uint32_t cmd = SBEFIFO_CMD_CLASS_MPIPL | SBEFIFO_CMD_ENTER_MPIPL;
87
88 // To store additional data about ffdc.
89 FFDCData pelAdditionalData;
90 pelAdditionalData.emplace_back("SRC6",
91 std::to_string((index << 16) | cmd));
92 createSbeErrorPEL(event, sbeError, pelAdditionalData);
93
94 if (dumpIsRequired)
95 {
96 // TODO Request SBE Dump
97 }
98 throw;
99 }
100 // Capture genaral libphal error
101 catch (const phalError_t& phalError)
102 {
103 // Failure reported
104 log<level::ERR>(fmt::format("captureFFDC: Exception({}) on proc({})",
105 phalError.what(), pdbg_target_index(tgt))
106 .c_str());
107 openpower::pel::createPEL(
108 "org.open_power.Processor.Error.SbeChipOpFailure");
109 throw;
110 }
111
112 log<level::INFO>(
113 fmt::format("Enter MPIPL completed on proc({})", pdbg_target_index(tgt))
114 .c_str());
115}
116
117/**
118 * @brief initiate memory preserving reboot on each SBE.
119 * @return void
120 */
121void enterMpReboot()
122{
123 using namespace phosphor::logging;
124 struct pdbg_target* target;
125 std::vector<pid_t> pidList;
126 bool failed = false;
127 pdbg_targets_init(NULL);
128 ATTR_HWAS_STATE_Type hwasState;
129
130 log<level::INFO>("Starting memory preserving reboot");
131 pdbg_for_each_class_target("proc", target)
132 {
133 if (DT_GET_PROP(ATTR_HWAS_STATE, target, hwasState))
134 {
135 log<level::ERR>("Could not read HWAS_STATE attribute");
136 }
137 if (!hwasState.functional)
138 {
139 continue;
140 }
141
142 pid_t pid = fork();
143
144 if (pid < 0)
145 {
146 log<level::ERR>("Fork failed while starting mp reboot");
147 failed = true;
148 }
149 else if (pid == 0)
150 {
151 sbeEnterMpReboot(target);
152 std::exit(EXIT_SUCCESS);
153 }
154 else
155 {
156 pidList.push_back(std::move(pid));
157 }
158 }
159
160 for (auto& p : pidList)
161 {
162 int status = 0;
163 waitpid(p, &status, 0);
164 if (WEXITSTATUS(status))
165 {
166 log<level::ERR>("Memory preserving reboot failed");
167 failed = true;
168 }
169 }
170
171 if (failed)
172 {
173 std::exit(EXIT_FAILURE);
174 }
175}
176
177REGISTER_PROCEDURE("enterMpReboot", enterMpReboot)
178
179} // namespace misc
180} // namespace openpower