blob: d6e6cef56699805e0cf1e9a837578c4ac11a7322 [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
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070017#include <boost/algorithm/string.hpp>
18#include <boost/container/flat_map.hpp>
19#include <chrono>
20#include <cmath>
21#include <commandutils.hpp>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070022#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070023#include <iostream>
Jason M. Bills99b78ec2019-01-18 10:42:18 -080024#include <ipmi_to_redfish_hooks.hpp>
James Feist2a265d52019-04-08 11:16:27 -070025#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070026#include <ipmid/utils.hpp>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070027#include <map>
Patrick Venturec4e9de62019-09-25 17:40:54 -070028#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070029#include <phosphor-logging/log.hpp>
30#include <sdbusplus/bus.hpp>
31#include <sdrutils.hpp>
32#include <sensorcommands.hpp>
33#include <sensorutils.hpp>
34#include <storagecommands.hpp>
35#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070036#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070037#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070038
39namespace ipmi
40{
41using ManagedObjectType =
42 std::map<sdbusplus::message::object_path,
43 std::map<std::string, std::map<std::string, DbusVariant>>>;
44
45using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
46
47static constexpr int sensorListUpdatePeriod = 10;
48static constexpr int sensorMapUpdatePeriod = 2;
49
50constexpr size_t maxSDRTotalSize =
51 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
52constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
53
54static uint16_t sdrReservationID;
55static uint32_t sdrLastAdd = noTimestamp;
56static uint32_t sdrLastRemove = noTimestamp;
57
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053058SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070059static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
60
Jason M. Bills17add592018-11-12 14:30:12 -080061// Specify the comparison required to sort and find char* map objects
62struct CmpStr
63{
64 bool operator()(const char *a, const char *b) const
65 {
66 return std::strcmp(a, b) < 0;
67 }
68};
69const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
70 sensorUnits{{{"temperature", SensorUnits::degreesC},
71 {"voltage", SensorUnits::volts},
72 {"current", SensorUnits::amps},
73 {"fan_tach", SensorUnits::rpm},
74 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070075
76void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070077
78static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070079 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070080 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
81 "sensors/'",
82 [](sdbusplus::message::message &m) {
83 sensorTree.clear();
84 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
85 std::chrono::system_clock::now().time_since_epoch())
86 .count();
87 });
88
89static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070090 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070091 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
92 "sensors/'",
93 [](sdbusplus::message::message &m) {
94 sensorTree.clear();
95 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
96 std::chrono::system_clock::now().time_since_epoch())
97 .count();
98 });
99
James Feist392786a2019-03-19 13:36:10 -0700100// this keeps track of deassertions for sensor event status command. A
101// deasertion can only happen if an assertion was seen first.
102static boost::container::flat_map<
103 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
104 thresholdDeassertMap;
105
106static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700107 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700108 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
109 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
110 [](sdbusplus::message::message &m) {
111 boost::container::flat_map<std::string, std::variant<bool, double>>
112 values;
113 m.read(std::string(), values);
114
115 auto findAssert =
116 std::find_if(values.begin(), values.end(), [](const auto &pair) {
117 return pair.first.find("Alarm") != std::string::npos;
118 });
119 if (findAssert != values.end())
120 {
121 auto ptr = std::get_if<bool>(&(findAssert->second));
122 if (ptr == nullptr)
123 {
124 phosphor::logging::log<phosphor::logging::level::ERR>(
125 "thresholdChanged: Assert non bool");
126 return;
127 }
128 if (*ptr)
129 {
130 phosphor::logging::log<phosphor::logging::level::INFO>(
131 "thresholdChanged: Assert",
132 phosphor::logging::entry("SENSOR=%s", m.get_path()));
133 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
134 }
135 else
136 {
137 auto &value =
138 thresholdDeassertMap[m.get_path()][findAssert->first];
139 if (value)
140 {
141 phosphor::logging::log<phosphor::logging::level::INFO>(
142 "thresholdChanged: deassert",
143 phosphor::logging::entry("SENSOR=%s", m.get_path()));
144 value = *ptr;
145 }
146 }
147 }
148 });
149
James Feistaecaef72019-04-26 10:30:32 -0700150static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
151 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700152{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700153 max = 127;
154 min = -128;
155
James Feistaecaef72019-04-26 10:30:32 -0700156 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
157 auto critical =
158 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
159 auto warning =
160 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
161
162 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700163 {
James Feistaecaef72019-04-26 10:30:32 -0700164 auto maxMap = sensorObject->second.find("MaxValue");
165 auto minMap = sensorObject->second.find("MinValue");
166
167 if (maxMap != sensorObject->second.end())
168 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700169 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700170 }
171 if (minMap != sensorObject->second.end())
172 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700173 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700174 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700175 }
James Feistaecaef72019-04-26 10:30:32 -0700176 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700177 {
James Feistaecaef72019-04-26 10:30:32 -0700178 auto lower = critical->second.find("CriticalLow");
179 auto upper = critical->second.find("CriticalHigh");
180 if (lower != critical->second.end())
181 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700182 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700183 min = std::min(value, min);
184 }
185 if (upper != critical->second.end())
186 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700187 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700188 max = std::max(value, max);
189 }
190 }
191 if (warning != sensorMap.end())
192 {
193
194 auto lower = warning->second.find("WarningLow");
195 auto upper = warning->second.find("WarningHigh");
196 if (lower != warning->second.end())
197 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700198 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700199 min = std::min(value, min);
200 }
201 if (upper != warning->second.end())
202 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700203 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700204 max = std::max(value, max);
205 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700206 }
207}
208
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700209static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
210 SensorMap &sensorMap)
211{
212 static boost::container::flat_map<
213 std::string, std::chrono::time_point<std::chrono::steady_clock>>
214 updateTimeMap;
215
216 auto updateFind = updateTimeMap.find(sensorConnection);
217 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
218 if (updateFind != updateTimeMap.end())
219 {
220 lastUpdate = updateFind->second;
221 }
222
223 auto now = std::chrono::steady_clock::now();
224
225 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
226 .count() > sensorMapUpdatePeriod)
227 {
228 updateTimeMap[sensorConnection] = now;
229
Vernon Mauery15419dd2019-05-24 09:40:30 -0700230 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
231 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700232 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
233 "GetManagedObjects");
234
235 ManagedObjectType managedObjects;
236 try
237 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700238 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700239 reply.read(managedObjects);
240 }
241 catch (sdbusplus::exception_t &)
242 {
243 phosphor::logging::log<phosphor::logging::level::ERR>(
244 "Error getting managed objects from connection",
245 phosphor::logging::entry("CONNECTION=%s",
246 sensorConnection.c_str()));
247 return false;
248 }
249
250 SensorCache[sensorConnection] = managedObjects;
251 }
252 auto connection = SensorCache.find(sensorConnection);
253 if (connection == SensorCache.end())
254 {
255 return false;
256 }
257 auto path = connection->second.find(sensorPath);
258 if (path == connection->second.end())
259 {
260 return false;
261 }
262 sensorMap = path->second;
263
264 return true;
265}
266
267/* sensor commands */
268ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
269 ipmi_request_t request,
270 ipmi_response_t response,
271 ipmi_data_len_t dataLen,
272 ipmi_context_t context)
273{
274 *dataLen = 0;
275 printCommand(+netfn, +cmd);
276 return IPMI_CC_INVALID;
277}
278
James Feist7aaf3fe2019-06-25 11:52:11 -0700279namespace meHealth
280{
281constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
282constexpr const char *path = "/xyz/openbmc_project/status/me";
283constexpr const char *interface = "xyz.openbmc_project.SetHealth";
284constexpr const char *method = "SetHealth";
285constexpr const char *critical = "critical";
286constexpr const char *warning = "warning";
287constexpr const char *ok = "ok";
288} // namespace meHealth
289
290static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
291{
292 constexpr const std::array<uint8_t, 10> critical = {
293 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
294 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
295 0x1A};
296
297 std::string state;
298 if (std::find(critical.begin(), critical.end(), eventData2) !=
299 critical.end())
300 {
301 state = meHealth::critical;
302 }
303 // special case 0x3 as we only care about a few states
304 else if (eventData2 == 0x3)
305 {
306 if (eventData3 <= 0x2)
307 {
308 state = meHealth::warning;
309 }
310 else
311 {
312 return;
313 }
314 }
315 else if (std::find(warning.begin(), warning.end(), eventData2) !=
316 warning.end())
317 {
318 state = meHealth::warning;
319 }
320 else
321 {
322 return;
323 }
324 if (disable)
325 {
326 state = meHealth::ok;
327 }
328
329 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
330 auto setHealth =
331 dbus->new_method_call(meHealth::busname, meHealth::path,
332 meHealth::interface, meHealth::method);
333 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
334 try
335 {
336 dbus->call(setHealth);
337 }
338 catch (sdbusplus::exception_t &)
339 {
340 phosphor::logging::log<phosphor::logging::level::ERR>(
341 "Failed to set ME Health");
342 }
343}
344
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700345ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
346{
James Feist7aaf3fe2019-06-25 11:52:11 -0700347 constexpr const uint8_t meId = 0x2C;
348 constexpr const uint8_t meSensorNum = 0x17;
349 constexpr const uint8_t disabled = 0x80;
350
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700351 uint8_t generatorID = 0;
352 uint8_t evmRev = 0;
353 uint8_t sensorType = 0;
354 uint8_t sensorNum = 0;
355 uint8_t eventType = 0;
356 uint8_t eventData1 = 0;
357 std::optional<uint8_t> eventData2 = 0;
358 std::optional<uint8_t> eventData3 = 0;
359
360 // todo: This check is supposed to be based on the incoming channel.
361 // e.g. system channel will provide upto 8 bytes including generator
362 // ID, but ipmb channel will provide only up to 7 bytes without the
363 // generator ID.
364 // Support for this check is coming in future patches, so for now just base
365 // it on if the first byte is the EvMRev (0x04).
366 if (p.size() && p.data()[0] == 0x04)
367 {
368 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
369 eventData2, eventData3);
370 // todo: the generator ID for this channel is supposed to come from the
371 // IPMB requesters slave address. Support for this is coming in future
372 // patches, so for now just assume it is coming from the ME (0x2C).
373 generatorID = 0x2C;
374 }
375 else
376 {
377 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
378 eventData1, eventData2, eventData3);
379 }
380 if (!p.fullyUnpacked())
381 {
382 return ipmi::responseReqDataLenInvalid();
383 }
384
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700385 // Send this request to the Redfish hooks to log it as a Redfish message
386 // instead. There is no need to add it to the SEL, so just return success.
387 intel_oem::ipmi::sel::checkRedfishHooks(
388 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
389 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700390
James Feist7aaf3fe2019-06-25 11:52:11 -0700391 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
392 eventData3)
393 {
394 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
395 }
396
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700397 return ipmi::responseSuccess();
398}
399
James Feist0cd014a2019-04-08 15:04:33 -0700400ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
401 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700402{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700403 std::string connection;
404 std::string path;
405
406 auto status = getSensorConnection(sensnum, connection, path);
407 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;
413 if (!getSensorMap(connection, path, sensorMap))
414 {
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 Feist0cd014a2019-04-08 15:04:33 -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);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700448
James Feist0cd014a2019-04-08 15:04:33 -0700449 uint8_t thresholds = 0;
450
451 auto warningObject =
452 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
453 if (warningObject != sensorMap.end())
454 {
455 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
456 auto alarmLow = warningObject->second.find("WarningAlarmLow");
457 if (alarmHigh != warningObject->second.end())
458 {
459 if (std::get<bool>(alarmHigh->second))
460 {
461 thresholds |= static_cast<uint8_t>(
462 IPMISensorReadingByte3::upperNonCritical);
463 }
464 }
465 if (alarmLow != warningObject->second.end())
466 {
467 if (std::get<bool>(alarmLow->second))
468 {
469 thresholds |= static_cast<uint8_t>(
470 IPMISensorReadingByte3::lowerNonCritical);
471 }
472 }
473 }
474
475 auto criticalObject =
476 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
477 if (criticalObject != sensorMap.end())
478 {
479 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
480 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
481 if (alarmHigh != criticalObject->second.end())
482 {
483 if (std::get<bool>(alarmHigh->second))
484 {
485 thresholds |=
486 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
487 }
488 }
489 if (alarmLow != criticalObject->second.end())
490 {
491 if (std::get<bool>(alarmLow->second))
492 {
493 thresholds |=
494 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
495 }
496 }
497 }
498
499 // no discrete as of today so optional byte is never returned
500 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700501}
502
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000503/** @brief implements the Set Sensor threshold command
504 * @param sensorNumber - sensor number
505 * @param lowerNonCriticalThreshMask
506 * @param lowerCriticalThreshMask
507 * @param lowerNonRecovThreshMask
508 * @param upperNonCriticalThreshMask
509 * @param upperCriticalThreshMask
510 * @param upperNonRecovThreshMask
511 * @param reserved
512 * @param lowerNonCritical - lower non-critical threshold
513 * @param lowerCritical - Lower critical threshold
514 * @param lowerNonRecoverable - Lower non recovarable threshold
515 * @param upperNonCritical - Upper non-critical threshold
516 * @param upperCritical - Upper critical
517 * @param upperNonRecoverable - Upper Non-recoverable
518 *
519 * @returns IPMI completion code
520 */
521ipmi::RspType<> ipmiSenSetSensorThresholds(
522 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
523 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
524 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
525 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
526 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
527 uint8_t upperNonCritical, uint8_t upperCritical,
528 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700529{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000530 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700531
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000532 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700533 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000534 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700535 }
536
537 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000538 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700539 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000540 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700541 }
542
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000543 // if none of the threshold mask are set, nothing to do
544 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
545 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
546 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700547 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000548 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700549 }
550
551 std::string connection;
552 std::string path;
553
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000554 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700555 if (status)
556 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000557 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700558 }
559 SensorMap sensorMap;
560 if (!getSensorMap(connection, path, sensorMap))
561 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000562 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700563 }
564
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700565 double max = 0;
566 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700567 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700568
569 int16_t mValue = 0;
570 int16_t bValue = 0;
571 int8_t rExp = 0;
572 int8_t bExp = 0;
573 bool bSigned = false;
574
575 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
576 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000577 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700578 }
579
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700580 // store a vector of property name, value to set, and interface
581 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
582
583 // define the indexes of the tuple
584 constexpr uint8_t propertyName = 0;
585 constexpr uint8_t thresholdValue = 1;
586 constexpr uint8_t interface = 2;
587 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000588 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700589 {
590 auto findThreshold =
591 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
592 if (findThreshold == sensorMap.end())
593 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000594 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700595 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000596 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700597 {
598 auto findLower = findThreshold->second.find("CriticalLow");
599 if (findLower == findThreshold->second.end())
600 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000601 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700602 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000603 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700604 findThreshold->first);
605 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000606 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700607 {
608 auto findUpper = findThreshold->second.find("CriticalHigh");
609 if (findUpper == findThreshold->second.end())
610 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000611 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700612 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000613 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700614 findThreshold->first);
615 }
616 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000617 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700618 {
619 auto findThreshold =
620 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
621 if (findThreshold == sensorMap.end())
622 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000623 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700624 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000625 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700626 {
627 auto findLower = findThreshold->second.find("WarningLow");
628 if (findLower == findThreshold->second.end())
629 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000632 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700633 findThreshold->first);
634 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000635 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700636 {
637 auto findUpper = findThreshold->second.find("WarningHigh");
638 if (findUpper == findThreshold->second.end())
639 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000640 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700641 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000642 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700643 findThreshold->first);
644 }
645 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700646 for (const auto &property : thresholdsToSet)
647 {
648 // from section 36.3 in the IPMI Spec, assume all linear
649 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
650 (bValue * std::pow(10, bExp))) *
651 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700652 setDbusProperty(
653 *getSdBus(), connection, path, std::get<interface>(property),
654 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700655 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000656 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700657}
658
James Feist902c4c52019-04-16 14:51:31 -0700659IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700660{
James Feist902c4c52019-04-16 14:51:31 -0700661 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700662 auto warningInterface =
663 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
664 auto criticalInterface =
665 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
666
667 if ((warningInterface != sensorMap.end()) ||
668 (criticalInterface != sensorMap.end()))
669 {
670 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
671
672 if (sensorPair == sensorMap.end())
673 {
674 // should not have been able to find a sensor not implementing
675 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700676 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700677 }
678
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800679 double max = 0;
680 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700681 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700682
683 int16_t mValue = 0;
684 int16_t bValue = 0;
685 int8_t rExp = 0;
686 int8_t bExp = 0;
687 bool bSigned = false;
688
689 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
690 {
James Feist902c4c52019-04-16 14:51:31 -0700691 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700692 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700693 if (warningInterface != sensorMap.end())
694 {
695 auto &warningMap = warningInterface->second;
696
697 auto warningHigh = warningMap.find("WarningHigh");
698 auto warningLow = warningMap.find("WarningLow");
699
700 if (warningHigh != warningMap.end())
701 {
James Feist902c4c52019-04-16 14:51:31 -0700702
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700703 double value =
704 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700705 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700706 value, mValue, rExp, bValue, bExp, bSigned);
707 }
708 if (warningLow != warningMap.end())
709 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700710 double value =
711 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700712 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700713 value, mValue, rExp, bValue, bExp, bSigned);
714 }
715 }
716 if (criticalInterface != sensorMap.end())
717 {
718 auto &criticalMap = criticalInterface->second;
719
720 auto criticalHigh = criticalMap.find("CriticalHigh");
721 auto criticalLow = criticalMap.find("CriticalLow");
722
723 if (criticalHigh != criticalMap.end())
724 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700725 double value =
726 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700727 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700728 value, mValue, rExp, bValue, bExp, bSigned);
729 }
730 if (criticalLow != criticalMap.end())
731 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700732 double value =
733 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700734 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700735 value, mValue, rExp, bValue, bExp, bSigned);
736 }
737 }
738 }
James Feist902c4c52019-04-16 14:51:31 -0700739 return resp;
740}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700741
James Feist902c4c52019-04-16 14:51:31 -0700742ipmi::RspType<uint8_t, // readable
743 uint8_t, // lowerNCrit
744 uint8_t, // lowerCrit
745 uint8_t, // lowerNrecoverable
746 uint8_t, // upperNC
747 uint8_t, // upperCrit
748 uint8_t> // upperNRecoverable
749 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
750{
751 std::string connection;
752 std::string path;
753
754 auto status = getSensorConnection(sensorNumber, connection, path);
755 if (status)
756 {
757 return ipmi::response(status);
758 }
759
760 SensorMap sensorMap;
761 if (!getSensorMap(connection, path, sensorMap))
762 {
763 return ipmi::responseResponseError();
764 }
765
766 IPMIThresholds thresholdData;
767 try
768 {
769 thresholdData = getIPMIThresholds(sensorMap);
770 }
771 catch (std::exception &)
772 {
773 return ipmi::responseResponseError();
774 }
775
776 uint8_t readable = 0;
777 uint8_t lowerNC = 0;
778 uint8_t lowerCritical = 0;
779 uint8_t lowerNonRecoverable = 0;
780 uint8_t upperNC = 0;
781 uint8_t upperCritical = 0;
782 uint8_t upperNonRecoverable = 0;
783
784 if (thresholdData.warningHigh)
785 {
786 readable |=
787 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
788 upperNC = *thresholdData.warningHigh;
789 }
790 if (thresholdData.warningLow)
791 {
792 readable |=
793 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
794 lowerNC = *thresholdData.warningLow;
795 }
796
797 if (thresholdData.criticalHigh)
798 {
799 readable |=
800 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
801 upperCritical = *thresholdData.criticalHigh;
802 }
803 if (thresholdData.criticalLow)
804 {
805 readable |=
806 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
807 lowerCritical = *thresholdData.criticalLow;
808 }
809
810 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
811 lowerNonRecoverable, upperNC, upperCritical,
812 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700813}
814
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000815/** @brief implements the get Sensor event enable command
816 * @param sensorNumber - sensor number
817 *
818 * @returns IPMI completion code plus response data
819 * - enabled - Sensor Event messages
820 * - assertionEnabledLsb - Assertion event messages
821 * - assertionEnabledMsb - Assertion event messages
822 * - deassertionEnabledLsb - Deassertion event messages
823 * - deassertionEnabledMsb - Deassertion event messages
824 */
825
826ipmi::RspType<uint8_t, // enabled
827 uint8_t, // assertionEnabledLsb
828 uint8_t, // assertionEnabledMsb
829 uint8_t, // deassertionEnabledLsb
830 uint8_t> // deassertionEnabledMsb
831 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700832{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700833 std::string connection;
834 std::string path;
835
Patrick Venturea41714c2019-09-25 16:59:41 -0700836 uint8_t enabled = 0;
837 uint8_t assertionEnabledLsb = 0;
838 uint8_t assertionEnabledMsb = 0;
839 uint8_t deassertionEnabledLsb = 0;
840 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000841
842 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700843 if (status)
844 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000845 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700846 }
847
848 SensorMap sensorMap;
849 if (!getSensorMap(connection, path, sensorMap))
850 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000851 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700852 }
853
854 auto warningInterface =
855 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
856 auto criticalInterface =
857 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700858 if ((warningInterface != sensorMap.end()) ||
859 (criticalInterface != sensorMap.end()))
860 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000861 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700862 IPMISensorEventEnableByte2::sensorScanningEnable);
863 if (warningInterface != sensorMap.end())
864 {
865 auto &warningMap = warningInterface->second;
866
867 auto warningHigh = warningMap.find("WarningHigh");
868 auto warningLow = warningMap.find("WarningLow");
869 if (warningHigh != warningMap.end())
870 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000871 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700872 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000873 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700874 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
875 }
876 if (warningLow != warningMap.end())
877 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000878 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700879 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000880 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700881 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
882 }
883 }
884 if (criticalInterface != sensorMap.end())
885 {
886 auto &criticalMap = criticalInterface->second;
887
888 auto criticalHigh = criticalMap.find("CriticalHigh");
889 auto criticalLow = criticalMap.find("CriticalLow");
890
891 if (criticalHigh != criticalMap.end())
892 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000893 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700894 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000895 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700896 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
897 }
898 if (criticalLow != criticalMap.end())
899 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000900 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700901 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000902 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700903 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
904 }
905 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700906 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000907
908 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
909 assertionEnabledMsb, deassertionEnabledLsb,
910 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700911}
912
913ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
914 ipmi_request_t request,
915 ipmi_response_t response,
916 ipmi_data_len_t dataLen,
917 ipmi_context_t context)
918{
919 if (*dataLen != 1)
920 {
921 *dataLen = 0;
922 return IPMI_CC_REQ_DATA_LEN_INVALID;
923 }
924 *dataLen = 0; // default to 0 in case of an error
925
926 uint8_t sensnum = *(static_cast<uint8_t *>(request));
927
928 std::string connection;
929 std::string path;
930
931 auto status = getSensorConnection(sensnum, connection, path);
932 if (status)
933 {
934 return status;
935 }
936
937 SensorMap sensorMap;
938 if (!getSensorMap(connection, path, sensorMap))
939 {
940 return IPMI_CC_RESPONSE_ERROR;
941 }
942
943 auto warningInterface =
944 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
945 auto criticalInterface =
946 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
947
948 // zero out response buff
949 auto responseClear = static_cast<uint8_t *>(response);
950 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
951 auto resp = static_cast<SensorEventStatusResp *>(response);
952 resp->enabled =
953 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
954
James Feist392786a2019-03-19 13:36:10 -0700955 std::optional<bool> criticalDeassertHigh =
956 thresholdDeassertMap[path]["CriticalAlarmHigh"];
957 std::optional<bool> criticalDeassertLow =
958 thresholdDeassertMap[path]["CriticalAlarmLow"];
959 std::optional<bool> warningDeassertHigh =
960 thresholdDeassertMap[path]["WarningAlarmHigh"];
961 std::optional<bool> warningDeassertLow =
962 thresholdDeassertMap[path]["WarningAlarmLow"];
963
964 if (criticalDeassertHigh && !*criticalDeassertHigh)
965 {
966 resp->deassertionsMSB |= static_cast<uint8_t>(
967 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
968 }
969 if (criticalDeassertLow && !*criticalDeassertLow)
970 {
971 resp->deassertionsMSB |= static_cast<uint8_t>(
972 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
973 }
974 if (warningDeassertHigh && !*warningDeassertHigh)
975 {
976 resp->deassertionsLSB |= static_cast<uint8_t>(
977 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
978 }
979 if (warningDeassertLow && !*warningDeassertLow)
980 {
981 resp->deassertionsLSB |= static_cast<uint8_t>(
982 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
983 }
984
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700985 if ((warningInterface != sensorMap.end()) ||
986 (criticalInterface != sensorMap.end()))
987 {
988 resp->enabled = static_cast<uint8_t>(
989 IPMISensorEventEnableByte2::eventMessagesEnable);
990 if (warningInterface != sensorMap.end())
991 {
992 auto &warningMap = warningInterface->second;
993
994 auto warningHigh = warningMap.find("WarningAlarmHigh");
995 auto warningLow = warningMap.find("WarningAlarmLow");
996 auto warningHighAlarm = false;
997 auto warningLowAlarm = false;
998
999 if (warningHigh != warningMap.end())
1000 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001001 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001002 }
1003 if (warningLow != warningMap.end())
1004 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001005 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001006 }
1007 if (warningHighAlarm)
1008 {
1009 resp->assertionsLSB |= static_cast<uint8_t>(
1010 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1011 }
1012 if (warningLowAlarm)
1013 {
1014 resp->assertionsLSB |= 1; // lower nc going low
1015 }
1016 }
1017 if (criticalInterface != sensorMap.end())
1018 {
1019 auto &criticalMap = criticalInterface->second;
1020
1021 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1022 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1023 auto criticalHighAlarm = false;
1024 auto criticalLowAlarm = false;
1025
1026 if (criticalHigh != criticalMap.end())
1027 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001028 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001029 }
1030 if (criticalLow != criticalMap.end())
1031 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001032 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001033 }
1034 if (criticalHighAlarm)
1035 {
1036 resp->assertionsMSB |= static_cast<uint8_t>(
1037 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1038 }
1039 if (criticalLowAlarm)
1040 {
1041 resp->assertionsLSB |= static_cast<uint8_t>(
1042 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1043 }
1044 }
1045 *dataLen = sizeof(SensorEventStatusResp);
1046 }
1047
1048 // no thresholds enabled, don't need assertionMSB
1049 else
1050 {
1051 *dataLen = sizeof(SensorEventStatusResp) - 1;
1052 }
1053
1054 return IPMI_CC_OK;
1055}
1056
1057/* end sensor commands */
1058
1059/* storage commands */
1060
James Feist74c50c62019-08-14 14:18:41 -07001061ipmi::RspType<uint8_t, // sdr version
1062 uint16_t, // record count
1063 uint16_t, // free space
1064 uint32_t, // most recent addition
1065 uint32_t, // most recent erase
1066 uint8_t // operationSupport
1067 >
1068 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001069{
James Feist74c50c62019-08-14 14:18:41 -07001070 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001071 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1072 {
James Feist74c50c62019-08-14 14:18:41 -07001073 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001074 }
1075
James Feist74c50c62019-08-14 14:18:41 -07001076 size_t fruCount = 0;
1077 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1078 if (ret != ipmi::ccSuccess)
1079 {
1080 return ipmi::response(ret);
1081 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001082
James Feist74c50c62019-08-14 14:18:41 -07001083 uint16_t recordCount =
1084 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001085
James Feist74c50c62019-08-14 14:18:41 -07001086 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001087 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001088
1089 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001090 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001091 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001092 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001093 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1094 unspecifiedFreeSpace, sdrLastAdd,
1095 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001096}
1097
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001098/** @brief implements the get SDR allocation info command
1099 *
1100 * @returns IPMI completion code plus response data
1101 * - allocUnits - Number of possible allocation units
1102 * - allocUnitSize - Allocation unit size in bytes.
1103 * - allocUnitFree - Number of free allocation units
1104 * - allocUnitLargestFree - Largest free block in allocation units
1105 * - maxRecordSize - Maximum record size in allocation units.
1106 */
1107ipmi::RspType<uint16_t, // allocUnits
1108 uint16_t, // allocUnitSize
1109 uint16_t, // allocUnitFree
1110 uint16_t, // allocUnitLargestFree
1111 uint8_t // maxRecordSize
1112 >
1113 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001114{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001115 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001116 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001117
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001118 constexpr uint16_t allocUnitFree = 0;
1119 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001121 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001122
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001123 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1124 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001125}
1126
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001127/** @brief implements the reserve SDR command
1128 * @returns IPMI completion code plus response data
1129 * - sdrReservationID
1130 */
1131ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001132{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001133 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001134 if (sdrReservationID == 0)
1135 {
1136 sdrReservationID++;
1137 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001138
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001139 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001140}
1141
James Feistb49a98a2019-04-16 13:48:09 -07001142ipmi::RspType<uint16_t, // next record ID
1143 std::vector<uint8_t> // payload
1144 >
1145 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1146 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001147{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001148 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001149
1150 // reservation required for partial reads with non zero offset into
1151 // record
James Feistb49a98a2019-04-16 13:48:09 -07001152 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153 {
James Feistb49a98a2019-04-16 13:48:09 -07001154 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001155 }
1156
1157 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1158 {
James Feistb49a98a2019-04-16 13:48:09 -07001159 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001160 }
1161
1162 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001163 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1164 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001165 {
James Feistb49a98a2019-04-16 13:48:09 -07001166 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167 }
1168
James Feist74c50c62019-08-14 14:18:41 -07001169 size_t lastRecord =
1170 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001171 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001172 {
James Feistb49a98a2019-04-16 13:48:09 -07001173 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001174 }
James Feistb49a98a2019-04-16 13:48:09 -07001175 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001176 {
James Feistb49a98a2019-04-16 13:48:09 -07001177 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001178 }
1179
James Feistb49a98a2019-04-16 13:48:09 -07001180 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001181
James Feistb49a98a2019-04-16 13:48:09 -07001182 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001183 {
James Feist74c50c62019-08-14 14:18:41 -07001184 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001185 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001186 if (fruIndex >= fruCount)
1187 {
James Feist74c50c62019-08-14 14:18:41 -07001188 // handle type 12 hardcoded records
1189 size_t type12Index = fruIndex - fruCount;
1190 if (type12Index >= ipmi::storage::type12Count ||
1191 offset > sizeof(Type12Record))
1192 {
1193 return ipmi::responseInvalidFieldRequest();
1194 }
1195 std::vector<uint8_t> record =
1196 ipmi::storage::getType12SDRs(type12Index, recordID);
1197 if (record.size() < (offset + bytesToRead))
1198 {
1199 bytesToRead = record.size() - offset;
1200 }
James Feistb49a98a2019-04-16 13:48:09 -07001201
James Feist74c50c62019-08-14 14:18:41 -07001202 recordData.insert(recordData.end(), record.begin() + offset,
1203 record.begin() + offset + bytesToRead);
1204 }
1205 else
1206 {
1207 // handle fru records
1208 get_sdr::SensorDataFruRecord data;
1209 if (offset > sizeof(data))
1210 {
1211 return ipmi::responseInvalidFieldRequest();
1212 }
1213 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1214 if (ret != IPMI_CC_OK)
1215 {
1216 return ipmi::response(ret);
1217 }
1218 data.header.record_id_msb = recordID << 8;
1219 data.header.record_id_lsb = recordID & 0xFF;
1220 if (sizeof(data) < (offset + bytesToRead))
1221 {
1222 bytesToRead = sizeof(data) - offset;
1223 }
1224
1225 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1226 recordData.insert(recordData.end(), respStart,
1227 respStart + bytesToRead);
1228 }
James Feistb49a98a2019-04-16 13:48:09 -07001229
1230 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001231 }
1232
1233 std::string connection;
1234 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001235 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001236 for (const auto &sensor : sensorTree)
1237 {
1238 if (sensorIndex-- == 0)
1239 {
1240 if (!sensor.second.size())
1241 {
James Feistb49a98a2019-04-16 13:48:09 -07001242 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001243 }
1244 connection = sensor.second.begin()->first;
1245 path = sensor.first;
1246 break;
1247 }
1248 }
1249
1250 SensorMap sensorMap;
1251 if (!getSensorMap(connection, path, sensorMap))
1252 {
James Feistb49a98a2019-04-16 13:48:09 -07001253 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001254 }
James Feistb49a98a2019-04-16 13:48:09 -07001255 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001256 get_sdr::SensorDataFullRecord record = {0};
1257
James Feistb49a98a2019-04-16 13:48:09 -07001258 record.header.record_id_msb = recordID << 8;
1259 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001260 record.header.sdr_version = ipmiSdrVersion;
1261 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1262 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1263 sizeof(get_sdr::SensorDataRecordHeader);
1264 record.key.owner_id = 0x20;
1265 record.key.owner_lun = 0x0;
1266 record.key.sensor_number = sensornumber;
1267
1268 record.body.entity_id = 0x0;
1269 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001270 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001271 record.body.sensor_type = getSensorTypeFromPath(path);
1272 std::string type = getSensorTypeStringFromPath(path);
1273 auto typeCstr = type.c_str();
1274 auto findUnits = sensorUnits.find(typeCstr);
1275 if (findUnits != sensorUnits.end())
1276 {
1277 record.body.sensor_units_2_base =
1278 static_cast<uint8_t>(findUnits->second);
1279 } // else default 0x0 unspecified
1280
1281 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1282
1283 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1284 if (sensorObject == sensorMap.end())
1285 {
James Feistb49a98a2019-04-16 13:48:09 -07001286 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001287 }
1288
1289 auto maxObject = sensorObject->second.find("MaxValue");
1290 auto minObject = sensorObject->second.find("MinValue");
1291 double max = 128;
1292 double min = -127;
1293 if (maxObject != sensorObject->second.end())
1294 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001295 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001296 }
1297
1298 if (minObject != sensorObject->second.end())
1299 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001300 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001301 }
1302
Yong Li1f2eb5e2019-05-23 14:07:17 +08001303 int16_t mValue = 0;
1304 int8_t rExp = 0;
1305 int16_t bValue = 0;
1306 int8_t bExp = 0;
1307 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001308
1309 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1310 {
James Feistb49a98a2019-04-16 13:48:09 -07001311 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001312 }
1313
1314 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1315 record.body.m_lsb = mValue & 0xFF;
1316
1317 // move the smallest bit of the MSB into place (bit 9)
1318 // the MSbs are bits 7:8 in m_msb_and_tolerance
1319 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1320
1321 // assign the negative
1322 if (mValue < 0)
1323 {
1324 mMsb |= (1 << 7);
1325 }
1326 record.body.m_msb_and_tolerance = mMsb;
1327
1328 record.body.b_lsb = bValue & 0xFF;
1329
1330 // move the smallest bit of the MSB into place
1331 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1332 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1333
1334 // assign the negative
1335 if (bValue < 0)
1336 {
1337 bMsb |= (1 << 7);
1338 }
1339 record.body.b_msb_and_accuracy_lsb = bMsb;
1340
1341 record.body.r_b_exponents = bExp & 0x7;
1342 if (bExp < 0)
1343 {
1344 record.body.r_b_exponents |= 1 << 3;
1345 }
1346 record.body.r_b_exponents = (rExp & 0x7) << 4;
1347 if (rExp < 0)
1348 {
1349 record.body.r_b_exponents |= 1 << 7;
1350 }
1351
1352 // todo fill out rest of units
1353 if (bSigned)
1354 {
1355 record.body.sensor_units_1 = 1 << 7;
1356 }
1357
1358 // populate sensor name from path
1359 std::string name;
1360 size_t nameStart = path.rfind("/");
1361 if (nameStart != std::string::npos)
1362 {
1363 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1364 }
1365
1366 std::replace(name.begin(), name.end(), '_', ' ');
1367 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1368 {
James Feist979a2322019-05-15 09:06:54 -07001369 // try to not truncate by replacing common words
1370 constexpr std::array<std::pair<const char *, const char *>, 2>
1371 replaceWords = {std::make_pair("Output", "Out"),
1372 std::make_pair("Input", "In")};
1373 for (const auto &[find, replace] : replaceWords)
1374 {
1375 boost::replace_all(name, find, replace);
1376 }
1377
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001378 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1379 }
1380 record.body.id_string_info = name.size();
1381 std::strncpy(record.body.id_string, name.c_str(),
1382 sizeof(record.body.id_string));
1383
James Feistc4b15bc2019-04-16 15:41:39 -07001384 IPMIThresholds thresholdData;
1385 try
1386 {
1387 thresholdData = getIPMIThresholds(sensorMap);
1388 }
1389 catch (std::exception &)
1390 {
1391 return ipmi::responseResponseError();
1392 }
1393
1394 if (thresholdData.criticalHigh)
1395 {
1396 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
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[0] |= static_cast<uint8_t>(
1408 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1409 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1410 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1411 record.body.discrete_reading_setting_mask[0] |=
1412 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1413 }
1414 if (thresholdData.criticalLow)
1415 {
1416 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1417 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1418 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1419 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1420 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1421 record.body.discrete_reading_setting_mask[0] |=
1422 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1423 }
1424 if (thresholdData.warningLow)
1425 {
1426 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1427 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1428 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1429 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1430 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1431 record.body.discrete_reading_setting_mask[0] |=
1432 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1433 }
1434
1435 // everything that is readable is setable
1436 record.body.discrete_reading_setting_mask[1] =
1437 record.body.discrete_reading_setting_mask[0];
1438
James Feistb49a98a2019-04-16 13:48:09 -07001439 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001440 {
James Feistb49a98a2019-04-16 13:48:09 -07001441 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001442 }
1443
James Feistb49a98a2019-04-16 13:48:09 -07001444 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1445 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001446
James Feistb49a98a2019-04-16 13:48:09 -07001447 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001448}
1449/* end storage commands */
1450
1451void registerSensorFunctions()
1452{
1453 // get firmware version information
1454 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1455 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1456
1457 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001458 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1459 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001460
1461 // <Set Sensor Reading and Event Status>
1462 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001463 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001464 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1465
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001466 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001467 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1468 ipmi::sensor_event::cmdPlatformEvent,
1469 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001470
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001471 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001472 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1473 ipmi::sensor_event::cmdGetSensorReading,
1474 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001475
1476 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001477 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1478 ipmi::sensor_event::cmdGetSensorThreshold,
1479 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001480
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001481 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001482 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1483 ipmi::sensor_event::cmdSetSensorThreshold,
1484 ipmi::Privilege::Operator,
1485 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001486
1487 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001488 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1489 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001490 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001491
1492 // <Get Sensor Event Status>
1493 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001494 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1495 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001496
1497 // register all storage commands for both Sensor and Storage command
1498 // versions
1499
1500 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001501 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1502 ipmi::storage::cmdGetSdrRepositoryInfo,
1503 ipmi::Privilege::User,
1504 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001505
1506 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001507 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1508 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1509 ipmi::Privilege::User,
1510 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001511
1512 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001513 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1514 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001515 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001516
Vernon Mauery98bbf692019-09-16 11:14:59 -07001517 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1518 ipmi::storage::cmdReserveSdrRepository,
1519 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001520
1521 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001522 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1523 ipmi::sensor_event::cmdGetDeviceSdr,
1524 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001525
Vernon Mauery98bbf692019-09-16 11:14:59 -07001526 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1527 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1528 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001529}
1530} // namespace ipmi