Support Device information for GetOEMDeviceInformation
Currently, it's support only for BIOS info for GetOEMDeviceInformation
IPMI OEM command; now, add getting Device information for it, it's to
get BMC version and Me version numbers from their DBUS properties.
Tested:
It's tested by IPMI OEM command.
ipmitool raw 0x30 0x27 1 10 0
ipmitool raw 0x30 0x27 2 2 0
Change-Id: I6bb4919c961b11f0b8dc33020f8fd5f4b250354b
Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com>
diff --git a/include/appcommands.hpp b/include/appcommands.hpp
new file mode 100644
index 0000000..95d262d
--- /dev/null
+++ b/include/appcommands.hpp
@@ -0,0 +1,36 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#pragma once
+#include <ipmid/api.hpp>
+namespace ipmi
+{
+
+#pragma pack(push, 1)
+typedef struct
+{
+ std::string platform;
+ uint8_t major;
+ uint8_t minor;
+ uint32_t buildNo;
+ std::string openbmcHash;
+ std::string metaHash;
+} MetaRevision;
+#pragma pack(pop)
+
+extern std::string getActiveSoftwareVersionInfo();
+extern std::optional<MetaRevision> convertIntelVersion(std::string& s);
+} // namespace ipmi
\ No newline at end of file
diff --git a/include/oemcommands.hpp b/include/oemcommands.hpp
index 9612ca5..753fdf3 100644
--- a/include/oemcommands.hpp
+++ b/include/oemcommands.hpp
@@ -301,13 +301,6 @@
uint8_t byteLSB;
};
-struct GetOemDeviceInfoReq
-{
- uint8_t entityType;
- uint8_t countToRead;
- uint8_t offset;
-};
-
struct GetOemDeviceInfoRes
{
uint8_t resDatalen;
diff --git a/src/appcommands.cpp b/src/appcommands.cpp
index ebf95be..5b29fa7 100644
--- a/src/appcommands.cpp
+++ b/src/appcommands.cpp
@@ -15,6 +15,7 @@
*/
#include "xyz/openbmc_project/Common/error.hpp"
+#include <appcommands.hpp>
#include <fstream>
#include <ipmid/api.hpp>
#include <ipmid/utils.hpp>
@@ -40,8 +41,6 @@
constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
constexpr auto bmc_state_property = "CurrentBMCState";
-namespace
-{
static constexpr auto redundancyIntf =
"xyz.openbmc_project.Software.RedundancyPriority";
static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
@@ -161,16 +160,6 @@
return revision;
}
-typedef struct
-{
- std::string platform;
- uint8_t major;
- uint8_t minor;
- uint32_t buildNo;
- std::string openbmcHash;
- std::string metaHash;
-} MetaRevision;
-
// Support both 2 solutions:
// 1.Current solution 2.7.0-dev-533-g14dc00e79-5e7d997
// openbmcTag 2.7.0-dev
@@ -236,7 +225,7 @@
return std::nullopt;
}
-} // namespace
+
RspType<uint8_t, // Device ID
uint8_t, // Device Revision
uint8_t, // Firmware Revision Major
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index 07f6f22..0389c46 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -19,6 +19,7 @@
#include <systemd/sd-journal.h>
+#include <appcommands.hpp>
#include <array>
#include <boost/container/flat_map.hpp>
#include <boost/process/child.hpp>
@@ -33,6 +34,7 @@
#include <nlohmann/json.hpp>
#include <oemcommands.hpp>
#include <phosphor-logging/log.hpp>
+#include <regex>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/message/types.hpp>
#include <string>
@@ -295,37 +297,87 @@
return IPMI_CC_OK;
}
-ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
- ipmi_request_t request,
- ipmi_response_t response,
- ipmi_data_len_t dataLen, ipmi_context_t context)
+bool getSwVerInfo(uint8_t& bmcMajor, uint8_t& bmcMinor, uint8_t& meMajor,
+ uint8_t& meMinor)
{
- GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
- GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
-
- if (*dataLen == 0)
+ // step 1 : get BMC Major and Minor numbers from its DBUS property
+ std::optional<MetaRevision> rev{};
+ try
{
- *dataLen = 0;
- return IPMI_CC_REQ_DATA_LEN_INVALID;
+ std::string version = getActiveSoftwareVersionInfo();
+ rev = convertIntelVersion(version);
+ }
+ catch (const std::exception& e)
+ {
+ return false;
}
- size_t reqDataLen = *dataLen;
- *dataLen = 0;
- if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
+ if (rev.has_value())
{
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ MetaRevision revision = rev.value();
+ bmcMajor = revision.major;
+
+ revision.minor = (revision.minor > 99 ? 99 : revision.minor);
+ bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
+ }
+
+ // step 2 : get ME Major and Minor numbers from its DBUS property
+ try
+ {
+ std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
+ std::string service =
+ getService(*dbus, "xyz.openbmc_project.Software.Version",
+ "/xyz/openbmc_project/me_version");
+ Value variant =
+ getDbusProperty(*dbus, service, "/xyz/openbmc_project/me_version",
+ "xyz.openbmc_project.Software.Version", "Version");
+
+ std::string& meString = std::get<std::string>(variant);
+
+ // get ME major number
+ std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
+ constexpr size_t matchedPhosphor = 6;
+ std::smatch results;
+ if (std::regex_match(meString, results, pattern1))
+ {
+ if (results.size() == matchedPhosphor)
+ {
+ meMajor = static_cast<uint8_t>(std::stoi(results[1]));
+ meMinor = static_cast<uint8_t>(std::stoi(results[2]));
+ }
+ }
+ }
+ catch (sdbusplus::exception::SdBusError& e)
+ {
+ return false;
+ }
+ return true;
+}
+
+ipmi::RspType<
+ std::variant<std::string,
+ std::tuple<uint8_t, std::array<uint8_t, 2>,
+ std::array<uint8_t, 2>, std::array<uint8_t, 2>,
+ std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
+ std::tuple<uint8_t, std::array<uint8_t, 2>>>>
+ ipmiOEMGetDeviceInfo(uint8_t entityType, uint8_t countToRead,
+ uint8_t offset)
+{
+ if (countToRead == 0)
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+
+ if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
+ {
+ return ipmi::responseInvalidFieldRequest();
}
// handle OEM command items
- switch (OEMDevEntityType(req->entityType))
+ switch (OEMDevEntityType(entityType))
{
case OEMDevEntityType::biosId:
{
- if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
- {
- return IPMI_CC_REQ_DATA_LEN_INVALID;
- }
-
std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
std::string service = getService(*dbus, biosIntf, biosObjPath);
try
@@ -333,40 +385,70 @@
Value variant = getDbusProperty(*dbus, service, biosObjPath,
biosIntf, biosProp);
std::string& idString = std::get<std::string>(variant);
- if (req->offset >= idString.size())
+ if (offset >= idString.size())
{
- return IPMI_CC_PARM_OUT_OF_RANGE;
+ return ipmi::responseParmOutOfRange();
}
size_t length = 0;
- if (req->countToRead > (idString.size() - req->offset))
+ if (countToRead > (idString.size() - offset))
{
- length = idString.size() - req->offset;
+ length = idString.size() - offset;
}
else
{
- length = req->countToRead;
+ length = countToRead;
}
- std::copy(idString.begin() + req->offset, idString.end(),
- res->data);
- res->resDatalen = length;
- *dataLen = res->resDatalen + 1;
+
+ std::string readBuf = {0};
+ readBuf.resize(length);
+ std::copy_n(idString.begin() + offset, length,
+ (readBuf.begin()));
+ return ipmi::responseSuccess(readBuf);
}
catch (std::bad_variant_access& e)
{
- phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
}
break;
case OEMDevEntityType::devVer:
+ {
+ constexpr const size_t verLen = 2;
+ constexpr const size_t verTotalLen = 10;
+ std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
+ std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
+ std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
+ std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
+ std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
+ // data0/1: BMC version number; data6/7: ME version number
+ // the others: HSC0/1/2 version number, not avaible.
+ if (true != getSwVerInfo(bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
+ {
+ return ipmi::responseUnspecifiedError();
+ }
+ return ipmi::responseSuccess(
+ std::tuple<
+ uint8_t, std::array<uint8_t, verLen>,
+ std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
+ std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
+ verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
+ }
+ break;
+
case OEMDevEntityType::sdrVer:
- // TODO:
- return IPMI_CC_ILLEGAL_COMMAND;
+ {
+ constexpr const size_t sdrLen = 2;
+ std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
+ return ipmi::responseSuccess(
+ std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
+ readBuf});
+ }
+ break;
+
default:
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ return ipmi::responseInvalidFieldRequest();
}
- return IPMI_CC_OK;
}
ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
@@ -3402,9 +3484,9 @@
ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
- ipmiPrintAndRegister(intel::netFnGeneral,
- intel::general::cmdGetOEMDeviceInfo, NULL,
- ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
+ registerHandler(prioOemBase, intel::netFnGeneral,
+ intel::general::cmdGetOEMDeviceInfo, Privilege::User,
+ ipmiOEMGetDeviceInfo);
ipmiPrintAndRegister(intel::netFnGeneral,
intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,