blob: a4d4be0fc45a62a2c98c4043914728d79f3dc280 [file] [log] [blame]
Tom Joseph250c4752020-04-15 10:32:45 +05301#include "dbus_to_host_effecters.hpp"
2
3#include "libpldm/pdr.h"
4#include "libpldm/platform.h"
5#include "libpldm/requester/pldm.h"
6
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{
19
20using InternalFailure =
21 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
22
23constexpr auto hostEffecterJson = "dbus_to_host_effecter.json";
24
25void HostEffecterParser::populatePropVals(
26 const Json& dBusValues, std::vector<PropertyValue>& propertyValues,
27 const std::string& propertyType)
28
29{
30 for (const auto& elem : dBusValues)
31 {
32 auto value = jsonEntryToDbusVal(propertyType, elem);
33 propertyValues.emplace_back(value);
34 }
35}
36
37void HostEffecterParser::parseEffecterJson(const std::string& jsonPath)
38{
39 fs::path jsonDir(jsonPath);
40 if (!fs::exists(jsonDir) || fs::is_empty(jsonDir))
41 {
42 std::cerr << "Host Effecter json path does not exist, DIR=" << jsonPath
43 << "\n";
44 return;
45 }
46
47 fs::path jsonFilePath = jsonDir / hostEffecterJson;
48 if (!fs::exists(jsonFilePath))
49 {
50 std::cerr << "json does not exist, PATH=" << jsonFilePath << "\n";
51 throw InternalFailure();
52 }
53
54 std::ifstream jsonFile(jsonFilePath);
55 auto data = Json::parse(jsonFile, nullptr, false);
56 if (data.is_discarded())
57 {
58 std::cerr << "Parsing json file failed, FILE=" << jsonFilePath << "\n";
59 throw InternalFailure();
60 }
61 const Json empty{};
62 const std::vector<Json> emptyList{};
63
64 auto entries = data.value("entries", emptyList);
65 for (const auto& entry : entries)
66 {
67 EffecterInfo effecterInfo;
68 effecterInfo.mctpEid = entry.value("mctp_eid", 0xFF);
69 auto jsonEffecterInfo = entry.value("effecter_info", empty);
70 auto effecterId =
71 jsonEffecterInfo.value("effecterID", PLDM_INVALID_EFFECTER_ID);
72 effecterInfo.containerId = jsonEffecterInfo.value("containerID", 0);
73 effecterInfo.entityType = jsonEffecterInfo.value("entityType", 0);
74 effecterInfo.entityInstance =
75 jsonEffecterInfo.value("entityInstance", 0);
76 effecterInfo.compEffecterCnt =
77 jsonEffecterInfo.value("compositeEffecterCount", 0);
78 auto effecters = entry.value("effecters", emptyList);
79 for (const auto& effecter : effecters)
80 {
81 DBusEffecterMapping dbusInfo{};
82 auto jsonDbusInfo = effecter.value("dbus_info", empty);
83 dbusInfo.dbusMap.objectPath = jsonDbusInfo.value("object_path", "");
84 dbusInfo.dbusMap.interface = jsonDbusInfo.value("interface", "");
85 dbusInfo.dbusMap.propertyName =
86 jsonDbusInfo.value("property_name", "");
87 dbusInfo.dbusMap.propertyType =
88 jsonDbusInfo.value("property_type", "");
89 Json propertyValues = jsonDbusInfo["property_values"];
90
91 populatePropVals(propertyValues, dbusInfo.propertyValues,
92 dbusInfo.dbusMap.propertyType);
93
94 const std::vector<uint8_t> emptyStates{};
95 auto state = effecter.value("state", empty);
96 dbusInfo.state.stateSetId = state.value("id", 0);
97 auto states = state.value("state_values", emptyStates);
98 if (dbusInfo.propertyValues.size() != states.size())
99 {
100 std::cerr << "Number of states do not match with"
101 << " number of D-Bus property values in the json. "
102 << "Object path " << dbusInfo.dbusMap.objectPath
103 << " and property " << dbusInfo.dbusMap.propertyName
104 << " will not be monitored \n";
105 continue;
106 }
107 for (const auto& s : states)
108 {
109 dbusInfo.state.states.emplace_back(s);
110 }
111
112 auto effecterInfoIndex = hostEffecterInfo.size();
113 auto dbusInfoIndex = effecterInfo.dbusInfo.size();
114 createHostEffecterMatch(
115 dbusInfo.dbusMap.objectPath, dbusInfo.dbusMap.interface,
116 effecterInfoIndex, dbusInfoIndex, effecterId);
117 effecterInfo.dbusInfo.emplace_back(std::move(dbusInfo));
118 }
119 hostEffecterInfo.emplace_back(std::move(effecterInfo));
120 }
121}
122
123void HostEffecterParser::processHostEffecterChangeNotification(
124 const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
125 size_t dbusInfoIndex, uint16_t effecterId)
126{
127 const auto& propertyName = hostEffecterInfo[effecterInfoIndex]
128 .dbusInfo[dbusInfoIndex]
129 .dbusMap.propertyName;
130
131 const auto& it = chProperties.find(propertyName);
132
133 if (it == chProperties.end())
134 {
135 return;
136 }
137
138 if (effecterId == PLDM_INVALID_EFFECTER_ID)
139 {
Sampa Misraa4a96162020-07-14 05:33:46 -0500140 constexpr auto localOrRemote = false;
Tom Joseph250c4752020-04-15 10:32:45 +0530141 effecterId = findStateEffecterId(
142 pdrRepo, hostEffecterInfo[effecterInfoIndex].entityType,
143 hostEffecterInfo[effecterInfoIndex].entityInstance,
144 hostEffecterInfo[effecterInfoIndex].containerId,
145 hostEffecterInfo[effecterInfoIndex]
146 .dbusInfo[dbusInfoIndex]
Sampa Misraa4a96162020-07-14 05:33:46 -0500147 .state.stateSetId,
148 localOrRemote);
Tom Joseph250c4752020-04-15 10:32:45 +0530149 if (effecterId == PLDM_INVALID_EFFECTER_ID)
150 {
151 std::cerr << "Effecter id not found in pdr repo \n";
152 return;
153 }
154 }
155 constexpr auto hostStateInterface =
Tom Joseph5dad5f42020-12-08 18:23:42 +0530156 "xyz.openbmc_project.State.Boot.Progress";
Tom Joseph250c4752020-04-15 10:32:45 +0530157 constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
158
159 try
160 {
161 auto propVal = dbusHandler->getDbusPropertyVariant(
Tom Joseph5dad5f42020-12-08 18:23:42 +0530162 hostStatePath, "BootProgress", hostStateInterface);
Tom Joseph250c4752020-04-15 10:32:45 +0530163 const auto& currHostState = std::get<std::string>(propVal);
Tom Joseph5dad5f42020-12-08 18:23:42 +0530164 if ((currHostState != "xyz.openbmc_project.State.Boot.Progress."
165 "ProgressStages.SystemInitComplete") &&
166 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
167 "ProgressStages.OSRunning") &&
168 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
Andrew Geisslerf2704dc2022-05-23 16:09:45 -0400169 "ProgressStages.OSStart") &&
170 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
171 "ProgressStages.SystemSetup"))
Tom Joseph250c4752020-04-15 10:32:45 +0530172 {
173 std::cout << "Host is not up. Current host state: "
174 << currHostState.c_str() << "\n";
175 return;
176 }
177 }
Patrick Williams4fea7a22021-09-02 09:54:12 -0500178 catch (const sdbusplus::exception::exception& e)
Tom Joseph250c4752020-04-15 10:32:45 +0530179 {
180 std::cerr << "Error in getting current host state. Will still "
181 "continue to set the host effecter \n";
182 }
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;
319 effecterInfoMatch.emplace_back(
320 std::make_unique<sdbusplus::bus::match::match>(
321 pldm::utils::DBusHandler::getBus(),
322 propertiesChanged(objectPath, interface),
323 [this, effecterInfoIndex, dbusInfoIndex,
324 effecterId](sdbusplus::message::message& msg) {
325 DbusChgHostEffecterProps props;
326 std::string iface;
327 msg.read(iface, props);
328 processHostEffecterChangeNotification(
329 props, effecterInfoIndex, dbusInfoIndex, effecterId);
330 }));
331}
332
333} // namespace host_effecters
334} // namespace pldm