Implement a Command To Get PSU Version
Implement an IPMI command to get PSU version.
Tested:
Run ipmitool raw 0x30 0xef
returns: 03 32 01 03 32 01
Signed-off-by: Cheng C Yang <cheng.c.yang@linux.intel.com>
Change-Id: I087b7786b7dd669f5b1eecb8a9bc9647362fd207
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index 8dcb66b..07f6f22 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -3265,6 +3265,109 @@
return ipmi::responseSuccess();
}
+using BasicVariantType =
+ std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
+ int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
+ uint16_t, uint8_t, bool>;
+using PropertyMapType =
+ boost::container::flat_map<std::string, BasicVariantType>;
+static constexpr const std::array<const char*, 1> psuPresenceTypes = {
+ "xyz.openbmc_project.Configuration.PSUPresence"};
+int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
+ std::vector<uint64_t>& addrTable)
+{
+ boost::system::error_code ec;
+ GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
+ ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to set dbus property to cold redundancy");
+ return -1;
+ }
+ for (const auto& object : subtree)
+ {
+ std::string pathName = object.first;
+ for (const auto& serviceIface : object.second)
+ {
+ std::string serviceName = serviceIface.first;
+
+ ec.clear();
+ PropertyMapType propMap =
+ ctx->bus->yield_method_call<PropertyMapType>(
+ ctx->yield, ec, serviceName, pathName,
+ "org.freedesktop.DBus.Properties", "GetAll",
+ "xyz.openbmc_project.Configuration.PSUPresence");
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to set dbus property to cold redundancy");
+ return -1;
+ }
+ auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
+ auto psuAddress =
+ std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
+
+ if (psuBus == nullptr || psuAddress == nullptr)
+ {
+ std::cerr << "error finding necessary "
+ "entry in configuration\n";
+ return -1;
+ }
+ bus = static_cast<uint8_t>(*psuBus);
+ addrTable = *psuAddress;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static const constexpr uint8_t addrOffset = 8;
+static const constexpr uint8_t psuRevision = 0xd9;
+static const constexpr uint8_t defaultPSUBus = 7;
+// Second Minor, Primary Minor, Major
+static const constexpr size_t verLen = 3;
+ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
+{
+ uint8_t bus = defaultPSUBus;
+ std::vector<uint64_t> addrTable;
+ std::vector<uint8_t> result;
+ if (getPSUAddress(ctx, bus, addrTable))
+ {
+ std::cerr << "Failed to get PSU bus and address\n";
+ return ipmi::responseResponseError();
+ }
+
+ for (const auto& slaveAddr : addrTable)
+ {
+ std::vector<uint8_t> writeData = {psuRevision};
+ std::vector<uint8_t> readBuf(verLen);
+ uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
+ std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
+
+ auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
+ if (retI2C != ipmi::ccSuccess)
+ {
+ for (size_t idx = 0; idx < verLen; idx++)
+ {
+ result.emplace_back(0x00);
+ }
+ }
+ else
+ {
+ for (const uint8_t& data : readBuf)
+ {
+ result.emplace_back(data);
+ }
+ }
+ }
+
+ return ipmi::responseSuccess(result);
+}
+
static void registerOEMFunctions(void)
{
phosphor::logging::log<phosphor::logging::level::INFO>(
@@ -3429,6 +3532,10 @@
registerHandler(prioOemBase, netFnChassis, chassis::cmdSetSystemBootOptions,
Privilege::Operator, ipmiOemSetBootOptions);
+
+ registerHandler(prioOemBase, intel::netFnGeneral,
+ intel::general::cmdGetPSUVersion, Privilege::User,
+ ipmiOEMGetPSUVersion);
}
} // namespace ipmi