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