blob: a70b86b8954617828afdad1aeaacf141da48e3ef [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);
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{
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.SystemSetup"))
Tom Joseph250c4752020-04-15 10:32:45 +0530173 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600174 info("Host is not up. Current host state: {CUR_HOST_STATE}",
175 "CUR_HOST_STATE", currHostState.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +0530176 return;
177 }
178 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500179 catch (const sdbusplus::exception_t& e)
Tom Joseph250c4752020-04-15 10:32:45 +0530180 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600181 error(
182 "Error in getting current host state. Will still continue to set the host effecter - {ERR_EXCEP}",
183 "ERR_EXCEP", e.what());
Tom Joseph250c4752020-04-15 10:32:45 +0530184 }
185 uint8_t newState{};
186 try
187 {
Patrick Williams6da4f912023-05-10 07:50:53 -0500188 newState = findNewStateValue(effecterInfoIndex, dbusInfoIndex,
189 it->second);
Tom Joseph250c4752020-04-15 10:32:45 +0530190 }
191 catch (const std::out_of_range& e)
192 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600193 error("New state not found in json");
Tom Joseph250c4752020-04-15 10:32:45 +0530194 return;
195 }
196
197 std::vector<set_effecter_state_field> stateField;
198 for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
199 i++)
200 {
201 if (i == dbusInfoIndex)
202 {
203 stateField.push_back({PLDM_REQUEST_SET, newState});
204 }
205 else
206 {
207 stateField.push_back({PLDM_NO_CHANGE, 0});
208 }
209 }
210 int rc{};
211 try
212 {
213 rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
214 }
215 catch (const std::runtime_error& e)
216 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600217 error("Could not set host state effecter");
Tom Joseph250c4752020-04-15 10:32:45 +0530218 return;
219 }
220 if (rc != PLDM_SUCCESS)
221 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600222 error("Could not set the host state effecter, rc= {RC}", "RC", rc);
Tom Joseph250c4752020-04-15 10:32:45 +0530223 }
224}
225
226uint8_t
227 HostEffecterParser::findNewStateValue(size_t effecterInfoIndex,
228 size_t dbusInfoIndex,
229 const PropertyValue& propertyValue)
230{
231 const auto& propValues = hostEffecterInfo[effecterInfoIndex]
232 .dbusInfo[dbusInfoIndex]
233 .propertyValues;
234 auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
235 uint8_t newState{};
236 if (it != propValues.end())
237 {
238 auto index = std::distance(propValues.begin(), it);
239 newState = hostEffecterInfo[effecterInfoIndex]
240 .dbusInfo[dbusInfoIndex]
241 .state.states[index];
242 }
243 else
244 {
245 throw std::out_of_range("new state not found in json");
246 }
247 return newState;
248}
249
250int HostEffecterParser::setHostStateEffecter(
251 size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
252 uint16_t effecterId)
253{
254 uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
255 uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930256 auto instanceId = instanceIdDb->next(mctpEid);
Tom Joseph250c4752020-04-15 10:32:45 +0530257
258 std::vector<uint8_t> requestMsg(
259 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
260 sizeof(set_effecter_state_field) * compEffCnt,
261 0);
262 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
263 auto rc = encode_set_state_effecter_states_req(
264 instanceId, effecterId, compEffCnt, stateField.data(), request);
265
266 if (rc != PLDM_SUCCESS)
267 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600268 error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
269 rc);
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930270 instanceIdDb->free(mctpEid, instanceId);
Tom Joseph250c4752020-04-15 10:32:45 +0530271 return rc;
272 }
273
Patrick Williams6da4f912023-05-10 07:50:53 -0500274 auto setStateEffecterStatesRespHandler =
275 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
Riya Dixit49cfb132023-03-02 04:26:53 -0600276 if (response == nullptr || !respMsgLen)
277 {
278 error(
279 "Failed to receive response for setStateEffecterStates command");
280 return;
281 }
282 uint8_t completionCode{};
283 auto rc = decode_set_state_effecter_states_resp(response, respMsgLen,
284 &completionCode);
285 if (rc)
286 {
287 error("Failed to decode setStateEffecterStates response, rc {RC}",
288 "RC", rc);
289 pldm::utils::reportError(
290 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
291 }
292 if (completionCode)
293 {
294 error("Failed to set a Host effecter, cc = {CC}", "CC",
295 static_cast<unsigned>(completionCode));
296 pldm::utils::reportError(
297 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
298 }
299 };
Tom Joseph250c4752020-04-15 10:32:45 +0530300
Sampa Misrac0c79482021-06-02 08:01:54 -0500301 rc = handler->registerRequest(
302 mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
303 std::move(requestMsg), std::move(setStateEffecterStatesRespHandler));
304 if (rc)
Tom Joseph250c4752020-04-15 10:32:45 +0530305 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600306 error("Failed to send request to set an effecter on Host");
Tom Joseph250c4752020-04-15 10:32:45 +0530307 }
308 return rc;
309}
310
311void HostEffecterParser::createHostEffecterMatch(const std::string& objectPath,
312 const std::string& interface,
313 size_t effecterInfoIndex,
314 size_t dbusInfoIndex,
315 uint16_t effecterId)
316{
317 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -0500318 effecterInfoMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
319 pldm::utils::DBusHandler::getBus(),
320 propertiesChanged(objectPath, interface),
321 [this, effecterInfoIndex, dbusInfoIndex,
322 effecterId](sdbusplus::message_t& msg) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500323 DbusChgHostEffecterProps props;
324 std::string iface;
325 msg.read(iface, props);
326 processHostEffecterChangeNotification(props, effecterInfoIndex,
327 dbusInfoIndex, effecterId);
Patrick Williams84b790c2022-07-22 19:26:56 -0500328 }));
Tom Joseph250c4752020-04-15 10:32:45 +0530329}
330
331} // namespace host_effecters
332} // namespace pldm