blob: ec168f4e0acecdfcd49af9f5a432af24d65d2511 [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
5#include "libpldmresponder/pdr.hpp"
6#include "libpldmresponder/utils.hpp"
7
Deepak Kodihalli557dfb02019-05-12 13:11:17 +05308#include <stdint.h>
9
Sampa Misraa2fa0702019-05-31 01:28:55 -050010#include <map>
Deepak Kodihalli557dfb02019-05-12 13:11:17 +053011
12#include "libpldm/platform.h"
Sampa Misraa2fa0702019-05-31 01:28:55 -050013#include "libpldm/states.h"
Deepak Kodihalli557dfb02019-05-12 13:11:17 +053014
15namespace pldm
16{
17
18using Response = std::vector<uint8_t>;
19
20namespace responder
21{
22
Sampa Misraa2fa0702019-05-31 01:28:55 -050023namespace platform
24{
25
26/** @brief Register handlers for commands from the platform spec
27 */
28void registerHandlers();
29
30} // namespace platform
31
Deepak Kodihalli557dfb02019-05-12 13:11:17 +053032/** @brief Handler for GetPDR
33 *
34 * @param[in] request - Request message payload
35 * @param[in] payloadLength - Request payload length
36 * @param[out] Response - Response message written here
37 */
38Response getPDR(const pldm_msg* request, size_t payloadLength);
39
Sampa Misraa2fa0702019-05-31 01:28:55 -050040/** @brief Handler for setStateEffecterStates
41 *
42 * @param[in] request - Request message
43 * @param[in] payloadLength - Request payload length
44 * @return Response - PLDM Response message
45 */
46Response setStateEffecterStates(const pldm_msg* request, size_t payloadLength);
47
48/** @brief Function to set the effecter requested by pldm requester
49 * @param[in] dBusIntf - The interface object
50 * @param[in] effecterId - Effecter ID sent by the requester to act on
51 * @param[in] stateField - The state field data for each of the states, equal
52 * to composite effecter count in number
53 * @return - Success or failure in setting the states. Returns failure in terms
54 * of PLDM completion codes if atleast one state fails to be set
55 */
56template <class DBusInterface>
57int setStateEffecterStatesHandler(
58 const DBusInterface& dBusIntf, effecter::Id effecterId,
59 const std::vector<set_effecter_state_field>& stateField)
60{
61 using namespace std::string_literals;
62 using DBusProperty = std::variant<std::string, bool>;
63 using StateSetId = uint16_t;
64 using StateSetNum = uint8_t;
65 using PropertyMap =
66 std::map<StateSetId, std::map<StateSetNum, DBusProperty>>;
67 static const PropertyMap stateNumToDbusProp = {
68 {PLDM_BOOT_PROGRESS_STATE,
69 {{PLDM_BOOT_NOT_ACTIVE,
70 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
71 "Standby"s},
72 {PLDM_BOOT_COMPLETED,
73 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
74 "BootComplete"s}}},
Deepak Kodihalli960dc962019-10-08 08:17:32 -050075 {PLDM_SYSTEM_POWER_STATE,
76 {{PLDM_OFF_SOFT_GRACEFUL,
77 "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
Sampa Misraa2fa0702019-05-31 01:28:55 -050078 using namespace phosphor::logging;
79 using namespace pldm::responder::pdr;
80 using namespace pldm::responder::effecter::dbus_mapping;
81
82 state_effecter_possible_states* states = nullptr;
83 pldm_state_effecter_pdr* pdr = nullptr;
84 uint8_t compEffecterCnt = stateField.size();
85 uint32_t recordHndl{};
86 Repo& pdrRepo = get(PDR_JSONS_DIR);
87 pdr::Entry pdrEntry{};
88
89 while (!pdr)
90 {
91 pdrEntry = pdrRepo.at(recordHndl);
92 pldm_pdr_hdr* header = reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data());
93 if (header->type != PLDM_STATE_EFFECTER_PDR)
94 {
95 recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
96 if (recordHndl)
97 {
98 continue;
99 }
100 return PLDM_PLATFORM_INVALID_EFFECTER_ID;
101 }
102 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data());
103 recordHndl = pdr->hdr.record_handle;
104 if (pdr->effecter_id == effecterId)
105 {
106 states = reinterpret_cast<state_effecter_possible_states*>(
107 pdr->possible_states);
108 if (compEffecterCnt > pdr->composite_effecter_count)
109 {
110 log<level::ERR>("The requester sent wrong composite effecter "
111 "count for the effecter",
112 entry("EFFECTER_ID=%d", effecterId),
113 entry("COMP_EFF_CNT=%d", compEffecterCnt));
114 return PLDM_ERROR_INVALID_DATA;
115 }
116 break;
117 }
118 recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
119 if (!recordHndl)
120 {
121 return PLDM_PLATFORM_INVALID_EFFECTER_ID;
122 }
123 pdr = nullptr;
124 }
125
126 std::map<StateSetId, std::function<int(const std::string& objPath,
127 const uint8_t currState)>>
128 effecterToDbusEntries = {
129 {PLDM_BOOT_PROGRESS_STATE,
130 [&](const std::string& objPath, const uint8_t currState) {
131 auto stateSet =
132 stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE);
133 if (stateSet == stateNumToDbusProp.end())
134 {
135 log<level::ERR>("Couldn't find D-Bus mapping for "
136 "PLDM_BOOT_PROGRESS_STATE",
137 entry("EFFECTER_ID=%d", effecterId));
138 return PLDM_ERROR;
139 }
140 auto iter = stateSet->second.find(
141 stateField[currState].effecter_state);
142 if (iter == stateSet->second.end())
143 {
144 log<level::ERR>(
145 "Invalid state field passed or field not "
146 "found for PLDM_BOOT_PROGRESS_STATE",
147 entry("EFFECTER_ID=%d", effecterId),
148 entry("FIELD=%d",
149 stateField[currState].effecter_state),
150 entry("OBJECT_PATH=%s", objPath.c_str()));
151 return PLDM_ERROR_INVALID_DATA;
152 }
153 auto dbusProp = "OperatingSystemState";
154 std::variant<std::string> value{
155 std::get<std::string>(iter->second)};
156 auto dbusInterface =
157 "xyz.openbmc_project.State.OperatingSystem.Status";
158 try
159 {
160 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
161 dbusInterface, value);
162 }
163 catch (const std::exception& e)
164 {
165 log<level::ERR>("Error setting property",
166 entry("ERROR=%s", e.what()),
167 entry("PROPERTY=%s", dbusProp),
168 entry("INTERFACE=%s", dbusInterface),
169 entry("PATH=%s", objPath.c_str()));
170 return PLDM_ERROR;
171 }
172 return PLDM_SUCCESS;
Deepak Kodihalli960dc962019-10-08 08:17:32 -0500173 }},
174 {PLDM_SYSTEM_POWER_STATE,
175 [&](const std::string& objPath, const uint8_t currState) {
176 auto stateSet =
177 stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
178 if (stateSet == stateNumToDbusProp.end())
179 {
180 log<level::ERR>("Couldn't find D-Bus mapping for "
181 "PLDM_SYSTEM_POWER_STATE",
182 entry("EFFECTER_ID=%d", effecterId));
183 return PLDM_ERROR;
184 }
185 auto iter = stateSet->second.find(
186 stateField[currState].effecter_state);
187 if (iter == stateSet->second.end())
188 {
189 log<level::ERR>(
190 "Invalid state field passed or field not "
191 "found for PLDM_SYSTEM_POWER_STATE",
192 entry("EFFECTER_ID=%d", effecterId),
193 entry("FIELD=%d",
194 stateField[currState].effecter_state),
195 entry("OBJECT_PATH=%s", objPath.c_str()));
196 return PLDM_ERROR_INVALID_DATA;
197 }
198 auto dbusProp = "RequestedPowerTransition";
199 std::variant<std::string> value{
200 std::get<std::string>(iter->second)};
201 auto dbusInterface = "xyz.openbmc_project.State.Chassis";
202 try
203 {
204 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
205 dbusInterface, value);
206 }
207 catch (const std::exception& e)
208 {
209 log<level::ERR>("Error setting property",
210 entry("ERROR=%s", e.what()),
211 entry("PROPERTY=%s", dbusProp),
212 entry("INTERFACE=%s", dbusInterface),
213 entry("PATH=%s", objPath.c_str()));
214 return PLDM_ERROR;
215 }
216 return PLDM_SUCCESS;
Sampa Misraa2fa0702019-05-31 01:28:55 -0500217 }}};
218
219 int rc = PLDM_SUCCESS;
220 auto paths = get(effecterId);
221 for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
222 {
223 std::vector<StateSetNum> allowed{};
224 // computation is based on table 79 from DSP0248 v1.1.1
225 uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
226 uint8_t bit =
227 stateField[currState].effecter_state - (8 * bitfieldIndex);
228 if (states->possible_states_size < bitfieldIndex ||
229 !(states->states[bitfieldIndex].byte & (1 << bit)))
230 {
231 log<level::ERR>(
232 "Invalid state set value", entry("EFFECTER_ID=%d", effecterId),
233 entry("VALUE=%d", stateField[currState].effecter_state),
234 entry("COMPOSITE_EFFECTER_ID=%d", currState),
235 entry("DBUS_PATH=%c", paths[currState].c_str()));
236 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
237 break;
238 }
239 auto iter = effecterToDbusEntries.find(states->state_set_id);
240 if (iter == effecterToDbusEntries.end())
241 {
242 uint16_t setId = states->state_set_id;
243 log<level::ERR>(
244 "Did not find the state set for the state effecter pdr ",
245 entry("STATE=%d", setId), entry("EFFECTER_ID=%d", effecterId));
246 rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
247 break;
248 }
249 if (stateField[currState].set_request == PLDM_REQUEST_SET)
250 {
251 rc = iter->second(paths[currState], currState);
252 if (rc != PLDM_SUCCESS)
253 {
254 break;
255 }
256 }
257 uint8_t* nextState =
258 reinterpret_cast<uint8_t*>(states) +
259 sizeof(state_effecter_possible_states) - sizeof(states->states) +
260 (states->possible_states_size * sizeof(states->states));
261 states = reinterpret_cast<state_effecter_possible_states*>(nextState);
262 }
263 return rc;
264}
265
Deepak Kodihalli557dfb02019-05-12 13:11:17 +0530266} // namespace responder
267} // namespace pldm