blob: 83d46f0f8daeb03f64e853b069eb02b44520ef91 [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
Sagar Srinivas4d99c312024-03-28 06:50:13 -050033pldm::pdr::TerminusID TID = 0; // TID will be implemented later.
Chicago Duan184f6022020-04-17 11:30:49 +080034namespace sdbusRule = sdbusplus::bus::match::rules;
35
Manojkiran Eda3fcfaa12024-02-26 15:17:58 +053036SoftPowerOff::SoftPowerOff(sdbusplus::bus_t& bus, sd_event* event,
37 pldm::InstanceIdDb& instanceIdDb) :
38 bus(bus),
39 timer(event), instanceIdDb(instanceIdDb)
Chicago Duan184f6022020-04-17 11:30:49 +080040{
Sagar Srinivas4d99c312024-03-28 06:50:13 -050041 auto jsonData = parseConfig();
42
43 if (jsonData.is_discarded())
44 {
45 error("Parsing softoff config JSON file failed");
46 return;
47 }
48
Manojkiran Eda31a78442021-09-12 15:18:25 +053049 getHostState();
Chicago Duan184f6022020-04-17 11:30:49 +080050 if (hasError || completed)
51 {
52 return;
53 }
Sagar Srinivas4d99c312024-03-28 06:50:13 -050054 const std::vector<Json> emptyJsonList{};
55 auto entries = jsonData.value("entries", emptyJsonList);
56 for (const auto& entry : entries)
57 {
58 TID = entry.value("tid", 0);
59 pldm::pdr::EntityType entityType = entry.value("entityType", 0);
60 pldm::pdr::StateSetId stateSetId = entry.value("stateSetId", 0);
Chicago Duan184f6022020-04-17 11:30:49 +080061
Sagar Srinivas4d99c312024-03-28 06:50:13 -050062 bool effecterFound = getEffecterID(entityType, stateSetId);
63 if (effecterFound)
64 {
65 auto rc = getSensorInfo(entityType, stateSetId);
66 if (rc != PLDM_SUCCESS)
67 {
68 error("Message get Sensor PDRs error. PLDM error code = {RC}",
69 "RC", lg2::hex, static_cast<int>(rc));
70 hasError = true;
71 return;
72 }
73 break;
74 }
75 else
76 {
77 continue;
78 }
Chicago Duan184f6022020-04-17 11:30:49 +080079 }
80
81 // Matches on the pldm StateSensorEvent signal
82 pldmEventSignal = std::make_unique<sdbusplus::bus::match_t>(
83 bus,
84 sdbusRule::type::signal() + sdbusRule::member("StateSensorEvent") +
85 sdbusRule::path("/xyz/openbmc_project/pldm") +
86 sdbusRule::interface("xyz.openbmc_project.PLDM.Event"),
87 std::bind(std::mem_fn(&SoftPowerOff::hostSoftOffComplete), this,
88 std::placeholders::_1));
89}
90
91int SoftPowerOff::getHostState()
92{
93 try
94 {
95 pldm::utils::PropertyValue propertyValue =
96 pldm::utils::DBusHandler().getDbusPropertyVariant(
97 "/xyz/openbmc_project/state/host0", "CurrentHostState",
98 "xyz.openbmc_project.State.Host");
99
Andrew Geissler5b5fa432021-01-22 16:27:24 -0600100 if ((std::get<std::string>(propertyValue) !=
101 "xyz.openbmc_project.State.Host.HostState.Running") &&
102 (std::get<std::string>(propertyValue) !=
103 "xyz.openbmc_project.State.Host.HostState.TransitioningToOff"))
Chicago Duan184f6022020-04-17 11:30:49 +0800104 {
105 // Host state is not "Running", this app should return success
106 completed = true;
107 return PLDM_SUCCESS;
108 }
109 }
110 catch (const std::exception& e)
111 {
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500112 error("PLDM host soft off: Can't get current host state: {ERROR}",
113 "ERROR", e);
Chicago Duan184f6022020-04-17 11:30:49 +0800114 hasError = true;
115 return PLDM_ERROR;
116 }
117
118 return PLDM_SUCCESS;
119}
120
Patrick Williams84b790c2022-07-22 19:26:56 -0500121void SoftPowerOff::hostSoftOffComplete(sdbusplus::message_t& msg)
Chicago Duan184f6022020-04-17 11:30:49 +0800122{
123 pldm::pdr::TerminusID msgTID;
124 pldm::pdr::SensorID msgSensorID;
125 pldm::pdr::SensorOffset msgSensorOffset;
126 pldm::pdr::EventState msgEventState;
127 pldm::pdr::EventState msgPreviousEventState;
128
129 // Read the msg and populate each variable
130 msg.read(msgTID, msgSensorID, msgSensorOffset, msgEventState,
131 msgPreviousEventState);
132
133 if (msgSensorID == sensorID && msgSensorOffset == sensorOffset &&
134 msgEventState == PLDM_SW_TERM_GRACEFUL_SHUTDOWN)
135 {
136 // Receive Graceful shutdown completion event message. Disable the timer
137 auto rc = timer.stop();
138 if (rc < 0)
139 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600140 error("PLDM soft off: Failure to STOP the timer. ERRNO={RC}", "RC",
141 rc);
Chicago Duan184f6022020-04-17 11:30:49 +0800142 }
143
144 // This marks the completion of pldm soft power off.
145 completed = true;
146 }
147}
148
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500149Json SoftPowerOff::parseConfig()
150{
151 fs::path softoffConfigJson(fs::path(SOFTOFF_CONFIG_JSON) /
152 "softoff_config.json");
153
154 if (!fs::exists(softoffConfigJson) || fs::is_empty(softoffConfigJson))
155 {
156 error("Parsing softoff config JSON file failed, File does not exist");
157 return PLDM_ERROR;
158 }
159
160 std::ifstream jsonFile(softoffConfigJson);
161 return Json::parse(jsonFile);
162}
163
164bool SoftPowerOff::getEffecterID(pldm::pdr::EntityType& entityType,
165 pldm::pdr::StateSetId& stateSetId)
Chicago Duan184f6022020-04-17 11:30:49 +0800166{
167 auto& bus = pldm::utils::DBusHandler::getBus();
Chicago Duan184f6022020-04-17 11:30:49 +0800168 try
169 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500170 std::vector<std::vector<uint8_t>> response{};
171 auto method = bus.new_method_call(
Chicago Duan184f6022020-04-17 11:30:49 +0800172 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
173 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500174 method.append(TID, entityType, stateSetId);
175 auto responseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800176
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500177 responseMsg.read(response);
178 if (response.size())
Chicago Duan184f6022020-04-17 11:30:49 +0800179 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500180 for (auto& rep : response)
Chicago Duan184f6022020-04-17 11:30:49 +0800181 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500182 auto softoffPdr =
Chicago Duan184f6022020-04-17 11:30:49 +0800183 reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500184 effecterID = softoffPdr->effecter_id;
Chicago Duan184f6022020-04-17 11:30:49 +0800185 }
186 }
187 else
188 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500189 return false;
Chicago Duan184f6022020-04-17 11:30:49 +0800190 }
191 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500192 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800193 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500194 error("PLDM soft off: Error get softPowerOff PDR,ERROR={ERR_EXCEP}",
Riya Dixit49cfb132023-03-02 04:26:53 -0600195 "ERR_EXCEP", e.what());
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500196 return false;
Chicago Duan184f6022020-04-17 11:30:49 +0800197 }
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500198 return true;
Chicago Duan184f6022020-04-17 11:30:49 +0800199}
200
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500201int SoftPowerOff::getSensorInfo(pldm::pdr::EntityType& entityType,
202 pldm::pdr::StateSetId& stateSetId)
Chicago Duan184f6022020-04-17 11:30:49 +0800203{
Chicago Duan184f6022020-04-17 11:30:49 +0800204 try
205 {
206 auto& bus = pldm::utils::DBusHandler::getBus();
207 std::vector<std::vector<uint8_t>> Response{};
208 auto method = bus.new_method_call(
209 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
210 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500211 method.append(TID, entityType, stateSetId);
Chicago Duan184f6022020-04-17 11:30:49 +0800212
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500213 auto ResponseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800214
215 ResponseMsg.read(Response);
216
217 if (Response.size() == 0)
218 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600219 error("No sensor PDR has been found that matches the criteria");
Chicago Duan184f6022020-04-17 11:30:49 +0800220 return PLDM_ERROR;
221 }
222
ThuBaNguyen499a29d2023-05-30 06:32:06 +0700223 pldm_state_sensor_pdr* pdr = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800224 for (auto& rep : Response)
225 {
226 pdr = reinterpret_cast<pldm_state_sensor_pdr*>(rep.data());
Manojkiran Eda31a78442021-09-12 15:18:25 +0530227 if (!pdr)
228 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600229 error("Failed to get state sensor PDR.");
Manojkiran Eda31a78442021-09-12 15:18:25 +0530230 return PLDM_ERROR;
231 }
Manojkiran Edabcf91ac2021-03-14 13:50:48 +0530232 }
233
Chicago Duan184f6022020-04-17 11:30:49 +0800234 sensorID = pdr->sensor_id;
235
236 auto compositeSensorCount = pdr->composite_sensor_count;
237 auto possibleStatesStart = pdr->possible_states;
238
239 for (auto offset = 0; offset < compositeSensorCount; offset++)
240 {
241 auto possibleStates =
242 reinterpret_cast<state_sensor_possible_states*>(
243 possibleStatesStart);
244 auto setId = possibleStates->state_set_id;
245 auto possibleStateSize = possibleStates->possible_states_size;
246
247 if (setId == PLDM_STATE_SET_SW_TERMINATION_STATUS)
248 {
249 sensorOffset = offset;
250 break;
251 }
Patrick Williams6da4f912023-05-10 07:50:53 -0500252 possibleStatesStart += possibleStateSize + sizeof(setId) +
253 sizeof(possibleStateSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800254 }
255 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500256 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800257 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600258 error("PLDM soft off: Error get State Sensor PDR,ERROR={ERR_EXCEP}",
259 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800260 return PLDM_ERROR;
261 }
262
263 return PLDM_SUCCESS;
264}
265
266int SoftPowerOff::hostSoftOff(sdeventplus::Event& event)
267{
268 constexpr uint8_t effecterCount = 1;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000269 PldmTransport pldmTransport{};
Chicago Duan184f6022020-04-17 11:30:49 +0800270 uint8_t instanceID;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000271 uint8_t mctpEID;
Chicago Duan184f6022020-04-17 11:30:49 +0800272
273 mctpEID = pldm::utils::readHostEID();
Dung Cao3d03f3f2023-09-07 06:51:33 +0000274 // TODO: fix mapping to work around OpenBMC ecosystem deficiencies
275 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEID);
Chicago Duan184f6022020-04-17 11:30:49 +0800276
277 std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterID) +
278 sizeof(effecterCount) +
279 sizeof(set_effecter_state_field)>
280 requestMsg{};
281 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
282 set_effecter_state_field stateField{
283 PLDM_REQUEST_SET, PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED};
Dung Cao3d03f3f2023-09-07 06:51:33 +0000284 instanceID = instanceIdDb.next(pldmTID);
Chicago Duan184f6022020-04-17 11:30:49 +0800285 auto rc = encode_set_state_effecter_states_req(
286 instanceID, effecterID, effecterCount, &stateField, request);
287 if (rc != PLDM_SUCCESS)
288 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000289 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600290 error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
291 static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800292 return PLDM_ERROR;
293 }
294
Chicago Duan184f6022020-04-17 11:30:49 +0800295 // Add a timer to the event loop, default 30s.
Patrick Williamsa6756622023-10-20 11:19:15 -0500296 auto timerCallback = [=, this](Timer& /*source*/,
297 Timer::TimePoint /*time*/) mutable {
Chicago Duan184f6022020-04-17 11:30:49 +0800298 if (!responseReceived)
299 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000300 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600301 error(
302 "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 +0800303 exit(-1);
304 }
305 return;
306 };
307 Timer time(event, (Clock(event).now() + std::chrono::seconds{30}),
308 std::chrono::seconds{1}, std::move(timerCallback));
309
310 // Add a callback to handle EPOLLIN on fd
Patrick Williamsa6756622023-10-20 11:19:15 -0500311 auto callback = [=, &pldmTransport, this](IO& io, int fd,
312 uint32_t revents) mutable {
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000313 if (fd != pldmTransport.getEventSource())
314 {
315 return;
316 }
317
Chicago Duan184f6022020-04-17 11:30:49 +0800318 if (!(revents & EPOLLIN))
319 {
320 return;
321 }
322
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000323 void* responseMsg = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800324 size_t responseMsgSize{};
Dung Cao3d03f3f2023-09-07 06:51:33 +0000325 pldm_tid_t srcTID = pldmTID;
Chicago Duan184f6022020-04-17 11:30:49 +0800326
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000327 auto rc = pldmTransport.recvMsg(pldmTID, responseMsg, responseMsgSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800328 if (rc)
329 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600330 error("Soft off: failed to recv pldm data. PLDM RC = {RC}", "RC",
331 static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800332 return;
333 }
334
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000335 std::unique_ptr<void, decltype(std::free)*> responseMsgPtr{responseMsg,
336 std::free};
Chicago Duan184f6022020-04-17 11:30:49 +0800337
338 // We've got the response meant for the PLDM request msg that was
339 // sent out
340 io.set_enabled(Enabled::Off);
341 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
Dung Cao3d03f3f2023-09-07 06:51:33 +0000342
343 if (srcTID != pldmTID ||
344 !pldm_msg_hdr_correlate_response(&request->hdr, &response->hdr))
345 {
346 /* This isn't the response we were looking for */
347 return;
348 }
349
350 /* We have the right response, release the instance ID and process */
351 io.set_enabled(Enabled::Off);
352 instanceIdDb.free(pldmTID, instanceID);
353
George Liu9915d022021-12-21 14:04:31 +0800354 if (response->payload[0] != PLDM_SUCCESS)
355 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600356 error("Getting the wrong response. PLDM RC = {RC}", "RC",
357 (unsigned)response->payload[0]);
George Liu9915d022021-12-21 14:04:31 +0800358 exit(-1);
359 }
Chicago Duan184f6022020-04-17 11:30:49 +0800360
361 responseReceived = true;
362
363 // Start Timer
364 using namespace std::chrono;
365 auto timeMicroseconds =
366 duration_cast<microseconds>(seconds(SOFTOFF_TIMEOUT_SECONDS));
367
368 auto ret = startTimer(timeMicroseconds);
369 if (ret < 0)
370 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600371 error(
372 "Failure to start Host soft off wait timer, ERRNO = {RET}. Exit the pldm-softpoweroff",
373 "RET", ret);
Chicago Duan184f6022020-04-17 11:30:49 +0800374 exit(-1);
375 }
376 else
377 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600378 error(
379 "Timer started waiting for host soft off, TIMEOUT_IN_SEC = {TIMEOUT_SEC}",
380 "TIMEOUT_SEC", SOFTOFF_TIMEOUT_SECONDS);
Chicago Duan184f6022020-04-17 11:30:49 +0800381 }
382 return;
383 };
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000384 IO io(event, pldmTransport.getEventSource(), EPOLLIN, std::move(callback));
Chicago Duan184f6022020-04-17 11:30:49 +0800385
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000386 // Asynchronously send the PLDM request
387 rc = pldmTransport.sendMsg(pldmTID, requestMsg.data(), requestMsg.size());
Sampa Misra9f8d2b02021-03-24 08:33:14 +0000388 if (0 > rc)
Chicago Duan184f6022020-04-17 11:30:49 +0800389 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000390 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600391 error(
392 "Failed to send message/receive response. RC = {RC}, errno = {ERR}",
393 "RC", static_cast<int>(rc), "ERR", errno);
Chicago Duan184f6022020-04-17 11:30:49 +0800394 return PLDM_ERROR;
395 }
396
397 // Time out or soft off complete
398 while (!isCompleted() && !isTimerExpired())
399 {
400 try
401 {
402 event.run(std::nullopt);
403 }
404 catch (const sdeventplus::SdEventError& e)
405 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000406 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600407 error(
408 "PLDM host soft off: Failure in processing request.ERROR= {ERR_EXCEP}",
409 "ERR_EXCEP", e.what());
Chicago Duan184f6022020-04-17 11:30:49 +0800410 return PLDM_ERROR;
411 }
412 }
413
414 return PLDM_SUCCESS;
415}
416
417int SoftPowerOff::startTimer(const std::chrono::microseconds& usec)
418{
419 return timer.start(usec);
420}
421} // namespace pldm