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