blob: df26ecb578deac241e62dae27b3e9bd6a99c2756 [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
Arya K Padman5bc26532024-04-10 06:19:25 -050018#include <phosphor-logging/lg2.hpp>
Matt Spinler1962e082020-08-05 13:44:53 -050019
Patrick Williams2544b412022-10-04 08:41:06 -050020#include <bitset>
21
Matt Spinler1962e082020-08-05 13:44:53 -050022namespace openpower::pels::service_indicators
23{
24
Matt Spinler48c44db2020-08-25 12:47:13 -050025static constexpr auto platformSaiLedGroup =
26 "/xyz/openbmc_project/led/groups/platform_system_attention_indicator";
27
Matt Spinler1962e082020-08-05 13:44:53 -050028std::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 {
Matt Spinler993168d2021-04-07 16:05:03 -050075 // Find the inventory paths for those location codes.
76 auto paths = getInventoryPaths(locCodes);
77 if (!paths.empty())
Matt Spinler1962e082020-08-05 13:44:53 -050078 {
Matt Spinler993168d2021-04-07 16:05:03 -050079 setNotFunctional(paths);
Sumit Kumar76198a22021-07-15 05:59:57 -050080 createCriticalAssociation(paths);
Matt Spinler1962e082020-08-05 13:44:53 -050081 sai = false;
82 }
83 }
84 }
85
86 if (sai)
87 {
Matt Spinler48c44db2020-08-25 12:47:13 -050088 try
89 {
90 _dataIface.assertLEDGroup(platformSaiLedGroup, true);
91 }
92 catch (const std::exception& e)
93 {
Arya K Padman5bc26532024-04-10 06:19:25 -050094 lg2::error("Failed to assert platform SAI LED group: {EXCEPTION}",
95 "EXCEPTION", e);
Matt Spinler48c44db2020-08-25 12:47:13 -050096 }
Matt Spinler1962e082020-08-05 13:44:53 -050097 }
98}
99
100std::vector<std::string> LightPath::getLocationCodes(
101 const std::vector<std::unique_ptr<src::Callout>>& callouts) const
102{
Matt Spinler05f0c6d2020-08-05 14:21:06 -0500103 std::vector<std::string> locCodes;
104 bool firstCallout = true;
105 uint8_t firstCalloutPriority;
106
107 // Collect location codes for the first group of callouts,
108 // where a group can be:
109 // * a single medium priority callout
110 // * one or more high priority callouts
111 // * one or more medium group a priority callouts
112 //
113 // All callouts in the group must be hardware callouts.
114
115 for (const auto& callout : callouts)
116 {
117 if (firstCallout)
118 {
119 firstCallout = false;
120
121 firstCalloutPriority = callout->priority();
122
123 // If the first callout is High, Medium, or Medium
124 // group A, and is a hardware callout, then we
125 // want it.
126 if (isRequiredPriority(firstCalloutPriority) &&
127 isHardwareCallout(*callout))
128 {
129 locCodes.push_back(callout->locationCode());
130 }
131 else
132 {
133 break;
134 }
135
136 // By definition a medium priority callout can't be part
137 // of a group, so no need to look for more.
138 if (static_cast<CalloutPriority>(firstCalloutPriority) ==
139 CalloutPriority::medium)
140 {
141 break;
142 }
143 }
144 else
145 {
146 // Only continue while the callouts are the same
147 // priority as the first callout.
148 if (callout->priority() != firstCalloutPriority)
149 {
150 break;
151 }
152
153 // If any callout in the group isn't a hardware callout,
154 // then don't light up any LEDs at all.
155 if (!isHardwareCallout(*callout))
156 {
157 locCodes.clear();
158 break;
159 }
160
161 locCodes.push_back(callout->locationCode());
162 }
163 }
164
165 return locCodes;
166}
167
168bool LightPath::isRequiredPriority(uint8_t priority) const
169{
170 auto calloutPriority = static_cast<CalloutPriority>(priority);
171 return (calloutPriority == CalloutPriority::high) ||
172 (calloutPriority == CalloutPriority::medium) ||
173 (calloutPriority == CalloutPriority::mediumGroupA);
174}
175
176bool LightPath::isHardwareCallout(const src::Callout& callout) const
177{
178 const auto& fruIdentity = callout.fruIdentity();
179 if (fruIdentity)
180 {
181 return (callout.locationCodeSize() != 0) &&
182 ((fruIdentity->failingComponentType() ==
183 src::FRUIdentity::hardwareFRU) ||
184 (fruIdentity->failingComponentType() ==
185 src::FRUIdentity::symbolicFRUTrustedLocCode));
186 }
187
188 return false;
Matt Spinler1962e082020-08-05 13:44:53 -0500189}
190
Matt Spinler993168d2021-04-07 16:05:03 -0500191std::vector<std::string> LightPath::getInventoryPaths(
Matt Spinler1962e082020-08-05 13:44:53 -0500192 const std::vector<std::string>& locationCodes) const
193{
Matt Spinler993168d2021-04-07 16:05:03 -0500194 std::vector<std::string> paths;
Matt Spinler34a904c2020-08-05 14:53:28 -0500195
196 for (const auto& locCode : locationCodes)
197 {
198 try
199 {
Patrick Williams075c7922024-08-16 15:19:49 -0400200 auto inventoryPaths =
201 _dataIface.getInventoryFromLocCode(locCode, 0, true);
Matt Spinlerbad056b2023-01-25 14:16:57 -0600202 for (const auto& path : inventoryPaths)
203 {
204 if (std::find(paths.begin(), paths.end(), path) == paths.end())
205 {
206 paths.push_back(path);
207 }
208 }
Matt Spinler34a904c2020-08-05 14:53:28 -0500209 }
210 catch (const std::exception& e)
211 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500212 lg2::error("Could not get inventory path for "
213 "location code {LOCCODE} ({EXCEPTION}).",
214 "LOCCODE", locCode, "EXCEPTION", e);
Matt Spinler34a904c2020-08-05 14:53:28 -0500215
Matt Spinler993168d2021-04-07 16:05:03 -0500216 // Unless we can set the LEDs for all FRUs, we can't turn
Matt Spinler34a904c2020-08-05 14:53:28 -0500217 // on any of them, so clear the list and quit.
Matt Spinler993168d2021-04-07 16:05:03 -0500218 paths.clear();
Matt Spinler34a904c2020-08-05 14:53:28 -0500219 break;
220 }
221 }
222
Matt Spinler993168d2021-04-07 16:05:03 -0500223 return paths;
Matt Spinler1962e082020-08-05 13:44:53 -0500224}
225
Matt Spinler993168d2021-04-07 16:05:03 -0500226void LightPath::setNotFunctional(
227 const std::vector<std::string>& inventoryPaths) const
Matt Spinler1962e082020-08-05 13:44:53 -0500228{
Matt Spinler993168d2021-04-07 16:05:03 -0500229 for (const auto& path : inventoryPaths)
Matt Spinler34a904c2020-08-05 14:53:28 -0500230 {
231 try
232 {
Matt Spinler993168d2021-04-07 16:05:03 -0500233 _dataIface.setFunctional(path, false);
Matt Spinler34a904c2020-08-05 14:53:28 -0500234 }
235 catch (const std::exception& e)
236 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500237 lg2::info(
238 "Could not write Functional property on {PATH} ({EXCEPTION})",
239 "PATH", path, "EXCEPTION", e);
Matt Spinler34a904c2020-08-05 14:53:28 -0500240 }
241 }
Matt Spinler1962e082020-08-05 13:44:53 -0500242}
243
Sumit Kumar76198a22021-07-15 05:59:57 -0500244void LightPath::createCriticalAssociation(
245 const std::vector<std::string>& inventoryPaths) const
246{
247 for (const auto& path : inventoryPaths)
248 {
249 try
250 {
251 _dataIface.setCriticalAssociation(path);
252 }
253 catch (const std::exception& e)
254 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500255 lg2::info(
256 "Could not set critical association on object path {PATH} ({EXCEPTION})",
257 "PATH", path, "EXCEPTION", e);
Sumit Kumar76198a22021-07-15 05:59:57 -0500258 }
259 }
260}
261
Matt Spinler1962e082020-08-05 13:44:53 -0500262} // namespace openpower::pels::service_indicators