blob: be789331631116fd727fa39e40e33996364a4752 [file] [log] [blame]
Chicago Duan184f6022020-04-17 11:30:49 +08001#include "softoff.hpp"
2
Chicago Duan184f6022020-04-17 11:30:49 +08003#include "common/utils.hpp"
4
George Liuc453e162022-12-21 17:16:23 +08005#include <libpldm/entity.h>
6#include <libpldm/platform.h>
7#include <libpldm/pldm.h>
8#include <libpldm/state_set.h>
9
Riya Dixit49cfb132023-03-02 04:26:53 -060010#include <phosphor-logging/lg2.hpp>
Chicago Duan184f6022020-04-17 11:30:49 +080011#include <sdbusplus/bus.hpp>
12#include <sdeventplus/clock.hpp>
George Liua2767e62021-02-24 18:53:34 +080013#include <sdeventplus/exception.hpp>
Chicago Duan184f6022020-04-17 11:30:49 +080014#include <sdeventplus/source/io.hpp>
15#include <sdeventplus/source/time.hpp>
16
17#include <array>
18#include <iostream>
19
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
Patrick Williams84b790c2022-07-22 19:26:56 -050033SoftPowerOff::SoftPowerOff(sdbusplus::bus_t& bus, sd_event* event) :
Chicago Duan184f6022020-04-17 11:30:49 +080034 bus(bus), timer(event)
35{
Manojkiran Eda31a78442021-09-12 15:18:25 +053036 getHostState();
Chicago Duan184f6022020-04-17 11:30:49 +080037 if (hasError || completed)
38 {
39 return;
40 }
41
Manojkiran Eda31a78442021-09-12 15:18:25 +053042 auto rc = getEffecterID();
Tom Joseph29d22112020-11-18 15:05:15 +053043 if (completed)
44 {
Riya Dixit49cfb132023-03-02 04:26:53 -060045 error("pldm-softpoweroff: effecter to initiate softoff not found");
Tom Joseph29d22112020-11-18 15:05:15 +053046 return;
47 }
48 else if (rc != PLDM_SUCCESS)
Chicago Duan184f6022020-04-17 11:30:49 +080049 {
50 hasError = true;
51 return;
52 }
53
54 rc = getSensorInfo();
55 if (rc != PLDM_SUCCESS)
56 {
Riya Dixit49cfb132023-03-02 04:26:53 -060057 error("Message get Sensor PDRs error. PLDM error code = {RC}", "RC",
58 lg2::hex, static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +080059 hasError = true;
60 return;
61 }
62
63 // Matches on the pldm StateSensorEvent signal
64 pldmEventSignal = std::make_unique<sdbusplus::bus::match_t>(
65 bus,
66 sdbusRule::type::signal() + sdbusRule::member("StateSensorEvent") +
67 sdbusRule::path("/xyz/openbmc_project/pldm") +
68 sdbusRule::interface("xyz.openbmc_project.PLDM.Event"),
69 std::bind(std::mem_fn(&SoftPowerOff::hostSoftOffComplete), this,
70 std::placeholders::_1));
71}
72
73int SoftPowerOff::getHostState()
74{
75 try
76 {
77 pldm::utils::PropertyValue propertyValue =
78 pldm::utils::DBusHandler().getDbusPropertyVariant(
79 "/xyz/openbmc_project/state/host0", "CurrentHostState",
80 "xyz.openbmc_project.State.Host");
81
Andrew Geissler5b5fa432021-01-22 16:27:24 -060082 if ((std::get<std::string>(propertyValue) !=
83 "xyz.openbmc_project.State.Host.HostState.Running") &&
84 (std::get<std::string>(propertyValue) !=
85 "xyz.openbmc_project.State.Host.HostState.TransitioningToOff"))
Chicago Duan184f6022020-04-17 11:30:49 +080086 {
87 // Host state is not "Running", this app should return success
88 completed = true;
89 return PLDM_SUCCESS;
90 }
91 }
92 catch (const std::exception& e)
93 {
Riya Dixit49cfb132023-03-02 04:26:53 -060094 error("PLDM host soft off: Can't get current host state.");
Chicago Duan184f6022020-04-17 11:30:49 +080095 hasError = true;
96 return PLDM_ERROR;
97 }
98
99 return PLDM_SUCCESS;
100}
101
Patrick Williams84b790c2022-07-22 19:26:56 -0500102void SoftPowerOff::hostSoftOffComplete(sdbusplus::message_t& msg)
Chicago Duan184f6022020-04-17 11:30:49 +0800103{
104 pldm::pdr::TerminusID msgTID;
105 pldm::pdr::SensorID msgSensorID;
106 pldm::pdr::SensorOffset msgSensorOffset;
107 pldm::pdr::EventState msgEventState;
108 pldm::pdr::EventState msgPreviousEventState;
109
110 // Read the msg and populate each variable
111 msg.read(msgTID, msgSensorID, msgSensorOffset, msgEventState,
112 msgPreviousEventState);
113
114 if (msgSensorID == sensorID && msgSensorOffset == sensorOffset &&
115 msgEventState == PLDM_SW_TERM_GRACEFUL_SHUTDOWN)
116 {
117 // Receive Graceful shutdown completion event message. Disable the timer
118 auto rc = timer.stop();
119 if (rc < 0)
120 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600121 error("PLDM soft off: Failure to STOP the timer. ERRNO={RC}", "RC",
122 rc);
Chicago Duan184f6022020-04-17 11:30:49 +0800123 }
124
125 // This marks the completion of pldm soft power off.
126 completed = true;
127 }
128}
129
130int SoftPowerOff::getEffecterID()
131{
132 auto& bus = pldm::utils::DBusHandler::getBus();
133
134 // VMM is a logical entity, so the bit 15 in entity type is set.
135 pdr::EntityType entityType = PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER | 0x8000;
136
137 try
138 {
139 std::vector<std::vector<uint8_t>> VMMResponse{};
140 auto VMMMethod = bus.new_method_call(
141 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
142 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
143 VMMMethod.append(TID, entityType,
144 (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
145
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500146 auto VMMResponseMsg = bus.call(VMMMethod, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800147
148 VMMResponseMsg.read(VMMResponse);
149 if (VMMResponse.size() != 0)
150 {
151 for (auto& rep : VMMResponse)
152 {
153 auto VMMPdr =
154 reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
155 effecterID = VMMPdr->effecter_id;
156 }
157 }
158 else
159 {
160 VMMPdrExist = false;
161 }
162 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500163 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800164 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600165 error("PLDM soft off: Error get VMM PDR,ERROR={ERR_EXCEP}", "ERR_EXCEP",
166 e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800167 VMMPdrExist = false;
168 }
169
170 if (VMMPdrExist)
171 {
172 return PLDM_SUCCESS;
173 }
174
175 // If the Virtual Machine Manager PDRs doesn't exist, go find the System
176 // Firmware PDRs.
177 // System Firmware is a logical entity, so the bit 15 in entity type is set
178 entityType = PLDM_ENTITY_SYS_FIRMWARE | 0x8000;
179 try
180 {
181 std::vector<std::vector<uint8_t>> sysFwResponse{};
182 auto sysFwMethod = bus.new_method_call(
183 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
184 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
185 sysFwMethod.append(TID, entityType,
186 (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
187
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500188 auto sysFwResponseMsg = bus.call(sysFwMethod, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800189
190 sysFwResponseMsg.read(sysFwResponse);
191
192 if (sysFwResponse.size() == 0)
193 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600194 error("No effecter ID has been found that matches the criteria");
Chicago Duan184f6022020-04-17 11:30:49 +0800195 return PLDM_ERROR;
196 }
197
198 for (auto& rep : sysFwResponse)
199 {
200 auto sysFwPdr =
201 reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
202 effecterID = sysFwPdr->effecter_id;
203 }
204 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500205 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800206 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600207 error("PLDM soft off: Error get system firmware PDR,ERROR={ERR_EXCEP}",
208 "ERR_EXCEP", e.what());
Tom Joseph29d22112020-11-18 15:05:15 +0530209 completed = true;
Chicago Duan184f6022020-04-17 11:30:49 +0800210 return PLDM_ERROR;
211 }
212
213 return PLDM_SUCCESS;
214}
215
216int SoftPowerOff::getSensorInfo()
217{
218 pldm::pdr::EntityType entityType;
219
220 entityType = VMMPdrExist ? PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER
221 : PLDM_ENTITY_SYS_FIRMWARE;
222
223 // The Virtual machine manager/System firmware is logical entity, so bit 15
224 // need to be set.
225 entityType = entityType | 0x8000;
226
227 try
228 {
229 auto& bus = pldm::utils::DBusHandler::getBus();
230 std::vector<std::vector<uint8_t>> Response{};
231 auto method = bus.new_method_call(
232 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
233 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
234 method.append(TID, entityType,
235 (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
236
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500237 auto ResponseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800238
239 ResponseMsg.read(Response);
240
241 if (Response.size() == 0)
242 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600243 error("No sensor PDR has been found that matches the criteria");
Chicago Duan184f6022020-04-17 11:30:49 +0800244 return PLDM_ERROR;
245 }
246
ThuBaNguyen499a29d2023-05-30 06:32:06 +0700247 pldm_state_sensor_pdr* pdr = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800248 for (auto& rep : Response)
249 {
250 pdr = reinterpret_cast<pldm_state_sensor_pdr*>(rep.data());
Manojkiran Eda31a78442021-09-12 15:18:25 +0530251 if (!pdr)
252 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600253 error("Failed to get state sensor PDR.");
Manojkiran Eda31a78442021-09-12 15:18:25 +0530254 return PLDM_ERROR;
255 }
Manojkiran Edabcf91ac2021-03-14 13:50:48 +0530256 }
257
Chicago Duan184f6022020-04-17 11:30:49 +0800258 sensorID = pdr->sensor_id;
259
260 auto compositeSensorCount = pdr->composite_sensor_count;
261 auto possibleStatesStart = pdr->possible_states;
262
263 for (auto offset = 0; offset < compositeSensorCount; offset++)
264 {
265 auto possibleStates =
266 reinterpret_cast<state_sensor_possible_states*>(
267 possibleStatesStart);
268 auto setId = possibleStates->state_set_id;
269 auto possibleStateSize = possibleStates->possible_states_size;
270
271 if (setId == PLDM_STATE_SET_SW_TERMINATION_STATUS)
272 {
273 sensorOffset = offset;
274 break;
275 }
Patrick Williams6da4f912023-05-10 07:50:53 -0500276 possibleStatesStart += possibleStateSize + sizeof(setId) +
277 sizeof(possibleStateSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800278 }
279 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500280 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800281 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600282 error("PLDM soft off: Error get State Sensor PDR,ERROR={ERR_EXCEP}",
283 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800284 return PLDM_ERROR;
285 }
286
287 return PLDM_SUCCESS;
288}
289
290int SoftPowerOff::hostSoftOff(sdeventplus::Event& event)
291{
292 constexpr uint8_t effecterCount = 1;
293 uint8_t mctpEID;
294 uint8_t instanceID;
295
296 mctpEID = pldm::utils::readHostEID();
297
298 // Get instanceID
299 try
300 {
301 auto& bus = pldm::utils::DBusHandler::getBus();
302 auto method = bus.new_method_call(
303 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
304 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
305 method.append(mctpEID);
306
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500307 auto ResponseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800308
309 ResponseMsg.read(instanceID);
310 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500311 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800312 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600313 error("PLDM soft off: Error get instanceID,ERROR={ERR_EXCEP}",
314 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800315 return PLDM_ERROR;
316 }
317
318 std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterID) +
319 sizeof(effecterCount) +
320 sizeof(set_effecter_state_field)>
321 requestMsg{};
322 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
323 set_effecter_state_field stateField{
324 PLDM_REQUEST_SET, PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED};
325 auto rc = encode_set_state_effecter_states_req(
326 instanceID, effecterID, effecterCount, &stateField, request);
327 if (rc != PLDM_SUCCESS)
328 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600329 error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
330 static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800331 return PLDM_ERROR;
332 }
333
334 // Open connection to MCTP socket
335 int fd = pldm_open();
336 if (-1 == fd)
337 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600338 error("Failed to connect to mctp demux daemon");
Chicago Duan184f6022020-04-17 11:30:49 +0800339 return PLDM_ERROR;
340 }
341
342 // Add a timer to the event loop, default 30s.
Patrick Williams6da4f912023-05-10 07:50:53 -0500343 auto timerCallback =
344 [=, this](Timer& /*source*/, Timer::TimePoint /*time*/) {
Chicago Duan184f6022020-04-17 11:30:49 +0800345 if (!responseReceived)
346 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600347 error(
348 "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 +0800349 exit(-1);
350 }
351 return;
352 };
353 Timer time(event, (Clock(event).now() + std::chrono::seconds{30}),
354 std::chrono::seconds{1}, std::move(timerCallback));
355
356 // Add a callback to handle EPOLLIN on fd
Deepak Kodihallib0d15f12021-04-16 12:18:10 +0530357 auto callback = [=, this](IO& io, int fd, uint32_t revents) {
Chicago Duan184f6022020-04-17 11:30:49 +0800358 if (!(revents & EPOLLIN))
359 {
360 return;
361 }
362
363 uint8_t* responseMsg = nullptr;
364 size_t responseMsgSize{};
365
366 auto rc = pldm_recv(mctpEID, fd, request->hdr.instance_id, &responseMsg,
367 &responseMsgSize);
368 if (rc)
369 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600370 error("Soft off: failed to recv pldm data. PLDM RC = {RC}", "RC",
371 static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800372 return;
373 }
374
375 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
376 responseMsg, std::free};
377
378 // We've got the response meant for the PLDM request msg that was
379 // sent out
380 io.set_enabled(Enabled::Off);
381 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
George Liu9915d022021-12-21 14:04:31 +0800382 if (response->payload[0] != PLDM_SUCCESS)
383 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600384 error("Getting the wrong response. PLDM RC = {RC}", "RC",
385 (unsigned)response->payload[0]);
George Liu9915d022021-12-21 14:04:31 +0800386 exit(-1);
387 }
Chicago Duan184f6022020-04-17 11:30:49 +0800388
389 responseReceived = true;
390
391 // Start Timer
392 using namespace std::chrono;
393 auto timeMicroseconds =
394 duration_cast<microseconds>(seconds(SOFTOFF_TIMEOUT_SECONDS));
395
396 auto ret = startTimer(timeMicroseconds);
397 if (ret < 0)
398 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600399 error(
400 "Failure to start Host soft off wait timer, ERRNO = {RET}. Exit the pldm-softpoweroff",
401 "RET", ret);
Chicago Duan184f6022020-04-17 11:30:49 +0800402 exit(-1);
403 }
404 else
405 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600406 error(
407 "Timer started waiting for host soft off, TIMEOUT_IN_SEC = {TIMEOUT_SEC}",
408 "TIMEOUT_SEC", SOFTOFF_TIMEOUT_SECONDS);
Chicago Duan184f6022020-04-17 11:30:49 +0800409 }
410 return;
411 };
412 IO io(event, fd, EPOLLIN, std::move(callback));
413
414 // Send PLDM Request message - pldm_send doesn't wait for response
415 rc = pldm_send(mctpEID, fd, requestMsg.data(), requestMsg.size());
Sampa Misra9f8d2b02021-03-24 08:33:14 +0000416 if (0 > rc)
Chicago Duan184f6022020-04-17 11:30:49 +0800417 {
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 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600433 error(
434 "PLDM host soft off: Failure in processing request.ERROR= {ERR_EXCEP}",
435 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800436 return PLDM_ERROR;
437 }
438 }
439
440 return PLDM_SUCCESS;
441}
442
443int SoftPowerOff::startTimer(const std::chrono::microseconds& usec)
444{
445 return timer.start(usec);
446}
447} // namespace pldm