Add Intel-specific IPMI sensor commands
Also includes SDR storage commands that are required to support
the 'ipmitool sensor list' command.
Change-Id: Id1830097d93882114085fce723f0b92367b2db48
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
diff --git a/include/commandutils.hpp b/include/commandutils.hpp
new file mode 100644
index 0000000..e296015
--- /dev/null
+++ b/include/commandutils.hpp
@@ -0,0 +1,55 @@
+/*
+// Copyright (c) 2017 2018 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 <iostream>
+#include <sdbusplus/bus.hpp>
+
+static constexpr bool debug = false;
+
+inline static void printRegistration(unsigned int netfn, unsigned int cmd)
+{
+ if constexpr (debug)
+ {
+ std::cout << "Registering NetFn:[0x" << std::hex << std::uppercase
+ << netfn << "], Cmd:[0x" << cmd << "]\n";
+ }
+}
+
+inline static void ipmiPrintAndRegister(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_context_t context,
+ ipmid_callback_t handler,
+ ipmi_cmd_privilege_t priv)
+{
+ printRegistration(netfn, cmd);
+ ipmi_register_callback(netfn, cmd, context, handler, priv);
+}
+
+inline static void printCommand(unsigned int netfn, unsigned int cmd)
+{
+ if constexpr (debug)
+ {
+ std::cout << "Executing NetFn:[0x" << std::hex << std::uppercase
+ << netfn << "], Cmd:[0x" << cmd << "]\n";
+ }
+}
+
+namespace ipmi
+{
+using DbusVariant =
+ sdbusplus::message::variant<std::string, bool, uint8_t, uint16_t, int16_t,
+ uint32_t, int32_t, uint64_t, int64_t, double>;
+} // namespace ipmi
diff --git a/include/sdrutils.hpp b/include/sdrutils.hpp
new file mode 100644
index 0000000..8b93e9b
--- /dev/null
+++ b/include/sdrutils.hpp
@@ -0,0 +1,165 @@
+/*
+// Copyright (c) 2018 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 <boost/algorithm/string.hpp>
+#include <boost/container/flat_map.hpp>
+#include <cstring>
+#include <phosphor-logging/log.hpp>
+#include <storagecommands.hpp>
+
+#pragma once
+
+struct CmpStrVersion
+{
+ bool operator()(std::string a, std::string b) const
+ {
+ return strverscmp(a.c_str(), b.c_str()) < 0;
+ }
+};
+
+using SensorSubTree = boost::container::flat_map<
+ std::string,
+ boost::container::flat_map<std::string, std::vector<std::string>>,
+ CmpStrVersion>;
+
+inline static bool getSensorSubtree(SensorSubTree& subtree)
+{
+ sd_bus* bus = NULL;
+ int ret = sd_bus_default_system(&bus);
+ if (ret < 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to connect to system bus",
+ phosphor::logging::entry("ERRNO=0x%X", -ret));
+ sd_bus_unref(bus);
+ return false;
+ }
+ sdbusplus::bus::bus dbus(bus);
+ auto mapperCall =
+ dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree");
+ static const auto depth = 2;
+ static constexpr std::array<const char*, 3> interfaces = {
+ "xyz.openbmc_project.Sensor.Value",
+ "xyz.openbmc_project.Sensor.Threshold.Warning",
+ "xyz.openbmc_project.Sensor.Threshold.Critical"};
+ mapperCall.append("/xyz/openbmc_project/sensors", depth, interfaces);
+
+ try
+ {
+ auto mapperReply = dbus.call(mapperCall);
+ subtree.clear();
+ mapperReply.read(subtree);
+ }
+ catch (sdbusplus::exception_t&)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "getSensorSubtree: Error calling mapper");
+ return false;
+ }
+ return true;
+}
+
+struct CmpStr
+{
+ bool operator()(const char* a, const char* b) const
+ {
+ return std::strcmp(a, b) < 0;
+ }
+};
+
+const static boost::container::flat_map<const char*, SensorTypeCodes, CmpStr>
+ sensorTypes{{{"temperature", SensorTypeCodes::temperature},
+ {"voltage", SensorTypeCodes::voltage},
+ {"current", SensorTypeCodes::current},
+ {"fan_tach", SensorTypeCodes::fan},
+ {"power", SensorTypeCodes::other}}};
+
+inline static std::string getSensorTypeStringFromPath(const std::string& path)
+{
+ // get sensor type string from path, path is defined as
+ // /xyz/openbmc_project/sensors/<type>/label
+ size_t typeEnd = path.rfind("/");
+ size_t typeStart = path.rfind("/", typeEnd - 1);
+ if (typeEnd != std::string::npos && typeStart != std::string::npos)
+ {
+ return path.substr(typeStart + 1, typeEnd - typeStart);
+ }
+ return path;
+}
+
+inline static uint8_t getSensorTypeFromPath(const std::string& path)
+{
+ uint8_t sensorType = 0;
+ std::string type = getSensorTypeStringFromPath(path);
+ auto findSensor = sensorTypes.find(type.c_str());
+ if (findSensor != sensorTypes.end())
+ {
+ sensorType = static_cast<uint8_t>(findSensor->second);
+ } // else default 0x0 RESERVED
+
+ return sensorType;
+}
+
+inline static uint8_t getSensorNumberFromPath(const std::string& path)
+{
+ SensorSubTree sensorTree;
+ if (!getSensorSubtree(sensorTree))
+ return 0xFF;
+ uint8_t sensorNum = 0xFF;
+
+ for (const auto& sensor : sensorTree)
+ {
+ sensorNum++;
+ if (sensor.first == path)
+ {
+ break;
+ }
+ }
+ return sensorNum;
+}
+
+inline static uint8_t getSensorEventTypeFromPath(const std::string& path)
+{
+ // TODO: Add support for additional reading types as needed
+ return 0x1; // reading type = threshold
+}
+
+inline static std::string getPathFromSensorNumber(uint8_t sensorNum)
+{
+ SensorSubTree sensorTree;
+ std::string path;
+ if (!getSensorSubtree(sensorTree))
+ return path;
+
+ if (sensorTree.size() < sensorNum)
+ {
+ return path;
+ }
+
+ uint8_t sensorIndex = sensorNum;
+ for (const auto& sensor : sensorTree)
+ {
+ if (sensorIndex-- == 0)
+ {
+ path = sensor.first;
+ break;
+ }
+ }
+
+ return path;
+}
diff --git a/include/sensorcommands.hpp b/include/sensorcommands.hpp
new file mode 100644
index 0000000..691fb11
--- /dev/null
+++ b/include/sensorcommands.hpp
@@ -0,0 +1,134 @@
+/*
+// Copyright (c) 2017 2018 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 <cstdint>
+
+#pragma pack(push, 1)
+struct SensorReadingResp
+{
+ uint8_t value;
+ uint8_t operation;
+ uint8_t indication[2];
+};
+
+struct SensorThresholdResp
+{
+ uint8_t readable;
+ uint8_t lowernc;
+ uint8_t lowercritical;
+ uint8_t lowernonrecoverable;
+ uint8_t uppernc;
+ uint8_t uppercritical;
+ uint8_t uppernonrecoverable;
+};
+
+struct SensorThresholdReq
+{
+ uint8_t sensorNum;
+ uint8_t mask;
+ uint8_t lowerNonCritical;
+ uint8_t lowerCritical;
+ uint8_t lowerNonRecoverable;
+ uint8_t upperNonCritical;
+ uint8_t upperCritical;
+ uint8_t upperNonRecoverable;
+};
+#pragma pack(pop)
+
+enum class SensorThresholdReqEnable : uint8_t
+{
+ setLowerNonCritical = 0x1,
+ setLowerCritical = 0x2,
+ setLowerNonRecoverable = 0x4,
+ setUpperNonCritical = 0x8,
+ setUpperCritical = 0x10,
+ setUpperNonRecoverable = 0x20
+};
+
+#pragma pack(push, 1)
+struct SensorEventEnableResp
+{
+ uint8_t enabled;
+ uint8_t assertionEnabledLSB;
+ uint8_t assertionEnabledMSB;
+ uint8_t deassertionEnabledLSB;
+ uint8_t deassertionEnabledMSB;
+};
+
+struct SensorEventStatusResp
+{
+ uint8_t enabled;
+ uint8_t assertionsLSB;
+ uint8_t assertionsMSB;
+ // deassertion events currently not supported
+ // uint8_t deassertionsLSB;
+ // uint8_t deassertionsMSB;
+};
+#pragma pack(pop)
+
+enum class IPMIhresholdRespBits
+{
+ lowerNonCritical,
+ lowerCritical,
+ lowerNonRecoverable,
+ upperNonCritical,
+ upperCritical,
+ upperNonRecoverable
+};
+
+enum class IPMISensorReadingByte2 : uint8_t
+{
+ eventMessagesEnable = (1 << 7),
+ sensorScanningEnable = (1 << 6),
+ readingStateUnavailable = (1 << 5),
+};
+
+enum class IPMISensorEventEnableByte2 : uint8_t
+{
+ eventMessagesEnable = (1 << 7),
+ sensorScanningEnable = (1 << 6),
+};
+
+enum class IPMISensorEventEnableThresholds : uint8_t
+{
+ upperNonRecoverableGoingHigh = (1 << 3),
+ upperNonRecoverableGoingLow = (1 << 2),
+ upperCriticalGoingHigh = (1 << 1),
+ upperCriticalGoingLow = (1 << 0),
+ upperNonCriticalGoingHigh = (1 << 7),
+ upperNonCriticalGoingLow = (1 << 6),
+ lowerNonRecoverableGoingHigh = (1 << 5),
+ lowerNonRecoverableGoingLow = (1 << 4),
+ lowerCriticalGoingHigh = (1 << 3),
+ lowerCriticalGoingLow = (1 << 2),
+ lowerNonCriticalGoingHigh = (1 << 1),
+ lowerNonCriticalGoingLow = (1 << 0),
+};
+
+enum class IPMINetfnSensorCmds : ipmi_cmd_t
+{
+ ipmiCmdGetDeviceSDRInfo = 0x20,
+ ipmiCmdGetDeviceSDR = 0x21,
+ ipmiCmdReserveDeviceSDRRepo = 0x22,
+ ipmiCmdGetSensorThreshold = 0x27,
+ ipmiCmdSetSensorThreshold = 0x28,
+ ipmiCmdGetSensorEventEnable = 0x29,
+ ipmiCmdGetSensorEventStatus = 0x2B,
+ ipmiCmdGetSensorReading = 0x2D,
+ ipmiCmdGetSensorType = 0x2F,
+ ipmiCmdSetSensorReadingAndEventStatus = 0x30,
+};
diff --git a/include/sensorutils.hpp b/include/sensorutils.hpp
new file mode 100644
index 0000000..7295a4b
--- /dev/null
+++ b/include/sensorutils.hpp
@@ -0,0 +1,28 @@
+/*
+// Copyright (c) 2017 2018 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 <cstdint>
+
+namespace ipmi
+{
+bool getSensorAttributes(const double maxValue, const double minValue,
+ int16_t &mValue, int8_t &rExp, int16_t &bValue,
+ int8_t &bExp, bool &bSigned);
+uint8_t scaleIPMIValueFromDouble(const double value, const uint16_t mValue,
+ const int8_t rExp, const uint16_t bValue,
+ const int8_t bExp, const bool bSigned);
+} // namespace ipmi
\ No newline at end of file
diff --git a/include/storagecommands.hpp b/include/storagecommands.hpp
new file mode 100644
index 0000000..ef32c74
--- /dev/null
+++ b/include/storagecommands.hpp
@@ -0,0 +1,118 @@
+/*
+// Copyright (c) 2017 2018 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 <cstdint>
+#include <phosphor-ipmi-host/sensorhandler.hpp>
+
+static constexpr uint8_t ipmiSdrVersion = 0x51;
+
+#pragma pack(push, 1)
+struct GetSDRInfoResp
+{
+ uint8_t sdrVersion;
+ uint8_t recordCountLS;
+ uint8_t recordCountMS;
+ uint8_t freeSpace[2];
+ uint32_t mostRecentAddition;
+ uint32_t mostRecentErase;
+ uint8_t operationSupport;
+};
+
+struct GetSDRReq
+{
+ uint16_t reservationID;
+ uint16_t recordID;
+ uint8_t offset;
+ uint8_t bytesToRead;
+};
+#pragma pack(pop)
+
+enum class SdrRepositoryInfoOps : uint8_t
+{
+ allocCommandSupported = 0x1,
+ reserveSDRRepositoryCommandSupported = 0x2,
+ partialAddSDRSupported = 0x4,
+ deleteSDRSupported = 0x8,
+ reserved = 0x10,
+ modalLSB = 0x20,
+ modalMSB = 0x40,
+ overflow = 0x80
+};
+
+#pragma pack(push, 1)
+struct GetAllocInfoResp
+{
+ uint8_t allocUnitsLSB;
+ uint8_t allocUnitsMSB;
+ uint8_t allocUnitSizeLSB;
+ uint8_t allocUnitSizeMSB;
+ uint8_t allocUnitFreeLSB;
+ uint8_t allocUnitFreeMSB;
+ uint8_t allocUnitLargestFreeLSB;
+ uint8_t allocUnitLargestFreeMSB;
+ uint8_t maxRecordSize;
+};
+#pragma pack(pop)
+
+enum class SensorTypeCodes : uint8_t
+{
+ reserved = 0x0,
+ temperature = 0x1,
+ voltage = 0x2,
+ current = 0x3,
+ fan = 0x4,
+ other = 0xB,
+};
+
+enum class SensorUnits : uint8_t
+{
+ unspecified = 0x0,
+ degreesC = 0x1,
+ volts = 0x4,
+ amps = 0x5,
+ watts = 0x6,
+ rpm = 0x12,
+};
+
+enum class IPMINetfnStorageCmds : ipmi_cmd_t
+{
+ ipmiCmdGetFRUInvAreaInfo = 0x10,
+ ipmiCmdReadFRUData = 0x11,
+ ipmiCmdWriteFRUData = 0x12,
+ ipmiCmdGetRepositoryInfo = 0x20,
+ ipmiCmdGetSDRAllocationInfo = 0x21,
+ ipmiCmdReserveSDR = 0x22,
+ ipmiCmdGetSDR = 0x23,
+ ipmiCmdGetSELInfo = 0x40,
+ ipmiCmdReserveSEL = 0x42,
+ ipmiCmdGetSELEntry = 0x43,
+ ipmiCmdAddSEL = 0x44,
+ ipmiCmdDeleteSEL = 0x46,
+ ipmiCmdClearSEL = 0x47,
+ ipmiCmdGetSELTime = 0x48,
+ ipmiCmdSetSELTime = 0x49,
+};
+
+namespace ipmi
+{
+namespace storage
+{
+ipmi_ret_t getFruSdrs(size_t index, get_sdr::SensorDataFruRecord& resp);
+
+ipmi_ret_t getFruSdrCount(size_t& count);
+} // namespace storage
+} // namespace ipmi