1 extern "C" 2 { 3 #include <libpdbg.h> 4 #include <libpdbg_sbe.h> 5 } 6 7 #include <config.h> 8 9 #ifdef CONFIG_PHAL_API 10 #include <libphal.H> 11 #endif 12 13 #include <analyzer/analyzer_main.hpp> 14 #include <attn/attention.hpp> 15 #include <attn/attn_common.hpp> 16 #include <attn/attn_config.hpp> 17 #include <attn/attn_dbus.hpp> 18 #include <attn/attn_handler.hpp> 19 #include <attn/attn_logging.hpp> 20 #include <attn/bp_handler.hpp> 21 #include <attn/ti_handler.hpp> 22 #include <attn/vital_handler.hpp> 23 #include <util/dbus.hpp> 24 #include <util/ffdc_file.hpp> 25 #include <util/trace.hpp> 26 27 #include <algorithm> 28 #include <iomanip> 29 #include <map> 30 #include <sstream> 31 #include <vector> 32 33 namespace attn 34 { 35 36 /** 37 * @brief Handle checkstop attention 38 * 39 * @param i_attention Attention object 40 * @return 0 indicates that the checkstop attention was successfully handled 41 * 1 indicates that the checkstop attention was NOT successfully 42 * handled. 43 */ 44 int handleCheckstop(Attention* i_attention); 45 46 /** 47 * @brief Handle special attention 48 * 49 * @param i_attention Attention object 50 * @return 0 indicates that the special attention was successfully handled 51 * 1 indicates that the special attention was NOT successfully handled 52 */ 53 int handleSpecial(Attention* i_attention); 54 55 /** @brief Determine if attention is active and not masked */ 56 bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn); 57 58 #ifdef CONFIG_PHAL_API 59 /** @brief Handle phal sbe exception */ 60 void phalSbeExceptionHandler(openpower::phal::exception::SbeError& e, 61 uint32_t chipPosition, uint32_t command); 62 #endif 63 64 /** @brief Get static TI info data based on host state */ 65 void getStaticTiInfo(uint8_t*& tiInfoPtr); 66 67 /** @brief Check if TI info data is valid */ 68 bool tiInfoValid(uint8_t* tiInfo); 69 70 /** 71 * @brief The main attention handler logic 72 * 73 * @param i_breakpoints true = breakpoint special attn handling enabled 74 */ 75 void attnHandler(Config* i_config) 76 { 77 // Vector of active attentions to be handled 78 std::vector<Attention> active_attentions; 79 80 uint32_t isr_val, isr_mask; 81 82 // loop through processors looking for active attentions 83 trace::inf("Attention handler started"); 84 85 pdbg_target* target; 86 pdbg_for_each_class_target("proc", target) 87 { 88 if (PDBG_TARGET_ENABLED == pdbg_target_probe(target)) 89 { 90 auto proc = pdbg_target_index(target); // get processor number 91 92 // Use PIB target to determine if a processor is enabled 93 char path[16]; 94 sprintf(path, "/proc%d/pib", proc); 95 pdbg_target* pibTarget = pdbg_target_from_path(nullptr, path); 96 97 // sanity check 98 if (nullptr == pibTarget) 99 { 100 trace::inf("pib path or target not found"); 101 continue; 102 } 103 104 // check if pib target is enabled 105 if (PDBG_TARGET_ENABLED == pdbg_target_probe(pibTarget)) 106 { 107 // The processor FSI target is required for CFAM read 108 sprintf(path, "/proc%d/fsi", proc); 109 pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path); 110 111 // sanity check 112 if (nullptr == fsiTarget) 113 { 114 trace::inf("fsi path or target not found"); 115 continue; 116 } 117 118 // trace the proc number 119 trace::inf("proc: %u", proc); 120 121 isr_val = 0xffffffff; // invalid isr value 122 123 // get active attentions on processor 124 if (RC_SUCCESS != fsi_read(fsiTarget, 0x1007, &isr_val)) 125 { 126 // log cfam read error 127 trace::err("cfam read 0x1007 FAILED"); 128 eventAttentionFail((int)AttnSection::attnHandler | 129 ATTN_PDBG_CFAM); 130 } 131 else if (0xffffffff == isr_val) 132 { 133 trace::err("cfam read 0x1007 INVALID"); 134 continue; 135 } 136 else 137 { 138 // trace isr value 139 trace::inf("cfam 0x1007 = 0x%08x", isr_val); 140 141 isr_mask = 0xffffffff; // invalid isr mask 142 143 // get interrupt enabled special attentions mask 144 if (RC_SUCCESS != fsi_read(fsiTarget, 0x100d, &isr_mask)) 145 { 146 // log cfam read error 147 trace::err("cfam read 0x100d FAILED"); 148 eventAttentionFail((int)AttnSection::attnHandler | 149 ATTN_PDBG_CFAM); 150 } 151 else if (0xffffffff == isr_mask) 152 { 153 trace::err("cfam read 0x100d INVALID"); 154 continue; 155 } 156 else 157 { 158 // trace true mask 159 trace::inf("cfam 0x100d = 0x%08x", isr_mask); 160 161 // SBE vital attention active and not masked? 162 if (true == activeAttn(isr_val, isr_mask, SBE_ATTN)) 163 { 164 active_attentions.emplace_back(Attention::Vital, 165 handleVital, target, 166 i_config); 167 } 168 169 // Checkstop attention active and not masked? 170 if (true == 171 activeAttn(isr_val, isr_mask, CHECKSTOP_ATTN)) 172 { 173 active_attentions.emplace_back(Attention::Checkstop, 174 handleCheckstop, 175 target, i_config); 176 } 177 178 // Special attention active and not masked? 179 if (true == activeAttn(isr_val, isr_mask, SPECIAL_ATTN)) 180 { 181 active_attentions.emplace_back(Attention::Special, 182 handleSpecial, 183 target, i_config); 184 } 185 } // cfam 0x100d valid 186 } // cfam 0x1007 valid 187 } // fsi target enabled 188 } // pib target enabled 189 } // next processor 190 191 // convert to heap, highest priority is at front 192 if (!std::is_heap(active_attentions.begin(), active_attentions.end())) 193 { 194 std::make_heap(active_attentions.begin(), active_attentions.end()); 195 } 196 197 // call the attention handler until one is handled or all were attempted 198 while (false == active_attentions.empty()) 199 { 200 // handle highest priority attention, done if successful 201 if (RC_SUCCESS == active_attentions.front().handle()) 202 { 203 // an attention was handled so we are done 204 break; 205 } 206 207 // move attention to back of vector 208 std::pop_heap(active_attentions.begin(), active_attentions.end()); 209 210 // remove attention from vector 211 active_attentions.pop_back(); 212 } 213 } 214 215 /** 216 * @brief Handle checkstop attention 217 * 218 * @param i_attention Attention object 219 * @return 0 indicates that the checkstop attention was successfully handled 220 * 1 indicates that the checkstop attention was NOT successfully 221 * handled. 222 */ 223 int handleCheckstop(Attention* i_attention) 224 { 225 int rc = RC_SUCCESS; // assume checkstop handled 226 227 trace::inf("checkstop handler started"); 228 229 // capture some additional data for logs/traces 230 addHbStatusRegs(); 231 232 // if checkstop handling enabled, handle checkstop attention 233 if (false == (i_attention->getConfig()->getFlag(enCheckstop))) 234 { 235 trace::inf("Checkstop handling disabled"); 236 } 237 else 238 { 239 // wait for power fault handling before starting analyses 240 sleepSeconds(POWER_FAULT_WAIT); 241 242 // Look for any attentions found in hardware. This will generate and 243 // commit a PEL if any errors are found. 244 DumpParameters dumpParameters; 245 auto logid = analyzer::analyzeHardware( 246 analyzer::AnalysisType::SYSTEM_CHECKSTOP, dumpParameters); 247 if (0 == logid) 248 { 249 // A PEL should exist for a checkstop attention. 250 rc = RC_ANALYZER_ERROR; 251 } 252 else 253 { 254 requestDump(logid, dumpParameters); 255 util::dbus::transitionHost(util::dbus::HostState::Quiesce); 256 } 257 } 258 259 return rc; 260 } 261 262 /** 263 * @brief Handle special attention 264 * 265 * @param i_attention Attention object 266 * @return 0 indicates that the special attention was successfully handled 267 * 1 indicates that the special attention was NOT successfully handled 268 */ 269 int handleSpecial(Attention* i_attention) 270 { 271 int rc = RC_SUCCESS; // assume special attention handled 272 273 // The TI info chipop will give us a pointer to the TI info data 274 uint8_t* tiInfo = nullptr; // ptr to TI info data 275 uint32_t tiInfoLen = 0; // length of TI info data 276 pdbg_target* attnProc = i_attention->getTarget(); // proc with attention 277 278 bool tiInfoStatic = false; // assume TI info was provided (not created) 279 280 // need proc target to get dynamic TI info 281 if (nullptr != attnProc) 282 { 283 #ifdef CONFIG_PHAL_API 284 trace::inf("using libphal to get TI info"); 285 286 // phal library uses proc target for get ti info 287 if (PDBG_TARGET_ENABLED == pdbg_target_probe(attnProc)) 288 { 289 try 290 { 291 // get dynamic TI info 292 openpower::phal::sbe::getTiInfo(attnProc, &tiInfo, &tiInfoLen); 293 } 294 catch (openpower::phal::exception::SbeError& sbeError) 295 { 296 // library threw an exception 297 // note: phal::sbe::getTiInfo = command class | command == 298 // 0xa900 | 0x04 = 0xa904. The sbe fifo command class and 299 // commands are defined in the sbefifo library source code but 300 // do not seem to be exported/installed for consumption 301 // externally. 302 uint32_t procNum = pdbg_target_index(attnProc); 303 phalSbeExceptionHandler(sbeError, procNum, 0xa904); 304 } 305 } 306 #else 307 trace::inf("using libpdbg to get TI info"); 308 309 // pdbg library uses pib target for get ti info 310 char path[16]; 311 sprintf(path, "/proc%d/pib", pdbg_target_index(attnProc)); 312 pdbg_target* tiInfoTarget = pdbg_target_from_path(nullptr, path); 313 314 if (nullptr != tiInfoTarget) 315 { 316 if (PDBG_TARGET_ENABLED == pdbg_target_probe(tiInfoTarget)) 317 { 318 sbe_mpipl_get_ti_info(tiInfoTarget, &tiInfo, &tiInfoLen); 319 } 320 } 321 #endif 322 } 323 324 // dynamic TI info is not available 325 if (nullptr == tiInfo) 326 { 327 trace::inf("TI info data ptr is invalid"); 328 getStaticTiInfo(tiInfo); 329 tiInfoStatic = true; 330 } 331 332 // check TI info for validity and handle 333 if (true == tiInfoValid(tiInfo)) 334 { 335 // TI info is valid handle TI if support enabled 336 if (true == (i_attention->getConfig()->getFlag(enTerminate))) 337 { 338 // Call TI special attention handler 339 rc = tiHandler((TiDataArea*)tiInfo); 340 } 341 } 342 else 343 { 344 trace::inf("TI info NOT valid"); 345 346 // if configured to handle TI as default special attention 347 if (i_attention->getConfig()->getFlag(dfltTi)) 348 { 349 // TI handling may be disabled 350 if (true == (i_attention->getConfig()->getFlag(enTerminate))) 351 { 352 // Call TI special attention handler 353 rc = tiHandler((TiDataArea*)tiInfo); 354 } 355 } 356 // configured to handle breakpoint as default special attention 357 else 358 { 359 // breakpoint handling may be disabled 360 if (true == (i_attention->getConfig()->getFlag(enBreakpoints))) 361 { 362 // Call the breakpoint special attention handler 363 rc = bpHandler(); 364 } 365 } 366 } 367 368 // release TI data buffer if not ours 369 if (false == tiInfoStatic) 370 { 371 // sanity check 372 if (nullptr != tiInfo) 373 { 374 free(tiInfo); 375 } 376 } 377 378 // trace non-successful exit condition 379 if (RC_SUCCESS != rc) 380 { 381 trace::inf("Special attn not handled"); 382 } 383 384 return rc; 385 } 386 387 /** 388 * @brief Determine if attention is active and not masked 389 * 390 * Determine whether an attention needs to be handled and trace details of 391 * attention type and whether it is masked or not. 392 * 393 * @param i_val attention status register 394 * @param i_mask attention true mask register 395 * @param i_attn attention type 396 * @param i_proc processor associated with registers 397 * 398 * @return true if attention is active and not masked, otherwise false 399 */ 400 bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn) 401 { 402 bool rc = false; // assume attn masked and/or inactive 403 404 // if attention active 405 if (0 != (i_val & i_attn)) 406 { 407 std::string msg; 408 409 bool validAttn = true; // known attention type 410 411 switch (i_attn) 412 { 413 case SBE_ATTN: 414 msg = "SBE attn"; 415 break; 416 case CHECKSTOP_ATTN: 417 msg = "Checkstop attn"; 418 break; 419 case SPECIAL_ATTN: 420 msg = "Special attn"; 421 break; 422 default: 423 msg = "Unknown attn"; 424 validAttn = false; 425 } 426 427 // see if attention is masked 428 if (true == validAttn) 429 { 430 if (0 != (i_mask & i_attn)) 431 { 432 rc = true; // attention active and not masked 433 } 434 else 435 { 436 msg += " masked"; 437 } 438 } 439 440 trace::inf(msg.c_str()); // commit trace stream 441 } 442 443 return rc; 444 } 445 446 #ifdef CONFIG_PHAL_API 447 448 /** 449 * @brief Handle phal sbe exception 450 * 451 * @param[in] e - exception object 452 * @param[in] procNum - processor number associated with sbe exception 453 */ 454 void phalSbeExceptionHandler(openpower::phal::exception::SbeError& sbeError, 455 uint32_t chipPosition, uint32_t command) 456 { 457 trace::err("Attention handler phal exception handler"); 458 459 // Trace exception details 460 trace::err(sbeError.what()); 461 462 // Create event log entry with SBE FFDC data if provided 463 auto fd = sbeError.getFd(); 464 if (fd > 0) 465 { 466 trace::err("SBE FFDC data is available"); 467 468 // FFDC parser expects chip position and command (command class | 469 // command) to be in the additional data. 470 std::map<std::string, std::string> additionalData = { 471 {"SRC6", std::to_string((chipPosition << 16) | command)}}; 472 473 // See phosphor-logging/extensions/openpower-pels/README.md, "Self Boot 474 // Engine(SBE) First Failure Data Capture(FFDC)" - SBE FFDC file type 475 // is 0xCB, version is 0x01. 476 std::vector<util::FFDCTuple> ffdc{util::FFDCTuple{ 477 util::FFDCFormat::Custom, static_cast<uint8_t>(0xCB), 478 static_cast<uint8_t>(0x01), fd}}; 479 480 // Create event log entry with FFDC data 481 util::dbus::createPel("org.open_power.Processor.Error.SbeChipOpFailure", 482 levelPelError, additionalData, ffdc); 483 } 484 } 485 #endif 486 487 /** 488 * @brief Get static TI info data based on host state 489 * 490 * @param[out] tiInfo - pointer to static TI info data 491 */ 492 void getStaticTiInfo(uint8_t*& tiInfo) 493 { 494 util::dbus::HostRunningState runningState = util::dbus::hostRunningState(); 495 496 // assume host state is unknown 497 std::string stateString = "host state unknown"; 498 499 if ((util::dbus::HostRunningState::Started == runningState) || 500 (util::dbus::HostRunningState::Unknown == runningState)) 501 { 502 if (util::dbus::HostRunningState::Started == runningState) 503 { 504 stateString = "host started"; 505 } 506 tiInfo = (uint8_t*)defaultPhypTiInfo; 507 } 508 else 509 { 510 stateString = "host not started"; 511 tiInfo = (uint8_t*)defaultHbTiInfo; 512 } 513 514 // trace host state 515 trace::inf(stateString.c_str()); 516 } 517 518 /** 519 * @brief Check if TI info data is valid 520 * 521 * @param[in] tiInfo - pointer to TI info data 522 * @return true if TI info data is valid, else false 523 */ 524 bool tiInfoValid(uint8_t* tiInfo) 525 { 526 bool tiInfoValid = false; // assume TI info invalid 527 528 // TI info data[0] non-zero indicates TI info valid (usually) 529 if ((nullptr != tiInfo) && (0 != tiInfo[0])) 530 { 531 TiDataArea* tiDataArea = (TiDataArea*)tiInfo; 532 533 // trace a few known TI data area values 534 trace::inf("TI data command = 0x%02x", tiDataArea->command); 535 536 // Another check for valid TI Info since it has been seen that 537 // tiInfo[0] != 0 but TI info is not valid 538 if (0xa1 == tiDataArea->command) 539 { 540 tiInfoValid = true; 541 542 // trace some more data since TI info appears valid 543 trace::inf("TI data term-type = 0x%02x", 544 tiDataArea->hbTerminateType); 545 546 trace::inf("TI data SRC format = 0x%02x", tiDataArea->srcFormat); 547 548 trace::inf("TI data source = 0x%02x", tiDataArea->source); 549 } 550 } 551 552 return tiInfoValid; 553 } 554 555 } // namespace attn 556