blob: bc70400a8bf40fddd67d9b3811f3fbc65d541d6c [file] [log] [blame]
Ratan Guptab8e99552017-07-27 07:07:48 +05301#include <arpa/inet.h>
2#include <dirent.h>
Yong Li7dc4ac02019-08-23 17:44:32 +08003#include <fcntl.h>
4#include <linux/i2c-dev.h>
5#include <linux/i2c.h>
Ratan Guptab8e99552017-07-27 07:07:48 +05306#include <net/if.h>
Yong Li7dc4ac02019-08-23 17:44:32 +08007#include <sys/ioctl.h>
8#include <sys/types.h>
9#include <unistd.h>
Ratan Guptab8e99552017-07-27 07:07:48 +053010
Vernon Mauery6a98fe72019-03-11 15:57:48 -070011#include <ipmid/utils.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070012#include <phosphor-logging/elog-errors.hpp>
George Liub4b40912024-07-17 16:14:17 +080013#include <phosphor-logging/lg2.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070014#include <sdbusplus/message/types.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <xyz/openbmc_project/Common/error.hpp>
16
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050017#include <algorithm>
18#include <chrono>
19
Tom Josephbe703f72017-03-09 12:34:35 +053020namespace ipmi
21{
22
Ratan Guptacc8feb42017-07-25 21:52:10 +053023using namespace phosphor::logging;
Willy Tu523e2d12023-09-05 11:36:48 -070024using namespace sdbusplus::error::xyz::openbmc_project::common;
Ratan Guptacc8feb42017-07-25 21:52:10 +053025
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -050026namespace network
27{
28
29/** @brief checks if the given ip is Link Local Ip or not.
Patrick Venture0b02be92018-08-31 11:55:55 -070030 * @param[in] ipaddress - IPAddress.
31 */
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -050032bool isLinkLocalIP(const std::string& ipaddress);
33
Patrick Venture0b02be92018-08-31 11:55:55 -070034} // namespace network
Ratan Guptacc8feb42017-07-25 21:52:10 +053035
Patrick Venture0b02be92018-08-31 11:55:55 -070036// TODO There may be cases where an interface is implemented by multiple
Ratan Guptacc8feb42017-07-25 21:52:10 +053037// objects,to handle such cases we are interested on that object
38// which are on interested busname.
39// Currently mapper doesn't give the readable busname(gives busid) so we can't
40// use busname to find the object,will do later once the support is there.
41
Patrick Williams69b4c282025-03-03 11:19:13 -050042DbusObjectInfo getDbusObject(
43 sdbusplus::bus_t& bus, const std::string& interface,
44 const std::string& serviceRoot, const std::string& match)
Ratan Guptacc8feb42017-07-25 21:52:10 +053045{
46 std::vector<DbusInterface> interfaces;
47 interfaces.emplace_back(interface);
48
George Liu50f186c2024-02-04 16:51:26 +080049 ObjectTree objectTree = getSubTree(bus, interfaces, serviceRoot);
Ratan Guptacc8feb42017-07-25 21:52:10 +053050 if (objectTree.empty())
51 {
George Liub4b40912024-07-17 16:14:17 +080052 lg2::error("No Object has implemented the interface: {INTERFACE}",
53 "INTERFACE", interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +053054 elog<InternalFailure>();
55 }
56
57 DbusObjectInfo objectInfo;
58
59 // if match is empty then return the first object
Patrick Venture0b02be92018-08-31 11:55:55 -070060 if (match == "")
Ratan Guptacc8feb42017-07-25 21:52:10 +053061 {
Patrick Venture0b02be92018-08-31 11:55:55 -070062 objectInfo = std::make_pair(
63 objectTree.begin()->first,
Ratan Guptacc8feb42017-07-25 21:52:10 +053064 std::move(objectTree.begin()->second.begin()->first));
65 return objectInfo;
66 }
67
68 // else search the match string in the object path
Patrick Williams1318a5e2024-08-16 15:19:54 -040069 auto found = std::find_if(
70 objectTree.begin(), objectTree.end(), [&match](const auto& object) {
71 return (object.first.find(match) != std::string::npos);
72 });
Ratan Guptacc8feb42017-07-25 21:52:10 +053073
Patrick Venture2e633522018-10-13 13:51:06 -070074 if (found == objectTree.end())
Ratan Guptacc8feb42017-07-25 21:52:10 +053075 {
George Liub4b40912024-07-17 16:14:17 +080076 lg2::error("Failed to find object which matches: {MATCH}", "MATCH",
77 match);
Ratan Guptacc8feb42017-07-25 21:52:10 +053078 elog<InternalFailure>();
Patrick Venture2e633522018-10-13 13:51:06 -070079 // elog<> throws an exception.
Ratan Guptacc8feb42017-07-25 21:52:10 +053080 }
Patrick Venture2e633522018-10-13 13:51:06 -070081
82 return make_pair(found->first, std::move(found->second.begin()->first));
Ratan Guptacc8feb42017-07-25 21:52:10 +053083}
84
Patrick Williams5d82f472022-07-22 19:26:53 -050085Value getDbusProperty(sdbusplus::bus_t& bus, const std::string& service,
Patrick Venture0b02be92018-08-31 11:55:55 -070086 const std::string& objPath, const std::string& interface,
Kun Yi5dcf41e2019-03-05 14:02:51 -080087 const std::string& property,
88 std::chrono::microseconds timeout)
Ratan Guptacc8feb42017-07-25 21:52:10 +053089{
Ratan Guptacc8feb42017-07-25 21:52:10 +053090 Value value;
91
Patrick Venture0b02be92018-08-31 11:55:55 -070092 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
93 PROP_INTF, METHOD_GET);
Ratan Guptacc8feb42017-07-25 21:52:10 +053094
95 method.append(interface, property);
96
Kun Yi5dcf41e2019-03-05 14:02:51 -080097 auto reply = bus.call(method, timeout.count());
Ratan Guptacc8feb42017-07-25 21:52:10 +053098 reply.read(value);
99
100 return value;
101}
102
Patrick Williams1318a5e2024-08-16 15:19:54 -0400103PropertyMap getAllDbusProperties(
104 sdbusplus::bus_t& bus, const std::string& service,
105 const std::string& objPath, const std::string& interface,
106 std::chrono::microseconds timeout)
Ratan Guptacc8feb42017-07-25 21:52:10 +0530107{
108 PropertyMap properties;
Ratan Guptacc8feb42017-07-25 21:52:10 +0530109
Patrick Venture0b02be92018-08-31 11:55:55 -0700110 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
111 PROP_INTF, METHOD_GET_ALL);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530112
113 method.append(interface);
114
Kun Yi5dcf41e2019-03-05 14:02:51 -0800115 auto reply = bus.call(method, timeout.count());
Ratan Guptacc8feb42017-07-25 21:52:10 +0530116 reply.read(properties);
George Liu3e3cc352023-07-26 15:59:31 +0800117
Ratan Guptacc8feb42017-07-25 21:52:10 +0530118 return properties;
119}
120
Patrick Williams5d82f472022-07-22 19:26:53 -0500121ObjectValueTree getManagedObjects(sdbusplus::bus_t& bus,
Patrick Venture0b02be92018-08-31 11:55:55 -0700122 const std::string& service,
123 const std::string& objPath)
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600124{
125 ipmi::ObjectValueTree interfaces;
126
Patrick Venture0b02be92018-08-31 11:55:55 -0700127 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
128 "org.freedesktop.DBus.ObjectManager",
129 "GetManagedObjects");
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600130 auto reply = bus.call(method);
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600131 reply.read(interfaces);
George Liu3e3cc352023-07-26 15:59:31 +0800132
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600133 return interfaces;
134}
135
Patrick Williams5d82f472022-07-22 19:26:53 -0500136void setDbusProperty(sdbusplus::bus_t& bus, const std::string& service,
Patrick Venture0b02be92018-08-31 11:55:55 -0700137 const std::string& objPath, const std::string& interface,
Kun Yi5dcf41e2019-03-05 14:02:51 -0800138 const std::string& property, const Value& value,
139 std::chrono::microseconds timeout)
Ratan Guptacc8feb42017-07-25 21:52:10 +0530140{
Patrick Venture0b02be92018-08-31 11:55:55 -0700141 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
142 PROP_INTF, METHOD_SET);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530143
144 method.append(interface, property, value);
145
Kun Yi5dcf41e2019-03-05 14:02:51 -0800146 if (!bus.call(method, timeout.count()))
Ratan Guptacc8feb42017-07-25 21:52:10 +0530147 {
George Liub4b40912024-07-17 16:14:17 +0800148 lg2::error("Failed to set {PROPERTY}, path: {PATH}, "
149 "interface: {INTERFACE}",
150 "PROPERTY", property, "PATH", objPath, "INTERFACE",
151 interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530152 elog<InternalFailure>();
153 }
Ratan Guptacc8feb42017-07-25 21:52:10 +0530154}
155
Patrick Venture0b02be92018-08-31 11:55:55 -0700156ServiceCache::ServiceCache(const std::string& intf, const std::string& path) :
Vernon Mauery54012502018-11-07 10:17:31 -0800157 intf(intf), path(path), cachedService(std::nullopt),
158 cachedBusName(std::nullopt)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500159{}
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700160
Patrick Venture0b02be92018-08-31 11:55:55 -0700161ServiceCache::ServiceCache(std::string&& intf, std::string&& path) :
Vernon Mauery54012502018-11-07 10:17:31 -0800162 intf(std::move(intf)), path(std::move(path)), cachedService(std::nullopt),
163 cachedBusName(std::nullopt)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500164{}
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700165
Patrick Williams5d82f472022-07-22 19:26:53 -0500166const std::string& ServiceCache::getService(sdbusplus::bus_t& bus)
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700167{
168 if (!isValid(bus))
169 {
170 cachedBusName = bus.get_unique_name();
171 cachedService = ::ipmi::getService(bus, intf, path);
172 }
Jayanth Othayoth195d5522025-06-07 02:28:07 -0500173
174 if (!cachedService)
175 {
176 throw std::runtime_error("Service not cached");
177 }
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700178 return cachedService.value();
179}
180
181void ServiceCache::invalidate()
182{
Vernon Mauery54012502018-11-07 10:17:31 -0800183 cachedBusName = std::nullopt;
184 cachedService = std::nullopt;
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700185}
186
Patrick Williams1318a5e2024-08-16 15:19:54 -0400187sdbusplus::message_t ServiceCache::newMethodCall(
188 sdbusplus::bus_t& bus, const char* intf, const char* method)
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700189{
Patrick Venture0b02be92018-08-31 11:55:55 -0700190 return bus.new_method_call(getService(bus).c_str(), path.c_str(), intf,
191 method);
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700192}
193
Patrick Williams5d82f472022-07-22 19:26:53 -0500194bool ServiceCache::isValid(sdbusplus::bus_t& bus) const
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700195{
196 return cachedService && cachedBusName == bus.get_unique_name();
197}
198
Patrick Williams5d82f472022-07-22 19:26:53 -0500199std::string getService(sdbusplus::bus_t& bus, const std::string& intf,
Tom Josephbe703f72017-03-09 12:34:35 +0530200 const std::string& path)
201{
Patrick Williams1318a5e2024-08-16 15:19:54 -0400202 auto mapperCall =
203 bus.new_method_call("xyz.openbmc_project.ObjectMapper",
204 "/xyz/openbmc_project/object_mapper",
205 "xyz.openbmc_project.ObjectMapper", "GetObject");
Tom Josephbe703f72017-03-09 12:34:35 +0530206
207 mapperCall.append(path);
208 mapperCall.append(std::vector<std::string>({intf}));
209
210 auto mapperResponseMsg = bus.call(mapperCall);
211
Tom Josephbe703f72017-03-09 12:34:35 +0530212 std::map<std::string, std::vector<std::string>> mapperResponse;
213 mapperResponseMsg.read(mapperResponse);
214
215 if (mapperResponse.begin() == mapperResponse.end())
216 {
217 throw std::runtime_error("ERROR in reading the mapper response");
218 }
219
220 return mapperResponse.begin()->first;
221}
222
George Liu50f186c2024-02-04 16:51:26 +0800223ObjectTree getSubTree(sdbusplus::bus_t& bus, const InterfaceList& interfaces,
224 const std::string& subtreePath, int32_t depth)
225{
226 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ,
227 MAPPER_INTF, "GetSubTree");
228
229 mapperCall.append(subtreePath, depth, interfaces);
230
231 auto mapperReply = bus.call(mapperCall);
232 ObjectTree objectTree;
233 mapperReply.read(objectTree);
234
235 return objectTree;
236}
237
Patrick Williams69b4c282025-03-03 11:19:13 -0500238ipmi::ObjectTree getAllDbusObjects(
239 sdbusplus::bus_t& bus, const std::string& serviceRoot,
240 const std::string& interface, const std::string& match)
Ratan Guptab8e99552017-07-27 07:07:48 +0530241{
242 std::vector<std::string> interfaces;
243 interfaces.emplace_back(interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530244
George Liu50f186c2024-02-04 16:51:26 +0800245 ObjectTree objectTree = getSubTree(bus, interfaces, serviceRoot);
Ratan Guptab8e99552017-07-27 07:07:48 +0530246 for (auto it = objectTree.begin(); it != objectTree.end();)
247 {
248 if (it->first.find(match) == std::string::npos)
249 {
250 it = objectTree.erase(it);
251 }
252 else
253 {
254 ++it;
255 }
256 }
257
258 return objectTree;
259}
260
Ratan Guptab8e99552017-07-27 07:07:48 +0530261namespace method_no_args
262{
263
Patrick Williams5d82f472022-07-22 19:26:53 -0500264void callDbusMethod(sdbusplus::bus_t& bus, const std::string& service,
Patrick Venture0b02be92018-08-31 11:55:55 -0700265 const std::string& objPath, const std::string& interface,
Ratan Guptab8e99552017-07-27 07:07:48 +0530266 const std::string& method)
267
268{
Patrick Venture0b02be92018-08-31 11:55:55 -0700269 auto busMethod = bus.new_method_call(service.c_str(), objPath.c_str(),
270 interface.c_str(), method.c_str());
Ratan Guptab8e99552017-07-27 07:07:48 +0530271 auto reply = bus.call(busMethod);
Ratan Guptab8e99552017-07-27 07:07:48 +0530272}
273
Patrick Venture0b02be92018-08-31 11:55:55 -0700274} // namespace method_no_args
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700275
276/********* Begin co-routine yielding alternatives ***************/
277
Patrick Williams69b4c282025-03-03 11:19:13 -0500278boost::system::error_code getService(Context::ptr ctx, const std::string& intf,
279 const std::string& path,
280 std::string& service)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700281{
282 boost::system::error_code ec;
283 std::map<std::string, std::vector<std::string>> mapperResponse =
284 ctx->bus->yield_method_call<decltype(mapperResponse)>(
285 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
286 "/xyz/openbmc_project/object_mapper",
Jason M. Billsf5967982020-03-06 10:42:08 -0800287 "xyz.openbmc_project.ObjectMapper", "GetObject", path,
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700288 std::vector<std::string>({intf}));
289
290 if (!ec)
291 {
292 service = std::move(mapperResponse.begin()->first);
293 }
294 return ec;
295}
296
Patrick Williams1318a5e2024-08-16 15:19:54 -0400297boost::system::error_code getSubTree(
298 Context::ptr ctx, const InterfaceList& interfaces,
299 const std::string& subtreePath, int32_t depth, ObjectTree& objectTree)
George Liu50f186c2024-02-04 16:51:26 +0800300{
301 boost::system::error_code ec;
302 objectTree = ctx->bus->yield_method_call<ObjectTree>(
303 ctx->yield, ec, MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF, "GetSubTree",
304 subtreePath, depth, interfaces);
305
306 return ec;
307}
308
Patrick Williams69b4c282025-03-03 11:19:13 -0500309boost::system::error_code getDbusObject(
310 Context::ptr ctx, const std::string& interface,
311 const std::string& subtreePath, const std::string& match,
312 DbusObjectInfo& dbusObject)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700313{
314 std::vector<DbusInterface> interfaces;
315 interfaces.emplace_back(interface);
316
317 auto depth = 0;
George Liu50f186c2024-02-04 16:51:26 +0800318 ObjectTree objectTree;
Patrick Williams1318a5e2024-08-16 15:19:54 -0400319 boost::system::error_code ec =
320 getSubTree(ctx, interfaces, subtreePath, depth, objectTree);
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700321
322 if (ec)
323 {
324 return ec;
325 }
326
327 if (objectTree.empty())
328 {
George Liub4b40912024-07-17 16:14:17 +0800329 lg2::error("No Object has implemented the interface: {INTERFACE}, "
330 "NetFn: {NETFN}, Cmd: {CMD}",
331 "INTERFACE", interface, "NETFN", lg2::hex, ctx->netFn, "CMD",
332 lg2::hex, ctx->cmd);
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700333 return boost::system::errc::make_error_code(
334 boost::system::errc::no_such_process);
335 }
336
337 // if match is empty then return the first object
338 if (match == "")
339 {
340 dbusObject = std::make_pair(
341 std::move(objectTree.begin()->first),
342 std::move(objectTree.begin()->second.begin()->first));
343 return ec;
344 }
345
346 // else search the match string in the object path
Patrick Williams1318a5e2024-08-16 15:19:54 -0400347 auto found = std::find_if(
348 objectTree.begin(), objectTree.end(), [&match](const auto& object) {
349 return (object.first.find(match) != std::string::npos);
350 });
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700351
352 if (found == objectTree.end())
353 {
George Liub4b40912024-07-17 16:14:17 +0800354 lg2::error("Failed to find object which matches: {MATCH}, "
355 "NetFn: {NETFN}, Cmd: {CMD}",
356 "MATCH", match, "NETFN", lg2::hex, ctx->netFn, "CMD",
357 lg2::hex, ctx->cmd);
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700358 // set ec
359 return boost::system::errc::make_error_code(
360 boost::system::errc::no_such_file_or_directory);
361 }
362
363 dbusObject = std::make_pair(std::move(found->first),
364 std::move(found->second.begin()->first));
365 return ec;
366}
367
Patrick Williams1318a5e2024-08-16 15:19:54 -0400368boost::system::error_code getAllDbusProperties(
369 Context::ptr ctx, const std::string& service, const std::string& objPath,
370 const std::string& interface, PropertyMap& properties)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700371{
372 boost::system::error_code ec;
373 properties = ctx->bus->yield_method_call<PropertyMap>(
374 ctx->yield, ec, service.c_str(), objPath.c_str(), PROP_INTF,
375 METHOD_GET_ALL, interface);
376 return ec;
377}
378
Patrick Williams69b4c282025-03-03 11:19:13 -0500379boost::system::error_code setDbusProperty(
380 Context::ptr ctx, const std::string& service, const std::string& objPath,
381 const std::string& interface, const std::string& property,
382 const Value& value)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700383{
384 boost::system::error_code ec;
385 ctx->bus->yield_method_call(ctx->yield, ec, service.c_str(),
386 objPath.c_str(), PROP_INTF, METHOD_SET,
387 interface, property, value);
388 return ec;
389}
390
Patrick Williams69b4c282025-03-03 11:19:13 -0500391boost::system::error_code getAllDbusObjects(
392 Context::ptr ctx, const std::string& serviceRoot,
393 const std::string& interface, const std::string& match,
394 ObjectTree& objectTree)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700395{
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700396 std::vector<std::string> interfaces;
397 interfaces.emplace_back(interface);
398
399 auto depth = 0;
Patrick Williams1318a5e2024-08-16 15:19:54 -0400400 boost::system::error_code ec =
401 getSubTree(ctx, interfaces, serviceRoot, depth, objectTree);
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700402 if (ec)
403 {
404 return ec;
405 }
406
407 for (auto it = objectTree.begin(); it != objectTree.end();)
408 {
409 if (it->first.find(match) == std::string::npos)
410 {
411 it = objectTree.erase(it);
412 }
413 else
414 {
415 ++it;
416 }
417 }
418
419 return ec;
420}
421
Patrick Williams69b4c282025-03-03 11:19:13 -0500422boost::system::error_code getManagedObjects(
423 Context::ptr ctx, const std::string& service, const std::string& objPath,
424 ObjectValueTree& objects)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700425{
426 boost::system::error_code ec;
427 objects = ctx->bus->yield_method_call<ipmi::ObjectValueTree>(
428 ctx->yield, ec, service.c_str(), objPath.c_str(),
429 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
430 return ec;
431}
432
Patrick Williams1318a5e2024-08-16 15:19:54 -0400433boost::system::error_code callDbusMethod(
434 Context::ptr ctx, const std::string& service, const std::string& objPath,
435 const std::string& interface, const std::string& method)
Albert Zhangb53049e2022-04-02 15:39:51 +0800436{
437 boost::system::error_code ec;
438 ctx->bus->yield_method_call(ctx->yield, ec, service, objPath, interface,
439 method);
440 return ec;
441}
442
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700443/********* End co-routine yielding alternatives ***************/
444
Matt Simmering68d9d402023-11-09 14:22:11 -0800445ipmi::Cc i2cWriteRead(std::string i2cBus, const uint8_t targetAddr,
Yong Li7dc4ac02019-08-23 17:44:32 +0800446 std::vector<uint8_t> writeData,
447 std::vector<uint8_t>& readBuf)
448{
449 // Open the i2c device, for low-level combined data write/read
450 int i2cDev = ::open(i2cBus.c_str(), O_RDWR | O_CLOEXEC);
451 if (i2cDev < 0)
452 {
George Liub4b40912024-07-17 16:14:17 +0800453 lg2::error("Failed to open i2c bus: {BUS}", "BUS", i2cBus);
Yong Li7dc4ac02019-08-23 17:44:32 +0800454 return ipmi::ccInvalidFieldRequest;
455 }
456
457 const size_t writeCount = writeData.size();
458 const size_t readCount = readBuf.size();
459 int msgCount = 0;
Willy Tu11d68892022-01-20 10:37:34 -0800460 i2c_msg i2cmsg[2] = {};
Yong Li7dc4ac02019-08-23 17:44:32 +0800461 if (writeCount)
462 {
Matt Simmering68d9d402023-11-09 14:22:11 -0800463 // Data will be writtern to the target address
464 i2cmsg[msgCount].addr = targetAddr;
Yong Li7dc4ac02019-08-23 17:44:32 +0800465 i2cmsg[msgCount].flags = 0x00;
466 i2cmsg[msgCount].len = writeCount;
467 i2cmsg[msgCount].buf = writeData.data();
468 msgCount++;
469 }
470 if (readCount)
471 {
Matt Simmering68d9d402023-11-09 14:22:11 -0800472 // Data will be read into the buffer from the target address
473 i2cmsg[msgCount].addr = targetAddr;
Yong Li7dc4ac02019-08-23 17:44:32 +0800474 i2cmsg[msgCount].flags = I2C_M_RD;
475 i2cmsg[msgCount].len = readCount;
476 i2cmsg[msgCount].buf = readBuf.data();
477 msgCount++;
478 }
479
Willy Tu11d68892022-01-20 10:37:34 -0800480 i2c_rdwr_ioctl_data msgReadWrite = {};
Yong Li7dc4ac02019-08-23 17:44:32 +0800481 msgReadWrite.msgs = i2cmsg;
482 msgReadWrite.nmsgs = msgCount;
483
484 // Perform the combined write/read
485 int ret = ::ioctl(i2cDev, I2C_RDWR, &msgReadWrite);
486 ::close(i2cDev);
487
488 if (ret < 0)
489 {
George Liub4b40912024-07-17 16:14:17 +0800490 lg2::error("I2C WR Failed! {RET}", "RET", ret);
Yong Li7dc4ac02019-08-23 17:44:32 +0800491 return ipmi::ccUnspecifiedError;
492 }
493 if (readCount)
494 {
495 readBuf.resize(msgReadWrite.msgs[msgCount - 1].len);
496 }
497
498 return ipmi::ccSuccess;
499}
500
Tom Josephbe703f72017-03-09 12:34:35 +0530501} // namespace ipmi