Add OEM IPMI commands to query node ID and node presence
These OEM IPMI commands are used on multi-node platform to query
info such as node ID, multi-node presence, node role.
Tested:
ipmitool raw 0x30 0x36 // Get multiNodeId
ipmitool raw 0x30 0x63 // Get multiNodePresence
ipmitool raw 0x30 0x33 // Get multiNodeRole
Change-Id: I54a78bb2ed37cf71770c7b9f7e3124f530fa9246
Signed-off-by: Qiang XU <qiang.xu@linux.intel.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 891e1d3..ac4388a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -79,7 +79,7 @@
add_library (
zinteloemcmds SHARED src/oemcommands.cpp src/sensorcommands.cpp
- src/storagecommands.cpp
+ src/storagecommands.cpp src/multinodecommands.cpp
)
set_target_properties (zinteloemcmds PROPERTIES VERSION "0.1.0")
set_target_properties (zinteloemcmds PROPERTIES SOVERSION "0")
diff --git a/include/multinodecommands.hpp b/include/multinodecommands.hpp
new file mode 100644
index 0000000..a7ec989
--- /dev/null
+++ b/include/multinodecommands.hpp
@@ -0,0 +1,37 @@
+/*
+// 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
+
+enum class IPMINetfnMultiNodeCmd
+{
+ cmdGetMultiNodeRole = 0x33,
+ cmdGetMultiNodeId = 0x36,
+ cmdGetMultiNodePresence = 0x63,
+};
+
+static constexpr const char* multiNodeObjPath =
+ "/xyz/openbmc_project/MultiNode/Status";
+static constexpr const char* multiNodeIntf =
+ "xyz.openbmc_project.Chassis.MultiNode";
+
+enum class NodeRole : uint8_t
+{
+ single,
+ master,
+ slave,
+ arbitrating
+};
diff --git a/src/multinodecommands.cpp b/src/multinodecommands.cpp
new file mode 100644
index 0000000..7e79fc0
--- /dev/null
+++ b/src/multinodecommands.cpp
@@ -0,0 +1,135 @@
+/*
+// 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.
+*/
+
+#include <ipmid/api.hpp>
+#include <ipmid/utils.hpp>
+#include <multinodecommands.hpp>
+#include <oemcommands.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/message/types.hpp>
+#include <string>
+
+namespace ipmi
+{
+void registerMultiNodeFunctions() __attribute__((constructor));
+
+std::optional<uint8_t> getMultiNodeInfo(std::string name)
+{
+ auto pdbus = getSdBus();
+ try
+ {
+ std::string service =
+ getService(*pdbus, multiNodeIntf, multiNodeObjPath);
+ Value dbusValue = getDbusProperty(*pdbus, service, multiNodeObjPath,
+ multiNodeIntf, name);
+ return std::get<uint8_t>(dbusValue);
+ }
+ catch (const std::exception& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "getMultiNodeInfo: can't get multi node info from dbus!",
+ phosphor::logging::entry("ERR=%s", e.what()));
+ return std::nullopt;
+ }
+}
+
+std::optional<uint8_t> getMultiNodeRole()
+{
+ auto pdbus = getSdBus();
+ try
+ {
+ std::string service =
+ getService(*pdbus, multiNodeIntf, multiNodeObjPath);
+ Value dbusValue = getDbusProperty(*pdbus, service, multiNodeObjPath,
+ multiNodeIntf, "NodeRole");
+ std::string valueStr = std::get<std::string>(dbusValue);
+ uint8_t value;
+ if (valueStr == "single")
+ value = static_cast<uint8_t>(NodeRole::single);
+ else if (valueStr == "master")
+ value = static_cast<uint8_t>(NodeRole::master);
+ else if (valueStr == "slave")
+ value = static_cast<uint8_t>(NodeRole::slave);
+ else if (valueStr == "arbitrating")
+ value = static_cast<uint8_t>(NodeRole::arbitrating);
+ return value;
+ }
+ catch (const std::exception& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "getMultiNodeRole: can't get multi node role from dbus!",
+ phosphor::logging::entry("ERR=%s", e.what()));
+ return std::nullopt;
+ }
+}
+
+ipmi::RspType<uint8_t> ipmiGetMultiNodePresence()
+
+{
+ std::optional<uint8_t> nodeInfo = getMultiNodeInfo("NodePresence");
+ if (!nodeInfo)
+ {
+ return ipmi::responseResponseError();
+ }
+
+ return ipmi::responseSuccess(*nodeInfo);
+}
+
+ipmi::RspType<uint8_t> ipmiGetMultiNodeId()
+{
+ std::optional<uint8_t> nodeInfo = getMultiNodeInfo("NodeId");
+ if (!nodeInfo)
+ {
+ return ipmi::responseResponseError();
+ }
+
+ return ipmi::responseSuccess(*nodeInfo);
+}
+
+ipmi::RspType<uint8_t> ipmiGetMultiNodeRole()
+{
+ std::optional<uint8_t> nodeInfo = getMultiNodeRole();
+ if (!nodeInfo)
+ {
+ return ipmi::responseResponseError();
+ }
+
+ return ipmi::responseSuccess(*nodeInfo);
+}
+
+void registerMultiNodeFunctions(void)
+{
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Registering MultiNode commands");
+
+ ipmi::registerHandler(
+ ipmi::prioOemBase, ipmi::netFnOemOne,
+ static_cast<ipmi::Cmd>(IPMINetfnMultiNodeCmd::cmdGetMultiNodePresence),
+ ipmi::Privilege::User, ipmiGetMultiNodePresence);
+
+ ipmi::registerHandler(
+ ipmi::prioOemBase, ipmi::netFnOemOne,
+ static_cast<ipmi::Cmd>(IPMINetfnMultiNodeCmd::cmdGetMultiNodeId),
+ ipmi::Privilege::User, ipmiGetMultiNodeId);
+
+ ipmi::registerHandler(
+ ipmi::prioOemBase, ipmi::netFnOemOne,
+ static_cast<ipmi::Cmd>(IPMINetfnMultiNodeCmd::cmdGetMultiNodeRole),
+ ipmi::Privilege::User, ipmiGetMultiNodeRole);
+}
+
+} // namespace ipmi