1 #include <libpdbg.h>
2 
3 #include <analyzer/analyzer_main.hpp>
4 #include <attn/attention.hpp>
5 #include <attn/attn_common.hpp>
6 #include <attn/attn_config.hpp>
7 #include <attn/attn_handler.hpp>
8 #include <attn/attn_logging.hpp>
9 #include <attn/bp_handler.hpp>
10 #include <attn/ti_handler.hpp>
11 #include <attn/vital_handler.hpp>
12 
13 #include <algorithm>
14 #include <iomanip>
15 #include <map>
16 #include <sstream>
17 #include <vector>
18 
19 namespace attn
20 {
21 
22 /**
23  * @brief Handle checkstop attention
24  *
25  * @param i_attention Attention object
26  * @return 0 indicates that the checkstop attention was successfully handled
27  *         1 indicates that the checkstop attention was NOT successfully
28  *           handled.
29  */
30 int handleCheckstop(Attention* i_attention);
31 
32 /**
33  * @brief Handle special attention
34  *
35  * @param i_attention Attention object
36  * @return 0 indicates that the special attention was successfully handled
37  *         1 indicates that the special attention was NOT successfully handled
38  */
39 int handleSpecial(Attention* i_attention);
40 
41 /** @brief Determine if attention is active and not masked */
42 bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn);
43 
44 /**
45  * @brief The main attention handler logic
46  *
47  * @param i_breakpoints true = breakpoint special attn handling enabled
48  */
49 void attnHandler(Config* i_config)
50 {
51     // Vector of active attentions to be handled
52     std::vector<Attention> active_attentions;
53 
54     uint32_t isr_val, isr_mask;
55     uint32_t proc;
56 
57     std::stringstream ss; // for trace messages
58 
59     // loop through processors looking for active attentions
60     trace<level::INFO>("Attention handler started");
61 
62     pdbg_target* target;
63     pdbg_for_each_class_target("proc", target)
64     {
65         if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
66         {
67             proc = pdbg_target_index(target); // get processor number
68 
69             // Use PIB target to determine if a processor is enabled
70             char path[16];
71             sprintf(path, "/proc%d/pib", proc);
72             pdbg_target* attnTarget = pdbg_target_from_path(nullptr, path);
73 
74             // sanity check
75             if (nullptr == attnTarget)
76             {
77                 trace<level::INFO>("pib path or target not found");
78                 continue;
79             }
80 
81             if (PDBG_TARGET_ENABLED == pdbg_target_probe(attnTarget))
82             {
83                 // The processor FSI target is required for CFAM read
84                 sprintf(path, "/proc%d/fsi", proc);
85                 attnTarget = pdbg_target_from_path(nullptr, path);
86 
87                 // sanity check
88                 if (nullptr == attnTarget)
89                 {
90                     trace<level::INFO>("fsi path or target not found");
91                     continue;
92                 }
93 
94                 // trace fsi path
95                 ss.str(std::string()); // clear stream
96                 ss << "target - " << path;
97                 trace<level::INFO>(ss.str().c_str());
98 
99                 isr_val = 0xffffffff; // invalid isr value
100 
101                 // get active attentions on processor
102                 if (RC_SUCCESS != fsi_read(attnTarget, 0x1007, &isr_val))
103                 {
104                     // log cfam read error
105                     trace<level::INFO>("Error! cfam read 0x1007 FAILED");
106                     eventAttentionFail(RC_CFAM_ERROR);
107                 }
108                 else if (0xffffffff == isr_val)
109                 {
110                     trace<level::INFO>("Error! cfam read 0x1007 INVALID");
111                     continue;
112                 }
113                 else
114                 {
115                     // trace isr
116                     ss.str(std::string());           // clear stream
117                     ss << std::hex << std::showbase; // trace as hex vals
118                     ss << "cfam 0x1007 = " << std::setw(8) << std::setfill('0')
119                        << isr_val;
120                     trace<level::INFO>(ss.str().c_str());
121 
122                     isr_mask = 0xffffffff; // invalid isr mask
123 
124                     // get interrupt enabled special attentions mask
125                     if (RC_SUCCESS != fsi_read(attnTarget, 0x100d, &isr_mask))
126                     {
127                         // log cfam read error
128                         trace<level::INFO>("Error! cfam read 0x100d FAILED");
129                         eventAttentionFail(RC_CFAM_ERROR);
130                     }
131                     else if (0xffffffff == isr_mask)
132                     {
133                         trace<level::INFO>("Error! cfam read 0x100d INVALID");
134                         continue;
135                     }
136                     else
137                     {
138                         // trace true-mask
139                         ss.str(std::string());           // clear stream
140                         ss << std::hex << std::showbase; // trace as hex vals
141                         ss << "cfam 0x100d = " << std::setw(8)
142                            << std::setfill('0') << isr_mask;
143                         trace<level::INFO>(ss.str().c_str());
144 
145                         // SBE vital attention active and not masked?
146                         if (true == activeAttn(isr_val, isr_mask, SBE_ATTN))
147                         {
148                             active_attentions.emplace_back(Attention::Vital,
149                                                            handleVital, target,
150                                                            i_config);
151                         }
152 
153                         // Checkstop attention active and not masked?
154                         if (true ==
155                             activeAttn(isr_val, isr_mask, CHECKSTOP_ATTN))
156                         {
157                             active_attentions.emplace_back(Attention::Checkstop,
158                                                            handleCheckstop,
159                                                            target, i_config);
160                         }
161 
162                         // Special attention active and not masked?
163                         if (true == activeAttn(isr_val, isr_mask, SPECIAL_ATTN))
164                         {
165                             active_attentions.emplace_back(Attention::Special,
166                                                            handleSpecial,
167                                                            target, i_config);
168                         }
169                     } // cfam 0x100d valid
170                 }     // cfam 0x1007 valid
171             }         // proc target enabled
172         }             // fsi target enabled
173     }                 // next processor
174 
175     // convert to heap, highest priority is at front
176     if (!std::is_heap(active_attentions.begin(), active_attentions.end()))
177     {
178         std::make_heap(active_attentions.begin(), active_attentions.end());
179     }
180 
181     // call the attention handler until one is handled or all were attempted
182     while (false == active_attentions.empty())
183     {
184         // handle highest priority attention, done if successful
185         if (RC_SUCCESS == active_attentions.front().handle())
186         {
187             // an attention was handled so we are done
188             break;
189         }
190 
191         // move attention to back of vector
192         std::pop_heap(active_attentions.begin(), active_attentions.end());
193 
194         // remove attention from vector
195         active_attentions.pop_back();
196     }
197 }
198 
199 /**
200  * @brief Handle checkstop attention
201  *
202  * @param i_attention Attention object
203  * @return 0 indicates that the checkstop attention was successfully handled
204  *         1 indicates that the checkstop attention was NOT successfully
205  *           handled.
206  */
207 int handleCheckstop(Attention* i_attention)
208 {
209     int rc = RC_SUCCESS; // assume checkstop handled
210 
211     trace<level::INFO>("checkstop handler started");
212 
213     // if checkstop handling enabled, handle checkstop attention
214     if (false == (i_attention->getConfig()->getFlag(enCheckstop)))
215     {
216         trace<level::INFO>("Checkstop handling disabled");
217     }
218     else
219     {
220         // Look for any attentions found in hardware. This will generate and
221         // commit a PEL if any errors are found.
222         if (true != analyzer::analyzeHardware())
223         {
224             rc = RC_ANALYZER_ERROR;
225         }
226     }
227 
228     return rc;
229 }
230 
231 /**
232  * @brief Handle special attention
233  *
234  * @param i_attention Attention object
235  * @return 0 indicates that the special attention was successfully handled
236  *         1 indicates that the special attention was NOT successfully handled
237  */
238 int handleSpecial(Attention* i_attention)
239 {
240     int rc = RC_SUCCESS; // assume special attention handled
241 
242     // The TI info chipop will give us a pointer to the TI info data
243     uint8_t* tiInfo       = nullptr;                  // ptr to TI info data
244     uint32_t tiInfoLen    = 0;                        // length of TI info data
245     pdbg_target* attnProc = i_attention->getTarget(); // proc with attention
246 
247     if (attnProc != nullptr)
248     {
249         // The processor PIB target is required for get TI info chipop
250         char path[16];
251         sprintf(path, "/proc%d/pib", pdbg_target_index(attnProc));
252         pdbg_target* tiInfoTarget = pdbg_target_from_path(nullptr, path);
253 
254         if (nullptr != tiInfoTarget)
255         {
256             if (PDBG_TARGET_ENABLED == pdbg_target_probe(tiInfoTarget))
257             {
258                 sbe_mpipl_get_ti_info(tiInfoTarget, &tiInfo, &tiInfoLen);
259                 if (tiInfo == nullptr)
260                 {
261                     trace<level::INFO>("TI info data ptr is null after call");
262                 }
263             }
264         }
265     }
266 
267     bool tiInfoValid = false; // TI area data not valid or not available
268 
269     // If TI area exists and is marked valid we can assume TI occurred
270     if ((nullptr != tiInfo) && (0 != tiInfo[0]))
271     {
272         TiDataArea* tiDataArea = (TiDataArea*)tiInfo;
273 
274         // trace a few known TI data area values
275         std::stringstream ss;
276         ss << std::hex << std::showbase;
277 
278         ss << "TI data command = " << (int)tiDataArea->command;
279         trace<level::INFO>(ss.str().c_str());
280         ss.str(std::string());
281 
282         // Another check for valid TI Info since it has been seen that
283         // tiInfo[0] != 0 but TI info is not valid
284         if (0xa1 == tiDataArea->command)
285         {
286             tiInfoValid = true;
287 
288             // trace some more data since TI info appears valid
289             ss << "TI data hb_terminate_type = "
290                << (int)tiDataArea->hbTerminateType;
291             trace<level::INFO>(ss.str().c_str());
292             ss.str(std::string());
293 
294             ss << "TI data SRC format = " << (int)tiDataArea->srcFormat;
295             trace<level::INFO>(ss.str().c_str());
296             ss.str(std::string());
297 
298             ss << "TI data source = " << (int)tiDataArea->source;
299             trace<level::INFO>(ss.str().c_str());
300             ss.str(std::string());
301 
302             if (true == (i_attention->getConfig()->getFlag(enTerminate)))
303             {
304                 // Call TI special attention handler
305                 rc = tiHandler(tiDataArea);
306             }
307         }
308     }
309 
310     // If TI area not valid or not available
311     if (false == tiInfoValid)
312     {
313         trace<level::INFO>("TI info NOT available");
314 
315         // if configured to handle breakpoint as default special attention
316         if (i_attention->getConfig()->getFlag(dfltBreakpoint))
317         {
318             if (true == (i_attention->getConfig()->getFlag(enBreakpoints)))
319             {
320                 // Call the breakpoint special attention handler
321                 bpHandler();
322             }
323         }
324         // if configured to handle TI as default special attention
325         else
326         {
327             trace<level::INFO>("assuming TI");
328 
329             if (true == (i_attention->getConfig()->getFlag(enTerminate)))
330             {
331                 // Call TI special attention handler
332                 rc = tiHandler(nullptr);
333             }
334         }
335     }
336 
337     // release TI data buffer
338     if (nullptr != tiInfo)
339     {
340         free(tiInfo);
341     }
342 
343     if (RC_SUCCESS != rc)
344     {
345         trace<level::INFO>("Special attn not handled");
346     }
347 
348     return rc;
349 }
350 
351 /**
352  * @brief Determine if attention is active and not masked
353  *
354  * Determine whether an attention needs to be handled and trace details of
355  * attention type and whether it is masked or not.
356  *
357  * @param i_val attention status register
358  * @param i_mask attention true mask register
359  * @param i_attn attention type
360  * @param i_proc processor associated with registers
361  *
362  * @return true if attention is active and not masked, otherwise false
363  */
364 bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn)
365 {
366     bool rc        = false; // assume attn masked and/or inactive
367     bool validAttn = true;  // known attention type
368 
369     // if attention active
370     if (0 != (i_val & i_attn))
371     {
372         std::stringstream ss;
373 
374         switch (i_attn)
375         {
376             case SBE_ATTN:
377                 ss << "SBE attn";
378                 break;
379             case CHECKSTOP_ATTN:
380                 ss << "Checkstop attn";
381                 break;
382             case SPECIAL_ATTN:
383                 ss << "Special attn";
384                 break;
385             default:
386                 ss << "Unknown attn";
387                 validAttn = false;
388         }
389 
390         // see if attention is masked
391         if (true == validAttn)
392         {
393             if (0 != (i_mask & i_attn))
394             {
395                 rc = true; // attention active and not masked
396             }
397             else
398             {
399                 ss << " masked";
400             }
401         }
402 
403         trace<level::INFO>(ss.str().c_str()); // commit trace stream
404     }
405 
406     return rc;
407 }
408 
409 } // namespace attn
410