1 /** 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 19 extern "C" 20 { 21 #include <libpdbg.h> 22 #include <libpdbg_sbe.h> 23 } 24 25 #include "extensions/phal/create_pel.hpp" 26 #include "extensions/phal/dump_utils.hpp" 27 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 40 namespace openpower 41 { 42 namespace misc 43 { 44 45 /** 46 * @brief Calls sbe_enter_mpipl on the SBE in the provided target. 47 * @return void 48 */ 49 void 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 { 63 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 74 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)); 104 auto logId = createSbeErrorPEL(event, sbeError, pelAdditionalData); 105 106 if (dumpIsRequired) 107 { 108 // Request SBE Dump 109 using namespace openpower::phal::dump; 110 DumpParameters dumpParameters = {logId, index, SBE_DUMP_TIMEOUT, 111 DumpType::SBE}; 112 requestDump(dumpParameters); 113 } 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 */ 137 void 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 193 REGISTER_PROCEDURE("enterMpReboot", enterMpReboot) 194 195 } // namespace misc 196 } // namespace openpower 197