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