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