blob: 1c6c7337aa06b4fe7ffcc1e056da9b348f948d15 [file] [log] [blame]
Deepak Kodihalli557dfb02019-05-12 13:11:17 +05301#pragma once
2
Sampa Misraa2fa0702019-05-31 01:28:55 -05003#include "config.h"
4
Deepak Kodihallibc669f12019-11-28 08:52:07 -06005#include "handler.hpp"
Sampa Misraa2fa0702019-05-31 01:28:55 -05006#include "libpldmresponder/pdr.hpp"
7#include "libpldmresponder/utils.hpp"
8
Deepak Kodihalli557dfb02019-05-12 13:11:17 +05309#include <stdint.h>
10
Sampa Misraa2fa0702019-05-31 01:28:55 -050011#include <map>
Deepak Kodihalli557dfb02019-05-12 13:11:17 +053012
13#include "libpldm/platform.h"
Sampa Misraa2fa0702019-05-31 01:28:55 -050014#include "libpldm/states.h"
Deepak Kodihalli557dfb02019-05-12 13:11:17 +053015
16namespace pldm
17{
Deepak Kodihalli557dfb02019-05-12 13:11:17 +053018namespace responder
19{
Sampa Misraa2fa0702019-05-31 01:28:55 -050020namespace platform
21{
22
Deepak Kodihallibc669f12019-11-28 08:52:07 -060023class Handler : public CmdHandler
Sampa Misraa2fa0702019-05-31 01:28:55 -050024{
Deepak Kodihallibc669f12019-11-28 08:52:07 -060025 public:
26 Handler()
Sampa Misraa2fa0702019-05-31 01:28:55 -050027 {
Deepak Kodihallibc669f12019-11-28 08:52:07 -060028 handlers.emplace(PLDM_GET_PDR,
29 [this](const pldm_msg* request, size_t payloadLength) {
30 return this->getPDR(request, payloadLength);
31 });
32 handlers.emplace(PLDM_SET_STATE_EFFECTER_STATES,
33 [this](const pldm_msg* request, size_t payloadLength) {
34 return this->setStateEffecterStates(request,
35 payloadLength);
36 });
Sampa Misraa2fa0702019-05-31 01:28:55 -050037 }
38
Deepak Kodihallibc669f12019-11-28 08:52:07 -060039 /** @brief Handler for GetPDR
40 *
41 * @param[in] request - Request message payload
42 * @param[in] payloadLength - Request payload length
43 * @param[out] Response - Response message written here
44 */
45 Response getPDR(const pldm_msg* request, size_t payloadLength);
Sampa Misraa2fa0702019-05-31 01:28:55 -050046
Deepak Kodihallibc669f12019-11-28 08:52:07 -060047 /** @brief Handler for setStateEffecterStates
48 *
49 * @param[in] request - Request message
50 * @param[in] payloadLength - Request payload length
51 * @return Response - PLDM Response message
52 */
53 Response setStateEffecterStates(const pldm_msg* request,
54 size_t payloadLength);
55
56 /** @brief Function to set the effecter requested by pldm requester
57 * @param[in] dBusIntf - The interface object
58 * @param[in] effecterId - Effecter ID sent by the requester to act on
59 * @param[in] stateField - The state field data for each of the states,
60 * equal to composite effecter count in number
61 * @return - Success or failure in setting the states. Returns failure in
62 * terms of PLDM completion codes if atleast one state fails to be set
63 */
64 template <class DBusInterface>
65 int setStateEffecterStatesHandler(
66 const DBusInterface& dBusIntf, effecter::Id effecterId,
67 const std::vector<set_effecter_state_field>& stateField)
Sampa Misraa2fa0702019-05-31 01:28:55 -050068 {
Deepak Kodihallibc669f12019-11-28 08:52:07 -060069 using namespace std::string_literals;
70 using DBusProperty = std::variant<std::string, bool>;
71 using StateSetId = uint16_t;
72 using StateSetNum = uint8_t;
73 using PropertyMap =
74 std::map<StateSetId, std::map<StateSetNum, DBusProperty>>;
75 static const PropertyMap stateNumToDbusProp = {
76 {PLDM_BOOT_PROGRESS_STATE,
77 {{PLDM_BOOT_NOT_ACTIVE,
78 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
79 "Standby"s},
80 {PLDM_BOOT_COMPLETED,
81 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
82 "BootComplete"s}}},
83 {PLDM_SYSTEM_POWER_STATE,
84 {{PLDM_OFF_SOFT_GRACEFUL,
85 "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
Deepak Kodihallibc669f12019-11-28 08:52:07 -060086 using namespace pldm::responder::pdr;
87 using namespace pldm::responder::effecter::dbus_mapping;
88
89 state_effecter_possible_states* states = nullptr;
90 pldm_state_effecter_pdr* pdr = nullptr;
91 uint8_t compEffecterCnt = stateField.size();
92 uint32_t recordHndl{};
93 Repo& pdrRepo = get(PDR_JSONS_DIR);
94 pdr::Entry pdrEntry{};
95
96 while (!pdr)
Sampa Misraa2fa0702019-05-31 01:28:55 -050097 {
Deepak Kodihallibc669f12019-11-28 08:52:07 -060098 pdrEntry = pdrRepo.at(recordHndl);
99 pldm_pdr_hdr* header =
100 reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data());
101 if (header->type != PLDM_STATE_EFFECTER_PDR)
Sampa Misraa2fa0702019-05-31 01:28:55 -0500102 {
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600103 recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
104 if (recordHndl)
105 {
106 continue;
107 }
108 return PLDM_PLATFORM_INVALID_EFFECTER_ID;
109 }
110 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data());
111 recordHndl = pdr->hdr.record_handle;
112 if (pdr->effecter_id == effecterId)
113 {
114 states = reinterpret_cast<state_effecter_possible_states*>(
115 pdr->possible_states);
116 if (compEffecterCnt > pdr->composite_effecter_count)
117 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600118 std::cerr
119 << "The requester sent wrong composite effecter"
120 << " count for the effecter, EFFECTER_ID=" << effecterId
121 << "COMP_EFF_CNT=" << compEffecterCnt << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600122 return PLDM_ERROR_INVALID_DATA;
123 }
Sampa Misraa2fa0702019-05-31 01:28:55 -0500124 break;
125 }
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600126 recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
127 if (!recordHndl)
128 {
129 return PLDM_PLATFORM_INVALID_EFFECTER_ID;
130 }
131 pdr = nullptr;
Sampa Misraa2fa0702019-05-31 01:28:55 -0500132 }
Sampa Misraa2fa0702019-05-31 01:28:55 -0500133
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600134 std::map<StateSetId, std::function<int(const std::string& objPath,
135 const uint8_t currState)>>
136 effecterToDbusEntries = {
137 {PLDM_BOOT_PROGRESS_STATE,
138 [&](const std::string& objPath, const uint8_t currState) {
139 auto stateSet =
140 stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE);
141 if (stateSet == stateNumToDbusProp.end())
142 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600143 std::cerr << "Couldn't find D-Bus mapping for "
144 << "PLDM_BOOT_PROGRESS_STATE, EFFECTER_ID="
145 << effecterId << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600146 return PLDM_ERROR;
147 }
148 auto iter = stateSet->second.find(
149 stateField[currState].effecter_state);
150 if (iter == stateSet->second.end())
151 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600152 std::cerr << "Invalid state field passed or field not "
153 << "found for PLDM_BOOT_PROGRESS_STATE, "
154 "EFFECTER_ID="
155 << effecterId << " FIELD="
156 << stateField[currState].effecter_state
157 << " OBJECT_PATH=" << objPath.c_str()
158 << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600159 return PLDM_ERROR_INVALID_DATA;
160 }
161 auto dbusProp = "OperatingSystemState";
162 std::variant<std::string> value{
163 std::get<std::string>(iter->second)};
164 auto dbusInterface =
165 "xyz.openbmc_project.State.OperatingSystem.Status";
166 try
167 {
168 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
169 dbusInterface, value);
170 }
171 catch (const std::exception& e)
172 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600173 std::cerr
174 << "Error setting property, ERROR=" << e.what()
175 << " PROPERTY=" << dbusProp
176 << " INTERFACE=" << dbusInterface
177 << " PATH=" << objPath.c_str() << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600178 return PLDM_ERROR;
179 }
180 return PLDM_SUCCESS;
181 }},
182 {PLDM_SYSTEM_POWER_STATE,
183 [&](const std::string& objPath, const uint8_t currState) {
184 auto stateSet =
185 stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
186 if (stateSet == stateNumToDbusProp.end())
187 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600188 std::cerr << "Couldn't find D-Bus mapping for "
189 << "PLDM_SYSTEM_POWER_STATE, EFFECTER_ID="
190 << effecterId << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600191 return PLDM_ERROR;
192 }
193 auto iter = stateSet->second.find(
194 stateField[currState].effecter_state);
195 if (iter == stateSet->second.end())
196 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600197 std::cerr << "Invalid state field passed or field not "
198 << "found for PLDM_SYSTEM_POWER_STATE, "
199 "EFFECTER_ID="
200 << effecterId << " FIELD="
201 << stateField[currState].effecter_state
202 << " OBJECT_PATH=" << objPath.c_str()
203 << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600204 return PLDM_ERROR_INVALID_DATA;
205 }
206 auto dbusProp = "RequestedPowerTransition";
207 std::variant<std::string> value{
208 std::get<std::string>(iter->second)};
209 auto dbusInterface = "xyz.openbmc_project.State.Chassis";
210 try
211 {
212 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
213 dbusInterface, value);
214 }
215 catch (const std::exception& e)
216 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600217 std::cerr
218 << "Error setting property, ERROR=" << e.what()
219 << " PROPERTY=" << dbusProp
220 << " INTERFACE=" << dbusInterface
221 << " PATH=" << objPath.c_str() << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600222 return PLDM_ERROR;
223 }
224 return PLDM_SUCCESS;
225 }}};
226
227 int rc = PLDM_SUCCESS;
228 auto paths = get(effecterId);
229 for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
230 {
231 std::vector<StateSetNum> allowed{};
232 // computation is based on table 79 from DSP0248 v1.1.1
233 uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
234 uint8_t bit =
235 stateField[currState].effecter_state - (8 * bitfieldIndex);
236 if (states->possible_states_size < bitfieldIndex ||
237 !(states->states[bitfieldIndex].byte & (1 << bit)))
238 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600239 std::cerr << "Invalid state set value, EFFECTER_ID="
240 << effecterId
241 << " VALUE=" << stateField[currState].effecter_state
242 << " COMPOSITE_EFFECTER_ID=" << currState
243 << " DBUS_PATH=" << paths[currState].c_str() << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600244 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
245 break;
246 }
247 auto iter = effecterToDbusEntries.find(states->state_set_id);
248 if (iter == effecterToDbusEntries.end())
249 {
250 uint16_t setId = states->state_set_id;
Sampa Misraaa8ae722019-12-12 03:20:40 -0600251 std::cerr << "Did not find the state set for the"
252 << " state effecter pdr, STATE=" << setId
253 << " EFFECTER_ID=" << effecterId << "\n";
Deepak Kodihallibc669f12019-11-28 08:52:07 -0600254 rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
255 break;
256 }
257 if (stateField[currState].set_request == PLDM_REQUEST_SET)
258 {
259 rc = iter->second(paths[currState], currState);
260 if (rc != PLDM_SUCCESS)
261 {
262 break;
263 }
264 }
265 uint8_t* nextState =
266 reinterpret_cast<uint8_t*>(states) +
267 sizeof(state_effecter_possible_states) -
268 sizeof(states->states) +
269 (states->possible_states_size * sizeof(states->states));
270 states =
271 reinterpret_cast<state_effecter_possible_states*>(nextState);
272 }
273 return rc;
274 }
275};
276
277} // namespace platform
Deepak Kodihalli557dfb02019-05-12 13:11:17 +0530278} // namespace responder
279} // namespace pldm