1 /** 2 * Copyright © 2020 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "service_indicators.hpp" 17 18 #include <fmt/format.h> 19 20 #include <bitset> 21 #include <phosphor-logging/log.hpp> 22 23 namespace openpower::pels::service_indicators 24 { 25 26 using namespace phosphor::logging; 27 28 std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface) 29 { 30 // At the moment there is just one type of policy. 31 return std::make_unique<LightPath>(dataIface); 32 } 33 34 bool LightPath::ignore(const PEL& pel) const 35 { 36 auto creator = pel.privateHeader().creatorID(); 37 38 // Don't ignore serviceable BMC or hostboot errors 39 if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) || 40 (static_cast<CreatorID>(creator) == CreatorID::hostboot)) 41 { 42 std::bitset<16> actionFlags{pel.userHeader().actionFlags()}; 43 if (actionFlags.test(serviceActionFlagBit)) 44 { 45 return false; 46 } 47 } 48 49 return true; 50 } 51 52 void LightPath::activate(const PEL& pel) 53 { 54 if (ignore(pel)) 55 { 56 return; 57 } 58 59 // Now that we've gotten this far, we'll need to turn on 60 // the system attention indicator if we don't find other 61 // indicators to turn on. 62 bool sai = true; 63 auto src = pel.primarySRC(); 64 const auto& calloutsObj = (*src)->callouts(); 65 66 if (calloutsObj && !calloutsObj->callouts().empty()) 67 { 68 const auto& callouts = calloutsObj->callouts(); 69 70 // From the callouts, find the location codes whose 71 // LEDs need to be turned on. 72 auto locCodes = getLocationCodes(callouts); 73 if (!locCodes.empty()) 74 { 75 // Find the LED groups for those location codes. 76 auto ledPaths = getLEDGroupPaths(locCodes); 77 if (!ledPaths.empty()) 78 { 79 // Tell the LED groups to assert their LEDs. 80 assertLEDs(ledPaths); 81 sai = false; 82 } 83 } 84 } 85 86 if (sai) 87 { 88 log<level::INFO>("The System Attention Indicator needs to be turned " 89 "on, when available"); 90 } 91 } 92 93 std::vector<std::string> LightPath::getLocationCodes( 94 const std::vector<std::unique_ptr<src::Callout>>& callouts) const 95 { 96 std::vector<std::string> locCodes; 97 bool firstCallout = true; 98 uint8_t firstCalloutPriority; 99 100 // Collect location codes for the first group of callouts, 101 // where a group can be: 102 // * a single medium priority callout 103 // * one or more high priority callouts 104 // * one or more medium group a priority callouts 105 // 106 // All callouts in the group must be hardware callouts. 107 108 for (const auto& callout : callouts) 109 { 110 if (firstCallout) 111 { 112 firstCallout = false; 113 114 firstCalloutPriority = callout->priority(); 115 116 // If the first callout is High, Medium, or Medium 117 // group A, and is a hardware callout, then we 118 // want it. 119 if (isRequiredPriority(firstCalloutPriority) && 120 isHardwareCallout(*callout)) 121 { 122 locCodes.push_back(callout->locationCode()); 123 } 124 else 125 { 126 break; 127 } 128 129 // By definition a medium priority callout can't be part 130 // of a group, so no need to look for more. 131 if (static_cast<CalloutPriority>(firstCalloutPriority) == 132 CalloutPriority::medium) 133 { 134 break; 135 } 136 } 137 else 138 { 139 // Only continue while the callouts are the same 140 // priority as the first callout. 141 if (callout->priority() != firstCalloutPriority) 142 { 143 break; 144 } 145 146 // If any callout in the group isn't a hardware callout, 147 // then don't light up any LEDs at all. 148 if (!isHardwareCallout(*callout)) 149 { 150 locCodes.clear(); 151 break; 152 } 153 154 locCodes.push_back(callout->locationCode()); 155 } 156 } 157 158 return locCodes; 159 } 160 161 bool LightPath::isRequiredPriority(uint8_t priority) const 162 { 163 auto calloutPriority = static_cast<CalloutPriority>(priority); 164 return (calloutPriority == CalloutPriority::high) || 165 (calloutPriority == CalloutPriority::medium) || 166 (calloutPriority == CalloutPriority::mediumGroupA); 167 } 168 169 bool LightPath::isHardwareCallout(const src::Callout& callout) const 170 { 171 const auto& fruIdentity = callout.fruIdentity(); 172 if (fruIdentity) 173 { 174 return (callout.locationCodeSize() != 0) && 175 ((fruIdentity->failingComponentType() == 176 src::FRUIdentity::hardwareFRU) || 177 (fruIdentity->failingComponentType() == 178 src::FRUIdentity::symbolicFRUTrustedLocCode)); 179 } 180 181 return false; 182 } 183 184 std::vector<std::string> LightPath::getLEDGroupPaths( 185 const std::vector<std::string>& locationCodes) const 186 { 187 std::vector<std::string> ledGroups; 188 std::string inventoryPath; 189 190 for (const auto& locCode : locationCodes) 191 { 192 try 193 { 194 inventoryPath = 195 _dataIface.getInventoryFromLocCode(locCode, 0, true); 196 } 197 catch (const std::exception& e) 198 { 199 log<level::ERR>(fmt::format("Could not get inventory path for " 200 "location code {} ({}).", 201 locCode, e.what()) 202 .c_str()); 203 204 // Unless we can get the LEDs for all FRUs, we can't turn 205 // on any of them, so clear the list and quit. 206 ledGroups.clear(); 207 break; 208 } 209 210 try 211 { 212 ledGroups.push_back(_dataIface.getFaultLEDGroup(inventoryPath)); 213 } 214 catch (const std::exception& e) 215 { 216 log<level::ERR>(fmt::format("Could not get LED group path for " 217 "inventory path {} ({}).", 218 inventoryPath, e.what()) 219 .c_str()); 220 ledGroups.clear(); 221 break; 222 } 223 } 224 225 return ledGroups; 226 } 227 228 void LightPath::assertLEDs(const std::vector<std::string>& ledGroups) const 229 { 230 for (const auto& ledGroup : ledGroups) 231 { 232 try 233 { 234 _dataIface.assertLEDGroup(ledGroup, true); 235 } 236 catch (const std::exception& e) 237 { 238 log<level::ERR>(fmt::format("Failed to assert LED group {} ({})", 239 ledGroup, e.what()) 240 .c_str()); 241 } 242 } 243 } 244 245 } // namespace openpower::pels::service_indicators 246