blob: 2fd0fbe5a882300e1620cc6b48988bc8359556c9 [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;
64static constexpr int GENERAL_ERROR = -1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070065
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053066SensorSubTree sensorTree;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070067
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070068static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
69
Jason M. Bills17add592018-11-12 14:30:12 -080070// Specify the comparison required to sort and find char* map objects
71struct CmpStr
72{
James Feistfcd2d3a2020-05-28 10:38:15 -070073 bool operator()(const char* a, const char* b) const
Jason M. Bills17add592018-11-12 14:30:12 -080074 {
75 return std::strcmp(a, b) < 0;
76 }
77};
James Feistfcd2d3a2020-05-28 10:38:15 -070078const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
Jason M. Bills17add592018-11-12 14:30:12 -080079 sensorUnits{{{"temperature", SensorUnits::degreesC},
80 {"voltage", SensorUnits::volts},
81 {"current", SensorUnits::amps},
82 {"fan_tach", SensorUnits::rpm},
83 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070084
85void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070086
87static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070088 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070089 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
90 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -070091 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070092 sensorTree.clear();
93 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
94 std::chrono::system_clock::now().time_since_epoch())
95 .count();
96 });
97
98static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070099 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700100 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
101 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -0700102 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700103 sensorTree.clear();
104 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
105 std::chrono::system_clock::now().time_since_epoch())
106 .count();
107 });
108
James Feist392786a2019-03-19 13:36:10 -0700109// this keeps track of deassertions for sensor event status command. A
110// deasertion can only happen if an assertion was seen first.
111static boost::container::flat_map<
112 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
113 thresholdDeassertMap;
114
115static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700116 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700117 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
118 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feistfcd2d3a2020-05-28 10:38:15 -0700119 [](sdbusplus::message::message& m) {
James Feist392786a2019-03-19 13:36:10 -0700120 boost::container::flat_map<std::string, std::variant<bool, double>>
121 values;
122 m.read(std::string(), values);
123
124 auto findAssert =
James Feistfcd2d3a2020-05-28 10:38:15 -0700125 std::find_if(values.begin(), values.end(), [](const auto& pair) {
James Feist392786a2019-03-19 13:36:10 -0700126 return pair.first.find("Alarm") != std::string::npos;
127 });
128 if (findAssert != values.end())
129 {
130 auto ptr = std::get_if<bool>(&(findAssert->second));
131 if (ptr == nullptr)
132 {
133 phosphor::logging::log<phosphor::logging::level::ERR>(
134 "thresholdChanged: Assert non bool");
135 return;
136 }
137 if (*ptr)
138 {
139 phosphor::logging::log<phosphor::logging::level::INFO>(
140 "thresholdChanged: Assert",
141 phosphor::logging::entry("SENSOR=%s", m.get_path()));
142 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
143 }
144 else
145 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700146 auto& value =
James Feist392786a2019-03-19 13:36:10 -0700147 thresholdDeassertMap[m.get_path()][findAssert->first];
148 if (value)
149 {
150 phosphor::logging::log<phosphor::logging::level::INFO>(
151 "thresholdChanged: deassert",
152 phosphor::logging::entry("SENSOR=%s", m.get_path()));
153 value = *ptr;
154 }
155 }
156 }
157 });
158
James Feistfcd2d3a2020-05-28 10:38:15 -0700159static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
160 double& min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700161{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700162 max = 127;
163 min = -128;
164
James Feistaecaef72019-04-26 10:30:32 -0700165 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
166 auto critical =
167 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
168 auto warning =
169 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
170
171 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700172 {
James Feistaecaef72019-04-26 10:30:32 -0700173 auto maxMap = sensorObject->second.find("MaxValue");
174 auto minMap = sensorObject->second.find("MinValue");
175
176 if (maxMap != sensorObject->second.end())
177 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700178 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700179 }
180 if (minMap != sensorObject->second.end())
181 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700182 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700183 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700184 }
James Feistaecaef72019-04-26 10:30:32 -0700185 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700186 {
James Feistaecaef72019-04-26 10:30:32 -0700187 auto lower = critical->second.find("CriticalLow");
188 auto upper = critical->second.find("CriticalHigh");
189 if (lower != critical->second.end())
190 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700191 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700192 min = std::min(value, min);
193 }
194 if (upper != critical->second.end())
195 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700196 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700197 max = std::max(value, max);
198 }
199 }
200 if (warning != sensorMap.end())
201 {
202
203 auto lower = warning->second.find("WarningLow");
204 auto upper = warning->second.find("WarningHigh");
205 if (lower != warning->second.end())
206 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700207 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700208 min = std::min(value, min);
209 }
210 if (upper != warning->second.end())
211 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700212 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700213 max = std::max(value, max);
214 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700215 }
216}
217
James Feist25690252019-12-23 12:25:49 -0800218static bool getSensorMap(boost::asio::yield_context yield,
219 std::string sensorConnection, std::string sensorPath,
Alex Qiu09701ef2020-07-15 17:56:21 -0700220 SensorMap& sensorMap,
221 int updatePeriod = sensorMapUpdatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700222{
223 static boost::container::flat_map<
224 std::string, std::chrono::time_point<std::chrono::steady_clock>>
225 updateTimeMap;
226
227 auto updateFind = updateTimeMap.find(sensorConnection);
228 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
229 if (updateFind != updateTimeMap.end())
230 {
231 lastUpdate = updateFind->second;
232 }
233
234 auto now = std::chrono::steady_clock::now();
235
236 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu09701ef2020-07-15 17:56:21 -0700237 .count() > updatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700238 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700239 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800240 boost::system::error_code ec;
241 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
242 yield, ec, sensorConnection.c_str(), "/",
243 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
244 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700245 {
246 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800247 "GetMangagedObjects for getSensorMap failed",
248 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
249
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700250 return false;
251 }
252
253 SensorCache[sensorConnection] = managedObjects;
Alex Qiu09701ef2020-07-15 17:56:21 -0700254 // Update time after finish building the map which allow the
255 // data to be cached for updatePeriod plus the build time.
256 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700257 }
258 auto connection = SensorCache.find(sensorConnection);
259 if (connection == SensorCache.end())
260 {
261 return false;
262 }
263 auto path = connection->second.find(sensorPath);
264 if (path == connection->second.end())
265 {
266 return false;
267 }
268 sensorMap = path->second;
269
270 return true;
271}
272
273/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700274namespace meHealth
275{
James Feistfcd2d3a2020-05-28 10:38:15 -0700276constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
277constexpr const char* path = "/xyz/openbmc_project/status/me";
278constexpr const char* interface = "xyz.openbmc_project.SetHealth";
279constexpr const char* method = "SetHealth";
280constexpr const char* critical = "critical";
281constexpr const char* warning = "warning";
282constexpr const char* ok = "ok";
James Feist7aaf3fe2019-06-25 11:52:11 -0700283} // namespace meHealth
284
285static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
286{
287 constexpr const std::array<uint8_t, 10> critical = {
288 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
289 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
290 0x1A};
291
292 std::string state;
293 if (std::find(critical.begin(), critical.end(), eventData2) !=
294 critical.end())
295 {
296 state = meHealth::critical;
297 }
298 // special case 0x3 as we only care about a few states
299 else if (eventData2 == 0x3)
300 {
301 if (eventData3 <= 0x2)
302 {
303 state = meHealth::warning;
304 }
305 else
306 {
307 return;
308 }
309 }
310 else if (std::find(warning.begin(), warning.end(), eventData2) !=
311 warning.end())
312 {
313 state = meHealth::warning;
314 }
315 else
316 {
317 return;
318 }
319 if (disable)
320 {
321 state = meHealth::ok;
322 }
323
324 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
325 auto setHealth =
326 dbus->new_method_call(meHealth::busname, meHealth::path,
327 meHealth::interface, meHealth::method);
328 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
329 try
330 {
331 dbus->call(setHealth);
332 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700333 catch (sdbusplus::exception_t&)
James Feist7aaf3fe2019-06-25 11:52:11 -0700334 {
335 phosphor::logging::log<phosphor::logging::level::ERR>(
336 "Failed to set ME Health");
337 }
338}
339
James Feistfcd2d3a2020-05-28 10:38:15 -0700340ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload& p)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700341{
James Feist7aaf3fe2019-06-25 11:52:11 -0700342 constexpr const uint8_t meId = 0x2C;
343 constexpr const uint8_t meSensorNum = 0x17;
344 constexpr const uint8_t disabled = 0x80;
345
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700346 uint8_t generatorID = 0;
347 uint8_t evmRev = 0;
348 uint8_t sensorType = 0;
349 uint8_t sensorNum = 0;
350 uint8_t eventType = 0;
351 uint8_t eventData1 = 0;
352 std::optional<uint8_t> eventData2 = 0;
353 std::optional<uint8_t> eventData3 = 0;
354
355 // todo: This check is supposed to be based on the incoming channel.
356 // e.g. system channel will provide upto 8 bytes including generator
357 // ID, but ipmb channel will provide only up to 7 bytes without the
358 // generator ID.
359 // Support for this check is coming in future patches, so for now just base
360 // it on if the first byte is the EvMRev (0x04).
361 if (p.size() && p.data()[0] == 0x04)
362 {
363 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
364 eventData2, eventData3);
365 // todo: the generator ID for this channel is supposed to come from the
366 // IPMB requesters slave address. Support for this is coming in future
367 // patches, so for now just assume it is coming from the ME (0x2C).
368 generatorID = 0x2C;
369 }
370 else
371 {
372 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
373 eventData1, eventData2, eventData3);
374 }
375 if (!p.fullyUnpacked())
376 {
377 return ipmi::responseReqDataLenInvalid();
378 }
379
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700380 // Send this request to the Redfish hooks to log it as a Redfish message
381 // instead. There is no need to add it to the SEL, so just return success.
382 intel_oem::ipmi::sel::checkRedfishHooks(
383 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
384 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700385
James Feist7aaf3fe2019-06-25 11:52:11 -0700386 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
387 eventData3)
388 {
389 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
390 }
391
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700392 return ipmi::responseSuccess();
393}
394
James Feist0cd014a2019-04-08 15:04:33 -0700395ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700396 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700397{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700398 std::string connection;
399 std::string path;
400
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000401 if (sensnum == reservedSensorNumber)
402 {
403 return ipmi::responseInvalidFieldRequest();
404 }
405
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700406 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700407 if (status)
408 {
James Feist0cd014a2019-04-08 15:04:33 -0700409 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700410 }
411
412 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700413 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700414 {
James Feist0cd014a2019-04-08 15:04:33 -0700415 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700416 }
417 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
418
419 if (sensorObject == sensorMap.end() ||
420 sensorObject->second.find("Value") == sensorObject->second.end())
421 {
James Feist0cd014a2019-04-08 15:04:33 -0700422 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700423 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700424 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700425 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700426
Yong Li1f2eb5e2019-05-23 14:07:17 +0800427 double max = 0;
428 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700429 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700430
431 int16_t mValue = 0;
432 int16_t bValue = 0;
433 int8_t rExp = 0;
434 int8_t bExp = 0;
435 bool bSigned = false;
436
437 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
438 {
James Feist0cd014a2019-04-08 15:04:33 -0700439 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700440 }
441
James Feist0cd014a2019-04-08 15:04:33 -0700442 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700443 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700444 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700445 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700446 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800447 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700448 bool notReading = std::isnan(reading);
449
450 if (!notReading)
451 {
452 auto availableObject =
453 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
454 if (availableObject != sensorMap.end())
455 {
456 auto findAvailable = availableObject->second.find("Available");
457 if (findAvailable != availableObject->second.end())
458 {
459 bool* available = std::get_if<bool>(&(findAvailable->second));
460 if (available && !(*available))
461 {
462 notReading = true;
463 }
464 }
465 }
466 }
467
468 if (notReading)
469 {
470 operation |= static_cast<uint8_t>(
471 IPMISensorReadingByte2::readingStateUnavailable);
472 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700473
Josh Lehan06aa21a2020-10-28 21:59:06 -0700474 int byteValue;
475 if (bSigned)
476 {
477 byteValue = static_cast<int>(static_cast<int8_t>(value));
478 }
479 else
480 {
481 byteValue = static_cast<int>(static_cast<uint8_t>(value));
482 }
483
484 // Keep stats on the reading just obtained, even if it is "NaN"
485 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
486 {
487 // This is the first reading, show the coefficients
488 double step = (max - min) / 255.0;
489 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
490 << ": Range min=" << min << " max=" << max
491 << ", step=" << step
492 << ", Coefficients mValue=" << static_cast<int>(mValue)
493 << " rExp=" << static_cast<int>(rExp)
494 << " bValue=" << static_cast<int>(bValue)
495 << " bExp=" << static_cast<int>(bExp)
496 << " bSigned=" << static_cast<int>(bSigned) << "\n";
497 };
498
James Feist0cd014a2019-04-08 15:04:33 -0700499 uint8_t thresholds = 0;
500
501 auto warningObject =
502 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
503 if (warningObject != sensorMap.end())
504 {
505 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
506 auto alarmLow = warningObject->second.find("WarningAlarmLow");
507 if (alarmHigh != warningObject->second.end())
508 {
509 if (std::get<bool>(alarmHigh->second))
510 {
511 thresholds |= static_cast<uint8_t>(
512 IPMISensorReadingByte3::upperNonCritical);
513 }
514 }
515 if (alarmLow != warningObject->second.end())
516 {
517 if (std::get<bool>(alarmLow->second))
518 {
519 thresholds |= static_cast<uint8_t>(
520 IPMISensorReadingByte3::lowerNonCritical);
521 }
522 }
523 }
524
525 auto criticalObject =
526 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
527 if (criticalObject != sensorMap.end())
528 {
529 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
530 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
531 if (alarmHigh != criticalObject->second.end())
532 {
533 if (std::get<bool>(alarmHigh->second))
534 {
535 thresholds |=
536 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
537 }
538 }
539 if (alarmLow != criticalObject->second.end())
540 {
541 if (std::get<bool>(alarmLow->second))
542 {
543 thresholds |=
544 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
545 }
546 }
547 }
548
549 // no discrete as of today so optional byte is never returned
550 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700551}
552
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000553/** @brief implements the Set Sensor threshold command
554 * @param sensorNumber - sensor number
555 * @param lowerNonCriticalThreshMask
556 * @param lowerCriticalThreshMask
557 * @param lowerNonRecovThreshMask
558 * @param upperNonCriticalThreshMask
559 * @param upperCriticalThreshMask
560 * @param upperNonRecovThreshMask
561 * @param reserved
562 * @param lowerNonCritical - lower non-critical threshold
563 * @param lowerCritical - Lower critical threshold
564 * @param lowerNonRecoverable - Lower non recovarable threshold
565 * @param upperNonCritical - Upper non-critical threshold
566 * @param upperCritical - Upper critical
567 * @param upperNonRecoverable - Upper Non-recoverable
568 *
569 * @returns IPMI completion code
570 */
571ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700572 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
573 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
574 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
575 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
576 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
577 uint8_t upperNonCritical, uint8_t upperCritical,
578 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700579{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000580 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700581
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000582 if (sensorNum == reservedSensorNumber)
583 {
584 return ipmi::responseInvalidFieldRequest();
585 }
586
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000587 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700588 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000589 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700590 }
591
592 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000593 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700594 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000595 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700596 }
597
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000598 // if none of the threshold mask are set, nothing to do
599 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
600 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
601 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700602 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000603 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700604 }
605
606 std::string connection;
607 std::string path;
608
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700609 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700610 if (status)
611 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000612 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700613 }
614 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700615 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700616 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000617 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700618 }
619
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620 double max = 0;
621 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700622 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700623
624 int16_t mValue = 0;
625 int16_t bValue = 0;
626 int8_t rExp = 0;
627 int8_t bExp = 0;
628 bool bSigned = false;
629
630 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
631 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000632 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700633 }
634
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700635 // store a vector of property name, value to set, and interface
636 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
637
638 // define the indexes of the tuple
639 constexpr uint8_t propertyName = 0;
640 constexpr uint8_t thresholdValue = 1;
641 constexpr uint8_t interface = 2;
642 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000643 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644 {
645 auto findThreshold =
646 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
647 if (findThreshold == sensorMap.end())
648 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000649 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000651 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700652 {
653 auto findLower = findThreshold->second.find("CriticalLow");
654 if (findLower == findThreshold->second.end())
655 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000656 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700657 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000658 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700659 findThreshold->first);
660 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000661 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700662 {
663 auto findUpper = findThreshold->second.find("CriticalHigh");
664 if (findUpper == findThreshold->second.end())
665 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000666 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700667 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000668 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700669 findThreshold->first);
670 }
671 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000672 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700673 {
674 auto findThreshold =
675 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
676 if (findThreshold == sensorMap.end())
677 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000678 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700679 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000680 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700681 {
682 auto findLower = findThreshold->second.find("WarningLow");
683 if (findLower == findThreshold->second.end())
684 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000685 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700686 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000687 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700688 findThreshold->first);
689 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000690 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700691 {
692 auto findUpper = findThreshold->second.find("WarningHigh");
693 if (findUpper == findThreshold->second.end())
694 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000695 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700696 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000697 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700698 findThreshold->first);
699 }
700 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700701 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700702 {
703 // from section 36.3 in the IPMI Spec, assume all linear
704 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800705 (bValue * std::pow(10.0, bExp))) *
706 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700707 setDbusProperty(
708 *getSdBus(), connection, path, std::get<interface>(property),
709 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700710 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000711 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700712}
713
James Feistfcd2d3a2020-05-28 10:38:15 -0700714IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700715{
James Feist902c4c52019-04-16 14:51:31 -0700716 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700717 auto warningInterface =
718 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
719 auto criticalInterface =
720 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
721
722 if ((warningInterface != sensorMap.end()) ||
723 (criticalInterface != sensorMap.end()))
724 {
725 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
726
727 if (sensorPair == sensorMap.end())
728 {
729 // should not have been able to find a sensor not implementing
730 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700731 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700732 }
733
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800734 double max = 0;
735 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700736 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700737
738 int16_t mValue = 0;
739 int16_t bValue = 0;
740 int8_t rExp = 0;
741 int8_t bExp = 0;
742 bool bSigned = false;
743
744 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
745 {
James Feist902c4c52019-04-16 14:51:31 -0700746 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700747 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700748 if (warningInterface != sensorMap.end())
749 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700750 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700751
752 auto warningHigh = warningMap.find("WarningHigh");
753 auto warningLow = warningMap.find("WarningLow");
754
755 if (warningHigh != warningMap.end())
756 {
James Feist902c4c52019-04-16 14:51:31 -0700757
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700758 double value =
759 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700760 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700761 value, mValue, rExp, bValue, bExp, bSigned);
762 }
763 if (warningLow != warningMap.end())
764 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700765 double value =
766 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700767 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700768 value, mValue, rExp, bValue, bExp, bSigned);
769 }
770 }
771 if (criticalInterface != sensorMap.end())
772 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700773 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700774
775 auto criticalHigh = criticalMap.find("CriticalHigh");
776 auto criticalLow = criticalMap.find("CriticalLow");
777
778 if (criticalHigh != criticalMap.end())
779 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700780 double value =
781 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700782 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700783 value, mValue, rExp, bValue, bExp, bSigned);
784 }
785 if (criticalLow != criticalMap.end())
786 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700787 double value =
788 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700789 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700790 value, mValue, rExp, bValue, bExp, bSigned);
791 }
792 }
793 }
James Feist902c4c52019-04-16 14:51:31 -0700794 return resp;
795}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700796
James Feist902c4c52019-04-16 14:51:31 -0700797ipmi::RspType<uint8_t, // readable
798 uint8_t, // lowerNCrit
799 uint8_t, // lowerCrit
800 uint8_t, // lowerNrecoverable
801 uint8_t, // upperNC
802 uint8_t, // upperCrit
803 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700804 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700805{
806 std::string connection;
807 std::string path;
808
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000809 if (sensorNumber == reservedSensorNumber)
810 {
811 return ipmi::responseInvalidFieldRequest();
812 }
813
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700814 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700815 if (status)
816 {
817 return ipmi::response(status);
818 }
819
820 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700821 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700822 {
823 return ipmi::responseResponseError();
824 }
825
826 IPMIThresholds thresholdData;
827 try
828 {
829 thresholdData = getIPMIThresholds(sensorMap);
830 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700831 catch (std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700832 {
833 return ipmi::responseResponseError();
834 }
835
836 uint8_t readable = 0;
837 uint8_t lowerNC = 0;
838 uint8_t lowerCritical = 0;
839 uint8_t lowerNonRecoverable = 0;
840 uint8_t upperNC = 0;
841 uint8_t upperCritical = 0;
842 uint8_t upperNonRecoverable = 0;
843
844 if (thresholdData.warningHigh)
845 {
846 readable |=
847 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
848 upperNC = *thresholdData.warningHigh;
849 }
850 if (thresholdData.warningLow)
851 {
852 readable |=
853 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
854 lowerNC = *thresholdData.warningLow;
855 }
856
857 if (thresholdData.criticalHigh)
858 {
859 readable |=
860 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
861 upperCritical = *thresholdData.criticalHigh;
862 }
863 if (thresholdData.criticalLow)
864 {
865 readable |=
866 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
867 lowerCritical = *thresholdData.criticalLow;
868 }
869
870 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
871 lowerNonRecoverable, upperNC, upperCritical,
872 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700873}
874
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000875/** @brief implements the get Sensor event enable command
876 * @param sensorNumber - sensor number
877 *
878 * @returns IPMI completion code plus response data
879 * - enabled - Sensor Event messages
880 * - assertionEnabledLsb - Assertion event messages
881 * - assertionEnabledMsb - Assertion event messages
882 * - deassertionEnabledLsb - Deassertion event messages
883 * - deassertionEnabledMsb - Deassertion event messages
884 */
885
886ipmi::RspType<uint8_t, // enabled
887 uint8_t, // assertionEnabledLsb
888 uint8_t, // assertionEnabledMsb
889 uint8_t, // deassertionEnabledLsb
890 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700891 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700892{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700893 std::string connection;
894 std::string path;
895
Patrick Venturea41714c2019-09-25 16:59:41 -0700896 uint8_t enabled = 0;
897 uint8_t assertionEnabledLsb = 0;
898 uint8_t assertionEnabledMsb = 0;
899 uint8_t deassertionEnabledLsb = 0;
900 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000901
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000902 if (sensorNum == reservedSensorNumber)
903 {
904 return ipmi::responseInvalidFieldRequest();
905 }
906
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700907 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700908 if (status)
909 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000910 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700911 }
912
913 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700914 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700915 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000916 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700917 }
918
919 auto warningInterface =
920 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
921 auto criticalInterface =
922 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700923 if ((warningInterface != sensorMap.end()) ||
924 (criticalInterface != sensorMap.end()))
925 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000926 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700927 IPMISensorEventEnableByte2::sensorScanningEnable);
928 if (warningInterface != sensorMap.end())
929 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700930 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700931
932 auto warningHigh = warningMap.find("WarningHigh");
933 auto warningLow = warningMap.find("WarningLow");
934 if (warningHigh != warningMap.end())
935 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000936 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700937 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000938 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700939 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
940 }
941 if (warningLow != warningMap.end())
942 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000943 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700944 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000945 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700946 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
947 }
948 }
949 if (criticalInterface != sensorMap.end())
950 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700951 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700952
953 auto criticalHigh = criticalMap.find("CriticalHigh");
954 auto criticalLow = criticalMap.find("CriticalLow");
955
956 if (criticalHigh != criticalMap.end())
957 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000958 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700959 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000960 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700961 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
962 }
963 if (criticalLow != criticalMap.end())
964 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000965 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700966 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000967 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700968 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
969 }
970 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700971 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000972
973 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
974 assertionEnabledMsb, deassertionEnabledLsb,
975 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700976}
977
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000978/** @brief implements the get Sensor event status command
979 * @param sensorNumber - sensor number, FFh = reserved
980 *
981 * @returns IPMI completion code plus response data
982 * - sensorEventStatus - Sensor Event messages state
983 * - assertions - Assertion event messages
984 * - deassertions - Deassertion event messages
985 */
986ipmi::RspType<uint8_t, // sensorEventStatus
987 std::bitset<16>, // assertions
988 std::bitset<16> // deassertion
989 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700990 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700991{
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700992 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700993 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000994 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700995 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700996
997 std::string connection;
998 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700999 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001000 if (status)
1001 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001002 phosphor::logging::log<phosphor::logging::level::ERR>(
1003 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1004 phosphor::logging::entry("SENSOR=%d", sensorNum));
1005 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001006 }
1007
1008 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001009 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001010 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001011 phosphor::logging::log<phosphor::logging::level::ERR>(
1012 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1013 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1014 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001015 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001016 auto warningInterface =
1017 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1018 auto criticalInterface =
1019 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1020
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001021 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001022 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1023
James Feist392786a2019-03-19 13:36:10 -07001024 std::optional<bool> criticalDeassertHigh =
1025 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1026 std::optional<bool> criticalDeassertLow =
1027 thresholdDeassertMap[path]["CriticalAlarmLow"];
1028 std::optional<bool> warningDeassertHigh =
1029 thresholdDeassertMap[path]["WarningAlarmHigh"];
1030 std::optional<bool> warningDeassertLow =
1031 thresholdDeassertMap[path]["WarningAlarmLow"];
1032
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001033 std::bitset<16> assertions = 0;
1034 std::bitset<16> deassertions = 0;
1035
James Feist392786a2019-03-19 13:36:10 -07001036 if (criticalDeassertHigh && !*criticalDeassertHigh)
1037 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001038 deassertions.set(static_cast<size_t>(
1039 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001040 }
1041 if (criticalDeassertLow && !*criticalDeassertLow)
1042 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001043 deassertions.set(static_cast<size_t>(
1044 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001045 }
1046 if (warningDeassertHigh && !*warningDeassertHigh)
1047 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001048 deassertions.set(static_cast<size_t>(
1049 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001050 }
1051 if (warningDeassertLow && !*warningDeassertLow)
1052 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001053 deassertions.set(static_cast<size_t>(
1054 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001055 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001056 if ((warningInterface != sensorMap.end()) ||
1057 (criticalInterface != sensorMap.end()))
1058 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001059 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001060 IPMISensorEventEnableByte2::eventMessagesEnable);
1061 if (warningInterface != sensorMap.end())
1062 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001063 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001064
1065 auto warningHigh = warningMap.find("WarningAlarmHigh");
1066 auto warningLow = warningMap.find("WarningAlarmLow");
1067 auto warningHighAlarm = false;
1068 auto warningLowAlarm = false;
1069
1070 if (warningHigh != warningMap.end())
1071 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001072 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001073 }
1074 if (warningLow != warningMap.end())
1075 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001076 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001077 }
1078 if (warningHighAlarm)
1079 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001080 assertions.set(
1081 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1082 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001083 }
1084 if (warningLowAlarm)
1085 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001086 assertions.set(
1087 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1088 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089 }
1090 }
1091 if (criticalInterface != sensorMap.end())
1092 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001093 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001094
1095 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1096 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1097 auto criticalHighAlarm = false;
1098 auto criticalLowAlarm = false;
1099
1100 if (criticalHigh != criticalMap.end())
1101 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001102 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001103 }
1104 if (criticalLow != criticalMap.end())
1105 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001106 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001107 }
1108 if (criticalHighAlarm)
1109 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001110 assertions.set(
1111 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1112 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001113 }
1114 if (criticalLowAlarm)
1115 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001116 assertions.set(static_cast<size_t>(
1117 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118 }
1119 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120 }
1121
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001122 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001123}
1124
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001125static int getSensorDataRecord(ipmi::Context::ptr ctx,
1126 std::vector<uint8_t>& recordData,
1127 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001128{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001129 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001130 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1131 if (ret != ipmi::ccSuccess)
1132 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001133 phosphor::logging::log<phosphor::logging::level::ERR>(
1134 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001135 return GENERAL_ERROR;
1136 }
1137
1138 size_t lastRecord = sensorTree.size() + fruCount +
1139 ipmi::storage::type12Count +
1140 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001141 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001142 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001143 recordID = lastRecord;
1144 }
1145 if (recordID > lastRecord)
1146 {
1147 phosphor::logging::log<phosphor::logging::level::ERR>(
1148 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001149 return GENERAL_ERROR;
1150 }
1151
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001152 if (recordID >= sensorTree.size())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001153 {
1154 size_t fruIndex = recordID - sensorTree.size();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001155 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001156
1157 if (fruIndex >= type12End)
1158 {
1159 // NM discovery SDR
1160 size_t nmDiscoveryIndex = fruIndex - type12End;
1161 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1162 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001163 phosphor::logging::log<phosphor::logging::level::ERR>(
1164 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001165 return GENERAL_ERROR;
1166 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001167 recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001168 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001169 }
1170 else if (fruIndex >= fruCount)
1171 {
1172 // handle type 12 hardcoded records
1173 size_t type12Index = fruIndex - fruCount;
1174 if (type12Index >= ipmi::storage::type12Count)
1175 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001176 phosphor::logging::log<phosphor::logging::level::ERR>(
1177 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001178 return GENERAL_ERROR;
1179 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001180 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001181 }
1182 else
1183 {
1184 // handle fru records
1185 get_sdr::SensorDataFruRecord data;
1186 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1187 if (ret != IPMI_CC_OK)
1188 {
1189 return GENERAL_ERROR;
1190 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001191 data.header.record_id_msb = recordID >> 8;
1192 data.header.record_id_lsb = recordID & 0xFF;
1193 recordData.insert(recordData.end(), (uint8_t*)&data,
1194 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001195 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001196
1197 return 0;
1198 }
1199
1200 std::string connection;
1201 std::string path;
1202 auto status = getSensorConnection(ctx, recordID, connection, path);
1203 if (status)
1204 {
1205 phosphor::logging::log<phosphor::logging::level::ERR>(
1206 "getSensorDataRecord: getSensorConnection error");
1207 return GENERAL_ERROR;
1208 }
1209 SensorMap sensorMap;
1210 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1211 sensorMapUpdatePeriod))
1212 {
1213 phosphor::logging::log<phosphor::logging::level::ERR>(
1214 "getSensorDataRecord: getSensorMap error");
1215 return GENERAL_ERROR;
1216 }
1217 uint16_t sensorNum = getSensorNumberFromPath(path);
1218 if (sensorNum == invalidSensorNumber)
1219 {
1220 phosphor::logging::log<phosphor::logging::level::ERR>(
1221 "getSensorDataRecord: invalidSensorNumber");
1222 return GENERAL_ERROR;
1223 }
1224 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1225 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1226
1227 get_sdr::SensorDataFullRecord record = {0};
1228
1229 get_sdr::header::set_record_id(
1230 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1231
1232 record.header.sdr_version = ipmiSdrVersion;
1233 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1234 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1235 sizeof(get_sdr::SensorDataRecordHeader);
1236 record.key.owner_id = 0x20;
1237 record.key.owner_lun = lun;
1238 record.key.sensor_number = sensornumber;
1239
1240 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1241 record.body.sensor_type = getSensorTypeFromPath(path);
1242 std::string type = getSensorTypeStringFromPath(path);
1243 auto typeCstr = type.c_str();
1244 auto findUnits = sensorUnits.find(typeCstr);
1245 if (findUnits != sensorUnits.end())
1246 {
1247 record.body.sensor_units_2_base =
1248 static_cast<uint8_t>(findUnits->second);
1249 } // else default 0x0 unspecified
1250
1251 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1252
1253 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1254 if (sensorObject == sensorMap.end())
1255 {
1256 phosphor::logging::log<phosphor::logging::level::ERR>(
1257 "getSensorDataRecord: sensorObject error");
1258 return GENERAL_ERROR;
1259 }
1260
1261 uint8_t entityId = 0;
1262 uint8_t entityInstance = 0x01;
1263
1264 // follow the association chain to get the parent board's entityid and
1265 // entityInstance
1266 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1267
1268 record.body.entity_id = entityId;
1269 record.body.entity_instance = entityInstance;
1270
1271 auto maxObject = sensorObject->second.find("MaxValue");
1272 auto minObject = sensorObject->second.find("MinValue");
1273
1274 // If min and/or max are left unpopulated,
1275 // then default to what a signed byte would be, namely (-128,127) range.
1276 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1277 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1278 if (maxObject != sensorObject->second.end())
1279 {
1280 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1281 }
1282
1283 if (minObject != sensorObject->second.end())
1284 {
1285 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1286 }
1287
1288 int16_t mValue = 0;
1289 int8_t rExp = 0;
1290 int16_t bValue = 0;
1291 int8_t bExp = 0;
1292 bool bSigned = false;
1293
1294 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1295 {
1296 phosphor::logging::log<phosphor::logging::level::ERR>(
1297 "getSensorDataRecord: getSensorAttributes error");
1298 return GENERAL_ERROR;
1299 }
1300
1301 // The record.body is a struct SensorDataFullRecordBody
1302 // from sensorhandler.hpp in phosphor-ipmi-host.
1303 // The meaning of these bits appears to come from
1304 // table 43.1 of the IPMI spec.
1305 // The above 5 sensor attributes are stuffed in as follows:
1306 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1307 // Byte 22-24 are for other purposes
1308 // Byte 25 = MMMMMMMM = LSB of M
1309 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1310 // Byte 27 = BBBBBBBB = LSB of B
1311 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1312 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1313 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1314
1315 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1316 record.body.m_lsb = mValue & 0xFF;
1317
1318 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1319 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1320
1321 // move the smallest bit of the MSB into place (bit 9)
1322 // the MSbs are bits 7:8 in m_msb_and_tolerance
1323 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1324
1325 record.body.b_lsb = bValue & 0xFF;
1326
1327 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1328 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1329
1330 // move the smallest bit of the MSB into place (bit 9)
1331 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1332 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1333
1334 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1335 uint8_t rExpBits = rExp & 0x07;
1336
1337 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1338 uint8_t bExpBits = bExp & 0x07;
1339
1340 // move rExp and bExp into place
1341 record.body.r_b_exponents =
1342 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1343
1344 // Set the analog reading byte interpretation accordingly
1345 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1346
1347 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1348 // These seem redundant, but derivable from the above 5 attributes
1349 // Original comment said "todo fill out rest of units"
1350
1351 // populate sensor name from path
1352 std::string name;
1353 size_t nameStart = path.rfind("/");
1354 if (nameStart != std::string::npos)
1355 {
1356 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1357 }
1358
1359 std::replace(name.begin(), name.end(), '_', ' ');
1360 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1361 {
1362 // try to not truncate by replacing common words
1363 constexpr std::array<std::pair<const char*, const char*>, 2>
1364 replaceWords = {std::make_pair("Output", "Out"),
1365 std::make_pair("Input", "In")};
1366 for (const auto& [find, replace] : replaceWords)
1367 {
1368 boost::replace_all(name, find, replace);
1369 }
1370
1371 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1372 }
1373 record.body.id_string_info = name.size();
1374 std::strncpy(record.body.id_string, name.c_str(),
1375 sizeof(record.body.id_string));
1376
Josh Lehan06aa21a2020-10-28 21:59:06 -07001377 // Remember the sensor name, as determined for this sensor number
1378 details::sdrStatsTable.updateName(sensornumber, name);
1379
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001380 IPMIThresholds thresholdData;
1381 try
1382 {
1383 thresholdData = getIPMIThresholds(sensorMap);
1384 }
1385 catch (std::exception&)
1386 {
1387 phosphor::logging::log<phosphor::logging::level::ERR>(
1388 "getSensorDataRecord: getIPMIThresholds error");
1389 return GENERAL_ERROR;
1390 }
1391
1392 if (thresholdData.criticalHigh)
1393 {
1394 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1395 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1396 IPMISensorEventEnableThresholds::criticalThreshold);
1397 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1398 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1399 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1400 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1401 record.body.discrete_reading_setting_mask[0] |=
1402 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1403 }
1404 if (thresholdData.warningHigh)
1405 {
1406 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1407 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1408 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1409 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1410 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1411 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1412 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1413 record.body.discrete_reading_setting_mask[0] |=
1414 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1415 }
1416 if (thresholdData.criticalLow)
1417 {
1418 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1419 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1420 IPMISensorEventEnableThresholds::criticalThreshold);
1421 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1422 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1423 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1424 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1425 record.body.discrete_reading_setting_mask[0] |=
1426 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1427 }
1428 if (thresholdData.warningLow)
1429 {
1430 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1431 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1432 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1433 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1434 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1435 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1436 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1437 record.body.discrete_reading_setting_mask[0] |=
1438 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1439 }
1440
1441 // everything that is readable is setable
1442 record.body.discrete_reading_setting_mask[1] =
1443 record.body.discrete_reading_setting_mask[0];
1444 recordData.insert(recordData.end(), (uint8_t*)&record,
1445 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001446 return 0;
1447}
1448
1449/** @brief implements the get SDR Info command
1450 * @param count - Operation
1451 *
1452 * @returns IPMI completion code plus response data
1453 * - sdrCount - sensor/SDR count
1454 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1455 */
1456static ipmi::RspType<uint8_t, // respcount
1457 uint8_t, // dynamic population flags
1458 uint32_t // last time a sensor was added
1459 >
1460 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1461 std::optional<uint8_t> count)
1462{
1463 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001464 uint16_t recordID = 0;
1465 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001466 // Sensors are dynamically allocated, and there is at least one LUN
1467 uint8_t lunsAndDynamicPopulation = 0x80;
1468 constexpr uint8_t getSdrCount = 0x01;
1469 constexpr uint8_t getSensorCount = 0x00;
1470
1471 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1472 {
1473 return ipmi::responseResponseError();
1474 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001475 uint16_t numSensors = sensorTree.size();
1476 if (count.value_or(0) == getSdrCount)
1477 {
1478 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001479 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001480 {
1481 get_sdr::SensorDataRecordHeader* hdr =
1482 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001483 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001484 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1485 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001486 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001487 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001488 record.data());
1489 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001490 {
1491 sdrCount++;
1492 }
1493 }
1494 }
1495 }
1496 else if (count.value_or(0) == getSensorCount)
1497 {
1498 // Return the number of sensors attached to the LUN
1499 if ((ctx->lun == 0) && (numSensors > 0))
1500 {
1501 sdrCount =
1502 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1503 }
1504 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1505 {
1506 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1507 ? maxSensorsPerLUN
1508 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1509 }
1510 else if (ctx->lun == 3)
1511 {
1512 if (numSensors <= maxIPMISensors)
1513 {
1514 sdrCount =
1515 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1516 }
1517 else
1518 {
1519 // error
1520 throw std::out_of_range(
1521 "Maximum number of IPMI sensors exceeded.");
1522 }
1523 }
1524 }
1525 else
1526 {
1527 return ipmi::responseInvalidFieldRequest();
1528 }
1529
1530 // Get Sensor count. This returns the number of sensors
1531 if (numSensors > 0)
1532 {
1533 lunsAndDynamicPopulation |= 1;
1534 }
1535 if (numSensors > maxSensorsPerLUN)
1536 {
1537 lunsAndDynamicPopulation |= 2;
1538 }
1539 if (numSensors >= (maxSensorsPerLUN * 2))
1540 {
1541 lunsAndDynamicPopulation |= 8;
1542 }
1543 if (numSensors > maxIPMISensors)
1544 {
1545 // error
1546 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1547 }
1548
1549 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1550 sdrLastAdd);
1551}
1552
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001553/* end sensor commands */
1554
1555/* storage commands */
1556
James Feist74c50c62019-08-14 14:18:41 -07001557ipmi::RspType<uint8_t, // sdr version
1558 uint16_t, // record count
1559 uint16_t, // free space
1560 uint32_t, // most recent addition
1561 uint32_t, // most recent erase
1562 uint8_t // operationSupport
1563 >
James Feist25690252019-12-23 12:25:49 -08001564 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001565{
James Feist74c50c62019-08-14 14:18:41 -07001566 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001567 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001568 {
James Feist74c50c62019-08-14 14:18:41 -07001569 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001570 }
1571
James Feist74c50c62019-08-14 14:18:41 -07001572 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001573 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001574 if (ret != ipmi::ccSuccess)
1575 {
1576 return ipmi::response(ret);
1577 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001578
James Feist74c50c62019-08-14 14:18:41 -07001579 uint16_t recordCount =
1580 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001581
James Feist74c50c62019-08-14 14:18:41 -07001582 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001583 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001584
1585 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001586 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001587 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001588 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001589 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1590 unspecifiedFreeSpace, sdrLastAdd,
1591 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001592}
1593
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001594/** @brief implements the get SDR allocation info command
1595 *
1596 * @returns IPMI completion code plus response data
1597 * - allocUnits - Number of possible allocation units
1598 * - allocUnitSize - Allocation unit size in bytes.
1599 * - allocUnitFree - Number of free allocation units
1600 * - allocUnitLargestFree - Largest free block in allocation units
1601 * - maxRecordSize - Maximum record size in allocation units.
1602 */
1603ipmi::RspType<uint16_t, // allocUnits
1604 uint16_t, // allocUnitSize
1605 uint16_t, // allocUnitFree
1606 uint16_t, // allocUnitLargestFree
1607 uint8_t // maxRecordSize
1608 >
1609 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001610{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001611 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001612 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001613
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001614 constexpr uint16_t allocUnitFree = 0;
1615 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001616 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001617 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001618
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001619 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1620 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001621}
1622
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001623/** @brief implements the reserve SDR command
1624 * @returns IPMI completion code plus response data
1625 * - sdrReservationID
1626 */
1627ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001628{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001629 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001630 if (sdrReservationID == 0)
1631 {
1632 sdrReservationID++;
1633 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001634
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001635 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001636}
1637
James Feistb49a98a2019-04-16 13:48:09 -07001638ipmi::RspType<uint16_t, // next record ID
1639 std::vector<uint8_t> // payload
1640 >
James Feist25690252019-12-23 12:25:49 -08001641 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1642 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001643{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001644 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001645 // reservation required for partial reads with non zero offset into
1646 // record
James Feistb49a98a2019-04-16 13:48:09 -07001647 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001648 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001649 phosphor::logging::log<phosphor::logging::level::ERR>(
1650 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001651 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001652 }
James Feist25690252019-12-23 12:25:49 -08001653 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001654 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001655 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001656 phosphor::logging::log<phosphor::logging::level::ERR>(
1657 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001658 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001659 }
1660
Yong Lifee5e4c2020-01-17 19:36:29 +08001661 size_t lastRecord = sensorTree.size() + fruCount +
1662 ipmi::storage::type12Count +
1663 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001664 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1665
1666 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001667 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001668 phosphor::logging::log<phosphor::logging::level::ERR>(
1669 "ipmiStorageGetSDR: getSensorSubtree error");
1670 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001671 }
1672
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001673 std::vector<uint8_t> record;
1674 if (getSensorDataRecord(ctx, record, recordID))
1675 {
1676 phosphor::logging::log<phosphor::logging::level::ERR>(
1677 "ipmiStorageGetSDR: fail to get SDR");
1678 return ipmi::responseInvalidFieldRequest();
1679 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001680 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001681 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001682 if (!hdr)
1683 {
1684 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001685 "ipmiStorageGetSDR: record header is null");
1686 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001687 }
1688
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001689 size_t sdrLength =
1690 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1691 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001692 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001693 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001694 }
1695
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001696 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001697 if (!respStart)
1698 {
1699 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001700 "ipmiStorageGetSDR: record is null");
1701 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001702 }
James Feistb49a98a2019-04-16 13:48:09 -07001703 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001704
James Feistb49a98a2019-04-16 13:48:09 -07001705 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001706}
1707/* end storage commands */
1708
1709void registerSensorFunctions()
1710{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001711 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001712 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1713 ipmi::sensor_event::cmdPlatformEvent,
1714 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001715
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001716 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001717 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1718 ipmi::sensor_event::cmdGetSensorReading,
1719 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001720
1721 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001722 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1723 ipmi::sensor_event::cmdGetSensorThreshold,
1724 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001725
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001726 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001727 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1728 ipmi::sensor_event::cmdSetSensorThreshold,
1729 ipmi::Privilege::Operator,
1730 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001731
1732 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001733 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1734 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001735 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001736
1737 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001738 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1739 ipmi::sensor_event::cmdGetSensorEventStatus,
1740 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001741
1742 // register all storage commands for both Sensor and Storage command
1743 // versions
1744
1745 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001746 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1747 ipmi::storage::cmdGetSdrRepositoryInfo,
1748 ipmi::Privilege::User,
1749 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001750
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001751 // <Get Device SDR Info>
1752 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1753 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1754 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1755
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001756 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001757 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1758 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1759 ipmi::Privilege::User,
1760 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001761
1762 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001763 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1764 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001765 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001766
Vernon Mauery98bbf692019-09-16 11:14:59 -07001767 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1768 ipmi::storage::cmdReserveSdrRepository,
1769 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001770
1771 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001772 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1773 ipmi::sensor_event::cmdGetDeviceSdr,
1774 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001775
Vernon Mauery98bbf692019-09-16 11:14:59 -07001776 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1777 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1778 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001779}
1780} // namespace ipmi