blob: 3f934c76ab58bf007604b655b8fcb1ce2fdca8de [file] [log] [blame]
Matt Spinler1962e082020-08-05 13:44:53 -05001/**
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
Matt Spinler34a904c2020-08-05 14:53:28 -050018#include <fmt/format.h>
19
Matt Spinler05f0c6d2020-08-05 14:21:06 -050020#include <bitset>
Matt Spinler1962e082020-08-05 13:44:53 -050021#include <phosphor-logging/log.hpp>
22
23namespace openpower::pels::service_indicators
24{
25
26using namespace phosphor::logging;
27
28std::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
34bool LightPath::ignore(const PEL& pel) const
35{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050036 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;
Matt Spinler1962e082020-08-05 13:44:53 -050050}
51
52void 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
93std::vector<std::string> LightPath::getLocationCodes(
94 const std::vector<std::unique_ptr<src::Callout>>& callouts) const
95{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050096 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
161bool 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
169bool 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;
Matt Spinler1962e082020-08-05 13:44:53 -0500182}
183
184std::vector<std::string> LightPath::getLEDGroupPaths(
185 const std::vector<std::string>& locationCodes) const
186{
Matt Spinler34a904c2020-08-05 14:53:28 -0500187 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;
Matt Spinler1962e082020-08-05 13:44:53 -0500226}
227
228void LightPath::assertLEDs(const std::vector<std::string>& ledGroups) const
229{
Matt Spinler34a904c2020-08-05 14:53:28 -0500230 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 }
Matt Spinler1962e082020-08-05 13:44:53 -0500243}
244
245} // namespace openpower::pels::service_indicators