blob: c522635969762fa445f0697cfeaedeb68e568031 [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 {
Riya Dixit087a7512024-04-06 14:28:08 -050049 error("Failed to parse softoff config JSON file");
Sagar Srinivas4d99c312024-03-28 06:50:13 -050050 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 {
Riya Dixit087a7512024-04-06 14:28:08 -050072 error("Failed to get Sensor PDRs, response code '{RC}'", "RC",
73 lg2::hex, static_cast<int>(rc));
Sagar Srinivas4d99c312024-03-28 06:50:13 -050074 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 {
Riya Dixit087a7512024-04-06 14:28:08 -0500116 error(
117 "PLDM remote terminus soft off. Can't get current remote terminus state, error - {ERROR}",
118 "ERROR", e);
Chicago Duan184f6022020-04-17 11:30:49 +0800119 hasError = true;
120 return PLDM_ERROR;
121 }
122
123 return PLDM_SUCCESS;
124}
125
Patrick Williams84b790c2022-07-22 19:26:56 -0500126void SoftPowerOff::hostSoftOffComplete(sdbusplus::message_t& msg)
Chicago Duan184f6022020-04-17 11:30:49 +0800127{
128 pldm::pdr::TerminusID msgTID;
129 pldm::pdr::SensorID msgSensorID;
130 pldm::pdr::SensorOffset msgSensorOffset;
131 pldm::pdr::EventState msgEventState;
132 pldm::pdr::EventState msgPreviousEventState;
133
134 // Read the msg and populate each variable
135 msg.read(msgTID, msgSensorID, msgSensorOffset, msgEventState,
136 msgPreviousEventState);
137
138 if (msgSensorID == sensorID && msgSensorOffset == sensorOffset &&
Zach Clarke98c51b2021-06-08 11:29:06 -0500139 msgEventState == PLDM_SW_TERM_GRACEFUL_SHUTDOWN && msgTID == TID)
Chicago Duan184f6022020-04-17 11:30:49 +0800140 {
141 // Receive Graceful shutdown completion event message. Disable the timer
142 auto rc = timer.stop();
143 if (rc < 0)
144 {
Riya Dixit087a7512024-04-06 14:28:08 -0500145 error(
146 "Failure to STOP the timer of PLDM soft off, response code '{RC}'",
147 "RC", rc);
Chicago Duan184f6022020-04-17 11:30:49 +0800148 }
149
150 // This marks the completion of pldm soft power off.
151 completed = true;
152 }
153}
154
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500155Json SoftPowerOff::parseConfig()
156{
157 fs::path softoffConfigJson(fs::path(SOFTOFF_CONFIG_JSON) /
158 "softoff_config.json");
159
160 if (!fs::exists(softoffConfigJson) || fs::is_empty(softoffConfigJson))
161 {
Riya Dixit087a7512024-04-06 14:28:08 -0500162 error(
163 "Failed to parse softoff config JSON file '{PATH}', file does not exist",
164 "PATH", softoffConfigJson);
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500165 return PLDM_ERROR;
166 }
167
168 std::ifstream jsonFile(softoffConfigJson);
169 return Json::parse(jsonFile);
170}
171
172bool SoftPowerOff::getEffecterID(pldm::pdr::EntityType& entityType,
173 pldm::pdr::StateSetId& stateSetId)
Chicago Duan184f6022020-04-17 11:30:49 +0800174{
175 auto& bus = pldm::utils::DBusHandler::getBus();
Chicago Duan184f6022020-04-17 11:30:49 +0800176 try
177 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500178 std::vector<std::vector<uint8_t>> response{};
179 auto method = bus.new_method_call(
Chicago Duan184f6022020-04-17 11:30:49 +0800180 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
181 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500182 method.append(TID, entityType, stateSetId);
183 auto responseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800184
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500185 responseMsg.read(response);
186 if (response.size())
Chicago Duan184f6022020-04-17 11:30:49 +0800187 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500188 for (auto& rep : response)
Chicago Duan184f6022020-04-17 11:30:49 +0800189 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500190 auto softoffPdr =
Chicago Duan184f6022020-04-17 11:30:49 +0800191 reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500192 effecterID = softoffPdr->effecter_id;
Chicago Duan184f6022020-04-17 11:30:49 +0800193 }
194 }
195 else
196 {
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500197 return false;
Chicago Duan184f6022020-04-17 11:30:49 +0800198 }
199 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500200 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800201 {
Riya Dixit087a7512024-04-06 14:28:08 -0500202 error("Failed to get softPowerOff PDR, error - {ERROR}", "ERROR", e);
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500203 return false;
Chicago Duan184f6022020-04-17 11:30:49 +0800204 }
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500205 return true;
Chicago Duan184f6022020-04-17 11:30:49 +0800206}
207
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500208int SoftPowerOff::getSensorInfo(pldm::pdr::EntityType& entityType,
209 pldm::pdr::StateSetId& stateSetId)
Chicago Duan184f6022020-04-17 11:30:49 +0800210{
Chicago Duan184f6022020-04-17 11:30:49 +0800211 try
212 {
213 auto& bus = pldm::utils::DBusHandler::getBus();
214 std::vector<std::vector<uint8_t>> Response{};
215 auto method = bus.new_method_call(
216 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
217 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
Sagar Srinivas4d99c312024-03-28 06:50:13 -0500218 method.append(TID, entityType, stateSetId);
Chicago Duan184f6022020-04-17 11:30:49 +0800219
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500220 auto ResponseMsg = bus.call(method, dbusTimeout);
Chicago Duan184f6022020-04-17 11:30:49 +0800221
222 ResponseMsg.read(Response);
223
224 if (Response.size() == 0)
225 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600226 error("No sensor PDR has been found that matches the criteria");
Chicago Duan184f6022020-04-17 11:30:49 +0800227 return PLDM_ERROR;
228 }
229
ThuBaNguyen499a29d2023-05-30 06:32:06 +0700230 pldm_state_sensor_pdr* pdr = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800231 for (auto& rep : Response)
232 {
233 pdr = reinterpret_cast<pldm_state_sensor_pdr*>(rep.data());
Manojkiran Eda31a78442021-09-12 15:18:25 +0530234 if (!pdr)
235 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600236 error("Failed to get state sensor PDR.");
Manojkiran Eda31a78442021-09-12 15:18:25 +0530237 return PLDM_ERROR;
238 }
Manojkiran Edabcf91ac2021-03-14 13:50:48 +0530239 }
240
Chicago Duan184f6022020-04-17 11:30:49 +0800241 sensorID = pdr->sensor_id;
242
243 auto compositeSensorCount = pdr->composite_sensor_count;
244 auto possibleStatesStart = pdr->possible_states;
245
246 for (auto offset = 0; offset < compositeSensorCount; offset++)
247 {
248 auto possibleStates =
249 reinterpret_cast<state_sensor_possible_states*>(
250 possibleStatesStart);
251 auto setId = possibleStates->state_set_id;
252 auto possibleStateSize = possibleStates->possible_states_size;
253
254 if (setId == PLDM_STATE_SET_SW_TERMINATION_STATUS)
255 {
256 sensorOffset = offset;
257 break;
258 }
Patrick Williams6da4f912023-05-10 07:50:53 -0500259 possibleStatesStart += possibleStateSize + sizeof(setId) +
260 sizeof(possibleStateSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800261 }
262 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500263 catch (const sdbusplus::exception_t& e)
Chicago Duan184f6022020-04-17 11:30:49 +0800264 {
Riya Dixit087a7512024-04-06 14:28:08 -0500265 error("Failed to get state sensor PDR during soft-off, error - {ERROR}",
266 "ERROR", e);
Chicago Duan184f6022020-04-17 11:30:49 +0800267 return PLDM_ERROR;
268 }
269
270 return PLDM_SUCCESS;
271}
272
273int SoftPowerOff::hostSoftOff(sdeventplus::Event& event)
274{
275 constexpr uint8_t effecterCount = 1;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000276 PldmTransport pldmTransport{};
Chicago Duan184f6022020-04-17 11:30:49 +0800277 uint8_t instanceID;
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000278 uint8_t mctpEID;
Chicago Duan184f6022020-04-17 11:30:49 +0800279
280 mctpEID = pldm::utils::readHostEID();
Dung Cao3d03f3f2023-09-07 06:51:33 +0000281 // TODO: fix mapping to work around OpenBMC ecosystem deficiencies
282 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEID);
Chicago Duan184f6022020-04-17 11:30:49 +0800283
284 std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterID) +
285 sizeof(effecterCount) +
286 sizeof(set_effecter_state_field)>
287 requestMsg{};
288 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
289 set_effecter_state_field stateField{
290 PLDM_REQUEST_SET, PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED};
Dung Cao3d03f3f2023-09-07 06:51:33 +0000291 instanceID = instanceIdDb.next(pldmTID);
Chicago Duan184f6022020-04-17 11:30:49 +0800292 auto rc = encode_set_state_effecter_states_req(
293 instanceID, effecterID, effecterCount, &stateField, request);
294 if (rc != PLDM_SUCCESS)
295 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000296 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit087a7512024-04-06 14:28:08 -0500297 error(
298 "Failed to encode set state effecter states request message, response code '{RC}'",
299 "RC", lg2::hex, static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800300 return PLDM_ERROR;
301 }
302
Chicago Duan184f6022020-04-17 11:30:49 +0800303 // Add a timer to the event loop, default 30s.
Patrick Williamsa6756622023-10-20 11:19:15 -0500304 auto timerCallback = [=, this](Timer& /*source*/,
305 Timer::TimePoint /*time*/) mutable {
Chicago Duan184f6022020-04-17 11:30:49 +0800306 if (!responseReceived)
307 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000308 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600309 error(
Riya Dixit087a7512024-04-06 14:28:08 -0500310 "PLDM soft off failed, can't get the response for the PLDM request msg. Time out! Exit the pldm-softpoweroff");
Chicago Duan184f6022020-04-17 11:30:49 +0800311 exit(-1);
312 }
313 return;
314 };
315 Timer time(event, (Clock(event).now() + std::chrono::seconds{30}),
316 std::chrono::seconds{1}, std::move(timerCallback));
317
318 // Add a callback to handle EPOLLIN on fd
Patrick Williamsa6756622023-10-20 11:19:15 -0500319 auto callback = [=, &pldmTransport, this](IO& io, int fd,
320 uint32_t revents) mutable {
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000321 if (fd != pldmTransport.getEventSource())
322 {
323 return;
324 }
325
Chicago Duan184f6022020-04-17 11:30:49 +0800326 if (!(revents & EPOLLIN))
327 {
328 return;
329 }
330
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000331 void* responseMsg = nullptr;
Chicago Duan184f6022020-04-17 11:30:49 +0800332 size_t responseMsgSize{};
Dung Cao3d03f3f2023-09-07 06:51:33 +0000333 pldm_tid_t srcTID = pldmTID;
Chicago Duan184f6022020-04-17 11:30:49 +0800334
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000335 auto rc = pldmTransport.recvMsg(pldmTID, responseMsg, responseMsgSize);
Chicago Duan184f6022020-04-17 11:30:49 +0800336 if (rc)
337 {
Riya Dixit087a7512024-04-06 14:28:08 -0500338 error(
339 "Failed to receive pldm data during soft-off, response code '{RC}'",
340 "RC", static_cast<int>(rc));
Chicago Duan184f6022020-04-17 11:30:49 +0800341 return;
342 }
343
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000344 std::unique_ptr<void, decltype(std::free)*> responseMsgPtr{responseMsg,
345 std::free};
Chicago Duan184f6022020-04-17 11:30:49 +0800346
347 // We've got the response meant for the PLDM request msg that was
348 // sent out
349 io.set_enabled(Enabled::Off);
350 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
Dung Cao3d03f3f2023-09-07 06:51:33 +0000351
352 if (srcTID != pldmTID ||
353 !pldm_msg_hdr_correlate_response(&request->hdr, &response->hdr))
354 {
355 /* This isn't the response we were looking for */
356 return;
357 }
358
359 /* We have the right response, release the instance ID and process */
360 io.set_enabled(Enabled::Off);
361 instanceIdDb.free(pldmTID, instanceID);
362
George Liu9915d022021-12-21 14:04:31 +0800363 if (response->payload[0] != PLDM_SUCCESS)
364 {
Riya Dixit087a7512024-04-06 14:28:08 -0500365 error("Getting the wrong response, response code '{RC}'", "RC",
Riya Dixit49cfb132023-03-02 04:26:53 -0600366 (unsigned)response->payload[0]);
George Liu9915d022021-12-21 14:04:31 +0800367 exit(-1);
368 }
Chicago Duan184f6022020-04-17 11:30:49 +0800369
370 responseReceived = true;
371
372 // Start Timer
373 using namespace std::chrono;
374 auto timeMicroseconds =
375 duration_cast<microseconds>(seconds(SOFTOFF_TIMEOUT_SECONDS));
376
377 auto ret = startTimer(timeMicroseconds);
378 if (ret < 0)
379 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600380 error(
Riya Dixit087a7512024-04-06 14:28:08 -0500381 "Failure to start remote terminus soft off wait timer, Exit the pldm-softpoweroff with response code:{NUM}",
382 "NUM", ret);
Chicago Duan184f6022020-04-17 11:30:49 +0800383 exit(-1);
384 }
385 else
386 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600387 error(
Riya Dixit087a7512024-04-06 14:28:08 -0500388 "Timer started waiting for remote terminus soft off, timeout in sec '{TIMEOUT_SEC}'",
Riya Dixit49cfb132023-03-02 04:26:53 -0600389 "TIMEOUT_SEC", SOFTOFF_TIMEOUT_SECONDS);
Chicago Duan184f6022020-04-17 11:30:49 +0800390 }
391 return;
392 };
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000393 IO io(event, pldmTransport.getEventSource(), EPOLLIN, std::move(callback));
Chicago Duan184f6022020-04-17 11:30:49 +0800394
Rashmica Gupta1ed5f7a2023-05-22 13:56:42 +1000395 // Asynchronously send the PLDM request
396 rc = pldmTransport.sendMsg(pldmTID, requestMsg.data(), requestMsg.size());
Sampa Misra9f8d2b02021-03-24 08:33:14 +0000397 if (0 > rc)
Chicago Duan184f6022020-04-17 11:30:49 +0800398 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000399 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600400 error(
Riya Dixit087a7512024-04-06 14:28:08 -0500401 "Failed to send message/receive response, response code '{RC}' and error - {ERROR}",
402 "RC", static_cast<int>(rc), "ERROR", errno);
Chicago Duan184f6022020-04-17 11:30:49 +0800403 return PLDM_ERROR;
404 }
405
406 // Time out or soft off complete
407 while (!isCompleted() && !isTimerExpired())
408 {
409 try
410 {
411 event.run(std::nullopt);
412 }
413 catch (const sdeventplus::SdEventError& e)
414 {
Dung Cao3d03f3f2023-09-07 06:51:33 +0000415 instanceIdDb.free(pldmTID, instanceID);
Riya Dixit49cfb132023-03-02 04:26:53 -0600416 error(
Riya Dixit087a7512024-04-06 14:28:08 -0500417 "Failed to process request while remote terminus soft off, error - {ERROR}",
418 "ERROR", e);
Chicago Duan184f6022020-04-17 11:30:49 +0800419 return PLDM_ERROR;
420 }
421 }
422
423 return PLDM_SUCCESS;
424}
425
426int SoftPowerOff::startTimer(const std::chrono::microseconds& usec)
427{
428 return timer.start(usec);
429}
430} // namespace pldm