1 #include <libpdbg.h>
2 
3 #include <attn/attn_common.hpp>
4 #include <attn/attn_handler.hpp>
5 #include <attn/attn_logging.hpp>
6 #include <sdbusplus/bus.hpp>
7 #include <util/pdbg.hpp>
8 #include <util/trace.hpp>
9 
10 #include <iomanip>
11 #include <iostream>
12 #include <map>
13 
14 namespace attn
15 {
16 
17 /** @brief Traces some regs for hostboot */
addHbStatusRegs()18 void addHbStatusRegs()
19 {
20     // Only do this for P10 systems
21     if (util::pdbg::queryHardwareAnalysisSupported())
22     {
23         // We only need this for PRIMARY processor
24         pdbg_target* pibTarget = pdbg_target_from_path(nullptr, "/proc0/pib");
25         pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, "/proc0/fsi");
26 
27         uint32_t l_cfamData = 0xFFFFFFFF;
28         uint64_t l_scomData1 = 0xFFFFFFFFFFFFFFFFull;
29         uint64_t l_scomData2 = 0xFFFFFFFFFFFFFFFFull;
30         uint32_t l_cfamAddr = 0x283C;
31         uint64_t l_scomAddr1 = 0x4602F489;
32         uint64_t l_scomAddr2 = 0x4602F487;
33 
34         if ((nullptr != fsiTarget) && (nullptr != pibTarget))
35         {
36             // get first debug reg (CFAM)
37             if (RC_SUCCESS != fsi_read(fsiTarget, l_cfamAddr, &l_cfamData))
38             {
39                 trace::err("cfam read error: 0x%08x", l_cfamAddr);
40                 l_cfamData = 0xFFFFFFFF;
41             }
42 
43             // Get SCOM regs next (just 2 of them)
44             if (RC_SUCCESS != pib_read(pibTarget, l_scomAddr1, &l_scomData1))
45             {
46                 trace::err("scom read error: 0x%016" PRIx64 "", l_scomAddr1);
47                 l_scomData1 = 0xFFFFFFFFFFFFFFFFull;
48             }
49 
50             if (RC_SUCCESS != pib_read(pibTarget, l_scomAddr2, &l_scomData2))
51             {
52                 trace::err("scom read error: 0x%016" PRIx64 "", l_scomAddr2);
53                 l_scomData2 = 0xFFFFFFFFFFFFFFFFull;
54             }
55         }
56 
57         // Trace out the results here of all 3 regs
58         // (Format should resemble FSP: HostBoot Reg:0000283C  Data:AA801504
59         // 00000000  Proc:00050001 )
60         trace::inf("HostBoot Reg:%08x Data:%08x Proc:00000000", l_cfamAddr,
61                    l_cfamData);
62         trace::inf("HostBoot Reg:%08" PRIx64 " Data:%016" PRIx64
63                    " Proc:00000000",
64                    l_scomAddr1, l_scomData1);
65         trace::inf("HostBoot Reg:%08" PRIx64 " Data:%016" PRIx64
66                    " Proc:00000000",
67                    l_scomAddr2, l_scomData2);
68     }
69 
70     return;
71 
72 } // end addHbStatusRegs
73 
74 /** @brief Capture some scratch registers for PRD */
addPrdScratchRegs(std::vector<util::FFDCFile> & o_files)75 void addPrdScratchRegs(std::vector<util::FFDCFile>& o_files)
76 {
77     // Get primary processor FSI target for CFAM reads
78     pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, "/proc0/fsi");
79 
80     if (nullptr == fsiTarget)
81     {
82         trace::err("error getting scratch register target");
83     }
84     else
85     {
86         uint32_t chipId = 0;
87         uint32_t signatureId = 0;
88 
89         // get scratch register 9 (CFAM)
90         if (RC_SUCCESS != fsi_read(fsiTarget, 0x2980, &chipId))
91         {
92             trace::err("error reading scratch register 9");
93             chipId = 0;
94         }
95 
96         // get scratch register 10 (CFAM)
97         if (RC_SUCCESS != fsi_read(fsiTarget, 0x2981, &signatureId))
98         {
99             trace::err("error reading scratch register 10");
100             signatureId = 0;
101         }
102 
103         // Add data to traces and create user data section
104         if (0 != chipId || 0 != signatureId)
105         {
106             // trace scratch register data
107             trace::inf("PRD scratch Proc0, Chip ID: %08x, Signature ID: %08x",
108                        chipId, signatureId);
109 
110             // create ffdc data for user data section
111             try
112             {
113                 util::FFDCFile file{util::FFDCFormat::Text};
114                 int fd = file.getFileDescriptor();
115                 char buffer[150];
116                 int len = sprintf(buffer,
117                                   "Scratch Register Error Signature\n"
118                                   "Processor            : 0\n"
119                                   "Chip ID              : %08x\n"
120                                   "Signature ID         : %08x\n",
121                                   chipId, signatureId);
122                 if (write(fd, buffer, len) < 0)
123                 {
124                     trace::err("error writing scratch register user data");
125                 }
126                 else
127                 {
128                     o_files.push_back(std::move(file));
129                 }
130             }
131             catch (const std::exception& e)
132             {
133                 trace::err(
134                     "exception when creating scratch register user data");
135                 trace::inf(e.what());
136             }
137         }
138     }
139 
140     return;
141 }
142 
143 /** @brief Check for recoverable errors present */
recoverableErrors()144 bool recoverableErrors()
145 {
146     bool recoverableErrors = false; // assume no recoverable attentions
147 
148     pdbg_target* target;
149     pdbg_for_each_class_target("proc", target)
150     {
151         if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
152         {
153             auto proc = pdbg_target_index(target); // get processor number
154 
155             // Use PIB target to determine if a processor is enabled
156             char path[16];
157             sprintf(path, "/proc%d/pib", proc);
158             pdbg_target* pibTarget = pdbg_target_from_path(nullptr, path);
159 
160             // sanity check
161             if (nullptr == pibTarget)
162             {
163                 trace::inf("pib path or target not found");
164                 continue;
165             }
166 
167             // check if pib target is enabled - indicates proc is enabled
168             if (PDBG_TARGET_ENABLED == pdbg_target_probe(pibTarget))
169             {
170                 // The processor FSI target is required for CFAM read
171                 sprintf(path, "/proc%d/fsi", proc);
172                 pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path);
173 
174                 // sanity check
175                 if (nullptr == fsiTarget)
176                 {
177                     trace::inf("fsi path or target not found");
178                     continue;
179                 }
180 
181                 uint32_t isr_val = 0xffffffff; // invalid isr value
182 
183                 // get active attentions on processor
184                 if (RC_SUCCESS != fsi_read(fsiTarget, 0x1007, &isr_val))
185                 {
186                     // log cfam read error
187                     trace::err("cfam read 0x1007 FAILED");
188                     eventAttentionFail(
189                         (int)AttnSection::attnHandler | ATTN_PDBG_CFAM);
190                 }
191                 // check for invalid/stale value
192                 else if (0xffffffff == isr_val)
193                 {
194                     trace::err("cfam read 0x1007 INVALID");
195                     continue;
196                 }
197                 // check recoverable error status bit
198                 else if (0 != (isr_val & RECOVERABLE_ATTN))
199                 {
200                     recoverableErrors = true;
201                     break;
202                 }
203             } // fsi target enabled
204         } // pib target enabled
205     } // next processor
206 
207     return recoverableErrors;
208 }
209 
210 /** @brief timesec less-than-equal-to compare */
operator <=(const timespec & lhs,const timespec & rhs)211 bool operator<=(const timespec& lhs, const timespec& rhs)
212 {
213     if (lhs.tv_sec == rhs.tv_sec)
214         return lhs.tv_nsec <= rhs.tv_nsec;
215     else
216         return lhs.tv_sec <= rhs.tv_sec;
217 }
218 
219 /** @brief sleep for n-seconds */
sleepSeconds(const unsigned int seconds)220 void sleepSeconds(const unsigned int seconds)
221 {
222     auto count = seconds;
223     struct timespec requested, remaining;
224 
225     while (0 < count)
226     {
227         requested.tv_sec = 1;
228         requested.tv_nsec = 0;
229         remaining = requested;
230 
231         while (-1 == nanosleep(&requested, &remaining))
232         {
233             // if not changing or implausible then abort
234             if (requested <= remaining)
235             {
236                 break;
237             }
238 
239             // back to sleep
240             requested = remaining;
241         }
242         count--;
243     }
244 }
245 
246 } // namespace attn
247