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::OMI_BUS == i_busType &&
69              util::pdbg::TYPE_OMI == rxType)
70     {
71         // This is a bit clunky. The pdbg APIs only give us the ability to
72         // iterate over the children instead of just returning a list. So we'll
73         // push all the children to a list and go from there.
74         std::vector<pdbg_target*> childList;
75 
76         pdbg_target* childTarget = nullptr;
77         pdbg_for_each_target("ocmb", i_rxTarget, childTarget)
78         {
79             if (nullptr != childTarget)
80             {
81                 childList.push_back(childTarget);
82             }
83         }
84 
85         // We know there should only be one OCMB per OMI.
86         if (1 != childList.size())
87         {
88             throw std::logic_error("Invalid child list size for " + rxPath);
89         }
90 
91         // Get the connected target.
92         txTarget = childList.front();
93     }
94     else if (callout::BusType::OMI_BUS == i_busType &&
95              util::pdbg::TYPE_OCMB == rxType)
96     {
97         txTarget = pdbg_target_parent("omi", i_rxTarget);
98         if (nullptr == txTarget)
99         {
100             throw std::logic_error("No parent OMI found for " + rxPath);
101         }
102     }
103     else
104     {
105         // This would be a code bug.
106         throw std::logic_error("Unsupported config: i_rxTarget=" + rxPath +
107                                " i_busType=" + i_busType.getString());
108     }
109 
110     assert(nullptr != txTarget); // just in case we missed something above
111 
112     return txTarget;
113 }
114 
115 //------------------------------------------------------------------------------
116 
117 void HardwareCalloutResolution::resolve(ServiceData& io_sd) const
118 {
119     // Get the target for the hardware callout.
120     auto target = __getUnitTarget(__getRootCauseChipTarget(io_sd), iv_unitPath);
121 
122     // Get the location code and entity path for this target.
123     auto locCode    = util::pdbg::getLocationCode(target);
124     auto entityPath = util::pdbg::getPhysDevPath(target);
125 
126     // Add the actual callout to the service data.
127     nlohmann::json callout;
128     callout["LocationCode"] = locCode;
129     callout["Priority"]     = iv_priority.getUserDataString();
130     io_sd.addCallout(callout);
131 
132     // Add the guard info to the service data.
133     Guard guard = io_sd.addGuard(entityPath, iv_guard);
134 
135     // Add the callout FFDC to the service data.
136     nlohmann::json ffdc;
137     ffdc["Callout Type"] = "Hardware Callout";
138     ffdc["Target"]       = entityPath;
139     ffdc["Priority"]     = iv_priority.getRegistryString();
140     ffdc["Guard Type"]   = guard.getString();
141     io_sd.addCalloutFFDC(ffdc);
142 }
143 
144 //------------------------------------------------------------------------------
145 
146 void ConnectedCalloutResolution::resolve(ServiceData& io_sd) const
147 {
148     // Get the chip target from the root cause signature.
149     auto chipTarget = __getRootCauseChipTarget(io_sd);
150 
151     // Get the endpoint target for the receiving side of the bus.
152     auto rxTarget = __getUnitTarget(chipTarget, iv_unitPath);
153 
154     // Get the endpoint target for the transfer side of the bus.
155     auto txTarget = __getConnectedTarget(rxTarget, iv_busType);
156 
157     // Callout the TX endpoint.
158     nlohmann::json txCallout;
159     txCallout["LocationCode"] = util::pdbg::getLocationCode(txTarget);
160     txCallout["Priority"]     = iv_priority.getUserDataString();
161     io_sd.addCallout(txCallout);
162 
163     // Guard the TX endpoint.
164     Guard txGuard =
165         io_sd.addGuard(util::pdbg::getPhysDevPath(txTarget), iv_guard);
166 
167     // Add the callout FFDC to the service data.
168     nlohmann::json ffdc;
169     ffdc["Callout Type"] = "Connected Callout";
170     ffdc["Bus Type"]     = iv_busType.getString();
171     ffdc["Target"]       = util::pdbg::getPhysDevPath(txTarget);
172     ffdc["Priority"]     = iv_priority.getRegistryString();
173     ffdc["Guard Type"]   = txGuard.getString();
174     io_sd.addCalloutFFDC(ffdc);
175 }
176 
177 //------------------------------------------------------------------------------
178 
179 void ClockCalloutResolution::resolve(ServiceData& io_sd) const
180 {
181     // Add the callout to the service data.
182     // TODO: For P10, the callout is simply the backplane. There isn't a devtree
183     //       object for this, yet. So will need to hardcode the location code
184     //       for now. In the future, we will need a mechanism to make this data
185     //       driven.
186     nlohmann::json callout;
187     callout["LocationCode"] = "P0";
188     callout["Priority"]     = iv_priority.getUserDataString();
189     io_sd.addCallout(callout);
190 
191     // Add the guard info to the service data.
192     // TODO: Still waiting for clock targets to be defined in the device tree.
193     //       For get the processor path for the FFDC.
194     // static const std::map<callout::ClockType, std::string> m = {
195     //     {callout::ClockType::OSC_REF_CLOCK_0, ""},
196     //     {callout::ClockType::OSC_REF_CLOCK_1, ""},
197     // };
198     // auto target = std::string{util::pdbg::getPath(m.at(iv_clockType))};
199     // auto guardPath = util::pdbg::getPhysDevPath(target);
200     // Guard guard = io_sd.addGuard(guardPath, iv_guard);
201     auto target    = __getRootCauseChipTarget(io_sd);
202     auto guardPath = util::pdbg::getPhysDevPath(target);
203 
204     // Add the callout FFDC to the service data.
205     nlohmann::json ffdc;
206     ffdc["Callout Type"] = "Clock Callout";
207     ffdc["Clock Type"]   = iv_clockType.getString();
208     ffdc["Target"]       = guardPath;
209     ffdc["Priority"]     = iv_priority.getRegistryString();
210     ffdc["Guard Type"]   = ""; // TODO: guard.getString();
211     io_sd.addCalloutFFDC(ffdc);
212 }
213 
214 //------------------------------------------------------------------------------
215 
216 void ProcedureCalloutResolution::resolve(ServiceData& io_sd) const
217 {
218     // Add the actual callout to the service data.
219     nlohmann::json callout;
220     callout["Procedure"] = iv_procedure.getString();
221     callout["Priority"]  = iv_priority.getUserDataString();
222     io_sd.addCallout(callout);
223 
224     // Add the callout FFDC to the service data.
225     nlohmann::json ffdc;
226     ffdc["Callout Type"] = "Procedure Callout";
227     ffdc["Procedure"]    = iv_procedure.getString();
228     ffdc["Priority"]     = iv_priority.getRegistryString();
229     io_sd.addCalloutFFDC(ffdc);
230 }
231 
232 //------------------------------------------------------------------------------
233 
234 } // namespace analyzer
235