blob: 2486c64e1e9868fcd61f8af35b695cc60c76a91f [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."
169 "ProgressStages.OSStart"))
Tom Joseph250c4752020-04-15 10:32:45 +0530170 {
171 std::cout << "Host is not up. Current host state: "
172 << currHostState.c_str() << "\n";
173 return;
174 }
175 }
Patrick Williams4fea7a22021-09-02 09:54:12 -0500176 catch (const sdbusplus::exception::exception& e)
Tom Joseph250c4752020-04-15 10:32:45 +0530177 {
178 std::cerr << "Error in getting current host state. Will still "
179 "continue to set the host effecter \n";
180 }
181 uint8_t newState{};
182 try
183 {
184 newState =
185 findNewStateValue(effecterInfoIndex, dbusInfoIndex, it->second);
186 }
187 catch (const std::out_of_range& e)
188 {
189 std::cerr << "new state not found in json"
190 << "\n";
191 return;
192 }
193
194 std::vector<set_effecter_state_field> stateField;
195 for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
196 i++)
197 {
198 if (i == dbusInfoIndex)
199 {
200 stateField.push_back({PLDM_REQUEST_SET, newState});
201 }
202 else
203 {
204 stateField.push_back({PLDM_NO_CHANGE, 0});
205 }
206 }
207 int rc{};
208 try
209 {
210 rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
211 }
212 catch (const std::runtime_error& e)
213 {
214 std::cerr << "Could not set host state effecter \n";
215 return;
216 }
217 if (rc != PLDM_SUCCESS)
218 {
219 std::cerr << "Could not set the host state effecter, rc= " << rc
220 << " \n";
221 }
222}
223
224uint8_t
225 HostEffecterParser::findNewStateValue(size_t effecterInfoIndex,
226 size_t dbusInfoIndex,
227 const PropertyValue& propertyValue)
228{
229 const auto& propValues = hostEffecterInfo[effecterInfoIndex]
230 .dbusInfo[dbusInfoIndex]
231 .propertyValues;
232 auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
233 uint8_t newState{};
234 if (it != propValues.end())
235 {
236 auto index = std::distance(propValues.begin(), it);
237 newState = hostEffecterInfo[effecterInfoIndex]
238 .dbusInfo[dbusInfoIndex]
239 .state.states[index];
240 }
241 else
242 {
243 throw std::out_of_range("new state not found in json");
244 }
245 return newState;
246}
247
248int HostEffecterParser::setHostStateEffecter(
249 size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
250 uint16_t effecterId)
251{
252 uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
253 uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
254 auto instanceId = requester->getInstanceId(mctpEid);
255
256 std::vector<uint8_t> requestMsg(
257 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
258 sizeof(set_effecter_state_field) * compEffCnt,
259 0);
260 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
261 auto rc = encode_set_state_effecter_states_req(
262 instanceId, effecterId, compEffCnt, stateField.data(), request);
263
264 if (rc != PLDM_SUCCESS)
265 {
266 std::cerr << "Message encode failure. PLDM error code = " << std::hex
267 << std::showbase << rc << "\n";
268 requester->markFree(mctpEid, instanceId);
269 return rc;
270 }
271
Sampa Misrac0c79482021-06-02 08:01:54 -0500272 auto setStateEffecterStatesRespHandler =
273 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
274 if (response == nullptr || !respMsgLen)
275 {
276 std::cerr << "Failed to receive response for "
277 << "setStateEffecterStates command \n";
278 return;
279 }
280 uint8_t completionCode{};
281 auto rc = decode_set_state_effecter_states_resp(
282 response, respMsgLen, &completionCode);
283 if (rc)
284 {
285 std::cerr << "Failed to decode setStateEffecterStates response,"
286 << " rc " << rc << "\n";
287 pldm::utils::reportError(
288 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
289 }
290 if (completionCode)
291 {
292 std::cerr << "Failed to set a Host effecter "
293 << ", cc=" << static_cast<unsigned>(completionCode)
294 << "\n";
295 pldm::utils::reportError(
296 "xyz.openbmc_project.bmc.pldm.SetHostEffecterFailed");
297 }
298 };
Tom Joseph250c4752020-04-15 10:32:45 +0530299
Sampa Misrac0c79482021-06-02 08:01:54 -0500300 rc = handler->registerRequest(
301 mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
302 std::move(requestMsg), std::move(setStateEffecterStatesRespHandler));
303 if (rc)
Tom Joseph250c4752020-04-15 10:32:45 +0530304 {
Sampa Misrac0c79482021-06-02 08:01:54 -0500305 std::cerr << "Failed to send request to set an effecter on Host \n";
Tom Joseph250c4752020-04-15 10:32:45 +0530306 }
307 return rc;
308}
309
310void HostEffecterParser::createHostEffecterMatch(const std::string& objectPath,
311 const std::string& interface,
312 size_t effecterInfoIndex,
313 size_t dbusInfoIndex,
314 uint16_t effecterId)
315{
316 using namespace sdbusplus::bus::match::rules;
317 effecterInfoMatch.emplace_back(
318 std::make_unique<sdbusplus::bus::match::match>(
319 pldm::utils::DBusHandler::getBus(),
320 propertiesChanged(objectPath, interface),
321 [this, effecterInfoIndex, dbusInfoIndex,
322 effecterId](sdbusplus::message::message& msg) {
323 DbusChgHostEffecterProps props;
324 std::string iface;
325 msg.read(iface, props);
326 processHostEffecterChangeNotification(
327 props, effecterInfoIndex, dbusInfoIndex, effecterId);
328 }));
329}
330
331} // namespace host_effecters
332} // namespace pldm