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