blob: 32419a2787fc6d6692e366326e508bc906c52ce0 [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>
5#include <libpldm/pldm.h>
Tom Joseph250c4752020-04-15 10:32:45 +05306
Riya Dixit49cfb132023-03-02 04:26:53 -06007#include <phosphor-logging/lg2.hpp>
Tom Joseph250c4752020-04-15 10:32:45 +05308#include <xyz/openbmc_project/Common/error.hpp>
9#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);
74 auto effecterId =
75 jsonEffecterInfo.value("effecterID", PLDM_INVALID_EFFECTER_ID);
76 effecterInfo.containerId = jsonEffecterInfo.value("containerID", 0);
77 effecterInfo.entityType = jsonEffecterInfo.value("entityType", 0);
78 effecterInfo.entityInstance =
79 jsonEffecterInfo.value("entityInstance", 0);
80 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", "");
89 dbusInfo.dbusMap.propertyName =
90 jsonDbusInfo.value("property_name", "");
91 dbusInfo.dbusMap.propertyType =
92 jsonDbusInfo.value("property_type", "");
93 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{
130 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 Dixit49cfb132023-03-02 04:26:53 -0600154 error("Effecter id not found in pdr repo");
Tom Joseph250c4752020-04-15 10:32:45 +0530155 return;
156 }
157 }
158 constexpr auto hostStateInterface =
Tom Joseph5dad5f42020-12-08 18:23:42 +0530159 "xyz.openbmc_project.State.Boot.Progress";
Tom Joseph250c4752020-04-15 10:32:45 +0530160 constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
161
162 try
163 {
164 auto propVal = dbusHandler->getDbusPropertyVariant(
Tom Joseph5dad5f42020-12-08 18:23:42 +0530165 hostStatePath, "BootProgress", hostStateInterface);
Tom Joseph250c4752020-04-15 10:32:45 +0530166 const auto& currHostState = std::get<std::string>(propVal);
Tom Joseph5dad5f42020-12-08 18:23:42 +0530167 if ((currHostState != "xyz.openbmc_project.State.Boot.Progress."
168 "ProgressStages.SystemInitComplete") &&
169 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
170 "ProgressStages.OSRunning") &&
171 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
Andrew Geisslerf2704dc2022-05-23 16:09:45 -0400172 "ProgressStages.OSStart") &&
173 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
174 "ProgressStages.SystemSetup"))
Tom Joseph250c4752020-04-15 10:32:45 +0530175 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600176 info("Host is not up. Current host state: {CUR_HOST_STATE}",
177 "CUR_HOST_STATE", currHostState.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +0530178 return;
179 }
180 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500181 catch (const sdbusplus::exception_t& e)
Tom Joseph250c4752020-04-15 10:32:45 +0530182 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600183 error(
184 "Error in getting current host state. Will still continue to set the host effecter - {ERR_EXCEP}",
185 "ERR_EXCEP", e.what());
Tom Joseph250c4752020-04-15 10:32:45 +0530186 }
187 uint8_t newState{};
188 try
189 {
190 newState =
191 findNewStateValue(effecterInfoIndex, dbusInfoIndex, it->second);
192 }
193 catch (const std::out_of_range& e)
194 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600195 error("New state not found in json");
Tom Joseph250c4752020-04-15 10:32:45 +0530196 return;
197 }
198
199 std::vector<set_effecter_state_field> stateField;
200 for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
201 i++)
202 {
203 if (i == dbusInfoIndex)
204 {
205 stateField.push_back({PLDM_REQUEST_SET, newState});
206 }
207 else
208 {
209 stateField.push_back({PLDM_NO_CHANGE, 0});
210 }
211 }
212 int rc{};
213 try
214 {
215 rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
216 }
217 catch (const std::runtime_error& e)
218 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600219 error("Could not set host state effecter");
Tom Joseph250c4752020-04-15 10:32:45 +0530220 return;
221 }
222 if (rc != PLDM_SUCCESS)
223 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600224 error("Could not set the host state effecter, rc= {RC}", "RC", rc);
Tom Joseph250c4752020-04-15 10:32:45 +0530225 }
226}
227
228uint8_t
229 HostEffecterParser::findNewStateValue(size_t effecterInfoIndex,
230 size_t dbusInfoIndex,
231 const PropertyValue& propertyValue)
232{
233 const auto& propValues = hostEffecterInfo[effecterInfoIndex]
234 .dbusInfo[dbusInfoIndex]
235 .propertyValues;
236 auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
237 uint8_t newState{};
238 if (it != propValues.end())
239 {
240 auto index = std::distance(propValues.begin(), it);
241 newState = hostEffecterInfo[effecterInfoIndex]
242 .dbusInfo[dbusInfoIndex]
243 .state.states[index];
244 }
245 else
246 {
247 throw std::out_of_range("new state not found in json");
248 }
249 return newState;
250}
251
252int HostEffecterParser::setHostStateEffecter(
253 size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
254 uint16_t effecterId)
255{
256 uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
257 uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
258 auto instanceId = requester->getInstanceId(mctpEid);
259
260 std::vector<uint8_t> requestMsg(
261 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
262 sizeof(set_effecter_state_field) * compEffCnt,
263 0);
264 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
265 auto rc = encode_set_state_effecter_states_req(
266 instanceId, effecterId, compEffCnt, stateField.data(), request);
267
268 if (rc != PLDM_SUCCESS)
269 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600270 error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
271 rc);
Tom Joseph250c4752020-04-15 10:32:45 +0530272 requester->markFree(mctpEid, instanceId);
273 return rc;
274 }
275
Riya Dixit49cfb132023-03-02 04:26:53 -0600276 auto setStateEffecterStatesRespHandler = [](mctp_eid_t /*eid*/,
277 const pldm_msg* response,
278 size_t respMsgLen) {
279 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) {
326 DbusChgHostEffecterProps props;
327 std::string iface;
328 msg.read(iface, props);
329 processHostEffecterChangeNotification(props, effecterInfoIndex,
330 dbusInfoIndex, effecterId);
331 }));
Tom Joseph250c4752020-04-15 10:32:45 +0530332}
333
334} // namespace host_effecters
335} // namespace pldm