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>
7*f4bd5ff6SZane 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 
19*f4bd5ff6SZane Shelley //------------------------------------------------------------------------------
20b1ebfcb1SBen Tyner 
21*f4bd5ff6SZane Shelley // Forward references for externally defined functions.
2287eabc65SBen Tyner 
23*f4bd5ff6SZane Shelley void initializeIsolator(const std::vector<libhei::Chip>& i_chips);
2487eabc65SBen Tyner 
25d84ed6e9SZane Shelley //------------------------------------------------------------------------------
26d84ed6e9SZane Shelley 
272f263181SZane Shelley uint8_t __attrType(pdbg_target* i_trgt)
282f263181SZane Shelley {
292f263181SZane Shelley     uint8_t attr = 0;
302f263181SZane Shelley     pdbg_target_get_attribute(i_trgt, "ATTR_TYPE", 1, 1, &attr);
312f263181SZane Shelley     return attr;
322f263181SZane Shelley }
332f263181SZane Shelley 
342f263181SZane Shelley uint32_t __attrFapiPos(pdbg_target* i_trgt)
352f263181SZane Shelley {
362f263181SZane Shelley     uint32_t attr = 0;
372f263181SZane Shelley     pdbg_target_get_attribute(i_trgt, "ATTR_FAPI_POS", 4, 1, &attr);
382f263181SZane Shelley     return attr;
392f263181SZane Shelley }
402f263181SZane Shelley 
412f263181SZane Shelley //------------------------------------------------------------------------------
422f263181SZane Shelley 
432f263181SZane Shelley const char* __attn(libhei::AttentionType_t i_attnType)
442f263181SZane Shelley {
452f263181SZane Shelley     const char* str = "";
462f263181SZane Shelley     switch (i_attnType)
472f263181SZane Shelley     {
482f263181SZane Shelley         case libhei::ATTN_TYPE_CHECKSTOP:
492f263181SZane Shelley             str = "CHECKSTOP";
502f263181SZane Shelley             break;
512f263181SZane Shelley         case libhei::ATTN_TYPE_UNIT_CS:
522f263181SZane Shelley             str = "UNIT_CS";
532f263181SZane Shelley             break;
542f263181SZane Shelley         case libhei::ATTN_TYPE_RECOVERABLE:
552f263181SZane Shelley             str = "RECOVERABLE";
562f263181SZane Shelley             break;
572f263181SZane Shelley         case libhei::ATTN_TYPE_SP_ATTN:
582f263181SZane Shelley             str = "SP_ATTN";
592f263181SZane Shelley             break;
602f263181SZane Shelley         case libhei::ATTN_TYPE_HOST_ATTN:
612f263181SZane Shelley             str = "HOST_ATTN";
622f263181SZane Shelley             break;
632f263181SZane Shelley         default:
642f263181SZane Shelley             trace::err("Unsupported attention type: %u", i_attnType);
652f263181SZane Shelley             assert(0);
662f263181SZane Shelley     }
672f263181SZane Shelley     return str;
682f263181SZane Shelley }
692f263181SZane Shelley 
702f263181SZane Shelley uint32_t __trgt(const libhei::Signature& i_sig)
712f263181SZane Shelley {
722f263181SZane Shelley     auto trgt = (pdbg_target*)i_sig.getChip().getChip();
732f263181SZane Shelley 
742f263181SZane Shelley     uint8_t type = __attrType(trgt);
752f263181SZane Shelley     uint32_t pos = __attrFapiPos(trgt);
762f263181SZane Shelley 
772f263181SZane Shelley     // Technically, the FapiPos attribute is 32-bit, but not likely to ever go
782f263181SZane Shelley     // over 24-bit.
792f263181SZane Shelley 
802f263181SZane Shelley     return type << 24 | (pos & 0xffffff);
812f263181SZane Shelley }
822f263181SZane Shelley 
832f263181SZane Shelley uint32_t __sig(const libhei::Signature& i_sig)
842f263181SZane Shelley {
852f263181SZane Shelley     return i_sig.getId() << 16 | i_sig.getInstance() << 8 | i_sig.getBit();
862f263181SZane Shelley }
872f263181SZane Shelley 
882f263181SZane Shelley //------------------------------------------------------------------------------
892f263181SZane Shelley 
90*f4bd5ff6SZane Shelley // Returns the chip model/level of the given target.
91*f4bd5ff6SZane Shelley libhei::ChipType_t __getChipType(pdbg_target* i_trgt)
92d84ed6e9SZane Shelley {
93d84ed6e9SZane Shelley     libhei::ChipType_t type;
94d84ed6e9SZane Shelley 
95d84ed6e9SZane Shelley     // START WORKAROUND
96d84ed6e9SZane Shelley     // TODO: Will need to grab the model/level from the target attributes when
97d84ed6e9SZane Shelley     //       they are available. For now, use ATTR_TYPE to determine which
98d84ed6e9SZane Shelley     //       currently supported value to use supported.
992f263181SZane Shelley     uint8_t attrType = __attrType(i_trgt);
1002f263181SZane Shelley     switch (attrType)
101d84ed6e9SZane Shelley     {
102d84ed6e9SZane Shelley         case 0x05: // PROC
103d84ed6e9SZane Shelley             type = 0x120DA049;
104d84ed6e9SZane Shelley             break;
105d84ed6e9SZane Shelley 
106d84ed6e9SZane Shelley         case 0x4b: // OCMB_CHIP
107d84ed6e9SZane Shelley             type = 0x160D2000;
108d84ed6e9SZane Shelley             break;
109d84ed6e9SZane Shelley 
110d84ed6e9SZane Shelley         default:
1112f263181SZane Shelley             trace::err("Unsupported ATTR_TYPE value: 0x%02x", attrType);
112d84ed6e9SZane Shelley             assert(0);
113d84ed6e9SZane Shelley     }
114d84ed6e9SZane Shelley     // END WORKAROUND
115d84ed6e9SZane Shelley 
116d84ed6e9SZane Shelley     return type;
117d84ed6e9SZane Shelley }
118d84ed6e9SZane Shelley 
119d84ed6e9SZane Shelley //------------------------------------------------------------------------------
120d84ed6e9SZane Shelley 
121*f4bd5ff6SZane Shelley // Gathers list of active chips to analyze.
122*f4bd5ff6SZane Shelley void __getActiveChips(std::vector<libhei::Chip>& o_chips)
123d84ed6e9SZane Shelley {
124d84ed6e9SZane Shelley     // Iterate each processor.
125d84ed6e9SZane Shelley     pdbg_target* procTrgt;
126d84ed6e9SZane Shelley     pdbg_for_each_class_target("proc", procTrgt)
127d84ed6e9SZane Shelley     {
128d84ed6e9SZane Shelley         // Active processors only.
129d84ed6e9SZane Shelley         if (PDBG_TARGET_ENABLED != pdbg_target_probe(procTrgt))
130d84ed6e9SZane Shelley             continue;
131d84ed6e9SZane Shelley 
132d84ed6e9SZane Shelley         // Add the processor to the list.
133*f4bd5ff6SZane Shelley         o_chips.emplace_back(procTrgt, __getChipType(procTrgt));
134d84ed6e9SZane Shelley 
135d84ed6e9SZane Shelley         // Iterate the connected OCMBs, if they exist.
136d84ed6e9SZane Shelley         pdbg_target* ocmbTrgt;
13706e10f91SZane Shelley         pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt)
138d84ed6e9SZane Shelley         {
139d84ed6e9SZane Shelley             // Active OCMBs only.
140d84ed6e9SZane Shelley             if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt))
141d84ed6e9SZane Shelley                 continue;
142d84ed6e9SZane Shelley 
143d84ed6e9SZane Shelley             // Add the OCMB to the list.
144*f4bd5ff6SZane Shelley             o_chips.emplace_back(ocmbTrgt, __getChipType(ocmbTrgt));
145d84ed6e9SZane Shelley         }
146d84ed6e9SZane Shelley     }
1472e994bcdSZane Shelley }
1482e994bcdSZane Shelley 
1492e994bcdSZane Shelley //------------------------------------------------------------------------------
1502e994bcdSZane Shelley 
151097a71adSZane Shelley // Takes a signature list that will be filtered and sorted. The first entry in
152097a71adSZane Shelley // the returned list will be the root cause. If the returned list is empty,
153097a71adSZane Shelley // analysis failed.
154097a71adSZane Shelley void __filterRootCause(std::vector<libhei::Signature>& io_list)
155097a71adSZane Shelley {
1562f263181SZane Shelley     // For debug, trace out the original list of signatures before filtering.
1572f263181SZane Shelley     for (const auto& sig : io_list)
1582f263181SZane Shelley     {
159*f4bd5ff6SZane Shelley         trace::inf("Signature: %s 0x%0" PRIx32 " %s",
160*f4bd5ff6SZane Shelley                    util::pdbg::getPath(sig.getChip()), __sig(sig),
161*f4bd5ff6SZane Shelley                    __attn(sig.getAttnType()));
1622f263181SZane Shelley     }
1632f263181SZane Shelley 
164097a71adSZane Shelley     // Special and host attentions are not supported by this user application.
165097a71adSZane Shelley     auto newEndItr =
166097a71adSZane Shelley         std::remove_if(io_list.begin(), io_list.end(), [&](const auto& t) {
167097a71adSZane Shelley             return (libhei::ATTN_TYPE_SP_ATTN == t.getAttnType() ||
168097a71adSZane Shelley                     libhei::ATTN_TYPE_HOST_ATTN == t.getAttnType());
169097a71adSZane Shelley         });
170097a71adSZane Shelley 
171097a71adSZane Shelley     // Shrink the vector, if needed.
172097a71adSZane Shelley     io_list.resize(std::distance(io_list.begin(), newEndItr));
173097a71adSZane Shelley 
174097a71adSZane Shelley     // START WORKAROUND
175097a71adSZane Shelley     // TODO: Filtering should be determined by the RAS Data Files provided by
176097a71adSZane Shelley     //       the host firmware via the PNOR (similar to the Chip Data Files).
177097a71adSZane Shelley     //       Until that support is available, use a rudimentary filter that
178097a71adSZane Shelley     //       first looks for any recoverable attention, then any unit checkstop,
179097a71adSZane Shelley     //       and then any system checkstop. This is built on the premise that
180097a71adSZane Shelley     //       recoverable errors could be the root cause of an system checkstop
181097a71adSZane Shelley     //       attentions. Fortunately, we just need to sort the list by the
182097a71adSZane Shelley     //       greater attention type value.
183097a71adSZane Shelley     std::sort(io_list.begin(), io_list.end(),
184097a71adSZane Shelley               [&](const auto& a, const auto& b) {
185097a71adSZane Shelley                   return a.getAttnType() > b.getAttnType();
186097a71adSZane Shelley               });
187097a71adSZane Shelley     // END WORKAROUND
188097a71adSZane Shelley }
189097a71adSZane Shelley 
190097a71adSZane Shelley //------------------------------------------------------------------------------
191097a71adSZane Shelley 
1929fb7393eSZane Shelley bool __logError(const std::vector<libhei::Signature>& i_sigList,
1939fb7393eSZane Shelley                 const libhei::IsolationData& i_isoData)
1949fb7393eSZane Shelley {
1959fb7393eSZane Shelley     bool attnFound = false;
1969fb7393eSZane Shelley 
1979fb7393eSZane Shelley     // Get numerical values for the root cause.
1989fb7393eSZane Shelley     uint32_t word6 = 0; // [ 0: 7]: chip target type
1999fb7393eSZane Shelley                         // [ 8:31]: chip FAPI position
2009fb7393eSZane Shelley                         //    uint32_t word7 = 0; // TODO: chip target info
2019fb7393eSZane Shelley     uint32_t word8 = 0; // [ 0:15]: node ID
2029fb7393eSZane Shelley                         // [16:23]: node instance
2039fb7393eSZane Shelley                         // [24:31]: bit position
2049fb7393eSZane Shelley                         //    uint32_t word9 = 0; // [ 0: 7]: attention type
2059fb7393eSZane Shelley 
2069fb7393eSZane Shelley     if (i_sigList.empty())
2079fb7393eSZane Shelley     {
2089fb7393eSZane Shelley         trace::inf("No active attentions found");
2099fb7393eSZane Shelley     }
2109fb7393eSZane Shelley     else
2119fb7393eSZane Shelley     {
2129fb7393eSZane Shelley         attnFound = true;
2139fb7393eSZane Shelley 
2149fb7393eSZane Shelley         // The root cause attention is the first in the filtered list.
2159fb7393eSZane Shelley         libhei::Signature root = i_sigList.front();
2169fb7393eSZane Shelley 
2179fb7393eSZane Shelley         word6 = __trgt(root);
2189fb7393eSZane Shelley         word8 = __sig(root);
2199fb7393eSZane Shelley 
2209fb7393eSZane Shelley         trace::inf("Root cause attention: %s 0x%0" PRIx32 " %s",
221*f4bd5ff6SZane Shelley                    util::pdbg::getPath(root.getChip()), word8,
222*f4bd5ff6SZane Shelley                    __attn(root.getAttnType()));
2239fb7393eSZane Shelley     }
2249fb7393eSZane Shelley 
2259fb7393eSZane Shelley     // Get the log data.
2269fb7393eSZane Shelley     std::map<std::string, std::string> logData;
2279fb7393eSZane Shelley     logData["_PID"]      = std::to_string(getpid());
2289fb7393eSZane Shelley     logData["CHIP_ID"]   = std::to_string(word6);
2299fb7393eSZane Shelley     logData["SIGNATURE"] = std::to_string(word8);
2309fb7393eSZane Shelley 
2319fb7393eSZane Shelley     // Get access to logging interface and method for creating log.
2329fb7393eSZane Shelley     auto bus = sdbusplus::bus::new_default_system();
2339fb7393eSZane Shelley 
2349fb7393eSZane Shelley     // Using direct create method (for additional data)
2359fb7393eSZane Shelley     auto method = bus.new_method_call(
2369fb7393eSZane Shelley         "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
2379fb7393eSZane Shelley         "xyz.openbmc_project.Logging.Create", "Create");
2389fb7393eSZane Shelley 
2399fb7393eSZane Shelley     // Attach additional data
2409fb7393eSZane Shelley     method.append("org.open_power.HwDiags.Error.Checkstop",
2419fb7393eSZane Shelley                   "xyz.openbmc_project.Logging.Entry.Level.Error", logData);
2429fb7393eSZane Shelley 
2439fb7393eSZane Shelley     // Log the event.
2449fb7393eSZane Shelley     // TODO: Should the reply be handled?
2459fb7393eSZane Shelley     bus.call(method);
2469fb7393eSZane Shelley 
2479fb7393eSZane Shelley     return attnFound;
2489fb7393eSZane Shelley }
2499fb7393eSZane Shelley 
2509fb7393eSZane Shelley //------------------------------------------------------------------------------
2519fb7393eSZane Shelley 
2529fb7393eSZane Shelley bool analyzeHardware()
25387eabc65SBen Tyner {
254097a71adSZane Shelley     bool attnFound = false;
25587eabc65SBen Tyner 
2562f263181SZane Shelley     trace::inf(">>> enter analyzeHardware()");
2572f263181SZane Shelley 
258*f4bd5ff6SZane Shelley     // Get the active chips to be analyzed.
259*f4bd5ff6SZane Shelley     std::vector<libhei::Chip> chips;
260*f4bd5ff6SZane Shelley     __getActiveChips(chips);
26187eabc65SBen Tyner 
262*f4bd5ff6SZane Shelley     // Initialize the isolator for all chips.
263*f4bd5ff6SZane Shelley     trace::inf("Initializing the isolator...");
264*f4bd5ff6SZane Shelley     initializeIsolator(chips);
2652e994bcdSZane Shelley 
266097a71adSZane Shelley     // Isolate attentions.
267*f4bd5ff6SZane Shelley     trace::inf("Isolating errors: # of chips=%u", chips.size());
268097a71adSZane Shelley     libhei::IsolationData isoData{};
269*f4bd5ff6SZane Shelley     libhei::isolate(chips, isoData);
27087eabc65SBen Tyner 
2712f263181SZane Shelley     // Filter signatures to determine root cause. We'll need to make a copy of
2722f263181SZane Shelley     // the list so that the original list is maintained for the log.
273097a71adSZane Shelley     std::vector<libhei::Signature> sigList{isoData.getSignatureList()};
274097a71adSZane Shelley     __filterRootCause(sigList);
275097a71adSZane Shelley 
2769fb7393eSZane Shelley     // Create and commit a log.
2779fb7393eSZane Shelley     attnFound = __logError(sigList, isoData);
27887eabc65SBen Tyner 
279097a71adSZane Shelley     // All done, clean up the isolator.
280*f4bd5ff6SZane Shelley     trace::inf("Uninitializing isolator...");
281097a71adSZane Shelley     libhei::uninitialize();
282b1ebfcb1SBen Tyner 
2832f263181SZane Shelley     trace::inf("<<< exit analyzeHardware()");
2842f263181SZane Shelley 
285097a71adSZane Shelley     return attnFound;
2860205f3b3SBen Tyner }
2870205f3b3SBen Tyner 
2880205f3b3SBen Tyner } // namespace analyzer
289