1792f32f7SBen Tyner #include <libpdbg.h>
2792f32f7SBen Tyner 
30205f3b3SBen Tyner #include <analyzer/analyzer_main.hpp>
4b797b3e1SBen Tyner #include <attn/attention.hpp>
5bcf65a8bSBen Tyner #include <attn/attn_common.hpp>
6b797b3e1SBen Tyner #include <attn/attn_config.hpp>
7b797b3e1SBen Tyner #include <attn/attn_handler.hpp>
8b797b3e1SBen Tyner #include <attn/attn_logging.hpp>
9b797b3e1SBen Tyner #include <attn/bp_handler.hpp>
10b797b3e1SBen Tyner #include <attn/ti_handler.hpp>
11bcf65a8bSBen Tyner #include <attn/vital_handler.hpp>
12ef320154SBen Tyner 
13b481d905SBen Tyner #include <algorithm>
14ef320154SBen Tyner #include <iomanip>
15b1ebfcb1SBen Tyner #include <map>
169ae5ca41SBen Tyner #include <sstream>
17b481d905SBen Tyner #include <vector>
18ef320154SBen Tyner 
19ef320154SBen Tyner namespace attn
20ef320154SBen Tyner {
21ef320154SBen Tyner 
22ef320154SBen Tyner /**
23ef320154SBen Tyner  * @brief Handle checkstop attention
24ef320154SBen Tyner  *
25b481d905SBen Tyner  * @param i_attention Attention object
263fb52e53SBen Tyner  * @return 0 indicates that the checkstop attention was successfully handled
273fb52e53SBen Tyner  *         1 indicates that the checkstop attention was NOT successfully
283fb52e53SBen Tyner  *           handled.
29ef320154SBen Tyner  */
30b481d905SBen Tyner int handleCheckstop(Attention* i_attention);
31ef320154SBen Tyner 
32ef320154SBen Tyner /**
33ef320154SBen Tyner  * @brief Handle special attention
34ef320154SBen Tyner  *
35b481d905SBen Tyner  * @param i_attention Attention object
363fb52e53SBen Tyner  * @return 0 indicates that the special attention was successfully handled
373fb52e53SBen Tyner  *         1 indicates that the special attention was NOT successfully handled
38ef320154SBen Tyner  */
39b481d905SBen Tyner int handleSpecial(Attention* i_attention);
40ef320154SBen Tyner 
41fb190545SBen Tyner /** @brief Determine if attention is active and not masked */
421965e504SBen Tyner bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn);
43fb190545SBen Tyner 
44ef320154SBen Tyner /**
45ef320154SBen Tyner  * @brief The main attention handler logic
46970fd4fbSBen Tyner  *
47970fd4fbSBen Tyner  * @param i_breakpoints true = breakpoint special attn handling enabled
48ef320154SBen Tyner  */
493fb52e53SBen Tyner void attnHandler(Config* i_config)
50ef320154SBen Tyner {
51b481d905SBen Tyner     // Vector of active attentions to be handled
52b481d905SBen Tyner     std::vector<Attention> active_attentions;
53b481d905SBen Tyner 
54ef320154SBen Tyner     uint32_t isr_val, isr_mask;
55ef320154SBen Tyner     uint32_t proc;
56ef320154SBen Tyner 
571965e504SBen Tyner     std::stringstream ss; // for trace messages
581965e504SBen Tyner 
59ef320154SBen Tyner     // loop through processors looking for active attentions
60b1ebfcb1SBen Tyner     trace<level::INFO>("Attention handler started");
61117af99bSBen Tyner 
62ef320154SBen Tyner     pdbg_target* target;
635e622d87SBen Tyner     pdbg_for_each_class_target("proc", target)
64ef320154SBen Tyner     {
65ef320154SBen Tyner         if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
66ef320154SBen Tyner         {
67ef320154SBen Tyner             proc = pdbg_target_index(target); // get processor number
68ef320154SBen Tyner 
69b83c852aSBen Tyner             // Use PIB target to determine if a processor is enabled
705e622d87SBen Tyner             char path[16];
71b83c852aSBen Tyner             sprintf(path, "/proc%d/pib", proc);
725e622d87SBen Tyner             pdbg_target* attnTarget = pdbg_target_from_path(nullptr, path);
735e622d87SBen Tyner 
74b83c852aSBen Tyner             // sanity check
75b83c852aSBen Tyner             if (nullptr == attnTarget)
76b83c852aSBen Tyner             {
77b83c852aSBen Tyner                 trace<level::INFO>("pib path or target not found");
78b83c852aSBen Tyner                 continue;
79b83c852aSBen Tyner             }
80b83c852aSBen Tyner 
815e622d87SBen Tyner             if (PDBG_TARGET_ENABLED == pdbg_target_probe(attnTarget))
825e622d87SBen Tyner             {
83b83c852aSBen Tyner                 // The processor FSI target is required for CFAM read
84b83c852aSBen Tyner                 sprintf(path, "/proc%d/fsi", proc);
85b83c852aSBen Tyner                 attnTarget = pdbg_target_from_path(nullptr, path);
86b83c852aSBen Tyner 
87b83c852aSBen Tyner                 // sanity check
88b83c852aSBen Tyner                 if (nullptr == attnTarget)
89b83c852aSBen Tyner                 {
90b83c852aSBen Tyner                     trace<level::INFO>("fsi path or target not found");
91b83c852aSBen Tyner                     continue;
92b83c852aSBen Tyner                 }
93b83c852aSBen Tyner 
941965e504SBen Tyner                 // trace fsi path
951965e504SBen Tyner                 ss.str(std::string()); // clear stream
961965e504SBen Tyner                 ss << "target - " << path;
971965e504SBen Tyner                 trace<level::INFO>(ss.str().c_str());
981965e504SBen Tyner 
995adc96eeSBen Tyner                 isr_val = 0xffffffff; // invalid isr value
1005adc96eeSBen Tyner 
101ef320154SBen Tyner                 // get active attentions on processor
1025e622d87SBen Tyner                 if (RC_SUCCESS != fsi_read(attnTarget, 0x1007, &isr_val))
103ef320154SBen Tyner                 {
104fb190545SBen Tyner                     // log cfam read error
105b1ebfcb1SBen Tyner                     trace<level::INFO>("Error! cfam read 0x1007 FAILED");
106fb190545SBen Tyner                     eventAttentionFail(RC_CFAM_ERROR);
107ef320154SBen Tyner                 }
1085adc96eeSBen Tyner                 else if (0xffffffff == isr_val)
1095adc96eeSBen Tyner                 {
1105adc96eeSBen Tyner                     trace<level::INFO>("Error! cfam read 0x1007 INVALID");
1115adc96eeSBen Tyner                     continue;
1125adc96eeSBen Tyner                 }
113ef320154SBen Tyner                 else
114ef320154SBen Tyner                 {
1151965e504SBen Tyner                     // trace isr
1161965e504SBen Tyner                     ss.str(std::string());           // clear stream
1171965e504SBen Tyner                     ss << std::hex << std::showbase; // trace as hex vals
1181965e504SBen Tyner                     ss << "cfam 0x1007 = " << std::setw(8) << std::setfill('0')
1191965e504SBen Tyner                        << isr_val;
1201965e504SBen Tyner                     trace<level::INFO>(ss.str().c_str());
1211965e504SBen Tyner 
1225adc96eeSBen Tyner                     isr_mask = 0xffffffff; // invalid isr mask
1235adc96eeSBen Tyner 
124ef320154SBen Tyner                     // get interrupt enabled special attentions mask
1255e622d87SBen Tyner                     if (RC_SUCCESS != fsi_read(attnTarget, 0x100d, &isr_mask))
126ef320154SBen Tyner                     {
127fb190545SBen Tyner                         // log cfam read error
128b1ebfcb1SBen Tyner                         trace<level::INFO>("Error! cfam read 0x100d FAILED");
129fb190545SBen Tyner                         eventAttentionFail(RC_CFAM_ERROR);
130ef320154SBen Tyner                     }
1315adc96eeSBen Tyner                     else if (0xffffffff == isr_mask)
1325adc96eeSBen Tyner                     {
1335adc96eeSBen Tyner                         trace<level::INFO>("Error! cfam read 0x100d INVALID");
1345adc96eeSBen Tyner                         continue;
1355adc96eeSBen Tyner                     }
136ef320154SBen Tyner                     else
137ef320154SBen Tyner                     {
1381965e504SBen Tyner                         // trace true-mask
1391965e504SBen Tyner                         ss.str(std::string());           // clear stream
1401965e504SBen Tyner                         ss << std::hex << std::showbase; // trace as hex vals
1411965e504SBen Tyner                         ss << "cfam 0x100d = " << std::setw(8)
1421965e504SBen Tyner                            << std::setfill('0') << isr_mask;
1431965e504SBen Tyner                         trace<level::INFO>(ss.str().c_str());
1441965e504SBen Tyner 
145fb190545SBen Tyner                         // SBE vital attention active and not masked?
1461965e504SBen Tyner                         if (true == activeAttn(isr_val, isr_mask, SBE_ATTN))
147ef320154SBen Tyner                         {
1485e622d87SBen Tyner                             active_attentions.emplace_back(Attention::Vital,
1495e622d87SBen Tyner                                                            handleVital, target,
1505e622d87SBen Tyner                                                            i_config);
151ef320154SBen Tyner                         }
152ef320154SBen Tyner 
153fb190545SBen Tyner                         // Checkstop attention active and not masked?
154fb190545SBen Tyner                         if (true ==
1551965e504SBen Tyner                             activeAttn(isr_val, isr_mask, CHECKSTOP_ATTN))
156ef320154SBen Tyner                         {
157b481d905SBen Tyner                             active_attentions.emplace_back(Attention::Checkstop,
1585e622d87SBen Tyner                                                            handleCheckstop,
1595e622d87SBen Tyner                                                            target, i_config);
160ef320154SBen Tyner                         }
161ef320154SBen Tyner 
162fb190545SBen Tyner                         // Special attention active and not masked?
1631965e504SBen Tyner                         if (true == activeAttn(isr_val, isr_mask, SPECIAL_ATTN))
164ef320154SBen Tyner                         {
165b481d905SBen Tyner                             active_attentions.emplace_back(Attention::Special,
1665e622d87SBen Tyner                                                            handleSpecial,
1675e622d87SBen Tyner                                                            target, i_config);
168ef320154SBen Tyner                         }
169ef320154SBen Tyner                     } // cfam 0x100d valid
170ef320154SBen Tyner                 }     // cfam 0x1007 valid
1715e622d87SBen Tyner             }         // proc target enabled
172ef320154SBen Tyner         }             // fsi target enabled
173ef320154SBen Tyner     }                 // next processor
174ef320154SBen Tyner 
175b481d905SBen Tyner     // convert to heap, highest priority is at front
176b481d905SBen Tyner     if (!std::is_heap(active_attentions.begin(), active_attentions.end()))
177b481d905SBen Tyner     {
178b481d905SBen Tyner         std::make_heap(active_attentions.begin(), active_attentions.end());
179b481d905SBen Tyner     }
180b481d905SBen Tyner 
181b481d905SBen Tyner     // call the attention handler until one is handled or all were attempted
182b481d905SBen Tyner     while (false == active_attentions.empty())
183b481d905SBen Tyner     {
184b481d905SBen Tyner         // handle highest priority attention, done if successful
185b481d905SBen Tyner         if (RC_SUCCESS == active_attentions.front().handle())
186b481d905SBen Tyner         {
187b1ebfcb1SBen Tyner             // an attention was handled so we are done
188b481d905SBen Tyner             break;
189b481d905SBen Tyner         }
190b481d905SBen Tyner 
191b481d905SBen Tyner         // move attention to back of vector
192b481d905SBen Tyner         std::pop_heap(active_attentions.begin(), active_attentions.end());
193b481d905SBen Tyner 
194b481d905SBen Tyner         // remove attention from vector
195b481d905SBen Tyner         active_attentions.pop_back();
196b481d905SBen Tyner     }
197ef320154SBen Tyner }
198ef320154SBen Tyner 
199ef320154SBen Tyner /**
200ef320154SBen Tyner  * @brief Handle checkstop attention
2013fb52e53SBen Tyner  *
2023fb52e53SBen Tyner  * @param i_attention Attention object
2033fb52e53SBen Tyner  * @return 0 indicates that the checkstop attention was successfully handled
2043fb52e53SBen Tyner  *         1 indicates that the checkstop attention was NOT successfully
2053fb52e53SBen Tyner  *           handled.
206ef320154SBen Tyner  */
207b481d905SBen Tyner int handleCheckstop(Attention* i_attention)
208ef320154SBen Tyner {
2093fb52e53SBen Tyner     int rc = RC_SUCCESS; // assume checkstop handled
210ef320154SBen Tyner 
211b1ebfcb1SBen Tyner     trace<level::INFO>("checkstop handler started");
212b1ebfcb1SBen Tyner 
2133fb52e53SBen Tyner     // if checkstop handling enabled, handle checkstop attention
2143fb52e53SBen Tyner     if (false == (i_attention->getConfig()->getFlag(enCheckstop)))
2153fb52e53SBen Tyner     {
216b1ebfcb1SBen Tyner         trace<level::INFO>("Checkstop handling disabled");
2173fb52e53SBen Tyner     }
2183fb52e53SBen Tyner     else
2193fb52e53SBen Tyner     {
2209fb7393eSZane Shelley         // Look for any attentions found in hardware. This will generate and
2217ae9c8c7SZane Shelley         // commit a PEL if any errors are found.
2229fb7393eSZane Shelley         if (true != analyzer::analyzeHardware())
223b1ebfcb1SBen Tyner         {
224b1ebfcb1SBen Tyner             rc = RC_ANALYZER_ERROR;
225b1ebfcb1SBen Tyner         }
2263fb52e53SBen Tyner     }
227ef320154SBen Tyner 
228ef320154SBen Tyner     return rc;
229ef320154SBen Tyner }
230ef320154SBen Tyner 
231ef320154SBen Tyner /**
232ef320154SBen Tyner  * @brief Handle special attention
2333fb52e53SBen Tyner  *
2343fb52e53SBen Tyner  * @param i_attention Attention object
2353fb52e53SBen Tyner  * @return 0 indicates that the special attention was successfully handled
2363fb52e53SBen Tyner  *         1 indicates that the special attention was NOT successfully handled
237ef320154SBen Tyner  */
238b481d905SBen Tyner int handleSpecial(Attention* i_attention)
239ef320154SBen Tyner {
240b1ebfcb1SBen Tyner     int rc = RC_SUCCESS; // assume special attention handled
241ef320154SBen Tyner 
242fb190545SBen Tyner     // The TI info chipop will give us a pointer to the TI info data
243792f32f7SBen Tyner     uint8_t* tiInfo       = nullptr;                  // ptr to TI info data
244792f32f7SBen Tyner     uint32_t tiInfoLen    = 0;                        // length of TI info data
24598430b30SBen Tyner     pdbg_target* attnProc = i_attention->getTarget(); // proc with attention
246b1ebfcb1SBen Tyner 
24798430b30SBen Tyner     if (attnProc != nullptr)
24898430b30SBen Tyner     {
24998430b30SBen Tyner         // The processor PIB target is required for get TI info chipop
25098430b30SBen Tyner         char path[16];
25198430b30SBen Tyner         sprintf(path, "/proc%d/pib", pdbg_target_index(attnProc));
25298430b30SBen Tyner         pdbg_target* tiInfoTarget = pdbg_target_from_path(nullptr, path);
25389c0a7afSBen Tyner 
25498430b30SBen Tyner         if (nullptr != tiInfoTarget)
25589c0a7afSBen Tyner         {
25689c0a7afSBen Tyner             if (PDBG_TARGET_ENABLED == pdbg_target_probe(tiInfoTarget))
25789c0a7afSBen Tyner             {
258792f32f7SBen Tyner                 sbe_mpipl_get_ti_info(tiInfoTarget, &tiInfo, &tiInfoLen);
25998430b30SBen Tyner                 if (tiInfo == nullptr)
26098430b30SBen Tyner                 {
26198430b30SBen Tyner                     trace<level::INFO>("TI info data ptr is null after call");
26298430b30SBen Tyner                 }
26398430b30SBen Tyner             }
26489c0a7afSBen Tyner         }
26589c0a7afSBen Tyner     }
266ef320154SBen Tyner 
2670fe5df40SBen Tyner     bool tiInfoValid = false; // TI area data not valid or not available
2680fe5df40SBen Tyner 
269792f32f7SBen Tyner     // If TI area exists and is marked valid we can assume TI occurred
270792f32f7SBen Tyner     if ((nullptr != tiInfo) && (0 != tiInfo[0]))
271792f32f7SBen Tyner     {
272792f32f7SBen Tyner         TiDataArea* tiDataArea = (TiDataArea*)tiInfo;
273792f32f7SBen Tyner 
274792f32f7SBen Tyner         // trace a few known TI data area values
2758c5e4f4eSBen Tyner         std::stringstream ss;
2768c5e4f4eSBen Tyner         ss << std::hex << std::showbase;
27740717725SBen Tyner 
27840717725SBen Tyner         ss << "TI data command = " << (int)tiDataArea->command;
279792f32f7SBen Tyner         trace<level::INFO>(ss.str().c_str());
28040717725SBen Tyner         ss.str(std::string());
28140717725SBen Tyner 
2820fe5df40SBen Tyner         // Another check for valid TI Info since it has been seen that
2830fe5df40SBen Tyner         // tiInfo[0] != 0 but TI info is not valid
2840fe5df40SBen Tyner         if (0xa1 == tiDataArea->command)
2850fe5df40SBen Tyner         {
2860fe5df40SBen Tyner             tiInfoValid = true;
2870fe5df40SBen Tyner 
2880fe5df40SBen Tyner             // trace some more data since TI info appears valid
2898c5e4f4eSBen Tyner             ss << "TI data hb_terminate_type = "
2908c5e4f4eSBen Tyner                << (int)tiDataArea->hbTerminateType;
2918c5e4f4eSBen Tyner             trace<level::INFO>(ss.str().c_str());
2928c5e4f4eSBen Tyner             ss.str(std::string());
2938c5e4f4eSBen Tyner 
29440717725SBen Tyner             ss << "TI data SRC format = " << (int)tiDataArea->srcFormat;
295792f32f7SBen Tyner             trace<level::INFO>(ss.str().c_str());
29640717725SBen Tyner             ss.str(std::string());
29740717725SBen Tyner 
2988c5e4f4eSBen Tyner             ss << "TI data source = " << (int)tiDataArea->source;
299792f32f7SBen Tyner             trace<level::INFO>(ss.str().c_str());
30040717725SBen Tyner             ss.str(std::string());
301792f32f7SBen Tyner 
3023fb52e53SBen Tyner             if (true == (i_attention->getConfig()->getFlag(enTerminate)))
303970fd4fbSBen Tyner             {
3049ae5ca41SBen Tyner                 // Call TI special attention handler
305792f32f7SBen Tyner                 rc = tiHandler(tiDataArea);
3063fb52e53SBen Tyner             }
307792f32f7SBen Tyner         }
3080fe5df40SBen Tyner     }
3090fe5df40SBen Tyner 
3100fe5df40SBen Tyner     // If TI area not valid or not available
3110fe5df40SBen Tyner     if (false == tiInfoValid)
3123fb52e53SBen Tyner     {
313e4f5dbefSBen Tyner         trace<level::INFO>("TI info NOT available");
314e4f5dbefSBen Tyner 
315e4f5dbefSBen Tyner         // if configured to handle breakpoint as default special attention
316e4f5dbefSBen Tyner         if (i_attention->getConfig()->getFlag(dfltBreakpoint))
317e4f5dbefSBen Tyner         {
3183fb52e53SBen Tyner             if (true == (i_attention->getConfig()->getFlag(enBreakpoints)))
3193fb52e53SBen Tyner             {
3203fb52e53SBen Tyner                 // Call the breakpoint special attention handler
3213fb52e53SBen Tyner                 bpHandler();
3223fb52e53SBen Tyner             }
323970fd4fbSBen Tyner         }
324e4f5dbefSBen Tyner         // if configured to handle TI as default special attention
325e4f5dbefSBen Tyner         else
326e4f5dbefSBen Tyner         {
327e4f5dbefSBen Tyner             trace<level::INFO>("assuming TI");
328e4f5dbefSBen Tyner 
329e4f5dbefSBen Tyner             if (true == (i_attention->getConfig()->getFlag(enTerminate)))
330e4f5dbefSBen Tyner             {
331e4f5dbefSBen Tyner                 // Call TI special attention handler
332e4f5dbefSBen Tyner                 rc = tiHandler(nullptr);
333e4f5dbefSBen Tyner             }
334e4f5dbefSBen Tyner         }
335e4f5dbefSBen Tyner     }
336ef320154SBen Tyner 
337792f32f7SBen Tyner     // release TI data buffer
338792f32f7SBen Tyner     if (nullptr != tiInfo)
339792f32f7SBen Tyner     {
340792f32f7SBen Tyner         free(tiInfo);
341792f32f7SBen Tyner     }
342792f32f7SBen Tyner 
3433fb52e53SBen Tyner     if (RC_SUCCESS != rc)
3443fb52e53SBen Tyner     {
345792f32f7SBen Tyner         trace<level::INFO>("Special attn not handled");
3463fb52e53SBen Tyner     }
347ef320154SBen Tyner 
348ef320154SBen Tyner     return rc;
349ef320154SBen Tyner }
350ef320154SBen Tyner 
351fb190545SBen Tyner /**
352fb190545SBen Tyner  * @brief Determine if attention is active and not masked
353fb190545SBen Tyner  *
354fb190545SBen Tyner  * Determine whether an attention needs to be handled and trace details of
355fb190545SBen Tyner  * attention type and whether it is masked or not.
356fb190545SBen Tyner  *
357fb190545SBen Tyner  * @param i_val attention status register
358fb190545SBen Tyner  * @param i_mask attention true mask register
359fb190545SBen Tyner  * @param i_attn attention type
360fb190545SBen Tyner  * @param i_proc processor associated with registers
361fb190545SBen Tyner  *
362fb190545SBen Tyner  * @return true if attention is active and not masked, otherwise false
363fb190545SBen Tyner  */
3641965e504SBen Tyner bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn)
365fb190545SBen Tyner {
366fb190545SBen Tyner     bool rc = false; // assume attn masked and/or inactive
367fb190545SBen Tyner 
368fb190545SBen Tyner     // if attention active
369fb190545SBen Tyner     if (0 != (i_val & i_attn))
370fb190545SBen Tyner     {
371fb190545SBen Tyner         std::stringstream ss;
372fb190545SBen Tyner 
373*9fb657f9SZane Shelley         bool validAttn = true; // known attention type
374*9fb657f9SZane Shelley 
375fb190545SBen Tyner         switch (i_attn)
376fb190545SBen Tyner         {
377fb190545SBen Tyner             case SBE_ATTN:
378fb190545SBen Tyner                 ss << "SBE attn";
379fb190545SBen Tyner                 break;
380fb190545SBen Tyner             case CHECKSTOP_ATTN:
381fb190545SBen Tyner                 ss << "Checkstop attn";
382fb190545SBen Tyner                 break;
383fb190545SBen Tyner             case SPECIAL_ATTN:
384fb190545SBen Tyner                 ss << "Special attn";
385fb190545SBen Tyner                 break;
386fb190545SBen Tyner             default:
387fb190545SBen Tyner                 ss << "Unknown attn";
388fb190545SBen Tyner                 validAttn = false;
389fb190545SBen Tyner         }
390fb190545SBen Tyner 
391fb190545SBen Tyner         // see if attention is masked
392fb190545SBen Tyner         if (true == validAttn)
393fb190545SBen Tyner         {
394fb190545SBen Tyner             if (0 != (i_mask & i_attn))
395fb190545SBen Tyner             {
396fb190545SBen Tyner                 rc = true; // attention active and not masked
397fb190545SBen Tyner             }
398fb190545SBen Tyner             else
399fb190545SBen Tyner             {
400fb190545SBen Tyner                 ss << " masked";
401fb190545SBen Tyner             }
402fb190545SBen Tyner         }
403fb190545SBen Tyner 
404fb190545SBen Tyner         trace<level::INFO>(ss.str().c_str()); // commit trace stream
405fb190545SBen Tyner     }
406fb190545SBen Tyner 
407fb190545SBen Tyner     return rc;
408fb190545SBen Tyner }
409fb190545SBen Tyner 
410ef320154SBen Tyner } // namespace attn
411