1 /**
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 <bitset>
19 #include <phosphor-logging/log.hpp>
20 
21 namespace openpower::pels::service_indicators
22 {
23 
24 using namespace phosphor::logging;
25 
26 std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface)
27 {
28     // At the moment there is just one type of policy.
29     return std::make_unique<LightPath>(dataIface);
30 }
31 
32 bool LightPath::ignore(const PEL& pel) const
33 {
34     auto creator = pel.privateHeader().creatorID();
35 
36     // Don't ignore serviceable BMC or hostboot errors
37     if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) ||
38         (static_cast<CreatorID>(creator) == CreatorID::hostboot))
39     {
40         std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
41         if (actionFlags.test(serviceActionFlagBit))
42         {
43             return false;
44         }
45     }
46 
47     return true;
48 }
49 
50 void LightPath::activate(const PEL& pel)
51 {
52     if (ignore(pel))
53     {
54         return;
55     }
56 
57     // Now that we've gotten this far, we'll need to turn on
58     // the system attention indicator if we don't find other
59     // indicators to turn on.
60     bool sai = true;
61     auto src = pel.primarySRC();
62     const auto& calloutsObj = (*src)->callouts();
63 
64     if (calloutsObj && !calloutsObj->callouts().empty())
65     {
66         const auto& callouts = calloutsObj->callouts();
67 
68         // From the callouts, find the location codes whose
69         // LEDs need to be turned on.
70         auto locCodes = getLocationCodes(callouts);
71         if (!locCodes.empty())
72         {
73             // Find the LED groups for those location codes.
74             auto ledPaths = getLEDGroupPaths(locCodes);
75             if (!ledPaths.empty())
76             {
77                 // Tell the LED groups to assert their LEDs.
78                 assertLEDs(ledPaths);
79                 sai = false;
80             }
81         }
82     }
83 
84     if (sai)
85     {
86         log<level::INFO>("The System Attention Indicator needs to be turned "
87                          "on, when available");
88     }
89 }
90 
91 std::vector<std::string> LightPath::getLocationCodes(
92     const std::vector<std::unique_ptr<src::Callout>>& callouts) const
93 {
94     std::vector<std::string> locCodes;
95     bool firstCallout = true;
96     uint8_t firstCalloutPriority;
97 
98     // Collect location codes for the first group of callouts,
99     // where a group can be:
100     //  * a single medium priority callout
101     //  * one or more high priority callouts
102     //  * one or more medium group a priority callouts
103     //
104     // All callouts in the group must be hardware callouts.
105 
106     for (const auto& callout : callouts)
107     {
108         if (firstCallout)
109         {
110             firstCallout = false;
111 
112             firstCalloutPriority = callout->priority();
113 
114             // If the first callout is High, Medium, or Medium
115             // group A, and is a hardware callout, then we
116             // want it.
117             if (isRequiredPriority(firstCalloutPriority) &&
118                 isHardwareCallout(*callout))
119             {
120                 locCodes.push_back(callout->locationCode());
121             }
122             else
123             {
124                 break;
125             }
126 
127             // By definition a medium priority callout can't be part
128             // of a group, so no need to look for more.
129             if (static_cast<CalloutPriority>(firstCalloutPriority) ==
130                 CalloutPriority::medium)
131             {
132                 break;
133             }
134         }
135         else
136         {
137             // Only continue while the callouts are the same
138             // priority as the first callout.
139             if (callout->priority() != firstCalloutPriority)
140             {
141                 break;
142             }
143 
144             // If any callout in the group isn't a hardware callout,
145             // then don't light up any LEDs at all.
146             if (!isHardwareCallout(*callout))
147             {
148                 locCodes.clear();
149                 break;
150             }
151 
152             locCodes.push_back(callout->locationCode());
153         }
154     }
155 
156     return locCodes;
157 }
158 
159 bool LightPath::isRequiredPriority(uint8_t priority) const
160 {
161     auto calloutPriority = static_cast<CalloutPriority>(priority);
162     return (calloutPriority == CalloutPriority::high) ||
163            (calloutPriority == CalloutPriority::medium) ||
164            (calloutPriority == CalloutPriority::mediumGroupA);
165 }
166 
167 bool LightPath::isHardwareCallout(const src::Callout& callout) const
168 {
169     const auto& fruIdentity = callout.fruIdentity();
170     if (fruIdentity)
171     {
172         return (callout.locationCodeSize() != 0) &&
173                ((fruIdentity->failingComponentType() ==
174                  src::FRUIdentity::hardwareFRU) ||
175                 (fruIdentity->failingComponentType() ==
176                  src::FRUIdentity::symbolicFRUTrustedLocCode));
177     }
178 
179     return false;
180 }
181 
182 std::vector<std::string> LightPath::getLEDGroupPaths(
183     const std::vector<std::string>& locationCodes) const
184 {
185     // TODO
186     return {};
187 }
188 
189 void LightPath::assertLEDs(const std::vector<std::string>& ledGroups) const
190 {
191     // TODO
192 }
193 
194 } // namespace openpower::pels::service_indicators
195