blob: 9b1c250679868bb0c392624ec8d5cad1dfc610e7 [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 Williams16c2a0a2024-08-16 15:20:59 -040071 auto effecterId =
72 jsonEffecterInfo.value("effecterID", 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 Williams16c2a0a2024-08-16 15:20:59 -040075 effecterInfo.entityInstance =
76 jsonEffecterInfo.value("entityInstance", 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 Williams16c2a0a2024-08-16 15:20:59 -040086 dbusInfo.dbusMap.propertyName =
87 jsonDbusInfo.value("property_name", "");
88 dbusInfo.dbusMap.propertyType =
89 jsonDbusInfo.value("property_type", "");
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 Williams16c2a0a2024-08-16 15:20:59 -0400195 newState =
196 findNewStateValue(effecterInfoIndex, dbusInfoIndex, 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
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400238uint8_t HostEffecterParser::findNewStateValue(
239 size_t effecterInfoIndex, size_t dbusInfoIndex,
240 const PropertyValue& propertyValue)
Tom Joseph250c4752020-04-15 10:32:45 +0530241{
242 const auto& propValues = hostEffecterInfo[effecterInfoIndex]
243 .dbusInfo[dbusInfoIndex]
244 .propertyValues;
245 auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
246 uint8_t newState{};
247 if (it != propValues.end())
248 {
249 auto index = std::distance(propValues.begin(), it);
250 newState = hostEffecterInfo[effecterInfoIndex]
251 .dbusInfo[dbusInfoIndex]
252 .state.states[index];
253 }
254 else
255 {
256 throw std::out_of_range("new state not found in json");
257 }
258 return newState;
259}
260
261int HostEffecterParser::setHostStateEffecter(
262 size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
263 uint16_t effecterId)
264{
265 uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
266 uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930267 auto instanceId = instanceIdDb->next(mctpEid);
Tom Joseph250c4752020-04-15 10:32:45 +0530268
269 std::vector<uint8_t> requestMsg(
270 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
271 sizeof(set_effecter_state_field) * compEffCnt,
272 0);
273 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
274 auto rc = encode_set_state_effecter_states_req(
275 instanceId, effecterId, compEffCnt, stateField.data(), request);
276
277 if (rc != PLDM_SUCCESS)
278 {
Riya Dixitd6e10ad2024-03-28 19:44:16 -0500279 error(
280 "Failed to encode set state effecter states message for effecter ID '{EFFECTERID}' and instanceID '{INSTANCE}' with response code '{RC}'",
281 "EFFECTERID", effecterId, "INSTANCE", instanceId, "RC", lg2::hex,
282 rc);
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930283 instanceIdDb->free(mctpEid, instanceId);
Tom Joseph250c4752020-04-15 10:32:45 +0530284 return rc;
285 }
286
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400287 auto setStateEffecterStatesRespHandler = [](mctp_eid_t /*eid*/,
288 const pldm_msg* response,
289 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
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400329void HostEffecterParser::createHostEffecterMatch(
330 const std::string& objectPath, const std::string& interface,
331 size_t effecterInfoIndex, size_t dbusInfoIndex, uint16_t effecterId)
Tom Joseph250c4752020-04-15 10:32:45 +0530332{
333 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -0500334 effecterInfoMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
335 pldm::utils::DBusHandler::getBus(),
336 propertiesChanged(objectPath, interface),
337 [this, effecterInfoIndex, dbusInfoIndex,
338 effecterId](sdbusplus::message_t& msg) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400339 DbusChgHostEffecterProps props;
340 std::string iface;
341 msg.read(iface, props);
342 processHostEffecterChangeNotification(props, effecterInfoIndex,
343 dbusInfoIndex, effecterId);
344 }));
Tom Joseph250c4752020-04-15 10:32:45 +0530345}
346
347} // namespace host_effecters
348} // namespace pldm