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 __calloutBackplane(ServiceData& io_sd, const callout::Priority& i_priority)
127 {
128     // TODO: There isn't a device tree object for this. So will need to hardcode
129     //       the location code for now. In the future, we will need a mechanism
130     //       to make this data driven.
131 
132     nlohmann::json callout;
133     callout["LocationCode"] = "P0";
134     callout["Priority"]     = i_priority.getUserDataString();
135     callout["Deconfigured"] = false;
136     callout["Guarded"]      = false;
137     io_sd.addCallout(callout);
138 }
139 
140 //------------------------------------------------------------------------------
141 
142 void HardwareCalloutResolution::resolve(ServiceData& io_sd) const
143 {
144     // Get the target for the hardware callout.
145     auto target = __getUnitTarget(__getRootCauseChipTarget(io_sd), iv_unitPath);
146 
147     // Get the location code and entity path for this target.
148     auto locCode    = util::pdbg::getLocationCode(target);
149     auto entityPath = util::pdbg::getPhysDevPath(target);
150 
151     // Add the actual callout to the service data.
152     nlohmann::json callout;
153     callout["LocationCode"] = locCode;
154     callout["Priority"]     = iv_priority.getUserDataString();
155     io_sd.addCallout(callout);
156 
157     // Add the guard info to the service data.
158     Guard guard = io_sd.addGuard(entityPath, iv_guard);
159 
160     // Add the callout FFDC to the service data.
161     nlohmann::json ffdc;
162     ffdc["Callout Type"] = "Hardware Callout";
163     ffdc["Target"]       = entityPath;
164     ffdc["Priority"]     = iv_priority.getRegistryString();
165     ffdc["Guard Type"]   = guard.getString();
166     io_sd.addCalloutFFDC(ffdc);
167 }
168 
169 //------------------------------------------------------------------------------
170 
171 void ConnectedCalloutResolution::resolve(ServiceData& io_sd) const
172 {
173     // Get the chip target from the root cause signature.
174     auto chipTarget = __getRootCauseChipTarget(io_sd);
175 
176     // Get the endpoint target for the receiving side of the bus.
177     auto rxTarget = __getUnitTarget(chipTarget, iv_unitPath);
178 
179     // Get the endpoint target for the transfer side of the bus.
180     auto txTarget = __getConnectedTarget(rxTarget, iv_busType);
181 
182     // Callout the TX endpoint.
183     nlohmann::json txCallout;
184     txCallout["LocationCode"] = util::pdbg::getLocationCode(txTarget);
185     txCallout["Priority"]     = iv_priority.getUserDataString();
186     io_sd.addCallout(txCallout);
187 
188     // Guard the TX endpoint.
189     Guard txGuard =
190         io_sd.addGuard(util::pdbg::getPhysDevPath(txTarget), iv_guard);
191 
192     // Add the callout FFDC to the service data.
193     nlohmann::json ffdc;
194     ffdc["Callout Type"] = "Connected Callout";
195     ffdc["Bus Type"]     = iv_busType.getString();
196     ffdc["Target"]       = util::pdbg::getPhysDevPath(txTarget);
197     ffdc["Priority"]     = iv_priority.getRegistryString();
198     ffdc["Guard Type"]   = txGuard.getString();
199     io_sd.addCalloutFFDC(ffdc);
200 }
201 
202 //------------------------------------------------------------------------------
203 
204 void BusCalloutResolution::resolve(ServiceData& io_sd) const
205 {
206     // Get the chip target from the root cause signature.
207     auto chipTarget = __getRootCauseChipTarget(io_sd);
208 
209     // Get the endpoint target for the receiving side of the bus.
210     auto rxTarget = __getUnitTarget(chipTarget, iv_unitPath);
211 
212     // Get the endpoint target for the transfer side of the bus.
213     auto txTarget = __getConnectedTarget(rxTarget, iv_busType);
214 
215     // Callout the RX endpoint.
216     nlohmann::json rxCallout;
217     rxCallout["LocationCode"] = util::pdbg::getLocationCode(rxTarget);
218     rxCallout["Priority"]     = iv_priority.getUserDataString();
219     io_sd.addCallout(rxCallout);
220 
221     // Callout the TX endpoint.
222     nlohmann::json txCallout;
223     txCallout["LocationCode"] = util::pdbg::getLocationCode(txTarget);
224     txCallout["Priority"]     = iv_priority.getUserDataString();
225     io_sd.addCallout(txCallout);
226 
227     // Callout everything else in between.
228     // TODO: For P10 (OMI bus and XBUS), the callout is simply the backplane.
229     __calloutBackplane(io_sd, iv_priority);
230 
231     // Guard the RX endpoint.
232     Guard guard =
233         io_sd.addGuard(util::pdbg::getPhysDevPath(rxTarget), iv_guard);
234 
235     // Guard the TX endpoint.
236     // No need to check return because it is the same as RX target.
237     io_sd.addGuard(util::pdbg::getPhysDevPath(txTarget), iv_guard);
238 
239     // TODO: Currently no guard for "everything else in between".
240 
241     // Add the callout FFDC to the service data.
242     nlohmann::json ffdc;
243     ffdc["Callout Type"] = "Bus Callout";
244     ffdc["Bus Type"]     = iv_busType.getString();
245     ffdc["RX Target"]    = util::pdbg::getPhysDevPath(rxTarget);
246     ffdc["TX Target"]    = util::pdbg::getPhysDevPath(txTarget);
247     ffdc["Priority"]     = iv_priority.getRegistryString();
248     ffdc["Guard Type"]   = guard.getString();
249     io_sd.addCalloutFFDC(ffdc);
250 }
251 
252 //------------------------------------------------------------------------------
253 
254 void ClockCalloutResolution::resolve(ServiceData& io_sd) const
255 {
256     // Callout the clock target.
257     // TODO: For P10, the callout is simply the backplane. Also, there are no
258     //       clock targets in the device tree. So at the moment there is no
259     //       guard support for clock targets.
260     __calloutBackplane(io_sd, iv_priority);
261 
262     // Add the callout FFDC to the service data.
263     // TODO: Add the target and guard type if guard is ever supported.
264     nlohmann::json ffdc;
265     ffdc["Callout Type"] = "Clock Callout";
266     ffdc["Clock Type"]   = iv_clockType.getString();
267     ffdc["Priority"]     = iv_priority.getRegistryString();
268     io_sd.addCalloutFFDC(ffdc);
269 }
270 
271 //------------------------------------------------------------------------------
272 
273 void ProcedureCalloutResolution::resolve(ServiceData& io_sd) const
274 {
275     // Add the actual callout to the service data.
276     nlohmann::json callout;
277     callout["Procedure"] = iv_procedure.getString();
278     callout["Priority"]  = iv_priority.getUserDataString();
279     io_sd.addCallout(callout);
280 
281     // Add the callout FFDC to the service data.
282     nlohmann::json ffdc;
283     ffdc["Callout Type"] = "Procedure Callout";
284     ffdc["Procedure"]    = iv_procedure.getString();
285     ffdc["Priority"]     = iv_priority.getRegistryString();
286     io_sd.addCalloutFFDC(ffdc);
287 }
288 
289 //------------------------------------------------------------------------------
290 
291 } // namespace analyzer
292