blob: fcc259378123e745475f9a5f44ac578b24b06220 [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>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070037#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070038#include <iostream>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070039#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070040#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070041#include <optional>
Patrick Venturee6154022019-09-25 17:50:25 -070042#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070043#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070044#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070045#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070046
47namespace ipmi
48{
49using ManagedObjectType =
50 std::map<sdbusplus::message::object_path,
51 std::map<std::string, std::map<std::string, DbusVariant>>>;
52
James Feist25690252019-12-23 12:25:49 -080053static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu09701ef2020-07-15 17:56:21 -070054static constexpr int sensorMapSdrUpdatePeriod = 60;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070055
56constexpr size_t maxSDRTotalSize =
57 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
58constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
59
60static uint16_t sdrReservationID;
61static uint32_t sdrLastAdd = noTimestamp;
62static uint32_t sdrLastRemove = noTimestamp;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070063static constexpr size_t lastRecordIndex = 0xFFFF;
Johnathan Mantey2346b5d2021-08-06 11:21:10 -070064
65// The IPMI spec defines four Logical Units (LUN), each capable of supporting
66// 255 sensors. The 256 values assigned to LUN 2 are special and are not used
67// for general purpose sensors. Each LUN reserves location 0xFF. The maximum
68// number of IPMI sensors are LUN 0 + LUN 1 + LUN 2, less the reserved
69// location.
70static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
71
72static constexpr size_t lun0MaxSensorNum = 0xfe;
73static constexpr size_t lun1MaxSensorNum = 0x1fe;
74static constexpr size_t lun3MaxSensorNum = 0x3fe;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070075static constexpr int GENERAL_ERROR = -1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070076
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053077SensorSubTree sensorTree;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070078
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070079static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
80
Jason M. Bills039c3492022-09-09 14:27:28 -070081constexpr static std::array<std::pair<const char*, SensorUnits>, 5> sensorUnits{
82 {{"temperature", SensorUnits::degreesC},
83 {"voltage", SensorUnits::volts},
84 {"current", SensorUnits::amps},
85 {"fan_tach", SensorUnits::rpm},
86 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070087
88void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070089
Patrick Williamsf944d2e2022-07-22 19:26:52 -050090static sdbusplus::bus::match_t sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070091 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070092 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
93 "sensors/'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -050094 [](sdbusplus::message_t& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070095 sensorTree.clear();
96 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
97 std::chrono::system_clock::now().time_since_epoch())
98 .count();
99 });
100
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500101static sdbusplus::bus::match_t sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700102 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700103 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
104 "sensors/'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500105 [](sdbusplus::message_t& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700106 sensorTree.clear();
107 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
108 std::chrono::system_clock::now().time_since_epoch())
109 .count();
110 });
111
James Feist392786a2019-03-19 13:36:10 -0700112// this keeps track of deassertions for sensor event status command. A
113// deasertion can only happen if an assertion was seen first.
114static boost::container::flat_map<
115 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
116 thresholdDeassertMap;
117
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500118static sdbusplus::bus::match_t thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700119 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700120 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
121 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500122 [](sdbusplus::message_t& m) {
Jason M. Bills0748c692022-09-08 15:34:08 -0700123 boost::container::flat_map<std::string, ipmi::DbusVariant> values;
James Feist392786a2019-03-19 13:36:10 -0700124 m.read(std::string(), values);
125
126 auto findAssert =
James Feistfcd2d3a2020-05-28 10:38:15 -0700127 std::find_if(values.begin(), values.end(), [](const auto& pair) {
James Feist392786a2019-03-19 13:36:10 -0700128 return pair.first.find("Alarm") != std::string::npos;
129 });
130 if (findAssert != values.end())
131 {
132 auto ptr = std::get_if<bool>(&(findAssert->second));
133 if (ptr == nullptr)
134 {
135 phosphor::logging::log<phosphor::logging::level::ERR>(
136 "thresholdChanged: Assert non bool");
137 return;
138 }
139 if (*ptr)
140 {
141 phosphor::logging::log<phosphor::logging::level::INFO>(
142 "thresholdChanged: Assert",
143 phosphor::logging::entry("SENSOR=%s", m.get_path()));
144 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
145 }
146 else
147 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700148 auto& value =
James Feist392786a2019-03-19 13:36:10 -0700149 thresholdDeassertMap[m.get_path()][findAssert->first];
150 if (value)
151 {
152 phosphor::logging::log<phosphor::logging::level::INFO>(
153 "thresholdChanged: deassert",
154 phosphor::logging::entry("SENSOR=%s", m.get_path()));
155 value = *ptr;
156 }
157 }
158 }
159 });
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 {
204
205 auto lower = warning->second.find("WarningLow");
206 auto upper = warning->second.find("WarningHigh");
207 if (lower != warning->second.end())
208 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700209 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700210 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700211 }
212 if (upper != warning->second.end())
213 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700214 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700215 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700216 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700217 }
218}
219
James Feist25690252019-12-23 12:25:49 -0800220static bool getSensorMap(boost::asio::yield_context yield,
221 std::string sensorConnection, std::string sensorPath,
Alex Qiu09701ef2020-07-15 17:56:21 -0700222 SensorMap& sensorMap,
223 int updatePeriod = sensorMapUpdatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700224{
225 static boost::container::flat_map<
226 std::string, std::chrono::time_point<std::chrono::steady_clock>>
227 updateTimeMap;
228
229 auto updateFind = updateTimeMap.find(sensorConnection);
230 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
231 if (updateFind != updateTimeMap.end())
232 {
233 lastUpdate = updateFind->second;
234 }
235
236 auto now = std::chrono::steady_clock::now();
237
238 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu09701ef2020-07-15 17:56:21 -0700239 .count() > updatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700240 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700241 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800242 boost::system::error_code ec;
243 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
Ed Tanousff4982a2022-10-04 17:27:35 -0700244 yield, ec, sensorConnection.c_str(), "/xyz/openbmc_project/sensors",
James Feist25690252019-12-23 12:25:49 -0800245 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
246 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700247 {
248 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800249 "GetMangagedObjects for getSensorMap failed",
250 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
251
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700252 return false;
253 }
254
255 SensorCache[sensorConnection] = managedObjects;
Alex Qiu09701ef2020-07-15 17:56:21 -0700256 // Update time after finish building the map which allow the
257 // data to be cached for updatePeriod plus the build time.
258 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700259 }
260 auto connection = SensorCache.find(sensorConnection);
261 if (connection == SensorCache.end())
262 {
263 return false;
264 }
265 auto path = connection->second.find(sensorPath);
266 if (path == connection->second.end())
267 {
268 return false;
269 }
270 sensorMap = path->second;
271
272 return true;
273}
274
275/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700276namespace meHealth
277{
James Feistfcd2d3a2020-05-28 10:38:15 -0700278constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
279constexpr const char* path = "/xyz/openbmc_project/status/me";
280constexpr const char* interface = "xyz.openbmc_project.SetHealth";
281constexpr const char* method = "SetHealth";
282constexpr const char* critical = "critical";
283constexpr const char* warning = "warning";
284constexpr const char* ok = "ok";
James Feist7aaf3fe2019-06-25 11:52:11 -0700285} // namespace meHealth
286
287static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
288{
289 constexpr const std::array<uint8_t, 10> critical = {
290 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
291 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
292 0x1A};
293
294 std::string state;
295 if (std::find(critical.begin(), critical.end(), eventData2) !=
296 critical.end())
297 {
298 state = meHealth::critical;
299 }
300 // special case 0x3 as we only care about a few states
301 else if (eventData2 == 0x3)
302 {
303 if (eventData3 <= 0x2)
304 {
305 state = meHealth::warning;
306 }
307 else
308 {
309 return;
310 }
311 }
312 else if (std::find(warning.begin(), warning.end(), eventData2) !=
313 warning.end())
314 {
315 state = meHealth::warning;
316 }
317 else
318 {
319 return;
320 }
321 if (disable)
322 {
323 state = meHealth::ok;
324 }
325
326 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
327 auto setHealth =
328 dbus->new_method_call(meHealth::busname, meHealth::path,
329 meHealth::interface, meHealth::method);
330 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
331 try
332 {
333 dbus->call(setHealth);
334 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500335 catch (const sdbusplus::exception_t&)
James Feist7aaf3fe2019-06-25 11:52:11 -0700336 {
337 phosphor::logging::log<phosphor::logging::level::ERR>(
338 "Failed to set ME Health");
339 }
340}
341
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000342ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
343 ipmi::message::Payload& p)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700344{
James Feist7aaf3fe2019-06-25 11:52:11 -0700345 constexpr const uint8_t meId = 0x2C;
346 constexpr const uint8_t meSensorNum = 0x17;
347 constexpr const uint8_t disabled = 0x80;
348
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700349 uint8_t sysgeneratorID = 0;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700350 uint8_t evmRev = 0;
351 uint8_t sensorType = 0;
352 uint8_t sensorNum = 0;
353 uint8_t eventType = 0;
354 uint8_t eventData1 = 0;
355 std::optional<uint8_t> eventData2 = 0;
356 std::optional<uint8_t> eventData3 = 0;
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700357 uint16_t generatorID = 0;
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000358 ipmi::ChannelInfo chInfo;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700359
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000360 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700361 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000362 phosphor::logging::log<phosphor::logging::level::ERR>(
363 "Failed to get Channel Info",
364 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
365 return ipmi::responseUnspecifiedError();
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700366 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000367
368 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
369 ipmi::EChannelMediumType::systemInterface)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700370 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000371
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700372 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700373 eventData1, eventData2, eventData3);
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700374 constexpr const uint8_t isSoftwareID = 0x01;
375 if (!(sysgeneratorID & isSoftwareID))
376 {
377 return ipmi::responseInvalidFieldRequest();
378 }
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700379 // Refer to IPMI Spec Table 32: SEL Event Records
380 generatorID = (ctx->channel << 12) // Channel
381 | (0x0 << 10) // Reserved
382 | (0x0 << 8) // 0x0 for sys-soft ID
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700383 | sysgeneratorID;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700384 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000385 else
386 {
387
388 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
389 eventData2, eventData3);
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700390 // Refer to IPMI Spec Table 32: SEL Event Records
391 generatorID = (ctx->channel << 12) // Channel
392 | (0x0 << 10) // Reserved
393 | ((ctx->lun & 0x3) << 8) // Lun
394 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000395 }
396
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700397 if (!p.fullyUnpacked())
398 {
399 return ipmi::responseReqDataLenInvalid();
400 }
401
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000402 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
403 if (evmRev != 0x04)
404 {
405 return ipmi::responseInvalidFieldRequest();
406 }
407 if ((sensorType > 0x2C) && (sensorType < 0xC0))
408 {
409 return ipmi::responseInvalidFieldRequest();
410 }
411
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700412 // Send this request to the Redfish hooks to log it as a Redfish message
413 // instead. There is no need to add it to the SEL, so just return success.
414 intel_oem::ipmi::sel::checkRedfishHooks(
415 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
416 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700417
Vernon Maueryce3b7572022-04-14 13:16:25 -0700418 if (static_cast<uint8_t>(generatorID) == meId && sensorNum == meSensorNum &&
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700419 eventData2 && eventData3)
James Feist7aaf3fe2019-06-25 11:52:11 -0700420 {
421 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
422 }
423
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700424 return ipmi::responseSuccess();
425}
426
James Feist0cd014a2019-04-08 15:04:33 -0700427ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700428 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700429{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700430 std::string connection;
431 std::string path;
432
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000433 if (sensnum == reservedSensorNumber)
434 {
435 return ipmi::responseInvalidFieldRequest();
436 }
437
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700438 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700439 if (status)
440 {
James Feist0cd014a2019-04-08 15:04:33 -0700441 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700442 }
443
444 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700445 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700446 {
James Feist0cd014a2019-04-08 15:04:33 -0700447 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700448 }
449 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
450
451 if (sensorObject == sensorMap.end() ||
452 sensorObject->second.find("Value") == sensorObject->second.end())
453 {
James Feist0cd014a2019-04-08 15:04:33 -0700454 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700455 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700456 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700457 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700458
Yong Li1f2eb5e2019-05-23 14:07:17 +0800459 double max = 0;
460 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700461 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700462
463 int16_t mValue = 0;
464 int16_t bValue = 0;
465 int8_t rExp = 0;
466 int8_t bExp = 0;
467 bool bSigned = false;
468
469 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
470 {
James Feist0cd014a2019-04-08 15:04:33 -0700471 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700472 }
473
James Feist0cd014a2019-04-08 15:04:33 -0700474 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700475 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700476 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700477 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700478 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800479 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700480 bool notReading = std::isnan(reading);
481
482 if (!notReading)
483 {
484 auto availableObject =
485 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
486 if (availableObject != sensorMap.end())
487 {
488 auto findAvailable = availableObject->second.find("Available");
489 if (findAvailable != availableObject->second.end())
490 {
491 bool* available = std::get_if<bool>(&(findAvailable->second));
492 if (available && !(*available))
493 {
494 notReading = true;
495 }
496 }
497 }
498 }
499
500 if (notReading)
501 {
502 operation |= static_cast<uint8_t>(
503 IPMISensorReadingByte2::readingStateUnavailable);
504 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700505
Josh Lehan06aa21a2020-10-28 21:59:06 -0700506 int byteValue;
507 if (bSigned)
508 {
509 byteValue = static_cast<int>(static_cast<int8_t>(value));
510 }
511 else
512 {
513 byteValue = static_cast<int>(static_cast<uint8_t>(value));
514 }
515
516 // Keep stats on the reading just obtained, even if it is "NaN"
517 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
518 {
519 // This is the first reading, show the coefficients
520 double step = (max - min) / 255.0;
521 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
522 << ": Range min=" << min << " max=" << max
523 << ", step=" << step
524 << ", Coefficients mValue=" << static_cast<int>(mValue)
525 << " rExp=" << static_cast<int>(rExp)
526 << " bValue=" << static_cast<int>(bValue)
527 << " bExp=" << static_cast<int>(bExp)
528 << " bSigned=" << static_cast<int>(bSigned) << "\n";
529 };
530
James Feist0cd014a2019-04-08 15:04:33 -0700531 uint8_t thresholds = 0;
532
533 auto warningObject =
534 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
535 if (warningObject != sensorMap.end())
536 {
537 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
538 auto alarmLow = warningObject->second.find("WarningAlarmLow");
539 if (alarmHigh != warningObject->second.end())
540 {
541 if (std::get<bool>(alarmHigh->second))
542 {
543 thresholds |= static_cast<uint8_t>(
544 IPMISensorReadingByte3::upperNonCritical);
545 }
546 }
547 if (alarmLow != warningObject->second.end())
548 {
549 if (std::get<bool>(alarmLow->second))
550 {
551 thresholds |= static_cast<uint8_t>(
552 IPMISensorReadingByte3::lowerNonCritical);
553 }
554 }
555 }
556
557 auto criticalObject =
558 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
559 if (criticalObject != sensorMap.end())
560 {
561 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
562 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
563 if (alarmHigh != criticalObject->second.end())
564 {
565 if (std::get<bool>(alarmHigh->second))
566 {
567 thresholds |=
568 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
569 }
570 }
571 if (alarmLow != criticalObject->second.end())
572 {
573 if (std::get<bool>(alarmLow->second))
574 {
575 thresholds |=
576 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
577 }
578 }
579 }
580
581 // no discrete as of today so optional byte is never returned
582 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700583}
584
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000585/** @brief implements the Set Sensor threshold command
586 * @param sensorNumber - sensor number
587 * @param lowerNonCriticalThreshMask
588 * @param lowerCriticalThreshMask
589 * @param lowerNonRecovThreshMask
590 * @param upperNonCriticalThreshMask
591 * @param upperCriticalThreshMask
592 * @param upperNonRecovThreshMask
593 * @param reserved
594 * @param lowerNonCritical - lower non-critical threshold
595 * @param lowerCritical - Lower critical threshold
596 * @param lowerNonRecoverable - Lower non recovarable threshold
597 * @param upperNonCritical - Upper non-critical threshold
598 * @param upperCritical - Upper critical
599 * @param upperNonRecoverable - Upper Non-recoverable
600 *
601 * @returns IPMI completion code
602 */
603ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700604 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
605 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
606 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
607 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
608 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
609 uint8_t upperNonCritical, uint8_t upperCritical,
610 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700611{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000612 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700613
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000614 if (sensorNum == reservedSensorNumber)
615 {
616 return ipmi::responseInvalidFieldRequest();
617 }
618
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000619 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000621 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700622 }
623
624 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000625 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700626 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 }
629
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 // if none of the threshold mask are set, nothing to do
631 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
632 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
633 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700634 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000635 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700636 }
637
638 std::string connection;
639 std::string path;
640
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700641 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700642 if (status)
643 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000644 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700645 }
646 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700647 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700648 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000649 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650 }
651
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700652 double max = 0;
653 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700654 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700655
656 int16_t mValue = 0;
657 int16_t bValue = 0;
658 int8_t rExp = 0;
659 int8_t bExp = 0;
660 bool bSigned = false;
661
662 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
663 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000664 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700665 }
666
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700667 // store a vector of property name, value to set, and interface
668 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
669
670 // define the indexes of the tuple
671 constexpr uint8_t propertyName = 0;
672 constexpr uint8_t thresholdValue = 1;
673 constexpr uint8_t interface = 2;
674 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000675 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700676 {
677 auto findThreshold =
678 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
679 if (findThreshold == sensorMap.end())
680 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000681 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700682 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000683 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700684 {
685 auto findLower = findThreshold->second.find("CriticalLow");
686 if (findLower == findThreshold->second.end())
687 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000688 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700689 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000690 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700691 findThreshold->first);
692 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000693 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700694 {
695 auto findUpper = findThreshold->second.find("CriticalHigh");
696 if (findUpper == findThreshold->second.end())
697 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000698 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700699 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000700 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700701 findThreshold->first);
702 }
703 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000704 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700705 {
706 auto findThreshold =
707 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
708 if (findThreshold == sensorMap.end())
709 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000710 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700711 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000712 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700713 {
714 auto findLower = findThreshold->second.find("WarningLow");
715 if (findLower == findThreshold->second.end())
716 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000717 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700718 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000719 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700720 findThreshold->first);
721 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000722 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700723 {
724 auto findUpper = findThreshold->second.find("WarningHigh");
725 if (findUpper == findThreshold->second.end())
726 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000727 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700728 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000729 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700730 findThreshold->first);
731 }
732 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700733 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700734 {
735 // from section 36.3 in the IPMI Spec, assume all linear
736 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800737 (bValue * std::pow(10.0, bExp))) *
738 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700739 setDbusProperty(
740 *getSdBus(), connection, path, std::get<interface>(property),
741 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700742 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000743 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700744}
745
James Feistfcd2d3a2020-05-28 10:38:15 -0700746IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700747{
James Feist902c4c52019-04-16 14:51:31 -0700748 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700749 auto warningInterface =
750 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
751 auto criticalInterface =
752 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
753
754 if ((warningInterface != sensorMap.end()) ||
755 (criticalInterface != sensorMap.end()))
756 {
757 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
758
759 if (sensorPair == sensorMap.end())
760 {
761 // should not have been able to find a sensor not implementing
762 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700763 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700764 }
765
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800766 double max = 0;
767 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700768 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700769
770 int16_t mValue = 0;
771 int16_t bValue = 0;
772 int8_t rExp = 0;
773 int8_t bExp = 0;
774 bool bSigned = false;
775
776 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
777 {
James Feist902c4c52019-04-16 14:51:31 -0700778 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700779 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700780 if (warningInterface != sensorMap.end())
781 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700782 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700783
784 auto warningHigh = warningMap.find("WarningHigh");
785 auto warningLow = warningMap.find("WarningLow");
786
787 if (warningHigh != warningMap.end())
788 {
James Feist902c4c52019-04-16 14:51:31 -0700789
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700790 double value =
791 std::visit(VariantToDoubleVisitor(), warningHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700792 if (std::isfinite(value))
793 {
794 resp.warningHigh = scaleIPMIValueFromDouble(
795 value, mValue, rExp, bValue, bExp, bSigned);
796 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700797 }
798 if (warningLow != warningMap.end())
799 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700800 double value =
801 std::visit(VariantToDoubleVisitor(), warningLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700802 if (std::isfinite(value))
803 {
804 resp.warningLow = scaleIPMIValueFromDouble(
805 value, mValue, rExp, bValue, bExp, bSigned);
806 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700807 }
808 }
809 if (criticalInterface != sensorMap.end())
810 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700811 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700812
813 auto criticalHigh = criticalMap.find("CriticalHigh");
814 auto criticalLow = criticalMap.find("CriticalLow");
815
816 if (criticalHigh != criticalMap.end())
817 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700818 double value =
819 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700820 if (std::isfinite(value))
821 {
822 resp.criticalHigh = scaleIPMIValueFromDouble(
823 value, mValue, rExp, bValue, bExp, bSigned);
824 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700825 }
826 if (criticalLow != criticalMap.end())
827 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700828 double value =
829 std::visit(VariantToDoubleVisitor(), criticalLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700830 if (std::isfinite(value))
831 {
832 resp.criticalLow = scaleIPMIValueFromDouble(
833 value, mValue, rExp, bValue, bExp, bSigned);
834 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700835 }
836 }
837 }
James Feist902c4c52019-04-16 14:51:31 -0700838 return resp;
839}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700840
James Feist902c4c52019-04-16 14:51:31 -0700841ipmi::RspType<uint8_t, // readable
842 uint8_t, // lowerNCrit
843 uint8_t, // lowerCrit
844 uint8_t, // lowerNrecoverable
845 uint8_t, // upperNC
846 uint8_t, // upperCrit
847 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700848 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700849{
850 std::string connection;
851 std::string path;
852
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000853 if (sensorNumber == reservedSensorNumber)
854 {
855 return ipmi::responseInvalidFieldRequest();
856 }
857
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700858 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700859 if (status)
860 {
861 return ipmi::response(status);
862 }
863
864 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700865 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700866 {
867 return ipmi::responseResponseError();
868 }
869
870 IPMIThresholds thresholdData;
871 try
872 {
873 thresholdData = getIPMIThresholds(sensorMap);
874 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500875 catch (const std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700876 {
877 return ipmi::responseResponseError();
878 }
879
880 uint8_t readable = 0;
881 uint8_t lowerNC = 0;
882 uint8_t lowerCritical = 0;
883 uint8_t lowerNonRecoverable = 0;
884 uint8_t upperNC = 0;
885 uint8_t upperCritical = 0;
886 uint8_t upperNonRecoverable = 0;
887
888 if (thresholdData.warningHigh)
889 {
890 readable |=
891 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
892 upperNC = *thresholdData.warningHigh;
893 }
894 if (thresholdData.warningLow)
895 {
896 readable |=
897 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
898 lowerNC = *thresholdData.warningLow;
899 }
900
901 if (thresholdData.criticalHigh)
902 {
903 readable |=
904 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
905 upperCritical = *thresholdData.criticalHigh;
906 }
907 if (thresholdData.criticalLow)
908 {
909 readable |=
910 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
911 lowerCritical = *thresholdData.criticalLow;
912 }
913
914 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
915 lowerNonRecoverable, upperNC, upperCritical,
916 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700917}
918
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000919/** @brief implements the get Sensor event enable command
920 * @param sensorNumber - sensor number
921 *
922 * @returns IPMI completion code plus response data
923 * - enabled - Sensor Event messages
924 * - assertionEnabledLsb - Assertion event messages
925 * - assertionEnabledMsb - Assertion event messages
926 * - deassertionEnabledLsb - Deassertion event messages
927 * - deassertionEnabledMsb - Deassertion event messages
928 */
929
930ipmi::RspType<uint8_t, // enabled
931 uint8_t, // assertionEnabledLsb
932 uint8_t, // assertionEnabledMsb
933 uint8_t, // deassertionEnabledLsb
934 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700935 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700936{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700937 std::string connection;
938 std::string path;
939
Patrick Venturea41714c2019-09-25 16:59:41 -0700940 uint8_t enabled = 0;
941 uint8_t assertionEnabledLsb = 0;
942 uint8_t assertionEnabledMsb = 0;
943 uint8_t deassertionEnabledLsb = 0;
944 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000945
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000946 if (sensorNum == reservedSensorNumber)
947 {
948 return ipmi::responseInvalidFieldRequest();
949 }
950
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700951 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700952 if (status)
953 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000954 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700955 }
956
957 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700958 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700959 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000960 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700961 }
962
963 auto warningInterface =
964 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
965 auto criticalInterface =
966 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700967 if ((warningInterface != sensorMap.end()) ||
968 (criticalInterface != sensorMap.end()))
969 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000970 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700971 IPMISensorEventEnableByte2::sensorScanningEnable);
972 if (warningInterface != sensorMap.end())
973 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700974 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700975
976 auto warningHigh = warningMap.find("WarningHigh");
977 auto warningLow = warningMap.find("WarningLow");
978 if (warningHigh != warningMap.end())
979 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700980 double value =
981 std::visit(VariantToDoubleVisitor(), warningHigh->second);
982 if (std::isfinite(value))
983 {
984 assertionEnabledLsb |=
985 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
986 upperNonCriticalGoingHigh);
987 deassertionEnabledLsb |=
988 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
989 upperNonCriticalGoingLow);
990 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700991 }
992 if (warningLow != warningMap.end())
993 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700994 double value =
995 std::visit(VariantToDoubleVisitor(), warningLow->second);
996 if (std::isfinite(value))
997 {
998 assertionEnabledLsb |=
999 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1000 lowerNonCriticalGoingLow);
1001 deassertionEnabledLsb |=
1002 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1003 lowerNonCriticalGoingHigh);
1004 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001005 }
1006 }
1007 if (criticalInterface != sensorMap.end())
1008 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001009 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001010
1011 auto criticalHigh = criticalMap.find("CriticalHigh");
1012 auto criticalLow = criticalMap.find("CriticalLow");
1013
1014 if (criticalHigh != criticalMap.end())
1015 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001016 double value =
1017 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
1018 if (std::isfinite(value))
1019 {
1020 assertionEnabledMsb |=
1021 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1022 upperCriticalGoingHigh);
1023 deassertionEnabledMsb |= static_cast<uint8_t>(
1024 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1025 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001026 }
1027 if (criticalLow != criticalMap.end())
1028 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001029 double value =
1030 std::visit(VariantToDoubleVisitor(), criticalLow->second);
1031 if (std::isfinite(value))
1032 {
1033 assertionEnabledLsb |= static_cast<uint8_t>(
1034 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1035 deassertionEnabledLsb |=
1036 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1037 lowerCriticalGoingHigh);
1038 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001039 }
1040 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001041 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001042
1043 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1044 assertionEnabledMsb, deassertionEnabledLsb,
1045 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001046}
1047
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001048/** @brief implements the get Sensor event status command
1049 * @param sensorNumber - sensor number, FFh = reserved
1050 *
1051 * @returns IPMI completion code plus response data
1052 * - sensorEventStatus - Sensor Event messages state
1053 * - assertions - Assertion event messages
1054 * - deassertions - Deassertion event messages
1055 */
1056ipmi::RspType<uint8_t, // sensorEventStatus
1057 std::bitset<16>, // assertions
1058 std::bitset<16> // deassertion
1059 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001060 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001061{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001062 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001063 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001064 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001065 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001066
1067 std::string connection;
1068 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001069 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001070 if (status)
1071 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001072 phosphor::logging::log<phosphor::logging::level::ERR>(
1073 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1074 phosphor::logging::entry("SENSOR=%d", sensorNum));
1075 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001076 }
1077
1078 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001079 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001080 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001081 phosphor::logging::log<phosphor::logging::level::ERR>(
1082 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1083 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1084 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001085 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001086 auto warningInterface =
1087 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1088 auto criticalInterface =
1089 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1090
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001091 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001092 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1093
James Feist392786a2019-03-19 13:36:10 -07001094 std::optional<bool> criticalDeassertHigh =
1095 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1096 std::optional<bool> criticalDeassertLow =
1097 thresholdDeassertMap[path]["CriticalAlarmLow"];
1098 std::optional<bool> warningDeassertHigh =
1099 thresholdDeassertMap[path]["WarningAlarmHigh"];
1100 std::optional<bool> warningDeassertLow =
1101 thresholdDeassertMap[path]["WarningAlarmLow"];
1102
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001103 std::bitset<16> assertions = 0;
1104 std::bitset<16> deassertions = 0;
1105
James Feist392786a2019-03-19 13:36:10 -07001106 if (criticalDeassertHigh && !*criticalDeassertHigh)
1107 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001108 deassertions.set(static_cast<size_t>(
1109 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001110 }
1111 if (criticalDeassertLow && !*criticalDeassertLow)
1112 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001113 deassertions.set(static_cast<size_t>(
1114 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001115 }
1116 if (warningDeassertHigh && !*warningDeassertHigh)
1117 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001118 deassertions.set(static_cast<size_t>(
1119 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001120 }
1121 if (warningDeassertLow && !*warningDeassertLow)
1122 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001123 deassertions.set(static_cast<size_t>(
1124 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001125 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001126 if ((warningInterface != sensorMap.end()) ||
1127 (criticalInterface != sensorMap.end()))
1128 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001129 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001130 IPMISensorEventEnableByte2::eventMessagesEnable);
1131 if (warningInterface != sensorMap.end())
1132 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001133 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001134
1135 auto warningHigh = warningMap.find("WarningAlarmHigh");
1136 auto warningLow = warningMap.find("WarningAlarmLow");
1137 auto warningHighAlarm = false;
1138 auto warningLowAlarm = false;
1139
1140 if (warningHigh != warningMap.end())
1141 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001142 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001143 }
1144 if (warningLow != warningMap.end())
1145 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001146 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001147 }
1148 if (warningHighAlarm)
1149 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001150 assertions.set(
1151 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1152 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153 }
1154 if (warningLowAlarm)
1155 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001156 assertions.set(
1157 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1158 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159 }
1160 }
1161 if (criticalInterface != sensorMap.end())
1162 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001163 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001164
1165 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1166 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1167 auto criticalHighAlarm = false;
1168 auto criticalLowAlarm = false;
1169
1170 if (criticalHigh != criticalMap.end())
1171 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001172 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173 }
1174 if (criticalLow != criticalMap.end())
1175 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001176 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001177 }
1178 if (criticalHighAlarm)
1179 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001180 assertions.set(
1181 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1182 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001183 }
1184 if (criticalLowAlarm)
1185 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001186 assertions.set(static_cast<size_t>(
1187 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001188 }
1189 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001190 }
1191
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001192 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001193}
1194
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001195static inline uint16_t getNumberOfSensors(void)
1196{
1197 return sensorTree.size() > maxIPMISensors ? maxIPMISensors
1198 : sensorTree.size();
1199}
1200
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001201static int getSensorDataRecord(ipmi::Context::ptr ctx,
1202 std::vector<uint8_t>& recordData,
1203 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001204{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001205 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001206 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1207 if (ret != ipmi::ccSuccess)
1208 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001209 phosphor::logging::log<phosphor::logging::level::ERR>(
1210 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001211 return GENERAL_ERROR;
1212 }
1213
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001214 size_t lastRecord = getNumberOfSensors() + fruCount +
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001215 ipmi::storage::type12Count +
1216 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001217 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001218 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001219 recordID = lastRecord;
1220 }
1221 if (recordID > lastRecord)
1222 {
1223 phosphor::logging::log<phosphor::logging::level::ERR>(
1224 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001225 return GENERAL_ERROR;
1226 }
1227
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001228 if (recordID >= getNumberOfSensors())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001229 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001230 size_t fruIndex = recordID - getNumberOfSensors();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001231 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001232
1233 if (fruIndex >= type12End)
1234 {
1235 // NM discovery SDR
1236 size_t nmDiscoveryIndex = fruIndex - type12End;
1237 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1238 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001239 phosphor::logging::log<phosphor::logging::level::ERR>(
1240 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001241 return GENERAL_ERROR;
1242 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001243 recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001244 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001245 }
1246 else if (fruIndex >= fruCount)
1247 {
1248 // handle type 12 hardcoded records
1249 size_t type12Index = fruIndex - fruCount;
1250 if (type12Index >= ipmi::storage::type12Count)
1251 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001252 phosphor::logging::log<phosphor::logging::level::ERR>(
1253 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001254 return GENERAL_ERROR;
1255 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001256 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001257 }
1258 else
1259 {
1260 // handle fru records
1261 get_sdr::SensorDataFruRecord data;
1262 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1263 if (ret != IPMI_CC_OK)
1264 {
1265 return GENERAL_ERROR;
1266 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001267 data.header.record_id_msb = recordID >> 8;
1268 data.header.record_id_lsb = recordID & 0xFF;
1269 recordData.insert(recordData.end(), (uint8_t*)&data,
1270 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001271 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001272
1273 return 0;
1274 }
1275
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001276 // Perform a incremental scan of the SDR Record ID's and translate the
1277 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
1278 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
1279 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
1280 // which has special meaning.
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001281 std::string connection;
1282 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001283 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001284 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001285 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001286 // LUN 0 has one reserved sensor number. Compensate here by adding one
1287 // to the record ID
1288 sensNumFromRecID = recordID + 1;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001289 ctx->lun = 1;
1290 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001291 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001292 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001293 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
1294 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
1295 // rules governing its use.
1296 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001297 ctx->lun = 3;
1298 }
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001299
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001300 auto status = getSensorConnection(
1301 ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001302 if (status)
1303 {
1304 phosphor::logging::log<phosphor::logging::level::ERR>(
1305 "getSensorDataRecord: getSensorConnection error");
1306 return GENERAL_ERROR;
1307 }
1308 SensorMap sensorMap;
1309 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1310 sensorMapUpdatePeriod))
1311 {
1312 phosphor::logging::log<phosphor::logging::level::ERR>(
1313 "getSensorDataRecord: getSensorMap error");
1314 return GENERAL_ERROR;
1315 }
1316 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001317 // Return an error on LUN 2 assingments, and any sensor number beyond the
1318 // range of LUN 3
1319 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
1320 (sensorNum > lun3MaxSensorNum))
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001321 {
1322 phosphor::logging::log<phosphor::logging::level::ERR>(
1323 "getSensorDataRecord: invalidSensorNumber");
1324 return GENERAL_ERROR;
1325 }
1326 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1327 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1328
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001329 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
1330 (lun != ctx->lun))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001331 {
1332 phosphor::logging::log<phosphor::logging::level::ERR>(
1333 "getSensorDataRecord: sensor record mismatch");
1334 return GENERAL_ERROR;
1335 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001336 get_sdr::SensorDataFullRecord record = {0};
1337
1338 get_sdr::header::set_record_id(
1339 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1340
1341 record.header.sdr_version = ipmiSdrVersion;
1342 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1343 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1344 sizeof(get_sdr::SensorDataRecordHeader);
1345 record.key.owner_id = 0x20;
1346 record.key.owner_lun = lun;
1347 record.key.sensor_number = sensornumber;
1348
1349 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1350 record.body.sensor_type = getSensorTypeFromPath(path);
1351 std::string type = getSensorTypeStringFromPath(path);
Jason M. Bills039c3492022-09-09 14:27:28 -07001352 for (const auto& [unitsType, units] : sensorUnits)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001353 {
Jason M. Bills039c3492022-09-09 14:27:28 -07001354 if (type == unitsType)
1355 {
1356 record.body.sensor_units_2_base = static_cast<uint8_t>(units);
1357 }
1358 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001359
1360 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1361
1362 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1363 if (sensorObject == sensorMap.end())
1364 {
1365 phosphor::logging::log<phosphor::logging::level::ERR>(
1366 "getSensorDataRecord: sensorObject error");
1367 return GENERAL_ERROR;
1368 }
1369
1370 uint8_t entityId = 0;
1371 uint8_t entityInstance = 0x01;
1372
1373 // follow the association chain to get the parent board's entityid and
1374 // entityInstance
1375 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1376
1377 record.body.entity_id = entityId;
1378 record.body.entity_instance = entityInstance;
1379
1380 auto maxObject = sensorObject->second.find("MaxValue");
1381 auto minObject = sensorObject->second.find("MinValue");
1382
1383 // If min and/or max are left unpopulated,
1384 // then default to what a signed byte would be, namely (-128,127) range.
1385 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1386 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1387 if (maxObject != sensorObject->second.end())
1388 {
1389 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1390 }
1391
1392 if (minObject != sensorObject->second.end())
1393 {
1394 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1395 }
1396
1397 int16_t mValue = 0;
1398 int8_t rExp = 0;
1399 int16_t bValue = 0;
1400 int8_t bExp = 0;
1401 bool bSigned = false;
1402
1403 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1404 {
1405 phosphor::logging::log<phosphor::logging::level::ERR>(
1406 "getSensorDataRecord: getSensorAttributes error");
1407 return GENERAL_ERROR;
1408 }
1409
1410 // The record.body is a struct SensorDataFullRecordBody
1411 // from sensorhandler.hpp in phosphor-ipmi-host.
1412 // The meaning of these bits appears to come from
1413 // table 43.1 of the IPMI spec.
1414 // The above 5 sensor attributes are stuffed in as follows:
1415 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1416 // Byte 22-24 are for other purposes
1417 // Byte 25 = MMMMMMMM = LSB of M
1418 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1419 // Byte 27 = BBBBBBBB = LSB of B
1420 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1421 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1422 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1423
1424 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1425 record.body.m_lsb = mValue & 0xFF;
1426
1427 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1428 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1429
1430 // move the smallest bit of the MSB into place (bit 9)
1431 // the MSbs are bits 7:8 in m_msb_and_tolerance
1432 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1433
1434 record.body.b_lsb = bValue & 0xFF;
1435
1436 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1437 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1438
1439 // move the smallest bit of the MSB into place (bit 9)
1440 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1441 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1442
1443 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1444 uint8_t rExpBits = rExp & 0x07;
1445
1446 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1447 uint8_t bExpBits = bExp & 0x07;
1448
1449 // move rExp and bExp into place
1450 record.body.r_b_exponents =
1451 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1452
1453 // Set the analog reading byte interpretation accordingly
1454 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1455
1456 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1457 // These seem redundant, but derivable from the above 5 attributes
1458 // Original comment said "todo fill out rest of units"
1459
1460 // populate sensor name from path
1461 std::string name;
1462 size_t nameStart = path.rfind("/");
1463 if (nameStart != std::string::npos)
1464 {
1465 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1466 }
1467
1468 std::replace(name.begin(), name.end(), '_', ' ');
1469 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1470 {
1471 // try to not truncate by replacing common words
1472 constexpr std::array<std::pair<const char*, const char*>, 2>
1473 replaceWords = {std::make_pair("Output", "Out"),
1474 std::make_pair("Input", "In")};
1475 for (const auto& [find, replace] : replaceWords)
1476 {
1477 boost::replace_all(name, find, replace);
1478 }
1479
1480 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1481 }
Paul Fertser97221512022-08-18 12:36:41 +00001482 get_sdr::body::set_id_strlen(name.size(), &record.body);
1483 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001484 std::strncpy(record.body.id_string, name.c_str(),
1485 sizeof(record.body.id_string));
1486
Josh Lehan06aa21a2020-10-28 21:59:06 -07001487 // Remember the sensor name, as determined for this sensor number
1488 details::sdrStatsTable.updateName(sensornumber, name);
1489
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001490 IPMIThresholds thresholdData;
1491 try
1492 {
1493 thresholdData = getIPMIThresholds(sensorMap);
1494 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001495 catch (const std::exception&)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001496 {
1497 phosphor::logging::log<phosphor::logging::level::ERR>(
1498 "getSensorDataRecord: getIPMIThresholds error");
1499 return GENERAL_ERROR;
1500 }
1501
1502 if (thresholdData.criticalHigh)
1503 {
1504 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1505 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1506 IPMISensorEventEnableThresholds::criticalThreshold);
1507 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1508 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1509 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1510 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1511 record.body.discrete_reading_setting_mask[0] |=
1512 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1513 }
1514 if (thresholdData.warningHigh)
1515 {
1516 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1517 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1518 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1519 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1520 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1521 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1522 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1523 record.body.discrete_reading_setting_mask[0] |=
1524 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1525 }
1526 if (thresholdData.criticalLow)
1527 {
1528 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1529 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1530 IPMISensorEventEnableThresholds::criticalThreshold);
1531 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1532 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1533 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1534 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1535 record.body.discrete_reading_setting_mask[0] |=
1536 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1537 }
1538 if (thresholdData.warningLow)
1539 {
1540 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1541 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1542 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1543 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1544 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1545 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1546 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1547 record.body.discrete_reading_setting_mask[0] |=
1548 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1549 }
1550
1551 // everything that is readable is setable
1552 record.body.discrete_reading_setting_mask[1] =
1553 record.body.discrete_reading_setting_mask[0];
1554 recordData.insert(recordData.end(), (uint8_t*)&record,
1555 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001556 return 0;
1557}
1558
1559/** @brief implements the get SDR Info command
1560 * @param count - Operation
1561 *
1562 * @returns IPMI completion code plus response data
1563 * - sdrCount - sensor/SDR count
1564 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1565 */
1566static ipmi::RspType<uint8_t, // respcount
1567 uint8_t, // dynamic population flags
1568 uint32_t // last time a sensor was added
1569 >
1570 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1571 std::optional<uint8_t> count)
1572{
1573 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001574 uint16_t recordID = 0;
1575 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001576 // Sensors are dynamically allocated, and there is at least one LUN
1577 uint8_t lunsAndDynamicPopulation = 0x80;
1578 constexpr uint8_t getSdrCount = 0x01;
1579 constexpr uint8_t getSensorCount = 0x00;
1580
1581 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1582 {
1583 return ipmi::responseResponseError();
1584 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001585 uint16_t numSensors = getNumberOfSensors();
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001586 if (count.value_or(0) == getSdrCount)
1587 {
1588 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001589 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001590 {
1591 get_sdr::SensorDataRecordHeader* hdr =
1592 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001593 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001594 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1595 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001596 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001597 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001598 record.data());
1599 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001600 {
1601 sdrCount++;
1602 }
1603 }
1604 }
1605 }
1606 else if (count.value_or(0) == getSensorCount)
1607 {
1608 // Return the number of sensors attached to the LUN
1609 if ((ctx->lun == 0) && (numSensors > 0))
1610 {
1611 sdrCount =
1612 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1613 }
1614 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1615 {
1616 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1617 ? maxSensorsPerLUN
1618 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1619 }
1620 else if (ctx->lun == 3)
1621 {
1622 if (numSensors <= maxIPMISensors)
1623 {
1624 sdrCount =
1625 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1626 }
1627 else
1628 {
1629 // error
1630 throw std::out_of_range(
1631 "Maximum number of IPMI sensors exceeded.");
1632 }
1633 }
1634 }
1635 else
1636 {
1637 return ipmi::responseInvalidFieldRequest();
1638 }
1639
1640 // Get Sensor count. This returns the number of sensors
1641 if (numSensors > 0)
1642 {
1643 lunsAndDynamicPopulation |= 1;
1644 }
1645 if (numSensors > maxSensorsPerLUN)
1646 {
1647 lunsAndDynamicPopulation |= 2;
1648 }
1649 if (numSensors >= (maxSensorsPerLUN * 2))
1650 {
1651 lunsAndDynamicPopulation |= 8;
1652 }
1653 if (numSensors > maxIPMISensors)
1654 {
1655 // error
1656 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1657 }
1658
1659 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1660 sdrLastAdd);
1661}
1662
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001663/* end sensor commands */
1664
1665/* storage commands */
1666
James Feist74c50c62019-08-14 14:18:41 -07001667ipmi::RspType<uint8_t, // sdr version
1668 uint16_t, // record count
1669 uint16_t, // free space
1670 uint32_t, // most recent addition
1671 uint32_t, // most recent erase
1672 uint8_t // operationSupport
1673 >
James Feist25690252019-12-23 12:25:49 -08001674 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001675{
James Feist74c50c62019-08-14 14:18:41 -07001676 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001677 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001678 {
James Feist74c50c62019-08-14 14:18:41 -07001679 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001680 }
1681
James Feist74c50c62019-08-14 14:18:41 -07001682 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001683 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001684 if (ret != ipmi::ccSuccess)
1685 {
1686 return ipmi::response(ret);
1687 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001688
sureshvijayv1d4b74b42021-10-08 10:49:18 +05301689 uint16_t recordCount = getNumberOfSensors() + fruCount +
1690 ipmi::storage::type12Count +
1691 ipmi::storage::nmDiscoverySDRCount;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001692
James Feist74c50c62019-08-14 14:18:41 -07001693 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001694 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001695
1696 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001697 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001698 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001699 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001700 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1701 unspecifiedFreeSpace, sdrLastAdd,
1702 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001703}
1704
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001705/** @brief implements the get SDR allocation info command
1706 *
1707 * @returns IPMI completion code plus response data
1708 * - allocUnits - Number of possible allocation units
1709 * - allocUnitSize - Allocation unit size in bytes.
1710 * - allocUnitFree - Number of free allocation units
1711 * - allocUnitLargestFree - Largest free block in allocation units
1712 * - maxRecordSize - Maximum record size in allocation units.
1713 */
1714ipmi::RspType<uint16_t, // allocUnits
1715 uint16_t, // allocUnitSize
1716 uint16_t, // allocUnitFree
1717 uint16_t, // allocUnitLargestFree
1718 uint8_t // maxRecordSize
1719 >
1720 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001721{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001722 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001723 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001724
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001725 constexpr uint16_t allocUnitFree = 0;
1726 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001727 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001728 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001729
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001730 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1731 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001732}
1733
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001734/** @brief implements the reserve SDR command
1735 * @returns IPMI completion code plus response data
1736 * - sdrReservationID
1737 */
1738ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001739{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001740 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001741 if (sdrReservationID == 0)
1742 {
1743 sdrReservationID++;
1744 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001745
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001746 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001747}
1748
James Feistb49a98a2019-04-16 13:48:09 -07001749ipmi::RspType<uint16_t, // next record ID
1750 std::vector<uint8_t> // payload
1751 >
James Feist25690252019-12-23 12:25:49 -08001752 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1753 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001754{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001755 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001756 // reservation required for partial reads with non zero offset into
1757 // record
James Feistb49a98a2019-04-16 13:48:09 -07001758 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001759 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001760 phosphor::logging::log<phosphor::logging::level::ERR>(
1761 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001762 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001763 }
James Feist25690252019-12-23 12:25:49 -08001764 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001765 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001766 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001767 phosphor::logging::log<phosphor::logging::level::ERR>(
1768 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001769 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001770 }
1771
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001772 size_t lastRecord = getNumberOfSensors() + fruCount +
Yong Lifee5e4c2020-01-17 19:36:29 +08001773 ipmi::storage::type12Count +
1774 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001775 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1776
1777 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001778 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001779 phosphor::logging::log<phosphor::logging::level::ERR>(
1780 "ipmiStorageGetSDR: getSensorSubtree error");
1781 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001782 }
1783
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001784 std::vector<uint8_t> record;
1785 if (getSensorDataRecord(ctx, record, recordID))
1786 {
1787 phosphor::logging::log<phosphor::logging::level::ERR>(
1788 "ipmiStorageGetSDR: fail to get SDR");
1789 return ipmi::responseInvalidFieldRequest();
1790 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001791 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001792 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001793 if (!hdr)
1794 {
1795 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001796 "ipmiStorageGetSDR: record header is null");
1797 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001798 }
1799
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001800 size_t sdrLength =
1801 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1802 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