blob: d97e2e422089bb98cd31eb5cf918ea8817f33db7 [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 Venturef777e1b2019-09-25 17:45:44 -070017#include <algorithm>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070018#include <boost/algorithm/string.hpp>
19#include <boost/container/flat_map.hpp>
20#include <chrono>
21#include <cmath>
22#include <commandutils.hpp>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070023#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070024#include <iostream>
Jason M. Bills99b78ec2019-01-18 10:42:18 -080025#include <ipmi_to_redfish_hooks.hpp>
James Feist2a265d52019-04-08 11:16:27 -070026#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070027#include <ipmid/utils.hpp>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070028#include <map>
Patrick Venturec4e9de62019-09-25 17:40:54 -070029#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070030#include <phosphor-logging/log.hpp>
31#include <sdbusplus/bus.hpp>
32#include <sdrutils.hpp>
33#include <sensorcommands.hpp>
34#include <sensorutils.hpp>
35#include <storagecommands.hpp>
36#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070037#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070038#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070039
40namespace ipmi
41{
42using ManagedObjectType =
43 std::map<sdbusplus::message::object_path,
44 std::map<std::string, std::map<std::string, DbusVariant>>>;
45
46using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
47
48static constexpr int sensorListUpdatePeriod = 10;
49static constexpr int sensorMapUpdatePeriod = 2;
50
51constexpr size_t maxSDRTotalSize =
52 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
53constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
54
55static uint16_t sdrReservationID;
56static uint32_t sdrLastAdd = noTimestamp;
57static uint32_t sdrLastRemove = noTimestamp;
58
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053059SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070060static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
61
Jason M. Bills17add592018-11-12 14:30:12 -080062// Specify the comparison required to sort and find char* map objects
63struct CmpStr
64{
65 bool operator()(const char *a, const char *b) const
66 {
67 return std::strcmp(a, b) < 0;
68 }
69};
70const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
71 sensorUnits{{{"temperature", SensorUnits::degreesC},
72 {"voltage", SensorUnits::volts},
73 {"current", SensorUnits::amps},
74 {"fan_tach", SensorUnits::rpm},
75 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070076
77void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070078
79static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070080 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070081 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
82 "sensors/'",
83 [](sdbusplus::message::message &m) {
84 sensorTree.clear();
85 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
86 std::chrono::system_clock::now().time_since_epoch())
87 .count();
88 });
89
90static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070091 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070092 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
93 "sensors/'",
94 [](sdbusplus::message::message &m) {
95 sensorTree.clear();
96 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
97 std::chrono::system_clock::now().time_since_epoch())
98 .count();
99 });
100
James Feist392786a2019-03-19 13:36:10 -0700101// this keeps track of deassertions for sensor event status command. A
102// deasertion can only happen if an assertion was seen first.
103static boost::container::flat_map<
104 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
105 thresholdDeassertMap;
106
107static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700108 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700109 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
110 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
111 [](sdbusplus::message::message &m) {
112 boost::container::flat_map<std::string, std::variant<bool, double>>
113 values;
114 m.read(std::string(), values);
115
116 auto findAssert =
117 std::find_if(values.begin(), values.end(), [](const auto &pair) {
118 return pair.first.find("Alarm") != std::string::npos;
119 });
120 if (findAssert != values.end())
121 {
122 auto ptr = std::get_if<bool>(&(findAssert->second));
123 if (ptr == nullptr)
124 {
125 phosphor::logging::log<phosphor::logging::level::ERR>(
126 "thresholdChanged: Assert non bool");
127 return;
128 }
129 if (*ptr)
130 {
131 phosphor::logging::log<phosphor::logging::level::INFO>(
132 "thresholdChanged: Assert",
133 phosphor::logging::entry("SENSOR=%s", m.get_path()));
134 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
135 }
136 else
137 {
138 auto &value =
139 thresholdDeassertMap[m.get_path()][findAssert->first];
140 if (value)
141 {
142 phosphor::logging::log<phosphor::logging::level::INFO>(
143 "thresholdChanged: deassert",
144 phosphor::logging::entry("SENSOR=%s", m.get_path()));
145 value = *ptr;
146 }
147 }
148 }
149 });
150
James Feistaecaef72019-04-26 10:30:32 -0700151static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
152 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700153{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700154 max = 127;
155 min = -128;
156
James Feistaecaef72019-04-26 10:30:32 -0700157 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
158 auto critical =
159 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
160 auto warning =
161 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
162
163 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700164 {
James Feistaecaef72019-04-26 10:30:32 -0700165 auto maxMap = sensorObject->second.find("MaxValue");
166 auto minMap = sensorObject->second.find("MinValue");
167
168 if (maxMap != sensorObject->second.end())
169 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700170 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700171 }
172 if (minMap != sensorObject->second.end())
173 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700174 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700175 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700176 }
James Feistaecaef72019-04-26 10:30:32 -0700177 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700178 {
James Feistaecaef72019-04-26 10:30:32 -0700179 auto lower = critical->second.find("CriticalLow");
180 auto upper = critical->second.find("CriticalHigh");
181 if (lower != critical->second.end())
182 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700183 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700184 min = std::min(value, min);
185 }
186 if (upper != critical->second.end())
187 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700188 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700189 max = std::max(value, max);
190 }
191 }
192 if (warning != sensorMap.end())
193 {
194
195 auto lower = warning->second.find("WarningLow");
196 auto upper = warning->second.find("WarningHigh");
197 if (lower != warning->second.end())
198 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700199 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700200 min = std::min(value, min);
201 }
202 if (upper != warning->second.end())
203 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700204 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700205 max = std::max(value, max);
206 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700207 }
208}
209
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700210static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
211 SensorMap &sensorMap)
212{
213 static boost::container::flat_map<
214 std::string, std::chrono::time_point<std::chrono::steady_clock>>
215 updateTimeMap;
216
217 auto updateFind = updateTimeMap.find(sensorConnection);
218 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
219 if (updateFind != updateTimeMap.end())
220 {
221 lastUpdate = updateFind->second;
222 }
223
224 auto now = std::chrono::steady_clock::now();
225
226 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
227 .count() > sensorMapUpdatePeriod)
228 {
229 updateTimeMap[sensorConnection] = now;
230
Vernon Mauery15419dd2019-05-24 09:40:30 -0700231 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
232 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700233 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
234 "GetManagedObjects");
235
236 ManagedObjectType managedObjects;
237 try
238 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700239 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700240 reply.read(managedObjects);
241 }
242 catch (sdbusplus::exception_t &)
243 {
244 phosphor::logging::log<phosphor::logging::level::ERR>(
245 "Error getting managed objects from connection",
246 phosphor::logging::entry("CONNECTION=%s",
247 sensorConnection.c_str()));
248 return false;
249 }
250
251 SensorCache[sensorConnection] = managedObjects;
252 }
253 auto connection = SensorCache.find(sensorConnection);
254 if (connection == SensorCache.end())
255 {
256 return false;
257 }
258 auto path = connection->second.find(sensorPath);
259 if (path == connection->second.end())
260 {
261 return false;
262 }
263 sensorMap = path->second;
264
265 return true;
266}
267
268/* sensor commands */
269ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
270 ipmi_request_t request,
271 ipmi_response_t response,
272 ipmi_data_len_t dataLen,
273 ipmi_context_t context)
274{
275 *dataLen = 0;
276 printCommand(+netfn, +cmd);
277 return IPMI_CC_INVALID;
278}
279
James Feist7aaf3fe2019-06-25 11:52:11 -0700280namespace meHealth
281{
282constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
283constexpr const char *path = "/xyz/openbmc_project/status/me";
284constexpr const char *interface = "xyz.openbmc_project.SetHealth";
285constexpr const char *method = "SetHealth";
286constexpr const char *critical = "critical";
287constexpr const char *warning = "warning";
288constexpr const char *ok = "ok";
289} // namespace meHealth
290
291static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
292{
293 constexpr const std::array<uint8_t, 10> critical = {
294 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
295 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
296 0x1A};
297
298 std::string state;
299 if (std::find(critical.begin(), critical.end(), eventData2) !=
300 critical.end())
301 {
302 state = meHealth::critical;
303 }
304 // special case 0x3 as we only care about a few states
305 else if (eventData2 == 0x3)
306 {
307 if (eventData3 <= 0x2)
308 {
309 state = meHealth::warning;
310 }
311 else
312 {
313 return;
314 }
315 }
316 else if (std::find(warning.begin(), warning.end(), eventData2) !=
317 warning.end())
318 {
319 state = meHealth::warning;
320 }
321 else
322 {
323 return;
324 }
325 if (disable)
326 {
327 state = meHealth::ok;
328 }
329
330 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
331 auto setHealth =
332 dbus->new_method_call(meHealth::busname, meHealth::path,
333 meHealth::interface, meHealth::method);
334 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
335 try
336 {
337 dbus->call(setHealth);
338 }
339 catch (sdbusplus::exception_t &)
340 {
341 phosphor::logging::log<phosphor::logging::level::ERR>(
342 "Failed to set ME Health");
343 }
344}
345
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700346ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
347{
James Feist7aaf3fe2019-06-25 11:52:11 -0700348 constexpr const uint8_t meId = 0x2C;
349 constexpr const uint8_t meSensorNum = 0x17;
350 constexpr const uint8_t disabled = 0x80;
351
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700352 uint8_t generatorID = 0;
353 uint8_t evmRev = 0;
354 uint8_t sensorType = 0;
355 uint8_t sensorNum = 0;
356 uint8_t eventType = 0;
357 uint8_t eventData1 = 0;
358 std::optional<uint8_t> eventData2 = 0;
359 std::optional<uint8_t> eventData3 = 0;
360
361 // todo: This check is supposed to be based on the incoming channel.
362 // e.g. system channel will provide upto 8 bytes including generator
363 // ID, but ipmb channel will provide only up to 7 bytes without the
364 // generator ID.
365 // Support for this check is coming in future patches, so for now just base
366 // it on if the first byte is the EvMRev (0x04).
367 if (p.size() && p.data()[0] == 0x04)
368 {
369 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
370 eventData2, eventData3);
371 // todo: the generator ID for this channel is supposed to come from the
372 // IPMB requesters slave address. Support for this is coming in future
373 // patches, so for now just assume it is coming from the ME (0x2C).
374 generatorID = 0x2C;
375 }
376 else
377 {
378 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
379 eventData1, eventData2, eventData3);
380 }
381 if (!p.fullyUnpacked())
382 {
383 return ipmi::responseReqDataLenInvalid();
384 }
385
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700386 // Send this request to the Redfish hooks to log it as a Redfish message
387 // instead. There is no need to add it to the SEL, so just return success.
388 intel_oem::ipmi::sel::checkRedfishHooks(
389 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
390 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700391
James Feist7aaf3fe2019-06-25 11:52:11 -0700392 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
393 eventData3)
394 {
395 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
396 }
397
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700398 return ipmi::responseSuccess();
399}
400
James Feist0cd014a2019-04-08 15:04:33 -0700401ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
402 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700403{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700404 std::string connection;
405 std::string path;
406
407 auto status = getSensorConnection(sensnum, connection, path);
408 if (status)
409 {
James Feist0cd014a2019-04-08 15:04:33 -0700410 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700411 }
412
413 SensorMap sensorMap;
414 if (!getSensorMap(connection, path, sensorMap))
415 {
James Feist0cd014a2019-04-08 15:04:33 -0700416 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700417 }
418 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
419
420 if (sensorObject == sensorMap.end() ||
421 sensorObject->second.find("Value") == sensorObject->second.end())
422 {
James Feist0cd014a2019-04-08 15:04:33 -0700423 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700424 }
James Feist0cd014a2019-04-08 15:04:33 -0700425 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700426 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700427
Yong Li1f2eb5e2019-05-23 14:07:17 +0800428 double max = 0;
429 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700430 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700431
432 int16_t mValue = 0;
433 int16_t bValue = 0;
434 int8_t rExp = 0;
435 int8_t bExp = 0;
436 bool bSigned = false;
437
438 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
439 {
James Feist0cd014a2019-04-08 15:04:33 -0700440 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700441 }
442
James Feist0cd014a2019-04-08 15:04:33 -0700443 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700444 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700445 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700446 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700447 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800448 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700449
James Feist0cd014a2019-04-08 15:04:33 -0700450 uint8_t thresholds = 0;
451
452 auto warningObject =
453 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
454 if (warningObject != sensorMap.end())
455 {
456 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
457 auto alarmLow = warningObject->second.find("WarningAlarmLow");
458 if (alarmHigh != warningObject->second.end())
459 {
460 if (std::get<bool>(alarmHigh->second))
461 {
462 thresholds |= static_cast<uint8_t>(
463 IPMISensorReadingByte3::upperNonCritical);
464 }
465 }
466 if (alarmLow != warningObject->second.end())
467 {
468 if (std::get<bool>(alarmLow->second))
469 {
470 thresholds |= static_cast<uint8_t>(
471 IPMISensorReadingByte3::lowerNonCritical);
472 }
473 }
474 }
475
476 auto criticalObject =
477 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
478 if (criticalObject != sensorMap.end())
479 {
480 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
481 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
482 if (alarmHigh != criticalObject->second.end())
483 {
484 if (std::get<bool>(alarmHigh->second))
485 {
486 thresholds |=
487 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
488 }
489 }
490 if (alarmLow != criticalObject->second.end())
491 {
492 if (std::get<bool>(alarmLow->second))
493 {
494 thresholds |=
495 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
496 }
497 }
498 }
499
500 // no discrete as of today so optional byte is never returned
501 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700502}
503
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000504/** @brief implements the Set Sensor threshold command
505 * @param sensorNumber - sensor number
506 * @param lowerNonCriticalThreshMask
507 * @param lowerCriticalThreshMask
508 * @param lowerNonRecovThreshMask
509 * @param upperNonCriticalThreshMask
510 * @param upperCriticalThreshMask
511 * @param upperNonRecovThreshMask
512 * @param reserved
513 * @param lowerNonCritical - lower non-critical threshold
514 * @param lowerCritical - Lower critical threshold
515 * @param lowerNonRecoverable - Lower non recovarable threshold
516 * @param upperNonCritical - Upper non-critical threshold
517 * @param upperCritical - Upper critical
518 * @param upperNonRecoverable - Upper Non-recoverable
519 *
520 * @returns IPMI completion code
521 */
522ipmi::RspType<> ipmiSenSetSensorThresholds(
523 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
524 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
525 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
526 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
527 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
528 uint8_t upperNonCritical, uint8_t upperCritical,
529 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700530{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000531 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700532
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000533 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700534 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000535 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700536 }
537
538 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000539 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700540 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000541 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700542 }
543
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000544 // if none of the threshold mask are set, nothing to do
545 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
546 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
547 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700548 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000549 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700550 }
551
552 std::string connection;
553 std::string path;
554
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000555 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700556 if (status)
557 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000558 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700559 }
560 SensorMap sensorMap;
561 if (!getSensorMap(connection, path, sensorMap))
562 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000563 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700564 }
565
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700566 double max = 0;
567 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700568 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700569
570 int16_t mValue = 0;
571 int16_t bValue = 0;
572 int8_t rExp = 0;
573 int8_t bExp = 0;
574 bool bSigned = false;
575
576 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
577 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000578 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700579 }
580
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700581 // store a vector of property name, value to set, and interface
582 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
583
584 // define the indexes of the tuple
585 constexpr uint8_t propertyName = 0;
586 constexpr uint8_t thresholdValue = 1;
587 constexpr uint8_t interface = 2;
588 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000589 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700590 {
591 auto findThreshold =
592 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
593 if (findThreshold == sensorMap.end())
594 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000595 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700596 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000597 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700598 {
599 auto findLower = findThreshold->second.find("CriticalLow");
600 if (findLower == findThreshold->second.end())
601 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000602 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700603 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000604 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700605 findThreshold->first);
606 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000607 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700608 {
609 auto findUpper = findThreshold->second.find("CriticalHigh");
610 if (findUpper == findThreshold->second.end())
611 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000612 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700613 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000614 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700615 findThreshold->first);
616 }
617 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000618 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700619 {
620 auto findThreshold =
621 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
622 if (findThreshold == sensorMap.end())
623 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000624 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700625 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000626 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700627 {
628 auto findLower = findThreshold->second.find("WarningLow");
629 if (findLower == findThreshold->second.end())
630 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000631 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700632 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000633 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700634 findThreshold->first);
635 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000636 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700637 {
638 auto findUpper = findThreshold->second.find("WarningHigh");
639 if (findUpper == findThreshold->second.end())
640 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000641 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700642 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000643 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644 findThreshold->first);
645 }
646 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700647 for (const auto &property : thresholdsToSet)
648 {
649 // from section 36.3 in the IPMI Spec, assume all linear
650 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
651 (bValue * std::pow(10, bExp))) *
652 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700653 setDbusProperty(
654 *getSdBus(), connection, path, std::get<interface>(property),
655 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700656 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000657 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700658}
659
James Feist902c4c52019-04-16 14:51:31 -0700660IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700661{
James Feist902c4c52019-04-16 14:51:31 -0700662 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700663 auto warningInterface =
664 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
665 auto criticalInterface =
666 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
667
668 if ((warningInterface != sensorMap.end()) ||
669 (criticalInterface != sensorMap.end()))
670 {
671 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
672
673 if (sensorPair == sensorMap.end())
674 {
675 // should not have been able to find a sensor not implementing
676 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700677 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700678 }
679
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800680 double max = 0;
681 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700682 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700683
684 int16_t mValue = 0;
685 int16_t bValue = 0;
686 int8_t rExp = 0;
687 int8_t bExp = 0;
688 bool bSigned = false;
689
690 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
691 {
James Feist902c4c52019-04-16 14:51:31 -0700692 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700693 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700694 if (warningInterface != sensorMap.end())
695 {
696 auto &warningMap = warningInterface->second;
697
698 auto warningHigh = warningMap.find("WarningHigh");
699 auto warningLow = warningMap.find("WarningLow");
700
701 if (warningHigh != warningMap.end())
702 {
James Feist902c4c52019-04-16 14:51:31 -0700703
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700704 double value =
705 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700706 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700707 value, mValue, rExp, bValue, bExp, bSigned);
708 }
709 if (warningLow != warningMap.end())
710 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700711 double value =
712 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700713 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700714 value, mValue, rExp, bValue, bExp, bSigned);
715 }
716 }
717 if (criticalInterface != sensorMap.end())
718 {
719 auto &criticalMap = criticalInterface->second;
720
721 auto criticalHigh = criticalMap.find("CriticalHigh");
722 auto criticalLow = criticalMap.find("CriticalLow");
723
724 if (criticalHigh != criticalMap.end())
725 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700726 double value =
727 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700728 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700729 value, mValue, rExp, bValue, bExp, bSigned);
730 }
731 if (criticalLow != criticalMap.end())
732 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700733 double value =
734 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700735 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700736 value, mValue, rExp, bValue, bExp, bSigned);
737 }
738 }
739 }
James Feist902c4c52019-04-16 14:51:31 -0700740 return resp;
741}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700742
James Feist902c4c52019-04-16 14:51:31 -0700743ipmi::RspType<uint8_t, // readable
744 uint8_t, // lowerNCrit
745 uint8_t, // lowerCrit
746 uint8_t, // lowerNrecoverable
747 uint8_t, // upperNC
748 uint8_t, // upperCrit
749 uint8_t> // upperNRecoverable
750 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
751{
752 std::string connection;
753 std::string path;
754
755 auto status = getSensorConnection(sensorNumber, connection, path);
756 if (status)
757 {
758 return ipmi::response(status);
759 }
760
761 SensorMap sensorMap;
762 if (!getSensorMap(connection, path, sensorMap))
763 {
764 return ipmi::responseResponseError();
765 }
766
767 IPMIThresholds thresholdData;
768 try
769 {
770 thresholdData = getIPMIThresholds(sensorMap);
771 }
772 catch (std::exception &)
773 {
774 return ipmi::responseResponseError();
775 }
776
777 uint8_t readable = 0;
778 uint8_t lowerNC = 0;
779 uint8_t lowerCritical = 0;
780 uint8_t lowerNonRecoverable = 0;
781 uint8_t upperNC = 0;
782 uint8_t upperCritical = 0;
783 uint8_t upperNonRecoverable = 0;
784
785 if (thresholdData.warningHigh)
786 {
787 readable |=
788 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
789 upperNC = *thresholdData.warningHigh;
790 }
791 if (thresholdData.warningLow)
792 {
793 readable |=
794 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
795 lowerNC = *thresholdData.warningLow;
796 }
797
798 if (thresholdData.criticalHigh)
799 {
800 readable |=
801 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
802 upperCritical = *thresholdData.criticalHigh;
803 }
804 if (thresholdData.criticalLow)
805 {
806 readable |=
807 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
808 lowerCritical = *thresholdData.criticalLow;
809 }
810
811 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
812 lowerNonRecoverable, upperNC, upperCritical,
813 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700814}
815
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000816/** @brief implements the get Sensor event enable command
817 * @param sensorNumber - sensor number
818 *
819 * @returns IPMI completion code plus response data
820 * - enabled - Sensor Event messages
821 * - assertionEnabledLsb - Assertion event messages
822 * - assertionEnabledMsb - Assertion event messages
823 * - deassertionEnabledLsb - Deassertion event messages
824 * - deassertionEnabledMsb - Deassertion event messages
825 */
826
827ipmi::RspType<uint8_t, // enabled
828 uint8_t, // assertionEnabledLsb
829 uint8_t, // assertionEnabledMsb
830 uint8_t, // deassertionEnabledLsb
831 uint8_t> // deassertionEnabledMsb
832 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700833{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700834 std::string connection;
835 std::string path;
836
Patrick Venturea41714c2019-09-25 16:59:41 -0700837 uint8_t enabled = 0;
838 uint8_t assertionEnabledLsb = 0;
839 uint8_t assertionEnabledMsb = 0;
840 uint8_t deassertionEnabledLsb = 0;
841 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000842
843 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700844 if (status)
845 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000846 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700847 }
848
849 SensorMap sensorMap;
850 if (!getSensorMap(connection, path, sensorMap))
851 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000852 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700853 }
854
855 auto warningInterface =
856 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
857 auto criticalInterface =
858 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700859 if ((warningInterface != sensorMap.end()) ||
860 (criticalInterface != sensorMap.end()))
861 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000862 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700863 IPMISensorEventEnableByte2::sensorScanningEnable);
864 if (warningInterface != sensorMap.end())
865 {
866 auto &warningMap = warningInterface->second;
867
868 auto warningHigh = warningMap.find("WarningHigh");
869 auto warningLow = warningMap.find("WarningLow");
870 if (warningHigh != warningMap.end())
871 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000872 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700873 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000874 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700875 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
876 }
877 if (warningLow != warningMap.end())
878 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000879 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700880 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000881 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700882 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
883 }
884 }
885 if (criticalInterface != sensorMap.end())
886 {
887 auto &criticalMap = criticalInterface->second;
888
889 auto criticalHigh = criticalMap.find("CriticalHigh");
890 auto criticalLow = criticalMap.find("CriticalLow");
891
892 if (criticalHigh != criticalMap.end())
893 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000894 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700895 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000896 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700897 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
898 }
899 if (criticalLow != criticalMap.end())
900 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000901 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700902 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000903 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700904 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
905 }
906 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700907 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000908
909 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
910 assertionEnabledMsb, deassertionEnabledLsb,
911 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700912}
913
914ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
915 ipmi_request_t request,
916 ipmi_response_t response,
917 ipmi_data_len_t dataLen,
918 ipmi_context_t context)
919{
920 if (*dataLen != 1)
921 {
922 *dataLen = 0;
923 return IPMI_CC_REQ_DATA_LEN_INVALID;
924 }
925 *dataLen = 0; // default to 0 in case of an error
926
927 uint8_t sensnum = *(static_cast<uint8_t *>(request));
928
929 std::string connection;
930 std::string path;
931
932 auto status = getSensorConnection(sensnum, connection, path);
933 if (status)
934 {
935 return status;
936 }
937
938 SensorMap sensorMap;
939 if (!getSensorMap(connection, path, sensorMap))
940 {
941 return IPMI_CC_RESPONSE_ERROR;
942 }
943
944 auto warningInterface =
945 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
946 auto criticalInterface =
947 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
948
949 // zero out response buff
950 auto responseClear = static_cast<uint8_t *>(response);
951 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
952 auto resp = static_cast<SensorEventStatusResp *>(response);
953 resp->enabled =
954 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
955
James Feist392786a2019-03-19 13:36:10 -0700956 std::optional<bool> criticalDeassertHigh =
957 thresholdDeassertMap[path]["CriticalAlarmHigh"];
958 std::optional<bool> criticalDeassertLow =
959 thresholdDeassertMap[path]["CriticalAlarmLow"];
960 std::optional<bool> warningDeassertHigh =
961 thresholdDeassertMap[path]["WarningAlarmHigh"];
962 std::optional<bool> warningDeassertLow =
963 thresholdDeassertMap[path]["WarningAlarmLow"];
964
965 if (criticalDeassertHigh && !*criticalDeassertHigh)
966 {
967 resp->deassertionsMSB |= static_cast<uint8_t>(
968 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
969 }
970 if (criticalDeassertLow && !*criticalDeassertLow)
971 {
972 resp->deassertionsMSB |= static_cast<uint8_t>(
973 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
974 }
975 if (warningDeassertHigh && !*warningDeassertHigh)
976 {
977 resp->deassertionsLSB |= static_cast<uint8_t>(
978 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
979 }
980 if (warningDeassertLow && !*warningDeassertLow)
981 {
982 resp->deassertionsLSB |= static_cast<uint8_t>(
983 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
984 }
985
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700986 if ((warningInterface != sensorMap.end()) ||
987 (criticalInterface != sensorMap.end()))
988 {
989 resp->enabled = static_cast<uint8_t>(
990 IPMISensorEventEnableByte2::eventMessagesEnable);
991 if (warningInterface != sensorMap.end())
992 {
993 auto &warningMap = warningInterface->second;
994
995 auto warningHigh = warningMap.find("WarningAlarmHigh");
996 auto warningLow = warningMap.find("WarningAlarmLow");
997 auto warningHighAlarm = false;
998 auto warningLowAlarm = false;
999
1000 if (warningHigh != warningMap.end())
1001 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001002 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001003 }
1004 if (warningLow != warningMap.end())
1005 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001006 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001007 }
1008 if (warningHighAlarm)
1009 {
1010 resp->assertionsLSB |= static_cast<uint8_t>(
1011 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1012 }
1013 if (warningLowAlarm)
1014 {
1015 resp->assertionsLSB |= 1; // lower nc going low
1016 }
1017 }
1018 if (criticalInterface != sensorMap.end())
1019 {
1020 auto &criticalMap = criticalInterface->second;
1021
1022 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1023 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1024 auto criticalHighAlarm = false;
1025 auto criticalLowAlarm = false;
1026
1027 if (criticalHigh != criticalMap.end())
1028 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001029 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001030 }
1031 if (criticalLow != criticalMap.end())
1032 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001033 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001034 }
1035 if (criticalHighAlarm)
1036 {
1037 resp->assertionsMSB |= static_cast<uint8_t>(
1038 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1039 }
1040 if (criticalLowAlarm)
1041 {
1042 resp->assertionsLSB |= static_cast<uint8_t>(
1043 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1044 }
1045 }
1046 *dataLen = sizeof(SensorEventStatusResp);
1047 }
1048
1049 // no thresholds enabled, don't need assertionMSB
1050 else
1051 {
1052 *dataLen = sizeof(SensorEventStatusResp) - 1;
1053 }
1054
1055 return IPMI_CC_OK;
1056}
1057
1058/* end sensor commands */
1059
1060/* storage commands */
1061
James Feist74c50c62019-08-14 14:18:41 -07001062ipmi::RspType<uint8_t, // sdr version
1063 uint16_t, // record count
1064 uint16_t, // free space
1065 uint32_t, // most recent addition
1066 uint32_t, // most recent erase
1067 uint8_t // operationSupport
1068 >
1069 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001070{
James Feist74c50c62019-08-14 14:18:41 -07001071 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001072 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1073 {
James Feist74c50c62019-08-14 14:18:41 -07001074 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001075 }
1076
James Feist74c50c62019-08-14 14:18:41 -07001077 size_t fruCount = 0;
1078 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1079 if (ret != ipmi::ccSuccess)
1080 {
1081 return ipmi::response(ret);
1082 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001083
James Feist74c50c62019-08-14 14:18:41 -07001084 uint16_t recordCount =
1085 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001086
James Feist74c50c62019-08-14 14:18:41 -07001087 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001088 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001089
1090 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001091 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001092 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001093 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001094 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1095 unspecifiedFreeSpace, sdrLastAdd,
1096 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001097}
1098
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001099/** @brief implements the get SDR allocation info command
1100 *
1101 * @returns IPMI completion code plus response data
1102 * - allocUnits - Number of possible allocation units
1103 * - allocUnitSize - Allocation unit size in bytes.
1104 * - allocUnitFree - Number of free allocation units
1105 * - allocUnitLargestFree - Largest free block in allocation units
1106 * - maxRecordSize - Maximum record size in allocation units.
1107 */
1108ipmi::RspType<uint16_t, // allocUnits
1109 uint16_t, // allocUnitSize
1110 uint16_t, // allocUnitFree
1111 uint16_t, // allocUnitLargestFree
1112 uint8_t // maxRecordSize
1113 >
1114 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001115{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001116 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001117 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001119 constexpr uint16_t allocUnitFree = 0;
1120 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001121 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001122 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001123
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001124 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1125 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001126}
1127
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001128/** @brief implements the reserve SDR command
1129 * @returns IPMI completion code plus response data
1130 * - sdrReservationID
1131 */
1132ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001133{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001134 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001135 if (sdrReservationID == 0)
1136 {
1137 sdrReservationID++;
1138 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001139
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001140 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001141}
1142
James Feistb49a98a2019-04-16 13:48:09 -07001143ipmi::RspType<uint16_t, // next record ID
1144 std::vector<uint8_t> // payload
1145 >
1146 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1147 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001148{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001149 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001150
1151 // reservation required for partial reads with non zero offset into
1152 // record
James Feistb49a98a2019-04-16 13:48:09 -07001153 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001154 {
James Feistb49a98a2019-04-16 13:48:09 -07001155 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001156 }
1157
1158 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1159 {
James Feistb49a98a2019-04-16 13:48:09 -07001160 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001161 }
1162
1163 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001164 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1165 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001166 {
James Feistb49a98a2019-04-16 13:48:09 -07001167 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001168 }
1169
James Feist74c50c62019-08-14 14:18:41 -07001170 size_t lastRecord =
1171 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001172 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173 {
James Feistb49a98a2019-04-16 13:48:09 -07001174 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001175 }
James Feistb49a98a2019-04-16 13:48:09 -07001176 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001177 {
James Feistb49a98a2019-04-16 13:48:09 -07001178 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001179 }
1180
James Feistb49a98a2019-04-16 13:48:09 -07001181 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001182
James Feistb49a98a2019-04-16 13:48:09 -07001183 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001184 {
James Feist74c50c62019-08-14 14:18:41 -07001185 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001186 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001187 if (fruIndex >= fruCount)
1188 {
James Feist74c50c62019-08-14 14:18:41 -07001189 // handle type 12 hardcoded records
1190 size_t type12Index = fruIndex - fruCount;
1191 if (type12Index >= ipmi::storage::type12Count ||
1192 offset > sizeof(Type12Record))
1193 {
1194 return ipmi::responseInvalidFieldRequest();
1195 }
1196 std::vector<uint8_t> record =
1197 ipmi::storage::getType12SDRs(type12Index, recordID);
1198 if (record.size() < (offset + bytesToRead))
1199 {
1200 bytesToRead = record.size() - offset;
1201 }
James Feistb49a98a2019-04-16 13:48:09 -07001202
James Feist74c50c62019-08-14 14:18:41 -07001203 recordData.insert(recordData.end(), record.begin() + offset,
1204 record.begin() + offset + bytesToRead);
1205 }
1206 else
1207 {
1208 // handle fru records
1209 get_sdr::SensorDataFruRecord data;
1210 if (offset > sizeof(data))
1211 {
1212 return ipmi::responseInvalidFieldRequest();
1213 }
1214 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1215 if (ret != IPMI_CC_OK)
1216 {
1217 return ipmi::response(ret);
1218 }
1219 data.header.record_id_msb = recordID << 8;
1220 data.header.record_id_lsb = recordID & 0xFF;
1221 if (sizeof(data) < (offset + bytesToRead))
1222 {
1223 bytesToRead = sizeof(data) - offset;
1224 }
1225
1226 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1227 recordData.insert(recordData.end(), respStart,
1228 respStart + bytesToRead);
1229 }
James Feistb49a98a2019-04-16 13:48:09 -07001230
1231 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001232 }
1233
1234 std::string connection;
1235 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001236 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001237 for (const auto &sensor : sensorTree)
1238 {
1239 if (sensorIndex-- == 0)
1240 {
1241 if (!sensor.second.size())
1242 {
James Feistb49a98a2019-04-16 13:48:09 -07001243 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001244 }
1245 connection = sensor.second.begin()->first;
1246 path = sensor.first;
1247 break;
1248 }
1249 }
1250
1251 SensorMap sensorMap;
1252 if (!getSensorMap(connection, path, sensorMap))
1253 {
James Feistb49a98a2019-04-16 13:48:09 -07001254 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001255 }
James Feistb49a98a2019-04-16 13:48:09 -07001256 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001257 get_sdr::SensorDataFullRecord record = {0};
1258
James Feistb49a98a2019-04-16 13:48:09 -07001259 record.header.record_id_msb = recordID << 8;
1260 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001261 record.header.sdr_version = ipmiSdrVersion;
1262 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1263 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1264 sizeof(get_sdr::SensorDataRecordHeader);
1265 record.key.owner_id = 0x20;
1266 record.key.owner_lun = 0x0;
1267 record.key.sensor_number = sensornumber;
1268
1269 record.body.entity_id = 0x0;
1270 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001271 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001272 record.body.sensor_type = getSensorTypeFromPath(path);
1273 std::string type = getSensorTypeStringFromPath(path);
1274 auto typeCstr = type.c_str();
1275 auto findUnits = sensorUnits.find(typeCstr);
1276 if (findUnits != sensorUnits.end())
1277 {
1278 record.body.sensor_units_2_base =
1279 static_cast<uint8_t>(findUnits->second);
1280 } // else default 0x0 unspecified
1281
1282 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1283
1284 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1285 if (sensorObject == sensorMap.end())
1286 {
James Feistb49a98a2019-04-16 13:48:09 -07001287 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001288 }
1289
1290 auto maxObject = sensorObject->second.find("MaxValue");
1291 auto minObject = sensorObject->second.find("MinValue");
1292 double max = 128;
1293 double min = -127;
1294 if (maxObject != sensorObject->second.end())
1295 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001296 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001297 }
1298
1299 if (minObject != sensorObject->second.end())
1300 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001301 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001302 }
1303
Yong Li1f2eb5e2019-05-23 14:07:17 +08001304 int16_t mValue = 0;
1305 int8_t rExp = 0;
1306 int16_t bValue = 0;
1307 int8_t bExp = 0;
1308 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001309
1310 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1311 {
James Feistb49a98a2019-04-16 13:48:09 -07001312 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001313 }
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 // move the smallest bit of the MSB into place (bit 9)
1319 // the MSbs are bits 7:8 in m_msb_and_tolerance
1320 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1321
1322 // assign the negative
1323 if (mValue < 0)
1324 {
1325 mMsb |= (1 << 7);
1326 }
1327 record.body.m_msb_and_tolerance = mMsb;
1328
1329 record.body.b_lsb = bValue & 0xFF;
1330
1331 // move the smallest bit of the MSB into place
1332 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1333 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1334
1335 // assign the negative
1336 if (bValue < 0)
1337 {
1338 bMsb |= (1 << 7);
1339 }
1340 record.body.b_msb_and_accuracy_lsb = bMsb;
1341
1342 record.body.r_b_exponents = bExp & 0x7;
1343 if (bExp < 0)
1344 {
1345 record.body.r_b_exponents |= 1 << 3;
1346 }
1347 record.body.r_b_exponents = (rExp & 0x7) << 4;
1348 if (rExp < 0)
1349 {
1350 record.body.r_b_exponents |= 1 << 7;
1351 }
1352
1353 // todo fill out rest of units
1354 if (bSigned)
1355 {
1356 record.body.sensor_units_1 = 1 << 7;
1357 }
1358
1359 // populate sensor name from path
1360 std::string name;
1361 size_t nameStart = path.rfind("/");
1362 if (nameStart != std::string::npos)
1363 {
1364 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1365 }
1366
1367 std::replace(name.begin(), name.end(), '_', ' ');
1368 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1369 {
James Feist979a2322019-05-15 09:06:54 -07001370 // try to not truncate by replacing common words
1371 constexpr std::array<std::pair<const char *, const char *>, 2>
1372 replaceWords = {std::make_pair("Output", "Out"),
1373 std::make_pair("Input", "In")};
1374 for (const auto &[find, replace] : replaceWords)
1375 {
1376 boost::replace_all(name, find, replace);
1377 }
1378
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001379 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1380 }
1381 record.body.id_string_info = name.size();
1382 std::strncpy(record.body.id_string, name.c_str(),
1383 sizeof(record.body.id_string));
1384
James Feistc4b15bc2019-04-16 15:41:39 -07001385 IPMIThresholds thresholdData;
1386 try
1387 {
1388 thresholdData = getIPMIThresholds(sensorMap);
1389 }
1390 catch (std::exception &)
1391 {
1392 return ipmi::responseResponseError();
1393 }
1394
1395 if (thresholdData.criticalHigh)
1396 {
1397 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1398 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1399 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1400 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1401 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1402 record.body.discrete_reading_setting_mask[0] |=
1403 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1404 }
1405 if (thresholdData.warningHigh)
1406 {
1407 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1408 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1409 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1410 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1411 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1412 record.body.discrete_reading_setting_mask[0] |=
1413 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1414 }
1415 if (thresholdData.criticalLow)
1416 {
1417 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1418 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1419 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1420 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1421 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1422 record.body.discrete_reading_setting_mask[0] |=
1423 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1424 }
1425 if (thresholdData.warningLow)
1426 {
1427 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1428 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1429 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1430 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1431 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1432 record.body.discrete_reading_setting_mask[0] |=
1433 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1434 }
1435
1436 // everything that is readable is setable
1437 record.body.discrete_reading_setting_mask[1] =
1438 record.body.discrete_reading_setting_mask[0];
1439
James Feistb49a98a2019-04-16 13:48:09 -07001440 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001441 {
James Feistb49a98a2019-04-16 13:48:09 -07001442 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001443 }
1444
James Feistb49a98a2019-04-16 13:48:09 -07001445 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1446 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001447
James Feistb49a98a2019-04-16 13:48:09 -07001448 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001449}
1450/* end storage commands */
1451
1452void registerSensorFunctions()
1453{
1454 // get firmware version information
1455 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1456 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1457
1458 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001459 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1460 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001461
1462 // <Set Sensor Reading and Event Status>
1463 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001464 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001465 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1466
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001467 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001468 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1469 ipmi::sensor_event::cmdPlatformEvent,
1470 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001471
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001472 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001473 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1474 ipmi::sensor_event::cmdGetSensorReading,
1475 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001476
1477 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001478 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1479 ipmi::sensor_event::cmdGetSensorThreshold,
1480 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001481
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001482 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001483 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1484 ipmi::sensor_event::cmdSetSensorThreshold,
1485 ipmi::Privilege::Operator,
1486 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001487
1488 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001489 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1490 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001491 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001492
1493 // <Get Sensor Event Status>
1494 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001495 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1496 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001497
1498 // register all storage commands for both Sensor and Storage command
1499 // versions
1500
1501 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001502 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1503 ipmi::storage::cmdGetSdrRepositoryInfo,
1504 ipmi::Privilege::User,
1505 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001506
1507 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001508 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1509 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1510 ipmi::Privilege::User,
1511 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001512
1513 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001514 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1515 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001516 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001517
Vernon Mauery98bbf692019-09-16 11:14:59 -07001518 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1519 ipmi::storage::cmdReserveSdrRepository,
1520 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001521
1522 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001523 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1524 ipmi::sensor_event::cmdGetDeviceSdr,
1525 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001526
Vernon Mauery98bbf692019-09-16 11:14:59 -07001527 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1528 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1529 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001530}
1531} // namespace ipmi