blob: 8826276905c3a8fb10d982a118063a9170790580 [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
18#include <phosphor-logging/log.hpp>
19
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
26using namespace phosphor::logging;
27
Matt Spinler48c44db2020-08-25 12:47:13 -050028static constexpr auto platformSaiLedGroup =
29 "/xyz/openbmc_project/led/groups/platform_system_attention_indicator";
30
Matt Spinler1962e082020-08-05 13:44:53 -050031std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface)
32{
33 // At the moment there is just one type of policy.
34 return std::make_unique<LightPath>(dataIface);
35}
36
37bool LightPath::ignore(const PEL& pel) const
38{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050039 auto creator = pel.privateHeader().creatorID();
40
41 // Don't ignore serviceable BMC or hostboot errors
42 if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) ||
43 (static_cast<CreatorID>(creator) == CreatorID::hostboot))
44 {
45 std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
46 if (actionFlags.test(serviceActionFlagBit))
47 {
48 return false;
49 }
50 }
51
52 return true;
Matt Spinler1962e082020-08-05 13:44:53 -050053}
54
55void LightPath::activate(const PEL& pel)
56{
57 if (ignore(pel))
58 {
59 return;
60 }
61
62 // Now that we've gotten this far, we'll need to turn on
63 // the system attention indicator if we don't find other
64 // indicators to turn on.
65 bool sai = true;
66 auto src = pel.primarySRC();
67 const auto& calloutsObj = (*src)->callouts();
68
69 if (calloutsObj && !calloutsObj->callouts().empty())
70 {
71 const auto& callouts = calloutsObj->callouts();
72
73 // From the callouts, find the location codes whose
74 // LEDs need to be turned on.
75 auto locCodes = getLocationCodes(callouts);
76 if (!locCodes.empty())
77 {
Matt Spinler993168d2021-04-07 16:05:03 -050078 // Find the inventory paths for those location codes.
79 auto paths = getInventoryPaths(locCodes);
80 if (!paths.empty())
Matt Spinler1962e082020-08-05 13:44:53 -050081 {
Matt Spinler993168d2021-04-07 16:05:03 -050082 setNotFunctional(paths);
Sumit Kumar76198a22021-07-15 05:59:57 -050083 createCriticalAssociation(paths);
Matt Spinler1962e082020-08-05 13:44:53 -050084 sai = false;
85 }
86 }
87 }
88
89 if (sai)
90 {
Matt Spinler48c44db2020-08-25 12:47:13 -050091 try
92 {
93 _dataIface.assertLEDGroup(platformSaiLedGroup, true);
94 }
95 catch (const std::exception& e)
96 {
97 log<level::ERR>(
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -050098 std::format("Failed to assert platform SAI LED group: {}",
Matt Spinler48c44db2020-08-25 12:47:13 -050099 e.what())
100 .c_str());
101 }
Matt Spinler1962e082020-08-05 13:44:53 -0500102 }
103}
104
105std::vector<std::string> LightPath::getLocationCodes(
106 const std::vector<std::unique_ptr<src::Callout>>& callouts) const
107{
Matt Spinler05f0c6d2020-08-05 14:21:06 -0500108 std::vector<std::string> locCodes;
109 bool firstCallout = true;
110 uint8_t firstCalloutPriority;
111
112 // Collect location codes for the first group of callouts,
113 // where a group can be:
114 // * a single medium priority callout
115 // * one or more high priority callouts
116 // * one or more medium group a priority callouts
117 //
118 // All callouts in the group must be hardware callouts.
119
120 for (const auto& callout : callouts)
121 {
122 if (firstCallout)
123 {
124 firstCallout = false;
125
126 firstCalloutPriority = callout->priority();
127
128 // If the first callout is High, Medium, or Medium
129 // group A, and is a hardware callout, then we
130 // want it.
131 if (isRequiredPriority(firstCalloutPriority) &&
132 isHardwareCallout(*callout))
133 {
134 locCodes.push_back(callout->locationCode());
135 }
136 else
137 {
138 break;
139 }
140
141 // By definition a medium priority callout can't be part
142 // of a group, so no need to look for more.
143 if (static_cast<CalloutPriority>(firstCalloutPriority) ==
144 CalloutPriority::medium)
145 {
146 break;
147 }
148 }
149 else
150 {
151 // Only continue while the callouts are the same
152 // priority as the first callout.
153 if (callout->priority() != firstCalloutPriority)
154 {
155 break;
156 }
157
158 // If any callout in the group isn't a hardware callout,
159 // then don't light up any LEDs at all.
160 if (!isHardwareCallout(*callout))
161 {
162 locCodes.clear();
163 break;
164 }
165
166 locCodes.push_back(callout->locationCode());
167 }
168 }
169
170 return locCodes;
171}
172
173bool LightPath::isRequiredPriority(uint8_t priority) const
174{
175 auto calloutPriority = static_cast<CalloutPriority>(priority);
176 return (calloutPriority == CalloutPriority::high) ||
177 (calloutPriority == CalloutPriority::medium) ||
178 (calloutPriority == CalloutPriority::mediumGroupA);
179}
180
181bool LightPath::isHardwareCallout(const src::Callout& callout) const
182{
183 const auto& fruIdentity = callout.fruIdentity();
184 if (fruIdentity)
185 {
186 return (callout.locationCodeSize() != 0) &&
187 ((fruIdentity->failingComponentType() ==
188 src::FRUIdentity::hardwareFRU) ||
189 (fruIdentity->failingComponentType() ==
190 src::FRUIdentity::symbolicFRUTrustedLocCode));
191 }
192
193 return false;
Matt Spinler1962e082020-08-05 13:44:53 -0500194}
195
Matt Spinler993168d2021-04-07 16:05:03 -0500196std::vector<std::string> LightPath::getInventoryPaths(
Matt Spinler1962e082020-08-05 13:44:53 -0500197 const std::vector<std::string>& locationCodes) const
198{
Matt Spinler993168d2021-04-07 16:05:03 -0500199 std::vector<std::string> paths;
Matt Spinler34a904c2020-08-05 14:53:28 -0500200
201 for (const auto& locCode : locationCodes)
202 {
203 try
204 {
Matt Spinlerbad056b2023-01-25 14:16:57 -0600205 auto inventoryPaths = _dataIface.getInventoryFromLocCode(locCode, 0,
206 true);
207 for (const auto& path : inventoryPaths)
208 {
209 if (std::find(paths.begin(), paths.end(), path) == paths.end())
210 {
211 paths.push_back(path);
212 }
213 }
Matt Spinler34a904c2020-08-05 14:53:28 -0500214 }
215 catch (const std::exception& e)
216 {
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -0500217 log<level::ERR>(std::format("Could not get inventory path for "
Matt Spinler34a904c2020-08-05 14:53:28 -0500218 "location code {} ({}).",
219 locCode, e.what())
220 .c_str());
221
Matt Spinler993168d2021-04-07 16:05:03 -0500222 // Unless we can set the LEDs for all FRUs, we can't turn
Matt Spinler34a904c2020-08-05 14:53:28 -0500223 // on any of them, so clear the list and quit.
Matt Spinler993168d2021-04-07 16:05:03 -0500224 paths.clear();
Matt Spinler34a904c2020-08-05 14:53:28 -0500225 break;
226 }
227 }
228
Matt Spinler993168d2021-04-07 16:05:03 -0500229 return paths;
Matt Spinler1962e082020-08-05 13:44:53 -0500230}
231
Matt Spinler993168d2021-04-07 16:05:03 -0500232void LightPath::setNotFunctional(
233 const std::vector<std::string>& inventoryPaths) const
Matt Spinler1962e082020-08-05 13:44:53 -0500234{
Matt Spinler993168d2021-04-07 16:05:03 -0500235 for (const auto& path : inventoryPaths)
Matt Spinler34a904c2020-08-05 14:53:28 -0500236 {
237 try
238 {
Matt Spinler993168d2021-04-07 16:05:03 -0500239 _dataIface.setFunctional(path, false);
Matt Spinler34a904c2020-08-05 14:53:28 -0500240 }
241 catch (const std::exception& e)
242 {
Matt Spinler993168d2021-04-07 16:05:03 -0500243 log<level::INFO>(
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -0500244 std::format("Could not write Functional property on {} ({})",
Matt Spinler993168d2021-04-07 16:05:03 -0500245 path, e.what())
246 .c_str());
Matt Spinler34a904c2020-08-05 14:53:28 -0500247 }
248 }
Matt Spinler1962e082020-08-05 13:44:53 -0500249}
250
Sumit Kumar76198a22021-07-15 05:59:57 -0500251void LightPath::createCriticalAssociation(
252 const std::vector<std::string>& inventoryPaths) const
253{
254 for (const auto& path : inventoryPaths)
255 {
256 try
257 {
258 _dataIface.setCriticalAssociation(path);
259 }
260 catch (const std::exception& e)
261 {
262 log<level::INFO>(
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -0500263 std::format(
Sumit Kumar76198a22021-07-15 05:59:57 -0500264 "Could not set critical association on object path {} ({})",
265 path, e.what())
266 .c_str());
267 }
268 }
269}
270
Matt Spinler1962e082020-08-05 13:44:53 -0500271} // namespace openpower::pels::service_indicators