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