xref: /openbmc/phosphor-logging/extensions/openpower-pels/service_indicators.cpp (revision 8a09b982ddeb0c1e13190d9cd196e06a778d6140)
11962e087SMatt Spinler /**
21962e087SMatt Spinler  * Copyright © 2020 IBM Corporation
31962e087SMatt Spinler  *
41962e087SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
51962e087SMatt Spinler  * you may not use this file except in compliance with the License.
61962e087SMatt Spinler  * You may obtain a copy of the License at
71962e087SMatt Spinler  *
81962e087SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
91962e087SMatt Spinler  *
101962e087SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
111962e087SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
121962e087SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131962e087SMatt Spinler  * See the License for the specific language governing permissions and
141962e087SMatt Spinler  * limitations under the License.
151962e087SMatt Spinler  */
161962e087SMatt Spinler #include "service_indicators.hpp"
171962e087SMatt Spinler 
185bc26533SArya K Padman #include <phosphor-logging/lg2.hpp>
191962e087SMatt Spinler 
202544b419SPatrick Williams #include <bitset>
212544b419SPatrick Williams 
221962e087SMatt Spinler namespace openpower::pels::service_indicators
231962e087SMatt Spinler {
241962e087SMatt Spinler 
2548c44dbbSMatt Spinler static constexpr auto platformSaiLedGroup =
2648c44dbbSMatt Spinler     "/xyz/openbmc_project/led/groups/platform_system_attention_indicator";
2748c44dbbSMatt Spinler 
getPolicy(const DataInterfaceBase & dataIface)281962e087SMatt Spinler std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface)
291962e087SMatt Spinler {
301962e087SMatt Spinler     // At the moment there is just one type of policy.
311962e087SMatt Spinler     return std::make_unique<LightPath>(dataIface);
321962e087SMatt Spinler }
331962e087SMatt Spinler 
ignore(const PEL & pel) const341962e087SMatt Spinler bool LightPath::ignore(const PEL& pel) const
351962e087SMatt Spinler {
3605f0c6dcSMatt Spinler     auto creator = pel.privateHeader().creatorID();
3705f0c6dcSMatt Spinler 
3805f0c6dcSMatt Spinler     // Don't ignore serviceable BMC or hostboot errors
3905f0c6dcSMatt Spinler     if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) ||
4005f0c6dcSMatt Spinler         (static_cast<CreatorID>(creator) == CreatorID::hostboot))
4105f0c6dcSMatt Spinler     {
4205f0c6dcSMatt Spinler         std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
4305f0c6dcSMatt Spinler         if (actionFlags.test(serviceActionFlagBit))
4405f0c6dcSMatt Spinler         {
451962e087SMatt Spinler             return false;
461962e087SMatt Spinler         }
4705f0c6dcSMatt Spinler     }
4805f0c6dcSMatt Spinler 
4905f0c6dcSMatt Spinler     return true;
5005f0c6dcSMatt Spinler }
511962e087SMatt Spinler 
activate(const PEL & pel)521962e087SMatt Spinler void LightPath::activate(const PEL& pel)
531962e087SMatt Spinler {
541962e087SMatt Spinler     if (ignore(pel))
551962e087SMatt Spinler     {
561962e087SMatt Spinler         return;
571962e087SMatt Spinler     }
581962e087SMatt Spinler 
591962e087SMatt Spinler     // Now that we've gotten this far, we'll need to turn on
601962e087SMatt Spinler     // the system attention indicator if we don't find other
611962e087SMatt Spinler     // indicators to turn on.
621962e087SMatt Spinler     bool sai = true;
631962e087SMatt Spinler     auto src = pel.primarySRC();
641962e087SMatt Spinler     const auto& calloutsObj = (*src)->callouts();
651962e087SMatt Spinler 
661962e087SMatt Spinler     if (calloutsObj && !calloutsObj->callouts().empty())
671962e087SMatt Spinler     {
681962e087SMatt Spinler         const auto& callouts = calloutsObj->callouts();
691962e087SMatt Spinler 
701962e087SMatt Spinler         // From the callouts, find the location codes whose
711962e087SMatt Spinler         // LEDs need to be turned on.
721962e087SMatt Spinler         auto locCodes = getLocationCodes(callouts);
731962e087SMatt Spinler         if (!locCodes.empty())
741962e087SMatt Spinler         {
75993168deSMatt Spinler             // Find the inventory paths for those location codes.
76993168deSMatt Spinler             auto paths = getInventoryPaths(locCodes);
77993168deSMatt Spinler             if (!paths.empty())
781962e087SMatt Spinler             {
79993168deSMatt Spinler                 setNotFunctional(paths);
8076198a2eSSumit Kumar                 createCriticalAssociation(paths);
811962e087SMatt Spinler                 sai = false;
821962e087SMatt Spinler             }
831962e087SMatt Spinler         }
841962e087SMatt Spinler     }
851962e087SMatt Spinler 
861962e087SMatt Spinler     if (sai)
871962e087SMatt Spinler     {
8848c44dbbSMatt Spinler         try
8948c44dbbSMatt Spinler         {
9048c44dbbSMatt Spinler             _dataIface.assertLEDGroup(platformSaiLedGroup, true);
9148c44dbbSMatt Spinler         }
9248c44dbbSMatt Spinler         catch (const std::exception& e)
9348c44dbbSMatt Spinler         {
945bc26533SArya K Padman             lg2::error("Failed to assert platform SAI LED group: {EXCEPTION}",
955bc26533SArya K Padman                        "EXCEPTION", e);
9648c44dbbSMatt Spinler         }
971962e087SMatt Spinler     }
981962e087SMatt Spinler }
991962e087SMatt Spinler 
getLocationCodes(const std::vector<std::unique_ptr<src::Callout>> & callouts) const1001962e087SMatt Spinler std::vector<std::string> LightPath::getLocationCodes(
1011962e087SMatt Spinler     const std::vector<std::unique_ptr<src::Callout>>& callouts) const
1021962e087SMatt Spinler {
10305f0c6dcSMatt Spinler     std::vector<std::string> locCodes;
10405f0c6dcSMatt Spinler     bool firstCallout = true;
10505f0c6dcSMatt Spinler     uint8_t firstCalloutPriority;
10605f0c6dcSMatt Spinler 
10705f0c6dcSMatt Spinler     // Collect location codes for the first group of callouts,
10805f0c6dcSMatt Spinler     // where a group can be:
10905f0c6dcSMatt Spinler     //  * a single medium priority callout
11005f0c6dcSMatt Spinler     //  * one or more high priority callouts
11105f0c6dcSMatt Spinler     //  * one or more medium group a priority callouts
11205f0c6dcSMatt Spinler     //
11305f0c6dcSMatt Spinler     // All callouts in the group must be hardware callouts.
11405f0c6dcSMatt Spinler 
11505f0c6dcSMatt Spinler     for (const auto& callout : callouts)
11605f0c6dcSMatt Spinler     {
11705f0c6dcSMatt Spinler         if (firstCallout)
11805f0c6dcSMatt Spinler         {
11905f0c6dcSMatt Spinler             firstCallout = false;
12005f0c6dcSMatt Spinler 
12105f0c6dcSMatt Spinler             firstCalloutPriority = callout->priority();
12205f0c6dcSMatt Spinler 
12305f0c6dcSMatt Spinler             // If the first callout is High, Medium, or Medium
12405f0c6dcSMatt Spinler             // group A, and is a hardware callout, then we
12505f0c6dcSMatt Spinler             // want it.
12605f0c6dcSMatt Spinler             if (isRequiredPriority(firstCalloutPriority) &&
12705f0c6dcSMatt Spinler                 isHardwareCallout(*callout))
12805f0c6dcSMatt Spinler             {
12905f0c6dcSMatt Spinler                 locCodes.push_back(callout->locationCode());
13005f0c6dcSMatt Spinler             }
13105f0c6dcSMatt Spinler             else
13205f0c6dcSMatt Spinler             {
13305f0c6dcSMatt Spinler                 break;
13405f0c6dcSMatt Spinler             }
13505f0c6dcSMatt Spinler 
13605f0c6dcSMatt Spinler             // By definition a medium priority callout can't be part
13705f0c6dcSMatt Spinler             // of a group, so no need to look for more.
13805f0c6dcSMatt Spinler             if (static_cast<CalloutPriority>(firstCalloutPriority) ==
13905f0c6dcSMatt Spinler                 CalloutPriority::medium)
14005f0c6dcSMatt Spinler             {
14105f0c6dcSMatt Spinler                 break;
14205f0c6dcSMatt Spinler             }
14305f0c6dcSMatt Spinler         }
14405f0c6dcSMatt Spinler         else
14505f0c6dcSMatt Spinler         {
14605f0c6dcSMatt Spinler             // Only continue while the callouts are the same
14705f0c6dcSMatt Spinler             // priority as the first callout.
14805f0c6dcSMatt Spinler             if (callout->priority() != firstCalloutPriority)
14905f0c6dcSMatt Spinler             {
15005f0c6dcSMatt Spinler                 break;
15105f0c6dcSMatt Spinler             }
15205f0c6dcSMatt Spinler 
15305f0c6dcSMatt Spinler             // If any callout in the group isn't a hardware callout,
15405f0c6dcSMatt Spinler             // then don't light up any LEDs at all.
15505f0c6dcSMatt Spinler             if (!isHardwareCallout(*callout))
15605f0c6dcSMatt Spinler             {
15705f0c6dcSMatt Spinler                 locCodes.clear();
15805f0c6dcSMatt Spinler                 break;
15905f0c6dcSMatt Spinler             }
16005f0c6dcSMatt Spinler 
16105f0c6dcSMatt Spinler             locCodes.push_back(callout->locationCode());
16205f0c6dcSMatt Spinler         }
16305f0c6dcSMatt Spinler     }
16405f0c6dcSMatt Spinler 
16505f0c6dcSMatt Spinler     return locCodes;
16605f0c6dcSMatt Spinler }
16705f0c6dcSMatt Spinler 
isRequiredPriority(uint8_t priority) const16805f0c6dcSMatt Spinler bool LightPath::isRequiredPriority(uint8_t priority) const
16905f0c6dcSMatt Spinler {
17005f0c6dcSMatt Spinler     auto calloutPriority = static_cast<CalloutPriority>(priority);
17105f0c6dcSMatt Spinler     return (calloutPriority == CalloutPriority::high) ||
17205f0c6dcSMatt Spinler            (calloutPriority == CalloutPriority::medium) ||
17305f0c6dcSMatt Spinler            (calloutPriority == CalloutPriority::mediumGroupA);
17405f0c6dcSMatt Spinler }
17505f0c6dcSMatt Spinler 
isHardwareCallout(const src::Callout & callout) const17605f0c6dcSMatt Spinler bool LightPath::isHardwareCallout(const src::Callout& callout) const
17705f0c6dcSMatt Spinler {
17805f0c6dcSMatt Spinler     const auto& fruIdentity = callout.fruIdentity();
17905f0c6dcSMatt Spinler     if (fruIdentity)
18005f0c6dcSMatt Spinler     {
18105f0c6dcSMatt Spinler         return (callout.locationCodeSize() != 0) &&
18205f0c6dcSMatt Spinler                ((fruIdentity->failingComponentType() ==
18305f0c6dcSMatt Spinler                  src::FRUIdentity::hardwareFRU) ||
18405f0c6dcSMatt Spinler                 (fruIdentity->failingComponentType() ==
18505f0c6dcSMatt Spinler                  src::FRUIdentity::symbolicFRUTrustedLocCode));
18605f0c6dcSMatt Spinler     }
18705f0c6dcSMatt Spinler 
18805f0c6dcSMatt Spinler     return false;
1891962e087SMatt Spinler }
1901962e087SMatt Spinler 
getInventoryPaths(const std::vector<std::string> & locationCodes) const191993168deSMatt Spinler std::vector<std::string> LightPath::getInventoryPaths(
1921962e087SMatt Spinler     const std::vector<std::string>& locationCodes) const
1931962e087SMatt Spinler {
194993168deSMatt Spinler     std::vector<std::string> paths;
19534a904cfSMatt Spinler 
19634a904cfSMatt Spinler     for (const auto& locCode : locationCodes)
19734a904cfSMatt Spinler     {
19834a904cfSMatt Spinler         try
19934a904cfSMatt Spinler         {
200*075c7923SPatrick Williams             auto inventoryPaths =
201*075c7923SPatrick Williams                 _dataIface.getInventoryFromLocCode(locCode, 0, true);
202bad056beSMatt Spinler             for (const auto& path : inventoryPaths)
203bad056beSMatt Spinler             {
204bad056beSMatt Spinler                 if (std::find(paths.begin(), paths.end(), path) == paths.end())
205bad056beSMatt Spinler                 {
206bad056beSMatt Spinler                     paths.push_back(path);
207bad056beSMatt Spinler                 }
208bad056beSMatt Spinler             }
20934a904cfSMatt Spinler         }
21034a904cfSMatt Spinler         catch (const std::exception& e)
21134a904cfSMatt Spinler         {
2125bc26533SArya K Padman             lg2::error("Could not get inventory path for "
2135bc26533SArya K Padman                        "location code {LOCCODE} ({EXCEPTION}).",
2145bc26533SArya K Padman                        "LOCCODE", locCode, "EXCEPTION", e);
21534a904cfSMatt Spinler 
216993168deSMatt Spinler             // Unless we can set the LEDs for all FRUs, we can't turn
21734a904cfSMatt Spinler             // on any of them, so clear the list and quit.
218993168deSMatt Spinler             paths.clear();
21934a904cfSMatt Spinler             break;
22034a904cfSMatt Spinler         }
22134a904cfSMatt Spinler     }
22234a904cfSMatt Spinler 
223993168deSMatt Spinler     return paths;
2241962e087SMatt Spinler }
2251962e087SMatt Spinler 
setNotFunctional(const std::vector<std::string> & inventoryPaths) const226993168deSMatt Spinler void LightPath::setNotFunctional(
227993168deSMatt Spinler     const std::vector<std::string>& inventoryPaths) const
2281962e087SMatt Spinler {
229993168deSMatt Spinler     for (const auto& path : inventoryPaths)
23034a904cfSMatt Spinler     {
23134a904cfSMatt Spinler         try
23234a904cfSMatt Spinler         {
233993168deSMatt Spinler             _dataIface.setFunctional(path, false);
23434a904cfSMatt Spinler         }
23534a904cfSMatt Spinler         catch (const std::exception& e)
23634a904cfSMatt Spinler         {
2375bc26533SArya K Padman             lg2::info(
2385bc26533SArya K Padman                 "Could not write Functional property on {PATH} ({EXCEPTION})",
2395bc26533SArya K Padman                 "PATH", path, "EXCEPTION", e);
24034a904cfSMatt Spinler         }
24134a904cfSMatt Spinler     }
2421962e087SMatt Spinler }
2431962e087SMatt Spinler 
createCriticalAssociation(const std::vector<std::string> & inventoryPaths) const24476198a2eSSumit Kumar void LightPath::createCriticalAssociation(
24576198a2eSSumit Kumar     const std::vector<std::string>& inventoryPaths) const
24676198a2eSSumit Kumar {
24776198a2eSSumit Kumar     for (const auto& path : inventoryPaths)
24876198a2eSSumit Kumar     {
24976198a2eSSumit Kumar         try
25076198a2eSSumit Kumar         {
25176198a2eSSumit Kumar             _dataIface.setCriticalAssociation(path);
25276198a2eSSumit Kumar         }
25376198a2eSSumit Kumar         catch (const std::exception& e)
25476198a2eSSumit Kumar         {
2555bc26533SArya K Padman             lg2::info(
2565bc26533SArya K Padman                 "Could not set critical association on object path {PATH} ({EXCEPTION})",
2575bc26533SArya K Padman                 "PATH", path, "EXCEPTION", e);
25876198a2eSSumit Kumar         }
25976198a2eSSumit Kumar     }
26076198a2eSSumit Kumar }
26176198a2eSSumit Kumar 
2621962e087SMatt Spinler } // namespace openpower::pels::service_indicators
263