blob: d83b4d9f641a264b1273ab2d1153c03f815d4326 [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>
12#include <iostream>
13
Riya Dixit49cfb132023-03-02 04:26:53 -060014PHOSPHOR_LOG2_USING;
15
Brad Bishop5079ac42021-08-19 18:35:06 -040016using namespace pldm::utils;
17
Tom Joseph250c4752020-04-15 10:32:45 +053018namespace pldm
19{
20namespace host_effecters
21{
Tom Joseph250c4752020-04-15 10:32:45 +053022using InternalFailure =
23 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
24
25constexpr auto hostEffecterJson = "dbus_to_host_effecter.json";
26
27void HostEffecterParser::populatePropVals(
28 const Json& dBusValues, std::vector<PropertyValue>& propertyValues,
29 const std::string& propertyType)
30
31{
32 for (const auto& elem : dBusValues)
33 {
34 auto value = jsonEntryToDbusVal(propertyType, elem);
35 propertyValues.emplace_back(value);
36 }
37}
38
39void HostEffecterParser::parseEffecterJson(const std::string& jsonPath)
40{
41 fs::path jsonDir(jsonPath);
42 if (!fs::exists(jsonDir) || fs::is_empty(jsonDir))
43 {
Riya Dixit49cfb132023-03-02 04:26:53 -060044 error("Host Effecter json path does not exist, DIR = {JSON_PATH}",
45 "JSON_PATH", jsonPath.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +053046 return;
47 }
48
49 fs::path jsonFilePath = jsonDir / hostEffecterJson;
50 if (!fs::exists(jsonFilePath))
51 {
Riya Dixit49cfb132023-03-02 04:26:53 -060052 error("json does not exist, PATH = {JSON_PATH}", "JSON_PATH",
53 jsonFilePath.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +053054 throw InternalFailure();
55 }
56
57 std::ifstream jsonFile(jsonFilePath);
58 auto data = Json::parse(jsonFile, nullptr, false);
59 if (data.is_discarded())
60 {
Riya Dixit49cfb132023-03-02 04:26:53 -060061 error("Parsing json file failed, FILE = {JSON_PATH}", "JSON_PATH",
62 jsonFilePath.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +053063 throw InternalFailure();
64 }
65 const Json empty{};
66 const std::vector<Json> emptyList{};
67
68 auto entries = data.value("entries", emptyList);
69 for (const auto& entry : entries)
70 {
71 EffecterInfo effecterInfo;
72 effecterInfo.mctpEid = entry.value("mctp_eid", 0xFF);
73 auto jsonEffecterInfo = entry.value("effecter_info", empty);
Patrick Williams6da4f912023-05-10 07:50:53 -050074 auto effecterId = jsonEffecterInfo.value("effecterID",
75 PLDM_INVALID_EFFECTER_ID);
Tom Joseph250c4752020-04-15 10:32:45 +053076 effecterInfo.containerId = jsonEffecterInfo.value("containerID", 0);
77 effecterInfo.entityType = jsonEffecterInfo.value("entityType", 0);
Patrick Williams6da4f912023-05-10 07:50:53 -050078 effecterInfo.entityInstance = jsonEffecterInfo.value("entityInstance",
79 0);
Tom Joseph250c4752020-04-15 10:32:45 +053080 effecterInfo.compEffecterCnt =
81 jsonEffecterInfo.value("compositeEffecterCount", 0);
82 auto effecters = entry.value("effecters", emptyList);
83 for (const auto& effecter : effecters)
84 {
85 DBusEffecterMapping dbusInfo{};
86 auto jsonDbusInfo = effecter.value("dbus_info", empty);
87 dbusInfo.dbusMap.objectPath = jsonDbusInfo.value("object_path", "");
88 dbusInfo.dbusMap.interface = jsonDbusInfo.value("interface", "");
Patrick Williams6da4f912023-05-10 07:50:53 -050089 dbusInfo.dbusMap.propertyName = jsonDbusInfo.value("property_name",
90 "");
91 dbusInfo.dbusMap.propertyType = jsonDbusInfo.value("property_type",
92 "");
Tom Joseph250c4752020-04-15 10:32:45 +053093 Json propertyValues = jsonDbusInfo["property_values"];
94
95 populatePropVals(propertyValues, dbusInfo.propertyValues,
96 dbusInfo.dbusMap.propertyType);
97
98 const std::vector<uint8_t> emptyStates{};
99 auto state = effecter.value("state", empty);
100 dbusInfo.state.stateSetId = state.value("id", 0);
101 auto states = state.value("state_values", emptyStates);
102 if (dbusInfo.propertyValues.size() != states.size())
103 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600104 error(
105 "Number of states do not match with number of D-Bus property values in the json. Object path {OBJ_PATH} and property {PROP_NAME} will not be monitored",
106 "OBJ_PATH", dbusInfo.dbusMap.objectPath.c_str(),
107 "PROP_NAME", dbusInfo.dbusMap.propertyName);
Tom Joseph250c4752020-04-15 10:32:45 +0530108 continue;
109 }
110 for (const auto& s : states)
111 {
112 dbusInfo.state.states.emplace_back(s);
113 }
114
115 auto effecterInfoIndex = hostEffecterInfo.size();
116 auto dbusInfoIndex = effecterInfo.dbusInfo.size();
117 createHostEffecterMatch(
118 dbusInfo.dbusMap.objectPath, dbusInfo.dbusMap.interface,
119 effecterInfoIndex, dbusInfoIndex, effecterId);
120 effecterInfo.dbusInfo.emplace_back(std::move(dbusInfo));
121 }
122 hostEffecterInfo.emplace_back(std::move(effecterInfo));
123 }
124}
125
126void HostEffecterParser::processHostEffecterChangeNotification(
127 const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
128 size_t dbusInfoIndex, uint16_t effecterId)
129{
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -0600130 using BootProgress =
131 sdbusplus::client::xyz::openbmc_project::state::boot::Progress<>;
132
Tom Joseph250c4752020-04-15 10:32:45 +0530133 const auto& propertyName = hostEffecterInfo[effecterInfoIndex]
134 .dbusInfo[dbusInfoIndex]
135 .dbusMap.propertyName;
136
137 const auto& it = chProperties.find(propertyName);
138
139 if (it == chProperties.end())
140 {
141 return;
142 }
143
144 if (effecterId == PLDM_INVALID_EFFECTER_ID)
145 {
Sampa Misraa4a96162020-07-14 05:33:46 -0500146 constexpr auto localOrRemote = false;
Tom Joseph250c4752020-04-15 10:32:45 +0530147 effecterId = findStateEffecterId(
148 pdrRepo, hostEffecterInfo[effecterInfoIndex].entityType,
149 hostEffecterInfo[effecterInfoIndex].entityInstance,
150 hostEffecterInfo[effecterInfoIndex].containerId,
151 hostEffecterInfo[effecterInfoIndex]
152 .dbusInfo[dbusInfoIndex]
Sampa Misraa4a96162020-07-14 05:33:46 -0500153 .state.stateSetId,
154 localOrRemote);
Tom Joseph250c4752020-04-15 10:32:45 +0530155 if (effecterId == PLDM_INVALID_EFFECTER_ID)
156 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600157 error("Effecter id not found in pdr repo");
Tom Joseph250c4752020-04-15 10:32:45 +0530158 return;
159 }
160 }
Tom Joseph250c4752020-04-15 10:32:45 +0530161 constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
162
163 try
164 {
165 auto propVal = dbusHandler->getDbusPropertyVariant(
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -0600166 hostStatePath, "BootProgress", BootProgress::interface);
Patrick Williamse4e2e822024-02-07 11:00:52 -0600167
168 using Stages = BootProgress::ProgressStages;
169 auto currHostState = sdbusplus::message::convert_from_string<Stages>(
170 std::get<std::string>(propVal))
171 .value();
172
173 if (currHostState != Stages::SystemInitComplete &&
174 currHostState != Stages::OSRunning &&
175 currHostState != Stages::SystemSetup)
Tom Joseph250c4752020-04-15 10:32:45 +0530176 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600177 info("Host is not up. Current host state: {CUR_HOST_STATE}",
Patrick Williamse4e2e822024-02-07 11:00:52 -0600178 "CUR_HOST_STATE", currHostState);
Tom Joseph250c4752020-04-15 10:32:45 +0530179 return;
180 }
181 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500182 catch (const sdbusplus::exception_t& e)
Tom Joseph250c4752020-04-15 10:32:45 +0530183 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600184 error(
185 "Error in getting current host state. Will still continue to set the host effecter - {ERR_EXCEP}",
186 "ERR_EXCEP", e.what());
Tom Joseph250c4752020-04-15 10:32:45 +0530187 }
188 uint8_t newState{};
189 try
190 {
Patrick Williams6da4f912023-05-10 07:50:53 -0500191 newState = findNewStateValue(effecterInfoIndex, dbusInfoIndex,
192 it->second);
Tom Joseph250c4752020-04-15 10:32:45 +0530193 }
194 catch (const std::out_of_range& e)
195 {
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500196 error("New state not found in json: {ERROR}", "ERROR", e);
Tom Joseph250c4752020-04-15 10:32:45 +0530197 return;
198 }
199
200 std::vector<set_effecter_state_field> stateField;
201 for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
202 i++)
203 {
204 if (i == dbusInfoIndex)
205 {
206 stateField.push_back({PLDM_REQUEST_SET, newState});
207 }
208 else
209 {
210 stateField.push_back({PLDM_NO_CHANGE, 0});
211 }
212 }
213 int rc{};
214 try
215 {
216 rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
217 }
218 catch (const std::runtime_error& e)
219 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600220 error("Could not set host state effecter");
Tom Joseph250c4752020-04-15 10:32:45 +0530221 return;
222 }
223 if (rc != PLDM_SUCCESS)
224 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600225 error("Could not set the host state effecter, rc= {RC}", "RC", rc);
Tom Joseph250c4752020-04-15 10:32:45 +0530226 }
227}
228
229uint8_t
230 HostEffecterParser::findNewStateValue(size_t effecterInfoIndex,
231 size_t dbusInfoIndex,
232 const PropertyValue& propertyValue)
233{
234 const auto& propValues = hostEffecterInfo[effecterInfoIndex]
235 .dbusInfo[dbusInfoIndex]
236 .propertyValues;
237 auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
238 uint8_t newState{};
239 if (it != propValues.end())
240 {
241 auto index = std::distance(propValues.begin(), it);
242 newState = hostEffecterInfo[effecterInfoIndex]
243 .dbusInfo[dbusInfoIndex]
244 .state.states[index];
245 }
246 else
247 {
248 throw std::out_of_range("new state not found in json");
249 }
250 return newState;
251}
252
253int HostEffecterParser::setHostStateEffecter(
254 size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
255 uint16_t effecterId)
256{
257 uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
258 uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930259 auto instanceId = instanceIdDb->next(mctpEid);
Tom Joseph250c4752020-04-15 10:32:45 +0530260
261 std::vector<uint8_t> requestMsg(
262 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
263 sizeof(set_effecter_state_field) * compEffCnt,
264 0);
265 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
266 auto rc = encode_set_state_effecter_states_req(
267 instanceId, effecterId, compEffCnt, stateField.data(), request);
268
269 if (rc != PLDM_SUCCESS)
270 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600271 error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
272 rc);
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930273 instanceIdDb->free(mctpEid, instanceId);
Tom Joseph250c4752020-04-15 10:32:45 +0530274 return rc;
275 }
276
Patrick Williams6da4f912023-05-10 07:50:53 -0500277 auto setStateEffecterStatesRespHandler =
278 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
Riya Dixit49cfb132023-03-02 04:26:53 -0600279 if (response == nullptr || !respMsgLen)
280 {
281 error(
282 "Failed to receive response for setStateEffecterStates command");
283 return;
284 }
285 uint8_t completionCode{};
286 auto rc = decode_set_state_effecter_states_resp(response, respMsgLen,
287 &completionCode);
288 if (rc)
289 {
290 error("Failed to decode setStateEffecterStates response, rc {RC}",
291 "RC", rc);
292 pldm::utils::reportError(
293 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
294 }
295 if (completionCode)
296 {
297 error("Failed to set a Host effecter, cc = {CC}", "CC",
298 static_cast<unsigned>(completionCode));
299 pldm::utils::reportError(
300 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
301 }
302 };
Tom Joseph250c4752020-04-15 10:32:45 +0530303
Sampa Misrac0c79482021-06-02 08:01:54 -0500304 rc = handler->registerRequest(
305 mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
306 std::move(requestMsg), std::move(setStateEffecterStatesRespHandler));
307 if (rc)
Tom Joseph250c4752020-04-15 10:32:45 +0530308 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600309 error("Failed to send request to set an effecter on Host");
Tom Joseph250c4752020-04-15 10:32:45 +0530310 }
311 return rc;
312}
313
314void HostEffecterParser::createHostEffecterMatch(const std::string& objectPath,
315 const std::string& interface,
316 size_t effecterInfoIndex,
317 size_t dbusInfoIndex,
318 uint16_t effecterId)
319{
320 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -0500321 effecterInfoMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
322 pldm::utils::DBusHandler::getBus(),
323 propertiesChanged(objectPath, interface),
324 [this, effecterInfoIndex, dbusInfoIndex,
325 effecterId](sdbusplus::message_t& msg) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500326 DbusChgHostEffecterProps props;
327 std::string iface;
328 msg.read(iface, props);
329 processHostEffecterChangeNotification(props, effecterInfoIndex,
330 dbusInfoIndex, effecterId);
Patrick Williamsa6756622023-10-20 11:19:15 -0500331 }));
Tom Joseph250c4752020-04-15 10:32:45 +0530332}
333
334} // namespace host_effecters
335} // namespace pldm