blob: df5807e297bfa3eb426db6ba03f51045497f5b9c [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>
Sagar Srinivas4d99c312024-03-28 06:50:13 -050019#include <filesystem>
20#include <fstream>
Chicago Duan184f6022020-04-17 11:30:49 +080021
Riya Dixit49cfb132023-03-02 04:26:53 -060022PHOSPHOR_LOG2_USING;
23
Chicago Duan184f6022020-04-17 11:30:49 +080024namespace pldm
25{
Chicago Duan184f6022020-04-17 11:30:49 +080026using namespace sdeventplus;
27using namespace sdeventplus::source;
Sagar Srinivas4d99c312024-03-28 06:50:13 -050028namespace fs = std::filesystem;
Chicago Duan184f6022020-04-17 11:30:49 +080029constexpr auto clockId = sdeventplus::ClockId::RealTime;
30using Clock = Clock<clockId>;
31using Timer = Time<clockId>;
32
Zach Clarke98c51b2021-06-08 11:29:06 -050033using sdbusplus::exception::SdBusError;
34
35// Shutdown effecter terminus ID, set when we look up the effecter
36pldm::pdr::TerminusID TID = 0;
37
Chicago Duan184f6022020-04-17 11:30:49 +080038namespace sdbusRule = sdbusplus::bus::match::rules;
39
Manojkiran Eda3fcfaa12024-02-26 15:17:58 +053040SoftPowerOff::SoftPowerOff(sdbusplus::bus_t& bus, sd_event* event,
41 pldm::InstanceIdDb& instanceIdDb) :
42 bus(bus),
43 timer(event), instanceIdDb(instanceIdDb)
Chicago Duan184f6022020-04-17 11:30:49 +080044{
Sagar Srinivas4d99c312024-03-28 06:50:13 -050045 auto jsonData = parseConfig();
46
47 if (jsonData.is_discarded())
48 {
49 error("Parsing softoff config JSON file failed");
50 return;
51 }
52
Manojkiran Eda31a78442021-09-12 15:18:25 +053053 getHostState();
Chicago Duan184f6022020-04-17 11:30:49 +080054 if (hasError || completed)
55 {
56 return;
57 }
Sagar Srinivas4d99c312024-03-28 06:50:13 -050058 const std::vector<Json> emptyJsonList{};
59 auto entries = jsonData.value("entries", emptyJsonList);
60 for (const auto& entry : entries)
61 {
62 TID = entry.value("tid", 0);
63 pldm::pdr::EntityType entityType = entry.value("entityType", 0);
64 pldm::pdr::StateSetId stateSetId = entry.value("stateSetId", 0);
Chicago Duan184f6022020-04-17 11:30:49 +080065
Sagar Srinivas4d99c312024-03-28 06:50:13 -050066 bool effecterFound = getEffecterID(entityType, stateSetId);
67 if (effecterFound)
68 {
69 auto rc = getSensorInfo(entityType, stateSetId);
70 if (rc != PLDM_SUCCESS)
71 {
72 error("Message get Sensor PDRs error. PLDM error code = {RC}",
73 "RC", lg2::hex, static_cast<int>(rc));
74 hasError = true;
75 return;
76 }
77 break;
78 }
79 else
80 {
81 continue;
82 }
Chicago Duan184f6022020-04-17 11:30:49 +080083 }
84
85 // Matches on the pldm StateSensorEvent signal
86 pldmEventSignal = std::make_unique<sdbusplus::bus::match_t>(
87 bus,
88 sdbusRule::type::signal() + sdbusRule::member("StateSensorEvent") +
89 sdbusRule::path("/xyz/openbmc_project/pldm") +
90 sdbusRule::interface("xyz.openbmc_project.PLDM.Event"),
91 std::bind(std::mem_fn(&SoftPowerOff::hostSoftOffComplete), this,
92 std::placeholders::_1));
93}
94
95int SoftPowerOff::getHostState()
96{
97 try
98 {
99 pldm::utils::PropertyValue propertyValue =
100 pldm::utils::DBusHandler().getDbusPropertyVariant(
101 "/xyz/openbmc_project/state/host0", "CurrentHostState",
102 "xyz.openbmc_project.State.Host");
103
Andrew Geissler5b5fa432021-01-22 16:27:24 -0600104 if ((std::get<std::string>(propertyValue) !=
105 "xyz.openbmc_project.State.Host.HostState.Running") &&
106 (std::get<std::string>(propertyValue) !=
107 "xyz.openbmc_project.State.Host.HostState.TransitioningToOff"))
Chicago Duan184f6022020-04-17 11:30:49 +0800108 {
109 // Host state is not "Running", this app should return success
110 completed = true;
111 return PLDM_SUCCESS;
112 }
113 }
114 catch (const std::exception& e)
115 {
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500116 error("PLDM host soft off: Can't get current host state: {ERROR}",
117 "ERROR", e);
Chicago Duan184f6022020-04-17 11:30:49 +0800118 hasError = true;
119 return PLDM_ERROR;
120 }
121
122 return PLDM_SUCCESS;
123}
124
Patrick Williams84b790c2022-07-22 19:26:56 -0500125void SoftPowerOff::hostSoftOffComplete(sdbusplus::message_t& msg)
Chicago Duan184f6022020-04-17 11:30:49 +0800126{
127 pldm::pdr::TerminusID msgTID;
128 pldm::pdr::SensorID msgSensorID;
129 pldm::pdr::SensorOffset msgSensorOffset;
130 pldm::pdr::EventState msgEventState;
131 pldm::pdr::EventState msgPreviousEventState;
132
133 // Read the msg and populate each variable
134 msg.read(msgTID, msgSensorID, msgSensorOffset, msgEventState,
135 msgPreviousEventState);
136
137 if (msgSensorID == sensorID && msgSensorOffset == sensorOffset &&
Zach Clarke98c51b2021-06-08 11:29:06 -0500138 msgEventState == PLDM_SW_TERM_GRACEFUL_SHUTDOWN && msgTID == TID)
Chicago Duan184f6022020-04-17 11:30:49 +0800139 {
140 // Receive Graceful shutdown completion event message. Disable the timer
141 auto rc = timer.stop();
142 if (rc < 0)
143 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600144 error("PLDM soft off: Failure to STOP the timer. ERRNO={RC}", "RC",
145 rc);
Chicago Duan184f6022020-04-17 11:30:49 +0800146 }
147
148 // This marks the completion of pldm soft power off.
149 completed = true;
150 }
151}
152
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500153Json SoftPowerOff::parseConfig()
154{
155 fs::path softoffConfigJson(fs::path(SOFTOFF_CONFIG_JSON) /
156 "softoff_config.json");
157
158 if (!fs::exists(softoffConfigJson) || fs::is_empty(softoffConfigJson))
159 {
160 error("Parsing softoff config JSON file failed, File does not exist");
161 return PLDM_ERROR;
162 }
163
164 std::ifstream jsonFile(softoffConfigJson);
165 return Json::parse(jsonFile);
166}
167
168bool SoftPowerOff::getEffecterID(pldm::pdr::EntityType& entityType,
169 pldm::pdr::StateSetId& stateSetId)
Chicago Duan184f6022020-04-17 11:30:49 +0800170{
171 auto& bus = pldm::utils::DBusHandler::getBus();
Chicago Duan184f6022020-04-17 11:30:49 +0800172 try
173 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500174 std::vector<std::vector<uint8_t>> response{};
175 auto method = bus.new_method_call(
Chicago Duan184f6022020-04-17 11:30:49 +0800176 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
177 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500178 method.append(TID, entityType, stateSetId);
179 auto responseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800180
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500181 responseMsg.read(response);
182 if (response.size())
Chicago Duan184f6022020-04-17 11:30:49 +0800183 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500184 for (auto& rep : response)
Chicago Duan184f6022020-04-17 11:30:49 +0800185 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500186 auto softoffPdr =
Chicago Duan184f6022020-04-17 11:30:49 +0800187 reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500188 effecterID = softoffPdr->effecter_id;
Chicago Duan184f6022020-04-17 11:30:49 +0800189 }
190 }
191 else
192 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500193 return false;
Chicago Duan184f6022020-04-17 11:30:49 +0800194 }
195 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500196 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800197 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500198 error("PLDM soft off: Error get softPowerOff PDR,ERROR={ERR_EXCEP}",
Riya Dixit49cfb132023-03-02 04:26:53 -0600199 "ERR_EXCEP", e.what());
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500200 return false;
Chicago Duan184f6022020-04-17 11:30:49 +0800201 }
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500202 return true;
Chicago Duan184f6022020-04-17 11:30:49 +0800203}
204
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500205int SoftPowerOff::getSensorInfo(pldm::pdr::EntityType& entityType,
206 pldm::pdr::StateSetId& stateSetId)
Chicago Duan184f6022020-04-17 11:30:49 +0800207{
Chicago Duan184f6022020-04-17 11:30:49 +0800208 try
209 {
210 auto& bus = pldm::utils::DBusHandler::getBus();
211 std::vector<std::vector<uint8_t>> Response{};
212 auto method = bus.new_method_call(
213 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
214 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500215 method.append(TID, entityType, stateSetId);
Chicago Duan184f6022020-04-17 11:30:49 +0800216
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500217 auto ResponseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800218
219 ResponseMsg.read(Response);
220
221 if (Response.size() == 0)
222 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600223 error("No sensor PDR has been found that matches the criteria");
Chicago Duan184f6022020-04-17 11:30:49 +0800224 return PLDM_ERROR;
225 }
226
ThuBaNguyen499a29d2023-05-30 06:32:06 +0700227 pldm_state_sensor_pdr* pdr = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800228 for (auto& rep : Response)
229 {
230 pdr = reinterpret_cast<pldm_state_sensor_pdr*>(rep.data());
Manojkiran Eda31a78442021-09-12 15:18:25 +0530231 if (!pdr)
232 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600233 error("Failed to get state sensor PDR.");
Manojkiran Eda31a78442021-09-12 15:18:25 +0530234 return PLDM_ERROR;
235 }
Manojkiran Edabcf91ac2021-03-14 13:50:48 +0530236 }
237
Chicago Duan184f6022020-04-17 11:30:49 +0800238 sensorID = pdr->sensor_id;
239
240 auto compositeSensorCount = pdr->composite_sensor_count;
241 auto possibleStatesStart = pdr->possible_states;
242
243 for (auto offset = 0; offset < compositeSensorCount; offset++)
244 {
245 auto possibleStates =
246 reinterpret_cast<state_sensor_possible_states*>(
247 possibleStatesStart);
248 auto setId = possibleStates->state_set_id;
249 auto possibleStateSize = possibleStates->possible_states_size;
250
251 if (setId == PLDM_STATE_SET_SW_TERMINATION_STATUS)
252 {
253 sensorOffset = offset;
254 break;
255 }
Patrick Williams6da4f912023-05-10 07:50:53 -0500256 possibleStatesStart += possibleStateSize + sizeof(setId) +
257 sizeof(possibleStateSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800258 }
259 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500260 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800261 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600262 error("PLDM soft off: Error get State Sensor PDR,ERROR={ERR_EXCEP}",
263 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800264 return PLDM_ERROR;
265 }
266
267 return PLDM_SUCCESS;
268}
269
270int SoftPowerOff::hostSoftOff(sdeventplus::Event& event)
271{
272 constexpr uint8_t effecterCount = 1;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000273 PldmTransport pldmTransport{};
Chicago Duan184f6022020-04-17 11:30:49 +0800274 uint8_t instanceID;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000275 uint8_t mctpEID;
Chicago Duan184f6022020-04-17 11:30:49 +0800276
277 mctpEID = pldm::utils::readHostEID();
Dung Cao3d03f3f2023-09-07 06:51:33 +0000278 // TODO: fix mapping to work around OpenBMC ecosystem deficiencies
279 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEID);
Chicago Duan184f6022020-04-17 11:30:49 +0800280
281 std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterID) +
282 sizeof(effecterCount) +
283 sizeof(set_effecter_state_field)>
284 requestMsg{};
285 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
286 set_effecter_state_field stateField{
287 PLDM_REQUEST_SET, PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED};
Dung Cao3d03f3f2023-09-07 06:51:33 +0000288 instanceID = instanceIdDb.next(pldmTID);
Chicago Duan184f6022020-04-17 11:30:49 +0800289 auto rc = encode_set_state_effecter_states_req(
290 instanceID, effecterID, effecterCount, &stateField, request);
291 if (rc != PLDM_SUCCESS)
292 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000293 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600294 error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
295 static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800296 return PLDM_ERROR;
297 }
298
Chicago Duan184f6022020-04-17 11:30:49 +0800299 // Add a timer to the event loop, default 30s.
Patrick Williamsa6756622023-10-20 11:19:15 -0500300 auto timerCallback = [=, this](Timer& /*source*/,
301 Timer::TimePoint /*time*/) mutable {
Chicago Duan184f6022020-04-17 11:30:49 +0800302 if (!responseReceived)
303 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000304 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600305 error(
306 "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 +0800307 exit(-1);
308 }
309 return;
310 };
311 Timer time(event, (Clock(event).now() + std::chrono::seconds{30}),
312 std::chrono::seconds{1}, std::move(timerCallback));
313
314 // Add a callback to handle EPOLLIN on fd
Patrick Williamsa6756622023-10-20 11:19:15 -0500315 auto callback = [=, &pldmTransport, this](IO& io, int fd,
316 uint32_t revents) mutable {
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000317 if (fd != pldmTransport.getEventSource())
318 {
319 return;
320 }
321
Chicago Duan184f6022020-04-17 11:30:49 +0800322 if (!(revents & EPOLLIN))
323 {
324 return;
325 }
326
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000327 void* responseMsg = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800328 size_t responseMsgSize{};
Dung Cao3d03f3f2023-09-07 06:51:33 +0000329 pldm_tid_t srcTID = pldmTID;
Chicago Duan184f6022020-04-17 11:30:49 +0800330
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000331 auto rc = pldmTransport.recvMsg(pldmTID, responseMsg, responseMsgSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800332 if (rc)
333 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600334 error("Soft off: failed to recv pldm data. PLDM RC = {RC}", "RC",
335 static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800336 return;
337 }
338
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000339 std::unique_ptr<void, decltype(std::free)*> responseMsgPtr{responseMsg,
340 std::free};
Chicago Duan184f6022020-04-17 11:30:49 +0800341
342 // We've got the response meant for the PLDM request msg that was
343 // sent out
344 io.set_enabled(Enabled::Off);
345 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
Dung Cao3d03f3f2023-09-07 06:51:33 +0000346
347 if (srcTID != pldmTID ||
348 !pldm_msg_hdr_correlate_response(&request->hdr, &response->hdr))
349 {
350 /* This isn't the response we were looking for */
351 return;
352 }
353
354 /* We have the right response, release the instance ID and process */
355 io.set_enabled(Enabled::Off);
356 instanceIdDb.free(pldmTID, instanceID);
357
George Liu9915d022021-12-21 14:04:31 +0800358 if (response->payload[0] != PLDM_SUCCESS)
359 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600360 error("Getting the wrong response. PLDM RC = {RC}", "RC",
361 (unsigned)response->payload[0]);
George Liu9915d022021-12-21 14:04:31 +0800362 exit(-1);
363 }
Chicago Duan184f6022020-04-17 11:30:49 +0800364
365 responseReceived = true;
366
367 // Start Timer
368 using namespace std::chrono;
369 auto timeMicroseconds =
370 duration_cast<microseconds>(seconds(SOFTOFF_TIMEOUT_SECONDS));
371
372 auto ret = startTimer(timeMicroseconds);
373 if (ret < 0)
374 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600375 error(
376 "Failure to start Host soft off wait timer, ERRNO = {RET}. Exit the pldm-softpoweroff",
377 "RET", ret);
Chicago Duan184f6022020-04-17 11:30:49 +0800378 exit(-1);
379 }
380 else
381 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600382 error(
383 "Timer started waiting for host soft off, TIMEOUT_IN_SEC = {TIMEOUT_SEC}",
384 "TIMEOUT_SEC", SOFTOFF_TIMEOUT_SECONDS);
Chicago Duan184f6022020-04-17 11:30:49 +0800385 }
386 return;
387 };
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000388 IO io(event, pldmTransport.getEventSource(), EPOLLIN, std::move(callback));
Chicago Duan184f6022020-04-17 11:30:49 +0800389
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000390 // Asynchronously send the PLDM request
391 rc = pldmTransport.sendMsg(pldmTID, requestMsg.data(), requestMsg.size());
Sampa Misra9f8d2b02021-03-24 08:33:14 +0000392 if (0 > rc)
Chicago Duan184f6022020-04-17 11:30:49 +0800393 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000394 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600395 error(
396 "Failed to send message/receive response. RC = {RC}, errno = {ERR}",
397 "RC", static_cast<int>(rc), "ERR", errno);
Chicago Duan184f6022020-04-17 11:30:49 +0800398 return PLDM_ERROR;
399 }
400
401 // Time out or soft off complete
402 while (!isCompleted() && !isTimerExpired())
403 {
404 try
405 {
406 event.run(std::nullopt);
407 }
408 catch (const sdeventplus::SdEventError& e)
409 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000410 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600411 error(
412 "PLDM host soft off: Failure in processing request.ERROR= {ERR_EXCEP}",
413 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800414 return PLDM_ERROR;
415 }
416 }
417
418 return PLDM_SUCCESS;
419}
420
421int SoftPowerOff::startTimer(const std::chrono::microseconds& usec)
422{
423 return timer.start(usec);
424}
425} // namespace pldm