blob: 831669003ecf0cfbb1ea2101d3dbc2587889f095 [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2020 IBM Corporation
3
Matt Spinler1962e082020-08-05 13:44:53 -05004#include "service_indicators.hpp"
5
Arya K Padman5bc26532024-04-10 06:19:25 -05006#include <phosphor-logging/lg2.hpp>
Matt Spinler1962e082020-08-05 13:44:53 -05007
Patrick Williams2544b412022-10-04 08:41:06 -05008#include <bitset>
9
Matt Spinler1962e082020-08-05 13:44:53 -050010namespace openpower::pels::service_indicators
11{
12
Matt Spinler48c44db2020-08-25 12:47:13 -050013static constexpr auto platformSaiLedGroup =
14 "/xyz/openbmc_project/led/groups/platform_system_attention_indicator";
15
Matt Spinler1962e082020-08-05 13:44:53 -050016std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface)
17{
18 // At the moment there is just one type of policy.
19 return std::make_unique<LightPath>(dataIface);
20}
21
22bool LightPath::ignore(const PEL& pel) const
23{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050024 auto creator = pel.privateHeader().creatorID();
25
26 // Don't ignore serviceable BMC or hostboot errors
27 if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) ||
28 (static_cast<CreatorID>(creator) == CreatorID::hostboot))
29 {
30 std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
31 if (actionFlags.test(serviceActionFlagBit))
32 {
33 return false;
34 }
35 }
36
37 return true;
Matt Spinler1962e082020-08-05 13:44:53 -050038}
39
40void LightPath::activate(const PEL& pel)
41{
42 if (ignore(pel))
43 {
44 return;
45 }
46
47 // Now that we've gotten this far, we'll need to turn on
48 // the system attention indicator if we don't find other
49 // indicators to turn on.
50 bool sai = true;
51 auto src = pel.primarySRC();
52 const auto& calloutsObj = (*src)->callouts();
53
54 if (calloutsObj && !calloutsObj->callouts().empty())
55 {
56 const auto& callouts = calloutsObj->callouts();
57
58 // From the callouts, find the location codes whose
59 // LEDs need to be turned on.
60 auto locCodes = getLocationCodes(callouts);
61 if (!locCodes.empty())
62 {
Matt Spinler993168d2021-04-07 16:05:03 -050063 // Find the inventory paths for those location codes.
64 auto paths = getInventoryPaths(locCodes);
65 if (!paths.empty())
Matt Spinler1962e082020-08-05 13:44:53 -050066 {
Matt Spinler993168d2021-04-07 16:05:03 -050067 setNotFunctional(paths);
Sumit Kumar76198a22021-07-15 05:59:57 -050068 createCriticalAssociation(paths);
Matt Spinler1962e082020-08-05 13:44:53 -050069 sai = false;
70 }
71 }
72 }
73
74 if (sai)
75 {
Matt Spinler48c44db2020-08-25 12:47:13 -050076 try
77 {
78 _dataIface.assertLEDGroup(platformSaiLedGroup, true);
79 }
80 catch (const std::exception& e)
81 {
Arya K Padman5bc26532024-04-10 06:19:25 -050082 lg2::error("Failed to assert platform SAI LED group: {EXCEPTION}",
83 "EXCEPTION", e);
Matt Spinler48c44db2020-08-25 12:47:13 -050084 }
Matt Spinler1962e082020-08-05 13:44:53 -050085 }
86}
87
88std::vector<std::string> LightPath::getLocationCodes(
89 const std::vector<std::unique_ptr<src::Callout>>& callouts) const
90{
Matt Spinler05f0c6d2020-08-05 14:21:06 -050091 std::vector<std::string> locCodes;
92 bool firstCallout = true;
93 uint8_t firstCalloutPriority;
94
95 // Collect location codes for the first group of callouts,
96 // where a group can be:
97 // * a single medium priority callout
98 // * one or more high priority callouts
99 // * one or more medium group a priority callouts
100 //
101 // All callouts in the group must be hardware callouts.
102
103 for (const auto& callout : callouts)
104 {
105 if (firstCallout)
106 {
107 firstCallout = false;
108
109 firstCalloutPriority = callout->priority();
110
111 // If the first callout is High, Medium, or Medium
112 // group A, and is a hardware callout, then we
113 // want it.
114 if (isRequiredPriority(firstCalloutPriority) &&
115 isHardwareCallout(*callout))
116 {
117 locCodes.push_back(callout->locationCode());
118 }
119 else
120 {
121 break;
122 }
123
124 // By definition a medium priority callout can't be part
125 // of a group, so no need to look for more.
126 if (static_cast<CalloutPriority>(firstCalloutPriority) ==
127 CalloutPriority::medium)
128 {
129 break;
130 }
131 }
132 else
133 {
134 // Only continue while the callouts are the same
135 // priority as the first callout.
136 if (callout->priority() != firstCalloutPriority)
137 {
138 break;
139 }
140
141 // If any callout in the group isn't a hardware callout,
142 // then don't light up any LEDs at all.
143 if (!isHardwareCallout(*callout))
144 {
145 locCodes.clear();
146 break;
147 }
148
149 locCodes.push_back(callout->locationCode());
150 }
151 }
152
153 return locCodes;
154}
155
156bool LightPath::isRequiredPriority(uint8_t priority) const
157{
158 auto calloutPriority = static_cast<CalloutPriority>(priority);
159 return (calloutPriority == CalloutPriority::high) ||
160 (calloutPriority == CalloutPriority::medium) ||
161 (calloutPriority == CalloutPriority::mediumGroupA);
162}
163
164bool LightPath::isHardwareCallout(const src::Callout& callout) const
165{
166 const auto& fruIdentity = callout.fruIdentity();
167 if (fruIdentity)
168 {
169 return (callout.locationCodeSize() != 0) &&
170 ((fruIdentity->failingComponentType() ==
171 src::FRUIdentity::hardwareFRU) ||
172 (fruIdentity->failingComponentType() ==
173 src::FRUIdentity::symbolicFRUTrustedLocCode));
174 }
175
176 return false;
Matt Spinler1962e082020-08-05 13:44:53 -0500177}
178
Matt Spinler993168d2021-04-07 16:05:03 -0500179std::vector<std::string> LightPath::getInventoryPaths(
Matt Spinler1962e082020-08-05 13:44:53 -0500180 const std::vector<std::string>& locationCodes) const
181{
Matt Spinler993168d2021-04-07 16:05:03 -0500182 std::vector<std::string> paths;
Matt Spinler34a904c2020-08-05 14:53:28 -0500183
184 for (const auto& locCode : locationCodes)
185 {
186 try
187 {
Patrick Williams075c7922024-08-16 15:19:49 -0400188 auto inventoryPaths =
189 _dataIface.getInventoryFromLocCode(locCode, 0, true);
Matt Spinlerbad056b2023-01-25 14:16:57 -0600190 for (const auto& path : inventoryPaths)
191 {
192 if (std::find(paths.begin(), paths.end(), path) == paths.end())
193 {
194 paths.push_back(path);
195 }
196 }
Matt Spinler34a904c2020-08-05 14:53:28 -0500197 }
198 catch (const std::exception& e)
199 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500200 lg2::error("Could not get inventory path for "
201 "location code {LOCCODE} ({EXCEPTION}).",
202 "LOCCODE", locCode, "EXCEPTION", e);
Matt Spinler34a904c2020-08-05 14:53:28 -0500203
Matt Spinler993168d2021-04-07 16:05:03 -0500204 // Unless we can set the LEDs for all FRUs, we can't turn
Matt Spinler34a904c2020-08-05 14:53:28 -0500205 // on any of them, so clear the list and quit.
Matt Spinler993168d2021-04-07 16:05:03 -0500206 paths.clear();
Matt Spinler34a904c2020-08-05 14:53:28 -0500207 break;
208 }
209 }
210
Matt Spinler993168d2021-04-07 16:05:03 -0500211 return paths;
Matt Spinler1962e082020-08-05 13:44:53 -0500212}
213
Matt Spinler993168d2021-04-07 16:05:03 -0500214void LightPath::setNotFunctional(
215 const std::vector<std::string>& inventoryPaths) const
Matt Spinler1962e082020-08-05 13:44:53 -0500216{
Matt Spinler993168d2021-04-07 16:05:03 -0500217 for (const auto& path : inventoryPaths)
Matt Spinler34a904c2020-08-05 14:53:28 -0500218 {
219 try
220 {
Matt Spinler993168d2021-04-07 16:05:03 -0500221 _dataIface.setFunctional(path, false);
Matt Spinler34a904c2020-08-05 14:53:28 -0500222 }
223 catch (const std::exception& e)
224 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500225 lg2::info(
226 "Could not write Functional property on {PATH} ({EXCEPTION})",
227 "PATH", path, "EXCEPTION", e);
Matt Spinler34a904c2020-08-05 14:53:28 -0500228 }
229 }
Matt Spinler1962e082020-08-05 13:44:53 -0500230}
231
Sumit Kumar76198a22021-07-15 05:59:57 -0500232void LightPath::createCriticalAssociation(
233 const std::vector<std::string>& inventoryPaths) const
234{
235 for (const auto& path : inventoryPaths)
236 {
237 try
238 {
239 _dataIface.setCriticalAssociation(path);
240 }
241 catch (const std::exception& e)
242 {
Arya K Padman5bc26532024-04-10 06:19:25 -0500243 lg2::info(
244 "Could not set critical association on object path {PATH} ({EXCEPTION})",
245 "PATH", path, "EXCEPTION", e);
Sumit Kumar76198a22021-07-15 05:59:57 -0500246 }
247 }
248}
249
Matt Spinler1962e082020-08-05 13:44:53 -0500250} // namespace openpower::pels::service_indicators