blob: 9572f258f5fe6bcca4b45fb441c4f02486c0d4e3 [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 Spinler1962e082020-08-05 13:44:53 -050020#include <phosphor-logging/log.hpp>
21
Patrick Williams2544b412022-10-04 08:41:06 -050022#include <bitset>
23
Matt Spinler1962e082020-08-05 13:44:53 -050024namespace openpower::pels::service_indicators
25{
26
27using namespace phosphor::logging;
28
Matt Spinler48c44db2020-08-25 12:47:13 -050029static constexpr auto platformSaiLedGroup =
30 "/xyz/openbmc_project/led/groups/platform_system_attention_indicator";
31
Matt Spinler1962e082020-08-05 13:44:53 -050032std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface)
33{
34 // At the moment there is just one type of policy.
35 return std::make_unique<LightPath>(dataIface);
36}
37
38bool LightPath::ignore(const PEL& pel) const
39{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050040 auto creator = pel.privateHeader().creatorID();
41
42 // Don't ignore serviceable BMC or hostboot errors
43 if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) ||
44 (static_cast<CreatorID>(creator) == CreatorID::hostboot))
45 {
46 std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
47 if (actionFlags.test(serviceActionFlagBit))
48 {
49 return false;
50 }
51 }
52
53 return true;
Matt Spinler1962e082020-08-05 13:44:53 -050054}
55
56void LightPath::activate(const PEL& pel)
57{
58 if (ignore(pel))
59 {
60 return;
61 }
62
63 // Now that we've gotten this far, we'll need to turn on
64 // the system attention indicator if we don't find other
65 // indicators to turn on.
66 bool sai = true;
67 auto src = pel.primarySRC();
68 const auto& calloutsObj = (*src)->callouts();
69
70 if (calloutsObj && !calloutsObj->callouts().empty())
71 {
72 const auto& callouts = calloutsObj->callouts();
73
74 // From the callouts, find the location codes whose
75 // LEDs need to be turned on.
76 auto locCodes = getLocationCodes(callouts);
77 if (!locCodes.empty())
78 {
Matt Spinler993168d2021-04-07 16:05:03 -050079 // Find the inventory paths for those location codes.
80 auto paths = getInventoryPaths(locCodes);
81 if (!paths.empty())
Matt Spinler1962e082020-08-05 13:44:53 -050082 {
Matt Spinler993168d2021-04-07 16:05:03 -050083 setNotFunctional(paths);
Sumit Kumar76198a22021-07-15 05:59:57 -050084 createCriticalAssociation(paths);
Matt Spinler1962e082020-08-05 13:44:53 -050085 sai = false;
86 }
87 }
88 }
89
90 if (sai)
91 {
Matt Spinler48c44db2020-08-25 12:47:13 -050092 try
93 {
94 _dataIface.assertLEDGroup(platformSaiLedGroup, true);
95 }
96 catch (const std::exception& e)
97 {
98 log<level::ERR>(
99 fmt::format("Failed to assert platform SAI LED group: {}",
100 e.what())
101 .c_str());
102 }
Matt Spinler1962e082020-08-05 13:44:53 -0500103 }
104}
105
106std::vector<std::string> LightPath::getLocationCodes(
107 const std::vector<std::unique_ptr<src::Callout>>& callouts) const
108{
Matt Spinler05f0c6d2020-08-05 14:21:06 -0500109 std::vector<std::string> locCodes;
110 bool firstCallout = true;
111 uint8_t firstCalloutPriority;
112
113 // Collect location codes for the first group of callouts,
114 // where a group can be:
115 // * a single medium priority callout
116 // * one or more high priority callouts
117 // * one or more medium group a priority callouts
118 //
119 // All callouts in the group must be hardware callouts.
120
121 for (const auto& callout : callouts)
122 {
123 if (firstCallout)
124 {
125 firstCallout = false;
126
127 firstCalloutPriority = callout->priority();
128
129 // If the first callout is High, Medium, or Medium
130 // group A, and is a hardware callout, then we
131 // want it.
132 if (isRequiredPriority(firstCalloutPriority) &&
133 isHardwareCallout(*callout))
134 {
135 locCodes.push_back(callout->locationCode());
136 }
137 else
138 {
139 break;
140 }
141
142 // By definition a medium priority callout can't be part
143 // of a group, so no need to look for more.
144 if (static_cast<CalloutPriority>(firstCalloutPriority) ==
145 CalloutPriority::medium)
146 {
147 break;
148 }
149 }
150 else
151 {
152 // Only continue while the callouts are the same
153 // priority as the first callout.
154 if (callout->priority() != firstCalloutPriority)
155 {
156 break;
157 }
158
159 // If any callout in the group isn't a hardware callout,
160 // then don't light up any LEDs at all.
161 if (!isHardwareCallout(*callout))
162 {
163 locCodes.clear();
164 break;
165 }
166
167 locCodes.push_back(callout->locationCode());
168 }
169 }
170
171 return locCodes;
172}
173
174bool LightPath::isRequiredPriority(uint8_t priority) const
175{
176 auto calloutPriority = static_cast<CalloutPriority>(priority);
177 return (calloutPriority == CalloutPriority::high) ||
178 (calloutPriority == CalloutPriority::medium) ||
179 (calloutPriority == CalloutPriority::mediumGroupA);
180}
181
182bool LightPath::isHardwareCallout(const src::Callout& callout) const
183{
184 const auto& fruIdentity = callout.fruIdentity();
185 if (fruIdentity)
186 {
187 return (callout.locationCodeSize() != 0) &&
188 ((fruIdentity->failingComponentType() ==
189 src::FRUIdentity::hardwareFRU) ||
190 (fruIdentity->failingComponentType() ==
191 src::FRUIdentity::symbolicFRUTrustedLocCode));
192 }
193
194 return false;
Matt Spinler1962e082020-08-05 13:44:53 -0500195}
196
Matt Spinler993168d2021-04-07 16:05:03 -0500197std::vector<std::string> LightPath::getInventoryPaths(
Matt Spinler1962e082020-08-05 13:44:53 -0500198 const std::vector<std::string>& locationCodes) const
199{
Matt Spinler993168d2021-04-07 16:05:03 -0500200 std::vector<std::string> paths;
Matt Spinler34a904c2020-08-05 14:53:28 -0500201
202 for (const auto& locCode : locationCodes)
203 {
204 try
205 {
Matt Spinlerbad056b2023-01-25 14:16:57 -0600206 auto inventoryPaths = _dataIface.getInventoryFromLocCode(locCode, 0,
207 true);
208 for (const auto& path : inventoryPaths)
209 {
210 if (std::find(paths.begin(), paths.end(), path) == paths.end())
211 {
212 paths.push_back(path);
213 }
214 }
Matt Spinler34a904c2020-08-05 14:53:28 -0500215 }
216 catch (const std::exception& e)
217 {
218 log<level::ERR>(fmt::format("Could not get inventory path for "
219 "location code {} ({}).",
220 locCode, e.what())
221 .c_str());
222
Matt Spinler993168d2021-04-07 16:05:03 -0500223 // Unless we can set the LEDs for all FRUs, we can't turn
Matt Spinler34a904c2020-08-05 14:53:28 -0500224 // on any of them, so clear the list and quit.
Matt Spinler993168d2021-04-07 16:05:03 -0500225 paths.clear();
Matt Spinler34a904c2020-08-05 14:53:28 -0500226 break;
227 }
228 }
229
Matt Spinler993168d2021-04-07 16:05:03 -0500230 return paths;
Matt Spinler1962e082020-08-05 13:44:53 -0500231}
232
Matt Spinler993168d2021-04-07 16:05:03 -0500233void LightPath::setNotFunctional(
234 const std::vector<std::string>& inventoryPaths) const
Matt Spinler1962e082020-08-05 13:44:53 -0500235{
Matt Spinler993168d2021-04-07 16:05:03 -0500236 for (const auto& path : inventoryPaths)
Matt Spinler34a904c2020-08-05 14:53:28 -0500237 {
238 try
239 {
Matt Spinler993168d2021-04-07 16:05:03 -0500240 _dataIface.setFunctional(path, false);
Matt Spinler34a904c2020-08-05 14:53:28 -0500241 }
242 catch (const std::exception& e)
243 {
Matt Spinler993168d2021-04-07 16:05:03 -0500244 log<level::INFO>(
245 fmt::format("Could not write Functional property on {} ({})",
246 path, e.what())
247 .c_str());
Matt Spinler34a904c2020-08-05 14:53:28 -0500248 }
249 }
Matt Spinler1962e082020-08-05 13:44:53 -0500250}
251
Sumit Kumar76198a22021-07-15 05:59:57 -0500252void LightPath::createCriticalAssociation(
253 const std::vector<std::string>& inventoryPaths) const
254{
255 for (const auto& path : inventoryPaths)
256 {
257 try
258 {
259 _dataIface.setCriticalAssociation(path);
260 }
261 catch (const std::exception& e)
262 {
263 log<level::INFO>(
264 fmt::format(
265 "Could not set critical association on object path {} ({})",
266 path, e.what())
267 .c_str());
268 }
269 }
270}
271
Matt Spinler1962e082020-08-05 13:44:53 -0500272} // namespace openpower::pels::service_indicators