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 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 39 namespace openpower 40 { 41 namespace misc 42 { 43 44 /** 45 * @brief Calls sbe_enter_mpipl on the SBE in the provided target. 46 * @return void 47 */ 48 void 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 */ 121 void 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 177 REGISTER_PROCEDURE("enterMpReboot", enterMpReboot) 178 179 } // namespace misc 180 } // namespace openpower 181