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