1 #include <analyzer/plugins/plugin.hpp>
2 #include <analyzer/resolution.hpp>
3 #include <util/pdbg.hpp>
4 #include <util/trace.hpp>
5 
6 namespace analyzer
7 {
8 
9 //------------------------------------------------------------------------------
10 
11 // Helper function to get the root cause chip target from the service data.
12 pdbg_target* __getRootCauseChipTarget(const ServiceData& i_sd)
13 {
14     auto target = util::pdbg::getTrgt(i_sd.getRootCause().getChip());
15     assert(nullptr != target); // This would be a really bad bug.
16     return target;
17 }
18 
19 //------------------------------------------------------------------------------
20 
21 // Helper function to get a unit target from the given unit path, which is a
22 // devtree path relative the the containing chip. An empty string indicates the
23 // chip target should be returned.
24 pdbg_target* __getUnitTarget(pdbg_target* i_chipTarget,
25                              const std::string& i_unitPath)
26 {
27     assert(nullptr != i_chipTarget);
28 
29     auto target = i_chipTarget; // default, if i_unitPath is empty
30 
31     if (!i_unitPath.empty())
32     {
33         auto path = std::string{util::pdbg::getPath(target)} + "/" + i_unitPath;
34 
35         target = util::pdbg::getTrgt(path);
36         if (nullptr == target)
37         {
38             // Likely a bug the RAS data files.
39             throw std::logic_error("Unable to find target for " + path);
40         }
41     }
42 
43     return target;
44 }
45 
46 //------------------------------------------------------------------------------
47 
48 // Helper function to get the connected target on the other side of the
49 // given bus.
50 pdbg_target* __getConnectedTarget(pdbg_target* i_rxTarget,
51                                   const callout::BusType& i_busType)
52 {
53     assert(nullptr != i_rxTarget);
54 
55     pdbg_target* txTarget = nullptr;
56 
57     auto rxType        = util::pdbg::getTrgtType(i_rxTarget);
58     std::string rxPath = util::pdbg::getPath(i_rxTarget);
59 
60     if (callout::BusType::SMP_BUS == i_busType &&
61         util::pdbg::TYPE_IOLINK == rxType)
62     {
63         // TODO: Will need to reference some sort of data that can tell us how
64         //       the processors are connected in the system. For now, return the
65         //       RX target to avoid returning a nullptr.
66         trace::inf("No support to get peer target on SMP bus");
67         txTarget = i_rxTarget;
68     }
69     else if (callout::BusType::SMP_BUS == i_busType &&
70              util::pdbg::TYPE_IOHS == rxType)
71     {
72         // TODO: Will need to reference some sort of data that can tell us how
73         //       the processors are connected in the system. For now, return the
74         //       RX target to avoid returning a nullptr.
75         trace::inf("No support to get peer target on SMP bus");
76         txTarget = i_rxTarget;
77     }
78     else if (callout::BusType::OMI_BUS == i_busType &&
79              util::pdbg::TYPE_OMI == rxType)
80     {
81         // This is a bit clunky. The pdbg APIs only give us the ability to
82         // iterate over the children instead of just returning a list. So we'll
83         // push all the children to a list and go from there.
84         std::vector<pdbg_target*> childList;
85 
86         pdbg_target* childTarget = nullptr;
87         pdbg_for_each_target("ocmb", i_rxTarget, childTarget)
88         {
89             if (nullptr != childTarget)
90             {
91                 childList.push_back(childTarget);
92             }
93         }
94 
95         // We know there should only be one OCMB per OMI.
96         if (1 != childList.size())
97         {
98             throw std::logic_error("Invalid child list size for " + rxPath);
99         }
100 
101         // Get the connected target.
102         txTarget = childList.front();
103     }
104     else if (callout::BusType::OMI_BUS == i_busType &&
105              util::pdbg::TYPE_OCMB == rxType)
106     {
107         txTarget = pdbg_target_parent("omi", i_rxTarget);
108         if (nullptr == txTarget)
109         {
110             throw std::logic_error("No parent OMI found for " + rxPath);
111         }
112     }
113     else
114     {
115         // This would be a code bug.
116         throw std::logic_error("Unsupported config: i_rxTarget=" + rxPath +
117                                " i_busType=" + i_busType.getString());
118     }
119 
120     assert(nullptr != txTarget); // just in case we missed something above
121 
122     return txTarget;
123 }
124 
125 //------------------------------------------------------------------------------
126 
127 void __calloutTarget(ServiceData& io_sd, pdbg_target* i_target,
128                      const callout::Priority& i_priority, bool i_guard)
129 {
130     nlohmann::json callout;
131     callout["LocationCode"] = util::pdbg::getLocationCode(i_target);
132     callout["Priority"]     = i_priority.getUserDataString();
133     callout["Deconfigured"] = false;
134     callout["Guarded"]      = false; // default
135 
136     // Check if guard info should be added.
137     if (i_guard)
138     {
139         auto guardType = io_sd.queryGuardPolicy();
140 
141         if (!(callout::GuardType::NONE == guardType))
142         {
143             callout["Guarded"]    = true;
144             callout["EntityPath"] = util::pdbg::getPhysBinPath(i_target);
145             callout["GuardType"]  = guardType.getString();
146         }
147     }
148 
149     io_sd.addCallout(callout);
150 }
151 
152 //------------------------------------------------------------------------------
153 
154 void __calloutBackplane(ServiceData& io_sd, const callout::Priority& i_priority)
155 {
156     // TODO: There isn't a device tree object for this. So will need to hardcode
157     //       the location code for now. In the future, we will need a mechanism
158     //       to make this data driven.
159 
160     nlohmann::json callout;
161     callout["LocationCode"] = "P0";
162     callout["Priority"]     = i_priority.getUserDataString();
163     callout["Deconfigured"] = false;
164     callout["Guarded"]      = false;
165     io_sd.addCallout(callout);
166 }
167 
168 //------------------------------------------------------------------------------
169 
170 void HardwareCalloutResolution::resolve(ServiceData& io_sd) const
171 {
172     // Get the target for the hardware callout.
173     auto target = __getUnitTarget(__getRootCauseChipTarget(io_sd), iv_unitPath);
174 
175     // Add the actual callout to the service data.
176     __calloutTarget(io_sd, target, iv_priority, iv_guard);
177 
178     // Add the callout FFDC to the service data.
179     nlohmann::json ffdc;
180     ffdc["Callout Type"] = "Hardware Callout";
181     ffdc["Target"]       = util::pdbg::getPhysDevPath(target);
182     ffdc["Priority"]     = iv_priority.getRegistryString();
183     ffdc["Guard"]        = iv_guard;
184     io_sd.addCalloutFFDC(ffdc);
185 }
186 
187 //------------------------------------------------------------------------------
188 
189 void ConnectedCalloutResolution::resolve(ServiceData& io_sd) const
190 {
191     // Get the chip target from the root cause signature.
192     auto chipTarget = __getRootCauseChipTarget(io_sd);
193 
194     // Get the endpoint target for the receiving side of the bus.
195     auto rxTarget = __getUnitTarget(chipTarget, iv_unitPath);
196 
197     // Get the endpoint target for the transfer side of the bus.
198     auto txTarget = __getConnectedTarget(rxTarget, iv_busType);
199 
200     // Callout the TX endpoint.
201     __calloutTarget(io_sd, txTarget, iv_priority, iv_guard);
202 
203     // Add the callout FFDC to the service data.
204     nlohmann::json ffdc;
205     ffdc["Callout Type"] = "Connected Callout";
206     ffdc["Bus Type"]     = iv_busType.getString();
207     ffdc["Target"]       = util::pdbg::getPhysDevPath(txTarget);
208     ffdc["Priority"]     = iv_priority.getRegistryString();
209     ffdc["Guard"]        = iv_guard;
210     io_sd.addCalloutFFDC(ffdc);
211 }
212 
213 //------------------------------------------------------------------------------
214 
215 void BusCalloutResolution::resolve(ServiceData& io_sd) const
216 {
217     // Get the chip target from the root cause signature.
218     auto chipTarget = __getRootCauseChipTarget(io_sd);
219 
220     // Get the endpoint target for the receiving side of the bus.
221     auto rxTarget = __getUnitTarget(chipTarget, iv_unitPath);
222 
223     // Get the endpoint target for the transfer side of the bus.
224     auto txTarget = __getConnectedTarget(rxTarget, iv_busType);
225 
226     // Callout the RX endpoint.
227     __calloutTarget(io_sd, rxTarget, iv_priority, iv_guard);
228 
229     // Callout the TX endpoint.
230     __calloutTarget(io_sd, txTarget, iv_priority, iv_guard);
231 
232     // Callout everything else in between.
233     // TODO: For P10 (OMI bus and XBUS), the callout is simply the backplane.
234     __calloutBackplane(io_sd, iv_priority);
235 
236     // Add the callout FFDC to the service data.
237     nlohmann::json ffdc;
238     ffdc["Callout Type"] = "Bus Callout";
239     ffdc["Bus Type"]     = iv_busType.getString();
240     ffdc["RX Target"]    = util::pdbg::getPhysDevPath(rxTarget);
241     ffdc["TX Target"]    = util::pdbg::getPhysDevPath(txTarget);
242     ffdc["Priority"]     = iv_priority.getRegistryString();
243     ffdc["Guard"]        = iv_guard;
244     io_sd.addCalloutFFDC(ffdc);
245 }
246 
247 //------------------------------------------------------------------------------
248 
249 void ClockCalloutResolution::resolve(ServiceData& io_sd) const
250 {
251     // Callout the clock target.
252     // TODO: For P10, the callout is simply the backplane. Also, there are no
253     //       clock targets in the device tree. So at the moment there is no
254     //       guard support for clock targets.
255     __calloutBackplane(io_sd, iv_priority);
256 
257     // Add the callout FFDC to the service data.
258     // TODO: Add the target and guard type if guard is ever supported.
259     nlohmann::json ffdc;
260     ffdc["Callout Type"] = "Clock Callout";
261     ffdc["Clock Type"]   = iv_clockType.getString();
262     ffdc["Priority"]     = iv_priority.getRegistryString();
263     io_sd.addCalloutFFDC(ffdc);
264 }
265 
266 //------------------------------------------------------------------------------
267 
268 void ProcedureCalloutResolution::resolve(ServiceData& io_sd) const
269 {
270     // Add the actual callout to the service data.
271     nlohmann::json callout;
272     callout["Procedure"] = iv_procedure.getString();
273     callout["Priority"]  = iv_priority.getUserDataString();
274     io_sd.addCallout(callout);
275 
276     // Add the callout FFDC to the service data.
277     nlohmann::json ffdc;
278     ffdc["Callout Type"] = "Procedure Callout";
279     ffdc["Procedure"]    = iv_procedure.getString();
280     ffdc["Priority"]     = iv_priority.getRegistryString();
281     io_sd.addCalloutFFDC(ffdc);
282 }
283 
284 //------------------------------------------------------------------------------
285 
286 void PluginResolution::resolve(ServiceData& io_sd) const
287 {
288     // Get the plugin function and call it.
289 
290     auto chip = io_sd.getRootCause().getChip();
291 
292     auto func = PluginMap::getSingleton().get(chip.getType(), iv_name);
293 
294     func(iv_instance, chip, io_sd);
295 }
296 
297 //------------------------------------------------------------------------------
298 
299 } // namespace analyzer
300