blob: 074251c4bdc281b0e2f26dc90a6e1e12c725c0d4 [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 Spinler05f0c6d2020-08-05 14:21:06 -050018#include <bitset>
Matt Spinler1962e082020-08-05 13:44:53 -050019#include <phosphor-logging/log.hpp>
20
21namespace openpower::pels::service_indicators
22{
23
24using namespace phosphor::logging;
25
26std::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
32bool LightPath::ignore(const PEL& pel) const
33{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050034 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;
Matt Spinler1962e082020-08-05 13:44:53 -050048}
49
50void 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
91std::vector<std::string> LightPath::getLocationCodes(
92 const std::vector<std::unique_ptr<src::Callout>>& callouts) const
93{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050094 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
159bool 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
167bool 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;
Matt Spinler1962e082020-08-05 13:44:53 -0500180}
181
182std::vector<std::string> LightPath::getLEDGroupPaths(
183 const std::vector<std::string>& locationCodes) const
184{
185 // TODO
186 return {};
187}
188
189void LightPath::assertLEDs(const std::vector<std::string>& ledGroups) const
190{
191 // TODO
192}
193
194} // namespace openpower::pels::service_indicators