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