blob: 7e26272867e2101a5665ab29ed66704ed6595e3d [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>
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -050021#include <format>
Patrick Williams2544b412022-10-04 08:41:06 -050022
Matt Spinler1962e082020-08-05 13:44:53 -050023namespace openpower::pels::service_indicators
24{
25
Matt Spinler48c44db2020-08-25 12:47:13 -050026static constexpr auto platformSaiLedGroup =
27 "/xyz/openbmc_project/led/groups/platform_system_attention_indicator";
28
Matt Spinler1962e082020-08-05 13:44:53 -050029std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface)
30{
31 // At the moment there is just one type of policy.
32 return std::make_unique<LightPath>(dataIface);
33}
34
35bool LightPath::ignore(const PEL& pel) const
36{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050037 auto creator = pel.privateHeader().creatorID();
38
39 // Don't ignore serviceable BMC or hostboot errors
40 if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) ||
41 (static_cast<CreatorID>(creator) == CreatorID::hostboot))
42 {
43 std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
44 if (actionFlags.test(serviceActionFlagBit))
45 {
46 return false;
47 }
48 }
49
50 return true;
Matt Spinler1962e082020-08-05 13:44:53 -050051}
52
53void LightPath::activate(const PEL& pel)
54{
55 if (ignore(pel))
56 {
57 return;
58 }
59
60 // Now that we've gotten this far, we'll need to turn on
61 // the system attention indicator if we don't find other
62 // indicators to turn on.
63 bool sai = true;
64 auto src = pel.primarySRC();
65 const auto& calloutsObj = (*src)->callouts();
66
67 if (calloutsObj && !calloutsObj->callouts().empty())
68 {
69 const auto& callouts = calloutsObj->callouts();
70
71 // From the callouts, find the location codes whose
72 // LEDs need to be turned on.
73 auto locCodes = getLocationCodes(callouts);
74 if (!locCodes.empty())
75 {
Matt Spinler993168d2021-04-07 16:05:03 -050076 // Find the inventory paths for those location codes.
77 auto paths = getInventoryPaths(locCodes);
78 if (!paths.empty())
Matt Spinler1962e082020-08-05 13:44:53 -050079 {
Matt Spinler993168d2021-04-07 16:05:03 -050080 setNotFunctional(paths);
Sumit Kumar76198a22021-07-15 05:59:57 -050081 createCriticalAssociation(paths);
Matt Spinler1962e082020-08-05 13:44:53 -050082 sai = false;
83 }
84 }
85 }
86
87 if (sai)
88 {
Matt Spinler48c44db2020-08-25 12:47:13 -050089 try
90 {
91 _dataIface.assertLEDGroup(platformSaiLedGroup, true);
92 }
93 catch (const std::exception& e)
94 {
Arya K Padman5bc26532024-04-10 06:19:25 -050095 lg2::error("Failed to assert platform SAI LED group: {EXCEPTION}",
96 "EXCEPTION", e);
Matt Spinler48c44db2020-08-25 12:47:13 -050097 }
Matt Spinler1962e082020-08-05 13:44:53 -050098 }
99}
100
101std::vector<std::string> LightPath::getLocationCodes(
102 const std::vector<std::unique_ptr<src::Callout>>& callouts) const
103{
Matt Spinler05f0c6d2020-08-05 14:21:06 -0500104 std::vector<std::string> locCodes;
105 bool firstCallout = true;
106 uint8_t firstCalloutPriority;
107
108 // Collect location codes for the first group of callouts,
109 // where a group can be:
110 // * a single medium priority callout
111 // * one or more high priority callouts
112 // * one or more medium group a priority callouts
113 //
114 // All callouts in the group must be hardware callouts.
115
116 for (const auto& callout : callouts)
117 {
118 if (firstCallout)
119 {
120 firstCallout = false;
121
122 firstCalloutPriority = callout->priority();
123
124 // If the first callout is High, Medium, or Medium
125 // group A, and is a hardware callout, then we
126 // want it.
127 if (isRequiredPriority(firstCalloutPriority) &&
128 isHardwareCallout(*callout))
129 {
130 locCodes.push_back(callout->locationCode());
131 }
132 else
133 {
134 break;
135 }
136
137 // By definition a medium priority callout can't be part
138 // of a group, so no need to look for more.
139 if (static_cast<CalloutPriority>(firstCalloutPriority) ==
140 CalloutPriority::medium)
141 {
142 break;
143 }
144 }
145 else
146 {
147 // Only continue while the callouts are the same
148 // priority as the first callout.
149 if (callout->priority() != firstCalloutPriority)
150 {
151 break;
152 }
153
154 // If any callout in the group isn't a hardware callout,
155 // then don't light up any LEDs at all.
156 if (!isHardwareCallout(*callout))
157 {
158 locCodes.clear();
159 break;
160 }
161
162 locCodes.push_back(callout->locationCode());
163 }
164 }
165
166 return locCodes;
167}
168
169bool LightPath::isRequiredPriority(uint8_t priority) const
170{
171 auto calloutPriority = static_cast<CalloutPriority>(priority);
172 return (calloutPriority == CalloutPriority::high) ||
173 (calloutPriority == CalloutPriority::medium) ||
174 (calloutPriority == CalloutPriority::mediumGroupA);
175}
176
177bool LightPath::isHardwareCallout(const src::Callout& callout) const
178{
179 const auto& fruIdentity = callout.fruIdentity();
180 if (fruIdentity)
181 {
182 return (callout.locationCodeSize() != 0) &&
183 ((fruIdentity->failingComponentType() ==
184 src::FRUIdentity::hardwareFRU) ||
185 (fruIdentity->failingComponentType() ==
186 src::FRUIdentity::symbolicFRUTrustedLocCode));
187 }
188
189 return false;
Matt Spinler1962e082020-08-05 13:44:53 -0500190}
191
Matt Spinler993168d2021-04-07 16:05:03 -0500192std::vector<std::string> LightPath::getInventoryPaths(
Matt Spinler1962e082020-08-05 13:44:53 -0500193 const std::vector<std::string>& locationCodes) const
194{
Matt Spinler993168d2021-04-07 16:05:03 -0500195 std::vector<std::string> paths;
Matt Spinler34a904c2020-08-05 14:53:28 -0500196
197 for (const auto& locCode : locationCodes)
198 {
199 try
200 {
Matt Spinlerbad056b2023-01-25 14:16:57 -0600201 auto inventoryPaths = _dataIface.getInventoryFromLocCode(locCode, 0,
202 true);
203 for (const auto& path : inventoryPaths)
204 {
205 if (std::find(paths.begin(), paths.end(), path) == paths.end())
206 {
207 paths.push_back(path);
208 }
209 }
Matt Spinler34a904c2020-08-05 14:53:28 -0500210 }
211 catch (const std::exception& e)
212 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500213 lg2::error("Could not get inventory path for "
214 "location code {LOCCODE} ({EXCEPTION}).",
215 "LOCCODE", locCode, "EXCEPTION", e);
Matt Spinler34a904c2020-08-05 14:53:28 -0500216
Matt Spinler993168d2021-04-07 16:05:03 -0500217 // Unless we can set the LEDs for all FRUs, we can't turn
Matt Spinler34a904c2020-08-05 14:53:28 -0500218 // on any of them, so clear the list and quit.
Matt Spinler993168d2021-04-07 16:05:03 -0500219 paths.clear();
Matt Spinler34a904c2020-08-05 14:53:28 -0500220 break;
221 }
222 }
223
Matt Spinler993168d2021-04-07 16:05:03 -0500224 return paths;
Matt Spinler1962e082020-08-05 13:44:53 -0500225}
226
Matt Spinler993168d2021-04-07 16:05:03 -0500227void LightPath::setNotFunctional(
228 const std::vector<std::string>& inventoryPaths) const
Matt Spinler1962e082020-08-05 13:44:53 -0500229{
Matt Spinler993168d2021-04-07 16:05:03 -0500230 for (const auto& path : inventoryPaths)
Matt Spinler34a904c2020-08-05 14:53:28 -0500231 {
232 try
233 {
Matt Spinler993168d2021-04-07 16:05:03 -0500234 _dataIface.setFunctional(path, false);
Matt Spinler34a904c2020-08-05 14:53:28 -0500235 }
236 catch (const std::exception& e)
237 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500238 lg2::info(
239 "Could not write Functional property on {PATH} ({EXCEPTION})",
240 "PATH", path, "EXCEPTION", e);
Matt Spinler34a904c2020-08-05 14:53:28 -0500241 }
242 }
Matt Spinler1962e082020-08-05 13:44:53 -0500243}
244
Sumit Kumar76198a22021-07-15 05:59:57 -0500245void LightPath::createCriticalAssociation(
246 const std::vector<std::string>& inventoryPaths) const
247{
248 for (const auto& path : inventoryPaths)
249 {
250 try
251 {
252 _dataIface.setCriticalAssociation(path);
253 }
254 catch (const std::exception& e)
255 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500256 lg2::info(
257 "Could not set critical association on object path {PATH} ({EXCEPTION})",
258 "PATH", path, "EXCEPTION", e);
Sumit Kumar76198a22021-07-15 05:59:57 -0500259 }
260 }
261}
262
Matt Spinler1962e082020-08-05 13:44:53 -0500263} // namespace openpower::pels::service_indicators