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