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