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 */
attnHandler(Config * i_config)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(
133 (int)AttnSection::attnHandler | 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(
153 (int)AttnSection::attnHandler | 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 */
handleCheckstop(Attention * i_attention)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 */
handleSpecial(Attention * i_attention)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 */
activeAttn(uint32_t i_val,uint32_t i_mask,uint32_t i_attn)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 */
phalSbeExceptionHandler(openpower::phal::exception::SbeError & sbeError,uint32_t chipPosition,uint32_t command)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 */
getStaticTiInfo(uint8_t * & tiInfo)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 */
tiInfoValid(uint8_t * tiInfo)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 */
clearAttnInterrupts()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