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 
25 #include <algorithm>
26 #include <iomanip>
27 #include <map>
28 #include <sstream>
29 #include <vector>
30 
31 namespace attn
32 {
33 
34 /**
35  * @brief Handle checkstop attention
36  *
37  * @param i_attention Attention object
38  * @return 0 indicates that the checkstop attention was successfully handled
39  *         1 indicates that the checkstop attention was NOT successfully
40  *           handled.
41  */
42 int handleCheckstop(Attention* i_attention);
43 
44 /**
45  * @brief Handle special attention
46  *
47  * @param i_attention Attention object
48  * @return 0 indicates that the special attention was successfully handled
49  *         1 indicates that the special attention was NOT successfully handled
50  */
51 int handleSpecial(Attention* i_attention);
52 
53 /** @brief Determine if attention is active and not masked */
54 bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn);
55 
56 #ifdef CONFIG_PHAL_API
57 /** @brief Handle phal sbe exception */
58 void phalSbeExceptionHandler(openpower::phal::exception::SbeError& e,
59                              uint32_t procNum);
60 #endif
61 
62 /** @brief Get static TI info data based on host state */
63 void getStaticTiInfo(uint8_t*& tiInfoPtr);
64 
65 /** @brief Check if TI info data is valid */
66 bool tiInfoValid(uint8_t* tiInfo);
67 
68 /**
69  * @brief The main attention handler logic
70  *
71  * @param i_breakpoints true = breakpoint special attn handling enabled
72  */
73 void attnHandler(Config* i_config)
74 {
75     // Vector of active attentions to be handled
76     std::vector<Attention> active_attentions;
77 
78     uint32_t isr_val, isr_mask;
79 
80     // loop through processors looking for active attentions
81     trace<level::INFO>("Attention handler started");
82 
83     pdbg_target* target;
84     pdbg_for_each_class_target("proc", target)
85     {
86         if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
87         {
88             auto proc = pdbg_target_index(target); // get processor number
89 
90             // Use PIB target to determine if a processor is enabled
91             char path[16];
92             sprintf(path, "/proc%d/pib", proc);
93             pdbg_target* pibTarget = pdbg_target_from_path(nullptr, path);
94 
95             // sanity check
96             if (nullptr == pibTarget)
97             {
98                 trace<level::INFO>("pib path or target not found");
99                 continue;
100             }
101 
102             // check if pib target is enabled
103             if (PDBG_TARGET_ENABLED == pdbg_target_probe(pibTarget))
104             {
105                 // The processor FSI target is required for CFAM read
106                 sprintf(path, "/proc%d/fsi", proc);
107                 pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path);
108 
109                 // sanity check
110                 if (nullptr == fsiTarget)
111                 {
112                     trace<level::INFO>("fsi path or target not found");
113                     continue;
114                 }
115 
116                 // trace the proc number
117                 std::string traceMsg = "proc: " + std::to_string(proc);
118                 trace<level::INFO>(traceMsg.c_str());
119 
120                 isr_val = 0xffffffff; // invalid isr value
121 
122                 // get active attentions on processor
123                 if (RC_SUCCESS != fsi_read(fsiTarget, 0x1007, &isr_val))
124                 {
125                     // log cfam read error
126                     trace<level::INFO>("Error! cfam read 0x1007 FAILED");
127                     eventAttentionFail((int)AttnSection::attnHandler |
128                                        ATTN_PDBG_CFAM);
129                 }
130                 else if (0xffffffff == isr_val)
131                 {
132                     trace<level::INFO>("Error! cfam read 0x1007 INVALID");
133                     continue;
134                 }
135                 else
136                 {
137                     // trace isr value
138                     std::stringstream ssIsr;
139                     ssIsr << "cfam 0x1007 = 0x" << std::setw(8)
140                           << std::setfill('0') << std::hex << isr_val;
141                     std::string strobjIsr = ssIsr.str();
142                     trace<level::INFO>(strobjIsr.c_str());
143 
144                     isr_mask = 0xffffffff; // invalid isr mask
145 
146                     // get interrupt enabled special attentions mask
147                     if (RC_SUCCESS != fsi_read(fsiTarget, 0x100d, &isr_mask))
148                     {
149                         // log cfam read error
150                         trace<level::INFO>("Error! cfam read 0x100d FAILED");
151                         eventAttentionFail((int)AttnSection::attnHandler |
152                                            ATTN_PDBG_CFAM);
153                     }
154                     else if (0xffffffff == isr_mask)
155                     {
156                         trace<level::INFO>("Error! cfam read 0x100d INVALID");
157                         continue;
158                     }
159                     else
160                     {
161                         // trace true mask
162                         std::stringstream ssMask;
163                         ssMask << "cfam 0x100d = 0x" << std::setw(8)
164                                << std::setfill('0') << std::hex << isr_mask;
165                         std::string strobjMask = ssMask.str();
166                         trace<level::INFO>(strobjMask.c_str());
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<level::INFO>("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<level::INFO>("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(dumpParameters);
253         if (0 == logid)
254         {
255             // A PEL should exist for a checkstop attention.
256             rc = RC_ANALYZER_ERROR;
257         }
258         else
259         {
260             requestDump(logid, dumpParameters);
261             util::dbus::transitionHost(util::dbus::HostState::Quiesce);
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  */
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<level::INFO>("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& e)
301             {
302                 // library threw an exception
303                 uint32_t procNum = pdbg_target_index(attnProc);
304                 phalSbeExceptionHandler(e, procNum);
305             }
306         }
307 #else
308         trace<level::INFO>("using libpdbg to get TI info");
309 
310         // pdbg library uses pib target for get ti info
311         char path[16];
312         sprintf(path, "/proc%d/pib", pdbg_target_index(attnProc));
313         pdbg_target* tiInfoTarget = pdbg_target_from_path(nullptr, path);
314 
315         if (nullptr != tiInfoTarget)
316         {
317             if (PDBG_TARGET_ENABLED == pdbg_target_probe(tiInfoTarget))
318             {
319                 sbe_mpipl_get_ti_info(tiInfoTarget, &tiInfo, &tiInfoLen);
320             }
321         }
322 #endif
323     }
324 
325     // dynamic TI info is not available
326     if (nullptr == tiInfo)
327     {
328         trace<level::INFO>("TI info data ptr is invalid");
329         getStaticTiInfo(tiInfo);
330         tiInfoStatic = true;
331     }
332 
333     // check TI info for validity and handle
334     if (true == tiInfoValid(tiInfo))
335     {
336         // TI info is valid handle TI if support enabled
337         if (true == (i_attention->getConfig()->getFlag(enTerminate)))
338         {
339             // Call TI special attention handler
340             rc = tiHandler((TiDataArea*)tiInfo);
341         }
342     }
343     else
344     {
345         trace<level::INFO>("TI info NOT valid");
346 
347         // if configured to handle TI as default special attention
348         if (i_attention->getConfig()->getFlag(dfltTi))
349         {
350             // TI handling may be disabled
351             if (true == (i_attention->getConfig()->getFlag(enTerminate)))
352             {
353                 // Call TI special attention handler
354                 rc = tiHandler((TiDataArea*)tiInfo);
355             }
356         }
357         // configured to handle breakpoint as default special attention
358         else
359         {
360             // breakpoint handling may be disabled
361             if (true == (i_attention->getConfig()->getFlag(enBreakpoints)))
362             {
363                 // Call the breakpoint special attention handler
364                 rc = bpHandler();
365             }
366         }
367     }
368 
369     // release TI data buffer if not ours
370     if (false == tiInfoStatic)
371     {
372         // sanity check
373         if (nullptr != tiInfo)
374         {
375             free(tiInfo);
376         }
377     }
378 
379     // trace non-successful exit condition
380     if (RC_SUCCESS != rc)
381     {
382         trace<level::INFO>("Special attn not handled");
383     }
384 
385     return rc;
386 }
387 
388 /**
389  * @brief Determine if attention is active and not masked
390  *
391  * Determine whether an attention needs to be handled and trace details of
392  * attention type and whether it is masked or not.
393  *
394  * @param i_val attention status register
395  * @param i_mask attention true mask register
396  * @param i_attn attention type
397  * @param i_proc processor associated with registers
398  *
399  * @return true if attention is active and not masked, otherwise false
400  */
401 bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn)
402 {
403     bool rc = false; // assume attn masked and/or inactive
404 
405     // if attention active
406     if (0 != (i_val & i_attn))
407     {
408         std::stringstream ss;
409 
410         bool validAttn = true; // known attention type
411 
412         switch (i_attn)
413         {
414             case SBE_ATTN:
415                 ss << "SBE attn";
416                 break;
417             case CHECKSTOP_ATTN:
418                 ss << "Checkstop attn";
419                 break;
420             case SPECIAL_ATTN:
421                 ss << "Special attn";
422                 break;
423             default:
424                 ss << "Unknown attn";
425                 validAttn = false;
426         }
427 
428         // see if attention is masked
429         if (true == validAttn)
430         {
431             if (0 != (i_mask & i_attn))
432             {
433                 rc = true; // attention active and not masked
434             }
435             else
436             {
437                 ss << " masked";
438             }
439         }
440 
441         std::string strobj = ss.str();      // ss.str() is temporary
442         trace<level::INFO>(strobj.c_str()); // commit trace stream
443     }
444 
445     return rc;
446 }
447 
448 #ifdef CONFIG_PHAL_API
449 /**
450  * @brief Handle phal sbe exception
451  *
452  * @param[in] e - exception object
453  * @param[in] procNum - processor number associated with sbe exception
454  */
455 void phalSbeExceptionHandler(openpower::phal::exception::SbeError& e,
456                              uint32_t procNum)
457 {
458     // trace exception details
459     std::string traceMsg = std::string(e.what());
460     trace<level::ERROR>(traceMsg.c_str());
461 
462     // Handle SBE chipop timeout error
463     if (e.errType() == openpower::phal::exception::SBE_CHIPOP_NOT_ALLOWED)
464     {
465         eventPhalSbeChipop(procNum);
466     }
467 }
468 #endif
469 
470 /**
471  * @brief Get static TI info data based on host state
472  *
473  * @param[out] tiInfo - pointer to static TI info data
474  */
475 void getStaticTiInfo(uint8_t*& tiInfo)
476 {
477     util::dbus::HostRunningState runningState = util::dbus::hostRunningState();
478 
479     // assume host state is unknown
480     std::string stateString = "host state unknown";
481 
482     if ((util::dbus::HostRunningState::Started == runningState) ||
483         (util::dbus::HostRunningState::Unknown == runningState))
484     {
485         if (util::dbus::HostRunningState::Started == runningState)
486         {
487             stateString = "host started";
488         }
489         tiInfo = (uint8_t*)defaultPhypTiInfo;
490     }
491     else
492     {
493         stateString = "host not started";
494         tiInfo      = (uint8_t*)defaultHbTiInfo;
495     }
496 
497     // trace host state
498     trace<level::INFO>(stateString.c_str());
499 }
500 
501 /**
502  * @brief Check if TI info data is valid
503  *
504  * @param[in] tiInfo - pointer to TI info data
505  * @return true if TI info data is valid, else false
506  */
507 bool tiInfoValid(uint8_t* tiInfo)
508 {
509     bool tiInfoValid = false; // assume TI info invalid
510 
511     // TI info data[0] non-zero indicates TI info valid (usually)
512     if ((nullptr != tiInfo) && (0 != tiInfo[0]))
513     {
514         TiDataArea* tiDataArea = (TiDataArea*)tiInfo;
515 
516         std::stringstream ss; // string stream object for tracing
517         std::string strobj;   // string object for tracing
518 
519         // trace a few known TI data area values
520         ss.str(std::string()); // empty the stream
521         ss.clear();            // clear the stream
522         ss << "TI data command = 0x" << std::setw(2) << std::setfill('0')
523            << std::hex << (int)tiDataArea->command;
524         strobj = ss.str();
525         trace<level::INFO>(strobj.c_str());
526 
527         // Another check for valid TI Info since it has been seen that
528         // tiInfo[0] != 0 but TI info is not valid
529         if (0xa1 == tiDataArea->command)
530         {
531             tiInfoValid = true;
532 
533             // trace some more data since TI info appears valid
534             ss.str(std::string()); // empty the stream
535             ss.clear();            // clear the stream
536             ss << "TI data term-type = 0x" << std::setw(2) << std::setfill('0')
537                << std::hex << (int)tiDataArea->hbTerminateType;
538             strobj = ss.str();
539             trace<level::INFO>(strobj.c_str());
540 
541             ss.str(std::string()); // empty the stream
542             ss.clear();            // clear the stream
543             ss << "TI data SRC format = 0x" << std::setw(2) << std::setfill('0')
544                << std::hex << (int)tiDataArea->srcFormat;
545             strobj = ss.str();
546             trace<level::INFO>(strobj.c_str());
547 
548             ss.str(std::string()); // empty the stream
549             ss.clear();            // clear the stream
550             ss << "TI data source = 0x" << std::setw(2) << std::setfill('0')
551                << std::hex << (int)tiDataArea->source;
552             strobj = ss.str();
553             trace<level::INFO>(strobj.c_str());
554         }
555     }
556 
557     return tiInfoValid;
558 }
559 
560 } // namespace attn
561