1 #include <analyzer/service_data.hpp>
2 
3 namespace analyzer
4 {
5 
6 //------------------------------------------------------------------------------
7 
8 void ServiceData::calloutTarget(pdbg_target* i_target,
9                                 callout::Priority i_priority, bool i_guard)
10 {
11     // Add the target to the callout list.
12     addTargetCallout(i_target, i_priority, i_guard);
13 
14     // Add the callout FFDC.
15     nlohmann::json ffdc;
16     ffdc["Callout Type"] = "Hardware Callout";
17     ffdc["Target"]       = util::pdbg::getPhysDevPath(i_target);
18     ffdc["Priority"]     = callout::getStringFFDC(i_priority);
19     ffdc["Guard"]        = i_guard;
20     addCalloutFFDC(ffdc);
21     setSrcSubsystem(getTargetSubsystem(i_target), i_priority);
22 }
23 
24 //------------------------------------------------------------------------------
25 
26 void ServiceData::calloutConnected(pdbg_target* i_rxTarget,
27                                    const callout::BusType& i_busType,
28                                    callout::Priority i_priority, bool i_guard)
29 {
30     // Get the endpoint target for the transfer side of the bus.
31     auto txTarget = util::pdbg::getConnectedTarget(i_rxTarget, i_busType);
32 
33     // Callout the TX endpoint.
34     addTargetCallout(txTarget, i_priority, i_guard);
35 
36     // Add the callout FFDC.
37     nlohmann::json ffdc;
38     ffdc["Callout Type"] = "Connected Callout";
39     ffdc["Bus Type"]     = i_busType.getString();
40     ffdc["RX Target"]    = util::pdbg::getPhysDevPath(i_rxTarget);
41     ffdc["TX Target"]    = util::pdbg::getPhysDevPath(txTarget);
42     ffdc["Priority"]     = callout::getStringFFDC(i_priority);
43     ffdc["Guard"]        = i_guard;
44     addCalloutFFDC(ffdc);
45     setSrcSubsystem(getTargetSubsystem(txTarget), i_priority);
46 }
47 
48 //------------------------------------------------------------------------------
49 
50 void ServiceData::calloutBus(pdbg_target* i_rxTarget,
51                              const callout::BusType& i_busType,
52                              callout::Priority i_priority, bool i_guard)
53 {
54     // Get the endpoint target for the transfer side of the bus.
55     auto txTarget = util::pdbg::getConnectedTarget(i_rxTarget, i_busType);
56 
57     // Callout the RX endpoint.
58     addTargetCallout(i_rxTarget, i_priority, i_guard);
59 
60     // Callout the TX endpoint.
61     addTargetCallout(txTarget, i_priority, i_guard);
62 
63     // Callout everything else in between.
64     // TODO: For P10 (OMI bus and XBUS), the callout is simply the backplane.
65     addBackplaneCallout(i_priority);
66 
67     // Add the callout FFDC.
68     nlohmann::json ffdc;
69     ffdc["Callout Type"] = "Bus Callout";
70     ffdc["Bus Type"]     = i_busType.getString();
71     ffdc["RX Target"]    = util::pdbg::getPhysDevPath(i_rxTarget);
72     ffdc["TX Target"]    = util::pdbg::getPhysDevPath(txTarget);
73     ffdc["Priority"]     = callout::getStringFFDC(i_priority);
74     ffdc["Guard"]        = i_guard;
75     addCalloutFFDC(ffdc);
76     setSrcSubsystem(i_busType.getSrcSubsystem(), i_priority);
77 }
78 
79 //------------------------------------------------------------------------------
80 
81 void ServiceData::calloutClock(const callout::ClockType& i_clockType,
82                                callout::Priority i_priority, bool)
83 {
84     // Callout the clock target.
85     // TODO: For P10, the callout is simply the backplane. Also, there are no
86     //       clock targets in the device tree. So at the moment there is no
87     //       guard support for clock targets.
88     addBackplaneCallout(i_priority);
89 
90     // Add the callout FFDC.
91     // TODO: Add the target and guard type if guard is ever supported.
92     nlohmann::json ffdc;
93     ffdc["Callout Type"] = "Clock Callout";
94     ffdc["Clock Type"]   = i_clockType.getString();
95     ffdc["Priority"]     = callout::getStringFFDC(i_priority);
96     addCalloutFFDC(ffdc);
97     setSrcSubsystem(i_clockType.getSrcSubsystem(), i_priority);
98 }
99 
100 //------------------------------------------------------------------------------
101 
102 void ServiceData::calloutProcedure(const callout::Procedure& i_procedure,
103                                    callout::Priority i_priority)
104 {
105     // Add the actual callout to the service data.
106     nlohmann::json callout;
107     callout["Procedure"] = i_procedure.getString();
108     callout["Priority"]  = callout::getString(i_priority);
109     addCallout(callout);
110 
111     // Add the callout FFDC.
112     nlohmann::json ffdc;
113     ffdc["Callout Type"] = "Procedure Callout";
114     ffdc["Procedure"]    = i_procedure.getString();
115     ffdc["Priority"]     = callout::getStringFFDC(i_priority);
116     addCalloutFFDC(ffdc);
117     setSrcSubsystem(i_procedure.getSrcSubsystem(), i_priority);
118 }
119 
120 //------------------------------------------------------------------------------
121 
122 void ServiceData::calloutPart(const callout::PartType& i_part,
123                               callout::Priority i_priority)
124 {
125     if (callout::PartType::PNOR == i_part)
126     {
127         // The PNOR is on the BMC card.
128         // TODO: Will need to be modified if we ever support systems with more
129         //       than one BMC.
130         addTargetCallout(util::pdbg::getTrgt("/bmc0"), i_priority, false);
131     }
132     else
133     {
134         throw std::logic_error("Unsupported part type: " + i_part.getString());
135     }
136 
137     // Add the callout FFDC.
138     nlohmann::json ffdc;
139     ffdc["Callout Type"] = "Part Callout";
140     ffdc["Part Type"]    = i_part.getString();
141     ffdc["Priority"]     = callout::getStringFFDC(i_priority);
142     addCalloutFFDC(ffdc);
143     setSrcSubsystem(i_part.getSrcSubsystem(), i_priority);
144 }
145 
146 //------------------------------------------------------------------------------
147 
148 void ServiceData::addCallout(const nlohmann::json& i_callout)
149 {
150     // The new callout is either a hardware callout with a location code or a
151     // procedure callout.
152 
153     std::string type{};
154     if (i_callout.contains("LocationCode"))
155     {
156         type = "LocationCode";
157     }
158     else if (i_callout.contains("Procedure"))
159     {
160         type = "Procedure";
161     }
162     else
163     {
164         throw std::logic_error("Unsupported callout: " + i_callout.dump());
165     }
166 
167     // A map to determine the priority order. All of the medium priorities,
168     // including the medium group priorities, are all the same level.
169     // clang-format off
170     static const std::map<std::string, unsigned int> m = {
171         {callout::getString(callout::Priority::HIGH),  3},
172         {callout::getString(callout::Priority::MED),   2},
173         {callout::getString(callout::Priority::MED_A), 2},
174         {callout::getString(callout::Priority::MED_B), 2},
175         {callout::getString(callout::Priority::MED_C), 2},
176         {callout::getString(callout::Priority::LOW),   1},
177     };
178     // clang-format on
179 
180     // The new callout must contain a valid priority.
181     assert(i_callout.contains("Priority") &&
182            m.contains(i_callout.at("Priority")));
183 
184     bool addCallout = true;
185 
186     for (auto& c : iv_calloutList)
187     {
188         if (c.contains(type) && (c.at(type) == i_callout.at(type)))
189         {
190             // The new callout already exists. Don't add a new callout.
191             addCallout = false;
192 
193             if (m.at(c.at("Priority")) < m.at(i_callout.at("Priority")))
194             {
195                 // The new callout has a higher priority, update it.
196                 c["Priority"] = i_callout.at("Priority");
197             }
198         }
199     }
200 
201     if (addCallout)
202     {
203         iv_calloutList.push_back(i_callout);
204     }
205 }
206 
207 //------------------------------------------------------------------------------
208 
209 void ServiceData::addTargetCallout(pdbg_target* i_target,
210                                    callout::Priority i_priority, bool i_guard)
211 {
212     nlohmann::json callout;
213 
214     callout["LocationCode"] = util::pdbg::getLocationCode(i_target);
215     callout["Priority"]     = callout::getString(i_priority);
216     callout["Deconfigured"] = false;
217     callout["Guarded"]      = false; // default
218 
219     // Check if guard info should be added.
220     if (i_guard)
221     {
222         auto guardType = queryGuardPolicy();
223 
224         if (!(callout::GuardType::NONE == guardType))
225         {
226             callout["Guarded"]    = true;
227             callout["EntityPath"] = util::pdbg::getPhysBinPath(i_target);
228             callout["GuardType"]  = guardType.getString();
229         }
230     }
231 
232     addCallout(callout);
233 }
234 
235 //------------------------------------------------------------------------------
236 
237 void ServiceData::addBackplaneCallout(callout::Priority i_priority)
238 {
239     // TODO: There isn't a device tree object for this. So will need to hardcode
240     //       the location code for now. In the future, we will need a mechanism
241     //       to make this data driven.
242 
243     nlohmann::json callout;
244 
245     callout["LocationCode"] = "P0";
246     callout["Priority"]     = callout::getString(i_priority);
247     callout["Deconfigured"] = false;
248     callout["Guarded"]      = false;
249 
250     addCallout(callout);
251 }
252 
253 //------------------------------------------------------------------------------
254 
255 void ServiceData::setSrcSubsystem(callout::SrcSubsystem i_subsystem,
256                                   callout::Priority i_priority)
257 {
258     // clang-format off
259     static const std::map<callout::Priority, unsigned int> m =
260     {
261         // Note that all medium priorities, including groups A, B, and C, are
262         // the same priority.
263         {callout::Priority::HIGH,  3},
264         {callout::Priority::MED,   2},
265         {callout::Priority::MED_A, 2},
266         {callout::Priority::MED_B, 2},
267         {callout::Priority::MED_C, 2},
268         {callout::Priority::LOW,   1},
269     };
270     // clang-format on
271 
272     // The default subsystem is CEC_HARDWARE with LOW priority. Change the
273     // subsystem if the given subsystem has a higher priority or if the stored
274     // subsystem is still the default.
275     if (m.at(iv_srcSubsystem.second) < m.at(i_priority) ||
276         (callout::SrcSubsystem::CEC_HARDWARE == iv_srcSubsystem.first &&
277          callout::Priority::LOW == iv_srcSubsystem.second))
278     {
279         iv_srcSubsystem.first  = i_subsystem;
280         iv_srcSubsystem.second = i_priority;
281     }
282 }
283 
284 //------------------------------------------------------------------------------
285 
286 callout::SrcSubsystem ServiceData::getTargetSubsystem(pdbg_target* i_target)
287 {
288     using TargetType_t = util::pdbg::TargetType_t;
289 
290     // Default the subsystem to CEC_HARDWARE
291     callout::SrcSubsystem o_subSys = callout::SrcSubsystem::CEC_HARDWARE;
292 
293     // clang-format off
294     static const std::map<uint8_t, callout::SrcSubsystem> subSysMap =
295     {
296         {TargetType_t::TYPE_DIMM,     callout::SrcSubsystem::MEMORY_DIMM   },
297         {TargetType_t::TYPE_PROC,     callout::SrcSubsystem::PROCESSOR_FRU },
298         {TargetType_t::TYPE_CORE,     callout::SrcSubsystem::PROCESSOR_UNIT},
299         {TargetType_t::TYPE_NX,       callout::SrcSubsystem::PROCESSOR     },
300         {TargetType_t::TYPE_EQ,       callout::SrcSubsystem::PROCESSOR_UNIT},
301         {TargetType_t::TYPE_PEC,      callout::SrcSubsystem::PROCESSOR_UNIT},
302         {TargetType_t::TYPE_PHB,      callout::SrcSubsystem::PHB           },
303         {TargetType_t::TYPE_MC,       callout::SrcSubsystem::MEMORY_CTLR   },
304         {TargetType_t::TYPE_IOLINK,   callout::SrcSubsystem::PROCESSOR_BUS },
305         {TargetType_t::TYPE_OMI,      callout::SrcSubsystem::MEMORY_CTLR   },
306         {TargetType_t::TYPE_MCC,      callout::SrcSubsystem::MEMORY_CTLR   },
307         {TargetType_t::TYPE_OMIC,     callout::SrcSubsystem::MEMORY_CTLR   },
308         {TargetType_t::TYPE_OCMB,     callout::SrcSubsystem::MEMORY_FRU    },
309         {TargetType_t::TYPE_MEM_PORT, callout::SrcSubsystem::MEMORY_CTLR   },
310         {TargetType_t::TYPE_NMMU,     callout::SrcSubsystem::PROCESSOR_UNIT},
311         {TargetType_t::TYPE_PAU,      callout::SrcSubsystem::PROCESSOR_UNIT},
312         {TargetType_t::TYPE_IOHS,     callout::SrcSubsystem::PROCESSOR_UNIT},
313         {TargetType_t::TYPE_PAUC,     callout::SrcSubsystem::PROCESSOR_UNIT},
314     };
315     // clang-format on
316 
317     auto targetType = util::pdbg::getTrgtType(i_target);
318 
319     // If the type of the input target exists in the map, update the output
320     if (subSysMap.count(targetType) > 0)
321     {
322         o_subSys = subSysMap.at(targetType);
323     }
324 
325     return o_subSys;
326 }
327 
328 //------------------------------------------------------------------------------
329 
330 } // namespace analyzer
331