blob: 95bb4911c6f31fd1d5f4fa4913d2004ffd4f1833 [file] [log] [blame]
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001/*
2// Copyright (c) 2017 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Patrick Venture31b35d52019-10-20 13:25:16 -070017#include "sensorcommands.hpp"
18
19#include "commandutils.hpp"
20#include "ipmi_to_redfish_hooks.hpp"
21#include "sdrutils.hpp"
22#include "sensorutils.hpp"
23#include "storagecommands.hpp"
Patrick Venturec2a07d42020-05-30 16:35:03 -070024#include "types.hpp"
Patrick Venture31b35d52019-10-20 13:25:16 -070025
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070026#include <boost/algorithm/string.hpp>
27#include <boost/container/flat_map.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070028#include <ipmid/api.hpp>
29#include <ipmid/utils.hpp>
30#include <phosphor-logging/log.hpp>
31#include <sdbusplus/bus.hpp>
32
33#include <algorithm>
34#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070035#include <chrono>
36#include <cmath>
Vernon Mauerydcff1502022-09-28 11:12:46 -070037#include <cstdint>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070038#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070039#include <iostream>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070040#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070041#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070042#include <optional>
Patrick Venturee6154022019-09-25 17:50:25 -070043#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070044#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070045#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070046#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070047
48namespace ipmi
49{
50using ManagedObjectType =
51 std::map<sdbusplus::message::object_path,
52 std::map<std::string, std::map<std::string, DbusVariant>>>;
53
James Feist25690252019-12-23 12:25:49 -080054static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu09701ef2020-07-15 17:56:21 -070055static constexpr int sensorMapSdrUpdatePeriod = 60;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070056
57constexpr size_t maxSDRTotalSize =
58 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
59constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
60
61static uint16_t sdrReservationID;
62static uint32_t sdrLastAdd = noTimestamp;
63static uint32_t sdrLastRemove = noTimestamp;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070064static constexpr size_t lastRecordIndex = 0xFFFF;
Johnathan Mantey2346b5d2021-08-06 11:21:10 -070065
66// The IPMI spec defines four Logical Units (LUN), each capable of supporting
67// 255 sensors. The 256 values assigned to LUN 2 are special and are not used
68// for general purpose sensors. Each LUN reserves location 0xFF. The maximum
69// number of IPMI sensors are LUN 0 + LUN 1 + LUN 2, less the reserved
70// location.
71static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
72
73static constexpr size_t lun0MaxSensorNum = 0xfe;
74static constexpr size_t lun1MaxSensorNum = 0x1fe;
75static constexpr size_t lun3MaxSensorNum = 0x3fe;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070076static constexpr int GENERAL_ERROR = -1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070077
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053078SensorSubTree sensorTree;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070079
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070080static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
81
Jason M. Bills039c3492022-09-09 14:27:28 -070082constexpr static std::array<std::pair<const char*, SensorUnits>, 5> sensorUnits{
83 {{"temperature", SensorUnits::degreesC},
84 {"voltage", SensorUnits::volts},
85 {"current", SensorUnits::amps},
86 {"fan_tach", SensorUnits::rpm},
87 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070088
89void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070090
Patrick Williamsf944d2e2022-07-22 19:26:52 -050091static sdbusplus::bus::match_t sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070092 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070093 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
94 "sensors/'",
Vernon Mauerydcff1502022-09-28 11:12:46 -070095 [](sdbusplus::message_t&) {
Patrick Williamsb37abfb2023-05-10 07:50:33 -050096 sensorTree.clear();
97 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
98 std::chrono::system_clock::now().time_since_epoch())
99 .count();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700100 });
101
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500102static sdbusplus::bus::match_t sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700103 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700104 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
105 "sensors/'",
Vernon Mauerydcff1502022-09-28 11:12:46 -0700106 [](sdbusplus::message_t&) {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500107 sensorTree.clear();
108 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
109 std::chrono::system_clock::now().time_since_epoch())
110 .count();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700111 });
112
James Feist392786a2019-03-19 13:36:10 -0700113// this keeps track of deassertions for sensor event status command. A
114// deasertion can only happen if an assertion was seen first.
115static boost::container::flat_map<
116 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
117 thresholdDeassertMap;
118
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500119static sdbusplus::bus::match_t thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700120 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700121 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
122 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500123 [](sdbusplus::message_t& m) {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500124 boost::container::flat_map<std::string, ipmi::DbusVariant> values;
125 m.read(std::string(), values);
James Feist392786a2019-03-19 13:36:10 -0700126
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500127 auto findAssert = std::find_if(values.begin(), values.end(),
128 [](const auto& pair) {
129 return pair.first.find("Alarm") != std::string::npos;
130 });
131 if (findAssert != values.end())
132 {
133 auto ptr = std::get_if<bool>(&(findAssert->second));
134 if (ptr == nullptr)
James Feist392786a2019-03-19 13:36:10 -0700135 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500136 phosphor::logging::log<phosphor::logging::level::ERR>(
137 "thresholdChanged: Assert non bool");
138 return;
139 }
140 if (*ptr)
141 {
142 phosphor::logging::log<phosphor::logging::level::INFO>(
143 "thresholdChanged: Assert",
144 phosphor::logging::entry("SENSOR=%s", m.get_path()));
145 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
146 }
147 else
148 {
149 auto& value = thresholdDeassertMap[m.get_path()][findAssert->first];
150 if (value)
James Feist392786a2019-03-19 13:36:10 -0700151 {
152 phosphor::logging::log<phosphor::logging::level::INFO>(
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500153 "thresholdChanged: deassert",
James Feist392786a2019-03-19 13:36:10 -0700154 phosphor::logging::entry("SENSOR=%s", m.get_path()));
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500155 value = *ptr;
James Feist392786a2019-03-19 13:36:10 -0700156 }
157 }
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500158 }
James Feist392786a2019-03-19 13:36:10 -0700159 });
160
James Feistfcd2d3a2020-05-28 10:38:15 -0700161static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
162 double& min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700163{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700164 max = 127;
165 min = -128;
166
James Feistaecaef72019-04-26 10:30:32 -0700167 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
168 auto critical =
169 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
170 auto warning =
171 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
172
173 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700174 {
James Feistaecaef72019-04-26 10:30:32 -0700175 auto maxMap = sensorObject->second.find("MaxValue");
176 auto minMap = sensorObject->second.find("MinValue");
177
178 if (maxMap != sensorObject->second.end())
179 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700180 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700181 }
182 if (minMap != sensorObject->second.end())
183 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700184 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700185 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700186 }
James Feistaecaef72019-04-26 10:30:32 -0700187 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700188 {
James Feistaecaef72019-04-26 10:30:32 -0700189 auto lower = critical->second.find("CriticalLow");
190 auto upper = critical->second.find("CriticalHigh");
191 if (lower != critical->second.end())
192 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700193 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700194 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700195 }
196 if (upper != critical->second.end())
197 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700198 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700199 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700200 }
201 }
202 if (warning != sensorMap.end())
203 {
James Feistaecaef72019-04-26 10:30:32 -0700204 auto lower = warning->second.find("WarningLow");
205 auto upper = warning->second.find("WarningHigh");
206 if (lower != warning->second.end())
207 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700208 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700209 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700210 }
211 if (upper != warning->second.end())
212 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700213 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700214 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700215 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700216 }
217}
218
James Feist25690252019-12-23 12:25:49 -0800219static bool getSensorMap(boost::asio::yield_context yield,
220 std::string sensorConnection, std::string sensorPath,
Alex Qiu09701ef2020-07-15 17:56:21 -0700221 SensorMap& sensorMap,
222 int updatePeriod = sensorMapUpdatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700223{
224 static boost::container::flat_map<
225 std::string, std::chrono::time_point<std::chrono::steady_clock>>
226 updateTimeMap;
227
228 auto updateFind = updateTimeMap.find(sensorConnection);
229 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
230 if (updateFind != updateTimeMap.end())
231 {
232 lastUpdate = updateFind->second;
233 }
234
235 auto now = std::chrono::steady_clock::now();
236
237 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu09701ef2020-07-15 17:56:21 -0700238 .count() > updatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700239 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700240 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800241 boost::system::error_code ec;
242 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
Ed Tanousff4982a2022-10-04 17:27:35 -0700243 yield, ec, sensorConnection.c_str(), "/xyz/openbmc_project/sensors",
James Feist25690252019-12-23 12:25:49 -0800244 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
245 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700246 {
247 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800248 "GetMangagedObjects for getSensorMap failed",
249 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
250
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700251 return false;
252 }
253
254 SensorCache[sensorConnection] = managedObjects;
Alex Qiu09701ef2020-07-15 17:56:21 -0700255 // Update time after finish building the map which allow the
256 // data to be cached for updatePeriod plus the build time.
257 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700258 }
259 auto connection = SensorCache.find(sensorConnection);
260 if (connection == SensorCache.end())
261 {
262 return false;
263 }
264 auto path = connection->second.find(sensorPath);
265 if (path == connection->second.end())
266 {
267 return false;
268 }
269 sensorMap = path->second;
270
271 return true;
272}
273
274/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700275namespace meHealth
276{
James Feistfcd2d3a2020-05-28 10:38:15 -0700277constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
278constexpr const char* path = "/xyz/openbmc_project/status/me";
279constexpr const char* interface = "xyz.openbmc_project.SetHealth";
280constexpr const char* method = "SetHealth";
281constexpr const char* critical = "critical";
282constexpr const char* warning = "warning";
283constexpr const char* ok = "ok";
James Feist7aaf3fe2019-06-25 11:52:11 -0700284} // namespace meHealth
285
286static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
287{
288 constexpr const std::array<uint8_t, 10> critical = {
289 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
290 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
291 0x1A};
292
293 std::string state;
294 if (std::find(critical.begin(), critical.end(), eventData2) !=
295 critical.end())
296 {
297 state = meHealth::critical;
298 }
299 // special case 0x3 as we only care about a few states
300 else if (eventData2 == 0x3)
301 {
302 if (eventData3 <= 0x2)
303 {
304 state = meHealth::warning;
305 }
306 else
307 {
308 return;
309 }
310 }
311 else if (std::find(warning.begin(), warning.end(), eventData2) !=
312 warning.end())
313 {
314 state = meHealth::warning;
315 }
316 else
317 {
318 return;
319 }
320 if (disable)
321 {
322 state = meHealth::ok;
323 }
324
325 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500326 auto setHealth = dbus->new_method_call(meHealth::busname, meHealth::path,
327 meHealth::interface,
328 meHealth::method);
James Feist7aaf3fe2019-06-25 11:52:11 -0700329 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
330 try
331 {
332 dbus->call(setHealth);
333 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500334 catch (const sdbusplus::exception_t&)
James Feist7aaf3fe2019-06-25 11:52:11 -0700335 {
336 phosphor::logging::log<phosphor::logging::level::ERR>(
337 "Failed to set ME Health");
338 }
339}
340
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000341ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
342 ipmi::message::Payload& p)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700343{
James Feist7aaf3fe2019-06-25 11:52:11 -0700344 constexpr const uint8_t meId = 0x2C;
345 constexpr const uint8_t meSensorNum = 0x17;
346 constexpr const uint8_t disabled = 0x80;
347
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700348 uint8_t sysgeneratorID = 0;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700349 uint8_t evmRev = 0;
350 uint8_t sensorType = 0;
351 uint8_t sensorNum = 0;
352 uint8_t eventType = 0;
353 uint8_t eventData1 = 0;
354 std::optional<uint8_t> eventData2 = 0;
355 std::optional<uint8_t> eventData3 = 0;
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700356 uint16_t generatorID = 0;
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000357 ipmi::ChannelInfo chInfo;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700358
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000359 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700360 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000361 phosphor::logging::log<phosphor::logging::level::ERR>(
362 "Failed to get Channel Info",
363 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
364 return ipmi::responseUnspecifiedError();
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700365 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000366
367 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
368 ipmi::EChannelMediumType::systemInterface)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700369 {
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700370 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700371 eventData1, eventData2, eventData3);
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700372 constexpr const uint8_t isSoftwareID = 0x01;
373 if (!(sysgeneratorID & isSoftwareID))
374 {
375 return ipmi::responseInvalidFieldRequest();
376 }
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700377 // Refer to IPMI Spec Table 32: SEL Event Records
378 generatorID = (ctx->channel << 12) // Channel
379 | (0x0 << 10) // Reserved
380 | (0x0 << 8) // 0x0 for sys-soft ID
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700381 | sysgeneratorID;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700382 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000383 else
384 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000385 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
386 eventData2, eventData3);
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700387 // Refer to IPMI Spec Table 32: SEL Event Records
388 generatorID = (ctx->channel << 12) // Channel
389 | (0x0 << 10) // Reserved
390 | ((ctx->lun & 0x3) << 8) // Lun
391 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000392 }
393
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700394 if (!p.fullyUnpacked())
395 {
396 return ipmi::responseReqDataLenInvalid();
397 }
398
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000399 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
400 if (evmRev != 0x04)
401 {
402 return ipmi::responseInvalidFieldRequest();
403 }
404 if ((sensorType > 0x2C) && (sensorType < 0xC0))
405 {
406 return ipmi::responseInvalidFieldRequest();
407 }
408
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700409 // Send this request to the Redfish hooks to log it as a Redfish message
410 // instead. There is no need to add it to the SEL, so just return success.
411 intel_oem::ipmi::sel::checkRedfishHooks(
412 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
413 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700414
Vernon Maueryce3b7572022-04-14 13:16:25 -0700415 if (static_cast<uint8_t>(generatorID) == meId && sensorNum == meSensorNum &&
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700416 eventData2 && eventData3)
James Feist7aaf3fe2019-06-25 11:52:11 -0700417 {
418 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
419 }
420
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700421 return ipmi::responseSuccess();
422}
423
James Feist0cd014a2019-04-08 15:04:33 -0700424ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700425 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700426{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700427 std::string connection;
428 std::string path;
429
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000430 if (sensnum == reservedSensorNumber)
431 {
432 return ipmi::responseInvalidFieldRequest();
433 }
434
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700435 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700436 if (status)
437 {
James Feist0cd014a2019-04-08 15:04:33 -0700438 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700439 }
440
441 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700442 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700443 {
James Feist0cd014a2019-04-08 15:04:33 -0700444 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700445 }
446 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
447
448 if (sensorObject == sensorMap.end() ||
449 sensorObject->second.find("Value") == sensorObject->second.end())
450 {
James Feist0cd014a2019-04-08 15:04:33 -0700451 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700452 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700453 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700454 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700455
Yong Li1f2eb5e2019-05-23 14:07:17 +0800456 double max = 0;
457 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700458 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700459
460 int16_t mValue = 0;
461 int16_t bValue = 0;
462 int8_t rExp = 0;
463 int8_t bExp = 0;
464 bool bSigned = false;
465
466 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
467 {
James Feist0cd014a2019-04-08 15:04:33 -0700468 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700469 }
470
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500471 uint8_t value = scaleIPMIValueFromDouble(reading, mValue, rExp, bValue,
472 bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700473 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700474 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700475 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800476 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700477 bool notReading = std::isnan(reading);
478
479 if (!notReading)
480 {
481 auto availableObject =
482 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
483 if (availableObject != sensorMap.end())
484 {
485 auto findAvailable = availableObject->second.find("Available");
486 if (findAvailable != availableObject->second.end())
487 {
488 bool* available = std::get_if<bool>(&(findAvailable->second));
489 if (available && !(*available))
490 {
491 notReading = true;
492 }
493 }
494 }
495 }
496
497 if (notReading)
498 {
499 operation |= static_cast<uint8_t>(
500 IPMISensorReadingByte2::readingStateUnavailable);
501 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700502
Josh Lehan06aa21a2020-10-28 21:59:06 -0700503 int byteValue;
504 if (bSigned)
505 {
506 byteValue = static_cast<int>(static_cast<int8_t>(value));
507 }
508 else
509 {
510 byteValue = static_cast<int>(static_cast<uint8_t>(value));
511 }
512
513 // Keep stats on the reading just obtained, even if it is "NaN"
514 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
515 {
516 // This is the first reading, show the coefficients
517 double step = (max - min) / 255.0;
518 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
519 << ": Range min=" << min << " max=" << max
520 << ", step=" << step
521 << ", Coefficients mValue=" << static_cast<int>(mValue)
522 << " rExp=" << static_cast<int>(rExp)
523 << " bValue=" << static_cast<int>(bValue)
524 << " bExp=" << static_cast<int>(bExp)
525 << " bSigned=" << static_cast<int>(bSigned) << "\n";
526 };
527
James Feist0cd014a2019-04-08 15:04:33 -0700528 uint8_t thresholds = 0;
529
530 auto warningObject =
531 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
532 if (warningObject != sensorMap.end())
533 {
534 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
535 auto alarmLow = warningObject->second.find("WarningAlarmLow");
536 if (alarmHigh != warningObject->second.end())
537 {
538 if (std::get<bool>(alarmHigh->second))
539 {
540 thresholds |= static_cast<uint8_t>(
541 IPMISensorReadingByte3::upperNonCritical);
542 }
543 }
544 if (alarmLow != warningObject->second.end())
545 {
546 if (std::get<bool>(alarmLow->second))
547 {
548 thresholds |= static_cast<uint8_t>(
549 IPMISensorReadingByte3::lowerNonCritical);
550 }
551 }
552 }
553
554 auto criticalObject =
555 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
556 if (criticalObject != sensorMap.end())
557 {
558 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
559 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
560 if (alarmHigh != criticalObject->second.end())
561 {
562 if (std::get<bool>(alarmHigh->second))
563 {
564 thresholds |=
565 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
566 }
567 }
568 if (alarmLow != criticalObject->second.end())
569 {
570 if (std::get<bool>(alarmLow->second))
571 {
572 thresholds |=
573 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
574 }
575 }
576 }
577
578 // no discrete as of today so optional byte is never returned
579 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700580}
581
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000582/** @brief implements the Set Sensor threshold command
583 * @param sensorNumber - sensor number
584 * @param lowerNonCriticalThreshMask
585 * @param lowerCriticalThreshMask
586 * @param lowerNonRecovThreshMask
587 * @param upperNonCriticalThreshMask
588 * @param upperCriticalThreshMask
589 * @param upperNonRecovThreshMask
590 * @param reserved
591 * @param lowerNonCritical - lower non-critical threshold
592 * @param lowerCritical - Lower critical threshold
593 * @param lowerNonRecoverable - Lower non recovarable threshold
594 * @param upperNonCritical - Upper non-critical threshold
595 * @param upperCritical - Upper critical
596 * @param upperNonRecoverable - Upper Non-recoverable
597 *
598 * @returns IPMI completion code
599 */
600ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700601 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
602 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
603 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
604 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
Vernon Mauerydcff1502022-09-28 11:12:46 -0700605 uint8_t lowerCritical, [[maybe_unused]] uint8_t lowerNonRecoverable,
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700606 uint8_t upperNonCritical, uint8_t upperCritical,
Vernon Mauerydcff1502022-09-28 11:12:46 -0700607 [[maybe_unused]] uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700608{
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000609 if (sensorNum == reservedSensorNumber)
610 {
611 return ipmi::responseInvalidFieldRequest();
612 }
613
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000614 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700615 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000616 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700617 }
618
619 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000620 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700621 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000622 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700623 }
624
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000625 // if none of the threshold mask are set, nothing to do
626 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
627 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
628 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700629 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 }
632
633 std::string connection;
634 std::string path;
635
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700636 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700637 if (status)
638 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000639 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700640 }
641 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700642 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700643 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000644 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700645 }
646
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700647 double max = 0;
648 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700649 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650
651 int16_t mValue = 0;
652 int16_t bValue = 0;
653 int8_t rExp = 0;
654 int8_t bExp = 0;
655 bool bSigned = false;
656
657 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
658 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000659 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700660 }
661
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700662 // store a vector of property name, value to set, and interface
663 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
664
665 // define the indexes of the tuple
666 constexpr uint8_t propertyName = 0;
667 constexpr uint8_t thresholdValue = 1;
668 constexpr uint8_t interface = 2;
669 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000670 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700671 {
672 auto findThreshold =
673 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
674 if (findThreshold == sensorMap.end())
675 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000676 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700677 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000678 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700679 {
680 auto findLower = findThreshold->second.find("CriticalLow");
681 if (findLower == findThreshold->second.end())
682 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000683 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700684 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000685 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700686 findThreshold->first);
687 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000688 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700689 {
690 auto findUpper = findThreshold->second.find("CriticalHigh");
691 if (findUpper == findThreshold->second.end())
692 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000693 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700694 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000695 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700696 findThreshold->first);
697 }
698 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000699 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700700 {
701 auto findThreshold =
702 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
703 if (findThreshold == sensorMap.end())
704 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000705 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700706 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000707 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700708 {
709 auto findLower = findThreshold->second.find("WarningLow");
710 if (findLower == findThreshold->second.end())
711 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000712 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700713 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000714 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700715 findThreshold->first);
716 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000717 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700718 {
719 auto findUpper = findThreshold->second.find("WarningHigh");
720 if (findUpper == findThreshold->second.end())
721 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000722 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700723 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000724 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700725 findThreshold->first);
726 }
727 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700728 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700729 {
730 // from section 36.3 in the IPMI Spec, assume all linear
731 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800732 (bValue * std::pow(10.0, bExp))) *
733 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700734 setDbusProperty(
735 *getSdBus(), connection, path, std::get<interface>(property),
736 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700737 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000738 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700739}
740
James Feistfcd2d3a2020-05-28 10:38:15 -0700741IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700742{
James Feist902c4c52019-04-16 14:51:31 -0700743 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700744 auto warningInterface =
745 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
746 auto criticalInterface =
747 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
748
749 if ((warningInterface != sensorMap.end()) ||
750 (criticalInterface != sensorMap.end()))
751 {
752 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
753
754 if (sensorPair == sensorMap.end())
755 {
756 // should not have been able to find a sensor not implementing
757 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700758 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700759 }
760
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800761 double max = 0;
762 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700763 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700764
765 int16_t mValue = 0;
766 int16_t bValue = 0;
767 int8_t rExp = 0;
768 int8_t bExp = 0;
769 bool bSigned = false;
770
771 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
772 {
James Feist902c4c52019-04-16 14:51:31 -0700773 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700774 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700775 if (warningInterface != sensorMap.end())
776 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700777 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700778
779 auto warningHigh = warningMap.find("WarningHigh");
780 auto warningLow = warningMap.find("WarningLow");
781
782 if (warningHigh != warningMap.end())
783 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500784 double value = std::visit(VariantToDoubleVisitor(),
785 warningHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700786 if (std::isfinite(value))
787 {
788 resp.warningHigh = scaleIPMIValueFromDouble(
789 value, mValue, rExp, bValue, bExp, bSigned);
790 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700791 }
792 if (warningLow != warningMap.end())
793 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500794 double value = std::visit(VariantToDoubleVisitor(),
795 warningLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700796 if (std::isfinite(value))
797 {
798 resp.warningLow = scaleIPMIValueFromDouble(
799 value, mValue, rExp, bValue, bExp, bSigned);
800 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700801 }
802 }
803 if (criticalInterface != sensorMap.end())
804 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700805 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700806
807 auto criticalHigh = criticalMap.find("CriticalHigh");
808 auto criticalLow = criticalMap.find("CriticalLow");
809
810 if (criticalHigh != criticalMap.end())
811 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500812 double value = std::visit(VariantToDoubleVisitor(),
813 criticalHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700814 if (std::isfinite(value))
815 {
816 resp.criticalHigh = scaleIPMIValueFromDouble(
817 value, mValue, rExp, bValue, bExp, bSigned);
818 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700819 }
820 if (criticalLow != criticalMap.end())
821 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500822 double value = std::visit(VariantToDoubleVisitor(),
823 criticalLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700824 if (std::isfinite(value))
825 {
826 resp.criticalLow = scaleIPMIValueFromDouble(
827 value, mValue, rExp, bValue, bExp, bSigned);
828 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700829 }
830 }
831 }
James Feist902c4c52019-04-16 14:51:31 -0700832 return resp;
833}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700834
James Feist902c4c52019-04-16 14:51:31 -0700835ipmi::RspType<uint8_t, // readable
836 uint8_t, // lowerNCrit
837 uint8_t, // lowerCrit
838 uint8_t, // lowerNrecoverable
839 uint8_t, // upperNC
840 uint8_t, // upperCrit
841 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700842 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700843{
844 std::string connection;
845 std::string path;
846
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000847 if (sensorNumber == reservedSensorNumber)
848 {
849 return ipmi::responseInvalidFieldRequest();
850 }
851
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700852 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700853 if (status)
854 {
855 return ipmi::response(status);
856 }
857
858 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700859 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700860 {
861 return ipmi::responseResponseError();
862 }
863
864 IPMIThresholds thresholdData;
865 try
866 {
867 thresholdData = getIPMIThresholds(sensorMap);
868 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500869 catch (const std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700870 {
871 return ipmi::responseResponseError();
872 }
873
874 uint8_t readable = 0;
875 uint8_t lowerNC = 0;
876 uint8_t lowerCritical = 0;
877 uint8_t lowerNonRecoverable = 0;
878 uint8_t upperNC = 0;
879 uint8_t upperCritical = 0;
880 uint8_t upperNonRecoverable = 0;
881
882 if (thresholdData.warningHigh)
883 {
884 readable |=
885 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
886 upperNC = *thresholdData.warningHigh;
887 }
888 if (thresholdData.warningLow)
889 {
890 readable |=
891 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
892 lowerNC = *thresholdData.warningLow;
893 }
894
895 if (thresholdData.criticalHigh)
896 {
897 readable |=
898 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
899 upperCritical = *thresholdData.criticalHigh;
900 }
901 if (thresholdData.criticalLow)
902 {
903 readable |=
904 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
905 lowerCritical = *thresholdData.criticalLow;
906 }
907
908 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
909 lowerNonRecoverable, upperNC, upperCritical,
910 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700911}
912
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000913/** @brief implements the get Sensor event enable command
914 * @param sensorNumber - sensor number
915 *
916 * @returns IPMI completion code plus response data
917 * - enabled - Sensor Event messages
918 * - assertionEnabledLsb - Assertion event messages
919 * - assertionEnabledMsb - Assertion event messages
920 * - deassertionEnabledLsb - Deassertion event messages
921 * - deassertionEnabledMsb - Deassertion event messages
922 */
923
924ipmi::RspType<uint8_t, // enabled
925 uint8_t, // assertionEnabledLsb
926 uint8_t, // assertionEnabledMsb
927 uint8_t, // deassertionEnabledLsb
928 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700929 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700930{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700931 std::string connection;
932 std::string path;
933
Patrick Venturea41714c2019-09-25 16:59:41 -0700934 uint8_t enabled = 0;
935 uint8_t assertionEnabledLsb = 0;
936 uint8_t assertionEnabledMsb = 0;
937 uint8_t deassertionEnabledLsb = 0;
938 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000939
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000940 if (sensorNum == reservedSensorNumber)
941 {
942 return ipmi::responseInvalidFieldRequest();
943 }
944
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700945 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700946 if (status)
947 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000948 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700949 }
950
951 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700952 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700953 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000954 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700955 }
956
957 auto warningInterface =
958 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
959 auto criticalInterface =
960 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700961 if ((warningInterface != sensorMap.end()) ||
962 (criticalInterface != sensorMap.end()))
963 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000964 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700965 IPMISensorEventEnableByte2::sensorScanningEnable);
966 if (warningInterface != sensorMap.end())
967 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700968 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700969
970 auto warningHigh = warningMap.find("WarningHigh");
971 auto warningLow = warningMap.find("WarningLow");
972 if (warningHigh != warningMap.end())
973 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500974 double value = std::visit(VariantToDoubleVisitor(),
975 warningHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700976 if (std::isfinite(value))
977 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500978 assertionEnabledLsb |= static_cast<uint8_t>(
979 IPMISensorEventEnableThresholds::
980 upperNonCriticalGoingHigh);
981 deassertionEnabledLsb |= static_cast<uint8_t>(
982 IPMISensorEventEnableThresholds::
983 upperNonCriticalGoingLow);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700984 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700985 }
986 if (warningLow != warningMap.end())
987 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500988 double value = std::visit(VariantToDoubleVisitor(),
989 warningLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700990 if (std::isfinite(value))
991 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500992 assertionEnabledLsb |= static_cast<uint8_t>(
993 IPMISensorEventEnableThresholds::
994 lowerNonCriticalGoingLow);
995 deassertionEnabledLsb |= static_cast<uint8_t>(
996 IPMISensorEventEnableThresholds::
997 lowerNonCriticalGoingHigh);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700998 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700999 }
1000 }
1001 if (criticalInterface != sensorMap.end())
1002 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001003 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001004
1005 auto criticalHigh = criticalMap.find("CriticalHigh");
1006 auto criticalLow = criticalMap.find("CriticalLow");
1007
1008 if (criticalHigh != criticalMap.end())
1009 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001010 double value = std::visit(VariantToDoubleVisitor(),
1011 criticalHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001012 if (std::isfinite(value))
1013 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001014 assertionEnabledMsb |= static_cast<uint8_t>(
1015 IPMISensorEventEnableThresholds::
1016 upperCriticalGoingHigh);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001017 deassertionEnabledMsb |= static_cast<uint8_t>(
1018 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1019 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001020 }
1021 if (criticalLow != criticalMap.end())
1022 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001023 double value = std::visit(VariantToDoubleVisitor(),
1024 criticalLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001025 if (std::isfinite(value))
1026 {
1027 assertionEnabledLsb |= static_cast<uint8_t>(
1028 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001029 deassertionEnabledLsb |= static_cast<uint8_t>(
1030 IPMISensorEventEnableThresholds::
1031 lowerCriticalGoingHigh);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001032 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001033 }
1034 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001035 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001036
1037 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1038 assertionEnabledMsb, deassertionEnabledLsb,
1039 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001040}
1041
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001042/** @brief implements the get Sensor event status command
1043 * @param sensorNumber - sensor number, FFh = reserved
1044 *
1045 * @returns IPMI completion code plus response data
1046 * - sensorEventStatus - Sensor Event messages state
1047 * - assertions - Assertion event messages
1048 * - deassertions - Deassertion event messages
1049 */
1050ipmi::RspType<uint8_t, // sensorEventStatus
1051 std::bitset<16>, // assertions
1052 std::bitset<16> // deassertion
1053 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001054 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001055{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001056 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001057 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001058 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001059 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001060
1061 std::string connection;
1062 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001063 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001064 if (status)
1065 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001066 phosphor::logging::log<phosphor::logging::level::ERR>(
1067 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1068 phosphor::logging::entry("SENSOR=%d", sensorNum));
1069 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001070 }
1071
1072 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001073 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001074 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001075 phosphor::logging::log<phosphor::logging::level::ERR>(
1076 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1077 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1078 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001079 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001080 auto warningInterface =
1081 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1082 auto criticalInterface =
1083 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1084
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001085 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001086 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1087
James Feist392786a2019-03-19 13:36:10 -07001088 std::optional<bool> criticalDeassertHigh =
1089 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1090 std::optional<bool> criticalDeassertLow =
1091 thresholdDeassertMap[path]["CriticalAlarmLow"];
1092 std::optional<bool> warningDeassertHigh =
1093 thresholdDeassertMap[path]["WarningAlarmHigh"];
1094 std::optional<bool> warningDeassertLow =
1095 thresholdDeassertMap[path]["WarningAlarmLow"];
1096
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001097 std::bitset<16> assertions = 0;
1098 std::bitset<16> deassertions = 0;
1099
James Feist392786a2019-03-19 13:36:10 -07001100 if (criticalDeassertHigh && !*criticalDeassertHigh)
1101 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001102 deassertions.set(static_cast<size_t>(
1103 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001104 }
1105 if (criticalDeassertLow && !*criticalDeassertLow)
1106 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001107 deassertions.set(static_cast<size_t>(
1108 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001109 }
1110 if (warningDeassertHigh && !*warningDeassertHigh)
1111 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001112 deassertions.set(static_cast<size_t>(
1113 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001114 }
1115 if (warningDeassertLow && !*warningDeassertLow)
1116 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001117 deassertions.set(static_cast<size_t>(
1118 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001119 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120 if ((warningInterface != sensorMap.end()) ||
1121 (criticalInterface != sensorMap.end()))
1122 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001123 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001124 IPMISensorEventEnableByte2::eventMessagesEnable);
1125 if (warningInterface != sensorMap.end())
1126 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001127 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001128
1129 auto warningHigh = warningMap.find("WarningAlarmHigh");
1130 auto warningLow = warningMap.find("WarningAlarmLow");
1131 auto warningHighAlarm = false;
1132 auto warningLowAlarm = false;
1133
1134 if (warningHigh != warningMap.end())
1135 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001136 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001137 }
1138 if (warningLow != warningMap.end())
1139 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001140 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001141 }
1142 if (warningHighAlarm)
1143 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001144 assertions.set(
1145 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1146 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001147 }
1148 if (warningLowAlarm)
1149 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001150 assertions.set(
1151 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1152 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153 }
1154 }
1155 if (criticalInterface != sensorMap.end())
1156 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001157 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001158
1159 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1160 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1161 auto criticalHighAlarm = false;
1162 auto criticalLowAlarm = false;
1163
1164 if (criticalHigh != criticalMap.end())
1165 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001166 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167 }
1168 if (criticalLow != criticalMap.end())
1169 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001170 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001171 }
1172 if (criticalHighAlarm)
1173 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001174 assertions.set(
1175 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1176 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001177 }
1178 if (criticalLowAlarm)
1179 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001180 assertions.set(static_cast<size_t>(
1181 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001182 }
1183 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001184 }
1185
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001186 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001187}
1188
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001189static inline uint16_t getNumberOfSensors(void)
1190{
1191 return sensorTree.size() > maxIPMISensors ? maxIPMISensors
1192 : sensorTree.size();
1193}
1194
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001195static int getSensorDataRecord(ipmi::Context::ptr ctx,
1196 std::vector<uint8_t>& recordData,
1197 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001198{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001199 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001200 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1201 if (ret != ipmi::ccSuccess)
1202 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001203 phosphor::logging::log<phosphor::logging::level::ERR>(
1204 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001205 return GENERAL_ERROR;
1206 }
1207
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001208 size_t lastRecord = getNumberOfSensors() + fruCount +
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001209 ipmi::storage::type12Count +
1210 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001211 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001212 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001213 recordID = lastRecord;
1214 }
1215 if (recordID > lastRecord)
1216 {
1217 phosphor::logging::log<phosphor::logging::level::ERR>(
1218 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001219 return GENERAL_ERROR;
1220 }
1221
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001222 if (recordID >= getNumberOfSensors())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001223 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001224 size_t fruIndex = recordID - getNumberOfSensors();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001225 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001226
1227 if (fruIndex >= type12End)
1228 {
1229 // NM discovery SDR
1230 size_t nmDiscoveryIndex = fruIndex - type12End;
1231 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1232 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001233 phosphor::logging::log<phosphor::logging::level::ERR>(
1234 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001235 return GENERAL_ERROR;
1236 }
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001237 recordData = ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex,
1238 recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001239 }
1240 else if (fruIndex >= fruCount)
1241 {
1242 // handle type 12 hardcoded records
1243 size_t type12Index = fruIndex - fruCount;
1244 if (type12Index >= ipmi::storage::type12Count)
1245 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001246 phosphor::logging::log<phosphor::logging::level::ERR>(
1247 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001248 return GENERAL_ERROR;
1249 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001250 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001251 }
1252 else
1253 {
1254 // handle fru records
1255 get_sdr::SensorDataFruRecord data;
1256 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1257 if (ret != IPMI_CC_OK)
1258 {
1259 return GENERAL_ERROR;
1260 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001261 data.header.record_id_msb = recordID >> 8;
1262 data.header.record_id_lsb = recordID & 0xFF;
1263 recordData.insert(recordData.end(), (uint8_t*)&data,
1264 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001265 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001266
1267 return 0;
1268 }
1269
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001270 // Perform a incremental scan of the SDR Record ID's and translate the
1271 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
1272 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
1273 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
1274 // which has special meaning.
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001275 std::string connection;
1276 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001277 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001278 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001279 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001280 // LUN 0 has one reserved sensor number. Compensate here by adding one
1281 // to the record ID
1282 sensNumFromRecID = recordID + 1;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001283 ctx->lun = 1;
1284 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001285 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001286 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001287 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
1288 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
1289 // rules governing its use.
1290 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001291 ctx->lun = 3;
1292 }
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001293
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001294 auto status = getSensorConnection(
1295 ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001296 if (status)
1297 {
1298 phosphor::logging::log<phosphor::logging::level::ERR>(
1299 "getSensorDataRecord: getSensorConnection error");
1300 return GENERAL_ERROR;
1301 }
1302 SensorMap sensorMap;
1303 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1304 sensorMapUpdatePeriod))
1305 {
1306 phosphor::logging::log<phosphor::logging::level::ERR>(
1307 "getSensorDataRecord: getSensorMap error");
1308 return GENERAL_ERROR;
1309 }
1310 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001311 // Return an error on LUN 2 assingments, and any sensor number beyond the
1312 // range of LUN 3
1313 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
1314 (sensorNum > lun3MaxSensorNum))
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001315 {
1316 phosphor::logging::log<phosphor::logging::level::ERR>(
1317 "getSensorDataRecord: invalidSensorNumber");
1318 return GENERAL_ERROR;
1319 }
1320 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1321 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1322
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001323 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
1324 (lun != ctx->lun))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001325 {
1326 phosphor::logging::log<phosphor::logging::level::ERR>(
1327 "getSensorDataRecord: sensor record mismatch");
1328 return GENERAL_ERROR;
1329 }
Vernon Mauerydcff1502022-09-28 11:12:46 -07001330 get_sdr::SensorDataFullRecord record = {{}, {}, {}};
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001331
1332 get_sdr::header::set_record_id(
1333 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1334
1335 record.header.sdr_version = ipmiSdrVersion;
1336 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1337 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1338 sizeof(get_sdr::SensorDataRecordHeader);
1339 record.key.owner_id = 0x20;
1340 record.key.owner_lun = lun;
1341 record.key.sensor_number = sensornumber;
1342
1343 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1344 record.body.sensor_type = getSensorTypeFromPath(path);
1345 std::string type = getSensorTypeStringFromPath(path);
Jason M. Bills039c3492022-09-09 14:27:28 -07001346 for (const auto& [unitsType, units] : sensorUnits)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001347 {
Jason M. Bills039c3492022-09-09 14:27:28 -07001348 if (type == unitsType)
1349 {
1350 record.body.sensor_units_2_base = static_cast<uint8_t>(units);
1351 }
1352 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001353
1354 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1355
1356 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1357 if (sensorObject == sensorMap.end())
1358 {
1359 phosphor::logging::log<phosphor::logging::level::ERR>(
1360 "getSensorDataRecord: sensorObject error");
1361 return GENERAL_ERROR;
1362 }
1363
1364 uint8_t entityId = 0;
1365 uint8_t entityInstance = 0x01;
1366
1367 // follow the association chain to get the parent board's entityid and
1368 // entityInstance
1369 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1370
1371 record.body.entity_id = entityId;
1372 record.body.entity_instance = entityInstance;
1373
1374 auto maxObject = sensorObject->second.find("MaxValue");
1375 auto minObject = sensorObject->second.find("MinValue");
1376
1377 // If min and/or max are left unpopulated,
1378 // then default to what a signed byte would be, namely (-128,127) range.
1379 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1380 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1381 if (maxObject != sensorObject->second.end())
1382 {
1383 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1384 }
1385
1386 if (minObject != sensorObject->second.end())
1387 {
1388 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1389 }
1390
1391 int16_t mValue = 0;
1392 int8_t rExp = 0;
1393 int16_t bValue = 0;
1394 int8_t bExp = 0;
1395 bool bSigned = false;
1396
1397 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1398 {
1399 phosphor::logging::log<phosphor::logging::level::ERR>(
1400 "getSensorDataRecord: getSensorAttributes error");
1401 return GENERAL_ERROR;
1402 }
1403
1404 // The record.body is a struct SensorDataFullRecordBody
1405 // from sensorhandler.hpp in phosphor-ipmi-host.
1406 // The meaning of these bits appears to come from
1407 // table 43.1 of the IPMI spec.
1408 // The above 5 sensor attributes are stuffed in as follows:
1409 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1410 // Byte 22-24 are for other purposes
1411 // Byte 25 = MMMMMMMM = LSB of M
1412 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1413 // Byte 27 = BBBBBBBB = LSB of B
1414 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1415 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1416 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1417
1418 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1419 record.body.m_lsb = mValue & 0xFF;
1420
1421 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1422 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1423
1424 // move the smallest bit of the MSB into place (bit 9)
1425 // the MSbs are bits 7:8 in m_msb_and_tolerance
1426 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1427
1428 record.body.b_lsb = bValue & 0xFF;
1429
1430 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1431 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1432
1433 // move the smallest bit of the MSB into place (bit 9)
1434 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1435 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1436
1437 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1438 uint8_t rExpBits = rExp & 0x07;
1439
1440 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1441 uint8_t bExpBits = bExp & 0x07;
1442
1443 // move rExp and bExp into place
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001444 record.body.r_b_exponents = (rExpSign << 7) | (rExpBits << 4) |
1445 (bExpSign << 3) | bExpBits;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001446
1447 // Set the analog reading byte interpretation accordingly
1448 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1449
1450 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1451 // These seem redundant, but derivable from the above 5 attributes
1452 // Original comment said "todo fill out rest of units"
1453
1454 // populate sensor name from path
1455 std::string name;
1456 size_t nameStart = path.rfind("/");
1457 if (nameStart != std::string::npos)
1458 {
1459 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1460 }
1461
1462 std::replace(name.begin(), name.end(), '_', ' ');
1463 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1464 {
1465 // try to not truncate by replacing common words
1466 constexpr std::array<std::pair<const char*, const char*>, 2>
1467 replaceWords = {std::make_pair("Output", "Out"),
1468 std::make_pair("Input", "In")};
1469 for (const auto& [find, replace] : replaceWords)
1470 {
1471 boost::replace_all(name, find, replace);
1472 }
1473
1474 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1475 }
Paul Fertser97221512022-08-18 12:36:41 +00001476 get_sdr::body::set_id_strlen(name.size(), &record.body);
1477 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001478 std::strncpy(record.body.id_string, name.c_str(),
1479 sizeof(record.body.id_string));
1480
Josh Lehan06aa21a2020-10-28 21:59:06 -07001481 // Remember the sensor name, as determined for this sensor number
1482 details::sdrStatsTable.updateName(sensornumber, name);
1483
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001484 IPMIThresholds thresholdData;
1485 try
1486 {
1487 thresholdData = getIPMIThresholds(sensorMap);
1488 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001489 catch (const std::exception&)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001490 {
1491 phosphor::logging::log<phosphor::logging::level::ERR>(
1492 "getSensorDataRecord: getIPMIThresholds error");
1493 return GENERAL_ERROR;
1494 }
1495
1496 if (thresholdData.criticalHigh)
1497 {
1498 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1499 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1500 IPMISensorEventEnableThresholds::criticalThreshold);
1501 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1502 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1503 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1504 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1505 record.body.discrete_reading_setting_mask[0] |=
1506 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1507 }
1508 if (thresholdData.warningHigh)
1509 {
1510 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1511 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1512 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1513 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1514 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1515 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1516 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1517 record.body.discrete_reading_setting_mask[0] |=
1518 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1519 }
1520 if (thresholdData.criticalLow)
1521 {
1522 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1523 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1524 IPMISensorEventEnableThresholds::criticalThreshold);
1525 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1526 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1527 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1528 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1529 record.body.discrete_reading_setting_mask[0] |=
1530 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1531 }
1532 if (thresholdData.warningLow)
1533 {
1534 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1535 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1536 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1537 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1538 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1539 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1540 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1541 record.body.discrete_reading_setting_mask[0] |=
1542 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1543 }
1544
1545 // everything that is readable is setable
1546 record.body.discrete_reading_setting_mask[1] =
1547 record.body.discrete_reading_setting_mask[0];
1548 recordData.insert(recordData.end(), (uint8_t*)&record,
1549 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001550 return 0;
1551}
1552
1553/** @brief implements the get SDR Info command
1554 * @param count - Operation
1555 *
1556 * @returns IPMI completion code plus response data
1557 * - sdrCount - sensor/SDR count
1558 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1559 */
1560static ipmi::RspType<uint8_t, // respcount
1561 uint8_t, // dynamic population flags
1562 uint32_t // last time a sensor was added
1563 >
1564 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1565 std::optional<uint8_t> count)
1566{
1567 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001568 uint16_t recordID = 0;
1569 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001570 // Sensors are dynamically allocated, and there is at least one LUN
1571 uint8_t lunsAndDynamicPopulation = 0x80;
1572 constexpr uint8_t getSdrCount = 0x01;
1573 constexpr uint8_t getSensorCount = 0x00;
1574
1575 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1576 {
1577 return ipmi::responseResponseError();
1578 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001579 uint16_t numSensors = getNumberOfSensors();
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001580 if (count.value_or(0) == getSdrCount)
1581 {
1582 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001583 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001584 {
1585 get_sdr::SensorDataRecordHeader* hdr =
1586 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001587 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001588 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1589 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001590 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001591 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001592 record.data());
1593 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001594 {
1595 sdrCount++;
1596 }
1597 }
1598 }
1599 }
1600 else if (count.value_or(0) == getSensorCount)
1601 {
1602 // Return the number of sensors attached to the LUN
1603 if ((ctx->lun == 0) && (numSensors > 0))
1604 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001605 sdrCount = (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN
1606 : numSensors;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001607 }
1608 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1609 {
1610 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1611 ? maxSensorsPerLUN
1612 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1613 }
1614 else if (ctx->lun == 3)
1615 {
1616 if (numSensors <= maxIPMISensors)
1617 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001618 sdrCount = (numSensors - (2 * maxSensorsPerLUN)) &
1619 maxSensorsPerLUN;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001620 }
1621 else
1622 {
1623 // error
1624 throw std::out_of_range(
1625 "Maximum number of IPMI sensors exceeded.");
1626 }
1627 }
1628 }
1629 else
1630 {
1631 return ipmi::responseInvalidFieldRequest();
1632 }
1633
1634 // Get Sensor count. This returns the number of sensors
1635 if (numSensors > 0)
1636 {
1637 lunsAndDynamicPopulation |= 1;
1638 }
1639 if (numSensors > maxSensorsPerLUN)
1640 {
1641 lunsAndDynamicPopulation |= 2;
1642 }
1643 if (numSensors >= (maxSensorsPerLUN * 2))
1644 {
1645 lunsAndDynamicPopulation |= 8;
1646 }
1647 if (numSensors > maxIPMISensors)
1648 {
1649 // error
1650 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1651 }
1652
1653 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1654 sdrLastAdd);
1655}
1656
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001657/* end sensor commands */
1658
1659/* storage commands */
1660
James Feist74c50c62019-08-14 14:18:41 -07001661ipmi::RspType<uint8_t, // sdr version
1662 uint16_t, // record count
1663 uint16_t, // free space
1664 uint32_t, // most recent addition
1665 uint32_t, // most recent erase
1666 uint8_t // operationSupport
1667 >
James Feist25690252019-12-23 12:25:49 -08001668 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001669{
James Feist74c50c62019-08-14 14:18:41 -07001670 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001671 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001672 {
James Feist74c50c62019-08-14 14:18:41 -07001673 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001674 }
1675
James Feist74c50c62019-08-14 14:18:41 -07001676 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001677 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001678 if (ret != ipmi::ccSuccess)
1679 {
1680 return ipmi::response(ret);
1681 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001682
sureshvijayv1d4b74b42021-10-08 10:49:18 +05301683 uint16_t recordCount = getNumberOfSensors() + fruCount +
1684 ipmi::storage::type12Count +
1685 ipmi::storage::nmDiscoverySDRCount;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001686
James Feist74c50c62019-08-14 14:18:41 -07001687 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001688 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001689
1690 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001691 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001692 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001693 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001694 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1695 unspecifiedFreeSpace, sdrLastAdd,
1696 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001697}
1698
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001699/** @brief implements the get SDR allocation info command
1700 *
1701 * @returns IPMI completion code plus response data
1702 * - allocUnits - Number of possible allocation units
1703 * - allocUnitSize - Allocation unit size in bytes.
1704 * - allocUnitFree - Number of free allocation units
1705 * - allocUnitLargestFree - Largest free block in allocation units
1706 * - maxRecordSize - Maximum record size in allocation units.
1707 */
1708ipmi::RspType<uint16_t, // allocUnits
1709 uint16_t, // allocUnitSize
1710 uint16_t, // allocUnitFree
1711 uint16_t, // allocUnitLargestFree
1712 uint8_t // maxRecordSize
1713 >
1714 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001715{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001716 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001717 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001718
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001719 constexpr uint16_t allocUnitFree = 0;
1720 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001721 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001722 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001723
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001724 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1725 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001726}
1727
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001728/** @brief implements the reserve SDR command
1729 * @returns IPMI completion code plus response data
1730 * - sdrReservationID
1731 */
1732ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001733{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001734 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001735 if (sdrReservationID == 0)
1736 {
1737 sdrReservationID++;
1738 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001739
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001740 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001741}
1742
James Feistb49a98a2019-04-16 13:48:09 -07001743ipmi::RspType<uint16_t, // next record ID
1744 std::vector<uint8_t> // payload
1745 >
James Feist25690252019-12-23 12:25:49 -08001746 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1747 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001748{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001749 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001750 // reservation required for partial reads with non zero offset into
1751 // record
James Feistb49a98a2019-04-16 13:48:09 -07001752 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001753 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001754 phosphor::logging::log<phosphor::logging::level::ERR>(
1755 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001756 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001757 }
James Feist25690252019-12-23 12:25:49 -08001758 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001759 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001760 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001761 phosphor::logging::log<phosphor::logging::level::ERR>(
1762 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001763 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001764 }
1765
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001766 size_t lastRecord = getNumberOfSensors() + fruCount +
Yong Lifee5e4c2020-01-17 19:36:29 +08001767 ipmi::storage::type12Count +
1768 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001769 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1770
1771 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001772 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001773 phosphor::logging::log<phosphor::logging::level::ERR>(
1774 "ipmiStorageGetSDR: getSensorSubtree error");
1775 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001776 }
1777
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001778 std::vector<uint8_t> record;
1779 if (getSensorDataRecord(ctx, record, recordID))
1780 {
1781 phosphor::logging::log<phosphor::logging::level::ERR>(
1782 "ipmiStorageGetSDR: fail to get SDR");
1783 return ipmi::responseInvalidFieldRequest();
1784 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001785 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001786 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001787 if (!hdr)
1788 {
1789 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001790 "ipmiStorageGetSDR: record header is null");
1791 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001792 }
1793
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001794 size_t sdrLength = sizeof(get_sdr::SensorDataRecordHeader) +
1795 hdr->record_length;
Jason M. Bills84c203d2023-07-21 09:55:41 -07001796 if (offset >= sdrLength)
1797 {
1798 phosphor::logging::log<phosphor::logging::level::ERR>(
1799 "ipmiStorageGetSDR: offset is outside the record");
1800 return ipmi::responseParmOutOfRange();
1801 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001802 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001803 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001804 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001805 }
1806
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001807 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001808 if (!respStart)
1809 {
1810 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001811 "ipmiStorageGetSDR: record is null");
1812 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001813 }
James Feistb49a98a2019-04-16 13:48:09 -07001814 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001815
James Feistb49a98a2019-04-16 13:48:09 -07001816 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001817}
1818/* end storage commands */
1819
1820void registerSensorFunctions()
1821{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001822 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001823 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1824 ipmi::sensor_event::cmdPlatformEvent,
1825 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001826
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001827 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001828 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1829 ipmi::sensor_event::cmdGetSensorReading,
1830 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001831
1832 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001833 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1834 ipmi::sensor_event::cmdGetSensorThreshold,
1835 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001836
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001837 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001838 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1839 ipmi::sensor_event::cmdSetSensorThreshold,
1840 ipmi::Privilege::Operator,
1841 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001842
1843 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001844 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1845 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001846 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001847
1848 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001849 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1850 ipmi::sensor_event::cmdGetSensorEventStatus,
1851 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001852
1853 // register all storage commands for both Sensor and Storage command
1854 // versions
1855
1856 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001857 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1858 ipmi::storage::cmdGetSdrRepositoryInfo,
1859 ipmi::Privilege::User,
1860 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001861
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001862 // <Get Device SDR Info>
1863 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1864 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1865 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1866
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001867 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001868 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1869 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1870 ipmi::Privilege::User,
1871 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001872
1873 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001874 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1875 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001876 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001877
Vernon Mauery98bbf692019-09-16 11:14:59 -07001878 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1879 ipmi::storage::cmdReserveSdrRepository,
1880 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001881
1882 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001883 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1884 ipmi::sensor_event::cmdGetDeviceSdr,
1885 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001886
Vernon Mauery98bbf692019-09-16 11:14:59 -07001887 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1888 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1889 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001890}
1891} // namespace ipmi