blob: 89a8a956232244881834ad8116e58adc1c7fd0ab [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
7#include <xyz/openbmc_project/Common/error.hpp>
8#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
9
10#include <fstream>
11#include <iostream>
12
Brad Bishop5079ac42021-08-19 18:35:06 -040013using namespace pldm::utils;
14
Tom Joseph250c4752020-04-15 10:32:45 +053015namespace pldm
16{
17namespace host_effecters
18{
Tom Joseph250c4752020-04-15 10:32:45 +053019using InternalFailure =
20 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
21
22constexpr auto hostEffecterJson = "dbus_to_host_effecter.json";
23
24void HostEffecterParser::populatePropVals(
25 const Json& dBusValues, std::vector<PropertyValue>& propertyValues,
26 const std::string& propertyType)
27
28{
29 for (const auto& elem : dBusValues)
30 {
31 auto value = jsonEntryToDbusVal(propertyType, elem);
32 propertyValues.emplace_back(value);
33 }
34}
35
36void HostEffecterParser::parseEffecterJson(const std::string& jsonPath)
37{
38 fs::path jsonDir(jsonPath);
39 if (!fs::exists(jsonDir) || fs::is_empty(jsonDir))
40 {
41 std::cerr << "Host Effecter json path does not exist, DIR=" << jsonPath
42 << "\n";
43 return;
44 }
45
46 fs::path jsonFilePath = jsonDir / hostEffecterJson;
47 if (!fs::exists(jsonFilePath))
48 {
49 std::cerr << "json does not exist, PATH=" << jsonFilePath << "\n";
50 throw InternalFailure();
51 }
52
53 std::ifstream jsonFile(jsonFilePath);
54 auto data = Json::parse(jsonFile, nullptr, false);
55 if (data.is_discarded())
56 {
57 std::cerr << "Parsing json file failed, FILE=" << jsonFilePath << "\n";
58 throw InternalFailure();
59 }
60 const Json empty{};
61 const std::vector<Json> emptyList{};
62
63 auto entries = data.value("entries", emptyList);
64 for (const auto& entry : entries)
65 {
66 EffecterInfo effecterInfo;
67 effecterInfo.mctpEid = entry.value("mctp_eid", 0xFF);
68 auto jsonEffecterInfo = entry.value("effecter_info", empty);
69 auto effecterId =
70 jsonEffecterInfo.value("effecterID", PLDM_INVALID_EFFECTER_ID);
71 effecterInfo.containerId = jsonEffecterInfo.value("containerID", 0);
72 effecterInfo.entityType = jsonEffecterInfo.value("entityType", 0);
73 effecterInfo.entityInstance =
74 jsonEffecterInfo.value("entityInstance", 0);
75 effecterInfo.compEffecterCnt =
76 jsonEffecterInfo.value("compositeEffecterCount", 0);
77 auto effecters = entry.value("effecters", emptyList);
78 for (const auto& effecter : effecters)
79 {
80 DBusEffecterMapping dbusInfo{};
81 auto jsonDbusInfo = effecter.value("dbus_info", empty);
82 dbusInfo.dbusMap.objectPath = jsonDbusInfo.value("object_path", "");
83 dbusInfo.dbusMap.interface = jsonDbusInfo.value("interface", "");
84 dbusInfo.dbusMap.propertyName =
85 jsonDbusInfo.value("property_name", "");
86 dbusInfo.dbusMap.propertyType =
87 jsonDbusInfo.value("property_type", "");
88 Json propertyValues = jsonDbusInfo["property_values"];
89
90 populatePropVals(propertyValues, dbusInfo.propertyValues,
91 dbusInfo.dbusMap.propertyType);
92
93 const std::vector<uint8_t> emptyStates{};
94 auto state = effecter.value("state", empty);
95 dbusInfo.state.stateSetId = state.value("id", 0);
96 auto states = state.value("state_values", emptyStates);
97 if (dbusInfo.propertyValues.size() != states.size())
98 {
99 std::cerr << "Number of states do not match with"
100 << " number of D-Bus property values in the json. "
101 << "Object path " << dbusInfo.dbusMap.objectPath
102 << " and property " << dbusInfo.dbusMap.propertyName
103 << " will not be monitored \n";
104 continue;
105 }
106 for (const auto& s : states)
107 {
108 dbusInfo.state.states.emplace_back(s);
109 }
110
111 auto effecterInfoIndex = hostEffecterInfo.size();
112 auto dbusInfoIndex = effecterInfo.dbusInfo.size();
113 createHostEffecterMatch(
114 dbusInfo.dbusMap.objectPath, dbusInfo.dbusMap.interface,
115 effecterInfoIndex, dbusInfoIndex, effecterId);
116 effecterInfo.dbusInfo.emplace_back(std::move(dbusInfo));
117 }
118 hostEffecterInfo.emplace_back(std::move(effecterInfo));
119 }
120}
121
122void HostEffecterParser::processHostEffecterChangeNotification(
123 const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
124 size_t dbusInfoIndex, uint16_t effecterId)
125{
126 const auto& propertyName = hostEffecterInfo[effecterInfoIndex]
127 .dbusInfo[dbusInfoIndex]
128 .dbusMap.propertyName;
129
130 const auto& it = chProperties.find(propertyName);
131
132 if (it == chProperties.end())
133 {
134 return;
135 }
136
137 if (effecterId == PLDM_INVALID_EFFECTER_ID)
138 {
Sampa Misraa4a96162020-07-14 05:33:46 -0500139 constexpr auto localOrRemote = false;
Tom Joseph250c4752020-04-15 10:32:45 +0530140 effecterId = findStateEffecterId(
141 pdrRepo, hostEffecterInfo[effecterInfoIndex].entityType,
142 hostEffecterInfo[effecterInfoIndex].entityInstance,
143 hostEffecterInfo[effecterInfoIndex].containerId,
144 hostEffecterInfo[effecterInfoIndex]
145 .dbusInfo[dbusInfoIndex]
Sampa Misraa4a96162020-07-14 05:33:46 -0500146 .state.stateSetId,
147 localOrRemote);
Tom Joseph250c4752020-04-15 10:32:45 +0530148 if (effecterId == PLDM_INVALID_EFFECTER_ID)
149 {
150 std::cerr << "Effecter id not found in pdr repo \n";
151 return;
152 }
153 }
154 constexpr auto hostStateInterface =
Tom Joseph5dad5f42020-12-08 18:23:42 +0530155 "xyz.openbmc_project.State.Boot.Progress";
Tom Joseph250c4752020-04-15 10:32:45 +0530156 constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
157
158 try
159 {
160 auto propVal = dbusHandler->getDbusPropertyVariant(
Tom Joseph5dad5f42020-12-08 18:23:42 +0530161 hostStatePath, "BootProgress", hostStateInterface);
Tom Joseph250c4752020-04-15 10:32:45 +0530162 const auto& currHostState = std::get<std::string>(propVal);
Tom Joseph5dad5f42020-12-08 18:23:42 +0530163 if ((currHostState != "xyz.openbmc_project.State.Boot.Progress."
164 "ProgressStages.SystemInitComplete") &&
165 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
166 "ProgressStages.OSRunning") &&
167 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
Andrew Geisslerf2704dc2022-05-23 16:09:45 -0400168 "ProgressStages.OSStart") &&
169 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
170 "ProgressStages.SystemSetup"))
Tom Joseph250c4752020-04-15 10:32:45 +0530171 {
172 std::cout << "Host is not up. Current host state: "
173 << currHostState.c_str() << "\n";
174 return;
175 }
176 }
Patrick Williams84b790c2022-07-22 19:26:56 -0500177 catch (const sdbusplus::exception_t& e)
Tom Joseph250c4752020-04-15 10:32:45 +0530178 {
179 std::cerr << "Error in getting current host state. Will still "
Archana Kakani040c6182023-02-20 07:01:51 -0600180 "continue to set the host effecter - "
181 << e.what() << std::endl;
Tom Joseph250c4752020-04-15 10:32:45 +0530182 }
183 uint8_t newState{};
184 try
185 {
186 newState =
187 findNewStateValue(effecterInfoIndex, dbusInfoIndex, it->second);
188 }
189 catch (const std::out_of_range& e)
190 {
191 std::cerr << "new state not found in json"
192 << "\n";
193 return;
194 }
195
196 std::vector<set_effecter_state_field> stateField;
197 for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
198 i++)
199 {
200 if (i == dbusInfoIndex)
201 {
202 stateField.push_back({PLDM_REQUEST_SET, newState});
203 }
204 else
205 {
206 stateField.push_back({PLDM_NO_CHANGE, 0});
207 }
208 }
209 int rc{};
210 try
211 {
212 rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
213 }
214 catch (const std::runtime_error& e)
215 {
216 std::cerr << "Could not set host state effecter \n";
217 return;
218 }
219 if (rc != PLDM_SUCCESS)
220 {
221 std::cerr << "Could not set the host state effecter, rc= " << rc
222 << " \n";
223 }
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;
256 auto instanceId = requester->getInstanceId(mctpEid);
257
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 {
268 std::cerr << "Message encode failure. PLDM error code = " << std::hex
269 << std::showbase << rc << "\n";
270 requester->markFree(mctpEid, instanceId);
271 return rc;
272 }
273
Sampa Misrac0c79482021-06-02 08:01:54 -0500274 auto setStateEffecterStatesRespHandler =
275 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
276 if (response == nullptr || !respMsgLen)
277 {
278 std::cerr << "Failed to receive response for "
279 << "setStateEffecterStates command \n";
280 return;
281 }
282 uint8_t completionCode{};
283 auto rc = decode_set_state_effecter_states_resp(
284 response, respMsgLen, &completionCode);
285 if (rc)
286 {
287 std::cerr << "Failed to decode setStateEffecterStates response,"
288 << " rc " << rc << "\n";
289 pldm::utils::reportError(
290 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
291 }
292 if (completionCode)
293 {
294 std::cerr << "Failed to set a Host effecter "
295 << ", cc=" << static_cast<unsigned>(completionCode)
296 << "\n";
297 pldm::utils::reportError(
298 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
299 }
300 };
Tom Joseph250c4752020-04-15 10:32:45 +0530301
Sampa Misrac0c79482021-06-02 08:01:54 -0500302 rc = handler->registerRequest(
303 mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
304 std::move(requestMsg), std::move(setStateEffecterStatesRespHandler));
305 if (rc)
Tom Joseph250c4752020-04-15 10:32:45 +0530306 {
Sampa Misrac0c79482021-06-02 08:01:54 -0500307 std::cerr << "Failed to send request to set an effecter on Host \n";
Tom Joseph250c4752020-04-15 10:32:45 +0530308 }
309 return rc;
310}
311
312void HostEffecterParser::createHostEffecterMatch(const std::string& objectPath,
313 const std::string& interface,
314 size_t effecterInfoIndex,
315 size_t dbusInfoIndex,
316 uint16_t effecterId)
317{
318 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -0500319 effecterInfoMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
320 pldm::utils::DBusHandler::getBus(),
321 propertiesChanged(objectPath, interface),
322 [this, effecterInfoIndex, dbusInfoIndex,
323 effecterId](sdbusplus::message_t& msg) {
324 DbusChgHostEffecterProps props;
325 std::string iface;
326 msg.read(iface, props);
327 processHostEffecterChangeNotification(props, effecterInfoIndex,
328 dbusInfoIndex, effecterId);
329 }));
Tom Joseph250c4752020-04-15 10:32:45 +0530330}
331
332} // namespace host_effecters
333} // namespace pldm