blob: 077468518f312e57d793c246db4095dbdd504b7f [file] [log] [blame]
Tom Joseph250c4752020-04-15 10:32:45 +05301#include "dbus_to_host_effecters.hpp"
2
George Liuc453e162022-12-21 17:16:23 +08003#include <libpldm/pdr.h>
4#include <libpldm/platform.h>
Tom Joseph250c4752020-04-15 10:32:45 +05305
Riya Dixit49cfb132023-03-02 04:26:53 -06006#include <phosphor-logging/lg2.hpp>
Tom Joseph250c4752020-04-15 10:32:45 +05307#include <xyz/openbmc_project/Common/error.hpp>
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -06008#include <xyz/openbmc_project/State/Boot/Progress/client.hpp>
Tom Joseph250c4752020-04-15 10:32:45 +05309#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
10
11#include <fstream>
Tom Joseph250c4752020-04-15 10:32:45 +053012
Riya Dixit49cfb132023-03-02 04:26:53 -060013PHOSPHOR_LOG2_USING;
14
Brad Bishop5079ac42021-08-19 18:35:06 -040015using namespace pldm::utils;
16
Tom Joseph250c4752020-04-15 10:32:45 +053017namespace pldm
18{
19namespace host_effecters
20{
Tom Joseph250c4752020-04-15 10:32:45 +053021using InternalFailure =
22 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23
24constexpr auto hostEffecterJson = "dbus_to_host_effecter.json";
25
26void HostEffecterParser::populatePropVals(
27 const Json& dBusValues, std::vector<PropertyValue>& propertyValues,
28 const std::string& propertyType)
29
30{
31 for (const auto& elem : dBusValues)
32 {
33 auto value = jsonEntryToDbusVal(propertyType, elem);
34 propertyValues.emplace_back(value);
35 }
36}
37
38void HostEffecterParser::parseEffecterJson(const std::string& jsonPath)
39{
40 fs::path jsonDir(jsonPath);
41 if (!fs::exists(jsonDir) || fs::is_empty(jsonDir))
42 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -050043 error("Effecter json file for remote terminus '{PATH}' does not exist.",
44 "PATH", jsonPath);
Tom Joseph250c4752020-04-15 10:32:45 +053045 return;
46 }
47
48 fs::path jsonFilePath = jsonDir / hostEffecterJson;
49 if (!fs::exists(jsonFilePath))
50 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -050051 error("Json at path '{PATH}' does not exist.", "PATH", jsonFilePath);
Tom Joseph250c4752020-04-15 10:32:45 +053052 throw InternalFailure();
53 }
54
55 std::ifstream jsonFile(jsonFilePath);
56 auto data = Json::parse(jsonFile, nullptr, false);
57 if (data.is_discarded())
58 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -050059 error("Failed to parse json file {PATH}", "PATH", jsonFilePath);
Tom Joseph250c4752020-04-15 10:32:45 +053060 throw InternalFailure();
61 }
62 const Json empty{};
63 const std::vector<Json> emptyList{};
64
65 auto entries = data.value("entries", emptyList);
66 for (const auto& entry : entries)
67 {
68 EffecterInfo effecterInfo;
69 effecterInfo.mctpEid = entry.value("mctp_eid", 0xFF);
70 auto jsonEffecterInfo = entry.value("effecter_info", empty);
Patrick Williams6da4f912023-05-10 07:50:53 -050071 auto effecterId = jsonEffecterInfo.value("effecterID",
72 PLDM_INVALID_EFFECTER_ID);
Tom Joseph250c4752020-04-15 10:32:45 +053073 effecterInfo.containerId = jsonEffecterInfo.value("containerID", 0);
74 effecterInfo.entityType = jsonEffecterInfo.value("entityType", 0);
Patrick Williams6da4f912023-05-10 07:50:53 -050075 effecterInfo.entityInstance = jsonEffecterInfo.value("entityInstance",
76 0);
Tom Joseph250c4752020-04-15 10:32:45 +053077 effecterInfo.compEffecterCnt =
78 jsonEffecterInfo.value("compositeEffecterCount", 0);
79 auto effecters = entry.value("effecters", emptyList);
80 for (const auto& effecter : effecters)
81 {
82 DBusEffecterMapping dbusInfo{};
83 auto jsonDbusInfo = effecter.value("dbus_info", empty);
84 dbusInfo.dbusMap.objectPath = jsonDbusInfo.value("object_path", "");
85 dbusInfo.dbusMap.interface = jsonDbusInfo.value("interface", "");
Patrick Williams6da4f912023-05-10 07:50:53 -050086 dbusInfo.dbusMap.propertyName = jsonDbusInfo.value("property_name",
87 "");
88 dbusInfo.dbusMap.propertyType = jsonDbusInfo.value("property_type",
89 "");
Tom Joseph250c4752020-04-15 10:32:45 +053090 Json propertyValues = jsonDbusInfo["property_values"];
91
92 populatePropVals(propertyValues, dbusInfo.propertyValues,
93 dbusInfo.dbusMap.propertyType);
94
95 const std::vector<uint8_t> emptyStates{};
96 auto state = effecter.value("state", empty);
97 dbusInfo.state.stateSetId = state.value("id", 0);
98 auto states = state.value("state_values", emptyStates);
99 if (dbusInfo.propertyValues.size() != states.size())
100 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600101 error(
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500102 "Number of states do not match with number of D-Bus property values in the json. Object path at '{PATH}' and property '{PROPERTY}' will not be monitored",
103 "PATH", dbusInfo.dbusMap.objectPath, "PROPERTY",
104 dbusInfo.dbusMap.propertyName);
Tom Joseph250c4752020-04-15 10:32:45 +0530105 continue;
106 }
107 for (const auto& s : states)
108 {
109 dbusInfo.state.states.emplace_back(s);
110 }
111
112 auto effecterInfoIndex = hostEffecterInfo.size();
113 auto dbusInfoIndex = effecterInfo.dbusInfo.size();
114 createHostEffecterMatch(
115 dbusInfo.dbusMap.objectPath, dbusInfo.dbusMap.interface,
116 effecterInfoIndex, dbusInfoIndex, effecterId);
117 effecterInfo.dbusInfo.emplace_back(std::move(dbusInfo));
118 }
119 hostEffecterInfo.emplace_back(std::move(effecterInfo));
120 }
121}
122
123void HostEffecterParser::processHostEffecterChangeNotification(
124 const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
125 size_t dbusInfoIndex, uint16_t effecterId)
126{
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -0600127 using BootProgress =
128 sdbusplus::client::xyz::openbmc_project::state::boot::Progress<>;
129
Tom Joseph250c4752020-04-15 10:32:45 +0530130 const auto& propertyName = hostEffecterInfo[effecterInfoIndex]
131 .dbusInfo[dbusInfoIndex]
132 .dbusMap.propertyName;
133
134 const auto& it = chProperties.find(propertyName);
135
136 if (it == chProperties.end())
137 {
138 return;
139 }
140
141 if (effecterId == PLDM_INVALID_EFFECTER_ID)
142 {
Sampa Misraa4a96162020-07-14 05:33:46 -0500143 constexpr auto localOrRemote = false;
Tom Joseph250c4752020-04-15 10:32:45 +0530144 effecterId = findStateEffecterId(
145 pdrRepo, hostEffecterInfo[effecterInfoIndex].entityType,
146 hostEffecterInfo[effecterInfoIndex].entityInstance,
147 hostEffecterInfo[effecterInfoIndex].containerId,
148 hostEffecterInfo[effecterInfoIndex]
149 .dbusInfo[dbusInfoIndex]
Sampa Misraa4a96162020-07-14 05:33:46 -0500150 .state.stateSetId,
151 localOrRemote);
Tom Joseph250c4752020-04-15 10:32:45 +0530152 if (effecterId == PLDM_INVALID_EFFECTER_ID)
153 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500154 error(
155 "Effecter ID '{EFFECTERID}' of entity type '{TYPE}', entityInstance '{INSTANCE}' and containerID '{CONTAINER_ID}' not found in pdr repo",
156 "EFFECTERID", effecterId, "TYPE",
157 hostEffecterInfo[effecterInfoIndex].entityType, "INSTANCE",
158 hostEffecterInfo[effecterInfoIndex].entityInstance,
159 "CONTAINER_ID",
160 hostEffecterInfo[effecterInfoIndex].containerId);
Tom Joseph250c4752020-04-15 10:32:45 +0530161 return;
162 }
163 }
Tom Joseph250c4752020-04-15 10:32:45 +0530164 constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
165
166 try
167 {
168 auto propVal = dbusHandler->getDbusPropertyVariant(
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -0600169 hostStatePath, "BootProgress", BootProgress::interface);
Patrick Williamse4e2e822024-02-07 11:00:52 -0600170
171 using Stages = BootProgress::ProgressStages;
172 auto currHostState = sdbusplus::message::convert_from_string<Stages>(
173 std::get<std::string>(propVal))
174 .value();
175
176 if (currHostState != Stages::SystemInitComplete &&
177 currHostState != Stages::OSRunning &&
178 currHostState != Stages::SystemSetup)
Tom Joseph250c4752020-04-15 10:32:45 +0530179 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500180 info(
181 "Remote terminus is not up/active, current remote terminus state is: '{CURRENT_HOST_STATE}'",
182 "CURRENT_HOST_STATE", currHostState);
Tom Joseph250c4752020-04-15 10:32:45 +0530183 return;
184 }
185 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500186 catch (const sdbusplus::exception_t& e)
Tom Joseph250c4752020-04-15 10:32:45 +0530187 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600188 error(
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500189 "Error in getting current remote terminus state. Will still continue to set the remote terminus effecter, error - {ERROR}",
190 "ERROR", e);
Tom Joseph250c4752020-04-15 10:32:45 +0530191 }
192 uint8_t newState{};
193 try
194 {
Patrick Williams6da4f912023-05-10 07:50:53 -0500195 newState = findNewStateValue(effecterInfoIndex, dbusInfoIndex,
196 it->second);
Tom Joseph250c4752020-04-15 10:32:45 +0530197 }
198 catch (const std::out_of_range& e)
199 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500200 error("Failed to find new state '{NEW_STATE}' in json, error - {ERROR}",
201 "ERROR", e, "NEW_STATE", newState);
Tom Joseph250c4752020-04-15 10:32:45 +0530202 return;
203 }
204
205 std::vector<set_effecter_state_field> stateField;
206 for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
207 i++)
208 {
209 if (i == dbusInfoIndex)
210 {
211 stateField.push_back({PLDM_REQUEST_SET, newState});
212 }
213 else
214 {
215 stateField.push_back({PLDM_NO_CHANGE, 0});
216 }
217 }
218 int rc{};
219 try
220 {
221 rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
222 }
223 catch (const std::runtime_error& e)
224 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500225 error(
226 "Failed to set remote terminus state effecter for effecter ID '{EFFECTERID}', error - {ERROR}",
227 "ERROR", e, "EFFECTERID", effecterId);
Tom Joseph250c4752020-04-15 10:32:45 +0530228 return;
229 }
230 if (rc != PLDM_SUCCESS)
231 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500232 error(
233 "Failed to set the remote terminus state effecter for effecter ID '{EFFECTERID}', response code '{RC}'",
234 "EFFECTERID", effecterId, "RC", rc);
Tom Joseph250c4752020-04-15 10:32:45 +0530235 }
236}
237
238uint8_t
239 HostEffecterParser::findNewStateValue(size_t effecterInfoIndex,
240 size_t dbusInfoIndex,
241 const PropertyValue& propertyValue)
242{
243 const auto& propValues = hostEffecterInfo[effecterInfoIndex]
244 .dbusInfo[dbusInfoIndex]
245 .propertyValues;
246 auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
247 uint8_t newState{};
248 if (it != propValues.end())
249 {
250 auto index = std::distance(propValues.begin(), it);
251 newState = hostEffecterInfo[effecterInfoIndex]
252 .dbusInfo[dbusInfoIndex]
253 .state.states[index];
254 }
255 else
256 {
257 throw std::out_of_range("new state not found in json");
258 }
259 return newState;
260}
261
262int HostEffecterParser::setHostStateEffecter(
263 size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
264 uint16_t effecterId)
265{
266 uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
267 uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930268 auto instanceId = instanceIdDb->next(mctpEid);
Tom Joseph250c4752020-04-15 10:32:45 +0530269
270 std::vector<uint8_t> requestMsg(
271 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
272 sizeof(set_effecter_state_field) * compEffCnt,
273 0);
274 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
275 auto rc = encode_set_state_effecter_states_req(
276 instanceId, effecterId, compEffCnt, stateField.data(), request);
277
278 if (rc != PLDM_SUCCESS)
279 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500280 error(
281 "Failed to encode set state effecter states message for effecter ID '{EFFECTERID}' and instanceID '{INSTANCE}' with response code '{RC}'",
282 "EFFECTERID", effecterId, "INSTANCE", instanceId, "RC", lg2::hex,
283 rc);
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930284 instanceIdDb->free(mctpEid, instanceId);
Tom Joseph250c4752020-04-15 10:32:45 +0530285 return rc;
286 }
287
Patrick Williams6da4f912023-05-10 07:50:53 -0500288 auto setStateEffecterStatesRespHandler =
289 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
Riya Dixit49cfb132023-03-02 04:26:53 -0600290 if (response == nullptr || !respMsgLen)
291 {
292 error(
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500293 "Failed to receive response for setting state effecter states.");
Riya Dixit49cfb132023-03-02 04:26:53 -0600294 return;
295 }
296 uint8_t completionCode{};
297 auto rc = decode_set_state_effecter_states_resp(response, respMsgLen,
298 &completionCode);
299 if (rc)
300 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500301 error(
302 "Failed to decode response of set state effecter states, response code '{RC}'",
303 "RC", rc);
Riya Dixit49cfb132023-03-02 04:26:53 -0600304 pldm::utils::reportError(
Manojkiran Eda92fb0b52024-04-17 10:48:17 +0530305 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
Riya Dixit49cfb132023-03-02 04:26:53 -0600306 }
307 if (completionCode)
308 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500309 error(
310 "Failed to set a remote terminus effecter, completion code '{CC}'",
311 "CC", completionCode);
Riya Dixit49cfb132023-03-02 04:26:53 -0600312 pldm::utils::reportError(
Manojkiran Eda92fb0b52024-04-17 10:48:17 +0530313 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
Riya Dixit49cfb132023-03-02 04:26:53 -0600314 }
315 };
Tom Joseph250c4752020-04-15 10:32:45 +0530316
Sampa Misrac0c79482021-06-02 08:01:54 -0500317 rc = handler->registerRequest(
318 mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
319 std::move(requestMsg), std::move(setStateEffecterStatesRespHandler));
320 if (rc)
Tom Joseph250c4752020-04-15 10:32:45 +0530321 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500322 error(
323 "Failed to send request to set an effecter on remote terminus for effecter ID '{EFFECTERID}', response code '{RC}'",
324 "EFFECTERID", effecterId, "RC", rc);
Tom Joseph250c4752020-04-15 10:32:45 +0530325 }
326 return rc;
327}
328
329void HostEffecterParser::createHostEffecterMatch(const std::string& objectPath,
330 const std::string& interface,
331 size_t effecterInfoIndex,
332 size_t dbusInfoIndex,
333 uint16_t effecterId)
334{
335 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -0500336 effecterInfoMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
337 pldm::utils::DBusHandler::getBus(),
338 propertiesChanged(objectPath, interface),
339 [this, effecterInfoIndex, dbusInfoIndex,
340 effecterId](sdbusplus::message_t& msg) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500341 DbusChgHostEffecterProps props;
342 std::string iface;
343 msg.read(iface, props);
344 processHostEffecterChangeNotification(props, effecterInfoIndex,
345 dbusInfoIndex, effecterId);
Patrick Williamsa6756622023-10-20 11:19:15 -0500346 }));
Tom Joseph250c4752020-04-15 10:32:45 +0530347}
348
349} // namespace host_effecters
350} // namespace pldm