1d84ed6e9SZane Shelley #include <assert.h>
287eabc65SBen Tyner #include <libpdbg.h>
39fb7393eSZane Shelley #include <unistd.h>
487eabc65SBen Tyner 
54ed4be56SZane Shelley #include <analyzer/service_data.hpp>
60205f3b3SBen Tyner #include <hei_main.hpp>
79fb7393eSZane Shelley #include <phosphor-logging/log.hpp>
8f4bd5ff6SZane Shelley #include <util/pdbg.hpp>
9d84ed6e9SZane Shelley #include <util/trace.hpp>
100205f3b3SBen Tyner 
11d84ed6e9SZane Shelley #include <algorithm>
1287eabc65SBen Tyner #include <fstream>
1387eabc65SBen Tyner #include <iostream>
14b1ebfcb1SBen Tyner #include <map>
15b1ebfcb1SBen Tyner #include <string>
16b1ebfcb1SBen Tyner 
170205f3b3SBen Tyner namespace analyzer
180205f3b3SBen Tyner {
190205f3b3SBen Tyner 
20f4bd5ff6SZane Shelley //------------------------------------------------------------------------------
21b1ebfcb1SBen Tyner 
22f4bd5ff6SZane Shelley // Forward references for externally defined functions.
2387eabc65SBen Tyner 
24d3b9bac9SZane Shelley /**
25d3b9bac9SZane Shelley  * @brief Will get the list of active chip and initialize the isolator.
26d3b9bac9SZane Shelley  * @param o_chips The returned list of active chips.
27d3b9bac9SZane Shelley  */
28171a2e04SZane Shelley void initializeIsolator(std::vector<libhei::Chip>& o_chips);
2987eabc65SBen Tyner 
30d3b9bac9SZane Shelley /**
31d3b9bac9SZane Shelley  * @brief Will create and submit a PEL using the given data.
32d3b9bac9SZane Shelley  * @param i_isoData   The data gathered during isolation (for FFDC).
334ed4be56SZane Shelley  * @param i_servData  Data regarding service actions gathered during analysis.
34d3b9bac9SZane Shelley  */
358af9e46fSZane Shelley void createPel(const libhei::IsolationData& i_isoData,
364ed4be56SZane Shelley                const ServiceData& i_servData);
37d3b9bac9SZane Shelley 
38d84ed6e9SZane Shelley //------------------------------------------------------------------------------
39d84ed6e9SZane Shelley 
402f263181SZane Shelley const char* __attn(libhei::AttentionType_t i_attnType)
412f263181SZane Shelley {
422f263181SZane Shelley     const char* str = "";
432f263181SZane Shelley     switch (i_attnType)
442f263181SZane Shelley     {
452f263181SZane Shelley         case libhei::ATTN_TYPE_CHECKSTOP:
462f263181SZane Shelley             str = "CHECKSTOP";
472f263181SZane Shelley             break;
482f263181SZane Shelley         case libhei::ATTN_TYPE_UNIT_CS:
492f263181SZane Shelley             str = "UNIT_CS";
502f263181SZane Shelley             break;
512f263181SZane Shelley         case libhei::ATTN_TYPE_RECOVERABLE:
522f263181SZane Shelley             str = "RECOVERABLE";
532f263181SZane Shelley             break;
542f263181SZane Shelley         case libhei::ATTN_TYPE_SP_ATTN:
552f263181SZane Shelley             str = "SP_ATTN";
562f263181SZane Shelley             break;
572f263181SZane Shelley         case libhei::ATTN_TYPE_HOST_ATTN:
582f263181SZane Shelley             str = "HOST_ATTN";
592f263181SZane Shelley             break;
602f263181SZane Shelley         default:
612f263181SZane Shelley             trace::err("Unsupported attention type: %u", i_attnType);
622f263181SZane Shelley             assert(0);
632f263181SZane Shelley     }
642f263181SZane Shelley     return str;
652f263181SZane Shelley }
662f263181SZane Shelley 
672f263181SZane Shelley //------------------------------------------------------------------------------
682f263181SZane Shelley 
69cb457383SZane Shelley bool __filterRootCause(const libhei::IsolationData& i_isoData,
70cb457383SZane Shelley                        libhei::Signature& o_signature)
71097a71adSZane Shelley {
72cb457383SZane Shelley     // We'll need to make a copy of the list so that the original list is
73cb457383SZane Shelley     // maintained for the log.
74cb457383SZane Shelley     std::vector<libhei::Signature> sigList{i_isoData.getSignatureList()};
75cb457383SZane Shelley 
762f263181SZane Shelley     // For debug, trace out the original list of signatures before filtering.
77cb457383SZane Shelley     for (const auto& sig : sigList)
782f263181SZane Shelley     {
79f4bd5ff6SZane Shelley         trace::inf("Signature: %s 0x%0" PRIx32 " %s",
80cb457383SZane Shelley                    util::pdbg::getPath(sig.getChip()), sig.toUint32(),
81f4bd5ff6SZane Shelley                    __attn(sig.getAttnType()));
822f263181SZane Shelley     }
832f263181SZane Shelley 
84097a71adSZane Shelley     // Special and host attentions are not supported by this user application.
85097a71adSZane Shelley     auto newEndItr =
86cb457383SZane Shelley         std::remove_if(sigList.begin(), sigList.end(), [&](const auto& t) {
87097a71adSZane Shelley             return (libhei::ATTN_TYPE_SP_ATTN == t.getAttnType() ||
88097a71adSZane Shelley                     libhei::ATTN_TYPE_HOST_ATTN == t.getAttnType());
89097a71adSZane Shelley         });
90097a71adSZane Shelley 
91097a71adSZane Shelley     // Shrink the vector, if needed.
92cb457383SZane Shelley     sigList.resize(std::distance(sigList.begin(), newEndItr));
93097a71adSZane Shelley 
94097a71adSZane Shelley     // START WORKAROUND
95097a71adSZane Shelley     // TODO: Filtering should be determined by the RAS Data Files provided by
96097a71adSZane Shelley     //       the host firmware via the PNOR (similar to the Chip Data Files).
97097a71adSZane Shelley     //       Until that support is available, use a rudimentary filter that
98097a71adSZane Shelley     //       first looks for any recoverable attention, then any unit checkstop,
99097a71adSZane Shelley     //       and then any system checkstop. This is built on the premise that
100097a71adSZane Shelley     //       recoverable errors could be the root cause of an system checkstop
101097a71adSZane Shelley     //       attentions. Fortunately, we just need to sort the list by the
102097a71adSZane Shelley     //       greater attention type value.
103cb457383SZane Shelley     std::sort(sigList.begin(), sigList.end(),
104097a71adSZane Shelley               [&](const auto& a, const auto& b) {
105097a71adSZane Shelley                   return a.getAttnType() > b.getAttnType();
106097a71adSZane Shelley               });
107097a71adSZane Shelley     // END WORKAROUND
108cb457383SZane Shelley 
109cb457383SZane Shelley     // Check if a root cause attention was found.
110cb457383SZane Shelley     if (!sigList.empty())
111cb457383SZane Shelley     {
112cb457383SZane Shelley         // The entry at the front of the list will be the root cause.
113cb457383SZane Shelley         o_signature = sigList.front();
114cb457383SZane Shelley         return true;
115cb457383SZane Shelley     }
116cb457383SZane Shelley 
117cb457383SZane Shelley     return false; // default, no active attentions found.
118097a71adSZane Shelley }
119097a71adSZane Shelley 
120097a71adSZane Shelley //------------------------------------------------------------------------------
121097a71adSZane Shelley 
122cb457383SZane Shelley bool __analyze(const libhei::IsolationData& i_isoData)
1239fb7393eSZane Shelley {
1249fb7393eSZane Shelley     bool attnFound = false;
1259fb7393eSZane Shelley 
126cb457383SZane Shelley     libhei::Signature rootCause{};
127cb457383SZane Shelley     attnFound = __filterRootCause(i_isoData, rootCause);
128cb457383SZane Shelley 
129cb457383SZane Shelley     if (!attnFound)
1309fb7393eSZane Shelley     {
131cb457383SZane Shelley         // NOTE: It is possible for TI handling that there will not be an active
132cb457383SZane Shelley         //       attention. In which case, we will not do anything and let the
133cb457383SZane Shelley         //       caller of this function determine if this is the expected
134cb457383SZane Shelley         //       behavior.
1359fb7393eSZane Shelley         trace::inf("No active attentions found");
1369fb7393eSZane Shelley     }
1379fb7393eSZane Shelley     else
1389fb7393eSZane Shelley     {
1399fb7393eSZane Shelley         trace::inf("Root cause attention: %s 0x%0" PRIx32 " %s",
140cb457383SZane Shelley                    util::pdbg::getPath(rootCause.getChip()),
141cb457383SZane Shelley                    rootCause.toUint32(), __attn(rootCause.getAttnType()));
142cb457383SZane Shelley 
1434ed4be56SZane Shelley         // TODO: Perform service actions based on the root cause. The default
1444ed4be56SZane Shelley         // callout if none other exist is level 2 support.
1458af9e46fSZane Shelley         ServiceData servData{rootCause};
1464ed4be56SZane Shelley         servData.addCallout(std::make_shared<ProcedureCallout>(
1474ed4be56SZane Shelley             ProcedureCallout::NEXTLVL, Callout::Priority::HIGH));
148d3b9bac9SZane Shelley 
149d3b9bac9SZane Shelley         // Create and commit a PEL.
1508af9e46fSZane Shelley         createPel(i_isoData, servData);
1519fb7393eSZane Shelley     }
1529fb7393eSZane Shelley 
1539fb7393eSZane Shelley     return attnFound;
1549fb7393eSZane Shelley }
1559fb7393eSZane Shelley 
1569fb7393eSZane Shelley //------------------------------------------------------------------------------
1579fb7393eSZane Shelley 
1589fb7393eSZane Shelley bool analyzeHardware()
15987eabc65SBen Tyner {
160097a71adSZane Shelley     bool attnFound = false;
16187eabc65SBen Tyner 
1622f263181SZane Shelley     trace::inf(">>> enter analyzeHardware()");
1632f263181SZane Shelley 
1647ae9c8c7SZane Shelley     if (util::pdbg::queryHardwareAnalysisSupported())
1657ae9c8c7SZane Shelley     {
166171a2e04SZane Shelley         // Initialize the isolator and get all of the chips to be analyzed.
167f4bd5ff6SZane Shelley         trace::inf("Initializing the isolator...");
168171a2e04SZane Shelley         std::vector<libhei::Chip> chips;
169f4bd5ff6SZane Shelley         initializeIsolator(chips);
1702e994bcdSZane Shelley 
171097a71adSZane Shelley         // Isolate attentions.
172f4bd5ff6SZane Shelley         trace::inf("Isolating errors: # of chips=%u", chips.size());
173097a71adSZane Shelley         libhei::IsolationData isoData{};
174f4bd5ff6SZane Shelley         libhei::isolate(chips, isoData);
17587eabc65SBen Tyner 
176cb457383SZane Shelley         // Analyze the isolation data and perform service actions if needed.
177cb457383SZane Shelley         attnFound = __analyze(isoData);
17887eabc65SBen Tyner 
179097a71adSZane Shelley         // All done, clean up the isolator.
180f4bd5ff6SZane Shelley         trace::inf("Uninitializing isolator...");
181097a71adSZane Shelley         libhei::uninitialize();
1827ae9c8c7SZane Shelley     }
1837ae9c8c7SZane Shelley     else
1847ae9c8c7SZane Shelley     {
1857ae9c8c7SZane Shelley         trace::err("Hardware error analysis is not supported on this system");
1867ae9c8c7SZane Shelley     }
187b1ebfcb1SBen Tyner 
1882f263181SZane Shelley     trace::inf("<<< exit analyzeHardware()");
1892f263181SZane Shelley 
190097a71adSZane Shelley     return attnFound;
1910205f3b3SBen Tyner }
1920205f3b3SBen Tyner 
193*eea45427SBen Tyner //------------------------------------------------------------------------------
194*eea45427SBen Tyner 
195*eea45427SBen Tyner /**
196*eea45427SBen Tyner  * @brief Get error isolator build information
197*eea45427SBen Tyner  *
198*eea45427SBen Tyner  * @return Pointer to build information
199*eea45427SBen Tyner  */
200*eea45427SBen Tyner const char* getBuildInfo()
201*eea45427SBen Tyner {
202*eea45427SBen Tyner     return libhei::getBuildInfo();
203*eea45427SBen Tyner }
204*eea45427SBen Tyner 
2050205f3b3SBen Tyner } // namespace analyzer
206