blob: 21e893d7857c1dc58e377ec62b873f8e482f3194 [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>
Tom Joseph250c4752020-04-15 10:32:45 +05305
Riya Dixit49cfb132023-03-02 04:26:53 -06006#include <phosphor-logging/lg2.hpp>
Tom Joseph250c4752020-04-15 10:32:45 +05307#include <xyz/openbmc_project/Common/error.hpp>
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -06008#include <xyz/openbmc_project/State/Boot/Progress/client.hpp>
Tom Joseph250c4752020-04-15 10:32:45 +05309#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
10
11#include <fstream>
Tom Joseph250c4752020-04-15 10:32:45 +053012
Riya Dixit49cfb132023-03-02 04:26:53 -060013PHOSPHOR_LOG2_USING;
14
Brad Bishop5079ac42021-08-19 18:35:06 -040015using namespace pldm::utils;
16
Tom Joseph250c4752020-04-15 10:32:45 +053017namespace pldm
18{
19namespace host_effecters
20{
Tom Joseph250c4752020-04-15 10:32:45 +053021using InternalFailure =
22 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23
24constexpr auto hostEffecterJson = "dbus_to_host_effecter.json";
25
26void HostEffecterParser::populatePropVals(
27 const Json& dBusValues, std::vector<PropertyValue>& propertyValues,
28 const std::string& propertyType)
29
30{
31 for (const auto& elem : dBusValues)
32 {
33 auto value = jsonEntryToDbusVal(propertyType, elem);
34 propertyValues.emplace_back(value);
35 }
36}
37
38void HostEffecterParser::parseEffecterJson(const std::string& jsonPath)
39{
40 fs::path jsonDir(jsonPath);
41 if (!fs::exists(jsonDir) || fs::is_empty(jsonDir))
42 {
Riya Dixit49cfb132023-03-02 04:26:53 -060043 error("Host Effecter json path does not exist, DIR = {JSON_PATH}",
44 "JSON_PATH", jsonPath.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +053045 return;
46 }
47
48 fs::path jsonFilePath = jsonDir / hostEffecterJson;
49 if (!fs::exists(jsonFilePath))
50 {
Riya Dixit49cfb132023-03-02 04:26:53 -060051 error("json does not exist, PATH = {JSON_PATH}", "JSON_PATH",
52 jsonFilePath.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +053053 throw InternalFailure();
54 }
55
56 std::ifstream jsonFile(jsonFilePath);
57 auto data = Json::parse(jsonFile, nullptr, false);
58 if (data.is_discarded())
59 {
Riya Dixit49cfb132023-03-02 04:26:53 -060060 error("Parsing json file failed, FILE = {JSON_PATH}", "JSON_PATH",
61 jsonFilePath.c_str());
Tom Joseph250c4752020-04-15 10:32:45 +053062 throw InternalFailure();
63 }
64 const Json empty{};
65 const std::vector<Json> emptyList{};
66
67 auto entries = data.value("entries", emptyList);
68 for (const auto& entry : entries)
69 {
70 EffecterInfo effecterInfo;
71 effecterInfo.mctpEid = entry.value("mctp_eid", 0xFF);
72 auto jsonEffecterInfo = entry.value("effecter_info", empty);
Patrick Williams6da4f912023-05-10 07:50:53 -050073 auto effecterId = jsonEffecterInfo.value("effecterID",
74 PLDM_INVALID_EFFECTER_ID);
Tom Joseph250c4752020-04-15 10:32:45 +053075 effecterInfo.containerId = jsonEffecterInfo.value("containerID", 0);
76 effecterInfo.entityType = jsonEffecterInfo.value("entityType", 0);
Patrick Williams6da4f912023-05-10 07:50:53 -050077 effecterInfo.entityInstance = jsonEffecterInfo.value("entityInstance",
78 0);
Tom Joseph250c4752020-04-15 10:32:45 +053079 effecterInfo.compEffecterCnt =
80 jsonEffecterInfo.value("compositeEffecterCount", 0);
81 auto effecters = entry.value("effecters", emptyList);
82 for (const auto& effecter : effecters)
83 {
84 DBusEffecterMapping dbusInfo{};
85 auto jsonDbusInfo = effecter.value("dbus_info", empty);
86 dbusInfo.dbusMap.objectPath = jsonDbusInfo.value("object_path", "");
87 dbusInfo.dbusMap.interface = jsonDbusInfo.value("interface", "");
Patrick Williams6da4f912023-05-10 07:50:53 -050088 dbusInfo.dbusMap.propertyName = jsonDbusInfo.value("property_name",
89 "");
90 dbusInfo.dbusMap.propertyType = jsonDbusInfo.value("property_type",
91 "");
Tom Joseph250c4752020-04-15 10:32:45 +053092 Json propertyValues = jsonDbusInfo["property_values"];
93
94 populatePropVals(propertyValues, dbusInfo.propertyValues,
95 dbusInfo.dbusMap.propertyType);
96
97 const std::vector<uint8_t> emptyStates{};
98 auto state = effecter.value("state", empty);
99 dbusInfo.state.stateSetId = state.value("id", 0);
100 auto states = state.value("state_values", emptyStates);
101 if (dbusInfo.propertyValues.size() != states.size())
102 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600103 error(
104 "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",
105 "OBJ_PATH", dbusInfo.dbusMap.objectPath.c_str(),
106 "PROP_NAME", dbusInfo.dbusMap.propertyName);
Tom Joseph250c4752020-04-15 10:32:45 +0530107 continue;
108 }
109 for (const auto& s : states)
110 {
111 dbusInfo.state.states.emplace_back(s);
112 }
113
114 auto effecterInfoIndex = hostEffecterInfo.size();
115 auto dbusInfoIndex = effecterInfo.dbusInfo.size();
116 createHostEffecterMatch(
117 dbusInfo.dbusMap.objectPath, dbusInfo.dbusMap.interface,
118 effecterInfoIndex, dbusInfoIndex, effecterId);
119 effecterInfo.dbusInfo.emplace_back(std::move(dbusInfo));
120 }
121 hostEffecterInfo.emplace_back(std::move(effecterInfo));
122 }
123}
124
125void HostEffecterParser::processHostEffecterChangeNotification(
126 const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
127 size_t dbusInfoIndex, uint16_t effecterId)
128{
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -0600129 using BootProgress =
130 sdbusplus::client::xyz::openbmc_project::state::boot::Progress<>;
131
Tom Joseph250c4752020-04-15 10:32:45 +0530132 const auto& propertyName = hostEffecterInfo[effecterInfoIndex]
133 .dbusInfo[dbusInfoIndex]
134 .dbusMap.propertyName;
135
136 const auto& it = chProperties.find(propertyName);
137
138 if (it == chProperties.end())
139 {
140 return;
141 }
142
143 if (effecterId == PLDM_INVALID_EFFECTER_ID)
144 {
Sampa Misraa4a96162020-07-14 05:33:46 -0500145 constexpr auto localOrRemote = false;
Tom Joseph250c4752020-04-15 10:32:45 +0530146 effecterId = findStateEffecterId(
147 pdrRepo, hostEffecterInfo[effecterInfoIndex].entityType,
148 hostEffecterInfo[effecterInfoIndex].entityInstance,
149 hostEffecterInfo[effecterInfoIndex].containerId,
150 hostEffecterInfo[effecterInfoIndex]
151 .dbusInfo[dbusInfoIndex]
Sampa Misraa4a96162020-07-14 05:33:46 -0500152 .state.stateSetId,
153 localOrRemote);
Tom Joseph250c4752020-04-15 10:32:45 +0530154 if (effecterId == PLDM_INVALID_EFFECTER_ID)
155 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600156 error("Effecter id not found in pdr repo");
Tom Joseph250c4752020-04-15 10:32:45 +0530157 return;
158 }
159 }
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(
Pavithra Barithaya7b4d59a2024-02-05 09:09:30 -0600165 hostStatePath, "BootProgress", BootProgress::interface);
Patrick Williamse4e2e822024-02-07 11:00:52 -0600166
167 using Stages = BootProgress::ProgressStages;
168 auto currHostState = sdbusplus::message::convert_from_string<Stages>(
169 std::get<std::string>(propVal))
170 .value();
171
172 if (currHostState != Stages::SystemInitComplete &&
173 currHostState != Stages::OSRunning &&
174 currHostState != Stages::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}",
Patrick Williamse4e2e822024-02-07 11:00:52 -0600177 "CUR_HOST_STATE", currHostState);
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 {
Patrick Williams6da4f912023-05-10 07:50:53 -0500190 newState = findNewStateValue(effecterInfoIndex, dbusInfoIndex,
191 it->second);
Tom Joseph250c4752020-04-15 10:32:45 +0530192 }
193 catch (const std::out_of_range& e)
194 {
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500195 error("New state not found in json: {ERROR}", "ERROR", e);
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;
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930258 auto instanceId = instanceIdDb->next(mctpEid);
Tom Joseph250c4752020-04-15 10:32:45 +0530259
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);
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930272 instanceIdDb->free(mctpEid, instanceId);
Tom Joseph250c4752020-04-15 10:32:45 +0530273 return rc;
274 }
275
Patrick Williams6da4f912023-05-10 07:50:53 -0500276 auto setStateEffecterStatesRespHandler =
277 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
Riya Dixit49cfb132023-03-02 04:26:53 -0600278 if (response == nullptr || !respMsgLen)
279 {
280 error(
281 "Failed to receive response for setStateEffecterStates command");
282 return;
283 }
284 uint8_t completionCode{};
285 auto rc = decode_set_state_effecter_states_resp(response, respMsgLen,
286 &completionCode);
287 if (rc)
288 {
289 error("Failed to decode setStateEffecterStates response, rc {RC}",
290 "RC", rc);
291 pldm::utils::reportError(
Pavithra Barithayad28f08c2021-12-15 03:37:14 -0600292 "xyz.openbmc_project.PLDM.Error.SetHostEffecterFailed");
Riya Dixit49cfb132023-03-02 04:26:53 -0600293 }
294 if (completionCode)
295 {
296 error("Failed to set a Host effecter, cc = {CC}", "CC",
297 static_cast<unsigned>(completionCode));
298 pldm::utils::reportError(
Pavithra Barithayad28f08c2021-12-15 03:37:14 -0600299 "xyz.openbmc_project.PLDM.Error.SetHostEffecterFailed");
Riya Dixit49cfb132023-03-02 04:26:53 -0600300 }
301 };
Tom Joseph250c4752020-04-15 10:32:45 +0530302
Sampa Misrac0c79482021-06-02 08:01:54 -0500303 rc = handler->registerRequest(
304 mctpEid, instanceId, PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
305 std::move(requestMsg), std::move(setStateEffecterStatesRespHandler));
306 if (rc)
Tom Joseph250c4752020-04-15 10:32:45 +0530307 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600308 error("Failed to send request to set an effecter on Host");
Tom Joseph250c4752020-04-15 10:32:45 +0530309 }
310 return rc;
311}
312
313void HostEffecterParser::createHostEffecterMatch(const std::string& objectPath,
314 const std::string& interface,
315 size_t effecterInfoIndex,
316 size_t dbusInfoIndex,
317 uint16_t effecterId)
318{
319 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -0500320 effecterInfoMatch.emplace_back(std::make_unique<sdbusplus::bus::match_t>(
321 pldm::utils::DBusHandler::getBus(),
322 propertiesChanged(objectPath, interface),
323 [this, effecterInfoIndex, dbusInfoIndex,
324 effecterId](sdbusplus::message_t& msg) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500325 DbusChgHostEffecterProps props;
326 std::string iface;
327 msg.read(iface, props);
328 processHostEffecterChangeNotification(props, effecterInfoIndex,
329 dbusInfoIndex, effecterId);
Patrick Williamsa6756622023-10-20 11:19:15 -0500330 }));
Tom Joseph250c4752020-04-15 10:32:45 +0530331}
332
333} // namespace host_effecters
334} // namespace pldm