xref: /openbmc/phosphor-power/phosphor-power-sequencer/src/system.cpp (revision 8cf26d93db5458c17fbe64ae74156f8a31989d6b)
1*8cf26d93SShawn McCarney /**
2*8cf26d93SShawn McCarney  * Copyright © 2025 IBM Corporation
3*8cf26d93SShawn McCarney  *
4*8cf26d93SShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
5*8cf26d93SShawn McCarney  * you may not use this file except in compliance with the License.
6*8cf26d93SShawn McCarney  * You may obtain a copy of the License at
7*8cf26d93SShawn McCarney  *
8*8cf26d93SShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
9*8cf26d93SShawn McCarney  *
10*8cf26d93SShawn McCarney  * Unless required by applicable law or agreed to in writing, software
11*8cf26d93SShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
12*8cf26d93SShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8cf26d93SShawn McCarney  * See the License for the specific language governing permissions and
14*8cf26d93SShawn McCarney  * limitations under the License.
15*8cf26d93SShawn McCarney  */
16*8cf26d93SShawn McCarney 
17*8cf26d93SShawn McCarney #include "system.hpp"
18*8cf26d93SShawn McCarney 
19*8cf26d93SShawn McCarney #include <exception>
20*8cf26d93SShawn McCarney 
21*8cf26d93SShawn McCarney namespace phosphor::power::sequencer
22*8cf26d93SShawn McCarney {
23*8cf26d93SShawn McCarney 
initializeMonitoring(Services & services)24*8cf26d93SShawn McCarney void System::initializeMonitoring(Services& services)
25*8cf26d93SShawn McCarney {
26*8cf26d93SShawn McCarney     // Initialize status monitoring in all the chassis
27*8cf26d93SShawn McCarney     for (auto& curChassis : chassis)
28*8cf26d93SShawn McCarney     {
29*8cf26d93SShawn McCarney         curChassis->initializeMonitoring(services);
30*8cf26d93SShawn McCarney     }
31*8cf26d93SShawn McCarney     isMonitoringInitialized = true;
32*8cf26d93SShawn McCarney }
33*8cf26d93SShawn McCarney 
setPowerState(PowerState newPowerState,Services & services)34*8cf26d93SShawn McCarney void System::setPowerState(PowerState newPowerState, Services& services)
35*8cf26d93SShawn McCarney {
36*8cf26d93SShawn McCarney     verifyMonitoringInitialized();
37*8cf26d93SShawn McCarney     verifyCanSetPowerState(newPowerState);
38*8cf26d93SShawn McCarney 
39*8cf26d93SShawn McCarney     // Get chassis that can be set to the new power state
40*8cf26d93SShawn McCarney     auto chassisToSet = getChassisForNewPowerState(newPowerState, services);
41*8cf26d93SShawn McCarney     if (chassisToSet.empty())
42*8cf26d93SShawn McCarney     {
43*8cf26d93SShawn McCarney         throw std::runtime_error{std::format(
44*8cf26d93SShawn McCarney             "Unable to set system to state {}: No chassis can be set to that state",
45*8cf26d93SShawn McCarney             PowerInterface::toString(newPowerState))};
46*8cf26d93SShawn McCarney     }
47*8cf26d93SShawn McCarney 
48*8cf26d93SShawn McCarney     // Set new power state
49*8cf26d93SShawn McCarney     powerState = newPowerState;
50*8cf26d93SShawn McCarney 
51*8cf26d93SShawn McCarney     // Save list of chassis selected for current power on/off attempt
52*8cf26d93SShawn McCarney     selectedChassis = chassisToSet;
53*8cf26d93SShawn McCarney 
54*8cf26d93SShawn McCarney     // Set power state for selected chassis
55*8cf26d93SShawn McCarney     for (auto& curChassis : chassis)
56*8cf26d93SShawn McCarney     {
57*8cf26d93SShawn McCarney         if (selectedChassis.contains(curChassis->getNumber()))
58*8cf26d93SShawn McCarney         {
59*8cf26d93SShawn McCarney             try
60*8cf26d93SShawn McCarney             {
61*8cf26d93SShawn McCarney                 curChassis->setPowerState(newPowerState, services);
62*8cf26d93SShawn McCarney             }
63*8cf26d93SShawn McCarney             catch (const std::exception& e)
64*8cf26d93SShawn McCarney             {
65*8cf26d93SShawn McCarney                 services.logErrorMsg(std::format(
66*8cf26d93SShawn McCarney                     "Unable to set chassis {} to state {}: {}",
67*8cf26d93SShawn McCarney                     curChassis->getNumber(),
68*8cf26d93SShawn McCarney                     PowerInterface::toString(newPowerState), e.what()));
69*8cf26d93SShawn McCarney             }
70*8cf26d93SShawn McCarney         }
71*8cf26d93SShawn McCarney     }
72*8cf26d93SShawn McCarney }
73*8cf26d93SShawn McCarney 
monitor(Services & services)74*8cf26d93SShawn McCarney void System::monitor(Services& services)
75*8cf26d93SShawn McCarney {
76*8cf26d93SShawn McCarney     verifyMonitoringInitialized();
77*8cf26d93SShawn McCarney 
78*8cf26d93SShawn McCarney     // Monitor the status of all chassis, including those not selected for
79*8cf26d93SShawn McCarney     // current power on/off attempt. All chassis need to react to D-Bus status
80*8cf26d93SShawn McCarney     // changes.
81*8cf26d93SShawn McCarney     for (auto& curChassis : chassis)
82*8cf26d93SShawn McCarney     {
83*8cf26d93SShawn McCarney         try
84*8cf26d93SShawn McCarney         {
85*8cf26d93SShawn McCarney             curChassis->monitor(services);
86*8cf26d93SShawn McCarney         }
87*8cf26d93SShawn McCarney         catch (const std::exception& e)
88*8cf26d93SShawn McCarney         {
89*8cf26d93SShawn McCarney             services.logErrorMsg(
90*8cf26d93SShawn McCarney                 std::format("Unable to monitor chassis {}: {}",
91*8cf26d93SShawn McCarney                             curChassis->getNumber(), e.what()));
92*8cf26d93SShawn McCarney         }
93*8cf26d93SShawn McCarney     }
94*8cf26d93SShawn McCarney 
95*8cf26d93SShawn McCarney     // Set initial set of chassis selected for power on/off if needed
96*8cf26d93SShawn McCarney     setInitialSelectedChassisIfNeeded();
97*8cf26d93SShawn McCarney 
98*8cf26d93SShawn McCarney     // Set the system power good based on the chassis power good values
99*8cf26d93SShawn McCarney     setPowerGood();
100*8cf26d93SShawn McCarney 
101*8cf26d93SShawn McCarney     // Set initial system power state based on system power good if needed
102*8cf26d93SShawn McCarney     setInitialPowerStateIfNeeded();
103*8cf26d93SShawn McCarney }
104*8cf26d93SShawn McCarney 
getChassisForNewPowerState(PowerState newPowerState,Services & services)105*8cf26d93SShawn McCarney std::set<size_t> System::getChassisForNewPowerState(PowerState newPowerState,
106*8cf26d93SShawn McCarney                                                     Services& services)
107*8cf26d93SShawn McCarney {
108*8cf26d93SShawn McCarney     std::set<size_t> chassisForState;
109*8cf26d93SShawn McCarney     for (auto& curChassis : chassis)
110*8cf26d93SShawn McCarney     {
111*8cf26d93SShawn McCarney         auto [canSet, reason] = curChassis->canSetPowerState(newPowerState);
112*8cf26d93SShawn McCarney         if (canSet)
113*8cf26d93SShawn McCarney         {
114*8cf26d93SShawn McCarney             chassisForState.emplace(curChassis->getNumber());
115*8cf26d93SShawn McCarney         }
116*8cf26d93SShawn McCarney         else
117*8cf26d93SShawn McCarney         {
118*8cf26d93SShawn McCarney             services.logInfoMsg(
119*8cf26d93SShawn McCarney                 std::format("Unable to set chassis {} to state {}: {}",
120*8cf26d93SShawn McCarney                             curChassis->getNumber(),
121*8cf26d93SShawn McCarney                             PowerInterface::toString(newPowerState), reason));
122*8cf26d93SShawn McCarney         }
123*8cf26d93SShawn McCarney     }
124*8cf26d93SShawn McCarney     return chassisForState;
125*8cf26d93SShawn McCarney }
126*8cf26d93SShawn McCarney 
setInitialSelectedChassisIfNeeded()127*8cf26d93SShawn McCarney void System::setInitialSelectedChassisIfNeeded()
128*8cf26d93SShawn McCarney {
129*8cf26d93SShawn McCarney     if (!selectedChassis.empty())
130*8cf26d93SShawn McCarney     {
131*8cf26d93SShawn McCarney         // Selected set of chassis is already defined
132*8cf26d93SShawn McCarney         return;
133*8cf26d93SShawn McCarney     }
134*8cf26d93SShawn McCarney 
135*8cf26d93SShawn McCarney     // Get the set of chassis that are powered on and off. Ignore chassis with
136*8cf26d93SShawn McCarney     // an invalid status like not present.
137*8cf26d93SShawn McCarney     std::set<size_t> chassisOn, chassisOff;
138*8cf26d93SShawn McCarney     for (auto& curChassis : chassis)
139*8cf26d93SShawn McCarney     {
140*8cf26d93SShawn McCarney         try
141*8cf26d93SShawn McCarney         {
142*8cf26d93SShawn McCarney             size_t chassisNumber = curChassis->getNumber();
143*8cf26d93SShawn McCarney             if (curChassis->isPresent() && curChassis->isAvailable() &&
144*8cf26d93SShawn McCarney                 curChassis->isInputPowerGood())
145*8cf26d93SShawn McCarney             {
146*8cf26d93SShawn McCarney                 if (curChassis->getPowerGood() == PowerGood::on)
147*8cf26d93SShawn McCarney                 {
148*8cf26d93SShawn McCarney                     chassisOn.emplace(chassisNumber);
149*8cf26d93SShawn McCarney                 }
150*8cf26d93SShawn McCarney                 else
151*8cf26d93SShawn McCarney                 {
152*8cf26d93SShawn McCarney                     chassisOff.emplace(chassisNumber);
153*8cf26d93SShawn McCarney                 }
154*8cf26d93SShawn McCarney             }
155*8cf26d93SShawn McCarney         }
156*8cf26d93SShawn McCarney         catch (...)
157*8cf26d93SShawn McCarney         {
158*8cf26d93SShawn McCarney             // Ignore errors; chassis status/power good might not be available
159*8cf26d93SShawn McCarney         }
160*8cf26d93SShawn McCarney     }
161*8cf26d93SShawn McCarney 
162*8cf26d93SShawn McCarney     if (chassisOn.empty())
163*8cf26d93SShawn McCarney     {
164*8cf26d93SShawn McCarney         // No chassis with a valid status is powered on. Assume last requested
165*8cf26d93SShawn McCarney         // power state was off. Use powered off chassis as initial selected set.
166*8cf26d93SShawn McCarney         selectedChassis = chassisOff;
167*8cf26d93SShawn McCarney     }
168*8cf26d93SShawn McCarney     else
169*8cf26d93SShawn McCarney     {
170*8cf26d93SShawn McCarney         // At least one chassis with a valid status is powered on. Assume last
171*8cf26d93SShawn McCarney         // requested power state was on. Use powered on chassis as initial
172*8cf26d93SShawn McCarney         // selected set.
173*8cf26d93SShawn McCarney         selectedChassis = chassisOn;
174*8cf26d93SShawn McCarney     }
175*8cf26d93SShawn McCarney }
176*8cf26d93SShawn McCarney 
setPowerGood()177*8cf26d93SShawn McCarney void System::setPowerGood()
178*8cf26d93SShawn McCarney {
179*8cf26d93SShawn McCarney     // Return if there are no chassis selected for a power on/off attempt
180*8cf26d93SShawn McCarney     if (selectedChassis.empty())
181*8cf26d93SShawn McCarney     {
182*8cf26d93SShawn McCarney         return;
183*8cf26d93SShawn McCarney     }
184*8cf26d93SShawn McCarney 
185*8cf26d93SShawn McCarney     // Count the number of selected chassis with power good on and off
186*8cf26d93SShawn McCarney     size_t powerGoodOnCount{0}, powerGoodOffCount{0};
187*8cf26d93SShawn McCarney     for (auto& curChassis : chassis)
188*8cf26d93SShawn McCarney     {
189*8cf26d93SShawn McCarney         if (selectedChassis.contains(curChassis->getNumber()))
190*8cf26d93SShawn McCarney         {
191*8cf26d93SShawn McCarney             try
192*8cf26d93SShawn McCarney             {
193*8cf26d93SShawn McCarney                 if (curChassis->getPowerGood() == PowerGood::on)
194*8cf26d93SShawn McCarney                 {
195*8cf26d93SShawn McCarney                     ++powerGoodOnCount;
196*8cf26d93SShawn McCarney                 }
197*8cf26d93SShawn McCarney                 else
198*8cf26d93SShawn McCarney                 {
199*8cf26d93SShawn McCarney                     ++powerGoodOffCount;
200*8cf26d93SShawn McCarney                 }
201*8cf26d93SShawn McCarney             }
202*8cf26d93SShawn McCarney             catch (...)
203*8cf26d93SShawn McCarney             {
204*8cf26d93SShawn McCarney                 // Chassis power good might not be available
205*8cf26d93SShawn McCarney             }
206*8cf26d93SShawn McCarney         }
207*8cf26d93SShawn McCarney     }
208*8cf26d93SShawn McCarney 
209*8cf26d93SShawn McCarney     if (powerGoodOnCount == selectedChassis.size())
210*8cf26d93SShawn McCarney     {
211*8cf26d93SShawn McCarney         // All selected chassis are on; set system power good to on
212*8cf26d93SShawn McCarney         powerGood = PowerGood::on;
213*8cf26d93SShawn McCarney     }
214*8cf26d93SShawn McCarney     else if (powerGoodOffCount == selectedChassis.size())
215*8cf26d93SShawn McCarney     {
216*8cf26d93SShawn McCarney         // All selected chassis are off; set system power good to off
217*8cf26d93SShawn McCarney         powerGood = PowerGood::off;
218*8cf26d93SShawn McCarney     }
219*8cf26d93SShawn McCarney }
220*8cf26d93SShawn McCarney 
setInitialPowerStateIfNeeded()221*8cf26d93SShawn McCarney void System::setInitialPowerStateIfNeeded()
222*8cf26d93SShawn McCarney {
223*8cf26d93SShawn McCarney     if (!powerState)
224*8cf26d93SShawn McCarney     {
225*8cf26d93SShawn McCarney         if (powerGood)
226*8cf26d93SShawn McCarney         {
227*8cf26d93SShawn McCarney             if (powerGood == PowerGood::off)
228*8cf26d93SShawn McCarney             {
229*8cf26d93SShawn McCarney                 powerState = PowerState::off;
230*8cf26d93SShawn McCarney             }
231*8cf26d93SShawn McCarney             else
232*8cf26d93SShawn McCarney             {
233*8cf26d93SShawn McCarney                 powerState = PowerState::on;
234*8cf26d93SShawn McCarney             }
235*8cf26d93SShawn McCarney         }
236*8cf26d93SShawn McCarney     }
237*8cf26d93SShawn McCarney }
238*8cf26d93SShawn McCarney 
239*8cf26d93SShawn McCarney } // namespace phosphor::power::sequencer
240