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((int)AttnSection::attnHandler |
133                                        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((int)AttnSection::attnHandler |
153                                            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