blob: b16c7508726349a91bee20e667eee4783ea800d5 [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);
Tom Joseph250c4752020-04-15 10:32:45 +0530167 const auto& currHostState = std::get<std::string>(propVal);
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -0600168 if ((sdbusplus::message::convert_from_string<
169 BootProgress::ProgressStages>(currHostState) !=
170 BootProgress::ProgressStages::SystemInitComplete) &&
171 (sdbusplus::message::convert_from_string<
172 BootProgress::ProgressStages>(currHostState) !=
173 BootProgress::ProgressStages::OSRunning) &&
174 (sdbusplus::message::convert_from_string<
175 BootProgress::ProgressStages>(currHostState) !=
176 BootProgress::ProgressStages::SystemSetup))
Tom Joseph250c4752020-04-15 10:32:45 +0530177 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600178 info("Host is not up. Current host state: {CUR_HOST_STATE}",
179 "CUR_HOST_STATE", currHostState.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +0530180 return;
181 }
182 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500183 catch (const sdbusplus::exception_t& e)
Tom Joseph250c4752020-04-15 10:32:45 +0530184 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600185 error(
186 "Error in getting current host state. Will still continue to set the host effecter - {ERR_EXCEP}",
187 "ERR_EXCEP", e.what());
Tom Joseph250c4752020-04-15 10:32:45 +0530188 }
189 uint8_t newState{};
190 try
191 {
Patrick Williams6da4f912023-05-10 07:50:53 -0500192 newState = findNewStateValue(effecterInfoIndex, dbusInfoIndex,
193 it->second);
Tom Joseph250c4752020-04-15 10:32:45 +0530194 }
195 catch (const std::out_of_range& e)
196 {
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500197 error("New state not found in json: {ERROR}", "ERROR", e);
Tom Joseph250c4752020-04-15 10:32:45 +0530198 return;
199 }
200
201 std::vector<set_effecter_state_field> stateField;
202 for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
203 i++)
204 {
205 if (i == dbusInfoIndex)
206 {
207 stateField.push_back({PLDM_REQUEST_SET, newState});
208 }
209 else
210 {
211 stateField.push_back({PLDM_NO_CHANGE, 0});
212 }
213 }
214 int rc{};
215 try
216 {
217 rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
218 }
219 catch (const std::runtime_error& e)
220 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600221 error("Could not set host state effecter");
Tom Joseph250c4752020-04-15 10:32:45 +0530222 return;
223 }
224 if (rc != PLDM_SUCCESS)
225 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600226 error("Could not set the host state effecter, rc= {RC}", "RC", rc);
Tom Joseph250c4752020-04-15 10:32:45 +0530227 }
228}
229
230uint8_t
231 HostEffecterParser::findNewStateValue(size_t effecterInfoIndex,
232 size_t dbusInfoIndex,
233 const PropertyValue& propertyValue)
234{
235 const auto& propValues = hostEffecterInfo[effecterInfoIndex]
236 .dbusInfo[dbusInfoIndex]
237 .propertyValues;
238 auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
239 uint8_t newState{};
240 if (it != propValues.end())
241 {
242 auto index = std::distance(propValues.begin(), it);
243 newState = hostEffecterInfo[effecterInfoIndex]
244 .dbusInfo[dbusInfoIndex]
245 .state.states[index];
246 }
247 else
248 {
249 throw std::out_of_range("new state not found in json");
250 }
251 return newState;
252}
253
254int HostEffecterParser::setHostStateEffecter(
255 size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
256 uint16_t effecterId)
257{
258 uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
259 uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930260 auto instanceId = instanceIdDb->next(mctpEid);
Tom Joseph250c4752020-04-15 10:32:45 +0530261
262 std::vector<uint8_t> requestMsg(
263 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
264 sizeof(set_effecter_state_field) * compEffCnt,
265 0);
266 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
267 auto rc = encode_set_state_effecter_states_req(
268 instanceId, effecterId, compEffCnt, stateField.data(), request);
269
270 if (rc != PLDM_SUCCESS)
271 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600272 error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
273 rc);
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930274 instanceIdDb->free(mctpEid, instanceId);
Tom Joseph250c4752020-04-15 10:32:45 +0530275 return rc;
276 }
277
Patrick Williams6da4f912023-05-10 07:50:53 -0500278 auto setStateEffecterStatesRespHandler =
279 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
Riya Dixit49cfb132023-03-02 04:26:53 -0600280 if (response == nullptr || !respMsgLen)
281 {
282 error(
283 "Failed to receive response for setStateEffecterStates command");
284 return;
285 }
286 uint8_t completionCode{};
287 auto rc = decode_set_state_effecter_states_resp(response, respMsgLen,
288 &completionCode);
289 if (rc)
290 {
291 error("Failed to decode setStateEffecterStates response, rc {RC}",
292 "RC", rc);
293 pldm::utils::reportError(
294 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
295 }
296 if (completionCode)
297 {
298 error("Failed to set a Host effecter, cc = {CC}", "CC",
299 static_cast<unsigned>(completionCode));
300 pldm::utils::reportError(
301 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
302 }
303 };
Tom Joseph250c4752020-04-15 10:32:45 +0530304
Sampa Misrac0c79482021-06-02 08:01:54 -0500305 rc = handler->registerRequest(
306 mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
307 std::move(requestMsg), std::move(setStateEffecterStatesRespHandler));
308 if (rc)
Tom Joseph250c4752020-04-15 10:32:45 +0530309 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600310 error("Failed to send request to set an effecter on Host");
Tom Joseph250c4752020-04-15 10:32:45 +0530311 }
312 return rc;
313}
314
315void HostEffecterParser::createHostEffecterMatch(const std::string& objectPath,
316 const std::string& interface,
317 size_t effecterInfoIndex,
318 size_t dbusInfoIndex,
319 uint16_t effecterId)
320{
321 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -0500322 effecterInfoMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
323 pldm::utils::DBusHandler::getBus(),
324 propertiesChanged(objectPath, interface),
325 [this, effecterInfoIndex, dbusInfoIndex,
326 effecterId](sdbusplus::message_t& msg) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500327 DbusChgHostEffecterProps props;
328 std::string iface;
329 msg.read(iface, props);
330 processHostEffecterChangeNotification(props, effecterInfoIndex,
331 dbusInfoIndex, effecterId);
Patrick Williamsa6756622023-10-20 11:19:15 -0500332 }));
Tom Joseph250c4752020-04-15 10:32:45 +0530333}
334
335} // namespace host_effecters
336} // namespace pldm