1d84ed6e9SZane Shelley #include <assert.h>
287eabc65SBen Tyner #include <libpdbg.h>
39fb7393eSZane Shelley #include <unistd.h>
487eabc65SBen Tyner 
50205f3b3SBen Tyner #include <hei_main.hpp>
69fb7393eSZane Shelley #include <phosphor-logging/log.hpp>
7f4bd5ff6SZane Shelley #include <util/pdbg.hpp>
8d84ed6e9SZane Shelley #include <util/trace.hpp>
90205f3b3SBen Tyner 
10d84ed6e9SZane Shelley #include <algorithm>
1187eabc65SBen Tyner #include <fstream>
1287eabc65SBen Tyner #include <iostream>
13b1ebfcb1SBen Tyner #include <map>
14b1ebfcb1SBen Tyner #include <string>
15b1ebfcb1SBen Tyner 
160205f3b3SBen Tyner namespace analyzer
170205f3b3SBen Tyner {
180205f3b3SBen Tyner 
19f4bd5ff6SZane Shelley //------------------------------------------------------------------------------
20b1ebfcb1SBen Tyner 
21f4bd5ff6SZane Shelley // Forward references for externally defined functions.
2287eabc65SBen Tyner 
23d3b9bac9SZane Shelley /**
24d3b9bac9SZane Shelley  * @brief Will get the list of active chip and initialize the isolator.
25d3b9bac9SZane Shelley  * @param o_chips The returned list of active chips.
26d3b9bac9SZane Shelley  */
27171a2e04SZane Shelley void initializeIsolator(std::vector<libhei::Chip>& o_chips);
2887eabc65SBen Tyner 
29d3b9bac9SZane Shelley /**
30d3b9bac9SZane Shelley  * @brief Will create and submit a PEL using the given data.
31d3b9bac9SZane Shelley  * @param i_rootCause A signature defining the attention root cause.
32d3b9bac9SZane Shelley  * @param i_isoData   The data gathered during isolation (for FFDC).
33d3b9bac9SZane Shelley  */
34d3b9bac9SZane Shelley void createPel(const libhei::Signature& i_rootCause,
35d3b9bac9SZane Shelley                const libhei::IsolationData& i_isoData);
36d3b9bac9SZane Shelley 
37d84ed6e9SZane Shelley //------------------------------------------------------------------------------
38d84ed6e9SZane Shelley 
392f263181SZane Shelley const char* __attn(libhei::AttentionType_t i_attnType)
402f263181SZane Shelley {
412f263181SZane Shelley     const char* str = "";
422f263181SZane Shelley     switch (i_attnType)
432f263181SZane Shelley     {
442f263181SZane Shelley         case libhei::ATTN_TYPE_CHECKSTOP:
452f263181SZane Shelley             str = "CHECKSTOP";
462f263181SZane Shelley             break;
472f263181SZane Shelley         case libhei::ATTN_TYPE_UNIT_CS:
482f263181SZane Shelley             str = "UNIT_CS";
492f263181SZane Shelley             break;
502f263181SZane Shelley         case libhei::ATTN_TYPE_RECOVERABLE:
512f263181SZane Shelley             str = "RECOVERABLE";
522f263181SZane Shelley             break;
532f263181SZane Shelley         case libhei::ATTN_TYPE_SP_ATTN:
542f263181SZane Shelley             str = "SP_ATTN";
552f263181SZane Shelley             break;
562f263181SZane Shelley         case libhei::ATTN_TYPE_HOST_ATTN:
572f263181SZane Shelley             str = "HOST_ATTN";
582f263181SZane Shelley             break;
592f263181SZane Shelley         default:
602f263181SZane Shelley             trace::err("Unsupported attention type: %u", i_attnType);
612f263181SZane Shelley             assert(0);
622f263181SZane Shelley     }
632f263181SZane Shelley     return str;
642f263181SZane Shelley }
652f263181SZane Shelley 
662f263181SZane Shelley uint32_t __trgt(const libhei::Signature& i_sig)
672f263181SZane Shelley {
68a0299858SZane Shelley     uint8_t type = util::pdbg::getTrgtType(i_sig.getChip());
69a0299858SZane Shelley     uint32_t pos = util::pdbg::getChipPos(i_sig.getChip());
702f263181SZane Shelley 
712f263181SZane Shelley     // Technically, the FapiPos attribute is 32-bit, but not likely to ever go
722f263181SZane Shelley     // over 24-bit.
732f263181SZane Shelley 
742f263181SZane Shelley     return type << 24 | (pos & 0xffffff);
752f263181SZane Shelley }
762f263181SZane Shelley 
772f263181SZane Shelley uint32_t __sig(const libhei::Signature& i_sig)
782f263181SZane Shelley {
792f263181SZane Shelley     return i_sig.getId() << 16 | i_sig.getInstance() << 8 | i_sig.getBit();
802f263181SZane Shelley }
812f263181SZane Shelley 
822f263181SZane Shelley //------------------------------------------------------------------------------
832f263181SZane Shelley 
84097a71adSZane Shelley // Takes a signature list that will be filtered and sorted. The first entry in
85097a71adSZane Shelley // the returned list will be the root cause. If the returned list is empty,
86097a71adSZane Shelley // analysis failed.
87097a71adSZane Shelley void __filterRootCause(std::vector<libhei::Signature>& io_list)
88097a71adSZane Shelley {
892f263181SZane Shelley     // For debug, trace out the original list of signatures before filtering.
902f263181SZane Shelley     for (const auto& sig : io_list)
912f263181SZane Shelley     {
92f4bd5ff6SZane Shelley         trace::inf("Signature: %s 0x%0" PRIx32 " %s",
93f4bd5ff6SZane Shelley                    util::pdbg::getPath(sig.getChip()), __sig(sig),
94f4bd5ff6SZane Shelley                    __attn(sig.getAttnType()));
952f263181SZane Shelley     }
962f263181SZane Shelley 
97097a71adSZane Shelley     // Special and host attentions are not supported by this user application.
98097a71adSZane Shelley     auto newEndItr =
99097a71adSZane Shelley         std::remove_if(io_list.begin(), io_list.end(), [&](const auto& t) {
100097a71adSZane Shelley             return (libhei::ATTN_TYPE_SP_ATTN == t.getAttnType() ||
101097a71adSZane Shelley                     libhei::ATTN_TYPE_HOST_ATTN == t.getAttnType());
102097a71adSZane Shelley         });
103097a71adSZane Shelley 
104097a71adSZane Shelley     // Shrink the vector, if needed.
105097a71adSZane Shelley     io_list.resize(std::distance(io_list.begin(), newEndItr));
106097a71adSZane Shelley 
107097a71adSZane Shelley     // START WORKAROUND
108097a71adSZane Shelley     // TODO: Filtering should be determined by the RAS Data Files provided by
109097a71adSZane Shelley     //       the host firmware via the PNOR (similar to the Chip Data Files).
110097a71adSZane Shelley     //       Until that support is available, use a rudimentary filter that
111097a71adSZane Shelley     //       first looks for any recoverable attention, then any unit checkstop,
112097a71adSZane Shelley     //       and then any system checkstop. This is built on the premise that
113097a71adSZane Shelley     //       recoverable errors could be the root cause of an system checkstop
114097a71adSZane Shelley     //       attentions. Fortunately, we just need to sort the list by the
115097a71adSZane Shelley     //       greater attention type value.
116097a71adSZane Shelley     std::sort(io_list.begin(), io_list.end(),
117097a71adSZane Shelley               [&](const auto& a, const auto& b) {
118097a71adSZane Shelley                   return a.getAttnType() > b.getAttnType();
119097a71adSZane Shelley               });
120097a71adSZane Shelley     // END WORKAROUND
121097a71adSZane Shelley }
122097a71adSZane Shelley 
123097a71adSZane Shelley //------------------------------------------------------------------------------
124097a71adSZane Shelley 
1259fb7393eSZane Shelley bool __logError(const std::vector<libhei::Signature>& i_sigList,
1269fb7393eSZane Shelley                 const libhei::IsolationData& i_isoData)
1279fb7393eSZane Shelley {
1289fb7393eSZane Shelley     bool attnFound = false;
1299fb7393eSZane Shelley 
1309fb7393eSZane Shelley     if (i_sigList.empty())
1319fb7393eSZane Shelley     {
1329fb7393eSZane Shelley         trace::inf("No active attentions found");
1339fb7393eSZane Shelley     }
1349fb7393eSZane Shelley     else
1359fb7393eSZane Shelley     {
1369fb7393eSZane Shelley         attnFound = true;
1379fb7393eSZane Shelley 
1389fb7393eSZane Shelley         // The root cause attention is the first in the filtered list.
1399fb7393eSZane Shelley         libhei::Signature root = i_sigList.front();
1409fb7393eSZane Shelley 
1419fb7393eSZane Shelley         trace::inf("Root cause attention: %s 0x%0" PRIx32 " %s",
142d3b9bac9SZane Shelley                    util::pdbg::getPath(root.getChip()), root.toUint32(),
143f4bd5ff6SZane Shelley                    __attn(root.getAttnType()));
144d3b9bac9SZane Shelley 
145d3b9bac9SZane Shelley         // Create and commit a PEL.
146d3b9bac9SZane Shelley         createPel(root, i_isoData);
1479fb7393eSZane Shelley     }
1489fb7393eSZane Shelley 
1499fb7393eSZane Shelley     return attnFound;
1509fb7393eSZane Shelley }
1519fb7393eSZane Shelley 
1529fb7393eSZane Shelley //------------------------------------------------------------------------------
1539fb7393eSZane Shelley 
1549fb7393eSZane Shelley bool analyzeHardware()
15587eabc65SBen Tyner {
156097a71adSZane Shelley     bool attnFound = false;
15787eabc65SBen Tyner 
1582f263181SZane Shelley     trace::inf(">>> enter analyzeHardware()");
1592f263181SZane Shelley 
160*7ae9c8c7SZane Shelley     if (util::pdbg::queryHardwareAnalysisSupported())
161*7ae9c8c7SZane Shelley     {
162171a2e04SZane Shelley         // Initialize the isolator and get all of the chips to be analyzed.
163f4bd5ff6SZane Shelley         trace::inf("Initializing the isolator...");
164171a2e04SZane Shelley         std::vector<libhei::Chip> chips;
165f4bd5ff6SZane Shelley         initializeIsolator(chips);
1662e994bcdSZane Shelley 
167097a71adSZane Shelley         // Isolate attentions.
168f4bd5ff6SZane Shelley         trace::inf("Isolating errors: # of chips=%u", chips.size());
169097a71adSZane Shelley         libhei::IsolationData isoData{};
170f4bd5ff6SZane Shelley         libhei::isolate(chips, isoData);
17187eabc65SBen Tyner 
172*7ae9c8c7SZane Shelley         // Filter signatures to determine root cause. We'll need to make a copy
173*7ae9c8c7SZane Shelley         // of the list so that the original list is maintained for the log.
174097a71adSZane Shelley         std::vector<libhei::Signature> sigList{isoData.getSignatureList()};
175097a71adSZane Shelley         __filterRootCause(sigList);
176097a71adSZane Shelley 
1779fb7393eSZane Shelley         // Create and commit a log.
1789fb7393eSZane Shelley         attnFound = __logError(sigList, isoData);
17987eabc65SBen Tyner 
180097a71adSZane Shelley         // All done, clean up the isolator.
181f4bd5ff6SZane Shelley         trace::inf("Uninitializing isolator...");
182097a71adSZane Shelley         libhei::uninitialize();
183*7ae9c8c7SZane Shelley     }
184*7ae9c8c7SZane Shelley     else
185*7ae9c8c7SZane Shelley     {
186*7ae9c8c7SZane Shelley         trace::err("Hardware error analysis is not supported on this system");
187*7ae9c8c7SZane Shelley     }
188b1ebfcb1SBen Tyner 
1892f263181SZane Shelley     trace::inf("<<< exit analyzeHardware()");
1902f263181SZane Shelley 
191097a71adSZane Shelley     return attnFound;
1920205f3b3SBen Tyner }
1930205f3b3SBen Tyner 
1940205f3b3SBen Tyner } // namespace analyzer
195