blob: 6f24991c6853b5ba9bb716069aab5fc4ad17d96c [file] [log] [blame]
Chicago Duan184f6022020-04-17 11:30:49 +08001#include "softoff.hpp"
2
Dung Cao3d03f3f2023-09-07 06:51:33 +00003#include "common/instance_id.hpp"
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +10004#include "common/transport.hpp"
Chicago Duan184f6022020-04-17 11:30:49 +08005#include "common/utils.hpp"
6
George Liuc453e162022-12-21 17:16:23 +08007#include <libpldm/entity.h>
8#include <libpldm/platform.h>
George Liuc453e162022-12-21 17:16:23 +08009#include <libpldm/state_set.h>
10
Riya Dixit49cfb132023-03-02 04:26:53 -060011#include <phosphor-logging/lg2.hpp>
Chicago Duan184f6022020-04-17 11:30:49 +080012#include <sdbusplus/bus.hpp>
13#include <sdeventplus/clock.hpp>
George Liua2767e62021-02-24 18:53:34 +080014#include <sdeventplus/exception.hpp>
Chicago Duan184f6022020-04-17 11:30:49 +080015#include <sdeventplus/source/io.hpp>
16#include <sdeventplus/source/time.hpp>
17
18#include <array>
Chicago Duan184f6022020-04-17 11:30:49 +080019
Riya Dixit49cfb132023-03-02 04:26:53 -060020PHOSPHOR_LOG2_USING;
21
Chicago Duan184f6022020-04-17 11:30:49 +080022namespace pldm
23{
Chicago Duan184f6022020-04-17 11:30:49 +080024using namespace sdeventplus;
25using namespace sdeventplus::source;
26constexpr auto clockId = sdeventplus::ClockId::RealTime;
27using Clock = Clock<clockId>;
28using Timer = Time<clockId>;
29
Chicago Duan184f6022020-04-17 11:30:49 +080030constexpr pldm::pdr::TerminusID TID = 0; // TID will be implemented later.
31namespace sdbusRule = sdbusplus::bus::match::rules;
32
Manojkiran Eda3fcfaa12024-02-26 15:17:58 +053033SoftPowerOff::SoftPowerOff(sdbusplus::bus_t& bus, sd_event* event,
34 pldm::InstanceIdDb& instanceIdDb) :
35 bus(bus),
36 timer(event), instanceIdDb(instanceIdDb)
Chicago Duan184f6022020-04-17 11:30:49 +080037{
Manojkiran Eda31a78442021-09-12 15:18:25 +053038 getHostState();
Chicago Duan184f6022020-04-17 11:30:49 +080039 if (hasError || completed)
40 {
41 return;
42 }
43
Manojkiran Eda31a78442021-09-12 15:18:25 +053044 auto rc = getEffecterID();
Tom Joseph29d22112020-11-18 15:05:15 +053045 if (completed)
46 {
Riya Dixit49cfb132023-03-02 04:26:53 -060047 error("pldm-softpoweroff: effecter to initiate softoff not found");
Tom Joseph29d22112020-11-18 15:05:15 +053048 return;
49 }
50 else if (rc != PLDM_SUCCESS)
Chicago Duan184f6022020-04-17 11:30:49 +080051 {
52 hasError = true;
53 return;
54 }
55
56 rc = getSensorInfo();
57 if (rc != PLDM_SUCCESS)
58 {
Riya Dixit49cfb132023-03-02 04:26:53 -060059 error("Message get Sensor PDRs error. PLDM error code = {RC}", "RC",
60 lg2::hex, static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +080061 hasError = true;
62 return;
63 }
64
65 // Matches on the pldm StateSensorEvent signal
66 pldmEventSignal = std::make_unique<sdbusplus::bus::match_t>(
67 bus,
68 sdbusRule::type::signal() + sdbusRule::member("StateSensorEvent") +
69 sdbusRule::path("/xyz/openbmc_project/pldm") +
70 sdbusRule::interface("xyz.openbmc_project.PLDM.Event"),
71 std::bind(std::mem_fn(&SoftPowerOff::hostSoftOffComplete), this,
72 std::placeholders::_1));
73}
74
75int SoftPowerOff::getHostState()
76{
77 try
78 {
79 pldm::utils::PropertyValue propertyValue =
80 pldm::utils::DBusHandler().getDbusPropertyVariant(
81 "/xyz/openbmc_project/state/host0", "CurrentHostState",
82 "xyz.openbmc_project.State.Host");
83
Andrew Geissler5b5fa432021-01-22 16:27:24 -060084 if ((std::get<std::string>(propertyValue) !=
85 "xyz.openbmc_project.State.Host.HostState.Running") &&
86 (std::get<std::string>(propertyValue) !=
87 "xyz.openbmc_project.State.Host.HostState.TransitioningToOff"))
Chicago Duan184f6022020-04-17 11:30:49 +080088 {
89 // Host state is not "Running", this app should return success
90 completed = true;
91 return PLDM_SUCCESS;
92 }
93 }
94 catch (const std::exception& e)
95 {
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -050096 error("PLDM host soft off: Can't get current host state: {ERROR}",
97 "ERROR", e);
Chicago Duan184f6022020-04-17 11:30:49 +080098 hasError = true;
99 return PLDM_ERROR;
100 }
101
102 return PLDM_SUCCESS;
103}
104
Patrick Williams84b790c2022-07-22 19:26:56 -0500105void SoftPowerOff::hostSoftOffComplete(sdbusplus::message_t& msg)
Chicago Duan184f6022020-04-17 11:30:49 +0800106{
107 pldm::pdr::TerminusID msgTID;
108 pldm::pdr::SensorID msgSensorID;
109 pldm::pdr::SensorOffset msgSensorOffset;
110 pldm::pdr::EventState msgEventState;
111 pldm::pdr::EventState msgPreviousEventState;
112
113 // Read the msg and populate each variable
114 msg.read(msgTID, msgSensorID, msgSensorOffset, msgEventState,
115 msgPreviousEventState);
116
117 if (msgSensorID == sensorID && msgSensorOffset == sensorOffset &&
118 msgEventState == PLDM_SW_TERM_GRACEFUL_SHUTDOWN)
119 {
120 // Receive Graceful shutdown completion event message. Disable the timer
121 auto rc = timer.stop();
122 if (rc < 0)
123 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600124 error("PLDM soft off: Failure to STOP the timer. ERRNO={RC}", "RC",
125 rc);
Chicago Duan184f6022020-04-17 11:30:49 +0800126 }
127
128 // This marks the completion of pldm soft power off.
129 completed = true;
130 }
131}
132
133int SoftPowerOff::getEffecterID()
134{
135 auto& bus = pldm::utils::DBusHandler::getBus();
136
137 // VMM is a logical entity, so the bit 15 in entity type is set.
138 pdr::EntityType entityType = PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER | 0x8000;
139
140 try
141 {
142 std::vector<std::vector<uint8_t>> VMMResponse{};
143 auto VMMMethod = bus.new_method_call(
144 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
145 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
146 VMMMethod.append(TID, entityType,
147 (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
148
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500149 auto VMMResponseMsg = bus.call(VMMMethod, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800150
151 VMMResponseMsg.read(VMMResponse);
152 if (VMMResponse.size() != 0)
153 {
154 for (auto& rep : VMMResponse)
155 {
156 auto VMMPdr =
157 reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
158 effecterID = VMMPdr->effecter_id;
159 }
160 }
161 else
162 {
163 VMMPdrExist = false;
164 }
165 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500166 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800167 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600168 error("PLDM soft off: Error get VMM PDR,ERROR={ERR_EXCEP}", "ERR_EXCEP",
169 e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800170 VMMPdrExist = false;
171 }
172
173 if (VMMPdrExist)
174 {
175 return PLDM_SUCCESS;
176 }
177
178 // If the Virtual Machine Manager PDRs doesn't exist, go find the System
179 // Firmware PDRs.
180 // System Firmware is a logical entity, so the bit 15 in entity type is set
181 entityType = PLDM_ENTITY_SYS_FIRMWARE | 0x8000;
182 try
183 {
184 std::vector<std::vector<uint8_t>> sysFwResponse{};
185 auto sysFwMethod = bus.new_method_call(
186 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
187 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
188 sysFwMethod.append(TID, entityType,
189 (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
190
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500191 auto sysFwResponseMsg = bus.call(sysFwMethod, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800192
193 sysFwResponseMsg.read(sysFwResponse);
194
195 if (sysFwResponse.size() == 0)
196 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600197 error("No effecter ID has been found that matches the criteria");
Chicago Duan184f6022020-04-17 11:30:49 +0800198 return PLDM_ERROR;
199 }
200
201 for (auto& rep : sysFwResponse)
202 {
203 auto sysFwPdr =
204 reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
205 effecterID = sysFwPdr->effecter_id;
206 }
207 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500208 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800209 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600210 error("PLDM soft off: Error get system firmware PDR,ERROR={ERR_EXCEP}",
211 "ERR_EXCEP", e.what());
Tom Joseph29d22112020-11-18 15:05:15 +0530212 completed = true;
Chicago Duan184f6022020-04-17 11:30:49 +0800213 return PLDM_ERROR;
214 }
215
216 return PLDM_SUCCESS;
217}
218
219int SoftPowerOff::getSensorInfo()
220{
221 pldm::pdr::EntityType entityType;
222
223 entityType = VMMPdrExist ? PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER
224 : PLDM_ENTITY_SYS_FIRMWARE;
225
226 // The Virtual machine manager/System firmware is logical entity, so bit 15
227 // need to be set.
228 entityType = entityType | 0x8000;
229
230 try
231 {
232 auto& bus = pldm::utils::DBusHandler::getBus();
233 std::vector<std::vector<uint8_t>> Response{};
234 auto method = bus.new_method_call(
235 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
236 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
237 method.append(TID, entityType,
238 (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
239
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500240 auto ResponseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800241
242 ResponseMsg.read(Response);
243
244 if (Response.size() == 0)
245 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600246 error("No sensor PDR has been found that matches the criteria");
Chicago Duan184f6022020-04-17 11:30:49 +0800247 return PLDM_ERROR;
248 }
249
ThuBaNguyen499a29d2023-05-30 06:32:06 +0700250 pldm_state_sensor_pdr* pdr = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800251 for (auto& rep : Response)
252 {
253 pdr = reinterpret_cast<pldm_state_sensor_pdr*>(rep.data());
Manojkiran Eda31a78442021-09-12 15:18:25 +0530254 if (!pdr)
255 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600256 error("Failed to get state sensor PDR.");
Manojkiran Eda31a78442021-09-12 15:18:25 +0530257 return PLDM_ERROR;
258 }
Manojkiran Edabcf91ac2021-03-14 13:50:48 +0530259 }
260
Chicago Duan184f6022020-04-17 11:30:49 +0800261 sensorID = pdr->sensor_id;
262
263 auto compositeSensorCount = pdr->composite_sensor_count;
264 auto possibleStatesStart = pdr->possible_states;
265
266 for (auto offset = 0; offset < compositeSensorCount; offset++)
267 {
268 auto possibleStates =
269 reinterpret_cast<state_sensor_possible_states*>(
270 possibleStatesStart);
271 auto setId = possibleStates->state_set_id;
272 auto possibleStateSize = possibleStates->possible_states_size;
273
274 if (setId == PLDM_STATE_SET_SW_TERMINATION_STATUS)
275 {
276 sensorOffset = offset;
277 break;
278 }
Patrick Williams6da4f912023-05-10 07:50:53 -0500279 possibleStatesStart += possibleStateSize + sizeof(setId) +
280 sizeof(possibleStateSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800281 }
282 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500283 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800284 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600285 error("PLDM soft off: Error get State Sensor PDR,ERROR={ERR_EXCEP}",
286 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800287 return PLDM_ERROR;
288 }
289
290 return PLDM_SUCCESS;
291}
292
293int SoftPowerOff::hostSoftOff(sdeventplus::Event& event)
294{
295 constexpr uint8_t effecterCount = 1;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000296 PldmTransport pldmTransport{};
Chicago Duan184f6022020-04-17 11:30:49 +0800297 uint8_t instanceID;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000298 uint8_t mctpEID;
Chicago Duan184f6022020-04-17 11:30:49 +0800299
300 mctpEID = pldm::utils::readHostEID();
Dung Cao3d03f3f2023-09-07 06:51:33 +0000301 // TODO: fix mapping to work around OpenBMC ecosystem deficiencies
302 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEID);
Chicago Duan184f6022020-04-17 11:30:49 +0800303
304 std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterID) +
305 sizeof(effecterCount) +
306 sizeof(set_effecter_state_field)>
307 requestMsg{};
308 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
309 set_effecter_state_field stateField{
310 PLDM_REQUEST_SET, PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED};
Dung Cao3d03f3f2023-09-07 06:51:33 +0000311 instanceID = instanceIdDb.next(pldmTID);
Chicago Duan184f6022020-04-17 11:30:49 +0800312 auto rc = encode_set_state_effecter_states_req(
313 instanceID, effecterID, effecterCount, &stateField, request);
314 if (rc != PLDM_SUCCESS)
315 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000316 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600317 error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
318 static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800319 return PLDM_ERROR;
320 }
321
Chicago Duan184f6022020-04-17 11:30:49 +0800322 // Add a timer to the event loop, default 30s.
Patrick Williamsa6756622023-10-20 11:19:15 -0500323 auto timerCallback = [=, this](Timer& /*source*/,
324 Timer::TimePoint /*time*/) mutable {
Chicago Duan184f6022020-04-17 11:30:49 +0800325 if (!responseReceived)
326 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000327 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600328 error(
329 "PLDM soft off: ERROR! Can't get the response for the PLDM request msg. Time out! Exit the pldm-softpoweroff");
Chicago Duan184f6022020-04-17 11:30:49 +0800330 exit(-1);
331 }
332 return;
333 };
334 Timer time(event, (Clock(event).now() + std::chrono::seconds{30}),
335 std::chrono::seconds{1}, std::move(timerCallback));
336
337 // Add a callback to handle EPOLLIN on fd
Patrick Williamsa6756622023-10-20 11:19:15 -0500338 auto callback = [=, &pldmTransport, this](IO& io, int fd,
339 uint32_t revents) mutable {
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000340 if (fd != pldmTransport.getEventSource())
341 {
342 return;
343 }
344
Chicago Duan184f6022020-04-17 11:30:49 +0800345 if (!(revents & EPOLLIN))
346 {
347 return;
348 }
349
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000350 void* responseMsg = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800351 size_t responseMsgSize{};
Dung Cao3d03f3f2023-09-07 06:51:33 +0000352 pldm_tid_t srcTID = pldmTID;
Chicago Duan184f6022020-04-17 11:30:49 +0800353
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000354 auto rc = pldmTransport.recvMsg(pldmTID, responseMsg, responseMsgSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800355 if (rc)
356 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600357 error("Soft off: failed to recv pldm data. PLDM RC = {RC}", "RC",
358 static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800359 return;
360 }
361
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000362 std::unique_ptr<void, decltype(std::free)*> responseMsgPtr{responseMsg,
363 std::free};
Chicago Duan184f6022020-04-17 11:30:49 +0800364
365 // We've got the response meant for the PLDM request msg that was
366 // sent out
367 io.set_enabled(Enabled::Off);
368 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
Dung Cao3d03f3f2023-09-07 06:51:33 +0000369
370 if (srcTID != pldmTID ||
371 !pldm_msg_hdr_correlate_response(&request->hdr, &response->hdr))
372 {
373 /* This isn't the response we were looking for */
374 return;
375 }
376
377 /* We have the right response, release the instance ID and process */
378 io.set_enabled(Enabled::Off);
379 instanceIdDb.free(pldmTID, instanceID);
380
George Liu9915d022021-12-21 14:04:31 +0800381 if (response->payload[0] != PLDM_SUCCESS)
382 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600383 error("Getting the wrong response. PLDM RC = {RC}", "RC",
384 (unsigned)response->payload[0]);
George Liu9915d022021-12-21 14:04:31 +0800385 exit(-1);
386 }
Chicago Duan184f6022020-04-17 11:30:49 +0800387
388 responseReceived = true;
389
390 // Start Timer
391 using namespace std::chrono;
392 auto timeMicroseconds =
393 duration_cast<microseconds>(seconds(SOFTOFF_TIMEOUT_SECONDS));
394
395 auto ret = startTimer(timeMicroseconds);
396 if (ret < 0)
397 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600398 error(
399 "Failure to start Host soft off wait timer, ERRNO = {RET}. Exit the pldm-softpoweroff",
400 "RET", ret);
Chicago Duan184f6022020-04-17 11:30:49 +0800401 exit(-1);
402 }
403 else
404 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600405 error(
406 "Timer started waiting for host soft off, TIMEOUT_IN_SEC = {TIMEOUT_SEC}",
407 "TIMEOUT_SEC", SOFTOFF_TIMEOUT_SECONDS);
Chicago Duan184f6022020-04-17 11:30:49 +0800408 }
409 return;
410 };
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000411 IO io(event, pldmTransport.getEventSource(), EPOLLIN, std::move(callback));
Chicago Duan184f6022020-04-17 11:30:49 +0800412
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000413 // Asynchronously send the PLDM request
414 rc = pldmTransport.sendMsg(pldmTID, requestMsg.data(), requestMsg.size());
Sampa Misra9f8d2b02021-03-24 08:33:14 +0000415 if (0 > rc)
Chicago Duan184f6022020-04-17 11:30:49 +0800416 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000417 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600418 error(
419 "Failed to send message/receive response. RC = {RC}, errno = {ERR}",
420 "RC", static_cast<int>(rc), "ERR", errno);
Chicago Duan184f6022020-04-17 11:30:49 +0800421 return PLDM_ERROR;
422 }
423
424 // Time out or soft off complete
425 while (!isCompleted() && !isTimerExpired())
426 {
427 try
428 {
429 event.run(std::nullopt);
430 }
431 catch (const sdeventplus::SdEventError& e)
432 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000433 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600434 error(
435 "PLDM host soft off: Failure in processing request.ERROR= {ERR_EXCEP}",
436 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800437 return PLDM_ERROR;
438 }
439 }
440
441 return PLDM_SUCCESS;
442}
443
444int SoftPowerOff::startTimer(const std::chrono::microseconds& usec)
445{
446 return timer.start(usec);
447}
448} // namespace pldm