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(
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<level::INFO>("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& e)
302             {
303                 // library threw an exception
304                 uint32_t procNum = pdbg_target_index(attnProc);
305                 phalSbeExceptionHandler(e, procNum);
306             }
307         }
308 #else
309         trace<level::INFO>("using libpdbg to get TI info");
310 
311         // pdbg library uses pib target for get ti info
312         char path[16];
313         sprintf(path, "/proc%d/pib", pdbg_target_index(attnProc));
314         pdbg_target* tiInfoTarget = pdbg_target_from_path(nullptr, path);
315 
316         if (nullptr != tiInfoTarget)
317         {
318             if (PDBG_TARGET_ENABLED == pdbg_target_probe(tiInfoTarget))
319             {
320                 sbe_mpipl_get_ti_info(tiInfoTarget, &tiInfo, &tiInfoLen);
321             }
322         }
323 #endif
324     }
325 
326     // dynamic TI info is not available
327     if (nullptr == tiInfo)
328     {
329         trace<level::INFO>("TI info data ptr is invalid");
330         getStaticTiInfo(tiInfo);
331         tiInfoStatic = true;
332     }
333 
334     // check TI info for validity and handle
335     if (true == tiInfoValid(tiInfo))
336     {
337         // TI info is valid handle TI if support enabled
338         if (true == (i_attention->getConfig()->getFlag(enTerminate)))
339         {
340             // Call TI special attention handler
341             rc = tiHandler((TiDataArea*)tiInfo);
342         }
343     }
344     else
345     {
346         trace<level::INFO>("TI info NOT valid");
347 
348         // if configured to handle TI as default special attention
349         if (i_attention->getConfig()->getFlag(dfltTi))
350         {
351             // TI handling may be disabled
352             if (true == (i_attention->getConfig()->getFlag(enTerminate)))
353             {
354                 // Call TI special attention handler
355                 rc = tiHandler((TiDataArea*)tiInfo);
356             }
357         }
358         // configured to handle breakpoint as default special attention
359         else
360         {
361             // breakpoint handling may be disabled
362             if (true == (i_attention->getConfig()->getFlag(enBreakpoints)))
363             {
364                 // Call the breakpoint special attention handler
365                 rc = bpHandler();
366             }
367         }
368     }
369 
370     // release TI data buffer if not ours
371     if (false == tiInfoStatic)
372     {
373         // sanity check
374         if (nullptr != tiInfo)
375         {
376             free(tiInfo);
377         }
378     }
379 
380     // trace non-successful exit condition
381     if (RC_SUCCESS != rc)
382     {
383         trace<level::INFO>("Special attn not handled");
384     }
385 
386     return rc;
387 }
388 
389 /**
390  * @brief Determine if attention is active and not masked
391  *
392  * Determine whether an attention needs to be handled and trace details of
393  * attention type and whether it is masked or not.
394  *
395  * @param i_val attention status register
396  * @param i_mask attention true mask register
397  * @param i_attn attention type
398  * @param i_proc processor associated with registers
399  *
400  * @return true if attention is active and not masked, otherwise false
401  */
402 bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn)
403 {
404     bool rc = false; // assume attn masked and/or inactive
405 
406     // if attention active
407     if (0 != (i_val & i_attn))
408     {
409         std::stringstream ss;
410 
411         bool validAttn = true; // known attention type
412 
413         switch (i_attn)
414         {
415             case SBE_ATTN:
416                 ss << "SBE attn";
417                 break;
418             case CHECKSTOP_ATTN:
419                 ss << "Checkstop attn";
420                 break;
421             case SPECIAL_ATTN:
422                 ss << "Special attn";
423                 break;
424             default:
425                 ss << "Unknown attn";
426                 validAttn = false;
427         }
428 
429         // see if attention is masked
430         if (true == validAttn)
431         {
432             if (0 != (i_mask & i_attn))
433             {
434                 rc = true; // attention active and not masked
435             }
436             else
437             {
438                 ss << " masked";
439             }
440         }
441 
442         std::string strobj = ss.str();      // ss.str() is temporary
443         trace<level::INFO>(strobj.c_str()); // commit trace stream
444     }
445 
446     return rc;
447 }
448 
449 #ifdef CONFIG_PHAL_API
450 /**
451  * @brief Handle phal sbe exception
452  *
453  * @param[in] e - exception object
454  * @param[in] procNum - processor number associated with sbe exception
455  */
456 void phalSbeExceptionHandler(openpower::phal::exception::SbeError& e,
457                              uint32_t procNum)
458 {
459     // trace exception details
460     std::string traceMsg = std::string(e.what());
461     trace<level::ERROR>(traceMsg.c_str());
462 
463     // Handle SBE chipop timeout error
464     if (e.errType() == openpower::phal::exception::SBE_CHIPOP_NOT_ALLOWED)
465     {
466         eventPhalSbeChipop(procNum);
467     }
468 }
469 #endif
470 
471 /**
472  * @brief Get static TI info data based on host state
473  *
474  * @param[out] tiInfo - pointer to static TI info data
475  */
476 void getStaticTiInfo(uint8_t*& tiInfo)
477 {
478     util::dbus::HostRunningState runningState = util::dbus::hostRunningState();
479 
480     // assume host state is unknown
481     std::string stateString = "host state unknown";
482 
483     if ((util::dbus::HostRunningState::Started == runningState) ||
484         (util::dbus::HostRunningState::Unknown == runningState))
485     {
486         if (util::dbus::HostRunningState::Started == runningState)
487         {
488             stateString = "host started";
489         }
490         tiInfo = (uint8_t*)defaultPhypTiInfo;
491     }
492     else
493     {
494         stateString = "host not started";
495         tiInfo      = (uint8_t*)defaultHbTiInfo;
496     }
497 
498     // trace host state
499     trace<level::INFO>(stateString.c_str());
500 }
501 
502 /**
503  * @brief Check if TI info data is valid
504  *
505  * @param[in] tiInfo - pointer to TI info data
506  * @return true if TI info data is valid, else false
507  */
508 bool tiInfoValid(uint8_t* tiInfo)
509 {
510     bool tiInfoValid = false; // assume TI info invalid
511 
512     // TI info data[0] non-zero indicates TI info valid (usually)
513     if ((nullptr != tiInfo) && (0 != tiInfo[0]))
514     {
515         TiDataArea* tiDataArea = (TiDataArea*)tiInfo;
516 
517         std::stringstream ss; // string stream object for tracing
518         std::string strobj;   // string object for tracing
519 
520         // trace a few known TI data area values
521         ss.str(std::string()); // empty the stream
522         ss.clear();            // clear the stream
523         ss << "TI data command = 0x" << std::setw(2) << std::setfill('0')
524            << std::hex << (int)tiDataArea->command;
525         strobj = ss.str();
526         trace<level::INFO>(strobj.c_str());
527 
528         // Another check for valid TI Info since it has been seen that
529         // tiInfo[0] != 0 but TI info is not valid
530         if (0xa1 == tiDataArea->command)
531         {
532             tiInfoValid = true;
533 
534             // trace some more data since TI info appears valid
535             ss.str(std::string()); // empty the stream
536             ss.clear();            // clear the stream
537             ss << "TI data term-type = 0x" << std::setw(2) << std::setfill('0')
538                << std::hex << (int)tiDataArea->hbTerminateType;
539             strobj = ss.str();
540             trace<level::INFO>(strobj.c_str());
541 
542             ss.str(std::string()); // empty the stream
543             ss.clear();            // clear the stream
544             ss << "TI data SRC format = 0x" << std::setw(2) << std::setfill('0')
545                << std::hex << (int)tiDataArea->srcFormat;
546             strobj = ss.str();
547             trace<level::INFO>(strobj.c_str());
548 
549             ss.str(std::string()); // empty the stream
550             ss.clear();            // clear the stream
551             ss << "TI data source = 0x" << std::setw(2) << std::setfill('0')
552                << std::hex << (int)tiDataArea->source;
553             strobj = ss.str();
554             trace<level::INFO>(strobj.c_str());
555         }
556     }
557 
558     return tiInfoValid;
559 }
560 
561 } // namespace attn
562