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 <bitset> 19 #include <phosphor-logging/log.hpp> 20 21 namespace openpower::pels::service_indicators 22 { 23 24 using namespace phosphor::logging; 25 26 std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface) 27 { 28 // At the moment there is just one type of policy. 29 return std::make_unique<LightPath>(dataIface); 30 } 31 32 bool LightPath::ignore(const PEL& pel) const 33 { 34 auto creator = pel.privateHeader().creatorID(); 35 36 // Don't ignore serviceable BMC or hostboot errors 37 if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) || 38 (static_cast<CreatorID>(creator) == CreatorID::hostboot)) 39 { 40 std::bitset<16> actionFlags{pel.userHeader().actionFlags()}; 41 if (actionFlags.test(serviceActionFlagBit)) 42 { 43 return false; 44 } 45 } 46 47 return true; 48 } 49 50 void LightPath::activate(const PEL& pel) 51 { 52 if (ignore(pel)) 53 { 54 return; 55 } 56 57 // Now that we've gotten this far, we'll need to turn on 58 // the system attention indicator if we don't find other 59 // indicators to turn on. 60 bool sai = true; 61 auto src = pel.primarySRC(); 62 const auto& calloutsObj = (*src)->callouts(); 63 64 if (calloutsObj && !calloutsObj->callouts().empty()) 65 { 66 const auto& callouts = calloutsObj->callouts(); 67 68 // From the callouts, find the location codes whose 69 // LEDs need to be turned on. 70 auto locCodes = getLocationCodes(callouts); 71 if (!locCodes.empty()) 72 { 73 // Find the LED groups for those location codes. 74 auto ledPaths = getLEDGroupPaths(locCodes); 75 if (!ledPaths.empty()) 76 { 77 // Tell the LED groups to assert their LEDs. 78 assertLEDs(ledPaths); 79 sai = false; 80 } 81 } 82 } 83 84 if (sai) 85 { 86 log<level::INFO>("The System Attention Indicator needs to be turned " 87 "on, when available"); 88 } 89 } 90 91 std::vector<std::string> LightPath::getLocationCodes( 92 const std::vector<std::unique_ptr<src::Callout>>& callouts) const 93 { 94 std::vector<std::string> locCodes; 95 bool firstCallout = true; 96 uint8_t firstCalloutPriority; 97 98 // Collect location codes for the first group of callouts, 99 // where a group can be: 100 // * a single medium priority callout 101 // * one or more high priority callouts 102 // * one or more medium group a priority callouts 103 // 104 // All callouts in the group must be hardware callouts. 105 106 for (const auto& callout : callouts) 107 { 108 if (firstCallout) 109 { 110 firstCallout = false; 111 112 firstCalloutPriority = callout->priority(); 113 114 // If the first callout is High, Medium, or Medium 115 // group A, and is a hardware callout, then we 116 // want it. 117 if (isRequiredPriority(firstCalloutPriority) && 118 isHardwareCallout(*callout)) 119 { 120 locCodes.push_back(callout->locationCode()); 121 } 122 else 123 { 124 break; 125 } 126 127 // By definition a medium priority callout can't be part 128 // of a group, so no need to look for more. 129 if (static_cast<CalloutPriority>(firstCalloutPriority) == 130 CalloutPriority::medium) 131 { 132 break; 133 } 134 } 135 else 136 { 137 // Only continue while the callouts are the same 138 // priority as the first callout. 139 if (callout->priority() != firstCalloutPriority) 140 { 141 break; 142 } 143 144 // If any callout in the group isn't a hardware callout, 145 // then don't light up any LEDs at all. 146 if (!isHardwareCallout(*callout)) 147 { 148 locCodes.clear(); 149 break; 150 } 151 152 locCodes.push_back(callout->locationCode()); 153 } 154 } 155 156 return locCodes; 157 } 158 159 bool LightPath::isRequiredPriority(uint8_t priority) const 160 { 161 auto calloutPriority = static_cast<CalloutPriority>(priority); 162 return (calloutPriority == CalloutPriority::high) || 163 (calloutPriority == CalloutPriority::medium) || 164 (calloutPriority == CalloutPriority::mediumGroupA); 165 } 166 167 bool LightPath::isHardwareCallout(const src::Callout& callout) const 168 { 169 const auto& fruIdentity = callout.fruIdentity(); 170 if (fruIdentity) 171 { 172 return (callout.locationCodeSize() != 0) && 173 ((fruIdentity->failingComponentType() == 174 src::FRUIdentity::hardwareFRU) || 175 (fruIdentity->failingComponentType() == 176 src::FRUIdentity::symbolicFRUTrustedLocCode)); 177 } 178 179 return false; 180 } 181 182 std::vector<std::string> LightPath::getLEDGroupPaths( 183 const std::vector<std::string>& locationCodes) const 184 { 185 // TODO 186 return {}; 187 } 188 189 void LightPath::assertLEDs(const std::vector<std::string>& ledGroups) const 190 { 191 // TODO 192 } 193 194 } // namespace openpower::pels::service_indicators 195