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