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